import { type WalletClient } from "viem"; import { type AgentWallet } from "./agentWallet.js"; import { type Chain } from "viem/chains"; import { type PaymentChain } from "./paymentChains.js"; import { AiFinPayError } from "./errors.js"; import { Agent, type AgentOptions } from "./agent.js"; import { type SettlementInvoice, type SettlementInvoiceInput, type SettlementRoute, type SettlementRouteClass } from "./settlement.js"; import { type AgentHistoryOptions, type QuotaSummary } from "./agentHistory.js"; import { type SpendLedger } from "./spendLedger.js"; import { type Aifp1PaymentRecovery, type Aifp1RecoveryOptions, type Aifp1PayResult, Aifp1ReceiptCache, type Aifp1MerchantPinStore, type Aifp1CachedReceipt, type Aifp1FetchOptions } from "./aifp1.js"; import { type BridgeQuote, type BridgeReceipt, type EvmChainName } from "./crossChain.js"; /** * Chains the unified agent can settle on. "solana" uses the Anchor * b2b_pay_with_split program; every other value is an EVM chain with a * verified B2BSplitter deployment (see SPLITTER_DEPLOYMENTS below). * Additive union — "polygon" remains the EVM default. */ export type ChainId = "solana" | SplitterChainName; export interface ProviderEntry { name: string; display_name?: string; preferred_chain: ChainId; accepted_chains: ChainId[]; price_usd: number; mode: "per_call" | "session" | "both"; bridge_url: string; merchant_wallet: string; service_type?: string; url?: string; } export interface CallOptions { provider: string; cost?: number; chain?: ChainId; bridgeUrl?: string; body?: unknown; method?: string; timeoutMs?: number; signal?: AbortSignal; } export interface BalanceSnapshot { agent_balance_usd: number; chains: { solana: { sol: number; usdc: number; msecco_balance: number; network: "mainnet" | "devnet" | null; usdc_mint: string; valuation: "spot-estimate" | "test-assets-not-valued" | "unverified-owner-rpc/mainnet-mint"; }; polygon: { matic: number; usdc: number; msecco_balance: number; }; }; spend_24h_usd: number; budget_caps: { daily_usd?: number; per_call_usd?: number; }; priced_at: number; /** Native price observations behind the total (env var or price feed). */ prices: { pol: { usd: number; source: string; }; sol: { usd: number | null; source: string; }; }; /** Native legs excluded from the total for lack of a price. Absent when empty. */ unknown_legs?: ("pol" | "sol")[]; } export interface ReputationSnapshot { trust_score: number; spend_score: number; tenure_days: number; verified: boolean; flags: string[]; } export interface BudgetCaps { daily_usd?: number; per_call_usd?: number; /** * Behaviour when a cap is hit during call(): * "throw" (default) — raise BudgetCapExceededError, caller decides * "skip" — call() resolves to null without paying; * useful in loops where you'd rather drop an * agent task than spike the daily envelope */ on_limit_exceeded?: "throw" | "skip"; } export interface SessionHandle { id: string; provider: string; chain: ChainId; budget_usd: number; spent_usd: number; remaining_usd: number; expires_at: number; call(body: unknown): Promise; close(): Promise; abandon(): Promise; } export interface SessionReceipt { session_id: string; spent_usd: number; refund_usd: number; settlement_tx: string; block: number | string; } export interface AiFinPayAgentOptions extends AgentOptions { /** Derive each chain key from its own versioned domain and this child index. */ derivationIndex?: number; registryUrl?: string; evmPrivateKey?: `0x${string}`; /** Inject a viem wallet client for EVM message and on-chain transaction signing. */ evmWalletClient?: WalletClient; budgetCaps?: BudgetCaps; telemetry?: boolean; polygonRpc?: string; /** * Where the daily cap is remembered. * * Omit it and the SDK picks: a file under ~/.aifinpay (or AIFINPAY_STATE_DIR) * once a daily cap is set, memory otherwise. Pass your own when the agent * runs on more than one host — a lock file cannot answer for a fleet. */ spendLedger?: SpendLedger; /** * Where fetchPaid remembers the merchant each gateway site was first paid * as. Omit it for a file per site under ~/.aifinpay/merchant-pins (or * AIFINPAY_STATE_DIR), which outlives the process. A store that forgets on * restart lets the next 402 choose the merchant again. */ merchantPins?: Aifp1MerchantPinStore; solanaRpc?: string; /** RPC overrides for non-Polygon EVM chains — both bridge-flow chains * and splitter-settlement chains (base, optimism, unichain, botchain (deprecated), * xrplevm). Splitter chains fall back to the public RPC listed in * SPLITTER_DEPLOYMENTS when no override is given. */ evmRpcUrls?: Partial>; } /** The native-token payment block of a bridge 402. One shape, two key names — * see EvmBridgeChallenge below for why both exist. */ interface PayNativeBlock { /** EVM chain the quote is denominated for. Legacy bridges emit * "polygon"; newer bridges may emit any SplitterChainName. */ chain: string; splitter: string; /** Which B2BSplitter the address above is. Absent on older bridges, which * is treated as "1.1" — the shape the entrypoint had before 2026-07-31. */ splitter_version?: "1.1" | "1.2"; merchant_wallet: string; total_wei: string; merchant_amount_wei?: string; treasury_amount_wei?: string; ip_creator_amount_wei?: string; /** Optional royalty recipient. When absent the SDK routes the slot to * the splitter's treasury (zero-address would strand the 1bp in the * contract — B2BSplitter has no sweep function). */ ip_creator?: string; order_id: string; function_signature?: string; ttl_seconds?: number; /** v1.2 bridges precompute keccak(order_id); the SDK derives it anyway. */ payment_id?: string; } interface PayMaticChallenge { error: string; protocol: string; service: string; facilitator?: string; /** The production bridges renamed this block to `pay_native` on 2026-08-04 * when payMatic became payNative on-chain — and every SDK branch kept * reading only `pay_matic`, so agent.call() failed against every live * bridge with an error blaming facilitator wiring (AIFINP-118). Both names * are accepted; `pay_native` wins when a bridge sends both. */ pay_native?: PayNativeBlock; pay_matic?: PayNativeBlock; pay_solana?: { chain: "solana"; program_id: string; instruction: string; merchant_wallet: string; treasury: string; merchant_amount_lamports: string; treasury_amount_lamports?: string; ip_creator_amount_lamports?: string; total_lamports?: string; order_id: string; asset?: string; ttl_seconds?: number; }; retry?: unknown; instructions?: string[]; } /** * The native-token payment block of a bridge 402, whichever key it arrived * under. * * Both names, newest first. The production bridges renamed the block * `pay_matic` → `pay_native` on 2026-08-04 when the on-chain entrypoint became * `payNative` — and no SDK branch followed, so `agent.call()` failed against * every live bridge with an error blaming facilitator wiring (AIFINP-118). * Exported so the captured-fixture test drives this exact function; the * original bug survived because the tests built their 402s in the SDK's own * vocabulary and never met a real one. */ export declare function nativePayBlock(challenge: PayMaticChallenge): PayNativeBlock | undefined; /** * Derive the on-chain paymentId from the quote's order id. * * Deliberately deterministic. v1.2 rejects a paymentId it has already settled, * and that guarantee is only worth something if the id is bound to the order: * a random id would let the same order be paid twice, which is precisely what * the guard exists to prevent. A retry after a *reverted* transaction is still * fine — a revert consumes nothing on-chain. */ export declare function paymentIdFor(orderId: string): `0x${string}`; /** * EVM chains with a live, on-chain-verified B2BSplitter deployment. * @deprecated "botchain" is deprecated and will be removed in a future version. Use "robinhood" instead. */ export type SplitterChainName = "polygon" | "base" | "optimism" | "unichain" | "robinhood" | "botchain" | "xrplevm"; export interface SplitterDeployment { chainId: number; /** viem chain object used for tx signing on this chain. */ chain: Chain; /** Public RPC used when no evmRpcUrls override is supplied. */ defaultRpc: string; /** * Deployed B2BSplitter version. The SDK tracks the on-chain version (e.g., "1.4") * but only distinguishes between v1.1 and v1.2+ for ABI compatibility. * Chains with version "1.1" use the payMatic entrypoint; chains with version * "1.2" or higher use the payNative entrypoint. */ version: string; /** B2BSplitter contract address (native-token entrypoint). */ splitter: `0x${string}`; /** * Circle-native USDC on this chain, when one exists. Informational for * now: the splitter payment path is native-token only (payMatic) — no * ERC-20 settlement path is implemented in the SDK or deployed splitter. */ usdc?: `0x${string}`; explorer: string; /** Env var consulted for the native-token USD price used by the * pre-sign challenge guard. An operator who sets it means it, so it wins. * * `nativeUsdDefault` is NOT consulted by the guard any more — see * nativeUsdFor(). It survives as published reference data only. A constant * in a blocking guard is what made this SDK reject valid payments: POL sat * at 0.70 here while trading near 0.073, so every quote looked ten times * its cost and BudgetCapExceededError fired before any money moved. */ nativeUsdEnv: string; nativeUsdDefault: number; } export declare const SPLITTER_DEPLOYMENTS: Record; /** * Union of every EVM chain name the SDK knows an RPC/client for: LiFi * bridge chains (EvmChainName) + splitter deployment chains. Used for * evmRpcUrls overrides and the internal client cache. */ export type AnyEvmChainName = EvmChainName | SplitterChainName | PaymentChain; export declare class ProviderUnknownError extends AiFinPayError { } export declare class WrongChainBalanceError extends AiFinPayError { has: ChainId[]; needed: ChainId; constructor(has: ChainId[], needed: ChainId, msg: string); } export declare class InsufficientFundsError extends AiFinPayError { needed_usd: number; available_usd: number; readonly details?: { address: string; chain: string; symbol: string; needed_wei: string; available_wei: string; } | undefined; /** * `details` carries the native amounts, which are what the caller acts on — * the USD figures depend on a price feed that may be unavailable, and an * error about missing funds is the worst possible place to invent a number. */ constructor(needed_usd: number, available_usd: number, msg: string, details?: { address: string; chain: string; symbol: string; needed_wei: string; available_wei: string; } | undefined); } export declare class BudgetCapExceededError extends AiFinPayError { kind: "daily" | "per_call"; constructor(kind: "daily" | "per_call", msg: string); } export declare class SettlementError extends AiFinPayError { reason: string; txHash?: string | undefined; constructor(reason: string, txHash?: string | undefined); } export declare class SessionExpiredError extends AiFinPayError { session_id: string; constructor(session_id: string); } /** * A published entry in the public AiFinPay agent network — what `search()` * returns and `register()` produces. Identity is the agent's EVM address. */ export interface NetworkAgent { address: string; name: string | null; description: string | null; endpoint: string | null; capabilities: string[]; pricing: { per_call: number; currency: string; } | null; rating: number | null; published_at: number | null; created_at: number | null; } export declare class AiFinPayAgent { private readonly rootSeed; readonly inner: Agent; readonly evmAccount: AgentWallet; readonly registryUrl: string; /** Fallback registry URLs, tried in order when `registryUrl` was defaulted. */ private registryCandidates; readonly polygonRpc: string; readonly solanaRpc: string; private cachedRegistry?; private budgetCaps; private spend24h; private _ledger?; private ledgerOverride?; private telemetry; private _polygonPublic?; private _polygonWallet?; private readonly injectedEvmWalletClient?; private readonly derivationIndex?; private _evmClients; private evmRpcUrls; private constructor(); /** * The injected evmAccount when it is a full viem LocalAccount — required by * on-chain client flows (bridge execution, splitter settlement), which sign * transactions, not just messages. A message-only AgentWallet fails here * with a clear error instead of a runtime type crash mid-payment. */ private viemEvmAccount; private walletClientFor; private polygonClients; private evmClients; private splitterClients; /** * Load an existing local identity without creating or replacing a wallet. * Priority: SEED_HASH → ./aifinpay/agents.json → AIFINPAY_AGENT_SECRET → * the MCP keystore at AIFINPAY_HOME/agent.json (default ~/.aifinpay). * AIFINPAY_AGENTS_FILE/AGENT_ID select a project file/record; encrypted * keystores require AIFINPAY_WALLET_PASSPHRASE. Reads process.env, not .env. * Missing, invalid or ambiguous configuration throws before any network call. */ static fromEnvironment(opts?: AiFinPayAgentOptions): Promise; /** * Generate a fresh, ephemeral agent. Every call selects a new identity; * existing environment variables and keystores are NOT loaded or changed. * This method does not persist its keys. Use fromEnvironment() for a funded * existing wallet, or privately persist the new seed/secret before funding. */ static new(opts?: AiFinPayAgentOptions): Promise; /** * Derive both keypairs from a single 32-byte hex seed. Same seed → * deterministic Solana pubkey AND EVM address. One backup phrase, two * chains. * * Solana key = nacl.sign.keyPair.fromSeed(seed) * EVM key = SHA-256("aifinpay:evm:v1\0" || seed) * (domain-separated; independent path; not BIP-44 — see * design notes in 23 - Unified SDK Design. This is the * canonical derivation both SDKs implement — the Python * SDK mirrors it byte-for-byte.) * * TODO(phase-1): replace with BIP-39/BIP-44 derivation * m/44'/501'/0'/0' (Solana) + m/44'/60'/0'/0/0 (EVM) once the * wallet-import audit recommendation lands. * With derivationIndex, each chain hashes its own domain, NUL, decimal * index, then the recovery seed. An explicit opts.evmPrivateKey imports an * existing EVM wallet instead; keep that key as well as the seed. */ static fromSeed(seedHex: string, opts?: AiFinPayAgentOptions): Promise; /** * Legacy: load the Solana side from an existing keypair. The EVM key is * derived deterministically from the Solana secret's 32-byte seed * (domain-separated SHA-256, same path as `fromSeed`) unless an explicit * `opts.evmPrivateKey` is provided. * * Why deterministic: a random key here would change the EVM address on * every process restart — anything sent to the previous address becomes * unrecoverable because the key was never persisted or printed. With * derivation, the same AIFINPAY_AGENT_SECRET always reproduces the same * EVM address (this is what the MCP server relies on). */ static fromSolanaSecret(secretB58: string, opts?: AiFinPayAgentOptions): Promise; get id(): string; get solanaAddress(): string; get evmAddress(): string; /** * Casper identity, derived from the same seed as the other two. * * A getter rather than a stored field, for the same reason the EVM key is * derived rather than generated: the agent's identity on every chain has to * be reproducible from one secret. Anything else means an address that * changes on restart, and funds sent to the old one are unrecoverable. * * Returns the tagged public key Casper tooling expects (01 = ed25519) and the * account hash. Verified against mainnet — see casperIdentityFromSeed. */ get casper(): { publicKey: string; accountHash: string; }; /** Convenience: the account hash, which is what a Casper explorer wants. */ get casperAddress(): string; fetchRegistry(force?: boolean): Promise; resolveProvider(name: string): Promise; /** * Publish this agent to the public AiFinPay network so other agents can * discover and call it. Self-sovereign: proves control of the EVM address by * signing a one-time nonce with the agent's own key (EIP-191) — no partner * account needed. */ /** * Sign the challenge that links this agent to its owner's dashboard * (https://dash.aifinpay.io → My Agents → Add agent by address). * * Signs ONLY `AiFinPay-claim:polygon::<32 hex nonce>` * — the exact message the dashboard issues — and refuses anything else, so it * cannot be used to obtain this key's signature over arbitrary text. The * owner pastes the returned signature into the dashboard. */ signDashboardClaim(challenge: string): Promise<`0x${string}`>; register(opts: { name: string; endpoint: string; description?: string; capabilities?: string[]; pricing?: { perCall: number; currency?: string; }; }): Promise; /** Remove this agent from the public network directory (same signature proof). */ unregister(): Promise; /** * Search the public network for agents advertising a capability or matching a * free-text query. Pass a bare string to search by capability * (`agent.search("weather")`) or an object for finer control. Returns the * directory entries; invoking one (pay + call) lands in a later release. */ search(query: string | { capability?: string; q?: string; limit?: number; }): Promise; private networkNonce; setBudget(caps: BudgetCaps): void; /** * Internal pre-call check. Returns `false` only when on_limit_exceeded * is "skip" and a cap is hit — `call()` should then resolve to null * without submitting an on-chain tx. Throws BudgetCapExceededError * in the default "throw" mode. */ /** * The ledger that enforces the daily cap. * * Chosen late, because setBudget() is usually called after construction and * the choice depends on whether a daily cap exists at all. Durability is * engaged only when one does: a library that writes to a user's disk because * it was imported would be rude, and one that promises a daily limit and * forgets it on restart is worse. */ private get ledger(); /** * Claim room in the daily cap before paying. * * Returns a reservation id, or "skip"/throws per on_limit_exceeded. The cap * comparison happens inside the ledger, atomically: a caller that read the * total and then reserved would have rebuilt the race this replaces, where * two concurrent calls both read the same total, both passed, and both paid. */ private reserveDaily; /** * The per-call cap, which needs no ledger. * * It is a property of one call and cannot be raced: nothing about a * concurrent call changes whether THIS one is too expensive. Only the daily * cap accumulates, and only it goes through reserve/commit. */ private checkPerCall; /** * Current 24-hour rolling spend across all paid calls made by this * agent instance. Useful for budget dashboards on the consumer side. */ getSpend24h(): number; /** * Durable daily spend from the budget ledger (settled + outstanding, 24h * window). Unlike getSpend24h()'s in-memory ring, this survives reload and * reflects reserve/commit accounting even with no signing tool attached — * the number a long-lived host (e.g. MCP) should display. 0 when no * daily_usd cap is set and nothing was reserved. */ getDailySpendUsd(): Promise; /** * Sanity-check the USD estimate of an on-chain challenge amount against * the declared cost and the per-call cap BEFORE signing the tx. * * The estimate uses env-priced MATIC/SOL (AIFINPAY_MATIC_USD / * AIFINPAY_SOL_USD — same stopgap as balance()), so it is approximate. * A 2x + $0.05 tolerance absorbs oracle drift while still catching the * dangerous case: a bridge that quotes $0.01 in the registry and then * demands 100x in the 402 challenge. * * Returns false (skip) instead of throwing when on_limit_exceeded="skip". */ /** * The native-token USD price for the pre-sign guard. * * Order: an explicit env var, then the protocol's own price feed, then * nothing. "Nothing" is deliberate and is the whole point of this method. * The guard used to fall back to a constant compiled into the SDK; POL sat * at 0.70 while trading near 0.073, so a real $0.01 payment estimated at * $0.096, cleared the $0.06 ceiling and threw BudgetCapExceededError. The * payment never left, and the error blamed the bridge for demanding too * much. * * A guard that blocks on a number it cannot justify is worse than no guard, * so an unknown price returns NaN and guardChallengeAmount declines to * block. Overpayment protection is given up only in the case where we have * no basis for it, which is the honest trade. */ private priceCache?; private nativeUsdFor; /** * Native-token USD price: explicit env var, then the protocol price feed, * then NaN ("unknown") — never a stale constant. Callers decide what an * unknown price means for their flow (balance() excludes the leg; * guardChallengeAmount declines to block). */ private tokenUsd; /** * Refuse to broadcast a transaction the account cannot pay for, and say so * in terms the caller can act on. * * Without this the SDK handed back viem's ContractFunctionExecutionError — * several paragraphs explaining that cost is `gas * gas fee + value` — for * the one condition an agent operator can fix in ten seconds. Worse, the SDK * has exported an InsufficientFundsError since the first release and never * threw it, so anyone who wrote `catch (e instanceof InsufficientFundsError)` * had a branch that could not run. */ private assertCanAffordNative; private guardChallengeAmount; /** * Chain selection heuristic — see Obsidian/23 - Unified SDK Design §Routing. * * 1. Explicit override always wins (subject to provider acceptance). * 2. Cost ≤ $0.005 + Solana per-call live + Solana accepted → Solana * (low gas wins for tiny calls). * 3. Cost > $0.05 + Polygon accepted → Polygon * (better finality for high-value calls). * 4. Middle band → provider.preferred_chain. * 5. Fallback → first accepted chain. * * Solana per-call is gated on the deploy of `b2b_pay_with_split` — * until then `solana` selection raises in `call()`. */ private pickChain; /** * TODO(phase-4): mint AgentPassport on the cheapest chain available * with the requested `stake_usd`. For now wires only the Solana side * via the existing `reserveSeatInvoice` semantics. */ verify(_args?: { stake_usd?: number; }): Promise<{ verified: boolean; }>; /** * TODO(phase-1): pick a chain (preferred USDC on Polygon for stability; * fallback Solana SOL). Return signed-tx instructions for the wallet. */ deposit(_usd: number, _opts?: { asset?: "USDC" | "USDT" | "SOL" | "MATIC"; chain?: ChainId; }): Promise; /** * Quote a USDC-denominated cross-chain transfer via LiFi. * * The convenience overload takes a USD amount and the chain names; the * full overload accepts arbitrary token addresses for non-USDC corridors. * The agent's EVM address is used as both `fromAddress` and `toAddress` * unless overridden — bridging to a different recipient is rare for agents. */ bridgeQuote(opts: { fromChain: EvmChainName; toChain: EvmChainName; amount_usdc?: number; fromToken?: `0x${string}`; toToken?: `0x${string}`; fromAmount?: string; toAddress?: `0x${string}`; slippage?: number; }): Promise; /** * Execute a previously-fetched bridge quote. Signs and submits the source * transaction with the agent's EVM key on the SOURCE chain. Returns once * source-side inclusion is confirmed; dest-side arrival is async — call * `bridgeWaitForArrival(receipt.source_tx)` if you need to block on it. */ bridgeExecute(quote: BridgeQuote): Promise; /** * Wait for the bridge to deliver on the destination chain. Wraps LiFi's * /status polling; timeout default is 30 minutes (Circle CCTP can take * 15-25 min on Polygon side). Throws AiFinPayError on timeout. */ bridgeWaitForArrival(sourceTxHash: `0x${string}`, opts?: { pollIntervalMs?: number; timeoutMs?: number; }): Promise<{ status: "done" | "failed"; dest_tx?: string; raw: unknown; }>; /** * Legacy bridge call. Free/read-only bridge responses are passed through; * paid 402 challenges fail closed because this legacy settlement surface has * no independently reviewed target. Use the reviewed fetchPaid v1.3 route * with a fresh trusted quote/FX result for paid requests. * * Returns `null` (instead of a `Response`) iff a budget cap was hit * AND budget.on_limit_exceeded is set to "skip" — the call is dropped * silently. Default behaviour throws BudgetCapExceededError. */ call(opts: CallOptions): Promise; private settleSplitterNative; private submitSolanaB2BPayWithSplit; private readonly _aifp1Cache; /** * The prepaid batches this agent is holding. * * Exposed because a batch is money the agent has already spent and has not * finished using: an operator deciding whether to shut an agent down, or a * test asserting that a receipt was reused, both need to see it. The entries * contain bearer JWTs — treat them like keys, and do not log them. */ get aifp1Receipts(): Aifp1ReceiptCache; /** * Redacted receipt-cache view (no bearer JWTs): what batches this instance * holds, for shutdown decisions and dashboards. Safe to log and to expose * over MCP — use this, never `aifp1Receipts.list()`. */ getReceiptCacheSummary(): Omit[]; /** * Use the canonical invoice executor only with a caller-supplied deployment * pin. An unauthenticated quote cannot establish its own signing authority. */ private settleAifp1NativeV13; /** * Fetch a paywalled URL, paying the AIFP-1 gateway if it asks. * * const res = await agent.fetchPaid("https://gateway.aifinpay.io/acme/articles/2026/x"); * * A URL that is not paywalled — or that answers a 402 belonging to some * other protocol — comes back untouched and costs nothing. A paywalled one * is quoted, settled on-chain, exchanged for a receipt and retried, and the * receipt is kept: subsequent calls it covers cost a header rather than a * transaction. See aifp1.ts for why that reuse is the entire design. * * Returns `null` on the same terms as call(): a budget cap was hit and * `budgetCaps.on_limit_exceeded` is "skip". */ fetchPaid(url: string, init?: RequestInit, opts?: Aifp1FetchOptions): Promise; /** Recover receipt issuance for an existing payment; never sends a transaction. */ recoverPaidPayment(recovery: Aifp1PaymentRecovery, opts?: Aifp1RecoveryOptions): Promise; /** * List verified settlement routes. Non-signing: fetches + returns the * backend route table (same client the MCP `settlement_routes` tool should * use instead of its own inline HTTP). Never signs or broadcasts. */ settlementRoutes(routeClass?: SettlementRouteClass, baseUrl?: string): Promise; /** * Request a settlement invoice and validate it (canonical split, * chain binding, request match). Non-signing: returns the invoice for * display/approval. Never signs or broadcasts. */ requestSettlementInvoice(input: SettlementInvoiceInput, baseUrl?: string): Promise; private settlementClient; /** * Prepaid quota batches for this agent's address, most room first with a * per-merchant rollup. Non-signing read of retained receipts metadata. */ getPaymentHistory(opts?: Omit): Promise>; getQuota(opts?: { merchantId?: string; includeExhausted?: boolean; baseUrl?: string; network?: import("./agentPassport.js").AgentPassportNetwork; solanaNetwork?: import("./generated/solanaV14Deployments.generated.js").SolanaNetwork; }): Promise; /** * TODO(phase-3): open a metered budget session. * @deprecated Not implemented — always throws. Tracked for phase 3; do not call. */ openSession(_args: { provider: string; budget_usd: number; ttl_seconds?: number; }): Promise; /** * Snapshot the agent's funds across both chains, USD-normalised. * * Native prices are env-first (`AIFINPAY_MATIC_USD` / `AIFINPAY_SOL_USD`), * then the protocol price feed — never a stale compiled-in constant. A leg * with no known price is excluded from the total and listed in * `unknown_legs` instead of being fabricated. */ balance(options?: { solanaNetwork?: "mainnet" | "devnet"; }): Promise; private fetchPolygonNative; private fetchSolanaNative; /** * Sum SPL USDC balances across all token accounts owned by the agent's * Solana pubkey. Uses raw JSON-RPC `getTokenAccountsByOwner` so we don't * pull `@solana/spl-token` as a dep. Returns 0 (never throws) when the * RPC is unreachable or returns nothing in the legacy, unverified context. * An explicit cluster requires a successful, well-formed balance read. */ private fetchSolanaUsdc; /** Read + cache B2BSplitter.treasury() on the given chain (default * polygon for back-compat). Returns null on RPC failure. */ /** * Which Splitter generation is actually deployed at this address. * * The version used to come from a chain -> version table while the ADDRESS * came from the bridge's 402 challenge. Two different sources, and they can * disagree — in production they did. The Exa bridge still hands out the * pre-v1.2 splitter 0xE34Fc0E6… and sends no version, the table says * "polygon is 1.2", and the SDK called payNative on a contract that only has * payMatic. The payment reverted with nothing in the reason to explain it. * * A table keyed by chain cannot be right when the address is variable input, * so this asks the contract instead. payNative's 4-byte selector appears in a * v1.2 dispatcher and is absent from v1.1 — the same check used to verify all * six registry chains against mainnet. * * One eth_getCode, cached per (chain, address). Falls back to the registry * only for this read-only diagnostic when code cannot be read. The legacy * payment path is disabled regardless of the reported or detected version. */ private splitterVersionCache; private detectSplitterVersion; /** * Read the native Polygon USDC (Circle-issued, 6 decimals) balance for the * agent's EVM address via the existing viem publicClient. Returns 0 * (never throws) on RPC failure — see fetchSolanaUsdc rationale. */ private fetchPolygonUsdc; /** * TODO(phase-4 / phase-5): query operator backend reputation engine. * @deprecated Zero-stub — returns unverified zeros until the engine lands; do not treat as signal. */ reputation(): Promise; private reportTelemetry; } /** The pair Casper tooling expects: tagged public key and account hash. */ export declare function casperIdentityFromSeed(seed: Uint8Array, index?: number): { publicKey: string; accountHash: string; }; export {}; //# sourceMappingURL=unifiedAgent.d.ts.map