TokenizeArt
Création du NFT Zehd42 (Z42) sur la BNB Smart Chain Testnet : mon premier jeton non fongible.
Présentation
Un NFT Zehd42 (Z42) conforme à la norme BEP-721 / ERC-721, déployé sur la BNB Smart Chain Testnet : un jeton unique portant le chiffre 42, avec son image et ses métadonnées hébergées sur IPFS et un mint réservé au propriétaire.
Contexte
Projet solo réalisé dans le cadre du partenariat 42 × BNB Chain.
L'objectif : comprendre concrètement le cycle de vie d'un jeton non fongible en créant, minant et vérifiant un NFT réel sur un réseau de test, sans jamais engager d'argent réel.
C'est le second volet de mon parcours blockchain après Tokenizer : là où un token BEP-20 est fongible (un G42 en vaut un autre), un NFT est unique !
Cette unicité change tout:
- Identifiant propre
- Métadonnées externalisées
- Notion de propriété.
Mon rôle
Projet 100 % solo, mené de bout en bout :
- Conception de l'œuvre contenant le chiffre 42 (exigence du sujet)
- Rédaction du smart contract
zehd42.solen Solidity, hérité d'OpenZeppelin - Publication de l'image et des métadonnées sur IPFS via Pinata (deux CID distincts)
- Déploiement sur la BSC Testnet via Remix + MetaMask
- Minage du tokenId
1et vérification de la propriété sur la chaîne - Vérification du code source sur BscScan
- Rédaction de la documentation (livre blanc, tutoriel pas à pas, guides IPFS & Pinata)
Architecture
Un contrat unique Zehd42 qui hérite de ERC721URIStorage et d'Ownable (OpenZeppelin v5.1.0). L'héritage fournit les fonctions natives de la norme : ownerOf, balanceOf, transferFrom, safeTransferFrom, approve…
Le contrat ajoute sa logique métier :
- Un compteur d'identifiants (
_tokenIds). - Un
mintNFTréservé au propriétaire - Un
setBaseURIpour faire évoluer l'emplacement des métadonnées sans redéployer.
Zehd42 is ERC721URIStorage, Ownable (OpenZeppelin v5.1.0)
├── from ERC721 : ownerOf, balanceOf, transferFrom, safeTransferFrom, approve…
├── from Ownable : onlyOwner, transferOwnership
├── _tokenIds : compteur privé d'identifiants (le premier vaut 1)
├── mintNFT() : crée le NFT réservé au propriétaire, associe les métadonnées IPFS
└── setBaseURI() : change l'URI des prochains mints (jetons déjà minés inchangés)
Les données sont réparties sur deux étages :
- La blockchain porte le contrat, la propriété et le
tokenId. - IPFS porte l'image et le JSON de métadonnées, référencés par
tokenURI.
Pourquoi stocker l'image hors chaîne ?
Écrire une image dans la blockchain coûterait des sommes considérables. Le contrat ne stocke donc que l'empreinte du fichier : c'est le rôle du CID IPFS. Voir IPFS & Pinata.
Technologies
Solidity ^0.8.20
Typé et compilé pour l'EVM
OpenZeppelin v5.1.0
ERC721URIStorage + Ownable, la référence ERC-721
IPFS
image et métadonnées adressées par contenu (CID)
Pinata
service d'épinglage
Remix IDE
écriture, compilation et déploiement
MetaMask
portefeuille connecté (Injected Provider)
BscScan Testnet
explorateur et vérification du contrat
BNB Smart Chain Testnet
blockchain EVM, Chain ID 97
Fonctionnalités
| Fonction | Rôle | Accès |
|---|---|---|
mintNFT(recipient) | Créer un NFT unique et lui associer les métadonnées | Propriétaire |
ownerOf(tokenId) | Connaître le propriétaire d'un NFT | Lecture |
balanceOf(owner) | Nombre de NFT détenus par une adresse | Lecture |
tokenURI(tokenId) | URL des métadonnées IPFS associées | Lecture |
baseURI() | URI de base utilisée pour les prochains mints | Lecture |
transferFrom(from, to, tokenId) | Transférer un NFT | Propriétaire ou approuvé |
safeTransferFrom(...) | Transfert sûr vers un contrat | Propriétaire ou approuvé |
approve / setApprovalForAll | Autoriser un tiers à transférer | Propriétaire |
setBaseURI(newURI) | Changer l'URI des prochains mints | Propriétaire |
Problème | Solution
| Problème | Solution |
|---|---|
| Un NFT doit être unique, contrairement à un token fongible | Norme BEP-721 : à chaque mint, un tokenId incrémenté par le compteur _tokenIds |
| Stocker l'œuvre sur la blockchain serait hors de prix | Image et métadonnées publiées sur IPFS : seul le CID est référencé par le contrat |
| Un lien vers un serveur central peut mourir | Épinglage IPFS via Pinata : le CID reste résolvable, sans point de défaillance unique |
| Les wallets affichent une case vide au lieu de l'image | tokenURI pointe vers le JSON de métadonnées, dont le champ image utilise une URL HTTPS de passerelle (et non ipfs://) |
| Un caractère parasite peut casser l'affichage | Champs d'URL vérifiés caractère par caractère (bug rencontré et corrigé en cours de projet) |
| N'importe qui ne doit pas pouvoir créer un NFT | mintNFT protégé par onlyOwner ; l'appel par un tiers échoue en revert |
| Faire évoluer les métadonnées sans redéployer | setBaseURI(...), réservé au propriétaire, n'affecte que les mints suivants |
| Éviter les transferts perdus vers un contrat | _safeMint / safeTransferFrom, qui vérifient que le destinataire accepte le NFT |
| Déployer sans argent réel | Testnet BSC + faucet tBNB gratuit - zéro argent réel engagé |
Résultats
- Smart contract
0x3fcCab7bb70aa5BCA5706B83e6Fcf08F80526ce9déployé sur la BSC Testnet (transaction de déploiement) - Contrat vérifié sur BscScan : code source public, transactions traçables
- NFT
Zehd42 (Z42), jeton unique conforme à la norme BEP-721 - tokenId
1miné vers0x**************, propriété vérifiée parownerOf(1) tokenURI(1)renvoie les métadonnées IPFS (CID JSON :bafkrei…numeb4pe)- Deux fichiers épinglés sur IPFS via Pinata : l'image (
bafybei…44eejcu) et son JSON de métadonnées - Code source, livre blanc et tutoriel documentés dans le dépôt
Explorer le résultat
NFT miné : voir le tokenId 1 sur BscScan
Ce que j'ai appris
La différence entre un token fongible et un NFT n'est pas cosmétique : un NFT vit sur deux étages, et c'est cette séparation qui le fait tenir. Le contrat garantit l'unicité et la propriété. IPFS garantit la pérennité de l'œuvre. Déployer le contrat ne suffit donc pas, il faut aussi publier et épingler les fichiers, et vérifier que le lien entre les deux est correct.
Le lien est justement le point le plus fragile : une URL avec un espace en trop, un tokenURI qui pointe vers l'image plutôt que vers le JSON, et le wallet affiche une case vide alors que tout est « déployé ». Raisonner sur les données avant la mise en ligne, et non après, reste la compétence centrale du développement blockchain.
Enfin, la vérification du code sur BscScan change la nature du livrable : elle transforme un contrat opaque en document public lisible et auditable par n'importe qui.
Tutoriel : Créer votre NFT BEP-721
Tu veux reproduire ce projet ? Consulte ce tutoriel qui couvre l'intégralité du processus, de l'installation de MetaMask à la vérification sur BscScan, avec la publication des métadonnées sur IPFS.