Composite Policies
Composite policies let you combine flat Policy objects into AND/OR trees. Use them when a single flat policy cannot express your authorization logic — for example, a treasury that allows small transfers without approval OR large transfers with approval, but always requires an allowlist check.
Primitives
import { policyAnd, policyOr, policyLeaf } from '@txfence/core'policyLeaf(policy, label?) — wraps a flat policy.
policyAnd(children, label?) — all children must pass.
policyOr(children, label?) — at least one child must pass.
Example — tiered treasury
const smallSpend = { ...basePolicy, maxSpendPerTx: { token: 'USDC', amount: 1000n, decimals: 6 } }
const largeSpend = { ...basePolicy, maxSpendPerTx: { token: 'USDC', amount: 50000n, decimals: 6 }, humanApprovalThreshold: { token: 'USDC', amount: 10000n, decimals: 6 } }
const allowlist = { ...basePolicy, allowedContracts: [...] }
const treasuryPolicy = policyAnd([
policyOr([
policyLeaf(smallSpend, 'small-spend'),
policyLeaf(largeSpend, 'large-spend'),
], 'spend-tier'),
policyLeaf(allowlist, 'allowlist'),
], 'treasury')An action passes if it satisfies either smallSpend or largeSpend, AND the allowlist check.
Wiring into createAgent
Pass policyNode instead of a flat policy:
const agent = createAgent(
{ chains: ['ethereum'], policies: smallSpend, signer }, // `policies` is still required even when using policyNode
adapters,
rpcUrls,
executor,
undefined, // 5: capLockProvider
undefined, // 6: metadataVerifier
undefined, // 7: approvalProvider
undefined, // 8: receiptStore
undefined, // 9: auditLog
undefined, // 10: telemetryProvider
undefined, // 11: capLockConfigs
treasuryPolicy, // 12: policyNode — when set, the pipeline uses tree evaluation instead of the flat policy
)PolicyNodeEvaluation
The evaluation result preserves which nodes passed and why:
interface PolicyNodeEvaluation {
passed: boolean
firstRejectionReason: PolicyRejectionReason | undefined
node: PolicyNode
children?: PolicyNodeEvaluation[]
}firstRejectionReason propagates from the deepest failing leaf to the root for backward-compatible error reporting.
AND semantics
- Empty
policyAnd([])— vacuously true (passes). - All children must pass. First failure short-circuits.
OR semantics
- Empty
policyOr([])— vacuously false (fails). - First passing child short-circuits.