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
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Address } from 'abitype'
|
|
2
|
+
import { VirtualAddress } from 'ox/tempo'
|
|
3
|
+
import { call } from '../../../core/actions/call.js'
|
|
4
|
+
import type { Client } from '../../../core/Client.js'
|
|
5
|
+
const zeroAddress = '0x0000000000000000000000000000000000000000'
|
|
6
|
+
import {
|
|
7
|
+
decode as decodeAbiParameters,
|
|
8
|
+
encode as encodeAbiParameters,
|
|
9
|
+
} from 'ox/AbiParameters'
|
|
10
|
+
import * as Hex from 'ox/Hex'
|
|
11
|
+
import * as Addresses from '../../Addresses.js'
|
|
12
|
+
|
|
13
|
+
/** Reads fee preferences, liquid fee-token balances, and virtual masters in one RPC request. */
|
|
14
|
+
export async function read(
|
|
15
|
+
client: Client,
|
|
16
|
+
options: {
|
|
17
|
+
account?: Address | undefined
|
|
18
|
+
tokens?: readonly Address[] | undefined
|
|
19
|
+
targets?: readonly Address[] | undefined
|
|
20
|
+
},
|
|
21
|
+
) {
|
|
22
|
+
const { account = zeroAddress, tokens = [], targets = [] } = options
|
|
23
|
+
const masterIds = [
|
|
24
|
+
...new Set(targets.map((target) => VirtualAddress.parse(target).masterId)),
|
|
25
|
+
]
|
|
26
|
+
const { data } = await call(client, {
|
|
27
|
+
batch: false,
|
|
28
|
+
data: Hex.concat(
|
|
29
|
+
bytecode,
|
|
30
|
+
encodeAbiParameters(
|
|
31
|
+
[
|
|
32
|
+
{ type: 'address' },
|
|
33
|
+
{ type: 'address' },
|
|
34
|
+
{ type: 'address[]' },
|
|
35
|
+
{ type: 'address' },
|
|
36
|
+
{ type: 'bytes4[]' },
|
|
37
|
+
],
|
|
38
|
+
[
|
|
39
|
+
account,
|
|
40
|
+
Addresses.feeManager,
|
|
41
|
+
tokens,
|
|
42
|
+
Addresses.addressRegistry,
|
|
43
|
+
masterIds,
|
|
44
|
+
],
|
|
45
|
+
),
|
|
46
|
+
),
|
|
47
|
+
})
|
|
48
|
+
const [preferredToken, preferredBalance, balances, resolved, masters] =
|
|
49
|
+
decodeAbiParameters(
|
|
50
|
+
[
|
|
51
|
+
{ type: 'address' },
|
|
52
|
+
{ type: 'uint256' },
|
|
53
|
+
{ type: 'uint256[]' },
|
|
54
|
+
{ type: 'bool' },
|
|
55
|
+
{ type: 'address[]' },
|
|
56
|
+
],
|
|
57
|
+
data ?? '0x',
|
|
58
|
+
)
|
|
59
|
+
return {
|
|
60
|
+
preferredToken,
|
|
61
|
+
preferredBalance,
|
|
62
|
+
balances: tokens.map((address, index) => ({
|
|
63
|
+
address,
|
|
64
|
+
balance: balances[index]!,
|
|
65
|
+
})),
|
|
66
|
+
virtualAddresses:
|
|
67
|
+
resolved && targets.length > 0
|
|
68
|
+
? (Object.fromEntries(
|
|
69
|
+
targets.map((target) => {
|
|
70
|
+
const master =
|
|
71
|
+
masters[
|
|
72
|
+
masterIds.indexOf(VirtualAddress.parse(target).masterId)
|
|
73
|
+
]!
|
|
74
|
+
return [target, master === zeroAddress ? null : master]
|
|
75
|
+
}),
|
|
76
|
+
) as Record<Address, Address | null>)
|
|
77
|
+
: undefined,
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// forge inspect --root contracts src/deployless/RelayPreflight.sol:RelayPreflight bytecode --optimize --evm-version paris
|
|
82
|
+
const bytecode =
|
|
83
|
+
'0x608060405234801561001057600080fd5b506040516108be3803806108be83398101604081905261002f916106ed565b6040516001600160a01b038616602482015260009061008090869060440160408051601f198184030181529190526020810180516001600160e01b03908116631da931f560e31b179091526103fc16565b9150600090506001600160a01b0382111561009c57600061009e565b815b905060006001600160a01b038816156101305760405141602482015260009081906100fb908a9060440160408051601f198184030181529190526020810180516001600160e01b039081166336e2a53d60e11b179091526103fc16565b9150915081801561011357506001600160a01b038111155b1561012d578015610124578061012a565b608360961b5b92505b50505b600086516001600160401b0381111561014b5761014b610601565b604051908082528060200260200182016040528015610174578160200160208202803683370190505b506040516001600160a01b038b1660248201529091506000908190819060440160408051601f198184030181529190526020810180516001600160e01b03166370a0823160e01b179052905060005b8a51811015610270576101f78b82815181106101e1576101e16107e9565b6020026020010151838e8961042c60201b60201c565b858281518110610209576102096107e9565b602002602001018181525050866001600160a01b03168b8281518110610231576102316107e9565b60200260200101516001600160a01b031603610268576001925084818151811061025d5761025d6107e9565b602002602001015193505b6001016101c3565b508115801561028757506001600160a01b03861615155b1561029b5761029886828d8861042c565b92505b600088516001600160401b038111156102b6576102b6610601565b6040519080825280602002602001820160405280156102df578160200160208202803683370190505b509050600160005b8a518110156103c7576000806103648e8e8581518110610309576103096107e9565b602002602001015160405160240161033191906001600160e01b031991909116815260200190565b60408051601f198184030181529190526020810180516001600160e01b03908116636c2558b360e11b179091526103fc16565b9150915081158061037b57506001600160a01b0381115b1561038957600093506103bd565b8085848151811061039c5761039c6107e9565b60200260200101906001600160a01b031690816001600160a01b0316815250505b50506001016102e7565b50600088868884866040516020016103e3959493929190610844565b6040516020818303038152906040529050805160208201f35b60008060405160208185516020870188620186a0fa60203d1015169250821561042457805191505b509250929050565b60008061043986866103fc565b91505080158061045057506001600160a01b038316155b1561045f576000915050610565565b826001600160a01b0316866001600160a01b03161480610485575061048584878561056d565b15610491579050610565565b6040805160048152602481019091526020810180516001600160e01b03908116630217a4b760e41b179091526000916104cd918991906103fc16565b9150508015806104e357506001600160a01b0381115b156104f357600092505050610565565b806001600160a01b03808216908916148061051f5750846001600160a01b0316816001600160a01b0316145b156105305760009350505050610565565b61053b86898361056d565b801561054d575061054d86828761056d565b1561055d57829350505050610565565b600093505050505b949350505050565b6040516001600160a01b03808416602483015282166044820152600090819060640160408051601f198184030181529181526020820180516001600160e01b031663298d501f60e11b1781528151835193945092839189620186a0fa600060208301511160403d101582161693505050509392505050565b80516001600160a01b03811681146105fc57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561063f5761063f610601565b604052919050565b60006001600160401b0382111561066057610660610601565b5060051b60200190565b600082601f83011261067b57600080fd5b815161068e61068982610647565b610617565b8082825260208201915060208360051b8601019250858311156106b057600080fd5b602085015b838110156106e35780516001600160e01b0319811681146106d557600080fd5b8352602092830192016106b5565b5095945050505050565b600080600080600060a0868803121561070557600080fd5b61070e866105e5565b945061071c602087016105e5565b60408701519094506001600160401b0381111561073857600080fd5b8601601f8101881361074957600080fd5b805161075761068982610647565b8082825260208201915060208360051b85010192508a83111561077957600080fd5b6020840193505b828410156107a257610791846105e5565b825260209384019390910190610780565b95506107b492505050606087016105e5565b60808701519092506001600160401b038111156107d057600080fd5b6107dc8882890161066a565b9150509295509295909350565b634e487b7160e01b600052603260045260246000fd5b600081518084526020840193506020830160005b8281101561083a5781516001600160a01b0316865260209586019590910190600101610813565b5093949350505050565b6001600160a01b0386168152602080820186905260a060408301819052855190830181905260009186019060c0840190835b81811015610894578351835260209384019390920191600101610876565b5050851515606085015283810360808501526108b081866107ff565b999850505050505050505056fe'
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
import type { Address } from 'abitype'
|
|
2
|
+
import { RpcResponse } from 'ox'
|
|
3
|
+
import type { Transaction as core_Transaction } from 'ox/tempo'
|
|
4
|
+
import { tempo } from '../../../chains/index.js'
|
|
5
|
+
import { type Client, create as createClient } from '../../../core/Client.js'
|
|
6
|
+
import type * as Relay from '../../Relay.js'
|
|
7
|
+
import * as Transaction from 'ox/tempo/TxEnvelopeTempo'
|
|
8
|
+
import * as Store from './cache.js'
|
|
9
|
+
import * as Deadline from './deadline.js'
|
|
10
|
+
import { formatError, isExecutionError } from './error.js'
|
|
11
|
+
import { getDefaultTokens } from './feeToken.js'
|
|
12
|
+
import * as Utils from './utils.js'
|
|
13
|
+
import {
|
|
14
|
+
extractCalls,
|
|
15
|
+
getVirtualAddressTargets,
|
|
16
|
+
resolveVirtualAddresses,
|
|
17
|
+
} from './virtualAddress.js'
|
|
18
|
+
|
|
19
|
+
export type Result = {
|
|
20
|
+
tx: Record<string, unknown>
|
|
21
|
+
capabilities?: Record<string, unknown> | undefined
|
|
22
|
+
sponsor?: unknown
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Compose middleware and execute post-fill hooks once for the selected result. */
|
|
26
|
+
export function compose(
|
|
27
|
+
downstream: Relay.handleRequest.Handler,
|
|
28
|
+
options: Relay.handleRequest.Options = {},
|
|
29
|
+
resolveClient?: ((chainId: number) => { chain: { id: number } }) | undefined,
|
|
30
|
+
): Relay.handleRequest.Handler {
|
|
31
|
+
const options_ = options
|
|
32
|
+
const plugins = options.plugins ?? []
|
|
33
|
+
if (plugins.length === 0) return downstream
|
|
34
|
+
if (plugins.filter((plugin) => plugin.signTransaction).length > 1)
|
|
35
|
+
throw new Error('Only one relay transaction signer may be configured.')
|
|
36
|
+
|
|
37
|
+
const handle: Relay.handleRequest.Handler = async (
|
|
38
|
+
request,
|
|
39
|
+
requestOptions = {},
|
|
40
|
+
) => {
|
|
41
|
+
const stores = new Map<Store.Store, Store.Store>()
|
|
42
|
+
const tokens = new Map<number, Promise<readonly Address[]>>()
|
|
43
|
+
const scoped = (store: Store.Store | undefined) => {
|
|
44
|
+
if (!store) return undefined
|
|
45
|
+
let result = stores.get(store)
|
|
46
|
+
if (!result) {
|
|
47
|
+
result = Store.scoped(store)!
|
|
48
|
+
stores.set(store, result)
|
|
49
|
+
}
|
|
50
|
+
return result
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const execute = async (
|
|
54
|
+
start: number,
|
|
55
|
+
request: Relay.handleRequest.Request,
|
|
56
|
+
options: Relay.handleRequest.RequestOptions,
|
|
57
|
+
) => {
|
|
58
|
+
const state = {
|
|
59
|
+
request,
|
|
60
|
+
options: { ...options },
|
|
61
|
+
result: undefined as unknown,
|
|
62
|
+
}
|
|
63
|
+
const contexts = new Map<number, Relay.Plugin.Context>()
|
|
64
|
+
const contextAt = (index: number): Relay.Plugin.Context => {
|
|
65
|
+
const existing = contexts.get(index)
|
|
66
|
+
if (existing) return existing
|
|
67
|
+
const clients = new Map<number, Client>()
|
|
68
|
+
const chainId = (id = state.options.chainId) => {
|
|
69
|
+
if (id === undefined || !Number.isSafeInteger(id) || id <= 0)
|
|
70
|
+
throw new RpcResponse.InvalidParamsError({
|
|
71
|
+
message:
|
|
72
|
+
'A chain ID is required to resolve the downstream client.',
|
|
73
|
+
})
|
|
74
|
+
return id
|
|
75
|
+
}
|
|
76
|
+
const context: Relay.Plugin.Context = {
|
|
77
|
+
get request() {
|
|
78
|
+
return state.request
|
|
79
|
+
},
|
|
80
|
+
set request(value) {
|
|
81
|
+
state.request = value
|
|
82
|
+
},
|
|
83
|
+
get result() {
|
|
84
|
+
return state.result
|
|
85
|
+
},
|
|
86
|
+
set result(value) {
|
|
87
|
+
state.result = value
|
|
88
|
+
},
|
|
89
|
+
get options() {
|
|
90
|
+
return state.options
|
|
91
|
+
},
|
|
92
|
+
set options(value) {
|
|
93
|
+
state.options = value
|
|
94
|
+
},
|
|
95
|
+
get client() {
|
|
96
|
+
return context.getClient()
|
|
97
|
+
},
|
|
98
|
+
getClient(id_) {
|
|
99
|
+
const id = chainId(id_)
|
|
100
|
+
let client = clients.get(id)
|
|
101
|
+
if (client) return client
|
|
102
|
+
const upstream = resolveClient?.(id)
|
|
103
|
+
if (upstream?.chain && upstream.chain.id !== id)
|
|
104
|
+
throw new RpcResponse.InvalidParamsError({
|
|
105
|
+
message: 'Conflicting chain ids.',
|
|
106
|
+
})
|
|
107
|
+
client = createClient({
|
|
108
|
+
chain: { ...tempo, ...upstream?.chain, id },
|
|
109
|
+
batch: { multicall: { deployless: true } },
|
|
110
|
+
transport: {
|
|
111
|
+
key: 'relay-forward',
|
|
112
|
+
name: 'Relay Forwarding',
|
|
113
|
+
type: 'relay-forward',
|
|
114
|
+
setup: () => ({
|
|
115
|
+
retryCount: 0,
|
|
116
|
+
request: (async (
|
|
117
|
+
request: Relay.handleRequest.Request,
|
|
118
|
+
options?: Relay.handleRequest.RequestOptions,
|
|
119
|
+
) => {
|
|
120
|
+
const child = await execute(
|
|
121
|
+
index + 1,
|
|
122
|
+
request as Relay.handleRequest.Request,
|
|
123
|
+
{
|
|
124
|
+
...state.options,
|
|
125
|
+
...options,
|
|
126
|
+
chainId: id,
|
|
127
|
+
},
|
|
128
|
+
)
|
|
129
|
+
return child.state.result
|
|
130
|
+
}) as Client['request'],
|
|
131
|
+
}),
|
|
132
|
+
},
|
|
133
|
+
})
|
|
134
|
+
clients.set(id, client)
|
|
135
|
+
return client
|
|
136
|
+
},
|
|
137
|
+
async resolveTokens(id_) {
|
|
138
|
+
const id = chainId(id_)
|
|
139
|
+
let result = tokens.get(id)
|
|
140
|
+
if (!result) {
|
|
141
|
+
result = Promise.resolve().then(() =>
|
|
142
|
+
(options_.resolveTokens ?? getDefaultTokens)(id),
|
|
143
|
+
)
|
|
144
|
+
tokens.set(id, result)
|
|
145
|
+
}
|
|
146
|
+
return result
|
|
147
|
+
},
|
|
148
|
+
getStore: scoped,
|
|
149
|
+
}
|
|
150
|
+
contexts.set(index, context)
|
|
151
|
+
return context
|
|
152
|
+
}
|
|
153
|
+
const dispatch = async (index: number): Promise<void> => {
|
|
154
|
+
if (index === plugins.length) {
|
|
155
|
+
const parameters = state.request.params?.[0] as
|
|
156
|
+
| Record<string, unknown>
|
|
157
|
+
| undefined
|
|
158
|
+
// The node must estimate unsigned sponsorship independently of the sender's fee-token balance.
|
|
159
|
+
const request =
|
|
160
|
+
state.request.method === 'eth_fillTransaction' &&
|
|
161
|
+
parameters?.feePayer === true &&
|
|
162
|
+
!parameters.feePayerSignature
|
|
163
|
+
? {
|
|
164
|
+
...state.request,
|
|
165
|
+
params: [{ ...parameters, feeToken: undefined }],
|
|
166
|
+
}
|
|
167
|
+
: state.request
|
|
168
|
+
requestOptions.signal?.throwIfAborted()
|
|
169
|
+
state.result = await downstream(request, {
|
|
170
|
+
...state.options,
|
|
171
|
+
...(isFill ? { signal: requestOptions.signal } : {}),
|
|
172
|
+
})
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
const plugin = plugins[index]!
|
|
176
|
+
const context = contextAt(index)
|
|
177
|
+
if (!plugin.handleRequest) return dispatch(index + 1)
|
|
178
|
+
let called = false
|
|
179
|
+
const result = await plugin.handleRequest(context, async () => {
|
|
180
|
+
if (called)
|
|
181
|
+
throw new Error(
|
|
182
|
+
'next() may only be called once per middleware invocation.',
|
|
183
|
+
)
|
|
184
|
+
called = true
|
|
185
|
+
await dispatch(index + 1)
|
|
186
|
+
})
|
|
187
|
+
if (result !== undefined) state.result = result
|
|
188
|
+
}
|
|
189
|
+
await dispatch(start)
|
|
190
|
+
return { state, contextAt }
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const isFill = request.method === 'eth_fillTransaction'
|
|
194
|
+
const isRaw = [
|
|
195
|
+
'eth_signRawTransaction',
|
|
196
|
+
'eth_sendRawTransaction',
|
|
197
|
+
'eth_sendRawTransactionSync',
|
|
198
|
+
].includes(request.method)
|
|
199
|
+
const parameters = request.params?.[0] as Record<string, unknown>
|
|
200
|
+
let root: Awaited<ReturnType<typeof execute>> | undefined
|
|
201
|
+
try {
|
|
202
|
+
requestOptions.signal?.throwIfAborted()
|
|
203
|
+
if (
|
|
204
|
+
isFill &&
|
|
205
|
+
(!parameters ||
|
|
206
|
+
typeof parameters !== 'object' ||
|
|
207
|
+
Array.isArray(parameters))
|
|
208
|
+
)
|
|
209
|
+
throw new RpcResponse.InvalidParamsError({
|
|
210
|
+
message: 'Expected a transaction object.',
|
|
211
|
+
})
|
|
212
|
+
if (isFill) Utils.normalizeFillTransactionRequest(parameters)
|
|
213
|
+
const bodyChainId = (() => {
|
|
214
|
+
if (isRaw && Utils.isSerializedTempoTransaction(request.params?.[0])) {
|
|
215
|
+
try {
|
|
216
|
+
return Transaction.deserialize(request.params[0]).chainId
|
|
217
|
+
} catch {
|
|
218
|
+
throw new RpcResponse.InvalidParamsError({
|
|
219
|
+
message: 'Invalid serialized Tempo transaction.',
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (!isFill || parameters.chainId === undefined) return undefined
|
|
224
|
+
const id = Utils.resolveChainId(parameters.chainId)
|
|
225
|
+
if (id === undefined || !Number.isSafeInteger(id) || id <= 0)
|
|
226
|
+
throw new RpcResponse.InvalidParamsError({
|
|
227
|
+
message: 'Invalid transaction chain ID.',
|
|
228
|
+
})
|
|
229
|
+
return id
|
|
230
|
+
})()
|
|
231
|
+
if (
|
|
232
|
+
bodyChainId !== undefined &&
|
|
233
|
+
requestOptions.chainId !== undefined &&
|
|
234
|
+
bodyChainId !== requestOptions.chainId
|
|
235
|
+
)
|
|
236
|
+
throw new RpcResponse.InvalidParamsError({
|
|
237
|
+
message: 'Conflicting chain ids.',
|
|
238
|
+
})
|
|
239
|
+
root = await execute(0, request, {
|
|
240
|
+
...requestOptions,
|
|
241
|
+
...((requestOptions.chainId ?? bodyChainId) !== undefined
|
|
242
|
+
? { chainId: requestOptions.chainId ?? bodyChainId }
|
|
243
|
+
: {}),
|
|
244
|
+
})
|
|
245
|
+
if (!isFill) return root.state.result
|
|
246
|
+
const filled = root.state.result as Result
|
|
247
|
+
if (filled.capabilities?.error) return filled
|
|
248
|
+
const transaction = Utils.normalizeTempoTransaction(
|
|
249
|
+
Utils.mergeCallsFromRequest(
|
|
250
|
+
filled.tx,
|
|
251
|
+
Utils.normalizeFillTransactionRequest(parameters),
|
|
252
|
+
),
|
|
253
|
+
)
|
|
254
|
+
const final: Result = {
|
|
255
|
+
...filled,
|
|
256
|
+
tx: Utils.formatTempoTransaction(
|
|
257
|
+
transaction as core_Transaction.Transaction,
|
|
258
|
+
),
|
|
259
|
+
}
|
|
260
|
+
const snapshot = freeze(structuredClone(final))
|
|
261
|
+
const targets = getVirtualAddressTargets(extractCalls(transaction))
|
|
262
|
+
const resolved = final.capabilities?.virtualAddresses as
|
|
263
|
+
| Record<Address, Address | null>
|
|
264
|
+
| undefined
|
|
265
|
+
const [patches, signatures, virtualAddresses] = await Promise.all([
|
|
266
|
+
Promise.all(
|
|
267
|
+
plugins.map((plugin, index) =>
|
|
268
|
+
plugin.afterFill?.(snapshot, root!.contextAt(index)),
|
|
269
|
+
),
|
|
270
|
+
),
|
|
271
|
+
Promise.all(
|
|
272
|
+
plugins.map((plugin, index) =>
|
|
273
|
+
plugin.signTransaction?.(snapshot, root!.contextAt(index)),
|
|
274
|
+
),
|
|
275
|
+
),
|
|
276
|
+
targets.length > 0 &&
|
|
277
|
+
!targets.every((target) => resolved && target in resolved)
|
|
278
|
+
? resolveVirtualAddresses(root.contextAt(-1).client, {
|
|
279
|
+
calls: extractCalls(transaction),
|
|
280
|
+
}).catch(() => {
|
|
281
|
+
requestOptions.signal?.throwIfAborted()
|
|
282
|
+
return undefined
|
|
283
|
+
})
|
|
284
|
+
: undefined,
|
|
285
|
+
])
|
|
286
|
+
requestOptions.signal?.throwIfAborted()
|
|
287
|
+
const capabilities = { ...final.capabilities }
|
|
288
|
+
const keys = new Set<string>()
|
|
289
|
+
for (const patch of patches) {
|
|
290
|
+
for (const [key, value] of Object.entries(patch?.capabilities ?? {})) {
|
|
291
|
+
if (keys.has(key))
|
|
292
|
+
throw new Error(`Conflicting relay capability: ${key}.`)
|
|
293
|
+
keys.add(key)
|
|
294
|
+
capabilities[key] = value
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const signature = signatures.find((signature) => signature !== undefined)
|
|
298
|
+
if (signature) {
|
|
299
|
+
delete final.tx.signature
|
|
300
|
+
final.tx.feePayerSignature = signature
|
|
301
|
+
}
|
|
302
|
+
const sponsor = capabilities.sponsor ?? final.sponsor
|
|
303
|
+
return {
|
|
304
|
+
...final,
|
|
305
|
+
capabilities: {
|
|
306
|
+
sponsored: !!sponsor,
|
|
307
|
+
...capabilities,
|
|
308
|
+
...(virtualAddresses ? { virtualAddresses } : {}),
|
|
309
|
+
},
|
|
310
|
+
}
|
|
311
|
+
} catch (error) {
|
|
312
|
+
requestOptions.signal?.throwIfAborted()
|
|
313
|
+
if (
|
|
314
|
+
isFill &&
|
|
315
|
+
isExecutionError(error) &&
|
|
316
|
+
(parameters.capabilities as Record<string, unknown> | undefined)
|
|
317
|
+
?.errors === true
|
|
318
|
+
) {
|
|
319
|
+
// Resolve errors through a downstream-only client; never restart the plugin pipeline.
|
|
320
|
+
const id =
|
|
321
|
+
requestOptions.chainId ?? Utils.resolveChainId(parameters.chainId)
|
|
322
|
+
const client = createClient({
|
|
323
|
+
chain: { ...tempo, id: id ?? tempo.id },
|
|
324
|
+
transport: {
|
|
325
|
+
key: 'relay-error',
|
|
326
|
+
name: 'Relay Error Enrichment',
|
|
327
|
+
type: 'relay-error',
|
|
328
|
+
setup: () => ({
|
|
329
|
+
request: ((
|
|
330
|
+
request: Relay.handleRequest.Request,
|
|
331
|
+
options?: Relay.handleRequest.RequestOptions,
|
|
332
|
+
) =>
|
|
333
|
+
downstream(request, {
|
|
334
|
+
...requestOptions,
|
|
335
|
+
...options,
|
|
336
|
+
chainId: id,
|
|
337
|
+
signal: requestOptions.signal,
|
|
338
|
+
})) as Client['request'],
|
|
339
|
+
}),
|
|
340
|
+
},
|
|
341
|
+
})
|
|
342
|
+
return formatError(error, parameters, client)
|
|
343
|
+
}
|
|
344
|
+
if (!isFill && !isRaw) throw error
|
|
345
|
+
throw Utils.toRpcError(error)
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (
|
|
349
|
+
options.timeout !== undefined &&
|
|
350
|
+
(!Number.isSafeInteger(options.timeout) || options.timeout <= 0)
|
|
351
|
+
)
|
|
352
|
+
throw new RpcResponse.InvalidParamsError({
|
|
353
|
+
message: 'Expected a positive integer for timeout.',
|
|
354
|
+
})
|
|
355
|
+
if (options.timeout !== undefined && options.timeout > 2_147_483_647)
|
|
356
|
+
throw new RpcResponse.InvalidParamsError({
|
|
357
|
+
message: 'The fill timeout cannot exceed 2147483647 milliseconds.',
|
|
358
|
+
})
|
|
359
|
+
return (request, requestOptions = {}) =>
|
|
360
|
+
request.method === 'eth_fillTransaction'
|
|
361
|
+
? Deadline.run(handle, request, requestOptions, options)
|
|
362
|
+
: handle(request, requestOptions)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/** Prevent hooks from mutating the transaction another hook signs. */
|
|
366
|
+
function freeze<value>(value: value): value {
|
|
367
|
+
if (value && typeof value === 'object') {
|
|
368
|
+
for (const child of Object.values(value)) freeze(child)
|
|
369
|
+
Object.freeze(value)
|
|
370
|
+
}
|
|
371
|
+
return value
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/** Normalize a downstream fill without discarding capabilities added by other plugins. */
|
|
375
|
+
export async function fill(
|
|
376
|
+
client: Client,
|
|
377
|
+
transaction: Record<string, unknown>,
|
|
378
|
+
options: Relay.handleRequest.RequestOptions = {},
|
|
379
|
+
): Promise<Result> {
|
|
380
|
+
const formatted = Utils.formatFillTransactionRequest(client, transaction)
|
|
381
|
+
const result = (await client.request(
|
|
382
|
+
{
|
|
383
|
+
method: 'eth_fillTransaction',
|
|
384
|
+
params: [formatted as never],
|
|
385
|
+
},
|
|
386
|
+
options,
|
|
387
|
+
)) as unknown as Result
|
|
388
|
+
|
|
389
|
+
const error = result.capabilities?.error as
|
|
390
|
+
| { message?: string; errorName?: string; data?: `0x${string}` }
|
|
391
|
+
| undefined
|
|
392
|
+
if (error) {
|
|
393
|
+
const cause = new Error(
|
|
394
|
+
error.message ?? error.errorName ?? 'UpstreamRevert',
|
|
395
|
+
)
|
|
396
|
+
Object.assign(cause, { name: 'UpstreamRevertError', data: error.data })
|
|
397
|
+
throw cause
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return { ...result, tx: Utils.mergeCallsFromRequest(result.tx, transaction) }
|
|
401
|
+
}
|