viem 3.0.0-next.12 → 3.0.0-next.13
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/dist/chains/definitions/creditCoin3Devnet.d.ts +6 -0
- package/dist/chains/definitions/creditCoin3Devnet.d.ts.map +1 -1
- package/dist/chains/definitions/creditCoin3Devnet.js +6 -0
- package/dist/chains/definitions/creditCoin3Devnet.js.map +1 -1
- package/dist/chains/definitions/creditCoin3Mainnet.d.ts +5 -1
- package/dist/chains/definitions/creditCoin3Mainnet.d.ts.map +1 -1
- package/dist/chains/definitions/creditCoin3Mainnet.js +4 -0
- package/dist/chains/definitions/creditCoin3Mainnet.js.map +1 -1
- package/dist/chains/definitions/creditCoin3Testnet.d.ts +5 -1
- package/dist/chains/definitions/creditCoin3Testnet.d.ts.map +1 -1
- package/dist/chains/definitions/creditCoin3Testnet.js +4 -0
- package/dist/chains/definitions/creditCoin3Testnet.js.map +1 -1
- package/dist/chains/definitions/crymad.d.ts +25 -0
- package/dist/chains/definitions/crymad.d.ts.map +1 -0
- package/dist/chains/definitions/crymad.js +23 -0
- package/dist/chains/definitions/crymad.js.map +1 -0
- package/dist/chains/definitions/crymadL2.d.ts +26 -0
- package/dist/chains/definitions/crymadL2.d.ts.map +1 -0
- package/dist/chains/definitions/crymadL2.js +24 -0
- package/dist/chains/definitions/crymadL2.js.map +1 -0
- package/dist/chains/definitions/kortana.d.ts +18 -0
- package/dist/chains/definitions/kortana.d.ts.map +1 -0
- package/dist/chains/definitions/kortana.js +16 -0
- package/dist/chains/definitions/kortana.js.map +1 -0
- package/dist/chains/index.d.ts +3 -0
- package/dist/chains/index.d.ts.map +1 -1
- package/dist/chains/index.js +3 -0
- package/dist/chains/index.js.map +1 -1
- package/dist/core/actions/wallet/sendCalls.d.ts.map +1 -1
- package/dist/core/actions/wallet/sendCalls.js +1 -0
- package/dist/core/actions/wallet/sendCalls.js.map +1 -1
- package/dist/erc4337/actions/userOperation/waitForReceipt.js +1 -1
- package/dist/erc4337/actions/userOperation/waitForReceipt.js.map +1 -1
- package/dist/node/transports/ipc.d.ts.map +1 -1
- package/dist/node/transports/ipc.js +20 -2
- package/dist/node/transports/ipc.js.map +1 -1
- package/dist/tempo/Abis.d.ts +778 -174
- package/dist/tempo/Abis.d.ts.map +1 -1
- package/dist/tempo/Abis.js +178 -37
- package/dist/tempo/Abis.js.map +1 -1
- package/dist/tempo/Capabilities.d.ts +7 -13
- package/dist/tempo/Capabilities.d.ts.map +1 -1
- package/dist/tempo/Client.d.ts +0 -5
- package/dist/tempo/Client.d.ts.map +1 -1
- package/dist/tempo/Client.js +3 -10
- package/dist/tempo/Client.js.map +1 -1
- package/dist/tempo/ExecutionError.d.ts +81 -0
- package/dist/tempo/ExecutionError.d.ts.map +1 -0
- package/dist/tempo/ExecutionError.js +309 -0
- package/dist/tempo/ExecutionError.js.map +1 -0
- package/dist/tempo/Relay.d.ts +303 -0
- package/dist/tempo/Relay.d.ts.map +1 -0
- package/dist/tempo/Relay.js +170 -0
- package/dist/tempo/Relay.js.map +1 -0
- package/dist/tempo/Selectors.d.ts +16 -5
- package/dist/tempo/Selectors.d.ts.map +1 -1
- package/dist/tempo/Selectors.js +16 -5
- package/dist/tempo/Selectors.js.map +1 -1
- package/dist/tempo/Transport.d.ts +11 -11
- package/dist/tempo/Transport.d.ts.map +1 -1
- package/dist/tempo/Transport.js +22 -51
- package/dist/tempo/Transport.js.map +1 -1
- package/dist/tempo/actions/token/burn.d.ts +38 -9
- package/dist/tempo/actions/token/burn.d.ts.map +1 -1
- package/dist/tempo/actions/token/burn.js +12 -5
- package/dist/tempo/actions/token/burn.js.map +1 -1
- package/dist/tempo/actions/token/burnSync.d.ts +2 -0
- package/dist/tempo/actions/token/burnSync.d.ts.map +1 -1
- package/dist/tempo/chainConfig.d.ts +4 -5
- package/dist/tempo/chainConfig.d.ts.map +1 -1
- package/dist/tempo/chainConfig.js +6 -1
- package/dist/tempo/chainConfig.js.map +1 -1
- package/dist/tempo/index.d.ts +5 -3
- package/dist/tempo/index.d.ts.map +1 -1
- package/dist/tempo/index.js +5 -3
- package/dist/tempo/index.js.map +1 -1
- package/dist/tempo/internal/relay/cache.d.ts +9 -0
- package/dist/tempo/internal/relay/cache.d.ts.map +1 -0
- package/dist/tempo/internal/relay/cache.js +72 -0
- package/dist/tempo/internal/relay/cache.js.map +1 -0
- package/dist/tempo/internal/relay/deadline.d.ts +4 -0
- package/dist/tempo/internal/relay/deadline.d.ts.map +1 -0
- package/dist/tempo/internal/relay/deadline.js +34 -0
- package/dist/tempo/internal/relay/deadline.js.map +1 -0
- package/dist/tempo/internal/relay/error.d.ts +47 -0
- package/dist/tempo/internal/relay/error.d.ts.map +1 -0
- package/dist/tempo/internal/relay/error.js +101 -0
- package/dist/tempo/internal/relay/error.js.map +1 -0
- package/dist/tempo/internal/relay/feePayer.d.ts +70 -0
- package/dist/tempo/internal/relay/feePayer.d.ts.map +1 -0
- package/dist/tempo/internal/relay/feePayer.js +442 -0
- package/dist/tempo/internal/relay/feePayer.js.map +1 -0
- package/dist/tempo/internal/relay/feeToken.d.ts +38 -0
- package/dist/tempo/internal/relay/feeToken.d.ts.map +1 -0
- package/dist/tempo/internal/relay/feeToken.js +143 -0
- package/dist/tempo/internal/relay/feeToken.js.map +1 -0
- package/dist/tempo/internal/relay/multisig.d.ts +4 -0
- package/dist/tempo/internal/relay/multisig.d.ts.map +1 -0
- package/dist/tempo/{Multisig.js → internal/relay/multisig.js} +134 -126
- package/dist/tempo/internal/relay/multisig.js.map +1 -0
- package/dist/tempo/internal/relay/plugin.d.ts +5 -0
- package/dist/tempo/internal/relay/plugin.d.ts.map +1 -0
- package/dist/tempo/internal/relay/plugin.js +10 -0
- package/dist/tempo/internal/relay/plugin.js.map +1 -0
- package/dist/tempo/internal/relay/preflight.d.ts +17 -0
- package/dist/tempo/internal/relay/preflight.d.ts.map +1 -0
- package/dist/tempo/internal/relay/preflight.js +53 -0
- package/dist/tempo/internal/relay/preflight.js.map +1 -0
- package/dist/tempo/internal/relay/request.d.ts +16 -0
- package/dist/tempo/internal/relay/request.d.ts.map +1 -0
- package/dist/tempo/internal/relay/request.js +327 -0
- package/dist/tempo/internal/relay/request.js.map +1 -0
- package/dist/tempo/internal/relay/simulate.d.ts +62 -0
- package/dist/tempo/internal/relay/simulate.d.ts.map +1 -0
- package/dist/tempo/internal/relay/simulate.js +284 -0
- package/dist/tempo/internal/relay/simulate.js.map +1 -0
- package/dist/tempo/internal/relay/utils.d.ts +346 -0
- package/dist/tempo/internal/relay/utils.d.ts.map +1 -0
- package/dist/tempo/internal/relay/utils.js +185 -0
- package/dist/tempo/internal/relay/utils.js.map +1 -0
- package/dist/tempo/internal/relay/virtualAddress.d.ts +9 -0
- package/dist/tempo/internal/relay/virtualAddress.d.ts.map +1 -0
- package/dist/tempo/internal/relay/virtualAddress.js +73 -0
- package/dist/tempo/internal/relay/virtualAddress.js.map +1 -0
- package/dist/tempo/internal/relay.d.ts +4 -0
- package/dist/tempo/internal/relay.d.ts.map +1 -0
- package/dist/tempo/internal/relay.js +132 -0
- package/dist/tempo/internal/relay.js.map +1 -0
- package/dist/tokens/definitions/ousd.d.ts +26 -0
- package/dist/tokens/definitions/ousd.d.ts.map +1 -0
- package/dist/tokens/definitions/ousd.js +26 -0
- package/dist/tokens/definitions/ousd.js.map +1 -0
- package/dist/tokens/index.d.ts +2 -0
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +2 -0
- package/dist/tokens/index.js.map +1 -1
- package/dist/tokens/sets.d.ts +33 -0
- package/dist/tokens/sets.d.ts.map +1 -1
- package/dist/tokens/sets.js +4 -1
- package/dist/tokens/sets.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/chains/definitions/creditCoin3Devnet.ts +6 -0
- package/src/chains/definitions/creditCoin3Mainnet.ts +4 -0
- package/src/chains/definitions/creditCoin3Testnet.ts +4 -0
- package/src/chains/definitions/crymad.ts +23 -0
- package/src/chains/definitions/crymadL2.ts +24 -0
- package/src/chains/definitions/kortana.ts +16 -0
- package/src/chains/index.ts +3 -0
- package/src/core/actions/wallet/sendCalls.ts +1 -0
- package/src/erc4337/actions/userOperation/waitForReceipt.ts +1 -1
- package/src/node/transports/ipc.ts +17 -2
- package/src/tempo/Abis.ts +179 -37
- package/src/tempo/Account.ts +1 -1
- package/src/tempo/Capabilities.ts +7 -15
- package/src/tempo/Client.ts +3 -23
- package/src/tempo/ExecutionError.ts +428 -0
- package/src/tempo/Relay.ts +430 -0
- package/src/tempo/Selectors.ts +25 -11
- package/src/tempo/Transport.ts +71 -41
- package/src/tempo/actions/token/burn.ts +21 -9
- package/src/tempo/actions/token/burnSync.ts +2 -0
- package/src/tempo/chainConfig.ts +9 -6
- package/src/tempo/index.ts +7 -4
- package/src/tempo/internal/relay/cache.ts +82 -0
- package/src/tempo/internal/relay/deadline.ts +45 -0
- package/src/tempo/internal/relay/error.ts +129 -0
- package/src/tempo/internal/relay/feePayer.ts +693 -0
- package/src/tempo/internal/relay/feeToken.ts +190 -0
- package/src/tempo/{Multisig.ts → internal/relay/multisig.ts} +165 -193
- package/src/tempo/internal/relay/plugin.ts +13 -0
- package/src/tempo/internal/relay/preflight.ts +83 -0
- package/src/tempo/internal/relay/request.ts +401 -0
- package/src/tempo/internal/relay/simulate.ts +394 -0
- package/src/tempo/internal/relay/utils.ts +213 -0
- package/src/tempo/internal/relay/virtualAddress.ts +95 -0
- package/src/tempo/internal/relay.ts +149 -0
- package/src/tokens/definitions/ousd.ts +26 -0
- package/src/tokens/index.ts +2 -0
- package/src/tokens/sets.ts +4 -1
- package/src/version.ts +1 -1
- package/dist/tempo/Multisig.d.ts +0 -39
- package/dist/tempo/Multisig.d.ts.map +0 -1
- package/dist/tempo/Multisig.js.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AbiEvent, Hex as Hex_ } from 'ox'
|
|
2
|
-
import type { Errors, Hex } from 'ox'
|
|
2
|
+
import type { Address, Errors, Hex } from 'ox'
|
|
3
|
+
import type { OneOf } from '../../../core/internal/types.js'
|
|
3
4
|
|
|
4
5
|
import type * as Account from '../../../core/Account.js'
|
|
5
6
|
import type * as Chain from '../../../core/Chain.js'
|
|
@@ -25,7 +26,7 @@ import {
|
|
|
25
26
|
} from '../../internal/utils.js'
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
|
-
* Burns TIP-20 tokens from the caller's balance
|
|
29
|
+
* Burns TIP-20 tokens from the caller's balance or a specified account with `BURN_AT_ROLE`.
|
|
29
30
|
*
|
|
30
31
|
* @example
|
|
31
32
|
* ```ts
|
|
@@ -60,9 +61,13 @@ export namespace burn {
|
|
|
60
61
|
export type Args = {
|
|
61
62
|
/** Amount of tokens to burn, in base units or formatted decimal form. */
|
|
62
63
|
amount: AmountInput
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
} & TokenParameter &
|
|
65
|
+
OneOf<
|
|
66
|
+
| { /** Memo to include in the burn. */ memo?: Hex.Hex | undefined }
|
|
67
|
+
| {
|
|
68
|
+
/** Address to burn from. Requires BURN_AT_ROLE. */ from: Address.Address
|
|
69
|
+
}
|
|
70
|
+
>
|
|
66
71
|
export type Options = WriteParameters & Args
|
|
67
72
|
export type ReturnType = write.ReturnType
|
|
68
73
|
// TODO: exhaustive error type
|
|
@@ -85,7 +90,7 @@ export namespace burn {
|
|
|
85
90
|
}
|
|
86
91
|
|
|
87
92
|
/**
|
|
88
|
-
* Defines a call to the `burn` or `
|
|
93
|
+
* Defines a call to the `burn`, `burnWithMemo`, or `burnAt` function.
|
|
89
94
|
*
|
|
90
95
|
* Can be passed to any action that accepts a contract call. The token is
|
|
91
96
|
* selected by `token`; `amount.decimals` is inferred from the client's
|
|
@@ -98,9 +103,16 @@ export namespace burn {
|
|
|
98
103
|
...parameters: CallParameters<Args, Client.Client<chain>>
|
|
99
104
|
) {
|
|
100
105
|
const [client, args] = resolveCallParameters(parameters)
|
|
101
|
-
const { amount, memo, token } = args
|
|
106
|
+
const { amount, from, memo, token } = args
|
|
102
107
|
const { address, decimals } = resolveToken(client, { token })
|
|
103
108
|
const value = toBaseUnits(amount, decimals)
|
|
109
|
+
if (from)
|
|
110
|
+
return defineCall({
|
|
111
|
+
abi: Abis.tip20,
|
|
112
|
+
address,
|
|
113
|
+
functionName: 'burnAt',
|
|
114
|
+
args: [from, value],
|
|
115
|
+
})
|
|
104
116
|
const callArgs = memo
|
|
105
117
|
? ({
|
|
106
118
|
args: [value, Hex_.padLeft(memo, 32)],
|
|
@@ -169,10 +181,10 @@ export namespace burn {
|
|
|
169
181
|
const logs extends readonly AbiEvent.extractLogs.Log[],
|
|
170
182
|
>(logs: logs) {
|
|
171
183
|
const [log] = AbiEvent.extractLogs(Abis.tip20, logs, {
|
|
172
|
-
eventName: 'Burn',
|
|
184
|
+
eventName: ['Burn', 'BurnAt'],
|
|
173
185
|
strict: true,
|
|
174
186
|
})
|
|
175
|
-
if (!log) throw new Error('`Burn` event not found.')
|
|
187
|
+
if (!log) throw new Error('`Burn` or `BurnAt` event not found.')
|
|
176
188
|
return log
|
|
177
189
|
}
|
|
178
190
|
}
|
|
@@ -65,6 +65,8 @@ export namespace burnSync {
|
|
|
65
65
|
export type Args = burn.Args
|
|
66
66
|
export type Options = burn.Options & WriteSyncParameters
|
|
67
67
|
export type ReturnType = {
|
|
68
|
+
/** BURN_AT_ROLE holder that performed the burn. */
|
|
69
|
+
burner?: Address.Address | undefined
|
|
68
70
|
/** Address tokens were burned from. */
|
|
69
71
|
from: Address.Address
|
|
70
72
|
/** Burned amount, in base units. */
|
package/src/tempo/chainConfig.ts
CHANGED
|
@@ -58,11 +58,10 @@ export type TransactionRequest = Omit<
|
|
|
58
58
|
/** Capabilities to pass to `eth_fillTransaction`. */
|
|
59
59
|
capabilities?: Capabilities.FillTransactionRequestCapabilities | undefined
|
|
60
60
|
/**
|
|
61
|
-
* Fee payer
|
|
62
|
-
*
|
|
63
|
-
* co-sign the transaction as the fee payer.
|
|
61
|
+
* Fee payer for TIP-1 gas sponsorship. Pass `true` for relay sponsorship,
|
|
62
|
+
* an Account to co-sign locally, or an external sponsor URL allowed by the relay.
|
|
64
63
|
*/
|
|
65
|
-
feePayer?: viem_Account.Account | boolean | undefined
|
|
64
|
+
feePayer?: viem_Account.Account | boolean | string | undefined
|
|
66
65
|
/** Stored multisig operation to approve. */
|
|
67
66
|
hash?: Hex.Hex | undefined
|
|
68
67
|
/** Owner signing a multisig approval. */
|
|
@@ -90,7 +89,7 @@ export type TransactionRequestRpc = TransactionRequestTempo.Rpc
|
|
|
90
89
|
*/
|
|
91
90
|
export type Envelope = TxEnvelopeTempo.TxEnvelopeTempo & {
|
|
92
91
|
/** Fee payer of the transaction (TIP-1 gas sponsorship). */
|
|
93
|
-
feePayer?: viem_Account.Account | boolean | undefined
|
|
92
|
+
feePayer?: viem_Account.Account | boolean | string | undefined
|
|
94
93
|
/** Owner signing a multisig approval. */
|
|
95
94
|
owner?: RootAccount | undefined
|
|
96
95
|
/** Multisig account, config, and modeled approvals for gas estimation. */
|
|
@@ -293,6 +292,9 @@ export const chainConfig = {
|
|
|
293
292
|
)
|
|
294
293
|
Object.assign(request, {
|
|
295
294
|
...storedTransaction,
|
|
295
|
+
gas: storedTransaction.gas ?? 0n,
|
|
296
|
+
maxFeePerGas: storedTransaction.maxFeePerGas ?? 0n,
|
|
297
|
+
maxPriorityFeePerGas: storedTransaction.maxPriorityFeePerGas ?? 0n,
|
|
296
298
|
nonce: Number(storedTransaction.nonce ?? 0n),
|
|
297
299
|
account: request.account,
|
|
298
300
|
from: operation.account,
|
|
@@ -436,7 +438,7 @@ export const chainConfig = {
|
|
|
436
438
|
request.nonce = 0
|
|
437
439
|
} else if (useExpiringNonce) {
|
|
438
440
|
request.nonceKey = maxUint256
|
|
439
|
-
request.nonce
|
|
441
|
+
request.nonce ??= 0
|
|
440
442
|
if (typeof request.validAfter === 'undefined')
|
|
441
443
|
request.validAfter = randomValidAfter()
|
|
442
444
|
if (typeof request.validBefore === 'undefined')
|
|
@@ -765,6 +767,7 @@ function encodeRequest(
|
|
|
765
767
|
// fee payer commits to it when co-signing. (ox withholds `feeToken` only
|
|
766
768
|
// for external sponsorship, where the fee payer picks the token.)
|
|
767
769
|
if (typeof feePayer === 'object') rpc.feePayer = true
|
|
770
|
+
if (typeof feePayer === 'string') Object.assign(rpc, { feePayer })
|
|
768
771
|
|
|
769
772
|
return rpc
|
|
770
773
|
}
|
package/src/tempo/index.ts
CHANGED
|
@@ -58,6 +58,9 @@ export { tempoActions, type Decorator as TempoActions } from './Decorator.js'
|
|
|
58
58
|
/** Tempo errors. */
|
|
59
59
|
export * from './errors.js'
|
|
60
60
|
|
|
61
|
+
/** Decodes Tempo precompile reverts into readable execution errors. */
|
|
62
|
+
export * as ExecutionError from './ExecutionError.js'
|
|
63
|
+
|
|
61
64
|
/** Helpers producing unix timestamps for key expiries. */
|
|
62
65
|
export * as Expiry from './Expiry.js'
|
|
63
66
|
|
|
@@ -70,6 +73,9 @@ export * as KeyAuthorizationManager from './KeyAuthorizationManager.js'
|
|
|
70
73
|
/** P256 (secp256r1) key utilities. Re-exports `ox/P256`. */
|
|
71
74
|
export * as P256 from './P256.js'
|
|
72
75
|
|
|
76
|
+
/** Composable relay request handlers. */
|
|
77
|
+
export * as Relay from './Relay.js'
|
|
78
|
+
|
|
73
79
|
/** Call scopes restricting access keys to targets & selectors. */
|
|
74
80
|
export * as Scopes from './Scopes.js'
|
|
75
81
|
|
|
@@ -80,7 +86,7 @@ export * as Selectors from './Selectors.js'
|
|
|
80
86
|
export * as Store from './Store.js'
|
|
81
87
|
|
|
82
88
|
/** Relay transport: routes fee sponsorship traffic to a fee payer service. */
|
|
83
|
-
export {
|
|
89
|
+
export { withRelay } from './Transport.js'
|
|
84
90
|
|
|
85
91
|
/** WebAuthn P256 credential creation & signing. */
|
|
86
92
|
export * as WebAuthnP256 from './WebAuthnP256.js'
|
|
@@ -93,8 +99,5 @@ export * as WebCryptoP256 from './WebCryptoP256.js'
|
|
|
93
99
|
// `viem/tempo` never imports `viem`. See `internal/inference.ts`.
|
|
94
100
|
export type * from '../internal/inference.js'
|
|
95
101
|
|
|
96
|
-
/** Coordinates native multisig approvals over JSON-RPC. */
|
|
97
|
-
export * as Multisig from './Multisig.js'
|
|
98
|
-
|
|
99
102
|
/** Tempo Zone chains. */
|
|
100
103
|
export * as Zone from './Zone.js'
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { withTimeout } from '../../../core/internal/promise.js'
|
|
2
|
+
import type * as Store_ from '../../Store.js'
|
|
3
|
+
|
|
4
|
+
export type Store = Store_.Store
|
|
5
|
+
|
|
6
|
+
// Scope in-flight work to one request so Workers never share request-owned I/O.
|
|
7
|
+
const flights = new WeakMap<Store, Map<string, Promise<unknown>>>()
|
|
8
|
+
const prefix = 'viem:relay:cache:'
|
|
9
|
+
|
|
10
|
+
export function scoped(store: Store | undefined): Store | undefined {
|
|
11
|
+
if (!store) return undefined
|
|
12
|
+
return {
|
|
13
|
+
getItem: (key) => store.getItem(key),
|
|
14
|
+
setItem: (key, value) => store.setItem(key, value),
|
|
15
|
+
removeItem: (key) => store.removeItem(key),
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function memoize<value>(
|
|
20
|
+
fetch: () => Promise<value>,
|
|
21
|
+
options: { key: string; store: Store; ttl: number },
|
|
22
|
+
): Promise<value> {
|
|
23
|
+
const { store, ttl } = options
|
|
24
|
+
const key = `${prefix}${options.key}`
|
|
25
|
+
let active = true
|
|
26
|
+
const timeoutError = new Error('Relay cache operation timed out.')
|
|
27
|
+
return withTimeout(
|
|
28
|
+
async () => {
|
|
29
|
+
const raw = await store.getItem(key)
|
|
30
|
+
if (!active) throw timeoutError
|
|
31
|
+
if (raw) {
|
|
32
|
+
try {
|
|
33
|
+
const entry = JSON.parse(raw, (_key, item) => {
|
|
34
|
+
if (typeof item !== 'string' || !item.startsWith(prefix))
|
|
35
|
+
return item
|
|
36
|
+
if (item.startsWith(`${prefix}string:`))
|
|
37
|
+
return item.slice(`${prefix}string:`.length)
|
|
38
|
+
if (item.startsWith(`${prefix}bigint:`))
|
|
39
|
+
return BigInt(item.slice(`${prefix}bigint:`.length))
|
|
40
|
+
throw new TypeError('Invalid relay cache value.')
|
|
41
|
+
}) as { value: value; expiresAt: number }
|
|
42
|
+
if (entry.expiresAt > Date.now()) return entry.value
|
|
43
|
+
} catch {
|
|
44
|
+
// Refresh malformed or older entries.
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
let pending = flights.get(store)
|
|
48
|
+
if (!pending) {
|
|
49
|
+
pending = new Map()
|
|
50
|
+
flights.set(store, pending)
|
|
51
|
+
}
|
|
52
|
+
const existing = pending.get(key)
|
|
53
|
+
if (existing) return existing as Promise<value>
|
|
54
|
+
const result = (async () => {
|
|
55
|
+
const value = await fetch()
|
|
56
|
+
if (!active) throw timeoutError
|
|
57
|
+
if (value !== undefined)
|
|
58
|
+
await store.setItem(
|
|
59
|
+
key,
|
|
60
|
+
JSON.stringify(
|
|
61
|
+
{ value, expiresAt: Date.now() + ttl },
|
|
62
|
+
(_key, item) => {
|
|
63
|
+
if (typeof item === 'bigint') return `${prefix}bigint:${item}`
|
|
64
|
+
if (typeof item === 'string' && item.startsWith(prefix))
|
|
65
|
+
return `${prefix}string:${item}`
|
|
66
|
+
return item
|
|
67
|
+
},
|
|
68
|
+
),
|
|
69
|
+
)
|
|
70
|
+
return value
|
|
71
|
+
})().finally(() => pending.delete(key))
|
|
72
|
+
pending.set(key, result)
|
|
73
|
+
return result
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
timeout: 30_000,
|
|
77
|
+
errorInstance: timeoutError,
|
|
78
|
+
},
|
|
79
|
+
).finally(() => {
|
|
80
|
+
active = false
|
|
81
|
+
})
|
|
82
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { RpcResponse } from 'ox'
|
|
2
|
+
import type * as Relay from '../../Relay.js'
|
|
3
|
+
|
|
4
|
+
/** Bounds the complete fill, including callbacks that do not observe abort signals. */
|
|
5
|
+
export async function run(
|
|
6
|
+
handler: Relay.handleRequest.Handler,
|
|
7
|
+
request: Relay.handleRequest.Request,
|
|
8
|
+
options: Relay.handleRequest.RequestOptions,
|
|
9
|
+
config: Relay.handleRequest.Options,
|
|
10
|
+
) {
|
|
11
|
+
const controller = new AbortController()
|
|
12
|
+
const abort = () => controller.abort(options.signal?.reason)
|
|
13
|
+
options.signal?.addEventListener('abort', abort, { once: true })
|
|
14
|
+
if (options.signal?.aborted) abort()
|
|
15
|
+
const timeout = setTimeout(
|
|
16
|
+
() =>
|
|
17
|
+
controller.abort(
|
|
18
|
+
new RpcResponse.LimitExceededError({
|
|
19
|
+
message: 'Relay fill exceeded its deadline.',
|
|
20
|
+
}),
|
|
21
|
+
),
|
|
22
|
+
config.timeout ?? 10_000,
|
|
23
|
+
)
|
|
24
|
+
const signal = controller.signal
|
|
25
|
+
|
|
26
|
+
let rejectAbort!: (reason: unknown) => void
|
|
27
|
+
const aborted = new Promise<never>((_, reject) => {
|
|
28
|
+
rejectAbort = reject
|
|
29
|
+
})
|
|
30
|
+
const onAbort = () => rejectAbort(signal.reason)
|
|
31
|
+
signal.addEventListener('abort', onAbort, { once: true })
|
|
32
|
+
try {
|
|
33
|
+
signal.throwIfAborted()
|
|
34
|
+
return await Promise.race([
|
|
35
|
+
handler(request, { ...options, signal }),
|
|
36
|
+
aborted,
|
|
37
|
+
])
|
|
38
|
+
} finally {
|
|
39
|
+
clearTimeout(timeout)
|
|
40
|
+
options.signal?.removeEventListener('abort', abort)
|
|
41
|
+
signal.removeEventListener('abort', onAbort)
|
|
42
|
+
// Prevent timed-out hooks from dispatching additional I/O after the response completes.
|
|
43
|
+
controller.abort()
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { Address } from 'abitype'
|
|
2
|
+
import { Hex } from 'ox'
|
|
3
|
+
import type { Client } from '../../../core/Client.js'
|
|
4
|
+
import { format as formatUnits } from 'ox/Value'
|
|
5
|
+
import * as ExecutionError from '../../ExecutionError.js'
|
|
6
|
+
import type * as Store from './cache.js'
|
|
7
|
+
import { resolveTokenMetadata } from './feeToken.js'
|
|
8
|
+
import { simulateAndParseDiffs } from './simulate.js'
|
|
9
|
+
import * as Utils from './utils.js'
|
|
10
|
+
import { extractCalls, resolveVirtualAddresses } from './virtualAddress.js'
|
|
11
|
+
|
|
12
|
+
/** Distinguishes execution reverts from transport and plugin failures. */
|
|
13
|
+
export function isExecutionError(error: unknown): error is Error {
|
|
14
|
+
if (!(error instanceof Error)) return false
|
|
15
|
+
|
|
16
|
+
const seen = new Set<unknown>()
|
|
17
|
+
const pending: unknown[] = [error]
|
|
18
|
+
while (pending.length) {
|
|
19
|
+
const current = pending.pop()
|
|
20
|
+
if (!current || typeof current !== 'object' || seen.has(current)) continue
|
|
21
|
+
seen.add(current)
|
|
22
|
+
|
|
23
|
+
const candidate = current as Record<string, unknown>
|
|
24
|
+
if (
|
|
25
|
+
candidate.code === 3 ||
|
|
26
|
+
candidate.name === 'UpstreamRevertError' ||
|
|
27
|
+
candidate.name === 'ExecutionRevertedError' ||
|
|
28
|
+
candidate.name === 'ContractFunctionRevertedError' ||
|
|
29
|
+
[candidate.message, candidate.details].some(
|
|
30
|
+
(message) =>
|
|
31
|
+
typeof message === 'string' && /^execution reverted\b/i.test(message),
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
return true
|
|
35
|
+
|
|
36
|
+
pending.push(candidate.cause, candidate.error)
|
|
37
|
+
}
|
|
38
|
+
return false
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const zeroAddress = '0x0000000000000000000000000000000000000000'
|
|
42
|
+
|
|
43
|
+
export async function formatError(
|
|
44
|
+
error: Error,
|
|
45
|
+
parameters: Record<string, unknown>,
|
|
46
|
+
client: Client,
|
|
47
|
+
simulateStore?: Store.Store,
|
|
48
|
+
) {
|
|
49
|
+
const revert = ExecutionError.from(error)
|
|
50
|
+
|
|
51
|
+
const stub = {
|
|
52
|
+
from: parameters.from,
|
|
53
|
+
to: parameters.to ?? null,
|
|
54
|
+
gas: '0x0',
|
|
55
|
+
nonce: '0x0',
|
|
56
|
+
value: '0x0',
|
|
57
|
+
maxFeePerGas: '0x0',
|
|
58
|
+
maxPriorityFeePerGas: '0x0',
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (revert.errorName === 'InsufficientBalance' && revert.args?.length === 3) {
|
|
62
|
+
const [available, required, token] = revert.args
|
|
63
|
+
|
|
64
|
+
const normalized = Utils.normalizeFillTransactionRequest(parameters)
|
|
65
|
+
|
|
66
|
+
// Simulate from zero address for optimistic balance diffs.
|
|
67
|
+
const optimisticCalls = normalized ? extractCalls(normalized) : undefined
|
|
68
|
+
const [{ balanceDiffs, tokenMetadata }, virtualAddresses] = optimisticCalls
|
|
69
|
+
? await Promise.all([
|
|
70
|
+
simulateAndParseDiffs(client, {
|
|
71
|
+
account: zeroAddress,
|
|
72
|
+
calls: optimisticCalls,
|
|
73
|
+
store: simulateStore,
|
|
74
|
+
}),
|
|
75
|
+
resolveVirtualAddresses(client, { calls: optimisticCalls }).catch(
|
|
76
|
+
() => undefined,
|
|
77
|
+
),
|
|
78
|
+
])
|
|
79
|
+
: [{ balanceDiffs: undefined, tokenMetadata: undefined }, undefined]
|
|
80
|
+
|
|
81
|
+
// Re-key balance diffs from zero address to the real sender.
|
|
82
|
+
const senderDiffs =
|
|
83
|
+
parameters.from && balanceDiffs
|
|
84
|
+
? { [parameters.from as Address]: balanceDiffs[zeroAddress] ?? [] }
|
|
85
|
+
: balanceDiffs
|
|
86
|
+
|
|
87
|
+
const metadata = await resolveTokenMetadata(client, {
|
|
88
|
+
token,
|
|
89
|
+
tokenMetadata,
|
|
90
|
+
store: simulateStore,
|
|
91
|
+
}).catch(() => undefined)
|
|
92
|
+
const deficit = required - available
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
tx: stub,
|
|
96
|
+
capabilities: {
|
|
97
|
+
balanceDiffs: senderDiffs,
|
|
98
|
+
error: ExecutionError.serialize(revert),
|
|
99
|
+
insufficientFunds: metadata
|
|
100
|
+
? {
|
|
101
|
+
amount: Hex.fromNumber(deficit) as `0x${string}`,
|
|
102
|
+
decimals: metadata.decimals,
|
|
103
|
+
formatted: formatUnits(deficit, metadata.decimals),
|
|
104
|
+
token,
|
|
105
|
+
symbol: metadata.symbol,
|
|
106
|
+
}
|
|
107
|
+
: undefined,
|
|
108
|
+
sponsored: false,
|
|
109
|
+
...(virtualAddresses ? { virtualAddresses } : {}),
|
|
110
|
+
},
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const normalized = Utils.normalizeFillTransactionRequest(parameters)
|
|
115
|
+
const virtualAddresses = normalized
|
|
116
|
+
? await resolveVirtualAddresses(client, {
|
|
117
|
+
calls: extractCalls(normalized),
|
|
118
|
+
}).catch(() => undefined)
|
|
119
|
+
: undefined
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
tx: stub,
|
|
123
|
+
capabilities: {
|
|
124
|
+
error: ExecutionError.serialize(revert),
|
|
125
|
+
sponsored: false,
|
|
126
|
+
...(virtualAddresses ? { virtualAddresses } : {}),
|
|
127
|
+
},
|
|
128
|
+
}
|
|
129
|
+
}
|