@tuwaio/pulsar-core 0.0.6 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/store/initializeTxTrackingStore.ts","../src/store/transactionsSelectors.ts","../src/utils/selectAdapterByKey.ts","../src/store/txTrackingStore.ts","../src/types.ts","../src/utils/createBoundedUseStore.ts","../src/utils/initializePollingTracker.ts"],"names":["initializeTxTrackingStore","onSucceedCallbacks","set","get","tx","state","produce","draft","txKey","fields","selectAllTransactions","transactionsPool","a","b","selectPendingTransactions","selectTxByKey","key","selectAllTransactionsByActiveWallet","from","selectPendingTransactionsByActiveWallet","selectAdapterByKey","adapterKey","adapters","adapter","createPulsarStore","options","createStore","persist","pendingTxs","defaultTracker","actionFunction","params","desiredChainID","restParams","localTimestamp","dayjs","error","handleTxError","walletType","walletAddress","txKeyFromAction","txInitialParams","updatedTracker","finalTxKey","newTx","e","errorMessage","TransactionAdapter","TransactionStatus","createBoundedUseStore","store","selector","useStore","DEFAULT_POLLING_INTERVAL","DEFAULT_MAX_RETRIES","initializePollingTracker","config","fetcher","onInitialize","onSuccess","onFailure","onIntervalTick","onReplaced","removeTxFromPool","pollingInterval","maxRetries","retriesLeft","isPolling","stopPolling","resolve"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @file This file provides the core slice for the Zustand store, responsible for managing the state of transactions.\n * It includes functions and types for initializing the store and performing basic CRUD operations on the transaction pool.\n */\n\nimport { Draft, produce } from 'immer';\n\nimport { EvmTransaction, InitialTransaction, StoreSlice, Transaction } from '../types';\n\n/**\n * Defines the structure of the transaction pool, which is a record of transactions indexed by their unique keys.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n */\nexport type TransactionPool<TR, T extends Transaction<TR>> = Record<string, T>;\n\n/**\n * A utility type that extracts a subset of fields from the `Transaction` type\n * that are updatable via the `updateTxParams` action.\n * @template TR - The type of the tracker identifier.\n */\ntype UpdatableTransactionFields<TR> = Partial<\n Pick<\n EvmTransaction<TR>,\n | 'to'\n | 'nonce'\n | 'txKey'\n | 'pending'\n | 'hash'\n | 'status'\n | 'replacedTxHash'\n | 'errorMessage'\n | 'finishedTimestamp'\n | 'isTrackedModalOpen'\n | 'isError'\n | 'maxPriorityFeePerGas'\n | 'maxFeePerGas'\n | 'input'\n | 'value'\n >\n>;\n\n/**\n * Defines the interface for the base transaction tracking store slice.\n * It includes the state and actions for managing transactions.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n */\nexport interface IInitializeTxTrackingStore<TR, T extends Transaction<TR>> {\n /** An optional callback function to be executed when a transaction successfully completes. */\n onSucceedCallbacks?: (tx: T) => Promise<void> | void;\n /** A pool of all transactions currently being tracked, indexed by their `txKey`. */\n transactionsPool: TransactionPool<TR, T>;\n /** The key of the most recently added transaction. */\n lastAddedTxKey?: string;\n /** The state of a transaction that is currently being initiated but not yet submitted. */\n initialTx?: InitialTransaction;\n\n /** Adds a new transaction to the tracking pool. */\n addTxToPool: (tx: T) => void;\n /** Updates one or more parameters of an existing transaction in the pool. */\n updateTxParams: (txKey: string, fields: UpdatableTransactionFields<TR>) => void;\n /** Removes a transaction from the tracking pool using its key. */\n removeTxFromPool: (txKey: string) => void;\n /** Closes the tracking modal for a specific transaction. */\n closeTxTrackedModal: (txKey?: string) => void;\n /** Returns the key of the last transaction that was added to the pool. */\n getLastTxKey: () => string | undefined;\n}\n\n/**\n * Creates a Zustand store slice containing the core logic for transaction tracking.\n * This function is a slice creator and is meant to be used within `createStore` from Zustand.\n * @param {object} options - Configuration options for the store slice.\n * @param {function} [options.onSucceedCallbacks] - An optional async callback to run when a transaction succeeds.\n * @returns {StoreSlice<IInitializeTxTrackingStore<TR, T>>} A Zustand store slice.\n */\nexport function initializeTxTrackingStore<TR, T extends Transaction<TR>>({\n onSucceedCallbacks,\n}: {\n onSucceedCallbacks?: (tx: T) => Promise<void> | void;\n}): StoreSlice<IInitializeTxTrackingStore<TR, T>> {\n return (set, get) => ({\n onSucceedCallbacks,\n\n transactionsPool: {},\n lastAddedTxKey: undefined,\n initialTx: undefined,\n\n addTxToPool: (tx) => {\n set((state) =>\n produce(state, (draft) => {\n draft.lastAddedTxKey = tx.txKey;\n if (tx.txKey) {\n draft.transactionsPool[tx.txKey] = {\n ...tx,\n pending: true,\n } as Draft<T>;\n }\n }),\n );\n },\n\n updateTxParams: (txKey, fields) => {\n set((state) =>\n produce(state, (draft) => {\n const tx = draft.transactionsPool[txKey];\n // Ensure the transaction exists before attempting to update\n if (tx) {\n Object.assign(tx, fields);\n }\n }),\n );\n },\n\n removeTxFromPool: (txKey) => {\n set((state) =>\n produce(state, (draft) => {\n delete draft.transactionsPool[txKey];\n }),\n );\n },\n\n closeTxTrackedModal: (txKey) => {\n set((state) =>\n produce(state, (draft) => {\n if (txKey && draft.transactionsPool[txKey]) {\n draft.transactionsPool[txKey].isTrackedModalOpen = false;\n }\n // Always clear the initial transaction state when a modal is closed\n draft.initialTx = undefined;\n }),\n );\n },\n\n getLastTxKey: () => get().lastAddedTxKey,\n });\n}\n","/**\n * @file This file contains selector functions for deriving state from the transaction tracking store.\n * Selectors help abstract the state's shape and provide efficient, memoized access to computed data.\n */\n\nimport { Transaction } from '../types';\nimport { TransactionPool } from './initializeTxTrackingStore';\n\n/**\n * Selects all transactions from the pool and sorts them by their creation timestamp in ascending order.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of all transactions, sorted chronologically.\n */\nexport const selectAllTransactions = <TR, T extends Transaction<TR>>(transactionsPool: TransactionPool<TR, T>): T[] => {\n return Object.values(transactionsPool).sort((a, b) => Number(a.localTimestamp) - Number(b.localTimestamp));\n};\n\n/**\n * Selects all transactions that are currently in a pending state, sorted chronologically.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of pending transactions.\n */\nexport const selectPendingTransactions = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n): T[] => {\n return selectAllTransactions(transactionsPool).filter((tx) => tx.pending);\n};\n\n/**\n * Selects a single transaction from the pool by its unique key (`txKey`).\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @param {string} key - The `txKey` of the transaction to retrieve.\n * @returns {T | undefined} The transaction object if found, otherwise undefined.\n */\nexport const selectTxByKey = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n key: string,\n): T | undefined => {\n return transactionsPool[key];\n};\n\n/**\n * Selects all transactions initiated by a specific wallet address, sorted chronologically.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @param {string} from - The wallet address (`from` address) to filter transactions by.\n * @returns {T[]} An array of transactions associated with the given wallet.\n */\nexport const selectAllTransactionsByActiveWallet = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n from: string,\n): T[] => {\n // Filters all transactions to find those matching the provided `from` address.\n return selectAllTransactions(transactionsPool).filter((tx) => tx.from.toLowerCase() === from.toLowerCase());\n};\n\n/**\n * Selects all pending transactions for a specific wallet address, sorted chronologically.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @param {string} from - The wallet address (`from` address) to filter transactions by.\n * @returns {T[]} An array of pending transactions for the given wallet.\n */\nexport const selectPendingTransactionsByActiveWallet = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n from: string,\n): T[] => {\n // Reuses the `selectAllTransactionsByActiveWallet` selector for efficiency\n // and then filters for pending transactions.\n return selectAllTransactionsByActiveWallet(transactionsPool, from).filter((tx) => tx.pending);\n};\n","/**\n * @file This file contains a utility function for selecting a specific transaction adapter from a list.\n */\n\nimport { Transaction, TransactionAdapter, TxAdapter } from '../types';\n\n/**\n * Selects a transaction adapter from a list based on a provided key.\n *\n * This function searches through an array of `TxAdapter` instances and returns the one\n * that matches the given `adapterKey`. If no specific adapter is found, it logs a warning\n * and returns the first adapter in the array as a fallback. This fallback mechanism\n * ensures that the system can still function, but it highlights a potential configuration issue.\n *\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type, extending the base `Transaction`.\n * @template A - The type for the adapter-specific context or API.\n *\n * @param {object} params - The parameters for the selection.\n * @param {TransactionAdapter} params.adapterKey - The key of the desired adapter.\n * @param {TxAdapter<TR, T, A>[]} params.adapters - An array of available transaction adapters.\n *\n * @returns {TxAdapter<TR, T, A> | undefined} The found transaction adapter, the fallback adapter, or undefined if the adapters array is empty.\n */\nexport const selectAdapterByKey = <TR, T extends Transaction<TR>, A>({\n adapterKey,\n adapters,\n}: {\n adapterKey: TransactionAdapter;\n adapters: TxAdapter<TR, T, A>[];\n}): TxAdapter<TR, T, A> | undefined => {\n if (!adapters || adapters.length === 0) {\n console.error('Adapter selection failed: The provided adapters array is empty.');\n return undefined;\n }\n\n const adapter = adapters.find((a) => a.key === adapterKey);\n\n if (adapter) {\n return adapter;\n } else {\n console.warn(\n `No adapter found for key: \"${adapterKey}\". Falling back to the first available adapter: \"${adapters[0].key}\".`,\n );\n return adapters[0];\n }\n};\n","/**\n * @file This file is the heart of the Pulsar store, orchestrating transaction handling,\n * state management, and communication with various blockchain adapters. It leverages\n * Zustand for state management, Immer for immutable updates, and a persistent middleware\n * to maintain state across sessions.\n */\n\nimport dayjs from 'dayjs';\nimport { Draft, produce } from 'immer';\nimport { persist, PersistOptions } from 'zustand/middleware';\nimport { createStore } from 'zustand/vanilla';\n\nimport { ITxTrackingStore, Transaction, TxAdapter } from '../types';\nimport { selectAdapterByKey } from '../utils/selectAdapterByKey';\nimport { initializeTxTrackingStore } from './initializeTxTrackingStore';\n\n/**\n * Creates the main Pulsar store for transaction tracking.\n *\n * This function sets up a Zustand store with persistence, combining the core\n * transaction slice with adapter-specific logic to handle the entire lifecycle\n * of a transaction.\n *\n * @template TR - The type of the tracker identifier (e.g., a string enum).\n * @template T - The specific transaction type, extending the base `Transaction`.\n * @template A - The type for the adapter-specific context or API.\n *\n * @param {object} config - Configuration object for creating the store.\n * @param {function} [config.onSucceedCallbacks] - Optional async callback executed on transaction success.\n * @param {TxAdapter<TR, T, A>[]} config.adapters - An array of adapters for different transaction types or chains.\n * @param {PersistOptions<ITxTrackingStore<TR, T, A>>} [options] - Configuration for the Zustand persist middleware.\n * @returns A fully configured Zustand store instance.\n */\nexport function createPulsarStore<TR, T extends Transaction<TR>, A>({\n onSucceedCallbacks,\n adapters,\n ...options\n}: {\n onSucceedCallbacks?: (tx: T) => Promise<void> | void;\n adapters: TxAdapter<TR, T, A>[];\n} & PersistOptions<ITxTrackingStore<TR, T, A>>) {\n return createStore<ITxTrackingStore<TR, T, A>>()(\n persist(\n (set, get) => ({\n ...initializeTxTrackingStore<TR, T>({ onSucceedCallbacks })(set, get),\n\n /**\n * Initializes trackers for all pending transactions upon store creation.\n * This is crucial for resuming tracking after a page refresh or session restoration.\n */\n initializeTransactionsPool: async () => {\n const pendingTxs = Object.values(get().transactionsPool).filter((tx) => tx.pending);\n\n await Promise.all(\n pendingTxs.map((tx) => {\n const adapter = selectAdapterByKey({\n adapterKey: tx.adapter,\n adapters,\n });\n return adapter?.checkAndInitializeTrackerInStore({ tx, ...get() });\n }),\n );\n },\n\n /**\n * The core function to orchestrate sending and tracking a new transaction.\n * It manages the entire lifecycle, including chain switching, wallet interactions,\n * state updates, and tracker initialization.\n */\n handleTransaction: async ({ defaultTracker, actionFunction, params }) => {\n const { desiredChainID, ...restParams } = params;\n const localTimestamp = dayjs().unix();\n\n // 1. Set initial state for immediate UI feedback\n set({\n initialTx: {\n ...params,\n localTimestamp,\n isInitializing: true,\n },\n });\n\n const adapter = selectAdapterByKey({\n adapterKey: restParams.adapter,\n adapters,\n });\n\n if (!adapter) {\n const error = new Error('No adapter found for this transaction.');\n handleTxError(error);\n throw error; // Re-throw to allow the caller to handle it\n }\n\n try {\n const { walletType, walletAddress } = adapter.getWalletInfo();\n\n // 2. Ensure the wallet is connected to the correct chain\n await adapter.checkChainForTx(desiredChainID);\n\n // 3. Execute the provided action function (e.g., signing a transaction)\n const txKeyFromAction = await actionFunction();\n\n if (!txKeyFromAction) {\n // If the user cancelled the action, clear the initial state.\n set({ initialTx: undefined });\n return;\n }\n\n // 4. Prepare the initial transaction object\n const txInitialParams = {\n ...restParams,\n walletType,\n from: walletAddress,\n tracker: defaultTracker,\n chainId: desiredChainID,\n localTimestamp,\n txKey: '', // Will be populated shortly\n pending: false,\n isTrackedModalOpen: params.withTrackedModal,\n } as Draft<T>;\n\n // 5. Determine the correct tracker and final txKey based on the action result\n const { tracker: updatedTracker, txKey: finalTxKey } = adapter.checkTransactionsTracker(\n txKeyFromAction,\n txInitialParams.walletType,\n );\n\n const newTx = {\n ...txInitialParams,\n tracker: updatedTracker,\n txKey: finalTxKey,\n hash: updatedTracker === 'ethereum' ? txKeyFromAction : undefined,\n } as T;\n\n // 6. Add the finalized transaction to the pool\n get().addTxToPool(newTx);\n\n // 7. Update the initial state to reflect completion\n set((state) =>\n produce(state, (draft) => {\n if (draft.initialTx) {\n draft.initialTx.isInitializing = false;\n draft.initialTx.lastTxKey = finalTxKey;\n }\n }),\n );\n\n // 8. Initialize the background tracker for the new transaction\n const tx = get().transactionsPool[finalTxKey];\n await adapter.checkAndInitializeTrackerInStore({ tx, ...get() });\n } catch (e) {\n handleTxError(e);\n throw e; // Re-throw for external handling\n }\n\n /**\n * A centralized error handler for the transaction process.\n * @param {unknown} e - The error object.\n */\n function handleTxError(e: unknown) {\n const errorMessage = e instanceof Error ? e.message : String(e);\n set((state) =>\n produce(state, (draft) => {\n if (draft.initialTx) {\n draft.initialTx.isInitializing = false;\n draft.initialTx.errorMessage = errorMessage;\n }\n }),\n );\n }\n },\n }),\n {\n ...options, // Zustand persist middleware options\n },\n ),\n );\n}\n","/**\n * @file This file defines the core data structures and TypeScript types for the Pulsar transaction tracking engine.\n * It includes types for transactions, their statuses, store interfaces, and utility types for Zustand slices.\n * These types are framework-agnostic and form the foundation of the entire tracking system.\n */\n\nimport { StoreApi } from 'zustand';\n\nimport { IInitializeTxTrackingStore, TransactionPool } from './store/initializeTxTrackingStore';\n\n// =================================================================================================\n// 1. ZUSTAND UTILITY TYPES\n// =================================================================================================\n\n/**\n * A utility type for creating modular Zustand store slices, enabling composable state management.\n * @template T - The type of the state slice.\n * @template S - The type of the full store state, defaulting to T.\n */\nexport type StoreSlice<T extends object, S extends object = T> = (\n set: StoreApi<S extends T ? S : S & T>['setState'],\n get: StoreApi<S extends T ? S : S & T>['getState'],\n) => T;\n\n// =================================================================================================\n// 2. ENUMS AND CORE TRANSACTION TYPES\n// =================================================================================================\n\n/**\n * Defines the supported blockchain adapters. Each adapter corresponds to a specific chain architecture.\n */\nexport enum TransactionAdapter {\n /** For Ethereum Virtual Machine (EVM) compatible chains like Ethereum, Polygon, etc. */\n EVM = 'evm',\n /** For the Solana blockchain. */\n SOLANA = 'solana',\n /** For the Starknet L2 network. */\n Starknet = 'starknet',\n}\n\n/**\n * Represents the terminal status of a transaction after it has been processed.\n */\nexport enum TransactionStatus {\n /** The transaction failed to execute due to an on-chain error or rejection. */\n Failed = 'Failed',\n /** The transaction was successfully mined and executed. */\n Success = 'Success',\n /** The transaction was replaced by another with the same nonce (e.g., a speed-up or cancel). */\n Replaced = 'Replaced',\n}\n\n/**\n * The fundamental structure for any transaction being tracked by Pulsar.\n * This forms the base upon which chain-specific transaction types are built.\n * @template T - The type of the tracker identifier (e.g., 'ethereum', 'gelato', 'safe').\n */\nexport type BaseTransaction<T> = {\n /** A unique key identifying a re-executable action from the `TxActions` registry. */\n actionKey?: string;\n /** The chain identifier (e.g., 1 for Ethereum Mainnet, 'SN_MAIN' for Starknet). */\n chainId: number | string;\n /** A user-facing description. Can be a single string or an array for [pending, success, error, replaced] states. */\n description?: string | [string, string, string, string];\n /** The error message if the transaction failed. */\n errorMessage?: string;\n /** The on-chain timestamp (in seconds) when the transaction was finalized. */\n finishedTimestamp?: number;\n /** The sender's wallet address. */\n from: string;\n /** A flag indicating if the transaction is in a failed state. */\n isError?: boolean;\n /** A UI flag to control the visibility of a detailed tracking modal for this transaction. */\n isTrackedModalOpen?: boolean;\n /** The local timestamp (in seconds) when the transaction was initiated by the user. */\n localTimestamp: number;\n /** Any additional, custom data associated with the transaction. */\n payload?: object;\n /** A flag indicating if the transaction is still awaiting on-chain confirmation. */\n pending: boolean;\n /** The final on-chain status of the transaction. */\n status?: TransactionStatus;\n /** A user-facing title. Can be a single string or an array for [pending, success, error, replaced] states. */\n title?: string | [string, string, string, string];\n /** The specific tracker responsible for monitoring this transaction's status. */\n tracker: T;\n /** The unique identifier for the transaction (e.g., EVM hash, Gelato task ID). */\n txKey: string;\n /** The application-specific type or category of the transaction (e.g., 'SWAP', 'APPROVE'). */\n type: string;\n /** The type of wallet used to sign the transaction (e.g., 'injected', 'walletConnect'). */\n walletType: string;\n};\n\n// =================================================================================================\n// 3. CHAIN-SPECIFIC TRANSACTION TYPES\n// =================================================================================================\n\n/**\n * Represents an EVM-specific transaction, extending the base properties with EVM fields.\n * @template T - The type of the tracker identifier.\n */\nexport type EvmTransaction<T> = BaseTransaction<T> & {\n adapter: TransactionAdapter.EVM;\n /** The on-chain transaction hash, available after submission. */\n hash?: `0x${string}`;\n /** The data payload for the transaction, typically for smart contract interactions. */\n input?: `0x${string}`;\n /** The maximum fee per gas for an EIP-1559 transaction (in wei). */\n maxFeePerGas?: string;\n /** The maximum priority fee per gas for an EIP-1559 transaction (in wei). */\n maxPriorityFeePerGas?: string;\n /** The transaction nonce, a sequential number for the sender's account. */\n nonce?: number;\n /** The hash of a transaction that this one replaced. */\n replacedTxHash?: `0x${string}`;\n /** The recipient's address or contract address. */\n to?: `0x${string}`;\n /** The amount of native currency (in wei) being sent. */\n value?: string;\n};\n\n/**\n * Represents a Solana-specific transaction, extending the base properties.\n * @template T - The type of the tracker identifier.\n */\nexport type SolanaTransaction<T> = BaseTransaction<T> & {\n adapter: TransactionAdapter.SOLANA;\n /** The transaction fee in lamports. */\n fee?: number;\n /** The instructions included in the transaction. */\n instructions?: unknown[];\n /** The recent blockhash used for the transaction. */\n recentBlockhash?: string;\n /** The slot in which the transaction was processed. */\n slot?: number;\n};\n\n/**\n * Represents a Starknet-specific transaction, extending the base properties.\n * @template T - The type of the tracker identifier.\n */\nexport type StarknetTransaction<T> = BaseTransaction<T> & {\n adapter: TransactionAdapter.Starknet;\n /** The actual fee paid for the transaction. */\n actualFee?: { amount: string; unit: string };\n /** The address of the contract being interacted with. */\n contractAddress?: string;\n /** The reason for transaction failure, if applicable. */\n revertReason?: string;\n};\n\n/** A union type representing any possible transaction structure that Pulsar can handle. */\nexport type Transaction<T> = EvmTransaction<T> | SolanaTransaction<T> | StarknetTransaction<T>;\n\n// =================================================================================================\n// 4. INITIAL TRANSACTION AND ACTION TYPES\n// =================================================================================================\n\n/**\n * A registry of functions that can be re-executed, keyed by `actionKey`.\n * Used for implementing \"Retry\" functionality.\n */\nexport type TxActions = Record<string, (...args: any[]) => Promise<unknown>>;\n\n/**\n * Represents the parameters required to initiate a new transaction tracking flow.\n */\nexport type InitialTransactionParams = {\n adapter: TransactionAdapter;\n /** A key to identify the re-executable action from the `TxActions` registry. */\n actionKey?: string;\n /** A user-facing description for the transaction. */\n description?: string | [string, string, string, string];\n /** The target chain ID for the transaction. */\n desiredChainID: number | string;\n /** Any custom data to associate with the transaction. */\n payload?: object;\n /** A user-facing title for the transaction. */\n title?: string | [string, string, string, string];\n /** The application-specific type of the transaction. */\n type: string;\n /** If true, the detailed tracking modal will open automatically upon initiation. */\n withTrackedModal?: boolean;\n};\n\n/**\n * Represents a transaction in its temporary, pre-submission state.\n * This is used for UI feedback while the transaction is being signed and sent.\n */\nexport type InitialTransaction = InitialTransactionParams & {\n /** An error message if the initialization fails (e.g., user rejects signature). */\n errorMessage?: string;\n /** A flag indicating if the transaction is being processed (e.g., waiting for signature). */\n isInitializing: boolean;\n /** The `txKey` of the on-chain transaction that this action produced, used for linking the states. */\n lastTxKey?: string;\n /** The local timestamp when the user initiated the action. */\n localTimestamp: number;\n};\n\n// =================================================================================================\n// 5. ADAPTER AND STORE INTERFACES\n// =================================================================================================\n\n/**\n * Defines the interface for a transaction adapter, which provides chain-specific logic and utilities.\n * @template TR - The type of the tracker identifier (e.g., a string enum).\n * @template T - The specific transaction type, extending `Transaction<TR>`.\n * @template A - The type of the key returned by the `actionFunction` (e.g., a transaction hash).\n */\nexport type TxAdapter<TR, T extends Transaction<TR>, A> = {\n /** The unique key identifying this adapter. */\n key: TransactionAdapter;\n /** Returns information about the currently connected wallet. */\n getWalletInfo: () => {\n walletAddress: string;\n walletType: string;\n };\n /** Ensures the connected wallet is on the correct network for the transaction. */\n checkChainForTx: (chainId: string | number) => Promise<void>;\n /** Determines the appropriate tracker and final `txKey` based on the result of an action. */\n checkTransactionsTracker: (actionTxKey: A, walletType: string) => { txKey: string; tracker: TR };\n /** Initializes the correct background tracker for a given transaction. */\n checkAndInitializeTrackerInStore: (\n params: { tx: T } & Pick<\n ITxTrackingStore<TR, T, A>,\n 'transactionsPool' | 'updateTxParams' | 'onSucceedCallbacks' | 'removeTxFromPool'\n >,\n ) => Promise<void>;\n /** Returns the base URL for the blockchain explorer. */\n getExplorerUrl: () => string | undefined;\n /** Optional: Fetches a name from a chain-specific name service (e.g., ENS). */\n getName?: (address: string) => Promise<string | null>;\n /** Optional: Fetches an avatar URL from a chain-specific name service. */\n getAvatar?: (name: string) => Promise<string | null>;\n /** Optional: Logic to cancel a pending EVM transaction. */\n cancelTxAction?: (tx: T) => Promise<string>;\n /** Optional: Logic to speed up a pending EVM transaction. */\n speedUpTxAction?: (tx: T) => Promise<string>;\n /** Optional: Logic to retry a failed transaction. */\n retryTxAction?: (\n params: {\n txKey: string;\n tx: InitialTransactionParams;\n actions?: TxActions;\n onClose: (txKey?: string) => void;\n } & Partial<Pick<ITxTrackingStore<TR, T, A>, 'handleTransaction'>>,\n ) => Promise<void>;\n /** Optional: Constructs a full explorer URL for a specific transaction. */\n getExplorerTxUrl?: (transactionsPool: TransactionPool<TR, T>, txKey: string, replacedTxHash?: string) => string;\n};\n\n/**\n * The complete interface for the Pulsar transaction tracking store.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @template A - The return type of the `actionFunction`.\n */\nexport type ITxTrackingStore<TR, T extends Transaction<TR>, A> = IInitializeTxTrackingStore<TR, T> & {\n /**\n * The core function that handles the entire lifecycle of a new transaction.\n * It manages UI state, executes the on-chain action, and initiates background tracking.\n * @param params - The parameters for handling the transaction.\n */\n handleTransaction: (params: {\n /** The async function to execute (e.g., a smart contract write call). Must return a unique key or undefined. */\n actionFunction: () => Promise<A | undefined>;\n /** The metadata for the transaction. */\n params: InitialTransactionParams;\n /** The default tracker to use if it cannot be determined automatically. */\n defaultTracker?: TR;\n }) => Promise<void>;\n\n /**\n * Initializes trackers for all pending transactions in the pool.\n * This is essential for resuming tracking after a page reload.\n */\n initializeTransactionsPool: () => Promise<void>;\n};\n","/**\n * @file This file provides a utility for creating a type-safe, bounded Zustand hook from a vanilla store.\n * This pattern is recommended by the official Zustand documentation to ensure full type\n * safety when integrating vanilla stores with React.\n *\n * @see https://docs.pmnd.rs/zustand/guides/typescript#bounded-usestore-hook-for-vanilla-stores\n */\n\nimport { StoreApi, useStore } from 'zustand';\n\n/**\n * A utility type that infers the state shape from a Zustand `StoreApi`.\n * It extracts the return type of the `getState` method.\n * @template S - The type of the Zustand store (`StoreApi`).\n */\ntype ExtractState<S> = S extends { getState: () => infer T } ? T : never;\n\n/**\n * Creates a bounded `useStore` hook from a vanilla Zustand store.\n *\n * This function takes a vanilla Zustand store instance and returns a React hook\n * that is pre-bound to that store. This approach provides a cleaner API and\n * enhances type inference, eliminating the need to pass the store instance\n * on every use.\n *\n * The returned hook supports two signatures:\n * 1. `useBoundedStore()`: Selects the entire state.\n * 2. `useBoundedStore(selector)`: Selects a slice of the state, returning only what the selector function specifies.\n *\n * @template S - The type of the Zustand store (`StoreApi`).\n * @param {S} store - The vanilla Zustand store instance to bind the hook to.\n * @returns {function} A fully typed React hook for accessing the store's state.\n */\nexport const createBoundedUseStore = ((store) => (selector) => useStore(store, selector)) as <\n S extends StoreApi<unknown>,\n>(\n store: S,\n) => {\n // This implementation uses a Immediately Invoked Function Expression (IIFE)\n // trick combined with casting to achieve the desired overloaded function signature in a concise way.\n (): ExtractState<S>;\n <T>(selector: (state: ExtractState<S>) => T): T;\n};\n","/**\n * @file This file provides a generic utility for creating a polling mechanism to track\n * asynchronous tasks, such as API-based transaction status checks (e.g., for Gelato or Safe).\n */\n\nimport { Transaction } from '../types';\n\n/**\n * Defines the parameters for the fetcher function used within the polling tracker.\n * The fetcher is the core logic that performs the actual API call.\n * @template R - The expected type of the successful API response.\n * @template T - The type of the transaction object being tracked.\n */\ntype PollingFetcherParams<R, T> = {\n /** The transaction object being tracked. */\n tx: T;\n /** A callback to stop the polling mechanism, typically called on success or terminal failure. */\n stopPolling: (options?: { withoutRemoving?: boolean }) => void;\n /** Callback to be invoked when the fetcher determines the transaction has succeeded. */\n onSuccess: (response: R) => void;\n /** Callback to be invoked when the fetcher determines the transaction has failed. */\n onFailure: (response?: R) => void;\n /** Optional callback for each successful poll, useful for updating UI with intermediate states. */\n onIntervalTick?: (response: R) => void;\n /** Optional callback for when a transaction is replaced (e.g., speed-up). */\n onReplaced?: (response: R) => void;\n};\n\n/**\n * Defines the configuration object for the `initializePollingTracker` function.\n * @template R - The expected type of the successful API response.\n * @template T - The type of the transaction object.\n * @template TR - The type of the tracker identifier.\n */\nexport type PollingTrackerConfig<R, T, TR> = {\n /** The transaction object to be tracked. It must include `txKey` and `pending` status. */\n tx: T & Pick<Transaction<TR>, 'txKey' | 'pending'>;\n /** The function that performs the data fetching (e.g., an API call) on each interval. */\n fetcher: (params: PollingFetcherParams<R, T>) => Promise<void>;\n /** Callback to be invoked when the transaction successfully completes. */\n onSuccess: (response: R) => void;\n /** Callback to be invoked when the transaction fails. */\n onFailure: (response?: R) => void;\n /** Optional callback executed once when the tracker is initialized. */\n onInitialize?: () => void;\n /** Optional callback for each successful poll. */\n onIntervalTick?: (response: R) => void;\n /** Optional callback for when a transaction is replaced. */\n onReplaced?: (response: R) => void;\n /** Optional function to remove the transaction from the main pool, typically after polling stops. */\n removeTxFromPool?: (txKey: string) => void;\n /** The interval (in milliseconds) between polling attempts. Defaults to 5000ms. */\n pollingInterval?: number;\n /** The number of consecutive failed fetches before stopping the tracker. Defaults to 10. */\n maxRetries?: number;\n};\n\nconst DEFAULT_POLLING_INTERVAL = 5000;\nconst DEFAULT_MAX_RETRIES = 10;\n\n/**\n * Initializes a generic polling tracker that repeatedly calls a fetcher function\n * to monitor the status of an asynchronous task.\n *\n * This function handles the lifecycle of polling, including starting, stopping,\n * and automatic termination after a certain number of failed attempts.\n *\n * @template R The expected type of the API response.\n * @template T The type of the transaction object.\n * @template TR The type of the tracker identifier.\n * @param {PollingTrackerConfig<R, T, TR>} config - The configuration for the tracker.\n */\nexport function initializePollingTracker<R, T, TR>(config: PollingTrackerConfig<R, T, TR>): void {\n const {\n tx,\n fetcher,\n onInitialize,\n onSuccess,\n onFailure,\n onIntervalTick,\n onReplaced,\n removeTxFromPool,\n pollingInterval = DEFAULT_POLLING_INTERVAL,\n maxRetries = DEFAULT_MAX_RETRIES,\n } = config;\n\n // 1. Early exit if the transaction is no longer pending\n if (!tx.pending) {\n return;\n }\n\n // Execute the initialization callback if provided\n onInitialize?.();\n\n let retriesLeft = maxRetries;\n let isPolling = true;\n\n /**\n * Stops the polling interval and optionally removes the transaction from the pool.\n * @param {object} [options] - Options for stopping the tracker.\n * @param {boolean} [options.withoutRemoving=false] - If true, the tx will not be removed from the pool.\n */\n const stopPolling = (options?: { withoutRemoving?: boolean }) => {\n if (!isPolling) return;\n isPolling = false;\n // The interval is cleared in the finally block of the polling loop\n if (removeTxFromPool && !options?.withoutRemoving) {\n removeTxFromPool(tx.txKey);\n }\n };\n\n const pollingLoop = async () => {\n while (isPolling && retriesLeft > 0) {\n try {\n await new Promise((resolve) => setTimeout(resolve, pollingInterval));\n if (!isPolling) break;\n\n // The fetcher's responsibility is to call onSuccess, onFailure, etc., which in turn call stopPolling.\n await fetcher({\n tx,\n stopPolling,\n onSuccess,\n onFailure,\n onIntervalTick,\n onReplaced,\n });\n } catch (error) {\n console.error(`Polling fetcher for txKey ${tx.txKey} threw an error:`, error);\n retriesLeft--;\n }\n }\n\n if (retriesLeft <= 0) {\n console.warn(`Polling for txKey ${tx.txKey} stopped after reaching the maximum number of retries.`);\n onFailure();\n stopPolling();\n }\n };\n\n // Start the asynchronous polling loop\n pollingLoop();\n}\n"]}
1
+ {"version":3,"sources":["../src/store/initializeTxTrackingStore.ts","../src/store/transactionsSelectors.ts","../src/utils/selectAdapterByKey.ts","../src/store/txTrackingStore.ts","../src/types.ts","../src/utils/createBoundedUseStore.ts","../src/utils/initializePollingTracker.ts"],"names":["initializeTxTrackingStore","onSucceedCallbacks","set","get","tx","state","produce","draft","txKey","fields","selectAllTransactions","transactionsPool","a","b","selectPendingTransactions","selectTxByKey","key","selectAllTransactionsByActiveWallet","from","selectPendingTransactionsByActiveWallet","selectAdapterByKey","adapterKey","adapters","adapter","createPulsarStore","options","createStore","persist","pendingTxs","defaultTracker","actionFunction","params","desiredChainID","restParams","localTimestamp","dayjs","handleTxError","e","errorMessage","error","walletType","walletAddress","txKeyFromAction","updatedTracker","finalTxKey","newTx","TransactionAdapter","TransactionStatus","createBoundedUseStore","store","selector","useStore","DEFAULT_POLLING_INTERVAL","DEFAULT_MAX_RETRIES","initializePollingTracker","config","fetcher","onInitialize","onSuccess","onFailure","onIntervalTick","onReplaced","removeTxFromPool","pollingInterval","maxRetries","retriesLeft","isPolling","stopPolling","resolve"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @file This file defines the core Zustand slice for managing the state of transactions. It includes the state,\n * actions, and types necessary for initializing the store and performing CRUD operations on the transaction pool.\n */\n\nimport { Draft, produce } from 'immer';\n\nimport { EvmTransaction, InitialTransaction, SolanaTransaction, StoreSlice, Transaction } from '../types';\n\n/**\n * Defines the structure of the transaction pool, a key-value store of transactions indexed by their unique keys.\n * @template TR The type of the tracker identifier.\n * @template T The transaction type.\n */\nexport type TransactionPool<TR, T extends Transaction<TR>> = Record<string, T>;\n\n/**\n * A utility type that creates a union of all fields that can be safely updated\n * on a transaction object via the `updateTxParams` action. This ensures type safety\n * and prevents accidental modification of immutable properties.\n * @template TR The type of the tracker identifier.\n */\ntype UpdatableTransactionFields<TR> = Partial<\n Pick<\n EvmTransaction<TR>,\n | 'to'\n | 'nonce'\n | 'txKey'\n | 'pending'\n | 'hash'\n | 'status'\n | 'replacedTxHash'\n | 'errorMessage'\n | 'finishedTimestamp'\n | 'isTrackedModalOpen'\n | 'isError'\n | 'maxPriorityFeePerGas'\n | 'maxFeePerGas'\n | 'input'\n | 'value'\n >\n> &\n Partial<\n Pick<SolanaTransaction<TR>, 'slot' | 'confirmations' | 'fee' | 'instructions' | 'recentBlockhash' | 'rpcUrl'>\n >;\n\n/**\n * The interface for the base transaction tracking store slice.\n * It includes the state and actions for managing the transaction lifecycle.\n * @template TR The type of the tracker identifier.\n * @template T The specific transaction type.\n * @template A The return type of the initial action function.\n */\nexport interface IInitializeTxTrackingStore<TR, T extends Transaction<TR>, A> {\n /** A callback function executed when any transaction successfully completes. */\n onSucceedCallbacks?: (tx: T) => Promise<void> | void;\n /** A pool of all transactions currently being tracked, indexed by `txKey`. */\n transactionsPool: TransactionPool<TR, T>;\n /** The `txKey` of the most recently added transaction. */\n lastAddedTxKey?: string;\n /** The state for a transaction being initiated, used for UI feedback before it's submitted to the chain. */\n initialTx?: InitialTransaction<A>;\n\n /** Adds a new transaction to the tracking pool and marks it as pending. */\n addTxToPool: (tx: Transaction<TR>) => void;\n /** Updates one or more properties of an existing transaction in the pool. */\n updateTxParams: (txKey: string, fields: UpdatableTransactionFields<TR>) => void;\n /** Removes a transaction from the tracking pool by its key. */\n removeTxFromPool: (txKey: string) => void;\n /** Closes the tracking modal for a transaction and clears any initial transaction state. */\n closeTxTrackedModal: (txKey?: string) => void;\n /** A selector function to retrieve the key of the last transaction added to the pool. */\n getLastTxKey: () => string | undefined;\n}\n\n/**\n * Creates a Zustand store slice with the core logic for transaction state management.\n * This function is a slice creator intended for use with Zustand's `create` function.\n *\n * @template TR The type of the tracker identifier.\n * @template T The specific transaction type.\n * @template A The return type of the initial action function.\n * @param options Configuration for the store slice.\n * @param options.onSucceedCallbacks An optional async callback to run when a transaction succeeds.\n * @returns A Zustand store slice implementing `IInitializeTxTrackingStore`.\n */\nexport function initializeTxTrackingStore<TR, T extends Transaction<TR>, A>({\n onSucceedCallbacks,\n}: {\n onSucceedCallbacks?: (tx: T) => Promise<void> | void;\n}): StoreSlice<IInitializeTxTrackingStore<TR, T, A>> {\n return (set, get) => ({\n onSucceedCallbacks,\n\n transactionsPool: {},\n lastAddedTxKey: undefined,\n initialTx: undefined,\n\n addTxToPool: (tx) => {\n set((state) =>\n produce(state, (draft) => {\n draft.lastAddedTxKey = tx.txKey;\n if (tx.txKey) {\n draft.transactionsPool[tx.txKey] = {\n ...tx,\n pending: true, // Ensure all new transactions start as pending.\n } as Draft<T>;\n }\n }),\n );\n },\n\n updateTxParams: (txKey, fields) => {\n set((state) =>\n produce(state, (draft) => {\n const tx = draft.transactionsPool[txKey];\n // Ensure the transaction exists before attempting to update.\n if (tx) {\n Object.assign(tx, fields);\n }\n }),\n );\n },\n\n removeTxFromPool: (txKey) => {\n set((state) =>\n produce(state, (draft) => {\n delete draft.transactionsPool[txKey];\n }),\n );\n },\n\n closeTxTrackedModal: (txKey) => {\n set((state) =>\n produce(state, (draft) => {\n if (txKey && draft.transactionsPool[txKey]) {\n draft.transactionsPool[txKey].isTrackedModalOpen = false;\n }\n // Always clear the initial transaction state when a modal is closed\n draft.initialTx = undefined;\n }),\n );\n },\n\n getLastTxKey: () => get().lastAddedTxKey,\n });\n}\n","/**\n * @file This file contains selector functions for deriving state from the transaction tracking store.\n * Selectors help abstract the state's shape and provide efficient, memoized access to computed data.\n */\n\nimport { Transaction } from '../types';\nimport { TransactionPool } from './initializeTxTrackingStore';\n\n/**\n * Selects all transactions from the pool and sorts them by their creation timestamp in ascending order.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of all transactions, sorted chronologically.\n */\nexport const selectAllTransactions = <TR, T extends Transaction<TR>>(transactionsPool: TransactionPool<TR, T>): T[] => {\n return Object.values(transactionsPool).sort((a, b) => Number(a.localTimestamp) - Number(b.localTimestamp));\n};\n\n/**\n * Selects all transactions that are currently in a pending state, sorted chronologically.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of pending transactions.\n */\nexport const selectPendingTransactions = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n): T[] => {\n return selectAllTransactions(transactionsPool).filter((tx) => tx.pending);\n};\n\n/**\n * Selects a single transaction from the pool by its unique key (`txKey`).\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @param {string} key - The `txKey` of the transaction to retrieve.\n * @returns {T | undefined} The transaction object if found, otherwise undefined.\n */\nexport const selectTxByKey = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n key: string,\n): T | undefined => {\n return transactionsPool[key];\n};\n\n/**\n * Selects all transactions initiated by a specific wallet address, sorted chronologically.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @param {string} from - The wallet address (`from` address) to filter transactions by.\n * @returns {T[]} An array of transactions associated with the given wallet.\n */\nexport const selectAllTransactionsByActiveWallet = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n from: string,\n): T[] => {\n // Filters all transactions to find those matching the provided `from` address.\n return selectAllTransactions(transactionsPool).filter((tx) => tx.from.toLowerCase() === from.toLowerCase());\n};\n\n/**\n * Selects all pending transactions for a specific wallet address, sorted chronologically.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @param {string} from - The wallet address (`from` address) to filter transactions by.\n * @returns {T[]} An array of pending transactions for the given wallet.\n */\nexport const selectPendingTransactionsByActiveWallet = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n from: string,\n): T[] => {\n // Reuses the `selectAllTransactionsByActiveWallet` selector for efficiency\n // and then filters for pending transactions.\n return selectAllTransactionsByActiveWallet(transactionsPool, from).filter((tx) => tx.pending);\n};\n","/**\n * @file This file contains a utility function for selecting a specific transaction adapter from a list.\n */\n\nimport { Transaction, TransactionAdapter, TxAdapter } from '../types';\n\n/**\n * Selects a transaction adapter from a list based on a provided key.\n *\n * This function searches through an array of `TxAdapter` instances and returns the one\n * that matches the given `adapterKey`. If no specific adapter is found, it logs a warning\n * and returns the first adapter in the array as a fallback. This fallback mechanism\n * ensures that the system can still function, but it highlights a potential configuration issue.\n *\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type, extending the base `Transaction`.\n * @template A - The type for the adapter-specific context or API.\n *\n * @param {object} params - The parameters for the selection.\n * @param {TransactionAdapter} params.adapterKey - The key of the desired adapter.\n * @param {TxAdapter<TR, T, A>[]} params.adapters - An array of available transaction adapters.\n *\n * @returns {TxAdapter<TR, T, A> | undefined} The found transaction adapter, the fallback adapter, or undefined if the adapters array is empty.\n */\nexport const selectAdapterByKey = <TR, T extends Transaction<TR>, A>({\n adapterKey,\n adapters,\n}: {\n adapterKey: TransactionAdapter;\n adapters: TxAdapter<TR, T, A>[];\n}): TxAdapter<TR, T, A> | undefined => {\n if (!adapters || adapters.length === 0) {\n console.error('Adapter selection failed: The provided adapters array is empty.');\n return undefined;\n }\n\n const adapter = adapters.find((a) => a.key === adapterKey);\n\n if (adapter) {\n return adapter;\n } else {\n console.warn(\n `No adapter found for key: \"${adapterKey}\". Falling back to the first available adapter: \"${adapters[0].key}\".`,\n );\n return adapters[0];\n }\n};\n","/**\n * @file This file is the nucleus of the Pulsar store, orchestrating transaction handling, state management,\n * and communication with blockchain adapters. It utilizes Zustand for state management, Immer for safe,\n * immutable updates, and a persistence middleware to maintain state across user sessions.\n */\n\nimport dayjs from 'dayjs';\nimport { produce } from 'immer';\nimport { persist, PersistOptions } from 'zustand/middleware';\nimport { createStore } from 'zustand/vanilla';\n\nimport { ITxTrackingStore, Transaction, TxAdapter } from '../types';\nimport { selectAdapterByKey } from '../utils/selectAdapterByKey';\nimport { initializeTxTrackingStore } from './initializeTxTrackingStore';\n\n/**\n * Creates the main Pulsar store for transaction tracking.\n *\n * This function configures a Zustand store enhanced with persistence. It combines the core transaction management\n * slice with a powerful orchestration logic that leverages chain-specific adapters to handle the entire\n * lifecycle of a transaction—from initiation and chain validation to execution and background status tracking.\n *\n * @template TR The type of the tracker identifier (e.g., a string enum).\n * @template T The specific transaction type, extending the base `Transaction`.\n * @template A The type of the key returned by the `actionFunction` (e.g., a transaction hash).\n *\n * @param config Configuration object for creating the store.\n * @param config.onSucceedCallbacks Optional async callback executed on transaction success.\n * @param config.adapters An array of adapters for different chains or transaction types.\n * @param options Configuration for the Zustand `persist` middleware.\n * @returns A fully configured Zustand store instance.\n */\nexport function createPulsarStore<TR, T extends Transaction<TR>, A>({\n onSucceedCallbacks,\n adapters,\n ...options\n}: {\n onSucceedCallbacks?: (tx: T) => Promise<void> | void;\n adapters: TxAdapter<TR, T, A>[];\n} & PersistOptions<ITxTrackingStore<TR, T, A>>) {\n return createStore<ITxTrackingStore<TR, T, A>>()(\n persist(\n (set, get) => ({\n // Initialize the base store slice with core state and actions\n ...initializeTxTrackingStore<TR, T, A>({ onSucceedCallbacks })(set, get),\n\n /**\n * Initializes trackers for all pending transactions upon store creation.\n * This is crucial for resuming tracking after a page refresh or session restoration.\n */\n initializeTransactionsPool: async () => {\n const pendingTxs = Object.values(get().transactionsPool).filter((tx) => tx.pending);\n\n // Concurrently initialize trackers for all pending transactions\n await Promise.all(\n pendingTxs.map((tx) => {\n const adapter = selectAdapterByKey({\n adapterKey: tx.adapter,\n adapters,\n });\n // Delegate tracker initialization to the appropriate adapter\n return adapter?.checkAndInitializeTrackerInStore({\n tx,\n ...get(),\n });\n }),\n );\n },\n\n /**\n * The primary function to orchestrate sending and tracking a new transaction.\n * It manages the entire lifecycle, from UI state updates and chain switching to\n * signing, submission, and background tracker initialization.\n */\n handleTransaction: async ({ defaultTracker, actionFunction, params }) => {\n const { desiredChainID, ...restParams } = params;\n const localTimestamp = dayjs().unix();\n\n // Step 1: Set initial state for immediate UI feedback (e.g., loading spinner).\n set({\n initialTx: {\n ...params,\n actionFunction,\n localTimestamp,\n isInitializing: true,\n },\n });\n\n const adapter = selectAdapterByKey({\n adapterKey: restParams.adapter,\n adapters,\n });\n\n // Centralized error handler for this transaction flow\n const handleTxError = (e: unknown) => {\n const errorMessage = e instanceof Error ? e.message : String(e);\n set((state) =>\n produce(state, (draft) => {\n if (draft.initialTx) {\n draft.initialTx.isInitializing = false;\n draft.initialTx.errorMessage = errorMessage;\n }\n }),\n );\n };\n\n if (!adapter) {\n const error = new Error('No adapter found for this transaction.');\n handleTxError(error);\n throw error; // Re-throw to allow the caller to handle it.\n }\n\n try {\n const { walletType, walletAddress } = adapter.getWalletInfo();\n\n // Step 2: Ensure the wallet is connected to the correct chain.\n await adapter.checkChainForTx(desiredChainID);\n\n // Step 3: Execute the provided action (e.g., signing and sending the transaction).\n const txKeyFromAction = await actionFunction();\n\n // If `txKeyFromAction` is undefined, it indicates the user cancelled the action.\n if (!txKeyFromAction) {\n set({ initialTx: undefined });\n return;\n }\n\n // Step 4: Determine the final tracker and txKey from the action's result.\n const { tracker: updatedTracker, txKey: finalTxKey } = adapter.checkTransactionsTracker(\n txKeyFromAction,\n walletType,\n );\n\n // Step 5: Construct the full transaction object for the pool.\n const newTx = {\n ...restParams,\n walletType,\n from: walletAddress,\n tracker: (updatedTracker || defaultTracker) as TR,\n chainId: desiredChainID,\n localTimestamp,\n txKey: finalTxKey,\n // For EVM, the hash is often the preliminary key from the action.\n hash: updatedTracker === 'ethereum' ? (txKeyFromAction as `0x${string}`) : undefined,\n pending: false, // will be set to true by addTxToPool\n isTrackedModalOpen: params.withTrackedModal,\n };\n\n // Step 6: Add the transaction to the pool.\n get().addTxToPool(newTx);\n\n // Step 7: Update the initial state to link it with the newly created transaction.\n set((state) =>\n produce(state, (draft) => {\n if (draft.initialTx) {\n draft.initialTx.isInitializing = false;\n draft.initialTx.lastTxKey = finalTxKey;\n }\n }),\n );\n\n // Step 8: Initialize the background tracker for the transaction.\n const tx = get().transactionsPool[finalTxKey];\n await adapter.checkAndInitializeTrackerInStore({ tx, ...get() });\n } catch (e) {\n handleTxError(e);\n throw e; // Re-throw for external handling if needed.\n }\n },\n }),\n {\n ...options, // Merges user-provided persistence options.\n },\n ),\n );\n}\n","/**\n * @file This file defines the core data structures and TypeScript types for the Pulsar transaction tracking engine.\n * It specifies the framework-agnostic models for transactions, their lifecycle statuses, and the interfaces for\n * the Zustand-based store and chain-specific adapters.\n */\n\nimport { StoreApi } from 'zustand';\n\nimport { IInitializeTxTrackingStore, TransactionPool } from './store/initializeTxTrackingStore';\n\n// =================================================================================================\n// 1. ZUSTAND UTILITY TYPES\n// =================================================================================================\n\n/**\n * A utility type for creating modular Zustand store slices, enabling composable state management.\n * @template T The state slice being defined.\n * @template S The full store state that includes the slice `T`.\n */\nexport type StoreSlice<T extends object, S extends object = T> = (\n set: StoreApi<S extends T ? S : S & T>['setState'],\n get: StoreApi<S extends T ? S : S & T>['getState'],\n) => T;\n\n// =================================================================================================\n// 2. ENUMS AND CORE TRANSACTION TYPES\n// =================================================================================================\n\n/**\n * Defines the supported blockchain adapters. Each adapter corresponds to a specific chain architecture.\n */\nexport enum TransactionAdapter {\n /** For Ethereum Virtual Machine (EVM) compatible chains like Ethereum, Polygon, etc. */\n EVM = 'evm',\n /** For the Solana blockchain. */\n SOLANA = 'solana',\n /** For the Starknet L2 network. */\n Starknet = 'starknet',\n}\n\n/**\n * Represents the terminal status of a transaction after it has been processed.\n */\nexport enum TransactionStatus {\n /** The transaction failed to execute due to an on-chain error or rejection. */\n Failed = 'Failed',\n /** The transaction was successfully mined and included in a block. */\n Success = 'Success',\n /** The transaction was replaced by another with the same nonce (e.g., a speed-up or cancel). */\n Replaced = 'Replaced',\n}\n\n/**\n * The fundamental structure for any transaction being tracked by Pulsar.\n * This serves as the base upon which chain-specific transaction types are built.\n * @template T The type of the tracker identifier (e.g., 'ethereum', 'gelato').\n */\nexport type BaseTransaction<T> = {\n /** The chain identifier (e.g., 1 for Ethereum Mainnet, 'SN_MAIN' for Starknet). */\n chainId: number | string;\n /**\n * User-facing description. Can be a single string for all states, or a tuple for specific states.\n * @example\n * // A single description for all states\n * description: 'Swap 1 ETH for 1,500 USDC'\n * // Specific descriptions for each state in order: [pending, success, error, replaced]\n * description: ['Swapping...', 'Swapped Successfully', 'Swap Failed', 'Swap Replaced']\n */\n description?: string | [string, string, string, string];\n /** The error message if the transaction failed. */\n errorMessage?: string;\n /** The on-chain timestamp (in seconds) when the transaction was finalized. */\n finishedTimestamp?: number;\n /** The sender's wallet address. */\n from: string;\n /** A flag indicating if the transaction is in a failed state. */\n isError?: boolean;\n /** A UI flag to control the visibility of a detailed tracking modal for this transaction. */\n isTrackedModalOpen?: boolean;\n /** The local timestamp (in seconds) when the transaction was initiated by the user. */\n localTimestamp: number;\n /** Any additional, custom data associated with the transaction. */\n payload?: object;\n /** A flag indicating if the transaction is still awaiting on-chain confirmation. */\n pending: boolean;\n /** The final on-chain status of the transaction. */\n status?: TransactionStatus;\n /**\n * User-facing title. Can be a single string for all states, or a tuple for specific states.\n * @example\n * // A single title for all states\n * title: 'ETH/USDC Swap'\n * // Specific titles for each state in order: [pending, success, error, replaced]\n * title: ['Processing Swap', 'Swap Complete', 'Swap Error', 'Swap Replaced']\n */\n title?: string | [string, string, string, string];\n /** The specific tracker responsible for monitoring this transaction's status. */\n tracker: T;\n /** The unique identifier for the transaction (e.g., EVM hash, Gelato task ID). */\n txKey: string;\n /** The application-specific type or category of the transaction (e.g., 'SWAP', 'APPROVE'). */\n type: string;\n /** The type of wallet used to sign the transaction (e.g., 'injected', 'walletConnect'). */\n walletType: string;\n};\n\n// =================================================================================================\n// 3. CHAIN-SPECIFIC TRANSACTION TYPES\n// =================================================================================================\n\n/**\n * Represents an EVM-specific transaction, extending the base properties with EVM fields.\n * @template T The type of the tracker identifier.\n */\nexport type EvmTransaction<T> = BaseTransaction<T> & {\n adapter: TransactionAdapter.EVM;\n /** The on-chain transaction hash, available after submission. */\n hash?: `0x${string}`;\n /** The data payload for the transaction, typically for smart contract interactions. */\n input?: `0x${string}`;\n /** The maximum fee per gas for an EIP-1559 transaction (in wei). */\n maxFeePerGas?: string;\n /** The maximum priority fee per gas for an EIP-1559 transaction (in wei). */\n maxPriorityFeePerGas?: string;\n /** The transaction nonce, a sequential number for the sender's account. */\n nonce?: number;\n /** The hash of a transaction that this one replaced. */\n replacedTxHash?: `0x${string}`;\n /** The recipient's address or contract address. */\n to?: `0x${string}`;\n /** The amount of native currency (in wei) being sent. */\n value?: string;\n};\n\n/**\n * Represents a Solana-specific transaction, extending the base properties.\n * @template T The type of the tracker identifier.\n */\nexport type SolanaTransaction<T> = BaseTransaction<T> & {\n adapter: TransactionAdapter.SOLANA;\n /** The transaction fee in lamports. */\n fee?: number;\n /** The instructions included in the transaction. */\n instructions?: unknown[];\n /** The recent blockhash used for the transaction. */\n recentBlockhash?: string;\n /** The slot in which the transaction was processed. */\n slot?: number;\n /** The number of confirmations received. `null` if the transaction is pending or unconfirmed. */\n confirmations?: number | null;\n /** The RPC URL used to submit and track this transaction. */\n rpcUrl?: string;\n};\n\n/**\n * Represents a Starknet-specific transaction, extending the base properties.\n * @template T The type of the tracker identifier.\n */\nexport type StarknetTransaction<T> = BaseTransaction<T> & {\n adapter: TransactionAdapter.Starknet;\n /** The actual fee paid for the transaction. */\n actualFee?: { amount: string; unit: string };\n /** The address of the contract being interacted with. */\n contractAddress?: string;\n /** The reason for transaction failure, if applicable. */\n revertReason?: string;\n};\n\n/** A union type representing any possible transaction structure that Pulsar can handle. */\nexport type Transaction<T> = EvmTransaction<T> | SolanaTransaction<T> | StarknetTransaction<T>;\n\n// =================================================================================================\n// 4. INITIAL TRANSACTION TYPES\n// =================================================================================================\n\n/**\n * Represents the parameters required to initiate a new transaction tracking flow.\n */\nexport type InitialTransactionParams<A> = {\n adapter: TransactionAdapter;\n /** The function that executes the on-chain action (e.g., sending a transaction) and returns a preliminary identifier like a hash. */\n actionFunction: (...args: any[]) => Promise<A | undefined>;\n /** A user-facing description for the transaction. Supports state-specific descriptions. */\n description?: string | [string, string, string, string];\n /** The target chain ID for the transaction. */\n desiredChainID: number | string;\n /** Any custom data to associate with the transaction. */\n payload?: object;\n /** A user-facing title for the transaction. Supports state-specific titles. */\n title?: string | [string, string, string, string];\n /** The application-specific type of the transaction. */\n type: string;\n /** If true, the detailed tracking modal will open automatically upon initiation. */\n withTrackedModal?: boolean;\n /** The RPC URL to use for the transaction. Required for Solana transactions. */\n rpcUrl?: string;\n};\n\n/**\n * Represents a transaction in its temporary, pre-submission state.\n * This is used for UI feedback while the transaction is being signed and sent.\n */\nexport type InitialTransaction<A> = InitialTransactionParams<A> & {\n /** An error message if the initialization fails (e.g., user rejects signature). */\n errorMessage?: string;\n /** A flag indicating if the transaction is being processed (e.g., waiting for signature). */\n isInitializing: boolean;\n /** The `txKey` of the on-chain transaction that this action produced, used for linking the states. */\n lastTxKey?: string;\n /** The local timestamp when the user initiated the action. */\n localTimestamp: number;\n};\n\n// =================================================================================================\n// 5. ADAPTER AND STORE INTERFACES\n// =================================================================================================\n\n/**\n * Defines the interface for a transaction adapter, which provides chain-specific logic and utilities.\n * @template TR The type of the tracker identifier (e.g., a string enum).\n * @template T The specific transaction type, extending `Transaction<TR>`.\n * @template A The type of the key returned by the `actionFunction` (e.g., a transaction hash).\n */\nexport type TxAdapter<TR, T extends Transaction<TR>, A> = {\n /** The unique key identifying this adapter. */\n key: TransactionAdapter;\n /** Returns information about the currently connected wallet. */\n getWalletInfo: () => {\n walletAddress: string;\n walletType: string;\n };\n /** Ensures the connected wallet is on the correct network for the transaction. Throws an error if the chain is mismatched. */\n checkChainForTx: (chainId: string | number) => Promise<void>;\n /** Determines the appropriate tracker and final `txKey` from the result of an action. */\n checkTransactionsTracker: (actionTxKey: A, walletType: string) => { txKey: string; tracker: TR };\n /** Selects and initializes the correct background tracker for a given transaction. */\n checkAndInitializeTrackerInStore: (\n params: { tx: T } & Pick<\n ITxTrackingStore<TR, T, A>,\n 'transactionsPool' | 'updateTxParams' | 'onSucceedCallbacks' | 'removeTxFromPool'\n >,\n ) => Promise<void>;\n /** Returns the base URL for the blockchain explorer for the current network. */\n getExplorerUrl: () => string | undefined;\n /** Optional: Fetches a name from a chain-specific name service (e.g., ENS). */\n getName?: (address: string) => Promise<string | null>;\n /** Optional: Fetches an avatar URL from a chain-specific name service. */\n getAvatar?: (name: string) => Promise<string | null>;\n /** Optional: Logic to cancel a pending EVM transaction. */\n cancelTxAction?: (tx: T) => Promise<string>;\n /** Optional: Logic to speed up a pending EVM transaction. */\n speedUpTxAction?: (tx: T) => Promise<string>;\n /** Optional: Logic to retry a failed transaction. */\n retryTxAction?: (\n params: {\n txKey: string;\n tx: InitialTransactionParams<A>;\n onClose: (txKey?: string) => void;\n } & Partial<Pick<ITxTrackingStore<TR, T, A>, 'handleTransaction'>>,\n ) => Promise<void>;\n /**\n * Optional: Constructs a full explorer URL for a specific transaction.\n * May require the full transaction pool to resolve details for replaced transactions.\n */\n getExplorerTxUrl?: (transactionsPool: TransactionPool<TR, T>, txKey: string, replacedTxHash?: string) => string;\n};\n\n/**\n * The complete interface for the Pulsar transaction tracking store.\n * @template TR The type of the tracker identifier.\n * @template T The transaction type.\n * @template A The return type of the `actionFunction`.\n */\nexport type ITxTrackingStore<TR, T extends Transaction<TR>, A> = IInitializeTxTrackingStore<TR, T, A> & {\n /**\n * The primary method for initiating and tracking a new transaction from start to finish.\n * It manages UI state, executes the on-chain action, and initiates background tracking.\n * @param params The parameters for handling the transaction.\n */\n handleTransaction: (params: {\n /** The async function to execute (e.g., a smart contract write call). Must return a unique key or undefined. */\n actionFunction: () => Promise<A | undefined>;\n /** The metadata for the transaction. */\n params: Omit<InitialTransactionParams<A>, 'actionFunction'>;\n /** The default tracker to use if it cannot be determined automatically. */\n defaultTracker?: TR;\n }) => Promise<void>;\n\n /**\n * Initializes trackers for all pending transactions in the pool.\n * This is essential for resuming tracking after a page reload.\n */\n initializeTransactionsPool: () => Promise<void>;\n};\n","/**\n * @file This file provides a utility for creating a type-safe, bounded Zustand hook from a vanilla store.\n * This pattern is recommended by the official Zustand documentation to ensure full type\n * safety when integrating vanilla stores with React.\n *\n * @see https://docs.pmnd.rs/zustand/guides/typescript#bounded-usestore-hook-for-vanilla-stores\n */\n\nimport { StoreApi, useStore } from 'zustand';\n\n/**\n * A utility type that infers the state shape from a Zustand `StoreApi`.\n * It extracts the return type of the `getState` method.\n * @template S - The type of the Zustand store (`StoreApi`).\n */\ntype ExtractState<S> = S extends { getState: () => infer T } ? T : never;\n\n/**\n * Creates a bounded `useStore` hook from a vanilla Zustand store.\n *\n * This function takes a vanilla Zustand store instance and returns a React hook\n * that is pre-bound to that store. This approach provides a cleaner API and\n * enhances type inference, eliminating the need to pass the store instance\n * on every use.\n *\n * The returned hook supports two signatures:\n * 1. `useBoundedStore()`: Selects the entire state.\n * 2. `useBoundedStore(selector)`: Selects a slice of the state, returning only what the selector function specifies.\n *\n * @template S - The type of the Zustand store (`StoreApi`).\n * @param {S} store - The vanilla Zustand store instance to bind the hook to.\n * @returns {function} A fully typed React hook for accessing the store's state.\n */\nexport const createBoundedUseStore = ((store) => (selector) => useStore(store, selector)) as <\n S extends StoreApi<unknown>,\n>(\n store: S,\n) => {\n // This implementation uses a Immediately Invoked Function Expression (IIFE)\n // trick combined with casting to achieve the desired overloaded function signature in a concise way.\n (): ExtractState<S>;\n <T>(selector: (state: ExtractState<S>) => T): T;\n};\n","/**\n * @file This file provides a generic utility for creating a polling mechanism to track\n * asynchronous tasks, such as API-based transaction status checks (e.g., for Gelato or Safe).\n */\n\nimport { Transaction } from '../types';\n\n/**\n * Defines the parameters for the fetcher function used within the polling tracker.\n * The fetcher is the core logic that performs the actual API call.\n * @template R - The expected type of the successful API response.\n * @template T - The type of the transaction object being tracked.\n */\ntype PollingFetcherParams<R, T> = {\n /** The transaction object being tracked. */\n tx: T;\n /** A callback to stop the polling mechanism, typically called on success or terminal failure. */\n stopPolling: (options?: { withoutRemoving?: boolean }) => void;\n /** Callback to be invoked when the fetcher determines the transaction has succeeded. */\n onSuccess: (response: R) => void;\n /** Callback to be invoked when the fetcher determines the transaction has failed. */\n onFailure: (response?: R) => void;\n /** Optional callback for each successful poll, useful for updating UI with intermediate states. */\n onIntervalTick?: (response: R) => void;\n /** Optional callback for when a transaction is replaced (e.g., speed-up). */\n onReplaced?: (response: R) => void;\n};\n\n/**\n * Defines the configuration object for the `initializePollingTracker` function.\n * @template R - The expected type of the successful API response.\n * @template T - The type of the transaction object.\n * @template TR - The type of the tracker identifier.\n */\nexport type PollingTrackerConfig<R, T, TR> = {\n /** The transaction object to be tracked. It must include `txKey` and `pending` status. */\n tx: T & Pick<Transaction<TR>, 'txKey' | 'pending'>;\n /** The function that performs the data fetching (e.g., an API call) on each interval. */\n fetcher: (params: PollingFetcherParams<R, T>) => Promise<void>;\n /** Callback to be invoked when the transaction successfully completes. */\n onSuccess: (response: R) => void;\n /** Callback to be invoked when the transaction fails. */\n onFailure: (response?: R) => void;\n /** Optional callback executed once when the tracker is initialized. */\n onInitialize?: () => void;\n /** Optional callback for each successful poll. */\n onIntervalTick?: (response: R) => void;\n /** Optional callback for when a transaction is replaced. */\n onReplaced?: (response: R) => void;\n /** Optional function to remove the transaction from the main pool, typically after polling stops. */\n removeTxFromPool?: (txKey: string) => void;\n /** The interval (in milliseconds) between polling attempts. Defaults to 5000ms. */\n pollingInterval?: number;\n /** The number of consecutive failed fetches before stopping the tracker. Defaults to 10. */\n maxRetries?: number;\n};\n\nconst DEFAULT_POLLING_INTERVAL = 5000;\nconst DEFAULT_MAX_RETRIES = 10;\n\n/**\n * Initializes a generic polling tracker that repeatedly calls a fetcher function\n * to monitor the status of an asynchronous task.\n *\n * This function handles the lifecycle of polling, including starting, stopping,\n * and automatic termination after a certain number of failed attempts.\n *\n * @template R The expected type of the API response.\n * @template T The type of the transaction object.\n * @template TR The type of the tracker identifier.\n * @param {PollingTrackerConfig<R, T, TR>} config - The configuration for the tracker.\n */\nexport function initializePollingTracker<R, T, TR>(config: PollingTrackerConfig<R, T, TR>): void {\n const {\n tx,\n fetcher,\n onInitialize,\n onSuccess,\n onFailure,\n onIntervalTick,\n onReplaced,\n removeTxFromPool,\n pollingInterval = DEFAULT_POLLING_INTERVAL,\n maxRetries = DEFAULT_MAX_RETRIES,\n } = config;\n\n // 1. Early exit if the transaction is no longer pending\n if (!tx.pending) {\n return;\n }\n\n // Execute the initialization callback if provided\n onInitialize?.();\n\n let retriesLeft = maxRetries;\n let isPolling = true;\n\n /**\n * Stops the polling interval and optionally removes the transaction from the pool.\n * @param {object} [options] - Options for stopping the tracker.\n * @param {boolean} [options.withoutRemoving=false] - If true, the tx will not be removed from the pool.\n */\n const stopPolling = (options?: { withoutRemoving?: boolean }) => {\n if (!isPolling) return;\n isPolling = false;\n // The interval is cleared in the finally block of the polling loop\n if (removeTxFromPool && !options?.withoutRemoving) {\n removeTxFromPool(tx.txKey);\n }\n };\n\n const pollingLoop = async () => {\n while (isPolling && retriesLeft > 0) {\n try {\n await new Promise((resolve) => setTimeout(resolve, pollingInterval));\n if (!isPolling) break;\n\n // The fetcher's responsibility is to call onSuccess, onFailure, etc., which in turn call stopPolling.\n await fetcher({\n tx,\n stopPolling,\n onSuccess,\n onFailure,\n onIntervalTick,\n onReplaced,\n });\n } catch (error) {\n console.error(`Polling fetcher for txKey ${tx.txKey} threw an error:`, error);\n retriesLeft--;\n }\n }\n\n if (retriesLeft <= 0) {\n console.warn(`Polling for txKey ${tx.txKey} stopped after reaching the maximum number of retries.`);\n onFailure();\n stopPolling();\n }\n };\n\n // Start the asynchronous polling loop\n pollingLoop();\n}\n"]}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import {produce}from'immer';import w from'dayjs';import {persist}from'zustand/middleware';import {createStore}from'zustand/vanilla';import {useStore}from'zustand';function S({onSucceedCallbacks:n}){return (e,o)=>({onSucceedCallbacks:n,transactionsPool:{},lastAddedTxKey:void 0,initialTx:void 0,addTxToPool:t=>{e(i=>produce(i,r=>{r.lastAddedTxKey=t.txKey,t.txKey&&(r.transactionsPool[t.txKey]={...t,pending:true});}));},updateTxParams:(t,i)=>{e(r=>produce(r,T=>{let c=T.transactionsPool[t];c&&Object.assign(c,i);}));},removeTxFromPool:t=>{e(i=>produce(i,r=>{delete r.transactionsPool[t];}));},closeTxTrackedModal:t=>{e(i=>produce(i,r=>{t&&r.transactionsPool[t]&&(r.transactionsPool[t].isTrackedModalOpen=false),r.initialTx=void 0;}));},getLastTxKey:()=>o().lastAddedTxKey})}var A=n=>Object.values(n).sort((e,o)=>Number(e.localTimestamp)-Number(o.localTimestamp)),D=n=>A(n).filter(e=>e.pending),U=(n,e)=>n[e],b=(n,e)=>A(n).filter(o=>o.from.toLowerCase()===e.toLowerCase()),$=(n,e)=>b(n,e).filter(o=>o.pending);var R=({adapterKey:n,adapters:e})=>{if(!e||e.length===0){console.error("Adapter selection failed: The provided adapters array is empty.");return}let o=e.find(t=>t.key===n);return o||(console.warn(`No adapter found for key: "${n}". Falling back to the first available adapter: "${e[0].key}".`),e[0])};function Z({onSucceedCallbacks:n,adapters:e,...o}){return createStore()(persist((t,i)=>({...S({onSucceedCallbacks:n})(t,i),initializeTransactionsPool:async()=>{let r=Object.values(i().transactionsPool).filter(T=>T.pending);await Promise.all(r.map(T=>R({adapterKey:T.adapter,adapters:e})?.checkAndInitializeTrackerInStore({tx:T,...i()})));},handleTransaction:async({defaultTracker:r,actionFunction:T,params:c})=>{let{desiredChainID:x,...m}=c,g=w().unix();t({initialTx:{...c,localTimestamp:g,isInitializing:true}});let l=R({adapterKey:m.adapter,adapters:e});if(!l){let a=new Error("No adapter found for this transaction.");throw d(a),a}try{let{walletType:a,walletAddress:u}=l.getWalletInfo();await l.checkChainForTx(x);let s=await T();if(!s){t({initialTx:void 0});return}let p={...m,walletType:a,from:u,tracker:r,chainId:x,localTimestamp:g,txKey:"",pending:!1,isTrackedModalOpen:c.withTrackedModal},{tracker:k,txKey:P}=l.checkTransactionsTracker(s,p.walletType),h={...p,tracker:k,txKey:P,hash:k==="ethereum"?s:void 0};i().addTxToPool(h),t(K=>produce(K,y=>{y.initialTx&&(y.initialTx.isInitializing=!1,y.initialTx.lastTxKey=P);}));let I=i().transactionsPool[P];await l.checkAndInitializeTrackerInStore({tx:I,...i()});}catch(a){throw d(a),a}function d(a){let u=a instanceof Error?a.message:String(a);t(s=>produce(s,p=>{p.initialTx&&(p.initialTx.isInitializing=false,p.initialTx.errorMessage=u);}));}}}),{...o}))}var z=(t=>(t.EVM="evm",t.SOLANA="solana",t.Starknet="starknet",t))(z||{}),M=(t=>(t.Failed="Failed",t.Success="Success",t.Replaced="Replaced",t))(M||{});var ie=(n=>e=>useStore(n,e));var C=5e3,O=10;function ae(n){let{tx:e,fetcher:o,onInitialize:t,onSuccess:i,onFailure:r,onIntervalTick:T,onReplaced:c,removeTxFromPool:x,pollingInterval:m=C,maxRetries:g=O}=n;if(!e.pending)return;t?.();let l=g,d=true,a=s=>{d&&(d=false,x&&!s?.withoutRemoving&&x(e.txKey));};(async()=>{for(;d&&l>0;)try{if(await new Promise(s=>setTimeout(s,m)),!d)break;await o({tx:e,stopPolling:a,onSuccess:i,onFailure:r,onIntervalTick:T,onReplaced:c});}catch(s){console.error(`Polling fetcher for txKey ${e.txKey} threw an error:`,s),l--;}l<=0&&(console.warn(`Polling for txKey ${e.txKey} stopped after reaching the maximum number of retries.`),r(),a());})();}export{z as TransactionAdapter,M as TransactionStatus,ie as createBoundedUseStore,Z as createPulsarStore,ae as initializePollingTracker,S as initializeTxTrackingStore,R as selectAdapterByKey,A as selectAllTransactions,b as selectAllTransactionsByActiveWallet,D as selectPendingTransactions,$ as selectPendingTransactionsByActiveWallet,U as selectTxByKey};//# sourceMappingURL=index.mjs.map
1
+ import {produce}from'immer';import K from'dayjs';import {persist}from'zustand/middleware';import {createStore}from'zustand/vanilla';import {useStore}from'zustand';function A({onSucceedCallbacks:n}){return (e,a)=>({onSucceedCallbacks:n,transactionsPool:{},lastAddedTxKey:void 0,initialTx:void 0,addTxToPool:t=>{e(i=>produce(i,r=>{r.lastAddedTxKey=t.txKey,t.txKey&&(r.transactionsPool[t.txKey]={...t,pending:true});}));},updateTxParams:(t,i)=>{e(r=>produce(r,s=>{let c=s.transactionsPool[t];c&&Object.assign(c,i);}));},removeTxFromPool:t=>{e(i=>produce(i,r=>{delete r.transactionsPool[t];}));},closeTxTrackedModal:t=>{e(i=>produce(i,r=>{t&&r.transactionsPool[t]&&(r.transactionsPool[t].isTrackedModalOpen=false),r.initialTx=void 0;}));},getLastTxKey:()=>a().lastAddedTxKey})}var k=n=>Object.values(n).sort((e,a)=>Number(e.localTimestamp)-Number(a.localTimestamp)),N=n=>k(n).filter(e=>e.pending),$=(n,e)=>n[e],b=(n,e)=>k(n).filter(a=>a.from.toLowerCase()===e.toLowerCase()),j=(n,e)=>b(n,e).filter(a=>a.pending);var y=({adapterKey:n,adapters:e})=>{if(!e||e.length===0){console.error("Adapter selection failed: The provided adapters array is empty.");return}let a=e.find(t=>t.key===n);return a||(console.warn(`No adapter found for key: "${n}". Falling back to the first available adapter: "${e[0].key}".`),e[0])};function Q({onSucceedCallbacks:n,adapters:e,...a}){return createStore()(persist((t,i)=>({...A({onSucceedCallbacks:n})(t,i),initializeTransactionsPool:async()=>{let r=Object.values(i().transactionsPool).filter(s=>s.pending);await Promise.all(r.map(s=>y({adapterKey:s.adapter,adapters:e})?.checkAndInitializeTrackerInStore({tx:s,...i()})));},handleTransaction:async({defaultTracker:r,actionFunction:s,params:c})=>{let{desiredChainID:x,...m}=c,g=K().unix();t({initialTx:{...c,actionFunction:s,localTimestamp:g,isInitializing:true}});let l=y({adapterKey:m.adapter,adapters:e}),d=o=>{let u=o instanceof Error?o.message:String(o);t(T=>produce(T,p=>{p.initialTx&&(p.initialTx.isInitializing=false,p.initialTx.errorMessage=u);}));};if(!l){let o=new Error("No adapter found for this transaction.");throw d(o),o}try{let{walletType:o,walletAddress:u}=l.getWalletInfo();await l.checkChainForTx(x);let T=await s();if(!T){t({initialTx:void 0});return}let{tracker:p,txKey:P}=l.checkTransactionsTracker(T,o),v={...m,walletType:o,from:u,tracker:p||r,chainId:x,localTimestamp:g,txKey:P,hash:p==="ethereum"?T:void 0,pending:!1,isTrackedModalOpen:c.withTrackedModal};i().addTxToPool(v),t(I=>produce(I,R=>{R.initialTx&&(R.initialTx.isInitializing=!1,R.initialTx.lastTxKey=P);}));let h=i().transactionsPool[P];await l.checkAndInitializeTrackerInStore({tx:h,...i()});}catch(o){throw d(o),o}}}),{...a}))}var E=(t=>(t.EVM="evm",t.SOLANA="solana",t.Starknet="starknet",t))(E||{}),z=(t=>(t.Failed="Failed",t.Success="Success",t.Replaced="Replaced",t))(z||{});var ne=(n=>e=>useStore(n,e));var L=5e3,C=10;function ie(n){let{tx:e,fetcher:a,onInitialize:t,onSuccess:i,onFailure:r,onIntervalTick:s,onReplaced:c,removeTxFromPool:x,pollingInterval:m=L,maxRetries:g=C}=n;if(!e.pending)return;t?.();let l=g,d=true,o=T=>{d&&(d=false,x&&!T?.withoutRemoving&&x(e.txKey));};(async()=>{for(;d&&l>0;)try{if(await new Promise(T=>setTimeout(T,m)),!d)break;await a({tx:e,stopPolling:o,onSuccess:i,onFailure:r,onIntervalTick:s,onReplaced:c});}catch(T){console.error(`Polling fetcher for txKey ${e.txKey} threw an error:`,T),l--;}l<=0&&(console.warn(`Polling for txKey ${e.txKey} stopped after reaching the maximum number of retries.`),r(),o());})();}export{E as TransactionAdapter,z as TransactionStatus,ne as createBoundedUseStore,Q as createPulsarStore,ie as initializePollingTracker,A as initializeTxTrackingStore,y as selectAdapterByKey,k as selectAllTransactions,b as selectAllTransactionsByActiveWallet,N as selectPendingTransactions,j as selectPendingTransactionsByActiveWallet,$ as selectTxByKey};//# sourceMappingURL=index.mjs.map
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/store/initializeTxTrackingStore.ts","../src/store/transactionsSelectors.ts","../src/utils/selectAdapterByKey.ts","../src/store/txTrackingStore.ts","../src/types.ts","../src/utils/createBoundedUseStore.ts","../src/utils/initializePollingTracker.ts"],"names":["initializeTxTrackingStore","onSucceedCallbacks","set","get","tx","state","produce","draft","txKey","fields","selectAllTransactions","transactionsPool","a","b","selectPendingTransactions","selectTxByKey","key","selectAllTransactionsByActiveWallet","from","selectPendingTransactionsByActiveWallet","selectAdapterByKey","adapterKey","adapters","adapter","createPulsarStore","options","createStore","persist","pendingTxs","defaultTracker","actionFunction","params","desiredChainID","restParams","localTimestamp","dayjs","error","handleTxError","walletType","walletAddress","txKeyFromAction","txInitialParams","updatedTracker","finalTxKey","newTx","e","errorMessage","TransactionAdapter","TransactionStatus","createBoundedUseStore","store","selector","useStore","DEFAULT_POLLING_INTERVAL","DEFAULT_MAX_RETRIES","initializePollingTracker","config","fetcher","onInitialize","onSuccess","onFailure","onIntervalTick","onReplaced","removeTxFromPool","pollingInterval","maxRetries","retriesLeft","isPolling","stopPolling","resolve"],"mappings":"mKA6EO,SAASA,CAAAA,CAAyD,CACvE,mBAAAC,CACF,CAAA,CAEkD,CAChD,OAAO,CAACC,EAAKC,CAAAA,IAAS,CACpB,mBAAAF,CAAAA,CAEA,gBAAA,CAAkB,EAAC,CACnB,cAAA,CAAgB,MAAA,CAChB,SAAA,CAAW,OAEX,WAAA,CAAcG,CAAAA,EAAO,CACnBF,CAAAA,CAAKG,CAAAA,EACHC,QAAQD,CAAAA,CAAQE,CAAAA,EAAU,CACxBA,CAAAA,CAAM,cAAA,CAAiBH,EAAG,KAAA,CACtBA,CAAAA,CAAG,QACLG,CAAAA,CAAM,gBAAA,CAAiBH,EAAG,KAAK,CAAA,CAAI,CACjC,GAAGA,EACH,OAAA,CAAS,IACX,GAEJ,CAAC,CACH,EACF,CAAA,CAEA,cAAA,CAAgB,CAACI,CAAAA,CAAOC,CAAAA,GAAW,CACjCP,CAAAA,CAAKG,CAAAA,EACHC,QAAQD,CAAAA,CAAQE,CAAAA,EAAU,CACxB,IAAMH,CAAAA,CAAKG,EAAM,gBAAA,CAAiBC,CAAK,EAEnCJ,CAAAA,EACF,MAAA,CAAO,OAAOA,CAAAA,CAAIK,CAAM,EAE5B,CAAC,CACH,EACF,CAAA,CAEA,gBAAA,CAAmBD,GAAU,CAC3BN,CAAAA,CAAKG,GACHC,OAAAA,CAAQD,CAAAA,CAAQE,GAAU,CACxB,OAAOA,CAAAA,CAAM,gBAAA,CAAiBC,CAAK,EACrC,CAAC,CACH,EACF,CAAA,CAEA,oBAAsBA,CAAAA,EAAU,CAC9BN,EAAKG,CAAAA,EACHC,OAAAA,CAAQD,EAAQE,CAAAA,EAAU,CACpBC,GAASD,CAAAA,CAAM,gBAAA,CAAiBC,CAAK,CAAA,GACvCD,CAAAA,CAAM,gBAAA,CAAiBC,CAAK,EAAE,kBAAA,CAAqB,KAAA,CAAA,CAGrDD,EAAM,SAAA,CAAY,OACpB,CAAC,CACH,EACF,EAEA,YAAA,CAAc,IAAMJ,GAAI,CAAE,cAC5B,EACF,CC1HO,IAAMO,EAAwDC,CAAAA,EAC5D,MAAA,CAAO,MAAA,CAAOA,CAAgB,EAAE,IAAA,CAAK,CAACC,EAAGC,CAAAA,GAAM,MAAA,CAAOD,EAAE,cAAc,CAAA,CAAI,OAAOC,CAAAA,CAAE,cAAc,CAAC,CAAA,CAU9FC,CAAAA,CACXH,GAEOD,CAAAA,CAAsBC,CAAgB,EAAE,MAAA,CAAQP,CAAAA,EAAOA,EAAG,OAAO,CAAA,CAW7DW,EAAgB,CAC3BJ,CAAAA,CACAK,IAEOL,CAAAA,CAAiBK,CAAG,EAWhBC,CAAAA,CAAsC,CACjDN,EACAO,CAAAA,GAGOR,CAAAA,CAAsBC,CAAgB,CAAA,CAAE,MAAA,CAAQP,GAAOA,CAAAA,CAAG,IAAA,CAAK,aAAY,GAAMc,CAAAA,CAAK,WAAA,EAAa,EAW/FC,CAAAA,CAA0C,CACrDR,EACAO,CAAAA,GAIOD,CAAAA,CAAoCN,EAAkBO,CAAI,CAAA,CAAE,OAAQd,CAAAA,EAAOA,CAAAA,CAAG,OAAO,MCrDjFgB,CAAAA,CAAqB,CAAmC,CACnE,UAAA,CAAAC,CAAAA,CACA,SAAAC,CACF,CAAA,GAGuC,CACrC,GAAI,CAACA,GAAYA,CAAAA,CAAS,MAAA,GAAW,CAAA,CAAG,CACtC,QAAQ,KAAA,CAAM,iEAAiE,EAC/E,MACF,CAEA,IAAMC,CAAAA,CAAUD,CAAAA,CAAS,KAAMV,CAAAA,EAAMA,CAAAA,CAAE,MAAQS,CAAU,CAAA,CAEzD,OAAIE,CAAAA,GAGF,OAAA,CAAQ,KACN,CAAA,2BAAA,EAA8BF,CAAU,oDAAoDC,CAAAA,CAAS,CAAC,EAAE,GAAG,CAAA,EAAA,CAC7G,EACOA,CAAAA,CAAS,CAAC,EAErB,ECbO,SAASE,EAAoD,CAClE,kBAAA,CAAAvB,EACA,QAAA,CAAAqB,CAAAA,CACA,GAAGG,CACL,CAAA,CAGgD,CAC9C,OAAOC,WAAAA,EAAwC,CAC7CC,OAAAA,CACE,CAACzB,CAAAA,CAAKC,CAAAA,IAAS,CACb,GAAGH,CAAAA,CAAiC,CAAE,kBAAA,CAAAC,CAAmB,CAAC,CAAA,CAAEC,CAAAA,CAAKC,CAAG,CAAA,CAMpE,0BAAA,CAA4B,SAAY,CACtC,IAAMyB,EAAa,MAAA,CAAO,MAAA,CAAOzB,CAAAA,EAAI,CAAE,gBAAgB,CAAA,CAAE,MAAA,CAAQC,GAAOA,CAAAA,CAAG,OAAO,EAElF,MAAM,OAAA,CAAQ,IACZwB,CAAAA,CAAW,GAAA,CAAKxB,GACEgB,CAAAA,CAAmB,CACjC,WAAYhB,CAAAA,CAAG,OAAA,CACf,SAAAkB,CACF,CAAC,CAAA,EACe,gCAAA,CAAiC,CAAE,EAAA,CAAAlB,CAAAA,CAAI,GAAGD,CAAAA,EAAM,CAAC,CAClE,CACH,EACF,CAAA,CAOA,iBAAA,CAAmB,MAAO,CAAE,cAAA,CAAA0B,EAAgB,cAAA,CAAAC,CAAAA,CAAgB,OAAAC,CAAO,CAAA,GAAM,CACvE,GAAM,CAAE,eAAAC,CAAAA,CAAgB,GAAGC,CAAW,CAAA,CAAIF,CAAAA,CACpCG,EAAiBC,CAAAA,EAAM,CAAE,MAAK,CAGpCjC,CAAAA,CAAI,CACF,SAAA,CAAW,CACT,GAAG6B,CAAAA,CACH,cAAA,CAAAG,EACA,cAAA,CAAgB,IAClB,CACF,CAAC,EAED,IAAMX,CAAAA,CAAUH,EAAmB,CACjC,UAAA,CAAYa,EAAW,OAAA,CACvB,QAAA,CAAAX,CACF,CAAC,CAAA,CAED,GAAI,CAACC,CAAAA,CAAS,CACZ,IAAMa,CAAAA,CAAQ,IAAI,KAAA,CAAM,wCAAwC,CAAA,CAChE,MAAAC,EAAcD,CAAK,CAAA,CACbA,CACR,CAEA,GAAI,CACF,GAAM,CAAE,WAAAE,CAAAA,CAAY,aAAA,CAAAC,CAAc,CAAA,CAAIhB,CAAAA,CAAQ,eAAc,CAG5D,MAAMA,EAAQ,eAAA,CAAgBS,CAAc,CAAA,CAG5C,IAAMQ,EAAkB,MAAMV,CAAAA,GAE9B,GAAI,CAACU,EAAiB,CAEpBtC,CAAAA,CAAI,CAAE,SAAA,CAAW,KAAA,CAAU,CAAC,CAAA,CAC5B,MACF,CAGA,IAAMuC,CAAAA,CAAkB,CACtB,GAAGR,CAAAA,CACH,WAAAK,CAAAA,CACA,IAAA,CAAMC,EACN,OAAA,CAASV,CAAAA,CACT,QAASG,CAAAA,CACT,cAAA,CAAAE,EACA,KAAA,CAAO,EAAA,CACP,QAAS,CAAA,CAAA,CACT,kBAAA,CAAoBH,EAAO,gBAC7B,CAAA,CAGM,CAAE,OAAA,CAASW,CAAAA,CAAgB,MAAOC,CAAW,CAAA,CAAIpB,CAAAA,CAAQ,wBAAA,CAC7DiB,EACAC,CAAAA,CAAgB,UAClB,EAEMG,CAAAA,CAAQ,CACZ,GAAGH,CAAAA,CACH,OAAA,CAASC,EACT,KAAA,CAAOC,CAAAA,CACP,KAAMD,CAAAA,GAAmB,UAAA,CAAaF,EAAkB,KAAA,CAC1D,CAAA,CAGArC,GAAI,CAAE,WAAA,CAAYyC,CAAK,CAAA,CAGvB1C,EAAKG,CAAAA,EACHC,OAAAA,CAAQD,EAAQE,CAAAA,EAAU,CACpBA,EAAM,SAAA,GACRA,CAAAA,CAAM,UAAU,cAAA,CAAiB,CAAA,CAAA,CACjCA,EAAM,SAAA,CAAU,SAAA,CAAYoC,GAEhC,CAAC,CACH,EAGA,IAAMvC,CAAAA,CAAKD,CAAAA,EAAI,CAAE,iBAAiBwC,CAAU,CAAA,CAC5C,MAAMpB,CAAAA,CAAQ,gCAAA,CAAiC,CAAE,EAAA,CAAAnB,CAAAA,CAAI,GAAGD,CAAAA,EAAM,CAAC,EACjE,CAAA,MAAS0C,EAAG,CACV,MAAAR,EAAcQ,CAAC,CAAA,CACTA,CACR,CAMA,SAASR,EAAcQ,CAAAA,CAAY,CACjC,IAAMC,CAAAA,CAAeD,CAAAA,YAAa,MAAQA,CAAAA,CAAE,OAAA,CAAU,OAAOA,CAAC,CAAA,CAC9D3C,EAAKG,CAAAA,EACHC,OAAAA,CAAQD,EAAQE,CAAAA,EAAU,CACpBA,EAAM,SAAA,GACRA,CAAAA,CAAM,SAAA,CAAU,cAAA,CAAiB,MACjCA,CAAAA,CAAM,SAAA,CAAU,aAAeuC,CAAAA,EAEnC,CAAC,CACH,EACF,CACF,CACF,CAAA,CAAA,CACA,CACE,GAAGrB,CACL,CACF,CACF,CACF,KClJYsB,CAAAA,CAAAA,CAAAA,CAAAA,GAEVA,CAAAA,CAAA,GAAA,CAAM,KAAA,CAENA,EAAA,MAAA,CAAS,QAAA,CAETA,EAAA,QAAA,CAAW,UAAA,CANDA,OAAA,EAAA,CAAA,CAYAC,CAAAA,CAAAA,CAAAA,CAAAA,GAEVA,EAAA,MAAA,CAAS,QAAA,CAETA,EAAA,OAAA,CAAU,SAAA,CAEVA,EAAA,QAAA,CAAW,UAAA,CANDA,OAAA,EAAA,ECVL,IAAMC,EAAAA,EAA0BC,GAAWC,CAAAA,EAAaC,QAAAA,CAASF,EAAOC,CAAQ,CAAA,ECwBvF,IAAME,CAAAA,CAA2B,GAAA,CAC3BC,EAAsB,EAAA,CAcrB,SAASC,GAAmCC,CAAAA,CAA8C,CAC/F,GAAM,CACJ,EAAA,CAAApD,EACA,OAAA,CAAAqD,CAAAA,CACA,aAAAC,CAAAA,CACA,SAAA,CAAAC,EACA,SAAA,CAAAC,CAAAA,CACA,eAAAC,CAAAA,CACA,UAAA,CAAAC,EACA,gBAAA,CAAAC,CAAAA,CACA,gBAAAC,CAAAA,CAAkBX,CAAAA,CAClB,WAAAY,CAAAA,CAAaX,CACf,EAAIE,CAAAA,CAGJ,GAAI,CAACpD,CAAAA,CAAG,QACN,OAIFsD,CAAAA,KAEA,IAAIQ,CAAAA,CAAcD,EACdE,CAAAA,CAAY,IAAA,CAOVC,EAAe3C,CAAAA,EAA4C,CAC1D0C,IACLA,CAAAA,CAAY,KAAA,CAERJ,GAAoB,CAACtC,CAAAA,EAAS,iBAChCsC,CAAAA,CAAiB3D,CAAAA,CAAG,KAAK,CAAA,EAE7B,GAEoB,SAAY,CAC9B,KAAO+D,CAAAA,EAAaD,CAAAA,CAAc,GAChC,GAAI,CAEF,GADA,MAAM,IAAI,QAASG,CAAAA,EAAY,UAAA,CAAWA,EAASL,CAAe,CAAC,EAC/D,CAACG,CAAAA,CAAW,MAGhB,MAAMV,EAAQ,CACZ,EAAA,CAAArD,EACA,WAAA,CAAAgE,CAAAA,CACA,UAAAT,CAAAA,CACA,SAAA,CAAAC,EACA,cAAA,CAAAC,CAAAA,CACA,WAAAC,CACF,CAAC,EACH,CAAA,MAAS1B,CAAAA,CAAO,CACd,OAAA,CAAQ,KAAA,CAAM,6BAA6BhC,CAAAA,CAAG,KAAK,mBAAoBgC,CAAK,CAAA,CAC5E8B,IACF,CAGEA,CAAAA,EAAe,IACjB,OAAA,CAAQ,IAAA,CAAK,qBAAqB9D,CAAAA,CAAG,KAAK,wDAAwD,CAAA,CAClGwD,CAAAA,GACAQ,CAAAA,EAAY,EAEhB,KAIF","file":"index.mjs","sourcesContent":["/**\n * @file This file provides the core slice for the Zustand store, responsible for managing the state of transactions.\n * It includes functions and types for initializing the store and performing basic CRUD operations on the transaction pool.\n */\n\nimport { Draft, produce } from 'immer';\n\nimport { EvmTransaction, InitialTransaction, StoreSlice, Transaction } from '../types';\n\n/**\n * Defines the structure of the transaction pool, which is a record of transactions indexed by their unique keys.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n */\nexport type TransactionPool<TR, T extends Transaction<TR>> = Record<string, T>;\n\n/**\n * A utility type that extracts a subset of fields from the `Transaction` type\n * that are updatable via the `updateTxParams` action.\n * @template TR - The type of the tracker identifier.\n */\ntype UpdatableTransactionFields<TR> = Partial<\n Pick<\n EvmTransaction<TR>,\n | 'to'\n | 'nonce'\n | 'txKey'\n | 'pending'\n | 'hash'\n | 'status'\n | 'replacedTxHash'\n | 'errorMessage'\n | 'finishedTimestamp'\n | 'isTrackedModalOpen'\n | 'isError'\n | 'maxPriorityFeePerGas'\n | 'maxFeePerGas'\n | 'input'\n | 'value'\n >\n>;\n\n/**\n * Defines the interface for the base transaction tracking store slice.\n * It includes the state and actions for managing transactions.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n */\nexport interface IInitializeTxTrackingStore<TR, T extends Transaction<TR>> {\n /** An optional callback function to be executed when a transaction successfully completes. */\n onSucceedCallbacks?: (tx: T) => Promise<void> | void;\n /** A pool of all transactions currently being tracked, indexed by their `txKey`. */\n transactionsPool: TransactionPool<TR, T>;\n /** The key of the most recently added transaction. */\n lastAddedTxKey?: string;\n /** The state of a transaction that is currently being initiated but not yet submitted. */\n initialTx?: InitialTransaction;\n\n /** Adds a new transaction to the tracking pool. */\n addTxToPool: (tx: T) => void;\n /** Updates one or more parameters of an existing transaction in the pool. */\n updateTxParams: (txKey: string, fields: UpdatableTransactionFields<TR>) => void;\n /** Removes a transaction from the tracking pool using its key. */\n removeTxFromPool: (txKey: string) => void;\n /** Closes the tracking modal for a specific transaction. */\n closeTxTrackedModal: (txKey?: string) => void;\n /** Returns the key of the last transaction that was added to the pool. */\n getLastTxKey: () => string | undefined;\n}\n\n/**\n * Creates a Zustand store slice containing the core logic for transaction tracking.\n * This function is a slice creator and is meant to be used within `createStore` from Zustand.\n * @param {object} options - Configuration options for the store slice.\n * @param {function} [options.onSucceedCallbacks] - An optional async callback to run when a transaction succeeds.\n * @returns {StoreSlice<IInitializeTxTrackingStore<TR, T>>} A Zustand store slice.\n */\nexport function initializeTxTrackingStore<TR, T extends Transaction<TR>>({\n onSucceedCallbacks,\n}: {\n onSucceedCallbacks?: (tx: T) => Promise<void> | void;\n}): StoreSlice<IInitializeTxTrackingStore<TR, T>> {\n return (set, get) => ({\n onSucceedCallbacks,\n\n transactionsPool: {},\n lastAddedTxKey: undefined,\n initialTx: undefined,\n\n addTxToPool: (tx) => {\n set((state) =>\n produce(state, (draft) => {\n draft.lastAddedTxKey = tx.txKey;\n if (tx.txKey) {\n draft.transactionsPool[tx.txKey] = {\n ...tx,\n pending: true,\n } as Draft<T>;\n }\n }),\n );\n },\n\n updateTxParams: (txKey, fields) => {\n set((state) =>\n produce(state, (draft) => {\n const tx = draft.transactionsPool[txKey];\n // Ensure the transaction exists before attempting to update\n if (tx) {\n Object.assign(tx, fields);\n }\n }),\n );\n },\n\n removeTxFromPool: (txKey) => {\n set((state) =>\n produce(state, (draft) => {\n delete draft.transactionsPool[txKey];\n }),\n );\n },\n\n closeTxTrackedModal: (txKey) => {\n set((state) =>\n produce(state, (draft) => {\n if (txKey && draft.transactionsPool[txKey]) {\n draft.transactionsPool[txKey].isTrackedModalOpen = false;\n }\n // Always clear the initial transaction state when a modal is closed\n draft.initialTx = undefined;\n }),\n );\n },\n\n getLastTxKey: () => get().lastAddedTxKey,\n });\n}\n","/**\n * @file This file contains selector functions for deriving state from the transaction tracking store.\n * Selectors help abstract the state's shape and provide efficient, memoized access to computed data.\n */\n\nimport { Transaction } from '../types';\nimport { TransactionPool } from './initializeTxTrackingStore';\n\n/**\n * Selects all transactions from the pool and sorts them by their creation timestamp in ascending order.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of all transactions, sorted chronologically.\n */\nexport const selectAllTransactions = <TR, T extends Transaction<TR>>(transactionsPool: TransactionPool<TR, T>): T[] => {\n return Object.values(transactionsPool).sort((a, b) => Number(a.localTimestamp) - Number(b.localTimestamp));\n};\n\n/**\n * Selects all transactions that are currently in a pending state, sorted chronologically.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of pending transactions.\n */\nexport const selectPendingTransactions = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n): T[] => {\n return selectAllTransactions(transactionsPool).filter((tx) => tx.pending);\n};\n\n/**\n * Selects a single transaction from the pool by its unique key (`txKey`).\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @param {string} key - The `txKey` of the transaction to retrieve.\n * @returns {T | undefined} The transaction object if found, otherwise undefined.\n */\nexport const selectTxByKey = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n key: string,\n): T | undefined => {\n return transactionsPool[key];\n};\n\n/**\n * Selects all transactions initiated by a specific wallet address, sorted chronologically.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @param {string} from - The wallet address (`from` address) to filter transactions by.\n * @returns {T[]} An array of transactions associated with the given wallet.\n */\nexport const selectAllTransactionsByActiveWallet = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n from: string,\n): T[] => {\n // Filters all transactions to find those matching the provided `from` address.\n return selectAllTransactions(transactionsPool).filter((tx) => tx.from.toLowerCase() === from.toLowerCase());\n};\n\n/**\n * Selects all pending transactions for a specific wallet address, sorted chronologically.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @param {string} from - The wallet address (`from` address) to filter transactions by.\n * @returns {T[]} An array of pending transactions for the given wallet.\n */\nexport const selectPendingTransactionsByActiveWallet = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n from: string,\n): T[] => {\n // Reuses the `selectAllTransactionsByActiveWallet` selector for efficiency\n // and then filters for pending transactions.\n return selectAllTransactionsByActiveWallet(transactionsPool, from).filter((tx) => tx.pending);\n};\n","/**\n * @file This file contains a utility function for selecting a specific transaction adapter from a list.\n */\n\nimport { Transaction, TransactionAdapter, TxAdapter } from '../types';\n\n/**\n * Selects a transaction adapter from a list based on a provided key.\n *\n * This function searches through an array of `TxAdapter` instances and returns the one\n * that matches the given `adapterKey`. If no specific adapter is found, it logs a warning\n * and returns the first adapter in the array as a fallback. This fallback mechanism\n * ensures that the system can still function, but it highlights a potential configuration issue.\n *\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type, extending the base `Transaction`.\n * @template A - The type for the adapter-specific context or API.\n *\n * @param {object} params - The parameters for the selection.\n * @param {TransactionAdapter} params.adapterKey - The key of the desired adapter.\n * @param {TxAdapter<TR, T, A>[]} params.adapters - An array of available transaction adapters.\n *\n * @returns {TxAdapter<TR, T, A> | undefined} The found transaction adapter, the fallback adapter, or undefined if the adapters array is empty.\n */\nexport const selectAdapterByKey = <TR, T extends Transaction<TR>, A>({\n adapterKey,\n adapters,\n}: {\n adapterKey: TransactionAdapter;\n adapters: TxAdapter<TR, T, A>[];\n}): TxAdapter<TR, T, A> | undefined => {\n if (!adapters || adapters.length === 0) {\n console.error('Adapter selection failed: The provided adapters array is empty.');\n return undefined;\n }\n\n const adapter = adapters.find((a) => a.key === adapterKey);\n\n if (adapter) {\n return adapter;\n } else {\n console.warn(\n `No adapter found for key: \"${adapterKey}\". Falling back to the first available adapter: \"${adapters[0].key}\".`,\n );\n return adapters[0];\n }\n};\n","/**\n * @file This file is the heart of the Pulsar store, orchestrating transaction handling,\n * state management, and communication with various blockchain adapters. It leverages\n * Zustand for state management, Immer for immutable updates, and a persistent middleware\n * to maintain state across sessions.\n */\n\nimport dayjs from 'dayjs';\nimport { Draft, produce } from 'immer';\nimport { persist, PersistOptions } from 'zustand/middleware';\nimport { createStore } from 'zustand/vanilla';\n\nimport { ITxTrackingStore, Transaction, TxAdapter } from '../types';\nimport { selectAdapterByKey } from '../utils/selectAdapterByKey';\nimport { initializeTxTrackingStore } from './initializeTxTrackingStore';\n\n/**\n * Creates the main Pulsar store for transaction tracking.\n *\n * This function sets up a Zustand store with persistence, combining the core\n * transaction slice with adapter-specific logic to handle the entire lifecycle\n * of a transaction.\n *\n * @template TR - The type of the tracker identifier (e.g., a string enum).\n * @template T - The specific transaction type, extending the base `Transaction`.\n * @template A - The type for the adapter-specific context or API.\n *\n * @param {object} config - Configuration object for creating the store.\n * @param {function} [config.onSucceedCallbacks] - Optional async callback executed on transaction success.\n * @param {TxAdapter<TR, T, A>[]} config.adapters - An array of adapters for different transaction types or chains.\n * @param {PersistOptions<ITxTrackingStore<TR, T, A>>} [options] - Configuration for the Zustand persist middleware.\n * @returns A fully configured Zustand store instance.\n */\nexport function createPulsarStore<TR, T extends Transaction<TR>, A>({\n onSucceedCallbacks,\n adapters,\n ...options\n}: {\n onSucceedCallbacks?: (tx: T) => Promise<void> | void;\n adapters: TxAdapter<TR, T, A>[];\n} & PersistOptions<ITxTrackingStore<TR, T, A>>) {\n return createStore<ITxTrackingStore<TR, T, A>>()(\n persist(\n (set, get) => ({\n ...initializeTxTrackingStore<TR, T>({ onSucceedCallbacks })(set, get),\n\n /**\n * Initializes trackers for all pending transactions upon store creation.\n * This is crucial for resuming tracking after a page refresh or session restoration.\n */\n initializeTransactionsPool: async () => {\n const pendingTxs = Object.values(get().transactionsPool).filter((tx) => tx.pending);\n\n await Promise.all(\n pendingTxs.map((tx) => {\n const adapter = selectAdapterByKey({\n adapterKey: tx.adapter,\n adapters,\n });\n return adapter?.checkAndInitializeTrackerInStore({ tx, ...get() });\n }),\n );\n },\n\n /**\n * The core function to orchestrate sending and tracking a new transaction.\n * It manages the entire lifecycle, including chain switching, wallet interactions,\n * state updates, and tracker initialization.\n */\n handleTransaction: async ({ defaultTracker, actionFunction, params }) => {\n const { desiredChainID, ...restParams } = params;\n const localTimestamp = dayjs().unix();\n\n // 1. Set initial state for immediate UI feedback\n set({\n initialTx: {\n ...params,\n localTimestamp,\n isInitializing: true,\n },\n });\n\n const adapter = selectAdapterByKey({\n adapterKey: restParams.adapter,\n adapters,\n });\n\n if (!adapter) {\n const error = new Error('No adapter found for this transaction.');\n handleTxError(error);\n throw error; // Re-throw to allow the caller to handle it\n }\n\n try {\n const { walletType, walletAddress } = adapter.getWalletInfo();\n\n // 2. Ensure the wallet is connected to the correct chain\n await adapter.checkChainForTx(desiredChainID);\n\n // 3. Execute the provided action function (e.g., signing a transaction)\n const txKeyFromAction = await actionFunction();\n\n if (!txKeyFromAction) {\n // If the user cancelled the action, clear the initial state.\n set({ initialTx: undefined });\n return;\n }\n\n // 4. Prepare the initial transaction object\n const txInitialParams = {\n ...restParams,\n walletType,\n from: walletAddress,\n tracker: defaultTracker,\n chainId: desiredChainID,\n localTimestamp,\n txKey: '', // Will be populated shortly\n pending: false,\n isTrackedModalOpen: params.withTrackedModal,\n } as Draft<T>;\n\n // 5. Determine the correct tracker and final txKey based on the action result\n const { tracker: updatedTracker, txKey: finalTxKey } = adapter.checkTransactionsTracker(\n txKeyFromAction,\n txInitialParams.walletType,\n );\n\n const newTx = {\n ...txInitialParams,\n tracker: updatedTracker,\n txKey: finalTxKey,\n hash: updatedTracker === 'ethereum' ? txKeyFromAction : undefined,\n } as T;\n\n // 6. Add the finalized transaction to the pool\n get().addTxToPool(newTx);\n\n // 7. Update the initial state to reflect completion\n set((state) =>\n produce(state, (draft) => {\n if (draft.initialTx) {\n draft.initialTx.isInitializing = false;\n draft.initialTx.lastTxKey = finalTxKey;\n }\n }),\n );\n\n // 8. Initialize the background tracker for the new transaction\n const tx = get().transactionsPool[finalTxKey];\n await adapter.checkAndInitializeTrackerInStore({ tx, ...get() });\n } catch (e) {\n handleTxError(e);\n throw e; // Re-throw for external handling\n }\n\n /**\n * A centralized error handler for the transaction process.\n * @param {unknown} e - The error object.\n */\n function handleTxError(e: unknown) {\n const errorMessage = e instanceof Error ? e.message : String(e);\n set((state) =>\n produce(state, (draft) => {\n if (draft.initialTx) {\n draft.initialTx.isInitializing = false;\n draft.initialTx.errorMessage = errorMessage;\n }\n }),\n );\n }\n },\n }),\n {\n ...options, // Zustand persist middleware options\n },\n ),\n );\n}\n","/**\n * @file This file defines the core data structures and TypeScript types for the Pulsar transaction tracking engine.\n * It includes types for transactions, their statuses, store interfaces, and utility types for Zustand slices.\n * These types are framework-agnostic and form the foundation of the entire tracking system.\n */\n\nimport { StoreApi } from 'zustand';\n\nimport { IInitializeTxTrackingStore, TransactionPool } from './store/initializeTxTrackingStore';\n\n// =================================================================================================\n// 1. ZUSTAND UTILITY TYPES\n// =================================================================================================\n\n/**\n * A utility type for creating modular Zustand store slices, enabling composable state management.\n * @template T - The type of the state slice.\n * @template S - The type of the full store state, defaulting to T.\n */\nexport type StoreSlice<T extends object, S extends object = T> = (\n set: StoreApi<S extends T ? S : S & T>['setState'],\n get: StoreApi<S extends T ? S : S & T>['getState'],\n) => T;\n\n// =================================================================================================\n// 2. ENUMS AND CORE TRANSACTION TYPES\n// =================================================================================================\n\n/**\n * Defines the supported blockchain adapters. Each adapter corresponds to a specific chain architecture.\n */\nexport enum TransactionAdapter {\n /** For Ethereum Virtual Machine (EVM) compatible chains like Ethereum, Polygon, etc. */\n EVM = 'evm',\n /** For the Solana blockchain. */\n SOLANA = 'solana',\n /** For the Starknet L2 network. */\n Starknet = 'starknet',\n}\n\n/**\n * Represents the terminal status of a transaction after it has been processed.\n */\nexport enum TransactionStatus {\n /** The transaction failed to execute due to an on-chain error or rejection. */\n Failed = 'Failed',\n /** The transaction was successfully mined and executed. */\n Success = 'Success',\n /** The transaction was replaced by another with the same nonce (e.g., a speed-up or cancel). */\n Replaced = 'Replaced',\n}\n\n/**\n * The fundamental structure for any transaction being tracked by Pulsar.\n * This forms the base upon which chain-specific transaction types are built.\n * @template T - The type of the tracker identifier (e.g., 'ethereum', 'gelato', 'safe').\n */\nexport type BaseTransaction<T> = {\n /** A unique key identifying a re-executable action from the `TxActions` registry. */\n actionKey?: string;\n /** The chain identifier (e.g., 1 for Ethereum Mainnet, 'SN_MAIN' for Starknet). */\n chainId: number | string;\n /** A user-facing description. Can be a single string or an array for [pending, success, error, replaced] states. */\n description?: string | [string, string, string, string];\n /** The error message if the transaction failed. */\n errorMessage?: string;\n /** The on-chain timestamp (in seconds) when the transaction was finalized. */\n finishedTimestamp?: number;\n /** The sender's wallet address. */\n from: string;\n /** A flag indicating if the transaction is in a failed state. */\n isError?: boolean;\n /** A UI flag to control the visibility of a detailed tracking modal for this transaction. */\n isTrackedModalOpen?: boolean;\n /** The local timestamp (in seconds) when the transaction was initiated by the user. */\n localTimestamp: number;\n /** Any additional, custom data associated with the transaction. */\n payload?: object;\n /** A flag indicating if the transaction is still awaiting on-chain confirmation. */\n pending: boolean;\n /** The final on-chain status of the transaction. */\n status?: TransactionStatus;\n /** A user-facing title. Can be a single string or an array for [pending, success, error, replaced] states. */\n title?: string | [string, string, string, string];\n /** The specific tracker responsible for monitoring this transaction's status. */\n tracker: T;\n /** The unique identifier for the transaction (e.g., EVM hash, Gelato task ID). */\n txKey: string;\n /** The application-specific type or category of the transaction (e.g., 'SWAP', 'APPROVE'). */\n type: string;\n /** The type of wallet used to sign the transaction (e.g., 'injected', 'walletConnect'). */\n walletType: string;\n};\n\n// =================================================================================================\n// 3. CHAIN-SPECIFIC TRANSACTION TYPES\n// =================================================================================================\n\n/**\n * Represents an EVM-specific transaction, extending the base properties with EVM fields.\n * @template T - The type of the tracker identifier.\n */\nexport type EvmTransaction<T> = BaseTransaction<T> & {\n adapter: TransactionAdapter.EVM;\n /** The on-chain transaction hash, available after submission. */\n hash?: `0x${string}`;\n /** The data payload for the transaction, typically for smart contract interactions. */\n input?: `0x${string}`;\n /** The maximum fee per gas for an EIP-1559 transaction (in wei). */\n maxFeePerGas?: string;\n /** The maximum priority fee per gas for an EIP-1559 transaction (in wei). */\n maxPriorityFeePerGas?: string;\n /** The transaction nonce, a sequential number for the sender's account. */\n nonce?: number;\n /** The hash of a transaction that this one replaced. */\n replacedTxHash?: `0x${string}`;\n /** The recipient's address or contract address. */\n to?: `0x${string}`;\n /** The amount of native currency (in wei) being sent. */\n value?: string;\n};\n\n/**\n * Represents a Solana-specific transaction, extending the base properties.\n * @template T - The type of the tracker identifier.\n */\nexport type SolanaTransaction<T> = BaseTransaction<T> & {\n adapter: TransactionAdapter.SOLANA;\n /** The transaction fee in lamports. */\n fee?: number;\n /** The instructions included in the transaction. */\n instructions?: unknown[];\n /** The recent blockhash used for the transaction. */\n recentBlockhash?: string;\n /** The slot in which the transaction was processed. */\n slot?: number;\n};\n\n/**\n * Represents a Starknet-specific transaction, extending the base properties.\n * @template T - The type of the tracker identifier.\n */\nexport type StarknetTransaction<T> = BaseTransaction<T> & {\n adapter: TransactionAdapter.Starknet;\n /** The actual fee paid for the transaction. */\n actualFee?: { amount: string; unit: string };\n /** The address of the contract being interacted with. */\n contractAddress?: string;\n /** The reason for transaction failure, if applicable. */\n revertReason?: string;\n};\n\n/** A union type representing any possible transaction structure that Pulsar can handle. */\nexport type Transaction<T> = EvmTransaction<T> | SolanaTransaction<T> | StarknetTransaction<T>;\n\n// =================================================================================================\n// 4. INITIAL TRANSACTION AND ACTION TYPES\n// =================================================================================================\n\n/**\n * A registry of functions that can be re-executed, keyed by `actionKey`.\n * Used for implementing \"Retry\" functionality.\n */\nexport type TxActions = Record<string, (...args: any[]) => Promise<unknown>>;\n\n/**\n * Represents the parameters required to initiate a new transaction tracking flow.\n */\nexport type InitialTransactionParams = {\n adapter: TransactionAdapter;\n /** A key to identify the re-executable action from the `TxActions` registry. */\n actionKey?: string;\n /** A user-facing description for the transaction. */\n description?: string | [string, string, string, string];\n /** The target chain ID for the transaction. */\n desiredChainID: number | string;\n /** Any custom data to associate with the transaction. */\n payload?: object;\n /** A user-facing title for the transaction. */\n title?: string | [string, string, string, string];\n /** The application-specific type of the transaction. */\n type: string;\n /** If true, the detailed tracking modal will open automatically upon initiation. */\n withTrackedModal?: boolean;\n};\n\n/**\n * Represents a transaction in its temporary, pre-submission state.\n * This is used for UI feedback while the transaction is being signed and sent.\n */\nexport type InitialTransaction = InitialTransactionParams & {\n /** An error message if the initialization fails (e.g., user rejects signature). */\n errorMessage?: string;\n /** A flag indicating if the transaction is being processed (e.g., waiting for signature). */\n isInitializing: boolean;\n /** The `txKey` of the on-chain transaction that this action produced, used for linking the states. */\n lastTxKey?: string;\n /** The local timestamp when the user initiated the action. */\n localTimestamp: number;\n};\n\n// =================================================================================================\n// 5. ADAPTER AND STORE INTERFACES\n// =================================================================================================\n\n/**\n * Defines the interface for a transaction adapter, which provides chain-specific logic and utilities.\n * @template TR - The type of the tracker identifier (e.g., a string enum).\n * @template T - The specific transaction type, extending `Transaction<TR>`.\n * @template A - The type of the key returned by the `actionFunction` (e.g., a transaction hash).\n */\nexport type TxAdapter<TR, T extends Transaction<TR>, A> = {\n /** The unique key identifying this adapter. */\n key: TransactionAdapter;\n /** Returns information about the currently connected wallet. */\n getWalletInfo: () => {\n walletAddress: string;\n walletType: string;\n };\n /** Ensures the connected wallet is on the correct network for the transaction. */\n checkChainForTx: (chainId: string | number) => Promise<void>;\n /** Determines the appropriate tracker and final `txKey` based on the result of an action. */\n checkTransactionsTracker: (actionTxKey: A, walletType: string) => { txKey: string; tracker: TR };\n /** Initializes the correct background tracker for a given transaction. */\n checkAndInitializeTrackerInStore: (\n params: { tx: T } & Pick<\n ITxTrackingStore<TR, T, A>,\n 'transactionsPool' | 'updateTxParams' | 'onSucceedCallbacks' | 'removeTxFromPool'\n >,\n ) => Promise<void>;\n /** Returns the base URL for the blockchain explorer. */\n getExplorerUrl: () => string | undefined;\n /** Optional: Fetches a name from a chain-specific name service (e.g., ENS). */\n getName?: (address: string) => Promise<string | null>;\n /** Optional: Fetches an avatar URL from a chain-specific name service. */\n getAvatar?: (name: string) => Promise<string | null>;\n /** Optional: Logic to cancel a pending EVM transaction. */\n cancelTxAction?: (tx: T) => Promise<string>;\n /** Optional: Logic to speed up a pending EVM transaction. */\n speedUpTxAction?: (tx: T) => Promise<string>;\n /** Optional: Logic to retry a failed transaction. */\n retryTxAction?: (\n params: {\n txKey: string;\n tx: InitialTransactionParams;\n actions?: TxActions;\n onClose: (txKey?: string) => void;\n } & Partial<Pick<ITxTrackingStore<TR, T, A>, 'handleTransaction'>>,\n ) => Promise<void>;\n /** Optional: Constructs a full explorer URL for a specific transaction. */\n getExplorerTxUrl?: (transactionsPool: TransactionPool<TR, T>, txKey: string, replacedTxHash?: string) => string;\n};\n\n/**\n * The complete interface for the Pulsar transaction tracking store.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @template A - The return type of the `actionFunction`.\n */\nexport type ITxTrackingStore<TR, T extends Transaction<TR>, A> = IInitializeTxTrackingStore<TR, T> & {\n /**\n * The core function that handles the entire lifecycle of a new transaction.\n * It manages UI state, executes the on-chain action, and initiates background tracking.\n * @param params - The parameters for handling the transaction.\n */\n handleTransaction: (params: {\n /** The async function to execute (e.g., a smart contract write call). Must return a unique key or undefined. */\n actionFunction: () => Promise<A | undefined>;\n /** The metadata for the transaction. */\n params: InitialTransactionParams;\n /** The default tracker to use if it cannot be determined automatically. */\n defaultTracker?: TR;\n }) => Promise<void>;\n\n /**\n * Initializes trackers for all pending transactions in the pool.\n * This is essential for resuming tracking after a page reload.\n */\n initializeTransactionsPool: () => Promise<void>;\n};\n","/**\n * @file This file provides a utility for creating a type-safe, bounded Zustand hook from a vanilla store.\n * This pattern is recommended by the official Zustand documentation to ensure full type\n * safety when integrating vanilla stores with React.\n *\n * @see https://docs.pmnd.rs/zustand/guides/typescript#bounded-usestore-hook-for-vanilla-stores\n */\n\nimport { StoreApi, useStore } from 'zustand';\n\n/**\n * A utility type that infers the state shape from a Zustand `StoreApi`.\n * It extracts the return type of the `getState` method.\n * @template S - The type of the Zustand store (`StoreApi`).\n */\ntype ExtractState<S> = S extends { getState: () => infer T } ? T : never;\n\n/**\n * Creates a bounded `useStore` hook from a vanilla Zustand store.\n *\n * This function takes a vanilla Zustand store instance and returns a React hook\n * that is pre-bound to that store. This approach provides a cleaner API and\n * enhances type inference, eliminating the need to pass the store instance\n * on every use.\n *\n * The returned hook supports two signatures:\n * 1. `useBoundedStore()`: Selects the entire state.\n * 2. `useBoundedStore(selector)`: Selects a slice of the state, returning only what the selector function specifies.\n *\n * @template S - The type of the Zustand store (`StoreApi`).\n * @param {S} store - The vanilla Zustand store instance to bind the hook to.\n * @returns {function} A fully typed React hook for accessing the store's state.\n */\nexport const createBoundedUseStore = ((store) => (selector) => useStore(store, selector)) as <\n S extends StoreApi<unknown>,\n>(\n store: S,\n) => {\n // This implementation uses a Immediately Invoked Function Expression (IIFE)\n // trick combined with casting to achieve the desired overloaded function signature in a concise way.\n (): ExtractState<S>;\n <T>(selector: (state: ExtractState<S>) => T): T;\n};\n","/**\n * @file This file provides a generic utility for creating a polling mechanism to track\n * asynchronous tasks, such as API-based transaction status checks (e.g., for Gelato or Safe).\n */\n\nimport { Transaction } from '../types';\n\n/**\n * Defines the parameters for the fetcher function used within the polling tracker.\n * The fetcher is the core logic that performs the actual API call.\n * @template R - The expected type of the successful API response.\n * @template T - The type of the transaction object being tracked.\n */\ntype PollingFetcherParams<R, T> = {\n /** The transaction object being tracked. */\n tx: T;\n /** A callback to stop the polling mechanism, typically called on success or terminal failure. */\n stopPolling: (options?: { withoutRemoving?: boolean }) => void;\n /** Callback to be invoked when the fetcher determines the transaction has succeeded. */\n onSuccess: (response: R) => void;\n /** Callback to be invoked when the fetcher determines the transaction has failed. */\n onFailure: (response?: R) => void;\n /** Optional callback for each successful poll, useful for updating UI with intermediate states. */\n onIntervalTick?: (response: R) => void;\n /** Optional callback for when a transaction is replaced (e.g., speed-up). */\n onReplaced?: (response: R) => void;\n};\n\n/**\n * Defines the configuration object for the `initializePollingTracker` function.\n * @template R - The expected type of the successful API response.\n * @template T - The type of the transaction object.\n * @template TR - The type of the tracker identifier.\n */\nexport type PollingTrackerConfig<R, T, TR> = {\n /** The transaction object to be tracked. It must include `txKey` and `pending` status. */\n tx: T & Pick<Transaction<TR>, 'txKey' | 'pending'>;\n /** The function that performs the data fetching (e.g., an API call) on each interval. */\n fetcher: (params: PollingFetcherParams<R, T>) => Promise<void>;\n /** Callback to be invoked when the transaction successfully completes. */\n onSuccess: (response: R) => void;\n /** Callback to be invoked when the transaction fails. */\n onFailure: (response?: R) => void;\n /** Optional callback executed once when the tracker is initialized. */\n onInitialize?: () => void;\n /** Optional callback for each successful poll. */\n onIntervalTick?: (response: R) => void;\n /** Optional callback for when a transaction is replaced. */\n onReplaced?: (response: R) => void;\n /** Optional function to remove the transaction from the main pool, typically after polling stops. */\n removeTxFromPool?: (txKey: string) => void;\n /** The interval (in milliseconds) between polling attempts. Defaults to 5000ms. */\n pollingInterval?: number;\n /** The number of consecutive failed fetches before stopping the tracker. Defaults to 10. */\n maxRetries?: number;\n};\n\nconst DEFAULT_POLLING_INTERVAL = 5000;\nconst DEFAULT_MAX_RETRIES = 10;\n\n/**\n * Initializes a generic polling tracker that repeatedly calls a fetcher function\n * to monitor the status of an asynchronous task.\n *\n * This function handles the lifecycle of polling, including starting, stopping,\n * and automatic termination after a certain number of failed attempts.\n *\n * @template R The expected type of the API response.\n * @template T The type of the transaction object.\n * @template TR The type of the tracker identifier.\n * @param {PollingTrackerConfig<R, T, TR>} config - The configuration for the tracker.\n */\nexport function initializePollingTracker<R, T, TR>(config: PollingTrackerConfig<R, T, TR>): void {\n const {\n tx,\n fetcher,\n onInitialize,\n onSuccess,\n onFailure,\n onIntervalTick,\n onReplaced,\n removeTxFromPool,\n pollingInterval = DEFAULT_POLLING_INTERVAL,\n maxRetries = DEFAULT_MAX_RETRIES,\n } = config;\n\n // 1. Early exit if the transaction is no longer pending\n if (!tx.pending) {\n return;\n }\n\n // Execute the initialization callback if provided\n onInitialize?.();\n\n let retriesLeft = maxRetries;\n let isPolling = true;\n\n /**\n * Stops the polling interval and optionally removes the transaction from the pool.\n * @param {object} [options] - Options for stopping the tracker.\n * @param {boolean} [options.withoutRemoving=false] - If true, the tx will not be removed from the pool.\n */\n const stopPolling = (options?: { withoutRemoving?: boolean }) => {\n if (!isPolling) return;\n isPolling = false;\n // The interval is cleared in the finally block of the polling loop\n if (removeTxFromPool && !options?.withoutRemoving) {\n removeTxFromPool(tx.txKey);\n }\n };\n\n const pollingLoop = async () => {\n while (isPolling && retriesLeft > 0) {\n try {\n await new Promise((resolve) => setTimeout(resolve, pollingInterval));\n if (!isPolling) break;\n\n // The fetcher's responsibility is to call onSuccess, onFailure, etc., which in turn call stopPolling.\n await fetcher({\n tx,\n stopPolling,\n onSuccess,\n onFailure,\n onIntervalTick,\n onReplaced,\n });\n } catch (error) {\n console.error(`Polling fetcher for txKey ${tx.txKey} threw an error:`, error);\n retriesLeft--;\n }\n }\n\n if (retriesLeft <= 0) {\n console.warn(`Polling for txKey ${tx.txKey} stopped after reaching the maximum number of retries.`);\n onFailure();\n stopPolling();\n }\n };\n\n // Start the asynchronous polling loop\n pollingLoop();\n}\n"]}
1
+ {"version":3,"sources":["../src/store/initializeTxTrackingStore.ts","../src/store/transactionsSelectors.ts","../src/utils/selectAdapterByKey.ts","../src/store/txTrackingStore.ts","../src/types.ts","../src/utils/createBoundedUseStore.ts","../src/utils/initializePollingTracker.ts"],"names":["initializeTxTrackingStore","onSucceedCallbacks","set","get","tx","state","produce","draft","txKey","fields","selectAllTransactions","transactionsPool","a","b","selectPendingTransactions","selectTxByKey","key","selectAllTransactionsByActiveWallet","from","selectPendingTransactionsByActiveWallet","selectAdapterByKey","adapterKey","adapters","adapter","createPulsarStore","options","createStore","persist","pendingTxs","defaultTracker","actionFunction","params","desiredChainID","restParams","localTimestamp","dayjs","handleTxError","e","errorMessage","error","walletType","walletAddress","txKeyFromAction","updatedTracker","finalTxKey","newTx","TransactionAdapter","TransactionStatus","createBoundedUseStore","store","selector","useStore","DEFAULT_POLLING_INTERVAL","DEFAULT_MAX_RETRIES","initializePollingTracker","config","fetcher","onInitialize","onSuccess","onFailure","onIntervalTick","onReplaced","removeTxFromPool","pollingInterval","maxRetries","retriesLeft","isPolling","stopPolling","resolve"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @file This file defines the core Zustand slice for managing the state of transactions. It includes the state,\n * actions, and types necessary for initializing the store and performing CRUD operations on the transaction pool.\n */\n\nimport { Draft, produce } from 'immer';\n\nimport { EvmTransaction, InitialTransaction, SolanaTransaction, StoreSlice, Transaction } from '../types';\n\n/**\n * Defines the structure of the transaction pool, a key-value store of transactions indexed by their unique keys.\n * @template TR The type of the tracker identifier.\n * @template T The transaction type.\n */\nexport type TransactionPool<TR, T extends Transaction<TR>> = Record<string, T>;\n\n/**\n * A utility type that creates a union of all fields that can be safely updated\n * on a transaction object via the `updateTxParams` action. This ensures type safety\n * and prevents accidental modification of immutable properties.\n * @template TR The type of the tracker identifier.\n */\ntype UpdatableTransactionFields<TR> = Partial<\n Pick<\n EvmTransaction<TR>,\n | 'to'\n | 'nonce'\n | 'txKey'\n | 'pending'\n | 'hash'\n | 'status'\n | 'replacedTxHash'\n | 'errorMessage'\n | 'finishedTimestamp'\n | 'isTrackedModalOpen'\n | 'isError'\n | 'maxPriorityFeePerGas'\n | 'maxFeePerGas'\n | 'input'\n | 'value'\n >\n> &\n Partial<\n Pick<SolanaTransaction<TR>, 'slot' | 'confirmations' | 'fee' | 'instructions' | 'recentBlockhash' | 'rpcUrl'>\n >;\n\n/**\n * The interface for the base transaction tracking store slice.\n * It includes the state and actions for managing the transaction lifecycle.\n * @template TR The type of the tracker identifier.\n * @template T The specific transaction type.\n * @template A The return type of the initial action function.\n */\nexport interface IInitializeTxTrackingStore<TR, T extends Transaction<TR>, A> {\n /** A callback function executed when any transaction successfully completes. */\n onSucceedCallbacks?: (tx: T) => Promise<void> | void;\n /** A pool of all transactions currently being tracked, indexed by `txKey`. */\n transactionsPool: TransactionPool<TR, T>;\n /** The `txKey` of the most recently added transaction. */\n lastAddedTxKey?: string;\n /** The state for a transaction being initiated, used for UI feedback before it's submitted to the chain. */\n initialTx?: InitialTransaction<A>;\n\n /** Adds a new transaction to the tracking pool and marks it as pending. */\n addTxToPool: (tx: Transaction<TR>) => void;\n /** Updates one or more properties of an existing transaction in the pool. */\n updateTxParams: (txKey: string, fields: UpdatableTransactionFields<TR>) => void;\n /** Removes a transaction from the tracking pool by its key. */\n removeTxFromPool: (txKey: string) => void;\n /** Closes the tracking modal for a transaction and clears any initial transaction state. */\n closeTxTrackedModal: (txKey?: string) => void;\n /** A selector function to retrieve the key of the last transaction added to the pool. */\n getLastTxKey: () => string | undefined;\n}\n\n/**\n * Creates a Zustand store slice with the core logic for transaction state management.\n * This function is a slice creator intended for use with Zustand's `create` function.\n *\n * @template TR The type of the tracker identifier.\n * @template T The specific transaction type.\n * @template A The return type of the initial action function.\n * @param options Configuration for the store slice.\n * @param options.onSucceedCallbacks An optional async callback to run when a transaction succeeds.\n * @returns A Zustand store slice implementing `IInitializeTxTrackingStore`.\n */\nexport function initializeTxTrackingStore<TR, T extends Transaction<TR>, A>({\n onSucceedCallbacks,\n}: {\n onSucceedCallbacks?: (tx: T) => Promise<void> | void;\n}): StoreSlice<IInitializeTxTrackingStore<TR, T, A>> {\n return (set, get) => ({\n onSucceedCallbacks,\n\n transactionsPool: {},\n lastAddedTxKey: undefined,\n initialTx: undefined,\n\n addTxToPool: (tx) => {\n set((state) =>\n produce(state, (draft) => {\n draft.lastAddedTxKey = tx.txKey;\n if (tx.txKey) {\n draft.transactionsPool[tx.txKey] = {\n ...tx,\n pending: true, // Ensure all new transactions start as pending.\n } as Draft<T>;\n }\n }),\n );\n },\n\n updateTxParams: (txKey, fields) => {\n set((state) =>\n produce(state, (draft) => {\n const tx = draft.transactionsPool[txKey];\n // Ensure the transaction exists before attempting to update.\n if (tx) {\n Object.assign(tx, fields);\n }\n }),\n );\n },\n\n removeTxFromPool: (txKey) => {\n set((state) =>\n produce(state, (draft) => {\n delete draft.transactionsPool[txKey];\n }),\n );\n },\n\n closeTxTrackedModal: (txKey) => {\n set((state) =>\n produce(state, (draft) => {\n if (txKey && draft.transactionsPool[txKey]) {\n draft.transactionsPool[txKey].isTrackedModalOpen = false;\n }\n // Always clear the initial transaction state when a modal is closed\n draft.initialTx = undefined;\n }),\n );\n },\n\n getLastTxKey: () => get().lastAddedTxKey,\n });\n}\n","/**\n * @file This file contains selector functions for deriving state from the transaction tracking store.\n * Selectors help abstract the state's shape and provide efficient, memoized access to computed data.\n */\n\nimport { Transaction } from '../types';\nimport { TransactionPool } from './initializeTxTrackingStore';\n\n/**\n * Selects all transactions from the pool and sorts them by their creation timestamp in ascending order.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of all transactions, sorted chronologically.\n */\nexport const selectAllTransactions = <TR, T extends Transaction<TR>>(transactionsPool: TransactionPool<TR, T>): T[] => {\n return Object.values(transactionsPool).sort((a, b) => Number(a.localTimestamp) - Number(b.localTimestamp));\n};\n\n/**\n * Selects all transactions that are currently in a pending state, sorted chronologically.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of pending transactions.\n */\nexport const selectPendingTransactions = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n): T[] => {\n return selectAllTransactions(transactionsPool).filter((tx) => tx.pending);\n};\n\n/**\n * Selects a single transaction from the pool by its unique key (`txKey`).\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @param {string} key - The `txKey` of the transaction to retrieve.\n * @returns {T | undefined} The transaction object if found, otherwise undefined.\n */\nexport const selectTxByKey = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n key: string,\n): T | undefined => {\n return transactionsPool[key];\n};\n\n/**\n * Selects all transactions initiated by a specific wallet address, sorted chronologically.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @param {string} from - The wallet address (`from` address) to filter transactions by.\n * @returns {T[]} An array of transactions associated with the given wallet.\n */\nexport const selectAllTransactionsByActiveWallet = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n from: string,\n): T[] => {\n // Filters all transactions to find those matching the provided `from` address.\n return selectAllTransactions(transactionsPool).filter((tx) => tx.from.toLowerCase() === from.toLowerCase());\n};\n\n/**\n * Selects all pending transactions for a specific wallet address, sorted chronologically.\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type.\n * @param {TransactionPool<TR, T>} transactionsPool - The entire transaction pool from the store.\n * @param {string} from - The wallet address (`from` address) to filter transactions by.\n * @returns {T[]} An array of pending transactions for the given wallet.\n */\nexport const selectPendingTransactionsByActiveWallet = <TR, T extends Transaction<TR>>(\n transactionsPool: TransactionPool<TR, T>,\n from: string,\n): T[] => {\n // Reuses the `selectAllTransactionsByActiveWallet` selector for efficiency\n // and then filters for pending transactions.\n return selectAllTransactionsByActiveWallet(transactionsPool, from).filter((tx) => tx.pending);\n};\n","/**\n * @file This file contains a utility function for selecting a specific transaction adapter from a list.\n */\n\nimport { Transaction, TransactionAdapter, TxAdapter } from '../types';\n\n/**\n * Selects a transaction adapter from a list based on a provided key.\n *\n * This function searches through an array of `TxAdapter` instances and returns the one\n * that matches the given `adapterKey`. If no specific adapter is found, it logs a warning\n * and returns the first adapter in the array as a fallback. This fallback mechanism\n * ensures that the system can still function, but it highlights a potential configuration issue.\n *\n * @template TR - The type of the tracker identifier.\n * @template T - The transaction type, extending the base `Transaction`.\n * @template A - The type for the adapter-specific context or API.\n *\n * @param {object} params - The parameters for the selection.\n * @param {TransactionAdapter} params.adapterKey - The key of the desired adapter.\n * @param {TxAdapter<TR, T, A>[]} params.adapters - An array of available transaction adapters.\n *\n * @returns {TxAdapter<TR, T, A> | undefined} The found transaction adapter, the fallback adapter, or undefined if the adapters array is empty.\n */\nexport const selectAdapterByKey = <TR, T extends Transaction<TR>, A>({\n adapterKey,\n adapters,\n}: {\n adapterKey: TransactionAdapter;\n adapters: TxAdapter<TR, T, A>[];\n}): TxAdapter<TR, T, A> | undefined => {\n if (!adapters || adapters.length === 0) {\n console.error('Adapter selection failed: The provided adapters array is empty.');\n return undefined;\n }\n\n const adapter = adapters.find((a) => a.key === adapterKey);\n\n if (adapter) {\n return adapter;\n } else {\n console.warn(\n `No adapter found for key: \"${adapterKey}\". Falling back to the first available adapter: \"${adapters[0].key}\".`,\n );\n return adapters[0];\n }\n};\n","/**\n * @file This file is the nucleus of the Pulsar store, orchestrating transaction handling, state management,\n * and communication with blockchain adapters. It utilizes Zustand for state management, Immer for safe,\n * immutable updates, and a persistence middleware to maintain state across user sessions.\n */\n\nimport dayjs from 'dayjs';\nimport { produce } from 'immer';\nimport { persist, PersistOptions } from 'zustand/middleware';\nimport { createStore } from 'zustand/vanilla';\n\nimport { ITxTrackingStore, Transaction, TxAdapter } from '../types';\nimport { selectAdapterByKey } from '../utils/selectAdapterByKey';\nimport { initializeTxTrackingStore } from './initializeTxTrackingStore';\n\n/**\n * Creates the main Pulsar store for transaction tracking.\n *\n * This function configures a Zustand store enhanced with persistence. It combines the core transaction management\n * slice with a powerful orchestration logic that leverages chain-specific adapters to handle the entire\n * lifecycle of a transaction—from initiation and chain validation to execution and background status tracking.\n *\n * @template TR The type of the tracker identifier (e.g., a string enum).\n * @template T The specific transaction type, extending the base `Transaction`.\n * @template A The type of the key returned by the `actionFunction` (e.g., a transaction hash).\n *\n * @param config Configuration object for creating the store.\n * @param config.onSucceedCallbacks Optional async callback executed on transaction success.\n * @param config.adapters An array of adapters for different chains or transaction types.\n * @param options Configuration for the Zustand `persist` middleware.\n * @returns A fully configured Zustand store instance.\n */\nexport function createPulsarStore<TR, T extends Transaction<TR>, A>({\n onSucceedCallbacks,\n adapters,\n ...options\n}: {\n onSucceedCallbacks?: (tx: T) => Promise<void> | void;\n adapters: TxAdapter<TR, T, A>[];\n} & PersistOptions<ITxTrackingStore<TR, T, A>>) {\n return createStore<ITxTrackingStore<TR, T, A>>()(\n persist(\n (set, get) => ({\n // Initialize the base store slice with core state and actions\n ...initializeTxTrackingStore<TR, T, A>({ onSucceedCallbacks })(set, get),\n\n /**\n * Initializes trackers for all pending transactions upon store creation.\n * This is crucial for resuming tracking after a page refresh or session restoration.\n */\n initializeTransactionsPool: async () => {\n const pendingTxs = Object.values(get().transactionsPool).filter((tx) => tx.pending);\n\n // Concurrently initialize trackers for all pending transactions\n await Promise.all(\n pendingTxs.map((tx) => {\n const adapter = selectAdapterByKey({\n adapterKey: tx.adapter,\n adapters,\n });\n // Delegate tracker initialization to the appropriate adapter\n return adapter?.checkAndInitializeTrackerInStore({\n tx,\n ...get(),\n });\n }),\n );\n },\n\n /**\n * The primary function to orchestrate sending and tracking a new transaction.\n * It manages the entire lifecycle, from UI state updates and chain switching to\n * signing, submission, and background tracker initialization.\n */\n handleTransaction: async ({ defaultTracker, actionFunction, params }) => {\n const { desiredChainID, ...restParams } = params;\n const localTimestamp = dayjs().unix();\n\n // Step 1: Set initial state for immediate UI feedback (e.g., loading spinner).\n set({\n initialTx: {\n ...params,\n actionFunction,\n localTimestamp,\n isInitializing: true,\n },\n });\n\n const adapter = selectAdapterByKey({\n adapterKey: restParams.adapter,\n adapters,\n });\n\n // Centralized error handler for this transaction flow\n const handleTxError = (e: unknown) => {\n const errorMessage = e instanceof Error ? e.message : String(e);\n set((state) =>\n produce(state, (draft) => {\n if (draft.initialTx) {\n draft.initialTx.isInitializing = false;\n draft.initialTx.errorMessage = errorMessage;\n }\n }),\n );\n };\n\n if (!adapter) {\n const error = new Error('No adapter found for this transaction.');\n handleTxError(error);\n throw error; // Re-throw to allow the caller to handle it.\n }\n\n try {\n const { walletType, walletAddress } = adapter.getWalletInfo();\n\n // Step 2: Ensure the wallet is connected to the correct chain.\n await adapter.checkChainForTx(desiredChainID);\n\n // Step 3: Execute the provided action (e.g., signing and sending the transaction).\n const txKeyFromAction = await actionFunction();\n\n // If `txKeyFromAction` is undefined, it indicates the user cancelled the action.\n if (!txKeyFromAction) {\n set({ initialTx: undefined });\n return;\n }\n\n // Step 4: Determine the final tracker and txKey from the action's result.\n const { tracker: updatedTracker, txKey: finalTxKey } = adapter.checkTransactionsTracker(\n txKeyFromAction,\n walletType,\n );\n\n // Step 5: Construct the full transaction object for the pool.\n const newTx = {\n ...restParams,\n walletType,\n from: walletAddress,\n tracker: (updatedTracker || defaultTracker) as TR,\n chainId: desiredChainID,\n localTimestamp,\n txKey: finalTxKey,\n // For EVM, the hash is often the preliminary key from the action.\n hash: updatedTracker === 'ethereum' ? (txKeyFromAction as `0x${string}`) : undefined,\n pending: false, // will be set to true by addTxToPool\n isTrackedModalOpen: params.withTrackedModal,\n };\n\n // Step 6: Add the transaction to the pool.\n get().addTxToPool(newTx);\n\n // Step 7: Update the initial state to link it with the newly created transaction.\n set((state) =>\n produce(state, (draft) => {\n if (draft.initialTx) {\n draft.initialTx.isInitializing = false;\n draft.initialTx.lastTxKey = finalTxKey;\n }\n }),\n );\n\n // Step 8: Initialize the background tracker for the transaction.\n const tx = get().transactionsPool[finalTxKey];\n await adapter.checkAndInitializeTrackerInStore({ tx, ...get() });\n } catch (e) {\n handleTxError(e);\n throw e; // Re-throw for external handling if needed.\n }\n },\n }),\n {\n ...options, // Merges user-provided persistence options.\n },\n ),\n );\n}\n","/**\n * @file This file defines the core data structures and TypeScript types for the Pulsar transaction tracking engine.\n * It specifies the framework-agnostic models for transactions, their lifecycle statuses, and the interfaces for\n * the Zustand-based store and chain-specific adapters.\n */\n\nimport { StoreApi } from 'zustand';\n\nimport { IInitializeTxTrackingStore, TransactionPool } from './store/initializeTxTrackingStore';\n\n// =================================================================================================\n// 1. ZUSTAND UTILITY TYPES\n// =================================================================================================\n\n/**\n * A utility type for creating modular Zustand store slices, enabling composable state management.\n * @template T The state slice being defined.\n * @template S The full store state that includes the slice `T`.\n */\nexport type StoreSlice<T extends object, S extends object = T> = (\n set: StoreApi<S extends T ? S : S & T>['setState'],\n get: StoreApi<S extends T ? S : S & T>['getState'],\n) => T;\n\n// =================================================================================================\n// 2. ENUMS AND CORE TRANSACTION TYPES\n// =================================================================================================\n\n/**\n * Defines the supported blockchain adapters. Each adapter corresponds to a specific chain architecture.\n */\nexport enum TransactionAdapter {\n /** For Ethereum Virtual Machine (EVM) compatible chains like Ethereum, Polygon, etc. */\n EVM = 'evm',\n /** For the Solana blockchain. */\n SOLANA = 'solana',\n /** For the Starknet L2 network. */\n Starknet = 'starknet',\n}\n\n/**\n * Represents the terminal status of a transaction after it has been processed.\n */\nexport enum TransactionStatus {\n /** The transaction failed to execute due to an on-chain error or rejection. */\n Failed = 'Failed',\n /** The transaction was successfully mined and included in a block. */\n Success = 'Success',\n /** The transaction was replaced by another with the same nonce (e.g., a speed-up or cancel). */\n Replaced = 'Replaced',\n}\n\n/**\n * The fundamental structure for any transaction being tracked by Pulsar.\n * This serves as the base upon which chain-specific transaction types are built.\n * @template T The type of the tracker identifier (e.g., 'ethereum', 'gelato').\n */\nexport type BaseTransaction<T> = {\n /** The chain identifier (e.g., 1 for Ethereum Mainnet, 'SN_MAIN' for Starknet). */\n chainId: number | string;\n /**\n * User-facing description. Can be a single string for all states, or a tuple for specific states.\n * @example\n * // A single description for all states\n * description: 'Swap 1 ETH for 1,500 USDC'\n * // Specific descriptions for each state in order: [pending, success, error, replaced]\n * description: ['Swapping...', 'Swapped Successfully', 'Swap Failed', 'Swap Replaced']\n */\n description?: string | [string, string, string, string];\n /** The error message if the transaction failed. */\n errorMessage?: string;\n /** The on-chain timestamp (in seconds) when the transaction was finalized. */\n finishedTimestamp?: number;\n /** The sender's wallet address. */\n from: string;\n /** A flag indicating if the transaction is in a failed state. */\n isError?: boolean;\n /** A UI flag to control the visibility of a detailed tracking modal for this transaction. */\n isTrackedModalOpen?: boolean;\n /** The local timestamp (in seconds) when the transaction was initiated by the user. */\n localTimestamp: number;\n /** Any additional, custom data associated with the transaction. */\n payload?: object;\n /** A flag indicating if the transaction is still awaiting on-chain confirmation. */\n pending: boolean;\n /** The final on-chain status of the transaction. */\n status?: TransactionStatus;\n /**\n * User-facing title. Can be a single string for all states, or a tuple for specific states.\n * @example\n * // A single title for all states\n * title: 'ETH/USDC Swap'\n * // Specific titles for each state in order: [pending, success, error, replaced]\n * title: ['Processing Swap', 'Swap Complete', 'Swap Error', 'Swap Replaced']\n */\n title?: string | [string, string, string, string];\n /** The specific tracker responsible for monitoring this transaction's status. */\n tracker: T;\n /** The unique identifier for the transaction (e.g., EVM hash, Gelato task ID). */\n txKey: string;\n /** The application-specific type or category of the transaction (e.g., 'SWAP', 'APPROVE'). */\n type: string;\n /** The type of wallet used to sign the transaction (e.g., 'injected', 'walletConnect'). */\n walletType: string;\n};\n\n// =================================================================================================\n// 3. CHAIN-SPECIFIC TRANSACTION TYPES\n// =================================================================================================\n\n/**\n * Represents an EVM-specific transaction, extending the base properties with EVM fields.\n * @template T The type of the tracker identifier.\n */\nexport type EvmTransaction<T> = BaseTransaction<T> & {\n adapter: TransactionAdapter.EVM;\n /** The on-chain transaction hash, available after submission. */\n hash?: `0x${string}`;\n /** The data payload for the transaction, typically for smart contract interactions. */\n input?: `0x${string}`;\n /** The maximum fee per gas for an EIP-1559 transaction (in wei). */\n maxFeePerGas?: string;\n /** The maximum priority fee per gas for an EIP-1559 transaction (in wei). */\n maxPriorityFeePerGas?: string;\n /** The transaction nonce, a sequential number for the sender's account. */\n nonce?: number;\n /** The hash of a transaction that this one replaced. */\n replacedTxHash?: `0x${string}`;\n /** The recipient's address or contract address. */\n to?: `0x${string}`;\n /** The amount of native currency (in wei) being sent. */\n value?: string;\n};\n\n/**\n * Represents a Solana-specific transaction, extending the base properties.\n * @template T The type of the tracker identifier.\n */\nexport type SolanaTransaction<T> = BaseTransaction<T> & {\n adapter: TransactionAdapter.SOLANA;\n /** The transaction fee in lamports. */\n fee?: number;\n /** The instructions included in the transaction. */\n instructions?: unknown[];\n /** The recent blockhash used for the transaction. */\n recentBlockhash?: string;\n /** The slot in which the transaction was processed. */\n slot?: number;\n /** The number of confirmations received. `null` if the transaction is pending or unconfirmed. */\n confirmations?: number | null;\n /** The RPC URL used to submit and track this transaction. */\n rpcUrl?: string;\n};\n\n/**\n * Represents a Starknet-specific transaction, extending the base properties.\n * @template T The type of the tracker identifier.\n */\nexport type StarknetTransaction<T> = BaseTransaction<T> & {\n adapter: TransactionAdapter.Starknet;\n /** The actual fee paid for the transaction. */\n actualFee?: { amount: string; unit: string };\n /** The address of the contract being interacted with. */\n contractAddress?: string;\n /** The reason for transaction failure, if applicable. */\n revertReason?: string;\n};\n\n/** A union type representing any possible transaction structure that Pulsar can handle. */\nexport type Transaction<T> = EvmTransaction<T> | SolanaTransaction<T> | StarknetTransaction<T>;\n\n// =================================================================================================\n// 4. INITIAL TRANSACTION TYPES\n// =================================================================================================\n\n/**\n * Represents the parameters required to initiate a new transaction tracking flow.\n */\nexport type InitialTransactionParams<A> = {\n adapter: TransactionAdapter;\n /** The function that executes the on-chain action (e.g., sending a transaction) and returns a preliminary identifier like a hash. */\n actionFunction: (...args: any[]) => Promise<A | undefined>;\n /** A user-facing description for the transaction. Supports state-specific descriptions. */\n description?: string | [string, string, string, string];\n /** The target chain ID for the transaction. */\n desiredChainID: number | string;\n /** Any custom data to associate with the transaction. */\n payload?: object;\n /** A user-facing title for the transaction. Supports state-specific titles. */\n title?: string | [string, string, string, string];\n /** The application-specific type of the transaction. */\n type: string;\n /** If true, the detailed tracking modal will open automatically upon initiation. */\n withTrackedModal?: boolean;\n /** The RPC URL to use for the transaction. Required for Solana transactions. */\n rpcUrl?: string;\n};\n\n/**\n * Represents a transaction in its temporary, pre-submission state.\n * This is used for UI feedback while the transaction is being signed and sent.\n */\nexport type InitialTransaction<A> = InitialTransactionParams<A> & {\n /** An error message if the initialization fails (e.g., user rejects signature). */\n errorMessage?: string;\n /** A flag indicating if the transaction is being processed (e.g., waiting for signature). */\n isInitializing: boolean;\n /** The `txKey` of the on-chain transaction that this action produced, used for linking the states. */\n lastTxKey?: string;\n /** The local timestamp when the user initiated the action. */\n localTimestamp: number;\n};\n\n// =================================================================================================\n// 5. ADAPTER AND STORE INTERFACES\n// =================================================================================================\n\n/**\n * Defines the interface for a transaction adapter, which provides chain-specific logic and utilities.\n * @template TR The type of the tracker identifier (e.g., a string enum).\n * @template T The specific transaction type, extending `Transaction<TR>`.\n * @template A The type of the key returned by the `actionFunction` (e.g., a transaction hash).\n */\nexport type TxAdapter<TR, T extends Transaction<TR>, A> = {\n /** The unique key identifying this adapter. */\n key: TransactionAdapter;\n /** Returns information about the currently connected wallet. */\n getWalletInfo: () => {\n walletAddress: string;\n walletType: string;\n };\n /** Ensures the connected wallet is on the correct network for the transaction. Throws an error if the chain is mismatched. */\n checkChainForTx: (chainId: string | number) => Promise<void>;\n /** Determines the appropriate tracker and final `txKey` from the result of an action. */\n checkTransactionsTracker: (actionTxKey: A, walletType: string) => { txKey: string; tracker: TR };\n /** Selects and initializes the correct background tracker for a given transaction. */\n checkAndInitializeTrackerInStore: (\n params: { tx: T } & Pick<\n ITxTrackingStore<TR, T, A>,\n 'transactionsPool' | 'updateTxParams' | 'onSucceedCallbacks' | 'removeTxFromPool'\n >,\n ) => Promise<void>;\n /** Returns the base URL for the blockchain explorer for the current network. */\n getExplorerUrl: () => string | undefined;\n /** Optional: Fetches a name from a chain-specific name service (e.g., ENS). */\n getName?: (address: string) => Promise<string | null>;\n /** Optional: Fetches an avatar URL from a chain-specific name service. */\n getAvatar?: (name: string) => Promise<string | null>;\n /** Optional: Logic to cancel a pending EVM transaction. */\n cancelTxAction?: (tx: T) => Promise<string>;\n /** Optional: Logic to speed up a pending EVM transaction. */\n speedUpTxAction?: (tx: T) => Promise<string>;\n /** Optional: Logic to retry a failed transaction. */\n retryTxAction?: (\n params: {\n txKey: string;\n tx: InitialTransactionParams<A>;\n onClose: (txKey?: string) => void;\n } & Partial<Pick<ITxTrackingStore<TR, T, A>, 'handleTransaction'>>,\n ) => Promise<void>;\n /**\n * Optional: Constructs a full explorer URL for a specific transaction.\n * May require the full transaction pool to resolve details for replaced transactions.\n */\n getExplorerTxUrl?: (transactionsPool: TransactionPool<TR, T>, txKey: string, replacedTxHash?: string) => string;\n};\n\n/**\n * The complete interface for the Pulsar transaction tracking store.\n * @template TR The type of the tracker identifier.\n * @template T The transaction type.\n * @template A The return type of the `actionFunction`.\n */\nexport type ITxTrackingStore<TR, T extends Transaction<TR>, A> = IInitializeTxTrackingStore<TR, T, A> & {\n /**\n * The primary method for initiating and tracking a new transaction from start to finish.\n * It manages UI state, executes the on-chain action, and initiates background tracking.\n * @param params The parameters for handling the transaction.\n */\n handleTransaction: (params: {\n /** The async function to execute (e.g., a smart contract write call). Must return a unique key or undefined. */\n actionFunction: () => Promise<A | undefined>;\n /** The metadata for the transaction. */\n params: Omit<InitialTransactionParams<A>, 'actionFunction'>;\n /** The default tracker to use if it cannot be determined automatically. */\n defaultTracker?: TR;\n }) => Promise<void>;\n\n /**\n * Initializes trackers for all pending transactions in the pool.\n * This is essential for resuming tracking after a page reload.\n */\n initializeTransactionsPool: () => Promise<void>;\n};\n","/**\n * @file This file provides a utility for creating a type-safe, bounded Zustand hook from a vanilla store.\n * This pattern is recommended by the official Zustand documentation to ensure full type\n * safety when integrating vanilla stores with React.\n *\n * @see https://docs.pmnd.rs/zustand/guides/typescript#bounded-usestore-hook-for-vanilla-stores\n */\n\nimport { StoreApi, useStore } from 'zustand';\n\n/**\n * A utility type that infers the state shape from a Zustand `StoreApi`.\n * It extracts the return type of the `getState` method.\n * @template S - The type of the Zustand store (`StoreApi`).\n */\ntype ExtractState<S> = S extends { getState: () => infer T } ? T : never;\n\n/**\n * Creates a bounded `useStore` hook from a vanilla Zustand store.\n *\n * This function takes a vanilla Zustand store instance and returns a React hook\n * that is pre-bound to that store. This approach provides a cleaner API and\n * enhances type inference, eliminating the need to pass the store instance\n * on every use.\n *\n * The returned hook supports two signatures:\n * 1. `useBoundedStore()`: Selects the entire state.\n * 2. `useBoundedStore(selector)`: Selects a slice of the state, returning only what the selector function specifies.\n *\n * @template S - The type of the Zustand store (`StoreApi`).\n * @param {S} store - The vanilla Zustand store instance to bind the hook to.\n * @returns {function} A fully typed React hook for accessing the store's state.\n */\nexport const createBoundedUseStore = ((store) => (selector) => useStore(store, selector)) as <\n S extends StoreApi<unknown>,\n>(\n store: S,\n) => {\n // This implementation uses a Immediately Invoked Function Expression (IIFE)\n // trick combined with casting to achieve the desired overloaded function signature in a concise way.\n (): ExtractState<S>;\n <T>(selector: (state: ExtractState<S>) => T): T;\n};\n","/**\n * @file This file provides a generic utility for creating a polling mechanism to track\n * asynchronous tasks, such as API-based transaction status checks (e.g., for Gelato or Safe).\n */\n\nimport { Transaction } from '../types';\n\n/**\n * Defines the parameters for the fetcher function used within the polling tracker.\n * The fetcher is the core logic that performs the actual API call.\n * @template R - The expected type of the successful API response.\n * @template T - The type of the transaction object being tracked.\n */\ntype PollingFetcherParams<R, T> = {\n /** The transaction object being tracked. */\n tx: T;\n /** A callback to stop the polling mechanism, typically called on success or terminal failure. */\n stopPolling: (options?: { withoutRemoving?: boolean }) => void;\n /** Callback to be invoked when the fetcher determines the transaction has succeeded. */\n onSuccess: (response: R) => void;\n /** Callback to be invoked when the fetcher determines the transaction has failed. */\n onFailure: (response?: R) => void;\n /** Optional callback for each successful poll, useful for updating UI with intermediate states. */\n onIntervalTick?: (response: R) => void;\n /** Optional callback for when a transaction is replaced (e.g., speed-up). */\n onReplaced?: (response: R) => void;\n};\n\n/**\n * Defines the configuration object for the `initializePollingTracker` function.\n * @template R - The expected type of the successful API response.\n * @template T - The type of the transaction object.\n * @template TR - The type of the tracker identifier.\n */\nexport type PollingTrackerConfig<R, T, TR> = {\n /** The transaction object to be tracked. It must include `txKey` and `pending` status. */\n tx: T & Pick<Transaction<TR>, 'txKey' | 'pending'>;\n /** The function that performs the data fetching (e.g., an API call) on each interval. */\n fetcher: (params: PollingFetcherParams<R, T>) => Promise<void>;\n /** Callback to be invoked when the transaction successfully completes. */\n onSuccess: (response: R) => void;\n /** Callback to be invoked when the transaction fails. */\n onFailure: (response?: R) => void;\n /** Optional callback executed once when the tracker is initialized. */\n onInitialize?: () => void;\n /** Optional callback for each successful poll. */\n onIntervalTick?: (response: R) => void;\n /** Optional callback for when a transaction is replaced. */\n onReplaced?: (response: R) => void;\n /** Optional function to remove the transaction from the main pool, typically after polling stops. */\n removeTxFromPool?: (txKey: string) => void;\n /** The interval (in milliseconds) between polling attempts. Defaults to 5000ms. */\n pollingInterval?: number;\n /** The number of consecutive failed fetches before stopping the tracker. Defaults to 10. */\n maxRetries?: number;\n};\n\nconst DEFAULT_POLLING_INTERVAL = 5000;\nconst DEFAULT_MAX_RETRIES = 10;\n\n/**\n * Initializes a generic polling tracker that repeatedly calls a fetcher function\n * to monitor the status of an asynchronous task.\n *\n * This function handles the lifecycle of polling, including starting, stopping,\n * and automatic termination after a certain number of failed attempts.\n *\n * @template R The expected type of the API response.\n * @template T The type of the transaction object.\n * @template TR The type of the tracker identifier.\n * @param {PollingTrackerConfig<R, T, TR>} config - The configuration for the tracker.\n */\nexport function initializePollingTracker<R, T, TR>(config: PollingTrackerConfig<R, T, TR>): void {\n const {\n tx,\n fetcher,\n onInitialize,\n onSuccess,\n onFailure,\n onIntervalTick,\n onReplaced,\n removeTxFromPool,\n pollingInterval = DEFAULT_POLLING_INTERVAL,\n maxRetries = DEFAULT_MAX_RETRIES,\n } = config;\n\n // 1. Early exit if the transaction is no longer pending\n if (!tx.pending) {\n return;\n }\n\n // Execute the initialization callback if provided\n onInitialize?.();\n\n let retriesLeft = maxRetries;\n let isPolling = true;\n\n /**\n * Stops the polling interval and optionally removes the transaction from the pool.\n * @param {object} [options] - Options for stopping the tracker.\n * @param {boolean} [options.withoutRemoving=false] - If true, the tx will not be removed from the pool.\n */\n const stopPolling = (options?: { withoutRemoving?: boolean }) => {\n if (!isPolling) return;\n isPolling = false;\n // The interval is cleared in the finally block of the polling loop\n if (removeTxFromPool && !options?.withoutRemoving) {\n removeTxFromPool(tx.txKey);\n }\n };\n\n const pollingLoop = async () => {\n while (isPolling && retriesLeft > 0) {\n try {\n await new Promise((resolve) => setTimeout(resolve, pollingInterval));\n if (!isPolling) break;\n\n // The fetcher's responsibility is to call onSuccess, onFailure, etc., which in turn call stopPolling.\n await fetcher({\n tx,\n stopPolling,\n onSuccess,\n onFailure,\n onIntervalTick,\n onReplaced,\n });\n } catch (error) {\n console.error(`Polling fetcher for txKey ${tx.txKey} threw an error:`, error);\n retriesLeft--;\n }\n }\n\n if (retriesLeft <= 0) {\n console.warn(`Polling for txKey ${tx.txKey} stopped after reaching the maximum number of retries.`);\n onFailure();\n stopPolling();\n }\n };\n\n // Start the asynchronous polling loop\n pollingLoop();\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tuwaio/pulsar-core",
3
- "version": "0.0.6",
3
+ "version": "0.1.1",
4
4
  "private": false,
5
5
  "author": "Oleksandr Tkach",
6
6
  "license": "Apache-2.0",