Estás a punto de lanzar una colección de activos digitales en la red más popular para NFTs: Polygon (Mumbai
). Para lograr ello se usará un contrato que implementa el estándar ERC721 con una cantidad de 2000 NFTs. Las estrategias para acuñación incluyen airdrop con lista blanca y compra directa.
Ethereum es la red más líquida en términos financieros. Hasta el día de hoy tiene el más alto total valor capturado (total value locked - TVL) en comparación con otros Blockchain. Tus clientes poseen sus dólares cripto (USDC
) aquí. Dicha razón te motivó a crear una capa intermedia para poder realizar operaciones cross-chain.
Como parte de este lanzamiento, decidiste crear tu propio token llamado BBites Token - BBTKN
. Lograr que este token adquiera un valor con el tiempo será clave para darle sostenibilidad al proyecto. Por eso decidiste que este token jugará un papel crucial al momento de adquirir los NFTs.
Una porción de los NFTs podrán ser comprados directamente en Ethereum (Goerli
). Dado que el contrato de compra y venta de NFTs (Public Sale
) solo recibe los tokens BBTKN
y el usuario posee USDC
, es necesario la creación de un pool de liquidez en Uniswap V2. Así, los compradores podrán intercambiar USDC
por BBTKN
y comprar los NFTs. También existe la modalidad de pagar directamente en USDC
y dejar al contrato Public Sale
que realice el swap internamente antes de comprar el NFT usando BBTKN
.
Existen tres maneras de adquirir los activos digitales y son las siguientes:
- Usando
BBTKN
oUSDC
: Las compradores pueden dirigirse al contrato de compra y venta de NFTs (Public Sale
) en la red Ethereum (Goerli
) y usar los tokensBBTKN
oUSDC
para adquirir NFTs. Los únicos tokens a la venta en esta modalidad van del id0
al699
(inclusivo) y tienen diferentes rangos de precio. Los tokensBBTKN
se deducen de la billeterá del comprador y se transfieren al contratoPublic Sale
. Se dispara un evento para que en Mumbai sea acuñado el NFT con el id que acaba de ser comprado. Si se usaUSDC
para pagar, internamente el contratoPublic Sale
primero convierte elUSDC
a una cantidad exacta deBBTKN
(usando Uniswap) para pagar por el NFT. - Usando
ether
: Los tokens que van del id700
al999
(inclusivo) pueden ser comprados depositando0.01
ether al contrato dePublic Sale
. Si el usuario llama al métodopurchaseWithEtherAndId(uint256 _id) public
del contratoPublic Sale
, el usuario puede comprar dicho _id del rango mencionado si está disponible. Sin embargo, el usuario también puede optar por enviarether
aPublic Sale
sin ejecutar ningún metodo. En dicho caso, de manera aleatoria el contrato escoge un id disponible en el rango700
a999
(inclusivo). Este id que es adquirido medianteether
se envía en un evento a la red Polygon (Mumbai
) para que se acuñe dicho NFT. - Usando una lista blanca: Los usuarios en la lista blanca pueden dirigirse a Polygon (
Mumbai
) e interactuar con el contrato de NFTs para acuñar y saltarse el paso del pago en Ethereum (Goerli
). Se han seleccionado 1000 billeteras para que cada una pueda acuñar un id en específico. El rango de id para esta modalidad va del1000
al1999
. Puedes revisar las billeteras que irán en la lista blanca en el archivo./wallets/walletList.js
.
Tu proyecto ofrece la oportunidad recomprar los NFTs cuyos ids fueron parte de la lista blanca (no importa si el dueño ya no lo es). Estos usuarios pueden acercarse al contrato de NFTs en Polygon (Mumbai
) y quemar su NFT usando el método buyBack(uint256 id) public
y recibir una compensación. Al quemarse el NFT, se emite el evento Burn(address account, uint256 id)
que finalmente, cross-chain, dispara una acuñación de 10,000 BBTKN
en Ethereum (Goerli
). De esta manera, tu proyecto propicia la deflación de los activos digitales.
Para asegurar la conveniencia del usuario y éxito de tu proyecto, has creado una arquitectura de contratos y middleware (Open Zeppelin Defender) que consta de las siguientes partes:
- Token ERC20 (llamado
BBites Token - BBTKN
) - NFT ERC721 (usar coleccion de 2000 cuyes)
- Contrato de compra y venta (
Public Sale
) USDC
(stable coin)- Open Zeppelin Defender (Middleware)
Goerli
=>Mumbai
Mumbai
=>Goerli
- IPFS
- Pool de liquidez (par:
USDC
yBBites Token
- UNISWAP V2) - Front-end
Ethereum (Goerli ) |
Polygon (Mumbai ) |
---|---|
BBites Token ERC20, USDC , Public Sale |
NFT ERC721 |
Actualizables | No Actualizables |
---|---|
BBites Token ERC20, NFT ERC721 y Public Sale |
USDC |
-
Este contrato es un ERC20 que debe ser convertido a actualizable. Posee 18 decimales. Es publicado en Ethereum (
Goerli
) -
En el método
initialize()
, usando_mint()
se acuña 1 millón de tokens al que publica el contrato. Ese millón será utilizado para crear el pool de liquidez junto al USDC. -
Posee un método
mint(address to, uint256 amount) onlyRole(MINTER_ROLE)
que solo es llamado por elRelayer
de Open Zeppelin. Este método es disparado cuando desde Polygon (Mumbai
) se quema un NFT cuyo id está entre1000
y1999
(inclusivo). Se acuña10,000
tokens aladdress
que quemó su NFT. -
Su método
mint
posee el modifierwhenNotPaused
para pausarse cuando sea necesario. -
Bonus: Implementar la extensión
ERC20Permit
. Aquellos compradores que no poseen gas para pagar la transacción crearán una firma digital para poner al contrato dePublic Sale
como el gastador de sus tokens. Esta firma digital podrá ser generada desde el front-end usando Metamask.Una vez generada la firma, se llamará a un autotask desde el front-end pasando los parámetros necesarios (e.g. firma). Este autotask usará un relayer en
Goerli
y tendrá la tarea de llamarexecutePermitAndPurchase() public onlyRole(EXECUTER_ROLE)
dePublic Sale
. Este método hace lo siguiente:- Ejecuta el método
permit()
del contrato ERC20PermitBBToken
con todos sus parámetros (owner
,spender
,value
,deadline
,v
,r
ys
) - Inmediatamente calcula un id aleatorio del tipo
mistico
(explicado más abajo) cuyos ids van del700
al999
. - Emite el evento
PurchaseNftWithId(owner, randomId)
Reutiliza la misma función aleatoria para este tipo de NFT
mistico
(ver cuarta modalidad de compra en el contratoPublic Sale
). - Ejecuta el método
- Este contrato
Cuy Collection Nft
implementa el estándar ERC721 que debe ser convertido a actualizable. - Posee el método
safeMint(address to, uint256 tokenId) public onlyRole(MINTER_ROLE)
que solo puede ser llamado por elRelayer
de Open Zeppelin enMumbai
. Los ids permitidos van del0
al999
para este método. Lleva el modifierwhenNotPaused
. - Posee el método
safeMintWhiteList(address to, uint256 tokenId, bytes32[] proofs) public
que será llamado por cada una de las 1000 billeteras de la lista blanca. Internamente este método valida queto
ytokenId
sean parte de la lista. Así también, se debe habilitar en el front-end una manera de solicitar las pruebas. Dado unaddress
y unuint256
, el front-end te entregará el array de pruebas a usarse como argumento de este método. LlevawhenNotPaused
. Puede ser llamado por cualquiera. - Posee el método
buyBack(uint256 id) public
que permite a los dueños de los ids en el rango de1000
y1999
(inclusivo) quemar sus NFTs a cambio de un repago deBBTKN
en la red de Ethereum (Goerli
). Este método emite el eventoBurn(address account, uint256 id)
que finalmente, cross-chain, disparamint()
en el tokenBBTKN
en la cantidad de10,000
BBTKNs.
-
Este contrato de
Public Sale
se publica en Ethereum (Goerli
). Sirve como intermediario para poder realizar el pago para adquirir NFTs. -
La comunicación entre el contrato de
Public Sale
y el contrato de NFTs se dará a través de Open Zeppelin Defender. El contrato dePublic Sale
emite eventos que serán escuchados por Open Zeppelin Defender, que a su vez ordenará al contrato de NFT en Polygon (Mumbai
) de acuñar un determinado NFT. -
Los ids para la venta usando
BBTKN
oUSDC
van del0
hasta el699
y tienen diferentes rangos de precio. -
Se puede enviar
0.01 ether
para comprar NFTs en el rango de700 - 999
. -
Los ids que van del
1000 - 1999
solo se acuñan en Polygon (Mumbai
) en el mismo contrato de NFTs usando la lista blanca (merkle tree). -
La siguiente tabla resume la información de ids vs tips vs precios.
id (inclusivo) Tipo Precio ( BBTKN
)0 - 199
Común 1000 BBTKN
fijo200 - 499
Raro Multiplicar su id por 20
500 - 699
Legendario Según días pasados***** 700 - 999
Místico 0.01 ether
fijo1000 - 1999
Whitelist Sin precio *****Nota: Su precio cambia según el # de días pasados desde las 00 horas del 30 de septiembre del 2023 GMT (obtener el timestamp en epoch converter). El primer día empieza en
10,000 BBTKN
. Por cada día pasado, el precio se incrementa en2,000 BBTKN
. El precio máximo es90,000 BBTKN
. -
La primera manera de compra es usando los
BBTKN
tokens. El método a usar espurchaseWithTokens(uint256 _id)
y el usuario escoge el id a comprar y se emite el evento. Estos tokens se transfieren al contratoPublic Sale
. Aplica para ids en el rango0 - 699
. -
La segunda manera de compra es usando
USDC
. El método a usar espurchaseWithUSDC(uint256 _id)
y el usuario escoge el id a comprar y se emite el evento. Internamente, en este método se usa el pool de liquidez para intercambiar losUSDC
por una cantidad exacta deBBTKN
. Aplica para ids en el rango0 - 699
. Dado que no se sabe la cantidad deUSDC
a depositar, se sugiere dar elapprove
de un monto seguro por parte del usuario. Este método tiene que dar el vuelto delUSDC
que no se llegó a usar en la compra.BONUS: Para obtener un estimado de cuántos
USDC
se necesitan para comprar una cantidad exacta deBBTKN
, revisar getAmountIn de Uniswap. El usuario, antes de comprar bajo este método, puede consultargetAmountIn
y dar elapprove
en dicha cantidad deUSDC
estimada. ExponergetAmountIn
en este contrato. -
La tercera manera de compra es enviando exactamente
0.01 ether
y ejecutando, al mismo tiempo, el métodopurchaseWithEtherAndId(uint256 _id)
. El usuario escoge el id a comprar y se emite el evento. Aplica para ids en el rango700 - 999
. Elether
es acumulado en el mismo contratoPublic Sale
. Dar vuelto si se envía más de0.01 ether
. -
La cuarta manera de compra es enviando exactamente
0.01 ether
al contrato sin ejecutar ningún metodo. Aleatoriamente se escoge un id de NFT que esté disponible y se emite el evento. Aplica para ids en el rango700 - 999
. Elether
es acumulado en el mismo contratoPublic Sale
. -
El evento que se emite luego de realizar cualquier compra tiena la siguiente forma:
event PurchaseNftWithId(address account, uint256 id)
. -
El método llamado
withdrawEther() public onlyRole(DEFAULT_ADMIN_ROLE)
permite a cualquier admin transferirse elether
que fue depositado a este contrato. -
El método llamado
withdrawTokens() public onlyRole(DEFAULT_ADMIN_ROLE)
permite a cualquier admin transferirse los tokensBBTKN
que fueron depositados a este contrato. -
Construir un método de ayuda que devuelve el precio dado un id. Este método se llamará
getPriceForId(uint256 id) public view returns(uint256)
. Solo aplica para ids en el rango0
y699
(inclusivo).
- Encontrarás una réplica del stable coin
USDC
en el repositorio. Al desplegarlo, elmsg.sender
se hace acreeder de500,000 USDC
. Esta cantidad es usada para crear el pool de liquidez junto alBBTKN
. - Este contrato no es actualizable y se publica en Ethereum (
Goerli
) - Inicialmente este contrato es de 18 decimales. Debes convertirlo a un token de 6 decimales como lo es el original
USDC
. - Puedes repartir
USDC
a cualquier comprador para que simule la posesión de fondos. Normalmente, este stable coin es adquirido en DEXes como Binance, KuCoin y otros.
De Ethereum (Goerli
) a Polygon (Mumbai
):
- El sentinel (
Goerli
) escucha los eventosPurchaseNftWithId
dePublic Sale
. El autotask ejecuta el script que acuña el NFT en Polygon (Mumbai
) en el contrato de NFT. El relayer (Mumbai
) será el único que puede firmar el métodosafeMint()
del contrato NFT para acuñar el id a la billetera respectiva. El relayer debe tener el rol deMINTER_ROLE
para poder acuñar.
De Polygon (Mumbai
) a Ethereum (Goerli
):
- El sentinel (
Mumbai
) escucha los eventosBurn
del contratoNFT
. El autotask ejecuta el script que acuña10,000 BBTKN
enGoerli
en el contrato del tokenBBTKN
. El relayer (Goerli
) será el único que puede firmar el métodomint()
para acuñarBBTKN
a la billetera respectiva. El relayer debe tener el rol deMINTER_ROLE
para poder acuñar.
- Dentro de la carpeta
ipfs
tenemos dos carpetas:images
ymetadata
. Estas dos carpetas representan a los activos digitales y la metadata, respectivamente. - Guardar la carpeta de
images
de activos digitales en la aplicación de escritorioIPFS
. Obtener elCID
luego de guardar la carpetaimages
. - Dentro de la carpeta de
metadata
, se encontrarán los archivosjson
enumerados de manera secuencial. Cada archivojson
, representa la metada de un activo digital en particular. Por ejemplo, el archivo0
, representa la metadata del activo digital0.png
, guardada en la otra carpetaimages
. - Vamos a modificar los archivos de
metadata
. Por ejemplo, empecemos con./metadata/0
. Buscar la propiedad"image": "ipfs://[enter the CID here]/0.png"
. Reemplazar por el valor delCID
obtenido en el punto 2 para todos los archivos. Usactrl + shift + h
. - Así también cambia la propiedad
description
y escoge un nombre apropiado para tu colección. Usactrl + shift + h
. - (Opcional) Dado que hay cinco grupos diferentes de NFTs, modificar el atributo
name
de cada archivojson
para que represente más apropiadamente al grupo de NFT al que pertenece. - (Opcional) Agregar más atributos en la propiedad
attributes
. Seguir la guía/estándar definido en la página de Open Sea que lo puedes encontrar aquí. Estos atributos serán vistos en la galería de Opean Sea. - Luego de terminar de editar los archivos de metadata, guardar la carpeta
metadata
enipfs
para poder obtener elCID
. - Finalmente, este
CID
es el que se guardará en el smart contract de NFT en el método_baseURI()
. Gracias a este método, el smart contract puede encontrar la metadata y el activo digital en elIPFS
.
- Se creará un pool de liquidez en Uniswap V2 usando los tokens
USDC
yBBTKN
. Dicho pool estará conformado por 1 Millón de tokensBBTKN
y medio millón del tokenUSDC
. - Acuñar
100,000 USDC
a la siguiente billetera para propósitos de testing:0xF90a9359f2422b6885c900091f2aCc93E0933B7a
. - Desde el contrato de
Public Sale
se establecerá una comunicación con elRouter
de Uniswap para intercambioUSDC
porBBTKN
y realizar la compra del NFT con su precio respectivo
Crear un front-end minimalista para poder interactuar con el contrato de Public Sale
(ver video). En este front, se podrán realizar las siguientes operaciones:
- Botón conectar a Metamask
- Ver cuenta conectada
- Observar el Balance
USDC
de la billetera conectada - Observar el Balance
BBToken
de la billetera conectada
- Dar approve de
BBTKN
al contrato dePublic Sale
- Dar approve de
USDC
al contrato dePublic Sale
- Comprar un NFT usando el método
purchaseWithTokens
- Comprar un NFT usando el método
purchaseWithUSDC
- Comprar un NFT usando el método
purchaseWithEtherAndId
- Comprar un NFT enviando
ether
al contratoPublic Sale
sin ejecutar métodos - Consultar el precio de un NFT dado su id
- Dados un
id
ybilletera
, consultar losproofs
� para el whitelist - Usando
billetera
,token id
yproofs
, acuñar NFT de whitelist - Ejecutar Buy Back quemando el NFT usando el
token id
- Public Sale
- PurchaseNftWithId
- Bites Token
- Transfer
- NFT contract
- Transfer
- Burn
- Token ERC20
BBITES Token - BBTKN
- Contrato NFT
ERC721
con una colección de 2000 cuyes - Contrato de
Public Sale
- Stable Coin
USDC
ficticio - Autotask:
Goerli
aMumbai
. Incluye código engoerliToMumbai.js
. - Autotask:
Mumbai
aGoerli
. Incluye código enmumbaiToGoerli.js
. - Pool de liquidez en Uniswap V2
- Front-end con los métodos implementados del punto
8 - Front-end
- Testing con alta cobertura para
Public Sale
- Testing con alta cobertura para
ERC721
- Script de deployment para contratos en
Goerli
- Script de deployment para contratos en
Mumbai
- Pega aquí la tx de una compra de un NFT
común
enPublic Sale
usandoUDSC
: - Pega aquí la tx de una compra de un NFT
raro
enPublic Sale
usandoBBTKN
: - Pega aquí la tx de una compra de un NFT
legendario
enPublic Sale
usandoUDSC
: - Pega aquí la tx de una compra de un NFT
mistico
enPublic Sale
usandoether
y unid
en específico: - Pega aquí la tx de una compra de un NFT
mistico
enPublic Sale
usandoether
(random id): - Pega aquí la tx de una acuñación whitelist de un NFT en el contrato
NFT
: - Pega aquí la tx de un buy back de NFT en el contrato
NFT
: