Créer un token sur la Binance Smart Chain

Nous allons voir comment créer un Token (Smart Contract) sur la Binance Smart Chain (BSC) et le déployer afin de permettre à tout le monde de le trader.

Nous partons du principe que vous connaissez déjà les principes de la crypto monnaie, que vous en avez déjà acheté, et que savez comment fonctionne les portefeuilles (wallets).

Les Smart Contracts sont des programmes qui contrôlent directement des actifs numériques. Ce sont ces programmes qui, une fois « inséré » dans la blockchain, vont définir comment ces actifs vont être gérés.

Une fois que le programme est ajouté à la blockchain, il n’est plus modifiable et il est impossible de le supprimer.

Nous utilisons ici les mécanismes de Smart Contract de la Blockchain de Binance, la BSC (sur le réseau BEP20).
Nous avons choisi la BSC car les frais de gaz sont très faibles.
Il est possible de faire la même chose sur la Blockchain Ethereum (ERC20) mais chaque transactions peut représenter plusieurs dizaines d’euros contre quelques fractions de centimes sur la BSC.

Ajouter le réseau BSC au wallet MetaMask

Pour valider les transactions sur la BSC il vous faudra un portefeuille (wallet) relié au réseau BEP20.
Pour cela nous allons installer MetaMask, lui ajouter du BNB (la monnaie nécessaire pour payer les frais de transaction), et le relier au réseau BEP20.

Vous pouvez l’installer sur votre téléphone ou bien sur votre PC (préférable pour suivre cet article).

https://metamask.io/download

image

Notez bien votre seed phrase (la clé privée) et gardez la en lieux sûr.

Ne la transférez jamais à un tiers.

C’est cette clé qui vous permettra de réinstaller votre portefeuille plus tard.

Une fois installée il vous faudra aller dans la configuration de l’extension et ajouter le réseau BSC.

Cliquez sur la barre du milieux qui contient le nom du réseau puis sur « RPC personnalisé ».

Complétez le formulaire suivant :

Pour le réseau principal (Main Net) :

Network Name : Binance Smart Chain
New RPC URL : https://bsc-dataseed.binance.org/
ChainID : 56
Symbol : BNB
Block Explorer URL : https://bscscan.com

Puis le réseau de test (Testnet) : https://docs.binance.org/smart-chain/developer/rpc.html

Network Name : Binance Smart Chain Testnet
New RPC URL : https://data-seed-prebsc-2-s1.binance.org:8545/
ChainID : 97
Symbol : BNB
Block Explorer URL : https://testnet.bscscan.com

En règle générale, pour tester votre contrat, vous commencerez par le publier dans le testnet.
Pour cela il vous faudra alimenter votre wallet avec du BNB de test (heureusement gratuit).

Il vous suffit de vous rendre sur la page suivante : https://testnet.binance.org/faucet-smart

Puis de renseigner l’adresse de votre portefeuille.

Votre adresse se trouve ici :

Vous renseignez votre adresse puis sélectionnez 1 BNB dans la liste ‘Give me BNB’.

Votre compte sera automatiquement crédité.

Création de votre Smart Contract

On a vu précédemment qu’un Smart Contract était un programme inséré dans la blockchain.
Pour le réseau BEP20 (BSC), le langage de programmation utilisé est le Solidity.

Vous trouverez la documentation complète ici : https://solidity-fr.readthedocs.io/fr/latest/

Honnêtement, ce n’est pas très compliqué. Il suffit de RTFM, comme un peu tous les langages. Il est aussi accessible que JavaScript.

Pour rédiger notre programme, le compiler et le publier, nous allons le faire directement en ligne sur le site https://remix.ethereum.org/

image-1


Tout vas se faire directement depuis ce site.

Nous allons créer un Token appelé le « PartiTech Token » avec le symbole « PTECH ».

1 – On crée notre fichier

On prendra bien soin de nommer notre fichier du nom de notre projet.

2 – L’entête de notre fichier

Très importante, c’est elle qui va définir la version du compilateur utilisé et par conséquent la version du langage.

Dans notre cas, nous allons utiliser la dernière version :

pragma solidity ^0.8.4;

3 – Le corp de notre programme

Nous créons ensuite notre contrat via la déclaration « contract » que nous nommerons de la même manière que notre fichier (ce qui est un peu plus propre).

A noter que vous pouvez déclarer autant de contrats que vous le souhaitez dans un même fichier.

