Co to jest token?
Definicja tokenu jest bardzo rozmyta. Na potrzeby tego wpisu przyjmijmy, że token:
- Jest to pewien zapis w
blockchain - Token podlega zasadą m.in.:
- Kto, kiedy i komu może przekazać tokeny
- Ile tokenów można wygenerować
- Kto, ile tokenów posiada
- Jaki jest czas życia tokenu
- Za kontrolę przestrzegania zasad odpowiada
smart contract - Aby wykonywać operacje na tokenach, wywołujemy funkcje w
smart contract - Aby wykonać operacje na tokenach, musimy zapłacić
gas fee
Funkcjonowanie tokena określa programista tworzący jego kontrakt. Programista może zdecydować o przekazaniu całkowitej kontroli nad tokenem jego właścicielowi. Z drugiej strony, może on sobie przyznać uprawnienia do unieważnienia tokenów dowolnej osobie lub do codziennego pobierania pojedynczych tokenów od wszystkich. Aby poznać zasady działania danego tokena, należy przeanalizować kod inteligentnego kontraktu.
Dlaczego potrzebujemy standardów/interfejsów dla tokenów
Wprowadzenie standardów przyspiesza rozwój ekosystemu, ponieważ programiści tworzący aplikacje nie muszą kodować odrębnych funkcji dla każdego tokenu. Zamiast tego, integrują oni wsparcie dla danego standardu, co umożliwia obsługę wszystkich tokenów zgodnych z tym standardem. Standardowe interfejsy usprawniają komunikację z zewnętrznymi kontraktami, niezależnie od tego, czy chodzi o tokeny. Doskonałym ilustratorem korzyści płynących ze standardów są portfele kryptowalut, zarówno te sprzętowe, jak i programowe, z których wiele obsługuje rozmaite kryptowaluty oraz setki tokenów.
ERC-20 Token Standard
Intencja
Podstawą tego standardu jest cyfrowy token. Ma on na celu ustanowienie jednolitych mechanizmów dla operacji na tokenie, analogicznie do przedmiotów fizycznych. Poszczególne tokeny są niezróżnicowane, tak jak w przypadku pieniędzy – jedna jednostka danego symbolu nie różni się od innej jednostki tego samego symbolu.
Funkcjonalności
- Sprawdzenie ilości tokenów w posiadaniu danego adresu
- Zwraca Podstawowe informacje o tokenie:
- Nazwę
- Symbol
- Miejsce dziesiętne, do którego token jest podzielny
- Łączną podaż tokenów w całej sieci
Etherium
- Transfer tokenów z jednego adresu do innego
- Przydzielenie pewnego limitu dla obcego adresu, aby ten mógł wypłacić środki do wysokości limitu
Interfejs
function name() public view returns (string)
function symbol() public view returns (string)
function decimals() public view returns (uint8)
function totalSupply() public view returns (uint256)
function balanceOf(address _owner) public view returns (uint256 balance)
function transfer(address _to, uint256 _value) public returns (bool success)
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
function approve(address _spender, uint256 _value) public returns (bool success)
function allowance(address _owner, address _spender) public view returns (uint256 remaining)
event Transfer(address indexed _from, address indexed _to, uint256 _value)
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
Implementacja
ERC-165 Interface Detection
Intencja
Jeśli chcemy komunikować się automatycznie z wieloma kontraktami/tokenami, to pojawia się potrzeba automatycznego sprawdzania jakie interfejsy dany kontrakt obsługuje. W standardzie ERC-165 mamy tylko jedną funkcję, pozwala ona sprawdzić, które interfejsy są obsługiwane. Wartość liczbowa identyfikująca standard to wynik operacji xor wszystkich 4 bajtowych skrótów sygnatur funkcji obecnych w standardzie.
Przykład wyliczanie interfaceID dla przykładowego interfejsy z dwoma funkcjami:
interfaceID = bytes4(keccak256('function_1(bytes4)')) ^ bytes4(keccak256('function_2(bytes4)'))
Funkcjonalności
- Sprawdzenie, czy standard ze skrótem
interfaceIDjest obsługiwany przez ten kontrakt - Opłata maksymalna wynosi 30,000 gas
Interfejs
interface ERC165 {
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
Implementacja
ERC-721 Non-Fungible Token
Intencja
W przeciwieństwie do ERC-20, te tokeny są rozróżnialne i niepodzielne. Możemy je bardziej porównać do certyfikatu własności niż do pieniędzy. Tokeny ERC-721 są nazywane NFT
Spełnia standardy
Funkcjonalności
- Każdy token posiada swój unikalny identyfikator
tokenId - Możemy poznać ile
NFTposiada dany adres oraz kto posiada konkretnytokenId - Możliwość przekazywanie
NFTod jednego właściciela do innego - Dany
tokenId, może mieć przypisanych wiele adresów uprawnionych do dokonania transferu, niekoniecznie będzie to tylko właściciel - (opcjonalnie
ERC721Metadata) Pozwala opublikować pełną listę tokenów w posiadaniu kontraktu - (opcjonalnie
ERC721Enumerable) Zwraca: nazwę, symbol i URI tokenu
Interfejs
interface ERC721 /* is ERC165 */ {
function balanceOf(address _owner) external view returns (uint256);
function ownerOf(uint256 _tokenId) external view returns (address);
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function approve(address _approved, uint256 _tokenId) external payable;
function setApprovalForAll(address _operator, bool _approved) external;
function getApproved(uint256 _tokenId) external view returns (address);
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
}
interface ERC721TokenReceiver {
function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);
}
interface ERC721Metadata /* is ERC721 */ {
function name() external view returns (string _name);
function symbol() external view returns (string _symbol);
function tokenURI(uint256 _tokenId) external view returns (string);
}
interface ERC721Enumerable /* is ERC721 */ {
function totalSupply() external view returns (uint256);
function tokenByIndex(uint256 _index) external view returns (uint256);
function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}
Implementacja
Linki
ERC-777 Token Standard
Intencja
Rozszerza ERC-20 i jest z nim wstecznie kompatybilny. Już standard ERC-20 pozwalał nadać innemu adresowi prawo do dokonania transferu własnych środków do pewnego limitu, ERC-777 rozszerz te możliwości, wprowadza pojęcie operatora, czyli konto, które może mieć nadane przywileje do wykonania określonych zadań. Użycie operatora pozwala delegować odpowiedzialność opłacenie gas na odbiorcę. Zamiast przelać odbiorcy X Eth i zapłacić za gas, możemy ustanowić odbiorcę operatorem i pozwolić mu wypłacić X Eth z naszych środków, wówczas ma on pełną kontrolę nad opłatami dla sieci.
Kolejnym aspektem jest zabezpieczenie przed pomyłkowym wysłaniem tokenów do innego kontraktu, który ich nie obsługuje, aby uniknąć takiej sytuacji, każdy kontrakt rejestruje się w bazie obsługiwanych tokenów i tylko wówczas może przyjąć dany token.
Spełnia standardy
Funkcjonalności
- Ustanowienie
operatoraktóry może mieć prawo do transferu lub spalenia środków - Ustanowienie
domyślnego operatoraktóry może transferować lub spalić środki dowolnego posiadacza tokenów - Prowadzenie rejestru adresów zdolnych do obsługi naszego tokenu i zablokowanie transferów do tych nie zarejestrowanych
Interfejs
interface ERC777Token {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function totalSupply() external view returns (uint256);
function balanceOf(address holder) external view returns (uint256);
function granularity() external view returns (uint256);
function defaultOperators() external view returns (address[] memory);
function isOperatorFor operator, holder) external view returns (bool);
function authorizeOperator(address operator) external;
function revokeOperator(address operator) external;
function send(to, amount, data) external;
function operatorSend(from, to, amount, data, operatorData) external;
function burn(uint256 amount, bytes calldata data) external;
function operatorBurn(from, amount, data, operatorData) external;
event Sent(operator, from, to, amount, data, operatorData);
event Minted( operator, to, amount, data, operatorData);
event Burned(operator, from, amount, data, operatorData);
event AuthorizedOperator(operator,holder);
event RevokedOperator(operator, holder);
}
interface ERC777TokensSender {
function tokensToSend(operator, from, to, amount, userData, operatorData) external;
}
interface ERC777TokensRecipient {
function tokensReceived(operator, from, to, amount, data, operatorData) external;
}
Implementacja
Linki
ERC-1155 Multi Token
Intencja
Zarówno tokeny ERC-20, jak i ERC-777 zakładają, że jeden rodzaj tokenu jest obsługiwany przez jeden kontrakt. Jeśli chcemy, obsługiwać nowy token to potrzebujemy nowego kontraktu. ERC-1155 zmienia sytuacje, teraz jeden kontrakt może obsługiwać wiele różnych tokenów.
Spełnia standardy
Funkcjonalności
- Obsługa wielu rodzajów tokenów o różnych charakterystykach
- Sprawdzanie stanu dla danego adresu dla każdego tokenu
- Obsługa bezpiecznego transferu (zabezpieczenie przed wysłaniem na niewłaściwy adres)
Interfejsy
interface ERC1155 /* is ERC165 */ {
function safeTransferFrom(_from, _to, _id, _value, _data) external;
function safeBatchTransferFrom(_from, _to, _ids, _values, _data) external;
function balanceOf(_owner, _id) external view returns (uint256);
function balanceOfBatch(_owners, _ids) external view returns (uint256[] memory);
function setApprovalForAll(_operator, _approved) external;
function isApprovedForAll(_owner, _operator) external view returns (bool);
event TransferSingle(_operator, _from, indexed _to, _id, _value);
event TransferBatch(_operator, _from, indexed _to, _ids, _values);
event ApprovalForAll(_owner, _operator, _approved);
event URI(_value, indexed _id);
}
interface ERC1155TokenReceiver {
function onERC1155Received(_operator, _from, _id, _value, _data) external returns(bytes4);
function onERC1155BatchReceived(_operator, _from, _ids, _values, _data) external returns(bytes4);
}
interface ERC1155Metadata_URI {
function uri(uint256 _id) external view returns (string memory);
}
Implementacja
Linki
ERC-1820 Pseudo-introspection Registry Contract
Intencja
Ten standard wprowadza drobne poprawki do ERC-820, rozwiązujące problemy z kompatybilnością z ERC-165 wprowadzone przez aktualizację Solidity v. 0.5.
Ten standard rozwiązuje ten sam problem, co ERC-165 tylko w inny sposób i dodaje nowe funkcje. W przypadku ERC-165 mogliśmy sprawdzić interfejsy obsługiwane tylko przez inne smart kontrakty, teraz możemy sprawdzić interfejsy obsługiwane zarówno przez kontrakty, jak i regularne konta.
Wprowadza pojęcie manager adresu, czyli innego adresu, który może rejestrować interfejsy w imieniu obcego adresu. Początkowo każdy adres, jest swoim własnym menagerem, dopóki nie deleguje tej roli. Przykładem zastosowania
Spełnia standardy
Funkcjonalności
- Odpowiada na pytanie, czy dany kontrakt obsługuje dany interfejs
- Pozwala rejestrować obsługiwane interfejsy
- Kompatybilny z ERC-165
Interfejs
interface ERC1820ImplementerInterface {
function canImplementInterfaceForAddress(interfaceHash, addr) external view returns(bytes32);
}
contract ERC1820Registry {
function setManager(address account, address newManager) external;
function getManager(address account) external view returns (address);
function setInterfaceImplementer(address account, bytes32 _interfaceHash, address implementer) external;
function getInterfaceImplementer(address account, bytes32 _interfaceHash) external view returns (address);
function interfaceHash(string calldata interfaceName) external pure returns (bytes32);
function updateERC165Cache(address account, bytes4 interfaceId) external;
function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool);
function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool);
event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer);
event ManagerChanged(address indexed account, address indexed newManager);
}
Implementacja
ERC-1363 Payable Token
Intencja
Rozszerzenie ERC-20 polegające na wywołanie callbacków przy transferach i zatwierdzaniu uprawnionych do transferów. Istotne jest, że wywołanie callback odbywa się w tej samej transakcji co transfer.
Spełnia standardy
Funkcjonalności
- Transfer tokenów i wywołanie
onTransferReceivedu odbiorcy - Delegacja uprawnienia do dokonania transferu w czyimś imieniu i wywołanie
onApprovalReceivedu odbiorcy
Interfejs
contract ERC1363 is ERC20, ERC165 {
function transferAndCall(address _to, uint256 _value) public returns (bool);
function transferAndCall(address _to, uint256 _value, bytes _data) public returns (bool);
function transferFromAndCall(address _from, address _to, uint256 _value) public returns (bool);
function transferFromAndCall(address _from, address _to, uint256 _value, bytes _data) public returns (bool);
function approveAndCall(address _spender, uint256 _value) public returns (bool);
function approveAndCall(address _spender, uint256 _value, bytes _data) public returns (bool);
}
contract ERC1363Receiver {
function onTransferReceived(address _operator, address _from, uint256 _value, bytes _data) external returns(bytes4);
}
contract ERC1363Spender {
function onApprovalReceived(address _owner, uint256 _value, bytes _data) external returns (bytes4);
}
Implementacja
Linki
Linki
