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?

o inicia sesi贸n.

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.

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

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

}


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

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 :(');
      }
    });
  }) 
});

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 鈥渂atchSize鈥, mientras que las segundas dos s铆 lo tienen. Adem谩s, las primeras dos funciones llaman a la funci贸n 鈥淿beforeTokenTransfer鈥 y 鈥渟upportsInterface鈥 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 鈥渂atchSize鈥 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);
    }
}

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