viem 2.48.8 → 2.49.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/CHANGELOG.md +43 -0
- package/_cjs/actions/public/call.js +26 -6
- package/_cjs/actions/public/call.js.map +1 -1
- package/_cjs/actions/wallet/sendTransactionSync.js +2 -2
- package/_cjs/actions/wallet/sendTransactionSync.js.map +1 -1
- package/_cjs/chains/definitions/hyperEvm.js +6 -0
- package/_cjs/chains/definitions/hyperEvm.js.map +1 -1
- package/_cjs/chains/index.js.map +1 -1
- package/_cjs/clients/transports/http.js +19 -2
- package/_cjs/clients/transports/http.js.map +1 -1
- package/_cjs/errors/utils.js +17 -0
- package/_cjs/errors/utils.js.map +1 -1
- package/_cjs/errors/version.js +1 -1
- package/_cjs/index.js.map +1 -1
- package/_cjs/tempo/actions/index.js +2 -1
- package/_cjs/tempo/actions/index.js.map +1 -1
- package/_cjs/tempo/actions/wallet.js +24 -0
- package/_cjs/tempo/actions/wallet.js.map +1 -0
- package/_cjs/tempo/actions/zone.js +14 -9
- package/_cjs/tempo/actions/zone.js.map +1 -1
- package/_cjs/utils/buildRequest.js +12 -2
- package/_cjs/utils/buildRequest.js.map +1 -1
- package/_cjs/utils/ccip.js +17 -4
- package/_cjs/utils/ccip.js.map +1 -1
- package/_cjs/utils/promise/withRetry.js +23 -3
- package/_cjs/utils/promise/withRetry.js.map +1 -1
- package/_cjs/utils/promise/withTimeout.js +5 -2
- package/_cjs/utils/promise/withTimeout.js.map +1 -1
- package/_cjs/utils/rpc/http.js +5 -0
- package/_cjs/utils/rpc/http.js.map +1 -1
- package/_cjs/utils/wait.js +19 -2
- package/_cjs/utils/wait.js.map +1 -1
- package/_esm/actions/public/call.js +26 -6
- package/_esm/actions/public/call.js.map +1 -1
- package/_esm/actions/wallet/sendTransactionSync.js +2 -2
- package/_esm/actions/wallet/sendTransactionSync.js.map +1 -1
- package/_esm/chains/definitions/hyperEvm.js +6 -0
- package/_esm/chains/definitions/hyperEvm.js.map +1 -1
- package/_esm/chains/index.js +5 -1
- package/_esm/chains/index.js.map +1 -1
- package/_esm/clients/transports/http.js +19 -2
- package/_esm/clients/transports/http.js.map +1 -1
- package/_esm/errors/utils.js +15 -0
- package/_esm/errors/utils.js.map +1 -1
- package/_esm/errors/version.js +1 -1
- package/_esm/index.js.map +1 -1
- package/_esm/tempo/actions/index.js +1 -0
- package/_esm/tempo/actions/index.js.map +1 -1
- package/_esm/tempo/actions/wallet.js +87 -0
- package/_esm/tempo/actions/wallet.js.map +1 -0
- package/_esm/tempo/actions/zone.js +14 -9
- package/_esm/tempo/actions/zone.js.map +1 -1
- package/_esm/utils/buildRequest.js +12 -2
- package/_esm/utils/buildRequest.js.map +1 -1
- package/_esm/utils/ccip.js +17 -4
- package/_esm/utils/ccip.js.map +1 -1
- package/_esm/utils/promise/withRetry.js +23 -3
- package/_esm/utils/promise/withRetry.js.map +1 -1
- package/_esm/utils/promise/withTimeout.js +5 -2
- package/_esm/utils/promise/withTimeout.js.map +1 -1
- package/_esm/utils/rpc/http.js +5 -0
- package/_esm/utils/rpc/http.js.map +1 -1
- package/_esm/utils/wait.js +19 -2
- package/_esm/utils/wait.js.map +1 -1
- package/_types/actions/public/call.d.ts +4 -1
- package/_types/actions/public/call.d.ts.map +1 -1
- package/_types/chains/definitions/hyperEvm.d.ts +6 -9
- package/_types/chains/definitions/hyperEvm.d.ts.map +1 -1
- package/_types/chains/index.d.ts +5 -1
- package/_types/chains/index.d.ts.map +1 -1
- package/_types/clients/transports/http.d.ts.map +1 -1
- package/_types/errors/utils.d.ts +3 -0
- package/_types/errors/utils.d.ts.map +1 -1
- package/_types/errors/version.d.ts +1 -1
- package/_types/index.d.ts +1 -1
- package/_types/index.d.ts.map +1 -1
- package/_types/tempo/Capabilities.d.ts +2 -0
- package/_types/tempo/Capabilities.d.ts.map +1 -1
- package/_types/tempo/actions/index.d.ts +1 -0
- package/_types/tempo/actions/index.d.ts.map +1 -1
- package/_types/tempo/actions/wallet.d.ts +152 -0
- package/_types/tempo/actions/wallet.d.ts.map +1 -0
- package/_types/tempo/actions/zone.d.ts.map +1 -1
- package/_types/types/eip1193.d.ts +2 -0
- package/_types/types/eip1193.d.ts.map +1 -1
- package/_types/utils/buildRequest.d.ts +5 -3
- package/_types/utils/buildRequest.d.ts.map +1 -1
- package/_types/utils/ccip.d.ts +5 -3
- package/_types/utils/ccip.d.ts.map +1 -1
- package/_types/utils/promise/withRetry.d.ts +3 -2
- package/_types/utils/promise/withRetry.d.ts.map +1 -1
- package/_types/utils/promise/withTimeout.d.ts +1 -1
- package/_types/utils/promise/withTimeout.d.ts.map +1 -1
- package/_types/utils/rpc/http.d.ts +1 -1
- package/_types/utils/rpc/http.d.ts.map +1 -1
- package/_types/utils/wait.d.ts +3 -1
- package/_types/utils/wait.d.ts.map +1 -1
- package/actions/public/call.ts +59 -23
- package/actions/wallet/sendTransactionSync.ts +2 -2
- package/chains/definitions/hyperEvm.ts +6 -0
- package/chains/index.ts +2 -0
- package/clients/transports/http.ts +18 -2
- package/errors/utils.ts +19 -0
- package/errors/version.ts +1 -1
- package/index.ts +1 -0
- package/package.json +1 -1
- package/tempo/Capabilities.ts +2 -0
- package/tempo/actions/index.ts +1 -0
- package/tempo/actions/wallet.ts +210 -0
- package/tempo/actions/zone.ts +35 -11
- package/types/eip1193.ts +2 -0
- package/utils/buildRequest.ts +22 -6
- package/utils/ccip.ts +22 -4
- package/utils/promise/withRetry.ts +29 -2
- package/utils/promise/withTimeout.ts +6 -3
- package/utils/rpc/http.ts +7 -1
- package/utils/wait.ts +24 -2
package/tempo/actions/index.ts
CHANGED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import type { Address } from 'abitype'
|
|
2
|
+
import type { Client } from '../../clients/createClient.js'
|
|
3
|
+
import type { Transport } from '../../clients/transports/createTransport.js'
|
|
4
|
+
import type { ErrorType as CoreErrorType } from '../../errors/utils.js'
|
|
5
|
+
import type { Chain } from '../../types/chain.js'
|
|
6
|
+
import type { RequestErrorType } from '../../utils/buildRequest.js'
|
|
7
|
+
import type { TransactionReceipt } from '../Transaction.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Opens the wallet send flow with optional pre-filled send fields.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { createClient, custom } from 'viem'
|
|
15
|
+
* import { Actions } from 'viem/tempo'
|
|
16
|
+
*
|
|
17
|
+
* const client = createClient({
|
|
18
|
+
* transport: custom(window.ethereum),
|
|
19
|
+
* })
|
|
20
|
+
*
|
|
21
|
+
* const { receipt } = await Actions.wallet.send(client, {
|
|
22
|
+
* amount: '1.5',
|
|
23
|
+
* to: '0x...',
|
|
24
|
+
* token: '0x...',
|
|
25
|
+
* })
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @param client - Client.
|
|
29
|
+
* @param parameters - Parameters.
|
|
30
|
+
* @returns The submitted send receipt and chain ID.
|
|
31
|
+
*/
|
|
32
|
+
export async function send<chain extends Chain | undefined>(
|
|
33
|
+
client: Client<Transport, chain>,
|
|
34
|
+
parameters: send.Parameters = {},
|
|
35
|
+
): Promise<send.ReturnValue> {
|
|
36
|
+
return client.request<{
|
|
37
|
+
Method: 'wallet_send'
|
|
38
|
+
Parameters: [send.Parameters]
|
|
39
|
+
ReturnType: send.ReturnValue
|
|
40
|
+
}>(
|
|
41
|
+
{
|
|
42
|
+
method: 'wallet_send',
|
|
43
|
+
params: [parameters],
|
|
44
|
+
},
|
|
45
|
+
{ retryCount: 0 },
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export declare namespace send {
|
|
50
|
+
export type Parameters = {
|
|
51
|
+
/** Human-readable amount to pre-fill (for example, "1.5"). */
|
|
52
|
+
amount?: string | undefined
|
|
53
|
+
/**
|
|
54
|
+
* Fee payer override. `false` to disable the wallet's default fee payer,
|
|
55
|
+
* a URL string to use a custom fee payer service.
|
|
56
|
+
*/
|
|
57
|
+
feePayer?: boolean | string | undefined
|
|
58
|
+
/**
|
|
59
|
+
* UTF-8 memo (max 32 bytes) to attach to the transfer. Wallet rejects
|
|
60
|
+
* the request if the selected token does not support memos (non-TIP-20).
|
|
61
|
+
*/
|
|
62
|
+
memo?: string | undefined
|
|
63
|
+
/** Recipient address to pre-fill. */
|
|
64
|
+
to?: Address | undefined
|
|
65
|
+
/**
|
|
66
|
+
* Token to pre-fill, accepted as either a contract address or a curated
|
|
67
|
+
* tokenlist symbol (case-insensitive, for example `"pathUsd"`). Symbols
|
|
68
|
+
* are resolved against the curated tokenlist on the active chain. Omit
|
|
69
|
+
* to let the user choose.
|
|
70
|
+
*/
|
|
71
|
+
token?: Address | string | undefined
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type ReturnValue = {
|
|
75
|
+
/** Chain ID the send was submitted to. */
|
|
76
|
+
chainId: number
|
|
77
|
+
/** Receipt of the submitted send. */
|
|
78
|
+
receipt: TransactionReceipt
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type ErrorType = RequestErrorType | CoreErrorType
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Opens the wallet swap flow with optional pre-filled swap fields.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* import { createClient, custom } from 'viem'
|
|
90
|
+
* import { Actions } from 'viem/tempo'
|
|
91
|
+
*
|
|
92
|
+
* const client = createClient({
|
|
93
|
+
* transport: custom(window.ethereum),
|
|
94
|
+
* })
|
|
95
|
+
*
|
|
96
|
+
* const { receipt } = await Actions.wallet.swap(client, {
|
|
97
|
+
* amount: '1.5',
|
|
98
|
+
* token: '0x...',
|
|
99
|
+
* type: 'sell',
|
|
100
|
+
* })
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* @param client - Client.
|
|
104
|
+
* @param parameters - Parameters.
|
|
105
|
+
* @returns The submitted swap receipt.
|
|
106
|
+
*/
|
|
107
|
+
export async function swap<chain extends Chain | undefined>(
|
|
108
|
+
client: Client<Transport, chain>,
|
|
109
|
+
parameters: swap.Parameters = {},
|
|
110
|
+
): Promise<swap.ReturnValue> {
|
|
111
|
+
return client.request<{
|
|
112
|
+
Method: 'wallet_swap'
|
|
113
|
+
Parameters: [swap.Parameters]
|
|
114
|
+
ReturnType: swap.ReturnValue
|
|
115
|
+
}>(
|
|
116
|
+
{
|
|
117
|
+
method: 'wallet_swap',
|
|
118
|
+
params: [parameters],
|
|
119
|
+
},
|
|
120
|
+
{ retryCount: 0 },
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export declare namespace swap {
|
|
125
|
+
export type Parameters = {
|
|
126
|
+
/** Human-readable amount to pre-fill (for example, "1.5"). */
|
|
127
|
+
amount?: string | undefined
|
|
128
|
+
/**
|
|
129
|
+
* Other side of the swap pair. For buys, this is the token to sell.
|
|
130
|
+
* For sells, this is the token to buy.
|
|
131
|
+
*/
|
|
132
|
+
pairToken?: Address | undefined
|
|
133
|
+
/** Maximum allowed slippage as a decimal fraction, for example `0.05`. */
|
|
134
|
+
slippage?: number | undefined
|
|
135
|
+
/** Token to buy or sell. Omit to let the user choose. */
|
|
136
|
+
token?: Address | undefined
|
|
137
|
+
/** Whether the amount is an exact buy or sell amount. */
|
|
138
|
+
type?: 'buy' | 'sell' | undefined
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export type ReturnValue = {
|
|
142
|
+
/** Receipt of the submitted swap. */
|
|
143
|
+
receipt: TransactionReceipt
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export type ErrorType = RequestErrorType | CoreErrorType
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Opens the wallet deposit flow with optional pre-filled deposit fields.
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```ts
|
|
154
|
+
* import { createClient, custom } from 'viem'
|
|
155
|
+
* import { Actions } from 'viem/tempo'
|
|
156
|
+
*
|
|
157
|
+
* const client = createClient({
|
|
158
|
+
* transport: custom(window.ethereum),
|
|
159
|
+
* })
|
|
160
|
+
*
|
|
161
|
+
* const result = await Actions.wallet.deposit(client, {
|
|
162
|
+
* token: '0x...',
|
|
163
|
+
* value: '1.5',
|
|
164
|
+
* })
|
|
165
|
+
* ```
|
|
166
|
+
*
|
|
167
|
+
* @param client - Client.
|
|
168
|
+
* @param parameters - Parameters.
|
|
169
|
+
* @returns Receipts for onchain deposit operations, when applicable.
|
|
170
|
+
*/
|
|
171
|
+
export async function deposit<chain extends Chain | undefined>(
|
|
172
|
+
client: Client<Transport, chain>,
|
|
173
|
+
parameters: deposit.Parameters = {},
|
|
174
|
+
): Promise<deposit.ReturnValue> {
|
|
175
|
+
return client.request<{
|
|
176
|
+
Method: 'wallet_deposit'
|
|
177
|
+
Parameters: [deposit.Parameters]
|
|
178
|
+
ReturnType: deposit.ReturnValue
|
|
179
|
+
}>(
|
|
180
|
+
{
|
|
181
|
+
method: 'wallet_deposit',
|
|
182
|
+
params: [parameters],
|
|
183
|
+
},
|
|
184
|
+
{ retryCount: 0 },
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export declare namespace deposit {
|
|
189
|
+
export type Parameters = {
|
|
190
|
+
/** Deposit address to pre-fill. */
|
|
191
|
+
address?: Address | undefined
|
|
192
|
+
/** Source chain ID to pre-fill. */
|
|
193
|
+
chainId?: number | undefined
|
|
194
|
+
/** Human-readable account display name. */
|
|
195
|
+
displayName?: string | undefined
|
|
196
|
+
/** Token contract address to pre-fill. Omit to let the user choose. */
|
|
197
|
+
token?: Address | undefined
|
|
198
|
+
/** Human-readable amount to pre-fill (for example, "1.5"). */
|
|
199
|
+
value?: string | undefined
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export type ReturnValue =
|
|
203
|
+
| {
|
|
204
|
+
/** Receipts of any onchain operations performed during the deposit. */
|
|
205
|
+
receipts?: readonly TransactionReceipt[] | undefined
|
|
206
|
+
}
|
|
207
|
+
| undefined
|
|
208
|
+
|
|
209
|
+
export type ErrorType = RequestErrorType | CoreErrorType
|
|
210
|
+
}
|
package/tempo/actions/zone.ts
CHANGED
|
@@ -18,7 +18,6 @@ import { zeroHash } from '../../constants/bytes.js'
|
|
|
18
18
|
import type { BaseErrorType } from '../../errors/base.js'
|
|
19
19
|
import type { Chain } from '../../types/chain.js'
|
|
20
20
|
import type { Compute } from '../../types/utils.js'
|
|
21
|
-
import { encodeAbiParameters } from '../../utils/abi/encodeAbiParameters.js'
|
|
22
21
|
import type { RequestErrorType } from '../../utils/buildRequest.js'
|
|
23
22
|
import * as Abis from '../Abis.js'
|
|
24
23
|
import * as Addresses from '../Addresses.js'
|
|
@@ -295,6 +294,8 @@ export async function encryptedDeposit<
|
|
|
295
294
|
const encrypted = await encryptDepositPayload(
|
|
296
295
|
{ x: publicKey[0], yParity: publicKey[1] },
|
|
297
296
|
recipient,
|
|
297
|
+
portalAddress,
|
|
298
|
+
keyIndex - 1n,
|
|
298
299
|
parameters.memo,
|
|
299
300
|
)
|
|
300
301
|
|
|
@@ -454,6 +455,8 @@ export async function encryptedDepositSync<
|
|
|
454
455
|
const encrypted = await encryptDepositPayload(
|
|
455
456
|
{ x: publicKey[0], yParity: publicKey[1] },
|
|
456
457
|
recipient,
|
|
458
|
+
portalAddress,
|
|
459
|
+
keyIndex - 1n,
|
|
457
460
|
parameters.memo,
|
|
458
461
|
)
|
|
459
462
|
|
|
@@ -1251,6 +1254,8 @@ export namespace signAuthorizationToken {
|
|
|
1251
1254
|
async function encryptDepositPayload(
|
|
1252
1255
|
publicKey: { x: Hex.Hex; yParity: number },
|
|
1253
1256
|
recipient: Address,
|
|
1257
|
+
portalAddress: Address,
|
|
1258
|
+
keyIndex: bigint,
|
|
1254
1259
|
memo: Hex.Hex = zeroHash,
|
|
1255
1260
|
): Promise<EncryptedPayload> {
|
|
1256
1261
|
const sequencerPublicKey = PublicKey.from({
|
|
@@ -1260,6 +1265,7 @@ async function encryptDepositPayload(
|
|
|
1260
1265
|
|
|
1261
1266
|
const { privateKey: ephemeralPrivateKey, publicKey: ephemeralPublicKey } =
|
|
1262
1267
|
Secp256k1.createKeyPair()
|
|
1268
|
+
const compressedEphemeral = PublicKey.compress(ephemeralPublicKey)
|
|
1263
1269
|
|
|
1264
1270
|
const sharedSecret = Secp256k1.getSharedSecret({
|
|
1265
1271
|
privateKey: ephemeralPrivateKey,
|
|
@@ -1269,7 +1275,7 @@ async function encryptDepositPayload(
|
|
|
1269
1275
|
|
|
1270
1276
|
const hkdfKey = await globalThis.crypto.subtle.importKey(
|
|
1271
1277
|
'raw',
|
|
1272
|
-
sharedSecret.
|
|
1278
|
+
sharedSecret.slice(1),
|
|
1273
1279
|
'HKDF',
|
|
1274
1280
|
false,
|
|
1275
1281
|
['deriveKey'],
|
|
@@ -1278,8 +1284,12 @@ async function encryptDepositPayload(
|
|
|
1278
1284
|
{
|
|
1279
1285
|
name: 'HKDF',
|
|
1280
1286
|
hash: 'SHA-256',
|
|
1281
|
-
salt: new
|
|
1282
|
-
info:
|
|
1287
|
+
salt: new TextEncoder().encode('ecies-aes-key'),
|
|
1288
|
+
info: buildDepositHkdfInfo(
|
|
1289
|
+
portalAddress,
|
|
1290
|
+
keyIndex,
|
|
1291
|
+
Hex.fromNumber(compressedEphemeral.x, { size: 32 }),
|
|
1292
|
+
) as BufferSource,
|
|
1283
1293
|
},
|
|
1284
1294
|
hkdfKey,
|
|
1285
1295
|
{ name: 'AES-GCM', length: 256 },
|
|
@@ -1288,11 +1298,7 @@ async function encryptDepositPayload(
|
|
|
1288
1298
|
)
|
|
1289
1299
|
|
|
1290
1300
|
const nonce = Bytes.random(12)
|
|
1291
|
-
|
|
1292
|
-
const plaintext = encodeAbiParameters(
|
|
1293
|
-
[{ type: 'address' }, { type: 'bytes32' }],
|
|
1294
|
-
[recipient, memo],
|
|
1295
|
-
)
|
|
1301
|
+
const plaintext = buildDepositPlaintext(recipient, memo)
|
|
1296
1302
|
|
|
1297
1303
|
const ciphertextWithTag = new Uint8Array(
|
|
1298
1304
|
await globalThis.crypto.subtle.encrypt(
|
|
@@ -1305,8 +1311,6 @@ async function encryptDepositPayload(
|
|
|
1305
1311
|
const ciphertext = ciphertextWithTag.slice(0, -16)
|
|
1306
1312
|
const tag = ciphertextWithTag.slice(-16)
|
|
1307
1313
|
|
|
1308
|
-
const compressedEphemeral = PublicKey.compress(ephemeralPublicKey)
|
|
1309
|
-
|
|
1310
1314
|
return {
|
|
1311
1315
|
ciphertext: Hex.fromBytes(ciphertext),
|
|
1312
1316
|
ephemeralPubkeyX: Hex.fromNumber(compressedEphemeral.x, { size: 32 }),
|
|
@@ -1315,3 +1319,23 @@ async function encryptDepositPayload(
|
|
|
1315
1319
|
tag: Hex.fromBytes(tag),
|
|
1316
1320
|
}
|
|
1317
1321
|
}
|
|
1322
|
+
|
|
1323
|
+
function buildDepositPlaintext(recipient: Address, memo: Hex.Hex): Bytes.Bytes {
|
|
1324
|
+
return Bytes.concat(
|
|
1325
|
+
Bytes.from(recipient),
|
|
1326
|
+
Bytes.from(memo),
|
|
1327
|
+
new Uint8Array(12),
|
|
1328
|
+
)
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
function buildDepositHkdfInfo(
|
|
1332
|
+
portalAddress: Address,
|
|
1333
|
+
keyIndex: bigint,
|
|
1334
|
+
ephemeralPubkeyX: Hex.Hex,
|
|
1335
|
+
): Bytes.Bytes {
|
|
1336
|
+
return Bytes.concat(
|
|
1337
|
+
Bytes.from(portalAddress),
|
|
1338
|
+
Bytes.fromNumber(keyIndex, { size: 32 }),
|
|
1339
|
+
Bytes.from(ephemeralPubkeyX),
|
|
1340
|
+
)
|
|
1341
|
+
}
|
package/types/eip1193.ts
CHANGED
|
@@ -2140,6 +2140,8 @@ export type EIP1193RequestOptions = {
|
|
|
2140
2140
|
retryDelay?: number | undefined
|
|
2141
2141
|
/** The max number of times to retry. */
|
|
2142
2142
|
retryCount?: number | undefined
|
|
2143
|
+
/** Abort signal to cancel the request. */
|
|
2144
|
+
signal?: AbortSignal | undefined
|
|
2143
2145
|
/** Unique identifier for the request. */
|
|
2144
2146
|
uid?: string | undefined
|
|
2145
2147
|
}
|
package/utils/buildRequest.ts
CHANGED
|
@@ -66,7 +66,12 @@ import {
|
|
|
66
66
|
WalletConnectSessionSettlementError,
|
|
67
67
|
type WalletConnectSessionSettlementErrorType,
|
|
68
68
|
} from '../errors/rpc.js'
|
|
69
|
-
import
|
|
69
|
+
import {
|
|
70
|
+
type AbortErrorType,
|
|
71
|
+
type ErrorType,
|
|
72
|
+
getAbortError,
|
|
73
|
+
isAbortError,
|
|
74
|
+
} from '../errors/utils.js'
|
|
70
75
|
import type {
|
|
71
76
|
EIP1193RequestFn,
|
|
72
77
|
EIP1193RequestOptions,
|
|
@@ -113,18 +118,22 @@ export type RequestErrorType =
|
|
|
113
118
|
| WalletConnectSessionSettlementErrorType
|
|
114
119
|
| WebSocketRequestErrorType
|
|
115
120
|
| WithRetryErrorType
|
|
121
|
+
| AbortErrorType
|
|
116
122
|
| ErrorType
|
|
117
123
|
|
|
118
|
-
export function buildRequest<
|
|
119
|
-
request
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
export function buildRequest<
|
|
125
|
+
request extends (
|
|
126
|
+
args: any,
|
|
127
|
+
options?: { signal?: AbortSignal | undefined } | undefined,
|
|
128
|
+
) => Promise<any>,
|
|
129
|
+
>(request: request, options: EIP1193RequestOptions = {}): EIP1193RequestFn {
|
|
122
130
|
return async (args, overrideOptions = {}) => {
|
|
123
131
|
const {
|
|
124
132
|
dedupe = false,
|
|
125
133
|
methods,
|
|
126
134
|
retryDelay = 150,
|
|
127
135
|
retryCount = 3,
|
|
136
|
+
signal,
|
|
128
137
|
uid,
|
|
129
138
|
} = {
|
|
130
139
|
...options,
|
|
@@ -141,6 +150,8 @@ export function buildRequest<request extends (args: any) => Promise<any>>(
|
|
|
141
150
|
method,
|
|
142
151
|
})
|
|
143
152
|
|
|
153
|
+
if (signal?.aborted) throw getAbortError(signal)
|
|
154
|
+
|
|
144
155
|
const requestId = dedupe
|
|
145
156
|
? hashString(`${uid}.${stringify(args)}`)
|
|
146
157
|
: undefined
|
|
@@ -149,8 +160,11 @@ export function buildRequest<request extends (args: any) => Promise<any>>(
|
|
|
149
160
|
withRetry(
|
|
150
161
|
async () => {
|
|
151
162
|
try {
|
|
152
|
-
return await request(args)
|
|
163
|
+
return await request(args, signal ? { signal } : undefined)
|
|
153
164
|
} catch (err_) {
|
|
165
|
+
if (signal?.aborted) throw getAbortError(signal)
|
|
166
|
+
if (isAbortError(err_)) throw err_
|
|
167
|
+
|
|
154
168
|
const err = err_ as unknown as RpcError<
|
|
155
169
|
RpcErrorCode | ProviderRpcErrorCode
|
|
156
170
|
>
|
|
@@ -264,6 +278,7 @@ export function buildRequest<request extends (args: any) => Promise<any>>(
|
|
|
264
278
|
return ~~(1 << count) * retryDelay
|
|
265
279
|
},
|
|
266
280
|
retryCount,
|
|
281
|
+
signal,
|
|
267
282
|
shouldRetry: ({ error }) => shouldRetry(error),
|
|
268
283
|
},
|
|
269
284
|
),
|
|
@@ -274,6 +289,7 @@ export function buildRequest<request extends (args: any) => Promise<any>>(
|
|
|
274
289
|
|
|
275
290
|
/** @internal */
|
|
276
291
|
export function shouldRetry(error: Error) {
|
|
292
|
+
if (isAbortError(error)) return false
|
|
277
293
|
if ('code' in error && typeof error.code === 'number') {
|
|
278
294
|
if (error.code === -1) return true // Unknown error
|
|
279
295
|
if (error.code === LimitExceededRpcError.code) return true
|
package/utils/ccip.ts
CHANGED
|
@@ -15,8 +15,9 @@ import {
|
|
|
15
15
|
HttpRequestError,
|
|
16
16
|
type HttpRequestErrorType,
|
|
17
17
|
} from '../errors/request.js'
|
|
18
|
-
import type
|
|
18
|
+
import { type ErrorType, getAbortError, isAbortError } from '../errors/utils.js'
|
|
19
19
|
import type { Chain } from '../types/chain.js'
|
|
20
|
+
import type { EIP1193RequestOptions } from '../types/eip1193.js'
|
|
20
21
|
import type { Hex } from '../types/misc.js'
|
|
21
22
|
import { decodeErrorResult } from './abi/decodeErrorResult.js'
|
|
22
23
|
import { encodeAbiParameters } from './abi/encodeAbiParameters.js'
|
|
@@ -65,8 +66,9 @@ export async function offchainLookup<chain extends Chain | undefined>(
|
|
|
65
66
|
blockNumber,
|
|
66
67
|
blockTag,
|
|
67
68
|
data,
|
|
69
|
+
requestOptions,
|
|
68
70
|
to,
|
|
69
|
-
}: Pick<CallParameters, 'blockNumber' | 'blockTag'> & {
|
|
71
|
+
}: Pick<CallParameters, 'blockNumber' | 'blockTag' | 'requestOptions'> & {
|
|
70
72
|
data: Hex
|
|
71
73
|
to: Address
|
|
72
74
|
},
|
|
@@ -90,9 +92,10 @@ export async function offchainLookup<chain extends Chain | undefined>(
|
|
|
90
92
|
const result = urls.includes(localBatchGatewayUrl)
|
|
91
93
|
? await localBatchGatewayRequest({
|
|
92
94
|
data: callData,
|
|
93
|
-
ccipRequest:
|
|
95
|
+
ccipRequest: (parameters) =>
|
|
96
|
+
ccipRequest_({ ...parameters, requestOptions }),
|
|
94
97
|
})
|
|
95
|
-
: await ccipRequest_({ data: callData, sender, urls })
|
|
98
|
+
: await ccipRequest_({ data: callData, requestOptions, sender, urls })
|
|
96
99
|
|
|
97
100
|
const { data: data_ } = await call(client, {
|
|
98
101
|
blockNumber,
|
|
@@ -104,11 +107,16 @@ export async function offchainLookup<chain extends Chain | undefined>(
|
|
|
104
107
|
[result, extraData],
|
|
105
108
|
),
|
|
106
109
|
]),
|
|
110
|
+
requestOptions,
|
|
107
111
|
to,
|
|
108
112
|
} as CallParameters)
|
|
109
113
|
|
|
110
114
|
return data_!
|
|
111
115
|
} catch (err) {
|
|
116
|
+
if (requestOptions?.signal?.aborted)
|
|
117
|
+
throw getAbortError(requestOptions.signal)
|
|
118
|
+
if (isAbortError(err)) throw err
|
|
119
|
+
|
|
112
120
|
throw new OffchainLookupError({
|
|
113
121
|
callbackSelector,
|
|
114
122
|
cause: err as BaseError,
|
|
@@ -122,6 +130,7 @@ export async function offchainLookup<chain extends Chain | undefined>(
|
|
|
122
130
|
|
|
123
131
|
export type CcipRequestParameters = {
|
|
124
132
|
data: Hex
|
|
133
|
+
requestOptions?: EIP1193RequestOptions | undefined
|
|
125
134
|
sender: Address
|
|
126
135
|
urls: readonly string[]
|
|
127
136
|
}
|
|
@@ -135,12 +144,16 @@ export type CcipRequestErrorType =
|
|
|
135
144
|
|
|
136
145
|
export async function ccipRequest({
|
|
137
146
|
data,
|
|
147
|
+
requestOptions,
|
|
138
148
|
sender,
|
|
139
149
|
urls,
|
|
140
150
|
}: CcipRequestParameters): Promise<CcipRequestReturnType> {
|
|
141
151
|
let error = new Error('An unknown error occurred.')
|
|
142
152
|
|
|
143
153
|
for (let i = 0; i < urls.length; i++) {
|
|
154
|
+
if (requestOptions?.signal?.aborted)
|
|
155
|
+
throw getAbortError(requestOptions.signal)
|
|
156
|
+
|
|
144
157
|
const url = urls[i]
|
|
145
158
|
const method = url.includes('{data}') ? 'GET' : 'POST'
|
|
146
159
|
const body = method === 'POST' ? { data, sender } : undefined
|
|
@@ -154,6 +167,7 @@ export async function ccipRequest({
|
|
|
154
167
|
body: JSON.stringify(body),
|
|
155
168
|
headers,
|
|
156
169
|
method,
|
|
170
|
+
...(requestOptions?.signal ? { signal: requestOptions.signal } : {}),
|
|
157
171
|
},
|
|
158
172
|
)
|
|
159
173
|
|
|
@@ -189,6 +203,10 @@ export async function ccipRequest({
|
|
|
189
203
|
|
|
190
204
|
return result
|
|
191
205
|
} catch (err) {
|
|
206
|
+
if (requestOptions?.signal?.aborted)
|
|
207
|
+
throw getAbortError(requestOptions.signal)
|
|
208
|
+
if (isAbortError(err)) throw err
|
|
209
|
+
|
|
192
210
|
error = new HttpRequestError({
|
|
193
211
|
body,
|
|
194
212
|
details: (err as Error).message,
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
type ErrorType,
|
|
3
|
+
getAbortError,
|
|
4
|
+
isAbortError,
|
|
5
|
+
} from '../../errors/utils.js'
|
|
2
6
|
import { wait } from '../wait.js'
|
|
3
7
|
|
|
4
8
|
export type WithRetryParameters = {
|
|
@@ -19,6 +23,8 @@ export type WithRetryParameters = {
|
|
|
19
23
|
error: Error
|
|
20
24
|
}) => Promise<boolean> | boolean)
|
|
21
25
|
| undefined
|
|
26
|
+
// AbortSignal to cancel retries.
|
|
27
|
+
signal?: AbortSignal | undefined
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
export type WithRetryErrorType = ErrorType
|
|
@@ -29,14 +35,27 @@ export function withRetry<data>(
|
|
|
29
35
|
delay: delay_ = 100,
|
|
30
36
|
retryCount = 2,
|
|
31
37
|
shouldRetry = () => true,
|
|
38
|
+
signal,
|
|
32
39
|
}: WithRetryParameters = {},
|
|
33
40
|
) {
|
|
34
41
|
return new Promise<data>((resolve, reject) => {
|
|
35
42
|
const attemptRetry = async ({ count = 0 } = {}) => {
|
|
43
|
+
if (signal?.aborted) {
|
|
44
|
+
reject(getAbortError(signal))
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
36
48
|
const retry = async ({ error }: { error: Error }) => {
|
|
37
49
|
const delay =
|
|
38
50
|
typeof delay_ === 'function' ? delay_({ count, error }) : delay_
|
|
39
|
-
if (delay)
|
|
51
|
+
if (delay) {
|
|
52
|
+
try {
|
|
53
|
+
await wait(delay, { signal })
|
|
54
|
+
} catch (err) {
|
|
55
|
+
reject(err)
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
}
|
|
40
59
|
attemptRetry({ count: count + 1 })
|
|
41
60
|
}
|
|
42
61
|
|
|
@@ -44,6 +63,14 @@ export function withRetry<data>(
|
|
|
44
63
|
const data = await fn()
|
|
45
64
|
resolve(data)
|
|
46
65
|
} catch (err) {
|
|
66
|
+
if (signal?.aborted) {
|
|
67
|
+
reject(getAbortError(signal))
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
if (isAbortError(err)) {
|
|
71
|
+
reject(err)
|
|
72
|
+
return
|
|
73
|
+
}
|
|
47
74
|
if (
|
|
48
75
|
count < retryCount &&
|
|
49
76
|
(await shouldRetry({ count, error: err as Error }))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ErrorType, isAbortError } from '../../errors/utils.js'
|
|
2
2
|
|
|
3
3
|
export type WithTimeoutErrorType = ErrorType
|
|
4
4
|
|
|
@@ -24,8 +24,8 @@ export function withTimeout<data>(
|
|
|
24
24
|
return new Promise((resolve, reject) => {
|
|
25
25
|
;(async () => {
|
|
26
26
|
let timeoutId!: NodeJS.Timeout
|
|
27
|
+
const controller = new AbortController()
|
|
27
28
|
try {
|
|
28
|
-
const controller = new AbortController()
|
|
29
29
|
if (timeout > 0) {
|
|
30
30
|
timeoutId = setTimeout(() => {
|
|
31
31
|
if (signal) {
|
|
@@ -37,7 +37,10 @@ export function withTimeout<data>(
|
|
|
37
37
|
}
|
|
38
38
|
resolve(await fn({ signal: controller?.signal || null }))
|
|
39
39
|
} catch (err) {
|
|
40
|
-
if (
|
|
40
|
+
if (controller?.signal.aborted && isAbortError(err)) {
|
|
41
|
+
reject(errorInstance)
|
|
42
|
+
return
|
|
43
|
+
}
|
|
41
44
|
reject(err)
|
|
42
45
|
} finally {
|
|
43
46
|
clearTimeout(timeoutId)
|
package/utils/rpc/http.ts
CHANGED
|
@@ -4,7 +4,11 @@ import {
|
|
|
4
4
|
TimeoutError,
|
|
5
5
|
type TimeoutErrorType,
|
|
6
6
|
} from '../../errors/request.js'
|
|
7
|
-
import
|
|
7
|
+
import {
|
|
8
|
+
type ErrorType,
|
|
9
|
+
getAbortError,
|
|
10
|
+
isAbortError,
|
|
11
|
+
} from '../../errors/utils.js'
|
|
8
12
|
import type { RpcRequest, RpcResponse } from '../../types/rpc.js'
|
|
9
13
|
import type { MaybePromise } from '../../types/utils.js'
|
|
10
14
|
import {
|
|
@@ -174,6 +178,8 @@ export function getHttpRpcClient(
|
|
|
174
178
|
|
|
175
179
|
return data
|
|
176
180
|
} catch (err) {
|
|
181
|
+
if (signal_?.aborted) throw getAbortError(signal_)
|
|
182
|
+
if (isAbortError(err)) throw err
|
|
177
183
|
if (err instanceof HttpRequestError) throw err
|
|
178
184
|
if (err instanceof TimeoutError) throw err
|
|
179
185
|
throw new HttpRequestError({
|
package/utils/wait.ts
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { getAbortError } from '../errors/utils.js'
|
|
2
|
+
|
|
3
|
+
export async function wait(
|
|
4
|
+
time: number,
|
|
5
|
+
{ signal }: { signal?: AbortSignal | undefined } = {},
|
|
6
|
+
) {
|
|
7
|
+
return new Promise<void>((resolve, reject) => {
|
|
8
|
+
if (signal?.aborted) {
|
|
9
|
+
reject(getAbortError(signal))
|
|
10
|
+
return
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const cleanup = () => signal?.removeEventListener('abort', onAbort)
|
|
14
|
+
const timeout = setTimeout(() => {
|
|
15
|
+
cleanup()
|
|
16
|
+
resolve()
|
|
17
|
+
}, time)
|
|
18
|
+
const onAbort = () => {
|
|
19
|
+
clearTimeout(timeout)
|
|
20
|
+
cleanup()
|
|
21
|
+
reject(getAbortError(signal))
|
|
22
|
+
}
|
|
23
|
+
signal?.addEventListener('abort', onAbort, { once: true })
|
|
24
|
+
})
|
|
3
25
|
}
|