Jak stworzyć token ERC20 w prosty sposób?

Opublikowany: 2022-03-11

Celem tego artykułu jest pokazanie, jak stworzyć token ERC20 w jak najkrótszym czasie.

Zacznijmy od podstaw: Co to jest token ERC20?

W ostatnich latach specyfikacja tokena ERC20 stała się de facto standardem dla tokenów Ethereum. Innymi słowy, większość dostępnych obecnie umów Ethereum jest zgodna z ERC20. W tym artykule szczegółowo opisano, w jaki sposób możesz stworzyć własny token Ethereum, ale zanim zaczniemy, przyjrzyjmy się bliżej standardowi ERC20.

Ilustracja tokena ERC20

Co sprawia, że ​​tokeny ERC20 są tak atrakcyjne i skuteczne? W grę wchodzi kilka czynników:

  1. Jak zobaczysz w tym samouczku, tokeny ERC20 są proste i łatwe do wdrożenia.
  2. Standard ERC20 rozwiązuje poważny problem, ponieważ rynki i portfele kryptograficzne oparte na blockchain potrzebują jednego, ustandaryzowanego zestawu poleceń do komunikacji z szeregiem zarządzanych tokenów. Obejmuje to zasady interakcji między różnymi tokenami, a także zasady zakupu tokenów.
  3. Była to pierwsza popularna specyfikacja oferująca standaryzację tokenów Ethereum. Nie był bynajmniej pierwszy , ale dzięki swojej popularności szybko stał się standardem w branży.

Podobnie jak inne tokeny Ethereum, tokeny ERC20 są implementowane jako inteligentne kontrakty i wykonywane na wirtualnej maszynie Ethereum (EVM) w sposób zdecentralizowany.

Solidność: język programowania inteligentnych kontraktów

Inteligentne kontrakty Ethereum są napisane w Solidity. Chociaż istnieją języki alternatywne, mało kto używa ich do tego celu. Solidity jest podobny do JavaScript, więc jeśli masz trochę wiedzy o JavaScript, a nawet Javie i innych językach podobnych do C, nie powinieneś mieć problemu z odkryciem, że kawałek kodu w Solidity ma to miejsce, nawet zanim faktycznie opanujesz Solidity na tyle, by używać go to.

Tutaj zaczyna się zabawa, ponieważ powinieneś być w stanie szybko rozpocząć tworzenie prostej umowy ERC20. To proste zadanie, na tyle proste, że ten artykuł pokaże, jak napisać i wdrożyć token ERC20 w niecałą godzinę.

Token, który będziemy tworzyć w tej demonstracji, będzie prostą implementacją ERC20, bez zbyt wielu dzwonków i gwizdków. Jednak widziałem wiele podobnie prostych tokenów w prawdziwym świecie i zwykle radzą sobie całkiem nieźle.

Przegląd standardu tokenów ERC20

Co to jest ERC20?

Mówiąc prościej, standard ERC20 definiuje zestaw funkcji, które mają być zaimplementowane przez wszystkie tokeny ERC20, aby umożliwić integrację z innymi kontraktami, portfelami lub platformami handlowymi. Ten zestaw funkcji jest raczej krótki i podstawowy.

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

Funkcje ERC20 pozwalają zewnętrznemu użytkownikowi, powiedzmy aplikacji kryptowalutowej, sprawdzić saldo użytkownika i przelać środki od jednego użytkownika do drugiego z odpowiednią autoryzacją.

Inteligentna umowa definiuje dwa konkretnie zdefiniowane zdarzenia:

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

Zdarzenia te będą wywoływane lub emitowane po przyznaniu użytkownikowi uprawnień do pobierania tokenów z konta oraz po faktycznym przekazaniu tokenów.

Oprócz standardowych funkcji ERC20, wiele tokenów ERC20 posiada również dodatkowe pola, a niektóre stały się de facto częścią standardu ERC20, jeśli nie w formie pisemnej, to w praktyce. Oto kilka przykładów takich pól.

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

Oto kilka punktów dotyczących nomenklatury ERC20 i Solidity:

  • Dostęp do funkcji public można uzyskać poza samą umową
  • view w zasadzie oznacza stały, tzn. stan wewnętrzny umowy nie zostanie zmieniony przez funkcję
  • event to sposób Solidity na to, aby klienci, np. frontend Twojej aplikacji, byli powiadamiani o określonych zdarzeniach w ramach umowy

Większość konstrukcji języka Solidity powinna być przejrzysta, jeśli posiadasz już podstawowe umiejętności Java/JavaScript.

Pisanie tokena ERC20 w Solidity

Solidność tokenów ERC20

Teraz, gdy nakreśliliśmy podstawy i wyjaśniliśmy, co jest potrzebne do stworzenia tokena ERC20, nadszedł czas, aby zacząć pisać trochę logiki.

Najpierw musimy zdefiniować dwa obiekty mapujące. To jest pojęcie solidności dla tablicy asocjacyjnej lub tablicy klucz/wartość:

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

Wyrażenie mapping(address => uint256) definiuje tablicę asocjacyjną, której klucze są typu address — liczba używana do oznaczania adresów kont, a której wartości są typu uint256 — 256-bitowa liczba całkowita zwykle używana do przechowywania sald tokenów.

Pierwszy obiekt mapowania, balances , będzie zawierał saldo tokenów każdego konta właściciela.

Drugi obiekt mapowania, allowed , będzie zawierał wszystkie rachunki zatwierdzone do wypłaty z danego rachunku wraz z dozwoloną kwotą wypłaty dla każdego z nich.

Jak widać, pole wartości dozwolonego mapowania jest samo w sobie mapowaniem adresu konta do jego zatwierdzonej sumy wypłaty.

Te mapowania wraz ze wszystkimi innymi polami kontraktów będą przechowywane w łańcuchu bloków i będą wydobywane , co spowoduje propagację zmian do wszystkich węzłów użytkowników sieci.

Przechowywanie Blockchain jest drogie, a użytkownicy Twojej umowy będą musieli zapłacić w taki czy inny sposób. Dlatego zawsze powinieneś starać się minimalizować rozmiar pamięci i zapisy w łańcuchu bloków.

Teraz, gdy mamy już wymagane struktury danych, możemy zacząć zapisywać logikę ERC20 w odpowiednich funkcjach.

Ustawianie liczby tokenów ICO

Jak ustalamy liczbę tokenów ICO? Cóż, istnieje wiele sposobów na ustawienie maksymalnej liczby tokenów ICO i sama ta kwestia może być warta długiej dyskusji.

Na potrzeby naszego samouczka ECR20 zastosujemy najprostsze podejście: ustaw łączną ilość tokenów w momencie tworzenia umowy i wstępnie przypisz je wszystkie do „właściciela kontraktu”, czyli konta, które wdrożyło inteligentną umowę:

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

Konstruktor to specjalna funkcja automatycznie wywoływana przez Ethereum zaraz po wdrożeniu kontraktu. Jest zwykle używany do inicjowania stanu tokenu przy użyciu parametrów przekazanych przez konto wdrażania kontraktu.

msg jest zmienną globalną zadeklarowaną i wypełnianą przez samo Ethereum. Zawiera ważne dane do wykonania umowy. Pole, którego tutaj używamy: msg.sender zawiera konto Ethereum realizujące bieżącą funkcję kontraktu.

Tylko konto wdrożeniowe może wprowadzić konstruktora kontraktu. Po uruchomieniu kontraktu funkcja ta przydziela dostępne tokeny na konto „właściciela kontraktu”.

Uzyskaj całkowitą podaż tokenów

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

Ta funkcja zwróci liczbę wszystkich tokenów przydzielonych przez tę umowę, niezależnie od właściciela.

Uzyskaj saldo tokena właściciela

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

balanceOf zwróci aktualne saldo tokena konta, identyfikowanego przez adres jego właściciela.

Przenieś tokeny na inne konto

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

Jak sama nazwa wskazuje, funkcja transfer służy do przeniesienia liczby tokenów numTokens z salda właściciela na saldo innego użytkownika lub receiver . Właścicielem przenoszącym jest msg.sender czyli wykonujący funkcję, co oznacza, że ​​tylko właściciel tokenów może przekazywać je innym.

Sposobem na twierdzenie orzecznika w Solidity jest require . W takim przypadku konto przelewu ma wystarczające saldo do wykonania przelewu. Jeśli instrukcja require nie powiedzie się, transakcja jest natychmiast wycofywana bez żadnych zmian zapisanych w łańcuchu bloków.

Tuż przed wyjściem funkcja uruchamia Transfer zdarzenia ERC20, umożliwiając zarejestrowanym słuchaczom reakcję na jego zakończenie.

Zatwierdź delegata, aby wypłacić tokeny

Ta funkcja jest najczęściej używana w scenariuszu rynku tokenów.

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

approve umożliwia właścicielowi, tj msg.sender , zatwierdzenie konta delegowanego — prawdopodobnie samego rynku — na wycofanie tokenów ze swojego konta i przeniesienie ich na inne konta.

Jak widać, ta funkcja jest używana w scenariuszach, w których właściciele oferują tokeny na rynku. Pozwala to rynkowi sfinalizować transakcję bez oczekiwania na uprzednią zgodę.

Pod koniec wykonywania ta funkcja uruchamia zdarzenie Approval .

Uzyskaj liczbę tokenów zatwierdzonych do wypłaty

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

Ta funkcja zwraca bieżącą zatwierdzoną liczbę tokenów przez właściciela do określonego delegata, zgodnie z ustawieniem w funkcji approve .

Przenieś tokeny przez delegata

Funkcja transferFrom jest równorzędna z funkcją approve , o której mówiliśmy wcześniej. Pozwala delegatowi zatwierdzonemu do wypłaty na przeniesienie środków właściciela na konto strony trzeciej.

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

Dwie instrukcje require na początku funkcji mają na celu sprawdzenie, czy transakcja jest legalna, tj. czy właściciel ma wystarczającą ilość tokenów do przeniesienia i czy delegat ma zgodę na (przynajmniej) numTokens .

Oprócz przeniesienia kwoty numTokens od właściciela do kupującego, ta funkcja odejmuje również numTokens od uprawnień delegata. Zasadniczo pozwala to delegatowi z danym dodatkiem na rozbicie go na kilka oddzielnych wypłat, co jest typowym zachowaniem na rynku.

Moglibyśmy się tutaj zatrzymać i mieć prawidłową implementację ERC20. Chcemy jednak pójść o krok dalej, ponieważ zależy nam na tokenie siły przemysłowej. Wymaga to od nas, aby nasz kod był nieco bezpieczniejszy, chociaż nadal będziemy mogli zachować stosunkowo prosty, jeśli nie podstawowy token.

Biblioteka Solidności SafeMath

SafeMath to biblioteka Solidity mająca na celu radzenie sobie z jednym ze sposobów, w jaki hakerzy łamią umowy: atakiem przepełnienia liczb całkowitych. W takim ataku haker wymusza na kontrakcie użycie błędnych wartości liczbowych, przekazując parametry, które przeniosą odpowiednie liczby całkowite poza ich maksymalne wartości.

Biblioteka Safemath w Solidity: ilustracja

SafeMath chroni przed tym, testując przepełnienie przed wykonaniem akcji arytmetycznej, eliminując w ten sposób niebezpieczeństwo ataku przepełnienia. Biblioteka jest tak mała, że ​​wpływ na wielkość kontraktu jest minimalny, nie wiąże się z wydajnością i niewielkimi karami za przechowywanie.

Dodajmy SafeMath do naszego kodu:

 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 używa instrukcji Asser assert aby zweryfikować poprawność przekazanych parametrów. W przypadku niepowodzenia assert wykonanie funkcji zostanie natychmiast zatrzymane, a wszystkie zmiany w łańcuchu bloków zostaną wycofane.