pragma solidity ^0.8.4;

contract PTECH
{

}

4 – Définition de notre contrat

Nous allons devoir définir quelques paramètres de notre contrat.
Son nom, le nombre de token, et son symbole.

Arrêtons nous un instant sur la syntaxe que nous allons utiliser. Nous devons déclarer des variables.
Comme dans la plupart des langages, elle sont typées (int, string, bool etc) et ont une portée (publique ou privée).

Dans la blockchains tout est publique. Donc ne vous méprenez pas sur la notion de privée, c’est une portée d’accès de la valeur mais il est toujours possible d’y accéder.

pragma solidity ^0.8.4;

contract PTECH
{
    uint private totalSupply = 1 000 000 000 000;
    string public name = "Parti Tech Token";
    string public symbol = "PTECH";
}


Notre contrat aura 1k Milliards de tokens disponibles et s’appellera le « Parti Tech Token » avec un symbole « PTECH ».
(Franchement, on a pas longtemps hésité entre PTECH et PTT…)

Donc comme vous le voyez, déclarer une chaîne est tout simple :

Type+Portée+Nom = valeur;

Mais ce n’est pas tout.
Nous voulons ajouter des décimales à notre token de sorte que les traders puissent en acheter des fractions. Nous allons donc spécifier le nombre de décimales.

pragma solidity ^0.8.4;

contract PTECH
{
    uint private totalSupply = 1 000 000 000 000 * 10 ** 18;
    string public name = "Parti Tech Token";
    string public symbol = "PTECH";
    uint public decimals = 18;

}

Notez bien notre nouvelle variable « decimals » et la modification faite sur la variable « totalSupply ».

18 décimal, puis un nombre de token de 1 000 000 000 000 * 10 ** 18

La double * permet de donner la puissance du nombre, et on multiplie le nombre de token par 10 car d’un point de vue du portefeuille pour afficher un token, il lui faut 10 unités. Donc nous devons multiplier le nombre réel de token par 10 puissance 18 pour les décimales.

5 – Ajouter le mapping des tokens aux adresses

A ce stade, notre contrat ne sait même pas qu’il a pour logique d’affecter des token à des utilisateurs. Pour le moment, il sait juste qu’il a un nombre de token total dont la répartition lui est totalement inconnue.

Pour cela, nous allons ajouter un mapping des adresses des gens (wallets) à la répartition des tokens que nous allons appeler balance (comme une balance en comptabilité).

pragma solidity ^0.8.4;

contract PTECH
{
    mapping (address => uint) public balances;
    uint private totalSupply = 1 000 000 000 000 * 10 ** 18;
    string public name = "Parti Tech Token";
    string public symbol = "PTECH";
    uint public decimals = 18;

}

En faisant ça, on affecte à notre objet « balances » l’ensemble des adresses qui vont interagir avec notre contrat. Nous pourrons plus tard manipuler « balance » pour ajouter ou supprimer des tokens aux adresses.

Pour faire simple, on va mapper un index à une valeur. L’index sera l’adresse d’un utilisateur et la valeur les token qu’il aura acheté ou gagné (oui parce qu’on est pas forcé d’acheter le token, on peut en faire gagner aussi, à l’image des token déflationnistes).


6 – Le constructeur

Le constructeur est à l’image d’un « constructor » dans les autres langages. C’est une fonction qui sera exécutée qu’une seule fois dans la vie du programme. Et comme on a vu que le programme était exécuté à vie, sans possibilité de le mettre à jour, le constructeur sera vraiment exécuté qu’une seule fois.

pragma solidity ^0.8.4;

contract PTECH
{
    mapping (address => uint) public balances;
    uint private totalSupply = 1 000 000 000 000 * 10 ** 18;
    string public name = "Parti Tech Token";
    string public symbol = "PTECH";
    uint public decimals = 18;

    constructor(){
        balances[msg.sender]=totalSupply;
    }



}

Faisons le point sur ce que l’on vient d’ajouter.
Notre constructeur ne prend pas d’argument. Dedans, nous affectons l’ensemble des tokens à un indice précis. Notre indice, c’est une adresse.

Pour bien comprendre le mécanisme, à chaque interaction entre un utilisateur et notre programme, la blockchains va envoyer des messages. Un message en entrée, un message en retour.
Lorsque le contrat est publié, celui qui le publie est le détenteur du contrat, c’est nous.
Donc le message en entrée qui est représenté par l’objet « msg » contient en paramètre « sender » notre adresse.
Nous affectons donc à notre adresse l’ensemble des tokens disponibles.

