Multisig wallet
Prerequisites
dYdX CLIEOA WalletsInstantiate a multisig
1. Add wallets locally
To verify your local setup, list all wallets with
dydxprotocold keys show
As an example, let’s imagine we have a generated wallet A with, e.g.:
dydxprotocold keys add walletA
And have added offline walletB and walletC
dydxprotocold keys add walletB --pubkey='{"@type":"/cosmos.crypto.secp256k1.PubKey"
dydxprotocold keys add walletC --pubkey='{"@type":"/cosmos.crypto.secp256k1.PubKey",
2. Instantiate the multisig
You need the names of the wallets, e.g. walletA , walletB and walletC and the threshold. ourMultisig is an arbitrary name, choose one that is meaningful to you
$ dydxprotocold keys add ourMultisig --multisig="walletA,walletB,walletC" --multisig-thr
- address: dydx1d02xdy...sw9fcq7jerkwe
name: ourMultisig
pubkey: '{"@type":"/cosmos.crypto.multisig.LegacyAminoPubKey","threshold":2,"public_keys":[{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A/C+dj94...9SCD2Uu11"},{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A9QEyr+iQoCI...IP76IjzVG2vEMf"},{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"ArarpFkTpgJOnjvUen...KMU5c2zbQ0"}]}'
type: multi
Now let's send some small funds to the multisig address in order to activate the address.
$ dydxprotocold tx bank send test dydx1z79c98w069eugzjme0dkd6quuhm8vfh2a00smh \
100000000000000000adv4tnt \
--fees 5000000000000000adv4tnt \
--node https://dydx-testnet-rpc.polkachu.com:443 \
--chain-id dydx-testnet-4
3. EXAMPLE scenario multisig
Let’s say that we have
WalletA ,
dydx18ym0ts7fw40x2qqw73plgg7wgmkljvvd7x8jk0
- the one that we controlWalletB ,
dydx1n72zp2myk6qzsec954nd6lap7tn5f6mwtr2qne
- an offline wallet of one of our counterparties in the multisigWalletC ,
dydx1h03ny3j2k4yltt767r3tjw92qs0vj3p2g5w6x3
- an offline wallet of the other counterparty in the multisigourMultisig ,
dydx1z79c98w069eugzjme0dkd6quuhm8vfh2a00smh
- a 2/3 multisig, instantiated with WalletA , WalletB , and WalletC
dydxprotocold keys show ourMultisig
- address: dydx1z79c98w069eugzjme0dkd6quuhm8vfh2a00smh
name: ourMultisig
pubkey: '{"@type":"/cosmos.crypto.multisig.LegacyAminoPubKey","threshold":2,"public_keys":[{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A/C+dj94...9SCD2Uu11"},{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A9QEyr+iQoCI...IP76IjzVG2vEMf"},{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"ArarpFkTpgJOnjvUen...KMU5c2zbQ0"}]}'
type: multi
Querying the multisig balances:
dydxprotocold query bank balances dydx1z79c98w069eugzjme0dkd6quuhm8vfh2a00smh
balances:
- amount: "231357500000000000000"
denom: adv4tnt
pagination:
next_key: null
total: "0"
4. Create send token Tx
$ dydxprotocold tx bank send ourMultisig \
dydx1h6x6pxkv2fv3jzsx5hc5efaarhue7gpsdmxafk \
100000000000000000adv4tnt \
--fees 5000000000000000adv4tnt \
--node https://dydx-testnet-rpc.polkachu.com:443 \
--chain-id dydx-testnet-4 \
--generate-only > unsignedTx.json
dydx1z79c98w069eugzjme0dkd6quuhm8vfh2a00smh
is the address of the multisig from which we send tokens - in case you have instantiated the multisig locally, you can use it’s name, e.g.ourMultisig
dydx1h6x6pxkv2fv3jzsx5hc5efaarhue7gpsdmxafk
is the recipient address700000000000000000adydx
is the amount to send - 0.7 DYDX--fees value 5000000000000000adydx
may need adjustment; the transaction will fail only when broadcasted if this amount is not enough--generate-only
will prevent the transaction to be submitted
The result will be stored in the file named unsignedTx.json
unsignedTx.json
```json
{
"body": {
"messages": [
{
"@type": "/cosmos.bank.v1beta1.MsgSend",
"from_address": "dydx1z79c98w069eugzjme0dkd6quuhm8vfh2a00smh",
"to_address": "dydx1h6x6pxkv2fv3jzsx5hc5efaarhue7gpsdmxafk",
"amount": [{ "denom": "adv4tnt", "amount": "100000000000000000" }]
}
],
"memo": "",
"timeout_height": "0",
"extension_options": [],
"non_critical_extension_options": []
},
"auth_info": {
"signer_infos": [],
"fee": {
"amount": [{ "denom": "adv4tnt", "amount": "5000000000000000" }],
"gas_limit": "200000",
"payer": "",
"granter": ""
},
"tip": null
},
"signatures": []
}
```
5. Sign Token Tx
dydxprotocold tx sign unsignedTx.json \
--from walletName \
--multisig=ourMultisig \
--multisig= --output-document=walletAsignedTx.json \
--node https://dydx-testnet-rpc.polkachu.com:443 \
--chain-id dydx-testnet-4
Replace walletName with the respective wallet name ( walletA , walletB , or walletC ).
Each signer must have instantiated the multisig locally - they must see
dydx1z79c98w069eugzjme0dkd6quuhm8vfh2a00smh
when listing their know walletsThe value of
--multisig
can also be the multisig name, e.g.ourMultisig
After this step, there should be two separate signed transaction files, e.g., walletASignedTx.json
and walletBSignedTx.json
.
// walletASignedTx.json
```json
{
"signatures": [
{
"public_key": {
"@type": "/cosmos.crypto.secp256k1.PubKey",
"key": "ArarpFkTpgJOn...wkKMU5c2zbQ0"
},
"data": {
"single": {
"mode": "SIGN_MODE_LEGACY_AMINO_JSON",
"signature": "Or9KGawXT...f3kT6DA=="
}
},
"sequence": "0"
}
]
}
```
6. Combine signatures
dydxprotocold tx multisign unsignedTx.json \
ourMultisig \
walletASignedTx.json \
walletBSignedTx.json \
--node https://dydx-testnet-rpc.polkachu.com:443 \
--chain-id dydx-testnet-4 > multisignedTx.json
One needs all the files generated until now: unsignedTx.json
, walletASignedTx.json
and walletBSignedTx.json
. ourMultisig cannot be the multisig address The result is a file called multisignedTx.json
//multisignedTx.json
```json
{
"body": {
"messages": [
{
"@type": "/cosmos.bank.v1beta1.MsgSend",
"from_address": "dydx1z79c98w069eugzjme0dkd6quuhm8vfh2a00smh",
"to_address": "dydx1h6x6pxkv2fv3jzsx5hc5efaarhue7gpsdmxafk",
"amount": [{ "denom": "adv4tnt", "amount": "100000000000000000" }]
}
],
"memo": "",
"timeout_height": "0",
"extension_options": [],
"non_critical_extension_options": []
},
"auth_info": {
"signer_infos": [
{
"public_key": {
"@type": "/cosmos.crypto.multisig.LegacyAminoPubKey",
"threshold": 2,
"public_keys": [
{
"@type": "/cosmos.crypto.secp256k1.PubKey",
"key": "A/C+dj94G1t...CD2Uu11"
},
{
"@type": "/cosmos.crypto.secp256k1.PubKey",
"key": "A9QEyr+i...P76IjzVG2vEMf"
},
{
"@type": "/cosmos.crypto.secp256k1.PubKey",
"key": "ArarpFkTpgJO....kKMU5c2zbQ0"
}
]
},
"mode_info": {
"multi": {
"bitarray": { "extra_bits_stored": 3, "elems": "oA==" },
"mode_infos": [
{ "single": { "mode": "SIGN_MODE_LEGACY_AMINO_JSON" } },
{ "single": { "mode": "SIGN_MODE_LEGACY_AMINO_JSON" } }
]
}
},
"sequence": "0"
}
],
"fee": {
"amount": [{ "denom": "adv4tnt", "amount": "5000000000000000" }],
"gas_limit": "200000",
"payer": "",
"granter": ""
},
"tip": null
},
"signatures": [
"CkDEtBh262Ur...oZrBdEd/R/eRPoM"
]
}
```
7. Broadcast Send Tokens Tx
$ dydxprotocold tx broadcast multisignedTx.json \
--node https://dydx-testnet-rpc.polkachu.com:443
--chain-id dydx-testnet-4
Code: 0
codespace: ""
data: ""
events: []
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: F51017738F91D758CBF857D0B...739F7177EFC778BA2811585F84
You can use the txhash to check MintScan for the transaction status. If nothing is available on MintScan, then the broadcast or signing were unsuccessful.
Last updated