smart-multisig-engine 0.1.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 +409 -0
- package/dist/chunk-YQE6NIEB.js +210 -0
- package/dist/chunk-YQE6NIEB.js.map +1 -0
- package/dist/index.cjs +247 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +85 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +324 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +43 -0
- package/dist/react.d.ts +43 -0
- package/dist/react.js +106 -0
- package/dist/react.js.map +1 -0
- package/dist/types-BJD1jdcY.d.cts +64 -0
- package/dist/types-BJD1jdcY.d.ts +64 -0
- package/package.json +70 -0
package/README.md
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
# smart-multisig-engine
|
|
2
|
+
|
|
3
|
+
A TypeScript utility library for submitting transactions to Safe multisig wallets and retrieving their `safeTxHash` from the Safe Transaction Service.
|
|
4
|
+
|
|
5
|
+
Built on [wagmi](https://wagmi.sh) and [viem](https://viem.sh).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add smart-multisig-engine
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Peer dependencies: `@wagmi/core`, `viem`.
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
Use `submitTx` with the generic adapter interface to submit transactions to any supported multisig:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { submitTx, waitForExecution } from "smart-multisig-engine";
|
|
21
|
+
import { config } from "./wagmi-config";
|
|
22
|
+
|
|
23
|
+
// Submit a transaction
|
|
24
|
+
const { txHash } = await submitTx({
|
|
25
|
+
adapter: "safe",
|
|
26
|
+
config,
|
|
27
|
+
walletAddress: "0xYourSafeAddress",
|
|
28
|
+
address: "0xTargetContract",
|
|
29
|
+
abi: contractAbi,
|
|
30
|
+
functionName: "transfer",
|
|
31
|
+
args: [recipientAddress, amount],
|
|
32
|
+
value: 0n,
|
|
33
|
+
chainId: 1n,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
console.log("Safe TX Hash:", txHash);
|
|
37
|
+
|
|
38
|
+
// Wait for execution
|
|
39
|
+
const { transactionHash } = await waitForExecution({
|
|
40
|
+
adapter: "safe",
|
|
41
|
+
txHash,
|
|
42
|
+
chainId: 1n,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
console.log("On-chain TX Hash:", transactionHash);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or use the Safe adapter directly for more control:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { safe } from "smart-multisig-engine";
|
|
52
|
+
import { config } from "./wagmi-config";
|
|
53
|
+
|
|
54
|
+
const { safeTxHash, txHash } = await safe.submitAndFindSafeTx({
|
|
55
|
+
config,
|
|
56
|
+
safeAddress: "0xYourSafeAddress",
|
|
57
|
+
address: "0xTargetContract",
|
|
58
|
+
abi: contractAbi,
|
|
59
|
+
functionName: "transfer",
|
|
60
|
+
args: [recipientAddress, amount],
|
|
61
|
+
value: 0n,
|
|
62
|
+
chainId: 1,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
console.log("Safe TX Hash:", safeTxHash);
|
|
66
|
+
console.log("On-chain TX Hash:", txHash);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Architecture
|
|
70
|
+
|
|
71
|
+
The library follows a **core/adapter** pattern:
|
|
72
|
+
|
|
73
|
+
- **Core** — Pure functions with no I/O. Can be used independently for encoding, matching, or URL resolution.
|
|
74
|
+
- **Adapters** — I/O implementations that wrap contract calls and external APIs. Currently supports Safe multisig.
|
|
75
|
+
|
|
76
|
+
### Generic Adapter Interface
|
|
77
|
+
|
|
78
|
+
The library provides adapter-agnostic entry points that route to the appropriate implementation:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { submitTx, waitForExecution, fetchPendingTxs, simulate, write } from "smart-multisig-engine";
|
|
82
|
+
|
|
83
|
+
// All functions take an `adapter` parameter to select the implementation
|
|
84
|
+
await submitTx({ adapter: "safe", ... });
|
|
85
|
+
await waitForExecution({ adapter: "safe", ... });
|
|
86
|
+
await fetchPendingTxs({ adapter: "safe", ... });
|
|
87
|
+
await simulate({ adapter: "safe", ... });
|
|
88
|
+
await write({ adapter: "safe", ... });
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Direct Adapter Access
|
|
92
|
+
|
|
93
|
+
For adapter-specific features, import the adapter namespace directly:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { safe } from "smart-multisig-engine";
|
|
97
|
+
|
|
98
|
+
// Access Safe-specific functions
|
|
99
|
+
await safe.submitAndFindSafeTx({ ... });
|
|
100
|
+
await safe.waitForExecution({ ... });
|
|
101
|
+
await safe.fetchPendingTransactions({ ... });
|
|
102
|
+
await safe.simulateContractCall(config, { ... });
|
|
103
|
+
await safe.writeContractCall(config, request);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## API Reference
|
|
107
|
+
|
|
108
|
+
### Generic Adapter Functions
|
|
109
|
+
|
|
110
|
+
These functions provide a unified interface across all adapters.
|
|
111
|
+
|
|
112
|
+
#### `submitTx(options): Promise<SubmitTxResult>`
|
|
113
|
+
|
|
114
|
+
Submit a transaction through the specified adapter.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
interface SubmitTxOptions {
|
|
118
|
+
adapter: "safe"; // Adapter type
|
|
119
|
+
config: Config; // wagmi Config instance
|
|
120
|
+
walletAddress: Address; // The multisig wallet address
|
|
121
|
+
address: Address; // Target contract address
|
|
122
|
+
abi: Abi; // Contract ABI
|
|
123
|
+
functionName: string; // Function to call
|
|
124
|
+
args?: readonly unknown[]; // Function arguments
|
|
125
|
+
value?: bigint; // ETH value (default: 0n)
|
|
126
|
+
chainId?: number; // Chain ID
|
|
127
|
+
txServiceUrl?: string; // Override service URL
|
|
128
|
+
apiKey?: string; // API key for the service
|
|
129
|
+
pollingInterval?: number; // Polling interval in ms
|
|
130
|
+
maxAttempts?: number; // Max poll attempts
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
interface SubmitTxResult {
|
|
134
|
+
txHash: string; // The transaction hash (safeTxHash for Safe)
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### `waitForExecution(options): Promise<WaitForExecutionResult>`
|
|
139
|
+
|
|
140
|
+
Wait for a transaction to be executed on-chain.
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
interface WaitForExecutionOptions {
|
|
144
|
+
adapter: "safe"; // Adapter type
|
|
145
|
+
txHash: string; // Transaction hash to wait for
|
|
146
|
+
chainId: bigint; // Chain ID
|
|
147
|
+
txServiceUrl?: string; // Override service URL
|
|
148
|
+
apiKey?: string; // API key for the service
|
|
149
|
+
pollingInterval?: number; // Polling interval in ms (default: 5000)
|
|
150
|
+
maxAttempts?: number; // Max poll attempts (default: 60)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
interface WaitForExecutionResult {
|
|
154
|
+
transactionHash: string; // The on-chain transaction hash
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### `fetchPendingTxs(options): Promise<unknown[]>`
|
|
159
|
+
|
|
160
|
+
Fetch pending transactions for a wallet.
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
interface FetchPendingOptions {
|
|
164
|
+
adapter: "safe"; // Adapter type
|
|
165
|
+
walletAddress: string; // The multisig wallet address
|
|
166
|
+
chainId: bigint; // Chain ID
|
|
167
|
+
txServiceUrl?: string; // Override service URL
|
|
168
|
+
apiKey?: string; // API key for the service
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
#### `simulate(options): Promise<unknown>`
|
|
173
|
+
|
|
174
|
+
Simulate a contract call before submission.
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
interface SimulateOptions {
|
|
178
|
+
adapter: "safe"; // Adapter type
|
|
179
|
+
config: Config; // wagmi Config instance
|
|
180
|
+
address: Address; // Target contract address
|
|
181
|
+
abi: Abi; // Contract ABI
|
|
182
|
+
functionName: string; // Function to call
|
|
183
|
+
args?: readonly unknown[]; // Function arguments
|
|
184
|
+
value?: bigint; // ETH value
|
|
185
|
+
chainId?: number; // Chain ID
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### `write(options): Promise<string>`
|
|
190
|
+
|
|
191
|
+
Write a contract call (submit the transaction).
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
interface WriteOptions {
|
|
195
|
+
adapter: "safe"; // Adapter type
|
|
196
|
+
config: Config; // wagmi Config instance
|
|
197
|
+
request: unknown; // Request from simulation result
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
### Safe Adapter
|
|
204
|
+
|
|
205
|
+
#### `safe.submitAndFindSafeTx(options): Promise<SubmitAndFindSafeTxResult>`
|
|
206
|
+
|
|
207
|
+
Full flow: simulate → write → poll Safe TX Service → match → return `safeTxHash`.
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
interface SubmitAndFindSafeTxOptions {
|
|
211
|
+
config: Config; // wagmi Config instance
|
|
212
|
+
safeAddress: Address; // The Safe wallet address to poll
|
|
213
|
+
address: Address; // Target contract address
|
|
214
|
+
abi: Abi; // Contract ABI
|
|
215
|
+
functionName: string; // Function to call
|
|
216
|
+
args?: readonly unknown[]; // Function arguments
|
|
217
|
+
value?: bigint; // ETH value (default: 0n)
|
|
218
|
+
chainId?: number; // Chain ID (auto-detected from config if omitted)
|
|
219
|
+
account?: Address; // Signer address
|
|
220
|
+
serviceUrl?: string; // Override Safe TX Service URL
|
|
221
|
+
pollingInterval?: number; // Polling interval in ms (default: 3000)
|
|
222
|
+
maxAttempts?: number; // Max poll attempts (default: 20)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
interface SubmitAndFindSafeTxResult {
|
|
226
|
+
safeTxHash: string; // The Safe transaction hash
|
|
227
|
+
txHash: `0x${string}`; // The on-chain transaction hash
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
#### `safe.waitForExecution(options): Promise<WaitForExecutionResult>`
|
|
232
|
+
|
|
233
|
+
Poll the Safe Transaction Service until a transaction is executed.
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
interface WaitForExecutionOptions {
|
|
237
|
+
safeTxHash: string; // The Safe transaction hash to monitor
|
|
238
|
+
chainId: bigint; // Chain ID
|
|
239
|
+
txServiceUrl?: string; // Override Safe TX Service URL
|
|
240
|
+
apiKey?: string; // API key for the Safe service
|
|
241
|
+
pollingInterval?: number; // Polling interval in ms (default: 5000)
|
|
242
|
+
maxAttempts?: number; // Max poll attempts (default: 60)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
interface WaitForExecutionResult {
|
|
246
|
+
transactionHash: string; // The on-chain transaction hash
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
### Core Utilities
|
|
253
|
+
|
|
254
|
+
#### `extractCallData(params): EncodedCallData`
|
|
255
|
+
|
|
256
|
+
Encodes a contract function call into `{ to, data, value }` using viem's `encodeFunctionData`. Pure function, no network calls.
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import { extractCallData } from "smart-multisig-engine";
|
|
260
|
+
|
|
261
|
+
const callData = extractCallData({
|
|
262
|
+
abi: myAbi,
|
|
263
|
+
functionName: "transfer",
|
|
264
|
+
args: [recipient, amount],
|
|
265
|
+
address: "0xContractAddress",
|
|
266
|
+
value: 0n,
|
|
267
|
+
});
|
|
268
|
+
// { to: "0x...", data: "0x...", value: 0n }
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
#### `matchPendingTransaction(pendingTxs, criteria): SafePendingTransaction | undefined`
|
|
272
|
+
|
|
273
|
+
Finds a pending Safe transaction matching `{ to, value, data }`. Comparison is case-insensitive for addresses and converts `bigint` value to string for matching.
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
import { matchPendingTransaction } from "smart-multisig-engine";
|
|
277
|
+
|
|
278
|
+
const match = matchPendingTransaction(pendingTransactions, {
|
|
279
|
+
to: "0xContractAddress",
|
|
280
|
+
value: 0n,
|
|
281
|
+
data: "0xEncodedCalldata",
|
|
282
|
+
});
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
#### `getSafeServiceUrl(chainId): string`
|
|
286
|
+
|
|
287
|
+
Resolves the Safe Transaction Service base URL for a chain ID. Throws if the chain is not in the known list.
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
import { getSafeServiceUrl } from "smart-multisig-engine";
|
|
291
|
+
|
|
292
|
+
getSafeServiceUrl(1); // "https://safe-transaction-mainnet.safe.global"
|
|
293
|
+
getSafeServiceUrl(11155111); // "https://safe-transaction-sepolia.safe.global"
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
#### `SAFE_TX_SERVICE_URLS`
|
|
297
|
+
|
|
298
|
+
The `Record<number, string>` map of supported chain IDs:
|
|
299
|
+
|
|
300
|
+
| Chain ID | Network |
|
|
301
|
+
|----------|---------|
|
|
302
|
+
| 1 | Ethereum Mainnet |
|
|
303
|
+
| 10 | Optimism |
|
|
304
|
+
| 56 | BSC |
|
|
305
|
+
| 100 | Gnosis Chain |
|
|
306
|
+
| 137 | Polygon |
|
|
307
|
+
| 8453 | Base |
|
|
308
|
+
| 42161 | Arbitrum |
|
|
309
|
+
| 11155111 | Sepolia |
|
|
310
|
+
| 84532 | Base Sepolia |
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
### Safe Low-Level Utilities
|
|
315
|
+
|
|
316
|
+
#### `safe.simulateContractCall(config, params)`
|
|
317
|
+
|
|
318
|
+
Wraps wagmi's `simulateContract`. Validates the transaction will succeed before submission.
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
import { safe } from "smart-multisig-engine";
|
|
322
|
+
|
|
323
|
+
const simulation = await safe.simulateContractCall(config, {
|
|
324
|
+
address: "0xContract",
|
|
325
|
+
abi: myAbi,
|
|
326
|
+
functionName: "transfer",
|
|
327
|
+
args: [recipient, amount],
|
|
328
|
+
});
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
#### `safe.writeContractCall(config, request): Promise<Hex>`
|
|
332
|
+
|
|
333
|
+
Wraps wagmi's `writeContract`. Accepts the `request` from a prior simulation result.
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
import { safe } from "smart-multisig-engine";
|
|
337
|
+
|
|
338
|
+
const txHash = await safe.writeContractCall(config, simulation.request);
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
#### `safe.fetchPendingTransactions(options): Promise<SafePendingTransaction[]>`
|
|
342
|
+
|
|
343
|
+
Fetches pending (unexecuted) multisig transactions from the Safe Transaction Service REST API.
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
import { safe } from "smart-multisig-engine";
|
|
347
|
+
|
|
348
|
+
const pending = await safe.fetchPendingTransactions({
|
|
349
|
+
safeAddress: "0xSafeAddress",
|
|
350
|
+
chainId: 1n,
|
|
351
|
+
apiKey: "optional-api-key",
|
|
352
|
+
});
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Using Individual Bricks
|
|
358
|
+
|
|
359
|
+
The high-level functions are convenience wrappers. You can compose the bricks yourself for custom flows:
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
import {
|
|
363
|
+
extractCallData,
|
|
364
|
+
matchPendingTransaction,
|
|
365
|
+
safe,
|
|
366
|
+
} from "smart-multisig-engine";
|
|
367
|
+
|
|
368
|
+
// 1. Encode the call data
|
|
369
|
+
const callData = extractCallData({ abi, functionName, args, address, value });
|
|
370
|
+
|
|
371
|
+
// 2. Simulate
|
|
372
|
+
const simulation = await safe.simulateContractCall(config, { abi, functionName, args, address, value });
|
|
373
|
+
|
|
374
|
+
// 3. Submit on-chain
|
|
375
|
+
const txHash = await safe.writeContractCall(config, simulation.request);
|
|
376
|
+
|
|
377
|
+
// 4. Poll for the pending Safe transaction
|
|
378
|
+
const pending = await safe.fetchPendingTransactions({
|
|
379
|
+
safeAddress,
|
|
380
|
+
chainId: 1n,
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// 5. Match
|
|
384
|
+
const match = matchPendingTransaction(pending, callData);
|
|
385
|
+
console.log(match?.safeTxHash);
|
|
386
|
+
|
|
387
|
+
// 6. Wait for execution
|
|
388
|
+
const result = await safe.waitForExecution({
|
|
389
|
+
safeTxHash: match.safeTxHash,
|
|
390
|
+
chainId: 1n,
|
|
391
|
+
});
|
|
392
|
+
console.log("Executed:", result.transactionHash);
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## Development
|
|
396
|
+
|
|
397
|
+
```bash
|
|
398
|
+
pnpm install
|
|
399
|
+
pnpm build # Bundle with tsup (ESM + CJS + .d.ts)
|
|
400
|
+
pnpm dev # Watch mode
|
|
401
|
+
pnpm test # Run vitest (watch mode)
|
|
402
|
+
pnpm test --run # Run tests once
|
|
403
|
+
pnpm typecheck # tsc --noEmit
|
|
404
|
+
pnpm clean # Remove dist/
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## License
|
|
408
|
+
|
|
409
|
+
ISC
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
// src/core/extract-call-data.ts
|
|
8
|
+
import { encodeFunctionData } from "viem";
|
|
9
|
+
function extractCallData(params) {
|
|
10
|
+
const data = encodeFunctionData({
|
|
11
|
+
abi: params.abi,
|
|
12
|
+
functionName: params.functionName,
|
|
13
|
+
args: params.args
|
|
14
|
+
});
|
|
15
|
+
return {
|
|
16
|
+
to: params.address,
|
|
17
|
+
data,
|
|
18
|
+
value: params.value ?? 0n
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/core/match-pending-tx.ts
|
|
23
|
+
function matchPendingTransaction(pendingTxs, criteria) {
|
|
24
|
+
return pendingTxs.find(
|
|
25
|
+
(tx) => tx.to.toLowerCase() === criteria.to.toLowerCase() && tx.value === String(criteria.value) && tx.data?.toLowerCase() === criteria.data.toLowerCase()
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/adapters/safe/index.ts
|
|
30
|
+
var safe_exports = {};
|
|
31
|
+
__export(safe_exports, {
|
|
32
|
+
fetchPendingTransactions: () => fetchPendingTransactions,
|
|
33
|
+
simulateContractCall: () => simulateContractCall,
|
|
34
|
+
submitAndFindSafeTx: () => submitAndFindSafeTx,
|
|
35
|
+
waitForExecution: () => waitForExecution,
|
|
36
|
+
writeContractCall: () => writeContractCall
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// src/adapters/safe/simulate-contract-call.ts
|
|
40
|
+
import { simulateContract } from "@wagmi/core";
|
|
41
|
+
async function simulateContractCall(config, params) {
|
|
42
|
+
return simulateContract(config, {
|
|
43
|
+
address: params.address,
|
|
44
|
+
abi: params.abi,
|
|
45
|
+
functionName: params.functionName,
|
|
46
|
+
args: params.args,
|
|
47
|
+
value: params.value,
|
|
48
|
+
chainId: params.chainId,
|
|
49
|
+
account: params.account
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/adapters/safe/write-contract-call.ts
|
|
54
|
+
import { writeContract } from "@wagmi/core";
|
|
55
|
+
async function writeContractCall(config, request) {
|
|
56
|
+
return writeContract(config, request);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/adapters/safe/fetch-pending-transactions.ts
|
|
60
|
+
import SafeApiKit from "@safe-global/api-kit";
|
|
61
|
+
async function fetchPendingTransactions(params) {
|
|
62
|
+
const apiKit = new SafeApiKit({
|
|
63
|
+
chainId: params.chainId,
|
|
64
|
+
...params.txServiceUrl && { txServiceUrl: params.txServiceUrl },
|
|
65
|
+
apiKey: params.apiKey
|
|
66
|
+
});
|
|
67
|
+
const response = await apiKit.getPendingTransactions(params.safeAddress);
|
|
68
|
+
return response.results;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/adapters/safe/submit-and-find-safe-tx.ts
|
|
72
|
+
function delay(ms) {
|
|
73
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
74
|
+
}
|
|
75
|
+
async function submitAndFindSafeTx(options) {
|
|
76
|
+
const {
|
|
77
|
+
config,
|
|
78
|
+
safeAddress,
|
|
79
|
+
txServiceUrl,
|
|
80
|
+
apiKey,
|
|
81
|
+
pollingInterval = 3e3,
|
|
82
|
+
maxAttempts = 20,
|
|
83
|
+
...callParams
|
|
84
|
+
} = options;
|
|
85
|
+
const callData = extractCallData(callParams);
|
|
86
|
+
const simulation = await simulateContractCall(config, callParams);
|
|
87
|
+
await writeContractCall(config, simulation.request);
|
|
88
|
+
const chainId = BigInt(callParams.chainId ?? await getChainId(config));
|
|
89
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
90
|
+
await delay(pollingInterval);
|
|
91
|
+
const pendingTxs = await fetchPendingTransactions({
|
|
92
|
+
chainId,
|
|
93
|
+
safeAddress,
|
|
94
|
+
txServiceUrl,
|
|
95
|
+
apiKey
|
|
96
|
+
});
|
|
97
|
+
const match = matchPendingTransaction(pendingTxs, callData);
|
|
98
|
+
if (match) {
|
|
99
|
+
return {
|
|
100
|
+
safeTxHash: match.safeTxHash
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
throw new Error(
|
|
105
|
+
`Could not find matching Safe transaction after ${maxAttempts} attempts`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
async function getChainId(config) {
|
|
109
|
+
const { getChainId: wagmiGetChainId } = await import("@wagmi/core");
|
|
110
|
+
return wagmiGetChainId(config);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/adapters/safe/wait-for-execution.ts
|
|
114
|
+
import SafeApiKit2 from "@safe-global/api-kit";
|
|
115
|
+
function delay2(ms) {
|
|
116
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
117
|
+
}
|
|
118
|
+
async function waitForExecution(options) {
|
|
119
|
+
const {
|
|
120
|
+
safeTxHash,
|
|
121
|
+
chainId,
|
|
122
|
+
txServiceUrl,
|
|
123
|
+
apiKey,
|
|
124
|
+
pollingInterval = 5e3,
|
|
125
|
+
maxAttempts = 60
|
|
126
|
+
} = options;
|
|
127
|
+
const apiKit = new SafeApiKit2({
|
|
128
|
+
chainId,
|
|
129
|
+
...txServiceUrl && { txServiceUrl },
|
|
130
|
+
apiKey
|
|
131
|
+
});
|
|
132
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
133
|
+
const tx = await apiKit.getTransaction(safeTxHash);
|
|
134
|
+
if (tx.isExecuted && tx.transactionHash) {
|
|
135
|
+
return {
|
|
136
|
+
transactionHash: tx.transactionHash
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
await delay2(pollingInterval);
|
|
140
|
+
}
|
|
141
|
+
throw new Error(
|
|
142
|
+
`Safe transaction ${safeTxHash} was not executed after ${maxAttempts} attempts`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/adapters/registry.ts
|
|
147
|
+
var adapters = {
|
|
148
|
+
safe: {
|
|
149
|
+
submitTx: submitAndFindSafeTx,
|
|
150
|
+
waitForExecution,
|
|
151
|
+
fetchPending: fetchPendingTransactions,
|
|
152
|
+
simulate: simulateContractCall,
|
|
153
|
+
write: writeContractCall
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// src/adapters/index.ts
|
|
158
|
+
async function submitTx(options) {
|
|
159
|
+
const { adapter, walletAddress, ...rest } = options;
|
|
160
|
+
assertAdapter(adapter);
|
|
161
|
+
const result = await adapters[adapter].submitTx({
|
|
162
|
+
safeAddress: walletAddress,
|
|
163
|
+
...rest
|
|
164
|
+
});
|
|
165
|
+
return { txHash: result.safeTxHash };
|
|
166
|
+
}
|
|
167
|
+
async function waitForExecution2(options) {
|
|
168
|
+
const { adapter, txHash, ...rest } = options;
|
|
169
|
+
assertAdapter(adapter);
|
|
170
|
+
const result = await adapters[adapter].waitForExecution({
|
|
171
|
+
safeTxHash: txHash,
|
|
172
|
+
...rest
|
|
173
|
+
});
|
|
174
|
+
return { transactionHash: result.transactionHash };
|
|
175
|
+
}
|
|
176
|
+
async function fetchPendingTxs(options) {
|
|
177
|
+
const { adapter, walletAddress, ...rest } = options;
|
|
178
|
+
assertAdapter(adapter);
|
|
179
|
+
return adapters[adapter].fetchPending({
|
|
180
|
+
safeAddress: walletAddress,
|
|
181
|
+
...rest
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
async function simulate(options) {
|
|
185
|
+
const { adapter, config, ...params } = options;
|
|
186
|
+
assertAdapter(adapter);
|
|
187
|
+
return adapters[adapter].simulate(config, params);
|
|
188
|
+
}
|
|
189
|
+
async function write(options) {
|
|
190
|
+
const { adapter, config, request } = options;
|
|
191
|
+
assertAdapter(adapter);
|
|
192
|
+
return adapters[adapter].write(config, request);
|
|
193
|
+
}
|
|
194
|
+
function assertAdapter(adapter) {
|
|
195
|
+
if (!(adapter in adapters)) {
|
|
196
|
+
throw new Error(`Unknown adapter: ${adapter}. Available: ${Object.keys(adapters).join(", ")}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export {
|
|
201
|
+
extractCallData,
|
|
202
|
+
matchPendingTransaction,
|
|
203
|
+
safe_exports,
|
|
204
|
+
submitTx,
|
|
205
|
+
waitForExecution2 as waitForExecution,
|
|
206
|
+
fetchPendingTxs,
|
|
207
|
+
simulate,
|
|
208
|
+
write
|
|
209
|
+
};
|
|
210
|
+
//# sourceMappingURL=chunk-YQE6NIEB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/extract-call-data.ts","../src/core/match-pending-tx.ts","../src/adapters/safe/index.ts","../src/adapters/safe/simulate-contract-call.ts","../src/adapters/safe/write-contract-call.ts","../src/adapters/safe/fetch-pending-transactions.ts","../src/adapters/safe/submit-and-find-safe-tx.ts","../src/adapters/safe/wait-for-execution.ts","../src/adapters/registry.ts","../src/adapters/index.ts"],"sourcesContent":["import type { Abi, Address } from \"viem\";\nimport { encodeFunctionData } from \"viem\";\nimport type { EncodedCallData } from \"./types.js\";\n\nexport function extractCallData(params: {\n abi: Abi;\n functionName: string;\n args?: readonly unknown[];\n address: Address;\n value?: bigint;\n}): EncodedCallData {\n const data = encodeFunctionData({\n abi: params.abi,\n functionName: params.functionName,\n args: params.args as unknown[],\n });\n\n return {\n to: params.address,\n data,\n value: params.value ?? 0n,\n };\n}\n","import type { SafeMultisigTransactionResponse } from \"@safe-global/types-kit\";\nimport type { TxMatchCriteria } from \"./types.js\";\n\nexport function matchPendingTransaction(\n pendingTxs: SafeMultisigTransactionResponse[],\n criteria: TxMatchCriteria,\n): SafeMultisigTransactionResponse | undefined {\n return pendingTxs.find(\n (tx) =>\n tx.to.toLowerCase() === criteria.to.toLowerCase() &&\n tx.value === String(criteria.value) &&\n tx.data?.toLowerCase() === criteria.data.toLowerCase(),\n );\n}\n","export * from \"./types.js\";\nexport * from \"./simulate-contract-call.js\";\nexport * from \"./write-contract-call.js\";\nexport * from \"./fetch-pending-transactions.js\";\nexport * from \"./submit-and-find-safe-tx.js\";\nexport * from \"./wait-for-execution.js\";\n","import { simulateContract, type Config } from \"@wagmi/core\";\nimport type { ContractCallParams } from \"../../core/types.js\";\n\nexport async function simulateContractCall(\n config: Config,\n params: ContractCallParams,\n) {\n return simulateContract(config, {\n address: params.address,\n abi: params.abi,\n functionName: params.functionName,\n args: params.args as unknown[],\n value: params.value,\n chainId: params.chainId,\n account: params.account,\n });\n}\n","import { writeContract, type Config } from \"@wagmi/core\";\nimport type { Hex } from \"viem\";\n\nexport async function writeContractCall(\n config: Config,\n request: Parameters<typeof writeContract>[1],\n): Promise<Hex> {\n return writeContract(config, request);\n}\n","import SafeApiKit from \"@safe-global/api-kit\";\nimport type { SafeMultisigTransactionResponse } from \"@safe-global/types-kit\";\n\nexport interface FetchPendingTransactionsParams {\n chainId: bigint;\n safeAddress: string;\n txServiceUrl?: string;\n apiKey?: string;\n}\n\nexport async function fetchPendingTransactions(\n params: FetchPendingTransactionsParams,\n): Promise<SafeMultisigTransactionResponse[]> {\n const apiKit = new SafeApiKit({\n chainId: params.chainId,\n ...(params.txServiceUrl && { txServiceUrl: params.txServiceUrl }),\n apiKey: params.apiKey,\n });\n\n const response = await apiKit.getPendingTransactions(params.safeAddress);\n return response.results;\n}\n","import { extractCallData } from \"../../core/extract-call-data.js\";\nimport { matchPendingTransaction } from \"../../core/match-pending-tx.js\";\nimport { fetchPendingTransactions } from \"./fetch-pending-transactions.js\";\nimport { simulateContractCall } from \"./simulate-contract-call.js\";\nimport { writeContractCall } from \"./write-contract-call.js\";\nimport type {\n SubmitAndFindSafeTxOptions,\n SubmitAndFindSafeTxResult,\n} from \"./types.js\";\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function submitAndFindSafeTx(\n options: SubmitAndFindSafeTxOptions,\n): Promise<SubmitAndFindSafeTxResult> {\n const {\n config,\n safeAddress,\n txServiceUrl,\n apiKey,\n pollingInterval = 3000,\n maxAttempts = 20,\n ...callParams\n } = options;\n\n const callData = extractCallData(callParams);\n\n const simulation = await simulateContractCall(config, callParams);\n\n await writeContractCall(config, simulation.request as Parameters<typeof writeContractCall>[1]);\n\n const chainId = BigInt(callParams.chainId ?? (await getChainId(config)));\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n await delay(pollingInterval);\n\n const pendingTxs = await fetchPendingTransactions({\n chainId,\n safeAddress,\n txServiceUrl,\n apiKey,\n });\n const match = matchPendingTransaction(pendingTxs, callData);\n\n if (match) {\n return {\n safeTxHash: match.safeTxHash,\n };\n }\n }\n\n throw new Error(\n `Could not find matching Safe transaction after ${maxAttempts} attempts`,\n );\n}\n\nasync function getChainId(config: Parameters<typeof simulateContractCall>[0]): Promise<number> {\n const { getChainId: wagmiGetChainId } = await import(\"@wagmi/core\");\n return wagmiGetChainId(config);\n}\n","import SafeApiKit from \"@safe-global/api-kit\";\nimport type {\n WaitForExecutionOptions,\n WaitForExecutionResult,\n} from \"./types.js\";\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function waitForExecution(\n options: WaitForExecutionOptions,\n): Promise<WaitForExecutionResult> {\n const {\n safeTxHash,\n chainId,\n txServiceUrl,\n apiKey,\n pollingInterval = 5000,\n maxAttempts = 60,\n } = options;\n\n const apiKit = new SafeApiKit({\n chainId,\n ...(txServiceUrl && { txServiceUrl }),\n apiKey,\n });\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const tx = await apiKit.getTransaction(safeTxHash);\n\n if (tx.isExecuted && tx.transactionHash) {\n return {\n transactionHash: tx.transactionHash,\n };\n }\n\n await delay(pollingInterval);\n }\n\n throw new Error(\n `Safe transaction ${safeTxHash} was not executed after ${maxAttempts} attempts`,\n );\n}\n","import * as safe from \"./safe/index.js\";\n\nexport const adapters = {\n safe: {\n submitTx: safe.submitAndFindSafeTx,\n waitForExecution: safe.waitForExecution,\n fetchPending: safe.fetchPendingTransactions,\n simulate: safe.simulateContractCall,\n write: safe.writeContractCall,\n },\n} as const;\n\nexport type AdapterRegistry = typeof adapters;\n","import { adapters } from \"./registry.js\";\nimport type {\n AdapterType,\n SubmitTxOptions,\n SubmitTxResult,\n WaitForExecutionOptions,\n WaitForExecutionResult,\n FetchPendingOptions,\n SimulateOptions,\n WriteOptions,\n} from \"./types.js\";\n\n// Re-export types\nexport * from \"./types.js\";\n\n// Re-export Safe adapter for direct access\nexport * as safe from \"./safe/index.js\";\n\n// Generic entry functions\n\nexport async function submitTx(\n options: SubmitTxOptions,\n): Promise<SubmitTxResult> {\n const { adapter, walletAddress, ...rest } = options;\n assertAdapter(adapter);\n\n const result = await adapters[adapter].submitTx({\n safeAddress: walletAddress,\n ...rest,\n });\n\n return { txHash: result.safeTxHash };\n}\n\nexport async function waitForExecution(\n options: WaitForExecutionOptions,\n): Promise<WaitForExecutionResult> {\n const { adapter, txHash, ...rest } = options;\n assertAdapter(adapter);\n\n const result = await adapters[adapter].waitForExecution({\n safeTxHash: txHash,\n ...rest,\n });\n\n return { transactionHash: result.transactionHash };\n}\n\nexport async function fetchPendingTxs(\n options: FetchPendingOptions,\n): Promise<unknown[]> {\n const { adapter, walletAddress, ...rest } = options;\n assertAdapter(adapter);\n\n return adapters[adapter].fetchPending({\n safeAddress: walletAddress,\n ...rest,\n });\n}\n\nexport async function simulate(\n options: SimulateOptions,\n): Promise<unknown> {\n const { adapter, config, ...params } = options;\n assertAdapter(adapter);\n\n return adapters[adapter].simulate(config, params);\n}\n\nexport async function write(\n options: WriteOptions,\n): Promise<string> {\n const { adapter, config, request } = options;\n assertAdapter(adapter);\n\n return adapters[adapter].write(config, request as Parameters<typeof adapters.safe.write>[1]);\n}\n\nfunction assertAdapter(adapter: AdapterType): asserts adapter is keyof typeof adapters {\n if (!(adapter in adapters)) {\n throw new Error(`Unknown adapter: ${adapter}. Available: ${Object.keys(adapters).join(\", \")}`);\n }\n}\n"],"mappings":"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","names":["SafeApiKit","delay","waitForExecution"]}
|