import { Address, ChainID, EIP1193Provider, IFormoEventProperties, SignatureStatus, TransactionStatus } from "../types"; import { WalletStateStore } from "../wallet/WalletStateStore"; import { EvmProviderRegistry } from "./EvmProviderRegistry"; import { AutocaptureEventType } from "../tracking/TrackingPolicy"; /** What the request tracker needs from the SDK that owns it. */ export interface EvmRequestTrackerDeps { isAutocaptureEnabled(eventType: AutocaptureEventType): boolean; /** * Hybrid-capture dedup: true when a PENDING wagmi mutation already covers * this request, so the mutation handler owns the capture. TanStack sets a * mutation pending BEFORE its mutationFn issues the wallet call, so a * hook-driven request always matches; an imperative one never does. */ shouldSkipRequestCapture?(method: string, params: unknown[]): boolean; signature(params: { status: SignatureStatus; chainId?: ChainID; address: Address; message: string; }, properties?: IFormoEventProperties): Promise; transaction(params: { status: TransactionStatus; chainId: ChainID; address: Address; data?: string; to?: string; value?: string; transactionHash?: string; function_name?: string; function_args?: Record; }, properties?: IFormoEventProperties): Promise; } export declare class EvmRequestTracker { private readonly wallet; private readonly registry; private readonly deps; /** * Timers for receipt and batch-status polling. * * A poll re-arms for up to thirty seconds, so a torn-down instance would * otherwise keep asking a wallet about transactions nobody is listening * for, and hold the process open for the whole window. That is the same * shape as the batch timer that hung the test suite in #338. */ private polls; private disposed; constructor(wallet: WalletStateStore, registry: EvmProviderRegistry, deps: EvmRequestTrackerDeps); /** Stop every poll in flight. Terminal, like the event queue's close(). */ cleanup(): void; /** Providers whose owner list includes this instance; pruned on cleanup. */ private wrappedProviders; /** Re-arm a poll, unless this tracker has been torn down. */ private schedulePoll; /** * Wrap a provider's `request`. Returns whether the wrapper is installed: * a caller that marks the provider as tracked on a false return would * never retry it, and every signature and transaction from that wallet * would be missed for the rest of the session. */ /** Monotonic creation stamp; owner precedence is decided by it. */ private static nextCreationSeq; readonly creationSeq: number; /** * Put this tracker into an owner list at its CREATION-ORDER position. * Registration can arrive out of order - an older instance's async wrap * kick may resolve after a newer instance's - and dispatch picks from * the END of the list, so append-on-registration would let resolution * order decide which instance owns capture. Creation order is what the * newest-live contract promises. */ private insertBySeniority; registerRequestListeners(provider: EIP1193Provider): boolean; /** Install the wrapper function onto the provider; separated so the * routing shim above stays small. */ private installWrappedRequest; /** * The wrapper body proper: everything a request observation does, run * against THIS instance's registry, wallet state, and event queue. Kept * as a method so a surviving wrapper installed by a previous SDK * instance can hand calls to the current one. */ private dispatchWrappedRequest; /** * Wallet attribution for request-derived events. * * Resolved through the registry at the START of each request and held * for that request's whole lifecycle, receipt included. Reading it per * status let a connector switch (two connectors sharing one provider) or * a session change made while a prompt was open split one operation * between two wallet names. Still live across requests: a WalletConnect * session names its actual signer ("MetaMask Wallet", "Ledger Live") - * the live-test rows had provider_name EMPTY on every signature and * transaction, which made per-wallet activity unanswerable in the * warehouse. */ private attributionFor; private buildSignatureEventPayload; private buildTransactionEventPayload; /** * Polls for transaction receipt and emits tx.status = CONFIRMED or REVERTED. */ private pollTransactionReceipt; /** * One `transaction` event per call in an EIP-5792 batch. * * The CALL is the unit of attribution: each has its own target, calldata, * and value, and folding a batch into one event would misattribute revenue * and per-contract activity for every app that adopts smart accounts. How * many on-chain transactions a batch becomes depends on execution - an * atomic batch lands as ONE transaction, a non-atomic fallback as several - * so on-chain volume is `count(distinct transaction_hash)`, wallet actions * `count(distinct batch_id)`, never the event count. Each call is reported * on its own, carrying the batch id so the calls reassemble downstream. * * Status is per BATCH, because that is what `wallet_getCallsStatus` reports. * When it resolves, every call in the batch moves together, except where * per-call receipts say otherwise on a non-atomic batch. */ private trackBatchedCalls; /** * Resolve a batch through `wallet_getCallsStatus`. * * The status codes are EIP-5792's: 100 pending, 200 confirmed, 400 failed * before landing, 500 reverted, 600 partially reverted. Anything below 200 * means keep waiting. * * A per-call receipt wins over the batch verdict where one exists, which is * what makes a partially reverted non-atomic batch report honestly instead * of marking every call with the batch's worst outcome. */ private pollBatchStatus; } //# sourceMappingURL=EvmRequestTracker.d.ts.map