WEB3DEV

Cover image for Cunhe Múltiplos NFTs Usando o Padrão ERC1155
Banana Labs
Banana Labs

Posted on

Cunhe Múltiplos NFTs Usando o Padrão ERC1155

Capa Imagem do Unsplash

Em meu artigo anterior, falei sobre alguns truques e dicas para adicionar modificadores de função para transições cronometradas, guardas de reentrância e retirada de fundos.

No entanto, isso foi feito por meio de arrastar e soltar trechos de código.

Neste artigo, mostrarei como criar um contrato ERC1155 NFT que use todas essas peças.

Um padrão ERC1155 permite que você crie várias cópias de um ID de token NFT exclusivo. O que o torna bastante útil para aplicativos de jogos descentralizados, onde os jogadores iriam cunhar espadas, poções mágicas, libré, etc.

O código que vou apresentar aqui pode ser copiado e colado no ETH-Remix para brincar com as diversas funções.

Eu deliberadamente deixei de fora a função batch mint como um exercício para o leitor.

O Open zeppelin tem uma documentação realmente boa que detalha seu padrão ERC1155, que está em contraste direto com o padrão ERC721, onde um token NFT pode ter apenas 1 cópia.

Resumindo, um ERC1155 NFT é o mesmo que um ERC721 NFT quando a quantidade de cunhagem permitida é igual a '1'.

Aqui estão todos os modificadores de função que usaremos. Coberto no meu artigo anterior.

  enum MintStage {
        MintLive,
        MintEnded
    }

    MintStage mintStage;
        modifier mintTimedTransitions() {
        if (block.timestamp > endAt)
            nextMintStage();
            _;
    }



    modifier atMintStage(MintStage mintStage_) {
        if (mintStage != mintStage_) revert FunctionInvalidAtThisStage();
        _;

    }

   //Modificador de função NoReentrant Call
    bool locked;
   modifier noReentrancy() {
       require(!locked,"Reentrant Call");
       locked = true;
       _;
       locked = false;
       _;
   }

    function nextMintStage() internal {
        mintStage = MintStage(uint(mintStage)+1);
    }
Enter fullscreen mode Exit fullscreen mode

FunctionModifiersAndReentrancyGuard.sol

Ao usar o ETH-Remix, certifique-se de inserir seus preços usando aspas duplas para que a entrada seja considerada como uma string.

Exemplo: Para ‘1 ether’, use “1000000000000000000”.

Então, você precisará de alguma forma para acompanhar suas reservas NFT e parar de cunhar ao esgotar as reservas. O ERC1155 fará o gerenciamento dos saldos NFT dos usuários.

Você pode rastrear as reservas NFT colocando-as em uma matriz do tipo struct NFTInfo. Você pode então criar uma função getter para o mesmo que retorna um tipo (NFTInfo).

  //Rastreie as informações do NFT para verificar as reservas
    struct NFTInfo {
        uint id;
        uint price;
        uint reserves;
       }

    NFTInfo[]  nftInfo;
Enter fullscreen mode Exit fullscreen mode

NFTInfo

Abaixo está o construtor para este contrato. Forneci entradas de exemplo para incorporar no código, facilitando a implantação e o teste do contrato sem a necessidade de inserir os argumentos do construtor todas as vezes.

Se você optar por fazer isso, simplesmente comente os argumentos do construtor para ids_, prices_, maxAmounts_, beneficiary e devAddress_.

constructor(
        uint[] memory ids_,
        uint[] memory prices_,
        uint[] memory maxAmounts_,
        address beneficiary_,
        address devAddress_
        ) 
        ERC1155(_baseURI)
        payable
         {


            owner = payable(msg.sender);
            prices = prices_;
            ids = ids_;
            maxAmounts  = maxAmounts_;
            beneficiary = beneficiary_;
            devAddress = devAddress_;
            require(ids.length == prices.length && ids.length == maxAmounts.length,"TokenIDs, TokenPrices e TokenAmounts deve ter o mesmo comprimento");

               for(uint i =0; i< ids.length; i++) {
            _idToidx[ids[i]] = i;
            nftInfo.push(NFTInfo({
            id: ids[i],
            price: prices[i],
            reserves: maxAmounts[i]
                  }));
            _tokenURI[ids[i]] = string.concat(_baseURI,Strings.toString(ids[i]),baseExtension);
        }


         startedAt = block.timestamp;
        endAt = startedAt + DURATION;


    }
