Створення і використання

Генерація Коду Спеціального Multisig Контракту

Перш, ніж продовжити, переконайтеся в тому, що Ви виконали всі кроки з налаштування.

Щоб побачити список підтримуваних контрактів і дій, введіть наступну команду:stack exec -- lorentz-contract-multisig --help

Ви також можете використовувати інструмент lorentz-contract-multisig для генерації коду Michelson для контракту Multisig, який Ви бажаєте створити, з функцією прийому тільки одного параметра, обраного Вами.

Припустимо, ми хочемо згенерувати контракт multisig, який приймає допустимим аргументом виключно nat. Ми можемо це зробити застосувавши наступну print-specialized команду:

$ stack exec -- lorentz-contract-multisig GenericMultisig print-specialized --parameterType 'nat' --oneline
parameter (pair (pair (nat :counter) (or :action (pair nat (contract nat)) (pair (nat :threshold) (list :keys key)))) (list :sigs (option signature)));storage (pair nat (pair nat (list key)));code { CAST (pair (pair (pair nat (or (pair nat (contract nat)) (pair nat (list key)))) (list (option signature))) (pair nat (pair nat (list key))));DUP;CAR;DIP { CDR };DIP { };PUSH mutez 0;AMOUNT;COMPARE;EQ;IF { } { PUSH string "Some tokens were sent to this contract outside of a unit entry point.";FAILWITH };SWAP;DUP;DIP { SWAP };DIP { DUP;CAR;DIP { CDR };DUP;SELF;ADDRESS;CHAIN_ID;PAIR;PAIR;PACK;DIP { DUP;CAR;DIP { CDR };DIP { SWAP } };SWAP };DUP;CAR;DIP { CDR };DIP { SWAP };COMPARE;EQ;IF { } { PUSH string "Counters do not match.";FAILWITH };DIP { SWAP };DUP;CAR;DIP { CDR };DIP { PUSH nat 0;SWAP;ITER { DIP { SWAP };SWAP;IF_CONS { IF_NONE { SWAP;DROP } { SWAP;DIP { SWAP;DIP { DIP { DIP { DUP };SWAP } };DIP 2 { DUP };DIG 2;DIP { CHECK_SIGNATURE };SWAP;IF { DROP } { FAILWITH };PUSH nat 1;ADD } } } { FAILWITH };SWAP } };COMPARE;LE;IF { } { PUSH string "Quorum not present";FAILWITH };IF_CONS { FAILWITH } { };DROP;DIP { DUP;CAR;DIP { CDR };PUSH nat 1;ADD;PAIR };IF_LEFT { DIP { };SWAP;DIP { DUP;CAR;DIP { CDR };DIP { DIP { NIL operation };PUSH mutez 0 };TRANSFER_TOKENS;CONS };SWAP } { DIP { CAR };SWAP;PAIR;NIL operation };PAIR };

Скрипт lorentz-contract-multisig дозволив нам згенерувати контракт Michelson. Цей самий скрипт можна застосовувати для різних допустимих типів Michelson.

У випадку, коли ми генеруємо контракт використовуючи map зі string в int, команда виглядатиме наступним чином:

$ stack exec -- lorentz-contract-multisig GenericMultisig print-specialized \
--parameterType 'map string int' --oneline
parameter (pair (pair (nat :counter) (or :action (pair (map string int) (contract (map string int))) (pair (nat :threshold) (list :keys key)))) (list :sigs (option signature)));storage (pair nat (pair nat (list key)));code { CAST (pair (pair (pair nat (or (pair (map string int) (contract (map string int))) (pair nat (list key)))) (list (option signature))) (pair nat (pair nat (list key))));DUP;CAR;DIP { CDR };DIP { };PUSH mutez 0;AMOUNT;COMPARE;EQ;IF { } { PUSH string "Some tokens were sent to this contract outside of a unit entry point.";FAILWITH };SWAP;DUP;DIP { SWAP };DIP { DUP;CAR;DIP { CDR };DUP;SELF;ADDRESS;CHAIN_ID;PAIR;PAIR;PACK;DIP { DUP;CAR;DIP { CDR };DIP { SWAP } };SWAP };DUP;CAR;DIP { CDR };DIP { SWAP };COMPARE;EQ;IF { } { PUSH string "Counters do not match.";FAILWITH };DIP { SWAP };DUP;CAR;DIP { CDR };DIP { PUSH nat 0;SWAP;ITER { DIP { SWAP };SWAP;IF_CONS { IF_NONE { SWAP;DROP } { SWAP;DIP { SWAP;DIP { DIP { DIP { DUP };SWAP } };DIP 2 { DUP };DIG 2;DIP { CHECK_SIGNATURE };SWAP;IF { DROP } { FAILWITH };PUSH nat 1;ADD } } } { FAILWITH };SWAP } };COMPARE;LE;IF { } { PUSH string "Quorum not present";FAILWITH };IF_CONS { FAILWITH } { };DROP;DIP { DUP;CAR;DIP { CDR };PUSH nat 1;ADD;PAIR };IF_LEFT { DIP { };SWAP;DIP { DUP;CAR;DIP { CDR };DIP { DIP { NIL operation };PUSH mutez 0 };TRANSFER_TOKENS;CONS };SWAP } { DIP { CAR };SWAP;PAIR;NIL operation };PAIR };

