Come creare un token ERC20 in modo semplice

Pubblicato: 2022-03-11

L'obiettivo di questo articolo è dimostrare come creare un token ERC20 nel minor tempo possibile.

Iniziamo con le basi: cos'è un token ERC20?

Negli ultimi anni, la specifica del token ERC20 è diventata lo standard di fatto per i token Ethereum. In altre parole, la maggior parte dei contratti Ethereum disponibili oggi sono conformi a ERC20. Questo articolo descriverà in dettaglio come creare il tuo token Ethereum, ma prima di iniziare, diamo un'occhiata più da vicino allo standard ERC20.

Illustrazione del token ERC20

Cosa rende i token ERC20 così attraenti e di successo? Ci sono diversi fattori in gioco:

  1. I token ERC20 sono semplici e facili da distribuire, come vedrai in questo tutorial.
  2. Lo standard ERC20 risolve un problema significativo, poiché i mercati basati su blockchain e i portafogli crittografici necessitano di un unico set standardizzato di comandi per comunicare con la gamma di token che gestiscono. Ciò include le regole di interazione tra diversi token, nonché le regole di acquisto dei token.
  3. È stata la prima specifica popolare a offrire la standardizzazione dei token Ethereum. Non è stato affatto il primo , ma grazie alla sua popolarità è diventato rapidamente lo standard del settore.

Proprio come gli altri token Ethereum, i token ERC20 sono implementati come contratti intelligenti ed eseguiti sulla macchina virtuale di Ethereum (EVM) in modo decentralizzato.

Solidità: il linguaggio di programmazione Smart Contract

Gli smart contract di Ethereum sono scritti in Solidity. Sebbene ci siano lingue alternative, quasi nessuno le usa per questo scopo. Solidity è simile a JavaScript, quindi se hai una certa conoscenza di JavaScript, o anche Java e altri linguaggi simili al C, non dovresti avere problemi a capire che un pezzo di codice in Solidity lo fa, anche prima di padroneggiare effettivamente Solidity abbastanza per usarlo esso.

È qui che inizia il divertimento, poiché dovresti essere in grado di iniziare a creare un semplice contratto ERC20 in pochissimo tempo. Questa è un'attività semplice, abbastanza semplice che questo articolo mostrerà come scrivere e distribuire un token ERC20 in meno di un'ora.

Il token che creeremo in questa dimostrazione sarà una semplice implementazione ERC20, senza troppi campanelli e fischietti. Tuttavia, ho visto molti token altrettanto semplici nel mondo reale e tendono a funzionare abbastanza bene.

Panoramica dello standard di token ERC20

Che cos'è ERC20?

In parole povere, lo standard ERC20 definisce un insieme di funzioni che devono essere implementate da tutti i token ERC20 in modo da consentire l'integrazione con altri contratti, portafogli o marketplace. Questo insieme di funzioni è piuttosto breve e basilare.

 function totalSupply() public view returns (uint256); function balanceOf(address tokenOwner) public view returns (uint); function allowance(address tokenOwner, address spender) public view returns (uint); function transfer(address to, uint tokens) public returns (bool); function approve(address spender, uint tokens) public returns (bool); function transferFrom(address from, address to, uint tokens) public returns (bool);

Le funzioni ERC20 consentono a un utente esterno, ad esempio un'app di cripto-portafoglio, di scoprire il saldo di un utente e trasferire fondi da un utente all'altro con l'adeguata autorizzazione.

Lo smart contract definisce due eventi specificatamente definiti:

 event Approval(address indexed tokenOwner, address indexed spender, uint tokens); event Transfer(address indexed from, address indexed to, uint tokens);

Questi eventi verranno invocati o emessi quando a un utente vengono concessi i diritti per ritirare i token da un account e dopo che i token sono stati effettivamente trasferiti.

Oltre alle funzioni standard ERC20, molti token ERC20 dispongono anche di campi aggiuntivi e alcuni sono diventati de facto parte dello standard ERC20, se non per iscritto poi nella pratica. Ecco alcuni esempi di tali campi.

 string public constant name; string public constant symbol; uint8 public constant decimals;

