🔗ERC721 Integration

This page demonstrates how an ERC721 smart contract can integrate the NFTDelegation.com smart contract during their minting.

Steps:

  1. Import Interfaces within your smart contract

import "./INFTDelegationRead.sol";
  1. Declare the Read Interface variable as below:

INFTDelegationRead public dmcRead;
  1. Add a control mechanism as follows to check the minting process and block the Delegators' addresses for minting more than one time.

mapping (address => bool) public checkDelegatorMints;
  1. Modify your ERC721 constructor as below. When deploying the smart contract input the NFTDelegation smart contract address 0x2202CB9c00487e7e8EF21e6d8E914B32e709f43d within your constructor.

constructor(address _delegationManagementContract, string memory name, string memory symbol) ERC721(name, symbol) {
    dmc = INFTDelegationRead(_delegationManagementContract);
}
  1. Suggested Options for minting

Option A:

Modify the minting function to take into consideration the retrieveDelegators() function from the NFTDelegation.com Smart Contract based on 'Any Collection' and 'All Use Cases'.

By calling this function all Delegators of the msg.sender are retrieved, the tokens are minted and they are sent to each one of the Delegators.

function mintTokensForAllDelegators() public payable {
    // add your minting requirements and control mechanisms
    // to use NFTDelegation.com Smart Contract please add the code below
    address[] memory dmcDelegators;
    // use the collection and use case that you would like to retrieve delegators, in this case is 'Any Collection' and 'All Use Cases'
    dmcDelegators = dmc.retrieveDelegators(msg.sender, 0x8888888888888888888888888888888888888888, 1);
    // minting process
    for(uint i = 0; i <= dmcDelegators.length-1; i++) {
        uint mintIndex = totalSupply();
        // control mechanisms to prevent wallets on minting again using the same delegators addresses
        if (checkDelegatorMints[dmcDelegators[i]] == false) {
            _safeMint(dmcDelegators[i], mintIndex);
            checkDelegatorMints[dmcDelegators[i]] = true;
        } else {}
    }
}

Option B:

Minting function modifications that takes into consideration the retrieveGlobalStatusOfDelegation() function from the NFTDelegation.com Smart Contract based on 'Any Collection' and 'All Use Cases'.

During Option B the function awaits for one parameter, address _vault. If a delegation between the _vault address and the msg.sender exists the token will be minted and sent to the _vault address.

function mintTokensPerDelegator(address _vault) public payable {
    // add your minting requirements and control mechanisms
    // to use NFTDelegation.com Smart Contract please add the code below
    bool isAllowedToMint;
    // check if a delegation between msg.sender and the vault exists on a specific usecase and collection, in this case is 'Any Collection' and 'All Use Cases'
    isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_vault, 0x8888888888888888888888888888888888888888, msg.sender, 1);
    require(isAllowedToMint == true, "No delegation exists");
    // minting process
    uint mintIndex = totalSupply();
    // control mechanisms to prevent wallets on minting again using the delegator's address
    if (checkDelegatorMints[_vault] == false) {
        _safeMint(_vault, mintIndex);
        checkDelegatorMints[_vault] = true;
    } else  { 
            revert("Already Minted");
            }
}

Option C:

Minting function modifications that takes into consideration the retrieveGlobalStatusOfDelegation() function from the NFTDelegation.com Smart Contract based on 'Any Collection' and 'All Use Cases'.

During Option C the function awaits for two parameters, address _vault and address _mintToAddress . If a delegation between the _vault address and the msg.sender exists the token will be minted and sent to the _mintToAddress address that can be different than the _vault.

function mintTokensPerDelegatorOtherAddress(address _vault, address _mintToAddress) public payable {
    // add your minting requirements and control mechanisms
    // to use NFTDelegation.com Smart Contract please add the code below
    bool isAllowedToMint;
    // check if a delegation between msg.sender and the vault exists on a specific usecase and collection, in this case is 'Any Collection' and 'All Use Cases'
    isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_vault, 0x8888888888888888888888888888888888888888, msg.sender, 1);
    require(isAllowedToMint == true, "No delegation exists");
    // minting process
    uint mintIndex = totalSupply();
    // control mechanisms to prevent wallets on minting again using the delegator's address
    if (checkDelegatorMints[_vault] == false) {
        _safeMint(_mintToAddress, mintIndex);
        checkDelegatorMints[_vault] = true;
    } else  { 
            revert("Already Minted");
            }
}