Ви можете порівняти обидва виходи, що представлені вище, і побачити, куди був вставлений новий тип.

Якщо ми спробуємо згенерувати контракт використовуючи підтримуваний тип, отримаємо помилку парсингу. Інструмент lorentz-contract-multisig виконує перевірку відповідності типів за Вас.

$ stack exec -- lorentz-contract-multisig GenericMultisig print-specialized \
--parameterType 'not-a-type' --oneline
ParseErrorBundle {bundleErrors = FancyError 0 (fromList [ErrorCustom UnknownTypeException]) :| [], bundlePosState = PosState {pstateInput = "not-a-type", pstateOffset = 0, pstateSourcePos = SourcePos {sourceName = "parameter", sourceLine = Pos 1, sourceColumn = Pos 1}, pstateTabWidth = Pos 8, pstateLinePrefix = ""}}
CallStack (from HasCallStack):
error, called at src/Lorentz/Contracts/GenericMultisig/Parsers.hs:246:29 in lorentz-contract-multisig-0.1.0.1-7nDq5hWdrcbHFov64Ydo4r:Lorentz.Contracts.GenericMultisig.Parsers

Створення початкового сховища

Зверніть увагу: дана секція використовує такі bash функції

Generic Multisig позволяет нам установить администраторов контракта (signerKeys) и количество этих администраторов, которое необходимо для подписи (threshold). На момент написания, инструмент командной строки разрешает делать администраторами только неявные учетные записи tz1, хотя контракт разрешает также учетные записи, созданные KT1.

Generic Multisig дозволяє нам встановити адміністраторів контракту (signerKeys) і кількість цих адміністраторів, яке необхідно для підпису (threshold). На момент написання, інструмент командного рядка дозволяє робити адміністраторами тільки неявні облікові записи tz1, хоча контракт дозволяє також облікові записи, створені KT1.

Щоб згенерувати Майкельсон для початкового зберігання, наприклад для двох адмінів:

$ stack exec -- lorentz-contract-multisig GenericMultisig init-specialized \
--threshold 1 --signerKeys "[\"$(get_public_key bob)\",\"$(get_public_key alice)\"]"
Pair 0 (Pair 1 { "edpkuPTVBFtbYd6gZWryXypSYYq6g7FvyucwphoU78T1vmGkbhj6qb"; "edpkvCHgVArnZo9RTP4P6euLTyhE89u73CYjBgsP4wEJbj4quao9oR" })

Зверніть увагу, що для правильного аналізу списку signerKeys ви повинні уникати лапок і розділяти їх комами і без пробілів.

У наведеній вище команді ми додали двох можливих підписують осіб і встановили поріг 1, тому, якщо ми инициализируем контракт з декількома підписами з цим сховищем, всі транзакції в ньому повинні бути підписані хоча б одним з двох адміністраторів, щоб список для транзакції став дійсним.

Якщо threshold встановлений вище, ніж кількість адміністраторів, які можуть підписувати, видається помилка, оскільки неможливо мати більше підписів адміністраторів, ніж зазначено в списку signerKeys:

$ stack exec -- lorentz-contract-multisig GenericMultisig init-specialized \
--threshold 2 --signerKeys "[\"$(get_public_key bob)\"]"
threshold is greater than the number of signer keys
CallStack (from HasCallStack):
error, called at src/Lorentz/Contracts/GenericMultisig/CmdLnArgs.hs:302:13 in lorentz-contract-multisig-0.1.0.1-7nDq5hWdrcbHFov64Ydo4r:Lorentz.Contracts.GenericMultisig.CmdLnArgs

