Endless
  • 🚀README
  • Discovery
    • 🚀Endless Web3 Genesis Cloud
    • 💎Business Model
    • 🎯Vision
    • ✈️Roadmap
    • 🪙Economics
    • 👤Team
      • Yu Xiong
      • Amit Kumar Jaiswal
      • Ned
      • 0xfun
      • Scott Trowbridge
      • Neeraj Sharma LLB
      • Amjad Suleman
      • Binu Paul
      • Eduard Romulus GOEAN
    • ❤️Developer Community
  • Endless Chain
    • Tech Docs
      • Account Address Format
      • Endless Account
      • Endless Coin(EDS)
      • Sponsored Transaction
      • On-Chain Multisig
      • Randomness
      • Safety Transaction
      • Token Locking & Distribution
    • Start
      • Learn about Endless
        • Accounts
        • Resources
        • Events
        • Transactions and States
        • Gas and Storage Fees
        • Computing Transaction Gas
        • Blocks
        • Staking
          • Delegated Staking
        • Governance
        • Endless Blockchain Deep Dive
          • Validator Nodes Overview
          • Fullnodes Overview
          • Node Networks and Synchronization
        • Move - A Web3 Language and Runtime
      • Explore Endless
      • Latest Endless Releases
      • Networks
    • Build
      • Tutorials
        • Your First Transaction
        • Your First Fungible Asset
        • Your First NFT
        • Your First Move Module
        • Your First Multisig
      • Learn the Move Language
        • The Move Book
          • Getting Started
            • Introduction
            • Modules and Scripts
          • Primitive Types
            • Move Tutorial
            • Integers
            • Bool
            • Address
            • Vector
            • Signer
            • References
            • Tuples and Unit
          • Basic Concepts
            • Local Variables and Scope
            • Equality
            • Abort and Assert
            • Conditionals
            • While, For, and Loop
            • Functions
            • Structs and Resources
            • Constants
            • Generics
            • Abilities
            • Uses and Aliases
            • Friends
            • Packages
            • Package Upgrades
            • Unit Tests
          • Global Storage
            • Global Storage - Structure
            • Global Storage - Operators
          • Reference
            • Libraries
            • Move Coding Conventions
        • Advanced Move Guides
          • Objects
            • Creating Objects
            • Configuring objects
            • Using objects
          • Move Scripts
            • Writing Move Scripts
            • Compiling Move Scripts
            • Running Move Scripts
            • Move Scripts Tutorial
          • Resource Accounts
          • Modules on Endless
          • Cryptography
          • Gas Profiling
          • Security
      • Endless Standards
        • Object
        • Endless Fungible Asset Standard
        • Endless Digital Asset Standard
        • Endless Wallet Standard
      • Endless APIs
        • Fullnode Rest API
        • Indexer Restful API
          • Indexer Installation
        • GRPC Transaction Stream
          • Running Locally
          • Custom Processors
            • End-to-End Tutorial
            • Parsing Transactions
          • Self-Hosted Transaction Stream Service
      • Endless SDKs
        • TypeScript SDK
          • Account
          • SDK Configuration
          • Fetch data from chain
          • Transaction Builder
          • HTTP Client
          • Move Types
          • Testing
          • Typescript
        • Rust SDK
        • Go SDK
      • Endless CLI
        • Install the Endless CLI
          • Install On Mac
          • Install On Alibaba Cloud
          • Install On Linux
          • Install On Windows
        • CLI Configuration
        • Use Endless CLI
          • Working With Move Contracts
            • Arguments in JSON Tutorial
          • Trying Things On-Chain
            • Look Up On-Chain Account Info
            • Create Test Accounts
          • Running A Local Network
            • Running a Public Network
          • Managing a Network Node
      • Integrate with Endless
        • Endless Token Overview
        • Application Integration Guide
      • Endless VSCode extension
      • Advanced Builder Guides
        • Develop Locally
          • Running a Local Network
          • Run a Localnet with Validator
    • Nodes
      • Learn about Nodes
      • Run a Validator and VFN
        • Node Requirements
        • Deploy Nodes
          • Using Docker
          • Using AWS
          • Using Azure
          • Using GCP
        • Connect Nodes
          • Connect to a Network
        • Verify Nodes
          • Node Health
          • Validator Leaderboard
      • Run a Public Fullnode
        • PFN Requirements
        • Deploy a PFN
          • Using Pre-compiled Binary
          • Using Docker
          • Using GCP 🚧 (under_construction)
        • Verify a PFN
        • Modify a PFN
          • Upgrade your PFN
          • Generate a PFN Identity
          • Customize PFN Networks
      • Bootstrap a Node
        • Bootstrap from a Snapshot
        • Bootstrap from a Backup
      • Configure a Node
        • State Synchronization
        • Data Pruning
        • Telemetry
        • Locating Node Files
          • Files For Mainnet
          • Files For Testnet
          • Files For Devnet
      • Monitor a Node
        • Node Inspection Service
        • Important Node Metrics
        • Node Health Checker
    • Reference
      • Endless Error Codes
      • Move Reference Documentation
      • Endless Glossary
    • FAQs
  • Endless Bridge
    • Intro to Endless Bridge
    • How to use bridge
    • Liquidity Management
    • Faucet
    • Developer Integration
      • Contract Integration
        • Message Contract
        • Execute Contract
      • Server-Side Integration
        • Message Sender
        • Example of Message Listener Service (Rust)
        • Example of Token Cross-Chain (JS)
  • Endless Wallet
    • User Guide
    • Basic Tutorial
    • FAQs
    • MultiAccount
    • SDK
      • Functions
      • Events
  • GameFi
    • Intro
    • GameFi & Endless
  • Endless Modules
    • Stacks
    • Storage
    • Module List
  • Endless Ecosystem
    • Intro
    • Show Cases
    • App Demo
  • Whitepaper
  • Endless SCAN
    • User Guide
  • MULTI-SIGNATURE
    • Multi-Signature User Guide
  • Regulations
    • Privacy Policy
    • Terms of Service
    • Funding Terms - Disclaimer
Powered by GitBook
On this page
  • Your First Multisig
  • Step 1: Pick an SDK
  • Step 2: Run the example
  • Step 3: Generate accounts and fund them
  • Step 4: Add Bob's authentication key into Alice's authentication key(list)
  • Step 5: Alice's authentication key (contains Bob's authentication key)
  • Step 6: Send coins from Alice to Chad, signed by Bob
  • Step 7: remove Bob's authentication key from Alice's authentication key list
  • Step 8: Check if Alice's authentication key is restored to default
  • Step 9: Batch add Bob&Chad authkey into Alice's authentication key list, but set Threashold to 2
  • Step 10: transfer transaction, signed only by Bob, will fail
  • Step 11: transfer transaction, signed by both Bob and Chad, will success
Export as PDF
  1. Endless Chain
  2. Build
  3. Tutorials

Your First Multisig

Your First Multisig

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

Try out the above tutorials (which include dependency installations) before moving on to multisig operations.

Step 1: Pick an SDK

Install your preferred SDK from the below list:

  • TypeScript SDK


Step 2: Run the example

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

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:

cd examples/endless

Install the necessary dependencies:

pnpm install
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:

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)

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.

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

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.

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.

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

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)

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

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

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.

PreviousYour First Move ModuleNextLearn the Move Language

Last updated 4 months ago

Run the example:

binding