# Multisig wallet

### Prerequisites

{% content-ref url="" %}
[](https://docs.dydx.community/dydx-chain-technical-docs/getting-started/developer-tools/dydx-cli)
{% endcontent-ref %}

{% content-ref url="eoa-wallets" %}
[eoa-wallets](https://docs.dydx.community/dydx-chain-technical-docs/getting-started/developer-tools/dydx-cli/eoa-wallets)
{% endcontent-ref %}

### Instantiate a multisig

{% hint style="info" %}
Note that a multisig is defined solely by the ordered list of wallets that are parts of it and its threshold - meaning that so long as the input parameter are unchanged, the same multisig address can be instantiated anywhere, including on tools like <https://multisig.keplr.app/>
{% endhint %}

### 1. Add wallets locally

{% hint style="info" %}
💡 You do not need to own a wallet that is part of the multisig to instantiate it locally - adding only offline ones is
{% endhint %}

To verify your local setup, list all wallets with&#x20;

```bash
dydxprotocold keys show
```

As an example, let’s imagine we have a generated wallet A with, e.g.:

```bash
dydxprotocold keys add walletA 
```

And have added offline walletB and walletC&#x20;

```bash
dydxprotocold keys add walletB --pubkey='{"@type":"/cosmos.crypto.secp256k1.PubKey"
```

```bash
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&#x20;

```bash
$ 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

```

{% hint style="info" %}
Key order matters and keys are automatically sorted by their public key. At the time of writing, this is how <https://multisig.keplr.app/> instantiates multisig wallets. To change the key ordering, use the `--nosort` flag.
{% endhint %}

Now let's send some small funds to the multisig address in order to activate the address.

{% hint style="info" %}
It is important to activate the address by sending a small amount of tokens to the address otherwise the network will not recognise the multisig address.
{% endhint %}

```bash
$ 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**

{% hint style="info" %}
Goal: send `700000000000000000adydx` (0.7 DYDX) from multisig `dydx1z79c98w069eugzjme0dkd6quuhm8vfh2a00smh` (added as ourMultisig ) to address `dydx1h6x6pxkv2fv3jzsx5hc5efaarhue7gpsdmxafk`&#x20;

💡 Transferring tokens to a multisig address does not differ from transferring tokens to other address types
{% endhint %}

Let’s say that we have

1. WalletA , `dydx18ym0ts7fw40x2qqw73plgg7wgmkljvvd7x8jk0` - the one that we control
2. WalletB , `dydx1n72zp2myk6qzsec954nd6lap7tn5f6mwtr2qne` - an offline wallet of one of our counterparties in the multisig
3. WalletC , `dydx1h03ny3j2k4yltt767r3tjw92qs0vj3p2g5w6x3` - an offline wallet of the other counterparty in the multisig
4. ourMultisig , `dydx1z79c98w069eugzjme0dkd6quuhm8vfh2a00smh` - a 2/3 multisig, instantiated with WalletA , WalletB , and WalletC

```bash
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

{% hint style="info" %}
This step can be executed from any workstation. It is not even necessary to have added walletA , walletB , walletC nor ourMultisig
{% endhint %}

```bash
$  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`&#x20;
* `dydx1h6x6pxkv2fv3jzsx5hc5efaarhue7gpsdmxafk` is the recipient address&#x20;
* `700000000000000000adydx` is the amount to send - 0.7 DYDX&#x20;
* `--fees value 5000000000000000adydx` may need adjustment; the transaction will fail only when broadcasted if this amount is not enough&#x20;
* `--generate-only` will prevent the transaction to be submitted

The result will be stored in the file named `unsignedTx.json`

````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

{% hint style="info" %}
💡 Each of the required signers must use their own instances of dydxprotocold CLI and their private keys. The unsignedTx.json file needs to be securely transferred to them.&#x20;

💡 Each signer should verify the transaction details in `unsignedTx.json` before signing!
{% endhint %}

```bash
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 ).&#x20;
* Each signer must have instantiated the multisig locally - they must see `dydx1z79c98w069eugzjme0dkd6quuhm8vfh2a00smh` when listing their know wallets
* &#x20;The value of `--multisig` can also be the multisig name, e.g. `ourMultisig`&#x20;

\
After this step, there should be two separate signed transaction files, e.g., `walletASignedTx.json` and `walletBSignedTx.json`.

````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

{% hint style="info" %}
This step can be executed from a workstation where the multisig has been instantiated. Not necessarily an owner of a wallet in the multisig though.
{% endhint %}

```bash
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
```

&#x20;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`

````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

```bash
$ 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.