Створення контракту з декількома підписами зі створеним Майкельсоном

Используя команды, которые мы видели выше, теперь мы можем создать наш контракт, используя tezos-client, а также контракт и начальное хранилище, которые мы сгенерировали. Мы создадим контракт MultisigNat с двумя администраторами, Бобом и Алисой, и разрешающий только тип параметров nat.

Використовуючи команди, які ми бачили вище, тепер ми можемо створити наш контракт, використовуючи tezos-client, а також контракт і початкова сховище, які ми згенерували. Ми створимо контракт MultisigNat з двома адміністраторами, Бобом і Алісою, що дозволяє тільки тип параметрів nat.

$ tezos-client --wait none originate contract MultisigNat transferring 0 from \
$BOB_ADDRESS running "$(stack exec -- lorentz-contract-multisig GenericMultisig \
print-specialized --parameterType 'nat' --oneline)" \
--init "$(stack exec -- lorentz-contract-multisig GenericMultisig \
init-specialized --threshold 1 \
--signerKeys "[\"$(get_public_key bob)\",\"$(get_public_key alice)\"]")" \
--burn-cap 1.14
Waiting for the node to be bootstrapped before injection...
Current head: BLzWwsRQcRsp (timestamp: 2020-07-09T16:31:42-00:00, validation: 2020-07-09T16:32:10-00:00)
Node is bootstrapped, ready for injecting operations.
Estimated gas: 31880 units (will add 100 for safety)
Estimated storage: 1140 bytes added (will add 20 for safety)
Operation successfully injected in the node.
Operation hash is 'oo9o8JHvRceyiUZ8DA1U3fTi8C6Nvc5mUBHxYGKTAXQa6BAddwT'
NOT waiting for the operation to be included.
Use command
tezos-client wait for oo9o8JHvRceyiUZ8DA1U3fTi8C6Nvc5mUBHxYGKTAXQa6BAddwT to be included --confirmations 30 --branch BLzWwsRQcRspFLWG5cWZF9No5g3VSZ5jgxnuDF3omYWg7ZVbHHR
and/or an external block explorer to make sure that it has been included.
This sequence of operations was run:
Manager signed operations:
From: tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm
Fee to the baker: ꜩ0.004353
Expected counter: 623986
Gas limit: 31980
Storage limit: 1160 bytes
Balance updates:
tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm ............. -ꜩ0.004353
fees(tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU,269) ... +ꜩ0.004353
Origination:
From: tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm
Credit: ꜩ0
Script:
{ ... }
Initial storage:
(Pair 0
(Pair 1
{ "edpkuPTVBFtbYd6gZWryXypSYYq6g7FvyucwphoU78T1vmGkbhj6qb" ;
"edpkvCHgVArnZo9RTP4P6euLTyhE89u73CYjBgsP4wEJbj4quao9oR" }))
No delegate for this contract
This origination was successfully applied
Originated contracts:
KT1NUp9a8gC5xQJDi4E9hr2WRZpUxx8BQrT3
Storage size: 883 bytes
Paid storage size diff: 883 bytes
Consumed gas: 31880
Balance updates:
tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm ... -ꜩ0.883
tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm ... -ꜩ0.257
New contract KT1NUp9a8gC5xQJDi4E9hr2WRZpUxx8BQrT3 originated.
Contract memorized as MultisigNat.

Тепер ми можемо зберегти адресу контракту в змінній bash:

$ MULTISIG_NAT_ADDRESS="KT1NUp9a8gC5xQJDi4E9hr2WRZpUxx8BQrT3"

Адміністрування другого контракту за допомогою Specialized Multisig

Створення контракту Admin42

Контракт MultisigNat тепер можна використовувати для управління контрактами, які приймають в якості параметрів nat. У цьому керівництві ми збираємося використовувати приклад контракту, знайдений в репозиторії lorentz-contract-multisig, який називається Admin42. Цей контракт вимагає, щоб адміністратор взаємодіяв з ним, і приймає nat як параметр (точніше, тільки параметр 42!), Тому ми можемо використовувати контракт MultisigNat для його адміністрування.

(Додаткову інформацію по самому контракту Admin42 можна знайти в репозиторіїlorentz-contract-multisig)

Спочатку ми створимо контракт Admin42, зробивши наш контракт MultisigNat адміністратором.

