Большинство токенов эфира выпускаются по стандарту ERC20 (подробнее можно почитать тут). Токены на основе этого стандарта работают вполне успешно.
Но все же были выявлены некоторые недостатки. Давайте посмотрим на эти недостатки и как их решили в ERC223.
Дополнение: На сегодняшний день ERC20 уже официально является стандартом и в него уже включены пункты 1, 2 и 3.
Кошелькам нужно отображать имя токена. Возможности получить имя стандарт ERC20 не предусматривает. В ERC223 для этого ввели метод name.Также в кошельках необходимо отображать короткое имя токена. В ERC20 такой возможности нет. Токен ERC223 — уже содержит метод symbol.Необходимо знать количество знаков после запятой, чего нет в ERC20. В ERC223 — для этого есть метод decimals.- Проблема потеряных токенов. Иногда люди по ошибке могут отправить токены на адрес, который является контрактом. В этом случае контракт станет владельцем токенов. И, если контракт не предусмотрел явную возможность работы с transfer, то токены останутся на адресе контракта навсегда. Стандарт ERC223 вводит интерфейс для контрактов, которые хотят работать с токенами. В этом интерфейсе есть функция tokenFallback, она должна вызываться при попытке отправить на контракт токены.
- При выполнении транзакции с помощью transfer возникает потребность добавлять дополнительную информацию. В ERC223 добавлен дополнительный метод transfer который содержит поле data — специально для передачи дополнительной информации. При этом старый метод transfer оставили для обратной совместимости.
До момента официального опубликования ERC20 в него не были включены функции symbol, name, decimals. Но многие контракты уже реализовывали эти функции. тем самым частично реализовав стандарт ERC223.
Рекомендованные интерфейсы и реализации ERC223 на Solidity можно посмотреть тут.
Стандарт ERC223 определяет из два интерфейса. Интерфейс токена.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
pragma solidity ^0.4.9; /* New ERC23 contract interface */ contract ERC223 { uint public totalSupply; function balanceOf(address who) constant returns (uint); function name() constant returns (string _name); function symbol() constant returns (string _symbol); function decimals() constant returns (uint8 _decimals); function totalSupply() constant returns (uint256 _supply); function transfer(address to, uint value) returns (bool ok); function transfer(address to, uint value, bytes data) returns (bool ok); event Transfer(address indexed from, address indexed to, uint value, bytes indexed data); } |
И интерфейс контракта, который может получать токены.
1 2 3 4 5 6 7 8 9 |
pragma solidity ^0.4.11; /* * Contract that is working with ERC223 tokens */ contract ERC223ReceivingContract { function tokenFallback(address _from, uint _value, bytes _data); } |
А вот рекомендованная реализация ERC223.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
contract ERC223BasicToken is ERC223Basic{ using SafeMath for uint; mapping(address => uint) balances; // Function that is called when a user or another contract wants to transfer funds . function transfer(address to, uint value, bytes data) { // Standard function transfer similar to ERC20 transfer with no _data . // Added due to backwards compatibility reasons . uint codeLength; assembly { // Retrieve the size of the code on target address, this needs assembly . codeLength := extcodesize(to) } balances[msg.sender] = balances[msg.sender].sub(value); balances[to] = balances[to].add(value); if(codeLength>0) { ERC223ReceivingContract receiver = ERC223ReceivingContract(to); receiver.tokenFallback(msg.sender, value, data); } Transfer(msg.sender, to, value, data); } // Standard function transfer similar to ERC20 transfer with no _data . // Added due to backwards compatibility reasons . function transfer(address to, uint value) { uint codeLength; assembly { // Retrieve the size of the code on target address, this needs assembly . codeLength := extcodesize(to) } balances[msg.sender] = balances[msg.sender].sub(value); balances[to] = balances[to].add(value); if(codeLength>0) { ERC223ReceivingContract receiver = ERC223ReceivingContract(to); bytes memory empty; receiver.tokenFallback(msg.sender, value, empty); } Transfer(msg.sender, to, value, empty); } function balanceOf(address _owner) constant returns (uint balance) { return balances[_owner]; } } |
В ERC223 функцию transfer с двумя параметрами оставили для обратной совместимости с ERC20. Ее реализация отличается от transfer с тремя параметрами только тем, что третий параметр заменяется на пустое значение.
Функция transfer теперь получает размер кода по адресу получателя. Если размер кода больше нуля, то получатель не просто адрес, а контракт. И в этом случае пытаемся вызвать функцию transferFallback.
А что передаётся или можно передавать в этом третьем параметре — bytes data?
Спасибо!
В ERC223 об этом прямо не сказано. Но судя по всему это дополнительные данные к транзакции. Т.е. поле используется на ваше усмотрение. Например, можно использовать как описание за что был платеж. Может быть равно нулю.
Добрый день. Интересует вопрос о пробросе исключений с помощью require: можно ли выводить кастомное сообщение в исключении? Чтобы покупатель токенов знал в чем его ошибка?
Сам бы с удовольствием пользовался. Но такой возможности, к сожалению, нет.
Спасибо за ответ. Очень жаль, конечно 🙁 Этого и правда сильно не хватает. Ну ладно, хоть пускай пока так.
Не совсем понял, почему при использовании transfer мы сначала изменяем значения баланса, а лишь затем проверяем куда были отправлены токены и при необходимости делаем возврат. Почему сперва не проверить адресата и лишь затем отправлять токены?
Заранее спасибо.
Потому что если мы сначала вызовем tokenFallback а потом отправим, то при работе tokenFallback не сможет оперировать с отправленными токенами. А где вы возврат увидели?
А что если вообще без tokenFallback. Если мы видим, что пользователь хочет отправить токены на адрес контракта, то просто не проводим операцию.
Мне показалось, что tokenFallback — это и есть возврат с адреса контракта или я не так понял?
tokenFallback это функция другого контракта, которая вызывается, чтобы оповестить другой контракт о поступлении средств (контракты работают только если у них кто-то вызывает функцию). Иначе другой контракт никак не отреагирует на прием средств. Соответственно если по адресу приема нет контракта, то мы все равно должны отправить средства. А в Вашем коде отправка только если на адресе нет контракта. Что не корректно. Стандарт именно для этого и сделан, чтобы другие контракты как-то реагировали на прием.
Хотя в целом Ваша мысль ясна — не отправлять на не поддерживающие стандарт контракты. Но мы тогда ограничим контракт и потеряем обратную совместимость. Что очень плохою
Скажите а если я напишу контракт на ERC223
смогут ли пользователи кошельков Ethereum Wallet и Mist
отправлять мне на контракт эфир и видеть балансы своих токенов в кошельках?
Искал эту статью ⠀
Спасибо