viem 2.56.8 → 2.57.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 +78 -0
- package/README.md +0 -1
- package/_cjs/actions/index.js +5 -3
- package/_cjs/actions/index.js.map +1 -1
- package/_cjs/actions/public/getStorageValues.js +17 -0
- package/_cjs/actions/public/getStorageValues.js.map +1 -0
- package/_cjs/actions/public/simulateBlocks.js +2 -0
- package/_cjs/actions/public/simulateBlocks.js.map +1 -1
- package/_cjs/actions/public/waitForTransactionReceipt.js +12 -1
- package/_cjs/actions/public/waitForTransactionReceipt.js.map +1 -1
- package/_cjs/chains/definitions/blockdag.js +23 -0
- package/_cjs/chains/definitions/blockdag.js.map +1 -0
- package/_cjs/chains/definitions/candyChain.js +29 -0
- package/_cjs/chains/definitions/candyChain.js.map +1 -0
- package/_cjs/chains/definitions/creditCoin3Devnet.js +6 -0
- package/_cjs/chains/definitions/creditCoin3Devnet.js.map +1 -1
- package/_cjs/chains/definitions/creditCoin3Mainnet.js +6 -0
- package/_cjs/chains/definitions/creditCoin3Mainnet.js.map +1 -1
- package/_cjs/chains/definitions/creditCoin3Testnet.js +6 -0
- package/_cjs/chains/definitions/creditCoin3Testnet.js.map +1 -1
- package/_cjs/chains/definitions/kortana.js +23 -0
- package/_cjs/chains/definitions/kortana.js.map +1 -0
- package/_cjs/chains/definitions/rabbitChainTestnet.js +24 -0
- package/_cjs/chains/definitions/rabbitChainTestnet.js.map +1 -0
- package/_cjs/chains/index.js +22 -14
- package/_cjs/chains/index.js.map +1 -1
- package/_cjs/clients/createClientResolver.js +45 -0
- package/_cjs/clients/createClientResolver.js.map +1 -0
- package/_cjs/clients/decorators/public.js +2 -0
- package/_cjs/clients/decorators/public.js.map +1 -1
- package/_cjs/errors/version.js +1 -1
- package/_cjs/index.js +13 -9
- package/_cjs/index.js.map +1 -1
- package/_cjs/op-stack/actions/getGame.js +1 -1
- package/_cjs/op-stack/actions/getGame.js.map +1 -1
- package/_cjs/op-stack/actions/getGames.js +1 -1
- package/_cjs/op-stack/actions/getGames.js.map +1 -1
- package/_cjs/op-stack/actions/getTimeToNextGame.js +1 -1
- package/_cjs/op-stack/actions/getTimeToNextGame.js.map +1 -1
- package/_cjs/op-stack/actions/getTimeToNextL2Output.js +1 -1
- package/_cjs/op-stack/actions/getTimeToNextL2Output.js.map +1 -1
- package/_cjs/tempo/Abis.js +1211 -32
- package/_cjs/tempo/Abis.js.map +1 -1
- package/_cjs/tempo/Addresses.js +2 -1
- package/_cjs/tempo/Addresses.js.map +1 -1
- package/_cjs/tempo/Client.js +2 -10
- package/_cjs/tempo/Client.js.map +1 -1
- package/_cjs/tempo/Decorator.js +12 -0
- package/_cjs/tempo/Decorator.js.map +1 -1
- package/_cjs/tempo/ExecutionError.js +290 -0
- package/_cjs/tempo/ExecutionError.js.map +1 -0
- package/_cjs/tempo/Relay.js +88 -0
- package/_cjs/tempo/Relay.js.map +1 -0
- package/_cjs/tempo/Selectors.js +7 -4
- package/_cjs/tempo/Selectors.js.map +1 -1
- package/_cjs/tempo/Transaction.js.map +1 -1
- package/_cjs/tempo/Transport.js +21 -12
- package/_cjs/tempo/Transport.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/propAmm.js +349 -0
- package/_cjs/tempo/actions/propAmm.js.map +1 -0
- package/_cjs/tempo/chainConfig.js +3 -0
- package/_cjs/tempo/chainConfig.js.map +1 -1
- package/_cjs/tempo/index.js +3 -3
- package/_cjs/tempo/index.js.map +1 -1
- package/_cjs/tempo/internal/relay/cache.js +74 -0
- package/_cjs/tempo/internal/relay/cache.js.map +1 -0
- package/_cjs/tempo/internal/relay/deadline.js +35 -0
- package/_cjs/tempo/internal/relay/deadline.js.map +1 -0
- package/_cjs/tempo/internal/relay/error.js +102 -0
- package/_cjs/tempo/internal/relay/error.js.map +1 -0
- package/_cjs/tempo/internal/relay/feePayer.js +426 -0
- package/_cjs/tempo/internal/relay/feePayer.js.map +1 -0
- package/_cjs/tempo/internal/relay/feeToken.js +143 -0
- package/_cjs/tempo/internal/relay/feeToken.js.map +1 -0
- package/_cjs/tempo/{Multisig.js → internal/relay/multisig.js} +132 -122
- package/_cjs/tempo/internal/relay/multisig.js.map +1 -0
- package/_cjs/tempo/internal/relay/plugin.js +13 -0
- package/_cjs/tempo/internal/relay/plugin.js.map +1 -0
- package/_cjs/tempo/internal/relay/preflight.js +58 -0
- package/_cjs/tempo/internal/relay/preflight.js.map +1 -0
- package/_cjs/tempo/internal/relay/request.js +319 -0
- package/_cjs/tempo/internal/relay/request.js.map +1 -0
- package/_cjs/tempo/internal/relay/simulate.js +267 -0
- package/_cjs/tempo/internal/relay/simulate.js.map +1 -0
- package/_cjs/tempo/internal/relay/utils.js +174 -0
- package/_cjs/tempo/internal/relay/utils.js.map +1 -0
- package/_cjs/tempo/internal/relay/virtualAddress.js +78 -0
- package/_cjs/tempo/internal/relay/virtualAddress.js.map +1 -0
- package/_cjs/tempo/internal/relay.js +139 -0
- package/_cjs/tempo/internal/relay.js.map +1 -0
- package/_cjs/tempo/multisig/Config.js +0 -2
- package/_cjs/tempo/multisig/Config.js.map +1 -1
- package/_cjs/tempo/multisig/Operation.js +1 -2
- package/_cjs/tempo/multisig/Operation.js.map +1 -1
- package/_cjs/tokens/definitions/eurc.js +1 -0
- package/_cjs/tokens/definitions/eurc.js.map +1 -1
- package/_cjs/tokens/definitions/usdc.js +1 -0
- package/_cjs/tokens/definitions/usdc.js.map +1 -1
- package/_cjs/utils/siwe/parseSiweMessage.js +3 -3
- package/_cjs/utils/siwe/parseSiweMessage.js.map +1 -1
- package/_esm/actions/index.js +1 -0
- package/_esm/actions/index.js.map +1 -1
- package/_esm/actions/public/getStorageValues.js +39 -0
- package/_esm/actions/public/getStorageValues.js.map +1 -0
- package/_esm/actions/public/simulateBlocks.js +4 -0
- package/_esm/actions/public/simulateBlocks.js.map +1 -1
- package/_esm/actions/public/waitForTransactionReceipt.js +15 -1
- package/_esm/actions/public/waitForTransactionReceipt.js.map +1 -1
- package/_esm/chains/definitions/blockdag.js +20 -0
- package/_esm/chains/definitions/blockdag.js.map +1 -0
- package/_esm/chains/definitions/candyChain.js +26 -0
- package/_esm/chains/definitions/candyChain.js.map +1 -0
- package/_esm/chains/definitions/creditCoin3Devnet.js +6 -0
- package/_esm/chains/definitions/creditCoin3Devnet.js.map +1 -1
- package/_esm/chains/definitions/creditCoin3Mainnet.js +6 -0
- package/_esm/chains/definitions/creditCoin3Mainnet.js.map +1 -1
- package/_esm/chains/definitions/creditCoin3Testnet.js +6 -0
- package/_esm/chains/definitions/creditCoin3Testnet.js.map +1 -1
- package/_esm/chains/definitions/kortana.js +20 -0
- package/_esm/chains/definitions/kortana.js.map +1 -0
- package/_esm/chains/definitions/rabbitChainTestnet.js +21 -0
- package/_esm/chains/definitions/rabbitChainTestnet.js.map +1 -0
- package/_esm/chains/index.js +4 -0
- package/_esm/chains/index.js.map +1 -1
- package/_esm/clients/createClientResolver.js +64 -0
- package/_esm/clients/createClientResolver.js.map +1 -0
- package/_esm/clients/decorators/public.js +2 -0
- package/_esm/clients/decorators/public.js.map +1 -1
- package/_esm/errors/version.js +1 -1
- package/_esm/index.js +2 -0
- package/_esm/index.js.map +1 -1
- package/_esm/op-stack/actions/getGame.js +1 -1
- package/_esm/op-stack/actions/getGame.js.map +1 -1
- package/_esm/op-stack/actions/getGames.js +1 -1
- package/_esm/op-stack/actions/getGames.js.map +1 -1
- package/_esm/op-stack/actions/getTimeToNextGame.js +2 -2
- package/_esm/op-stack/actions/getTimeToNextGame.js.map +1 -1
- package/_esm/op-stack/actions/getTimeToNextL2Output.js +2 -2
- package/_esm/op-stack/actions/getTimeToNextL2Output.js.map +1 -1
- package/_esm/tempo/Abis.js +1214 -34
- package/_esm/tempo/Abis.js.map +1 -1
- package/_esm/tempo/Addresses.js +2 -0
- package/_esm/tempo/Addresses.js.map +1 -1
- package/_esm/tempo/Client.js +8 -14
- package/_esm/tempo/Client.js.map +1 -1
- package/_esm/tempo/Decorator.js +12 -0
- package/_esm/tempo/Decorator.js.map +1 -1
- package/_esm/tempo/ExecutionError.js +306 -0
- package/_esm/tempo/ExecutionError.js.map +1 -0
- package/_esm/tempo/Relay.js +170 -0
- package/_esm/tempo/Relay.js.map +1 -0
- package/_esm/tempo/Selectors.js +6 -3
- package/_esm/tempo/Selectors.js.map +1 -1
- package/_esm/tempo/Transaction.js.map +1 -1
- package/_esm/tempo/Transport.js +21 -46
- package/_esm/tempo/Transport.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/propAmm.js +539 -0
- package/_esm/tempo/actions/propAmm.js.map +1 -0
- package/_esm/tempo/chainConfig.js +4 -0
- package/_esm/tempo/chainConfig.js.map +1 -1
- package/_esm/tempo/index.js +8 -3
- package/_esm/tempo/index.js.map +1 -1
- package/_esm/tempo/internal/relay/cache.js +72 -0
- package/_esm/tempo/internal/relay/cache.js.map +1 -0
- package/_esm/tempo/internal/relay/deadline.js +34 -0
- package/_esm/tempo/internal/relay/deadline.js.map +1 -0
- package/_esm/tempo/internal/relay/error.js +101 -0
- package/_esm/tempo/internal/relay/error.js.map +1 -0
- package/_esm/tempo/internal/relay/feePayer.js +442 -0
- package/_esm/tempo/internal/relay/feePayer.js.map +1 -0
- package/_esm/tempo/internal/relay/feeToken.js +143 -0
- package/_esm/tempo/internal/relay/feeToken.js.map +1 -0
- package/_esm/tempo/{Multisig.js → internal/relay/multisig.js} +133 -129
- package/_esm/tempo/internal/relay/multisig.js.map +1 -0
- package/_esm/tempo/internal/relay/plugin.js +10 -0
- package/_esm/tempo/internal/relay/plugin.js.map +1 -0
- package/_esm/tempo/internal/relay/preflight.js +57 -0
- package/_esm/tempo/internal/relay/preflight.js.map +1 -0
- package/_esm/tempo/internal/relay/request.js +321 -0
- package/_esm/tempo/internal/relay/request.js.map +1 -0
- package/_esm/tempo/internal/relay/simulate.js +277 -0
- package/_esm/tempo/internal/relay/simulate.js.map +1 -0
- package/_esm/tempo/internal/relay/utils.js +174 -0
- package/_esm/tempo/internal/relay/utils.js.map +1 -0
- package/_esm/tempo/internal/relay/virtualAddress.js +73 -0
- package/_esm/tempo/internal/relay/virtualAddress.js.map +1 -0
- package/_esm/tempo/internal/relay.js +138 -0
- package/_esm/tempo/internal/relay.js.map +1 -0
- package/_esm/tempo/multisig/Config.js +2 -1
- package/_esm/tempo/multisig/Config.js.map +1 -1
- package/_esm/tempo/multisig/Operation.js +1 -1
- package/_esm/tempo/multisig/Operation.js.map +1 -1
- package/_esm/tokens/definitions/eurc.js +1 -0
- package/_esm/tokens/definitions/eurc.js.map +1 -1
- package/_esm/tokens/definitions/usdc.js +1 -0
- package/_esm/tokens/definitions/usdc.js.map +1 -1
- package/_esm/utils/siwe/parseSiweMessage.js +3 -3
- package/_esm/utils/siwe/parseSiweMessage.js.map +1 -1
- package/_types/actions/index.d.ts +1 -0
- package/_types/actions/index.d.ts.map +1 -1
- package/_types/actions/public/getStorageValues.d.ts +59 -0
- package/_types/actions/public/getStorageValues.d.ts.map +1 -0
- package/_types/actions/public/simulateBlocks.d.ts +8 -0
- package/_types/actions/public/simulateBlocks.d.ts.map +1 -1
- package/_types/actions/public/waitForTransactionReceipt.d.ts.map +1 -1
- package/_types/chains/definitions/blockdag.d.ts +51 -0
- package/_types/chains/definitions/blockdag.d.ts.map +1 -0
- package/_types/chains/definitions/candyChain.d.ts +48 -0
- package/_types/chains/definitions/candyChain.d.ts.map +1 -0
- package/_types/chains/definitions/creditCoin3Devnet.d.ts +6 -9
- package/_types/chains/definitions/creditCoin3Devnet.d.ts.map +1 -1
- package/_types/chains/definitions/creditCoin3Mainnet.d.ts +6 -9
- package/_types/chains/definitions/creditCoin3Mainnet.d.ts.map +1 -1
- package/_types/chains/definitions/creditCoin3Testnet.d.ts +6 -9
- package/_types/chains/definitions/creditCoin3Testnet.d.ts.map +1 -1
- package/_types/chains/definitions/kortana.d.ts +51 -0
- package/_types/chains/definitions/kortana.d.ts.map +1 -0
- package/_types/chains/definitions/rabbitChainTestnet.d.ts +51 -0
- package/_types/chains/definitions/rabbitChainTestnet.d.ts.map +1 -0
- package/_types/chains/index.d.ts +4 -0
- package/_types/chains/index.d.ts.map +1 -1
- package/_types/clients/createClientResolver.d.ts +76 -0
- package/_types/clients/createClientResolver.d.ts.map +1 -0
- package/_types/clients/decorators/public.d.ts +11 -0
- package/_types/clients/decorators/public.d.ts.map +1 -1
- package/_types/errors/version.d.ts +1 -1
- package/_types/index.d.ts +3 -0
- package/_types/index.d.ts.map +1 -1
- package/_types/op-stack/actions/getGame.d.ts.map +1 -1
- package/_types/tempo/Abis.d.ts +14686 -9568
- package/_types/tempo/Abis.d.ts.map +1 -1
- package/_types/tempo/Addresses.d.ts +2 -0
- package/_types/tempo/Addresses.d.ts.map +1 -1
- package/_types/tempo/Capabilities.d.ts +7 -28
- package/_types/tempo/Capabilities.d.ts.map +1 -1
- package/_types/tempo/Client.d.ts +6 -15
- package/_types/tempo/Client.d.ts.map +1 -1
- package/_types/tempo/Decorator.d.ts +205 -1
- package/_types/tempo/Decorator.d.ts.map +1 -1
- package/_types/tempo/ExecutionError.d.ts +79 -0
- package/_types/tempo/ExecutionError.d.ts.map +1 -0
- package/_types/tempo/Relay.d.ts +302 -0
- package/_types/tempo/Relay.d.ts.map +1 -0
- package/_types/tempo/Selectors.d.ts +6 -3
- package/_types/tempo/Selectors.d.ts.map +1 -1
- package/_types/tempo/Transaction.d.ts +2 -1
- package/_types/tempo/Transaction.d.ts.map +1 -1
- package/_types/tempo/Transport.d.ts +15 -29
- package/_types/tempo/Transport.d.ts.map +1 -1
- package/_types/tempo/actions/earn.d.ts +621 -1
- package/_types/tempo/actions/earn.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/propAmm.d.ts +2228 -0
- package/_types/tempo/actions/propAmm.d.ts.map +1 -0
- package/_types/tempo/chainConfig.d.ts.map +1 -1
- package/_types/tempo/index.d.ts +8 -3
- package/_types/tempo/index.d.ts.map +1 -1
- package/_types/tempo/internal/relay/cache.d.ts +9 -0
- package/_types/tempo/internal/relay/cache.d.ts.map +1 -0
- package/_types/tempo/internal/relay/deadline.d.ts +4 -0
- package/_types/tempo/internal/relay/deadline.d.ts.map +1 -0
- package/_types/tempo/internal/relay/error.d.ts +47 -0
- package/_types/tempo/internal/relay/error.d.ts.map +1 -0
- package/_types/tempo/internal/relay/feePayer.d.ts +70 -0
- package/_types/tempo/internal/relay/feePayer.d.ts.map +1 -0
- package/_types/tempo/internal/relay/feeToken.d.ts +38 -0
- package/_types/tempo/internal/relay/feeToken.d.ts.map +1 -0
- package/_types/tempo/internal/relay/multisig.d.ts +4 -0
- package/_types/tempo/internal/relay/multisig.d.ts.map +1 -0
- package/_types/tempo/internal/relay/plugin.d.ts +5 -0
- package/_types/tempo/internal/relay/plugin.d.ts.map +1 -0
- package/_types/tempo/internal/relay/preflight.d.ts +17 -0
- package/_types/tempo/internal/relay/preflight.d.ts.map +1 -0
- package/_types/tempo/internal/relay/request.d.ts +16 -0
- package/_types/tempo/internal/relay/request.d.ts.map +1 -0
- package/_types/tempo/internal/relay/simulate.d.ts +59 -0
- package/_types/tempo/internal/relay/simulate.d.ts.map +1 -0
- package/_types/tempo/internal/relay/utils.d.ts +294 -0
- package/_types/tempo/internal/relay/utils.d.ts.map +1 -0
- package/_types/tempo/internal/relay/virtualAddress.d.ts +9 -0
- package/_types/tempo/internal/relay/virtualAddress.d.ts.map +1 -0
- package/_types/tempo/internal/relay.d.ts +4 -0
- package/_types/tempo/internal/relay.d.ts.map +1 -0
- package/_types/tempo/multisig/Config.d.ts +0 -13
- package/_types/tempo/multisig/Config.d.ts.map +1 -1
- package/_types/tempo/multisig/Operation.d.ts +0 -5
- package/_types/tempo/multisig/Operation.d.ts.map +1 -1
- package/_types/tokens/definitions/eurc.d.ts +1 -0
- package/_types/tokens/definitions/eurc.d.ts.map +1 -1
- package/_types/tokens/definitions/usdc.d.ts +1 -0
- package/_types/tokens/definitions/usdc.d.ts.map +1 -1
- package/_types/tokens/sets.d.ts +3 -0
- package/_types/tokens/sets.d.ts.map +1 -1
- package/_types/types/eip1193.d.ts +20 -0
- package/_types/types/eip1193.d.ts.map +1 -1
- package/_types/utils/siwe/parseSiweMessage.d.ts.map +1 -1
- package/actions/index.ts +6 -0
- package/actions/public/getStorageValues.ts +93 -0
- package/actions/public/simulateBlocks.ts +13 -0
- package/actions/public/waitForTransactionReceipt.ts +16 -2
- package/chains/definitions/blockdag.ts +20 -0
- package/chains/definitions/candyChain.ts +26 -0
- package/chains/definitions/creditCoin3Devnet.ts +6 -0
- package/chains/definitions/creditCoin3Mainnet.ts +6 -0
- package/chains/definitions/creditCoin3Testnet.ts +6 -0
- package/chains/definitions/kortana.ts +20 -0
- package/chains/definitions/rabbitChainTestnet.ts +21 -0
- package/chains/index.ts +4 -0
- package/clients/createClientResolver.ts +191 -0
- package/clients/decorators/public.ts +18 -0
- package/errors/version.ts +1 -1
- package/index.ts +11 -0
- package/op-stack/actions/getGame.ts +3 -1
- package/op-stack/actions/getGames.ts +1 -1
- package/op-stack/actions/getTimeToNextGame.ts +2 -2
- package/op-stack/actions/getTimeToNextL2Output.ts +2 -2
- package/package.json +1 -1
- package/tempo/Abis.ts +1218 -34
- package/tempo/Addresses.ts +2 -0
- package/tempo/Capabilities.ts +7 -29
- package/tempo/Client.ts +8 -38
- package/tempo/Decorator.ts +239 -3
- package/tempo/ExecutionError.ts +418 -0
- package/tempo/Relay.ts +428 -0
- package/tempo/Selectors.ts +10 -4
- package/tempo/Transaction.ts +2 -1
- package/tempo/Transport.ts +69 -60
- package/tempo/actions/index.ts +1 -0
- package/tempo/actions/propAmm.ts +998 -0
- package/tempo/chainConfig.ts +4 -0
- package/tempo/index.ts +7 -3
- package/tempo/internal/relay/cache.ts +82 -0
- package/tempo/internal/relay/deadline.ts +45 -0
- package/tempo/internal/relay/error.ts +128 -0
- package/tempo/internal/relay/feePayer.ts +692 -0
- package/tempo/internal/relay/feeToken.ts +190 -0
- package/tempo/{Multisig.ts → internal/relay/multisig.ts} +162 -193
- package/tempo/internal/relay/plugin.ts +13 -0
- package/tempo/internal/relay/preflight.ts +81 -0
- package/tempo/internal/relay/request.ts +391 -0
- package/tempo/internal/relay/simulate.ts +367 -0
- package/tempo/internal/relay/utils.ts +202 -0
- package/tempo/internal/relay/virtualAddress.ts +95 -0
- package/tempo/internal/relay.ts +158 -0
- package/tempo/multisig/Config.ts +3 -2
- package/tempo/multisig/Operation.ts +1 -1
- package/tokens/definitions/eurc.ts +1 -0
- package/tokens/definitions/usdc.ts +1 -0
- package/types/eip1193.ts +20 -0
- package/utils/siwe/parseSiweMessage.ts +21 -13
- package/_cjs/tempo/Multisig.js.map +0 -1
- package/_esm/tempo/Multisig.js.map +0 -1
- package/_types/tempo/Multisig.d.ts +0 -37
- package/_types/tempo/Multisig.d.ts.map +0 -1
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import type { Address } from 'abitype'
|
|
2
|
+
import { AbiEvent, Hex } from 'ox'
|
|
3
|
+
import type { Client } from '../../../clients/createClient.js'
|
|
4
|
+
import { zeroAddress } from '../../../constants/address.js'
|
|
5
|
+
import type { Call } from '../../../types/calls.js'
|
|
6
|
+
import type { Log } from '../../../types/log.js'
|
|
7
|
+
import { parseEventLogs } from '../../../utils/abi/parseEventLogs.js'
|
|
8
|
+
import { formatUnits } from '../../../utils/unit/formatUnits.js'
|
|
9
|
+
import * as Abis from '../../Abis.js'
|
|
10
|
+
import * as Actions from '../../actions/index.js'
|
|
11
|
+
import type * as Capabilities from '../../Capabilities.js'
|
|
12
|
+
import type * as Relay from '../../Relay.js'
|
|
13
|
+
import type * as Store from './cache.js'
|
|
14
|
+
import { formatError, isExecutionError } from './error.js'
|
|
15
|
+
import { resolveTokenMetadata } from './feeToken.js'
|
|
16
|
+
import * as Utils from './utils.js'
|
|
17
|
+
import { extractCalls } from './virtualAddress.js'
|
|
18
|
+
|
|
19
|
+
export function create(options: Relay.simulate.Options): Relay.Plugin {
|
|
20
|
+
return {
|
|
21
|
+
async handleRequest(context, next) {
|
|
22
|
+
if (context.request.method !== 'eth_fillTransaction') return next()
|
|
23
|
+
try {
|
|
24
|
+
await next()
|
|
25
|
+
} catch (error) {
|
|
26
|
+
const parameters = context.request.params![0] as Record<string, unknown>
|
|
27
|
+
if (
|
|
28
|
+
isExecutionError(error) &&
|
|
29
|
+
(parameters.capabilities as Record<string, unknown> | undefined)
|
|
30
|
+
?.errors === true
|
|
31
|
+
)
|
|
32
|
+
return formatError(
|
|
33
|
+
error,
|
|
34
|
+
parameters,
|
|
35
|
+
context.client,
|
|
36
|
+
context.getStore(options.store),
|
|
37
|
+
)
|
|
38
|
+
throw error
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
async afterFill(result, context) {
|
|
42
|
+
const parameters = context.request.params![0] as Record<string, unknown>
|
|
43
|
+
const store = context.getStore(options.store)
|
|
44
|
+
const signal = context.options.signal
|
|
45
|
+
const transaction = Utils.normalizeTempoTransaction(result.tx)
|
|
46
|
+
const feeToken = transaction.feeToken as Address | undefined
|
|
47
|
+
const simulation =
|
|
48
|
+
(parameters.capabilities as Record<string, unknown> | undefined)
|
|
49
|
+
?.balanceDiffs !== false
|
|
50
|
+
? await simulateAndParseDiffs(context.client, {
|
|
51
|
+
account: parameters.from as Address | undefined,
|
|
52
|
+
calls: extractCalls(transaction),
|
|
53
|
+
feeToken,
|
|
54
|
+
gas: transaction.gas,
|
|
55
|
+
maxFeePerGas: transaction.maxFeePerGas,
|
|
56
|
+
store,
|
|
57
|
+
signal,
|
|
58
|
+
})
|
|
59
|
+
: await computeFee(context.client, {
|
|
60
|
+
feeToken,
|
|
61
|
+
gas: transaction.gas,
|
|
62
|
+
maxFeePerGas: transaction.maxFeePerGas,
|
|
63
|
+
store,
|
|
64
|
+
signal,
|
|
65
|
+
}).then((fee) => ({ balanceDiffs: undefined, fee }))
|
|
66
|
+
return {
|
|
67
|
+
capabilities: {
|
|
68
|
+
balanceDiffs: simulation.balanceDiffs,
|
|
69
|
+
fee: simulation.fee,
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export async function simulateAndParseDiffs(
|
|
77
|
+
client: Client,
|
|
78
|
+
options: simulateAndParseDiffs.Options,
|
|
79
|
+
) {
|
|
80
|
+
const { account, calls, feeToken, gas, store, maxFeePerGas, signal } = options
|
|
81
|
+
signal?.throwIfAborted()
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
// Including the fee token as a read target asks the node to return its metadata too.
|
|
85
|
+
const probe =
|
|
86
|
+
feeToken &&
|
|
87
|
+
!calls.some((call) => call.to?.toLowerCase() === feeToken.toLowerCase())
|
|
88
|
+
? [
|
|
89
|
+
Actions.token.getBalance.call(client, {
|
|
90
|
+
account: account ?? zeroAddress,
|
|
91
|
+
token: feeToken,
|
|
92
|
+
}),
|
|
93
|
+
]
|
|
94
|
+
: []
|
|
95
|
+
const simulation = await Actions.simulate.simulateCalls(client, {
|
|
96
|
+
account: account === zeroAddress ? undefined : account,
|
|
97
|
+
calls: [...calls, ...probe] as Call[],
|
|
98
|
+
traceTransfers: true,
|
|
99
|
+
})
|
|
100
|
+
const results = simulation.results.slice(0, calls.length)
|
|
101
|
+
const { tokenMetadata } = simulation
|
|
102
|
+
|
|
103
|
+
signal?.throwIfAborted()
|
|
104
|
+
|
|
105
|
+
// Collect all logs across all call results.
|
|
106
|
+
const logs: (typeof results)[number]['logs'] = []
|
|
107
|
+
for (const result of results as {
|
|
108
|
+
logs?: (typeof logs)[number][] | undefined
|
|
109
|
+
}[])
|
|
110
|
+
if (result.logs) logs.push(...result.logs)
|
|
111
|
+
|
|
112
|
+
// Build per-token balance diffs relative to the sender.
|
|
113
|
+
const balanceDiffs = account
|
|
114
|
+
? await buildBalanceDiffs(client, {
|
|
115
|
+
account,
|
|
116
|
+
store,
|
|
117
|
+
signal,
|
|
118
|
+
logs,
|
|
119
|
+
tokenMetadata: tokenMetadata as never,
|
|
120
|
+
})
|
|
121
|
+
: {}
|
|
122
|
+
|
|
123
|
+
// Compute fee breakdown.
|
|
124
|
+
const fee = await computeFee(client, {
|
|
125
|
+
feeToken,
|
|
126
|
+
gas,
|
|
127
|
+
store,
|
|
128
|
+
signal,
|
|
129
|
+
maxFeePerGas,
|
|
130
|
+
tokenMetadata: tokenMetadata as never,
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
return { balanceDiffs, fee, tokenMetadata }
|
|
134
|
+
} catch {
|
|
135
|
+
signal?.throwIfAborted()
|
|
136
|
+
// Simulation failures should not block the fill response —
|
|
137
|
+
// return empty diffs with fee computed from transaction fields.
|
|
138
|
+
const fee = await computeFee(client, {
|
|
139
|
+
feeToken,
|
|
140
|
+
gas,
|
|
141
|
+
store,
|
|
142
|
+
maxFeePerGas,
|
|
143
|
+
signal,
|
|
144
|
+
})
|
|
145
|
+
return { balanceDiffs: undefined, fee, tokenMetadata: undefined }
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export declare namespace simulateAndParseDiffs {
|
|
150
|
+
type Options = {
|
|
151
|
+
account?: Address | undefined
|
|
152
|
+
calls: readonly Call[]
|
|
153
|
+
feeToken?: Address | undefined
|
|
154
|
+
gas?: bigint | undefined
|
|
155
|
+
store?: Store.Store | undefined
|
|
156
|
+
signal?: AbortSignal | undefined
|
|
157
|
+
maxFeePerGas?: bigint | undefined
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Builds a complete preview within the metadata lookup budget. @internal */
|
|
162
|
+
export async function buildBalanceDiffs(
|
|
163
|
+
client: Client,
|
|
164
|
+
options: buildBalanceDiffs.Options,
|
|
165
|
+
) {
|
|
166
|
+
const { account, store, logs, tokenMetadata, signal } = options
|
|
167
|
+
signal?.throwIfAborted()
|
|
168
|
+
const accountLower = account.toLowerCase()
|
|
169
|
+
|
|
170
|
+
const transferLogs = parseEventLogs({
|
|
171
|
+
abi: [AbiEvent.fromAbi(Abis.tip20, 'Transfer')],
|
|
172
|
+
eventName: 'Transfer',
|
|
173
|
+
logs,
|
|
174
|
+
})
|
|
175
|
+
const approvalLogs = parseEventLogs({
|
|
176
|
+
abi: [AbiEvent.fromAbi(Abis.tip20, 'Approval')],
|
|
177
|
+
eventName: 'Approval',
|
|
178
|
+
logs,
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
// Track net movement per token: incoming vs outgoing.
|
|
182
|
+
const tokenMap = new Map<
|
|
183
|
+
string,
|
|
184
|
+
{
|
|
185
|
+
incoming: bigint
|
|
186
|
+
outgoing: bigint
|
|
187
|
+
approved: bigint
|
|
188
|
+
recipients: Set<Address>
|
|
189
|
+
token: Address
|
|
190
|
+
}
|
|
191
|
+
>()
|
|
192
|
+
|
|
193
|
+
for (const log of transferLogs) {
|
|
194
|
+
const token = log.address.toLowerCase()
|
|
195
|
+
const fromLower = log.args.from.toLowerCase()
|
|
196
|
+
const toLower = log.args.to.toLowerCase()
|
|
197
|
+
|
|
198
|
+
const entry = tokenMap.get(token) ?? {
|
|
199
|
+
incoming: 0n,
|
|
200
|
+
outgoing: 0n,
|
|
201
|
+
approved: 0n,
|
|
202
|
+
recipients: new Set<Address>(),
|
|
203
|
+
token: log.address,
|
|
204
|
+
}
|
|
205
|
+
if (fromLower === accountLower) {
|
|
206
|
+
entry.outgoing += log.args.amount
|
|
207
|
+
entry.recipients.add(log.args.to)
|
|
208
|
+
}
|
|
209
|
+
if (toLower === accountLower) entry.incoming += log.args.amount
|
|
210
|
+
tokenMap.set(token, entry)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Approvals replace allowances; retain the last event for each token and spender.
|
|
214
|
+
const approvals = new Map<string, (typeof approvalLogs)[number]>()
|
|
215
|
+
for (const log of approvalLogs) {
|
|
216
|
+
if (log.args.owner.toLowerCase() !== accountLower) continue
|
|
217
|
+
approvals.set(
|
|
218
|
+
`${log.address.toLowerCase()}:${log.args.spender.toLowerCase()}`,
|
|
219
|
+
log,
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Transfers do not identify allowance consumption, so retain final approval exposure.
|
|
224
|
+
for (const log of approvals.values()) {
|
|
225
|
+
if (log.args.amount === 0n) continue
|
|
226
|
+
const token = log.address.toLowerCase()
|
|
227
|
+
|
|
228
|
+
const entry = tokenMap.get(token) ?? {
|
|
229
|
+
incoming: 0n,
|
|
230
|
+
outgoing: 0n,
|
|
231
|
+
approved: 0n,
|
|
232
|
+
recipients: new Set<Address>(),
|
|
233
|
+
token: log.address,
|
|
234
|
+
}
|
|
235
|
+
entry.approved += log.args.amount
|
|
236
|
+
entry.recipients.add(log.args.spender)
|
|
237
|
+
tokenMap.set(token, entry)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Collect unique tokens that need decimals.
|
|
241
|
+
const entries = [...tokenMap.values()].filter((e) => {
|
|
242
|
+
const net =
|
|
243
|
+
e.outgoing > e.incoming
|
|
244
|
+
? e.outgoing - e.incoming
|
|
245
|
+
: e.incoming - e.outgoing
|
|
246
|
+
return net > 0n || e.approved > 0n
|
|
247
|
+
})
|
|
248
|
+
if (entries.length === 0) return {}
|
|
249
|
+
// Omit an unavailable preview rather than returning a partial set of movements.
|
|
250
|
+
if (entries.length > 100) return undefined
|
|
251
|
+
|
|
252
|
+
// Bound metadata work for a single fill independently of the RPC batch limit.
|
|
253
|
+
const metadataMap = new Map<
|
|
254
|
+
string,
|
|
255
|
+
{ decimals: number; symbol: string; name: string }
|
|
256
|
+
>()
|
|
257
|
+
let index = 0
|
|
258
|
+
await Promise.all(
|
|
259
|
+
Array.from({ length: Math.min(10, entries.length) }, async () => {
|
|
260
|
+
while (index < entries.length) {
|
|
261
|
+
const entry = entries[index++]!
|
|
262
|
+
try {
|
|
263
|
+
const metadata = await resolveTokenMetadata(client, {
|
|
264
|
+
token: entry.token,
|
|
265
|
+
tokenMetadata,
|
|
266
|
+
store,
|
|
267
|
+
})
|
|
268
|
+
metadataMap.set(entry.token.toLowerCase(), metadata)
|
|
269
|
+
} catch {
|
|
270
|
+
signal?.throwIfAborted()
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}),
|
|
274
|
+
)
|
|
275
|
+
signal?.throwIfAborted()
|
|
276
|
+
if (metadataMap.size !== entries.length) return undefined
|
|
277
|
+
|
|
278
|
+
// Build the diff array for this account.
|
|
279
|
+
const diffs: Capabilities.BalanceDiff[] = []
|
|
280
|
+
for (const entry of entries) {
|
|
281
|
+
const incoming =
|
|
282
|
+
entry.incoming > entry.outgoing ? entry.incoming - entry.outgoing : 0n
|
|
283
|
+
const outgoing =
|
|
284
|
+
(entry.outgoing > entry.incoming ? entry.outgoing - entry.incoming : 0n) +
|
|
285
|
+
entry.approved
|
|
286
|
+
const meta = metadataMap.get(entry.token.toLowerCase())!
|
|
287
|
+
const decimals = meta.decimals
|
|
288
|
+
const metadata = {
|
|
289
|
+
address: entry.token,
|
|
290
|
+
decimals,
|
|
291
|
+
name: meta.name,
|
|
292
|
+
symbol: meta.symbol,
|
|
293
|
+
}
|
|
294
|
+
if (incoming > 0n)
|
|
295
|
+
diffs.push({
|
|
296
|
+
...metadata,
|
|
297
|
+
direction: 'incoming',
|
|
298
|
+
formatted: formatUnits(incoming, decimals),
|
|
299
|
+
recipients: [],
|
|
300
|
+
value: Hex.fromNumber(incoming),
|
|
301
|
+
})
|
|
302
|
+
if (outgoing > 0n)
|
|
303
|
+
diffs.push({
|
|
304
|
+
...metadata,
|
|
305
|
+
direction: 'outgoing',
|
|
306
|
+
formatted: formatUnits(outgoing, decimals),
|
|
307
|
+
recipients: [...entry.recipients],
|
|
308
|
+
value: Hex.fromNumber(outgoing),
|
|
309
|
+
})
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return { [account]: diffs }
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export declare namespace buildBalanceDiffs {
|
|
316
|
+
type Options = {
|
|
317
|
+
account: Address
|
|
318
|
+
store?: Store.Store | undefined
|
|
319
|
+
signal?: AbortSignal | undefined
|
|
320
|
+
logs: Log[]
|
|
321
|
+
tokenMetadata: Record<
|
|
322
|
+
Address,
|
|
323
|
+
{ name: string; symbol: string; currency: string }
|
|
324
|
+
>
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// biome-ignore lint/correctness/noUnusedVariables: declaration merge
|
|
329
|
+
async function computeFee(client: Client, options: computeFee.Options) {
|
|
330
|
+
const { feeToken, gas, store, maxFeePerGas, tokenMetadata, signal } = options
|
|
331
|
+
signal?.throwIfAborted()
|
|
332
|
+
if (!feeToken || !gas || !maxFeePerGas) return undefined
|
|
333
|
+
|
|
334
|
+
try {
|
|
335
|
+
const metadata = await resolveTokenMetadata(client, {
|
|
336
|
+
token: feeToken,
|
|
337
|
+
tokenMetadata,
|
|
338
|
+
store,
|
|
339
|
+
})
|
|
340
|
+
signal?.throwIfAborted()
|
|
341
|
+
const raw = gas * maxFeePerGas
|
|
342
|
+
const scale = 10n ** BigInt(Math.max(0, 18 - metadata.decimals))
|
|
343
|
+
const amount = (raw + scale - 1n) / scale
|
|
344
|
+
return {
|
|
345
|
+
amount: Hex.fromNumber(amount) as `0x${string}`,
|
|
346
|
+
decimals: metadata.decimals,
|
|
347
|
+
formatted: formatUnits(amount, metadata.decimals),
|
|
348
|
+
symbol: metadata.symbol,
|
|
349
|
+
}
|
|
350
|
+
} catch {
|
|
351
|
+
signal?.throwIfAborted()
|
|
352
|
+
return undefined
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
declare namespace computeFee {
|
|
357
|
+
type Options = {
|
|
358
|
+
feeToken?: Address | undefined
|
|
359
|
+
gas?: bigint | undefined
|
|
360
|
+
store?: Store.Store | undefined
|
|
361
|
+
signal?: AbortSignal | undefined
|
|
362
|
+
maxFeePerGas?: bigint | undefined
|
|
363
|
+
tokenMetadata?:
|
|
364
|
+
| Record<Address, { name: string; symbol: string; currency: string }>
|
|
365
|
+
| undefined
|
|
366
|
+
}
|
|
367
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { Address, Hex, RpcResponse } from 'ox'
|
|
2
|
+
import {
|
|
3
|
+
Transaction as core_Transaction,
|
|
4
|
+
KeyAuthorization,
|
|
5
|
+
TxEnvelopeTempo,
|
|
6
|
+
} from 'ox/tempo'
|
|
7
|
+
import type { Client } from '../../../clients/createClient.js'
|
|
8
|
+
import { UnknownRpcError } from '../../../errors/rpc.js'
|
|
9
|
+
|
|
10
|
+
export function resolveChainId(value: unknown) {
|
|
11
|
+
if (typeof value === 'number') return value
|
|
12
|
+
if (typeof value === 'bigint') return Number(value)
|
|
13
|
+
if (typeof value === 'string') {
|
|
14
|
+
if (!/^(?:0x[0-9a-f]+|[0-9]+)$/i.test(value)) return undefined
|
|
15
|
+
const n = Number(value)
|
|
16
|
+
if (Number.isFinite(n)) return n
|
|
17
|
+
}
|
|
18
|
+
return undefined
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function formatFillTransactionRequest(
|
|
22
|
+
client: Client,
|
|
23
|
+
value: Record<string, unknown>,
|
|
24
|
+
) {
|
|
25
|
+
if (value.type === '0x76') return { ...value }
|
|
26
|
+
const format = client.chain?.formatters?.transactionRequest?.format
|
|
27
|
+
if (!format) return value
|
|
28
|
+
return {
|
|
29
|
+
...format({ ...value } as never, 'fillTransaction'),
|
|
30
|
+
// Keep the selected token until the request leaves the plugin pipeline.
|
|
31
|
+
...(value.feeToken !== undefined ? { feeToken: value.feeToken } : {}),
|
|
32
|
+
} as Record<string, unknown>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function normalizeFillTransactionRequest(
|
|
36
|
+
tx: Record<string, unknown>,
|
|
37
|
+
): Record<string, unknown> & { calls: unknown[] } {
|
|
38
|
+
const { to, data, value, ...rest } = tx
|
|
39
|
+
const keyAuthorization = normalizeKeyAuthorization(tx.keyAuthorization)
|
|
40
|
+
const withKeyAuthorization = keyAuthorization ? { keyAuthorization } : {}
|
|
41
|
+
if (Array.isArray(tx.calls))
|
|
42
|
+
return {
|
|
43
|
+
...tx,
|
|
44
|
+
...withKeyAuthorization,
|
|
45
|
+
calls: tx.calls.map((call) => {
|
|
46
|
+
if (!call || typeof call !== 'object' || Array.isArray(call))
|
|
47
|
+
throw new RpcResponse.InvalidParamsError({
|
|
48
|
+
message: 'Expected a transaction call object.',
|
|
49
|
+
})
|
|
50
|
+
assertCallTarget(call.to)
|
|
51
|
+
return { ...call, value: normalizeFillValue(call.value) }
|
|
52
|
+
}),
|
|
53
|
+
}
|
|
54
|
+
assertCallTarget(to)
|
|
55
|
+
const call = {
|
|
56
|
+
...(typeof to !== 'undefined' ? { to } : {}),
|
|
57
|
+
...(typeof data !== 'undefined' ? { data } : {}),
|
|
58
|
+
...(typeof value !== 'undefined'
|
|
59
|
+
? { value: normalizeFillValue(value) }
|
|
60
|
+
: {}),
|
|
61
|
+
}
|
|
62
|
+
return { ...rest, ...withKeyAuthorization, calls: [call] }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Forwards `keyAuthorization` to the chain in RPC shape. Pass-through
|
|
67
|
+
* when already RPC; convert via `KeyAuthorization.toRpc` when internal.
|
|
68
|
+
*/
|
|
69
|
+
function normalizeKeyAuthorization(value: unknown) {
|
|
70
|
+
if (!value || typeof value !== 'object') return undefined
|
|
71
|
+
const ka = value as Record<string, unknown>
|
|
72
|
+
const signature = ka.signature as Record<string, unknown> | undefined
|
|
73
|
+
if (!signature || typeof signature !== 'object') return undefined
|
|
74
|
+
const isInternal =
|
|
75
|
+
typeof signature.signature === 'object' && signature.signature !== null
|
|
76
|
+
return isInternal ? KeyAuthorization.toRpc(value as never) : value
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function assertCallTarget(to: unknown) {
|
|
80
|
+
if (to === undefined || to === null) return
|
|
81
|
+
if (typeof to !== 'string' || !Address.validate(to, { strict: false }))
|
|
82
|
+
throw new RpcResponse.InvalidParamsError({
|
|
83
|
+
message: 'Invalid transaction call target.',
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function normalizeFillValue(value: unknown) {
|
|
88
|
+
if (typeof value !== 'string' || !value.startsWith('0x')) return value
|
|
89
|
+
if (!/^0x[\da-f]*$/i.test(value))
|
|
90
|
+
throw new RpcResponse.InvalidParamsError({
|
|
91
|
+
message: 'Invalid transaction value.',
|
|
92
|
+
})
|
|
93
|
+
return BigInt(value === '0x' ? '0x0' : value)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Returns whether a raw transaction uses a Tempo sender or fee-payer wire prefix. */
|
|
97
|
+
export function isSerializedTempoTransaction(
|
|
98
|
+
value: unknown,
|
|
99
|
+
): value is `0x76${string}` | `0x78${string}` {
|
|
100
|
+
if (typeof value !== 'string') return false
|
|
101
|
+
// `0x78` is Tempo's fee-payer handoff magic, not a separate EIP-2718 type.
|
|
102
|
+
return (
|
|
103
|
+
value.startsWith(TxEnvelopeTempo.serializedType) ||
|
|
104
|
+
value.startsWith(TxEnvelopeTempo.feePayerMagic)
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function normalizeTempoTransaction(
|
|
109
|
+
value: Record<string, unknown> | undefined,
|
|
110
|
+
) {
|
|
111
|
+
if (!value) throw new Error('Expected `tx` in eth_fillTransaction response.')
|
|
112
|
+
return core_Transaction.fromRpc({
|
|
113
|
+
type: '0x76',
|
|
114
|
+
...value,
|
|
115
|
+
} as core_Transaction.Rpc)!
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Preserves the nonce domain when serializing filled Tempo transactions. */
|
|
119
|
+
export function formatTempoTransaction(
|
|
120
|
+
transaction: core_Transaction.Transaction,
|
|
121
|
+
) {
|
|
122
|
+
return {
|
|
123
|
+
...core_Transaction.toRpc(transaction),
|
|
124
|
+
...('nonceKey' in transaction && transaction.nonceKey !== undefined
|
|
125
|
+
? { nonceKey: Hex.fromNumber(transaction.nonceKey) }
|
|
126
|
+
: {}),
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Preserves upstream RPC errors and the relay's expired-transaction contract. */
|
|
131
|
+
export function toRpcError(error: unknown): RpcResponse.BaseError {
|
|
132
|
+
let current: unknown = error
|
|
133
|
+
let deepest: { code: number; message: string; data?: unknown } | undefined
|
|
134
|
+
const seen = new Set<unknown>()
|
|
135
|
+
while (current && typeof current === 'object' && !seen.has(current)) {
|
|
136
|
+
seen.add(current)
|
|
137
|
+
const candidate = current as Record<string, unknown>
|
|
138
|
+
if (
|
|
139
|
+
!(current instanceof UnknownRpcError) &&
|
|
140
|
+
typeof candidate.code === 'number' &&
|
|
141
|
+
typeof candidate.message === 'string'
|
|
142
|
+
)
|
|
143
|
+
deepest =
|
|
144
|
+
current instanceof RpcResponse.BaseError
|
|
145
|
+
? current
|
|
146
|
+
: {
|
|
147
|
+
code: candidate.code,
|
|
148
|
+
message: candidate.message,
|
|
149
|
+
data: candidate.data,
|
|
150
|
+
}
|
|
151
|
+
current = candidate.cause
|
|
152
|
+
}
|
|
153
|
+
if (!deepest)
|
|
154
|
+
return new RpcResponse.InternalError({
|
|
155
|
+
message: 'Internal error',
|
|
156
|
+
data: { code: 'internal_error' },
|
|
157
|
+
})
|
|
158
|
+
if (
|
|
159
|
+
deepest.code === -32603 &&
|
|
160
|
+
/^Revm error: transaction expired(?:\.|: .+)?$/.test(deepest.message)
|
|
161
|
+
)
|
|
162
|
+
return new RpcResponse.TransactionRejectedError({
|
|
163
|
+
message: 'Transaction expired.',
|
|
164
|
+
data: { code: 'transaction_expired' },
|
|
165
|
+
})
|
|
166
|
+
return deepest instanceof RpcResponse.BaseError
|
|
167
|
+
? deepest
|
|
168
|
+
: new RpcResponse.BaseError(deepest)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Preserves envelope inputs omitted by the node, including calls and chain ID. Filled fields take precedence; legacy calls are normalized separately. */
|
|
172
|
+
export function mergeCallsFromRequest(
|
|
173
|
+
resultTx: Record<string, unknown>,
|
|
174
|
+
request: Record<string, unknown>,
|
|
175
|
+
): Record<string, unknown> {
|
|
176
|
+
const merged: Record<string, unknown> = { ...request, ...resultTx }
|
|
177
|
+
const resultCalls = resultTx.calls
|
|
178
|
+
if (Array.isArray(resultCalls) && resultCalls.length > 0) return merged
|
|
179
|
+
|
|
180
|
+
const reqCalls = request.calls
|
|
181
|
+
if (Array.isArray(reqCalls)) {
|
|
182
|
+
merged.calls = reqCalls
|
|
183
|
+
return merged
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const { to, data, value } = request
|
|
187
|
+
if (
|
|
188
|
+
typeof to === 'undefined' &&
|
|
189
|
+
typeof data === 'undefined' &&
|
|
190
|
+
typeof value === 'undefined'
|
|
191
|
+
)
|
|
192
|
+
return merged
|
|
193
|
+
|
|
194
|
+
merged.calls = [
|
|
195
|
+
{
|
|
196
|
+
...(typeof to !== 'undefined' ? { to } : {}),
|
|
197
|
+
...(typeof data !== 'undefined' ? { data } : {}),
|
|
198
|
+
...(typeof value !== 'undefined' ? { value } : {}),
|
|
199
|
+
},
|
|
200
|
+
]
|
|
201
|
+
return merged
|
|
202
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { Address } from 'abitype'
|
|
2
|
+
import { type Hex, RpcResponse } from 'ox'
|
|
3
|
+
import * as VirtualAddress from 'ox/tempo/VirtualAddress'
|
|
4
|
+
import type { Client } from '../../../clients/createClient.js'
|
|
5
|
+
import type { Call } from '../../../types/calls.js'
|
|
6
|
+
import { decodeFunctionData } from '../../../utils/abi/decodeFunctionData.js'
|
|
7
|
+
import { isAddress } from '../../../utils/address/isAddress.js'
|
|
8
|
+
import * as Abis from '../../Abis.js'
|
|
9
|
+
import * as Preflight from './preflight.js'
|
|
10
|
+
|
|
11
|
+
export async function resolveVirtualAddresses(
|
|
12
|
+
client: Client,
|
|
13
|
+
options: { calls: readonly Call[] },
|
|
14
|
+
): Promise<Record<Address, Address | null> | undefined> {
|
|
15
|
+
const targets = getVirtualAddressTargets(options.calls)
|
|
16
|
+
if (targets.length === 0) return undefined
|
|
17
|
+
|
|
18
|
+
const result = await Preflight.read(client, { targets })
|
|
19
|
+
return result.virtualAddresses
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function getVirtualAddressTargets(
|
|
23
|
+
calls: readonly Call[],
|
|
24
|
+
): readonly Address[] {
|
|
25
|
+
const targets = new Set<Address>()
|
|
26
|
+
for (const call of calls) {
|
|
27
|
+
for (const address of [call.to, decodeTransferRecipient(call.data)]) {
|
|
28
|
+
if (!address || !isAddress(address) || !VirtualAddress.isVirtual(address))
|
|
29
|
+
continue
|
|
30
|
+
targets.add(address.toLowerCase() as Address)
|
|
31
|
+
if (targets.size > 100)
|
|
32
|
+
throw new RpcResponse.InvalidParamsError({
|
|
33
|
+
message: 'Virtual-address targets exceed the limit of 100 addresses.',
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return [...targets]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function decodeTransferRecipient(data?: string): Address | undefined {
|
|
42
|
+
if (!data) return undefined
|
|
43
|
+
|
|
44
|
+
const selector = data.slice(0, 10).toLowerCase()
|
|
45
|
+
if (!transferSelectors.has(selector)) return undefined
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const { args, functionName } = decodeFunctionData({
|
|
49
|
+
abi: Abis.tip20,
|
|
50
|
+
data: data as Hex.Hex,
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
if (
|
|
54
|
+
(functionName === 'transfer' || functionName === 'transferWithMemo') &&
|
|
55
|
+
typeof args[0] === 'string'
|
|
56
|
+
)
|
|
57
|
+
return args[0]
|
|
58
|
+
|
|
59
|
+
if (
|
|
60
|
+
(functionName === 'transferFrom' ||
|
|
61
|
+
functionName === 'transferFromWithMemo') &&
|
|
62
|
+
typeof args[1] === 'string'
|
|
63
|
+
)
|
|
64
|
+
return args[1]
|
|
65
|
+
} catch {}
|
|
66
|
+
|
|
67
|
+
return undefined
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const transferSelectors = new Set([
|
|
71
|
+
'0xa9059cbb',
|
|
72
|
+
'0x95777d59',
|
|
73
|
+
'0x23b872dd',
|
|
74
|
+
'0x929c2539',
|
|
75
|
+
])
|
|
76
|
+
|
|
77
|
+
export function extractCalls(
|
|
78
|
+
transaction: Record<string, unknown>,
|
|
79
|
+
): readonly Call[] {
|
|
80
|
+
const calls = transaction.calls as readonly Call[] | undefined
|
|
81
|
+
if (calls && calls.length > 0)
|
|
82
|
+
return calls.map((c) => ({
|
|
83
|
+
...(c.to ? { to: c.to } : {}),
|
|
84
|
+
...(c.data ? { data: c.data } : {}),
|
|
85
|
+
...(c.value ? { value: c.value } : {}),
|
|
86
|
+
})) as readonly Call[]
|
|
87
|
+
|
|
88
|
+
return [
|
|
89
|
+
{
|
|
90
|
+
...(transaction.to ? { to: transaction.to as Address } : {}),
|
|
91
|
+
...(transaction.data ? { data: transaction.data as `0x${string}` } : {}),
|
|
92
|
+
...(transaction.value ? { value: transaction.value as bigint } : {}),
|
|
93
|
+
},
|
|
94
|
+
] as readonly Call[]
|
|
95
|
+
}
|