Ecco alcuni punti riguardanti la nomenclatura ERC20 e Solidity:

  • È possibile accedere a una funzione public al di fuori del contratto stesso
  • view significa sostanzialmente costante, cioè lo stato interno del contratto non sarà modificato dalla funzione
  • Un event è il modo in cui Solidity consente ai clienti, ad esempio il frontend dell'applicazione, di essere avvisati su eventi specifici all'interno del contratto

La maggior parte dei costrutti del linguaggio Solidity dovrebbe essere chiara se possiedi già competenze Java/JavaScript essenziali.

Scrivere un token ERC20 in Solidity

Gettoni ERC20 in solidità

Ora che abbiamo delineato le basi e spiegato cosa serve per creare un token ERC20, è tempo di iniziare a scrivere un po' di logica.

Innanzitutto, dobbiamo definire due oggetti di mappatura. Questa è la nozione di Solidità per un array associativo o chiave/valore:

 mapping(address => uint256) balances; mapping(address => mapping (address => uint256)) allowed;

L'espressione mapping(address => uint256) definisce un array associativo le cui chiavi sono di tipo address — un numero utilizzato per denotare gli indirizzi dei conti e i cui valori sono di tipo uint256 — un intero a 256 bit tipicamente utilizzato per memorizzare i saldi dei token.

Il primo oggetto di mappatura, balances , conterrà il saldo del token di ciascun account proprietario.

Il secondo oggetto di mappatura, allowed , includerà tutti gli account autorizzati a prelevare da un determinato account insieme alla somma di prelievo consentita per ciascuno.

Come puoi vedere, il campo del valore della mappatura consentita è di per sé una mappatura dell'indirizzo del conto in base alla somma di prelievo approvata.

Queste mappature insieme a tutti gli altri campi del contratto verranno archiviate nella blockchain e verranno estratte con conseguente propagazione delle modifiche a tutti i nodi utente della rete.

Lo storage blockchain è costoso e gli utenti del tuo contratto dovranno pagare, in un modo o nell'altro. Pertanto dovresti sempre cercare di ridurre al minimo le dimensioni dello spazio di archiviazione e le scritture nella blockchain.

Ora che abbiamo le strutture dati richieste, possiamo iniziare a scrivere effettivamente la logica ERC20 nelle funzioni appropriate.

Impostazione del numero di token ICO

Come impostiamo il numero di token ICO? Bene, ci sono diversi modi per impostare il numero massimo di token ICO e questo argomento potrebbe valere una lunga discussione da solo.

Per le esigenze del nostro tutorial ECR20, utilizzeremo l'approccio più semplice: impostare la quantità totale di token al momento della creazione del contratto e assegnarli inizialmente tutti al "proprietario del contratto", ovvero l'account che ha distribuito lo smart contract:

 uint256 totalSupply_; constructor(uint256 total) public { totalSupply_ = total; balances[msg.sender] = _totalSupply; }

Un costruttore è una funzione speciale chiamata automaticamente da Ethereum subito dopo la distribuzione del contratto. Viene in genere utilizzato per inizializzare lo stato del token utilizzando i parametri passati dall'account di distribuzione del contratto.

msg è una variabile globale dichiarata e popolata da Ethereum stesso. Contiene dati importanti per l'esecuzione del contratto. Il campo che stiamo usando qui: msg.sender contiene l'account Ethereum che esegue la funzione di contratto corrente.

Solo l'account di distribuzione può immettere il costruttore di un contratto. All'avvio del contratto, questa funzione assegna i token disponibili all'account 'titolare del contratto'.

Ottieni la fornitura totale di token

 function totalSupply() public view returns (uint256) { return totalSupply_; }

Questa funzione restituirà il numero di tutti i token assegnati da questo contratto indipendentemente dal proprietario.

Ottieni il saldo del token del proprietario

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

balanceOf restituirà il saldo token corrente di un account, identificato dall'indirizzo del suo proprietario.

Trasferisci token su un altro account

 function transfer(address receiver, uint numTokens) public returns (bool) { require(numTokens <= balances[msg.sender]); balances[msg.sender] = balances[msg.sender] — numTokens; balances[receiver] = balances[receiver] + numTokens; emit Transfer(msg.sender, receiver, numTokens); return true; }