Enter fullscreen mode Exit fullscreen mode

ERC1155Constructor

 //Entradas de exemplo para debug
    address devAddress; 
    //= 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2;
    address beneficiary;
    //= 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db;
    mapping (address => uint ) pendingWithdrawal;

    uint256[]  ids;
    //= [46,93];
    uint256[]  prices;
    //  = [1 ether, 0.5 ether];
    /Se estiver usando Remix, use o seguinte formato para entradas de preço
    //["1000000000000000000","500000000000000000"]
    uint256[]  maxAmounts;
    //= [10,20];
    uint maxMintAmount = 100;
Enter fullscreen mode Exit fullscreen mode

InputsToTheERC1155

 //variáveis token URI 
    string _baseURI = "https://ipfs.io/ipfs/QmcDRWwXCE1LjvdESNZsmc75syTJP2zA8WW9SHEaCwEmkc/";
    mapping (uint256=>  string) _tokenURI; //TokenId to tokenURI mapping
    string baseExtension = ".json";
Enter fullscreen mode Exit fullscreen mode

TokenURIsAndTokenIds

A próxima função crucial é o coração do contrato, uma vez que permite que uma conta de usuário cunhe NFTs. A conta do usuário tem permissão para cunhar NFTs, desde que tenham fundos suficientes, não possua um endereço inválido e as reservas de NFT para o tokenID não tenham sido esgotadas.

 function mintSingle(uint256 _id, uint256 _amount)  
         external   
         payable 
         mintTimedTransitions() 
         atMintStage(MintStage.MintLive){
       if (msg.sender == address(0)) revert InvalidAddress();
        require(_amount<= maxMintAmount && balanceOf(msg.sender,_id) <= maxMintAmount,"There's a limit to minting per address");
        // require(msg.sender != owner && msg.sender != beneficiary && msg.sender != devAddress,"Owner, beneficiary and devs cannot bid on this auction");

        uint256 _idx;
        _idx =  _idToidx[_id];
        uint256 price;
       uint256 royaltyFees;
       uint256 ownerPayment;
       uint256 nftReserves;

       price = nftInfo[_idx].price;
      nftReserves = nftInfo[_idx].reserves;

        require( nftReserves >= _amount,"ERC1155: Sorry, this NFT's sold out!");
        require(price.mul(_amount) <= msg.value,"ERC1155: You don't have enough funds.");

        //Atualize Reservas NFT 
        _updateReserves(_idx,_amount);

       //Cunhe para o endereço da conta de chamada
        _mint(msg.sender,_id,_amount,""); //Will update the user balances and enumerations

        //Calcular e pagar a taxa de royalties ao proprietário/plataforma
         royaltyFees = (msg.value*_royaltyFee)/100;

        //O proprietário retira os fundos do saldo
        ownerPayment = msg.value-royaltyFees;

        //Usando o método pendingWithdrawal
        pendingWithdrawal[devAddress] = pendingWithdrawal[devAddress]+ royaltyFees;
        pendingWithdrawal[beneficiary] =  pendingWithdrawal[beneficiary] +ownerPayment;

    } 



    function _updateReserves(uint256 _idx,uint256 amount) internal {
        if (nftInfo[_idx].reserves < amount) revert ErrorNFTReserves();
        nftInfo[_idx].reserves -= amount;
        emit NFTReservesUpdated();
    }
Enter fullscreen mode Exit fullscreen mode

MintSingle

O código completo do contrato pode ser encontrado no meu Github para você usar em uma IDE de sua escolha.

🔗https://github.com/cryptonomicon46/ERC1155

Por enquanto é isso e espero ter ajudado você a entender como cunhar NFTs usando o padrão ERC1155.

Como exercício para o leitor, deixei de fora a função batch mint. A batchMint() deve permitir que uma conta de usuário crie cópias de vários tokenIDs e deve ser possível implementar com pequenas modificações na função mintSingle().

Aqui está um link para uma implementação da função batch mint.

Esse artigo é uma tradução feita por @bananlabs. Você pode encontrar o artigo original aqui

Top comments (0)