Mints random verificables de NFTs

Ahmed Castro - Oct 26 '21 - - Dev Community

Muchos usuarios no saben que la mayoría de NFTs en el mercado de hoy tienen fuertes componentes centralizados. La buena noticia es que poco a poco nuevos proyectos están integrando componentes que ayudan a decentralizar. En este video exploramos cómo hacer mints random verificables y porqué quisiéramos hacerlo o no.

1. La metadata

Subimos la metadata a cualquier servidor web siguiendo los estándares de los ERC-1155.

Recuerda llamar a los archivos de metadata siguiendo la sequencia 0000000000000000000000000000000000000000000000000000000000000000.json.

{
    "name": "Zanahoria",
    "description": "Tiene muchas vitaminas",
    "image": "https://TUURL/Zanahoria.png"
}
Enter fullscreen mode Exit fullscreen mode

2. El contrato

Este contrato funciona únicamente en Polygon Ethereum Plasma y está compuesto de los siguientes elementos:

  • Router de Quickswap: Nos permite comprar el token LINK que ocupamos como fee para recibir un número random del oráculo. En el caso de polygon el fee es de 0.0001 LINK.
  • PegSwap: Los tokens que obtenemos a través de Quickswap (o a través del Polygon Bridge) no son compatibles con el oráculo. Por eso debemos swapearlos via PegSwap donde cambiamos nuestros LINKS normales con los LINKS ERC-677 que sí son compatibles con el oráculo.
  • Chainlink VRF: Es oráculo de chainlink que nos devuelve un número random
  • Los Price Feeds: Nos ayudan a calcular el precio de mercado al momento de comprar el fee de los oráculos.

En este contrato, cuando compramos un NFT vía mintNFT destinamos un poco del MATIC del precio de compra para comprar 0.0001 LINK en Quickswap. Luego cambiamos ese 0.0001 LINK por LINK ERC-677 que usamos para pagar el fee cuando solicitamos un número random por medio de requestRandomness. Obtenemos ese valor en el callback fulfillRandomness y es ahí donde seleccionamos un id del token ERC-1155 de manera aleatoria.

Recuerda modificar CREATOR, BASE_URI y PRICE antes de lanzar.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

contract Router {
    function swapETHForExactTokens(
        uint amountOut,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable returns (uint[] memory amounts) {}
}

contract PegSwap {
    function swap(
        uint256 amount,
        address source,
        address target
    ) external {}
}

contract MyNFT is ERC1155, VRFConsumerBase {
    address CREATOR = 0x0000000000000000000000000000000000000000;
    string BASE_URI = "https://MIURL{id}.json";

    uint256 public PRICE = 0.1 ether;
    uint256 SLIPPAGE_PERCENTAGE = 20;

    bytes32 VRF_KEYHASH = 0xf86195cf7690c55907b2b611ebb7343a6f649bff128701cc542f0569e2c549da;
    uint256 VRF_FEE = 0.0001 ether;
    address VRF_COORDINATOR = 0x3d2341ADb2D31f1c5530cDC622016af293177AE0;

    Router quickswap = Router(0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff);
    PegSwap peg_swap = PegSwap(0xAA1DC356dc4B18f30C347798FD5379F3D77ABC5b);
    ERC20 WMATIC_token  = ERC20(0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270);
    ERC20 LINK_token  = ERC20(0x53E0bca35eC356BD5ddDFebbD1Fc0fD03FaBad39);
    ERC20 LINK_ERC677_token  = ERC20(0xb0897686c545045aFc77CF20eC7A532E3120E0F1);
    AggregatorV3Interface MATIC_LINK_price_feed = AggregatorV3Interface(0x5787BefDc0ECd210Dfa948264631CD53E68F7802);

    mapping(bytes32  => address) public sender_request_ids;

    constructor()
        ERC1155(BASE_URI)
        VRFConsumerBase(
            VRF_COORDINATOR,
            address(LINK_ERC677_token)
        )
    {
    }

    function mintNFT(address to) public payable
    {
        require(msg.value >= PRICE, "Value below price");
        swapMATICToLINK();
        sender_request_ids[requestRandomness(VRF_KEYHASH, VRF_FEE)] = to;
    }

    function swapMATICToLINK() public payable
    {
        address[] memory path = new address[](2);
        path[0] = address(WMATIC_token);
        path[1] = address(LINK_token);

        quickswap.swapETHForExactTokens{value: ((getMaticPrice() * VRF_FEE) / 1 ether) * (100 + SLIPPAGE_PERCENTAGE) / 100}(
            VRF_FEE,
            path,
            address(this),
            block.timestamp
        );
        LINK_token.approve(address(peg_swap), VRF_FEE);
        peg_swap.swap(
            VRF_FEE,
            address(LINK_token),
            address(LINK_ERC677_token)
        );
    }

    function getMaticPrice() public view returns (uint)
    {
        (
            uint80 roundID, 
            int price,
            uint startedAt,
            uint timeStamp,
            uint80 answeredInRound
        ) = MATIC_LINK_price_feed.latestRoundData();
        roundID;
        startedAt;
        timeStamp;
        answeredInRound;
        return uint(price);
    }

    function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
        uint token_id = randomness % 3;
        uint amount = 1;
        _mint(sender_request_ids[requestId], token_id, amount, "");
    }

    function withdraw() public
    {
        payable(CREATOR).transfer(address(this).balance);
        LINK_token.transfer(payable(CREATOR), LINK_token.balanceOf(address(this)));
        LINK_ERC677_token.transfer(payable(CREATOR), LINK_ERC677_token.balanceOf(address(this)));
    }

    fallback() external payable {}
    receive() external payable {}
}
Enter fullscreen mode Exit fullscreen mode

¡Gracias por ver este tutorial!

Sígueme en dev.to y en Youtube para todo lo relacionado al desarrollo en Blockchain en Español.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .