Links

FA2-SmartPy

В этом руководстве показано, как взаимодействовать с «FA2-SmartPy» реализацией стандарта FA2 в некоторых распространенных сценариях использования. В первой части используются команды tezos-client для работы с основными передачами и запросами. Вторая часть идет дальше: она использует интерфейс командной строки fatoo для пакетной передачи и использует механизм «оператора» для делегирования прав передачи.

Базовое использование с tezos-client

Это предполагает, что у вас правильно настроен tezos-client для взаимодействия с Carthagenet или с «полной» песочницей.
Для этой части требуется 4 аккаунта, с несколькими импортироваными в tezos-client ꜩ . Аккаунты: administrator, originator, alice иbob.
Согласно нашему руководству по песочнице мы используем alice также как originator и administrator:
$ tezos-client import secret key alice \
unencrypted:edsk3QoqBuvdamxouPhin7swCvkQNgq4jP5KZPbwWNnwdZpSpJiEbq \
--force
tezos-client import secret key originator \
unencrypted:edsk3QoqBuvdamxouPhin7swCvkQNgq4jP5KZPbwWNnwdZpSpJiEbq \
--force
tezos-client import secret key administrator \
unencrypted:edsk3QoqBuvdamxouPhin7swCvkQNgq4jP5KZPbwWNnwdZpSpJiEbq \
--force
tezos-client import secret key bob \
unencrypted:edsk3RFfvaFaxbHx8BMtEW1rKQcPtDML3LXjNqMNLCzC3wLC1bWbAt \
--force

Получение кода Майкельсона

FA2-SmartPy использует средства метапрограммирования SmartPy для предоставления более одного контракта Майкельсона. Такие контракты также известны как «сборки». Некоторые сборки доступны по адресу https://gitlab.com/smondet/fa2-smartpy/-/tree/master/michelson, далее в руководстве будет описание различных сборок.
Скачиваем сборку «по умолчанию»:
$ wget -O fa2_default.tz \
'https://gitlab.com/smondet/fa2-smartpy/-/raw/a58e9f11/michelson/20200724-170337+0000_8cee712_contract.tz'

Создание

Создание работает так же, как и для любого контракта, нам нужен приведенный выше код, несколько ꜩ и выражение Майкельсона для инициализации хранилища. В нашем случае это должно выглядеть так:
(Pair
(Pair "<admin-pkh>" (Pair <nb-of-tokens> <ledger-big-map>))
(Pair (Pair Unit <operators-big-set>)
(Pair <paused> <tokens-big-map>)))
Ожидается, что <nb-of-tokens> является кардиналом карты <tokens-big-map>, а в <ledger-big-map> используются только «известные» токены. Чтобы правильно поддерживать все инварианты, рекомендуется инициализировать хранилище пустым и использовать точку входа %mint для заполнения контракта.
Создадим такой не приостановленный пустой контракт при установке адреса administrator:
$ tezos-client originate contract myfa2 \
transferring 0 from originator \
running fa2_default.tz \
--init '(Pair (Pair "tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb" (Pair 0 {})) (Pair (Pair Unit {}) (Pair False {})))' \
--burn-cap 10 \
--force --no-print-source
┃ Node is bootstrapped.
┃ Estimated gas: 130373 units (will add 100 for safety)
┃ Estimated storage: 4447 bytes added (will add 20 for safety)
┃ Operation successfully injected in the node.
┃ Operation hash is 'onosZKPHVN5dGy7LGKX2NV3Tyy3Dyg7qMNeGAn1Eqp7Mwx8sazk'
┃ Waiting for the operation to be included...
┃ Operation found in block: BM31KMRfkmiDDBMfaq9tCQe5TM6Xhxp3D8XseDWMynG7k81S9q8 (pass: 3, offset: 0)
...
┃ tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb ... -ꜩ0.257
┃ New contract KT1Wf2sNVoosmXZqXEppsPZkS4BNAUL7hjTL originated.
┃ The operation has only been included 0 blocks ago.
┃ We recommend to wait more.
┃ Use command
┃ tezos-client wait for onosZKPHVN5dGy7LGKX2NV3Tyy3Dyg7qMNeGAn1Eqp7Mwx8sazk to be included --confirmations 30 --branch BMHcbMLmK3avi1ntw9rtcMgyPFjzyUxXhf5a8zDdjKM8eqJHenx
┃ and/or an external block explorer.
┃ Contract memorized as myfa2.

