import { type Abi, type Account, type Address, type Hex, type LocalAccount, type PublicClient, type WalletClient } from "viem"; import * as WriterRuntime from "./writerRuntime.js"; import type { ClientConfig } from "./config.js"; import type { Debug } from "./debug.js"; import type { BinarySide } from "./store.js"; import type { TraderConfig, TxResult, PlaceOrderResult, PlaceOrderParams, AmendOrderResult, AmendOrdersResult } from "./trade.js"; export declare function farFutureNs(): bigint; export declare const ZERO_BYTES32: Hex; export declare const ZERO_ADDRESS: Address; /** * What a placement escrows: collateral for a buy (ceil-rounded), or an outcome * position for a sell (moved under the one-time ERC-6909 operator approval). */ export type Escrow = { kind: "erc20"; token: Address; amount: bigint; } | { kind: "erc6909"; outcomeToken: Address; id: bigint; amount: bigint; }; /** * v2 OrderKind enum for `placeBinaryOrder` (0 BUY_YES, 1 SELL_YES, 2 BUY_NO, * 3 SELL_NO) — the side is explicit, NOT encoded in userData. The pool maps kind * onto the base book's (isBid, price) internally; the SDK just forwards the enum. * * @category trading */ export declare const ORDER_KIND: Record; /** One contract write, as the send path sees it. */ export interface WriteCall { address: Address; abi: Abi; functionName: string; args: readonly unknown[]; gas?: bigint; value?: bigint; } /** * One unsigned call, ready for any signer: spread into viem's `sendTransaction`, * wrap as an ERC-4337 UserOp call field, or hand to a relayer. * * Deliberately minimal, following `BridgeTransaction` in the `/chains` bridge * module: no nonce, no fees, no gas — those are the signer's job, and pinning * them here would stale the moment the call is cached. `description` is a human * label for a confirmation UI. * * Unlike `BridgeTransaction` there is no `chainId`: these calls are always on the * chain the client is already connected to, whereas a bridge leg is explicitly * cross-chain. Note `value` is a `bigint`, so `JSON.stringify` throws on it — * convert it yourself if the call crosses a serialization boundary. * * @category trading */ export interface UnsignedCall { /** Contract to call. */ to: Address; /** ABI-encoded calldata. */ data: Hex; /** Native value to attach, in wei. `0n` unless the call pays native. */ value: bigint; /** What this call does, for a UI to label a confirmation with. */ description: string; } /** * Converts a {@link WriteCall} to an unsigned transaction request. * * Lives here rather than beside any one build verb because several modules * (`perp/stops.ts`, `perp/margin.ts`, `orders.ts`) encode through it, and the * point of a build verb is that its bytes cannot diverge from what the sending * twin puts on the wire — one encoder keeps that true. * * @internal */ export declare function toUnsigned(call: WriteCall, description: string): UnsignedCall; /** * Builds the ERC-20 approval that a write needs as an unsigned call. * * `maxUint256`, as the send path's `approveIfNeeded` uses — so the two agree, and * a caller who batches this once is not asked again. * * @internal */ export declare function approvalCall(token: Address, spender: Address, description: string): UnsignedCall; /** * A placement expanded into the unsigned calls it actually takes. * * Two or one: a placement that escrows an ERC-20 (or outcome tokens) needs an * approval before the order call, while a native-base sell and every perp * placement need only the order. `approval` is simply absent when there is * nothing to approve — branching on it narrows: * * **Example** (Sending an unsigned order) * * ```ts * const { order, approval } = await trader.buildPlaceOrder(params); * if (approval) await walletClient.sendTransaction({ ...approval, account }); * await walletClient.sendTransaction({ ...order, account }); * ``` * * The approval is RETURNED, never sent — unlike `placeOrder`, which sends it as * a side effect. A caller who skips a needed approval gets an on-chain revert, * so check `approval` rather than assuming it is handled. * * `approval` is present whenever the placement escrows something, without * checking the current allowance (that check is an `eth_call`, which a * build-only verb should not make) — so it may be redundant, never short: it * approves `maxUint256`, as the send path does. (A token that demands its * allowance be zeroed before being re-set would reject that, same as on the send * path.) Pass `autoApprove: false` to drop it and skip the escrow lookup. * * @category trading */ export interface UnsignedOrder { /** The placement call itself. */ order: UnsignedCall; /** The approval the placement needs first; absent when nothing needs approving. */ approval?: UnsignedCall; } /** A pool's escrow tokens, outcome IDs, and exact collateral scale. */ export interface PoolTokens { /** ERC-6909 outcome-token singleton (shared across all markets). */ outcomeToken: Address; /** This pool's YES/NO position ids on the singleton. */ yesId: bigint; noId: bigint; collateral: Address; /** `10 ** collateral.decimals()`, as used by BinaryPool commitment math. */ oneCollateral: bigint; } /** * Infrastructure that binds a writer to its owning client. * * `createClient()` * passes its own so writes share that client's chain, fees, addresses, and * WebSocket. * * @internal */ export interface WriterDeps { getConfig: () => ClientConfig; getClient: () => PublicClient; /** * The owning client's debug channel. It defaults to a no-op when absent. * * @internal */ dbg?: Debug; /** Writer state shared by every trader derived from the same configured owner. */ writerRuntime?: WriterRuntime.WriterRuntime; } /** * The chain-write capability every concept write takes as its first parameter. * * **Details** * * Members are exactly what the write verbs were capturing as closures — the send * funnel (`execute`/`executeOrder`), the idempotent approval + operator grants, * the cached pool/bank/token resolvers, and the config a write needs (gas, fees, * decimals, addresses, signer). Nothing here is a convenience: each member has a * measured call site among the verbs. */ export interface Writer { /** Send one write and await its receipt; a revert throws {@link ContractRevertError}. */ execute(call: WriteCall): Promise; /** {@link execute} plus order-id/fill decoding from the receipt logs. */ executeOrder(call: WriteCall): Promise; /** Escrow tokens for a pool (cached per pool+nonce). */ poolTokens(pool: Address, nonceOverride?: bigint): Promise; /** {@link poolTokens} for a placement, honoring explicit param overrides. */ tokens(p: PlaceOrderParams): Promise; /** The pool's market expiry (orders must not outlive the market). */ marketExpiryNs(pool: Address): Promise; /** Which token+amount a placement escrows, from its side and the pool's tokens. */ escrow(p: PlaceOrderParams, tokens: PoolTokens): Escrow; /** * Approve `spender` for `token` if the current allowance is below `amount` * (cached per pair). `amount` may be a thunk: it is only resolved when the pair * is not cached, so a caller can price the pool's exact worst-case pull * (principal + fee headroom) without paying that read on the hot path. */ approveIfNeeded(token: Address, spender: Address, amount: bigint | (() => Promise), gas: bigint): Promise; /** Grant the one-time ERC-6909 operator approval if absent (cached per pair). */ ensureOperator(outcomeToken: Address, spender: Address, gas: bigint): Promise; /** Forget cached approvals — call after an external revoke. */ clearApprovalCache(token?: Address, spender?: Address): void; /** The pool's collateral token (explicit override wins). */ poolCollateral(pool: Address, override?: Address): Promise
; /** The margin bank for a perp write, from `marginBank` or the pool. */ resolveMarginBank(p: { marginBank?: Address; pool?: Address; }): Promise
; /** A margin bank's collateral token (explicit override wins). */ bankCollateral(bank: Address, override?: Address): Promise
; /** CollateralRouter address, or {@link NotConfiguredError}. */ resolveRouter(override?: Address): Address; /** BinaryMarketsModule address, or {@link NotConfiguredError}. */ resolveModule(override?: Address): Address; /** BinarySettlement address, or {@link NotConfiguredError}. */ resolveSettlement(override?: Address): Address; /** OperatorPermissionsRegistry address, or {@link NotConfiguredError}. */ resolveOperatorRegistry(override?: Address, attempting?: string): Address; /** The settlement singleton's outcome token (cached — immutable). */ settlementOutcomeToken(settlement: Address): Promise
; /** The wrapped public client (chain reads reject with SDK errors). */ readonly publicClient: PublicClient; /** Live addresses from the owning client's config. */ readonly addresses: () => NonNullable; /** The signing account (or its address, for an external wallet). */ readonly from: Account | Address; /** The signer's address. */ readonly fromAddress: Address; /** Present only for a local (in-process) signer. */ readonly localAccount: LocalAccount | undefined; /** The external wallet client, for the non-local-signer paths. */ readonly wallet: () => WalletClient; /** The chain writes are sent to. */ readonly chain: NonNullable; /** Default gas ceiling per write. */ readonly defaultGas: bigint; /** 10^decimals — one whole unit in raw terms. */ readonly oneBase: bigint; /** Collateral/outcome decimals for this client. */ readonly decimals: number; /** The owning client's debug channel. */ readonly dbg: Debug; } /** * Reconstructs a batch amendment's replacement identifiers. * * `amendOrders` is all-or-nothing, so every amendment either placed a replacement * or the whole tx reverted — which means the n-th `OrderPlaced` is the n-th * amendment's replacement, with no rejection gaps to skip. A replacement that * filled fully still emits `OrderPlaced`, so the alignment holds. * * @internal */ export declare function decodeBatchAmendResult({ hash, receipt }: TxResult, { pool, amendmentCount }: { pool: Address; amendmentCount: number; }): AmendOrdersResult; /** * Reconstructs one amendment's outcome from its receipt. The pool returns the new * `uint128` order id, but an EOA cannot read a transaction's return data, so the * id comes from the `OrderPlaced` log instead. * * A single amend reverts outright when its replacement does not rest or fill, so a * receipt that reached here carries exactly one placement. * * @internal */ export declare function decodeAmendResult({ hash, receipt }: TxResult, { pool }: { pool: Address; }): AmendOrderResult; /** * Builds the write context for a signer and its owning client's dependencies. Public entry * is `client.createTrader(...)`, which builds one of these and binds the verbs. * * @internal */ export declare function createWriter(config: TraderConfig, deps: WriterDeps): Writer;