AURA

Quick Start

Create your first AURA treasury and submit a proposal in under 5 minutes using the TypeScript SDK.

Install

npm install @aura-protocol/sdk-ts @solana/web3.js bn.js

Current published version: @aura-protocol/sdk-ts@0.2.13

Connect

import { Connection, Keypair } from "@solana/web3.js";
import { Aura, AURA_PROGRAM_ID } from "@aura-protocol/sdk-ts";

// Load your funded devnet keypair
const keypair = Keypair.fromSecretKey(/* your secret key bytes */);

const aura = new Aura({
  rpcUrl: "https://api.devnet.solana.com",
  keypair,
  // programId defaults to AURA_PROGRAM_ID = EaRoLVwL8EErDUeEMPHJ5QJeLVQZWJMtZcgmFzT9bhHs
});

Create a treasury

Aura.treasury.create injects timestamps automatically and applies sensible defaults for unspecified limits.

const { treasury, signature } = await aura.treasury.create({
  agentId: "my-agent-1",       // unique per owner — used in PDA seed
  dailyLimitUsd: 10_000,       // USD cents = $100/day
  perTxLimitUsd: 1_000,        // USD cents = $10/tx

  // Optional — defaults shown:
  // daytimeHourlyLimitUsd: dailyLimitUsd / 10   → 1_000
  // nighttimeHourlyLimitUsd: dailyLimitUsd / 20 → 500
  // velocityLimitUsd: dailyLimitUsd / 2          → 5_000
  // allowedProtocolBitmap: 31                    → all 5 protocols
  // maxSlippageBps: 100                          → 1%
  // maxQuoteAgeSecs: 300                         → 5 minutes
  // maxCounterpartyRiskScore: 70                 → 0–100 scale
  // bitcoinManualReviewThresholdUsd: 5_000       → $50
  // pendingTransactionTtlSecs: 900               → 15 minutes
});

console.log("Treasury PDA:", treasury.toBase58());
// Seeds: ["treasury", keypair.publicKey, "my-agent-1"]

Register a dWallet

Each chain needs its own DwalletRecord before proposals can be approved for that chain.

await aura.dwallet.register({
  treasury,
  chain: 2,                          // 0=Solana 1=Bitcoin 2=Ethereum 3=Polygon 4=Arbitrum 5=Optimism
  dwalletId: "dwallet-abc123",       // from Ika dWallet provisioning
  address: "0xYourEthAddress",       // native address on the target chain
  balanceUsd: 5_000,                 // USD cents — balance hint
});

Propose a transaction

const signature = await aura.treasury.propose({
  treasury,
  amountUsd: 250,                    // USD cents = $2.50
  chain: 2,                          // Ethereum
  recipient: "0xRecipientAddress",
  txType: 0,                         // 0=Transfer 1=DeFiSwap 2=LendingDeposit 3=NFTPurchase 4=ContractInteraction

  // Optional policy telemetry:
  // counterpartyRiskScore: 15,      // 0–100
  // quoteAgeSecs: 60,               // seconds since price quote
  // expectedOutputUsd: 248,         // for slippage check
  // actualOutputUsd: 247,
});

The proposal goes through evaluate_transaction in aura-policy:

  1. Scoped pause check
  2. Budget envelope check
  3. Per-tx limit: 250 ≤ 1_000
  4. Daily limit: spent_today + 250 ≤ 10_000
  5. Time window, protocol, slippage, quote freshness, counterparty risk...
  6. Velocity limit check

If all pass, a PendingTransaction account is created on-chain.

Read treasury state

const account = await aura.treasury.get(treasury);

console.log("Agent ID:", account.agentId);
console.log("Paused:", account.paused);
console.log("Total transactions:", account.totalTransactions.toString());
console.log("Daily limit:", account.policyConfig.dailyLimitUsd.toString());

Or derive the PDA and fetch by owner + agentId:

const { treasury: pda, account } = await aura.treasury.getForOwner(
  keypair.publicKey,
  "my-agent-1",
);

Using the Low-Level Client

For full control — all 67 instructions, manual BN values, instruction composition:

import { AuraClient, AURA_PROGRAM_ID, deriveTreasuryAddress } from "@aura-protocol/sdk-ts";
import { Connection } from "@solana/web3.js";
import BN from "bn.js";

const client = new AuraClient({
  connection: new Connection("https://api.devnet.solana.com", "confirmed"),
  programId: AURA_PROGRAM_ID,
});

// Derive the treasury PDA manually
const [treasury] = deriveTreasuryAddress(owner.publicKey, "my-agent-1");

// Build and send an instruction without broadcasting
const { instruction } = await client.createTreasuryInstruction({
  owner: owner.publicKey,
  args: { /* full CreateTreasuryArgs with BN values */ },
});

// Compose with other instructions in one transaction
await client.sendInstructions(owner, [instruction, otherInstruction]);

Error Handling

Program errors start at code 6000. Use AuraErrorCode and isAuraError:

import { AuraErrorCode, isAuraError } from "@aura-protocol/sdk-ts";

try {
  await aura.treasury.propose({ ... });
} catch (err) {
  if (isAuraError(err, AuraErrorCode.PendingTransactionExists)) {
    console.log("A proposal is already pending — cancel it first");
  } else if (isAuraError(err, AuraErrorCode.ExecutionPaused)) {
    console.log("Treasury is paused");
  }
}

Common errors:

CodeNameMeaning
6004PendingTransactionExistsOnly one pending proposal allowed at a time
6005NoPendingTransactionNo proposal to execute or cancel
6006DWalletNotConfiguredNo dWallet registered for the target chain
6015ConfidentialGuardrailsNotConfiguredConfidential path requires ciphertext accounts
6017ExecutionPausedTreasury is paused
6018PendingTransactionExpiredProposal TTL elapsed
6027TimelockNotElapsedDangerous config change timelock still active

What's Next

On this page