Treasury API Reference
Canister: treasury Candid Interface: treasury.did — the live .did is the source of truth for all method names and signatures. Last reconciled: 2026-08-25 (bl-1404 — unified from the former treasury.md quick-ref and treasury-api.md comprehensive guide; signatures re-derived from the live Candid interface).
Overview
The treasury canister is the DAO's on-chain financial system of record. It provides role-gated payout management with multi-signature approval, membership-payment records, conditional and milestone-based escrow, annual profit-sharing and patronage distributions, DOM-token vesting, an internal sub-account ledger, a digital-asset registry, cross-entity transfer records, and point-in-time asset snapshots.
Per ADR-014 (records on-chain, business logic off-chain), the treasury records financial state and the Subchapter-T-required audit trail on-chain; oracle-bridge orchestrates the off-chain workflow and calls in over the service-principal auth boundary.
Method groups
- Payout management — propose / approve / execute / retry payouts, with a governance-orchestrated entrypoint
- Payment records — membership-fee payment history (Stripe-backed, written by oracle-bridge)
- Escrow — conditional single-release escrow
- Milestone escrow — multi-milestone escrow with approve / release / dispute / resolve
- Profit sharing — annual member distributions with proration
- Patronage credits — Subchapter-T patronage allocation, claim, and reversion
- Vesting — DOM-token vesting schedules (federation partner token locks)
- Sub-accounts & internal transfers — the account-type ledger with an audit trail
- Digital-asset registry & reconciliation — asset entries, cross-entity transfers, snapshots, floor-value calculation
- Configuration & backup — canister wiring, signing key, state export/import
Authentication
Methods authenticate on the caller principal via ic_cdk::caller(). The common access levels are:
- Controllers — canister controllers (configuration, escrow/vesting/registry writes, distribution lifecycle)
- oracle-bridge service principal — the off-chain orchestrator; gates payout proposal/approval/execution (AUTH-003.3) and payment recording
principals.is_authorizedOR-gate — several lifecycle processors acceptcontroller OR the configured oracle-bridge service principal OR principals.is_authorized(caller, "treasury:lifecycle:process")— an OR, never an AND (bl-1159)- Release authority — escrow releases are gated to the escrow's configured
ReleaseAuthority(Controller / Governance / a specific principal) - Member — a member claims their own distribution / patronage
Auth-service note (2026-04-11): session-token variants (
get_payment_history_with_session,get_payment_count_with_session) andset_auth_servicewere removed when the auth-service canister was decommissioned. Session validation now happens off-chain in oracle-bridge; the on-chain queries are keyed on principal. If you are migrating from an older client, useget_payment_history/get_payment_countbelow.
Core Types
type PaymentType = variant { Initial; Renewal };
type PaymentStatus = variant { Succeeded; Failed; Pending };
type PaymentRecord = record {
id: nat64;
user_id: principal;
amount: nat;
currency: text;
payment_type: PaymentType;
status: PaymentStatus;
stripe_payment_intent_id: text;
receipt_number: opt text;
payment_method_last4: text;
timestamp: nat64;
};
type TokenType = variant { ICP; DOM };
type PayoutStatus = variant { Proposed; Approved; Executed; Failed };
type Payout = record {
id: nat64;
to: principal;
amount: nat;
reason: text;
token_type: TokenType;
status: PayoutStatus;
approved_by: vec principal;
proposed_at: nat64;
executed_at: opt nat64;
tx_id: opt text;
};
type TreasuryConfig = record {
required_approvals: nat32;
dom_token_canister: opt principal;
};
type TreasuryPolicy = record {
max_single_payout: nat;
daily_limit: nat;
required_approvals: nat32;
large_payout_threshold: nat;
allowed_tokens: vec TokenType;
};Additional record/variant types back the escrow, milestone, profit-sharing, patronage, vesting, sub-account, digital-asset, entity-transfer, and snapshot method groups — see the live .did for their full definitions.
Health
health (query)
health : () -> (text) query;Health check for uptime monitoring. Returns a status string.
dfx canister call treasury healthPayout Management
Payouts move funds out of the treasury. A payout is proposed, gathers approvals up to the configured threshold, and is then executed. Proposal/approval/execution are gated to the oracle-bridge service principal (AUTH-003.3); retry_payout is controllers-only.
propose_payout
propose_payout : (principal, nat, text, TokenType) -> (variant { Ok: nat64; Err: text });Create a new payout proposal. Parameters: recipient principal, amount (smallest token units, e8s), reason text, and TokenType (ICP or DOM). Returns the new payout ID.
const res = await treasuryActor.propose_payout(
Principal.fromText("aaaaa-aa"),
BigInt(100_000_000), // 1 DOM (8 decimals)
"Developer compensation - Q1",
{ DOM: null }
);
if ('Ok' in res) console.log("Payout ID:", res.Ok);propose_payout_with_options
propose_payout_with_options : (principal, nat, text, TokenType, opt nat64, opt bool, opt nat64) -> (variant { Ok: nat64; Err: text });Propose a payout with extended spending-authority options (BL-087): amount_usd_cents (USD value for threshold enforcement), emergency flag, and a governance proposal_id for above-threshold payouts. All three are optional.
propose_payout_for_governance_proposal
propose_payout_for_governance_proposal : (nat64, principal, nat, text, TokenType) -> (variant { Ok: nat64; Err: text });Dedicated governance-orchestrated payout entrypoint. Gated by the OR-gate (oracle-bridge principal OR principals.is_authorized(caller, "treasury:payout:execute")). Independently verifies (to, amount, token_type) against the on-chain governance proposal (category == Treasury, status == Executing, execution_data JSON match) and deduplicates retries by proposal_id.
approve_payout
approve_payout : (nat64) -> (variant { Ok: text; Err: text });Add an approval to a payout proposal (oracle-bridge principal only). When the approval count reaches the configured threshold the payout becomes eligible for execution.
execute_payout
execute_payout : (nat64) -> (variant { Ok: text; Err: text });Execute an approved payout, transferring funds to the recipient. execute_payout ceiling-gates every caller that is NOT the configured oracle_bridge principal against auto_execute_ceiling (USD cents; default 0 = human-execute-only).
retry_payout
retry_payout : (nat64) -> (variant { Ok: text; Err: text });Retry a failed payout (controllers only).
Queries
get_payout : (nat64) -> (opt Payout) query;
list_payouts : (opt PayoutStatus) -> (vec Payout) query;
get_payout_history : (nat32, nat32) -> (vec Payout) query; // (page, page_size)Multi-sig payout workflow
// 1. Propose (oracle-bridge principal)
const { Ok: payoutId } = await treasuryActor.propose_payout(
Principal.fromText("aaaaa-aa"), BigInt(50_000_000), "Marketing budget", { DOM: null }
);
// 2. Approve until threshold reached
await treasuryActor.approve_payout(payoutId);
// 3. Execute
await treasuryActor.execute_payout(payoutId);Payment Records
Membership-fee payments recorded on-chain after Stripe confirmation. Written by oracle-bridge (controllers only); read by suites and admin surfaces.
record_payment
record_payment : (principal, nat, PaymentType, text, text, opt text) -> (nat64);Record a payment. Parameters: user_id, amount, PaymentType, stripe_payment_intent_id, payment_method_last4, receipt_number (opt). Returns the new payment ID. Note: returns a bare nat64, not a Result.
get_payment_history (query)
get_payment_history : (principal, nat32, nat32, opt PaymentType, opt nat64, opt nat64) -> (vec PaymentRecord) query;Paginated payment history. Parameters: user_id, page, page_size, payment_type (opt filter), from_date / to_date (opt nanosecond bounds).
const payments = await treasuryActor.get_payment_history(
Principal.fromText(userId), 0, 10, [], [], []
);get_payment_count (query)
get_payment_count : (principal, opt PaymentType, opt nat64, opt nat64) -> (nat64) query;Count payments for a user with the same optional filters.
cleanup_old_payments
cleanup_old_payments : () -> (nat64);GDPR/retention processor — removes payments past the retention window. Returns the deleted count as a bare nat64 (a refusal traps). Auth: the treasury:lifecycle:process OR-gate (bl-1159).
Configuration (controllers only)
Canister wiring and policy. Highlights:
set_oracle_bridge_principal : (principal) -> (variant { Ok; Err: text });
get_oracle_bridge_principal : () -> (opt principal) query;
set_principals_canister : (principal) -> (variant { Ok; Err: text });
clear_principals_canister : () -> (variant { Ok; Err: text }); // kill switch for the is_authorized OR-gate
get_principals_canister : () -> (opt principal) query;
set_governance_canister : (principal) -> (variant { Ok; Err: text }); // for the anti-drain get_proposal query
get_governance_canister : () -> (opt principal) query;
set_governance_service_principal : (principal) -> (variant { Ok; Err: text });
get_governance_service_principal : () -> (opt principal) query;
set_auto_execute_ceiling : (nat64) -> (variant { Ok; Err: text }); // USD cents; default 0 = human-execute-only
get_auto_execute_ceiling : () -> (opt nat64) query;
set_dom_token_canister : (principal) -> (variant { Ok; Err: text });
set_required_approvals : (nat32) -> (variant { Ok; Err: text });
get_treasury_config : () -> (TreasuryConfig) query;
set_policy : (TreasuryPolicy) -> (variant { Ok; Err: text });
get_policy : () -> (TreasuryPolicy) query;Oracle-bridge notification + request signing (BL-002.2 / bl-1177): set_oracle_bridge : (text), clear_oracle_bridge : (), initialize_signing_key : (), get_signing_public_key : () query. The Ed25519 signing secret is generated in-canister and never leaves it; get_signing_public_key exposes only the derived public key for oracle-bridge's dynamic discovery. transform_http_response supports IC HTTP outcalls (system use).
Additional live method groups
The following method groups are live in the canonical .did. Their full per-method signatures and parameter semantics are authoritative there; the summaries below name each method so you can find it. (A method-by-method expansion of these groups is a documentation follow-up — file against docs if you need one.)
Escrow
Conditional single-release escrow with a configurable ReleaseAuthority.
create_escrow,release_escrow(optional partial-release amount),cancel_escrow,get_escrow(query),list_escrows(query),process_expired_escrows(lifecycle processor)
Milestone escrow
Multi-milestone escrow with per-milestone approval, release, and dispute resolution.
create_milestone_escrow,approve_milestone,release_milestone,dispute_milestone,resolve_dispute,get_milestone_status(query)
Profit sharing (annual member distributions)
Proration-aware annual distributions (26 CFR §1.6001-1 audit trail; ProrationBasis distinguishes a supplied join date from an assumed full year — bl-1094).
set_distribution_cap,initiate_profit_sharing,approve_distribution,cancel_distribution,execute_distribution,claim_profit_share,claim_profit_share_for(service-vouched twin, ADR-014 C1),process_unclaimed_distributions,get_distribution_status(query),get_member_distribution(query),get_my_distribution(query),list_distributions(query)
Patronage credits (Subchapter T)
initialize_member_equity_accounts,allocate_patronage,claim_patronage,claim_patronage_for(service-vouched twin),process_patronage_reversions,get_member_patronage(query),set_patronage_claim_window
Vesting (BL-088 — DOM-token federation-partner locks)
create_vesting_schedule,get_vesting_schedule(query),list_vesting_schedules(query),get_vested_balance(query),pause_vesting,resume_vesting,forfeit_vesting
Sub-accounts & internal transfers (BL-075.1 / BL-075.2)
The account-type ledger (Operating, Capital, MemberEquity, Escrow, Restricted, DigitalAsset, Reconciliation) with an audit trail.
create_sub_account,get_sub_account(query),list_sub_accounts(query),deposit_to_sub_account,transfer_between_accounts,get_transfer_history(query)
Digital-asset registry, cross-entity transfers & reconciliation (BL-079.1 / BL-077 / BL-079.2)
- Registry:
register_digital_asset,update_digital_asset,remove_digital_asset,list_digital_assets(query) - Cross-entity transfers:
record_entity_transfer,get_entity_transfers(query),get_entity_balance_summary(query) - Reconciliation:
create_asset_snapshot,get_snapshot(query),diff_snapshots(query),calculate_floor_value(query) - Asset contributions:
record_asset_contribution,get_member_contributions(query)
Balance & backup
get_treasury_balance : () -> (variant { Ok: TreasuryBalance; Err: text })export_state : () -> (blob) query(public — financial data is auditable),import_state : (blob)(controller-only)
Error Handling
Most update methods return variant { Ok; Err : text } (or Ok : nat64 / Ok : text). Handle both arms:
const res = await treasuryActor.execute_payout(payoutId);
if ('Err' in res) {
console.error("Payout failed:", res.Err);
}Common error strings:
| Error | Cause | Resolution |
|---|---|---|
Unauthorized / auth error | Caller is not a controller / not the oracle-bridge principal / not authorized | Use the authorized identity |
Payment not found / Payout not found | Invalid ID | Verify the ID exists |
Payout not approved | Executing before the approval threshold is met | Collect the required approvals first |
| Insufficient-balance error | Treasury balance below the payout amount | Fund the treasury |
Related
- Treasury quick-reference index — all canister APIs
- dom-token — the DOM ledger the treasury transacts against
- governance — proposals that orchestrate treasury payouts