Выпуск

Здесь мы хотим сделать перевод в качестве administrator, установленного в предыдущем разделе.
Точка входа для выпуска не имеет жесткой стандартизации в спецификации FA2, для fa2-smartpy она должна выглядеть так:
(Pair (Pair "<address>" <amount>) (Pair "<token-symbol>" <token-id>))
Сборка по умолчанию предполагает, что идентификаторы токенов являются последовательными натуральными числами (0, 1, 2, ...), если из-за какого-то конкретного ограничения пользователю требуются произвольные идентификаторы токенов, в FA2-SmartPy есть опция сборки для создания такого контракта ( см. документацию).
Например, давайте, как administrator, выпустим 100 TK0 токенов на счет alice:
$ tezos-client transfer 0 from administrator to myfa2 \
--entrypoint mint \
--arg '(Pair (Pair "tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb" 100) (Pair "TK0" 0))' \
--burn-cap 3
┃ Node is bootstrapped.
┃ Estimated gas: 113946 units (will add 100 for safety)
┃ Estimated storage: 163 bytes added (will add 20 for safety)
┃ Operation successfully injected in the node.
┃ Operation hash is 'onpcARPLVMjXqRfjFxyaZFGnpbCdsP2uSVKQwMiBHie4ujRf7fe'
┃ Waiting for the operation to be included...
┃ Operation found in block: BMCwBfn9B2E5zmrNfAu3z4rwoTo3h2DhDjTFgsn4BvTB21Xguff (pass: 3, offset: 0)
...
┃ Consumed gas: 113946
┃ Balance updates:
┃ tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb ... -ꜩ0.163
┃ The operation has only been included 0 blocks ago.
┃ We recommend to wait more.
┃ Use command
┃ tezos-client wait for onpcARPLVMjXqRfjFxyaZFGnpbCdsP2uSVKQwMiBHie4ujRf7fe to be included --confirmations 30 --branch BM31KMRfkmiDDBMfaq9tCQe5TM6Xhxp3D8XseDWMynG7k81S9q8
┃ and/or an external block explorer.

Перевод

Точка входа передачи в FA2 «группируется» на двух уровнях, т.е. один контрактный вызов содержит список элементов передачи, каждый элемент передачи является «адресом отправителя» и списком исходящих транзакций:
{
Pair "<from-1>" {Pair "<to-1>" (Pair <token-id-1> <amount-1>)} ;
Pair "<from-2>" {Pair "<to-2>" (Pair <token-id-2> <amount-2>) ; Pair "<to-3>" (Pair <token-id-3> <amount-3>)} ;
...
}
Здесь мы, как alice, переводим 5 из наших 100 TK0 на аккаунт bob:
$ tezos-client transfer 0 from alice to myfa2 \
--entrypoint transfer \
--arg '{ Pair "tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb" {Pair "tz1aSkwEot3L2kmUvcoxzjMomb9mvBNuzFK6" (Pair 0 5)} }' \
--burn-cap 3
┃ Node is bootstrapped.
┃ Estimated gas: 116015 units (will add 100 for safety)
┃ Estimated storage: 67 bytes added (will add 20 for safety)
┃ Operation successfully injected in the node.
┃ Operation hash is 'ontGCqsFh1uSDp5vmucU6EJxkivXw6bto2DN8LRekhXdo6WSTjK'
┃ Waiting for the operation to be included...
┃ Operation found in block: BLgT1CrszWaeEnxo4ncHWHwRZ1g39ig1NxT2zQB8AtCaFKhijnn (pass: 3, offset: 0)
┃ This sequence of operations was run:
...
┃ Consumed gas: 116015
┃ Balance updates:
┃ tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb ... -ꜩ0.067
┃ The operation has only been included 0 blocks ago.
┃ We recommend to wait more.
┃ Use command
┃ tezos-client wait for ontGCqsFh1uSDp5vmucU6EJxkivXw6bto2DN8LRekhXdo6WSTjK to be included --confirmations 30 --branch BMCwBfn9B2E5zmrNfAu3z4rwoTo3h2DhDjTFgsn4BvTB21Xguff
┃ and/or an external block explorer.