On pourrait très bien faire une répartition sur plusieurs adresses. Par exemple, créer un portefeuille mort (dead wallet) et y affecter dès la création du contrat un pourcentage de nos tokens.
On pourrais aussi créer un portefeuille pour le marketing, pour les devs et leurs répartir des tokens qu’ils utiliseront plus tard, lorsqu’il y aura de la liquidité, pour se rémunérer ou financer une action marketing.

7 – Fonction pour lire la balance d’un utilisateur

Nous devons maintenant produire une série de fonctionnalités à notre programme qui permettront de gérer les fonctions basiques de notre contrat.
La première est de récupérer la balance de l’utilisateur.
En gros, lorsque vous ouvrez votre wallet, la première chose qu’il va faire est d’envoyer une requête vers le contrat pour récupérer votre solde.
Et le protocole va exécuter une fonction définie par le protocole qui s’appelle « balanceOf() ». Cette fonction aura toujours comme argument l’adresse du messager.

pragma solidity ^0.8.4;

contract PTECH
{
    mapping (address => uint) public balances;
    uint private totalSupply = 1 000 000 000 000 * 10 ** 18;
    string public name = "Parti Tech Token";
    string public symbol = "PTECH";
    uint public decimals = 18;

    constructor(){
        balances[msg.sender]=totalSupply;
    }

    function balanceOf(address user) public view returns (uint)
    {
        return balances[user];
        
    }

}

Wait. Prends 2 secondes pour analyser la syntaxe de notre fonction.

function balanceOf(address user) public view returns (uint)

En gros qu’est-ce que l’on vient de faire ? On spécifie le type de retour que va produire notre fonction. Tout simplement.
Avec une portée publique ou privée et un retour de type integer (uint). Et chose importante, la propriété n’est que lisible (view, en gros lecture seule).
Ensuite, on voit que notre fonction prend en entrée une variable user qui n’est autre qu’une adresse et que l’on retourne ensuite la valeur affectée pour l’indice correspondant à notre adresse dans notre tableau « balances ».

8 – Le transfert de tokens aux utilisateurs

Il nous faut maintenant définir l’interaction entre chaque transaction.
Lorsqu’un utilisateur va acheter notre token sur une maketplace il va nous envoyer une demande de transfert. A la réception nous devrons affecter le nombre de tokens à notre utilisateur.

Si nous voulions faire un système comme le DOGE coin, qui crée des tokens à chaque transaction, nous pourrions le faire ici. De même, si nous voulions faire un mécanisme de Burn, nous pourrions le faire ici aussi.

Comme vous le voyez, tous ces termes qui circulent autour des contrats sont en réalité très simples à implémenter.
Une règle mathématique toute bête.

Ça ne sera pas notre cas ici. Restons simple.

Donc à chaque transaction le protocole de la blockchain va nous envoyer un message qui appellera la fonction « transfer() » qui contiendra l’adresse de l’utilisateur.

pragma solidity ^0.8.4;

contract PTECH
{
    mapping (address => uint) public balances;
    uint private totalSupply = 1 000 000 000 000 * 10 ** 18;
    string public name = "Parti Tech Token";
    string public symbol = "PTECH";
    uint public decimals = 18;

    constructor(){
        balances[msg.sender]=totalSupply;
    }

    function balanceOf(address user) public view returns (uint)
    {
        return balances[user];
        
    }

    function transfer(address to, uint value) public view returns (uint)
    {
        require(balanceOf(msg.sender)>=value, "Solde est insuffisant");
        
    }

}

Globalement, une transaction c’est un transfert d’une valeur d’une adresse à une autre. Donc si le détenteur A veux transférer un token à un détenteur B, il faut impérativement que A possède au moins 1 token.

Pour cela nous allons utiliser l’instruction « requier », qui permet de valider une condition. Si la condition échoue, alors le processus est arrêté, et une erreur est renvoyée au protocole qui se charge de le transmettre à l’utilisateur.

Donc ce que l’on fait, c’est récupérer l’adresse de l’utilisateur et appeler notre fonction « balanceOf » qui nous retourne le solde pour l’adresse donnée et valider que le nombre de tokens à transférer est disponible dans la balance du donneur d’ordre.
Si le solde est insuffisant, on arrête la transaction.