Please note that this is a sample smart contract for demonstrating the usage of NFTDelegation within an ERC721 contract.

Source Code

// SPDX-License-Identifier: MIT

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./INFTDelegationRead.sol";

pragma solidity ^0.8.19;

contract ERC721_sample is ERC721, ERC721Enumerable, Ownable {

        // NFTDelegation.com contract declaration
        INFTDelegationRead public dmc;

        // Contol mechanism to check minting and not allow the same Delegatees to mint again
        mapping (address => bool) public checkDelegatorMints;

        constructor(address _delegationManagementContract, string memory name, string memory symbol) ERC721(name, symbol) {
            dmc = INFTDelegationRead(_delegationManagementContract);
        }

        /**
        * OPTION A:
        * Minting function that takes into consideration the retrieveDelegators() function from the NFTDelegation.com Smart Contract
        * The msg.sender (delegated address) mints on behalf of all Delegators and the minted tokens are sent to the Delegators Addresses
        */

        function mintTokensForAllDelegators() public payable {
            // add your minting requirements and control mechanisms
            // to use NFTDelegation.com Smart Contract please add the code below
            address[] memory dmcDelegators;
            // use the collection and use case that you would like to retrieve delegators, in this case is 'Any Collection' and 'All Use Cases'
            dmcDelegators = dmc.retrieveDelegators(msg.sender, 0x8888888888888888888888888888888888888888, 1);
            // minting process
            for(uint i = 0; i <= dmcDelegators.length-1; i++) {
                uint mintIndex = totalSupply();
                // control mechanisms to prevent wallets on minting again using the delegators addresses
                if (checkDelegatorMints[dmcDelegators[i]] == false) {
                    _safeMint(dmcDelegators[i], mintIndex);
                    checkDelegatorMints[dmcDelegators[i]] = true;
                } else {}
            }
        }

        /**
        * OPTION B:
        * Minting function that takes into consideration the retrieveGlobalStatusOfDelegation() function from the NFTDelegation.com Smart Contract
        * In this option the minted token is sent to the Delegator's Address
        */

        function mintTokensPerDelegator(address _vault) public payable {
            // add your minting requirements and control mechanisms
            // to use NFTDelegation.com Smart Contract please add the code below
            bool isAllowedToMint;
            // check if a delegation between msg.sender and the vault exists on a specific usecase and collection, in this case is 'Any Collection' and 'All Use Cases'
            isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_vault, 0x8888888888888888888888888888888888888888, msg.sender, 1);
            require(isAllowedToMint == true, "No delegation exists");
            // minting process
            uint mintIndex = totalSupply();
            // control mechanisms to prevent wallets on minting again using the delegator's address
            if (checkDelegatorMints[_vault] == false) {
                _safeMint(_vault, mintIndex);
                checkDelegatorMints[_vault] = true;
            } else  { 
                    revert("Already Minted");
                    }
        }

        /**
        * OPTION C:
        * Minting function that takes into consideration the retrieveGlobalStatusOfDelegation() function from the NFTDelegation.com Smart Contract
        * In this option the minted token is sent to the _mintToAddress address
        */

        function mintTokensPerDelegatorOtherAddress(address _vault, address _mintToAddress) public payable {
            // add your minting requirements and control mechanisms
            // to use NFTDelegation.com Smart Contract please add the code below
            bool isAllowedToMint;
            // check if a delegation between msg.sender and the vault exists on a specific usecase and collection, in this case is 'Any Collection' and 'All Use Cases'
            isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_vault, 0x8888888888888888888888888888888888888888, msg.sender, 1);
            require(isAllowedToMint == true, "No delegation exists");
            // minting process
            uint mintIndex = totalSupply();
            // control mechanisms to prevent wallets on minting again using the delegator's address
            if (checkDelegatorMints[_vault] == false) {
                _safeMint(_mintToAddress, mintIndex);
                checkDelegatorMints[_vault] = true;
            } else  { 
                    revert("Already Minted");
                    }
        }

        // The following functions are overrides required by Solidity.

        function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize) internal override(ERC721, ERC721Enumerable) {
        super._beforeTokenTransfer(from, to, tokenId, batchSize);
        }

        function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721Enumerable) returns (bool) {
        return super.supportsInterface(interfaceId);
        }

}