Получение баланса вне сети

В качестве примера взаимодействия с big-картами в хранилище контрактов с помощью Michelson и tezos-client мы получаем баланс Алисы в токенах TK0.
Нам нужен скрипт, который принимает тип хранилища контракта в качестве параметра (буквально копирует и вставляет) и использует Майкельсон для извлечения значения в карту %ledger; в этом случае мы просто отображаем его с инструкцией FAILWITH, но можно было бы сделать гораздо больше, включая помещение в память (оставлено как упражнение для читателя ☺). Сохраним его как get-balance.tz:
parameter
(pair (pair (address %administrator)
(pair (nat %all_tokens) (big_map %ledger (pair address nat) nat)))
(pair (pair (unit %version_20200724_tzip_a57dfe86_contract)
(big_map %operators (pair (address %owner) (address %operator)) unit))
(pair (bool %paused)
(big_map %tokens
nat
(pair (nat %token_id)
(pair (string %symbol)
(pair (string %name) (pair (nat %decimals) (map %extras string string))))))))) ;
storage unit;
code
{
CAR ; # Get parameter
CAR ; # Get the pair (admin , _)
CDR ; # Get the pair (all_token, ledger)
CDR ; # Get %ledger
PUSH (pair address nat) (Pair "tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb" 0);
GET ; # Get the value in the ledger at the above key
FAILWITH
};
В этом случае мы ожидаем сбоя команды tezos-client, поскольку мы хотим прочитать сообщение об ошибке:
$ tezos-client run script get-balance.tz on storage Unit \
and input \
"$(tezos-client get contract storage for myfa2)"
...
20: GET ; # Get the value in the ledger at the above key
21: FAILWITH
22: };
‖ At line 21 characters 4 to 12,
‖ script reached FAILWITH instruction
‖ with (Some 95)
‖ Fatal error:
‖ error running script
Мы можем отчетливо видеть в значении ошибки (переданном в FAILWITH), что баланс aliceсоставляет 95 TK0 (100 выпущено минус 5 переведено в аккаунт bob).

Приложение fatoo

Получение и настройка клиента

В этом разделе мы используем интерфейс командной строки fatoo для некоторых сборок FA2-SmartPy. Вам нужно установить fatoo по вашему $PATH, или вы можете использовать Docker:
$ fatoo --version
# or:
docker run -it --rm --entrypoint fatoo registry.gitlab.com/smondet/fa2-smartpy:a58e9f11-run --version
В приложении fatoo есть много команд, см. fatoo [subcommand] --help. В то же время он находится в стадии разработки, поэтому не стесняйтесь отправлять вопросы и запросы функций в основном репозитории.
Для настройки могут использоваться две переменные среды:
  • fatoo_root_path: логи, вывод
  • fatoo_client: более важный - это URI, описывающий, как настроить tezos-client и взаимодействовать с узлом
Смотрите команду fatoo show-client-uri-documentation:
URI следует обычному шаблону: <scheme>://<host>:<port>/<path>?<options>:
  • <scheme> может быть http или http (--tls вариант);
  • <host>:<port> определяет подключение к узлу;
  • <path> это закрытый ключ (URI) для учетной записи «спонсора», используется для оплаты горючего и хранения
Доступные <options> это:
  • bake=true: используйте аккаунт funder запекать блоки после операций инъекции (полезно для «ручных» песочниц);
  • wait=<INT>: установите опцию --wait для tezos-client (сколько блоков нужно ждать после инъекции операции);
  • command=<STRING>: используйте альтернативную команду для tezos-client.
См., например, текущее значение по умолчанию: http://:2020/unencrypted:edsk3S7mCwuuMVS21jsYTczxBU4tgTbQp98J3YmTGcstuUxsrZxKYd?bake=true.
Предполагая, что мы используем песочницу, мы можем настроить клиента, используя закрытый ключ alice следующим образом:
export fatoo_client='http://:20000/unencrypted:edsk3QoqBuvdamxouPhin7swCvkQNgq4jP5KZPbwWNnwdZpSpJiEbq?wait=0'
# Or, for docker, use:
alias fatoo='docker run -it -u "$UID" --network host -v "$PWD:/work" -w /work --rm -e fatoo_client="http://:20000/unencrypted:edsk3QoqBuvdamxouPhin7swCvkQNgq4jP5KZPbwWNnwdZpSpJiEbq?wait=0" --entrypoint fatoo registry.gitlab.com/smondet/fa2-smartpy:a58e9f11-run'
В приложении есть подкоманда client, которая просто правильно вызывает tezos-client, их настройку можно проверить с помощью:
$ fatoo client bootstrapped
┃ Node is bootstrapped.