Następnie dodajmy następującą wypowiedź wprowadzającą bibliotekę do kompilatora Solidity:

using SafeMath for uint256;

Następnie zastępujemy naiwną arytmetykę, której używaliśmy na początku, funkcjami 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);

Pakowanie wszystkiego razem

W Solidity funkcje i zdarzenia inteligentnej umowy są opakowane w encję zwaną umową , którą można po cichu przetłumaczyć na „klasę blockchain”. Poniżej znajduje się przygotowana przez nas umowa zgodna z ERC20, w tym sedno naszego kodu. Pola nazwy i symbolu można dowolnie zmieniać. Większość tokenów utrzymuje wartość dziesiętną 18, więc zrobimy to samo.

Wdrożenie umowy Ethereum

Nadszedł czas, aby wdrożyć naszą umowę w blockchain. Po wdrożeniu nasza umowa zostanie przeniesiona na wszystkie węzły uczestniczące w sieci. Wszelkie zmiany wprowadzone do umowy będą propagowane do wszystkich uczestniczących węzłów.

Deweloperzy Ethereum zwykle używają narzędzi do wdrażania, takich jak Truffle. Nawet Truffle to przesada, jeśli chodzi o ograniczone potrzeby tego artykułu, wystarczy proste narzędzie online o nazwie Remix.

Aby z niego skorzystać, musisz zainstalować wtyczkę MetaMask w przeglądarce i konto Rinkeby (sieć testowa Ethereum) z co najmniej kilkoma Rinkeby Ether. Są to stosunkowo proste kroki, więc nie będziemy wchodzić w szczegóły.

Jeśli ich nie masz, przejdź do MetaMask i Rinkeby, aby uzyskać linki do pobrania i uzyskać jasne wskazówki dotyczące instalacji i użytkowania.

Teraz, gdy mamy już wszystkie bloki konstrukcyjne, przejdziemy do Remix i wkleimy powyższy kod, w tym wiersz pragma i bibliotekę SafeMath, do edytora online.

Następnie przejdziemy do drugiej karty po prawej o nazwie „ Uruchom ” i klikniemy „ Wdróż ”. Pojawi się wyskakujące okienko MetaMask z prośbą o potwierdzenie transakcji. Oczywiście zatwierdzimy to.

tekst alternatywny obrazu

  • Zielona skrzynka: Upewnij się, że jesteś na Rinkeby
  • Niebieskie pole: Ustaw całkowitą podaż tokenów
  • Czerwone pudełko: Rozmieszczanie!

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

Gratulacje! Właśnie wdrożyłeś swój pierwszy token ERC20, niczym prawdziwy profesjonalista Ethereum. Zgodnie z obietnicą token jest prosty i lekki, a jednocześnie w pełni funkcjonalny, zgodny ze standardem ERC20 i zabezpieczony za pomocą MathSafe. Jest gotowy do zakupu, zapłaty i przeniesienia w całym Blockchain.

Czy to wszystko, co dotyczy inteligentnych kontraktów?

Nie, nawet nie blisko, ponieważ nasza krótka demonstracja ledwo zarysowuje powierzchnię i dotyczy wyłącznie jednego aspektu rozwoju inteligentnych kontraktów.

Inteligentne kontrakty mogą być znacznie bardziej złożone w zależności od logiki biznesowej, modelowania interakcji z użytkownikiem, tego, czy zezwalasz na wydobywanie i wypalanie tokenów, zmian w cyklu życia, które wprowadzasz do umowy, zapotrzebowania na funkcje na poziomie administratora, które zwykle towarzyszą zestaw funkcji autoryzowany przez administratora i tak dalej. Dostajesz obraz.

Mimo to, jeśli możesz powtórzyć to, co tutaj zrobiliśmy, jest to solidna podstawa do poszerzenia swojej wiedzy i przejścia do bardziej złożonych kontraktów, gdy jest to konieczne.