Which is the point on having a uri method that recieves an id as parameter, but cause of id substitution mechanism it doesn’t makes absolutely anything with it??
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/
function uri(uint256) external view override returns (string memory) {
return _uri;
}
Seems like uri should be just a single getter method without any parameter as the uri is the same for all token ids. What’s more, this also allows for having a setUri public method (with access control) and changing the base of all token types base URL or endpoint, so I like having a single uri for the entire contract
Finally, is another method that needs to be called forcefully with an argument with no practical reason. Similar case as _data argument when executing mint funtion on erc1155 too. Those arguments coud be usefull if we modify the implementation, but as default they just creates confution.
My doubt could be expressed also in this way: if uri method is already expecting id as an argument, then why the standard doesn’t implement id substitution onchain? which is the advantage of having such a important behavior relying on each client? It could be arguable that this kind of delegation forces clients to know too much about erc1155 internals and provides no much improvements in return.
Which is why it must take a tokenID parameter to be compliant with the EIP.
The OpenZeppelin Contracts ERC1155 implementation only supports a single URI for the entire contract, and contract deployers can make use of the client {id} substitution.
A different implementation could have a URI per token, e.g. using a mapping to obtain the URI for each tokenID.
The differences you are seeing is the OpenZeppelin Contracts implementation complying with the EIP.
String manipulation onchain is limited and can be expensive in terms of gas.
It reduces the gas cost, as a single URI can be used for the entire contract, reducing the amount of storage required.
A different implementation could have a URI per token, e.g. using a mapping to obtain the URI for each tokenID.
However right now it's not possible to extend OpenZeppelin implementation and override uri(uint256) to be able to achieve this.
Extending @openzeppelin/contracts/token/ERC1155/ERC1155.sol and trying to override uri(uint256 _id) throws a compilation Error: TypeError: Trying to override non-virtual function. Did you forget to add "virtual"?
Is this the expected behavior? Shouldn't OpenZeppelin implementation let us change the default behavior of one uri per contract? It seems counter productive to have to create a copy of the OZ ERC1155 implementation just to be able to have one uri per TokenID, when adding one virtual to the implementation would make this more flexible
This is the current behavior. There is an open issue (and discussion) to make functions such as uri virtual. You can add your use case to the issue, along with any other functions that you would need made virtual.
I am looking for something the same as you. I just wanted to ask you what was your temporary solution to this besides copying and adjusting the contract locally.
I already saw the issue open which would make view functions such as uri virtual so that we could modify for our use case. However, I wanted to ask if you know when (an estimation of time) this will get implemented and would be possible to use? So that we don’t copy the whole ERC1155 locally?
This is planned to be looked at for the next release of OpenZeppelin Contracts.
In the mean time, you could clone the current implementation and add the URI functionality that you need. You will need to appropriately test and audit this.
Wondering the same. Can someone share how they modify the uri function to match the exact path of the metadata json file (including the 0 padding). Thanks in Advance!
As a contract 1155 actually what it does is create serialized tokens with a balance, so for me strictly speaking they are not NFTs, we must create a mapping to be able to create unique NFTs.
mapping(uint => string) private _URIS;
So we create a token id with a unique balance and we already have an NFT uint256 public constant NFT = 1;
The uri function will first check if there is a specific uri for that token, and if not, it will concatenate the id to receive the metada associated with the semi-fungible token, as shown above.
Thanks for sharing this. I've heard a lazier approach. Restrict who can mint, and simply don't mint more than 1. Ie. check is not mandatory but good to have.
Regarding the URI, I'm confused which of the following are compliant with ERC1155 standards if id=250.
ipfs://uri/250.json
ipfs://uri/fa.json
ipfs://uri/00000000000000000000000000000000000000000000000000000000000000fa.json