Skip to content

Latest commit

 

History

History
322 lines (257 loc) · 9.24 KB

roles-and-multi-sig.rst

File metadata and controls

322 lines (257 loc) · 9.24 KB

This guide uses the roles functionality provided by basecli to create a multi-sig wallet. It builds upon the basecoin basics and key management guides. You should have basecoin started with blocks streaming in, and three accounts: rich, poor, igor where rich was the account used on basecoin init, and run basecli init with the appropriate flags. Review the intro guides for more information.

In this example, rich will create the role and send it some coins (i.e., fill the multi-sig wallet). Then, poor will prepare a transaction to withdraw coins, which will be approved by igor. Let's look at our keys:

basecli keys list
All keys:
igor        5E4CB7A4E729BA0A8B18DE99E21409B6D706D0F1
poor        65D406E028319289A0706E294F3B764F44EBA3CF
rich        CB76F4092D1B13475272B36585EBD15D22A2848D

Using the basecli query account command, you'll see that rich has plenty of coins:

{
  "height": 81,
  "data": {
    "coins": [
      {
        "denom": "mycoin",
        "amount": 9007199254740992
      }
    ],
    "credit": []
  }
}

whereas poor and igor have no coins (in fact, the chain doesn't know about them yet):

ERROR: Account bytes are empty for address 65D406E028319289A0706E294F3B764F44EBA3CF

Create Role

This first step defines the parameters of a new role, which will have control of any coins sent to it, and only release them if correct conditions are met. In this example, we are going to make a 2/3 multi-sig wallet. Let's look a the command and dissect it below:

basecli tx create-role --role=10CAFE4E --min-sigs=2 --members=5E4CB7A4E729BA0A8B18DE99E21409B6D706D0F1,65D406E028319289A0706E294F3B764F44EBA3CF,CB76F4092D1B13475272B36585EBD15D22A2848D --sequence=1 --name=rich

In the first part we are sending a transaction that creates a role, rather than transfering coins. The --role flag is the name of the role (in hex only) and must be in double quotes. The --min-sigs and --members define your multi-sig parameters. Here, we require a minimum of 2 signatures out of 3 members but we could easily say 3 of 5 or 9 of 10, or whatever your application requires. The --members flag requires a comma-seperated list of addresses that will be signatories on the role. Then we set the --sequence number for the transaction, which will start at 1 and must be incremented by 1 for every transaction from an account. Finally, we use the name of the key/account that will be used to create the role, in this case the account rich.

Remember that rich's address was used on basecoin init and is included in the --members list. The command above will prompt for a password (which can also be piped into the command if desired) then - if executed correctly - return some data:

{
  "check_tx": {
    "code": 0,
    "data": "",
    "log": ""
  },
  "deliver_tx": {
    "code": 0,
    "data": "",
    "log": ""
  },
  "hash": "4849DA762E19CE599460B9882DD42C7F19655DC1",
  "height": 321
}

showing the block height at which the transaction was committed and its hash. A quick review of what we did: 1) created a role, essentially an account, that requires a minimum of two (2) signatures from three (3) accounts (members). And since it was the account named rich's first transaction, the sequence was set to 1.

Let's look at the balance of the role that we've created:

basecli query account role:10CAFE4E

and it should be empty:

ERROR: Account bytes are empty for address role:10CAFE4E

Next, we want to send coins to that role. Notice that because this is the second transaction being sent by rich, we need to increase --sequence to 2:

basecli tx send --fee=90mycoin --amount=10000mycoin --to=role:10CAFE4E --sequence=2 --name=rich

We need to pay a transaction fee to the validators, in this case 90 mycoin to send 10000 mycoin Notice that for the --to flag, to specify that we are sending to a role instead of an account, the role: prefix is added before the role. Because it's rich's second transaction, we've incremented the sequence. The output will be nearly identical to the output from create-role above.

Now the role has coins (think of it like a bank).

