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: [],
},
});
Simulate the transaction by passing in all additional public keys to secondarySignersPublicKeys
. (Optional)
const [userTransactionResponse] = await aptos.transaction.simulate.multiAgent(
{
signerPublicKey: alice.publicKey,
secondarySignersPublicKeys: [bob.publicKey],
transaction,
},
);
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.