Контракты кошельков
Возможно, вы слышали о разных версиях кошельков на блокчейне TON. Но что значат эти версии и чем различаются?
В этом тексте мы рассмотрим разные версии и модификации TON-кошельков.
Before we start, there are some terms and concepts that you should be familiar with to fully understand the article:
- Управление сообщениями, поскольку это основная функциональность кошельков.
- Язык FunC, потому что мы будем активно обращаться к реализациям, написанным на этом языке.
Общая концепция
Для начала стоит осозна ть, что в экосистеме TON кошельки не являются какой-то отдельной сущностью. Это просто смарт-контракты, состоящие из кода и данных, и в этом смысле они равны любому другому актору (то есть смарт-контракту) в TON.
Как и любой смарт-контракт, включая написанные вами, кошельки могут получать внешние и внутренние сообщения, отправлять внутренние сообщения и логи, а также предоставлять get-методы
.
Так что вопрос в следующем: какую именно функциональность они предоставляют и чем различаются их версии?
Можно рассматривать каждую версию кошелька как реализацию смарт-контракта, предоставляющую стандартный внешний интерфейс, позволяющий различным внешним клиентам взаимодействовать с кошельками одинаковым образом. Вы можете найти эти реализации на языках FunC и Fift в основном монорепозитории TON:
Стандартные кошельки
Хеши контрактов кошельков
Здесь вы можете найти текущие хеши различных версий кода контрактов кошельков. Подробные спецификации каждого контракта кошелька приведены ниже в тексте, а также на странице ContractSources.md.
Показать таблицу хешей контрактов кошельков
Версия контракта | Хеш |
---|---|
walletv1r1 | oM/CxIruFqJx8s/AtzgtgXVs7LEBfQd/qqs7tgL2how= |
walletv1r2 | 1JAvzJ+tdGmPqONTIgpo2g3PcuMryy657gQhfBfTBiw= |
walletv1r3 | WHzHie/xyE9G7DeX5F/ICaFP9a4k8eDHpqmcydyQYf8= |
walletv2r1 | XJpeaMEI4YchoHxC+ZVr+zmtd+xtYktgxXbsiO7mUyk= |
walletv2r2 | /pUw0yQ4Uwg+8u8LTCkIwKv2+hwx6iQ6rKpb+MfXU/E= |
walletv3r1 | thBBpYp5gLlG6PueGY48kE0keZ/6NldOpCUcQaVm9YE= |
walletv3r2 | hNr6RJ+Ypph3ibojI1gHK8D3bcRSQAKl0JGLmnXS1Zk= |
walletv4r1 | ZN1UgFUixb6KnbWc6gEFzPDQh4bKeb64y3nogKjXMi0= |
walletv4r2 | /rX/aCDi/w2Ug+fg1iyBfYRniftK5YDIeIZtlZ2r1cA= |
walletv5r1 | IINLe3KxEhR+Gy+0V7hOdNGjDwT3N9T2KmaOlVLSty8= |
Примечание: Эти хеши также можно найти в эксплорерах.
Кошелёк V1
Это самый простой вариант. Он позволяет только отправлять до четырёх транзакций за раз и не проверяет ничего, кроме вашей подписи и seqno.
Исходный код кошелька:
Эта версия даже не используется в стандартных приложениях, потому что у неё есть несколько серьёзных недостатков:
- Нет простого способа запросить у контракта seqno и публичный ключ.
- Нет проверки
valid_until
, позволяющей быть уверенными, что транзакция не окажется подтверждена слишком поздно.
Первая проблема была исправлена в версиях V1R2
и V1R3
. Буква R
означает ревизию. Обычно ревизии — это небольшие обновления, которые добавляют только get-методы; вы можете найти их в истории изменений new-wallet.fif. Здесь и далее мы будем рассматривать только последние ревизии.
Тем не менее, поскольку каждая последующая версия наследует функциональность предыдущей, мы все равно рассмотрим первую, так как это поможет нам с более поздними.
Официальные хеши кода
Версия контракта | Хеш |
---|---|
walletv1r1 | oM/CxIruFqJx8s/AtzgtgXVs7LEBfQd/qqs7tgL2how= |
walletv1r2 | 1JAvzJ+tdGmPqONTIgpo2g3PcuMryy657gQhfBfTBiw= |
walletv1r3 | WHzHie/xyE9G7DeX5F/ICaFP9a4k8eDHpqmcydyQYf8= |
Структура постоянной памяти
- seqno: 32-битный порядковый номер.
- public-key: 256-битный публичный ключ.
Структура тела внешнего сообщения
- Данные:
- signature: 512-битная подпись в формате Ed25519.
- msg-seqno: 32-битный порядковый номер.
- (0-4) mode: до четырёх 8-битных целых чисел, определяющих режим отправки для каждого из сообщений на отправку.
- До 4 ссылок на ячейки, содержащие сообщения:
Как вы можете видеть, основная функциональность кошелька — это обеспечение безопасного способа связи с блокчейном TON из внешнего мира. Механизм seqno
защищает от атак повторного воспроизведения, а подпись Ed25519
обеспечивает авторизованный доступ к функциональности кошелька. Мы не будем подробно останавливаться на каждом из этих механизмов, так как они подробно описаны на странице документации внешнего сообщения и довольно распространены среди с март-контрактов, получающих внешние сообщения. Полезная нагрузка сообщения состоит из ссылок на ячейки (не более 4) и соответствующего количества режимов, которые будут напрямую переданы методу send_raw_message(cell msg, int mode).
Обратите внимание, что кошелёк никак не проверяет внутренние сообщения, которые вы отправляете через него. Ответственность за сериализацию данных в соответствии со структурой внутреннего сообщения лежит на программисте (т. е. на внешнем клиенте).
Коды возврата
Код возврата | Описание |
---|---|
0x21 | Проверка seqno не пройдена, сработала защита от повторного воспроизведения |
0x22 | Проверка подписи Ed25519 не пройдена |
0x0 | Стандартный код возврата при успешном выполнении. |
Обратите внимание, что у TVM есть стандартные коды возврата (0x0
— один из них), поэтому вы можете столкнуться и с один из них: например, если у вас закончится газ, вы получите код 0xD
.
Get-методы
- int seqno() возвращает текущее хранимое значение seqno.
- int get_public_key() возвращает текущий хранимый публичный ключ.
Кошелёк V2
Исходный код кошелька:
Эта версия добавляет параметр valid_until
, позволяющий установить временное ограничение для транзакции, если вы не хотите, чтобы она могла оказаться подтверждена слишком поздно. В первой ревизии также нет get-метода для публичного ключа, он добавлен в V2R2
.
Все отличия по сравнению с предыдущей версией — следствие добавления valid_until
. Был добавлен новый код возврата 0x23
, сообщающий о неудаче проверки valid_until. Кроме того, в структуру тела внешнего сообщения было добавлено новое поле в формате UNIX-времени, устанавливающее ограничение по времени для транзакции. Все get-методы остались прежними.
Официальные хеши кода
Версия контракта | Hash |
---|---|
walletv2r1 | XJpeaMEI4YchoHxC+ZVr+zmtd+xtYktgxXbsiO7mUyk= |
walletv2r2 | /pUw0yQ4Uwg+8u8LTCkIwKv2+hwx6iQ6rKpb+MfXU/E= |
Структура тела внешнего сообщения
- Данные:
- signature: 512-битная подпись Ed25519.
- msg-seqno: 32-битный порядковый номер.
- valid-until: 32-битное целое число с меткой UNIX-времени.
- (0-4) mode: до четырёх 8-битных целых чисел, определяющих режим отправки для каждого сообщения.
- До 4 ссылок на ячейки, содержащие сообщения.
Кошелёк V3
В этой версии появился параметр subwallet_id
, позволяющий создавать несколько кошельков с использованием одного и того же публичного ключа (таким образом, у вас может быть несколько кошельков с всего лишь одной сид-фразой). Как и прежде, ревизия V3R2
добавляет только get-метод для публичного ключа.
Исходный код кошелька:
По сути, subwallet_id
— это просто число, добавляемое в состояние контракта при его развёртывании. Поскольку адрес контракта в TON является хешем его состояния и кода, при использовании другого subwallet_id
адрес кошелька также окажется другим. На момент сочинения этого текста версия является наиболее используемой. Она подходит для большинства сценариев использования, при этом оставаясь чистой, простой и в основном совпадающей с предыдущими версиями. Все get-методы остались прежними.
Официальные хеши кода
Версия контракта | Hash |
---|---|
walletv3r1 | thBBpYp5gLlG6PueGY48kE0keZ/6NldOpCUcQaVm9YE= |
walletv3r2 | hNr6RJ+Ypph3ibojI1gHK8D3bcRSQAKl0JGLmnXS1Zk= |
Структура постоянной памяти
- seqno: 32-битный порядковый номер.
- subwallet: 32-битный идентификатор субкошелька.
- public-key: 256-битный публичный ключ.
Структура тела внешнего сообщения
- Данные:
- signature: 512-битная подпись Ed25519.
- subwallet-id: 32-битный идентификатор субкошелька.
- msg-seqno: 32-битный порядковый номер.
- valid-until: 32-битное целое число с меткой UNIX-времени.
- (0-4) mode: до четырёх 8-битных целых чисел, определяющих режим отправки для каждого сообщения.
- До 4 ссылок на ячейки, содержащие сообщения.
Коды возврата
Код возврата | Описание |
---|---|
0x23 | Проверка valid_until не пройдена; попытка подтверждения транзакции слишком поздно |
0x23 | Проверка подписи Ed25519 не пройдена |
0x21 | Проверка seqno не пройдена; сработала защита от повторного воспроизведения |
0x22 | subwallet_id не соответствует сохранённому |
0x0 | Стандартный код возврата при успешном выполнении. |
Кошелёк V4
Эта версия сохраняет всю функциональность предыдущих, но также добавляет очень мощную сущность: плагины
(plugins).
Исходный код кошелька:
Это позволяет разработчикам реализовывать сложную логику, которая действует совместно с кошельком пользователя. Например, децентрализованное приложение может взимать небольшую оплату за определённые возможности посуточно. В этом случае пользователю необходимо будет установить плагин в своём кошельке, подписав транзакцию. Затем этот плагин ежедневно будет отправлять монеты на адрес наз начения по запросу внешним сообщением.
Официальные хеши кода
Версия контракта | Hash |
---|---|
walletv4r1 | ZN1UgFUixb6KnbWc6gEFzPDQh4bKeb64y3nogKjXMi0= |
walletv4r2 | /rX/aCDi/w2Ug+fg1iyBfYRniftK5YDIeIZtlZ2r1cA= |
Плагины
По сути, плагины — это другие смарт-контракты в TON, разработчики могут реализовывать их как считают нужным. По отношению к кошельку они представляют собой просто адреса смарт-контрактов, хранящиеся в словаре в постоянной памяти кошелька. Этим плагинам разрешено запрашивать средства и удалять себя из «списка разрешённых», отправляя внутренние сообщения в кошелек.