@tuwaio/pulsar-evm 0.5.10 → 0.7.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
@@ -1,211 +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.
10
+ ## 🏛️ Core Capabilities
19
11
 
20
- ---
21
-
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
- ### 3. Using Standalone Actions
125
-
126
- This package also exports utility actions that you can wire up to your UI for features like speeding up or canceling transactions.
127
-
128
- **Example: A button to speed up a stuck transaction**
129
-
130
- ```tsx
131
- // src/components/SpeedUpButton.tsx
132
- import { speedUpTxAction } from '@tuwaio/pulsar-evm';
133
- import { usePulsarStore } from '../hooks/txTrackingHooks'; // Or your custom hook
134
- import { wagmiConfig } from '../configs/wagmi'; // Your wagmi config
135
-
136
- function SpeedUpButton({ txKey }) {
137
- const transactionsPool = usePulsarStore((state) => state.transactionsPool);
138
- const stuckTransaction = transactionsPool[txKey];
139
-
140
- // Only show the button if the transaction is pending and is a standard EVM tx
141
- if (!stuckTransaction?.pending || stuckTransaction.tracker !== 'ethereum') {
142
- return null;
143
- }
144
-
145
- const handleSpeedUp = async () => {
146
- try {
147
- const newTxHash = await speedUpTxAction({
148
- config: wagmiConfig,
149
- tx: stuckTransaction,
150
- });
151
- console.log('Transaction sped up with new hash:', newTxHash);
152
- // Pulsar's `executeTxAction` will automatically add and track this new transaction
153
- // if you integrate it with the action that calls this.
154
- } catch (error) {
155
- console.error('Failed to speed up transaction:', error);
156
- }
157
- };
158
-
159
- return <button onClick={handleSpeedUp}>Speed Up</button>;
160
- }
161
- ```
78
+ The step-by-step React setup is on the **[Getting Started](https://pulsar.docs.tuwa.io/gettingStarted)** page, and tracking without the store on **[EVM Trackers Standalone](https://pulsar.docs.tuwa.io/evmStandalone)**.
162
79
 
163
- ### 4. Using Standalone Utilities
164
-
165
- You can use exported utilities, like selectors or routing functions, to get derived data for your UI.
166
-
167
- **Example: Determining the correct tracker**
168
-
169
- ```tsx
170
- import { checkTransactionsTracker } from '@tuwaio/pulsar-evm';
171
- import { TransactionTracker } from '@tuwaio/pulsar-core';
172
-
173
- // Automatically routes to 'gelato', 'safe', or 'ethereum'
174
- const { tracker, txKey } = checkTransactionsTracker('0xabc...', 'injected');
175
- // tracker -> TransactionTracker.Ethereum
176
- ```
177
-
178
- **Example: Getting a block explorer link for a transaction**
80
+ ---
179
81
 
180
- ```tsx
181
- // src/components/ExplorerLink.tsx
182
- import { selectEvmTxExplorerLink } from '@tuwaio/pulsar-evm';
183
- import { appChains } from '../configs/wagmi'; // Your wagmi chains
82
+ ## 🌐 External Services
184
83
 
185
- function ExplorerLink({ tx }) {
186
- // The selector needs your app's chains, and the transaction.
187
- 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:
188
85
 
189
- 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` |
190
92
 
191
- return (
192
- <a href={explorerLink} target="_blank" rel="noopener noreferrer">
193
- View on Explorer
194
- </a>
195
- );
196
- }
197
- ```
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.
198
94
 
199
95
  ---
200
96
 
201
- ## 🤝 Contributing & Support
202
-
203
- Contributions are welcome! Please read our main **[Contribution Guidelines](https://github.com/TuwaIO/workflows/blob/main/CONTRIBUTING.md)**.
204
-
205
- If you find this library useful, please consider supporting its development. Every contribution helps!
97
+ ## 📚 API Reference
206
98
 
207
- [**➡️ 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)**.
208
100
 
209
101
  ## 📄 License
210
102
 
211
- 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.