@tuwaio/pulsar-evm 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,228 +1,103 @@
1
- # Pulsar EVM Adapter & Toolkit
1
+ # @tuwaio/pulsar-evm
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/@tuwaio/pulsar-evm.svg)](https://www.npmjs.com/package/@tuwaio/pulsar-evm)
4
- [![License](https://img.shields.io/npm/l/@tuwaio/pulsar-evm.svg)](./LICENSE)
5
- [![Build Status](https://img.shields.io/github/actions/workflow/status/TuwaIO/pulsar-core/release.yml?branch=main)](https://github.com/TuwaIO/pulsar-core/actions)
4
+ [![License](https://img.shields.io/npm/l/@tuwaio/pulsar-evm.svg)](https://github.com/TuwaIO/pulsar-core/blob/main/packages/pulsar-evm/LICENSE)
6
5
 
7
- Layer 4 (L4) of the TUWA Ecosystem. Low-level EVM state trackers and lifecycle indexers powered strictly by viem and wagmi primitives.
8
-
9
- > [!WARNING]
10
- > Use of legacy `web3.js` and `ethers.js` libraries is strictly prohibited. All interactions must proceed via `viem` and `wagmi` primitives to ensure deterministic transaction status reconciliation and application sovereignty.
6
+ `@tuwaio/pulsar-evm` is the EVM Layer 4 (L4) package of **Pulsar**, the transaction tracking project of TUWA Stage 2 ("State & Connection", next to Satellite Connect). Built on **`@wagmi/core`**, **`viem`** and **`@tuwaio/orbit-evm`**, it provides the EVM adapter for [`@tuwaio/pulsar-core`](https://pulsar.docs.tuwa.io/packages/pulsar-core) and trackers for standard transactions, ERC-4337 UserOperations, Safe multisig transactions and Gelato relay tasks (deprecated). It does not use `ethers.js` or `web3.js`.
11
7
 
12
8
  ---
13
9
 
14
- ## 🏛️ What is `@tuwaio/pulsar-evm`?
15
-
16
- This package is the low-level EVM state tracking and indexing adapter for `@tuwaio/pulsar-core`. It provides specialized tracking pipelines for standard transactions, contract wallets, Safe multisignature wallets, and Gelato transaction relayers utilizing `viem` clients.
17
-
18
- While its main export is the `pulsarEvmAdapter`, it also includes a suite of standalone trackers, actions, and utilities that can be used for advanced or custom implementations.
19
-
20
- ---
10
+ ## 🏛️ Core Capabilities
21
11
 
22
- ## ✨ Core Features
12
+ - **Adapter:** `pulsarEvmAdapter(wagmiConfig, appChains)` reads the wallet from the active wagmi connection, asks the wallet to switch to `desiredChainID` before signing, picks the tracker, builds explorer links, and adds speed-up, cancel and retry actions for UI kits such as Nova Transactions.
13
+ - **Tracker routing:** the key returned by your `actionFunction` is tracked as a Safe transaction when the connector is a Safe wallet, and as a standard transaction otherwise. ERC-4337 and Gelato are never detected automatically: pass `tracker: TransactionTracker.ERC4337` (or `Gelato`) in the transaction params.
14
+ - **Standard transactions:** `evmTracker` retries `getTransaction` while the node has not indexed the transaction yet, retries the receipt on transient RPC errors (timeouts, rate limits, 5xx), detects speed-ups and cancels made in the wallet (`Replaced` with `replacedTxHash`), waits for `requiredConfirmations` and records the block timestamp.
15
+ - **ERC-4337 UserOperations:** a two-stage tracker polls `eth_getUserOperationReceipt` on your bundler (`bundlerUrl`, or Pimlico with `pimlicoApiKey`), then follows the bundle transaction on-chain like a standard transaction. After a reload it resumes at the stage it reached.
16
+ - **Safe multisig:** polls the Safe Transaction Service until the `safeTxHash` is executed, and reports it as replaced when another transaction with the same nonce was executed.
17
+ - **Speed up and cancel:** `speedUpTxAction` and `cancelTxAction` resend a pending EIP-1559 transaction with the same nonce and fees raised by 15%; the original tracker then reports it as `Replaced`.
18
+ - **Standalone use:** the trackers and fetchers work without the store, in your own state or on a server. See [EVM Trackers Standalone](https://pulsar.docs.tuwa.io/evmStandalone).
23
19
 
24
- - **🔌 Seamless Integration:** A single `pulsarEvmAdapter` factory function to integrate full EVM tracking capabilities into `@tuwaio/pulsar-core`.
25
- - **🎯 Specialized Pipelines:** Distinct, optimized trackers for:
26
- - **Standard EVM Transactions** (via `evmTracker` and `viem`).
27
- - **Safe (formerly Gnosis Safe) Multi-Sigs** (via `safeFetcher` and the Safe Transaction Service API).
28
- - **Gelato Relayer Pipes** (via `gelatoFetcher` and the Gelato API).
29
- - **🤖 Automatic Routing:** Automatically resolves the correct pipeline (Safe, Gelato, or standard EVM) based on the transaction context and wallet type.
30
- - **⚡ Built-in Actions:** Ready-to-use actions for managing transaction state, including `speedUpTxAction` and `cancelTxAction`.
20
+ Trackers write their results to the store with `updateTxParams`, and the `onSuccess`, `onError` and `onReplaced` callbacks of `executeTxAction` receive the updated transaction. No tracker removes a transaction from the pool: when a tracker gives up (for example a Safe transaction still not executed a day after it was proposed), the transaction is marked `Failed` with the reason in `error` and stays in the pool.
31
21
 
32
22
  ---
33
23
 
34
24
  ## 💾 Installation
35
25
 
36
- This package is designed to be used as part of the Pulsar stack and requires `@wagmi/core` and `viem`. Install all necessary packages together:
37
-
38
26
  ```bash
39
- # Using pnpm (recommended), but you can use npm, yarn or bun as well
40
27
  pnpm add @tuwaio/pulsar-evm @tuwaio/pulsar-core @tuwaio/orbit-core @tuwaio/orbit-evm @wagmi/core viem zustand immer dayjs
41
28
  ```
42
29
 
30
+ > [!IMPORTANT]
31
+ > `@tuwaio/pulsar-core` (>=0.8), `@tuwaio/orbit-core` (>=0.3), `@tuwaio/orbit-evm` (>=0.3), `@wagmi/core` (3.x), `viem` (2.x) and `dayjs` (1.x) are peer dependencies and must be installed alongside `@tuwaio/pulsar-evm`. `zustand` and `immer` are the peer dependencies of `@tuwaio/pulsar-core`.
32
+
43
33
  ---
44
34
 
45
35
  ## 🚀 Usage
46
36
 
47
- ### 1. Primary Usage: The `pulsarEvmAdapter`
48
-
49
- For most applications, you'll only need to import the `pulsarEvmAdapter` and pass it to your `createPulsarStore` configuration.
37
+ Add the adapter to the store and pass `tracker` for UserOperations:
50
38
 
51
- ```ts
52
- // src/hooks/txTrackingHooks.ts
53
- import { createBoundedUseStore, createPulsarStore, Transaction } from '@tuwaio/pulsar-core';
39
+ ```typescript
40
+ import { OrbitAdapter } from '@tuwaio/orbit-core';
41
+ import { createPimlicoSmartAccountClient } from '@tuwaio/orbit-evm';
42
+ import { createPulsarStore, type EvmTransaction, TransactionTracker } from '@tuwaio/pulsar-core';
54
43
  import { pulsarEvmAdapter } from '@tuwaio/pulsar-evm';
55
-
56
- import { appChains, config } from '@/configs/wagmiConfig';
57
-
58
- const storageName = 'transactions-tracking-storage';
59
-
60
- export enum TxType {
61
- example = 'example',
62
- }
63
-
64
- type ExampleTx = Transaction & {
65
- type: TxType.example;
66
- payload: {
67
- value: number;
68
- };
69
- };
70
-
71
- export type TransactionUnion = ExampleTx;
72
-
73
- export const usePulsarStore = createBoundedUseStore(
74
- createPulsarStore<TransactionUnion>({
75
- name: storageName,
76
- adapter: pulsarEvmAdapter(config, appChains),
77
- beforeTxProcess: async () => {
78
- // Optional global preflight. Throw here to block before wallet interaction.
79
- await assertUserCanSubmitTransactions();
80
- },
81
- }),
82
- );
83
- ```
84
-
85
- `@tuwaio/pulsar-core` validates EVM transaction metadata before any wallet interaction or persistence. `title` strings are limited to 100 characters, `description` strings to 300 characters, and the serialized `payload` to 10KB. A local `beforeTxProcess` passed to `executeTxAction` overrides the global callback from `createPulsarStore`.
86
-
87
- ### 2. Using Standalone Trackers
88
-
89
- You can use `evmTracker` for standard transactions or `initializePollingTracker` with `gelatoFetcher`/`safeFetcher` for polling-based tracking.
90
-
91
- #### Standard EVM Tracker
92
-
93
- ```tsx
94
- import { evmTracker } from '@tuwaio/pulsar-evm';
95
- import { config } from './wagmi'; // Your wagmi config
96
-
97
- async function trackMyTransaction(txHash: string, chainId: number) {
98
- await evmTracker({
99
- config,
100
- tx: {
101
- txKey: txHash,
102
- chainId,
103
- requiredConfirmations: 3,
104
- },
105
- onTxDetailsFetched: (txDetails) => {
106
- console.log('Transaction details:', txDetails);
107
- },
108
- onSuccess: async (txDetails, receipt, client) => {
109
- console.log('Transaction mined!', receipt);
110
- },
111
- onReplaced: (replacement) => {
112
- console.log('Transaction replaced:', replacement);
113
- },
114
- onFailure: (error) => {
115
- console.error('Tracking failed:', error);
44
+ import { type Config } from '@wagmi/core';
45
+ import { mainnet, sepolia } from 'viem/chains';
46
+
47
+ declare const wagmiConfig: Config;
48
+ const pimlicoApiKey = process.env.NEXT_PUBLIC_PIMLICO_API_KEY;
49
+
50
+ export const pulsarStore = createPulsarStore<EvmTransaction>({
51
+ name: 'pulsar-transactions',
52
+ adapter: pulsarEvmAdapter(wagmiConfig, [mainnet, sepolia]),
53
+ });
54
+
55
+ export async function pingWithSmartAccount() {
56
+ await pulsarStore.getState().executeTxAction({
57
+ actionFunction: async () => {
58
+ const { account, bundlerClient } = await createPimlicoSmartAccountClient({
59
+ chain: sepolia,
60
+ wagmiConfig,
61
+ apiKey: pimlicoApiKey,
62
+ });
63
+ // Returns the userOpHash, which becomes the txKey.
64
+ return bundlerClient.sendUserOperation({ account, calls: [{ to: account.address, value: 0n }] });
116
65
  },
117
- onConfirmationsUpdate: (confirmations) => {
118
- console.log(`Current confirmations: ${confirmations}/3`);
66
+ params: {
67
+ adapter: OrbitAdapter.EVM,
68
+ desiredChainID: sepolia.id,
69
+ type: 'ping',
70
+ title: 'Smart account ping',
71
+ tracker: TransactionTracker.ERC4337, // required for UserOperations
72
+ pimlicoApiKey, // or bundlerUrl; saved locally to resume tracking after a reload, never sent to onRemoteCreate
119
73
  },
120
74
  });
121
75
  }
122
76
  ```
123
77
 
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
-
141
- ### 3. Using Standalone Actions
142
-
143
- This package also exports utility actions that you can wire up to your UI for features like speeding up or canceling transactions.
144
-
145
- **Example: A button to speed up a stuck transaction**
146
-
147
- ```tsx
148
- // src/components/SpeedUpButton.tsx
149
- import { speedUpTxAction } from '@tuwaio/pulsar-evm';
150
- import { usePulsarStore } from '../hooks/txTrackingHooks'; // Or your custom hook
151
- import { wagmiConfig } from '../configs/wagmi'; // Your wagmi config
152
-
153
- function SpeedUpButton({ txKey }) {
154
- const transactionsPool = usePulsarStore((state) => state.transactionsPool);
155
- const stuckTransaction = transactionsPool[txKey];
156
-
157
- // Only show the button if the transaction is pending and is a standard EVM tx
158
- if (!stuckTransaction?.pending || stuckTransaction.tracker !== 'ethereum') {
159
- return null;
160
- }
161
-
162
- const handleSpeedUp = async () => {
163
- try {
164
- const newTxHash = await speedUpTxAction({
165
- config: wagmiConfig,
166
- tx: stuckTransaction,
167
- });
168
- console.log('Transaction sped up with new hash:', newTxHash);
169
- // Pulsar's `executeTxAction` will automatically add and track this new transaction
170
- // if you integrate it with the action that calls this.
171
- } catch (error) {
172
- console.error('Failed to speed up transaction:', error);
173
- }
174
- };
175
-
176
- return <button onClick={handleSpeedUp}>Speed Up</button>;
177
- }
178
- ```
179
-
180
- ### 4. Using Standalone Utilities
78
+ The step-by-step React setup is in the **[React transaction tracking guide](https://docs.tuwa.io/guides/react-transaction-tracking)**, and tracking without the store on **[EVM Trackers Standalone](https://pulsar.docs.tuwa.io/evmStandalone)**.
181
79
 
182
- You can use exported utilities, like selectors or routing functions, to get derived data for your UI.
183
-
184
- **Example: Determining the correct tracker**
185
-
186
- ```tsx
187
- import { checkTransactionsTracker } from '@tuwaio/pulsar-evm';
188
- import { TransactionTracker } from '@tuwaio/pulsar-core';
189
-
190
- // Automatically routes to 'gelato', 'safe', or 'ethereum'
191
- const { tracker, txKey } = checkTransactionsTracker('0xabc...', 'injected');
192
- // tracker -> TransactionTracker.Ethereum
193
- ```
194
-
195
- **Example: Getting a block explorer link for a transaction**
80
+ ---
196
81
 
197
- ```tsx
198
- // src/components/ExplorerLink.tsx
199
- import { selectEvmTxExplorerLink } from '@tuwaio/pulsar-evm';
200
- import { appChains } from '../configs/wagmi'; // Your wagmi chains
82
+ ## 🌐 External Services
201
83
 
202
- function ExplorerLink({ tx }) {
203
- // The selector needs your app's chains, and the transaction.
204
- const explorerLink = selectEvmTxExplorerLink({ chains: appChains, tx });
84
+ The trackers send requests to these hosts. The transaction hash, `userOpHash` or `safeTxHash` (and for Safe, the Safe address) is sent to them:
205
85
 
206
- if (!explorerLink) return null;
86
+ | Tracker | Host | Purpose |
87
+ | -------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
88
+ | Standard, ERC-4337 stage 2 | The RPC transports of your wagmi config | `getTransaction`, receipts, confirmations and block timestamps |
89
+ | ERC-4337 stage 1 | `bundlerUrl`, else `api.pimlico.io` (with `pimlicoApiKey` in the URL), else the rate-limited public `public.pimlico.io` | `eth_getUserOperationReceipt` |
90
+ | Safe | `safe-transaction-<network>.safe.global` (see `SafeTransactionServiceUrls`) | Status of the multisig transaction and of other transactions with its nonce |
91
+ | Gelato (deprecated) | `api.gelato.cloud`, with the Gelato API key as a `Bearer` token | `relayer_getStatus` and `relayer_getCapabilities` |
207
92
 
208
- return (
209
- <a href={explorerLink} target="_blank" rel="noopener noreferrer">
210
- View on Explorer
211
- </a>
212
- );
213
- }
214
- ```
93
+ Explorer links point to the block explorer configured in your viem chains, or to `app.safe.global` for Safe transactions; they are not requested by the package.
215
94
 
216
95
  ---
217
96
 
218
- ## 🤝 Contributing & Support
219
-
220
- Contributions are welcome! Please read our main **[Contribution Guidelines](https://github.com/TuwaIO/workflows/blob/main/CONTRIBUTING.md)**.
221
-
222
- If you find this library useful, please consider supporting its development. Every contribution helps!
97
+ ## 📚 API Reference
223
98
 
224
- [**➡️ View Support Options**](https://github.com/TuwaIO/workflows/blob/main/Donation.md)
99
+ Every export, with signatures and types generated from the source, is documented at **[pulsar.docs.tuwa.io/packages/pulsar-evm](https://pulsar.docs.tuwa.io/packages/pulsar-evm)**.
225
100
 
226
101
  ## 📄 License
227
102
 
228
- This project is licensed under the **Apache-2.0 License** - see the [LICENSE](./LICENSE) file for details.
103
+ Licensed under the **Apache-2.0 License**. See the [LICENSE](https://github.com/TuwaIO/pulsar-core/blob/main/packages/pulsar-evm/LICENSE) file for details.