NEWTON

NEWTON


Popular tags

    Are you able to nest mappings in Cairo like you can in Solidity?

    Asked

    5 months ago

    108

    views


    0

    Are you able to nest mappings in Cairo like you can in Solidity?

    e.g. in Solidity you can do

    mapping(address => mapping(uint256 => bool));

    is this doable in Cairo? I want to do something similar to

    func mappingA(value: felt) -> func mappingB(value: felt) -> (value: felt){ }

    mapping(x, y) -> (z) is not gonna work, here is some context:

    I'm working through the sample ERC721_Metadata.cairo and ERC721_Metadata_Base contract shown here https://github.com/starknet-edu/starknet-erc721/tree/main/contracts/token/ERC721

    It looks like from what I can tell the tokenUri is set for each domain, and even though calling the @view function does take in a tokenId, calling to set the tokenUri does not and it's not clear to me how that mapping could exist otherwise. So I wanted to modify the contract to have a token_id -> token_uri mapping. Because of the way those mappings exist though, you need to provide both the token_uri_len: felt and token_uri: felt* when writing them. This means it can only be done once, otherwise you'd need a specific @storage_var for every token that's minted, just to hold it's tokenuri. I was hoping to do something like

    // Represents a tokenUri struct TokenUri { // The length of the token bytes token_uri_len: felt, // The pointer to the beginning of the token uri bytes token_uri: felt*, } @storage_var func token_uris(token_id: felt) -> (token_uri: TokenUri) { }

    But because of the token_url: felt* pointer in that struct, it can't be used as a storage variable return type. It gives an error when I try to compile showing

    starknet_contracts/ERC721_Metadata.cairo:29:36: The return type of storage variables must be a felts-only type (cannot contain pointers). func token_uris(token_id: felt) -> (token_uri: TokenUri) {

    This question was originally posted on StarkNet Discord

      solidity cairodiscordcairo

    Newton

    asked

    5 months ago


    1 answers

    0

    Accepted answer

    Ugh yeah, it looks like the way this is done there has to be two storage variables per token. One holds the length of the token_uri, and the other holds the index -> value mapping for each byte of the token uri

    @storage_var func ERC721_base_token_uri(index: felt) -> (res: felt) { } @storage var func ERC721_base_token uri len() -> (res: felt) { }
    func ERC721_Metadata_setBaseTokenURIf { syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range check ptr }(token uri _len: felt, token uri: felt*, token uri suffix: felt) { _ERC721 Metadata_setBaseTokenURI (token_uri_len, token uri); ERC721_base_token_uri_len.write(token_uri_len); return (); } func _ERC721_Metadata_setBaseTokenURI{ syscall _ptr: felt*, pedersen ptr: HashBuiltin*, range check ptr }(token uri len: felt, token uri: felt*) { if (token_uri_len == 0) { return (); } ERC721_base_token_uri.write(index=token uri len, value=[token uril); ERC721 Metadata setBaseTokenURI(token_uri_len=token_uri_len- 1, token_uri=token_uri + 1); return (); }

    This answer was originally posted on StarkNet Discord

    Newton

    answered

    5 months ago

    Your answer

    NEWTON

    NEWTON