AURA

dWallet Execution

How AURA uses Ika dWallet records to co-sign transactions across 6 chains without exposing a private key.

Why dWallet

Giving an AI agent a raw private key means the key can be extracted from memory, a compromised agent can drain the wallet instantly, and there is no on-chain record of what was authorized. Ika dWallet records solve all three: the agent never sees the key, every co-sign request is gated by the AURA program, and the audit trail lives on Solana.

Supported Chains

Chain IDs are u8 values used in ProposeTransactionArgs.target_chain and RegisterDwalletArgs.chain:

IDChainNotes
0SolanaNative; no bridge
1Bitcoinbitcoin_manual_review_threshold_usd applies
2EthereumEVM-compatible
3PolygonEVM-compatible
4ArbitrumEVM-compatible
5OptimismEVM-compatible

These map to the Chain enum in aura-policy: Bitcoin, Ethereum, Solana, Polygon, Arbitrum, Optimism.

Registering a dWallet

Before any proposal can be approved for a chain, a DwalletRecord must be registered against the treasury. One record per chain.

// Register an Ethereum dWallet (owner signs)
await aura.dwallet.register({
  treasury,
  chain: 2,                          // Ethereum
  dwalletId: "dwallet-abc123",       // from Ika dWallet provisioning
  address: "0xYourEthAddress",
  balanceUsd: 5_000,                 // USD cents — balance hint
});

RegisterDwalletArgs also accepts optional fields used in the full CPI path:

FieldTypeDescription
chainnumberChain ID 0–5
dwalletIdstringUnique dWallet identifier from Ika
addressstringNative address on the target chain
balanceUsdBNCurrent balance hint in USD cents
dwalletAccountPublicKey | nullIka dWallet account (for CPI path)
authorizedUserPubkeyUint8Array | nullAuthorized user public key bytes
messageMetadataDigestUint8Array | null32-byte metadata digest
publicKeyHexstring | nullRaw dWallet public key hex
timestampBNRegistration timestamp

Execution Flow

execute_pending Accounts

AccountSeed / SourcePurpose
operatorsignerDrives execution lifecycle
treasury["treasury", owner, agentId]Treasury PDA
message_approvalderived on dWallet programStores co-signed bytes
dwalletdWallet account from IkaThe co-signer
caller_programaura-core program IDCPI caller identity
cpi_authority["__ika_cpi_authority"] on aura-coreSigns the CPI
dwallet_program87W54kGYFQ1rgWqMeu4XTPHWXWmXSQCcjm8vCTfiq1oYIka dWallet program
dwallet_coordinatordWallet coordinator accountNetwork coordinator
external_liveness["external_liveness", treasury]Optional freshness check
system_program11111111111111111111111111111111Account creation

MessageApproval PDA Derivation

The MessageApproval PDA is derived on the Ika dWallet program, not on aura-core. The SDK exports deriveMessageApprovalAddress which mirrors aura-core::find_message_approval_pda:

import { deriveMessageApprovalAddress } from "@aura-protocol/sdk-ts";

const [messageApproval] = deriveMessageApprovalAddress(
  DWALLET_DEVNET_PROGRAM_ID,
  curveCode,              // 0=secp256k1, 1=secp256r1, 2=ed25519, 3=ristretto
  publicKeyBytes,         // raw dWallet public key bytes
  signatureSchemeCode,    // Ika signature scheme code
  messageDigest,          // 32-byte Keccak-256 digest
  messageMetadataDigest,  // optional 32-byte metadata digest
);

Seeds (in order):

  1. b"dwallet"
  2. u16_le(curveCode) ++ publicKey — chunked into 32-byte segments
  3. b"message_approval"
  4. u16_le(signatureSchemeCode)
  5. messageDigest (32 bytes)
  6. messageMetadataDigest (32 bytes, only if non-zero)

Bitcoin Manual Review

Bitcoin transactions above bitcoin_manual_review_threshold_usd (default: 5_000 USD cents = $50) are blocked by ViolationCode::BitcoinManualReview in evaluate_public_precheck. A guardian must approve via approve_pending_execution before execute_pending can proceed.

finalize_execution Accounts

AccountPurpose
operatorSigner driving finalization
treasuryTreasury PDA
message_approvalMessageApproval PDA with co-signed bytes
swarm_poolOptional — updated after finalization if swarm is configured
budget_envelopeOptional — updated after finalization if envelope is configured
exposure_groupOptional — updated after finalization if group is configured
external_livenessOptional — freshness check if liveness_config requires it

Security Properties

PropertyGuarantee
Key never exposedAgent receives signed bytes, not the private key
Authorization gatedOnly aura-core's cpi_authority PDA can request co-signs
Per-chain isolationEach chain has its own DwalletRecord
Audit trailEvery execute_pending and finalize_execution emits on-chain events
RevocableOwner can deregister a dWallet record at any time
Liveness checksLivenessConfig.require_dwallet_freshness can require a fresh ExternalLiveness record

On this page