viem 2.55.18 → 2.55.19
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 +10 -0
- package/_cjs/chains/definitions/morphTachyon.js +25 -0
- package/_cjs/chains/definitions/morphTachyon.js.map +1 -0
- package/_cjs/chains/definitions/morphTachyonTestnet.js +26 -0
- package/_cjs/chains/definitions/morphTachyonTestnet.js.map +1 -0
- package/_cjs/chains/definitions/ynxTestnet.js +26 -0
- package/_cjs/chains/definitions/ynxTestnet.js.map +1 -0
- package/_cjs/chains/index.js +13 -7
- package/_cjs/chains/index.js.map +1 -1
- package/_cjs/errors/version.js +1 -1
- package/_cjs/tempo/Abis.js +102 -1
- package/_cjs/tempo/Abis.js.map +1 -1
- package/_cjs/tempo/Account.js +188 -16
- package/_cjs/tempo/Account.js.map +1 -1
- package/_cjs/tempo/Addresses.js +2 -1
- package/_cjs/tempo/Addresses.js.map +1 -1
- package/_cjs/tempo/Decorator.js +8 -0
- package/_cjs/tempo/Decorator.js.map +1 -1
- package/_cjs/tempo/Formatters.js +1 -1
- package/_cjs/tempo/Formatters.js.map +1 -1
- package/_cjs/tempo/Selectors.js +7 -1
- package/_cjs/tempo/Selectors.js.map +1 -1
- package/_cjs/tempo/Transaction.js +31 -10
- package/_cjs/tempo/Transaction.js.map +1 -1
- package/_cjs/tempo/actions/accessKey.js +49 -8
- package/_cjs/tempo/actions/accessKey.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/multisig.js +95 -0
- package/_cjs/tempo/actions/multisig.js.map +1 -0
- package/_cjs/tempo/chainConfig.js +58 -29
- package/_cjs/tempo/chainConfig.js.map +1 -1
- package/_cjs/tempo/internal/multisig.js +56 -0
- package/_cjs/tempo/internal/multisig.js.map +1 -0
- package/_esm/chains/definitions/morphTachyon.js +22 -0
- package/_esm/chains/definitions/morphTachyon.js.map +1 -0
- package/_esm/chains/definitions/morphTachyonTestnet.js +23 -0
- package/_esm/chains/definitions/morphTachyonTestnet.js.map +1 -0
- package/_esm/chains/definitions/ynxTestnet.js +23 -0
- package/_esm/chains/definitions/ynxTestnet.js.map +1 -0
- package/_esm/chains/index.js +3 -0
- package/_esm/chains/index.js.map +1 -1
- package/_esm/errors/version.js +1 -1
- package/_esm/tempo/Abis.js +101 -0
- package/_esm/tempo/Abis.js.map +1 -1
- package/_esm/tempo/Account.js +196 -66
- package/_esm/tempo/Account.js.map +1 -1
- package/_esm/tempo/Addresses.js +1 -0
- package/_esm/tempo/Addresses.js.map +1 -1
- package/_esm/tempo/Decorator.js +8 -0
- package/_esm/tempo/Decorator.js.map +1 -1
- package/_esm/tempo/Formatters.js +3 -6
- package/_esm/tempo/Formatters.js.map +1 -1
- package/_esm/tempo/Selectors.js +6 -0
- package/_esm/tempo/Selectors.js.map +1 -1
- package/_esm/tempo/Transaction.js +31 -10
- package/_esm/tempo/Transaction.js.map +1 -1
- package/_esm/tempo/actions/accessKey.js +65 -23
- package/_esm/tempo/actions/accessKey.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/multisig.js +245 -0
- package/_esm/tempo/actions/multisig.js.map +1 -0
- package/_esm/tempo/chainConfig.js +65 -35
- package/_esm/tempo/chainConfig.js.map +1 -1
- package/_esm/tempo/internal/multisig.js +56 -0
- package/_esm/tempo/internal/multisig.js.map +1 -0
- package/_types/chains/definitions/morphTachyon.d.ts +51 -0
- package/_types/chains/definitions/morphTachyon.d.ts.map +1 -0
- package/_types/chains/definitions/morphTachyonTestnet.d.ts +51 -0
- package/_types/chains/definitions/morphTachyonTestnet.d.ts.map +1 -0
- package/_types/chains/definitions/tempo.d.ts +30 -2
- package/_types/chains/definitions/tempo.d.ts.map +1 -1
- package/_types/chains/definitions/tempoDevnet.d.ts +30 -2
- package/_types/chains/definitions/tempoDevnet.d.ts.map +1 -1
- package/_types/chains/definitions/tempoLocalnet.d.ts +30 -2
- package/_types/chains/definitions/tempoLocalnet.d.ts.map +1 -1
- package/_types/chains/definitions/tempoModerato.d.ts +30 -2
- package/_types/chains/definitions/tempoModerato.d.ts.map +1 -1
- package/_types/chains/definitions/ynxTestnet.d.ts +51 -0
- package/_types/chains/definitions/ynxTestnet.d.ts.map +1 -0
- package/_types/chains/index.d.ts +3 -0
- package/_types/chains/index.d.ts.map +1 -1
- package/_types/errors/version.d.ts +1 -1
- package/_types/tempo/Abis.d.ts +321 -0
- package/_types/tempo/Abis.d.ts.map +1 -1
- package/_types/tempo/Account.d.ts +42 -26
- package/_types/tempo/Account.d.ts.map +1 -1
- package/_types/tempo/Addresses.d.ts +1 -0
- package/_types/tempo/Addresses.d.ts.map +1 -1
- package/_types/tempo/Decorator.d.ts +32 -0
- package/_types/tempo/Decorator.d.ts.map +1 -1
- package/_types/tempo/Formatters.d.ts.map +1 -1
- package/_types/tempo/Selectors.d.ts +6 -0
- package/_types/tempo/Selectors.d.ts.map +1 -1
- package/_types/tempo/Transaction.d.ts +17 -2
- package/_types/tempo/Transaction.d.ts.map +1 -1
- package/_types/tempo/actions/accessKey.d.ts +35 -17
- package/_types/tempo/actions/accessKey.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/multisig.d.ts +472 -0
- package/_types/tempo/actions/multisig.d.ts.map +1 -0
- package/_types/tempo/chainConfig.d.ts +15 -1
- package/_types/tempo/chainConfig.d.ts.map +1 -1
- package/_types/tempo/internal/multisig.d.ts +13 -0
- package/_types/tempo/internal/multisig.d.ts.map +1 -0
- package/_types/tempo/zones/zone.d.ts +90 -6
- package/_types/tempo/zones/zone.d.ts.map +1 -1
- package/chains/definitions/morphTachyon.ts +22 -0
- package/chains/definitions/morphTachyonTestnet.ts +23 -0
- package/chains/definitions/ynxTestnet.ts +23 -0
- package/chains/index.ts +3 -0
- package/errors/version.ts +1 -1
- package/package.json +2 -2
- package/tempo/Abis.ts +102 -0
- package/tempo/Account.ts +329 -51
- package/tempo/Addresses.ts +1 -0
- package/tempo/Decorator.ts +50 -0
- package/tempo/Formatters.ts +4 -5
- package/tempo/Selectors.ts +7 -0
- package/tempo/Transaction.ts +52 -12
- package/tempo/actions/accessKey.ts +128 -32
- package/tempo/actions/index.ts +1 -0
- package/tempo/actions/multisig.ts +356 -0
- package/tempo/chainConfig.ts +82 -35
- package/tempo/internal/multisig.ts +72 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import type { Address } from 'abitype'
|
|
2
|
+
import { MultisigConfig } from 'ox/tempo'
|
|
3
|
+
import type { Account } from '../../accounts/types.js'
|
|
4
|
+
import type { ReadContractReturnType } from '../../actions/public/readContract.js'
|
|
5
|
+
import { readContract } from '../../actions/public/readContract.js'
|
|
6
|
+
import type { WriteContractReturnType } from '../../actions/wallet/writeContract.js'
|
|
7
|
+
import { writeContract } from '../../actions/wallet/writeContract.js'
|
|
8
|
+
import { writeContractSync } from '../../actions/wallet/writeContractSync.js'
|
|
9
|
+
import type { Client } from '../../clients/createClient.js'
|
|
10
|
+
import type { Transport } from '../../clients/transports/createTransport.js'
|
|
11
|
+
import type { BaseErrorType } from '../../errors/base.js'
|
|
12
|
+
import type { Chain } from '../../types/chain.js'
|
|
13
|
+
import type { GetEventArgs } from '../../types/contract.js'
|
|
14
|
+
import type { Log } from '../../types/log.js'
|
|
15
|
+
import type { Compute } from '../../types/utils.js'
|
|
16
|
+
import { parseEventLogs } from '../../utils/abi/parseEventLogs.js'
|
|
17
|
+
import * as Abis from '../Abis.js'
|
|
18
|
+
import * as Addresses from '../Addresses.js'
|
|
19
|
+
import type { ReadParameters, WriteParameters } from '../internal/types.js'
|
|
20
|
+
import { defineCall } from '../internal/utils.js'
|
|
21
|
+
import type { TransactionReceipt } from '../Transaction.js'
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Checks whether an address is an initialized native multisig account.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { createClient, http } from 'viem'
|
|
29
|
+
* import { tempo } from 'viem/chains'
|
|
30
|
+
* import { Actions } from 'viem/tempo'
|
|
31
|
+
*
|
|
32
|
+
* const client = createClient({
|
|
33
|
+
* chain: tempo,
|
|
34
|
+
* transport: http(),
|
|
35
|
+
* })
|
|
36
|
+
*
|
|
37
|
+
* const initialized = await Actions.multisig.isInitialized(client, {
|
|
38
|
+
* account: '0x...',
|
|
39
|
+
* })
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @param client - Client.
|
|
43
|
+
* @param parameters - Parameters.
|
|
44
|
+
* @returns Whether the account is an initialized native multisig account.
|
|
45
|
+
*/
|
|
46
|
+
export async function isInitialized<
|
|
47
|
+
chain extends Chain | undefined,
|
|
48
|
+
account extends Account | undefined,
|
|
49
|
+
>(
|
|
50
|
+
client: Client<Transport, chain, account>,
|
|
51
|
+
parameters: isInitialized.Parameters,
|
|
52
|
+
): Promise<isInitialized.ReturnValue> {
|
|
53
|
+
const { account, ...rest } = parameters
|
|
54
|
+
return readContract(client, {
|
|
55
|
+
...rest,
|
|
56
|
+
...isInitialized.call({ account }),
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export namespace isInitialized {
|
|
61
|
+
export type Parameters = ReadParameters & Args
|
|
62
|
+
|
|
63
|
+
export type Args = {
|
|
64
|
+
/** Account address. */
|
|
65
|
+
account: Address
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type ReturnValue = ReadContractReturnType<
|
|
69
|
+
typeof Abis.nativeMultisig,
|
|
70
|
+
'isMultisigAccount',
|
|
71
|
+
never
|
|
72
|
+
>
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Defines a call to the precompile's `isMultisigAccount` function.
|
|
76
|
+
*
|
|
77
|
+
* Can be passed to [`multicall`](https://viem.sh/docs/contract/multicall).
|
|
78
|
+
*
|
|
79
|
+
* @param args - Arguments.
|
|
80
|
+
* @returns The call.
|
|
81
|
+
*/
|
|
82
|
+
export function call(args: Args) {
|
|
83
|
+
return defineCall({
|
|
84
|
+
address: Addresses.nativeMultisig,
|
|
85
|
+
abi: Abis.nativeMultisig,
|
|
86
|
+
args: [args.account],
|
|
87
|
+
functionName: 'isMultisigAccount',
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Gets the current configuration for an initialized native multisig account.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* import { createClient, http } from 'viem'
|
|
98
|
+
* import { tempo } from 'viem/chains'
|
|
99
|
+
* import { Actions } from 'viem/tempo'
|
|
100
|
+
*
|
|
101
|
+
* const client = createClient({
|
|
102
|
+
* chain: tempo,
|
|
103
|
+
* transport: http(),
|
|
104
|
+
* })
|
|
105
|
+
*
|
|
106
|
+
* const config = await Actions.multisig.getConfig(client, {
|
|
107
|
+
* account: '0x...',
|
|
108
|
+
* })
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* @param client - Client.
|
|
112
|
+
* @param parameters - Parameters.
|
|
113
|
+
* @returns The current version, threshold, and owners.
|
|
114
|
+
*/
|
|
115
|
+
export async function getConfig<
|
|
116
|
+
chain extends Chain | undefined,
|
|
117
|
+
account extends Account | undefined,
|
|
118
|
+
>(
|
|
119
|
+
client: Client<Transport, chain, account>,
|
|
120
|
+
parameters: getConfig.Parameters,
|
|
121
|
+
): Promise<getConfig.ReturnValue> {
|
|
122
|
+
const { account, ...rest } = parameters
|
|
123
|
+
return readContract(client, {
|
|
124
|
+
...rest,
|
|
125
|
+
...getConfig.call({ account }),
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export namespace getConfig {
|
|
130
|
+
export type Parameters = ReadParameters & Args
|
|
131
|
+
|
|
132
|
+
export type Args = {
|
|
133
|
+
/** Initialized multisig account address. */
|
|
134
|
+
account: Address
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export type ReturnValue = ReadContractReturnType<
|
|
138
|
+
typeof Abis.nativeMultisig,
|
|
139
|
+
'getConfig',
|
|
140
|
+
never
|
|
141
|
+
>
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Defines a call to the `getConfig` function.
|
|
145
|
+
*
|
|
146
|
+
* Can be passed to [`multicall`](https://viem.sh/docs/contract/multicall).
|
|
147
|
+
*
|
|
148
|
+
* @param args - Arguments.
|
|
149
|
+
* @returns The call.
|
|
150
|
+
*/
|
|
151
|
+
export function call(args: Args) {
|
|
152
|
+
return defineCall({
|
|
153
|
+
address: Addresses.nativeMultisig,
|
|
154
|
+
abi: Abis.nativeMultisig,
|
|
155
|
+
args: [args.account],
|
|
156
|
+
functionName: 'getConfig',
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Replaces the current configuration for a native multisig account.
|
|
163
|
+
*
|
|
164
|
+
* The transaction must be authorized directly by the account's current owner
|
|
165
|
+
* quorum. Local owner-signing flows can include {@link updateConfig.call} in a
|
|
166
|
+
* prepared transaction before collecting approvals.
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```ts
|
|
170
|
+
* import { createClient, http } from 'viem'
|
|
171
|
+
* import { sendTransactionSync } from 'viem/actions'
|
|
172
|
+
* import { tempoLocalnet } from 'viem/chains'
|
|
173
|
+
* import { Account, Actions } from 'viem/tempo'
|
|
174
|
+
*
|
|
175
|
+
* const owner = Account.fromSecp256k1(
|
|
176
|
+
* '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
|
|
177
|
+
* )
|
|
178
|
+
* const account = Account.fromMultisig({ owners: [owner] })
|
|
179
|
+
* const client = createClient({
|
|
180
|
+
* chain: tempoLocalnet,
|
|
181
|
+
* transport: http(),
|
|
182
|
+
* })
|
|
183
|
+
*
|
|
184
|
+
* await sendTransactionSync(client, {
|
|
185
|
+
* account,
|
|
186
|
+
* to: account.address,
|
|
187
|
+
* })
|
|
188
|
+
*
|
|
189
|
+
* const hash = await Actions.multisig.updateConfig(client, {
|
|
190
|
+
* account,
|
|
191
|
+
* threshold: 1,
|
|
192
|
+
* owners: [{ owner: owner.address, weight: 1 }],
|
|
193
|
+
* })
|
|
194
|
+
* ```
|
|
195
|
+
*
|
|
196
|
+
* @param client - Client.
|
|
197
|
+
* @param parameters - Parameters.
|
|
198
|
+
* @returns The transaction hash.
|
|
199
|
+
*/
|
|
200
|
+
export async function updateConfig<
|
|
201
|
+
chain extends Chain | undefined,
|
|
202
|
+
account extends Account | undefined,
|
|
203
|
+
>(
|
|
204
|
+
client: Client<Transport, chain, account>,
|
|
205
|
+
parameters: updateConfig.Parameters<chain, account>,
|
|
206
|
+
): Promise<updateConfig.ReturnValue> {
|
|
207
|
+
return updateConfig.inner(writeContract, client, parameters)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export namespace updateConfig {
|
|
211
|
+
export type Parameters<
|
|
212
|
+
chain extends Chain | undefined = Chain | undefined,
|
|
213
|
+
account extends Account | undefined = Account | undefined,
|
|
214
|
+
> = WriteParameters<chain, account> & Args
|
|
215
|
+
|
|
216
|
+
export type Args = {
|
|
217
|
+
/** New multisig owners and their weights. */
|
|
218
|
+
owners: MultisigConfig.Config['owners']
|
|
219
|
+
/** New signature weight required to authorize the account. */
|
|
220
|
+
threshold: MultisigConfig.Config['threshold']
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export type ReturnValue = WriteContractReturnType
|
|
224
|
+
|
|
225
|
+
// TODO: exhaustive error type
|
|
226
|
+
export type ErrorType = BaseErrorType
|
|
227
|
+
|
|
228
|
+
/** @internal */
|
|
229
|
+
export async function inner<
|
|
230
|
+
action extends typeof writeContract | typeof writeContractSync,
|
|
231
|
+
chain extends Chain | undefined,
|
|
232
|
+
account extends Account | undefined,
|
|
233
|
+
>(
|
|
234
|
+
action: action,
|
|
235
|
+
client: Client<Transport, chain, account>,
|
|
236
|
+
parameters: Parameters<chain, account>,
|
|
237
|
+
): Promise<ReturnType<action>> {
|
|
238
|
+
const { owners, threshold, ...rest } = parameters
|
|
239
|
+
return (await action(client, {
|
|
240
|
+
...rest,
|
|
241
|
+
...updateConfig.call({ owners, threshold }),
|
|
242
|
+
} as never)) as never
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Defines a call to the `updateConfig` function.
|
|
247
|
+
*
|
|
248
|
+
* Can be passed as a parameter to:
|
|
249
|
+
* - [`estimateContractGas`](https://viem.sh/docs/contract/estimateContractGas): estimate gas
|
|
250
|
+
* - [`simulateContract`](https://viem.sh/docs/contract/simulateContract): simulate the update
|
|
251
|
+
* - [`sendCalls`](https://viem.sh/docs/actions/wallet/sendCalls): include the update in a call batch
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```ts
|
|
255
|
+
* import { Actions } from 'viem/tempo'
|
|
256
|
+
*
|
|
257
|
+
* const call = Actions.multisig.updateConfig.call({
|
|
258
|
+
* threshold: 1,
|
|
259
|
+
* owners: [{ owner: '0x...', weight: 1 }],
|
|
260
|
+
* })
|
|
261
|
+
* ```
|
|
262
|
+
*
|
|
263
|
+
* @param args - New multisig configuration.
|
|
264
|
+
* @returns The call.
|
|
265
|
+
*/
|
|
266
|
+
export function call(args: Args) {
|
|
267
|
+
const config = MultisigConfig.from(args)
|
|
268
|
+
return defineCall({
|
|
269
|
+
address: Addresses.nativeMultisig,
|
|
270
|
+
abi: Abis.nativeMultisig,
|
|
271
|
+
args: [config.threshold, config.owners],
|
|
272
|
+
functionName: 'updateConfig',
|
|
273
|
+
})
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Extracts the `MultisigConfigUpdated` event from logs.
|
|
278
|
+
*
|
|
279
|
+
* @param logs - Transaction logs.
|
|
280
|
+
* @returns The configuration update event.
|
|
281
|
+
*/
|
|
282
|
+
export function extractEvent(logs: Log[]) {
|
|
283
|
+
const [log] = parseEventLogs({
|
|
284
|
+
abi: Abis.nativeMultisig,
|
|
285
|
+
logs,
|
|
286
|
+
eventName: 'MultisigConfigUpdated',
|
|
287
|
+
strict: true,
|
|
288
|
+
})
|
|
289
|
+
if (!log) throw new Error('`MultisigConfigUpdated` event not found.')
|
|
290
|
+
return log
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Replaces a native multisig configuration and waits for confirmation.
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* ```ts
|
|
299
|
+
* import { createWalletClient, custom, type EIP1193Provider } from 'viem'
|
|
300
|
+
* import { tempo } from 'viem/chains'
|
|
301
|
+
* import { Actions } from 'viem/tempo'
|
|
302
|
+
*
|
|
303
|
+
* declare const provider: EIP1193Provider
|
|
304
|
+
*
|
|
305
|
+
* const client = createWalletClient({
|
|
306
|
+
* account: '0x...',
|
|
307
|
+
* chain: tempo,
|
|
308
|
+
* transport: custom(provider),
|
|
309
|
+
* })
|
|
310
|
+
*
|
|
311
|
+
* const { receipt } = await Actions.multisig.updateConfigSync(client, {
|
|
312
|
+
* threshold: 1,
|
|
313
|
+
* owners: [{ owner: '0x...', weight: 1 }],
|
|
314
|
+
* })
|
|
315
|
+
* ```
|
|
316
|
+
*
|
|
317
|
+
* @param client - Client.
|
|
318
|
+
* @param parameters - Parameters.
|
|
319
|
+
* @returns The updated configuration event and transaction receipt.
|
|
320
|
+
*/
|
|
321
|
+
export async function updateConfigSync<
|
|
322
|
+
chain extends Chain | undefined,
|
|
323
|
+
account extends Account | undefined,
|
|
324
|
+
>(
|
|
325
|
+
client: Client<Transport, chain, account>,
|
|
326
|
+
parameters: updateConfigSync.Parameters<chain, account>,
|
|
327
|
+
): Promise<updateConfigSync.ReturnValue> {
|
|
328
|
+
const { throwOnReceiptRevert = true, ...rest } = parameters
|
|
329
|
+
const receipt = await updateConfig.inner(writeContractSync, client, {
|
|
330
|
+
...rest,
|
|
331
|
+
throwOnReceiptRevert,
|
|
332
|
+
} as never)
|
|
333
|
+
const { args } = updateConfig.extractEvent(receipt.logs)
|
|
334
|
+
return { ...args, receipt } as never
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export namespace updateConfigSync {
|
|
338
|
+
export type Parameters<
|
|
339
|
+
chain extends Chain | undefined = Chain | undefined,
|
|
340
|
+
account extends Account | undefined = Account | undefined,
|
|
341
|
+
> = updateConfig.Parameters<chain, account>
|
|
342
|
+
|
|
343
|
+
export type Args = updateConfig.Args
|
|
344
|
+
|
|
345
|
+
export type ReturnValue = Compute<
|
|
346
|
+
GetEventArgs<
|
|
347
|
+
typeof Abis.nativeMultisig,
|
|
348
|
+
'MultisigConfigUpdated',
|
|
349
|
+
{ IndexedOnly: false; Required: true }
|
|
350
|
+
> & {
|
|
351
|
+
receipt: TransactionReceipt
|
|
352
|
+
}
|
|
353
|
+
>
|
|
354
|
+
|
|
355
|
+
export type ErrorType = updateConfig.ErrorType
|
|
356
|
+
}
|
package/tempo/chainConfig.ts
CHANGED
|
@@ -15,9 +15,14 @@ import { keccak256 } from '../utils/hash/keccak256.js'
|
|
|
15
15
|
import type { SerializeTransactionFn } from '../utils/transaction/serializeTransaction.js'
|
|
16
16
|
import type { Account, MultisigAccount } from './Account.js'
|
|
17
17
|
import { getMetadata } from './actions/accessKey.js'
|
|
18
|
+
import * as multisig from './actions/multisig.js'
|
|
18
19
|
import * as Formatters from './Formatters.js'
|
|
19
20
|
import type { Hardfork } from './Hardfork.js'
|
|
20
21
|
import * as Concurrent from './internal/concurrent.js'
|
|
22
|
+
import {
|
|
23
|
+
createMultisigStateResolver,
|
|
24
|
+
getMultisigOwnerStates,
|
|
25
|
+
} from './internal/multisig.js'
|
|
21
26
|
import * as Transaction from './Transaction.js'
|
|
22
27
|
|
|
23
28
|
const maxExpirySecs = 25
|
|
@@ -60,7 +65,10 @@ export const chainConfig = {
|
|
|
60
65
|
| undefined
|
|
61
66
|
feePayerSignature?: Transaction.TransactionSerializableTempo['feePayerSignature']
|
|
62
67
|
from?: Address | undefined
|
|
63
|
-
|
|
68
|
+
keyData?: Hex.Hex | undefined
|
|
69
|
+
keyType?: 'p256' | 'secp256k1' | 'webAuthn' | undefined
|
|
70
|
+
multisig?: Address | MultisigConfig.Config | undefined
|
|
71
|
+
multisigOwnerStates?: Transaction.TransactionRequestTempo['multisigOwnerStates']
|
|
64
72
|
signatures?: readonly unknown[] | undefined
|
|
65
73
|
}
|
|
66
74
|
|
|
@@ -82,36 +90,88 @@ export const chainConfig = {
|
|
|
82
90
|
return request as unknown as typeof r
|
|
83
91
|
}
|
|
84
92
|
|
|
85
|
-
// Native multisig (TIP-1061). The transaction sender is the
|
|
86
|
-
// multisig
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
// serializer auto-detects bootstrap (`init`) from `nonce == 0`.
|
|
93
|
+
// Native multisig (TIP-1061). The transaction sender is the stable
|
|
94
|
+
// multisig address, not a signing account. Initial configs support
|
|
95
|
+
// bootstrap; initialized accounts can be reconstructed from their
|
|
96
|
+
// address and resolved through the multisig precompile.
|
|
90
97
|
//
|
|
91
98
|
// The config is taken from an explicit `multisig` field, or inferred from
|
|
92
99
|
// a multisig account (so callers can just pass `account` to
|
|
93
100
|
// `prepareTransactionRequest` without also passing `multisig`).
|
|
94
|
-
const
|
|
101
|
+
const multisigIdentity =
|
|
95
102
|
request.multisig ??
|
|
96
103
|
(request.account?.source === 'multisig'
|
|
97
|
-
? (request.account as MultisigAccount).config
|
|
104
|
+
? ((request.account as MultisigAccount).config ??
|
|
105
|
+
request.account.address)
|
|
98
106
|
: undefined)
|
|
99
|
-
if (
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
if (multisigIdentity) {
|
|
108
|
+
const initialConfig =
|
|
109
|
+
typeof multisigIdentity === 'string'
|
|
110
|
+
? undefined
|
|
111
|
+
: MultisigConfig.from(multisigIdentity)
|
|
112
|
+
const multisigAddress =
|
|
113
|
+
typeof multisigIdentity === 'string'
|
|
114
|
+
? multisigIdentity
|
|
115
|
+
: MultisigConfig.getAddress(initialConfig!)
|
|
116
|
+
request.multisig = initialConfig ?? multisigIdentity
|
|
117
|
+
request.from = multisigAddress
|
|
118
|
+
// Key types are not part of the config, so conservatively model every
|
|
119
|
+
// approval as a maximum-size WebAuthn signature.
|
|
120
|
+
if (typeof request.keyType === 'undefined') {
|
|
121
|
+
request.keyType = 'webAuthn'
|
|
122
|
+
if (typeof request.keyData === 'undefined') request.keyData = '0x0578'
|
|
123
|
+
}
|
|
124
|
+
const getState = createMultisigStateResolver((account) =>
|
|
125
|
+
getAction(client, multisig.getConfig, 'getConfig')({ account }),
|
|
126
|
+
)
|
|
127
|
+
const ownerStates =
|
|
128
|
+
request.account?.source === 'multisig'
|
|
129
|
+
? getMultisigOwnerStates(
|
|
130
|
+
request.account as MultisigAccount,
|
|
131
|
+
getState,
|
|
132
|
+
)
|
|
133
|
+
: undefined
|
|
134
|
+
const state = ownerStates
|
|
135
|
+
? (await ownerStates)[0]!
|
|
136
|
+
: await getState(multisigAddress)
|
|
137
|
+
if (!initialConfig && !state.initialized)
|
|
138
|
+
throw new Error(
|
|
139
|
+
'Cannot prepare an uninitialized multisig account from an address. Provide its initial config instead.',
|
|
140
|
+
)
|
|
141
|
+
if (typeof request.multisigVersion === 'undefined')
|
|
142
|
+
request.multisigVersion = state.version
|
|
143
|
+
const authorizationSignature = request.keyAuthorization?.signature
|
|
144
|
+
if (
|
|
145
|
+
authorizationSignature?.type === 'multisig' &&
|
|
146
|
+
typeof authorizationSignature.init !== 'undefined'
|
|
147
|
+
)
|
|
148
|
+
request.keyAuthorization = {
|
|
149
|
+
...request.keyAuthorization!,
|
|
150
|
+
signature: SignatureEnvelope.from({
|
|
151
|
+
initialConfig: authorizationSignature.init,
|
|
152
|
+
signatures: authorizationSignature.signatures,
|
|
153
|
+
}),
|
|
154
|
+
}
|
|
155
|
+
const keyAuthorizationSignature = request.keyAuthorization?.signature
|
|
156
|
+
const keyAuthorizationInitializes =
|
|
157
|
+
keyAuthorizationSignature?.type === 'multisig' &&
|
|
158
|
+
typeof keyAuthorizationSignature.init !== 'undefined'
|
|
159
|
+
if (initialConfig && !keyAuthorizationInitializes)
|
|
160
|
+
request.multisigInit = {
|
|
161
|
+
salt: initialConfig.salt ?? MultisigConfig.zeroSalt,
|
|
162
|
+
threshold: Number(initialConfig.threshold),
|
|
163
|
+
owners: initialConfig.owners.map((owner) => ({
|
|
164
|
+
owner: owner.owner,
|
|
165
|
+
weight: Number(owner.weight),
|
|
166
|
+
})),
|
|
167
|
+
}
|
|
168
|
+
if (ownerStates) {
|
|
169
|
+
const states = await ownerStates
|
|
170
|
+
if (states.length > 0) request.multisigOwnerStates = states
|
|
110
171
|
}
|
|
111
|
-
request.multisigSignatureCount ??= inferMultisigSignatureCount(config)
|
|
112
172
|
// A non-multisig `account` (e.g. the client's default) isn't the sender,
|
|
113
173
|
// so drop it: core then fills nonce/gas/fees for the multisig sender via
|
|
114
|
-
// `request.from`. A multisig account *is* the sender
|
|
174
|
+
// `request.from`. A multisig account *is* the sender, so keep it so the
|
|
115
175
|
// prepared request can be sent without re-passing `account`.
|
|
116
176
|
if (request.account?.source !== 'multisig') delete request.account
|
|
117
177
|
}
|
|
@@ -121,7 +181,7 @@ export const chainConfig = {
|
|
|
121
181
|
const useExpiringNonce = await (async () => {
|
|
122
182
|
if (request.nonceKey === 'expiring' || request.nonceKey === maxUint256)
|
|
123
183
|
return true
|
|
124
|
-
if (
|
|
184
|
+
if (multisigIdentity) return false
|
|
125
185
|
if (request.feePayer && typeof request.nonceKey === 'undefined')
|
|
126
186
|
return true
|
|
127
187
|
const account = request.account as
|
|
@@ -286,16 +346,3 @@ export const chainConfig = {
|
|
|
286
346
|
} as const satisfies viem_ChainConfig & { blockTime: number }
|
|
287
347
|
|
|
288
348
|
export type ChainConfig = typeof chainConfig
|
|
289
|
-
|
|
290
|
-
function inferMultisigSignatureCount(config: MultisigConfig.Config) {
|
|
291
|
-
const threshold = Number(config.threshold)
|
|
292
|
-
const weights = config.owners
|
|
293
|
-
.map((owner) => Number(owner.weight))
|
|
294
|
-
.sort((a, b) => b - a)
|
|
295
|
-
let total = 0
|
|
296
|
-
for (const [index, weight] of weights.entries()) {
|
|
297
|
-
total += weight
|
|
298
|
-
if (total >= threshold) return index + 1
|
|
299
|
-
}
|
|
300
|
-
return weights.length
|
|
301
|
-
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { Address } from 'abitype'
|
|
2
|
+
import type { MultisigConfig } from 'ox/tempo'
|
|
3
|
+
import { BaseError } from '../../errors/base.js'
|
|
4
|
+
import { ContractFunctionRevertedError } from '../../errors/contract.js'
|
|
5
|
+
import type { MultisigAccount } from '../Account.js'
|
|
6
|
+
import type { MultisigOwnerState } from '../Transaction.js'
|
|
7
|
+
|
|
8
|
+
/** @internal */
|
|
9
|
+
export function createMultisigStateResolver(
|
|
10
|
+
getConfig: (account: Address) => Promise<{
|
|
11
|
+
owners: MultisigConfig.Config['owners']
|
|
12
|
+
threshold: MultisigConfig.Config['threshold']
|
|
13
|
+
version: bigint
|
|
14
|
+
}>,
|
|
15
|
+
) {
|
|
16
|
+
// Cache only within one operation because config versions can change between requests.
|
|
17
|
+
const cache = new Map<Address, Promise<MultisigOwnerState>>()
|
|
18
|
+
return (account: Address): Promise<MultisigOwnerState> => {
|
|
19
|
+
const address = account.toLowerCase() as Address
|
|
20
|
+
const cached = cache.get(address)
|
|
21
|
+
if (cached) return cached
|
|
22
|
+
|
|
23
|
+
const state = (async () => {
|
|
24
|
+
try {
|
|
25
|
+
const config = await getConfig(account)
|
|
26
|
+
return {
|
|
27
|
+
account,
|
|
28
|
+
config: { owners: config.owners, threshold: config.threshold },
|
|
29
|
+
initialized: true,
|
|
30
|
+
version: config.version,
|
|
31
|
+
}
|
|
32
|
+
} catch (error) {
|
|
33
|
+
const cause =
|
|
34
|
+
error instanceof BaseError
|
|
35
|
+
? error.walk(
|
|
36
|
+
(error) => error instanceof ContractFunctionRevertedError,
|
|
37
|
+
)
|
|
38
|
+
: undefined
|
|
39
|
+
if (
|
|
40
|
+
!(cause instanceof ContractFunctionRevertedError) ||
|
|
41
|
+
cause.data?.errorName !== 'NotMultisigAccount'
|
|
42
|
+
)
|
|
43
|
+
throw error
|
|
44
|
+
return { account, initialized: false, version: 0n }
|
|
45
|
+
}
|
|
46
|
+
})()
|
|
47
|
+
cache.set(address, state)
|
|
48
|
+
return state
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** @internal */
|
|
53
|
+
export function getMultisigOwnerStates(
|
|
54
|
+
account: MultisigAccount,
|
|
55
|
+
getState: (account: Address) => Promise<MultisigOwnerState>,
|
|
56
|
+
): Promise<readonly MultisigOwnerState[]> {
|
|
57
|
+
// Collect locally first so all config reads start in one latency wave.
|
|
58
|
+
const owners: MultisigAccount[] = [account]
|
|
59
|
+
const seen = new Set<Address>([account.address.toLowerCase() as Address])
|
|
60
|
+
const visit = (account: MultisigAccount) => {
|
|
61
|
+
for (const owner of account.owners) {
|
|
62
|
+
if (owner.source !== 'multisig') continue
|
|
63
|
+
const address = owner.address.toLowerCase() as Address
|
|
64
|
+
if (seen.has(address)) continue
|
|
65
|
+
seen.add(address)
|
|
66
|
+
owners.push(owner as MultisigAccount)
|
|
67
|
+
visit(owner as MultisigAccount)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
visit(account)
|
|
71
|
+
return Promise.all(owners.map((owner) => getState(owner.address)))
|
|
72
|
+
}
|