import { WalletMonitorTask } from './tasks/WalletMonitorTask'; import { WalletStorageManager } from '../storage/WalletStorageManager'; import { TaskPurgeParams } from './tasks/TaskPurge'; import { Chain, ProvenTransactionStatus } from '../sdk/types'; import { ReviewActionResult } from '../sdk/WalletStorage.interfaces'; import { BlockHeader, WalletServices } from '../sdk/WalletServices.interfaces'; import { Services } from '../services/Services'; import { ChaintracksClientApi } from '../services/chaintracker/chaintracks/Api/ChaintracksClientApi'; export type MonitorStorage = WalletStorageManager; export type MonitorStartupTaskMode = 'none' | 'default' | 'multiuser' | 'alltoother'; export interface MonitorOptions { chain: Chain; services: Services | WalletServices; storage: MonitorStorage; chaintracks: ChaintracksClientApi; chaintracksWithEvents?: ChaintracksClientApi; /** Maximum deactivated block headers retained for reproof. Default: 4096. */ maxQueuedDeactivatedHeaders?: number; /** Optional bounded operational logger. Monitor library code is silent by default. */ logging?: (...args: unknown[]) => void; startupTaskMode?: MonitorStartupTaskMode; /** * How many msecs to wait after each getMerkleProof service request. */ msecsWaitPerMerkleProofServiceReq: number; taskRunWaitMsecs: number; abandonedMsecs: number; unprovenAttemptsLimitTest: number; unprovenAttemptsLimitMain: number; /** * Maximum number of times a broadcast transaction may be reset to 'unsent' for * rebroadcast after proof check timeout (circuit breaker). * * Default 0 means unlimited — the tx is rebroadcast indefinitely until a proof * is found. Set to a positive integer to cap rebroadcast cycles; once the limit * is reached the req is marked 'invalid'. */ maxRebroadcastAttempts: number; /** * Stable callback token for ARC SSE event streaming. * When set, TaskArcadeSSE will open an SSE connection to Arcade's * /events endpoint and receive real-time transaction status updates. * Must match the X-CallbackToken header sent during broadcast. */ callbackToken?: string; /** Load persisted SSE lastEventId (e.g. from SQLite) for catchup on startup */ loadLastSSEEventId?: () => Promise; /** Save SSE lastEventId to persistent storage */ saveLastSSEEventId?: (lastEventId: string) => Promise; /** The react-native-sse EventSource class for SSE support in React Native */ EventSourceClass?: any; /** * These are hooks for a wallet-toolbox client to get transaction updates. */ onTransactionBroadcasted?: (broadcastResult: ReviewActionResult) => Promise; onTransactionProven?: (txStatus: ProvenTransactionStatus) => Promise; onTransactionStatusChanged?: (txid: string, newStatus: string) => Promise; } /** * Background task to make sure transactions are processed, transaction proofs are received and propagated, * and potentially that reorgs update proofs that were already received. */ export declare class Monitor { static createDefaultWalletMonitorOptions(chain: Chain, storage: MonitorStorage, services?: Services, chaintracks?: ChaintracksClientApi, startupTaskMode?: MonitorStartupTaskMode): MonitorOptions; options: MonitorOptions; services: Services | WalletServices; chain: Chain; storage: MonitorStorage; chaintracks: ChaintracksClientApi; chaintracksWithEvents?: ChaintracksClientApi; reorgSubscriptionPromise?: Promise; reorgInvalidationPromise: Promise; headersSubscriptionPromise?: Promise; onTransactionBroadcasted?: (broadcastResult: ReviewActionResult) => Promise; onTransactionProven?: (txStatus: ProvenTransactionStatus) => Promise; onTransactionStatusChanged?: (txid: string, newStatus: string) => Promise; /** * Resolves once the optional Chaintracks subscriptions have been registered. * Await this before calling `startTasks()` if `chaintracksWithEvents` is provided * and you need subscriptions to be active before the first task loop runs. * * `runOnce`/`startTasks` do not await this directly — they call it through * `ensureEventSubscriptions`, which treats a rejection as best-effort and * always lets the scheduler proceed. A rejection here is not itself a * disaster: on failure `_readyInit` is reset below so the next access * retries `_init()`. */ get ready(): Promise; private _readyInit?; private readonly maxQueuedDeactivatedHeaders; private readonly deactivatedHeaderHashes; private reorgInvalidationPending; private readonly logging?; constructor(options: MonitorOptions); private _init; private applyStartupTaskMode; destroy(): Promise; static readonly oneSecond = 1000; static readonly oneMinute: number; static readonly oneHour: number; static readonly oneDay: number; static readonly oneWeek: number; /** * _tasks are typically run by the scheduler but may also be run by runTask. */ _tasks: WalletMonitorTask[]; /** * _otherTasks can be run by runTask but not by scheduler. */ _otherTasks: WalletMonitorTask[]; _tasksRunning: boolean; defaultPurgeParams: TaskPurgeParams; addAllTasksToOther(): void; /** * Default tasks with settings appropriate for a single user storage */ addDefaultTasks(): void; /** * Tasks appropriate for multi-user storage */ addMultiUserTasks(): void; addTask(task: WalletMonitorTask): void; removeTask(name: string): void; runTask(name: string): Promise; runOnce(): Promise; /** * Best-effort attempt to (re)register the optional Chaintracks header/reorg * push subscriptions ahead of this scheduler tick. * * Header and reorg events are a latency optimization, not a requirement: * every task that cares about chain height or reorgs (TaskNewHeader, * TaskReorg, ...) already polls the configured `chaintracks` on its own * schedule regardless of whether push events are flowing. An offline, * unimplemented (see the `supportsReorgEvents` skip in `_init`), or * otherwise misconfigured event source must not stop the scheduler that * runs every other maintenance task. * * A failure here is swallowed and logged once per outage; the `ready` * getter's own `.catch` resets `_readyInit` first, so the *next* call to * this method (i.e. the next scheduler tick) retries `_init()` from * scratch. A genuine configured-chain mismatch (see * `_init`) still fails `ready` every time it is retried, so the event * source never transitions to a subscribed state on mismatched data — * only this outer scheduling loop is decoupled from that failure. * * A caller that specifically needs subscriptions active before its own * first task loop can still `await monitor.ready` directly and handle the * rejection itself; that public contract is unchanged. */ private ensureEventSubscriptions; private _chaintracksEventsErrorLogged; private logChaintracksEventsError; private setupTasksOnce; private tasksReadyToRun; private runScheduledTask; private logTaskError; _runAsyncSetup: boolean; private readonly setupTasksComplete; _tasksRunningPromise?: PromiseLike; resolveCompletion: ((value: void | PromiseLike) => void) | undefined; startTasks(): Promise; logEvent(event: string, details?: string): Promise; stopTasks(): void; private emitLog; lastNewHeader: BlockHeader | undefined; lastNewHeaderWhen: Date | undefined; /** * Process new chain header event received from Chaintracks * * Kicks processing 'unconfirmed' and 'unmined' request processing. * * @param reqs */ processNewBlockHeader(header: BlockHeader): void; /** * This is a function run from a TaskSendWaiting Monitor task. * * This allows the user of wallet-toolbox to 'subscribe' for transaction broadcast updates. * * @param broadcastResult */ callOnBroadcastedTransaction(broadcastResult: ReviewActionResult): void; /** * This is a function run from a TaskCheckForProofs Monitor task. * * This allows the user of wallet-toolbox to 'subscribe' for transaction updates. * * @param txStatus */ callOnProvenTransaction(txStatus: ProvenTransactionStatus): void; /** * Called by TaskArcadeSSE when an SSE status event is received from Arcade. */ callOnTransactionStatusChanged(txid: string, newStatus: string): void; private invokeCallback; /** * Fetch pending transaction status events from Arcade on demand. * Call this on app open, balance refresh, transaction list view, etc. */ fetchSSEEvents(): Promise; deactivatedHeaders: DeactivedHeader[]; /** * Process reorg event received from Chaintracks * * Reorgs can move recent transactions to new blocks at new index positions. * Affected transaction proofs become invalid and must be updated. * * It is possible for a transaction to become invalid. * * Coinbase transactions always become invalid. */ processReorg(depth: number, oldTip: BlockHeader, newTip: BlockHeader, deactivatedHeaders?: BlockHeader[]): void; enqueueDeactivatedHeader(item: DeactivedHeader): void; shiftDeactivatedHeader(): DeactivedHeader | undefined; private preparedBeefInvalidation; private requestPreparedBeefInvalidation; private validateReorgEvent; private copyValidatedHeader; /** * Handler for new header events from Chaintracks. * * To minimize reorg processing, new headers are aged before processing via TaskNewHeader. * Therefore this handler is intentionally a no-op. * * @param header */ processHeader(header: BlockHeader): void; } export interface DeactivedHeader { /** * To control aging of notification before pursuing updated proof data. */ whenMsecs: number; /** * Number of attempts made to process the header. * Supports returning deactivation notification to the queue if proof data is not yet available. */ tries: number; /** * The deactivated block header. */ header: BlockHeader; } //# sourceMappingURL=Monitor.d.ts.map