Skip to Content
API Reference@txfence/core

@txfence/core

Policy engine, agent orchestration, cap locking, receipt storage, webhook approval, temporal rules, intent execution, and a chain-agnostic registry. This is the only required package — every other @txfence/* package plugs into it.

createAgent

Primary entry point. Wires policy, adapters, RPC URLs, and an executor into an agent with submit, dryRun, executeIntent, shutdown, health, and isShuttingDown methods. The signature is positional with 16 slots — pass undefined for slots you don’t need.

function createAgent( config: AgentConfig, // 1 adapters: AdapterMap, // 2 rpcUrls: Partial<Record<ChainId, string>>, // 3 executor?: (action, chainId, rpcUrl, evaluation, simulation) => Promise<SuccessReceipt>, // 4 capLockProvider?: CapLockProvider, // 5 metadataVerifier?: MetadataVerifier, // 6 approvalProvider?: ApprovalProvider, // 7 receiptStore?: ReceiptStore, // 8 auditLog?: AuditLog, // 9 telemetryProvider?: TelemetryProvider, // 10 capLockConfigs?: CapConfig[], // 11 policyNode?: PolicyNode, // 12 notificationProvider?: NotificationProvider, // 13 provenanceChain?: ProvenanceChain, // 14 eventStore?: EventStore, // 15 agentId?: string, // 16 ): Agent

AgentConfig is { chains, policies: Policy, signer }. policies is required even when you also pass a policyNode — see the Composite Policies guide.

Agent

type Agent = { submit: (input: { action: Action; policy: Policy }) => Promise<ExecutionResult> dryRun: (input: { action: Action; policy: Policy }) => Promise<DryRunResult> executeIntent: (intent: Intent, options?: Partial<IntentExecutionOptions>) => Promise<IntentExecutionResult> shutdown: (timeoutMs?: number) => Promise<AgentShutdownResult> isShuttingDown: () => boolean health: () => AgentHealth config: AgentConfig }

Default shutdown timeout is 30 seconds. See Agent Health & Shutdown, Dry Run Mode, Intent Execution.

runPipeline

Low-level pipeline if you don’t want to wrap state in an Agent. Same 16 positional slots after the leading action and policy.

async function runPipeline( action: Action, policy: Policy, adapters: AdapterMap, rpcUrls: Partial<Record<ChainId, string>>, executor?: /* ... same as createAgent ... */, // capLockProvider, metadataVerifier, approvalProvider, receiptStore, // auditLog, telemetryProvider, policyNode, notificationProvider, // (capLockConfigs is on createAgent only — pipeline doesn't need it) // provenanceChain, eventStore, agentId ): Promise<ExecutionResult>

Pipeline stages

  1. Policy evaluation — six static checks against action and policy
  2. Temporal rules — if policy.temporalRules and an eventStore are set
  3. Simulationadapter.simulate(); gas buffer and revert check
  4. Staleness check — if policy.simulationStalenessMs is set, reject if simulation is older
  5. Cap lock acquire — two-phase reservation
  6. Human approval — if action value ≥ humanApprovalThreshold
  7. Executionexecutor signs and broadcasts
  8. Cap lock commit/release — based on execution result

ExecutionResult

type ExecutionResult = | { status: 'success'; receipt: SuccessReceipt } | { status: 'policy_rejected'; action: Action; evaluation: PolicyEvaluation } | { status: 'simulation_failed'; action: Action; simulation: SimulationResult } | { status: 'simulation_stale'; action: Action; simulation: SimulationResult; stalenessMs: number } | { status: 'approval_timeout'; action: BoundAction } | { status: 'execution_failed'; action: Action; txHash: string; reason: ExecutionFailureReason }

ExecutionFailureReason is a discriminated union with codes no_executor, executor_threw, signing_failed, broadcast_failed. Use formatExecutionFailureReason(reason) for a human-readable string.

Policy

