> For the complete documentation index, see [llms.txt](https://docs.endless.link/endless/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.endless.link/endless/devbuild/build/tutorials/your-first-multisig.md).

# Your First Multisig

## Your First Multisig <a href="#your-first-multisig" id="your-first-multisig"></a>

This tutorial introduces assorted K-of-N multi-signer authentication operations and supplements content from the following tutorials:

* Your First Transaction
* Your First Coin
* Your First Move Module

{% hint style="info" %}
Try out the above tutorials (which include dependency installations) before moving on to multisig operations.
{% endhint %}

## Step 1: Pick an SDK <a href="#step-1-pick-an-sdk" id="step-1-pick-an-sdk"></a>

Install your preferred SDK from the below list:

* TypeScript SDK

***

## Step 2: Run the example <a href="#step-2-run-the-example" id="step-2-run-the-example"></a>

Clone the endless-ts-sdk repo and build it:

```shell
git clone https://github.com/endless-labs/endless-ts-sdk.git
cd endless-ts-sdk
pnpm install
pnpm build
```

Navigate to the Typescript examples directory:

```shell
cd examples/endless
```

Install the necessary dependencies:

```shell
pnpm install
```

Run the [`binding`](https://github.com/endless-labs/endless-ts-sdk/blob/main/examples/typescript/binding.ts) example:

```shell
pnpm run bindings
```

## Step 3: Generate accounts and fund them

First, we will generate accounts for Alice, Bob, and Chad and fund them:

Fresh accounts are generated for each example run, but the output should resemble:

```shell
Fund alice: version 633280
Fund bob: version 633291

=== Account addresses ===
Alice: 0x91c381ec582ee96f96841a8f71b13a9feea83f52441e15a9e8b9d2bcf2ebbbc9
Bob:   0xd92dffdee6345ed5a0b3e3fe72b972dd90ba200bb478693dba4288998bc8343d
Chad:  0x820a4393e98c207b920a098c251c72435b5830b5b938bdb1aee77f83713d359c

=== Authentication keys ===
Alice: 0x91c381ec582ee96f96841a8f71b13a9feea83f52441e15a9e8b9d2bcf2ebbbc9
Bob:   0xd92dffdee6345ed5a0b3e3fe72b972dd90ba200bb478693dba4288998bc8343d
Chad:  0x820a4393e98c207b920a098c251c72435b5830b5b938bdb1aee77f83713d359c
```

For each user, at this moment, the account address and authentication key are identical.

## Step 4: Add Bob's authentication key into Alice's authentication key(list) <a href="#step-4-add-auth-key" id="step-4-add-auth-key"></a>

Next, Alice adds Bob's authentication key to her list of authentication keys. This involves submitting a transaction that invokes the \`add\_authentication\_key\` function within the account module of the system contract. Both Alice and Bob must sign this transaction.

```js
let txn = await endless.transaction.build.multiAgent({
    sender: alice.accountAddress,
    data: {
        function: "0x1::account::add_authentication_key",
        functionArguments: []
    },
    secondarySignerAddresses: [bob.accountAddress],
})

let aliceAuth = alice.signTransactionWithAuthenticator(txn)
let bobAuth = bob.signTransactionWithAuthenticator(txn)
pending = await endless.transaction.submit.multiAgent({
    transaction: txn,
    senderAuthenticator: aliceAuth,
    additionalSignersAuthenticators: [bobAuth],
})
tx_response = await endless.waitForTransaction({ transactionHash: pending.hash })

console.log(`\nAdd Bob's authkey into Alice authkey list: version ${tx_response.version}`)
```

## Step 5: Alice's authentication key (contains Bob's authentication key)

After add authentication key transaction, bob's authentication key is added into Alice's authentication

```shell
Alice authentication_key:
0x91c381ec582ee96f96841a8f71b13a9feea83f52441e15a9e8b9d2bcf2ebbbc9,
0xd92dffdee6345ed5a0b3e3fe72b972dd90ba200bb478693dba4288998bc8343d

Bob controlled accounts:
0x91c381ec582ee96f96841a8f71b13a9feea83f52441e15a9e8b9d2bcf2ebbbc9
```

## Step 6: Send coins from Alice to Chad, signed by Bob

We now build an EDS transfer transaction, sender is Alice's account, receiver is Chad, transaction is signed by Bob.

```js
let transferEDSRawTransaction = await endless.transaction.build.simple({
    sender: alice.accountAddress,
    data: {
        function: "0x1::endless_account::transfer",
        functionArguments: [chad.accountAddress, 1000]
    },
})

let multiAuthKeyAccount = new MultiAuthKeyAccount({ sender: alice.accountAddress, signers: [bob] })

pending = await endless.signAndSubmitTransaction({
    transaction: transferEDSRawTransaction,
    signer: multiAuthKeyAccount,
})
tx_response = await endless.waitForTransaction({ transactionHash: pending.hash })

console.log(`\ntransfer EDS from Alice to Chad with Bob auth: version ${tx_response.version}`)
```

## Step 7: remove Bob's authentication key from Alice's authentication key list

We invoke `0x1::account::remove_authentication_key` to remove Bob's authenticaion key, restore Alice's authentication key as default. This transaction also must be signed by both Alice and Bob.

```js
txn = await endless.transaction.build.simple({
    sender: alice.accountAddress,
    data: {
        function: "0x1::account::remove_authentication_key",
        functionArguments: [bob.accountAddress.data]
    },
})

aliceAuth = alice.signTransactionWithAuthenticator(txn)
pending = await endless.transaction.submit.simple({
    transaction: txn,
    senderAuthenticator: aliceAuth,
})
tx_response = await endless.waitForTransaction({ transactionHash: pending.hash })

console.log(`\nRemove Bob from Alice's auth key : version ${tx_response.version}`)
```

## Step 8: Check if Alice's authentication key is restored to default

```shell
Alice authentication_key:
0x91c381ec582ee96f96841a8f71b13a9feea83f52441e15a9e8b9d2bcf2ebbbc9

Bob controlled accounts:
None
```

## Step 9: Batch add Bob\&Chad authkey into Alice's authentication key list, but set `Threashold` to 2

By adding Bob and Chad auth key to Alice's auth key list, either Bob or Chad can sign transaction on Alice behalf. A required signature count of 2 (Threshold = 2) is enforced for transactions originating from Alice. Verification will fail if fewer than two signatures are present (e.g., only Alice's signature, or only one of Bob's or Chad's)

```js
txn = await endless.transaction.build.multiAgent({
    sender: alice.accountAddress,
    data: {
        function: "0x1::account::batch_add_authentication_key",
        functionArguments: [2]
    },
    secondarySignerAddresses: [bob.accountAddress, chad.accountAddress],
})

aliceAuth = alice.signTransactionWithAuthenticator(txn)
bobAuth = bob.signTransactionWithAuthenticator(txn)
let chadAuth = chad.signTransactionWithAuthenticator(txn)
pending = await endless.transaction.submit.multiAgent({
    transaction: txn,
    senderAuthenticator: aliceAuth,
    additionalSignersAuthenticators: [bobAuth, chadAuth],
})
tx_response = await endless.waitForTransaction({ transactionHash: pending.hash })

console.log(`\nBatch Add auth key, set "AuthThreadhold" to 2: version ${tx_response.version}`)
```

## Step 10: transfer transaction, signed only by Bob, will fail

```js
transferEDSRawTransaction = await endless.transaction.build.simple({
    sender: alice.accountAddress,
    data: {
        function: "0x1::endless_account::transfer",
        functionArguments: [chad.accountAddress, 1000]
    },
})
multiAuthKeyAccount = new MultiAuthKeyAccount({ sender: alice.accountAddress, signers: [bob] })

try {
    pending = await endless.signAndSubmitTransaction({
    transaction: transferEDSRawTransaction,
    signer: multiAuthKeyAccount,
    })
    await endless.waitForTransaction({ transactionHash: pending.hash });
} catch (error) {
    console.log("\nFailed to transfer EDS from Alice to Chad with only by Bob auth, cause `Auth Threshold` is 2")
}
```

## Step 11: transfer transaction, signed by both Bob and Chad, will success

```js
multiAuthKeyAccount = new MultiAuthKeyAccount({ sender: alice.accountAddress, signers: [bob, alice] })
pending = await endless.signAndSubmitTransaction({
    transaction: transferEDSRawTransaction,
    signer: multiAuthKeyAccount,
})
tx_response = await endless.waitForTransaction({ transactionHash: pending.hash })
console.log(`\ntransfer EDS from Alice to Chad with Alice and Bob auth, version ${tx_response.version}`)
```

The above examples showcase the Endless multi-signature feature, demonstrating how to manage Authentication Keys and generate transaction signatures. This multi-signature implementation, combined with Keyless functionality, offers an emergency escape route.

For example, if a Keyless account (A) is locked due to Web2 service issues, and its authentication key list includes another wallet (AA), then AA can rescue the funds by initiating a transaction on A's behalf, avoiding assets locked.