$ tezos-client --wait none originate contract MultisigAdmin42 transferring 0 \
from $BOB_ADDRESS running "$(cat admin_42.tz | tr '\n' ' ')" \
--init "\"$MULTISIG_NAT_ADDRESS\"" --burn-cap 0.406
Waiting for the node to be bootstrapped before injection...
Current head: BLGqGwqVRJEd (timestamp: 2020-07-09T16:35:12-00:00, validation: 2020-07-09T16:35:38-00:00)
Node is bootstrapped, ready for injecting operations.
Estimated gas: 13516 units (will add 100 for safety)
Estimated storage: 406 bytes added (will add 20 for safety)
Operation successfully injected in the node.
Operation hash is 'op8Swwt9bYvQ58gbGPoZijJfx94tB2pbByVSco44PXuWme8oMwT'
NOT waiting for the operation to be included.
Use command
tezos-client wait for op8Swwt9bYvQ58gbGPoZijJfx94tB2pbByVSco44PXuWme8oMwT to be included --confirmations 30 --branch BLGqGwqVRJEdkEF9oborwD3BQkLKVuuWRxni6FwP155s5aqxKqQ
and/or an external block explorer to make sure that it has been included.
This sequence of operations was run:
Manager signed operations:
From: tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm
Fee to the baker: ꜩ0.001754
Expected counter: 623987
Gas limit: 13616
Storage limit: 426 bytes
Balance updates:
tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm ............. -ꜩ0.001754
fees(tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU,269) ... +ꜩ0.001754
Origination:
From: tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm
Credit: ꜩ0
Script:
{ parameter nat ;
storage address ;
code { DUP ;
CDR ;
SENDER ;
ASSERT_CMPEQ ;
DUP ;
CAR ;
PUSH nat 42 ;
ASSERT_CMPEQ ;
CDR ;
NIL operation ;
PAIR } }
Initial storage: "KT1NUp9a8gC5xQJDi4E9hr2WRZpUxx8BQrT3"
No delegate for this contract
This origination was successfully applied
Originated contracts:
KT1U2qHuZrKm7EwwRZ9j6XpZyd9y6VDhpQVo
Storage size: 149 bytes
Paid storage size diff: 149 bytes
Consumed gas: 13516
Balance updates:
tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm ... -ꜩ0.149
tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm ... -ꜩ0.257
New contract KT1U2qHuZrKm7EwwRZ9j6XpZyd9y6VDhpQVo originated.
Contract memorized as MultisigAdmin42.

І збережемо адресу контракту в змінну:

$ MULTISIG_ADMIN42_ADDRESS="KT1U2qHuZrKm7EwwRZ9j6XpZyd9y6VDhpQVo"

Підписання транзакції з одним підписувачем

Коли ми взаємодіємо з нашим контрактом MultisigNat, ми повинні включати достатню кількість підписних ключів адміністратора, щоб відповідати нашому граничному значенню. В цьому випадку у нас є два адміністратора і поріг 1, тому Боб або Аліса повинні підписати будь-яку транзакцію, яка викликає цей контракт, в іншому випадку вона буде відхилена.

Кроки для підписання:

  1. Генерація байтів

  2. Підписання байтів

  3. Збереження підпису

  4. Запуск транзакції за допомогою підпису

Давайте для початку підпишемо операцію як Аліса.

Нам знадобиться ідентифікатор ланцюжка, який ми можемо отримати з RPC:

$ tezos-client rpc get /chains/main/chain_id
"NetXjD3HPJJjmcd"

Встановимо bash змінну для ідентифікатора ланцюжка:

$ CHAIN_ID="NetXjD3HPJJjmcd"

Спочатку ми сгенерируемо байти для підпису за допомогою інструменту orentz-contract-multisig.

$ stack exec -- lorentz-contract-multisig GenericMultisig run-multisig \
--target-parameterType 'nat' --target-parameter '42' \
--target-contract "\"$MULTISIG_ADMIN42_ADDRESS\"" \
--multisig-contract "$MULTISIG_NAT_ADDRESS" --counter 0 --signatures "Nothing" \
--signerKeys "[\"$(get_public_key bob)\",\"$(get_public_key alice)\"]" --chainId $CHAIN_ID
"0x05070707070a000000049caecab90a000000160198716bd8c37c014c606841e5f7398ed70d99a6a9000707000005050707002a0a0000001601d55850d12efa417a6d53f8290f027c2650390aef00"

