A step-by-step tutorial for creating secure multi-signature account on the Aptos blockchain
Introduction
Multisig account enhance blockchain security by requiring multiple signatures to authorize transactions, reducing single points of failure. In this guide, we’ll set up a 2-of-3 multisig account on the Aptos blockchain — three owners, two required approvals — then walk through proposing, approving, and executing a transaction.
Why Use Multisig Account?
- More Secure: One compromised key won’t risk funds
- Shared Control: No single point of failure
- Great for DAOs: Ideal for team-managed funds
- Fewer Mistakes: Multiple signers catch errors
Prerequisites
- Aptos CLI installed
- Basic blockchain knowledge
- Some APT tokens (use faucet for testnet)
Step 1: Creating Owner Accounts
First things first: we need to create the accounts that will share control of our multisig account.
Open up your terminal and run these commands:
aptos key generate \
--vanity-prefix 0xaaa \
--output-file aaa.key
aptos key generate \
--vanity-prefix 0xbbb \
--output-file bbb.key
aptos key generate \
--vanity-prefix 0xccc \
--output-file ccc.key
After running these, you’ll have three files, each containing a private key and public key. Mine looked something like this:
{
"Result": {
"Account Address:": "0xaaada5932a10d899c46307a25d1db698acf61b55a9595af57414f44a3052bc6e",
"PrivateKey Path": "aaa.key",
"PublicKey Path": "aaa.key.pub"
}
}
{
"Result": {
"PublicKey Path": "bbb.key.pub",
"PrivateKey Path": "bbb.key",
"Account Address:": "0xbbb3d185c70b6720c65bc434940533983cbd9eb7746408740faea9d0adae9c71"
}
}
{
"Result": {
"PrivateKey Path": "ccc.key",
"Account Address:": "0xccc5b889f29d1d1ebbd9130911c759e8426a73ca67ad558a1e5373c104c395c1",
"PublicKey Path": "ccc.key.pub"
}
}
Make sure to store these files securely and back them up. Save this address as we’ll need it throughout the rest of this tutorial.
# Save theaddress in an environment variable for easy reference
aaa_addr=0xaaada5932a10d899c46307a25d1db698acf61b55a9595af57414f44a3052bc6e
bbb_addr=0xbbb3d185c70b6720c65bc434940533983cbd9eb7746408740faea9d0adae9c71
ccc_addr=0xccc5b889f29d1d1ebbd9130911c759e8426a73ca67ad558a1e5373c104c395c1
Step 2: Funding Owner Accounts
Each of our owner accounts needs a small amount of APT to pay for gas when interacting with the blockchain.
For this tutorial, I’m transferring 1 APT to each account.
If you’re using the testnet, you can obtain APT from a faucet. On mainnet, you’ll need to transfer APT from an existing account.
Step 3: Creating the Multisig Account
Now we’re ready to create our multisig account. We’ll use the first owner account to create the multisig and add the other two owners. We’ll set the signature threshold to 2, meaning any two owners must approve a transaction before it can be executed.
aptos multisig create \
--additional-owners $bbb_addr \
--additional-owners $ccc_addr \
--num-signatures-required 2 \
--private-key-file aaa.key\
--assume-yes
The command will output some information, including the new multisig account address. Save this address as we’ll need it throughout the rest of this tutorial.
Here the output should look something like:
{
"Result": {
"multisig_address": "e00538ccfe0b96621755e40e1202ddb99838babe2ae4652e9473aa719f1a09e1",
"transaction_hash": "0xca08f21be8a68091e551754bf2af842144bfe444976d9529ce927872f7963adc",
"gas_used": 1694,
"gas_unit_price": 100,
"sender": "aaada5932a10d899c46307a25d1db698acf61b55a9595af57414f44a3052bc6e",
"sequence_number": 0,
"success": true,
"timestamp_us": 1747748767156589,
"version": 6731543805,
"vm_status": "Executed successfully"
}
}
# Save the multisig address in an environment variable for easy reference
multisig_addr=0xbd699a09b4dda1bc09b4a6d2fc48dfd0b1c01c0ae6bac7152f8682f6252dc737
Step 4: Funding the Multisig Account
Just like our owner accounts, the multisig account itself needs some APT to execute transactions. Let’s transfer a small amount ( 1 APT) to the multisig account
Step 5: Verifying the Multisig Configuration
Before we start using our multisig account, let’s verify that it’s configured correctly.
Checking Required Signatures
First, let’s confirm that our multisig requires 2 signatures as we intended:
aptos move view \
--function-id 0x1::multisig_account::num_signatures_required \
--args address:"$multisig_addr"
The output should be:
{
"Result": [
"2"
]
}
Verifying Owners
Let’s also check that all three owners are correctly associated with the multisig:
aptos move view \
--function-id 0x1::multisig_account::owners \
--args address:"$multisig_addr"
The output should be:
{
"Result": [
[
"0xbbb3d185c70b6720c65bc434940533983cbd9eb7746408740faea9d0adae9c71",
"0xccc5b889f29d1d1ebbd9130911c759e8426a73ca67ad558a1e5373c104c395c1",
"0xaaada5932a10d899c46307a25d1db698acf61b55a9595af57414f44a3052bc6e"
]
]
}
Checking Transaction Sequence Number
Each multisig transaction is assigned a sequence number. For a new multisig account, the last executed transaction sequence number should be 0:
aptos move view \
--function-id 0x1::multisig_account::last_resolved_sequence_number \
--args address:"$multisig_addr"
This should return:
{
"Result": [
"0"
]
}
Step 6: Creating a Transaction Proposal
Now, let’s create our first transaction using the multisig account. We’ll set up a simple APT transfer to another address.
First, let’s define the recipient address and the amount we want to send:
RECIPIENT_ADDRESS=0x49fe344c4e0fcf3f90721b3c4b20c1a599f70348a0a772efe3933ff4d0578b9e
AMOUNT=10000000 # 0.1 APT
Now, let's create the transaction proposal using aaa's private key:
aptos multisig create-transaction \
--multisig-address $multisig_addr \
--private-key-file aaa.key\
--function-id 0x1::aptos_account::transfer_coins \
--type-args 0x1::aptos_coin::AptosCoin \
--args address:$RECIPIENT_ADDRESS u64:$AMOUNT
Aptos Transacion
Here the output should look something like:
{
"Result": {
"transaction_hash": "0x9c38c99a4e66822271f633472c0767672a40de490e7a0b2cf52d45a9ec96a54e",
"gas_used": 519,
"gas_unit_price": 100,
"sender": "aaada5932a10d899c46307a25d1db698acf61b55a9595af57414f44a3052bc6e",
"sequence_number": 1,
"success": true,
"timestamp_us": 1747749060331918,
"version": 6731549770,
"vm_status": "Executed successfully"
}
}
This command creates a transaction proposal with sequence number 1. The transaction specifies:
- The function to call: 0x1::aptos_account::transfer_coins
- The type argument (which coin to transfer):0x1::aptos_coin::AptosCoin
- The function arguments: the recipient address and the amount
Since aaa created the transaction, their approval is automatically counted. However, we still need one more approval to reach our threshold of 2 signatures.
Step 7: Approving the Transaction
Now, let’s have bbb approve the transaction:
aptos multisig approve \
--multisig-address $multisig_addr \
--sequence-number 1 \
--private-key-file bbb.key
Aptos Transacion
Here the output should look something like:
{
"Result": {
"transaction_hash": "0xf4a68c68bc9168bf63da89ce52007299f15a9581511ba626f724a3650a2ccdbe",
"gas_used": 512,
"gas_unit_price": 100,
"sender": "bbb3d185c70b6720c65bc434940533983cbd9eb7746408740faea9d0adae9c71",
"sequence_number": 0,
"success": true,
"timestamp_us": 1747749402504574,
"version": 6731556647,
"vm_status": "Executed successfully"
}
}
This command adds bbb’s approval to the transaction proposal with sequence number 0.
We can verify the pending transaction and check that it has the required approvals:
aptos move view \
--function-id 0x1::multisig_account::get_pending_transactions \
--args address:"$multisig_addr"
This should return:
{
"Result": [
[
{
"creation_time_secs": "1747749060",
"creator": "0xaaada5932a10d899c46307a25d1db698acf61b55a9595af57414f44a3052bc6e",
"payload": {
"vec": [
"0x0000000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e740e7472616e736665725f636f696e73010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e000220d2cf7dd5d8ac235e59c94e26262c78976024892032dc6a74e9073e6e433cff23088096980000000000"
]
},
"payload_hash": {
"vec": []
},
"votes": {
"data": [
{
"key": "0xaaada5932a10d899c46307a25d1db698acf61b55a9595af57414f44a3052bc6e",
"value": true
},
{
"key": "0xbbb3d185c70b6720c65bc434940533983cbd9eb7746408740faea9d0adae9c71",
"value": true
}
]
}
}
]
]
}
This should show the details of our pending transaction, including the approvers (aaa and bbb).
Step 8: Executing the Transaction
Now that we have collected the required number of signatures (2), we can execute the transaction. Any of the owners can execute a transaction once it has enough approvals:
aptos multisig execute \
--multisig-address $multisig_addr \
--private-key-file aaa.key
Aptos Transacion
Here the output should look something like:
{
"Result": {
"transaction_hash": "0x6c084d9f00863c86a2e64d3849c4c72b5381f594b683c7199de77116d0cb16e4",
"gas_used": 19,
"gas_unit_price": 100,
"sender": "aaada5932a10d899c46307a25d1db698acf61b55a9595af57414f44a3052bc6e",
"sequence_number": 2,
"success": true,
"timestamp_us": 1747749828315657,
"version": 6731567900,
"vm_status": "Executed successfully"
}
}
This command will execute the pending transaction with sequence number 0, transferring 1 APT to our recipient address.
To verify that the transaction was executed, we can check the last resolved sequence number again:
aptos move view \
--function-id 0x1::multisig_account::last_resolved_sequence_number \
--args address:"$multisig_addr"
This should now return:
{
"Result": [
"1"
]
}
Advanced Multisig Features
While we’ve covered the basics of creating and using a multisig account on Aptos, there are several advanced features and considerations worth exploring:
Rejecting Transactions
If an owner disagrees with a proposed transaction, they can reject it:
aptos multisig reject \
--multisig-address $multisig_addr \
--sequence-number 2\
--private-key-file ccc.key
However, as long as the required number of signatures is met, the transaction can still be executed despite rejections.
Removing Owners
The multisig configuration can be updated to remove owners:
aptos multisig create-transaction \ ─╯
--multisig-address $multisig_addr \
--private-key-file aaa.key \
--function-id 0x1::multisig_account::remove_owner \
--args address:$ccc_addr
Like any other multisig transaction, this requires the threshold number of approvals before it can be executed.
Adding Owners
Similarly, new owners can be added to the multisig:
aptos multisig create-transaction \
--multisig-address $multisig_addr \
--private-key-file aaa.key \
--function-id 0x1::multisig_account::add_owner \
--args address:$ccc_addr
Like any other multisig transaction, this requires the threshold number of approvals before it can be executed.
Changing the Signature Threshold
The number of required signatures can also be updated:
aptos multisig create-transaction \ ─╯
--multisig-address $multisig_addr \
--private-key-file aaa.key \
--function-id 0x1::multisig_account::update_signatures_required \
--args u64:3
This would change the requirement from 2 signatures to 3, meaning all owners must approve to executed transaction.
Future Developments for Aptos Multisig
The Aptos multisig implementation is already robust, but there are several potential improvements on the horizon:
Weighted Voting
One exciting potential feature is weighted voting, where different owners could have different voting weights. This would be particularly valuable for DAOs and organizations with varied stakeholder influence.
Conclusion
Multisig accounts offer a major upgrade in blockchain security and governance. Aptos’s native support makes them efficient, secure, and easy to use with minimal overhead.
Whether you’re protecting personal assets, managing team funds, or securing a DAO treasury, multisig accounts add a crucial layer of safety. The slight added complexity is a small trade-off for the strong protection they provide.
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.