Развёртывание в сеть
Резюме: В предыдущих этапах мы разработали и протестировали наши смарт-контракты, убедившись в их корректности.
В этой части руководства мы приступим к развёртыванию ранее разработанных смарт-контрактов и рассмотрим взаимодействие с ними в блокчейне.
Адрес и начальное состояние
Мы уже знаем, что адрес — это уникальный идентификатор смарт-контракта
в сети, используемый для отправки транзакций и верификации отправителя при получении. Однако мы пока что не обсуждали, как он возникает. Стандартная формула для адресов смарт-контр актов выглядит так:
address = hash(state_init(code, data))
Адрес смарт-контракта — это хэш, вычисленный из первоначальных кода и данных смарт-контракта. Из этого простого механизма есть несколько важных следствий:
Вы уже знаете адрес
В TON любой адрес, не имеющий данных, рассматривается в состоянии несуществующий
(nonexistent
). Тем не менее, когда мы создавали новый кошелёк с помощью приложения в разделе Начало работы, мы могли получить адрес будущего смарт-контракта нашего кошелька в приложении ещё до его развёртывания и изучить его в эксплорере.
Причина в том, что создание вашей пары ключей (приватного и публичного) с помощью мнемонической фразы, где второй ключ является частью первоначальных данных смарт-контракта, делает state_init
этого контракта полностью детерминированным:
- code будет одной из стандартных реализаций ко шелька, таких как
v5r1
. - data — это
public_key
вместе с другими полями, инициализированными по умолчанию.
Это позволяет рассчитать адрес смарт-контракта будущего кошелька.
Магический элемент хранилища
В предыдущих шагах, мы сознательно не объясняли назначение ctxID
и ID
, хранимых в состоянии нашего смарт-контракта, и почему они оставались нетронутыми во всех функциях смарт-контракта. Теперь их предназначение должно стать яснее.
Вспомним, что нельзя развернуть много разных смарт-контрактов с одним и тем же state_init
— получится одинаковый контракт с одним адресом. Поэтому единственный способ предоставить всем вам один и тот же исходный код и "одинаковые" исходные данные — добавить в state_init
отдельное поле, обеспечивающее дополнительную уникальность. В случае кошелька это позволяет использовать одну и ту же пару ключей для развёртывания нескольких смарт-контрактов кошелька.
Одно, чтоб править ими всеми
Если вы уже предположили, что поле ID
является обязательным для любого смарт-контракта, есть и другая возможность, которая может изменить ваше мнение. Рассмотрим раздел инициализации ранее разработанного контракта HelloWorld
:
init(id: Int, owner: Address) {
self.id = id;
self.counter = 0;
self.owner = owner;
}
Если мы удалим поле id
из его первоначального состояния хранилища, то сможем быть уверенными, что для определённого владельца может существовать только один смарт-контракт HelloWorld
.
Этот механизм играет ключевую роль в обработке Jetton. Каждый токен, не являющийся нативным (Jetton), требует наличия собственного Jetton Wallet
для определённого владельца и, следовательно, предоставляет для него вычислимый адрес, создавая схему звезды с базовым кошельком в центре.
Реализация
Теперь, когда наши контракты полностью протестированы, мы готовы развернуть их в TON. В Blueprint
этот процесс выглядит одинаково для мейннета
и тестнета
, а также для любого из языков в этом гайде: Tact
, FunC
и Tolk
.
Шаг 1: обновить скрипт установки
Скрипты установки опираются на те же обёртки, которые вы использовали в скриптах тестирования. Мы будем использовать один общий скрипт для развёртывания обоих ранее разработанных смарт-контрактов. Обновите deployHelloWorld.ts
этим кодом:
// @version TypeScript 5.8.3
import { toNano } from '@ton/core';
import { HelloWorld } from '../wrappers/HelloWorld';
import { compile, NetworkProvider } from '@ton/blueprint';
export async function run(provider: NetworkProvider) {
const sender = provider.sender();
if (!sender.address) {
throw new Error('Sender address is required');
}
const helloWorld = provider.open(
await HelloWorld.fromInit(0n, sender.address)
);
await helloWorld.send(
sender,
{ value: toNano('0.05') },
null
);
await provider.waitForDeploy(helloWorld.address);
console.log('ID', await helloWorld.getId());
}
Шаг 2: запустите скрипт развёртывания
Вы можете запустить скрипт, введя следующую команду:
npx blueprint run deployHelloWorld
Шаг 3: выберите сеть
После этого вы увидите интерактивное меню, позволяющее выбрать сеть:
? Which network do you want to use? (Use arrow keys)
mainnet
❯ testnet
custom
Перед развёртыванием в мейннете
убедитесь, что ваши смарт-контракты соответствуют мерам безопасности. Как мы уже говорили ранее, смарт-контракт HelloWorld
им не соответствует.
Шаг 4: выберите приложение кошелька
Далее выберите способ доступа к вашему кошельку. Самый простой способ сделать это — использовать TON Connect и одно из самых популярных приложений кошельков: TonKeeper
, MyTonWallet
, или Tonhub
.
? Which wallet are you using? (Use arrow keys)
❯ TON Connect compatible mobile wallet (example: Tonkeeper)
Create a ton:// deep link
Mnemonic
? Choose your wallet (Use arrow keys)
❯ Tonkeeper
MyTonWallet
Tonhub
Наконец, отсканируйте QR-код в терминале через приложение кошелька и подключите кошелёк. После того, как вы сделали это впервые в проекте, этот шаг будет пропускаться.
Вы будете получать запрос на транзакцию в вашем приложении кошелька каждый раз, когда ваш код требует валюты для транзакции.
Шаг 5: наблюдайте ваш смарт-контракт в сети
После того, как вы подтвердите запрос в вашем кошельке и дождётесь развёртывания, вы увидите сообщение со ссылкой на просмотр вашего недавно развёрнутого смарт-контракта в эксплорере:
Contract deployed at address EQBrFHgzSwxVYBXjIYAM6g2RHbeFebJA8QUDwg4IX8CPDPug
You can view it at https://testnet.tonscan.org/address/EQBrFHgzSwxVYBXjIYAM6g2RHbeFebJA8QUDwg4IX8CPDPug
Поздравляем! Ваш собственный смарт-контракт
готов исполнять get-методы
так же, как это делал ваш кошелёк в разделе Как начать. И он может исполнять транзакции
так же, как описано в разделе о взаимодействии с блокчейном — если вы ещё его не читали, это полезно сделать, чтобы понять, как взаимодействовать со смарт-контрактами
извне блокчейна.
Использование Blueprint
и приложений кошельков — не единственный вариант. Вы можете создать сообщение со state_init самостоятельно. Более того, вы даже можете сделать это с помощью внутреннего сообщения от смарт-контракта.