Давайте розберемося з цим.

  • target-parameterType: Ми вже знаємо, що наш MultisigNat і MultisigAdmin42 контракти приймають параметр типу nat.

  • target-parameter: MultisigAdmin42 дозволяє відправляти тільки значення параметра 42, тому ми передамо це як наш цільової параметр.

  • target-contract: Наша кінцева мета - відправити параметр в $MULTISIG_ADMIN42_ADDRESS, так що це наша ціль.

  • multisig-contract: Контракт з декількома підписами, керуючий нашим цільовим контрактом - це $MULTISIG_NAT_ADDRESS.

  • counter: Оскільки це перша транзакція, яку ми відправляємо через наш MultisigNat контракт, наш counter дорівнює 0. Якщо ви не знаєте правильного значення лічильника, ви можете використовувати наступну команду для отримання значення.

    stack exec -- lorentz-contract-multisig GenericMultisig get-counter-specialized --storageText "$(tezos-client get contract storage for $MULTISIG_NAT_ADDRESS)" --signerKeys "[\"$(get_public_key bob)\",\"$(get_public_key alice)\"]"
  • signatures: Зараз ми нічого не підписуємо, тому аргумент "Nothing". Ще через пару кроків ми передамо сюди список підписів.

  • signerKeys: Це той же самий список ключів, з якими ви створили контракт (в тому ж порядку!). Як бонус функція get-counter-specialized, описана в маркері counter, підтвердить, що список відкритих ключів, які у вас є, відповідає списку ключів в сховищі.

  • chainId: Це ідентифікатор ланцюжка, в який ми відправляємо. Включення його в сигнатуру запобігає атаці повторного відтворення в різних ланцюжках.

Тепер візьмемо байти, згенеровані за допомогою останньої команди, і підпишемо їх як Аліса.

$ tezos-client sign bytes \
"0x05070707070a000000049caecab90a000000160198716bd8c37c014c606841e5f7398ed70d99a6a9000707000005050707002a0a0000001601d55850d12efa417a6d53f8290f027c2650390aef00" \
for alice
Signature: edsigtczKcLhrkFsRKhp9cUPdbv19z9g9ZUmKkHXLA42UJMJDJ2nQypNK2iwzbrGM2HHDQR5cGYSpyVPctSkM8jAC1zHGEKyVGc

І збережемо підпис

$ OPERATION_SIGNATURE="edsigtczKcLhrkFsRKhp9cUPdbv19z9g9ZUmKkHXLA42UJMJDJ2nQypNK2iwzbrGM2HHDQR5cGYSpyVPctSkM8jAC1zHGEKyVGc"

Тепер ми збираємося знову використовувати інструмент lorentz-contract-multisig, але тепер ми збираємося додати наш підпис. Тут слід зазначити кілька моментів:

  • Незважаючи на те, що я відправляю $OPERATION_SIGNATURE від Аліси, я все одно можу створити транзакцію як переклад з $BOB_ADDRESS на $MULTISIG_NAT_ADDRESS. Фактично, ми могли відправити цю транзакцію з $FRED_ADDRESS, і поки у нас є правильні підписи, він буде працювати.

  • Слід зазначити синтаксис аргументу signatures. Структура повинна бути у вигляді списку, який відповідає signerKeys, тобто для кожного signerKey, в підписному листі повинен бути відповідний запис. У цьому випадку ми маємо тільки підпис Аліси. Аліса - другий відкритий ключ в списку signerKeys, коли ми структуруємо наш список підписів, ми додамо $OPERATION_SIGNATURE, яку вона підписала в якості другого запису в списку. Оскільки Боб не підписує, ми нічого не поміщаємо в його індекс у списку. Отже у нас буде "Just[Nothing,Just\"$OPERATION_SIGNATURE\"]". Якби Боб підписував, а Аліси не було б, у нас було б "Just[Just\"$OPERATION_SIGNATURE\",Nothing]". А, якби обидва підписували, у нас було б "Just[Just\"$BOB_SIGNATURE\",Just\"$ALICE_SIGNATURE\"]". Далі ми покажемо повний приклад з декількома сторонами підписання.

  • Ми повинні вказати нашу точку входу як 'mainParameter'

