First time I'm writing a smart contract. If anything doesn't make sense at all, feel free to call out what specifically doesn't make sense and suggest a better approach. Thanks!
At a high level I just want to store and fetch important immutable metadata on the NFT. In my example this would be x/y coordinates and width/height of it.
class TezosLandNft(FA2.FA2):
@sp.entry_point
def mint(self, params):
sp.verify(~ self.token_id_set.contains(self.data.all_tokens, params.token_id), "NFT-asset: cannon mint the same token twice")
self.token_id_set.add(self.data.all_tokens, params.token_id)
# TODO: add back ledger bookkeeping code to maintain FA2 compliance
self.data.tokens[params.token_id] = self.token_meta_data.make(
amount = 1,
metadata = TezosLandNft.make_metadata(
decimals = 0,
name = "TezosLand",
symbol = "TZL ",
x = params.x,
y = params.y,
width = params.width,
height = params.height
)
)
def make_metadata(symbol, name, decimals, x, y, width, height):
"Helper function to build metadata JSON bytes values."
return (sp.map(l = {
# Remember that michelson wants map already in ordered
"decimals" : sp.bytes_of_string("%d" % decimals),
"name" : sp.bytes_of_string(name),
"symbol" : sp.bytes_of_string(symbol),
"attributes": sp.map({
"x": sp.bytes_of_string(str(x)),
"y": sp.bytes_of_string(str(y)),
"width": sp.bytes_of_string(str(width)),
"height": sp.bytes_of_string(str(height))
})
}))
Having the custom attributes under the "attributes" key throws an error (as a temporary workaround I have been putting the custom keys at the top level):
Error: Type Error sp.TMap(sp.TString, sp.TBytes) is not sp.TBytes bad type for map value
Then the issue I'm having is figuring out how to fetch the NFT's meta_data for all existing token ids... Should this be a new entrypoint on the TezosLandNft FA2 contract?
Also, could the code below be simplified such that all the state is stored within the NFT and is that advisable? There are certain metadata fields that should be immutable (x,y,width,height), but others are mutable. Would overriding the FA2 contract set_metdata entry point work for this? Or is there a better approach to this?
class TezosWorld(sp.Contract):
def __init__(self, admin, land):
grid = {}
self.land_nft = land
self.init(admin=admin, grid=grid, lands={})
@sp.entry_point
def buy(self, params):
land_id = sp.len(self.data.lands)
self.land_nft.mint(token_id=land_id, address=sp.sender, amount=1, x=params.x, y=params.y, height=params.height, width=params.width)
self.data.lands[land_id] = sp.record(title="", image="", link="",nsfw=False, land_id=land_id)
# how to fetch metadata by token_id later?