Настройка аккаунтов

Здесь мы создаем четыре пары ключей из мнемонических семян, которые будут использоваться в следующих разделах:
$ fatoo account-of-seed \
"the-only-administrator-of-the-contract" \
--output admin.csv
fatoo account-of-seed \
"the-0th-aka-first-owner" \
--output owner0.csv
fatoo account-of-seed \
"ready-owner-one" \
--output owner1.csv
fatoo account-of-seed \
"this-is-a-potential-token-owner-too" \
--output owner2.csv
Полученные CSV имеют тот же формат, что и flextesa, они содержат: <phrase>,<pk>,<pkh>,<sk>. См., например:
$ echo "Public key hash: $(cut -d, -f 3 admin.csv)"
echo "Secret key: $(cut -d, -f 4 admin.csv)"
┃ Public key hash: tz1ZnxqPNMXyiZLTANYJLJ9ZTBpQ5Qu16BXe
┃ Secret key: unencrypted:edsk3ZAm4BwNkG2uUmCcA64BadPWuwNt16zZisnfcQEuvyStaBa6oG
Установим имена для всего этого:
$ export admin_pkh="$(cut -d, -f 3 admin.csv)"
export admin_sk="$(cut -d, -f 4 admin.csv)"
export owner0_pkh="$(cut -d, -f 3 owner0.csv)"
export owner0_sk="$(cut -d, -f 4 owner0.csv)"
export owner1_pkh="$(cut -d, -f 3 owner1.csv)"
export owner1_sk="$(cut -d, -f 4 owner1.csv)"
export owner2_pkh="$(cut -d, -f 3 owner2.csv)"
export owner2_sk="$(cut -d, -f 4 owner2.csv)"

Создание

Приложение содержит код для нескольких вариантов контракта:
$ fatoo list-contract-variants \
--details description --format markdown
┃ * `contract`: The default.
┃ * `dbg_contract`: The default in debug mode.
┃ * `baby_contract`: The default in Babylon mode.
┃ * `nolay_contract`: The default without right-combs.
┃ * `mutran_contract`: The default with mutez transfer entry-point.
┃ * `tokset_contract`: The default with non-consecutive token-IDs.
┃ * `perdesc_noops_contract`: The default without operators and with permissions-descriptor.
┃ * `perdesc_noops_dbg_contract`: The perdesc_noops_contract but in debug mode.
┃ * `single_contract`: The default for single-asset.
┃ * `single_mutran_contract`: The single-asset with mutez transfer entry-point.
┃ * `nft_mutran_contract`: The default in NFT mode with mutez transfer entry-point.
┃ * `lzep_contract`: The default with lazy-entry-points flag.
┃ * `lzepm_contract`: The default with lazy-entry-points-multiple flag.
┃ * `lzep_mutran_contract`: The default with mutez-transfer and lazy-entry-points flag.
┃ * `lzepm_mutran_contract`: The default with mutez-transfer and lazy-entry-points-multiple flag.
Можно сбросить код Майкельсона в файл (см. fatoo get-code --help), но в этом нет необходимости, поскольку можно напрямую создавать контракты из приложения. Давайте создадим mutran_contract, полномасштабную реализацию FA2 с дополнительной точкой входа, которая позволяет администратору переводить средства, которые потенциально могут оказаться на балансе контракта.
$ fatoo originate mutran_contract \
--administrator "${admin_pkh}" \
--output-address kt1_mutran_contract.txt
[FA2->Info]:
‖ Originations:
‖ * Success: mutran_contract (The default with mutez transfer entry-point)
‖ -> KT1MSQj5BUmuuDMqoz4jpwabAcuxmhnUjhd9
Команда сохранила адрес контракта в файле:
$ cat kt1_mutran_contract.txt
┃ KT1MSQj5BUmuuDMqoz4jpwabAcuxmhnUjhd9
И, мы уже можем отображать состояние контракта (хранилища):
$ fatoo show-storage "$(cat kt1_mutran_contract.txt)"
[FA2->Info]:
‖ Contract: KT1MSQj5BUmuuDMqoz4jpwabAcuxmhnUjhd9
‖ Balance: 0 mutez
‖ Administrator: "tz1ZnxqPNMXyiZLTANYJLJ9ZTBpQ5Qu16BXe"
‖ Status: Ready
‖ Tokens-big-map: 42
‖ Ledger-big-map: 40
‖ Operators-big-map: 41
‖ All-Tokens: None
‖ Known-Owners-and-Operators: None