$ tezos-client --wait none transfer 0 from $BOB_ADDRESS to $MULTISIG_NAT_ADDRESS \
--arg "$(stack exec -- lorentz-contract-multisig \
GenericMultisig run-multisig --target-parameterType 'nat' \
--target-parameter '42' --target-contract "\"$MULTISIG_ADMIN42_ADDRESS\"" \
--multisig-contract "$MULTISIG_NAT_ADDRESS" --counter 0 \
--signatures "Just[Nothing,Just\"$OPERATION_SIGNATURE\"]" \
--signerKeys "[\"$(get_public_key bob)\",\"$(get_public_key alice)\"]" \
--chainId $CHAIN_ID)" --burn-cap 0.000001
Waiting for the node to be bootstrapped before injection...
Current head: BMUPZBFduaBY (timestamp: 2020-07-09T16:37:12-00:00, validation: 2020-07-09T16:37:28-00:00)
Node is bootstrapped, ready for injecting operations.
Estimated gas: 46362 units (will add 100 for safety)
Estimated storage: no bytes added
Operation successfully injected in the node.
Operation hash is 'ooqtqmu4MyKzS5Hw7TzBjvcS9B7KMVwQ8x846tPrLsqoXwq3BJM'
NOT waiting for the operation to be included.
Use command
tezos-client wait for ooqtqmu4MyKzS5Hw7TzBjvcS9B7KMVwQ8x846tPrLsqoXwq3BJM to be included --confirmations 30 --branch BMUPZBFduaBYE2SfjHkUK8NqfX3UVrKwCR3Q6ffMMmC3puVM5Fy
and/or an external block explorer to make sure that it has been included.
This sequence of operations was run:
Manager signed operations:
From: tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm
Fee to the baker: ꜩ0.005069
Expected counter: 623988
Gas limit: 46462
Storage limit: 0 bytes
Balance updates:
tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm ............. -ꜩ0.005069
fees(tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU,269) ... +ꜩ0.005069
Transaction:
Amount: ꜩ0
From: tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm
To: KT1NUp9a8gC5xQJDi4E9hr2WRZpUxx8BQrT3
Parameter: (Pair (Pair 0 (Left (Pair 42 "KT1U2qHuZrKm7EwwRZ9j6XpZyd9y6VDhpQVo")))
{ None ;
Some "edsigtczKcLhrkFsRKhp9cUPdbv19z9g9ZUmKkHXLA42UJMJDJ2nQypNK2iwzbrGM2HHDQR5cGYSpyVPctSkM8jAC1zHGEKyVGc" })
This transaction was successfully applied
Updated storage:
(Pair 1
(Pair 1
{ 0x00622ace8f1d06165b951d0362624033e6f6eb5650c45290ff0ddbff6055d2caa1 ;
0x00cc80ab168b04973d9e1f9d4d2248b077a9250d3bce750b2735b4818a7b9bb7d3 }))
Storage size: 883 bytes
Consumed gas: 32580
Internal operations:
Transaction:
Amount: ꜩ0
From: KT1NUp9a8gC5xQJDi4E9hr2WRZpUxx8BQrT3
To: KT1U2qHuZrKm7EwwRZ9j6XpZyd9y6VDhpQVo
Parameter: 42
This transaction was successfully applied
Updated storage: 0x0198716bd8c37c014c606841e5f7398ed70d99a6a900
Storage size: 149 bytes
Consumed gas: 13782

Підписання транзакції з двома підписувачими

Тепер, коли ми побачили, як виглядає підписання транзакції від імені Аліси, давайте подивимося, як це виглядає, коли у нас є обидві особи с правом підпису.

Кроки дуже схожі на підписання з одного стороною підписання, але повторюються для кожної сторони підписання.

Спочатку ми генеруємо нові байти. Ми не можемо використовувати байти, згенеровані на останньому кроці, тому що тепер лічильник збільшився, оскільки ми вже відправили транзакцію в контракт MultisigNat.

$ stack exec -- lorentz-contract-multisig GenericMultisig run-multisig \
--target-parameterType 'nat' --target-parameter '42' \
--target-contract "\"$MULTISIG_ADMIN42_ADDRESS\"" \
--multisig-contract "$MULTISIG_NAT_ADDRESS" --counter 1 --signatures "Nothing" \
--signerKeys "[\"$(get_public_key bob)\",\"$(get_public_key alice)\"]" --chainId $CHAIN_ID
"0x05070707070a000000049caecab90a000000160198716bd8c37c014c606841e5f7398ed70d99a6a9000707000105050707002a0a0000001601d55850d12efa417a6d53f8290f027c2650390aef00"

