Skip to content

Client: add commands for managing a multisig smart contract

This MR adds a few commands to the client to ease the interaction with the multisig smart contract written by @murbard.

Usage example in sandbox mode:

$ # Generate some keys
$ tezos-client gen keys alice
$ tezos-client gen keys bob --sig secp256k1
$ tezos-client gen keys charlie --sig ed25519

$ # Originate the multisig contract
$ tezos-client deploy multisig msig for bootstrap1 transferring 100 from bootstrap1 with threshold 2 on public keys alice bob charlie --burn-cap 100
Node is bootstrapped, ready for injecting operations.
Estimated gas: 34825 units (will add 100 for safety)
Estimated storage: 1283 bytes added (will add 20 for safety)
Operation successfully injected in the node.
Operation hash is 'opUJAVrUtzCyHKbvsFwJPcEjaLE94sEAhc1xe8tcw9JPkHtUNTq'
Waiting for the operation to be included...
Operation found in block: BLCTTB5rirYiUPKKvYRMuhZja7frTagRhUBRZQpPkY5rNxqd3v3 (pass: 3, offset: 0)
This sequence of operations was run:
  Manager signed operations:
    From: tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx
    Fee to the baker: ꜩ0.004838
    Expected counter: 1
    Gas limit: 34925
    Storage limit: 1303 bytes
    Balance updates:
      tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx ........... -ꜩ0.004838
      fees(tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx,0) ... +ꜩ0.004838
    Origination:
      From: tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx
      For: tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx
      Credit: ꜩ100
      Script:
        { parameter
            (pair (pair :payload
                     (nat %counter)
                     (or :action
                        (pair :transfer (mutez %amount) (contract %dest unit))
                        (or (option %delegate key_hash)
                            (pair %change_keys (nat %threshold) (list %keys key)))))
                  (list %sigs (option signature))) ;
          storage (pair (nat %stored_counter) (pair (nat %threshold) (list %keys key))) ;
          code { UNPAIR ;
                 SWAP ;
                 DUP ;
                 DIP { SWAP } ;
                 DIP { UNPAIR ;
                       DUP ;
                       SELF ;
                       ADDRESS ;
                       PAIR ;
                       PACK ;
                       DIP { { { DUP ; CAR @counter ; DIP { CDR } } } ; DIP { SWAP } } ;
                       SWAP } ;
                 { { DUP ; CAR @stored_counter ; DIP { CDR } } } ;
                 DIP { SWAP } ;
                 ASSERT_CMPEQ ;
                 DIP { SWAP } ;
                 { { DUP ; CAR @threshold ; DIP { CDR @keys } } } ;
                 DIP { PUSH @valid nat 0 ;
                       SWAP ;
                       ITER { DIP { SWAP } ;
                              SWAP ;
                              IF_CONS
                                { IF_SOME
                                    { SWAP ;
                                      DIP { SWAP ;
                                            DIIP { DUUP } ;
                                            { DUUUP ;
                                              DIP { CHECK_SIGNATURE } ;
                                              SWAP ;
                                              IF { DROP } { FAILWITH } } ;
                                            PUSH nat 1 ;
                                            ADD @valid } }
                                    { SWAP ; DROP } }
                                { FAIL } ;
                              SWAP } } ;
                 ASSERT_CMPLE ;
                 DROP ;
                 DROP ;
                 DIP { UNPAIR ; PUSH nat 1 ; ADD @new_counter ; PAIR } ;
                 NIL operation ;
                 SWAP ;
                 IF_LEFT
                   { UNPAIR ; UNIT ; TRANSFER_TOKENS ; CONS }
                   { IF_LEFT
                       { SET_DELEGATE ; CONS }
                       { DIP { SWAP ; CAR } ; SWAP ; PAIR ; SWAP } } ;
                 PAIR } }
        Initial storage:
          (Pair 0
                (Pair 2
                      { "edpkuakZ5gDnDb4eWf4NVDqBKHPgtgNouffLZqtUncZzzAvrknHJqv" ;
                        "sppk7ZcEgHvnkV6Za5qkLyJRUZr9ydEB8FbMUz2fmGpnsQaVLBNFJoY" ;
                        "edpktgXhBmgbBEJqdWf95pZMt1pGjZ5VUB3g4dARAfapXM7jdvC8y3" }))
        No delegate for this contract
        This origination was successfully applied
        Originated contracts:
          KT1NvL2n8qtBUHPWQNzviTprvUagjgQmHv4d
        Storage size: 1026 bytes
        Paid storage size diff: 1026 bytes
        Consumed gas: 34825
        Balance updates:
          tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx ... -ꜩ1.026
          tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx ... -ꜩ0.257
          tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx ... -ꜩ100
          KT1NvL2n8qtBUHPWQNzviTprvUagjgQmHv4d ... +ꜩ100

New contract KT1NvL2n8qtBUHPWQNzviTprvUagjgQmHv4d originated.
The operation has only been included 0 blocks ago.
We recommend to wait more.
Use command
  tezos-client wait for opUJAVrUtzCyHKbvsFwJPcEjaLE94sEAhc1xe8tcw9JPkHtUNTq to be included --confirmations 30 --branch BM8UwMguNd5pXqnEKqSEafg6zJVQ7J4omqWmRHaVqxDTn1eBFWv
