Multi-Agent Transactions
Multi-agent transactions allow multiple accounts to participate in the logic of a Move contract.
This can be used to require multiple parties agree to a transaction before executing or to use resources from multiple accounts.
Writing Multi-Agent Transactions
Creating and executing a multi-agent transaction follows a similar flow to the simple transaction flow, but with several notable differences.
Instead of .simple
, multi-agent transaction functions use .multiAgent
.
Build the transaction by including secondarySignerAddresses
with a list of each additional agent.
Make sure to replace the function
field below with your entry function that requires multiple agents to sign.
const transaction = await aptos.transaction.build.multiAgent({
sender: alice.accountAddress,
secondarySignerAddresses: [bob.accountAddress],
data: {
// REPLACE WITH YOUR MULTI-AGENT FUNCTION HERE
function:
"<REPLACE WITH YOUR MULTI AGENT MOVE ENTRY FUNCTION> (Syntax {address}::{module}::{function})",
// Pass in arguments for the function you specify above
functionArguments: [],
},
});
(Optional) Simulate the transaction.
You can simulate the multi-agent transaction to preview the result before submitting it as follows:
const [userTransactionResponse] = await aptos.transaction.simulate.multiAgent(
{
signerPublicKey: alice.publicKey,
secondarySignersPublicKeys: [bob.publicKey],
transaction,
},
);
Note that signerPublicKey
is optional and can be omitted to skip the authentication key check for the sender. Similarly, secondarySignersPublicKeys
is optional and can be omitted to skip the authentication key check for all secondary signers. If you want to skip the authentication key check for only some of the secondary signers, you can provide secondarySignersPublicKeys
with the public keys of the specific signers you want to check, using undefined
as a placeholder for the others. For example, if bob
and carol
are secondary signers and you only want to check carol
’s authentication key, you can set secondarySignersPublicKeys: [undefined, carol.publicKey]
, leaving undefined
as a placeholder for bob
.
Sign once for each agent.
You will combine these signatures in the next step.
const aliceSenderAuthenticator = aptos.transaction.sign({
signer: alice,
transaction,
});
// Bob is a secondary signer for this transaction
const bobSenderAuthenticator = aptos.transaction.sign({
signer: bob,
transaction,
});
Submit the transaction by combining all agent signatures via the additionalSignerAuthenticators
parameter.
const committedTransaction = await aptos.transaction.submit.multiAgent({
transaction,
senderAuthenticator: aliceSenderAuthenticator,
additionalSignersAuthenticators: [bobSenderAuthenticator],
});
Lastly, wait for the transaction to resolve.
const executedTransaction = await aptos.waitForTransaction({
transactionHash: committedTransaction.hash,
});
Full TypeScript Multi-Agent Code Snippet
The below snippet needs light editing to work properly! (See below steps)
- Install
@aptos-labs/ts-sdk
by runningpnpm i @aptos-labs/ts-sdk
or using whichever package manager is most comfortable for you. - Update the below snippet to build a transaction that requires multi-agent signing.
- Replace the function and parameters below this comment:
// REPLACE WITH YOUR MULTI-AGENT FUNCTION HERE
- This customization is needed as there are no pre-made Aptos contracts which need multi-agent signatures. If you want to deploy your own example multi-agent contract, you can deploy the “transfer two by two” example Move contract.
- Replace the function and parameters below this comment:
/**
* This example shows how to use the Aptos SDK to send a transaction.
*/
import { Account, Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";
async function example() {
console.log(
"This example will create two accounts (Alice and Bob) and send a transaction transfering APT to Bob's account.",
);
// 0. Setup the client and test accounts
const config = new AptosConfig({ network: Network.DEVNET });
const aptos = new Aptos(config);
let alice = Account.generate();
let bob = Account.generate();
let carol = Account.generate();
console.log("=== Addresses ===\n");
console.log(`Alice's address is: ${alice.accountAddress}`);
console.log(`Bob's address is: ${bob.accountAddress}`);
console.log(`Carol's address is: ${carol.accountAddress}`);
console.log("\n=== Funding accounts ===\n");
await aptos.fundAccount({
accountAddress: alice.accountAddress,
amount: 100_000_000,
});
await aptos.fundAccount({
accountAddress: bob.accountAddress,
amount: 100_000_000,
});
await aptos.fundAccount({
accountAddress: carol.accountAddress,
amount: 100_000_000,
});
console.log("Done funding Alice, Bob, and Carol's accounts.");
// 1. Build
console.log("\n=== 1. Building the transaction ===\n");
const transaction = await aptos.transaction.build.multiAgent({
sender: alice.accountAddress,
secondarySignerAddresses: [bob.accountAddress],
data: {
// REPLACE WITH YOUR MULTI-AGENT FUNCTION HERE
function:
"<REPLACE WITH YOUR MULTI AGENT MOVE ENTRY FUNCTION> (Syntax {address}::{module}::{function})",
functionArguments: [],
},
});
console.log("Transaction:", transaction);
// 2. Simulate (Optional)
console.log("\n === 2. Simulating Response (Optional) === \n");
const [userTransactionResponse] = await aptos.transaction.simulate.multiAgent(
{
signerPublicKey: alice.publicKey,
secondarySignersPublicKeys: [bob.publicKey],
transaction,
},
);
console.log(userTransactionResponse);
// 3. Sign
console.log("\n=== 3. Signing transaction ===\n");
const aliceSenderAuthenticator = aptos.transaction.sign({
signer: alice,
transaction,
});
const bobSenderAuthenticator = aptos.transaction.sign({
signer: bob,
transaction,
});
console.log(aliceSenderAuthenticator);
console.log(bobSenderAuthenticator);
// 4. Submit
console.log("\n=== 4. Submitting transaction ===\n");
const committedTransaction = await aptos.transaction.submit.multiAgent({
transaction,
senderAuthenticator: aliceSenderAuthenticator,
additionalSignersAuthenticators: [bobSenderAuthenticator],
});
console.log("Submitted transaction hash:", committedTransaction.hash);
// 5. Wait for results
console.log("\n=== 5. Waiting for result of transaction ===\n");
const executedTransaction = await aptos.waitForTransaction({
transactionHash: committedTransaction.hash,
});
console.log(executedTransaction);
}
example();
Common Errors
NUMBER_OF_SIGNER_ARGUMENTS_MISMATCH
- This happens when you are attempting to do multi-agent signing for a function which does not require that number of accounts. For example, if you try using multiple signatures for a 0x1::aptos_account::transfer
function - it only expects one address, and so produces an error when more than one is provided.