viem 2.56.5 → 2.56.7
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 +28 -0
- package/_cjs/actions/public/simulateCalls.js +6 -1
- package/_cjs/actions/public/simulateCalls.js.map +1 -1
- package/_cjs/chains/definitions/arc.js +19 -1
- package/_cjs/chains/definitions/arc.js.map +1 -1
- package/_cjs/chains/definitions/eCanna.js +23 -0
- package/_cjs/chains/definitions/eCanna.js.map +1 -0
- package/_cjs/chains/definitions/eCannaTestnet.js +24 -0
- package/_cjs/chains/definitions/eCannaTestnet.js.map +1 -0
- package/_cjs/chains/definitions/hyveChain.js +29 -0
- package/_cjs/chains/definitions/hyveChain.js.map +1 -0
- package/_cjs/chains/definitions/robinhood.js +5 -1
- package/_cjs/chains/definitions/robinhood.js.map +1 -1
- package/_cjs/chains/definitions/zagros.js +33 -0
- package/_cjs/chains/definitions/zagros.js.map +1 -0
- package/_cjs/chains/index.js +20 -12
- package/_cjs/chains/index.js.map +1 -1
- package/_cjs/errors/version.js +1 -1
- package/_cjs/op-stack/chains.js +3 -1
- package/_cjs/op-stack/chains.js.map +1 -1
- package/_cjs/tempo/Account.js +21 -30
- 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/Multisig.js +14 -107
- package/_cjs/tempo/Multisig.js.map +1 -1
- package/_cjs/tempo/Transaction.js +5 -2
- package/_cjs/tempo/Transaction.js.map +1 -1
- package/_cjs/tempo/actions/accessKey.js +2 -1
- package/_cjs/tempo/actions/accessKey.js.map +1 -1
- package/_cjs/tempo/chainConfig.js +3 -31
- package/_cjs/tempo/chainConfig.js.map +1 -1
- package/_cjs/tempo/multisig/Config.js +8 -4
- package/_cjs/tempo/multisig/Config.js.map +1 -1
- package/_cjs/tempo/multisig/Signature.js +11 -0
- package/_cjs/tempo/multisig/Signature.js.map +1 -0
- package/_cjs/tokens/definitions/cirbtc.js +1 -0
- package/_cjs/tokens/definitions/cirbtc.js.map +1 -1
- package/_cjs/tokens/definitions/eurc.js +1 -0
- package/_cjs/tokens/definitions/eurc.js.map +1 -1
- package/_cjs/tokens/definitions/usdc.js +1 -0
- package/_cjs/tokens/definitions/usdc.js.map +1 -1
- package/_cjs/utils/buildRequest.js +2 -0
- package/_cjs/utils/buildRequest.js.map +1 -1
- package/_esm/actions/public/simulateCalls.js +7 -1
- package/_esm/actions/public/simulateCalls.js.map +1 -1
- package/_esm/chains/definitions/arc.js +19 -1
- package/_esm/chains/definitions/arc.js.map +1 -1
- package/_esm/chains/definitions/eCanna.js +20 -0
- package/_esm/chains/definitions/eCanna.js.map +1 -0
- package/_esm/chains/definitions/eCannaTestnet.js +21 -0
- package/_esm/chains/definitions/eCannaTestnet.js.map +1 -0
- package/_esm/chains/definitions/hyveChain.js +26 -0
- package/_esm/chains/definitions/hyveChain.js.map +1 -0
- package/_esm/chains/definitions/robinhood.js +5 -1
- package/_esm/chains/definitions/robinhood.js.map +1 -1
- package/_esm/chains/definitions/zagros.js +30 -0
- package/_esm/chains/definitions/zagros.js.map +1 -0
- package/_esm/chains/index.js +4 -0
- package/_esm/chains/index.js.map +1 -1
- package/_esm/errors/version.js +1 -1
- package/_esm/op-stack/chains.js +1 -0
- package/_esm/op-stack/chains.js.map +1 -1
- package/_esm/tempo/Account.js +21 -30
- package/_esm/tempo/Account.js.map +1 -1
- package/_esm/tempo/Addresses.js +2 -0
- package/_esm/tempo/Addresses.js.map +1 -1
- package/_esm/tempo/Multisig.js +15 -111
- package/_esm/tempo/Multisig.js.map +1 -1
- package/_esm/tempo/Transaction.js +5 -2
- package/_esm/tempo/Transaction.js.map +1 -1
- package/_esm/tempo/actions/accessKey.js +2 -1
- package/_esm/tempo/actions/accessKey.js.map +1 -1
- package/_esm/tempo/chainConfig.js +3 -31
- package/_esm/tempo/chainConfig.js.map +1 -1
- package/_esm/tempo/multisig/Config.js +10 -5
- package/_esm/tempo/multisig/Config.js.map +1 -1
- package/_esm/tempo/multisig/Signature.js +9 -0
- package/_esm/tempo/multisig/Signature.js.map +1 -0
- package/_esm/tokens/definitions/cirbtc.js +1 -0
- package/_esm/tokens/definitions/cirbtc.js.map +1 -1
- package/_esm/tokens/definitions/eurc.js +1 -0
- package/_esm/tokens/definitions/eurc.js.map +1 -1
- package/_esm/tokens/definitions/usdc.js +1 -0
- package/_esm/tokens/definitions/usdc.js.map +1 -1
- package/_esm/utils/buildRequest.js +7 -0
- package/_esm/utils/buildRequest.js.map +1 -1
- package/_types/actions/public/simulateCalls.d.ts.map +1 -1
- package/_types/chains/definitions/arc.d.ts +13 -21
- package/_types/chains/definitions/arc.d.ts.map +1 -1
- package/_types/chains/definitions/eCanna.d.ts +51 -0
- package/_types/chains/definitions/eCanna.d.ts.map +1 -0
- package/_types/chains/definitions/eCannaTestnet.d.ts +51 -0
- package/_types/chains/definitions/eCannaTestnet.d.ts.map +1 -0
- package/_types/chains/definitions/hyveChain.d.ts +49 -0
- package/_types/chains/definitions/hyveChain.d.ts.map +1 -0
- package/_types/chains/definitions/robinhood.d.ts +2 -1
- package/_types/chains/definitions/robinhood.d.ts.map +1 -1
- package/_types/chains/definitions/tempo.d.ts +2 -4
- package/_types/chains/definitions/tempo.d.ts.map +1 -1
- package/_types/chains/definitions/tempoDevnet.d.ts +2 -4
- package/_types/chains/definitions/tempoDevnet.d.ts.map +1 -1
- package/_types/chains/definitions/tempoLocalnet.d.ts +2 -4
- package/_types/chains/definitions/tempoLocalnet.d.ts.map +1 -1
- package/_types/chains/definitions/tempoModerato.d.ts +2 -4
- package/_types/chains/definitions/tempoModerato.d.ts.map +1 -1
- package/_types/chains/definitions/zagros.d.ts +50 -0
- package/_types/chains/definitions/zagros.d.ts.map +1 -0
- package/_types/chains/index.d.ts +4 -0
- package/_types/chains/index.d.ts.map +1 -1
- package/_types/errors/version.d.ts +1 -1
- package/_types/op-stack/chains.d.ts +1 -0
- package/_types/op-stack/chains.d.ts.map +1 -1
- package/_types/tempo/Account.d.ts +9 -3
- package/_types/tempo/Account.d.ts.map +1 -1
- package/_types/tempo/Addresses.d.ts +2 -0
- package/_types/tempo/Addresses.d.ts.map +1 -1
- package/_types/tempo/Multisig.d.ts.map +1 -1
- package/_types/tempo/Transaction.d.ts +16 -7
- package/_types/tempo/Transaction.d.ts.map +1 -1
- package/_types/tempo/actions/accessKey.d.ts +2 -2
- package/_types/tempo/actions/accessKey.d.ts.map +1 -1
- package/_types/tempo/chainConfig.d.ts +1 -3
- package/_types/tempo/chainConfig.d.ts.map +1 -1
- package/_types/tempo/multisig/Config.d.ts.map +1 -1
- package/_types/tempo/multisig/Signature.d.ts +4 -0
- package/_types/tempo/multisig/Signature.d.ts.map +1 -0
- package/_types/tokens/definitions/cirbtc.d.ts +1 -0
- package/_types/tokens/definitions/cirbtc.d.ts.map +1 -1
- package/_types/tokens/definitions/eurc.d.ts +1 -0
- package/_types/tokens/definitions/eurc.d.ts.map +1 -1
- package/_types/tokens/definitions/usdc.d.ts +1 -0
- package/_types/tokens/definitions/usdc.d.ts.map +1 -1
- package/_types/tokens/sets.d.ts +4 -0
- package/_types/tokens/sets.d.ts.map +1 -1
- package/_types/utils/buildRequest.d.ts.map +1 -1
- package/actions/public/simulateCalls.ts +8 -1
- package/chains/definitions/arc.ts +19 -1
- package/chains/definitions/eCanna.ts +20 -0
- package/chains/definitions/eCannaTestnet.ts +21 -0
- package/chains/definitions/hyveChain.ts +26 -0
- package/chains/definitions/robinhood.ts +5 -1
- package/chains/definitions/zagros.ts +30 -0
- package/chains/index.ts +4 -0
- package/errors/version.ts +1 -1
- package/op-stack/chains.ts +1 -0
- package/package.json +2 -2
- package/tempo/Account.ts +32 -43
- package/tempo/Addresses.ts +3 -0
- package/tempo/Multisig.ts +19 -132
- package/tempo/Transaction.ts +24 -9
- package/tempo/actions/accessKey.ts +4 -3
- package/tempo/chainConfig.ts +3 -42
- package/tempo/multisig/Config.ts +15 -5
- package/tempo/multisig/Signature.ts +11 -0
- package/tokens/definitions/cirbtc.ts +1 -0
- package/tokens/definitions/eurc.ts +1 -0
- package/tokens/definitions/usdc.ts +1 -0
- package/utils/buildRequest.ts +6 -0
package/tempo/Account.ts
CHANGED
|
@@ -24,7 +24,9 @@ import { keccak256 } from '../utils/hash/keccak256.js'
|
|
|
24
24
|
import { hashMessage } from '../utils/signature/hashMessage.js'
|
|
25
25
|
import { hashTypedData } from '../utils/signature/hashTypedData.js'
|
|
26
26
|
import type { SerializeTransactionFn } from '../utils/transaction/serializeTransaction.js'
|
|
27
|
+
import { nativeMultisigFactory } from './Addresses.js'
|
|
27
28
|
import type { KeyAuthorizationManager } from './KeyAuthorizationManager.js'
|
|
29
|
+
import { parseApproval } from './multisig/Signature.js'
|
|
28
30
|
import * as Transaction from './Transaction.js'
|
|
29
31
|
|
|
30
32
|
export type Account_base<source extends string = string> = RequiredBy<
|
|
@@ -284,7 +286,7 @@ export declare namespace fromSecp256k1 {
|
|
|
284
286
|
*
|
|
285
287
|
* Owners can be accounts or addresses directly, or weighted `{ owner, weight }`
|
|
286
288
|
* entries. Direct owners default to weight `1`, and `threshold` defaults to `1`.
|
|
287
|
-
* Local owner accounts are retained for signing,
|
|
289
|
+
* Local owner accounts are retained for signing, using primitive signatures.
|
|
288
290
|
* Configs containing only owner addresses require external approvals through
|
|
289
291
|
* `signatures`.
|
|
290
292
|
*
|
|
@@ -359,11 +361,13 @@ export function fromMultisig(value: fromMultisig.Parameters): MultisigAccount {
|
|
|
359
361
|
(() => {
|
|
360
362
|
if (typeof value === 'string') return value
|
|
361
363
|
if (value.address === undefined || value.address === 'infer')
|
|
362
|
-
return MultisigConfig.getAddress(config
|
|
364
|
+
return MultisigConfig.getAddress(config!, {
|
|
365
|
+
factory: nativeMultisigFactory,
|
|
366
|
+
})
|
|
363
367
|
return value.address
|
|
364
368
|
})(),
|
|
365
369
|
)
|
|
366
|
-
const ownerAccounts = (() => {
|
|
370
|
+
const ownerAccounts: LocalAccount[] = (() => {
|
|
367
371
|
if (!configInput) return []
|
|
368
372
|
return configInput.owners.flatMap((value) => {
|
|
369
373
|
const owner =
|
|
@@ -371,6 +375,12 @@ export function fromMultisig(value: fromMultisig.Parameters): MultisigAccount {
|
|
|
371
375
|
return typeof owner === 'string' ? [] : [parseAccount(owner)]
|
|
372
376
|
})
|
|
373
377
|
})()
|
|
378
|
+
if (
|
|
379
|
+
ownerAccounts.some(
|
|
380
|
+
(owner) => owner.source === 'multisig' || isAccessKeyAccount(owner),
|
|
381
|
+
)
|
|
382
|
+
)
|
|
383
|
+
throw new Error('Multisig owners must use primitive signatures.')
|
|
374
384
|
const owners =
|
|
375
385
|
config?.owners.flatMap(({ owner }) => {
|
|
376
386
|
const account = ownerAccounts.find((account) =>
|
|
@@ -403,7 +413,7 @@ export function fromMultisig(value: fromMultisig.Parameters): MultisigAccount {
|
|
|
403
413
|
throw new Error(
|
|
404
414
|
'A local owner account is required to approve a multisig transaction.',
|
|
405
415
|
)
|
|
406
|
-
if (owner.source !== 'root'
|
|
416
|
+
if (owner.source !== 'root')
|
|
407
417
|
throw new Error(
|
|
408
418
|
'A Tempo owner account is required to approve a multisig transaction.',
|
|
409
419
|
)
|
|
@@ -422,29 +432,16 @@ export function fromMultisig(value: fromMultisig.Parameters): MultisigAccount {
|
|
|
422
432
|
}
|
|
423
433
|
const payload = keccak256(await serializer(presign as never))
|
|
424
434
|
const simulation = request.multisigSimulation
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
if (!simulation)
|
|
429
|
-
throw new Error('A multisig config is required for local signing.')
|
|
430
|
-
const parentConfig = MultisigConfig.from(simulation.config)
|
|
431
|
-
const parentDigest = MultisigConfig.getSignPayload({
|
|
432
|
-
account: requestAccount,
|
|
433
|
-
config: parentConfig,
|
|
434
|
-
payload,
|
|
435
|
-
})
|
|
436
|
-
return SignatureEnvelope.serialize(
|
|
437
|
-
await signMultisig(account, {
|
|
438
|
-
payload: parentDigest,
|
|
439
|
-
}),
|
|
435
|
+
if (request.from && !Address.isEqual(request.from, address))
|
|
436
|
+
throw new Error(
|
|
437
|
+
'Multisig account does not match the transaction sender.',
|
|
440
438
|
)
|
|
441
|
-
}
|
|
442
439
|
|
|
443
440
|
const signature = await signMultisig(account, {
|
|
444
441
|
config: simulation?.config,
|
|
445
442
|
payload,
|
|
446
443
|
signatures: request.signatures?.map((signature) =>
|
|
447
|
-
|
|
444
|
+
parseApproval(signature),
|
|
448
445
|
),
|
|
449
446
|
})
|
|
450
447
|
return (await serializer(
|
|
@@ -494,9 +491,11 @@ export declare namespace fromMultisig {
|
|
|
494
491
|
/** Multisig owner account or address, optionally with an explicit weight. */
|
|
495
492
|
export type Owner =
|
|
496
493
|
| Address.Address
|
|
497
|
-
| LocalAccount
|
|
494
|
+
| (LocalAccount & { accessKeyAddress?: never; owners?: never })
|
|
498
495
|
| (Omit<MultisigConfig.Owner, 'owner'> & {
|
|
499
|
-
owner:
|
|
496
|
+
owner:
|
|
497
|
+
| Address.Address
|
|
498
|
+
| (LocalAccount & { accessKeyAddress?: never; owners?: never })
|
|
500
499
|
})
|
|
501
500
|
|
|
502
501
|
/** Parameters for {@link fromMultisig}. */
|
|
@@ -523,7 +522,7 @@ async function signMultisig(
|
|
|
523
522
|
parameters: {
|
|
524
523
|
config?: MultisigConfig.Config | undefined
|
|
525
524
|
payload: Hex.Hex
|
|
526
|
-
signatures?: readonly SignatureEnvelope.
|
|
525
|
+
signatures?: readonly SignatureEnvelope.Primitive[] | undefined
|
|
527
526
|
},
|
|
528
527
|
): Promise<SignatureEnvelope.Multisig> {
|
|
529
528
|
const { config, payload, signatures: providedSignatures = [] } = parameters
|
|
@@ -558,6 +557,7 @@ async function signMultisig(
|
|
|
558
557
|
a.owner.toLowerCase().localeCompare(b.owner.toLowerCase()),
|
|
559
558
|
)
|
|
560
559
|
for (const owner of owners) {
|
|
560
|
+
if (weight >= Number(currentConfig.threshold)) break
|
|
561
561
|
const address = owner.owner.toLowerCase() as Address.Address
|
|
562
562
|
if (signedOwners.has(address)) continue
|
|
563
563
|
const ownerAccount = account.owners.find((account) =>
|
|
@@ -565,19 +565,9 @@ async function signMultisig(
|
|
|
565
565
|
)
|
|
566
566
|
if (!ownerAccount) continue
|
|
567
567
|
|
|
568
|
-
if (
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
payload: digest,
|
|
572
|
-
}),
|
|
573
|
-
)
|
|
574
|
-
} else {
|
|
575
|
-
if (!ownerAccount.sign)
|
|
576
|
-
throw new Error('Multisig owner account cannot sign.')
|
|
577
|
-
signatures.push(
|
|
578
|
-
SignatureEnvelope.from(await ownerAccount.sign({ hash: digest })),
|
|
579
|
-
)
|
|
580
|
-
}
|
|
568
|
+
if (!ownerAccount.sign)
|
|
569
|
+
throw new Error('Multisig owner account cannot sign.')
|
|
570
|
+
signatures.push(parseApproval(await ownerAccount.sign({ hash: digest })))
|
|
581
571
|
|
|
582
572
|
signedOwners.add(address)
|
|
583
573
|
weight += Number(owner.weight)
|
|
@@ -856,9 +846,7 @@ export async function signKeyAuthorization(
|
|
|
856
846
|
await signMultisig(account, {
|
|
857
847
|
config: multisigState.config,
|
|
858
848
|
payload: hash,
|
|
859
|
-
signatures: signatures?.map((signature) =>
|
|
860
|
-
SignatureEnvelope.from(signature),
|
|
861
|
-
),
|
|
849
|
+
signatures: signatures?.map((signature) => parseApproval(signature)),
|
|
862
850
|
}),
|
|
863
851
|
)
|
|
864
852
|
}
|
|
@@ -982,16 +970,17 @@ function fromBase(parameters: fromBase.Parameters): Account_base {
|
|
|
982
970
|
// primitive signature over the multisig owner approval digest, instead of
|
|
983
971
|
// a full serialized transaction. Approvals are combined later in
|
|
984
972
|
// `sendTransaction({ signatures })`.
|
|
985
|
-
const { multisigSimulation } = transaction as {
|
|
973
|
+
const { multisigSimulation, from } = transaction as {
|
|
974
|
+
from?: Address.Address
|
|
986
975
|
multisigSimulation?: {
|
|
987
|
-
account: Address.Address
|
|
988
976
|
config: MultisigConfig.Config
|
|
989
977
|
}
|
|
990
978
|
}
|
|
991
979
|
if (multisigSimulation) {
|
|
980
|
+
if (!from) throw new Error('A multisig sender is required for signing.')
|
|
992
981
|
const config = MultisigConfig.from(multisigSimulation.config)
|
|
993
982
|
const digest = MultisigConfig.getSignPayload({
|
|
994
|
-
account:
|
|
983
|
+
account: from,
|
|
995
984
|
config,
|
|
996
985
|
payload,
|
|
997
986
|
})
|
package/tempo/Addresses.ts
CHANGED
|
@@ -14,6 +14,9 @@ export const accountRegistrar = '0x7702ac0000000000000000000000000000000000'
|
|
|
14
14
|
export const addressRegistry = '0xfdc0000000000000000000000000000000000000'
|
|
15
15
|
export const feeManager = '0xfeec000000000000000000000000000000000000'
|
|
16
16
|
export const nativeMultisig = '0xAACC000000000000000000000000000000000000'
|
|
17
|
+
/** Temporary recovery factory until the production address is finalized. */
|
|
18
|
+
export const nativeMultisigFactory =
|
|
19
|
+
'0x7171717171717171717171717171717171717171'
|
|
17
20
|
export const nonceManager = '0x4e4F4E4345000000000000000000000000000000'
|
|
18
21
|
export const pathUsd = '0x20c0000000000000000000000000000000000000'
|
|
19
22
|
export const receivePolicyGuard = '0xB10C000000000000000000000000000000000000'
|
package/tempo/Multisig.ts
CHANGED
|
@@ -140,13 +140,12 @@ export function handleRequest(
|
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
if (operation.status === 'pending')
|
|
143
|
-
return await toTransaction(client, operation
|
|
143
|
+
return await toTransaction(client, operation)
|
|
144
144
|
const transactionHash = await getSubmittedTransactionHash(
|
|
145
145
|
parameters.store,
|
|
146
146
|
operation,
|
|
147
147
|
)
|
|
148
|
-
if (!transactionHash)
|
|
149
|
-
return await toTransaction(client, operation, parameters.store)
|
|
148
|
+
if (!transactionHash) return await toTransaction(client, operation)
|
|
150
149
|
const transaction = await next(
|
|
151
150
|
{
|
|
152
151
|
...request,
|
|
@@ -155,7 +154,7 @@ export function handleRequest(
|
|
|
155
154
|
requestOptions,
|
|
156
155
|
)
|
|
157
156
|
if (!transaction || typeof transaction !== 'object')
|
|
158
|
-
return await toTransaction(client, operation
|
|
157
|
+
return await toTransaction(client, operation)
|
|
159
158
|
const success =
|
|
160
159
|
operation.status === 'submitting'
|
|
161
160
|
? await completeSubmission(
|
|
@@ -306,23 +305,16 @@ async function submit(options: submit.Options) {
|
|
|
306
305
|
const existingApprovals = existing
|
|
307
306
|
? await selectApprovals({
|
|
308
307
|
account: signature.account,
|
|
309
|
-
client: options.client,
|
|
310
308
|
config,
|
|
311
|
-
discardInvalidNested: true,
|
|
312
309
|
hash: operationHash,
|
|
313
310
|
approvals: existing.approvals,
|
|
314
|
-
blockNumber,
|
|
315
|
-
store: options.store,
|
|
316
311
|
})
|
|
317
312
|
: undefined
|
|
318
313
|
const approvals = await selectApprovals({
|
|
319
314
|
account: signature.account,
|
|
320
|
-
client: options.client,
|
|
321
315
|
config,
|
|
322
316
|
hash: operationHash,
|
|
323
317
|
approvals: [...(existingApprovals?.approvals ?? []), ...incoming],
|
|
324
|
-
blockNumber,
|
|
325
|
-
store: options.store,
|
|
326
318
|
})
|
|
327
319
|
return MultisigOperation.from({
|
|
328
320
|
account: signature.account,
|
|
@@ -427,12 +419,9 @@ async function submit(options: submit.Options) {
|
|
|
427
419
|
})
|
|
428
420
|
const finalApprovals = await selectApprovals({
|
|
429
421
|
account: claim.account,
|
|
430
|
-
blockNumber,
|
|
431
|
-
client: options.client,
|
|
432
422
|
config: claim.config,
|
|
433
423
|
hash: claim.hash,
|
|
434
424
|
approvals: claim.approvals,
|
|
435
|
-
store: options.store,
|
|
436
425
|
})
|
|
437
426
|
const final = MultisigOperation.serializeTransaction(claim, {
|
|
438
427
|
approvals: finalApprovals.selectedApprovals,
|
|
@@ -703,12 +692,8 @@ async function approveKeyAuthorization(
|
|
|
703
692
|
? await selectApprovals({
|
|
704
693
|
account: approval.account,
|
|
705
694
|
approvals: existing.approvals,
|
|
706
|
-
blockNumber,
|
|
707
|
-
client: options.client,
|
|
708
695
|
config: approval.config,
|
|
709
|
-
discardInvalidNested: true,
|
|
710
696
|
hash: approval.hash,
|
|
711
|
-
store: options.store,
|
|
712
697
|
})
|
|
713
698
|
: undefined
|
|
714
699
|
const approvals = await selectApprovals({
|
|
@@ -717,11 +702,8 @@ async function approveKeyAuthorization(
|
|
|
717
702
|
...(existingApprovals?.approvals ?? []),
|
|
718
703
|
...approval.approvals,
|
|
719
704
|
],
|
|
720
|
-
blockNumber,
|
|
721
|
-
client: options.client,
|
|
722
705
|
config: approval.config,
|
|
723
706
|
hash: approval.hash,
|
|
724
|
-
store: options.store,
|
|
725
707
|
})
|
|
726
708
|
if (
|
|
727
709
|
existing &&
|
|
@@ -804,16 +786,18 @@ function assertConfig(options: {
|
|
|
804
786
|
const { account, commitment, config } = options
|
|
805
787
|
if (
|
|
806
788
|
config.version === 0n &&
|
|
807
|
-
MultisigConfig.getAddress(config
|
|
789
|
+
MultisigConfig.getAddress(config, {
|
|
790
|
+
factory: Addresses.nativeMultisigFactory,
|
|
791
|
+
}).toLowerCase() !== account.toLowerCase()
|
|
808
792
|
)
|
|
809
793
|
throw new RpcResponse.InvalidParamsError({
|
|
810
794
|
message: 'Initial multisig config does not match the multisig account.',
|
|
811
795
|
})
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
796
|
+
if (config.version === 0n && Hex.toBigInt(commitment) === 0n) return
|
|
797
|
+
if (
|
|
798
|
+
commitment.toLowerCase() !==
|
|
799
|
+
MultisigConfig.getCommitment(config).toLowerCase()
|
|
800
|
+
)
|
|
817
801
|
throw new RpcResponse.InvalidParamsError({
|
|
818
802
|
message: `Multisig config does not match account ${account}.`,
|
|
819
803
|
})
|
|
@@ -904,82 +888,12 @@ declare namespace cacheNextConfigs {
|
|
|
904
888
|
}
|
|
905
889
|
}
|
|
906
890
|
|
|
907
|
-
/**
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
let validationCount = 0
|
|
912
|
-
const select = async (approvals: readonly SignatureEnvelope.Serialized[]) => {
|
|
913
|
-
const result = await MultisigOperation.selectApprovals({
|
|
914
|
-
account: options.account,
|
|
915
|
-
approvals,
|
|
916
|
-
config: options.config,
|
|
917
|
-
hash: options.hash,
|
|
918
|
-
})
|
|
919
|
-
const configs = new Map<
|
|
920
|
-
string,
|
|
921
|
-
{ account: Address; config: MultisigConfig.Config }
|
|
922
|
-
>()
|
|
923
|
-
const visit = (signature: SignatureEnvelope.SignatureEnvelope) => {
|
|
924
|
-
if (signature.type !== 'multisig') return
|
|
925
|
-
const config = MultisigConfig.from(signature.config)
|
|
926
|
-
const key = signature.account.toLowerCase()
|
|
927
|
-
configs.set(key, { account: signature.account, config })
|
|
928
|
-
for (const approval of signature.signatures) visit(approval)
|
|
929
|
-
}
|
|
930
|
-
for (const approval of result.approvals)
|
|
931
|
-
visit(SignatureEnvelope.from(approval))
|
|
932
|
-
|
|
933
|
-
for (const { account, config } of configs.values()) {
|
|
934
|
-
const key = `${account.toLowerCase()}:${MultisigConfig.getCommitment(config)}`
|
|
935
|
-
const pending = (() => {
|
|
936
|
-
const existing = validation.get(key)
|
|
937
|
-
if (existing) return existing
|
|
938
|
-
validationCount++
|
|
939
|
-
if (validationCount > MultisigConfig.maxOwners)
|
|
940
|
-
throw new RpcResponse.InvalidParamsError({
|
|
941
|
-
message: 'Multisig approval validation exceeds the owner limit.',
|
|
942
|
-
})
|
|
943
|
-
const pending = validateConfig({
|
|
944
|
-
account,
|
|
945
|
-
blockNumber: options.blockNumber,
|
|
946
|
-
client: options.client,
|
|
947
|
-
config,
|
|
948
|
-
})
|
|
949
|
-
validation.set(key, pending)
|
|
950
|
-
return pending
|
|
951
|
-
})()
|
|
952
|
-
const commitment = await pending
|
|
953
|
-
await ConfigStore.write(options.store, {
|
|
954
|
-
address: account,
|
|
955
|
-
commitment,
|
|
956
|
-
config,
|
|
957
|
-
})
|
|
958
|
-
}
|
|
959
|
-
return result
|
|
960
|
-
}
|
|
891
|
+
/** Validates primitive approvals and translates invalid input into an RPC error. */
|
|
892
|
+
async function selectApprovals(
|
|
893
|
+
options: MultisigOperation.selectApprovals.Options,
|
|
894
|
+
) {
|
|
961
895
|
try {
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
const approvals: SignatureEnvelope.Serialized[] = []
|
|
965
|
-
for (const approval of options.approvals) {
|
|
966
|
-
if (SignatureEnvelope.from(approval).type !== 'multisig') {
|
|
967
|
-
approvals.push(approval)
|
|
968
|
-
continue
|
|
969
|
-
}
|
|
970
|
-
try {
|
|
971
|
-
const retained = (await select([approval])).approvals[0]
|
|
972
|
-
if (retained) approvals.push(retained)
|
|
973
|
-
} catch (error) {
|
|
974
|
-
if (
|
|
975
|
-
error instanceof MultisigOperation.InvalidApprovalError ||
|
|
976
|
-
error instanceof RpcResponse.InvalidParamsError
|
|
977
|
-
)
|
|
978
|
-
continue
|
|
979
|
-
throw error
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
return await select(approvals)
|
|
896
|
+
return await MultisigOperation.selectApprovals(options)
|
|
983
897
|
} catch (error) {
|
|
984
898
|
if (error instanceof MultisigOperation.InvalidApprovalError)
|
|
985
899
|
throw new RpcResponse.InvalidParamsError({ message: error.shortMessage })
|
|
@@ -987,20 +901,6 @@ async function selectApprovals(options: selectApprovals.Options) {
|
|
|
987
901
|
}
|
|
988
902
|
}
|
|
989
903
|
|
|
990
|
-
declare namespace selectApprovals {
|
|
991
|
-
/** Options for {@link selectApprovals}. */
|
|
992
|
-
export type Options = MultisigOperation.selectApprovals.Options & {
|
|
993
|
-
/** Block used to validate every config. */
|
|
994
|
-
blockNumber: bigint
|
|
995
|
-
/** Client used to validate nested multisig configurations. */
|
|
996
|
-
client: ReturnType<typeof createClient>
|
|
997
|
-
/** Discards stored nested approvals invalidated by a child configuration change. */
|
|
998
|
-
discardInvalidNested?: boolean | undefined
|
|
999
|
-
/** Shared multisig store. */
|
|
1000
|
-
store: Store.Store
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
904
|
/** Returns an existing successful operation through the requested send method. */
|
|
1005
905
|
async function submittedResult(
|
|
1006
906
|
options: submit.Options,
|
|
@@ -1186,7 +1086,6 @@ function mergeTransaction(existing: Hex.Hex | undefined, incoming: Hex.Hex) {
|
|
|
1186
1086
|
async function toTransaction(
|
|
1187
1087
|
client: ReturnType<typeof createClient>,
|
|
1188
1088
|
operation: MultisigOperation.TransactionOperation,
|
|
1189
|
-
store: Store.Store,
|
|
1190
1089
|
) {
|
|
1191
1090
|
const approvals = await (async () => {
|
|
1192
1091
|
if (operation.status !== 'pending')
|
|
@@ -1206,12 +1105,8 @@ async function toTransaction(
|
|
|
1206
1105
|
return await selectApprovals({
|
|
1207
1106
|
account: operation.account,
|
|
1208
1107
|
approvals: operation.approvals,
|
|
1209
|
-
blockNumber,
|
|
1210
|
-
client,
|
|
1211
1108
|
config: operation.config,
|
|
1212
|
-
discardInvalidNested: true,
|
|
1213
1109
|
hash: operation.hash,
|
|
1214
|
-
store,
|
|
1215
1110
|
})
|
|
1216
1111
|
})()
|
|
1217
1112
|
const current =
|
|
@@ -1224,17 +1119,9 @@ async function toTransaction(
|
|
|
1224
1119
|
weight: approvals.weight,
|
|
1225
1120
|
})
|
|
1226
1121
|
: operation
|
|
1227
|
-
const serialized = MultisigOperation.serializeTransaction(
|
|
1228
|
-
approvals
|
|
1229
|
-
|
|
1230
|
-
// Keep one stored approval in the synthetic envelope when every nested
|
|
1231
|
-
// approval became stale. The next submission replaces it before broadcast.
|
|
1232
|
-
approvals:
|
|
1233
|
-
approvals.selectedApprovals.length > 0
|
|
1234
|
-
? approvals.selectedApprovals
|
|
1235
|
-
: operation.approvals.slice(0, 1),
|
|
1236
|
-
},
|
|
1237
|
-
)
|
|
1122
|
+
const serialized = MultisigOperation.serializeTransaction(current, {
|
|
1123
|
+
approvals: approvals.selectedApprovals,
|
|
1124
|
+
})
|
|
1238
1125
|
const transaction = deserialize(serialized)
|
|
1239
1126
|
return {
|
|
1240
1127
|
...ox_Transaction.toRpc(
|
package/tempo/Transaction.ts
CHANGED
|
@@ -42,7 +42,8 @@ import {
|
|
|
42
42
|
parseTransaction as viem_parseTransaction,
|
|
43
43
|
} from '../utils/transaction/parseTransaction.js'
|
|
44
44
|
import { serializeTransaction as viem_serializeTransaction } from '../utils/transaction/serializeTransaction.js'
|
|
45
|
-
import type {
|
|
45
|
+
import type { RootAccount } from './Account.js'
|
|
46
|
+
import { parseApproval } from './multisig/Signature.js'
|
|
46
47
|
|
|
47
48
|
export type Transaction<
|
|
48
49
|
bigintType = bigint,
|
|
@@ -135,7 +136,7 @@ export type TransactionRequestTempo<
|
|
|
135
136
|
keyAuthorization?: KeyAuthorization.Signed<quantity, index> | undefined
|
|
136
137
|
multisigSimulation?: MultisigSimulation.Spec | undefined
|
|
137
138
|
nonceKey?: 'expiring' | quantity | undefined
|
|
138
|
-
owner?:
|
|
139
|
+
owner?: RootAccount | undefined
|
|
139
140
|
signatures?: readonly SignatureEnvelope.Serialized[] | undefined
|
|
140
141
|
validBefore?: index | undefined
|
|
141
142
|
validAfter?: index | undefined
|
|
@@ -155,17 +156,30 @@ export type TransactionSerializableTempo<
|
|
|
155
156
|
chainId: number
|
|
156
157
|
feeToken?: Address | bigint | undefined
|
|
157
158
|
feePayerSignature?: viem_Signature | null | undefined
|
|
158
|
-
from?: Address | undefined
|
|
159
159
|
keyAuthorization?: KeyAuthorization.Signed<quantity, index> | undefined
|
|
160
|
-
multisigSimulation?: MultisigSimulation.Spec | undefined
|
|
161
160
|
nonceKey?: quantity | undefined
|
|
162
|
-
owner?:
|
|
161
|
+
owner?: RootAccount | undefined
|
|
163
162
|
signature?: SignatureEnvelope.SignatureEnvelope<quantity, index> | undefined
|
|
164
|
-
signatures?: readonly SignatureEnvelope.Serialized[] | undefined
|
|
165
163
|
validBefore?: index | undefined
|
|
166
164
|
validAfter?: index | undefined
|
|
167
165
|
type?: 'tempo' | undefined
|
|
168
|
-
}
|
|
166
|
+
} & (
|
|
167
|
+
| {
|
|
168
|
+
from: Address
|
|
169
|
+
multisigSimulation?: MultisigSimulation.Spec | undefined
|
|
170
|
+
signatures?: readonly SignatureEnvelope.Serialized[] | undefined
|
|
171
|
+
}
|
|
172
|
+
| {
|
|
173
|
+
from?: Address | undefined
|
|
174
|
+
multisigSimulation?: undefined
|
|
175
|
+
signatures?: readonly SignatureEnvelope.Serialized[] | undefined
|
|
176
|
+
}
|
|
177
|
+
| {
|
|
178
|
+
from?: Address | undefined
|
|
179
|
+
multisigSimulation?: MultisigSimulation.Spec | undefined
|
|
180
|
+
signatures?: undefined
|
|
181
|
+
}
|
|
182
|
+
)
|
|
169
183
|
|
|
170
184
|
export type TransactionSerialized<
|
|
171
185
|
type extends TransactionType = TransactionType,
|
|
@@ -381,10 +395,11 @@ async function serializeTempo(
|
|
|
381
395
|
|
|
382
396
|
const payload = TxTempo.getSignPayload(TxTempo.from(transaction_sender_ox))
|
|
383
397
|
const signatures = transaction.signatures.map((approval) =>
|
|
384
|
-
|
|
398
|
+
parseApproval(approval),
|
|
385
399
|
)
|
|
386
400
|
const config = MultisigConfig.from(multisigSimulation.config)
|
|
387
|
-
const account =
|
|
401
|
+
const account = transaction.from
|
|
402
|
+
if (!account) throw new Error('A multisig sender is required for signing.')
|
|
388
403
|
const sorted = SignatureEnvelope.sortMultisigApprovals({
|
|
389
404
|
account,
|
|
390
405
|
config,
|
|
@@ -48,6 +48,7 @@ import type {
|
|
|
48
48
|
WriteParameters,
|
|
49
49
|
} from '../internal/types.js'
|
|
50
50
|
import { defineCall } from '../internal/utils.js'
|
|
51
|
+
import { parseApproval } from '../multisig/Signature.js'
|
|
51
52
|
import type { TransactionReceipt } from '../Transaction.js'
|
|
52
53
|
import { getConfig } from './multisig.js'
|
|
53
54
|
|
|
@@ -1240,7 +1241,7 @@ export async function signAuthorization<
|
|
|
1240
1241
|
signature: SignatureEnvelope.from({
|
|
1241
1242
|
account: account.address,
|
|
1242
1243
|
config,
|
|
1243
|
-
signatures: [
|
|
1244
|
+
signatures: [parseApproval(signature)],
|
|
1244
1245
|
}),
|
|
1245
1246
|
type,
|
|
1246
1247
|
...(witness ? { witness } : {}),
|
|
@@ -1323,7 +1324,7 @@ export namespace signAuthorization {
|
|
|
1323
1324
|
/** Multisig account being authorized. */
|
|
1324
1325
|
account: Address | MultisigAccount
|
|
1325
1326
|
/** Local owner that approves the authorization. */
|
|
1326
|
-
owner: RootAccount
|
|
1327
|
+
owner: RootAccount
|
|
1327
1328
|
}
|
|
1328
1329
|
|
|
1329
1330
|
/** Coordinated key authorization parameters. */
|
|
@@ -1333,7 +1334,7 @@ export namespace signAuthorization {
|
|
|
1333
1334
|
/** Stored multisig operation hash. */
|
|
1334
1335
|
hash: Hex
|
|
1335
1336
|
/** Local owner that approves the authorization. */
|
|
1336
|
-
owner: RootAccount
|
|
1337
|
+
owner: RootAccount
|
|
1337
1338
|
}
|
|
1338
1339
|
>
|
|
1339
1340
|
|
package/tempo/chainConfig.ts
CHANGED
|
@@ -85,10 +85,7 @@ export const chainConfig = {
|
|
|
85
85
|
throw new Error(
|
|
86
86
|
'A local owner account is required to approve a stored multisig transaction.',
|
|
87
87
|
)
|
|
88
|
-
if (
|
|
89
|
-
request.owner.source !== 'root' &&
|
|
90
|
-
request.owner.source !== 'multisig'
|
|
91
|
-
)
|
|
88
|
+
if (request.owner.source !== 'root')
|
|
92
89
|
throw new Error(
|
|
93
90
|
'A Tempo owner account is required to approve a stored multisig transaction.',
|
|
94
91
|
)
|
|
@@ -125,7 +122,6 @@ export const chainConfig = {
|
|
|
125
122
|
account: request.account,
|
|
126
123
|
from: operation.account,
|
|
127
124
|
multisigSimulation: getMultisigSimulation({
|
|
128
|
-
account: operation.account,
|
|
129
125
|
config: operation.config,
|
|
130
126
|
local: request.account,
|
|
131
127
|
}),
|
|
@@ -168,11 +164,7 @@ export const chainConfig = {
|
|
|
168
164
|
throw new Error(
|
|
169
165
|
'A local owner account is required to approve a multisig transaction.',
|
|
170
166
|
)
|
|
171
|
-
if (
|
|
172
|
-
request.owner &&
|
|
173
|
-
request.owner.source !== 'root' &&
|
|
174
|
-
request.owner.source !== 'multisig'
|
|
175
|
-
)
|
|
167
|
+
if (request.owner && request.owner.source !== 'root')
|
|
176
168
|
throw new Error(
|
|
177
169
|
'A Tempo owner account is required to approve a multisig transaction.',
|
|
178
170
|
)
|
|
@@ -206,7 +198,6 @@ export const chainConfig = {
|
|
|
206
198
|
)
|
|
207
199
|
request.from = account
|
|
208
200
|
request.multisigSimulation = getMultisigSimulation({
|
|
209
|
-
account,
|
|
210
201
|
config,
|
|
211
202
|
local,
|
|
212
203
|
})
|
|
@@ -409,48 +400,18 @@ export type ChainConfig = typeof chainConfig
|
|
|
409
400
|
|
|
410
401
|
/** Builds a bounded multisig spec for gas simulation. */
|
|
411
402
|
function getMultisigSimulation(options: {
|
|
412
|
-
account: Address
|
|
413
403
|
config: MultisigConfig.Config
|
|
414
404
|
local?: MultisigAccount | undefined
|
|
415
405
|
}): MultisigSimulation.Spec {
|
|
416
|
-
const {
|
|
406
|
+
const { config, local } = options
|
|
417
407
|
return {
|
|
418
|
-
account,
|
|
419
408
|
approvals: selectOwners(config).map((owner) => {
|
|
420
409
|
const localOwner = local?.owners.find((account) =>
|
|
421
410
|
isAddressEqual(account.address, owner.owner),
|
|
422
411
|
)
|
|
423
|
-
if (localOwner?.source === 'multisig') {
|
|
424
|
-
const nested = localOwner as MultisigAccount
|
|
425
|
-
if (!nested.config)
|
|
426
|
-
throw new Error(
|
|
427
|
-
'A nested multisig config is required for gas estimation.',
|
|
428
|
-
)
|
|
429
|
-
return {
|
|
430
|
-
type: 'multisig',
|
|
431
|
-
spec: {
|
|
432
|
-
account: nested.address,
|
|
433
|
-
approvals: selectOwners(nested.config).map((owner) => {
|
|
434
|
-
const nestedOwner = nested.owners.find((account) =>
|
|
435
|
-
isAddressEqual(account.address, owner.owner),
|
|
436
|
-
)
|
|
437
|
-
if (nestedOwner?.source === 'multisig')
|
|
438
|
-
throw new Error(
|
|
439
|
-
'Multisig simulation nesting exceeds depth two.',
|
|
440
|
-
)
|
|
441
|
-
return {
|
|
442
|
-
...getSimulationKey(nestedOwner),
|
|
443
|
-
owner: owner.owner,
|
|
444
|
-
}
|
|
445
|
-
}),
|
|
446
|
-
config: nested.config,
|
|
447
|
-
},
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
412
|
return {
|
|
451
413
|
...getSimulationKey(localOwner),
|
|
452
414
|
owner: owner.owner,
|
|
453
|
-
type: 'primitive',
|
|
454
415
|
}
|
|
455
416
|
}),
|
|
456
417
|
config,
|
package/tempo/multisig/Config.ts
CHANGED
|
@@ -4,12 +4,13 @@ import type * as Hex from 'ox/Hex'
|
|
|
4
4
|
import * as Json from 'ox/Json'
|
|
5
5
|
import { MultisigConfig } from 'ox/tempo'
|
|
6
6
|
import { BaseError } from '../../errors/base.js'
|
|
7
|
+
import { nativeMultisigFactory } from '../Addresses.js'
|
|
7
8
|
import type * as Store from '../Store.js'
|
|
8
9
|
|
|
9
10
|
/** A valid 48-owner config is much smaller; 64 KiB bounds hostile store parsing work. */
|
|
10
11
|
const maxStoredValueLength = 65_536
|
|
11
12
|
|
|
12
|
-
/** Zero commitment used before an account
|
|
13
|
+
/** Zero commitment used before an account is initialized. */
|
|
13
14
|
const zeroCommitment = `0x${'00'.repeat(32)}` as const
|
|
14
15
|
|
|
15
16
|
/** Reads a cached multisig config. */
|
|
@@ -43,7 +44,14 @@ export async function write(
|
|
|
43
44
|
const { address, commitment } = options
|
|
44
45
|
const config = MultisigConfig.from(options.config)
|
|
45
46
|
assertKey({ address, commitment, config })
|
|
46
|
-
|
|
47
|
+
const value = serialize(config)
|
|
48
|
+
await store.setItem(key({ address, commitment }), value)
|
|
49
|
+
// Initialization commits the version-zero config without changing its version.
|
|
50
|
+
if (commitment.toLowerCase() === zeroCommitment)
|
|
51
|
+
await store.setItem(
|
|
52
|
+
key({ address, commitment: MultisigConfig.getCommitment(config) }),
|
|
53
|
+
value,
|
|
54
|
+
)
|
|
47
55
|
}
|
|
48
56
|
|
|
49
57
|
export declare namespace write {
|
|
@@ -69,11 +77,13 @@ function assertKey(options: {
|
|
|
69
77
|
throw new InvalidStoreValueError()
|
|
70
78
|
if (config.version === 0n) {
|
|
71
79
|
if (
|
|
72
|
-
|
|
73
|
-
|
|
80
|
+
!Address.isEqual(
|
|
81
|
+
MultisigConfig.getAddress(config, { factory: nativeMultisigFactory }),
|
|
82
|
+
address,
|
|
83
|
+
)
|
|
74
84
|
)
|
|
75
85
|
throw new InvalidStoreValueError()
|
|
76
|
-
return
|
|
86
|
+
if (commitment.toLowerCase() === zeroCommitment) return
|
|
77
87
|
}
|
|
78
88
|
if (
|
|
79
89
|
MultisigConfig.getCommitment(config).toLowerCase() !==
|