Multi-Agent Transactions
Multi-agent transactions enable multiple independent signers to authorize a single transaction on Aptos, allowing complex operations that require coordination between different accounts. This feature is essential for marketplaces, atomic swaps, escrow services, and any scenario where multiple parties must agree to a state change.
Overview#
Traditional blockchain transactions have a single sender who pays gas and authorizes all operations. Multi-agent transactions extend this model by allowing additional signers (secondary signers) to authorize operations on their own resources within the same atomic transaction. All signers must provide signatures before the transaction can execute, ensuring all parties consent to the operation.
Technical Implementation#
Multi-agent transactions use a special transaction payload that includes addresses of all required signers. Each signer must sign the same transaction hash, and the transaction only executes if all signatures are valid.
module 0x1::marketplace {
use std::signer;
use aptos_framework::coin;
use aptos_framework::aptos_coin::AptosCoin;
struct Listing has key {
price: u64,
owner: address
}
struct NFT has key, store {
id: u64,
metadata: vector<u8>
}
// Requires both buyer and seller signatures
public entry fun purchase_nft(
buyer: &signer,
seller: &signer,
nft_id: u64
) acquires NFT, Listing {
let seller_addr = signer::address_of(seller);
let buyer_addr = signer::address_of(buyer);
// Get listing from seller
let listing = borrow_global<Listing>(seller_addr);
let price = listing.price;
// Transfer payment from buyer to seller
coin::transfer<AptosCoin>(buyer, seller_addr, price);
// Transfer NFT from seller to buyer
let nft = move_from<NFT>(seller_addr);
move_to(buyer, nft);
// Clean up listing
let Listing { price: _, owner: _ } = move_from<Listing>(seller_addr);
}
}
Creating Multi-Agent Transactions#
TypeScript SDK#
import { Aptos, Account, AccountAuthenticator } from "@aptos-labs/ts-sdk";
const aptos = new Aptos();
// Create accounts
const buyer = Account.generate();
const seller = Account.generate();
// Build multi-agent transaction
const transaction = await aptos.transaction.build.multiAgent({
sender: buyer.accountAddress,
secondarySignerAddresses: [seller.accountAddress],
data: {
function: "0x1::marketplace::purchase_nft",
functionArguments: [seller.accountAddress, 123]
}
});
// Both parties sign
const buyerAuth = aptos.transaction.sign({ signer: buyer, transaction });
const sellerAuth = aptos.transaction.sign({ signer: seller, transaction });
// Submit with all signatures
const committedTxn = await aptos.transaction.submit.multiAgent({
transaction,
senderAuthenticator: buyerAuth,
additionalSignersAuthenticators: [sellerAuth]
});
await aptos.waitForTransaction({ transactionHash: committedTxn.hash });
Python SDK#
from aptos_sdk.client import RestClient
from aptos_sdk.account import Account
from aptos_sdk.transactions import EntryFunction, TransactionPayload
client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")
buyer = Account.generate()
seller = Account.generate()
# Build multi-agent transaction
payload = EntryFunction.natural(
"0x1::marketplace",
"purchase_nft",
[],
[seller.address(), 123]
)
# Create and sign with both accounts
signed_txn = client.create_multi_agent_bcs_transaction(
buyer, [seller], payload
)
tx_hash = client.submit_bcs_transaction(signed_txn)
client.wait_for_transaction(tx_hash)
Real-World Use Cases#
-
NFT Marketplaces: Execute atomic NFT sales where the buyer transfers payment and seller transfers the NFT in a single transaction, eliminating front-running or partial execution risks.
-
Atomic Swaps: Enable trustless peer-to-peer token swaps where both parties exchange assets simultaneously without requiring an intermediary or escrow.
-
Joint Account Operations: Implement shared accounts or vaults that require multiple parties to approve withdrawals or significant operations.
-
Escrow Releases: Coordinate between buyer, seller, and escrow agent to release funds and assets when conditions are met.
-
Multi-Party Gaming: Execute game moves or state transitions that require agreement from multiple players in competitive or cooperative games.
-
Cross-Protocol Operations: Coordinate actions across different protocols where multiple protocol administrators must authorize complex operations.
Advanced Patterns#
Three-Way Transactions#
public entry fun escrow_complete(
buyer: &signer,
seller: &signer,
escrow_agent: &signer,
item_id: u64
) acquires EscrowedItem, Payment {
// All three parties must sign
// Agent verifies conditions
// Buyer gets item
// Seller gets payment
// Agent gets fee
}
Conditional Multi-Agent#
public entry fun conditional_transfer(
sender: &signer,
receiver: &signer,
amount: u64,
condition_met: bool
) {
assert!(condition_met, ECONDITION_NOT_MET);
// Both parties acknowledge the condition is met
// Execute transfer
}
Best Practices#
Verify All Signers: Always validate that all required signers have provided valid signatures before executing critical operations.
Atomic Operations: Structure multi-agent transactions to be truly atomic - either all operations succeed or all fail together.
Clear Responsibilities: Document which signer pays gas (primary signer) and what each secondary signer authorizes.
Timeout Mechanisms: Implement expiration times for multi-agent transaction proposals to prevent indefinite pending states.
Off-Chain Coordination: Use off-chain communication channels to coordinate signature collection before submitting the final transaction.
Gas Estimation: The primary signer pays all gas fees, so ensure they have sufficient funds for the entire transaction.
Order Independence: Design functions so that the order of secondary signers doesn't matter when possible to simplify coordination.
Signature Collection Flow#
- Transaction Construction: Primary signer builds the transaction with all secondary signer addresses
- Hash Distribution: Share the transaction hash with all secondary signers
- Signature Collection: Each party signs the transaction hash independently
- Aggregation: Primary signer collects all signatures
- Submission: Submit the fully-signed transaction to the network
- Atomic Execution: All operations execute or fail together
Security Considerations#
Signature Verification: Never submit a multi-agent transaction without verifying all signatures are authentic and match expected signers.
Transaction Inspection: All signers should inspect the transaction details before signing to ensure they agree with the operations.
Replay Protection: Multi-agent transactions include sequence numbers to prevent replay attacks.
Partial Signing Attacks: Protect against scenarios where some signers might try to modify the transaction after others have signed.
Resource Ownership: Verify that all signers actually own or control the resources the transaction will modify.
Comparison with Multi-Sig#
Multi-agent transactions differ from multi-sig accounts:
- Multi-Agent: Multiple independent accounts coordinate on a single transaction
- Multi-Sig: Single account controlled by multiple keys with threshold approval
Multi-agent is better for:
- Peer-to-peer interactions between distinct parties
- Operations involving resources from multiple accounts
- One-time coordinated actions
Multi-sig is better for:
- Shared account management
- Corporate treasury controls
- Ongoing governance of a single account
Related Concepts#
- Sponsored Transactions - Separate signer and fee payer
- Resource Accounts - Autonomous contract accounts
- Key Rotation - Change account keys
- Object Model - Alternative ownership patterns