No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Extendiendo la funcionalidad de PlatziPunks

15/24
Recursos

¡Hola!, si has llegado hasta aquí te felicito, ya que has comenzado con el trabajo técnico de tu contrato inteligente.
No obstante, en esta clase se omitió un paso importante en la función mint, ya que no se añadió el incremento del _tokenId, lo cual causaría un error después de que se crea el primer token, indicando que ese token ya fue minteado con anterioridad (siempre mintea el token 0).

Para solucionarlo, te pido que añadas la siguiente línea de código después del _safeMint(msg.sender, current):

_tokenId.increment()

Este problema se soluciona en la clase donde agregamos tests, así que no es mayor problema, pero es importante, por si deseas realizar pruebas desde ahora.

Aportes 20

Preguntas 3

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

ATENCIÓN ⚠️

¡Hola!, si has llegado hasta aquí te felicito, ya que has comenzado con el trabajo técnico de tu contrato inteligente.
No obstante, en esta clase se omitió un paso importante en la función mint, ya que no se añadió el incremento del _tokenId, lo cuál causaría un error después de que se crea el primer token, indicando que ese token ya fue minteado con anterioridad (siempre mintea el token 0).

Para solucionarlo, te pido que añadas la siguiente línea de código después del _safeMint(msg.sender, current):

_tokenId.increment()

Este problema se soluciona en la clase donde agregamos tests, así que no es mayor problema, pero es relevante, por si deseas realizar pruebas desde ahora.

Dale 💚 para que más personas se enteren de este cambio :pray

Resolviendo el RETO:
No pude usar de la sección Payment la función PullPayment por que esta hasta la v0.3, así que en la v0.4 está solo PaymentSplitter, aqui va la implementación:

  1. Hacemos la importación:
import "@openzeppelin/contracts/finance/PaymentSplitter.sol";
  1. Agregar la herencia al contracto:
contract PinaPunks is ERC721, ERC721Enumerable, PaymentSplitter { ...
  1. Actualizar el constructor:
    constructor(address[] memory _payees, uint256[] memory  _shares, uint256 _maxSupply) ERC721("PinaPunks", "PP") PaymentSplitter(_payees, _shares) payable {
        maxSupply = _maxSupply;
    }

Note: payess y shares, son dos arreglos, en el primero agregar las wallets que desean recibir la recompensan y la segunda, la equidad de las mismas.

  1. Actualizar la función mint :
    function mint() public payable {
        require(msg.value >= 50000000000000000,"you neet 0.05 ETH to mint the PinaPunks");

Ahora es payable y le agregue un require para garantizar un monto a al momento de hacer el mint.

Me gusta que el profe nos muestre abiertamente como hace uso de la documentación y de las funciones que nos proveen porque creo yo que a la final eso es de lo mas normal y no que transcriba lo que esta en la documentación haciendo como que se lo sabe y que no lo esta copiando

Dejo mi implementacion. Me estuve peleando mas con el test que con la funcionalidad del contrato 🤦‍♂️
Saludos

contract PlatziPunks is ERC721, ERC721Enumerable{
    using Counters for Counters.Counter;
    uint256 immutable _maxSupply;
    address _owner;

    Counters.Counter private id_counter;

    constructor( uint256 maxSupply ) ERC721("PlatziPunks","PUNKS") {
        _maxSupply = maxSupply;
        _owner = msg.sender;
    }

    function getMaxSupply() public view returns(uint256){
        return _maxSupply;
    }

    function mint() public payable  {
        // pregunto si esta enviando 0.1 eth
        require( msg.value >= 0.1 ether, "Insufficient funds" );

        // me fijo si quedan PUNKS disponibles        
        uint256 current = id_counter.current();
        require( current < _maxSupply, "No PUNKS left");

        // transfiero los ethers
        payable(_owner).transfer( msg.value );

        // envio el NFT
        _safeMint(msg.sender, current);

        // incremento el contador
        id_counter.increment();
    }

    // Override required
    function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) {
        super._beforeTokenTransfer(from, to, tokenId);
    }

    function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721Enumerable) returns (bool) {
        return super.supportsInterface(interfaceId);
    }

}

Tener algo de conocimiento en smart contracts y implementar estas funciones con esta clases + Github Copilot una delicia xd

El maxSupply debería ser privado, ¿no?, si no lo cambio y me salteo la validación.

requerimos un curso intermedio de solidity porque con el using quede un poco en el aire.

Aca les dejo mi version super optimizada del contrato mostrado en esta clase.

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";

contract PlatziPunks is ERC721Enumerable {
    uint public maxSupply;

    constructor(uint _maxSuppy) ERC721("PlatziPunks", "PLPKS") {
        maxSupply = _maxSuppy;
    }

    function mint() public {
        uint _current = totalSupply();
        require(_current < maxSupply, "No PlatziPunks left :(");
        _safeMint(msg.sender, totalSupply());
    }

}


