No tienes acceso a esta clase

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

Extendiendo la funcionalidad de PlatziPunks

14/23
Recursos

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 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 17

Preguntas 2

Ordenar por:

Los aportes, preguntas y respuestas son vitales para aprender en comunidad. Regístrate o inicia sesión para participar.

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

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

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

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

}

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

con using podemos usar esas librerias

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

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

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

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

}


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

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

//Overrride required son necesarios para este amrt contract

Wizard permite composiciones de ssmart contract