> For the complete documentation index, see [llms.txt](https://docs.dydx.community/dydx-chain-technical-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.dydx.community/dydx-chain-technical-docs/getting-started/developer-tools/dydx-cli/multisig-wallet.md).

# Multisig wallet

### Prerequisites

{% content-ref url="/pages/jVa8XOMCyFthaR535LVX" %}
[dYdX CLI](/dydx-chain-technical-docs/getting-started/developer-tools/dydx-cli.md)
{% endcontent-ref %}

{% content-ref url="/pages/z8Qkc7gnse6WGUz6VYjZ" %}
[EOA Wallets](/dydx-chain-technical-docs/getting-started/developer-tools/dydx-cli/eoa-wallets.md)
{% 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.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.dydx.community/dydx-chain-technical-docs/getting-started/developer-tools/dydx-cli/multisig-wallet.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
