The DynamicUriResolver contract, as well as your customized DynamicUriRenderer contract, can be implemented in all Item-based applications and protocols.

We provide the abstract DynamicMetadataCapableElement contract, which natively integrates the IDynamicURIResolver interface, and thus the resolve function too.

Developers can integrate DynamicMetadataCapableElement and use its functions to interact more easily with the dynamic on-chain metadata protocol.


To integrate the DynamicMetadataCapableElement, a contract must be initialized with plainUri, the dynamicUriResolver and an additionalData parameter.

To learn more about this initialization content, see here.

You can use our dynamicUriResolver contract address. Its plainUri parameter can contain a general uri string—traditional or dynamic—and therefore the general metadata of the contract that is integrating the DynamicMetadataCapableElement.

For example, the Item Main Interface contract has a plainUri that contains the Metadata of the Main Interface contract itself.

The plainUri parameter’s general uri string and the dynamicUriResolver contract address that are used can be modified using the setUri and setDynamicUriResolver functions.

How It Works

The DynamicMetadataCapableElement provides the internal _uri function:

function _uri(string memory _plainUri, bytes memory additionalData) internal view returns(string memory)

As input, this function takes a plainUri string and the additionalData bytes.

Recall that _plainUri can contain a traditional uri string or a dynamic one. For a dynamic one, the uri must take the form of an encoded ABI string that contains the address of a customized DynamicUriRenderer contract and an optional payload of bytes.

The additionalData is the bytes calldata inputData parameter of the resolve function. It should contain encoded parameters that are used to retrieve and render specific information from the chain. In the “MyUriRenderer” example, it contains the encoded collectionId and itemId parameters, used to calculate the caller’s balance amount.

If a dynamicUriResolver contract is passed, the uri function calls the resolve function; otherwise, it returns the _plainUri string. From the _plainUri and additionalData parameters, the _uri function also calls the resolve function, passing the parameters it requires:

function _uri(string memory _plainUri, bytes memory additionalData) internal view returns(string memory) {
    if(dynamicUriResolver == address(0)) {
        return _plainUri;
    return IDynamicUriResolver(dynamicUriResolver).resolve(address(this), _plainUri, additionalData, msg.sender);

The subject is equal to the address that calls the _uri function (address(this)). To take the Main Interface contract as an example, the subject address is the Main Interface contract address.

As an internal function, _uri can be called by a custom function to render metadata.

For example, the Main Interface provides the uri (uint256 itemId) function. As input, this takes a specific itemId, and calls _uri internally, passing the data of that Item.

function uri(uint256 itemId) override external view returns(string memory) {
    ItemData storage itemData = item[itemId];
    return _uri(itemData.header.uri, abi.encode(itemData.collectionId, itemId));

DynamicMetadataCapableElement also then provides the uri() function:

function uri() external override view returns(string memory) {
    return _uri(plainUri, "");

This function calls the _uri function, passing the general plainUri of the contract itself. plainUri is passed when the contract is initialized or when it is modified via the setUri function, and the additionalData bytes parameter is passed as empty.

A contract can implement DynamicMetadataCapableElement contract use its functions—such as _uri and uri—to interact with the DynamicUriResolver, and therefore the dynamic on-chain metadata protocol, in the way that you would like it to.

Last updated