@tuwaio/pulsar-core 1.0.0-fix-adapter-alpha.2.60bbca9 → 1.0.0-fix-adapter-alpha.3.9b2850a
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.d.mts +96 -22
- package/dist/index.d.ts +96 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -26,7 +26,7 @@ declare enum TransactionAdapter {
|
|
|
26
26
|
Starknet = "starknet"
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
|
-
* Enum representing the different tracking strategies available for
|
|
29
|
+
* Enum representing the different tracking strategies available for transactions.
|
|
30
30
|
* Each tracker corresponds to a specific method of monitoring a transaction's lifecycle.
|
|
31
31
|
*/
|
|
32
32
|
declare enum TransactionTracker {
|
|
@@ -54,18 +54,20 @@ declare enum TransactionStatus {
|
|
|
54
54
|
* Defines the shape of the identifier for a Gelato transaction task.
|
|
55
55
|
*/
|
|
56
56
|
type GelatoTxKey = {
|
|
57
|
+
/** The unique identifier assigned by the Gelato relay service. */
|
|
57
58
|
taskId: string;
|
|
58
59
|
};
|
|
59
60
|
/**
|
|
60
61
|
* A union type representing the unique identifier returned by an `actionFunction`
|
|
61
62
|
* after a transaction is submitted to the network or a relay service.
|
|
62
63
|
*
|
|
63
|
-
* This key is crucial for the
|
|
64
|
+
* This key is crucial for the adapter to determine which tracker should
|
|
64
65
|
* monitor the transaction.
|
|
65
66
|
*
|
|
66
67
|
* It can be one of the following:
|
|
67
68
|
* - A standard `0x...` transaction hash (`Hex`).
|
|
68
69
|
* - A structured object from a relay service like Gelato (`GelatoTxKey`).
|
|
70
|
+
* - A Solana transaction signature (string).
|
|
69
71
|
*/
|
|
70
72
|
type ActionTxKey = `0x${string}` | GelatoTxKey | string;
|
|
71
73
|
/**
|
|
@@ -113,7 +115,7 @@ type BaseTransaction = {
|
|
|
113
115
|
title?: string | [string, string, string, string];
|
|
114
116
|
/** The specific tracker responsible for monitoring this transaction's status. */
|
|
115
117
|
tracker: TransactionTracker;
|
|
116
|
-
/** The unique identifier for the transaction (e.g., EVM hash, Gelato task ID). */
|
|
118
|
+
/** The unique identifier for the transaction (e.g., EVM hash, Solana signature, or Gelato task ID). */
|
|
117
119
|
txKey: string;
|
|
118
120
|
/** The application-specific type or category of the transaction (e.g., 'SWAP', 'APPROVE'). */
|
|
119
121
|
type: string;
|
|
@@ -124,6 +126,7 @@ type BaseTransaction = {
|
|
|
124
126
|
* Represents an EVM-specific transaction, extending the base properties with EVM fields.
|
|
125
127
|
*/
|
|
126
128
|
type EvmTransaction = BaseTransaction & {
|
|
129
|
+
/** The adapter type for EVM transactions. */
|
|
127
130
|
adapter: TransactionAdapter.EVM;
|
|
128
131
|
/** The on-chain transaction hash, available after submission. */
|
|
129
132
|
hash?: `0x${string}`;
|
|
@@ -146,6 +149,7 @@ type EvmTransaction = BaseTransaction & {
|
|
|
146
149
|
* Represents a Solana-specific transaction, extending the base properties.
|
|
147
150
|
*/
|
|
148
151
|
type SolanaTransaction = BaseTransaction & {
|
|
152
|
+
/** The adapter type for Solana transactions. */
|
|
149
153
|
adapter: TransactionAdapter.SOLANA;
|
|
150
154
|
/** The transaction fee in lamports. */
|
|
151
155
|
fee?: number;
|
|
@@ -155,7 +159,7 @@ type SolanaTransaction = BaseTransaction & {
|
|
|
155
159
|
recentBlockhash?: string;
|
|
156
160
|
/** The slot in which the transaction was processed. */
|
|
157
161
|
slot?: number;
|
|
158
|
-
/** The number of confirmations received.
|
|
162
|
+
/** The number of confirmations received. A string value indicates a confirmed transaction, while `null` means it's pending. */
|
|
159
163
|
confirmations?: number | string | null;
|
|
160
164
|
/** The RPC URL used to submit and track this transaction. */
|
|
161
165
|
rpcUrl?: string;
|
|
@@ -164,6 +168,7 @@ type SolanaTransaction = BaseTransaction & {
|
|
|
164
168
|
* Represents a Starknet-specific transaction, extending the base properties.
|
|
165
169
|
*/
|
|
166
170
|
type StarknetTransaction = BaseTransaction & {
|
|
171
|
+
/** The adapter type for Starknet transactions. */
|
|
167
172
|
adapter: TransactionAdapter.Starknet;
|
|
168
173
|
/** The actual fee paid for the transaction. */
|
|
169
174
|
actualFee?: {
|
|
@@ -179,6 +184,7 @@ type Transaction = EvmTransaction | SolanaTransaction | StarknetTransaction;
|
|
|
179
184
|
* Represents the parameters required to initiate a new transaction tracking flow.
|
|
180
185
|
*/
|
|
181
186
|
type InitialTransactionParams = {
|
|
187
|
+
/** The specific blockchain adapter for this transaction. */
|
|
182
188
|
adapter: TransactionAdapter;
|
|
183
189
|
/** The function that executes the on-chain action (e.g., sending a transaction) and returns a preliminary identifier like a hash. */
|
|
184
190
|
actionFunction: (...args: any[]) => Promise<ActionTxKey | undefined>;
|
|
@@ -211,11 +217,20 @@ type InitialTransaction = InitialTransactionParams & {
|
|
|
211
217
|
/** The local timestamp when the user initiated the action. */
|
|
212
218
|
localTimestamp: number;
|
|
213
219
|
};
|
|
220
|
+
/**
|
|
221
|
+
* Defines a callback function to be executed upon a successful transaction.
|
|
222
|
+
* @template T The specific transaction type, extending `Transaction`.
|
|
223
|
+
*/
|
|
214
224
|
type OnSuccessCallback<T extends Transaction> = {
|
|
215
225
|
/** Callback to execute when the transaction is successfully submitted. */
|
|
216
226
|
onSuccessCallback?: (tx: T) => Promise<void> | void;
|
|
217
227
|
};
|
|
228
|
+
/**
|
|
229
|
+
* The configuration object containing one or more transaction adapters.
|
|
230
|
+
* @template T The specific transaction type.
|
|
231
|
+
*/
|
|
218
232
|
type Adapter<T extends Transaction> = {
|
|
233
|
+
/** A single `TxAdapter` instance or an array of them. */
|
|
219
234
|
adapter: TxAdapter<T> | TxAdapter<T>[];
|
|
220
235
|
};
|
|
221
236
|
/**
|
|
@@ -227,31 +242,69 @@ type TxAdapter<T extends Transaction> = {
|
|
|
227
242
|
key: TransactionAdapter;
|
|
228
243
|
/** Returns information about the currently connected wallet. */
|
|
229
244
|
getWalletInfo: () => {
|
|
245
|
+
/** The currently connected wallet address. */
|
|
230
246
|
walletAddress: string;
|
|
247
|
+
/** The type of the wallet (e.g., 'metamask', 'phantom'). */
|
|
231
248
|
walletType: string;
|
|
232
249
|
};
|
|
233
|
-
/**
|
|
250
|
+
/**
|
|
251
|
+
* Ensures the connected wallet is on the correct network for the transaction.
|
|
252
|
+
*
|
|
253
|
+
* This method should throw an error if the chain is mismatched.
|
|
254
|
+
* @param chainId The desired chain ID for the transaction.
|
|
255
|
+
*/
|
|
234
256
|
checkChainForTx: (chainId: string | number) => Promise<void>;
|
|
235
|
-
/**
|
|
257
|
+
/**
|
|
258
|
+
* Determines the appropriate tracker and final `txKey` from the result of an action.
|
|
259
|
+
* @param actionTxKey The preliminary key returned after an action function is executed.
|
|
260
|
+
* @param walletType The type of wallet used for the transaction.
|
|
261
|
+
* @returns An object containing the final `txKey` and the `TransactionTracker` to be used.
|
|
262
|
+
*/
|
|
236
263
|
checkTransactionsTracker: (actionTxKey: ActionTxKey, walletType: string) => {
|
|
237
264
|
txKey: string;
|
|
238
265
|
tracker: TransactionTracker;
|
|
239
266
|
};
|
|
240
|
-
/**
|
|
267
|
+
/**
|
|
268
|
+
* Selects and initializes the correct background tracker for a given transaction.
|
|
269
|
+
* @param params The parameters for initializing the tracker, including the transaction and store callbacks.
|
|
270
|
+
*/
|
|
241
271
|
checkAndInitializeTrackerInStore: (params: {
|
|
242
272
|
tx: T;
|
|
243
273
|
} & OnSuccessCallback<T> & Pick<ITxTrackingStore<T>, 'updateTxParams' | 'removeTxFromPool' | 'transactionsPool'>) => Promise<void> | void;
|
|
244
|
-
/**
|
|
274
|
+
/**
|
|
275
|
+
* Returns the base URL for the blockchain explorer for the current network.
|
|
276
|
+
* @param url Optional URL to override the default explorer URL.
|
|
277
|
+
*/
|
|
245
278
|
getExplorerUrl: (url?: string) => string | undefined;
|
|
246
|
-
/**
|
|
279
|
+
/**
|
|
280
|
+
* Optional: Fetches a name from a chain-specific name service (e.g., ENS).
|
|
281
|
+
* @param address The address to resolve the name for.
|
|
282
|
+
*/
|
|
247
283
|
getName?: (address: string) => Promise<string | null>;
|
|
248
|
-
/**
|
|
284
|
+
/**
|
|
285
|
+
* Optional: Fetches an avatar URL from a chain-specific name service.
|
|
286
|
+
* @param name The name to resolve the avatar for.
|
|
287
|
+
*/
|
|
249
288
|
getAvatar?: (name: string) => Promise<string | null>;
|
|
250
|
-
/**
|
|
289
|
+
/**
|
|
290
|
+
* Optional: Logic to cancel a pending EVM transaction.
|
|
291
|
+
* @param tx The transaction to cancel.
|
|
292
|
+
* @returns The new transaction hash for the cancellation.
|
|
293
|
+
*/
|
|
251
294
|
cancelTxAction?: (tx: T) => Promise<string>;
|
|
252
|
-
/**
|
|
295
|
+
/**
|
|
296
|
+
* Optional: Logic to speed up a pending EVM transaction.
|
|
297
|
+
* @param tx The transaction to speed up.
|
|
298
|
+
* @returns The new transaction hash for the sped-up transaction.
|
|
299
|
+
*/
|
|
253
300
|
speedUpTxAction?: (tx: T) => Promise<string>;
|
|
254
|
-
/**
|
|
301
|
+
/**
|
|
302
|
+
* Optional: Logic to retry a failed transaction.
|
|
303
|
+
* @param params The parameters for retrying the transaction.
|
|
304
|
+
* @param params.txKey The unique key of the transaction to retry.
|
|
305
|
+
* @param params.tx The initial parameters of the transaction.
|
|
306
|
+
* @param params.onClose Callback function to close the tracking modal.
|
|
307
|
+
*/
|
|
255
308
|
retryTxAction?: (params: {
|
|
256
309
|
txKey: string;
|
|
257
310
|
tx: InitialTransactionParams;
|
|
@@ -260,6 +313,8 @@ type TxAdapter<T extends Transaction> = {
|
|
|
260
313
|
/**
|
|
261
314
|
* Optional: Constructs a full explorer URL for a specific transaction.
|
|
262
315
|
* May require the full transaction pool to resolve details for replaced transactions.
|
|
316
|
+
* @param tx The transaction object.
|
|
317
|
+
* @returns The full URL to the transaction on the explorer.
|
|
263
318
|
*/
|
|
264
319
|
getExplorerTxUrl?: (tx: T) => string;
|
|
265
320
|
};
|
|
@@ -286,15 +341,31 @@ interface IInitializeTxTrackingStore<T extends Transaction> {
|
|
|
286
341
|
lastAddedTxKey?: string;
|
|
287
342
|
/** The state for a transaction being initiated, used for UI feedback before it's submitted to the chain. */
|
|
288
343
|
initialTx?: InitialTransaction;
|
|
289
|
-
/**
|
|
344
|
+
/**
|
|
345
|
+
* Adds a new transaction to the tracking pool and marks it as pending.
|
|
346
|
+
* @param tx The transaction object to add.
|
|
347
|
+
*/
|
|
290
348
|
addTxToPool: (tx: T) => void;
|
|
291
|
-
/**
|
|
349
|
+
/**
|
|
350
|
+
* Updates one or more properties of an existing transaction in the pool.
|
|
351
|
+
* @param txKey The key of the transaction to update.
|
|
352
|
+
* @param fields The partial object containing the fields to update.
|
|
353
|
+
*/
|
|
292
354
|
updateTxParams: (txKey: string, fields: UpdatableTransactionFields) => void;
|
|
293
|
-
/**
|
|
355
|
+
/**
|
|
356
|
+
* Removes a transaction from the tracking pool by its key.
|
|
357
|
+
* @param txKey The key of the transaction to remove.
|
|
358
|
+
*/
|
|
294
359
|
removeTxFromPool: (txKey: string) => void;
|
|
295
|
-
/**
|
|
360
|
+
/**
|
|
361
|
+
* Closes the tracking modal for a transaction and clears any initial transaction state.
|
|
362
|
+
* @param txKey The optional key of the transaction modal to close.
|
|
363
|
+
*/
|
|
296
364
|
closeTxTrackedModal: (txKey?: string) => void;
|
|
297
|
-
/**
|
|
365
|
+
/**
|
|
366
|
+
* A selector function to retrieve the key of the last transaction added to the pool.
|
|
367
|
+
* @returns The key of the last added transaction, or undefined if none exists.
|
|
368
|
+
*/
|
|
298
369
|
getLastTxKey: () => string | undefined;
|
|
299
370
|
}
|
|
300
371
|
/**
|
|
@@ -302,23 +373,26 @@ interface IInitializeTxTrackingStore<T extends Transaction> {
|
|
|
302
373
|
* @template T The transaction type.
|
|
303
374
|
*/
|
|
304
375
|
type ITxTrackingStore<T extends Transaction> = IInitializeTxTrackingStore<T> & {
|
|
376
|
+
/** A getter function that returns the configured transaction adapter(s). */
|
|
305
377
|
getAdapter: () => TxAdapter<T> | TxAdapter<T>[];
|
|
306
378
|
/**
|
|
307
379
|
* The primary method for initiating and tracking a new transaction from start to finish.
|
|
308
380
|
* It manages UI state, executes the on-chain action, and initiates background tracking.
|
|
381
|
+
*
|
|
309
382
|
* @param params The parameters for handling the transaction.
|
|
383
|
+
* @param params.actionFunction The async function to execute (e.g., a smart contract write call). Must return a unique key or undefined.
|
|
384
|
+
* @param params.params The metadata for the transaction.
|
|
385
|
+
* @param params.defaultTracker The default tracker to use if it cannot be determined automatically.
|
|
386
|
+
* @param params.onSuccessCallback Callback to execute when the transaction is successfully submitted.
|
|
310
387
|
*/
|
|
311
388
|
handleTransaction: (params: {
|
|
312
|
-
/** The async function to execute (e.g., a smart contract write call). Must return a unique key or undefined. */
|
|
313
389
|
actionFunction: () => Promise<ActionTxKey | undefined>;
|
|
314
|
-
/** The metadata for the transaction. */
|
|
315
390
|
params: Omit<InitialTransactionParams, 'actionFunction'>;
|
|
316
|
-
/** The default tracker to use if it cannot be determined automatically. */
|
|
317
391
|
defaultTracker?: TransactionTracker;
|
|
318
392
|
} & OnSuccessCallback<T>) => Promise<void>;
|
|
319
393
|
/**
|
|
320
394
|
* Initializes trackers for all pending transactions in the pool.
|
|
321
|
-
* This is essential for resuming tracking after a page reload.
|
|
395
|
+
* This is essential for resuming tracking after a page reload or application restart.
|
|
322
396
|
*/
|
|
323
397
|
initializeTransactionsPool: () => Promise<void>;
|
|
324
398
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ declare enum TransactionAdapter {
|
|
|
26
26
|
Starknet = "starknet"
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
|
-
* Enum representing the different tracking strategies available for
|
|
29
|
+
* Enum representing the different tracking strategies available for transactions.
|
|
30
30
|
* Each tracker corresponds to a specific method of monitoring a transaction's lifecycle.
|
|
31
31
|
*/
|
|
32
32
|
declare enum TransactionTracker {
|
|
@@ -54,18 +54,20 @@ declare enum TransactionStatus {
|
|
|
54
54
|
* Defines the shape of the identifier for a Gelato transaction task.
|
|
55
55
|
*/
|
|
56
56
|
type GelatoTxKey = {
|
|
57
|
+
/** The unique identifier assigned by the Gelato relay service. */
|
|
57
58
|
taskId: string;
|
|
58
59
|
};
|
|
59
60
|
/**
|
|
60
61
|
* A union type representing the unique identifier returned by an `actionFunction`
|
|
61
62
|
* after a transaction is submitted to the network or a relay service.
|
|
62
63
|
*
|
|
63
|
-
* This key is crucial for the
|
|
64
|
+
* This key is crucial for the adapter to determine which tracker should
|
|
64
65
|
* monitor the transaction.
|
|
65
66
|
*
|
|
66
67
|
* It can be one of the following:
|
|
67
68
|
* - A standard `0x...` transaction hash (`Hex`).
|
|
68
69
|
* - A structured object from a relay service like Gelato (`GelatoTxKey`).
|
|
70
|
+
* - A Solana transaction signature (string).
|
|
69
71
|
*/
|
|
70
72
|
type ActionTxKey = `0x${string}` | GelatoTxKey | string;
|
|
71
73
|
/**
|
|
@@ -113,7 +115,7 @@ type BaseTransaction = {
|
|
|
113
115
|
title?: string | [string, string, string, string];
|
|
114
116
|
/** The specific tracker responsible for monitoring this transaction's status. */
|
|
115
117
|
tracker: TransactionTracker;
|
|
116
|
-
/** The unique identifier for the transaction (e.g., EVM hash, Gelato task ID). */
|
|
118
|
+
/** The unique identifier for the transaction (e.g., EVM hash, Solana signature, or Gelato task ID). */
|
|
117
119
|
txKey: string;
|
|
118
120
|
/** The application-specific type or category of the transaction (e.g., 'SWAP', 'APPROVE'). */
|
|
119
121
|
type: string;
|
|
@@ -124,6 +126,7 @@ type BaseTransaction = {
|
|
|
124
126
|
* Represents an EVM-specific transaction, extending the base properties with EVM fields.
|
|
125
127
|
*/
|
|
126
128
|
type EvmTransaction = BaseTransaction & {
|
|
129
|
+
/** The adapter type for EVM transactions. */
|
|
127
130
|
adapter: TransactionAdapter.EVM;
|
|
128
131
|
/** The on-chain transaction hash, available after submission. */
|
|
129
132
|
hash?: `0x${string}`;
|
|
@@ -146,6 +149,7 @@ type EvmTransaction = BaseTransaction & {
|
|
|
146
149
|
* Represents a Solana-specific transaction, extending the base properties.
|
|
147
150
|
*/
|
|
148
151
|
type SolanaTransaction = BaseTransaction & {
|
|
152
|
+
/** The adapter type for Solana transactions. */
|
|
149
153
|
adapter: TransactionAdapter.SOLANA;
|
|
150
154
|
/** The transaction fee in lamports. */
|
|
151
155
|
fee?: number;
|
|
@@ -155,7 +159,7 @@ type SolanaTransaction = BaseTransaction & {
|
|
|
155
159
|
recentBlockhash?: string;
|
|
156
160
|
/** The slot in which the transaction was processed. */
|
|
157
161
|
slot?: number;
|
|
158
|
-
/** The number of confirmations received.
|
|
162
|
+
/** The number of confirmations received. A string value indicates a confirmed transaction, while `null` means it's pending. */
|
|
159
163
|
confirmations?: number | string | null;
|
|
160
164
|
/** The RPC URL used to submit and track this transaction. */
|
|
161
165
|
rpcUrl?: string;
|
|
@@ -164,6 +168,7 @@ type SolanaTransaction = BaseTransaction & {
|
|
|
164
168
|
* Represents a Starknet-specific transaction, extending the base properties.
|
|
165
169
|
*/
|
|
166
170
|
type StarknetTransaction = BaseTransaction & {
|
|
171
|
+
/** The adapter type for Starknet transactions. */
|
|
167
172
|
adapter: TransactionAdapter.Starknet;
|
|
168
173
|
/** The actual fee paid for the transaction. */
|
|
169
174
|
actualFee?: {
|
|
@@ -179,6 +184,7 @@ type Transaction = EvmTransaction | SolanaTransaction | StarknetTransaction;
|
|
|
179
184
|
* Represents the parameters required to initiate a new transaction tracking flow.
|
|
180
185
|
*/
|
|
181
186
|
type InitialTransactionParams = {
|
|
187
|
+
/** The specific blockchain adapter for this transaction. */
|
|
182
188
|
adapter: TransactionAdapter;
|
|
183
189
|
/** The function that executes the on-chain action (e.g., sending a transaction) and returns a preliminary identifier like a hash. */
|
|
184
190
|
actionFunction: (...args: any[]) => Promise<ActionTxKey | undefined>;
|
|
@@ -211,11 +217,20 @@ type InitialTransaction = InitialTransactionParams & {
|
|
|
211
217
|
/** The local timestamp when the user initiated the action. */
|
|
212
218
|
localTimestamp: number;
|
|
213
219
|
};
|
|
220
|
+
/**
|
|
221
|
+
* Defines a callback function to be executed upon a successful transaction.
|
|
222
|
+
* @template T The specific transaction type, extending `Transaction`.
|
|
223
|
+
*/
|
|
214
224
|
type OnSuccessCallback<T extends Transaction> = {
|
|
215
225
|
/** Callback to execute when the transaction is successfully submitted. */
|
|
216
226
|
onSuccessCallback?: (tx: T) => Promise<void> | void;
|
|
217
227
|
};
|
|
228
|
+
/**
|
|
229
|
+
* The configuration object containing one or more transaction adapters.
|
|
230
|
+
* @template T The specific transaction type.
|
|
231
|
+
*/
|
|
218
232
|
type Adapter<T extends Transaction> = {
|
|
233
|
+
/** A single `TxAdapter` instance or an array of them. */
|
|
219
234
|
adapter: TxAdapter<T> | TxAdapter<T>[];
|
|
220
235
|
};
|
|
221
236
|
/**
|
|
@@ -227,31 +242,69 @@ type TxAdapter<T extends Transaction> = {
|
|
|
227
242
|
key: TransactionAdapter;
|
|
228
243
|
/** Returns information about the currently connected wallet. */
|
|
229
244
|
getWalletInfo: () => {
|
|
245
|
+
/** The currently connected wallet address. */
|
|
230
246
|
walletAddress: string;
|
|
247
|
+
/** The type of the wallet (e.g., 'metamask', 'phantom'). */
|
|
231
248
|
walletType: string;
|
|
232
249
|
};
|
|
233
|
-
/**
|
|
250
|
+
/**
|
|
251
|
+
* Ensures the connected wallet is on the correct network for the transaction.
|
|
252
|
+
*
|
|
253
|
+
* This method should throw an error if the chain is mismatched.
|
|
254
|
+
* @param chainId The desired chain ID for the transaction.
|
|
255
|
+
*/
|
|
234
256
|
checkChainForTx: (chainId: string | number) => Promise<void>;
|
|
235
|
-
/**
|
|
257
|
+
/**
|
|
258
|
+
* Determines the appropriate tracker and final `txKey` from the result of an action.
|
|
259
|
+
* @param actionTxKey The preliminary key returned after an action function is executed.
|
|
260
|
+
* @param walletType The type of wallet used for the transaction.
|
|
261
|
+
* @returns An object containing the final `txKey` and the `TransactionTracker` to be used.
|
|
262
|
+
*/
|
|
236
263
|
checkTransactionsTracker: (actionTxKey: ActionTxKey, walletType: string) => {
|
|
237
264
|
txKey: string;
|
|
238
265
|
tracker: TransactionTracker;
|
|
239
266
|
};
|
|
240
|
-
/**
|
|
267
|
+
/**
|
|
268
|
+
* Selects and initializes the correct background tracker for a given transaction.
|
|
269
|
+
* @param params The parameters for initializing the tracker, including the transaction and store callbacks.
|
|
270
|
+
*/
|
|
241
271
|
checkAndInitializeTrackerInStore: (params: {
|
|
242
272
|
tx: T;
|
|
243
273
|
} & OnSuccessCallback<T> & Pick<ITxTrackingStore<T>, 'updateTxParams' | 'removeTxFromPool' | 'transactionsPool'>) => Promise<void> | void;
|
|
244
|
-
/**
|
|
274
|
+
/**
|
|
275
|
+
* Returns the base URL for the blockchain explorer for the current network.
|
|
276
|
+
* @param url Optional URL to override the default explorer URL.
|
|
277
|
+
*/
|
|
245
278
|
getExplorerUrl: (url?: string) => string | undefined;
|
|
246
|
-
/**
|
|
279
|
+
/**
|
|
280
|
+
* Optional: Fetches a name from a chain-specific name service (e.g., ENS).
|
|
281
|
+
* @param address The address to resolve the name for.
|
|
282
|
+
*/
|
|
247
283
|
getName?: (address: string) => Promise<string | null>;
|
|
248
|
-
/**
|
|
284
|
+
/**
|
|
285
|
+
* Optional: Fetches an avatar URL from a chain-specific name service.
|
|
286
|
+
* @param name The name to resolve the avatar for.
|
|
287
|
+
*/
|
|
249
288
|
getAvatar?: (name: string) => Promise<string | null>;
|
|
250
|
-
/**
|
|
289
|
+
/**
|
|
290
|
+
* Optional: Logic to cancel a pending EVM transaction.
|
|
291
|
+
* @param tx The transaction to cancel.
|
|
292
|
+
* @returns The new transaction hash for the cancellation.
|
|
293
|
+
*/
|
|
251
294
|
cancelTxAction?: (tx: T) => Promise<string>;
|
|
252
|
-
/**
|
|
295
|
+
/**
|
|
296
|
+
* Optional: Logic to speed up a pending EVM transaction.
|
|
297
|
+
* @param tx The transaction to speed up.
|
|
298
|
+
* @returns The new transaction hash for the sped-up transaction.
|
|
299
|
+
*/
|
|
253
300
|
speedUpTxAction?: (tx: T) => Promise<string>;
|
|
254
|
-
/**
|
|
301
|
+
/**
|
|
302
|
+
* Optional: Logic to retry a failed transaction.
|
|
303
|
+
* @param params The parameters for retrying the transaction.
|
|
304
|
+
* @param params.txKey The unique key of the transaction to retry.
|
|
305
|
+
* @param params.tx The initial parameters of the transaction.
|
|
306
|
+
* @param params.onClose Callback function to close the tracking modal.
|
|
307
|
+
*/
|
|
255
308
|
retryTxAction?: (params: {
|
|
256
309
|
txKey: string;
|
|
257
310
|
tx: InitialTransactionParams;
|
|
@@ -260,6 +313,8 @@ type TxAdapter<T extends Transaction> = {
|
|
|
260
313
|
/**
|
|
261
314
|
* Optional: Constructs a full explorer URL for a specific transaction.
|
|
262
315
|
* May require the full transaction pool to resolve details for replaced transactions.
|
|
316
|
+
* @param tx The transaction object.
|
|
317
|
+
* @returns The full URL to the transaction on the explorer.
|
|
263
318
|
*/
|
|
264
319
|
getExplorerTxUrl?: (tx: T) => string;
|
|
265
320
|
};
|
|
@@ -286,15 +341,31 @@ interface IInitializeTxTrackingStore<T extends Transaction> {
|
|
|
286
341
|
lastAddedTxKey?: string;
|
|
287
342
|
/** The state for a transaction being initiated, used for UI feedback before it's submitted to the chain. */
|
|
288
343
|
initialTx?: InitialTransaction;
|
|
289
|
-
/**
|
|
344
|
+
/**
|
|
345
|
+
* Adds a new transaction to the tracking pool and marks it as pending.
|
|
346
|
+
* @param tx The transaction object to add.
|
|
347
|
+
*/
|
|
290
348
|
addTxToPool: (tx: T) => void;
|
|
291
|
-
/**
|
|
349
|
+
/**
|
|
350
|
+
* Updates one or more properties of an existing transaction in the pool.
|
|
351
|
+
* @param txKey The key of the transaction to update.
|
|
352
|
+
* @param fields The partial object containing the fields to update.
|
|
353
|
+
*/
|
|
292
354
|
updateTxParams: (txKey: string, fields: UpdatableTransactionFields) => void;
|
|
293
|
-
/**
|
|
355
|
+
/**
|
|
356
|
+
* Removes a transaction from the tracking pool by its key.
|
|
357
|
+
* @param txKey The key of the transaction to remove.
|
|
358
|
+
*/
|
|
294
359
|
removeTxFromPool: (txKey: string) => void;
|
|
295
|
-
/**
|
|
360
|
+
/**
|
|
361
|
+
* Closes the tracking modal for a transaction and clears any initial transaction state.
|
|
362
|
+
* @param txKey The optional key of the transaction modal to close.
|
|
363
|
+
*/
|
|
296
364
|
closeTxTrackedModal: (txKey?: string) => void;
|
|
297
|
-
/**
|
|
365
|
+
/**
|
|
366
|
+
* A selector function to retrieve the key of the last transaction added to the pool.
|
|
367
|
+
* @returns The key of the last added transaction, or undefined if none exists.
|
|
368
|
+
*/
|
|
298
369
|
getLastTxKey: () => string | undefined;
|
|
299
370
|
}
|
|
300
371
|
/**
|
|
@@ -302,23 +373,26 @@ interface IInitializeTxTrackingStore<T extends Transaction> {
|
|
|
302
373
|
* @template T The transaction type.
|
|
303
374
|
*/
|
|
304
375
|
type ITxTrackingStore<T extends Transaction> = IInitializeTxTrackingStore<T> & {
|
|
376
|
+
/** A getter function that returns the configured transaction adapter(s). */
|
|
305
377
|
getAdapter: () => TxAdapter<T> | TxAdapter<T>[];
|
|
306
378
|
/**
|
|
307
379
|
* The primary method for initiating and tracking a new transaction from start to finish.
|
|
308
380
|
* It manages UI state, executes the on-chain action, and initiates background tracking.
|
|
381
|
+
*
|
|
309
382
|
* @param params The parameters for handling the transaction.
|
|
383
|
+
* @param params.actionFunction The async function to execute (e.g., a smart contract write call). Must return a unique key or undefined.
|
|
384
|
+
* @param params.params The metadata for the transaction.
|
|
385
|
+
* @param params.defaultTracker The default tracker to use if it cannot be determined automatically.
|
|
386
|
+
* @param params.onSuccessCallback Callback to execute when the transaction is successfully submitted.
|
|
310
387
|
*/
|
|
311
388
|
handleTransaction: (params: {
|
|
312
|
-
/** The async function to execute (e.g., a smart contract write call). Must return a unique key or undefined. */
|
|
313
389
|
actionFunction: () => Promise<ActionTxKey | undefined>;
|
|
314
|
-
/** The metadata for the transaction. */
|
|
315
390
|
params: Omit<InitialTransactionParams, 'actionFunction'>;
|
|
316
|
-
/** The default tracker to use if it cannot be determined automatically. */
|
|
317
391
|
defaultTracker?: TransactionTracker;
|
|
318
392
|
} & OnSuccessCallback<T>) => Promise<void>;
|
|
319
393
|
/**
|
|
320
394
|
* Initializes trackers for all pending transactions in the pool.
|
|
321
|
-
* This is essential for resuming tracking after a page reload.
|
|
395
|
+
* This is essential for resuming tracking after a page reload or application restart.
|
|
322
396
|
*/
|
|
323
397
|
initializeTransactionsPool: () => Promise<void>;
|
|
324
398
|
};
|
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","set","get","tx","state","produce","draft","txKey","fields","selectAllTransactions","transactionsPool","a","b","selectPendingTransactions","selectTxByKey","key","selectAllTransactionsByActiveWallet","from","selectPendingTransactionsByActiveWallet","selectAdapterByKey","adapterKey","adapter","foundAdapter","createPulsarStore","options","createStore","persist","pendingTxs","defaultTracker","actionFunction","onSuccessCallback","params","desiredChainID","restParams","localTimestamp","dayjs","handleTxError","e","errorMessage","error","walletType","walletAddress","txKeyFromAction","updatedTracker","finalTxKey","newTx","TransactionAdapter","TransactionTracker","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 { IInitializeTxTrackingStore, StoreSlice, Transaction } from '../types';\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 T The specific transaction type.\n * @param options Configuration for the store slice.\n * @returns A Zustand store slice implementing `IInitializeTxTrackingStore`.\n */\nexport function initializeTxTrackingStore<T extends Transaction>(): StoreSlice<IInitializeTxTrackingStore<T>> {\n return (set, get) => ({\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, TransactionPool } from '../types';\n\n/**\n * Selects all transactions from the pool and sorts them by their creation timestamp in ascending order.\n * @template T - The transaction type.\n * @param {TransactionPool<T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of all transactions, sorted chronologically.\n */\nexport const selectAllTransactions = <T extends Transaction>(transactionsPool: TransactionPool<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 T - The transaction type.\n * @param {TransactionPool<T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of pending transactions.\n */\nexport const selectPendingTransactions = <T extends Transaction>(transactionsPool: TransactionPool<T>): 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 T - The transaction type.\n * @param {TransactionPool<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 = <T extends Transaction>(\n transactionsPool: TransactionPool<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 T - The transaction type.\n * @param {TransactionPool<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 = <T extends Transaction>(\n transactionsPool: TransactionPool<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 T - The transaction type.\n * @param {TransactionPool<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 = <T extends Transaction>(\n transactionsPool: TransactionPool<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 { Adapter, 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 T - The transaction type, extending the base `Transaction`.\n *\n * @param {object} params - The parameters for the selection.\n * @param {TransactionAdapter} params.adapterKey - The key of the desired adapter.\n * @param {TxAdapter<T> | TxAdapter<T>[]} params.adapter - Adapter or an array of adapters for different chains or transaction types.\n *\n * @returns {TxAdapter<T> | undefined} The found transaction adapter, the fallback adapter, or undefined if the adapters array is empty.\n */\nexport const selectAdapterByKey = <T extends Transaction>({\n adapterKey,\n adapter,\n}: {\n adapterKey: TransactionAdapter;\n} & Adapter<T>): TxAdapter<T> | undefined => {\n if (Array.isArray(adapter)) {\n if (adapter.length === 0) {\n console.error('Adapter selection failed: The provided adapters array is empty.');\n return undefined;\n }\n\n const foundAdapter = adapter.find((a) => a.key === adapterKey);\n\n if (foundAdapter) {\n return foundAdapter;\n } else {\n console.warn(\n `No adapter found for key: \"${adapterKey}\". Falling back to the first available adapter: \"${adapter[0].key}\".`,\n );\n return adapter[0];\n }\n }\n return adapter;\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 { Adapter, ITxTrackingStore, Transaction } 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 T The specific transaction type, extending the base `Transaction`.\n *\n * @param config Configuration object for creating the store.\n * @param config.adapter Adapter or 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<T extends Transaction>({\n adapter,\n ...options\n}: Adapter<T> & PersistOptions<ITxTrackingStore<T>>) {\n return createStore<ITxTrackingStore<T>>()(\n persist(\n (set, get) => ({\n // Initialize the base store slice with core state and actions\n ...initializeTxTrackingStore<T>()(set, get),\n\n getAdapter: () => adapter,\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 foundAdapter = selectAdapterByKey({\n adapterKey: tx.adapter,\n adapter,\n });\n // Delegate tracker initialization to the appropriate adapter\n return foundAdapter?.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, onSuccessCallback, 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 foundAdapter = selectAdapterByKey({\n adapterKey: restParams.adapter,\n adapter,\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 (!foundAdapter) {\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 } = foundAdapter.getWalletInfo();\n\n // Step 2: Ensure the wallet is connected to the correct chain.\n await foundAdapter.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 } = foundAdapter.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,\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 as T);\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 foundAdapter.checkAndInitializeTrackerInStore({ tx, onSuccessCallback, ...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\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 * Enum representing the different tracking strategies available for EVM transactions.\n * Each tracker corresponds to a specific method of monitoring a transaction's lifecycle.\n */\nexport enum TransactionTracker {\n /** For standard on-chain EVM transactions tracked by their hash. */\n Ethereum = 'ethereum',\n /** For multi-signature transactions managed and executed via a Safe contract. */\n Safe = 'safe',\n /** For meta-transactions relayed and executed by the Gelato Network. */\n Gelato = 'gelato',\n /** The tracker for monitoring standard Solana transaction signatures. */\n Solana = 'solana',\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 * Defines the shape of the identifier for a Gelato transaction task.\n */\nexport type GelatoTxKey = {\n taskId: string;\n};\n\n/**\n * A union type representing the unique identifier returned by an `actionFunction`\n * after a transaction is submitted to the network or a relay service.\n *\n * This key is crucial for the EVM adapter to determine which tracker should\n * monitor the transaction.\n *\n * It can be one of the following:\n * - A standard `0x...` transaction hash (`Hex`).\n * - A structured object from a relay service like Gelato (`GelatoTxKey`).\n */\nexport type ActionTxKey = `0x${string}` | GelatoTxKey | string;\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 */\nexport type BaseTransaction = {\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: TransactionTracker;\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 */\nexport type EvmTransaction = BaseTransaction & {\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 */\nexport type SolanaTransaction = BaseTransaction & {\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. `string` when tx successed. `null` if the transaction is pending or unconfirmed. */\n confirmations?: number | string | 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 */\nexport type StarknetTransaction = BaseTransaction & {\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};\n\n/** A union type representing any possible transaction structure that Pulsar can handle. */\nexport type Transaction = EvmTransaction | SolanaTransaction | StarknetTransaction;\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 = {\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<ActionTxKey | 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 = 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\nexport type OnSuccessCallback<T extends Transaction> = {\n /** Callback to execute when the transaction is successfully submitted. */\n onSuccessCallback?: (tx: T) => Promise<void> | void;\n};\n\nexport type Adapter<T extends Transaction> = {\n adapter: TxAdapter<T> | TxAdapter<T>[];\n};\n\n/**\n * Defines the interface for a transaction adapter, which provides chain-specific logic and utilities.\n * @template T The specific transaction type, extending `Transaction`.\n */\nexport type TxAdapter<T extends Transaction> = {\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: (\n actionTxKey: ActionTxKey,\n walletType: string,\n ) => { txKey: string; tracker: TransactionTracker };\n /** Selects and initializes the correct background tracker for a given transaction. */\n checkAndInitializeTrackerInStore: (\n params: { tx: T } & OnSuccessCallback<T> &\n Pick<ITxTrackingStore<T>, 'updateTxParams' | 'removeTxFromPool' | 'transactionsPool'>,\n ) => Promise<void> | void;\n /** Returns the base URL for the blockchain explorer for the current network. */\n getExplorerUrl: (url?: string) => 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 onClose: (txKey?: string) => void;\n } & Partial<Pick<ITxTrackingStore<T>, '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?: (tx: T) => string;\n};\n\n/**\n * Defines the structure of the transaction pool, a key-value store of transactions indexed by their unique keys.\n * @template T The type of the transaction object being tracked.\n */\nexport type TransactionPool<T extends Transaction> = 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 */\ntype UpdatableTransactionFields = Partial<\n Pick<\n EvmTransaction,\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<Pick<SolanaTransaction, 'slot' | 'confirmations' | 'fee' | 'instructions' | 'recentBlockhash' | 'rpcUrl'>>;\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 T The specific transaction type.\n */\nexport interface IInitializeTxTrackingStore<T extends Transaction> {\n /** A pool of all transactions currently being tracked, indexed by `txKey`. */\n transactionsPool: TransactionPool<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;\n\n /** Adds a new transaction to the tracking pool and marks it as pending. */\n addTxToPool: (tx: T) => void;\n /** Updates one or more properties of an existing transaction in the pool. */\n updateTxParams: (txKey: string, fields: UpdatableTransactionFields) => 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 * The complete interface for the Pulsar transaction tracking store.\n * @template T The transaction type.\n */\nexport type ITxTrackingStore<T extends Transaction> = IInitializeTxTrackingStore<T> & {\n getAdapter: () => TxAdapter<T> | TxAdapter<T>[];\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: (\n params: {\n /** The async function to execute (e.g., a smart contract write call). Must return a unique key or undefined. */\n actionFunction: () => Promise<ActionTxKey | undefined>;\n /** The metadata for the transaction. */\n params: Omit<InitialTransactionParams, 'actionFunction'>;\n /** The default tracker to use if it cannot be determined automatically. */\n defaultTracker?: TransactionTracker;\n } & OnSuccessCallback<T>,\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 */\nexport type PollingTrackerConfig<R, T extends Transaction> = {\n /** The transaction object to be tracked. It must include `txKey` and `pending` status. */\n tx: T & Pick<Transaction, '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 * @param {PollingTrackerConfig<R, T>} config - The configuration for the tracker.\n */\nexport function initializePollingTracker<R, T extends Transaction>(config: PollingTrackerConfig<R, T>): 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","set","get","tx","state","produce","draft","txKey","fields","selectAllTransactions","transactionsPool","a","b","selectPendingTransactions","selectTxByKey","key","selectAllTransactionsByActiveWallet","from","selectPendingTransactionsByActiveWallet","selectAdapterByKey","adapterKey","adapter","foundAdapter","createPulsarStore","options","createStore","persist","pendingTxs","defaultTracker","actionFunction","onSuccessCallback","params","desiredChainID","restParams","localTimestamp","dayjs","handleTxError","e","errorMessage","error","walletType","walletAddress","txKeyFromAction","updatedTracker","finalTxKey","newTx","TransactionAdapter","TransactionTracker","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 { IInitializeTxTrackingStore, StoreSlice, Transaction } from '../types';\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 T The specific transaction type.\n * @param options Configuration for the store slice.\n * @returns A Zustand store slice implementing `IInitializeTxTrackingStore`.\n */\nexport function initializeTxTrackingStore<T extends Transaction>(): StoreSlice<IInitializeTxTrackingStore<T>> {\n return (set, get) => ({\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, TransactionPool } from '../types';\n\n/**\n * Selects all transactions from the pool and sorts them by their creation timestamp in ascending order.\n * @template T - The transaction type.\n * @param {TransactionPool<T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of all transactions, sorted chronologically.\n */\nexport const selectAllTransactions = <T extends Transaction>(transactionsPool: TransactionPool<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 T - The transaction type.\n * @param {TransactionPool<T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of pending transactions.\n */\nexport const selectPendingTransactions = <T extends Transaction>(transactionsPool: TransactionPool<T>): 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 T - The transaction type.\n * @param {TransactionPool<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 = <T extends Transaction>(\n transactionsPool: TransactionPool<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 T - The transaction type.\n * @param {TransactionPool<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 = <T extends Transaction>(\n transactionsPool: TransactionPool<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 T - The transaction type.\n * @param {TransactionPool<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 = <T extends Transaction>(\n transactionsPool: TransactionPool<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 { Adapter, 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 T - The transaction type, extending the base `Transaction`.\n *\n * @param {object} params - The parameters for the selection.\n * @param {TransactionAdapter} params.adapterKey - The key of the desired adapter.\n * @param {TxAdapter<T> | TxAdapter<T>[]} params.adapter - Adapter or an array of adapters for different chains or transaction types.\n *\n * @returns {TxAdapter<T> | undefined} The found transaction adapter, the fallback adapter, or undefined if the adapters array is empty.\n */\nexport const selectAdapterByKey = <T extends Transaction>({\n adapterKey,\n adapter,\n}: {\n adapterKey: TransactionAdapter;\n} & Adapter<T>): TxAdapter<T> | undefined => {\n if (Array.isArray(adapter)) {\n if (adapter.length === 0) {\n console.error('Adapter selection failed: The provided adapters array is empty.');\n return undefined;\n }\n\n const foundAdapter = adapter.find((a) => a.key === adapterKey);\n\n if (foundAdapter) {\n return foundAdapter;\n } else {\n console.warn(\n `No adapter found for key: \"${adapterKey}\". Falling back to the first available adapter: \"${adapter[0].key}\".`,\n );\n return adapter[0];\n }\n }\n return adapter;\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 { Adapter, ITxTrackingStore, Transaction } 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 T The specific transaction type, extending the base `Transaction`.\n *\n * @param config Configuration object for creating the store.\n * @param config.adapter Adapter or 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<T extends Transaction>({\n adapter,\n ...options\n}: Adapter<T> & PersistOptions<ITxTrackingStore<T>>) {\n return createStore<ITxTrackingStore<T>>()(\n persist(\n (set, get) => ({\n // Initialize the base store slice with core state and actions\n ...initializeTxTrackingStore<T>()(set, get),\n\n getAdapter: () => adapter,\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 foundAdapter = selectAdapterByKey({\n adapterKey: tx.adapter,\n adapter,\n });\n // Delegate tracker initialization to the appropriate adapter\n return foundAdapter?.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, onSuccessCallback, 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 foundAdapter = selectAdapterByKey({\n adapterKey: restParams.adapter,\n adapter,\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 (!foundAdapter) {\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 } = foundAdapter.getWalletInfo();\n\n // Step 2: Ensure the wallet is connected to the correct chain.\n await foundAdapter.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 } = foundAdapter.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,\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 as T);\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 foundAdapter.checkAndInitializeTrackerInStore({ tx, onSuccessCallback, ...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\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 * Enum representing the different tracking strategies available for transactions.\n * Each tracker corresponds to a specific method of monitoring a transaction's lifecycle.\n */\nexport enum TransactionTracker {\n /** For standard on-chain EVM transactions tracked by their hash. */\n Ethereum = 'ethereum',\n /** For multi-signature transactions managed and executed via a Safe contract. */\n Safe = 'safe',\n /** For meta-transactions relayed and executed by the Gelato Network. */\n Gelato = 'gelato',\n /** The tracker for monitoring standard Solana transaction signatures. */\n Solana = 'solana',\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 * Defines the shape of the identifier for a Gelato transaction task.\n */\nexport type GelatoTxKey = {\n /** The unique identifier assigned by the Gelato relay service. */\n taskId: string;\n};\n\n/**\n * A union type representing the unique identifier returned by an `actionFunction`\n * after a transaction is submitted to the network or a relay service.\n *\n * This key is crucial for the adapter to determine which tracker should\n * monitor the transaction.\n *\n * It can be one of the following:\n * - A standard `0x...` transaction hash (`Hex`).\n * - A structured object from a relay service like Gelato (`GelatoTxKey`).\n * - A Solana transaction signature (string).\n */\nexport type ActionTxKey = `0x${string}` | GelatoTxKey | string;\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 */\nexport type BaseTransaction = {\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: TransactionTracker;\n /** The unique identifier for the transaction (e.g., EVM hash, Solana signature, or 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 */\nexport type EvmTransaction = BaseTransaction & {\n /** The adapter type for EVM transactions. */\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 */\nexport type SolanaTransaction = BaseTransaction & {\n /** The adapter type for Solana transactions. */\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. A string value indicates a confirmed transaction, while `null` means it's pending. */\n confirmations?: number | string | 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 */\nexport type StarknetTransaction = BaseTransaction & {\n /** The adapter type for Starknet transactions. */\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};\n\n/** A union type representing any possible transaction structure that Pulsar can handle. */\nexport type Transaction = EvmTransaction | SolanaTransaction | StarknetTransaction;\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 = {\n /** The specific blockchain adapter for this transaction. */\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<ActionTxKey | 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 = 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 a callback function to be executed upon a successful transaction.\n * @template T The specific transaction type, extending `Transaction`.\n */\nexport type OnSuccessCallback<T extends Transaction> = {\n /** Callback to execute when the transaction is successfully submitted. */\n onSuccessCallback?: (tx: T) => Promise<void> | void;\n};\n\n/**\n * The configuration object containing one or more transaction adapters.\n * @template T The specific transaction type.\n */\nexport type Adapter<T extends Transaction> = {\n /** A single `TxAdapter` instance or an array of them. */\n adapter: TxAdapter<T> | TxAdapter<T>[];\n};\n\n/**\n * Defines the interface for a transaction adapter, which provides chain-specific logic and utilities.\n * @template T The specific transaction type, extending `Transaction`.\n */\nexport type TxAdapter<T extends Transaction> = {\n /** The unique key identifying this adapter. */\n key: TransactionAdapter;\n /** Returns information about the currently connected wallet. */\n getWalletInfo: () => {\n /** The currently connected wallet address. */\n walletAddress: string;\n /** The type of the wallet (e.g., 'metamask', 'phantom'). */\n walletType: string;\n };\n /**\n * Ensures the connected wallet is on the correct network for the transaction.\n *\n * This method should throw an error if the chain is mismatched.\n * @param chainId The desired chain ID for the transaction.\n */\n checkChainForTx: (chainId: string | number) => Promise<void>;\n /**\n * Determines the appropriate tracker and final `txKey` from the result of an action.\n * @param actionTxKey The preliminary key returned after an action function is executed.\n * @param walletType The type of wallet used for the transaction.\n * @returns An object containing the final `txKey` and the `TransactionTracker` to be used.\n */\n checkTransactionsTracker: (\n actionTxKey: ActionTxKey,\n walletType: string,\n ) => { txKey: string; tracker: TransactionTracker };\n /**\n * Selects and initializes the correct background tracker for a given transaction.\n * @param params The parameters for initializing the tracker, including the transaction and store callbacks.\n */\n checkAndInitializeTrackerInStore: (\n params: { tx: T } & OnSuccessCallback<T> &\n Pick<ITxTrackingStore<T>, 'updateTxParams' | 'removeTxFromPool' | 'transactionsPool'>,\n ) => Promise<void> | void;\n /**\n * Returns the base URL for the blockchain explorer for the current network.\n * @param url Optional URL to override the default explorer URL.\n */\n getExplorerUrl: (url?: string) => string | undefined;\n /**\n * Optional: Fetches a name from a chain-specific name service (e.g., ENS).\n * @param address The address to resolve the name for.\n */\n getName?: (address: string) => Promise<string | null>;\n /**\n * Optional: Fetches an avatar URL from a chain-specific name service.\n * @param name The name to resolve the avatar for.\n */\n getAvatar?: (name: string) => Promise<string | null>;\n /**\n * Optional: Logic to cancel a pending EVM transaction.\n * @param tx The transaction to cancel.\n * @returns The new transaction hash for the cancellation.\n */\n cancelTxAction?: (tx: T) => Promise<string>;\n /**\n * Optional: Logic to speed up a pending EVM transaction.\n * @param tx The transaction to speed up.\n * @returns The new transaction hash for the sped-up transaction.\n */\n speedUpTxAction?: (tx: T) => Promise<string>;\n /**\n * Optional: Logic to retry a failed transaction.\n * @param params The parameters for retrying the transaction.\n * @param params.txKey The unique key of the transaction to retry.\n * @param params.tx The initial parameters of the transaction.\n * @param params.onClose Callback function to close the tracking modal.\n */\n retryTxAction?: (\n params: {\n txKey: string;\n tx: InitialTransactionParams;\n onClose: (txKey?: string) => void;\n } & Partial<Pick<ITxTrackingStore<T>, '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 * @param tx The transaction object.\n * @returns The full URL to the transaction on the explorer.\n */\n getExplorerTxUrl?: (tx: T) => string;\n};\n\n/**\n * Defines the structure of the transaction pool, a key-value store of transactions indexed by their unique keys.\n * @template T The type of the transaction object being tracked.\n */\nexport type TransactionPool<T extends Transaction> = 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 */\ntype UpdatableTransactionFields = Partial<\n Pick<\n EvmTransaction,\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<Pick<SolanaTransaction, 'slot' | 'confirmations' | 'fee' | 'instructions' | 'recentBlockhash' | 'rpcUrl'>>;\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 T The specific transaction type.\n */\nexport interface IInitializeTxTrackingStore<T extends Transaction> {\n /** A pool of all transactions currently being tracked, indexed by `txKey`. */\n transactionsPool: TransactionPool<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;\n\n /**\n * Adds a new transaction to the tracking pool and marks it as pending.\n * @param tx The transaction object to add.\n */\n addTxToPool: (tx: T) => void;\n /**\n * Updates one or more properties of an existing transaction in the pool.\n * @param txKey The key of the transaction to update.\n * @param fields The partial object containing the fields to update.\n */\n updateTxParams: (txKey: string, fields: UpdatableTransactionFields) => void;\n /**\n * Removes a transaction from the tracking pool by its key.\n * @param txKey The key of the transaction to remove.\n */\n removeTxFromPool: (txKey: string) => void;\n /**\n * Closes the tracking modal for a transaction and clears any initial transaction state.\n * @param txKey The optional key of the transaction modal to close.\n */\n closeTxTrackedModal: (txKey?: string) => void;\n /**\n * A selector function to retrieve the key of the last transaction added to the pool.\n * @returns The key of the last added transaction, or undefined if none exists.\n */\n getLastTxKey: () => string | undefined;\n}\n\n/**\n * The complete interface for the Pulsar transaction tracking store.\n * @template T The transaction type.\n */\nexport type ITxTrackingStore<T extends Transaction> = IInitializeTxTrackingStore<T> & {\n /** A getter function that returns the configured transaction adapter(s). */\n getAdapter: () => TxAdapter<T> | TxAdapter<T>[];\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 *\n * @param params The parameters for handling the transaction.\n * @param params.actionFunction The async function to execute (e.g., a smart contract write call). Must return a unique key or undefined.\n * @param params.params The metadata for the transaction.\n * @param params.defaultTracker The default tracker to use if it cannot be determined automatically.\n * @param params.onSuccessCallback Callback to execute when the transaction is successfully submitted.\n */\n handleTransaction: (\n params: {\n actionFunction: () => Promise<ActionTxKey | undefined>;\n params: Omit<InitialTransactionParams, 'actionFunction'>;\n defaultTracker?: TransactionTracker;\n } & OnSuccessCallback<T>,\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 or application restart.\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 */\nexport type PollingTrackerConfig<R, T extends Transaction> = {\n /** The transaction object to be tracked. It must include `txKey` and `pending` status. */\n tx: T & Pick<Transaction, '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 * @param {PollingTrackerConfig<R, T>} config - The configuration for the tracker.\n */\nexport function initializePollingTracker<R, T extends Transaction>(config: PollingTrackerConfig<R, T>): 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.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","set","get","tx","state","produce","draft","txKey","fields","selectAllTransactions","transactionsPool","a","b","selectPendingTransactions","selectTxByKey","key","selectAllTransactionsByActiveWallet","from","selectPendingTransactionsByActiveWallet","selectAdapterByKey","adapterKey","adapter","foundAdapter","createPulsarStore","options","createStore","persist","pendingTxs","defaultTracker","actionFunction","onSuccessCallback","params","desiredChainID","restParams","localTimestamp","dayjs","handleTxError","e","errorMessage","error","walletType","walletAddress","txKeyFromAction","updatedTracker","finalTxKey","newTx","TransactionAdapter","TransactionTracker","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 { IInitializeTxTrackingStore, StoreSlice, Transaction } from '../types';\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 T The specific transaction type.\n * @param options Configuration for the store slice.\n * @returns A Zustand store slice implementing `IInitializeTxTrackingStore`.\n */\nexport function initializeTxTrackingStore<T extends Transaction>(): StoreSlice<IInitializeTxTrackingStore<T>> {\n return (set, get) => ({\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, TransactionPool } from '../types';\n\n/**\n * Selects all transactions from the pool and sorts them by their creation timestamp in ascending order.\n * @template T - The transaction type.\n * @param {TransactionPool<T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of all transactions, sorted chronologically.\n */\nexport const selectAllTransactions = <T extends Transaction>(transactionsPool: TransactionPool<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 T - The transaction type.\n * @param {TransactionPool<T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of pending transactions.\n */\nexport const selectPendingTransactions = <T extends Transaction>(transactionsPool: TransactionPool<T>): 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 T - The transaction type.\n * @param {TransactionPool<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 = <T extends Transaction>(\n transactionsPool: TransactionPool<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 T - The transaction type.\n * @param {TransactionPool<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 = <T extends Transaction>(\n transactionsPool: TransactionPool<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 T - The transaction type.\n * @param {TransactionPool<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 = <T extends Transaction>(\n transactionsPool: TransactionPool<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 { Adapter, 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 T - The transaction type, extending the base `Transaction`.\n *\n * @param {object} params - The parameters for the selection.\n * @param {TransactionAdapter} params.adapterKey - The key of the desired adapter.\n * @param {TxAdapter<T> | TxAdapter<T>[]} params.adapter - Adapter or an array of adapters for different chains or transaction types.\n *\n * @returns {TxAdapter<T> | undefined} The found transaction adapter, the fallback adapter, or undefined if the adapters array is empty.\n */\nexport const selectAdapterByKey = <T extends Transaction>({\n adapterKey,\n adapter,\n}: {\n adapterKey: TransactionAdapter;\n} & Adapter<T>): TxAdapter<T> | undefined => {\n if (Array.isArray(adapter)) {\n if (adapter.length === 0) {\n console.error('Adapter selection failed: The provided adapters array is empty.');\n return undefined;\n }\n\n const foundAdapter = adapter.find((a) => a.key === adapterKey);\n\n if (foundAdapter) {\n return foundAdapter;\n } else {\n console.warn(\n `No adapter found for key: \"${adapterKey}\". Falling back to the first available adapter: \"${adapter[0].key}\".`,\n );\n return adapter[0];\n }\n }\n return adapter;\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 { Adapter, ITxTrackingStore, Transaction } 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 T The specific transaction type, extending the base `Transaction`.\n *\n * @param config Configuration object for creating the store.\n * @param config.adapter Adapter or 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<T extends Transaction>({\n adapter,\n ...options\n}: Adapter<T> & PersistOptions<ITxTrackingStore<T>>) {\n return createStore<ITxTrackingStore<T>>()(\n persist(\n (set, get) => ({\n // Initialize the base store slice with core state and actions\n ...initializeTxTrackingStore<T>()(set, get),\n\n getAdapter: () => adapter,\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 foundAdapter = selectAdapterByKey({\n adapterKey: tx.adapter,\n adapter,\n });\n // Delegate tracker initialization to the appropriate adapter\n return foundAdapter?.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, onSuccessCallback, 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 foundAdapter = selectAdapterByKey({\n adapterKey: restParams.adapter,\n adapter,\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 (!foundAdapter) {\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 } = foundAdapter.getWalletInfo();\n\n // Step 2: Ensure the wallet is connected to the correct chain.\n await foundAdapter.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 } = foundAdapter.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,\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 as T);\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 foundAdapter.checkAndInitializeTrackerInStore({ tx, onSuccessCallback, ...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\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 * Enum representing the different tracking strategies available for EVM transactions.\n * Each tracker corresponds to a specific method of monitoring a transaction's lifecycle.\n */\nexport enum TransactionTracker {\n /** For standard on-chain EVM transactions tracked by their hash. */\n Ethereum = 'ethereum',\n /** For multi-signature transactions managed and executed via a Safe contract. */\n Safe = 'safe',\n /** For meta-transactions relayed and executed by the Gelato Network. */\n Gelato = 'gelato',\n /** The tracker for monitoring standard Solana transaction signatures. */\n Solana = 'solana',\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 * Defines the shape of the identifier for a Gelato transaction task.\n */\nexport type GelatoTxKey = {\n taskId: string;\n};\n\n/**\n * A union type representing the unique identifier returned by an `actionFunction`\n * after a transaction is submitted to the network or a relay service.\n *\n * This key is crucial for the EVM adapter to determine which tracker should\n * monitor the transaction.\n *\n * It can be one of the following:\n * - A standard `0x...` transaction hash (`Hex`).\n * - A structured object from a relay service like Gelato (`GelatoTxKey`).\n */\nexport type ActionTxKey = `0x${string}` | GelatoTxKey | string;\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 */\nexport type BaseTransaction = {\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: TransactionTracker;\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 */\nexport type EvmTransaction = BaseTransaction & {\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 */\nexport type SolanaTransaction = BaseTransaction & {\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. `string` when tx successed. `null` if the transaction is pending or unconfirmed. */\n confirmations?: number | string | 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 */\nexport type StarknetTransaction = BaseTransaction & {\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};\n\n/** A union type representing any possible transaction structure that Pulsar can handle. */\nexport type Transaction = EvmTransaction | SolanaTransaction | StarknetTransaction;\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 = {\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<ActionTxKey | 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 = 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\nexport type OnSuccessCallback<T extends Transaction> = {\n /** Callback to execute when the transaction is successfully submitted. */\n onSuccessCallback?: (tx: T) => Promise<void> | void;\n};\n\nexport type Adapter<T extends Transaction> = {\n adapter: TxAdapter<T> | TxAdapter<T>[];\n};\n\n/**\n * Defines the interface for a transaction adapter, which provides chain-specific logic and utilities.\n * @template T The specific transaction type, extending `Transaction`.\n */\nexport type TxAdapter<T extends Transaction> = {\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: (\n actionTxKey: ActionTxKey,\n walletType: string,\n ) => { txKey: string; tracker: TransactionTracker };\n /** Selects and initializes the correct background tracker for a given transaction. */\n checkAndInitializeTrackerInStore: (\n params: { tx: T } & OnSuccessCallback<T> &\n Pick<ITxTrackingStore<T>, 'updateTxParams' | 'removeTxFromPool' | 'transactionsPool'>,\n ) => Promise<void> | void;\n /** Returns the base URL for the blockchain explorer for the current network. */\n getExplorerUrl: (url?: string) => 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 onClose: (txKey?: string) => void;\n } & Partial<Pick<ITxTrackingStore<T>, '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?: (tx: T) => string;\n};\n\n/**\n * Defines the structure of the transaction pool, a key-value store of transactions indexed by their unique keys.\n * @template T The type of the transaction object being tracked.\n */\nexport type TransactionPool<T extends Transaction> = 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 */\ntype UpdatableTransactionFields = Partial<\n Pick<\n EvmTransaction,\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<Pick<SolanaTransaction, 'slot' | 'confirmations' | 'fee' | 'instructions' | 'recentBlockhash' | 'rpcUrl'>>;\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 T The specific transaction type.\n */\nexport interface IInitializeTxTrackingStore<T extends Transaction> {\n /** A pool of all transactions currently being tracked, indexed by `txKey`. */\n transactionsPool: TransactionPool<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;\n\n /** Adds a new transaction to the tracking pool and marks it as pending. */\n addTxToPool: (tx: T) => void;\n /** Updates one or more properties of an existing transaction in the pool. */\n updateTxParams: (txKey: string, fields: UpdatableTransactionFields) => 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 * The complete interface for the Pulsar transaction tracking store.\n * @template T The transaction type.\n */\nexport type ITxTrackingStore<T extends Transaction> = IInitializeTxTrackingStore<T> & {\n getAdapter: () => TxAdapter<T> | TxAdapter<T>[];\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: (\n params: {\n /** The async function to execute (e.g., a smart contract write call). Must return a unique key or undefined. */\n actionFunction: () => Promise<ActionTxKey | undefined>;\n /** The metadata for the transaction. */\n params: Omit<InitialTransactionParams, 'actionFunction'>;\n /** The default tracker to use if it cannot be determined automatically. */\n defaultTracker?: TransactionTracker;\n } & OnSuccessCallback<T>,\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 */\nexport type PollingTrackerConfig<R, T extends Transaction> = {\n /** The transaction object to be tracked. It must include `txKey` and `pending` status. */\n tx: T & Pick<Transaction, '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 * @param {PollingTrackerConfig<R, T>} config - The configuration for the tracker.\n */\nexport function initializePollingTracker<R, T extends Transaction>(config: PollingTrackerConfig<R, T>): 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","set","get","tx","state","produce","draft","txKey","fields","selectAllTransactions","transactionsPool","a","b","selectPendingTransactions","selectTxByKey","key","selectAllTransactionsByActiveWallet","from","selectPendingTransactionsByActiveWallet","selectAdapterByKey","adapterKey","adapter","foundAdapter","createPulsarStore","options","createStore","persist","pendingTxs","defaultTracker","actionFunction","onSuccessCallback","params","desiredChainID","restParams","localTimestamp","dayjs","handleTxError","e","errorMessage","error","walletType","walletAddress","txKeyFromAction","updatedTracker","finalTxKey","newTx","TransactionAdapter","TransactionTracker","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 { IInitializeTxTrackingStore, StoreSlice, Transaction } from '../types';\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 T The specific transaction type.\n * @param options Configuration for the store slice.\n * @returns A Zustand store slice implementing `IInitializeTxTrackingStore`.\n */\nexport function initializeTxTrackingStore<T extends Transaction>(): StoreSlice<IInitializeTxTrackingStore<T>> {\n return (set, get) => ({\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, TransactionPool } from '../types';\n\n/**\n * Selects all transactions from the pool and sorts them by their creation timestamp in ascending order.\n * @template T - The transaction type.\n * @param {TransactionPool<T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of all transactions, sorted chronologically.\n */\nexport const selectAllTransactions = <T extends Transaction>(transactionsPool: TransactionPool<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 T - The transaction type.\n * @param {TransactionPool<T>} transactionsPool - The entire transaction pool from the store.\n * @returns {T[]} An array of pending transactions.\n */\nexport const selectPendingTransactions = <T extends Transaction>(transactionsPool: TransactionPool<T>): 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 T - The transaction type.\n * @param {TransactionPool<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 = <T extends Transaction>(\n transactionsPool: TransactionPool<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 T - The transaction type.\n * @param {TransactionPool<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 = <T extends Transaction>(\n transactionsPool: TransactionPool<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 T - The transaction type.\n * @param {TransactionPool<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 = <T extends Transaction>(\n transactionsPool: TransactionPool<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 { Adapter, 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 T - The transaction type, extending the base `Transaction`.\n *\n * @param {object} params - The parameters for the selection.\n * @param {TransactionAdapter} params.adapterKey - The key of the desired adapter.\n * @param {TxAdapter<T> | TxAdapter<T>[]} params.adapter - Adapter or an array of adapters for different chains or transaction types.\n *\n * @returns {TxAdapter<T> | undefined} The found transaction adapter, the fallback adapter, or undefined if the adapters array is empty.\n */\nexport const selectAdapterByKey = <T extends Transaction>({\n adapterKey,\n adapter,\n}: {\n adapterKey: TransactionAdapter;\n} & Adapter<T>): TxAdapter<T> | undefined => {\n if (Array.isArray(adapter)) {\n if (adapter.length === 0) {\n console.error('Adapter selection failed: The provided adapters array is empty.');\n return undefined;\n }\n\n const foundAdapter = adapter.find((a) => a.key === adapterKey);\n\n if (foundAdapter) {\n return foundAdapter;\n } else {\n console.warn(\n `No adapter found for key: \"${adapterKey}\". Falling back to the first available adapter: \"${adapter[0].key}\".`,\n );\n return adapter[0];\n }\n }\n return adapter;\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 { Adapter, ITxTrackingStore, Transaction } 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 T The specific transaction type, extending the base `Transaction`.\n *\n * @param config Configuration object for creating the store.\n * @param config.adapter Adapter or 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<T extends Transaction>({\n adapter,\n ...options\n}: Adapter<T> & PersistOptions<ITxTrackingStore<T>>) {\n return createStore<ITxTrackingStore<T>>()(\n persist(\n (set, get) => ({\n // Initialize the base store slice with core state and actions\n ...initializeTxTrackingStore<T>()(set, get),\n\n getAdapter: () => adapter,\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 foundAdapter = selectAdapterByKey({\n adapterKey: tx.adapter,\n adapter,\n });\n // Delegate tracker initialization to the appropriate adapter\n return foundAdapter?.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, onSuccessCallback, 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 foundAdapter = selectAdapterByKey({\n adapterKey: restParams.adapter,\n adapter,\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 (!foundAdapter) {\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 } = foundAdapter.getWalletInfo();\n\n // Step 2: Ensure the wallet is connected to the correct chain.\n await foundAdapter.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 } = foundAdapter.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,\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 as T);\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 foundAdapter.checkAndInitializeTrackerInStore({ tx, onSuccessCallback, ...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\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 * Enum representing the different tracking strategies available for transactions.\n * Each tracker corresponds to a specific method of monitoring a transaction's lifecycle.\n */\nexport enum TransactionTracker {\n /** For standard on-chain EVM transactions tracked by their hash. */\n Ethereum = 'ethereum',\n /** For multi-signature transactions managed and executed via a Safe contract. */\n Safe = 'safe',\n /** For meta-transactions relayed and executed by the Gelato Network. */\n Gelato = 'gelato',\n /** The tracker for monitoring standard Solana transaction signatures. */\n Solana = 'solana',\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 * Defines the shape of the identifier for a Gelato transaction task.\n */\nexport type GelatoTxKey = {\n /** The unique identifier assigned by the Gelato relay service. */\n taskId: string;\n};\n\n/**\n * A union type representing the unique identifier returned by an `actionFunction`\n * after a transaction is submitted to the network or a relay service.\n *\n * This key is crucial for the adapter to determine which tracker should\n * monitor the transaction.\n *\n * It can be one of the following:\n * - A standard `0x...` transaction hash (`Hex`).\n * - A structured object from a relay service like Gelato (`GelatoTxKey`).\n * - A Solana transaction signature (string).\n */\nexport type ActionTxKey = `0x${string}` | GelatoTxKey | string;\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 */\nexport type BaseTransaction = {\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: TransactionTracker;\n /** The unique identifier for the transaction (e.g., EVM hash, Solana signature, or 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 */\nexport type EvmTransaction = BaseTransaction & {\n /** The adapter type for EVM transactions. */\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 */\nexport type SolanaTransaction = BaseTransaction & {\n /** The adapter type for Solana transactions. */\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. A string value indicates a confirmed transaction, while `null` means it's pending. */\n confirmations?: number | string | 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 */\nexport type StarknetTransaction = BaseTransaction & {\n /** The adapter type for Starknet transactions. */\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};\n\n/** A union type representing any possible transaction structure that Pulsar can handle. */\nexport type Transaction = EvmTransaction | SolanaTransaction | StarknetTransaction;\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 = {\n /** The specific blockchain adapter for this transaction. */\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<ActionTxKey | 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 = 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 a callback function to be executed upon a successful transaction.\n * @template T The specific transaction type, extending `Transaction`.\n */\nexport type OnSuccessCallback<T extends Transaction> = {\n /** Callback to execute when the transaction is successfully submitted. */\n onSuccessCallback?: (tx: T) => Promise<void> | void;\n};\n\n/**\n * The configuration object containing one or more transaction adapters.\n * @template T The specific transaction type.\n */\nexport type Adapter<T extends Transaction> = {\n /** A single `TxAdapter` instance or an array of them. */\n adapter: TxAdapter<T> | TxAdapter<T>[];\n};\n\n/**\n * Defines the interface for a transaction adapter, which provides chain-specific logic and utilities.\n * @template T The specific transaction type, extending `Transaction`.\n */\nexport type TxAdapter<T extends Transaction> = {\n /** The unique key identifying this adapter. */\n key: TransactionAdapter;\n /** Returns information about the currently connected wallet. */\n getWalletInfo: () => {\n /** The currently connected wallet address. */\n walletAddress: string;\n /** The type of the wallet (e.g., 'metamask', 'phantom'). */\n walletType: string;\n };\n /**\n * Ensures the connected wallet is on the correct network for the transaction.\n *\n * This method should throw an error if the chain is mismatched.\n * @param chainId The desired chain ID for the transaction.\n */\n checkChainForTx: (chainId: string | number) => Promise<void>;\n /**\n * Determines the appropriate tracker and final `txKey` from the result of an action.\n * @param actionTxKey The preliminary key returned after an action function is executed.\n * @param walletType The type of wallet used for the transaction.\n * @returns An object containing the final `txKey` and the `TransactionTracker` to be used.\n */\n checkTransactionsTracker: (\n actionTxKey: ActionTxKey,\n walletType: string,\n ) => { txKey: string; tracker: TransactionTracker };\n /**\n * Selects and initializes the correct background tracker for a given transaction.\n * @param params The parameters for initializing the tracker, including the transaction and store callbacks.\n */\n checkAndInitializeTrackerInStore: (\n params: { tx: T } & OnSuccessCallback<T> &\n Pick<ITxTrackingStore<T>, 'updateTxParams' | 'removeTxFromPool' | 'transactionsPool'>,\n ) => Promise<void> | void;\n /**\n * Returns the base URL for the blockchain explorer for the current network.\n * @param url Optional URL to override the default explorer URL.\n */\n getExplorerUrl: (url?: string) => string | undefined;\n /**\n * Optional: Fetches a name from a chain-specific name service (e.g., ENS).\n * @param address The address to resolve the name for.\n */\n getName?: (address: string) => Promise<string | null>;\n /**\n * Optional: Fetches an avatar URL from a chain-specific name service.\n * @param name The name to resolve the avatar for.\n */\n getAvatar?: (name: string) => Promise<string | null>;\n /**\n * Optional: Logic to cancel a pending EVM transaction.\n * @param tx The transaction to cancel.\n * @returns The new transaction hash for the cancellation.\n */\n cancelTxAction?: (tx: T) => Promise<string>;\n /**\n * Optional: Logic to speed up a pending EVM transaction.\n * @param tx The transaction to speed up.\n * @returns The new transaction hash for the sped-up transaction.\n */\n speedUpTxAction?: (tx: T) => Promise<string>;\n /**\n * Optional: Logic to retry a failed transaction.\n * @param params The parameters for retrying the transaction.\n * @param params.txKey The unique key of the transaction to retry.\n * @param params.tx The initial parameters of the transaction.\n * @param params.onClose Callback function to close the tracking modal.\n */\n retryTxAction?: (\n params: {\n txKey: string;\n tx: InitialTransactionParams;\n onClose: (txKey?: string) => void;\n } & Partial<Pick<ITxTrackingStore<T>, '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 * @param tx The transaction object.\n * @returns The full URL to the transaction on the explorer.\n */\n getExplorerTxUrl?: (tx: T) => string;\n};\n\n/**\n * Defines the structure of the transaction pool, a key-value store of transactions indexed by their unique keys.\n * @template T The type of the transaction object being tracked.\n */\nexport type TransactionPool<T extends Transaction> = 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 */\ntype UpdatableTransactionFields = Partial<\n Pick<\n EvmTransaction,\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<Pick<SolanaTransaction, 'slot' | 'confirmations' | 'fee' | 'instructions' | 'recentBlockhash' | 'rpcUrl'>>;\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 T The specific transaction type.\n */\nexport interface IInitializeTxTrackingStore<T extends Transaction> {\n /** A pool of all transactions currently being tracked, indexed by `txKey`. */\n transactionsPool: TransactionPool<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;\n\n /**\n * Adds a new transaction to the tracking pool and marks it as pending.\n * @param tx The transaction object to add.\n */\n addTxToPool: (tx: T) => void;\n /**\n * Updates one or more properties of an existing transaction in the pool.\n * @param txKey The key of the transaction to update.\n * @param fields The partial object containing the fields to update.\n */\n updateTxParams: (txKey: string, fields: UpdatableTransactionFields) => void;\n /**\n * Removes a transaction from the tracking pool by its key.\n * @param txKey The key of the transaction to remove.\n */\n removeTxFromPool: (txKey: string) => void;\n /**\n * Closes the tracking modal for a transaction and clears any initial transaction state.\n * @param txKey The optional key of the transaction modal to close.\n */\n closeTxTrackedModal: (txKey?: string) => void;\n /**\n * A selector function to retrieve the key of the last transaction added to the pool.\n * @returns The key of the last added transaction, or undefined if none exists.\n */\n getLastTxKey: () => string | undefined;\n}\n\n/**\n * The complete interface for the Pulsar transaction tracking store.\n * @template T The transaction type.\n */\nexport type ITxTrackingStore<T extends Transaction> = IInitializeTxTrackingStore<T> & {\n /** A getter function that returns the configured transaction adapter(s). */\n getAdapter: () => TxAdapter<T> | TxAdapter<T>[];\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 *\n * @param params The parameters for handling the transaction.\n * @param params.actionFunction The async function to execute (e.g., a smart contract write call). Must return a unique key or undefined.\n * @param params.params The metadata for the transaction.\n * @param params.defaultTracker The default tracker to use if it cannot be determined automatically.\n * @param params.onSuccessCallback Callback to execute when the transaction is successfully submitted.\n */\n handleTransaction: (\n params: {\n actionFunction: () => Promise<ActionTxKey | undefined>;\n params: Omit<InitialTransactionParams, 'actionFunction'>;\n defaultTracker?: TransactionTracker;\n } & OnSuccessCallback<T>,\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 or application restart.\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 */\nexport type PollingTrackerConfig<R, T extends Transaction> = {\n /** The transaction object to be tracked. It must include `txKey` and `pending` status. */\n tx: T & Pick<Transaction, '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 * @param {PollingTrackerConfig<R, T>} config - The configuration for the tracker.\n */\nexport function initializePollingTracker<R, T extends Transaction>(config: PollingTrackerConfig<R, T>): 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"]}
|