@tuwaio/pulsar-evm 0.5.9 → 0.6.0

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/README.md CHANGED
@@ -121,6 +121,23 @@ async function trackMyTransaction(txHash: string, chainId: number) {
121
121
  }
122
122
  ```
123
123
 
124
+ #### Two-Stage ERC-4337 UserOperation Architecture (Pimlico / Account Abstraction)
125
+
126
+ For ERC-4337 smart accounts (e.g. Solady smart accounts orchestrated with Pimlico via `@tuwaio/orbit-evm`), `@tuwaio/pulsar-evm` provides a resilient **Two-Stage tracking pipeline**:
127
+
128
+ 1. **Stage 1: Bundler Mempool (`erc4337Fetcher`)**:
129
+ - The initial `userOpHash` is submitted to the Pimlico / Bundler RPC endpoint.
130
+ - `erc4337Fetcher` polls `eth_getUserOperationReceipt` until the UserOp is bundled into an on-chain transaction.
131
+ - Updates the store record with `tx.hash` (the mined transaction hash) and extracted parameters (`to`, `nonce`, `input`, `maxFeePerGas`).
132
+ 2. **Stage 2: On-Chain Block Settlement (`evmTracker`)**:
133
+ - Transitions to `evmTracker` with `{ withoutRemoving: true }` so the store entry is never deleted prematurely.
134
+ - Waits for full on-chain block confirmations (`requiredConfirmations`), resolves the native transaction receipt, and queries the block header timestamp (`getBlock`).
135
+ 3. **Session Restoration Resilience**:
136
+ - If the user refreshes or reloads the browser, `initializeTransactionsPool()` inspects the stored transaction.
137
+ - If `tx.hash` is already present, it bypasses Stage 1 completely and resumes directly in Stage 2 (`evmTracker`).
138
+ 4. **Native Explorer Linking**:
139
+ - Links directly to standard block explorers (e.g. Etherscan `/tx/${hash}`) with zero reliance on third-party indexers.
140
+
124
141
  ### 3. Using Standalone Actions
125
142
 
126
143
  This package also exports utility actions that you can wire up to your UI for features like speeding up or canceling transactions.
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Transaction, TxAdapter, ITxTrackingStore, TrackerCallbacks, PollingTrackerConfig, TransactionTracker, CheckTxTracker } from '@tuwaio/pulsar-core';
2
2
  import { Config } from '@wagmi/core';
3
- import { Chain, GetTransactionReturnType, TransactionReceipt, Client, ReplacementReturnType, WaitForTransactionReceiptParameters, Hex, Transport, HttpTransportConfig } from 'viem';
3
+ import { Chain, Hex, GetTransactionReturnType, TransactionReceipt, Client, ReplacementReturnType, WaitForTransactionReceiptParameters, Transport, HttpTransportConfig } from 'viem';
4
+ import { GetUserOperationReceiptReturnType } from 'viem/account-abstraction';
4
5
 
5
6
  /**
6
7
  * @file This file contains the factory function for creating the EVM (Ethereum Virtual Machine) transaction adapter.
@@ -24,6 +25,74 @@ import { Chain, GetTransactionReturnType, TransactionReceipt, Client, Replacemen
24
25
  */
25
26
  declare function pulsarEvmAdapter<T extends Transaction>(config: Config, appChains: readonly [Chain, ...Chain[]]): TxAdapter<T>;
26
27
 
28
+ /**
29
+ * @file This file implements transaction tracking for ERC-4337 UserOperations.
30
+ * It uses a polling mechanism against a Bundler RPC endpoint (e.g., Pimlico)
31
+ * to check the status of a UserOperation via `eth_getUserOperationReceipt`.
32
+ */
33
+
34
+ /**
35
+ * The receipt returned by `getUserOperationReceipt`.
36
+ */
37
+ type Erc4337UserOpReceipt = GetUserOperationReceiptReturnType;
38
+ /**
39
+ * Result structure produced by `erc4337Fetcher` on each polling cycle.
40
+ */
41
+ type Erc4337FetchResult = {
42
+ receipt: Erc4337UserOpReceipt | null;
43
+ status: 'pending' | 'success' | 'failed';
44
+ hash?: Hex;
45
+ reason?: string;
46
+ };
47
+ type Erc4337FetcherParams<T extends Transaction> = Parameters<PollingTrackerConfig<Erc4337FetchResult, T>['fetcher']>[0];
48
+ /**
49
+ * Low-level fetcher for ERC-4337 UserOperation status.
50
+ * Queries `eth_getUserOperationReceipt` on the configured Bundler client.
51
+ *
52
+ * @param params - The fetcher parameters provided by the polling tracker.
53
+ */
54
+ declare function erc4337Fetcher<T extends Transaction>({ tx, stopPolling, onSuccess, onFailure, onIntervalTick, }: Erc4337FetcherParams<T>): Promise<void>;
55
+ /**
56
+ * Configuration options for the low-level ERC-4337 tracker.
57
+ */
58
+ type Erc4337TrackerConfig<T extends Transaction> = {
59
+ tx: T & Pick<Transaction, 'txKey' | 'pending'>;
60
+ onSuccess: (result: Erc4337FetchResult) => void;
61
+ onFailure: (result?: Erc4337FetchResult) => void;
62
+ onIntervalTick?: (result: Erc4337FetchResult) => void;
63
+ removeTxFromPool?: (txKey: string) => void;
64
+ pollingInterval?: number;
65
+ maxRetries?: number;
66
+ };
67
+ /**
68
+ * Initializes a low-level polling tracker for ERC-4337 UserOperations.
69
+ *
70
+ * @param config - The tracker configuration options.
71
+ */
72
+ declare function erc4337Tracker<T extends Transaction>(config: Erc4337TrackerConfig<T>): void;
73
+ /**
74
+ * Parameters for the store-connected ERC-4337 tracker.
75
+ */
76
+ type Erc4337TrackerForStoreParams<T extends Transaction> = Pick<ITxTrackingStore<T>, 'updateTxParams' | 'removeTxFromPool' | 'transactionsPool'> & {
77
+ tx: T;
78
+ config?: Config;
79
+ } & TrackerCallbacks<T>;
80
+ /**
81
+ * High-level two-stage tracker for ERC-4337 UserOperations integrated with the Pulsar store.
82
+ *
83
+ * - Stage 1 (Bundler Mempool): Polls `eth_getUserOperationReceipt` against the Bundler RPC.
84
+ * As soon as the UserOp is bundled on-chain, writes `tx.hash` to the store and stops Bundler polling
85
+ * without evicting the transaction from the pool.
86
+ * - Stage 2 (EVM On-Chain Finality): Hands off tracking to `evmTracker` for on-chain block confirmations,
87
+ * block timestamp resolution, and final terminal status update.
88
+ *
89
+ * Supports seamless session restoration across page reloads: if `tx.hash` is already populated,
90
+ * Stage 1 is bypassed and tracking resumes directly at Stage 2.
91
+ *
92
+ * @param params - The store actions, Wagmi config, and transaction object to track.
93
+ */
94
+ declare function erc4337TrackerForStore<T extends Transaction>({ tx, config, updateTxParams, transactionsPool, onSuccess, onError, onReplaced, }: Erc4337TrackerForStoreParams<T>): Promise<void>;
95
+
27
96
  /**
28
97
  * @file This file contains the tracker implementation for standard EVM transactions.
29
98
  * It uses viem's public actions (`getTransaction`, `waitForTransactionReceipt`) to monitor
@@ -157,11 +226,13 @@ type GelatoTaskStatus = (GelatoBaseStatus & {
157
226
  * - {@link GelatoStatusCode.Rejected} / {@link GelatoStatusCode.Reverted} → `onFailure`
158
227
  * - {@link GelatoStatusCode.Submitted} → `onIntervalTick` (to update the tx hash)
159
228
  *
229
+ * @deprecated Gelato relay is deprecated. Use TransactionTracker.ERC4337 and erc4337Fetcher instead.
160
230
  * @param {ReturnType<Transport>} client - A viem transport client configured for the Gelato API.
161
231
  * @returns {PollingTrackerConfig<GelatoTaskStatus, Transaction>['fetcher']} The fetcher function.
162
232
  */
163
233
  declare function gelatoFetcher(client: ReturnType<Transport>): PollingTrackerConfig<GelatoTaskStatus, Transaction>['fetcher'];
164
234
  /**
235
+ * @deprecated Gelato relay is deprecated. Use TransactionTracker.ERC4337 and erc4337TrackerForStore instead.
165
236
  * A higher-level wrapper that integrates the Gelato polling logic with the Pulsar store.
166
237
  * It creates an authenticated Gelato RPC client and uses {@link gelatoFetcher} to
167
238
  * build the fetcher, then delegates to `initializePollingTracker` with store-specific callbacks.
@@ -180,6 +251,10 @@ declare function gelatoTrackerForStore<T extends Transaction>({ tx, gelatoApiKey
180
251
  tx: T;
181
252
  gelatoApiKey: string;
182
253
  } & TrackerCallbacks<T>): void;
254
+ /**
255
+ * @deprecated Gelato relay is deprecated. Use TransactionTracker.ERC4337 and erc4337Tracker instead.
256
+ */
257
+ declare const gelatoTracker: typeof gelatoTrackerForStore;
183
258
 
184
259
  /**
185
260
  * @file This file implements the transaction tracking logic for Safe (formerly Gnosis Safe) multisig transactions.
@@ -276,7 +351,7 @@ type InitializeTrackerParams<T extends Transaction> = Pick<ITxTrackingStore<T>,
276
351
  /**
277
352
  * Initializes the appropriate tracker for a given transaction based on its `tracker` type.
278
353
  * This function acts as a central router, delegating to the specific tracker implementation
279
- * (e.g., standard EVM, Gelato, or Safe).
354
+ * (e.g., standard EVM, Gelato, Safe, or ERC-4337).
280
355
  *
281
356
  * @template T - The application-specific transaction type, extending the base `Transaction`.
282
357
  * @param {InitializeTrackerParams<T>} params - The parameters for initializing the tracker.
@@ -319,6 +394,7 @@ type GelatoCapabilities = Record<number, GelatoCapabilitiesByChain>;
319
394
  * (`relayer_getCapabilities`) and checks whether the specified chain is present in the response.
320
395
  * Results are cached in memory per API key for the lifetime of the application to minimize network requests.
321
396
  *
397
+ * @deprecated Gelato relay is deprecated. Use TransactionTracker.ERC4337 instead.
322
398
  * @param {number} chainId - The chain identifier to check.
323
399
  * @param {string} gelatoApiKey - The Gelato API key used for authentication.
324
400
  * @returns {Promise<boolean>} A promise that resolves to `true` if Gelato supports the chain, `false` otherwise.
@@ -382,6 +458,7 @@ type GelatoClientConfig = {
382
458
  * Gelato's synchronous relay methods may take up to 10 seconds on the server side,
383
459
  * and the client should not time out before the server does.
384
460
  *
461
+ * @deprecated Gelato relay is deprecated. Use TransactionTracker.ERC4337 and createBundlerRpcClient instead.
385
462
  * @param {GelatoClientConfig} parameters - The configuration for the Gelato client.
386
463
  * @returns {ReturnType<Transport>} A viem transport instance configured for the Gelato API.
387
464
  */
@@ -419,15 +496,14 @@ declare const SafeTransactionServiceUrls: Record<number, string>;
419
496
 
420
497
  /**
421
498
  * Generates a URL to a block explorer or Safe UI for a given transaction.
422
- * It handles different URL structures for standard EVM transactions and Safe multi-sig transactions.
499
+ * It handles different URL structures for standard EVM transactions, Safe multi-sig, and ERC-4337 UserOperations.
500
+ * Both standard transactions and ERC-4337 UserOperations link to the native block explorer (e.g., Etherscan).
423
501
  *
424
502
  * @template T - The transaction type, extending the base `Transaction`.
425
503
  *
426
504
  * @param {object} params - The parameters for the selection.
427
- * @param {TransactionPool<T>} params.transactionsPool - The entire pool of transactions from the store.
428
505
  * @param {Chain[]} params.chains - An array of supported chain objects, typically from `viem/chains`.
429
- * @param {Hex} params.txKey - The unique key (`txKey`) of the transaction for which to generate the link.
430
- * @param {Hex} [params.replacedTxHash] - Optional. If this is a speed-up/cancel transaction, this is the hash of the new transaction.
506
+ * @param {T} params.tx - The transaction object for which to generate the link.
431
507
  *
432
508
  * @returns {string} The full URL to the transaction on the corresponding block explorer or Safe app,
433
509
  * or an empty string if the transaction or required chain configuration is not found.
@@ -481,4 +557,4 @@ declare function speedUpTxAction<T extends Transaction>({ config, tx }: {
481
557
  tx: T;
482
558
  }): Promise<Hex>;
483
559
 
484
- export { type EVMTrackerParams, type GelatoCapabilities, type GelatoCapabilitiesByChain, type GelatoClientConfig, GelatoStatusCode, type GelatoTaskStatus, type GelatoToken, SafeTransactionServiceUrls, type SafeTxStatusResponse, cancelTxAction, checkAndInitializeTrackerInStore, checkIsGelatoAvailable, checkTransactionsTracker, createGelatoClient, evmTracker, evmTrackerForStore, gelatoFetcher, gelatoTrackerForStore, gnosisSafeLinksHelper, isRetryableReceiptError, pulsarEvmAdapter, safeFetcher, safeSdkOptions, safeTrackerForStore, selectEvmTxExplorerLink, speedUpTxAction };
560
+ export { type EVMTrackerParams, type Erc4337FetchResult, type Erc4337TrackerConfig, type Erc4337TrackerForStoreParams, type Erc4337UserOpReceipt, type GelatoCapabilities, type GelatoCapabilitiesByChain, type GelatoClientConfig, GelatoStatusCode, type GelatoTaskStatus, type GelatoToken, SafeTransactionServiceUrls, type SafeTxStatusResponse, cancelTxAction, checkAndInitializeTrackerInStore, checkIsGelatoAvailable, checkTransactionsTracker, createGelatoClient, erc4337Fetcher, erc4337Tracker, erc4337TrackerForStore, evmTracker, evmTrackerForStore, gelatoFetcher, gelatoTracker, gelatoTrackerForStore, gnosisSafeLinksHelper, isRetryableReceiptError, pulsarEvmAdapter, safeFetcher, safeSdkOptions, safeTrackerForStore, selectEvmTxExplorerLink, speedUpTxAction };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Transaction, TxAdapter, ITxTrackingStore, TrackerCallbacks, PollingTrackerConfig, TransactionTracker, CheckTxTracker } from '@tuwaio/pulsar-core';
2
2
  import { Config } from '@wagmi/core';
3
- import { Chain, GetTransactionReturnType, TransactionReceipt, Client, ReplacementReturnType, WaitForTransactionReceiptParameters, Hex, Transport, HttpTransportConfig } from 'viem';
3
+ import { Chain, Hex, GetTransactionReturnType, TransactionReceipt, Client, ReplacementReturnType, WaitForTransactionReceiptParameters, Transport, HttpTransportConfig } from 'viem';
4
+ import { GetUserOperationReceiptReturnType } from 'viem/account-abstraction';
4
5
 
5
6
  /**
6
7
  * @file This file contains the factory function for creating the EVM (Ethereum Virtual Machine) transaction adapter.
@@ -24,6 +25,74 @@ import { Chain, GetTransactionReturnType, TransactionReceipt, Client, Replacemen
24
25
  */
25
26
  declare function pulsarEvmAdapter<T extends Transaction>(config: Config, appChains: readonly [Chain, ...Chain[]]): TxAdapter<T>;
26
27
 
28
+ /**
29
+ * @file This file implements transaction tracking for ERC-4337 UserOperations.
30
+ * It uses a polling mechanism against a Bundler RPC endpoint (e.g., Pimlico)
31
+ * to check the status of a UserOperation via `eth_getUserOperationReceipt`.
32
+ */
33
+
34
+ /**
35
+ * The receipt returned by `getUserOperationReceipt`.
36
+ */
37
+ type Erc4337UserOpReceipt = GetUserOperationReceiptReturnType;
38
+ /**
39
+ * Result structure produced by `erc4337Fetcher` on each polling cycle.
40
+ */
41
+ type Erc4337FetchResult = {
42
+ receipt: Erc4337UserOpReceipt | null;
43
+ status: 'pending' | 'success' | 'failed';
44
+ hash?: Hex;
45
+ reason?: string;
46
+ };
47
+ type Erc4337FetcherParams<T extends Transaction> = Parameters<PollingTrackerConfig<Erc4337FetchResult, T>['fetcher']>[0];
48
+ /**
49
+ * Low-level fetcher for ERC-4337 UserOperation status.
50
+ * Queries `eth_getUserOperationReceipt` on the configured Bundler client.
51
+ *
52
+ * @param params - The fetcher parameters provided by the polling tracker.
53
+ */
54
+ declare function erc4337Fetcher<T extends Transaction>({ tx, stopPolling, onSuccess, onFailure, onIntervalTick, }: Erc4337FetcherParams<T>): Promise<void>;
55
+ /**
56
+ * Configuration options for the low-level ERC-4337 tracker.
57
+ */
58
+ type Erc4337TrackerConfig<T extends Transaction> = {
59
+ tx: T & Pick<Transaction, 'txKey' | 'pending'>;
60
+ onSuccess: (result: Erc4337FetchResult) => void;
61
+ onFailure: (result?: Erc4337FetchResult) => void;
62
+ onIntervalTick?: (result: Erc4337FetchResult) => void;
63
+ removeTxFromPool?: (txKey: string) => void;
64
+ pollingInterval?: number;
65
+ maxRetries?: number;
66
+ };
67
+ /**
68
+ * Initializes a low-level polling tracker for ERC-4337 UserOperations.
69
+ *
70
+ * @param config - The tracker configuration options.
71
+ */
72
+ declare function erc4337Tracker<T extends Transaction>(config: Erc4337TrackerConfig<T>): void;
73
+ /**
74
+ * Parameters for the store-connected ERC-4337 tracker.
75
+ */
76
+ type Erc4337TrackerForStoreParams<T extends Transaction> = Pick<ITxTrackingStore<T>, 'updateTxParams' | 'removeTxFromPool' | 'transactionsPool'> & {
77
+ tx: T;
78
+ config?: Config;
79
+ } & TrackerCallbacks<T>;
80
+ /**
81
+ * High-level two-stage tracker for ERC-4337 UserOperations integrated with the Pulsar store.
82
+ *
83
+ * - Stage 1 (Bundler Mempool): Polls `eth_getUserOperationReceipt` against the Bundler RPC.
84
+ * As soon as the UserOp is bundled on-chain, writes `tx.hash` to the store and stops Bundler polling
85
+ * without evicting the transaction from the pool.
86
+ * - Stage 2 (EVM On-Chain Finality): Hands off tracking to `evmTracker` for on-chain block confirmations,
87
+ * block timestamp resolution, and final terminal status update.
88
+ *
89
+ * Supports seamless session restoration across page reloads: if `tx.hash` is already populated,
90
+ * Stage 1 is bypassed and tracking resumes directly at Stage 2.
91
+ *
92
+ * @param params - The store actions, Wagmi config, and transaction object to track.
93
+ */
94
+ declare function erc4337TrackerForStore<T extends Transaction>({ tx, config, updateTxParams, transactionsPool, onSuccess, onError, onReplaced, }: Erc4337TrackerForStoreParams<T>): Promise<void>;
95
+
27
96
  /**
28
97
  * @file This file contains the tracker implementation for standard EVM transactions.
29
98
  * It uses viem's public actions (`getTransaction`, `waitForTransactionReceipt`) to monitor
@@ -157,11 +226,13 @@ type GelatoTaskStatus = (GelatoBaseStatus & {
157
226
  * - {@link GelatoStatusCode.Rejected} / {@link GelatoStatusCode.Reverted} → `onFailure`
158
227
  * - {@link GelatoStatusCode.Submitted} → `onIntervalTick` (to update the tx hash)
159
228
  *
229
+ * @deprecated Gelato relay is deprecated. Use TransactionTracker.ERC4337 and erc4337Fetcher instead.
160
230
  * @param {ReturnType<Transport>} client - A viem transport client configured for the Gelato API.
161
231
  * @returns {PollingTrackerConfig<GelatoTaskStatus, Transaction>['fetcher']} The fetcher function.
162
232
  */
163
233
  declare function gelatoFetcher(client: ReturnType<Transport>): PollingTrackerConfig<GelatoTaskStatus, Transaction>['fetcher'];
164
234
  /**
235
+ * @deprecated Gelato relay is deprecated. Use TransactionTracker.ERC4337 and erc4337TrackerForStore instead.
165
236
  * A higher-level wrapper that integrates the Gelato polling logic with the Pulsar store.
166
237
  * It creates an authenticated Gelato RPC client and uses {@link gelatoFetcher} to
167
238
  * build the fetcher, then delegates to `initializePollingTracker` with store-specific callbacks.
@@ -180,6 +251,10 @@ declare function gelatoTrackerForStore<T extends Transaction>({ tx, gelatoApiKey
180
251
  tx: T;
181
252
  gelatoApiKey: string;
182
253
  } & TrackerCallbacks<T>): void;
254
+ /**
255
+ * @deprecated Gelato relay is deprecated. Use TransactionTracker.ERC4337 and erc4337Tracker instead.
256
+ */
257
+ declare const gelatoTracker: typeof gelatoTrackerForStore;
183
258
 
184
259
  /**
185
260
  * @file This file implements the transaction tracking logic for Safe (formerly Gnosis Safe) multisig transactions.
@@ -276,7 +351,7 @@ type InitializeTrackerParams<T extends Transaction> = Pick<ITxTrackingStore<T>,
276
351
  /**
277
352
  * Initializes the appropriate tracker for a given transaction based on its `tracker` type.
278
353
  * This function acts as a central router, delegating to the specific tracker implementation
279
- * (e.g., standard EVM, Gelato, or Safe).
354
+ * (e.g., standard EVM, Gelato, Safe, or ERC-4337).
280
355
  *
281
356
  * @template T - The application-specific transaction type, extending the base `Transaction`.
282
357
  * @param {InitializeTrackerParams<T>} params - The parameters for initializing the tracker.
@@ -319,6 +394,7 @@ type GelatoCapabilities = Record<number, GelatoCapabilitiesByChain>;
319
394
  * (`relayer_getCapabilities`) and checks whether the specified chain is present in the response.
320
395
  * Results are cached in memory per API key for the lifetime of the application to minimize network requests.
321
396
  *
397
+ * @deprecated Gelato relay is deprecated. Use TransactionTracker.ERC4337 instead.
322
398
  * @param {number} chainId - The chain identifier to check.
323
399
  * @param {string} gelatoApiKey - The Gelato API key used for authentication.
324
400
  * @returns {Promise<boolean>} A promise that resolves to `true` if Gelato supports the chain, `false` otherwise.
@@ -382,6 +458,7 @@ type GelatoClientConfig = {
382
458
  * Gelato's synchronous relay methods may take up to 10 seconds on the server side,
383
459
  * and the client should not time out before the server does.
384
460
  *
461
+ * @deprecated Gelato relay is deprecated. Use TransactionTracker.ERC4337 and createBundlerRpcClient instead.
385
462
  * @param {GelatoClientConfig} parameters - The configuration for the Gelato client.
386
463
  * @returns {ReturnType<Transport>} A viem transport instance configured for the Gelato API.
387
464
  */
@@ -419,15 +496,14 @@ declare const SafeTransactionServiceUrls: Record<number, string>;
419
496
 
420
497
  /**
421
498
  * Generates a URL to a block explorer or Safe UI for a given transaction.
422
- * It handles different URL structures for standard EVM transactions and Safe multi-sig transactions.
499
+ * It handles different URL structures for standard EVM transactions, Safe multi-sig, and ERC-4337 UserOperations.
500
+ * Both standard transactions and ERC-4337 UserOperations link to the native block explorer (e.g., Etherscan).
423
501
  *
424
502
  * @template T - The transaction type, extending the base `Transaction`.
425
503
  *
426
504
  * @param {object} params - The parameters for the selection.
427
- * @param {TransactionPool<T>} params.transactionsPool - The entire pool of transactions from the store.
428
505
  * @param {Chain[]} params.chains - An array of supported chain objects, typically from `viem/chains`.
429
- * @param {Hex} params.txKey - The unique key (`txKey`) of the transaction for which to generate the link.
430
- * @param {Hex} [params.replacedTxHash] - Optional. If this is a speed-up/cancel transaction, this is the hash of the new transaction.
506
+ * @param {T} params.tx - The transaction object for which to generate the link.
431
507
  *
432
508
  * @returns {string} The full URL to the transaction on the corresponding block explorer or Safe app,
433
509
  * or an empty string if the transaction or required chain configuration is not found.
@@ -481,4 +557,4 @@ declare function speedUpTxAction<T extends Transaction>({ config, tx }: {
481
557
  tx: T;
482
558
  }): Promise<Hex>;
483
559
 
484
- export { type EVMTrackerParams, type GelatoCapabilities, type GelatoCapabilitiesByChain, type GelatoClientConfig, GelatoStatusCode, type GelatoTaskStatus, type GelatoToken, SafeTransactionServiceUrls, type SafeTxStatusResponse, cancelTxAction, checkAndInitializeTrackerInStore, checkIsGelatoAvailable, checkTransactionsTracker, createGelatoClient, evmTracker, evmTrackerForStore, gelatoFetcher, gelatoTrackerForStore, gnosisSafeLinksHelper, isRetryableReceiptError, pulsarEvmAdapter, safeFetcher, safeSdkOptions, safeTrackerForStore, selectEvmTxExplorerLink, speedUpTxAction };
560
+ export { type EVMTrackerParams, type Erc4337FetchResult, type Erc4337TrackerConfig, type Erc4337TrackerForStoreParams, type Erc4337UserOpReceipt, type GelatoCapabilities, type GelatoCapabilitiesByChain, type GelatoClientConfig, GelatoStatusCode, type GelatoTaskStatus, type GelatoToken, SafeTransactionServiceUrls, type SafeTxStatusResponse, cancelTxAction, checkAndInitializeTrackerInStore, checkIsGelatoAvailable, checkTransactionsTracker, createGelatoClient, erc4337Fetcher, erc4337Tracker, erc4337TrackerForStore, evmTracker, evmTrackerForStore, gelatoFetcher, gelatoTracker, gelatoTrackerForStore, gnosisSafeLinksHelper, isRetryableReceiptError, pulsarEvmAdapter, safeFetcher, safeSdkOptions, safeTrackerForStore, selectEvmTxExplorerLink, speedUpTxAction };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var orbitCore=require('@tuwaio/orbit-core'),orbitEvm=require('@tuwaio/orbit-evm'),pulsarCore=require('@tuwaio/pulsar-core'),core=require('@wagmi/core'),viem=require('viem'),actions=require('viem/actions'),b=require('dayjs'),chains=require('viem/chains');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var b__default=/*#__PURE__*/_interopDefault(b);var P=1.15;async function A({config:t,tx:e}){if(e.adapter!==orbitCore.OrbitAdapter.EVM)throw new Error(`Cancellation is only available for EVM transactions. Received adapter type: '${e.adapter}'.`);let{nonce:a,maxFeePerGas:r,maxPriorityFeePerGas:i,chainId:o}=e;if(a===void 0||!r||!i)throw new Error("Transaction is missing required fields for cancellation (nonce, maxFeePerGas, maxPriorityFeePerGas).");try{if(!t)throw new Error("Wagmi config is not provided.");let s=core.getAccount(t);if(!s.address)throw new Error("No connected account found.");let c=BigInt(Math.ceil(Number(i)*P)),n=BigInt(Math.ceil(Number(r)*P));return await core.sendTransaction(t,{to:s.address,value:0n,chainId:o,nonce:a,maxFeePerGas:n,maxPriorityFeePerGas:c})}catch(s){let c=s instanceof Error?s.message:String(s);throw new Error(`Failed to cancel transaction: ${c}`,{cause:s})}}var $=10,H=3e3,R=5,Re=5e3,ve=5e3,Ge=6e4;function K(t){return t?(a=>{if(!(a instanceof Error))return false;if(a instanceof viem.WaitForTransactionReceiptTimeoutError||a instanceof viem.TransactionReceiptNotFoundError||a.name==="WaitForTransactionReceiptTimeoutError"||a.name==="TransactionReceiptNotFoundError"||a instanceof viem.HttpRequestError||a instanceof viem.WebSocketRequestError||a.name==="HttpRequestError"||a.name==="WebSocketRequestError"||a.name==="TimeoutError")return true;let r=a.message.toLowerCase();return r.includes("fetch failed")||r.includes("network error")||r.includes("timeout")||r.includes("timed out")||r.includes("econnreset")||r.includes("rate limit")||r.includes("502")||r.includes("503")||r.includes("504")})(t)?true:t instanceof Error&&"cause"in t&&t.cause?K(t.cause):false:false}async function Ie(t){let{tx:e,config:a,onInitialize:r,onTxDetailsFetched:i,onSuccess:o,onFailure:s,onReplaced:c,retryCount:n=$,retryTimeout:l=H,onConfirmationsUpdate:p,waitForTransactionReceiptParams:f}=t,{requiredConfirmations:m}=e;if(r?.(),e.txKey===viem.zeroHash)return s(new Error("Transaction hash cannot be the zero hash."));let u=core.getClient(a,{chainId:e.chainId});if(!u)return s(new Error(`Could not create a viem client for chainId: ${e.chainId}`));let T=null;for(let h=0;h<n;h++)try{T=await actions.getTransaction(u,{hash:e.txKey}),i(T);break}catch(d){if(h===n-1)return console.error(`[evmTracker] Fatal error fetching transaction ${e.txKey} on chain ${e.chainId}:`,d),s(d);console.warn(`[evmTracker] Error fetching transaction ${e.txKey} on chain ${e.chainId} (attempt ${h+1}/${n}):`,d),await new Promise(g=>setTimeout(g,l));}if(!T)return s(new Error("Transaction details could not be fetched."));let w=false;for(let h=0;h<=R;h++)try{let d=await actions.waitForTransactionReceipt(u,{hash:T.hash,onReplaced:g=>{w=!0,c(g);},retryCount:$,retryDelay:H,timeout:Ge,...f});if(!w){let g=m??1;if(g>1)for(;;){try{let x=await actions.getTransactionConfirmations(u,{transactionReceipt:d}),F=Number(x);if(p?.(F),F>=g)break}catch(x){console.warn(`[evmTracker] Error fetching confirmations for ${e.txKey} on chain ${e.chainId}:`,x);}await new Promise(x=>setTimeout(x,ve));}await o(T,d,u);}return}catch(d){if(K(d)&&!w&&h<R){console.warn(`[evmTracker] Transient error for ${e.txKey} on chain ${e.chainId} (attempt ${h+1}/${R}). Error: ${d instanceof Error?d.name:"Unknown"}. Retrying...`),await new Promise(x=>setTimeout(x,Re*(h+1)));continue}s(d);return}}async function y(t){let{tx:e,config:a,updateTxParams:r,transactionsPool:i,onSuccess:o,onError:s,onReplaced:c}=t;return Ie({tx:e,config:a,onInitialize:()=>{r(e.txKey,{hash:e.txKey});},onTxDetailsFetched:n=>{r(e.txKey,{to:n.to??void 0,input:n.input,value:n.value?.toString(),nonce:n.nonce,maxFeePerGas:n.maxFeePerGas?.toString(),maxPriorityFeePerGas:n.maxPriorityFeePerGas?.toString()});},onConfirmationsUpdate:n=>{r(e.txKey,{confirmations:n});},onSuccess:async(n,l,p)=>{let f=await actions.getBlock(p,{blockNumber:l.blockNumber}),m=Number(f.timestamp),u=l.status==="success";r(e.txKey,{status:u?pulsarCore.TransactionStatus.Success:pulsarCore.TransactionStatus.Failed,isError:!u,pending:false,finishedTimestamp:m});let T=i[e.txKey];u&&o&&T&&o(T),!u&&s&&T&&s(new Error("Transaction reverted"),T);},onReplaced:n=>{r(e.txKey,{status:pulsarCore.TransactionStatus.Replaced,replacedTxHash:n.transaction.hash,pending:false});let l=i[e.txKey];c&&l&&c(l,e);},onFailure:n=>{r(e.txKey,{status:pulsarCore.TransactionStatus.Failed,pending:false,isError:true,error:orbitCore.normalizeError(n)});let l=i[e.txKey];s&&l&&s(n,l);}})}var M=new Map,E=t=>{let{apiKey:e,baseUrl:a,timeout:r}=t,i=a||"https://api.gelato.cloud",o=`${e}:${i}`,s=M.get(o);if(s)return s;let c={timeout:r??15e3,...t.httpTransportConfig,fetchOptions:{headers:{Authorization:`Bearer ${e}`,...t.httpTransportConfig?.fetchOptions?.headers},...t.httpTransportConfig?.fetchOptions}},n=viem.http(`${i}/rpc`,c)({});return M.set(o,n),n};var $e=(o=>(o[o.Pending=100]="Pending",o[o.Submitted=110]="Submitted",o[o.Success=200]="Success",o[o.Rejected=400]="Rejected",o[o.Reverted=500]="Reverted",o))($e||{}),He=new Set([200,400,500]);function Ke(t){return !He.has(t)}function Me(t){return async({tx:e,stopPolling:a,onSuccess:r,onFailure:i,onIntervalTick:o})=>{let s=await t.request({method:"relayer_getStatus",params:{id:e.txKey,logs:false}});o?.(s);let{status:c,createdAt:n}=s;if(n&&b__default.default().diff(b__default.default.unix(n),"hour")>=1&&Ke(c)){a();return}c===200?(r(s),a({withoutRemoving:true})):(c===400||c===500)&&(i(s),a({withoutRemoving:true}));}}function _({tx:t,gelatoApiKey:e,updateTxParams:a,removeTxFromPool:r,transactionsPool:i,onSuccess:o,onError:s}){let c=E({apiKey:e}),n=Me(c);return pulsarCore.initializePollingTracker({tx:t,fetcher:n,removeTxFromPool:r,onSuccess:l=>{let p=l.status===200?l.receipt.transactionHash:void 0;a(t.txKey,{status:pulsarCore.TransactionStatus.Success,pending:false,isError:false,hash:p,finishedTimestamp:b__default.default().unix()});let f=i[t.txKey];o&&f&&o(f);},onIntervalTick:l=>{l.status===110&&a(t.txKey,{hash:l.hash});},onFailure:l=>{let p="Transaction failed or was not found.",f;l&&(l.status===400?p=l.message||"Transaction was rejected by Gelato Relay.":l.status===500&&(p=l.message||"Transaction reverted on-chain.",f=l.receipt.transactionHash));let m=new Error(p);a(t.txKey,{status:pulsarCore.TransactionStatus.Failed,pending:false,isError:true,hash:f,error:orbitCore.normalizeError(m),finishedTimestamp:b__default.default().unix()});let u=i[t.txKey];s&&u&&s(m,u);}})}var $t={allowedDomains:[/gnosis-safe.io$/,/app.safe.global$/,/metissafe.tech$/],debug:false},ee={[chains.mainnet.id]:"https://app.safe.global/eth:",[chains.goerli.id]:"https://app.safe.global/gor:",[chains.sepolia.id]:"https://app.safe.global/sep:",[chains.polygon.id]:"https://app.safe.global/matic:",[chains.arbitrum.id]:"https://app.safe.global/arb1:",[chains.aurora.id]:"https://app.safe.global/aurora:",[chains.avalanche.id]:"https://app.safe.global/avax:",[chains.base.id]:"https://app.safe.global/base:",[chains.boba.id]:"https://app.safe.global/boba:",[chains.bsc.id]:"https://app.safe.global/bnb:",[chains.celo.id]:"https://app.safe.global/celo:",[chains.gnosis.id]:"https://app.safe.global/gno:",[chains.optimism.id]:"https://app.safe.global/oeth:",[chains.polygonZkEvm.id]:"https://app.safe.global/zkevm:",[chains.zksync.id]:"https://app.safe.global/zksync:"},te={[chains.mainnet.id]:"https://safe-transaction-mainnet.safe.global/api/v1",[chains.goerli.id]:"https://safe-transaction-goerli.safe.global/api/v1",[chains.sepolia.id]:"https://safe-transaction-sepolia.safe.global/api/v1",[chains.polygon.id]:"https://safe-transaction-polygon.safe.global/api/v1",[chains.arbitrum.id]:"https://safe-transaction-arbitrum.safe.global/api/v1",[chains.aurora.id]:"https://safe-transaction-aurora.safe.global/api/v1",[chains.avalanche.id]:"https://safe-transaction-avalanche.safe.global/api/v1",[chains.base.id]:"https://safe-transaction-base.safe.global/api/v1",[chains.boba.id]:"https://safe-transaction-boba.safe.global/api/v1",[chains.bsc.id]:"https://safe-transaction-bsc.safe.global/api/v1",[chains.celo.id]:"https://safe-transaction-celo.safe.global/api/v1",[chains.gnosis.id]:"https://safe-transaction-gnosis-chain.safe.global/api/v1",[chains.optimism.id]:"https://safe-transaction-optimism.safe.global/api/v1",[chains.polygonZkEvm.id]:"https://safe-transaction-zkevm.safe.global/api/v1",[chains.zksync.id]:"https://safe-transaction-zksync.safe.global/api/v1"};var Ue=async({tx:t,stopPolling:e,onSuccess:a,onFailure:r,onReplaced:i,onIntervalTick:o})=>{let s=te[t.chainId];if(!s)throw new Error(`Safe Transaction Service URL not found for chainId: ${t.chainId}`);let c=await fetch(`${s}/multisig-transactions/${t.txKey}/`);if(!c.ok)throw c.status===404&&(r(),e()),new Error(`Safe API responded with status: ${c.status}`);let n=await c.json();if(o?.(n),n.isExecuted){n.isSuccessful?a(n):r(n),e({withoutRemoving:true});return}let l=await fetch(`${s}/safes/${t.from}/multisig-transactions/?nonce=${n.nonce}`);if(!l.ok)throw new Error(`Safe API (nonce check) responded with status: ${l.status}`);let f=(await l.json()).results.find(m=>m.isExecuted);if(f){i?.(f),e({withoutRemoving:true});return}b__default.default().diff(b__default.default(n.submissionDate),"day")>=1&&e();};function re({tx:t,updateTxParams:e,removeTxFromPool:a,transactionsPool:r,onSuccess:i,onError:o,onReplaced:s}){return pulsarCore.initializePollingTracker({tx:t,fetcher:Ue,removeTxFromPool:a,onSuccess:c=>{e(t.txKey,{status:pulsarCore.TransactionStatus.Success,pending:false,isError:false,hash:c.transactionHash??void 0,finishedTimestamp:c.executionDate?b__default.default(c.executionDate).unix():void 0});let n=r[t.txKey];i&&n&&i(n);},onIntervalTick:c=>{e(t.txKey,{hash:c.transactionHash??void 0});},onFailure:c=>{let n=c?new Error("Safe transaction failed or was rejected."):new Error("Transaction not found.");e(t.txKey,{status:pulsarCore.TransactionStatus.Failed,pending:false,isError:true,hash:c?.transactionHash??void 0,error:orbitCore.normalizeError(n),finishedTimestamp:c?.executionDate?b__default.default(c.executionDate).unix():void 0});let l=r[t.txKey];o&&l&&o(n,l);},onReplaced:c=>{e(t.txKey,{status:pulsarCore.TransactionStatus.Replaced,pending:false,hash:t.adapter===orbitCore.OrbitAdapter.EVM?t.hash:viem.zeroHash,replacedTxHash:c.safeTxHash??viem.zeroHash,finishedTimestamp:c.executionDate?b__default.default(c.executionDate).unix():void 0});let n=r[t.txKey];s&&n&&s(n,t);}})}async function ne({tracker:t,tx:e,config:a,transactionsPool:r,onSuccess:i,onError:o,onReplaced:s,gelatoApiKey:c,...n}){switch(t){case pulsarCore.TransactionTracker.Ethereum:return y({tx:e,config:a,transactionsPool:r,onSuccess:i,onError:o,onReplaced:s,...n});case pulsarCore.TransactionTracker.Gelato:return c?_({tx:e,transactionsPool:r,onSuccess:i,onError:o,gelatoApiKey:c,...n}):(console.warn(`Gelato tracker requested for tx '${e.txKey}', but no 'gelatoApiKey' was provided. Falling back to default EVM tracker.`),y({tx:e,config:a,transactionsPool:r,onSuccess:i,onError:o,onReplaced:s,...n}));case pulsarCore.TransactionTracker.Safe:return re({tx:e,transactionsPool:r,onSuccess:i,onError:o,onReplaced:s,...n});default:return console.warn(`Unknown tracker type: '${t}'. Falling back to default EVM tracker.`),y({tx:e,config:a,transactionsPool:r,onSuccess:i,onError:o,onReplaced:s,...n})}}function oe({actionTxKey:t,connectorType:e,tracker:a,gelatoApiKey:r}){if(a&&a===pulsarCore.TransactionTracker.Gelato&&r)return {tracker:pulsarCore.TransactionTracker.Gelato,txKey:t};if(!viem.isHex(t))throw new Error(`Invalid transaction key format. Expected a Hex string or a GelatoTxKey object, but received: ${JSON.stringify(t)}`);let i=e.split(":");return (i.length>1?i[i.length-1]==="safe"||i[i.length-1]==="safewallet":e?.toLowerCase()==="safe")?{tracker:pulsarCore.TransactionTracker.Safe,txKey:t}:{tracker:pulsarCore.TransactionTracker.Ethereum,txKey:t}}var se=({chains:t,tx:e})=>{if(e.tracker===pulsarCore.TransactionTracker.Safe){let o=ee[e.chainId];return o?`${o}${e.from}/transactions/tx?id=multisig_${e.from}_${e.txKey}`:""}let r=t.find(o=>o.id===e.chainId)?.blockExplorers?.default.url;if(!r)return "";let i=(e.adapter===orbitCore.OrbitAdapter.EVM?e.replacedTxHash:e.txKey)||(e.adapter===orbitCore.OrbitAdapter.EVM?e.hash:e.txKey);return i?`${r}/tx/${i}`:""};var ce=1.15;async function le({config:t,tx:e}){if(e.adapter!==orbitCore.OrbitAdapter.EVM)throw new Error(`Speed up is only available for EVM transactions. Received adapter type: '${e.adapter}'.`);let{nonce:a,from:r,to:i,value:o,input:s,maxFeePerGas:c,maxPriorityFeePerGas:n,chainId:l}=e;if(a===void 0||!r||!i||!o||!c||!n)throw new Error("Transaction is missing required fields for speed-up.");try{if(!t)throw new Error("Wagmi config is not provided.");if(!core.getAccount(t).address)throw new Error("No connected account found.");let f=BigInt(Math.ceil(Number(n)*ce)),m=BigInt(Math.ceil(Number(c)*ce));return await core.sendTransaction(t,{to:i,value:BigInt(o),data:s||"0x",chainId:l,nonce:a,maxFeePerGas:m,maxPriorityFeePerGas:f})}catch(p){let f=p instanceof Error?p.message:String(p);throw new Error(`Failed to speed up transaction: ${f}`,{cause:p})}}function va(t,e){if(!t)throw new Error("EVM adapter requires a wagmi config object.");return {key:orbitCore.OrbitAdapter.EVM,getConnectorInfo:()=>{let a=core.getConnection(t),r=orbitCore.lastConnectedConnectorHelpers.getLastConnectedConnector();return {walletAddress:a.address??r?.address??viem.zeroAddress,connectorType:orbitCore.getConnectorTypeFromName(orbitCore.OrbitAdapter.EVM,a.connector?.name?.toLowerCase()??"unknown")}},checkChainForTx:a=>orbitEvm.checkAndSwitchChain(a,t),checkTransactionsTracker:a=>oe(a),checkAndInitializeTrackerInStore:({tx:a,...r})=>ne({tracker:a.tracker,tx:a,config:t,...r}),getExplorerUrl:a=>{let{chain:r}=core.getConnection(t),i=r?.blockExplorers?.default.url;return a?`${i}/${a}`:i},getExplorerTxUrl:a=>se({chains:e,tx:a}),cancelTxAction:a=>A({config:t,tx:a}),speedUpTxAction:a=>le({config:t,tx:a}),retryTxAction:async({onClose:a,txKey:r,executeTxAction:i,tx:o})=>{if(a(r),!i){console.error("Retry failed: executeTxAction function is not provided.");return}await i({actionFunction:()=>o.actionFunction({config:t,...o.payload}),params:o,defaultTracker:pulsarCore.TransactionTracker.Ethereum});}}}var I=new Map;async function Xe(t){let e=await t.request({method:"relayer_getCapabilities",params:[]}),a={};for(let[r,i]of Object.entries(e))a[Number(r)]=i;return a}async function Ze(t){let e=I.get(t);if(e)return e;let a=E({apiKey:t}),r=await Xe(a);return I.set(t,r),r}async function Fa(t,e){try{let a=await Ze(e);return t in a}catch(a){return console.error("Failed to fetch Gelato relay capabilities:",a),I.delete(e),false}}
2
- exports.GelatoStatusCode=$e;exports.SafeTransactionServiceUrls=te;exports.cancelTxAction=A;exports.checkAndInitializeTrackerInStore=ne;exports.checkIsGelatoAvailable=Fa;exports.checkTransactionsTracker=oe;exports.createGelatoClient=E;exports.evmTracker=Ie;exports.evmTrackerForStore=y;exports.gelatoFetcher=Me;exports.gelatoTrackerForStore=_;exports.gnosisSafeLinksHelper=ee;exports.isRetryableReceiptError=K;exports.pulsarEvmAdapter=va;exports.safeFetcher=Ue;exports.safeSdkOptions=$t;exports.safeTrackerForStore=re;exports.selectEvmTxExplorerLink=se;exports.speedUpTxAction=le;
1
+ 'use strict';var orbitCore=require('@tuwaio/orbit-core'),orbitEvm=require('@tuwaio/orbit-evm'),pulsarCore=require('@tuwaio/pulsar-core'),core=require('@wagmi/core'),viem=require('viem'),E=require('dayjs'),actions=require('viem/actions'),chains=require('viem/chains');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var E__default=/*#__PURE__*/_interopDefault(E);var $=1.15;async function N({config:e,tx:t}){if(t.adapter!==orbitCore.OrbitAdapter.EVM)throw new Error(`Cancellation is only available for EVM transactions. Received adapter type: '${t.adapter}'.`);let{nonce:r,maxFeePerGas:a,maxPriorityFeePerGas:i,chainId:o}=t;if(r===void 0||!a||!i)throw new Error("Transaction is missing required fields for cancellation (nonce, maxFeePerGas, maxPriorityFeePerGas).");try{if(!e)throw new Error("Wagmi config is not provided.");let s=core.getAccount(e);if(!s.address)throw new Error("No connected account found.");let c=BigInt(Math.ceil(Number(i)*$)),n=BigInt(Math.ceil(Number(a)*$));return await core.sendTransaction(e,{to:s.address,value:0n,chainId:o,nonce:r,maxFeePerGas:n,maxPriorityFeePerGas:c})}catch(s){let c=s instanceof Error?s.message:String(s);throw new Error(`Failed to cancel transaction: ${c}`,{cause:s})}}var M=10,U=3e3,I=5,Ke=5e3,He=5e3,Ae=6e4;function O(e){return e?(r=>{if(!(r instanceof Error))return false;if(r instanceof viem.WaitForTransactionReceiptTimeoutError||r instanceof viem.TransactionReceiptNotFoundError||r.name==="WaitForTransactionReceiptTimeoutError"||r.name==="TransactionReceiptNotFoundError"||r instanceof viem.HttpRequestError||r instanceof viem.WebSocketRequestError||r.name==="HttpRequestError"||r.name==="WebSocketRequestError"||r.name==="TimeoutError")return true;let a=r.message.toLowerCase();return a.includes("fetch failed")||a.includes("network error")||a.includes("timeout")||a.includes("timed out")||a.includes("econnreset")||a.includes("rate limit")||a.includes("502")||a.includes("503")||a.includes("504")})(e)?true:e instanceof Error&&"cause"in e&&e.cause?O(e.cause):false:false}async function G(e){let{tx:t,config:r,onInitialize:a,onTxDetailsFetched:i,onSuccess:o,onFailure:s,onReplaced:c,retryCount:n=M,retryTimeout:l=U,onConfirmationsUpdate:f,waitForTransactionReceiptParams:u}=e,{requiredConfirmations:p}=t;if(a?.(),t.txKey===viem.zeroHash)return s(new Error("Transaction hash cannot be the zero hash."));let d=core.getClient(r,{chainId:t.chainId});if(!d)return s(new Error(`Could not create a viem client for chainId: ${t.chainId}`));let h=null;for(let T=0;T<n;T++)try{h=await actions.getTransaction(d,{hash:t.txKey}),i(h);break}catch(m){if(T===n-1)return console.error(`[evmTracker] Fatal error fetching transaction ${t.txKey} on chain ${t.chainId}:`,m),s(m);console.warn(`[evmTracker] Error fetching transaction ${t.txKey} on chain ${t.chainId} (attempt ${T+1}/${n}):`,m),await new Promise(g=>setTimeout(g,l));}if(!h)return s(new Error("Transaction details could not be fetched."));let k=false;for(let T=0;T<=I;T++)try{let m=await actions.waitForTransactionReceipt(d,{hash:h.hash,onReplaced:g=>{k=!0,c(g);},retryCount:M,retryDelay:U,timeout:Ae,...u});if(!k){let g=p??1;if(g>1)for(;;){try{let x=await actions.getTransactionConfirmations(d,{transactionReceipt:m}),A=Number(x);if(f?.(A),A>=g)break}catch(x){console.warn(`[evmTracker] Error fetching confirmations for ${t.txKey} on chain ${t.chainId}:`,x);}await new Promise(x=>setTimeout(x,He));}await o(h,m,d);}return}catch(m){if(O(m)&&!k&&T<I){console.warn(`[evmTracker] Transient error for ${t.txKey} on chain ${t.chainId} (attempt ${T+1}/${I}). Error: ${m instanceof Error?m.name:"Unknown"}. Retrying...`),await new Promise(x=>setTimeout(x,Ke*(T+1)));continue}s(m);return}}async function w(e){let{tx:t,config:r,updateTxParams:a,transactionsPool:i,onSuccess:o,onError:s,onReplaced:c}=e;return G({tx:t,config:r,onInitialize:()=>{a(t.txKey,{hash:t.txKey});},onTxDetailsFetched:n=>{a(t.txKey,{to:n.to??void 0,input:n.input,value:n.value?.toString(),nonce:n.nonce,maxFeePerGas:n.maxFeePerGas?.toString(),maxPriorityFeePerGas:n.maxPriorityFeePerGas?.toString()});},onConfirmationsUpdate:n=>{a(t.txKey,{confirmations:n});},onSuccess:async(n,l,f)=>{let u=await actions.getBlock(f,{blockNumber:l.blockNumber}),p=Number(u.timestamp),d=l.status==="success";a(t.txKey,{status:d?pulsarCore.TransactionStatus.Success:pulsarCore.TransactionStatus.Failed,isError:!d,pending:false,finishedTimestamp:p});let h=i[t.txKey];d&&o&&h&&o(h),!d&&s&&h&&s(new Error("Transaction reverted"),h);},onReplaced:n=>{a(t.txKey,{status:pulsarCore.TransactionStatus.Replaced,replacedTxHash:n.transaction.hash,pending:false});let l=i[t.txKey];c&&l&&c(l,t);},onFailure:n=>{a(t.txKey,{status:pulsarCore.TransactionStatus.Failed,pending:false,isError:true,error:orbitCore.normalizeError(n)});let l=i[t.txKey];s&&l&&s(n,l);}})}async function B({tx:e,stopPolling:t,onSuccess:r,onFailure:a,onIntervalTick:i}){let o=e,s=o.chainId,c=typeof s=="number"?s:parseInt(String(s),10);if(!c||Number.isNaN(c)){t({withoutRemoving:true}),a({receipt:null,status:"failed",reason:`Invalid chainId: ${String(s)}`});return}let n=orbitEvm.createBundlerRpcClient({chainId:c,apiKey:o.pimlicoApiKey,bundlerUrl:o.bundlerUrl}),l;try{l=await n.getUserOperationReceipt({hash:o.txKey});}catch(u){let p=u;if(p?.name==="UserOperationReceiptNotFoundError"||p?.message?.includes("could not be found")||p?.shortMessage?.includes("could not be found")||p?.details?.includes("could not be found")||p?.message?.includes("not been processed yet")||p?.shortMessage?.includes("not been processed yet")){i?.({receipt:null,status:"pending"});return}throw u}if(!l){i?.({receipt:null,status:"pending"});return}let f=l.receipt?.transactionHash??l.transactionHash;l.success?(t({withoutRemoving:true}),r({receipt:l,status:"success",hash:f})):(t({withoutRemoving:true}),a({receipt:l,status:"failed",hash:f,reason:l.reason??"UserOperation reverted on-chain."}));}function Ut(e){return pulsarCore.initializePollingTracker({...e,fetcher:B,pollingInterval:e.pollingInterval??2e3,maxRetries:e.maxRetries??60})}async function L({tx:e,config:t,updateTxParams:r,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s}){let c=async l=>{if(t)return G({tx:{chainId:e.chainId,txKey:l,requiredConfirmations:e.requiredConfirmations},config:t,onTxDetailsFetched:u=>{r(e.txKey,{to:u.to??void 0,input:u.input,value:u.value?.toString(),nonce:u.nonce,maxFeePerGas:u.maxFeePerGas?.toString(),maxPriorityFeePerGas:u.maxPriorityFeePerGas?.toString()});},onConfirmationsUpdate:u=>{r(e.txKey,{confirmations:u});},onSuccess:async(u,p,d)=>{let h=await actions.getBlock(d,{blockNumber:p.blockNumber}),k=Number(h.timestamp),T=p.status==="success";r(e.txKey,{status:T?pulsarCore.TransactionStatus.Success:pulsarCore.TransactionStatus.Failed,isError:!T,pending:false,hash:l,finishedTimestamp:k});let m=a[e.txKey];T&&i&&m&&i(m),!T&&o&&m&&o(new Error("Transaction reverted on-chain."),m);},onFailure:u=>{r(e.txKey,{status:pulsarCore.TransactionStatus.Failed,pending:false,isError:true,hash:l,error:orbitCore.normalizeError(u),finishedTimestamp:E__default.default().unix()});let p=a[e.txKey];o&&p&&o(u,p);},onReplaced:u=>{r(e.txKey,{status:pulsarCore.TransactionStatus.Replaced,replacedTxHash:u.transaction.hash,pending:false});let p=a[e.txKey];s&&p&&s(p,e);}});r(e.txKey,{status:pulsarCore.TransactionStatus.Success,pending:false,isError:false,hash:l,finishedTimestamp:E__default.default().unix()});let f=a[e.txKey];i&&f&&i(f);},n=e;if(n.hash)return c(n.hash);pulsarCore.initializePollingTracker({tx:e,fetcher:B,pollingInterval:2e3,maxRetries:60,onSuccess:async l=>{let f=l.hash;if(!f){r(e.txKey,{status:pulsarCore.TransactionStatus.Success,pending:false,isError:false,finishedTimestamp:E__default.default().unix()});let u=a[e.txKey];i&&u&&i(u);return}r(e.txKey,{hash:f}),await c(f);},onIntervalTick:l=>{l.hash&&r(e.txKey,{hash:l.hash});},onFailure:l=>{let f=l?.reason||"UserOperation failed or was not found.",u=l?.hash,p=new Error(f);r(e.txKey,{status:pulsarCore.TransactionStatus.Failed,pending:false,isError:true,hash:u,error:orbitCore.normalizeError(p),finishedTimestamp:E__default.default().unix()});let d=a[e.txKey];o&&d&&o(p,d);}});}var j=new Map,R=e=>{let{apiKey:t,baseUrl:r,timeout:a}=e,i=r||"https://api.gelato.cloud",o=`${t}:${i}`,s=j.get(o);if(s)return s;let c={timeout:a??15e3,...e.httpTransportConfig,fetchOptions:{headers:{Authorization:`Bearer ${t}`,...e.httpTransportConfig?.fetchOptions?.headers},...e.httpTransportConfig?.fetchOptions}},n=viem.http(`${i}/rpc`,c)({});return j.set(o,n),n};var _e=(o=>(o[o.Pending=100]="Pending",o[o.Submitted=110]="Submitted",o[o.Success=200]="Success",o[o.Rejected=400]="Rejected",o[o.Reverted=500]="Reverted",o))(_e||{}),ze=new Set([200,400,500]);function Be(e){return !ze.has(e)}function Le(e){return async({tx:t,stopPolling:r,onSuccess:a,onFailure:i,onIntervalTick:o})=>{let s=await e.request({method:"relayer_getStatus",params:{id:t.txKey,logs:false}});o?.(s);let{status:c,createdAt:n}=s;if(n&&E__default.default().diff(E__default.default.unix(n),"hour")>=1&&Be(c)){r();return}c===200?(a(s),r({withoutRemoving:true})):(c===400||c===500)&&(i(s),r({withoutRemoving:true}));}}function P({tx:e,gelatoApiKey:t,updateTxParams:r,removeTxFromPool:a,transactionsPool:i,onSuccess:o,onError:s}){let c=R({apiKey:t}),n=Le(c);return pulsarCore.initializePollingTracker({tx:e,fetcher:n,removeTxFromPool:a,onSuccess:l=>{let f=l.status===200?l.receipt.transactionHash:void 0;r(e.txKey,{status:pulsarCore.TransactionStatus.Success,pending:false,isError:false,hash:f,finishedTimestamp:E__default.default().unix()});let u=i[e.txKey];o&&u&&o(u);},onIntervalTick:l=>{l.status===110&&r(e.txKey,{hash:l.hash});},onFailure:l=>{let f="Transaction failed or was not found.",u;l&&(l.status===400?f=l.message||"Transaction was rejected by Gelato Relay.":l.status===500&&(f=l.message||"Transaction reverted on-chain.",u=l.receipt.transactionHash));let p=new Error(f);r(e.txKey,{status:pulsarCore.TransactionStatus.Failed,pending:false,isError:true,hash:u,error:orbitCore.normalizeError(p),finishedTimestamp:E__default.default().unix()});let d=i[e.txKey];s&&d&&s(p,d);}})}var Zt=P;var tr={allowedDomains:[/gnosis-safe.io$/,/app.safe.global$/,/metissafe.tech$/],debug:false},se={[chains.mainnet.id]:"https://app.safe.global/eth:",[chains.goerli.id]:"https://app.safe.global/gor:",[chains.sepolia.id]:"https://app.safe.global/sep:",[chains.polygon.id]:"https://app.safe.global/matic:",[chains.arbitrum.id]:"https://app.safe.global/arb1:",[chains.aurora.id]:"https://app.safe.global/aurora:",[chains.avalanche.id]:"https://app.safe.global/avax:",[chains.base.id]:"https://app.safe.global/base:",[chains.boba.id]:"https://app.safe.global/boba:",[chains.bsc.id]:"https://app.safe.global/bnb:",[chains.celo.id]:"https://app.safe.global/celo:",[chains.gnosis.id]:"https://app.safe.global/gno:",[chains.optimism.id]:"https://app.safe.global/oeth:",[chains.polygonZkEvm.id]:"https://app.safe.global/zkevm:",[chains.zksync.id]:"https://app.safe.global/zksync:"},ce={[chains.mainnet.id]:"https://safe-transaction-mainnet.safe.global/api/v1",[chains.goerli.id]:"https://safe-transaction-goerli.safe.global/api/v1",[chains.sepolia.id]:"https://safe-transaction-sepolia.safe.global/api/v1",[chains.polygon.id]:"https://safe-transaction-polygon.safe.global/api/v1",[chains.arbitrum.id]:"https://safe-transaction-arbitrum.safe.global/api/v1",[chains.aurora.id]:"https://safe-transaction-aurora.safe.global/api/v1",[chains.avalanche.id]:"https://safe-transaction-avalanche.safe.global/api/v1",[chains.base.id]:"https://safe-transaction-base.safe.global/api/v1",[chains.boba.id]:"https://safe-transaction-boba.safe.global/api/v1",[chains.bsc.id]:"https://safe-transaction-bsc.safe.global/api/v1",[chains.celo.id]:"https://safe-transaction-celo.safe.global/api/v1",[chains.gnosis.id]:"https://safe-transaction-gnosis-chain.safe.global/api/v1",[chains.optimism.id]:"https://safe-transaction-optimism.safe.global/api/v1",[chains.polygonZkEvm.id]:"https://safe-transaction-zkevm.safe.global/api/v1",[chains.zksync.id]:"https://safe-transaction-zksync.safe.global/api/v1"};var De=async({tx:e,stopPolling:t,onSuccess:r,onFailure:a,onReplaced:i,onIntervalTick:o})=>{let s=ce[e.chainId];if(!s)throw new Error(`Safe Transaction Service URL not found for chainId: ${e.chainId}`);let c=await fetch(`${s}/multisig-transactions/${e.txKey}/`);if(!c.ok)throw c.status===404&&(a(),t()),new Error(`Safe API responded with status: ${c.status}`);let n=await c.json();if(o?.(n),n.isExecuted){n.isSuccessful?r(n):a(n),t({withoutRemoving:true});return}let l=await fetch(`${s}/safes/${e.from}/multisig-transactions/?nonce=${n.nonce}`);if(!l.ok)throw new Error(`Safe API (nonce check) responded with status: ${l.status}`);let u=(await l.json()).results.find(p=>p.isExecuted);if(u){i?.(u),t({withoutRemoving:true});return}E__default.default().diff(E__default.default(n.submissionDate),"day")>=1&&t();};function ue({tx:e,updateTxParams:t,removeTxFromPool:r,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s}){return pulsarCore.initializePollingTracker({tx:e,fetcher:De,removeTxFromPool:r,onSuccess:c=>{t(e.txKey,{status:pulsarCore.TransactionStatus.Success,pending:false,isError:false,hash:c.transactionHash??void 0,finishedTimestamp:c.executionDate?E__default.default(c.executionDate).unix():void 0});let n=a[e.txKey];i&&n&&i(n);},onIntervalTick:c=>{t(e.txKey,{hash:c.transactionHash??void 0});},onFailure:c=>{let n=c?new Error("Safe transaction failed or was rejected."):new Error("Transaction not found.");t(e.txKey,{status:pulsarCore.TransactionStatus.Failed,pending:false,isError:true,hash:c?.transactionHash??void 0,error:orbitCore.normalizeError(n),finishedTimestamp:c?.executionDate?E__default.default(c.executionDate).unix():void 0});let l=a[e.txKey];o&&l&&o(n,l);},onReplaced:c=>{t(e.txKey,{status:pulsarCore.TransactionStatus.Replaced,pending:false,hash:e.adapter===orbitCore.OrbitAdapter.EVM?e.hash:viem.zeroHash,replacedTxHash:c.safeTxHash??viem.zeroHash,finishedTimestamp:c.executionDate?E__default.default(c.executionDate).unix():void 0});let n=a[e.txKey];s&&n&&s(n,e);}})}async function pe({tracker:e,tx:t,config:r,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s,gelatoApiKey:c,...n}){switch(e){case pulsarCore.TransactionTracker.Ethereum:return w({tx:t,config:r,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s,...n});case pulsarCore.TransactionTracker.ERC4337:return L({tx:t,config:r,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s,...n});case pulsarCore.TransactionTracker.Gelato:return c?P({tx:t,transactionsPool:a,onSuccess:i,onError:o,gelatoApiKey:c,...n}):(console.warn(`Gelato tracker requested for tx '${t.txKey}', but no 'gelatoApiKey' was provided. Falling back to default EVM tracker.`),w({tx:t,config:r,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s,...n}));case pulsarCore.TransactionTracker.Safe:return ue({tx:t,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s,...n});default:return console.warn(`Unknown tracker type: '${e}'. Falling back to default EVM tracker.`),w({tx:t,config:r,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s,...n})}}function fe({actionTxKey:e,connectorType:t,tracker:r,gelatoApiKey:a}){if(r&&r===pulsarCore.TransactionTracker.Gelato&&a)return {tracker:pulsarCore.TransactionTracker.Gelato,txKey:e};if(!viem.isHex(e))throw new Error(`Invalid transaction key format. Expected a Hex string or a GelatoTxKey object, but received: ${JSON.stringify(e)}`);if(r&&r===pulsarCore.TransactionTracker.ERC4337)return {tracker:pulsarCore.TransactionTracker.ERC4337,txKey:e};let i=t.split(":");return (i.length>1?i[i.length-1]==="safe"||i[i.length-1]==="safewallet":t?.toLowerCase()==="safe")?{tracker:pulsarCore.TransactionTracker.Safe,txKey:e}:{tracker:pulsarCore.TransactionTracker.Ethereum,txKey:e}}var de=({chains:e,tx:t})=>{if(t.tracker===pulsarCore.TransactionTracker.Safe){let c=se[t.chainId];return c?`${c}${t.from}/transactions/tx?id=multisig_${t.from}_${t.txKey}`:""}let a=e.find(c=>c.id===t.chainId)?.blockExplorers?.default.url;if(!a)return "";let o=t.adapter===orbitCore.OrbitAdapter.EVM?t:void 0,s=o?.replacedTxHash||o?.hash||t.txKey;return s?`${a}/tx/${s}`:""};var me=1.15;async function Te({config:e,tx:t}){if(t.adapter!==orbitCore.OrbitAdapter.EVM)throw new Error(`Speed up is only available for EVM transactions. Received adapter type: '${t.adapter}'.`);let{nonce:r,from:a,to:i,value:o,input:s,maxFeePerGas:c,maxPriorityFeePerGas:n,chainId:l}=t;if(r===void 0||!a||!i||!o||!c||!n)throw new Error("Transaction is missing required fields for speed-up.");try{if(!e)throw new Error("Wagmi config is not provided.");if(!core.getAccount(e).address)throw new Error("No connected account found.");let u=BigInt(Math.ceil(Number(n)*me)),p=BigInt(Math.ceil(Number(c)*me));return await core.sendTransaction(e,{to:i,value:BigInt(o),data:s||"0x",chainId:l,nonce:r,maxFeePerGas:p,maxPriorityFeePerGas:u})}catch(f){let u=f instanceof Error?f.message:String(f);throw new Error(`Failed to speed up transaction: ${u}`,{cause:f})}}function Xr(e,t){if(!e)throw new Error("EVM adapter requires a wagmi config object.");return {key:orbitCore.OrbitAdapter.EVM,getConnectorInfo:()=>{let r=core.getConnection(e),a=orbitCore.lastConnectedConnectorHelpers.getLastConnectedConnector();return {walletAddress:r.address??a?.address??viem.zeroAddress,connectorType:orbitCore.getConnectorTypeFromName(orbitCore.OrbitAdapter.EVM,r.connector?.name?.toLowerCase()??"unknown")}},checkChainForTx:r=>orbitEvm.checkAndSwitchChain(r,e),checkTransactionsTracker:r=>fe(r),checkAndInitializeTrackerInStore:({tx:r,...a})=>pe({tracker:r.tracker,tx:r,config:e,...a}),getExplorerUrl:r=>{let{chain:a}=core.getConnection(e),i=a?.blockExplorers?.default.url;return r?`${i}/${r}`:i},getExplorerTxUrl:r=>de({chains:t,tx:r}),cancelTxAction:r=>N({config:e,tx:r}),speedUpTxAction:r=>Te({config:e,tx:r}),retryTxAction:async({onClose:r,txKey:a,executeTxAction:i,tx:o})=>{if(r(a),!i){console.error("Retry failed: executeTxAction function is not provided.");return}await i({actionFunction:()=>o.actionFunction({config:e,...o.payload}),params:o,defaultTracker:pulsarCore.TransactionTracker.Ethereum});}}}var H=new Map;async function ot(e){let t=await e.request({method:"relayer_getCapabilities",params:[]}),r={};for(let[a,i]of Object.entries(t))r[Number(a)]=i;return r}async function it(e){let t=H.get(e);if(t)return t;let r=R({apiKey:e}),a=await ot(r);return H.set(e,a),a}async function ea(e,t){try{let r=await it(t);return e in r}catch(r){return console.error("Failed to fetch Gelato relay capabilities:",r),H.delete(t),false}}
2
+ exports.GelatoStatusCode=_e;exports.SafeTransactionServiceUrls=ce;exports.cancelTxAction=N;exports.checkAndInitializeTrackerInStore=pe;exports.checkIsGelatoAvailable=ea;exports.checkTransactionsTracker=fe;exports.createGelatoClient=R;exports.erc4337Fetcher=B;exports.erc4337Tracker=Ut;exports.erc4337TrackerForStore=L;exports.evmTracker=G;exports.evmTrackerForStore=w;exports.gelatoFetcher=Le;exports.gelatoTracker=Zt;exports.gelatoTrackerForStore=P;exports.gnosisSafeLinksHelper=se;exports.isRetryableReceiptError=O;exports.pulsarEvmAdapter=Xr;exports.safeFetcher=De;exports.safeSdkOptions=tr;exports.safeTrackerForStore=ue;exports.selectEvmTxExplorerLink=de;exports.speedUpTxAction=Te;
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import {OrbitAdapter,normalizeError,lastConnectedConnectorHelpers,getConnectorTypeFromName}from'@tuwaio/orbit-core';import {checkAndSwitchChain}from'@tuwaio/orbit-evm';import {TransactionStatus,initializePollingTracker,TransactionTracker}from'@tuwaio/pulsar-core';import {getAccount,sendTransaction,getClient,getConnection}from'@wagmi/core';import {WaitForTransactionReceiptTimeoutError,TransactionReceiptNotFoundError,HttpRequestError,WebSocketRequestError,zeroHash,http,isHex,zeroAddress}from'viem';import {getTransaction,waitForTransactionReceipt,getTransactionConfirmations,getBlock}from'viem/actions';import b from'dayjs';import {zksync,polygonZkEvm,optimism,gnosis,celo,bsc,boba,base,avalanche,aurora,arbitrum,polygon,sepolia,goerli,mainnet}from'viem/chains';var P=1.15;async function A({config:t,tx:e}){if(e.adapter!==OrbitAdapter.EVM)throw new Error(`Cancellation is only available for EVM transactions. Received adapter type: '${e.adapter}'.`);let{nonce:a,maxFeePerGas:r,maxPriorityFeePerGas:i,chainId:o}=e;if(a===void 0||!r||!i)throw new Error("Transaction is missing required fields for cancellation (nonce, maxFeePerGas, maxPriorityFeePerGas).");try{if(!t)throw new Error("Wagmi config is not provided.");let s=getAccount(t);if(!s.address)throw new Error("No connected account found.");let c=BigInt(Math.ceil(Number(i)*P)),n=BigInt(Math.ceil(Number(r)*P));return await sendTransaction(t,{to:s.address,value:0n,chainId:o,nonce:a,maxFeePerGas:n,maxPriorityFeePerGas:c})}catch(s){let c=s instanceof Error?s.message:String(s);throw new Error(`Failed to cancel transaction: ${c}`,{cause:s})}}var $=10,H=3e3,R=5,Re=5e3,ve=5e3,Ge=6e4;function K(t){return t?(a=>{if(!(a instanceof Error))return false;if(a instanceof WaitForTransactionReceiptTimeoutError||a instanceof TransactionReceiptNotFoundError||a.name==="WaitForTransactionReceiptTimeoutError"||a.name==="TransactionReceiptNotFoundError"||a instanceof HttpRequestError||a instanceof WebSocketRequestError||a.name==="HttpRequestError"||a.name==="WebSocketRequestError"||a.name==="TimeoutError")return true;let r=a.message.toLowerCase();return r.includes("fetch failed")||r.includes("network error")||r.includes("timeout")||r.includes("timed out")||r.includes("econnreset")||r.includes("rate limit")||r.includes("502")||r.includes("503")||r.includes("504")})(t)?true:t instanceof Error&&"cause"in t&&t.cause?K(t.cause):false:false}async function Ie(t){let{tx:e,config:a,onInitialize:r,onTxDetailsFetched:i,onSuccess:o,onFailure:s,onReplaced:c,retryCount:n=$,retryTimeout:l=H,onConfirmationsUpdate:p,waitForTransactionReceiptParams:f}=t,{requiredConfirmations:m}=e;if(r?.(),e.txKey===zeroHash)return s(new Error("Transaction hash cannot be the zero hash."));let u=getClient(a,{chainId:e.chainId});if(!u)return s(new Error(`Could not create a viem client for chainId: ${e.chainId}`));let T=null;for(let h=0;h<n;h++)try{T=await getTransaction(u,{hash:e.txKey}),i(T);break}catch(d){if(h===n-1)return console.error(`[evmTracker] Fatal error fetching transaction ${e.txKey} on chain ${e.chainId}:`,d),s(d);console.warn(`[evmTracker] Error fetching transaction ${e.txKey} on chain ${e.chainId} (attempt ${h+1}/${n}):`,d),await new Promise(g=>setTimeout(g,l));}if(!T)return s(new Error("Transaction details could not be fetched."));let w=false;for(let h=0;h<=R;h++)try{let d=await waitForTransactionReceipt(u,{hash:T.hash,onReplaced:g=>{w=!0,c(g);},retryCount:$,retryDelay:H,timeout:Ge,...f});if(!w){let g=m??1;if(g>1)for(;;){try{let x=await getTransactionConfirmations(u,{transactionReceipt:d}),F=Number(x);if(p?.(F),F>=g)break}catch(x){console.warn(`[evmTracker] Error fetching confirmations for ${e.txKey} on chain ${e.chainId}:`,x);}await new Promise(x=>setTimeout(x,ve));}await o(T,d,u);}return}catch(d){if(K(d)&&!w&&h<R){console.warn(`[evmTracker] Transient error for ${e.txKey} on chain ${e.chainId} (attempt ${h+1}/${R}). Error: ${d instanceof Error?d.name:"Unknown"}. Retrying...`),await new Promise(x=>setTimeout(x,Re*(h+1)));continue}s(d);return}}async function y(t){let{tx:e,config:a,updateTxParams:r,transactionsPool:i,onSuccess:o,onError:s,onReplaced:c}=t;return Ie({tx:e,config:a,onInitialize:()=>{r(e.txKey,{hash:e.txKey});},onTxDetailsFetched:n=>{r(e.txKey,{to:n.to??void 0,input:n.input,value:n.value?.toString(),nonce:n.nonce,maxFeePerGas:n.maxFeePerGas?.toString(),maxPriorityFeePerGas:n.maxPriorityFeePerGas?.toString()});},onConfirmationsUpdate:n=>{r(e.txKey,{confirmations:n});},onSuccess:async(n,l,p)=>{let f=await getBlock(p,{blockNumber:l.blockNumber}),m=Number(f.timestamp),u=l.status==="success";r(e.txKey,{status:u?TransactionStatus.Success:TransactionStatus.Failed,isError:!u,pending:false,finishedTimestamp:m});let T=i[e.txKey];u&&o&&T&&o(T),!u&&s&&T&&s(new Error("Transaction reverted"),T);},onReplaced:n=>{r(e.txKey,{status:TransactionStatus.Replaced,replacedTxHash:n.transaction.hash,pending:false});let l=i[e.txKey];c&&l&&c(l,e);},onFailure:n=>{r(e.txKey,{status:TransactionStatus.Failed,pending:false,isError:true,error:normalizeError(n)});let l=i[e.txKey];s&&l&&s(n,l);}})}var M=new Map,E=t=>{let{apiKey:e,baseUrl:a,timeout:r}=t,i=a||"https://api.gelato.cloud",o=`${e}:${i}`,s=M.get(o);if(s)return s;let c={timeout:r??15e3,...t.httpTransportConfig,fetchOptions:{headers:{Authorization:`Bearer ${e}`,...t.httpTransportConfig?.fetchOptions?.headers},...t.httpTransportConfig?.fetchOptions}},n=http(`${i}/rpc`,c)({});return M.set(o,n),n};var $e=(o=>(o[o.Pending=100]="Pending",o[o.Submitted=110]="Submitted",o[o.Success=200]="Success",o[o.Rejected=400]="Rejected",o[o.Reverted=500]="Reverted",o))($e||{}),He=new Set([200,400,500]);function Ke(t){return !He.has(t)}function Me(t){return async({tx:e,stopPolling:a,onSuccess:r,onFailure:i,onIntervalTick:o})=>{let s=await t.request({method:"relayer_getStatus",params:{id:e.txKey,logs:false}});o?.(s);let{status:c,createdAt:n}=s;if(n&&b().diff(b.unix(n),"hour")>=1&&Ke(c)){a();return}c===200?(r(s),a({withoutRemoving:true})):(c===400||c===500)&&(i(s),a({withoutRemoving:true}));}}function _({tx:t,gelatoApiKey:e,updateTxParams:a,removeTxFromPool:r,transactionsPool:i,onSuccess:o,onError:s}){let c=E({apiKey:e}),n=Me(c);return initializePollingTracker({tx:t,fetcher:n,removeTxFromPool:r,onSuccess:l=>{let p=l.status===200?l.receipt.transactionHash:void 0;a(t.txKey,{status:TransactionStatus.Success,pending:false,isError:false,hash:p,finishedTimestamp:b().unix()});let f=i[t.txKey];o&&f&&o(f);},onIntervalTick:l=>{l.status===110&&a(t.txKey,{hash:l.hash});},onFailure:l=>{let p="Transaction failed or was not found.",f;l&&(l.status===400?p=l.message||"Transaction was rejected by Gelato Relay.":l.status===500&&(p=l.message||"Transaction reverted on-chain.",f=l.receipt.transactionHash));let m=new Error(p);a(t.txKey,{status:TransactionStatus.Failed,pending:false,isError:true,hash:f,error:normalizeError(m),finishedTimestamp:b().unix()});let u=i[t.txKey];s&&u&&s(m,u);}})}var $t={allowedDomains:[/gnosis-safe.io$/,/app.safe.global$/,/metissafe.tech$/],debug:false},ee={[mainnet.id]:"https://app.safe.global/eth:",[goerli.id]:"https://app.safe.global/gor:",[sepolia.id]:"https://app.safe.global/sep:",[polygon.id]:"https://app.safe.global/matic:",[arbitrum.id]:"https://app.safe.global/arb1:",[aurora.id]:"https://app.safe.global/aurora:",[avalanche.id]:"https://app.safe.global/avax:",[base.id]:"https://app.safe.global/base:",[boba.id]:"https://app.safe.global/boba:",[bsc.id]:"https://app.safe.global/bnb:",[celo.id]:"https://app.safe.global/celo:",[gnosis.id]:"https://app.safe.global/gno:",[optimism.id]:"https://app.safe.global/oeth:",[polygonZkEvm.id]:"https://app.safe.global/zkevm:",[zksync.id]:"https://app.safe.global/zksync:"},te={[mainnet.id]:"https://safe-transaction-mainnet.safe.global/api/v1",[goerli.id]:"https://safe-transaction-goerli.safe.global/api/v1",[sepolia.id]:"https://safe-transaction-sepolia.safe.global/api/v1",[polygon.id]:"https://safe-transaction-polygon.safe.global/api/v1",[arbitrum.id]:"https://safe-transaction-arbitrum.safe.global/api/v1",[aurora.id]:"https://safe-transaction-aurora.safe.global/api/v1",[avalanche.id]:"https://safe-transaction-avalanche.safe.global/api/v1",[base.id]:"https://safe-transaction-base.safe.global/api/v1",[boba.id]:"https://safe-transaction-boba.safe.global/api/v1",[bsc.id]:"https://safe-transaction-bsc.safe.global/api/v1",[celo.id]:"https://safe-transaction-celo.safe.global/api/v1",[gnosis.id]:"https://safe-transaction-gnosis-chain.safe.global/api/v1",[optimism.id]:"https://safe-transaction-optimism.safe.global/api/v1",[polygonZkEvm.id]:"https://safe-transaction-zkevm.safe.global/api/v1",[zksync.id]:"https://safe-transaction-zksync.safe.global/api/v1"};var Ue=async({tx:t,stopPolling:e,onSuccess:a,onFailure:r,onReplaced:i,onIntervalTick:o})=>{let s=te[t.chainId];if(!s)throw new Error(`Safe Transaction Service URL not found for chainId: ${t.chainId}`);let c=await fetch(`${s}/multisig-transactions/${t.txKey}/`);if(!c.ok)throw c.status===404&&(r(),e()),new Error(`Safe API responded with status: ${c.status}`);let n=await c.json();if(o?.(n),n.isExecuted){n.isSuccessful?a(n):r(n),e({withoutRemoving:true});return}let l=await fetch(`${s}/safes/${t.from}/multisig-transactions/?nonce=${n.nonce}`);if(!l.ok)throw new Error(`Safe API (nonce check) responded with status: ${l.status}`);let f=(await l.json()).results.find(m=>m.isExecuted);if(f){i?.(f),e({withoutRemoving:true});return}b().diff(b(n.submissionDate),"day")>=1&&e();};function re({tx:t,updateTxParams:e,removeTxFromPool:a,transactionsPool:r,onSuccess:i,onError:o,onReplaced:s}){return initializePollingTracker({tx:t,fetcher:Ue,removeTxFromPool:a,onSuccess:c=>{e(t.txKey,{status:TransactionStatus.Success,pending:false,isError:false,hash:c.transactionHash??void 0,finishedTimestamp:c.executionDate?b(c.executionDate).unix():void 0});let n=r[t.txKey];i&&n&&i(n);},onIntervalTick:c=>{e(t.txKey,{hash:c.transactionHash??void 0});},onFailure:c=>{let n=c?new Error("Safe transaction failed or was rejected."):new Error("Transaction not found.");e(t.txKey,{status:TransactionStatus.Failed,pending:false,isError:true,hash:c?.transactionHash??void 0,error:normalizeError(n),finishedTimestamp:c?.executionDate?b(c.executionDate).unix():void 0});let l=r[t.txKey];o&&l&&o(n,l);},onReplaced:c=>{e(t.txKey,{status:TransactionStatus.Replaced,pending:false,hash:t.adapter===OrbitAdapter.EVM?t.hash:zeroHash,replacedTxHash:c.safeTxHash??zeroHash,finishedTimestamp:c.executionDate?b(c.executionDate).unix():void 0});let n=r[t.txKey];s&&n&&s(n,t);}})}async function ne({tracker:t,tx:e,config:a,transactionsPool:r,onSuccess:i,onError:o,onReplaced:s,gelatoApiKey:c,...n}){switch(t){case TransactionTracker.Ethereum:return y({tx:e,config:a,transactionsPool:r,onSuccess:i,onError:o,onReplaced:s,...n});case TransactionTracker.Gelato:return c?_({tx:e,transactionsPool:r,onSuccess:i,onError:o,gelatoApiKey:c,...n}):(console.warn(`Gelato tracker requested for tx '${e.txKey}', but no 'gelatoApiKey' was provided. Falling back to default EVM tracker.`),y({tx:e,config:a,transactionsPool:r,onSuccess:i,onError:o,onReplaced:s,...n}));case TransactionTracker.Safe:return re({tx:e,transactionsPool:r,onSuccess:i,onError:o,onReplaced:s,...n});default:return console.warn(`Unknown tracker type: '${t}'. Falling back to default EVM tracker.`),y({tx:e,config:a,transactionsPool:r,onSuccess:i,onError:o,onReplaced:s,...n})}}function oe({actionTxKey:t,connectorType:e,tracker:a,gelatoApiKey:r}){if(a&&a===TransactionTracker.Gelato&&r)return {tracker:TransactionTracker.Gelato,txKey:t};if(!isHex(t))throw new Error(`Invalid transaction key format. Expected a Hex string or a GelatoTxKey object, but received: ${JSON.stringify(t)}`);let i=e.split(":");return (i.length>1?i[i.length-1]==="safe"||i[i.length-1]==="safewallet":e?.toLowerCase()==="safe")?{tracker:TransactionTracker.Safe,txKey:t}:{tracker:TransactionTracker.Ethereum,txKey:t}}var se=({chains:t,tx:e})=>{if(e.tracker===TransactionTracker.Safe){let o=ee[e.chainId];return o?`${o}${e.from}/transactions/tx?id=multisig_${e.from}_${e.txKey}`:""}let r=t.find(o=>o.id===e.chainId)?.blockExplorers?.default.url;if(!r)return "";let i=(e.adapter===OrbitAdapter.EVM?e.replacedTxHash:e.txKey)||(e.adapter===OrbitAdapter.EVM?e.hash:e.txKey);return i?`${r}/tx/${i}`:""};var ce=1.15;async function le({config:t,tx:e}){if(e.adapter!==OrbitAdapter.EVM)throw new Error(`Speed up is only available for EVM transactions. Received adapter type: '${e.adapter}'.`);let{nonce:a,from:r,to:i,value:o,input:s,maxFeePerGas:c,maxPriorityFeePerGas:n,chainId:l}=e;if(a===void 0||!r||!i||!o||!c||!n)throw new Error("Transaction is missing required fields for speed-up.");try{if(!t)throw new Error("Wagmi config is not provided.");if(!getAccount(t).address)throw new Error("No connected account found.");let f=BigInt(Math.ceil(Number(n)*ce)),m=BigInt(Math.ceil(Number(c)*ce));return await sendTransaction(t,{to:i,value:BigInt(o),data:s||"0x",chainId:l,nonce:a,maxFeePerGas:m,maxPriorityFeePerGas:f})}catch(p){let f=p instanceof Error?p.message:String(p);throw new Error(`Failed to speed up transaction: ${f}`,{cause:p})}}function va(t,e){if(!t)throw new Error("EVM adapter requires a wagmi config object.");return {key:OrbitAdapter.EVM,getConnectorInfo:()=>{let a=getConnection(t),r=lastConnectedConnectorHelpers.getLastConnectedConnector();return {walletAddress:a.address??r?.address??zeroAddress,connectorType:getConnectorTypeFromName(OrbitAdapter.EVM,a.connector?.name?.toLowerCase()??"unknown")}},checkChainForTx:a=>checkAndSwitchChain(a,t),checkTransactionsTracker:a=>oe(a),checkAndInitializeTrackerInStore:({tx:a,...r})=>ne({tracker:a.tracker,tx:a,config:t,...r}),getExplorerUrl:a=>{let{chain:r}=getConnection(t),i=r?.blockExplorers?.default.url;return a?`${i}/${a}`:i},getExplorerTxUrl:a=>se({chains:e,tx:a}),cancelTxAction:a=>A({config:t,tx:a}),speedUpTxAction:a=>le({config:t,tx:a}),retryTxAction:async({onClose:a,txKey:r,executeTxAction:i,tx:o})=>{if(a(r),!i){console.error("Retry failed: executeTxAction function is not provided.");return}await i({actionFunction:()=>o.actionFunction({config:t,...o.payload}),params:o,defaultTracker:TransactionTracker.Ethereum});}}}var I=new Map;async function Xe(t){let e=await t.request({method:"relayer_getCapabilities",params:[]}),a={};for(let[r,i]of Object.entries(e))a[Number(r)]=i;return a}async function Ze(t){let e=I.get(t);if(e)return e;let a=E({apiKey:t}),r=await Xe(a);return I.set(t,r),r}async function Fa(t,e){try{let a=await Ze(e);return t in a}catch(a){return console.error("Failed to fetch Gelato relay capabilities:",a),I.delete(e),false}}
2
- export{$e as GelatoStatusCode,te as SafeTransactionServiceUrls,A as cancelTxAction,ne as checkAndInitializeTrackerInStore,Fa as checkIsGelatoAvailable,oe as checkTransactionsTracker,E as createGelatoClient,Ie as evmTracker,y as evmTrackerForStore,Me as gelatoFetcher,_ as gelatoTrackerForStore,ee as gnosisSafeLinksHelper,K as isRetryableReceiptError,va as pulsarEvmAdapter,Ue as safeFetcher,$t as safeSdkOptions,re as safeTrackerForStore,se as selectEvmTxExplorerLink,le as speedUpTxAction};
1
+ import {OrbitAdapter,normalizeError,lastConnectedConnectorHelpers,getConnectorTypeFromName}from'@tuwaio/orbit-core';import {createBundlerRpcClient,checkAndSwitchChain}from'@tuwaio/orbit-evm';import {TransactionStatus,initializePollingTracker,TransactionTracker}from'@tuwaio/pulsar-core';import {getAccount,sendTransaction,getClient,getConnection}from'@wagmi/core';import {WaitForTransactionReceiptTimeoutError,TransactionReceiptNotFoundError,HttpRequestError,WebSocketRequestError,zeroHash,http,isHex,zeroAddress}from'viem';import E from'dayjs';import {getTransaction,waitForTransactionReceipt,getTransactionConfirmations,getBlock}from'viem/actions';import {zksync,polygonZkEvm,optimism,gnosis,celo,bsc,boba,base,avalanche,aurora,arbitrum,polygon,sepolia,goerli,mainnet}from'viem/chains';var $=1.15;async function N({config:e,tx:t}){if(t.adapter!==OrbitAdapter.EVM)throw new Error(`Cancellation is only available for EVM transactions. Received adapter type: '${t.adapter}'.`);let{nonce:r,maxFeePerGas:a,maxPriorityFeePerGas:i,chainId:o}=t;if(r===void 0||!a||!i)throw new Error("Transaction is missing required fields for cancellation (nonce, maxFeePerGas, maxPriorityFeePerGas).");try{if(!e)throw new Error("Wagmi config is not provided.");let s=getAccount(e);if(!s.address)throw new Error("No connected account found.");let c=BigInt(Math.ceil(Number(i)*$)),n=BigInt(Math.ceil(Number(a)*$));return await sendTransaction(e,{to:s.address,value:0n,chainId:o,nonce:r,maxFeePerGas:n,maxPriorityFeePerGas:c})}catch(s){let c=s instanceof Error?s.message:String(s);throw new Error(`Failed to cancel transaction: ${c}`,{cause:s})}}var M=10,U=3e3,I=5,Ke=5e3,He=5e3,Ae=6e4;function O(e){return e?(r=>{if(!(r instanceof Error))return false;if(r instanceof WaitForTransactionReceiptTimeoutError||r instanceof TransactionReceiptNotFoundError||r.name==="WaitForTransactionReceiptTimeoutError"||r.name==="TransactionReceiptNotFoundError"||r instanceof HttpRequestError||r instanceof WebSocketRequestError||r.name==="HttpRequestError"||r.name==="WebSocketRequestError"||r.name==="TimeoutError")return true;let a=r.message.toLowerCase();return a.includes("fetch failed")||a.includes("network error")||a.includes("timeout")||a.includes("timed out")||a.includes("econnreset")||a.includes("rate limit")||a.includes("502")||a.includes("503")||a.includes("504")})(e)?true:e instanceof Error&&"cause"in e&&e.cause?O(e.cause):false:false}async function G(e){let{tx:t,config:r,onInitialize:a,onTxDetailsFetched:i,onSuccess:o,onFailure:s,onReplaced:c,retryCount:n=M,retryTimeout:l=U,onConfirmationsUpdate:f,waitForTransactionReceiptParams:u}=e,{requiredConfirmations:p}=t;if(a?.(),t.txKey===zeroHash)return s(new Error("Transaction hash cannot be the zero hash."));let d=getClient(r,{chainId:t.chainId});if(!d)return s(new Error(`Could not create a viem client for chainId: ${t.chainId}`));let h=null;for(let T=0;T<n;T++)try{h=await getTransaction(d,{hash:t.txKey}),i(h);break}catch(m){if(T===n-1)return console.error(`[evmTracker] Fatal error fetching transaction ${t.txKey} on chain ${t.chainId}:`,m),s(m);console.warn(`[evmTracker] Error fetching transaction ${t.txKey} on chain ${t.chainId} (attempt ${T+1}/${n}):`,m),await new Promise(g=>setTimeout(g,l));}if(!h)return s(new Error("Transaction details could not be fetched."));let k=false;for(let T=0;T<=I;T++)try{let m=await waitForTransactionReceipt(d,{hash:h.hash,onReplaced:g=>{k=!0,c(g);},retryCount:M,retryDelay:U,timeout:Ae,...u});if(!k){let g=p??1;if(g>1)for(;;){try{let x=await getTransactionConfirmations(d,{transactionReceipt:m}),A=Number(x);if(f?.(A),A>=g)break}catch(x){console.warn(`[evmTracker] Error fetching confirmations for ${t.txKey} on chain ${t.chainId}:`,x);}await new Promise(x=>setTimeout(x,He));}await o(h,m,d);}return}catch(m){if(O(m)&&!k&&T<I){console.warn(`[evmTracker] Transient error for ${t.txKey} on chain ${t.chainId} (attempt ${T+1}/${I}). Error: ${m instanceof Error?m.name:"Unknown"}. Retrying...`),await new Promise(x=>setTimeout(x,Ke*(T+1)));continue}s(m);return}}async function w(e){let{tx:t,config:r,updateTxParams:a,transactionsPool:i,onSuccess:o,onError:s,onReplaced:c}=e;return G({tx:t,config:r,onInitialize:()=>{a(t.txKey,{hash:t.txKey});},onTxDetailsFetched:n=>{a(t.txKey,{to:n.to??void 0,input:n.input,value:n.value?.toString(),nonce:n.nonce,maxFeePerGas:n.maxFeePerGas?.toString(),maxPriorityFeePerGas:n.maxPriorityFeePerGas?.toString()});},onConfirmationsUpdate:n=>{a(t.txKey,{confirmations:n});},onSuccess:async(n,l,f)=>{let u=await getBlock(f,{blockNumber:l.blockNumber}),p=Number(u.timestamp),d=l.status==="success";a(t.txKey,{status:d?TransactionStatus.Success:TransactionStatus.Failed,isError:!d,pending:false,finishedTimestamp:p});let h=i[t.txKey];d&&o&&h&&o(h),!d&&s&&h&&s(new Error("Transaction reverted"),h);},onReplaced:n=>{a(t.txKey,{status:TransactionStatus.Replaced,replacedTxHash:n.transaction.hash,pending:false});let l=i[t.txKey];c&&l&&c(l,t);},onFailure:n=>{a(t.txKey,{status:TransactionStatus.Failed,pending:false,isError:true,error:normalizeError(n)});let l=i[t.txKey];s&&l&&s(n,l);}})}async function B({tx:e,stopPolling:t,onSuccess:r,onFailure:a,onIntervalTick:i}){let o=e,s=o.chainId,c=typeof s=="number"?s:parseInt(String(s),10);if(!c||Number.isNaN(c)){t({withoutRemoving:true}),a({receipt:null,status:"failed",reason:`Invalid chainId: ${String(s)}`});return}let n=createBundlerRpcClient({chainId:c,apiKey:o.pimlicoApiKey,bundlerUrl:o.bundlerUrl}),l;try{l=await n.getUserOperationReceipt({hash:o.txKey});}catch(u){let p=u;if(p?.name==="UserOperationReceiptNotFoundError"||p?.message?.includes("could not be found")||p?.shortMessage?.includes("could not be found")||p?.details?.includes("could not be found")||p?.message?.includes("not been processed yet")||p?.shortMessage?.includes("not been processed yet")){i?.({receipt:null,status:"pending"});return}throw u}if(!l){i?.({receipt:null,status:"pending"});return}let f=l.receipt?.transactionHash??l.transactionHash;l.success?(t({withoutRemoving:true}),r({receipt:l,status:"success",hash:f})):(t({withoutRemoving:true}),a({receipt:l,status:"failed",hash:f,reason:l.reason??"UserOperation reverted on-chain."}));}function Ut(e){return initializePollingTracker({...e,fetcher:B,pollingInterval:e.pollingInterval??2e3,maxRetries:e.maxRetries??60})}async function L({tx:e,config:t,updateTxParams:r,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s}){let c=async l=>{if(t)return G({tx:{chainId:e.chainId,txKey:l,requiredConfirmations:e.requiredConfirmations},config:t,onTxDetailsFetched:u=>{r(e.txKey,{to:u.to??void 0,input:u.input,value:u.value?.toString(),nonce:u.nonce,maxFeePerGas:u.maxFeePerGas?.toString(),maxPriorityFeePerGas:u.maxPriorityFeePerGas?.toString()});},onConfirmationsUpdate:u=>{r(e.txKey,{confirmations:u});},onSuccess:async(u,p,d)=>{let h=await getBlock(d,{blockNumber:p.blockNumber}),k=Number(h.timestamp),T=p.status==="success";r(e.txKey,{status:T?TransactionStatus.Success:TransactionStatus.Failed,isError:!T,pending:false,hash:l,finishedTimestamp:k});let m=a[e.txKey];T&&i&&m&&i(m),!T&&o&&m&&o(new Error("Transaction reverted on-chain."),m);},onFailure:u=>{r(e.txKey,{status:TransactionStatus.Failed,pending:false,isError:true,hash:l,error:normalizeError(u),finishedTimestamp:E().unix()});let p=a[e.txKey];o&&p&&o(u,p);},onReplaced:u=>{r(e.txKey,{status:TransactionStatus.Replaced,replacedTxHash:u.transaction.hash,pending:false});let p=a[e.txKey];s&&p&&s(p,e);}});r(e.txKey,{status:TransactionStatus.Success,pending:false,isError:false,hash:l,finishedTimestamp:E().unix()});let f=a[e.txKey];i&&f&&i(f);},n=e;if(n.hash)return c(n.hash);initializePollingTracker({tx:e,fetcher:B,pollingInterval:2e3,maxRetries:60,onSuccess:async l=>{let f=l.hash;if(!f){r(e.txKey,{status:TransactionStatus.Success,pending:false,isError:false,finishedTimestamp:E().unix()});let u=a[e.txKey];i&&u&&i(u);return}r(e.txKey,{hash:f}),await c(f);},onIntervalTick:l=>{l.hash&&r(e.txKey,{hash:l.hash});},onFailure:l=>{let f=l?.reason||"UserOperation failed or was not found.",u=l?.hash,p=new Error(f);r(e.txKey,{status:TransactionStatus.Failed,pending:false,isError:true,hash:u,error:normalizeError(p),finishedTimestamp:E().unix()});let d=a[e.txKey];o&&d&&o(p,d);}});}var j=new Map,R=e=>{let{apiKey:t,baseUrl:r,timeout:a}=e,i=r||"https://api.gelato.cloud",o=`${t}:${i}`,s=j.get(o);if(s)return s;let c={timeout:a??15e3,...e.httpTransportConfig,fetchOptions:{headers:{Authorization:`Bearer ${t}`,...e.httpTransportConfig?.fetchOptions?.headers},...e.httpTransportConfig?.fetchOptions}},n=http(`${i}/rpc`,c)({});return j.set(o,n),n};var _e=(o=>(o[o.Pending=100]="Pending",o[o.Submitted=110]="Submitted",o[o.Success=200]="Success",o[o.Rejected=400]="Rejected",o[o.Reverted=500]="Reverted",o))(_e||{}),ze=new Set([200,400,500]);function Be(e){return !ze.has(e)}function Le(e){return async({tx:t,stopPolling:r,onSuccess:a,onFailure:i,onIntervalTick:o})=>{let s=await e.request({method:"relayer_getStatus",params:{id:t.txKey,logs:false}});o?.(s);let{status:c,createdAt:n}=s;if(n&&E().diff(E.unix(n),"hour")>=1&&Be(c)){r();return}c===200?(a(s),r({withoutRemoving:true})):(c===400||c===500)&&(i(s),r({withoutRemoving:true}));}}function P({tx:e,gelatoApiKey:t,updateTxParams:r,removeTxFromPool:a,transactionsPool:i,onSuccess:o,onError:s}){let c=R({apiKey:t}),n=Le(c);return initializePollingTracker({tx:e,fetcher:n,removeTxFromPool:a,onSuccess:l=>{let f=l.status===200?l.receipt.transactionHash:void 0;r(e.txKey,{status:TransactionStatus.Success,pending:false,isError:false,hash:f,finishedTimestamp:E().unix()});let u=i[e.txKey];o&&u&&o(u);},onIntervalTick:l=>{l.status===110&&r(e.txKey,{hash:l.hash});},onFailure:l=>{let f="Transaction failed or was not found.",u;l&&(l.status===400?f=l.message||"Transaction was rejected by Gelato Relay.":l.status===500&&(f=l.message||"Transaction reverted on-chain.",u=l.receipt.transactionHash));let p=new Error(f);r(e.txKey,{status:TransactionStatus.Failed,pending:false,isError:true,hash:u,error:normalizeError(p),finishedTimestamp:E().unix()});let d=i[e.txKey];s&&d&&s(p,d);}})}var Zt=P;var tr={allowedDomains:[/gnosis-safe.io$/,/app.safe.global$/,/metissafe.tech$/],debug:false},se={[mainnet.id]:"https://app.safe.global/eth:",[goerli.id]:"https://app.safe.global/gor:",[sepolia.id]:"https://app.safe.global/sep:",[polygon.id]:"https://app.safe.global/matic:",[arbitrum.id]:"https://app.safe.global/arb1:",[aurora.id]:"https://app.safe.global/aurora:",[avalanche.id]:"https://app.safe.global/avax:",[base.id]:"https://app.safe.global/base:",[boba.id]:"https://app.safe.global/boba:",[bsc.id]:"https://app.safe.global/bnb:",[celo.id]:"https://app.safe.global/celo:",[gnosis.id]:"https://app.safe.global/gno:",[optimism.id]:"https://app.safe.global/oeth:",[polygonZkEvm.id]:"https://app.safe.global/zkevm:",[zksync.id]:"https://app.safe.global/zksync:"},ce={[mainnet.id]:"https://safe-transaction-mainnet.safe.global/api/v1",[goerli.id]:"https://safe-transaction-goerli.safe.global/api/v1",[sepolia.id]:"https://safe-transaction-sepolia.safe.global/api/v1",[polygon.id]:"https://safe-transaction-polygon.safe.global/api/v1",[arbitrum.id]:"https://safe-transaction-arbitrum.safe.global/api/v1",[aurora.id]:"https://safe-transaction-aurora.safe.global/api/v1",[avalanche.id]:"https://safe-transaction-avalanche.safe.global/api/v1",[base.id]:"https://safe-transaction-base.safe.global/api/v1",[boba.id]:"https://safe-transaction-boba.safe.global/api/v1",[bsc.id]:"https://safe-transaction-bsc.safe.global/api/v1",[celo.id]:"https://safe-transaction-celo.safe.global/api/v1",[gnosis.id]:"https://safe-transaction-gnosis-chain.safe.global/api/v1",[optimism.id]:"https://safe-transaction-optimism.safe.global/api/v1",[polygonZkEvm.id]:"https://safe-transaction-zkevm.safe.global/api/v1",[zksync.id]:"https://safe-transaction-zksync.safe.global/api/v1"};var De=async({tx:e,stopPolling:t,onSuccess:r,onFailure:a,onReplaced:i,onIntervalTick:o})=>{let s=ce[e.chainId];if(!s)throw new Error(`Safe Transaction Service URL not found for chainId: ${e.chainId}`);let c=await fetch(`${s}/multisig-transactions/${e.txKey}/`);if(!c.ok)throw c.status===404&&(a(),t()),new Error(`Safe API responded with status: ${c.status}`);let n=await c.json();if(o?.(n),n.isExecuted){n.isSuccessful?r(n):a(n),t({withoutRemoving:true});return}let l=await fetch(`${s}/safes/${e.from}/multisig-transactions/?nonce=${n.nonce}`);if(!l.ok)throw new Error(`Safe API (nonce check) responded with status: ${l.status}`);let u=(await l.json()).results.find(p=>p.isExecuted);if(u){i?.(u),t({withoutRemoving:true});return}E().diff(E(n.submissionDate),"day")>=1&&t();};function ue({tx:e,updateTxParams:t,removeTxFromPool:r,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s}){return initializePollingTracker({tx:e,fetcher:De,removeTxFromPool:r,onSuccess:c=>{t(e.txKey,{status:TransactionStatus.Success,pending:false,isError:false,hash:c.transactionHash??void 0,finishedTimestamp:c.executionDate?E(c.executionDate).unix():void 0});let n=a[e.txKey];i&&n&&i(n);},onIntervalTick:c=>{t(e.txKey,{hash:c.transactionHash??void 0});},onFailure:c=>{let n=c?new Error("Safe transaction failed or was rejected."):new Error("Transaction not found.");t(e.txKey,{status:TransactionStatus.Failed,pending:false,isError:true,hash:c?.transactionHash??void 0,error:normalizeError(n),finishedTimestamp:c?.executionDate?E(c.executionDate).unix():void 0});let l=a[e.txKey];o&&l&&o(n,l);},onReplaced:c=>{t(e.txKey,{status:TransactionStatus.Replaced,pending:false,hash:e.adapter===OrbitAdapter.EVM?e.hash:zeroHash,replacedTxHash:c.safeTxHash??zeroHash,finishedTimestamp:c.executionDate?E(c.executionDate).unix():void 0});let n=a[e.txKey];s&&n&&s(n,e);}})}async function pe({tracker:e,tx:t,config:r,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s,gelatoApiKey:c,...n}){switch(e){case TransactionTracker.Ethereum:return w({tx:t,config:r,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s,...n});case TransactionTracker.ERC4337:return L({tx:t,config:r,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s,...n});case TransactionTracker.Gelato:return c?P({tx:t,transactionsPool:a,onSuccess:i,onError:o,gelatoApiKey:c,...n}):(console.warn(`Gelato tracker requested for tx '${t.txKey}', but no 'gelatoApiKey' was provided. Falling back to default EVM tracker.`),w({tx:t,config:r,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s,...n}));case TransactionTracker.Safe:return ue({tx:t,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s,...n});default:return console.warn(`Unknown tracker type: '${e}'. Falling back to default EVM tracker.`),w({tx:t,config:r,transactionsPool:a,onSuccess:i,onError:o,onReplaced:s,...n})}}function fe({actionTxKey:e,connectorType:t,tracker:r,gelatoApiKey:a}){if(r&&r===TransactionTracker.Gelato&&a)return {tracker:TransactionTracker.Gelato,txKey:e};if(!isHex(e))throw new Error(`Invalid transaction key format. Expected a Hex string or a GelatoTxKey object, but received: ${JSON.stringify(e)}`);if(r&&r===TransactionTracker.ERC4337)return {tracker:TransactionTracker.ERC4337,txKey:e};let i=t.split(":");return (i.length>1?i[i.length-1]==="safe"||i[i.length-1]==="safewallet":t?.toLowerCase()==="safe")?{tracker:TransactionTracker.Safe,txKey:e}:{tracker:TransactionTracker.Ethereum,txKey:e}}var de=({chains:e,tx:t})=>{if(t.tracker===TransactionTracker.Safe){let c=se[t.chainId];return c?`${c}${t.from}/transactions/tx?id=multisig_${t.from}_${t.txKey}`:""}let a=e.find(c=>c.id===t.chainId)?.blockExplorers?.default.url;if(!a)return "";let o=t.adapter===OrbitAdapter.EVM?t:void 0,s=o?.replacedTxHash||o?.hash||t.txKey;return s?`${a}/tx/${s}`:""};var me=1.15;async function Te({config:e,tx:t}){if(t.adapter!==OrbitAdapter.EVM)throw new Error(`Speed up is only available for EVM transactions. Received adapter type: '${t.adapter}'.`);let{nonce:r,from:a,to:i,value:o,input:s,maxFeePerGas:c,maxPriorityFeePerGas:n,chainId:l}=t;if(r===void 0||!a||!i||!o||!c||!n)throw new Error("Transaction is missing required fields for speed-up.");try{if(!e)throw new Error("Wagmi config is not provided.");if(!getAccount(e).address)throw new Error("No connected account found.");let u=BigInt(Math.ceil(Number(n)*me)),p=BigInt(Math.ceil(Number(c)*me));return await sendTransaction(e,{to:i,value:BigInt(o),data:s||"0x",chainId:l,nonce:r,maxFeePerGas:p,maxPriorityFeePerGas:u})}catch(f){let u=f instanceof Error?f.message:String(f);throw new Error(`Failed to speed up transaction: ${u}`,{cause:f})}}function Xr(e,t){if(!e)throw new Error("EVM adapter requires a wagmi config object.");return {key:OrbitAdapter.EVM,getConnectorInfo:()=>{let r=getConnection(e),a=lastConnectedConnectorHelpers.getLastConnectedConnector();return {walletAddress:r.address??a?.address??zeroAddress,connectorType:getConnectorTypeFromName(OrbitAdapter.EVM,r.connector?.name?.toLowerCase()??"unknown")}},checkChainForTx:r=>checkAndSwitchChain(r,e),checkTransactionsTracker:r=>fe(r),checkAndInitializeTrackerInStore:({tx:r,...a})=>pe({tracker:r.tracker,tx:r,config:e,...a}),getExplorerUrl:r=>{let{chain:a}=getConnection(e),i=a?.blockExplorers?.default.url;return r?`${i}/${r}`:i},getExplorerTxUrl:r=>de({chains:t,tx:r}),cancelTxAction:r=>N({config:e,tx:r}),speedUpTxAction:r=>Te({config:e,tx:r}),retryTxAction:async({onClose:r,txKey:a,executeTxAction:i,tx:o})=>{if(r(a),!i){console.error("Retry failed: executeTxAction function is not provided.");return}await i({actionFunction:()=>o.actionFunction({config:e,...o.payload}),params:o,defaultTracker:TransactionTracker.Ethereum});}}}var H=new Map;async function ot(e){let t=await e.request({method:"relayer_getCapabilities",params:[]}),r={};for(let[a,i]of Object.entries(t))r[Number(a)]=i;return r}async function it(e){let t=H.get(e);if(t)return t;let r=R({apiKey:e}),a=await ot(r);return H.set(e,a),a}async function ea(e,t){try{let r=await it(t);return e in r}catch(r){return console.error("Failed to fetch Gelato relay capabilities:",r),H.delete(t),false}}
2
+ export{_e as GelatoStatusCode,ce as SafeTransactionServiceUrls,N as cancelTxAction,pe as checkAndInitializeTrackerInStore,ea as checkIsGelatoAvailable,fe as checkTransactionsTracker,R as createGelatoClient,B as erc4337Fetcher,Ut as erc4337Tracker,L as erc4337TrackerForStore,G as evmTracker,w as evmTrackerForStore,Le as gelatoFetcher,Zt as gelatoTracker,P as gelatoTrackerForStore,se as gnosisSafeLinksHelper,O as isRetryableReceiptError,Xr as pulsarEvmAdapter,De as safeFetcher,tr as safeSdkOptions,ue as safeTrackerForStore,de as selectEvmTxExplorerLink,Te as speedUpTxAction};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tuwaio/pulsar-evm",
3
- "version": "0.5.9",
3
+ "version": "0.6.0",
4
4
  "private": false,
5
5
  "author": "Oleksandr Tkach",
6
6
  "license": "Apache-2.0",
@@ -40,9 +40,9 @@
40
40
  }
41
41
  ],
42
42
  "peerDependencies": {
43
- "@tuwaio/pulsar-core": ">=0.5",
44
- "@tuwaio/orbit-core": ">=0.2.8",
45
- "@tuwaio/orbit-evm": ">=0.2.11",
43
+ "@tuwaio/pulsar-core": ">=0.7",
44
+ "@tuwaio/orbit-core": ">=0.3",
45
+ "@tuwaio/orbit-evm": ">=0.3",
46
46
  "@wagmi/core": "3.x.x",
47
47
  "dayjs": "1.x.x",
48
48
  "immer": "11.x.x",
@@ -50,23 +50,23 @@
50
50
  "zustand": "5.x.x"
51
51
  },
52
52
  "devDependencies": {
53
- "@tuwaio/orbit-core": "^0.2.15",
54
- "@tuwaio/orbit-evm": "^0.2.21",
55
- "@wagmi/core": "^3.6.4",
56
- "dayjs": "^1.11.21",
57
- "immer": "^11.1.15",
53
+ "@tuwaio/pulsar-core": "^0.7.0",
54
+ "@tuwaio/orbit-core": "^0.3.0",
55
+ "@tuwaio/orbit-evm": "^0.3.0",
56
+ "@wagmi/core": "^3.6.5",
57
+ "dayjs": "^1.11.23",
58
+ "immer": "^11.1.18",
58
59
  "jsdom": "^30.0.1",
59
60
  "tsup": "^8.5.1",
60
- "typescript": "^6.0.3",
61
- "viem": "^2.55.10",
62
- "vitest": "^4.1.10",
63
- "zustand": "^5.0.14",
64
- "dotenv": "^17.4.2",
65
- "@tuwaio/pulsar-core": "^0.6.10"
61
+ "typescript": "6.0.3",
62
+ "viem": "^2.56.3",
63
+ "vitest": "^4.1.11",
64
+ "zustand": "^5.0.15",
65
+ "dotenv": "^17.4.2"
66
66
  },
67
67
  "scripts": {
68
68
  "start": "tsup src/index.ts --watch",
69
69
  "build": "tsup",
70
- "test": "vitest"
70
+ "test": "vitest run"
71
71
  }
72
72
  }