viem 2.56.9 → 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 +40 -0
- 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/index.js +20 -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/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/Client.js +2 -10
- package/_cjs/tempo/Client.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/Transaction.js.map +1 -1
- package/_cjs/tempo/Transport.js +21 -12
- package/_cjs/tempo/Transport.js.map +1 -1
- 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/utils/siwe/parseSiweMessage.js +3 -3
- package/_cjs/utils/siwe/parseSiweMessage.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/index.js +3 -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/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/Client.js +8 -14
- package/_esm/tempo/Client.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/Transaction.js.map +1 -1
- package/_esm/tempo/Transport.js +21 -46
- package/_esm/tempo/Transport.js.map +1 -1
- 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/utils/siwe/parseSiweMessage.js +3 -3
- package/_esm/utils/siwe/parseSiweMessage.js.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/index.d.ts +3 -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/errors/version.d.ts +1 -1
- package/_types/index.d.ts +2 -0
- package/_types/index.d.ts.map +1 -1
- package/_types/op-stack/actions/getGame.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/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/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/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/utils/siwe/parseSiweMessage.d.ts.map +1 -1
- 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/index.ts +3 -0
- package/clients/createClientResolver.ts +191 -0
- package/errors/version.ts +1 -1
- package/index.ts +6 -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/Capabilities.ts +7 -29
- package/tempo/Client.ts +8 -38
- package/tempo/ExecutionError.ts +418 -0
- package/tempo/Relay.ts +428 -0
- package/tempo/Transaction.ts +2 -1
- package/tempo/Transport.ts +69 -60
- 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/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,190 @@
|
|
|
1
|
+
import type { Address } from 'abitype'
|
|
2
|
+
import { RpcResponse } from 'ox'
|
|
3
|
+
import type { Client } from '../../../clients/createClient.js'
|
|
4
|
+
import { tokens as tokenSets } from '../../../tokens/sets.js'
|
|
5
|
+
import * as Actions from '../../actions/index.js'
|
|
6
|
+
import type * as Relay from '../../Relay.js'
|
|
7
|
+
import * as Store from './cache.js'
|
|
8
|
+
import * as Preflight from './preflight.js'
|
|
9
|
+
import * as Utils from './utils.js'
|
|
10
|
+
import { extractCalls, getVirtualAddressTargets } from './virtualAddress.js'
|
|
11
|
+
|
|
12
|
+
export function create(): Relay.Plugin {
|
|
13
|
+
return {
|
|
14
|
+
async handleRequest(context, next) {
|
|
15
|
+
const { request } = context
|
|
16
|
+
if (request.method !== 'eth_fillTransaction') return next()
|
|
17
|
+
const parameters = request.params![0] as Record<string, unknown>
|
|
18
|
+
const transaction = Utils.normalizeFillTransactionRequest(parameters)
|
|
19
|
+
|
|
20
|
+
if (transaction.feeToken) {
|
|
21
|
+
context.request = {
|
|
22
|
+
...request,
|
|
23
|
+
params: [
|
|
24
|
+
Utils.formatFillTransactionRequest(context.client, transaction),
|
|
25
|
+
],
|
|
26
|
+
}
|
|
27
|
+
return next()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const tokens = await context.resolveTokens()
|
|
31
|
+
const candidates = [
|
|
32
|
+
...tokens,
|
|
33
|
+
...callTargetTokens(transaction).filter(
|
|
34
|
+
(token) =>
|
|
35
|
+
!tokens.some(
|
|
36
|
+
(candidate) => candidate.toLowerCase() === token.toLowerCase(),
|
|
37
|
+
),
|
|
38
|
+
),
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
const resolved = transaction.feePayer
|
|
42
|
+
? { feeToken: tokens[0], virtualAddresses: undefined }
|
|
43
|
+
: await resolveFeeToken(context.client, {
|
|
44
|
+
account: transaction.from as Address | undefined,
|
|
45
|
+
feeToken: transaction.feeToken as Address | undefined,
|
|
46
|
+
targets: getVirtualAddressTargets(extractCalls(transaction)),
|
|
47
|
+
tokens: candidates,
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const { feeToken, virtualAddresses } = resolved
|
|
51
|
+
const selected = { ...transaction, ...(feeToken ? { feeToken } : {}) }
|
|
52
|
+
context.request = {
|
|
53
|
+
...request,
|
|
54
|
+
params: [Utils.formatFillTransactionRequest(context.client, selected)],
|
|
55
|
+
}
|
|
56
|
+
await next()
|
|
57
|
+
const result = context.result as Relay.Plugin.FillResult
|
|
58
|
+
context.result = {
|
|
59
|
+
...result,
|
|
60
|
+
// Unsigned sponsored estimates can omit the fee token selected by this plugin.
|
|
61
|
+
tx: {
|
|
62
|
+
...result.tx,
|
|
63
|
+
...(!result.tx.feeToken && feeToken ? { feeToken } : {}),
|
|
64
|
+
},
|
|
65
|
+
...(virtualAddresses
|
|
66
|
+
? { capabilities: { ...result.capabilities, virtualAddresses } }
|
|
67
|
+
: {}),
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function getDefaultTokens(
|
|
74
|
+
chainId: number,
|
|
75
|
+
): Promise<readonly Address[]> {
|
|
76
|
+
return tokenSets.tempo.flatMap((token) => {
|
|
77
|
+
const address = (token.addresses as Record<number, Address>)[chainId]
|
|
78
|
+
return address ? [address] : []
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Resolves a funded fee-token candidate. @internal */
|
|
83
|
+
export async function resolveFeeToken(
|
|
84
|
+
client: Client,
|
|
85
|
+
options: resolveFeeToken.Options,
|
|
86
|
+
) {
|
|
87
|
+
const { feeToken, account, exclude, tokens } = options
|
|
88
|
+
if (feeToken || !account) return { feeToken, virtualAddresses: undefined }
|
|
89
|
+
const candidates = [
|
|
90
|
+
...new Set(tokens?.map((token) => token.toLowerCase() as Address)),
|
|
91
|
+
]
|
|
92
|
+
if (candidates.length > 100)
|
|
93
|
+
throw new RpcResponse.InvalidParamsError({
|
|
94
|
+
message: 'Fee-token candidates exceed the limit of 100 tokens.',
|
|
95
|
+
})
|
|
96
|
+
const { preferredToken, preferredBalance, balances, virtualAddresses } =
|
|
97
|
+
await Preflight.read(client, {
|
|
98
|
+
account,
|
|
99
|
+
tokens: candidates,
|
|
100
|
+
targets: options.targets,
|
|
101
|
+
})
|
|
102
|
+
const minimumBalance = options.minimumBalance ?? 1n
|
|
103
|
+
if (
|
|
104
|
+
preferredToken.toLowerCase() !== exclude?.toLowerCase() &&
|
|
105
|
+
preferredBalance >= minimumBalance
|
|
106
|
+
)
|
|
107
|
+
return { feeToken: preferredToken, virtualAddresses }
|
|
108
|
+
|
|
109
|
+
let best: { address: Address; balance: bigint } | undefined
|
|
110
|
+
for (const asset of balances) {
|
|
111
|
+
if (
|
|
112
|
+
asset.balance < minimumBalance ||
|
|
113
|
+
asset.address.toLowerCase() === exclude?.toLowerCase()
|
|
114
|
+
)
|
|
115
|
+
continue
|
|
116
|
+
if (!best || asset.balance > best.balance) best = asset
|
|
117
|
+
}
|
|
118
|
+
return { feeToken: best?.address, virtualAddresses }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export declare namespace resolveFeeToken {
|
|
122
|
+
type Options = {
|
|
123
|
+
minimumBalance?: bigint | undefined
|
|
124
|
+
exclude?: Address | undefined
|
|
125
|
+
feeToken?: Address | undefined
|
|
126
|
+
account?: Address | undefined
|
|
127
|
+
tokens?: readonly Address[] | undefined
|
|
128
|
+
targets?: readonly Address[] | undefined
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Includes call-target TIP20 tokens as fee candidates, allowing transfers to pay fees with the transferred token. */
|
|
133
|
+
function callTargetTokens(
|
|
134
|
+
transaction: Record<string, unknown>,
|
|
135
|
+
): readonly Address[] {
|
|
136
|
+
const calls = transaction.calls as readonly { to?: Address }[] | undefined
|
|
137
|
+
if (!calls) return []
|
|
138
|
+
const out: Address[] = []
|
|
139
|
+
const seen = new Set<string>()
|
|
140
|
+
for (const c of calls) {
|
|
141
|
+
if (!c.to) continue
|
|
142
|
+
const lower = c.to.toLowerCase()
|
|
143
|
+
if (!lower.startsWith('0x20c0')) continue
|
|
144
|
+
if (seen.has(lower)) continue
|
|
145
|
+
seen.add(lower)
|
|
146
|
+
out.push(c.to)
|
|
147
|
+
if (out.length > 100)
|
|
148
|
+
throw new RpcResponse.InvalidParamsError({
|
|
149
|
+
message: 'Fee-token candidates exceed the limit of 100 tokens.',
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
return out
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export async function resolveTokenMetadata(
|
|
156
|
+
client: Client,
|
|
157
|
+
options: resolveTokenMetadata.Options,
|
|
158
|
+
) {
|
|
159
|
+
const { token, tokenMetadata, store } = options
|
|
160
|
+
const meta =
|
|
161
|
+
tokenMetadata?.[token] ?? tokenMetadata?.[token.toLowerCase() as Address]
|
|
162
|
+
// Tempo simulation metadata covers TIP-20 tokens, whose decimals are always six.
|
|
163
|
+
if (token.toLowerCase().startsWith('0x20c0') && meta)
|
|
164
|
+
return { decimals: 6, symbol: meta.symbol, name: meta.name }
|
|
165
|
+
// TIP-20 metadata (decimals/symbol/name) is immutable per token, so cache
|
|
166
|
+
// long-term. Skips the multicall RPC on cache hits.
|
|
167
|
+
const fetcher = () => Actions.token.getMetadata(client, { token })
|
|
168
|
+
const fallback = store
|
|
169
|
+
? await Store.memoize(fetcher, {
|
|
170
|
+
key: `tokenMetadata:${client.chain?.id ?? 0}:${token.toLowerCase()}`,
|
|
171
|
+
store,
|
|
172
|
+
ttl: 24 * 60 * 60 * 1000,
|
|
173
|
+
})
|
|
174
|
+
: await fetcher()
|
|
175
|
+
return {
|
|
176
|
+
decimals: fallback.decimals ?? 6,
|
|
177
|
+
symbol: meta?.symbol || fallback.symbol,
|
|
178
|
+
name: meta?.name || fallback.name,
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export declare namespace resolveTokenMetadata {
|
|
183
|
+
type Options = {
|
|
184
|
+
token: Address
|
|
185
|
+
tokenMetadata?:
|
|
186
|
+
| Record<Address, { name: string; symbol: string; currency: string }>
|
|
187
|
+
| undefined
|
|
188
|
+
store?: Store.Store | undefined
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -11,232 +11,201 @@ import {
|
|
|
11
11
|
SignatureEnvelope,
|
|
12
12
|
TxEnvelopeTempo,
|
|
13
13
|
} from 'ox/tempo'
|
|
14
|
-
import { getBlockNumber } from '
|
|
15
|
-
import { createClient } from '
|
|
16
|
-
import { custom } from '
|
|
17
|
-
import
|
|
18
|
-
import {
|
|
19
|
-
import
|
|
20
|
-
import * as
|
|
21
|
-
import
|
|
22
|
-
import
|
|
23
|
-
import * as
|
|
24
|
-
import * as
|
|
25
|
-
import type * as Store from '
|
|
26
|
-
import * as Transaction from '
|
|
14
|
+
import { getBlockNumber } from '../../../actions/public/getBlockNumber.js'
|
|
15
|
+
import { createClient } from '../../../clients/createClient.js'
|
|
16
|
+
import { custom } from '../../../clients/transports/custom.js'
|
|
17
|
+
import { decodeFunctionData } from '../../../utils/abi/decodeFunctionData.js'
|
|
18
|
+
import { isAddressEqual } from '../../../utils/address/isAddressEqual.js'
|
|
19
|
+
import * as Abis from '../../Abis.js'
|
|
20
|
+
import * as Addresses from '../../Addresses.js'
|
|
21
|
+
import { getConfigCommitment } from '../../actions/multisig.js'
|
|
22
|
+
import * as ConfigStore from '../../multisig/Config.js'
|
|
23
|
+
import * as OperationStore from '../../multisig/Operation.js'
|
|
24
|
+
import type * as Relay from '../../Relay.js'
|
|
25
|
+
import type * as Store from '../../Store.js'
|
|
26
|
+
import * as Transaction from '../../Transaction.js'
|
|
27
|
+
import * as Plugin from './plugin.js'
|
|
27
28
|
|
|
28
29
|
const submissionTtl = 30_000
|
|
29
30
|
const pollingInterval = 100
|
|
30
31
|
|
|
31
|
-
/**
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
* @returns The multisig-aware RPC request handler.
|
|
37
|
-
*/
|
|
38
|
-
export function handleRequest(
|
|
39
|
-
next: handleRequest.Handler,
|
|
40
|
-
parameters: handleRequest.Parameters,
|
|
41
|
-
): handleRequest.Handler {
|
|
42
|
-
if (!parameters.store.compareAndSet)
|
|
32
|
+
/** Creates middleware for multisig approval coordination. @internal */
|
|
33
|
+
export function create(
|
|
34
|
+
options: Relay.multisig.Options,
|
|
35
|
+
): Relay.multisig.ReturnType {
|
|
36
|
+
if (!options.store.compareAndSet)
|
|
43
37
|
throw new RpcResponse.InvalidParamsError({
|
|
44
38
|
message:
|
|
45
39
|
'Multisig coordination requires a store with atomic `compareAndSet`.',
|
|
46
40
|
})
|
|
47
|
-
return
|
|
48
|
-
|
|
49
|
-
request,
|
|
50
|
-
requestOptions
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
transport: custom({
|
|
55
|
-
request: ({ method, params }, options) =>
|
|
56
|
-
next({ method, params }, { ...requestOptions, ...options }),
|
|
57
|
-
}),
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
if (request.method === 'multisig_getConfig') {
|
|
61
|
-
const value = request.params?.[0]
|
|
62
|
-
const address =
|
|
63
|
-
value && typeof value === 'object' && 'address' in value
|
|
64
|
-
? value.address
|
|
65
|
-
: undefined
|
|
66
|
-
if (
|
|
67
|
-
typeof address !== 'string' ||
|
|
68
|
-
!Address_.validate(address) ||
|
|
69
|
-
Hex.toBigInt(address) === 0n
|
|
70
|
-
)
|
|
71
|
-
throw new RpcResponse.InvalidParamsError({
|
|
72
|
-
message: 'Expected a multisig account address.',
|
|
73
|
-
})
|
|
74
|
-
const blockNumber = await getBlockNumber(client, { cacheTime: 0 })
|
|
75
|
-
const commitment = await getConfigCommitment(client, {
|
|
76
|
-
account: address,
|
|
77
|
-
blockNumber,
|
|
41
|
+
return Plugin.multisig({
|
|
42
|
+
async handleRequest(context, forward) {
|
|
43
|
+
const { request, options: requestOptions_ } = context
|
|
44
|
+
const requestOptions = await resolveRequestOptions({
|
|
45
|
+
request,
|
|
46
|
+
requestOptions: requestOptions_,
|
|
47
|
+
store: options.store,
|
|
78
48
|
})
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
49
|
+
context.options = requestOptions ?? {}
|
|
50
|
+
const next: Relay.handleRequest.Handler = async (request, options) => {
|
|
51
|
+
return context
|
|
52
|
+
.getClient(options?.chainId)
|
|
53
|
+
.request(request as never, options)
|
|
54
|
+
}
|
|
55
|
+
const client = createClient({
|
|
56
|
+
transport: custom(
|
|
57
|
+
{
|
|
58
|
+
request: (request, options) =>
|
|
59
|
+
next(request, { ...requestOptions, ...options }),
|
|
60
|
+
},
|
|
61
|
+
{ retryCount: 0 },
|
|
62
|
+
),
|
|
82
63
|
})
|
|
83
|
-
if (!config) return null
|
|
84
|
-
return MultisigConfig.toRpc(config)
|
|
85
|
-
}
|
|
86
64
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
65
|
+
if (request.method === 'multisig_getConfig') {
|
|
66
|
+
const value = request.params?.[0]
|
|
67
|
+
const address =
|
|
68
|
+
value && typeof value === 'object' && 'address' in value
|
|
69
|
+
? value.address
|
|
70
|
+
: undefined
|
|
71
|
+
if (
|
|
72
|
+
typeof address !== 'string' ||
|
|
73
|
+
!Address_.validate(address) ||
|
|
74
|
+
Hex.toBigInt(address) === 0n
|
|
75
|
+
)
|
|
76
|
+
throw new RpcResponse.InvalidParamsError({
|
|
77
|
+
message: 'Expected a multisig account address.',
|
|
78
|
+
})
|
|
79
|
+
const blockNumber = await getBlockNumber(client, { cacheTime: 0 })
|
|
80
|
+
const commitment = await getConfigCommitment(client, {
|
|
81
|
+
account: address,
|
|
82
|
+
blockNumber,
|
|
92
83
|
})
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
84
|
+
const config = await ConfigStore.read(options.store, {
|
|
85
|
+
address,
|
|
86
|
+
commitment,
|
|
87
|
+
})
|
|
88
|
+
if (!config) return null
|
|
89
|
+
return MultisigConfig.toRpc(config)
|
|
90
|
+
}
|
|
96
91
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
92
|
+
if (request.method === 'multisig_getOperation') {
|
|
93
|
+
const hash = request.params?.[0]
|
|
94
|
+
if (typeof hash !== 'string' || !Hash.validate(hash))
|
|
95
|
+
throw new RpcResponse.InvalidParamsError({
|
|
96
|
+
message: 'Expected a multisig operation hash.',
|
|
97
|
+
})
|
|
98
|
+
const operation = await OperationStore.read(options.store, hash)
|
|
99
|
+
return operation ? MultisigOperation.toRpc(operation) : null
|
|
100
|
+
}
|
|
103
101
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
102
|
+
if (request.method === 'multisig_approveKeyAuthorization')
|
|
103
|
+
return await approveKeyAuthorization({
|
|
104
|
+
client,
|
|
105
|
+
request,
|
|
106
|
+
store: options.store,
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
if (
|
|
110
|
+
request.method === 'eth_getTransactionByHash' ||
|
|
111
|
+
request.method === 'eth_getTransactionReceipt'
|
|
112
|
+
) {
|
|
113
|
+
const hash = request.params?.[0]
|
|
114
|
+
if (typeof hash !== 'string' || !Hash.validate(hash)) return forward()
|
|
115
|
+
const operation = await OperationStore.read(options.store, hash)
|
|
116
|
+
if (!operation || operation.type !== 'transaction') return forward()
|
|
117
|
+
if (request.method === 'eth_getTransactionReceipt') {
|
|
118
|
+
if (operation.status === 'pending') return null
|
|
119
|
+
const transactionHash = await getSubmittedTransactionHash(
|
|
120
|
+
options.store,
|
|
121
|
+
operation,
|
|
122
|
+
)
|
|
123
|
+
if (!transactionHash) return null
|
|
124
|
+
const receipt = await next(
|
|
125
|
+
{
|
|
126
|
+
...request,
|
|
127
|
+
params: [transactionHash],
|
|
128
|
+
},
|
|
129
|
+
requestOptions,
|
|
130
|
+
)
|
|
131
|
+
if (!receipt || typeof receipt !== 'object') return receipt
|
|
132
|
+
const success =
|
|
133
|
+
operation.status === 'submitting'
|
|
134
|
+
? await completeSubmission(
|
|
135
|
+
options.store,
|
|
136
|
+
operation,
|
|
137
|
+
transactionHash,
|
|
138
|
+
)
|
|
139
|
+
: operation
|
|
140
|
+
return {
|
|
141
|
+
...receipt,
|
|
142
|
+
multisig: MultisigOperation.toRpc(success),
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (operation.status === 'pending')
|
|
146
|
+
return await toTransaction(client, operation)
|
|
116
147
|
const transactionHash = await getSubmittedTransactionHash(
|
|
117
|
-
|
|
148
|
+
options.store,
|
|
118
149
|
operation,
|
|
119
150
|
)
|
|
120
|
-
if (!transactionHash) return
|
|
121
|
-
const
|
|
151
|
+
if (!transactionHash) return await toTransaction(client, operation)
|
|
152
|
+
const transaction = await next(
|
|
122
153
|
{
|
|
123
154
|
...request,
|
|
124
155
|
params: [transactionHash],
|
|
125
156
|
},
|
|
126
157
|
requestOptions,
|
|
127
158
|
)
|
|
128
|
-
if (!
|
|
159
|
+
if (!transaction || typeof transaction !== 'object')
|
|
160
|
+
return await toTransaction(client, operation)
|
|
129
161
|
const success =
|
|
130
162
|
operation.status === 'submitting'
|
|
131
163
|
? await completeSubmission(
|
|
132
|
-
|
|
164
|
+
options.store,
|
|
133
165
|
operation,
|
|
134
166
|
transactionHash,
|
|
135
167
|
)
|
|
136
168
|
: operation
|
|
137
169
|
return {
|
|
138
|
-
...
|
|
170
|
+
...transaction,
|
|
139
171
|
multisig: MultisigOperation.toRpc(success),
|
|
140
172
|
}
|
|
141
173
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (!transactionHash) return await toTransaction(client, operation)
|
|
149
|
-
const transaction = await next(
|
|
150
|
-
{
|
|
151
|
-
...request,
|
|
152
|
-
params: [transactionHash],
|
|
153
|
-
},
|
|
154
|
-
requestOptions,
|
|
174
|
+
|
|
175
|
+
if (
|
|
176
|
+
request.method !== 'eth_sendRawTransaction' &&
|
|
177
|
+
request.method !== 'eth_sendRawTransactionSync' &&
|
|
178
|
+
request.method !== 'multisig_approveRawTransaction' &&
|
|
179
|
+
request.method !== 'multisig_approveRawTransactionSync'
|
|
155
180
|
)
|
|
156
|
-
|
|
157
|
-
return await toTransaction(client, operation)
|
|
158
|
-
const success =
|
|
159
|
-
operation.status === 'submitting'
|
|
160
|
-
? await completeSubmission(
|
|
161
|
-
parameters.store,
|
|
162
|
-
operation,
|
|
163
|
-
transactionHash,
|
|
164
|
-
)
|
|
165
|
-
: operation
|
|
166
|
-
return {
|
|
167
|
-
...transaction,
|
|
168
|
-
multisig: MultisigOperation.toRpc(success),
|
|
169
|
-
}
|
|
170
|
-
}
|
|
181
|
+
return forward()
|
|
171
182
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
183
|
+
const standard =
|
|
184
|
+
request.method === 'eth_sendRawTransaction' ||
|
|
185
|
+
request.method === 'eth_sendRawTransactionSync'
|
|
186
|
+
const serialized = request.params?.[0]
|
|
187
|
+
if (!isSerializedTempoTransaction(serialized)) {
|
|
188
|
+
if (standard) return forward()
|
|
189
|
+
throw new RpcResponse.InvalidParamsError({
|
|
190
|
+
message: 'Expected a serialized Tempo multisig transaction.',
|
|
191
|
+
})
|
|
192
|
+
}
|
|
179
193
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
194
|
+
return await submit({
|
|
195
|
+
client,
|
|
196
|
+
method: request.method,
|
|
197
|
+
next,
|
|
198
|
+
request,
|
|
199
|
+
requestOptions,
|
|
200
|
+
serialized,
|
|
201
|
+
store: options.store,
|
|
188
202
|
})
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return await submit({
|
|
192
|
-
client,
|
|
193
|
-
method: request.method,
|
|
194
|
-
next,
|
|
195
|
-
request,
|
|
196
|
-
requestOptions,
|
|
197
|
-
serialized,
|
|
198
|
-
store: parameters.store,
|
|
199
|
-
})
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export declare namespace handleRequest {
|
|
204
|
-
/** RPC request handler. */
|
|
205
|
-
export type Handler = (
|
|
206
|
-
request: Request,
|
|
207
|
-
options?: RequestOptions | undefined,
|
|
208
|
-
) => Promise<unknown>
|
|
209
|
-
|
|
210
|
-
/** RPC request passed to a handler. */
|
|
211
|
-
export type Request = {
|
|
212
|
-
/** RPC method name. */
|
|
213
|
-
method: string
|
|
214
|
-
/** RPC method parameters. */
|
|
215
|
-
params?: readonly unknown[] | undefined
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/** Options for one handled request. */
|
|
219
|
-
export type RequestOptions = EIP1193RequestOptions & {
|
|
220
|
-
/** Chain selected by the caller or inferred from the multisig request. */
|
|
221
|
-
chainId?: number | undefined
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/** Parameters for {@link handleRequest}. */
|
|
225
|
-
export type Parameters = {
|
|
226
|
-
/** Store shared by multisig coordinators. */
|
|
227
|
-
store: Store.Atomic
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/** Error type for {@link handleRequest}. */
|
|
231
|
-
export type ErrorType =
|
|
232
|
-
| ConfigStore.InvalidStoreValueError
|
|
233
|
-
| OperationStore.InvalidStoreValueError
|
|
234
|
-
| OperationStore.StoreConflictError
|
|
235
|
-
| RpcResponse.InvalidParamsError
|
|
203
|
+
},
|
|
204
|
+
})
|
|
236
205
|
}
|
|
237
206
|
|
|
238
207
|
/** Collects approvals and submits a transaction after quorum. @internal */
|
|
239
|
-
// biome-ignore lint/correctness/noUnusedVariables:
|
|
208
|
+
// biome-ignore lint/correctness/noUnusedVariables: declaration merge
|
|
240
209
|
async function submit(options: submit.Options) {
|
|
241
210
|
const transaction = (() => {
|
|
242
211
|
try {
|
|
@@ -551,11 +520,11 @@ declare namespace submit {
|
|
|
551
520
|
| 'multisig_approveRawTransaction'
|
|
552
521
|
| 'multisig_approveRawTransactionSync'
|
|
553
522
|
/** Downstream RPC request handler. */
|
|
554
|
-
next: handleRequest.Handler
|
|
523
|
+
next: Relay.handleRequest.Handler
|
|
555
524
|
/** Original RPC request. */
|
|
556
|
-
request: handleRequest.Request
|
|
525
|
+
request: Relay.handleRequest.Request
|
|
557
526
|
/** Original request overrides. */
|
|
558
|
-
requestOptions?: handleRequest.RequestOptions | undefined
|
|
527
|
+
requestOptions?: Relay.handleRequest.RequestOptions | undefined
|
|
559
528
|
/** Serialized Tempo transaction. */
|
|
560
529
|
serialized: Hex.Hex
|
|
561
530
|
/** Shared multisig store. */
|
|
@@ -758,7 +727,7 @@ declare namespace approveKeyAuthorization {
|
|
|
758
727
|
/** Client used to validate configs. */
|
|
759
728
|
client: ReturnType<typeof createClient>
|
|
760
729
|
/** Original RPC request. */
|
|
761
|
-
request: handleRequest.Request
|
|
730
|
+
request: Relay.handleRequest.Request
|
|
762
731
|
/** Shared multisig store. */
|
|
763
732
|
store: Store.Atomic
|
|
764
733
|
}
|
|
@@ -1240,10 +1209,10 @@ function getTransactionHash(result: unknown): Hex.Hex {
|
|
|
1240
1209
|
|
|
1241
1210
|
/** Resolves and validates the chain used by a handled request. */
|
|
1242
1211
|
async function resolveRequestOptions(options: {
|
|
1243
|
-
request: handleRequest.Request
|
|
1244
|
-
requestOptions?: handleRequest.RequestOptions | undefined
|
|
1212
|
+
request: Relay.handleRequest.Request
|
|
1213
|
+
requestOptions?: Relay.handleRequest.RequestOptions | undefined
|
|
1245
1214
|
store: Store.Store
|
|
1246
|
-
}): Promise<handleRequest.RequestOptions | undefined> {
|
|
1215
|
+
}): Promise<Relay.handleRequest.RequestOptions | undefined> {
|
|
1247
1216
|
const { request, requestOptions, store } = options
|
|
1248
1217
|
const chainId_explicit = requestOptions?.chainId
|
|
1249
1218
|
if (
|
|
@@ -1269,7 +1238,7 @@ async function resolveRequestOptions(options: {
|
|
|
1269
1238
|
|
|
1270
1239
|
/** Resolves a chain from request fields, envelopes, or stored operations. */
|
|
1271
1240
|
async function resolveRequestChainId(
|
|
1272
|
-
request: handleRequest.Request,
|
|
1241
|
+
request: Relay.handleRequest.Request,
|
|
1273
1242
|
store: Store.Store,
|
|
1274
1243
|
) {
|
|
1275
1244
|
const value = request.params?.[0]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type * as Relay from '../../Relay.js'
|
|
2
|
+
|
|
3
|
+
const multisigPlugins = new WeakSet<Relay.Plugin>()
|
|
4
|
+
|
|
5
|
+
/** Registers the built-in multisig plugin for transport capability detection. */
|
|
6
|
+
export function multisig(plugin: Relay.Plugin): Relay.multisig.ReturnType {
|
|
7
|
+
multisigPlugins.add(plugin)
|
|
8
|
+
return plugin as Relay.multisig.ReturnType
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function isMultisig(plugin: Relay.Plugin): boolean {
|
|
12
|
+
return multisigPlugins.has(plugin)
|
|
13
|
+
}
|