AURA
Advanced

Budget

Scoped budget envelopes, cross-treasury exposure groups, and approval ladders.

Pre-alpha — not production ready

@aura-protocol/sdk-ts targets Solana devnet only. APIs may change without notice. Do not use for real funds until a stable release and audit are published.

configureBudgetEnvelope

Create or update a scoped sub-budget on the treasury. Envelopes can be scoped by chain, category, or protocol and have their own daily and weekly caps independent of the main policy limits.

// Build only
const instruction = await client.configureBudgetEnvelopeInstruction(
  accounts: ConfigureBudgetEnvelopeAccounts,
  args: ConfigureBudgetEnvelopeArgs,
);

// Build + send
await client.configureBudgetEnvelope(owner, accounts, args);
interface ConfigureBudgetEnvelopeAccounts {
  owner: PublicKey;
  treasury: PublicKey;
  budgetEnvelope: PublicKey;  // PDA: deriveBudgetEnvelopeAddress(treasury, envelopeId)
  systemProgram: PublicKey;
}
import { deriveBudgetEnvelopeAddress } from '@aura-protocol/sdk-ts';
import BN from 'bn.js';

const envelopeId = new BN(1);
const [budgetEnvelope] = deriveBudgetEnvelopeAddress(treasury, envelopeId);

await client.configureBudgetEnvelope(
  owner,
  {
    owner: owner.publicKey,
    treasury,
    budgetEnvelope,
    systemProgram: SystemProgram.programId,
  },
  {
    envelopeId,
    dailyLimitUsd: new BN(2_000),
    weeklyLimitUsd: new BN(10_000),
    scope: { chain: 2 },  // Ethereum only
    timestamp: new BN(Math.floor(Date.now() / 1000)),
  },
);

Pass budgetEnvelope in ProposeTransactionAccounts to enforce the envelope on a proposal.


initExposureGroup / joinExposureGroup

Create a cross-treasury aggregate cap. Multiple treasuries can join the same group; the group tracks total spend across all members.

// Init — creates the exposure group PDA
await client.initExposureGroup(authority, accounts, args);

// Join — adds a treasury to an existing group
await client.joinExposureGroup(authority, accounts);
interface InitExposureGroupAccounts {
  authority: PublicKey;    // owns the group — must be a signer
  exposureGroup: PublicKey;  // PDA: deriveExposureGroupAddress(authority, groupId)
  systemProgram: PublicKey;
}

interface JoinExposureGroupAccounts {
  authority: PublicKey;
  exposureGroup: PublicKey;
  treasury: PublicKey;  // treasury being added to the group
}
import { deriveExposureGroupAddress } from '@aura-protocol/sdk-ts';

const groupId = new Uint8Array(16).fill(1); // 16-byte group identifier
const [exposureGroup] = deriveExposureGroupAddress(authority.publicKey, groupId);

// Create the group
await client.initExposureGroup(
  authority,
  { authority: authority.publicKey, exposureGroup, systemProgram: SystemProgram.programId },
  { groupId: Array.from(groupId), limitUsd: new BN(100_000), timestamp: new BN(Math.floor(Date.now() / 1000)) },
);

// Add a treasury
await client.joinExposureGroup(
  authority,
  { authority: authority.publicKey, exposureGroup, treasury },
);

Pass exposureGroup in ProposeTransactionAccounts or FinalizeExecutionAccounts to enforce the group cap.


configureApprovalLadder

Set amount and risk-score thresholds that require escalating approval levels before a proposal can be executed.

// Build only
const instruction = await client.configureApprovalLadderInstruction(
  accounts: OwnerTreasuryAccounts,
  args: ConfigureApprovalLadderArgs,
);

// Build + send
await client.configureApprovalLadder(owner, accounts, args);
await client.configureApprovalLadder(
  owner,
  { owner: owner.publicKey, treasury },
  {
    levels: [
      { minAmountUsd: new BN(5_000), minRiskScore: 0, requiredLevel: 1 },
      { minAmountUsd: new BN(20_000), minRiskScore: 0, requiredLevel: 2 },
    ],
    denyAboveAmountUsd: new BN(50_000),
    denyAboveRiskScore: 90,
    timestamp: new BN(Math.floor(Date.now() / 1000)),
  },
);

When a proposal triggers an approval level, approvePendingExecution must be called by the owner or a guardian before executePending can proceed.

On this page