# Lazy Mint Extension ERC1155

### 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 an ERC1155 contract, but something similar can be done with ERC721s.

### 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/IERC1155CreatorCore.sol";
import "@manifoldxyz/creator-core-solidity/contracts/extensions/ICreatorExtensionTokenURI.sol";

import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

contract Tutorial2 is AdminControl, ICreatorExtensionTokenURI{

    address private _core;
    string private _baseURI;

    function initialize(address core) public adminRequired {
      _core = core;

      address[] memory to = new address[](1);
      to[0] = msg.sender;
      uint[] memory amounts = new uint[](1);
      amounts[0] = 1;
      string[] memory uris = new string[](1);
      uris[0] = "";

      IERC1155CreatorCore(_core).mintExtensionNew(to, amounts, uris);
    }

    function mint() public {
      address[] memory to = new address[](1);
      to[0] = msg.sender;
      uint[] memory tokenIds = new uint[](1);
      tokenIds[0] = 1;
      uint[] memory amounts = new uint[](1);
      amounts[0] = 1;

      IERC1155CreatorCore(_core).mintExtensionExisting(to, tokenIds, amounts);
    }

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

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

    function tokenURI(address core, uint256 tokenId) external view override returns (string memory) {
        require(core == _core, "Invalid token");
        return _baseURI;
    }
}

```

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

The first function we have there is called `initialize` and this is where we set ourselves up by minting the first copy of the token. In this case, we've hard-coded it to token #1. It is important to note that we're taking the assumption here that the extension will only be used for this token. When we call this function, we're saving the address of our *core* contract, and calling the `mintExtensionNew` function on it to mint the token.

The `mint` function is where we allow other people to mint more copies of this token. You can see that it is pretty simple, it prepares the input, and then calls `mintExtensionExisting` to mint another copy of an existing token (token #1 that we made in `initialize`).

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

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

The `tokenURI` function returns this URI. It is important to note that this *does not* follow the EIP-1155 spec (as the extension does not keep track of tokens itself, it only helps mint them). The base contract, of course, has the `uri` function specified by the spec.

### How to Deploy

1. Deploy *core* contract (using Manifold Studio is easiest) - example [here](https://rinkeby.etherscan.io/address/0x9d5fb2d05ace6368b92723fd08b8572c6ddd1434)
2. Deploy the *extension* contract - example [here](https://rinkeby.etherscan.io/address/0x7054A2b1001b97b09B095a7538B136436100C26E)
3. Register the extension with #9 `registerExtension` on your base contract - example [here](https://rinkeby.etherscan.io/tx/0xeaa87a23df123b4b1eedcf25f2dacf9fc332fb74c30404feb64c19ea4a618e56)
4. Initialize the extension with #2 `initialize` - example [here](https://rinkeby.etherscan.io/tx/0x0485e8950ad163d2ea2d905bbd066bf70b674c278939a729011376876f4e7964)
5. Set the baseURI for your extension - example [here](https://rinkeby.etherscan.io/tx/0xf59f7526ccd7545135cabc77920bce8e896ea3c898ac3eedeba123644f7704ff)
6. Mint - example [here](https://rinkeby.etherscan.io/tx/0x4700d1fd37d90883395b222c95cbd99526c78cabe7d559a93a7711a5ea4088fa)

You should be able to see your token on OpenSea TestNet. Here is mine:

<https://testnets.opensea.io/assets/0x9d5fb2d05ace6368b92723fd08b8572c6ddd1434/1>

There are just a couple things to note here. The first is that this is token #1 on the *core* contract. Notice the OpenSea URL which has the address of the *core* contract. There are 2 tokens, and 2 owners. 1 of the tokens is owned by the wallet I called `initialize` with, and the other is owned by a wallet I called `mint` with.

### FAQ

**Is this contract an ERC1155 contract?**

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

**Can this deployed contract be re-used?**

Not in its current form. However, an extension can be written in such a way that it manages tokens for many different *core* contracts.

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