# Lazy Mint Extension ERC721

### Intro

Another common ask is how to do lazy-minting with Manifold. If you're unfamiliar, lazy-minting is a technique by which minting costs are passed on to the buyer. This makes sense in many situations (especially collectible-style projects), but does not make sense in others. We'll take a look at the contract and how to deploy it here, but I would not suggest doing this for collections of less than, say, 20 tokens. The reason for this is that deploying an extension costs gas! And on a smaller scale, the savings from lazy-minting are less than the cost to deploy the contract.

Anyway, let's take a look. We'll do this with a contract that mints ERC721 tokens to your base contract.

### Contract

```
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/// @author: manifold.xyz

import "@manifoldxyz/libraries-solidity/contracts/access/AdminControl.sol";
import "@manifoldxyz/creator-core-solidity/contracts/core/IERC721CreatorCore.sol";
import "@manifoldxyz/creator-core-solidity/contracts/extensions/ICreatorExtensionTokenURI.sol";

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

contract Tutorial3 is AdminControl, ICreatorExtensionTokenURI {

    using Strings for uint256;

    address private _creator;
    string private _baseURI;

    constructor(address creator) {
        _creator = creator;
    }

    function supportsInterface(bytes4 interfaceId) public view virtual override(AdminControl, IERC165) returns (bool) {
        return interfaceId == type(ICreatorExtensionTokenURI).interfaceId || AdminControl.supportsInterface(interfaceId) || super.supportsInterface(interfaceId);
    }
    
    function mint() public {
      IERC721CreatorCore(_creator).mintExtension(msg.sender);
    }

    function setBaseURI(string memory baseURI) public adminRequired {
      _baseURI = baseURI;
    }

    function tokenURI(address creator, uint256 tokenId) external view override returns (string memory) {
        require(creator == _creator, "Invalid token");
        return string(abi.encodePacked(_baseURI, tokenId.toString()));
    }
}
```

Let's walk through the contract here before we think about deploying it.

The first function we have there is the `constructor` and this is called when we deploy the contract. At the time of deployment we must pass in the `_creator` (the address of your creator core contract). We have that so we can interact with it later when minting.

The `supportsInterface` function simply tells other contracts that are calling this one what functions it supports.

The `mint` function is where we allow other people to mint more tokens on this contract. You can see that it is pretty simple, it really just calls the `mintExtension` function to mint a token to the person who sent the transaction. Note that we do not specify a tokenURI here. This is because the core contract will hook back into this contracts `tokenURI` function later to get the URI.

The `setBaseURI` function lets us set the base for the tokenURI we want to return. It also lets us update this information at any time in the future.

The `tokenURI` function returns the base tokenURI concatenated with the tokenId. So in this case if your base tokenURI is `https://arweave.net/abcd/` this will return `https://arweave.net/abcd/1` for tokenId 1.

### How to Deploy

1. Deploy your *creator* contract using Manifold Studio (in this example, you will want a 721 contract)
2. Deploy the *extension* contract above using [remix](https://remix.ethereum.org/).
3. Register the extension with write as proxy function `#14: registerExtension` on your creator contract from step 1. You can access this function by visiting the etherscan page for your contract, then clicking `contract` -> `write as proxy`. You will want to enter the address from the extension contract from *step 2* in the `extension` parameter, and a blank space for the `baseURI` parameter.\
   ![](https://268636785-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8n4plerMUJrsrAiaKpc2%2Fuploads%2FW2aC0rij59u5wRhx2f5Q%2FScreen%20Shot%202023-03-19%20at%206.28.01%20AM.png?alt=media\&token=d4dae8df-ce9e-4c76-bd3a-3feeda3d92eb)
4. Set the baseURI for your extension with write function `#4. setBaseURI`. You can do this in via remix, or via the etherscan page for the extension contract.
5. Mint with write function `#3. mint`. You can do this in via remix, or via the etherscan page for the extension contract.
6. Mint with write function `#3. mint`. You can do this in via remix, or via the etherscan page for the extension contract.

You should be able to see your tokens on OpenSea TestNet via:\
<https://testnets.opensea.io/assets/\\>\<CREATOR\_CONTRACT\_ADDRESS>/1\
<https://testnets.opensea.io/assets/\\>\<CREATOR\_CONTRACT\_ADDRESS>/2

As you can see, these are token #1 and token #2 on the *creator* contract. Notice the OpenSea URL which has the address of the *creator* contract.

Congrats! You are done.

### FAQ

**Is this contract an EC721 contract?**

No - but it helps you mint tokens on an ERC721 contract (your *core* contract)

**What is the gas cost for deploying an extension like this?**

This particular extension cost me 1,833,652 gas to deploy. At gas prices of 40 gwei, that would be about 0.07 ETH.