and/or an external block explorer.
Contract memorized as msig.
$ # Alice and Charlie agree to send 10tz to bootstrap2
$ # Alice has an up-to-date client, she signs using the new command
$ SIGA=$(tezos-client sign multisig transaction on msig transferring 10 to bootstrap2 using secret key alice)
$ echo "$SIGA"
edsigtuiywJo1aCyAocrjoL38KEmgeP3YuchQFdAtDjrB3dJa4np9iPEfYj9QD98LENQioSyF7jP3cN1um2bjEGUR3WW4kZtKqa
$ # Charlie's client does not feature the new multisig commands, we send him the bytes to sign,
$ tezos-client prepare multisig transaction on msig transferring 10 to bootstrap2
Bytes to sign: '0x0507070a00000016019d44c3ea27ec7d974a7ba05318bee422d1d39cbb0007070000050507070080dac4090a000000160000e7670f32038107a59a2b9cfefae36ea21f5aa63c'
Threshold (number of signatures required): 2
Public keys of the signers:
  edpkuakZ5gDnDb4eWf4NVDqBKHPgtgNouffLZqtUncZzzAvrknHJqv
  sppk7ZcEgHvnkV6Za5qkLyJRUZr9ydEB8FbMUz2fmGpnsQaVLBNFJoY
  edpktgXhBmgbBEJqdWf95pZMt1pGjZ5VUB3g4dARAfapXM7jdvC8y3
$ BYTES=$(tezos-client prepare multisig transaction on msig transferring 10 to bootstrap2 --bytes-only)
$ echo "$BYTES"
0x0507070a00000016019d44c3ea27ec7d974a7ba05318bee422d1d39cbb0007070000050507070080dac4090a000000160000e7670f32038107a59a2b9cfefae36ea21f5aa63c
$ # Charlie can partly check what he signs, he can see that it is a transfer of 10tz
$ tezos-client unpack michelson data "$BYTES"
Pair 0x019d44c3ea27ec7d974a7ba05318bee422d1d39cbb00
     (Pair 0 (Left (Pair 10000000 0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c)))
$ # And he can sign
$ SIGC=$(tezos-client sign bytes "$BYTES" for charlie | cut -d ' ' -f 2)
$ echo "$SIGC"
edsigtuLZWdyecNDatT2t2E1wPrWo9jxLEahV8wJiriDhJMUVPKFZ4uNF3TZwJz7x4bqB5KHEHbbDtED2hDfnqeNfWBzwXvRNRA
$ tezos-client multisign transfer 10 from bootstrap1 to bootstrap2 on msig with signatures "$SIGA" "$SIGC"
Node is bootstrapped, ready for injecting operations.
Estimated gas: 44492 units (will add 100 for safety)
Estimated storage: no bytes added
Operation successfully injected in the node.
Operation hash is 'ooi3Ucat2dkNV7mYqWFMu2wDZg8k7cpwJxWNEC3qJ9U4sjoCLJj'
Waiting for the operation to be included...
Operation found in block: BLzLmL4unhhZY8z19Y5bqgWzHdXmXeaqU35vob2uGTqh3BzAkqY (pass: 3, offset: 0)
This sequence of operations was run:
  Manager signed operations:
    From: tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx
    Fee to the baker: ꜩ0.004975
    Expected counter: 2
    Gas limit: 44592
    Storage limit: 0 bytes
    Balance updates:
      tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx ........... -ꜩ0.004975
      fees(tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx,0) ... +ꜩ0.004975
    Transaction:
      Amount: ꜩ0
      From: tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx
      To: KT1NvL2n8qtBUHPWQNzviTprvUagjgQmHv4d
      Parameter: (Pair (Pair 0 (Left (Pair 10000000 0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c)))
                       { Some "edsigtuiywJo1aCyAocrjoL38KEmgeP3YuchQFdAtDjrB3dJa4np9iPEfYj9QD98LENQioSyF7jP3cN1um2bjEGUR3WW4kZtKqa" ;
                         None ;
                         Some "edsigtuLZWdyecNDatT2t2E1wPrWo9jxLEahV8wJiriDhJMUVPKFZ4uNF3TZwJz7x4bqB5KHEHbbDtED2hDfnqeNfWBzwXvRNRA" })
      This transaction was successfully applied
      Updated storage:
        (Pair 1
              (Pair 2
                    { 0x007bcfedcb5bab7fd810cab9d0b92acdfe26a9b84e1df8090d1be3edac367d5c34 ;
                      0x010227f6be91c739897f1b26130a20ceb841d34074431c65a7c825d5e0b7fa934b2c ;
                      0x00053c84a5996c98d2471a5ce27a5d2eadc85a32e7fd569221dc67f6da34e660e0 }))
      Storage size: 1026 bytes
      Consumed gas: 34385
    Internal operations:
      Transaction:
        Amount: ꜩ10
        From: KT1NvL2n8qtBUHPWQNzviTprvUagjgQmHv4d
        To: tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN
        Parameter: Unit
        This transaction was successfully applied
        Consumed gas: 10107
        Balance updates:
          KT1NvL2n8qtBUHPWQNzviTprvUagjgQmHv4d ... -ꜩ10
          tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN ... +ꜩ10

The operation has only been included 0 blocks ago.
We recommend to wait more.
Use command
  tezos-client wait for ooi3Ucat2dkNV7mYqWFMu2wDZg8k7cpwJxWNEC3qJ9U4sjoCLJj to be included --confirmations 30 --branch BLCTTB5rirYiUPKKvYRMuhZja7frTagRhUBRZQpPkY5rNxqd3v3
and/or an external block explorer.
Edited by Raphaël Cauderlier

Merge request reports