How it works

DynamicMetadataCapableElement is an abstract contract that your model contract must integrate in order for your contract to be Factory clonable.

DynamicMetadataCapableElement implements LazyInitCapableElement. This means any contract integrating DynamicMetadataCapableElement also has all the capabilities of LazyInitCapableElement.

It provides:

  • The constructor, which can be used if your contract is deployed and initialized manually (i.e, not via a Factory)

  • The lazyInit function, which is automatically called when your contract is cloned from a Factory

The lazyInit function internally calls the empty virtual _dynamicMetadataElementLazyInit function, which your model contract can override in order to manage and initialize its specific custom data.

Dynamic on-chain Metadata Protocol

Implementing the DynamicMetadataCapableElement, your model contract gains the native support for the Dynamic on-chain Metadata Protocol.

The dynamic on-chain metadata protocol allows metadata, via simple call time requests, to be not only saved but also regenerated 100% on-chain at any time. This metadata can be anything: images, descriptions, card game properties, supply info, balance info etc.

The DynamicMetadataCapableElement provides the host address parameters of the LazyInitCapableElement , plainUri and dynamicUriResolver. These last two parameters are used for the Dynamic on-chain Metadata Protocol. See here to learn more.

How to Code Dynamic On-chain Metadata Compliant Smart Contracts

Your model contract must integrate LazyInitCapableElement as follows:

contract Example is....., DynamicMetadataCapableElement {

And in an interface, if any, las follows:

contract IExample is....., IDynamicMetadataCapableElement {

Through this integration, the contract acquires all DynamicMetadataCapableElement capabilities.

You also need to insert the constructor function into your smart contract. This allows you to deploy the contract even without a Factory, and to initialize it in the “traditional” way:

contract Example is....., DynamicMetadataCapableElement {

    constructor(bytes memory lazyInitData) DynamicMetadataCapableElement(lazyInitData) { 

Coded like this, the constructor calls the LazyInitCapableElement constructor and thus can use all logic of the lazyinitCapableElement, such as that which allows it to execute lazyInitData.

After integrating the constructor, you need to override _dynamicMetadataElementLazyInit virtual function, which manages data initialization of your model contract.

In the example below, _dynamicMetadataElementLazyInit initializes three parameters: Test1, Test2 and Test3.

contract Example is....., DynamicMetadataCapableElement {

    //a costant is not initialized
    uint256 public constant override ONE_HUNDRED = 1e18;
    //parameters to initialize 
    uint256 public override Test1;
    address override public Test2;
    address private Test3;
    constructor(bytes memory lazyInitData) DynamicMetadataCapableElement(lazyInitData) { 
    function _dynamicMetadataElementLazyInit(bytes memory lazyInitData) internal override virtual returns (bytes memory) {
    (Test1, Test2, Test3) = abi.decode(lazyInitData, (uint256, address, address));

Of course, if your model contract doesn’t have any additional data to initialize, the _dynamicMetadataElementLazyInit override function doesn’t have to be included.

Now you have a contract that is Factory-compliant. It can be cloned via a factory, and then initialized either via that factory or (if it was manually deployed) via the traditional constructor method.

Initialize the model contract

Here, you learn how to clone and initialize the model contract using a Factory.

Last updated