type Policy = { chains: ChainId[] maxSpendPerTx: TokenAmount allowedContracts: ContractEntry[] requireSimulation: boolean gasBufferMultiplier: number humanApprovalThreshold: TokenAmount humanApprovalTimeoutMs: number capLockMode: 'per-agent' | 'shared' capLocks?: CapConfig[] simulationStalenessMs?: number mevProtection?: 'flashbots' | 'mev-blocker' | 'none' temporalRules?: TemporalRule[] } type TokenAmount = { token: string; amount: bigint; decimals: number } type ContractEntry = { address: string; chain: ChainId; bytecodeHash?: string; ownerAddress?: string; expiresAt?: number }

See MEV Protection, Temporal Rules, Config Validation.

Action

Three action kinds — transfer, swap, contract_call.

type TransferAction = { kind: 'transfer' chain: ChainId token: TokenAmount to: string calldata?: `0x${string}` solanaTransaction?: Uint8Array cosmosTransaction?: Uint8Array } type SwapAction = { kind: 'swap' chain: ChainId from: TokenAmount // source token + amount to: string // destination token symbol via: string // router contract address maxSlippage: number // basis points; 0 is rejected as 'not declared' calldata?: `0x${string}` solanaTransaction?: Uint8Array cosmosTransaction?: Uint8Array } type ContractCallAction = { kind: 'contract_call' chain: ChainId contract: string method: string args: unknown[] value?: TokenAmount calldata?: `0x${string}` solanaAccounts?: SolanaAccountMeta[] solanaData?: Uint8Array solanaTransaction?: Uint8Array cosmosTransaction?: Uint8Array } type Action = TransferAction | SwapAction | ContractCallAction

maxSlippage: 0 is treated as not declared and is always rejected. Set a non-zero value even for zero-tolerance swaps — use 1 for one-basis-point tolerance.

ReceiptStore

type ReceiptStore = { save: (receipt: SuccessReceipt) => Promise<void> get: (txHash: string) => Promise<SuccessReceipt | null> list: (filter?: ReceiptFilter) => Promise<SuccessReceipt[]> } type ReceiptFilter = { chain?: ChainId from?: number // start block, inclusive to?: number // end block, inclusive }

In-memory: createMemoryReceiptStore(). File-backed NDJSON: createFileReceiptStore(path). PostgreSQL: @txfence/storage-pg. SQLite: @txfence/storage-sqlite.

CapLockProvider

type CapLockProvider = { acquire: (capId: string, amount: bigint, token: string) => Promise<CapLockResult> release: (capId: string, lockId: string, amount: bigint) => Promise<void> commit: (capId: string, lockId: string, amount: bigint) => Promise<void> onCapWarning?: (event: CapWarningEvent) => void inspect?: (capId: string) => Promise<CapInspection> } type CapLockResult = | { granted: true; lockId: string } | { granted: false; reason: 'absolute_cap_exceeded' | 'rolling_window_exceeded' }

commit and release take the lockId returned by acquire — the pipeline tracks IDs internally so callers rarely interact with them directly.

createMemoryCapLockProvider

function createMemoryCapLockProvider( configs: CapConfig[], options?: { onCapWarning?: (event: CapWarningEvent) => void }, ): CapLockProvider & { inspect: (capId: string) => Promise<CapInspection> } type CapConfig = { capId: string absoluteCap?: { maxAmount: bigint; token: string } rollingWindow?: { windowMs: number; maxAmount: bigint; token: string } warningThresholdPct?: number // 0-100, triggers onCapWarning }

Single-process only. For distributed deployments, use @txfence/redis.

ApprovalProvider

type ApprovalProvider = { request: (req: ApprovalRequest) => Promise<void> poll: (token: string) => Promise<ApprovalDecision | null> } type ApprovalDecision = 'approved' | 'rejected'

request dispatches the approval (e.g. webhook POST). poll returns null while pending. Cancel-on-timeout is enforced by the pipeline — a timeout returns { status: 'approval_timeout' }, never falls through to execution.

createWebhookApprovalProvider

function createWebhookApprovalProvider( webhookUrl: string, pollUrl: string, options?: { webhookSecret?: string // enables HMAC-SHA256 signing of the payload pollIntervalMs?: number }, ): ApprovalProvider

POSTs the ApprovalRequest to webhookUrl with an X-TXFence-Signature header when webhookSecret is set. The payload includes approveUrl and rejectUrl for one-click approval via email.

Low-level helpers

Exports useful when building custom infrastructure around the engine. None of these are needed for normal createAgent usage.

Policy evaluation

function evaluate( policy: Policy, action: Action, simulationResult?: SimulationResult, ): PolicyEvaluation

Pure synchronous policy evaluator. Returns { passed, checksRun, rejectionReason? }. Used internally by runPipeline.

function evaluateNode( node: PolicyNode, action: Action, simulationResult?: SimulationResult, ): PolicyNodeEvaluation

Tree-aware version for composite policies. Returns a tree-structured result that preserves which branches passed.

Adapter composition

function createMultiChainAdapter(adapters: AdapterMap): ChainAdapter

Wraps an AdapterMap ({ ethereum: { simulate }, arbitrum: { simulate } }) into a single ChainAdapter that dispatches by action.chain. Used when a downstream API expects one adapter.

function wrapAdapterWithCircuitBreaker( adapter: ChainAdapter, breaker: CircuitBreaker, chainId: ChainId, ): ChainAdapter

See Circuit Breaker.

Error formatting

function getPolicyRejectionMessage(reason: PolicyRejectionReason): string function getSimulationFailureMessage(result: SimulationResult): string function formatExecutionFailureReason(reason: ExecutionFailureReason): string

All three produce human-readable strings for logs, CLI output, or UI display.

Serialization

function bigintReplacer(key: string, value: unknown): unknown function serializeWithBigInt(obj: unknown): string function parseWithBigInt(json: string): unknown function reviveTokenAmount(raw: unknown): TokenAmount function revivePolicy(raw: unknown): Policy function reviveAction(raw: unknown): Action function reviveSimulationResult(raw: unknown): SimulationResult function reviveSuccessReceipt(raw: unknown): SuccessReceipt

Used by every storage backend (file, SQLite, PostgreSQL, audit, provenance) so the same bigint-handling round-trip is consistent across the project.

Contract test suites

Every interface has a portable contract suite — run them against your own implementation to verify substitutability:

import { receiptStoreContract, capLockProviderContract, auditLogContract, approvalProviderContract } from '@txfence/core/contracts' receiptStoreContract('My S3 receipt store', () => createS3ReceiptStore({ ... }))

Other exports

The registry (asset, protocol, maxSpend, createRegistry, defaultRegistry, BUILT_IN_ASSETS, BUILT_IN_PROTOCOLS) is documented in Chain-Agnostic Policy.

Notification providers (createConsoleNotificationProvider, createWebhookNotificationProvider, createCompositeNotificationProvider) are documented in Notifications.

Telemetry (noopTelemetry, TelemetryProvider, Span) is documented in Telemetry.

Policy versioning (getPolicyVersionId, createPolicyVersion, createPolicyVersionStore) is documented in Policy Versioning.

Multi-agent coordination (createMemoryAgentCoordinator, getIntentId, getIntentIdWithNonce) is documented in Multi-Agent Coordination.

Intent helpers (executeIntent, evaluateIntent, validateIntentGraph, getExecutionPlan, getPoisonedSteps, analyzeIntentPosition, getActionPositionChanges, mergePositionChanges, isSingleTokenIntent, getDominantToken, checkMaxSteps) are documented in Intent Execution.

Temporal rules (createMemoryEventStore, evaluateTemporalRules) are documented in Temporal Rules.

Replay (replayAuditLog) is documented in Replay & Backtesting.

Diff (diffPolicies, createTestActions) is documented in Policy Diff.

Validation (validateConfig) is documented in Config Validation.

Last updated on