En openzepelin hay seccion de MIsc y alli hay una seccion de utils, tiene una librerias de contadores

msg.sender -> tiene una direccion de aquel que ejecuta la funcion

con using podemos usar esas librerias

L aimplemtacion de standares es muy facil, solo hay que ver el constructor y ver que requiere

Ojo nota importante. Ya que el curso tiene mas de un Ano de haber sido publicado, esto es 1 tip sobre todo para los principiantes como yo! al intentar seguir la clase en el minuto 3:15 ; cuando el profesor esta construyendo las funciones con el Wizard actualmente estas cambian:

La diferencia es que las primeras dos funciones no tienen el parámetro “batchSize”, mientras que las segundas dos sí lo tienen. Además, las primeras dos funciones llaman a la función “_beforeTokenTransfer” y “supportsInterface” de las clases padre ERC721 y ERC721Enumerable, mientras que las segundas dos funciones llaman a esas mismas funciones, pero también incluyen el parámetro adicional “batchSize” y heredan de las mismas clases padre.

Pero lo importante es que ademas hay que hacer una nueva importacion =

import "@openzeppelin/contracts/access/Ownable.sol";

Las funciones quedarian asi:


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

Los tests quedarían algo así:

const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("PlatziPunks", function () {
  let platzi_punks;
  beforeEach(async function(){
    const PlatziPunks = await ethers.getContractFactory("PlatziPunks");
    platzi_punks = await PlatziPunks.deploy(2);
    await platzi_punks.deployed();
  })

  it("Should init contract with name and symbol", async function () {
    expect(await platzi_punks.name()).to.equal("PlatziPunks");
    expect(await platzi_punks.symbol()).to.equal("PLPKS");
  });

  describe("When mint a token", async function (){
    let sender;
    beforeEach(async function() {
      [sender] = await ethers.getSigners();
    })

    it("Should increment the balanceof the sender by 1 every mint", async function () {
      expect(await platzi_punks.balanceOf(sender.address)).to.equal(0);
      await platzi_punks.mint()
      await platzi_punks.mint()
      expect(await platzi_punks.balanceOf(sender.address)).to.equal(2);
    });

    it("Should give the ownership of minted tokenId to the sender", async function () {
      await platzi_punks.mint()
      expect(await platzi_punks.ownerOf(0)).to.equal(sender.address);
    });

    it("Should increment tokenId in every mint", async function () {
      await platzi_punks.mint()
      expect(await platzi_punks.ownerOf(0)).to.equal(sender.address);
      await platzi_punks.mint()
      expect(await platzi_punks.ownerOf(1)).to.equal(sender.address);
    });
  }) 

  describe("Token Max supply", async function (){
    it("Should throw an error if minting exceeds the token max supply limit", async function () {
      try {
        await platzi_punks.mint()
        await platzi_punks.mint()
        await platzi_punks.mint()
        expect.fail('should throw a No Platzi Punks left :( error');
      } catch (error) {
        expect(error.message).to.contains('No Platzi Punks left :(');
      }
    });
  }) 
});

Cómo debería quedar la función mint:

    function mint () public {
        uint256 current = _idCounter.current();
        require(current < maxSupply, "No PlatziPunks left");
        _idCounter.increment();
        _safeMint(msg.sender, current);
    }

//Overrride required son necesarios para este amrt contract

Mi aporte

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

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract CuadrosPunks is ERC721, ERC721Enumerable {

  using Counters for Counters.Counter;

  Counters.Counter private _idCounter;
  
  uint256 public maxSupply;
  address owner;
  
  constructor( uint256 _maxSupply ) ERC721("CuadrosPunks", "CPT") {
    maxSupply = _maxSupply;
    owner = msg.sender;
  }


  function mint() public virtual payable checkSupply {
    uint256 currentTokenId = _idCounter.current();
    require( 
      msg.value == 100000000000000000, 
      "Not enough ETH sent; check price!"
    );
    payable(owner).transfer(msg.value);
    _safeMint( msg.sender, currentTokenId );
    _idCounter.increment();
  }

  modifier checkSupply {
    require( 
      _idCounter.current() < maxSupply,
      "No more nfts can be minted"   
    );
    _;
  }

  function _beforeTokenTransfer(address from, address to, uint256 tokenId)
    internal
    override(ERC721, ERC721Enumerable)
  {
    super._beforeTokenTransfer(from, to, tokenId);
  }

  function supportsInterface(bytes4 interfaceId)
    public
    view
    override(ERC721, ERC721Enumerable)
    returns (bool)
  {
    return super.supportsInterface(interfaceId);
  }

} 

que tema de vs code usa ???

Ya pueden entrar a la web de OpenZeppeling y ver que esta en el wizard la posibilidad del mint + autoincrement.

https://docs.openzeppelin.com/contracts/4.x/wizard

Wizard permite composiciones de ssmart contract