@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 +62 -170
- package/dist/index.d.mts +463 -221
- package/dist/index.d.ts +463 -221
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +28 -25
package/README.md
CHANGED
|
@@ -1,211 +1,103 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @tuwaio/pulsar-evm
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@tuwaio/pulsar-evm)
|
|
4
|
-
[](
|
|
5
|
-
[](https://github.com/TuwaIO/pulsar-core/actions)
|
|
4
|
+
[](https://github.com/TuwaIO/pulsar-core/blob/main/packages/pulsar-evm/LICENSE)
|
|
6
5
|
|
|
7
|
-
Layer 4 (L4) of the TUWA
|
|
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
|
-
## 🏛️
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
```
|
|
52
|
-
|
|
53
|
-
import {
|
|
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 {
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
118
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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.
|