A noter que l’objet msg est global et disponible à tout moment dans chaque function au moment d’une transaction.

En fonction du résultat, on incrémente le solde du destinataire et on décrémente le solde du donneur d’ordre.

pragma solidity ^0.8.4;

contract PTECH
{
    mapping (address => uint) public balances;
    uint private totalSupply = 1 000 000 000 000 * 10 ** 18;
    string public name = "Parti Tech Token";
    string public symbol = "PTECH";
    uint public decimals = 18;

    constructor(){
        balances[msg.sender]=totalSupply;
    }

    function balanceOf(address user) public view returns (uint)
    {
        return balances[user];
        
    }

    function transfer(address to, uint value) public view returns (uint)
    {
        require(balanceOf(msg.sender)>=value, "Solde est insuffisant");
        balances[to]+=value;
        balances[msg.sender]-=value;
    }

}

Une fois que la balance est faite, on va écrire dans la blockchain. Pour cela nous allons émettre un événement « Transfer ».
Un peu comme en JS on pourrait faire un fire event dans le DOM.
Pour invoquer un évènement, on utilise le mot-clé « emit », et pour déclarer l’évènement, on utilise le mot-clé « event ».

pragma solidity ^0.8.4;

contract PTECH
{
    mapping (address => uint) public balances;
    uint private totalSupply = 1 000 000 000 000 * 10 ** 18;
    string public name = "Parti Tech Token";
    string public symbol = "PTECH";
    uint public decimals = 18;

    event Transfer(address indexed from, address indexed to, uint value);

    constructor(){
        balances[msg.sender]=totalSupply;
    }

    function balanceOf(address user) public view returns (uint)
    {
        return balances[user];
        
    }

    function transfer(address to, uint value) public returns (bool)
    {
        require(balanceOf(msg.sender)>=value, "Solde insuffisant");
        balances[to]+=value;
        balances[msg.sender]-=value;
        emit Transfer(msg.sender, to, value);
        return true;
    }

}

Donc une fois validée, on envoit un ordre de transfert du donneur d’ordre « msg.sender » vers le destinataire « to » pour une valeur « value ».

8 -La délégation de transfert

La délégation de transfert donne la possibilité à un tiers de faire des transferts à la place du détenteur du contrat. C’est exactement ce que fait la finance décentralisée (DEFI).
Donc ce qu’il se passe c’est que l’on autorise le contrat à effectuer des transferts à notre place ce qui permet ensuite au contrat de passer des ordres depuis l’adresse du détenteur vers l’adresse du destinataire.

pragma solidity ^0.8.4;

contract PTECH
{
    mapping (address => uint) public balances;
    mapping (address => mapping (address=>uint)) public allowance;

    uint private totalSupply = 1 000 000 000 000 * 10 ** 18;
    string public name = "Parti Tech Token";
    string public symbol = "PTECH";
    uint public decimals = 18;

    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);

    constructor(){
        balances[msg.sender]=totalSupply;
    }

    function balanceOf(address user) public view returns (uint)
    {
        return balances[user];
        
    }

    function transfer(address to, uint value) public returns (bool)
    {
        require(balanceOf(msg.sender)>=value, "Solde insuffisant");
        balances[to]+=value;
        balances[msg.sender]-=value;
        emit Transfer(msg.sender, to, value);
        return true;
    }

    function approve(address spender, uint value) public  returns (bool)
    {
        allowance[msg.sender][spender]=value;
        emit Approval(msg.sender, spender, value);
        return true;
    }

}

Je ne vais pas revenir sur les concepts que nous avons vus plus haut.
On crée un mapping d’adresses qui contient lui même un mapping d’adresses. En gros un tableau à 3 dimensions.
On crée une fonction « approve » qui va affecter à notre mapping d’adresses une valeur. Ce qui va permettre de dire au système que cette adresse a le droit de dépenser en notre nom tel nombre de tokens.

On rajoute une fonction « TransferFrom » qui, lorsque l’ordre sera un ordre délégué, va vérifier la balance et vérifier la délégation. Si la balance est suffisante, et que la délégation est suffisante aussi, alors on calcule les balances de notre tableau « balances » et on émet un évènement transfert pour écrire dans la blockchain.

pragma solidity ^0.8.4;