Come suggerisce il nome, la funzione di transfer viene utilizzata per spostare numTokens quantità di token dal saldo del proprietario a quello di un altro utente o receiver . Il proprietario trasferente è msg.sender ovvero colui che esegue la funzione, il che implica che solo il proprietario dei token può trasferirli ad altri.

Il modo di solidità di asserire un predicato è require . In questo caso che il conto trasferente abbia un saldo sufficiente per eseguire il trasferimento. Se un'istruzione require non riesce, la transazione viene immediatamente annullata senza modifiche scritte nella blockchain.

Subito prima di uscire, la funzione attiva il Transfer dell'evento ERC20 consentendo agli ascoltatori registrati di reagire al suo completamento.

Approva il delegato per il prelievo di token

Questa funzione viene utilizzata più spesso in uno scenario di mercato dei token.

 function approve(address delegate, uint numTokens) public returns (bool) { allowed[msg.sender][delegate] = numTokens; emit Approval(msg.sender, delegate, numTokens); return true; }

Ciò che fa l' approve è consentire a un proprietario, ad esempio msg.sender di approvare un account delegato, possibilmente il mercato stesso, di prelevare token dal suo account e trasferirli ad altri account.

Come puoi vedere, questa funzione viene utilizzata per scenari in cui i proprietari offrono token su un mercato. Consente al mercato di finalizzare la transazione senza attendere l'approvazione preventiva.

Al termine della sua esecuzione, questa funzione attiva un evento di Approval .

Ottieni il numero di token approvati per il prelievo

 function allowance(address owner, address delegate) public view returns (uint) { return allowed[owner][delegate]; }

Questa funzione restituisce il numero di token attualmente approvato da un proprietario a un delegato specifico, come impostato nella funzione di approve .

Trasferisci i token dal delegato

La funzione transferFrom è il peer della funzione di approve , di cui abbiamo discusso in precedenza. Consente a un delegato approvato per il prelievo di trasferire i fondi del proprietario su un conto di terze parti.

 function transferFrom(address owner, address buyer, uint numTokens) public returns (bool) { require(numTokens <= balances[owner]); require(numTokens <= allowed[owner][msg.sender]); balances[owner] = balances[owner] — numTokens; allowed[owner][msg.sender] = allowed[from][msg.sender] — numTokens; balances[buyer] = balances[buyer] + numTokens; Transfer(owner, buyer, numTokens); return true; }

Le due istruzioni require all'inizio della funzione sono per verificare che la transazione sia legittima, ovvero che il proprietario abbia abbastanza token da trasferire e che il delegato abbia l'approvazione per (almeno) numTokens da ritirare.

Oltre a trasferire l'importo di numTokens dal proprietario all'acquirente, questa funzione sottrae anche numTokens dall'indennità del delegato. Ciò sostanzialmente consente a un delegato con una determinata indennità di suddividerla in diversi prelievi separati, che è un comportamento tipico del mercato.

Potremmo fermarci qui e avere un'implementazione ERC20 valida. Tuttavia, vogliamo fare un ulteriore passo avanti, poiché vogliamo un token di forza industriale. Ciò richiede di rendere il nostro codice un po' più sicuro, anche se saremo comunque in grado di mantenere il token relativamente semplice, se non di base.

Libreria della solidità di SafeMath

SafeMath è una libreria Solidity volta a gestire un modo in cui gli hacker sono noti per infrangere i contratti: attacco di overflow di numeri interi. In un tale attacco, l'hacker forza il contratto a utilizzare valori numerici errati passando parametri che porteranno gli interi rilevanti oltre i loro valori massimi.

Libreria Safemath in Solidity: illustrazione

SafeMath protegge da questo verificando l'overflow prima di eseguire l'azione aritmetica, eliminando così il pericolo di un attacco di overflow. La libreria è così piccola che l'impatto sulle dimensioni del contratto è minimo, non comportando alcuna penalizzazione in termini di prestazioni e costi di archiviazione.

