nft.gno

3.58 Kb ยท 144 lines
  1package nft
  2
  3import (
  4	"std"
  5	"strconv"
  6
  7	"gno.land/p/demo/avl"
  8	"gno.land/p/demo/grc/grc721"
  9)
 10
 11type token struct {
 12	grc721.IGRC721 // implements the GRC721 interface
 13
 14	tokenCounter int
 15	tokens       avl.Tree // grc721.TokenID -> *NFToken{}
 16	operators    avl.Tree // owner std.Address -> operator std.Address
 17}
 18
 19type NFToken struct {
 20	owner    std.Address
 21	approved std.Address
 22	tokenID  grc721.TokenID
 23	data     string
 24}
 25
 26var gToken = &token{}
 27
 28func GetToken() *token { return gToken }
 29
 30func (grc *token) nextTokenID() grc721.TokenID {
 31	grc.tokenCounter++
 32	s := strconv.Itoa(grc.tokenCounter)
 33	return grc721.TokenID(s)
 34}
 35
 36func (grc *token) getToken(tid grc721.TokenID) (*NFToken, bool) {
 37	token, ok := grc.tokens.Get(string(tid))
 38	if !ok {
 39		return nil, false
 40	}
 41	return token.(*NFToken), true
 42}
 43
 44func (grc *token) Mint(to std.Address, data string) grc721.TokenID {
 45	tid := grc.nextTokenID()
 46	grc.tokens.Set(string(tid), &NFToken{
 47		owner:   to,
 48		tokenID: tid,
 49		data:    data,
 50	})
 51	return tid
 52}
 53
 54func (grc *token) BalanceOf(owner std.Address) (count int64) {
 55	panic("not yet implemented")
 56}
 57
 58func (grc *token) OwnerOf(tid grc721.TokenID) std.Address {
 59	token, ok := grc.getToken(tid)
 60	if !ok {
 61		panic("token does not exist")
 62	}
 63	return token.owner
 64}
 65
 66// XXX not fully implemented yet.
 67func (grc *token) SafeTransferFrom(from, to std.Address, tid grc721.TokenID) {
 68	grc.TransferFrom(from, to, tid)
 69	// When transfer is complete, this function checks if `_to` is a smart
 70	// contract (code size > 0). If so, it calls `onERC721Received` on
 71	// `_to` and throws if the return value is not
 72	// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
 73	// XXX ensure "to" is a realm with onERC721Received() signature.
 74}
 75
 76func (grc *token) TransferFrom(from, to std.Address, tid grc721.TokenID) {
 77	caller := std.GetCallerAt(2)
 78	token, ok := grc.getToken(tid)
 79	// Throws if `_tokenId` is not a valid NFT.
 80	if !ok {
 81		panic("token does not exist")
 82	}
 83	// Throws unless `msg.sender` is the current owner, an authorized
 84	// operator, or the approved address for this NFT.
 85	if caller != token.owner && caller != token.approved {
 86		operator, ok := grc.operators.Get(token.owner.String())
 87		if !ok || caller != operator.(std.Address) {
 88			panic("unauthorized")
 89		}
 90	}
 91	// Throws if `_from` is not the current owner.
 92	if from != token.owner {
 93		panic("from is not the current owner")
 94	}
 95	// Throws if `_to` is the zero address.
 96	if to == "" {
 97		panic("to cannot be empty")
 98	}
 99	// Good.
100	token.owner = to
101}
102
103func (grc *token) Approve(approved std.Address, tid grc721.TokenID) {
104	caller := std.GetCallerAt(2)
105	token, ok := grc.getToken(tid)
106	// Throws if `_tokenId` is not a valid NFT.
107	if !ok {
108		panic("token does not exist")
109	}
110	// Throws unless `msg.sender` is the current owner,
111	// or an authorized operator.
112	if caller != token.owner {
113		operator, ok := grc.operators.Get(token.owner.String())
114		if !ok || caller != operator.(std.Address) {
115			panic("unauthorized")
116		}
117	}
118	// Good.
119	token.approved = approved
120}
121
122// XXX make it work for set of operators.
123func (grc *token) SetApprovalForAll(operator std.Address, approved bool) {
124	caller := std.GetCallerAt(2)
125	grc.operators.Set(caller.String(), operator)
126}
127
128func (grc *token) GetApproved(tid grc721.TokenID) std.Address {
129	token, ok := grc.getToken(tid)
130	// Throws if `_tokenId` is not a valid NFT.
131	if !ok {
132		panic("token does not exist")
133	}
134	return token.approved
135}
136
137// XXX make it work for set of operators
138func (grc *token) IsApprovedForAll(owner, operator std.Address) bool {
139	operator2, ok := grc.operators.Get(owner.String())
140	if !ok {
141		return false
142	}
143	return operator == operator2.(std.Address)
144}