Выпуск и мультитрансфер

Чтобы выпускать токены, администратор должен иметь возможность вызывать контракт в цепочке, для этого нам нужно передать как минимум несколько μꜩ на этот адрес. Можно использовать tezos-client, но у fatoo есть команда быстрого доступа для перевода с настроенной учетной записи «спонсора» (суммы указаны в mutez):
$ fatoo fund-address \
"${admin_pkh}" \
10_000_000
[FA2->Info]: Balance for tz1ZnxqPNMXyiZLTANYJLJ9ZTBpQ5Qu16BXe is now
1019633807 mutez.
Обратите внимание, что на данный момент owner0 не существует в цепочке, мы все еще выпускаем для них токены:
$ fatoo call-mint --token-id 0 --token-symbol TQ0 \
"${owner0_pkh}" 1_000_000 \
--source "${admin_sk}" \
--address "$(cat kt1_mutran_contract.txt)"
(Pair (Pair "tz1MUP3sCWTUQRG2Hon7uhRfmuYZ4guEQntS" 1000000) (Pair "TQ0" 0))
Давайте добавим еще один токен TQ1, который все еще выпускается для owner0:
$ fatoo call-mint --token-id 1 --token-symbol TQ1 \
"${owner0_pkh}" 2_000 \
--source "${admin_sk}" \
--address "$(cat kt1_mutran_contract.txt)"
(Pair (Pair "tz1MUP3sCWTUQRG2Hon7uhRfmuYZ4guEQntS" 2000) (Pair "TQ1" 1))
Посмотрим на хранилище; мы видим новые токены TQ0 и TQ1, и, поскольку мы указываем «известного владельца токена» в командной строке, мы можем видеть их балансы:
$ fatoo show-storage "$(cat kt1_mutran_contract.txt)" \
--known-address "$(cut -d, -f 3 owner0.csv)"
[FA2->Info]:
‖ Contract: KT1MSQj5BUmuuDMqoz4jpwabAcuxmhnUjhd9
‖ Balance: 0 mutez
‖ Administrator: "tz1ZnxqPNMXyiZLTANYJLJ9ZTBpQ5Qu16BXe"
‖ Status: Ready
‖ Tokens-big-map: 42
‖ Ledger-big-map: 40
‖ Operators-big-map: 41
‖ All-Tokens: 0 = TQ0.
1 = TQ1.
‖ Known-Owners-and-Operators:
‖ * Owner: "tz1MUP3sCWTUQRG2Hon7uhRfmuYZ4guEQntS" [0 ops]
‖ - Balance: 1000000 TQ0(0)
‖ - Balance: 2000 TQ1(1)
Теперь давайте заставим owner0 выполнить пакетную передачу. Во-первых, нам нужно подать немного горючего по этому адресу:
$ fatoo fund-address \
"${owner0_pkh}" \
1_000_000
[FA2->Info]: Balance for tz1MUP3sCWTUQRG2Hon7uhRfmuYZ4guEQntS is now 1704820
‖ mutez.
Затем, поскольку владелец токена может выполнять самопередачу, мы используем секретный ключ для owner1 для передачи TQ0 и TQ1 owner1 и owner2:
$ fatoo call-transfer \
"from:${owner0_pkh} to:${owner1_pkh} amount: 10 token: 0" \
"from:${owner0_pkh} to:${owner1_pkh} amount: 100 token: 1" \
"from:${owner0_pkh} to:${owner2_pkh} amount: 10 token: 1" \
--source "${owner0_sk}" \
--address "$(cat kt1_mutran_contract.txt)"
{ Pair "tz1MUP3sCWTUQRG2Hon7uhRfmuYZ4guEQntS" { Pair "tz1YYrxf529d3EYzEv5TnsiTpRCzFFB87dAS" (Pair 0 10) ; Pair "tz1YYrxf529d3EYzEv5TnsiTpRCzFFB87dAS" (Pair 1 100) ; Pair "tz1TyFYCuKrQ7A3yB4AvpoPRLacb3J6iQB9V" (Pair 1 10)}}
Затем мы можем наблюдать получившееся состояние:
$ fatoo show-storage "$(cat kt1_mutran_contract.txt)" \
--known-address "$(cut -d, -f 3 owner0.csv)" \
--known-address "$(cut -d, -f 3 owner1.csv)" \
--known-address "$(cut -d, -f 3 owner2.csv)"
[FA2->Info]:
‖ Contract: KT1MSQj5BUmuuDMqoz4jpwabAcuxmhnUjhd9
‖ Balance: 0 mutez
‖ Administrator: "tz1ZnxqPNMXyiZLTANYJLJ9ZTBpQ5Qu16BXe"
‖ Status: Ready
‖ Tokens-big-map: 42
‖ Ledger-big-map: 40
‖ Operators-big-map: 41
‖ All-Tokens: 0 = TQ0.
1 = TQ1.
‖ Known-Owners-and-Operators:
‖ * Owner: "tz1MUP3sCWTUQRG2Hon7uhRfmuYZ4guEQntS" [0 ops]
‖ - Balance: 999990 TQ0(0)
‖ - Balance: 1890 TQ1(1)
‖ * Owner: "tz1YYrxf529d3EYzEv5TnsiTpRCzFFB87dAS" [0 ops]
‖ - Balance: 10 TQ0(0)
‖ - Balance: 100 TQ1(1)
‖ * Owner: "tz1TyFYCuKrQ7A3yB4AvpoPRLacb3J6iQB9V" [0 ops]
‖ - Balance: 10 TQ1(1)