Aggiungiamo SafeMath al nostro codice:

 library SafeMath { // Only relevant functions function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a — b; } function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } }

SafeMath utilizza le istruzioni assert per verificare la correttezza dei parametri passati. Se l' assert fallisce, l'esecuzione della funzione verrà immediatamente interrotta e tutte le modifiche alla blockchain verranno annullate.

Successivamente, aggiungiamo la seguente istruzione che introduce la libreria al compilatore Solidity:

using SafeMath for uint256;

Quindi, sostituiamo l'aritmetica ingenua che abbiamo usato all'inizio con le funzioni di SafeMath:

 balances[msg.sender] = balances[msg.sender].sub(numTokens); balances[receiver] = balances[receiver].add(numTokens); balances[buyer] = balances[buyer].add(numTokens); balances[owner] = balances[owner].sub(numTokens);

Imballando tutto insieme

In Solidity, le funzioni e gli eventi di un contratto intelligente sono racchiusi in un'entità chiamata contratto che puoi tradurre silenziosamente in una "classe blockchain". Di seguito è riportato il contratto compatibile con ERC20 che abbiamo creato, incluso un Gist del nostro codice. I campi nome e simbolo possono essere modificati a piacimento. La maggior parte dei token mantiene il valore decimale a 18, quindi faremo lo stesso.

Distribuzione del contratto Ethereum

È giunto il momento di implementare il nostro contratto sulla blockchain. Dopo la distribuzione, il nostro contratto sarà trasferito a tutti i nodi che partecipano alla rete. Tutte le modifiche apportate al contratto verranno propagate a tutti i nodi partecipanti.

Gli sviluppatori di Ethereum di solito utilizzano strumenti di distribuzione come Truffle. Anche il tartufo è eccessivo per le limitate esigenze di questo articolo e sarà sufficiente un semplice strumento online chiamato Remix.

Per usarlo, dovrai installare il plug-in MetaMask sul tuo browser e un account Rinkeby (rete di test Ethereum) con almeno un po' di Rinkeby Ether. Questi sono passaggi relativamente semplici, quindi non entreremo nei dettagli.

Nel caso in cui non li possiedi, vai su MetaMask e Rinkeby per i collegamenti per il download e per ottenere istruzioni chiare sull'installazione e l'utilizzo.

Ora che abbiamo tutti gli elementi costitutivi, andremo su Remix e incolleremo il codice sopra, inclusa la linea pragma e la libreria SafeMath, nell'editor online.

Quindi, passeremo alla seconda scheda a destra chiamata " Esegui " e faremo clic su " Distribuisci ". Apparirà un popup MetaMask che ci chiede di confermare la transazione. Ovviamente lo approveremo.

testo alternativo immagine

  • Riquadro verde: assicurati di essere su Rinkeby
  • Riquadro blu: imposta la tua scorta totale di gettoni
  • Riquadro rosso: schieramento!

Sommario : https://gist.github.com/giladHaimov/8e81dbde10c9aeff69a1d683ed6870be#file-basicerc20-sol

Congratulazioni! Hai appena distribuito il tuo primo token ERC20, come un vero professionista di Ethereum. Come promesso, il token è semplice e leggero, ma perfettamente funzionante, conforme allo standard ERC20 e protetto con MathSafe. È pronto per essere acquistato, pagato e trasferito attraverso la Blockchain.

È tutto quello che c'è da fare per gli smart contract?

No, nemmeno vicino, poiché la nostra breve dimostrazione graffia a malapena la superficie e si occupa esclusivamente di un aspetto dello sviluppo di contratti intelligenti.

Gli smart contract possono essere molto più complessi a seconda della tua logica aziendale, della modellazione dell'interazione dell'utente, del fatto che tu consenta o meno il conio e la masterizzazione di token, le modifiche al ciclo di vita che introduci nel contratto, la necessità di funzionalità a livello di amministratore che di solito viene fornita con un insieme di funzioni autorizzato dall'amministratore e così via. Ottieni l'immagine.

Tuttavia, se puoi replicare ciò che abbiamo fatto qui, questa è una solida base per espandere le tue conoscenze e passare a contratti più complessi quando necessario.