Extension A: Mint based on smart contract's max Allowance

Modify the smart contract to allow a delegated address to mint on behalf of the Delegator address the max tokens allowed. In this case the minting is not 1 token per Delegator Address but more based on the maxAllowance number set on the smart contract.

Modifications:

Add a uint256 variable and a mapping that will be used to count the number of successful mints per address.

uint256 maxAllowance;
mapping (address => uint256) public checkDelegatorMintsAllowance;

Modify the constructor as below and add a value for the maxAllowance variable.

constructor(address _delegationManagementContract, string memory name, string memory symbol) ERC721(name, symbol) {
    dmc = INFTDelegationRead(_delegationManagementContract);
    maxAllowance = 2;
}

Modify the minting function as below:

function mintTokensPerDelegatorAllowance(address _vault, uint256 _noOfTokens) public payable {
    // add your minting requirements and control mechanisms
    // to use NFTDelegation.com Smart Contract please add the code below
    bool isAllowedToMint;
    // check if a delegation between msg.sender and the vault exists on a specific usecase and collection, in this case is 'Any Collection' and 'All Use Cases'
    isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_vault, 0x8888888888888888888888888888888888888888, msg.sender, 1);
    require(isAllowedToMint == true, "No delegation exists");
    // control mechanisms to mint based on max Allowance
    for (uint256 i=0; i < _noOfTokens; i++) {
        if (checkDelegatorMintsAllowance[_vault] < maxAllowance) {
            uint mintIndex = totalSupply();
            _safeMint(_vault, mintIndex);
            checkDelegatorMintsAllowance[_vault] = checkDelegatorMintsAllowance[_vault] + 1;
        } else  { 
                revert("Max Allowance Reached");
                }
        }
}

Extension B: Mint based on Merkle Proofs

Modify the smart contract to allow the delegated address to mint on behalf of the Delegator Address when the Delegator Address has an allowlist. The amount of tokens minted per Delegator Address varies.

Example:

Modifications:

Import the MerkleProof library

import "./MerkleProof.sol";

Add a bytes32 variable for the MerkleRoot and a mapping that will be used to count the number of successful mints per address.

bytes32 merkleRoot;
mapping (address => uint256) public checkDelegatorMintsAllowance;

Modify the constructor so as to accept a Merkle Root as an input.

constructor(address _delegationManagementContract, bytes32 _merkleRoot, string memory name, string memory symbol) ERC721(name, symbol) {
    dmc = INFTDelegationRead(_delegationManagementContract);
    merkleRoot = _merkleRoot;
}

Modify the minting function as below:

function mintTokensPerDelegatorMerkle(address _vault, uint256 _noOfTokens, bytes32[] calldata merkleProof) public payable {
    // add your minting requirements and control mechanisms
    // to use NFTDelegation.com Smart Contract please add the code below
    bool isAllowedToMint;
    // check if a delegation between msg.sender and the vault exists on a specific usecase and collection, in this case is 'Any Collection' and 'All Use Cases'
    isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_vault, 0x8888888888888888888888888888888888888888, msg.sender, 1);
    require(isAllowedToMint == true, "No delegation exists");
    // check merkle proofs
    bytes32 node = keccak256(abi.encodePacked(_vault, _noOfTokens));
    require(MerkleProof.verifyCalldata(merkleProof, merkleRoot, node), 'invalid proof');
    // control mechanisms to mint based on max Allowance per address
    for (uint256 i=0; i < _noOfTokens; i++) {
        if (checkDelegatorMintsAllowance[_vault] < _noOfTokens) {
            uint mintIndex = totalSupply();
            _safeMint(_vault, mintIndex);
            checkDelegatorMintsAllowance[_vault] = checkDelegatorMintsAllowance[_vault] + 1;
        } else  { 
                revert("Max Allowance Reached");
                }
        }
}

Last updated