Double check with:

basecli query account role:10CAFE4E

and this time you'll see the coins in the role's account:

{
  "height": 2453,
  "data": {
    "coins": [
      {
        "denom": "mycoin",
        "amount": 10000
      }
    ],
    "credit": []
  }
}

Poor decides to initiate a multi-sig transaction to himself from the role's account. First, it must be prepared like so:

basecli tx send --amount=6000mycoin --from=role:10CAFE4E --to=65D406E028319289A0706E294F3B764F44EBA3CF --sequence=1 --assume-role=10CAFE4E --name=poor --multi --prepare=tx.json

you'll be prompted for poor's password and there won't be any stdout to the terminal. Note that the address in the --to flag matches the address of poor's account from the beginning of the tutorial. The main output is the tx.json file that has just been created. In the above command, the --assume-role flag is used to evaluate account permissions on the transaction, while the --multi flag is used in combination with --prepare, to specify the file that is prepared for a multi-sig transaction.

The tx.json file will look like this:

{
  "type": "sigs/multi",
  "data": {
    "tx": {
      "type": "chain/tx",
      "data": {
        "chain_id": "test_chain_id",
        "expires_at": 0,
        "tx": {
          "type": "nonce",
          "data": {
            "sequence": 1,
            "signers": [
              {
                "chain": "",
                "app": "sigs",
                "addr": "65D406E028319289A0706E294F3B764F44EBA3CF"
              }
            ],
            "tx": {
              "type": "role/assume",
              "data": {
                "role": "10CAFE4E",
                "tx": {
                  "type": "coin/send",
                  "data": {
                    "inputs": [
                      {
                        "address": {
                          "chain": "",
                          "app": "role",
                          "addr": "10CAFE4E"
                        },
                        "coins": [
                          {
                            "denom": "mycoin",
                            "amount": 6000
                          }
                        ]
                      }
                    ],
                    "outputs": [
                      {
                        "address": {
                          "chain": "",
                          "app": "sigs",
                          "addr": "65D406E028319289A0706E294F3B764F44EBA3CF"
                        },
                        "coins": [
                          {
                            "denom": "mycoin",
                            "amount": 6000
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "signatures": [
      {
        "Sig": {
          "type": "ed25519",
          "data": "A38F73BF2D109015E4B0B6782C84875292D5FAA75F0E3362C9BD29B16CB15D57FDF0553205E7A33C740319397A434B7C31CBB10BE7F8270C9984C5567D2DC002"
        },
        "Pubkey": {
          "type": "ed25519",
          "data": "6ED38C7453148DD90DFC41D9339CE45BEFA5EB505FD7E93D85E71DFFDAFD9B8F"
        }
      }
    ]
  }
}

and it is loaded by the next command.

With the transaction prepared, but not sent, we'll have igor sign and send the prepared transaction:

basecli tx --in=tx.json --name=igor

which will give output similar to:

{
  "check_tx": {
    "code": 0,
    "data": "",
    "log": ""
  },
  "deliver_tx": {
    "code": 0,
    "data": "",
    "log": ""
  },
  "hash": "E345BDDED9517EB2CAAF5E30AFF3AB38A1172833",
  "height": 2673
}

and voila! That's the basics for creating roles and sending multi-sig transactions. For 3 of 3, you'd add an intermediate transactions like:

basecli tx --in=tx.json --name=igor --prepare=tx2.json

before having rich sign and send the transaction. The --prepare flag writes files to disk rather than sending the transaction and can be used to chain together multiple transactions.

We can check the balance of the role:

basecli query account role:10CAFE4E

and get the result:

{
  "height": 2683,
  "data": {
    "coins": [
      {
        "denom": "mycoin",
        "amount": 4000
      }
    ],
    "credit": []
  }
}

and see that poor now has 6000 mycoin:

basecli query account 65D406E028319289A0706E294F3B764F44EBA3CF

to confirm that everything worked as expected.