contract PTECH
{
    mapping (address => uint) public balances;
    mapping (address => mapping (address=>uint)) public allowance;

    uint private totalSupply = 1 000 000 000 000 * 10 ** 18;
    string public name = "Parti Tech Token";
    string public symbol = "PTECH";
    uint public decimals = 18;

    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);

    constructor(){
        balances[msg.sender]=totalSupply;
    }

    function balanceOf(address user) public view returns (uint)
    {
        return balances[user];
        
    }

    function transfer(address to, uint value) public returns (bool)
    {
        require(balanceOf(msg.sender)>=value, "Solde insuffisant");
        balances[to]+=value;
        balances[msg.sender]-=value;
        emit Transfer(msg.sender, to, value);
        return true;
    }

    function TransferFrom(address from, address to, uint value) public  returns (bool)
    {
        require(balanceOf(from)>=value, "Solde insuffisant");
        require(allowance[from][msg.sender]>=value, "Délégation insuffisante");
        balances[to]+=value;
        balances[from]-=value;
        emit Transfer(from, to, value);
        return true;
    }

    function approve(address spender, uint value) public  returns (bool)
    {
        allowance[msg.sender][spender]=value;
        emit Approval(msg.sender, spender, value);
        return true;
    }

}

Déploiement du contrat dans la Blockchain

Pour lé déploiement, on reste dans notre éditeur du site https://remix.ethereum.org/

On va maintenant compiler notre contrat en vérifiant bien la version du compilateur et le type de langage.
On cochera « Hide warning » pour ne pas se polluer avec des messages non bloquants.

Il faut ensuite injecter web3 dans votre projet. En gros, cela va lier votre portefeuille MetaMask à votre contrat.
On positionnera au préalable MetaMask sur le réseau TestNet.

Ensuite on se positionne dans l’onglet déploiement, on injecte « Web3 », MetaMask s’ouvre et nous demande de valider quel compte nous voulons utiliser.

Selection_202

On valide.

Le numéro de notre compte est directement remplis dans l’interface.

On clique sur « Déploy » et MétaMask nous demande de valider la transaction.

Le déploiement va nous coûter 0.0088 BNB. Une broutille. Sans compter que sur le TestNet, on peut se créditer des BNB de tests 😉

Et on confirme.

On a la petite coche verte, tout est bon !

On vérifie la transaction dans MétaMask.

On clique sur le lien pour vérifier le déploiement sur bscscan.com

Selection_210

Voilà, notre contrat est créé.
Nous verrons dans un prochain chapitre comment y ajouter de la liquidité afin de permettre le tradding dans les différentes places de marché.

Création d’une paire et pool de liquidité

Pour que votre contrat soit en capacité d’être traidé, il faudra créer une paire avec un autre token et y ajouter de la liquidité.
Par exemple, faire une paire PTECH/BNB. On y créera un pool d’une fraction ou de la totalité de nos token disponibles, et on lui affectera une valeur de départ.
250 000 000 000 token pour 33BNB (soit à peut pret 10 000$ au cours d’aujourd’hui) serait une bonne valeur de départ.

Pour cela nous allons aller sur pancakeswap : https://pancakeswap.finance
On choisi « Liquidity » dans le menu « Trade »

Ensuite on selectionne l’onglet « Liquidity » et on clique sur « + Add Liquidity »

Il faut impérativement connecter son wallet au site, si nous souhaitons que le site créé notre pool.

Une fois connecté, le site nous indique nos pools. Pour le moment, nous n’en avons pas.

On clique sur « + Add liquidity »

Et on ajoute notre token. Dans la liste, on clique sur Manage token

Puis dans l’onglet token on ajoute l’adresse de notre contrat :

Une fois le contrat importé, on le selectionne :

Et on choisis la deuxieme devise a « coupler » avec notre contrat. Contrat/devise ou devise/Contrat, c’est comme vous le souhaitez.

On clique sur « Enable » et on laisse travailler Metamask qui va vous demander d’authoriser les transactions necessaire à la création du pool.

Vous ne devriez pas tarder a le voir listé dans les nouveaux contrats disponibles. Par exemple sur https://poocoin.app/ape

Une fois que votre pool est créé

Si vous cet article vous a été utile, n’hésitez pas a me faire un petit dont de quelques milliards 😉
Mon adresse : 0x3637fCa571aeA47DBC90f61c38629dd92a742315

Je listerais ci-dessous les généreux donateurs avec l’adresse du pool sur un exchange pour pouvoir le trader :

Montant Token Addresse exchange
Pour le moment, personne n’a fait de don. Soyez le premier !