diff --git a/examples/gno.land/p/demo/openocean/collection.gno b/examples/gno.land/p/demo/openocean/collection.gno new file mode 100644 index 00000000000..5b5e082176e --- /dev/null +++ b/examples/gno.land/p/demo/openocean/collection.gno @@ -0,0 +1,321 @@ +package openocean + +import ( + "std" + "errors" + "gno.land/p/demo/avl" + "gno.land/p/demo/ufmt" + "gno.land/p/demo/grc/grc721" +) + +type Collection struct { + id string + name string + symbol string + addrOwner std.Address + description string + logo string // ipfs path + avaiableTokens uint64 + nftsBought uint64 + nfts *avl.Tree + stars *avl.Tree +} + +var ( + invalidAdrErr = errors.New("Invalid address") + idNotFoundErr = errors.New("Couldn't find the id that you are searching for") +) + +func (c *Collection) BalanceOf(owner std.Address) (uint64, bool) { + var blc uint64 = 0 + + c.nfts.Iterate("", "", func (id string, value interface{}) bool { + nft := value.(*NFTtoken721) + if nft.GetOwner() == owner { + blc += 1 + } + return false + }) + if blc > 0 { + return blc, true + } + return blc, false +} + +func (c *Collection) OwnerOf(tokenId string) (std.Address, bool) { + i, found := c.nfts.Get(tokenId) + + if found == false { + panic(idNotFoundErr) + } + + nft := i.(*NFTtoken721) + return nft.GetOwner(), found +} + +func (c *Collection) SafeTransferFrom( + from std.Address, + to std.Address, + tokenId string, +) { + if to.IsValid() == false { + panic(invalidAdrErr) + } + + i, ok := c.nfts.Get(tokenId) + + if ok == false { + panic(idNotFoundErr) + } + + nft := i.(*NFTtoken721) + nft.SetOwner(to) +} + +func (c *Collection) SafeTransferFromWithData( + from std.Address, + to std.Address, + tokenId string, + data string, +) { + if to.IsValid() == false { + panic(invalidAdrErr) + } + + i, ok := c.nfts.Get(tokenId) + + if ok == false { + panic(idNotFoundErr) + } + + nft := i.(*NFTtoken721) + nft.SetOwner(to) +} + +func (c *Collection) TransferFrom( + from std.Address, + to std.Address, + tokenId string, +) { + i, ok := c.nfts.Get(tokenId) + + if ok == false { + panic(idNotFoundErr) + } + + nft := i.(*NFTtoken721) + nft.SetOwner(to) +} + +func (c *Collection) Approve(to std.Address, tokenId string) error { + caller := std.GetOrigCaller() + + if to.IsValid() == false { + panic(invalidAdrErr) + } + + nft, found := c.GetNFTByID(tokenId) + + if found == false { + panic(idNotFoundErr) + } + return nft.Approve(caller, to) +} + +func (c *Collection) GetApproved(tokenId string) (std.Address, error) { + nft, found := c.GetNFTByID(tokenId) + + if found == false { + panic(idNotFoundErr) + } + return nft.GetApproved() +} + +func (c *Collection) SetApprovalForAll(tokenId string, operator std.Address, _approved std.Address) error { + caller := std.GetOrigCaller() + + if _approved.IsValid() == false || operator.IsValid() == false { + panic(invalidAdrErr) + } + + nft, found := c.GetNFTByID(tokenId) + + if found == false { + panic(idNotFoundErr) + } + return nft.SetApprovalForAll(caller, operator, _approved) +} + +func (c *Collection) IsApprovedForAll(tokenId string, owner std.Address, operator std.Address) bool { + if owner.IsValid() == false || operator.IsValid() == false { + panic(invalidAdrErr) + } + + nft, found := c.GetNFTByID(tokenId) + + if found == false { + panic(idNotFoundErr) + } + return nft.IsApprovedForAll(owner, operator) +} + +func (c *Collection) GetId() string { + return c.id +} + +func (c *Collection) GetName() string { + return c.name +} + +func (c *Collection) GetSymbol() string { + return c.symbol +} + +func (c *Collection) GetOwner() std.Address { + return c.addrOwner +} + +func (c *Collection) IncreateNFTSBought() { + c.nftsBought += 1 +} + +func (c *Collection) GetNFTSBought() uint64 { + return c.nftsBought +} + +func (c *Collection) GetDescription() string { + return c.description +} + +func (c *Collection) GetLogo() string { + return c.logo +} + +func (c *Collection) GetNFTS() *avl.Tree { + return c.nfts +} + +func (c *Collection) GetAvaiableTokens() uint64 { + return c.avaiableTokens +} + +func (c *Collection) GetStars() *avl.Tree { + return c.stars +} + +func (c *Collection) getAvailableNFT() (*NFTtoken721, bool) { + var nft *NFTtoken721 + var found bool = false + + c.nfts.Iterate("", "", func(id string, n interface{}) bool { + nft = n.(*NFTtoken721) + + if nft.IsMinted() == false { + found = true + return true + } + return false + }) + return nft, found +} + +func (c *Collection) Mint( + name string, + cid string, + description string, + owner std.Address, + price uint64, +) bool { + if c.avaiableTokens <= 0 { + panic(errors.New("Collection hasn`t any available tokens")) + } + c.avaiableTokens -= 1 + nft, found := c.getAvailableNFT() + + if found == false { + panic(errors.New("There are no more available nfts")) + } + nft.Mint(name, cid, description, owner, price) + return true +} + +func (c *Collection) GetNFTByID(nftID string) (*NFTtoken721, bool) { + nft, found := c.nfts.Get(nftID) + + return nft.(*NFTtoken721), found +} + +func GetCollectionByID(clts *avl.Tree, idToFind string) (*Collection, bool) { + value, exists := clts.Get(idToFind) + + if exists == false { + panic(idNotFoundErr) + } + return value.(*Collection), true +} + +func (c *Collection) IsStarred() bool { + addr := std.GetOrigCaller() + _, exists := c.stars.Get(addr.String()) + return exists +} + +func (c *Collection) Star() bool { + addr := std.GetOrigCaller() + if c.IsStarred() == true { + return false + } + c.stars.Set(addr.String(), true) + return true; +} + +func (c *Collection) Unstar() bool { + addr := std.GetOrigCaller() + if c.IsStarred() == false { + return false + } + c.stars.Remove(addr.String()) + return true +} + +func CreateCollection( + collectionId uint64, + nftID *uint64, + name string, + symbol string, + addrOwner std.Address, + description string, + logo string, + avaiableTokens uint64, +) (*Collection, error) { + var nfts *avl.Tree = avl.NewTree() + var stars *avl.Tree = avl.NewTree() + + if addrOwner.IsValid() == false { + return nil, errors.New("Invalid address") + } + for i := uint64(0); i < avaiableTokens; i += 1 { + idStr := ufmt.Sprintf("%d", *nftID) + tkn, err := InitToken(addrOwner, grc721.TokenID(idStr)) + if err != nil { + panic(err) + } + nfts.Set(string(tkn.GetId()), tkn) + *nftID += 1 + } + idClt := ufmt.Sprintf("%d", collectionId) + clt := &Collection{ + id: idClt, + name: name, + symbol: symbol, + addrOwner: addrOwner, + description: description, + logo: logo, + avaiableTokens: avaiableTokens, + nftsBought: 0, + nfts: nfts, + stars: stars, + } + clt.Star() + return clt, nil +} diff --git a/examples/gno.land/p/demo/openocean/collection_test.gno b/examples/gno.land/p/demo/openocean/collection_test.gno new file mode 100644 index 00000000000..4c70004ecc6 --- /dev/null +++ b/examples/gno.land/p/demo/openocean/collection_test.gno @@ -0,0 +1,127 @@ +package openocean + +import ( + "std" + "testing" +) + +func TestInitCollection(t *testing.T) { + { + const adr std.Address = "g125fhetg9kc3surkxh78avppegc3997l3jr4wdf" + var nftID uint64 = 0 + description := "This is a planet collection" + clt, err := CreateCollection( + 0, + &nftID, + "Neptune", + "NEP", + adr, + description, + "no logo", + 5, + ) + + if err != nil { + t.Fatal(err) + } + + expectedId := "0" + expectedName := "Neptune" + expectedSymbol := "NEP" + expectedOwner := adr + expectedDescription := description + expectedLogo := "no logo" + var expectedAvaiableTokens uint64 = 5 + + if expectedId != clt.GetId() { + t.Fatalf("expected %s, got %s", expectedId, clt.GetId()) + } + + if expectedName != clt.GetName() { + t.Fatalf("expected %s, got %s", expectedName, clt.GetName()) + } + + if expectedSymbol != clt.GetSymbol() { + t.Fatalf("expected %s, got %s", expectedSymbol, clt.GetSymbol()) + } + + if expectedOwner != clt.GetOwner() { + t.Fatalf("expected %s, got %s", expectedOwner, clt.GetOwner()) + } + + if expectedDescription != clt.GetDescription() { + t.Fatalf("expected %s, got %s", expectedDescription, clt.GetDescription()) + } + + if expectedLogo != clt.GetLogo() { + t.Fatalf("expected %s, got %s", expectedLogo, clt.GetLogo()) + } + + if expectedAvaiableTokens != clt.GetAvaiableTokens(){ + t.Fatalf("expected %d avai, got %d", expectedAvaiableTokens, clt.GetAvaiableTokens()) + } + } + { + const adr std.Address = "g125fhetg9kc3surkxh78avppegc3997l3jr4wdf" + var nftID uint64 = 1 + description := "This is a planet collection" + clt, err := CreateCollection( + 0, + &nftID, + "Neptune", + "NEP", + adr, + description, + "no logo", + 5, + ) + + if err != nil { + t.Fatal(err) + } + + + } + { + countOwner := 1 + var countNfts uint64 = 0 + expectedNbOfOwners := 1 + var expectedNbOfNfts uint64 = 5 + const adr std.Address = "g125fhetg9kc3surkxh78avppegc3997l3jr4wdf" + var nftID uint64 = 0 + description := "This is a planet collection" + clt, err := CreateCollection( + 0, + &nftID, + "Neptune", + "NEP", + adr, + description, + "no logo", + 5, + ) + nfts := clt.GetNFTS() + + if err != nil { + t.Fatal(err) + } + + + nfts.Iterate("", "", func (id string, i interface{}) bool { + nft := i.(*NFTtoken721) + if nft.GetOwner() != adr { + countOwner++ + } + countNfts++ + return false + }) + + if expectedNbOfOwners != countOwner{ + t.Fatalf("expected %d owners of nfts, got %d", expectedNbOfOwners, countOwner) + } + + if expectedNbOfNfts != countNfts{ + t.Fatalf("expected %d nfts, got %d", expectedNbOfNfts, countNfts) + } + } +} diff --git a/examples/gno.land/p/demo/openocean/doc.gno b/examples/gno.land/p/demo/openocean/doc.gno new file mode 100644 index 00000000000..2c6a932c355 --- /dev/null +++ b/examples/gno.land/p/demo/openocean/doc.gno @@ -0,0 +1,44 @@ +/* +Package openocean is a library that will help you create your own NFT markeplace, following the GRC721 + +Example: + + import ( + "gno.land/p/demo/openocean" + "gno.land/p/demo/avl" + "std" + ) + + var collections *avl.Tree + var collectionID uint64 + var nftsID uint64 + + + func CreateMyFirstCollection( + collectionID int, + ) { + caller := std.GetOrigCaller() + symbol := "TST" + name := "test" + description := "this is the test collection" + logo := "ipfs link..." + var avaiableNfts uint64 = 5 + + clt, err := openocean.CreateCollection( + collectionId, + &nftsID, + name, + symbol, + caller, + description, + logo, + avaiableNfts, + ) + + if err != nil { + panic(err) + } + } +*/ + +package openocean // import "gno.land/p/demo/openocean" diff --git a/examples/gno.land/p/demo/openocean/gno.mod b/examples/gno.land/p/demo/openocean/gno.mod new file mode 100644 index 00000000000..85426ab37ca --- /dev/null +++ b/examples/gno.land/p/demo/openocean/gno.mod @@ -0,0 +1,8 @@ +module gno.land/p/molaryy/openocean + +require ( + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/grc/grc721 v0.0.0-latest + gno.land/p/demo/json v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest +) diff --git a/examples/gno.land/p/demo/openocean/nft.gno b/examples/gno.land/p/demo/openocean/nft.gno new file mode 100644 index 00000000000..db50f96fea0 --- /dev/null +++ b/examples/gno.land/p/demo/openocean/nft.gno @@ -0,0 +1,156 @@ +package openocean + +import ( + "std" + "errors" + "gno.land/p/demo/ufmt" + "gno.land/p/demo/json" + "gno.land/p/demo/grc/grc721" + "gno.land/p/demo/avl" +) + +type NFTtoken721 struct { + id grc721.TokenID + name string + owner std.Address + metadata string + isMinted bool + isForSale bool + price uint64 + tokenApprovals *avl.Tree +} + +func (n *NFTtoken721) GetId() grc721.TokenID { + return n.id +} + +func (n *NFTtoken721) GetName() string { + return n.name +} + +func (n *NFTtoken721) GetOwner() std.Address { + return n.owner +} + +func (n *NFTtoken721) GetMetadata() string { + return n.metadata +} + +func (n *NFTtoken721) GetPrice() uint64 { + return n.price +} + +func (n *NFTtoken721) SetForSale(state bool) { + n.isForSale = state +} + +func (n *NFTtoken721) IsForSale() bool { + return n.isForSale +} + +func (n *NFTtoken721) SetOwner(owner std.Address) bool { + if owner.IsValid() == false { + return false + } + n.owner = owner + return true +} + +func (n *NFTtoken721) IsMinted() bool { + return n.isMinted +} + +func (n *NFTtoken721) Mint( + name string, + cid string, + description string, + owner std.Address, + price uint64, +) bool { + if n.isMinted == true { + panic(errors.New(ufmt.Sprintf("NFT: %d has already been minted!", n.id))) + } + nftJson := json.ObjectNode("", map[string]*json.Node{ + "owner": json.StringNode("owner", owner.String()), + "name": json.StringNode("name", name), + "cid": json.StringNode("cid", cid), + "description": json.StringNode("description", description), + }) + + encoded, err := json.Marshal(nftJson) + + if err != nil { + panic(err) + } + n.metadata = string(encoded) + n.isMinted = true + n.owner = owner + n.name = name + n.price = price + n.isForSale = true + return true +} + +func (n *NFTtoken721) Approve(caller std.Address, to std.Address) error { + if !n.isMinted { + return errors.New("token does not exist") + } + + if caller != n.owner && !n.IsApprovedForAll(n.owner, caller) { + return errors.New("caller is not owner nor approved for all") + } + n.tokenApprovals.Set(string(n.GetId()), to) + return nil +} + +func (n *NFTtoken721) GetApproved() (std.Address, error) { + var adr std.Address + + if !n.isMinted { + return adr, errors.New("token does not exist") + } + + approvedAddr, exists := n.tokenApprovals.Get(string(n.GetId())) + if !exists { + return adr, errors.New("no approved address for this token") + } + + return approvedAddr.(std.Address), nil +} + +func (n *NFTtoken721) SetApprovalForAll(caller std.Address, operator std.Address, _approved std.Address) error { + if caller != n.owner { + return errors.New("caller is not the owner") + } + + n.tokenApprovals.Set(operator.String(), _approved) + return nil +} + +func (n *NFTtoken721) IsApprovedForAll(owner std.Address, operator std.Address) bool { + approved, exists := n.tokenApprovals.Get(operator.String()) + + if !exists { + return false + } + return approved.(bool) +} + +func InitToken( + addrOwner std.Address, + nftId grc721.TokenID, +) (*NFTtoken721, error) { + if addrOwner.IsValid() == false { + return nil, errors.New("Invalid owner address") + } + return &NFTtoken721 { + id: nftId, + name: "", + owner: addrOwner, + metadata: "", + isMinted: false, + isForSale: true, + price: 0, + tokenApprovals: nil, + }, nil +} diff --git a/examples/gno.land/p/demo/openocean/nft_test.gno b/examples/gno.land/p/demo/openocean/nft_test.gno new file mode 100644 index 00000000000..f9766685f46 --- /dev/null +++ b/examples/gno.land/p/demo/openocean/nft_test.gno @@ -0,0 +1,149 @@ +package openocean + +import ( + "std" + "testing" + "errors" + + "gno.land/p/demo/json" +) + +const adr std.Address = "g125fhetg9kc3surkxh78avppegc3997l3jr4wdf" + +func TestInitNft(t *testing.T) { + { + const adrT std.Address = "hello world!" + _, err := InitToken(adrT, "0") + expectedErr := errors.New("Invalid owner address") + + if err == nil { + t.Fatalf("expected %s, got %s", expectedErr, err) + } + } + { + initNft, err := InitToken(adr, "0") + + if err != nil { + t.Fatal(err) + } + + expectedId := "0" + id := initNft.GetId() + + if string(id) != expectedId { + t.Fatalf("expected %s, got %s", expectedId, id) + } + } + { + initNft, err := InitToken(adr, "1") + + if err != nil { + t.Fatal(err) + } + + gotAdr := initNft.GetOwner() + + if gotAdr != adr { + t.Fatalf("expected %s, got %s.", adr.String(), gotAdr.String()) + } + } + { + initNft, err := InitToken(adr, "2") + + if err != nil { + t.Fatal(err) + } + + gotMinted := initNft.IsMinted() + + if gotMinted != false { + t.Fatalf("expected %t, got %t.", false, gotMinted) + } + } +} + +func TestMintNft(t *testing.T) { + { + const nwAdr std.Address = "g199esk77thuk3lhzz2ktmkgffk7d9eh7hn0kmqt" + nft, err := InitToken(adr, "3") + + if err != nil { + t.Fatal(err) + } + + + isMinted := nft.IsMinted() + + if isMinted { + t.Fatalf("expected false, got true") + } + + nft.Mint("Pablo", "test", "hey everyone", nwAdr, 25) + expectedIsMinted := true + expectedOwner := nwAdr + expectedName := "Pablo" + var expectedPrice uint64 = 25 + expectedMetadata := json.ObjectNode("", map[string]*json.Node{ + "owner": json.StringNode("owner", nwAdr.String()), + "name": json.StringNode("name", "Pablo"), + "cid": json.StringNode("cid", "test"), + "description": json.StringNode("description", "hey everyone"), + }) + + if expectedIsMinted != nft.IsMinted() { + t.Fatalf("expected true, got false") + } + + if expectedOwner != nft.GetOwner() { + t.Fatalf("expected %s, got %s", expectedOwner.String(), nft.GetOwner().String()) + } + + if expectedName != nft.GetName() { + t.Fatalf("expected %s, got %s", expectedName, nft.GetName()) + } + + if expectedPrice != nft.GetPrice() { + t.Fatalf("expected %d, got %d", expectedPrice, nft.GetPrice()) + } + + encodedExpectedMetadata, err := json.Marshal(expectedMetadata) + + if err != nil { + t.Fatal(err) + } + strEncodedExpectedMetadata := string(encodedExpectedMetadata) + if strEncodedExpectedMetadata != nft.GetMetadata() { + t.Fatalf("expected %s, got %s", strEncodedExpectedMetadata, nft.GetMetadata()) + } + } +} + +func TestOwnerNft(t *testing.T) { + { + { + const nwAdr std.Address = "g199esk77thuk3lhzz2ktmkgffk7d9eh7hn0kmqt" + nft, err := InitToken(adr, "4") + + if err != nil { + t.Fatal(err) + } + + gotAdr := nft.GetOwner() + + if gotAdr != adr { + t.Fatalf("expected %s, got %s.", adr.String(), gotAdr.String()) + } + + ok := nft.SetOwner(nwAdr) + + if ok == false { + t.Fatal("There was an error when trying to set a new owner") + } + + gotAdr = nft.GetOwner() + if gotAdr != nwAdr { + t.Fatalf("expected %s, got %s.", nwAdr.String(), gotAdr.String()) + } + } + } +} diff --git a/examples/gno.land/r/demo/openocean/gno.mod b/examples/gno.land/r/demo/openocean/gno.mod new file mode 100644 index 00000000000..98c0f2b803e --- /dev/null +++ b/examples/gno.land/r/demo/openocean/gno.mod @@ -0,0 +1,8 @@ +module gno.land/r/molaryy/openocean + +require ( + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/json v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest + gno.land/p/molaryy/openocean v0.0.0-latest +) diff --git a/examples/gno.land/r/demo/openocean/openocean.gno b/examples/gno.land/r/demo/openocean/openocean.gno new file mode 100644 index 00000000000..a9b97c5b2a0 --- /dev/null +++ b/examples/gno.land/r/demo/openocean/openocean.gno @@ -0,0 +1,273 @@ +package openr + +import ( + "std" + "errors" + "gno.land/p/demo/avl" + "gno.land/p/molaryy/openocean" + "gno.land/p/demo/json" +) + +// change to another address +const ( + openoceanAdr std.Address = "g125fhetg9kc3surkxh78avppegc3997l3jr4wdf" +) + +var ( + collections *avl.Tree + collectionCounter uint64 + nftID uint64 +) + +func init() { + collections = avl.NewTree() +} + +var count int + +func AddCollection( + name string, + symbol string, + description string, + logo string, + avaiableTokens uint64, +) { + caller := std.GetOrigCaller() + coinSent := std.GetOrigSend() + banker := std.GetBanker(std.BankerTypeOrigSend) + realmAddr := std.CurrentRealm().Addr() + + if coinSent.AmountOf("ugnot") < 5 { + panic(errors.New("You don't have enough founds to create a collection, it costs 5 ugnots and you have " + string(coinSent.AmountOf("ugnot")) + " ugnots")) + } + + clt, err := openocean.CreateCollection( + collectionCounter, + &nftID, + name, + symbol, + caller, + description, + logo, + avaiableTokens, + ) + + if clt == nil || err != nil { + panic(err) + } + + banker.SendCoins(realmAddr, openoceanAdr, std.Coins{coinSent[0]}) + id := clt.GetId() + collections.Set(id, clt) + collectionCounter++ +} + +func GetCollections() string { + cltsJson := json.ArrayNode("", []*json.Node{}) + + collections.Iterate("", "", func (id string, value interface{}) bool { + clt := value.(*openocean.Collection) + + if clt == nil { + return true + } + + nfts := clt.GetNFTS() + nftsJson := json.ArrayNode("", []*json.Node{}) + cltField := json.ObjectNode("", map[string]*json.Node{ + "id": json.StringNode("id", clt.GetId()), + "name": json.StringNode("name", clt.GetName()), + "logo": json.StringNode("logo", clt.GetLogo()), + "owner": json.StringNode("owner", clt.GetOwner().String()), + "description": json.StringNode("description", clt.GetDescription()), + "volume": json.NumberNode("volume", float64(clt.GetAvaiableTokens())), + "sales": json.NumberNode("sales", float64(clt.GetNFTSBought())), + }) + nfts.Iterate("", "", func (id string, valueNft interface{}) bool { + nft := valueNft.(* openocean.NFTtoken721) + nftField := json.ObjectNode("", map[string]*json.Node{ + "id": json.StringNode("id",string(nft.GetId())), + "owner": json.StringNode("owner", nft.GetOwner().String()), + "isMinted": json.BoolNode("isMinted", nft.IsMinted()), + "price": json.NumberNode("price", float64(nft.GetPrice())), + "isForSale": json.BoolNode("isForSale", nft.IsForSale()), + "collectionId": json.StringNode("collectionId", clt.GetId()), + }) + cltField.AppendObject(string(nft.GetId()), nftField) + metadata := nft.GetMetadata() + + if metadata != "" { + metadataJson, err := json.Unmarshal([]byte(metadata)) + if err != nil { + panic(err) + } + nftField.AppendObject("metadata", metadataJson) + } + + nftsJson.AppendArray(nftField) + return false + }) + cltField.AppendObject("nfts", nftsJson) + starsJson := json.ArrayNode("", []*json.Node{}) + stars := clt.GetStars() + + stars.Iterate("", "", func (id string, value interface{}) bool { + starsJson.AppendArray(json.StringNode("", id)) + return false + }) + + cltField.AppendObject("stars", starsJson) + cltsJson.AppendArray(cltField) + return false + }) + encoded, err := json.Marshal(cltsJson) + + if err != nil { + panic(err) + } + + return string(encoded) +} + +func MintInCollectionById( + collectionID string, + nftName string, + cid string, + description string, + price uint64, +) bool { + clt, ok := openocean.GetCollectionByID(collections, collectionID) + caller := std.GetOrigCaller() + + if ok == false { + panic(errors.New("Couldn't find collection: " + collectionID)) + } + + if caller != clt.GetOwner() { + panic(errors.New("You are not the owner of the collection")) + } + + return clt.Mint(nftName, cid, description, caller, price) +} + +func BuyNFT(collectionID string, nftID string) { + caller := std.GetOrigCaller() + clt, ok := openocean.GetCollectionByID(collections, collectionID) + coinSent := std.GetOrigSend() + banker := std.GetBanker(std.BankerTypeOrigSend) + realmAddr := std.CurrentRealm().Addr() + + if ok == false { + panic(errors.New("Couldn't find collection: " + collectionID)) + } + + nft, ok := clt.GetNFTByID(nftID) + + if ok == false { + panic(errors.New("Couldn't find an nft with this iD")) + } + + if nft.GetOwner() == caller { + panic(errors.New("You already have this nft: " + nftID)) + } + + if nft.IsForSale() == false { + panic(errors.New("The nft: " + nftID + " is not for sale")) + } + + + if nft.GetPrice() > uint64(coinSent.AmountOf("ugnot")) { + panic(errors.New("You don't have enough ugnots to buy the nft: " + nftID)) + } + + clt.IncreateNFTSBought() + nft.SetOwner(caller) + nft.SetForSale(false) + banker.SendCoins(realmAddr, clt.GetOwner(), std.Coins{coinSent[0]}) +} + +func SetNFTForSale(collectionID string, nftID string, sellingState bool) { + caller := std.GetOrigCaller() + clt, ok := openocean.GetCollectionByID(collections, collectionID) + + if ok == false { + panic(errors.New("Couldn't find collection: " + collectionID)) + } + + nft, ok := clt.GetNFTByID(nftID) + + if ok == false { + panic(errors.New("Couldn't find nft:" + nftID + " in collection: " + collectionID)) + } + + if nft.GetOwner() != caller { + panic(errors.New("You can't set the sell state of an NFT if you are not the owner!")) + } + + if nft.IsForSale() == sellingState { + panic(errors.New("This NFT is already has the selling state that you are trying to set")) + } + + nft.SetForSale(sellingState) +} + +func GetCollectionStats(collectionID string) string { + clt, ok := openocean.GetCollectionByID(collections, collectionID) + + if ok == false { + panic(errors.New("Couldn't find collection: " + collectionID)) + } + + collectionJSON := json.ObjectNode("", map[string]*json.Node{ + "id": json.StringNode("id", clt.GetId()), + "name": json.StringNode("name", clt.GetName()), + "logo": json.StringNode("logo", clt.GetLogo()), + "volume": json.NumberNode("volume", float64(clt.GetAvaiableTokens())), + "sales": json.NumberNode("sales", float64(clt.GetNFTSBought())), + }) + + nftsJson := json.ArrayNode("", []*json.Node{}) + nfts := clt.GetNFTS() + nfts.Iterate("", "", func (id string, value interface{}) bool { + nft := value.(* openocean.NFTtoken721) + + if nft.IsMinted() == false { + return false + } + + nftJSON := json.ObjectNode("", map[string]*json.Node{ + "id": json.StringNode("id", string(nft.GetId())), + "name": json.StringNode("name", nft.GetName()), + "price": json.NumberNode("price", float64(nft.GetPrice())), + }) + nftsJson.AppendArray(nftJSON) + return false + }) + collectionJSON.AppendObject("nfts", nftsJson) + + encoded, err := json.Marshal(collectionJSON) + + if err != nil { + panic(err) + } + + return string(encoded) +} + +func StarCollection(collectionID string, starred string) { + clt, ok := openocean.GetCollectionByID(collections, collectionID) + + if ok == false { + panic(errors.New("Couldn't find collection: " + collectionID)) + } + + if starred == "true" { + clt.Star() + } else if starred == "false" { + clt.Unstar() + } +} + +func Render(path string) string { + return GetCollections() +}