# 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";
```

2. Declare the Read Interface variable as below:

```
INFTDelegationRead public dmcRead;
```

3. 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;
```

4. Modify your ERC721 constructor as below. When deploying the smart contract input the NFTDelegation smart contract address 0x2202CB9c00487e7e8EF21e6d8E914B32e709f43d within your constructor.

{% code overflow="wrap" %}

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

{% endcode %}

5. Suggested Options for minting

**Option A:**&#x20;

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'.&#x20;

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.

{% code overflow="wrap" %}

```
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 {}
    }
}
```

{% endcode %}

**Option B:**&#x20;

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

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.

{% code overflow="wrap" %}

```
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");
            }
}
```

{% endcode %}

**Option C:**&#x20;

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

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*.

{% code overflow="wrap" %}

```
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");
            }
}
```

{% endcode %}

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

**Source Code**

{% tabs %}
{% tab title="Code" %}
{% code overflow="wrap" %}

```
// 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);
        }

}
```

{% endcode %}
{% endtab %}
{% endtabs %}

**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.

{% code overflow="wrap" %}

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

{% endcode %}

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

{% code overflow="wrap" %}

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

{% endcode %}

Modify the minting function as below:

{% code overflow="wrap" %}

```
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");
                }
        }
}
```

{% endcode %}

**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:

<table><thead><tr><th width="577">Delegator Address</th><th>Max Allowance</th></tr></thead><tbody><tr><td>0x5B38Da6a701c568545dCfcB03FcB875f56beddC4</td><td>1</td></tr><tr><td>0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2</td><td>2</td></tr><tr><td>0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db</td><td>3</td></tr></tbody></table>

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.

{% code overflow="wrap" %}

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

{% endcode %}

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

{% code overflow="wrap" %}

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

```

{% endcode %}

Modify the minting function as below:

{% code overflow="wrap" %}

```
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");
                }
        }
}

```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.nftdelegation.com/developer-center/nftdelegation-integrations/erc721-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
