Skip to main content
A policy governs which transactions a wallet can authorize. Every wallet must have at least one policy attached before it can sign outbound transactions — Dakota’s policy engine default-denies any transaction on a wallet with zero attached policies ("transaction denied: No policies found for wallet", HTTP 403). Inbound deposits are independent of policies: an on-chain address can always receive crypto regardless of the wallet’s governance. Policies are versioned, mutable resources. You attach them to wallets, and a wallet can have multiple policies layered on top of one another. The policy engine evaluates all attached policies for every transaction and applies the result.

Anatomy of a Policy

A policy is three things:
  1. A signer group that governs the policy itself. Future mutations of the policy — adding rules, deleting it, updating limits — must be signed by members of this group via the endorsed-request flow. It can be the same group attached to the wallet, or a separate admin group for stricter compartmentalization.
  2. One or more rules. Each rule has a rule_type, an action (allow or deny), and a definition whose shape depends on the rule type.
  3. Metadata. A human-readable name and optional description.

Rule Types

There are three rule types. Each evaluates a different aspect of the transaction.

approval_threshold

Requires a minimum number of valid signatures from the policy’s signer group.
  • threshold — minimum number of signers required.
  • The rule always applies to every transaction (it’s a count check, not a conditional).
  • If the threshold is met → emit the rule’s action (allow or deny). If not met → emit the inverted action.
The minimum permissive policy — “any single member can authorize anything” — is approval_threshold with threshold: 1 and action: allow.

amount_threshold

Sets transaction-value limits. Useful for tiered approval (small transfers single-sig, large transfers multi-sig) or hard caps.
  • min_amount — integer in the smallest currency unit (USD → cents). The example above is $10,000.00.
  • threshold — number of approvals required to override. 0 means hard deny; higher values mean N approvers can let it through.
  • asset — object with id (asset symbol, e.g. USD) and name (display name).
  • The rule applies only when the transaction’s amount in asset is at or above min_amount. Below the threshold, the rule does not apply (does not contribute allow or deny).

address_list

Restricts which on-chain destinations a wallet can send to. Allow-list (only these) or deny-list (block these).
  • The rule applies only when the destination address is in the addresses list.
  • For an allow-list, set action: allow and pair with a default-deny in another rule (or rely on the policy engine’s default-deny on no-applicable-policy).
  • For a deny-list, set action: deny and the listed addresses are blocked outright.

Evaluation Order

For a given transaction, the policy engine:
  1. Loads every policy attached to the wallet. If zero policies, return deny immediately ("No policies found for wallet").
  2. For each policy, evaluates each rule in turn. A rule produces one of: applied + allow, applied + deny, or not-applicable.
  3. Aggregates per policy: if any rule denies → policy = deny. Else if any rule allows → policy = allow. Else (no rule applied) → policy = not-applicable.
  4. Aggregates across policies: if any policy denies → transaction = deny. Else if any policy allows → transaction = allow. Else (no applicable policy) → transaction = deny (default).
Translation: deny wins, allow loses, silence is deny. Layering policies is safe — adding more policies can only block transactions, never relax existing controls.

Lifecycle

Policy creation itself is not endorsed — it’s a regular API request authenticated only by your API key. Once the policy exists, every subsequent mutation goes through the endorsed-request flow: canonicalize the intent per RFC 8785 JCS, sign with ECDSA P-256, encode as DER + base64.

Practical Examples

”Default permissive” — single signature, no restrictions

For sandbox testing or low-risk accounts:

“Tiered approval by amount” — single-sig under $10k, dual-sig above

The deny-wins logic blocks single-sig above $10k; the second approval_threshold rule lets dual-sig through.

”Sanctions deny-list” — block specific addresses outright

Stack this alongside other policies — its deny will override any allow from sibling policies.