Использование операторов

Давайте создадим пару ключей для operator:
$ fatoo account-of-seed \
"youve-been-operated-ill-be-back" \
--output operator.csv
export operator_pkh="$(cut -d, -f 3 operator.csv)"
export operator_sk="$(cut -d, -f 4 operator.csv)"
Теперь мы заставим всех владельцев делегировать «оператору», см. Также командуfatoo call-update-operators --help:
$ fatoo call-update-operators \
"add@ operator: ${operator_pkh} owner: ${owner0_pkh}" \
--source "${owner0_sk}" \
--address "$(cat kt1_mutran_contract.txt)"
fatoo fund-address \
"${owner1_pkh}" \
1_000_000
fatoo call-update-operators \
"add@ operator: ${operator_pkh} owner: ${owner1_pkh}" \
--source "${owner1_sk}" \
--address "$(cat kt1_mutran_contract.txt)"
fatoo fund-address \
"${owner2_pkh}" \
1_000_000
fatoo call-update-operators \
"add@ operator: ${operator_pkh} owner: ${owner2_pkh}" \
--source "${owner2_sk}" \
--address "$(cat kt1_mutran_contract.txt)"
Мы видим, что теперь один и тот же оператор присутствует в каждой учетной записи:
$ fatoo show-storage "$(cat kt1_mutran_contract.txt)" \
--known-address "$(cut -d, -f 3 owner0.csv)" \
--known-address "$(cut -d, -f 3 owner1.csv)" \
--known-address "$(cut -d, -f 3 owner2.csv)" \
--known-address "$(cut -d, -f 3 operator.csv)"
[FA2->Info]:
‖ Contract: KT1MSQj5BUmuuDMqoz4jpwabAcuxmhnUjhd9
‖ Balance: 0 mutez
‖ Administrator: "tz1ZnxqPNMXyiZLTANYJLJ9ZTBpQ5Qu16BXe"
‖ Status: Ready
‖ Tokens-big-map: 42
‖ Ledger-big-map: 40
‖ Operators-big-map: 41
‖ All-Tokens: 0 = TQ0.
1 = TQ1.
‖ Known-Owners-and-Operators:
‖ * Owner: "tz1MUP3sCWTUQRG2Hon7uhRfmuYZ4guEQntS"
‖ - Operator: "tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85"
‖ - Balance: 999990 TQ0(0)
‖ - Balance: 1890 TQ1(1)
‖ * Owner: "tz1YYrxf529d3EYzEv5TnsiTpRCzFFB87dAS"
‖ - Operator: "tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85"
‖ - Balance: 10 TQ0(0)
‖ - Balance: 100 TQ1(1)
‖ * Owner: "tz1TyFYCuKrQ7A3yB4AvpoPRLacb3J6iQB9V"
‖ - Operator: "tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85"
‖ - Balance: 10 TQ1(1)
‖ * Owner: "tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85" [0 ops] [0 toks]
Наконец, давайте заставим operator запустить трансфер пакетного ограбления всех токенов:
$ fatoo fund-address \
"${operator_pkh}" \
2_000_000_000
[FA2->Info]: Balance for tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85 is now
2999839761 mutez.
$ fatoo call-transfer \
"from:${owner0_pkh} to:${operator_pkh} amount: 999990 token: 0" \
"from:${owner0_pkh} to:${operator_pkh} amount: 1890 token: 1" \
"from:${owner1_pkh} to:${operator_pkh} amount: 10 token: 0" \
"from:${owner1_pkh} to:${operator_pkh} amount: 100 token: 1" \
"from:${owner2_pkh} to:${operator_pkh} amount: 10 token: 1" \
--source "${operator_sk}" \
--address "$(cat kt1_mutran_contract.txt)"
{ Pair "tz1MUP3sCWTUQRG2Hon7uhRfmuYZ4guEQntS" { Pair "tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85" (Pair 0 999990) ; Pair "tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85" (Pair 1 1890)} ; Pair "tz1YYrxf529d3EYzEv5TnsiTpRCzFFB87dAS" { Pair "tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85" (Pair 0 10) ; Pair "tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85" (Pair 1 100)} ; Pair "tz1TyFYCuKrQ7A3yB4AvpoPRLacb3J6iQB9V" { Pair "tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85" (Pair 1 10)}}
Затем мы можем наблюдать результирующее состояние, в котором все балансы равны 0, за исключением operator, которому принадлежат вообще все токены:
$ fatoo show-storage "$(cat kt1_mutran_contract.txt)" \
--known-address "$(cut -d, -f 3 owner0.csv)" \
--known-address "$(cut -d, -f 3 owner1.csv)" \
--known-address "$(cut -d, -f 3 owner2.csv)" \
--known-address "$(cut -d, -f 3 operator.csv)"
[FA2->Info]:
‖ Contract: KT1MSQj5BUmuuDMqoz4jpwabAcuxmhnUjhd9
‖ Balance: 0 mutez
‖ Administrator: "tz1ZnxqPNMXyiZLTANYJLJ9ZTBpQ5Qu16BXe"
‖ Status: Ready
‖ Tokens-big-map: 42
‖ Ledger-big-map: 40
‖ Operators-big-map: 41
‖ All-Tokens: 0 = TQ0.
1 = TQ1.
‖ Known-Owners-and-Operators:
‖ * Owner: "tz1MUP3sCWTUQRG2Hon7uhRfmuYZ4guEQntS"
‖ - Operator: "tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85"
‖ - Balance: 0 TQ0(0)
‖ - Balance: 0 TQ1(1)
‖ * Owner: "tz1YYrxf529d3EYzEv5TnsiTpRCzFFB87dAS"
‖ - Operator: "tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85"
‖ - Balance: 0 TQ0(0)
‖ - Balance: 0 TQ1(1)
‖ * Owner: "tz1TyFYCuKrQ7A3yB4AvpoPRLacb3J6iQB9V"
‖ - Operator: "tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85"
‖ - Balance: 0 TQ1(1)
‖ * Owner: "tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85" [0 ops]
‖ - Balance: 1000000 TQ0(0)
‖ - Balance: 2000 TQ1(1)