Тепер Аліса підпише ці нові байти, і ми збережемо підпис як ALICE_SIGNATURE.

$ tezos-client sign bytes \
"0x05070707070a000000049caecab90a000000160198716bd8c37c014c606841e5f7398ed70d99a6a9000707000105050707002a0a0000001601d55850d12efa417a6d53f8290f027c2650390aef00" \
for alice
Signature: edsigu2ay8M6gXj2LqBmc3fJ7tMDuNP8ExiCBMFjBsi3sPSFWR8SWERNaymMqAivm9aWVAWLwiqu4qYMtBKp7B7oujM8DLxC5BM
$ ALICE_SIGNATURE="edsigu2ay8M6gXj2LqBmc3fJ7tMDuNP8ExiCBMFjBsi3sPSFWR8SWERNaymMqAivm9aWVAWLwiqu4qYMtBKp7B7oujM8DLxC5BM"

І Боб зробить те ж саме. Ми збережемо його підпис як BOB_SIGNATURE

$ tezos-client sign bytes \
"0x05070707070a000000049caecab90a000000160198716bd8c37c014c606841e5f7398ed70d99a6a9000707000105050707002a0a0000001601d55850d12efa417a6d53f8290f027c2650390aef00" \
for bob
Signature: edsigtvraShNmfMppX65BDsJuaWjasWPie9qfNyTBHwGD2kyZMe7atTvm5CULseNSD4uKY2bzzGvQDq7Jks8yFp4DRdb9t5FKX4
$ BOB_SIGNATURE="edsigtvraShNmfMppX65BDsJuaWjasWPie9qfNyTBHwGD2kyZMe7atTvm5CULseNSD4uKY2bzzGvQDq7Jks8yFp4DRdb9t5FKX4"
$ tezos-client --wait none transfer 0 from $BOB_ADDRESS to $MULTISIG_NAT_ADDRESS \
--arg "$(stack exec -- lorentz-contract-multisig \
GenericMultisig run-multisig --target-parameterType 'nat' \
--target-parameter '42' --target-contract "\"$MULTISIG_ADMIN42_ADDRESS\"" \
--multisig-contract "$MULTISIG_NAT_ADDRESS" --counter 1 \
--signatures "Just[Just\"$BOB_SIGNATURE\",Just\"$ALICE_SIGNATURE\"]" \
--signerKeys "[\"$(get_public_key bob)\",\"$(get_public_key alice)\"]" --chainId $CHAIN_ID)" \
--burn-cap 0.000001
Waiting for the node to be bootstrapped before injection...
Current head: BLkZFogRt69q (timestamp: 2020-07-09T16:39:12-00:00, validation: 2020-07-09T16:39:32-00:00)
Node is bootstrapped, ready for injecting operations.
Estimated gas: 47004 units (will add 100 for safety)
Estimated storage: no bytes added
Operation successfully injected in the node.
Operation hash is 'op3zyuj5wFPxyyrLAicv99DBWxHdAWU9obAwmGPEULj5gy3bEUq'
NOT waiting for the operation to be included.
Use command
tezos-client wait for op3zyuj5wFPxyyrLAicv99DBWxHdAWU9obAwmGPEULj5gy3bEUq to be included --confirmations 30 --branch BLkZFogRt69qpkNRupifySnJfiPZTpoPTRn2SfgEDwsaK4xQCoX
and/or an external block explorer to make sure that it has been included.
This sequence of operations was run:
Manager signed operations:
From: tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm
Fee to the baker: ꜩ0.005237
Expected counter: 623989
Gas limit: 47104
Storage limit: 0 bytes
Balance updates:
tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm ............. -ꜩ0.005237
fees(tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU,269) ... +ꜩ0.005237
Transaction:
Amount: ꜩ0
From: tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm
To: KT1NUp9a8gC5xQJDi4E9hr2WRZpUxx8BQrT3
Parameter: (Pair (Pair 1 (Left (Pair 42 "KT1U2qHuZrKm7EwwRZ9j6XpZyd9y6VDhpQVo")))
{ Some "edsigtvraShNmfMppX65BDsJuaWjasWPie9qfNyTBHwGD2kyZMe7atTvm5CULseNSD4uKY2bzzGvQDq7Jks8yFp4DRdb9t5FKX4" ;
Some "edsigu2ay8M6gXj2LqBmc3fJ7tMDuNP8ExiCBMFjBsi3sPSFWR8SWERNaymMqAivm9aWVAWLwiqu4qYMtBKp7B7oujM8DLxC5BM" })
This transaction was successfully applied
Updated storage:
(Pair 2
(Pair 1
{ 0x00622ace8f1d06165b951d0362624033e6f6eb5650c45290ff0ddbff6055d2caa1 ;
0x00cc80ab168b04973d9e1f9d4d2248b077a9250d3bce750b2735b4818a7b9bb7d3 }))
Storage size: 883 bytes
Consumed gas: 33222
Internal operations:
Transaction:
Amount: ꜩ0
From: KT1NUp9a8gC5xQJDi4E9hr2WRZpUxx8BQrT3
To: KT1U2qHuZrKm7EwwRZ9j6XpZyd9y6VDhpQVo
Parameter: 42
This transaction was successfully applied
Updated storage: 0x0198716bd8c37c014c606841e5f7398ed70d99a6a900
Storage size: 149 bytes
Consumed gas: 13782