Получение баланса контракта

Сборка контракта, которую мы создали выше, имеет дополнительную точку входа, чтобы иметь возможность перенести баланс контракта, например на случай, если кто-то случайно переведет μꜩ на контракт.
Итак, давайте представим, что после вышеупомянутого ограбления operator хочет публично дать чаевые/подкупить администратора(ов) контракта, пройдя через сам контракт (это может быть запутанным предлогом для включения XTZ в контракт…). Мы вызываем точку входа transfer с пустым списком элементов передачи, но с несколькими XTZ в качестве суммы:
$ tezos-client import secret key operator \
"${operator_sk}" --force
tezos-client transfer 1_000 from operator \
to "$(cat kt1_mutran_contract.txt)" \
--entrypoint transfer \
--arg '{}' --burn-cap 1
...
┃ Balance updates:
┃ tz1NkpWhHsBSZHPg2Ljz2hycRiZvcYdcyu85 ... -ꜩ1000
┃ KT1MSQj5BUmuuDMqoz4jpwabAcuxmhnUjhd9 ... +ꜩ1000
┃ The operation has only been included 0 blocks ago.
┃ We recommend to wait more.
┃ Use command
┃ tezos-client wait for op2Cibz8jgB2Djb8MEqUg8X7mfKLzywo9SuQxxR2nDMVJZMH14N to be included --confirmations 30 --branch BMWfkKTCCWBatJ3rRXjp2H7DW3cwU4dr8cmP2ddccvnFi1z4geT
┃ and/or an external block explorer.
Мы видим, что теперь fatoo показывает ненулевой баланс контракта:
$ fatoo show-storage "$(cat kt1_mutran_contract.txt)"
[FA2->Info]:
‖ Contract: KT1MSQj5BUmuuDMqoz4jpwabAcuxmhnUjhd9
‖ Balance: 1000000000 mutez
‖ Administrator: "tz1ZnxqPNMXyiZLTANYJLJ9ZTBpQ5Qu16BXe"
‖ Status: Ready
‖ Tokens-big-map: 42
‖ Ledger-big-map: 40
‖ Operators-big-map: 41
‖ All-Tokens: 0 = TQ0.
1 = TQ1.
‖ Known-Owners-and-Operators: None
Давайте заставим admin забрать эти деньги себе; точка входа называется mutez_transfer и принимает пару mutez × address:
$ tezos-client import secret key admin \
"${admin_sk}" --force
tezos-client transfer 0 from admin \
to "$(cat kt1_mutran_contract.txt)" \
--entrypoint mutez_transfer \
--arg "Pair 1000000000 \"${admin_pkh}\"" \
--burn-cap 1
...
┃ Balance updates:
┃ KT1MSQj5BUmuuDMqoz4jpwabAcuxmhnUjhd9 ... -ꜩ1000
┃ tz1ZnxqPNMXyiZLTANYJLJ9ZTBpQ5Qu16BXe ... +ꜩ1000
┃ The operation has only been included 0 blocks ago.
┃ We recommend to wait more.
┃ Use command
┃ tezos-client wait for ooQZfBpcar3jevFxpbvUkdgZPJ67kSrtQ4DAaFDUpkoNAnrV7ji to be included --confirmations 30 --branch BLKDsTiAm4sdSGiKnTuiwmyaSo6NoaVgChPPab3voLoiuvwFfRV
┃ and/or an external block explorer.
Мы видим, что баланс КТ1 обнулен:
$ fatoo show-storage "$(cat kt1_mutran_contract.txt)"
[FA2->Info]:
‖ Contract: KT1MSQj5BUmuuDMqoz4jpwabAcuxmhnUjhd9
‖ Balance: 0 mutez
‖ Administrator: "tz1ZnxqPNMXyiZLTANYJLJ9ZTBpQ5Qu16BXe"
‖ Status: Ready
‖ Tokens-big-map: 42
‖ Ledger-big-map: 40
‖ Operators-big-map: 41
‖ All-Tokens: 0 = TQ0.
1 = TQ1.
‖ Known-Owners-and-Operators: None
... и увидим, что admin стал богаче:
$ tezos-client get balance for \
"${admin_pkh}"
2019.268775
‖ Warning: the --addr --port --tls options are now deprecated; use --endpoint instead

Также читайте

Будем надеяться, в этом руководстве достаточно ясно представлена FA2-SmartPy реализация FA2 с точки зрения пользователя. Пожалуйста, поделитесь своим мнением, используя раздел проблемы репозитория. Дополнительные материалы для чтения:
Материалы разработаны TQ Tezos переведены на русский язык Tezos Ukraine