Ми успішно підписали контракт з декількома адміністраторами!

Підписання транзакції з неавторизованою стороною підписання

Якщо хтось, хто не є адміністратором, спробує підписатися, ми отримаємо помилку моделювання трансферу. Давайте спробуємо використовувати цей контракт з декількома підписами, щоб підписатися від імені Фреда.

$ stack exec -- lorentz-contract-multisig GenericMultisig run-multisig \
--target-parameterType 'nat' --target-parameter '42' \
--target-contract "\"$MULTISIG_ADMIN42_ADDRESS\"" \
--multisig-contract "$MULTISIG_NAT_ADDRESS" --counter 4 --signatures "Nothing" \
--signerKeys "[\"$(get_public_key bob)\",\"$(get_public_key fred)\"]" --chainId $CHAIN_ID
"0x05070707070a000000049caecab90a0000001601e434087b4651ce2e3132592129765f42427bde9d000707000405050707002a0a000000160122d24b94f44833a82467937ddf66a5a8960a28b200"
$ tezos-client sign bytes \
"0x05070707070a000000049caecab90a0000001601e434087b4651ce2e3132592129765f42427bde9d000707000405050707002a0a000000160122d24b94f44833a82467937ddf66a5a8960a28b200" \
for fred
Signature: edsigu3vWQjfgAH63MbXDx2Tv6j1DQ4x73Zebhvfcqg3Vw9rzaG1j6LUFPPVr9dFVySS9BPwYf5323ECRETLBcgFWyqazDcJN6z
$ FRED_SIGNATURE="edsigu3vWQjfgAH63MbXDx2Tv6j1DQ4x73Zebhvfcqg3Vw9rzaG1j6LUFPPVr9dFVySS9BPwYf5323ECRETLBcgFWyqazDcJN6z"
$ tezos-client --wait none transfer 0 from $BOB_ADDRESS to $MULTISIG_NAT_ADDRESS \
--arg "$(stack exec -- lorentz-contract-multisig \
GenericMultisig run-multisig --target-parameterType 'nat' \
--target-parameter '42' --target-contract "\"$MULTISIG_ADMIN42_ADDRESS\"" \
--multisig-contract "$MULTISIG_NAT_ADDRESS" --counter 4 \
--signatures "Just[Just\"$BOB_SIGNATURE\",Just\"$FRED_SIGNATURE\"]" \
--signerKeys "[\"$(get_public_key bob)\",\"$(get_public_key fred)\"]" --chainId $CHAIN_ID)" \
--burn-cap 0.000001
CallStack (from HasCallStack):
error, called at src/Lorentz/Contracts/GenericMultisig/CmdLnArgs.hs:397:25 in lorentz-contract-multisig-0.1.0.1-7nDq5hWdrcbHFov64Ydo4r:Lorentz.Contracts.GenericMultisig.CmdLnArgs
empty expression
Fatal error:
transfer simulation failed

Зверніть увагу, що передача не вдалася через «надано недійсний підпис». Контракт передбачає, що відкритий ключ Аліси буде перебувати в signerKeys з індексом 1, а її підпис (або Nothing) буде надана в списку підписів з індексом 1. Однак, в нашій спробі взяти під контроль контракт від імені Фреда, ми замінили її відкритий ключ і підпис. Однак контракт бачить це і не приймає виклик.

Матеріали розроблені TQ Tezos перекладені українською мовою Tezos Ukraine