viem 2.55.17 → 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 +16 -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/earn.js +12 -4
- package/_cjs/tempo/actions/earn.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/actions/zone.js +16 -16
- package/_cjs/tempo/actions/zone.js.map +1 -1
- 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/_cjs/tempo/zones/Abis.js +2 -2
- package/_cjs/tempo/zones/Abis.js.map +1 -1
- 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/earn.js +14 -6
- package/_esm/tempo/actions/earn.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/actions/zone.js +17 -17
- package/_esm/tempo/actions/zone.js.map +1 -1
- 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/_esm/tempo/zones/Abis.js +2 -2
- package/_esm/tempo/zones/Abis.js.map +1 -1
- 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 +34 -2
- 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/earn.d.ts +5 -5
- package/_types/tempo/actions/earn.d.ts.map +1 -1
- package/_types/tempo/actions/index.d.ts +1 -0
- package/_types/tempo/actions/index.d.ts.map +1 -1
- package/_types/tempo/actions/multisig.d.ts +472 -0
- package/_types/tempo/actions/multisig.d.ts.map +1 -0
- package/_types/tempo/actions/zone.d.ts +17 -17
- package/_types/tempo/actions/zone.d.ts.map +1 -1
- 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/Abis.d.ts +2 -2
- 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 +52 -2
- 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/earn.ts +19 -11
- package/tempo/actions/index.ts +1 -0
- package/tempo/actions/multisig.ts +356 -0
- package/tempo/actions/zone.ts +35 -31
- package/tempo/chainConfig.ts +82 -35
- package/tempo/internal/multisig.ts +72 -0
- package/tempo/zones/Abis.ts +2 -2
package/tempo/Abis.ts
CHANGED
|
@@ -443,6 +443,107 @@ export const addressRegistry = [
|
|
|
443
443
|
{ name: 'VirtualAddressUnregistered', type: 'error', inputs: [] },
|
|
444
444
|
] as const
|
|
445
445
|
|
|
446
|
+
export const nativeMultisig = [
|
|
447
|
+
{
|
|
448
|
+
name: 'deriveAccount',
|
|
449
|
+
type: 'function',
|
|
450
|
+
stateMutability: 'pure',
|
|
451
|
+
inputs: [
|
|
452
|
+
{ type: 'bytes32', name: 'salt' },
|
|
453
|
+
{ type: 'uint8', name: 'threshold' },
|
|
454
|
+
{
|
|
455
|
+
type: 'tuple[]',
|
|
456
|
+
name: 'owners',
|
|
457
|
+
components: [
|
|
458
|
+
{ type: 'address', name: 'owner' },
|
|
459
|
+
{ type: 'uint8', name: 'weight' },
|
|
460
|
+
],
|
|
461
|
+
},
|
|
462
|
+
],
|
|
463
|
+
outputs: [{ type: 'address', name: 'account' }],
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
name: 'isMultisigAccount',
|
|
467
|
+
type: 'function',
|
|
468
|
+
stateMutability: 'view',
|
|
469
|
+
inputs: [{ type: 'address', name: 'account' }],
|
|
470
|
+
outputs: [{ type: 'bool' }],
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
name: 'getConfig',
|
|
474
|
+
type: 'function',
|
|
475
|
+
stateMutability: 'view',
|
|
476
|
+
inputs: [{ type: 'address', name: 'account' }],
|
|
477
|
+
outputs: [
|
|
478
|
+
{
|
|
479
|
+
type: 'tuple',
|
|
480
|
+
components: [
|
|
481
|
+
{ type: 'uint64', name: 'version' },
|
|
482
|
+
{ type: 'uint8', name: 'threshold' },
|
|
483
|
+
{
|
|
484
|
+
type: 'tuple[]',
|
|
485
|
+
name: 'owners',
|
|
486
|
+
components: [
|
|
487
|
+
{ type: 'address', name: 'owner' },
|
|
488
|
+
{ type: 'uint8', name: 'weight' },
|
|
489
|
+
],
|
|
490
|
+
},
|
|
491
|
+
],
|
|
492
|
+
},
|
|
493
|
+
],
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
name: 'updateConfig',
|
|
497
|
+
type: 'function',
|
|
498
|
+
stateMutability: 'nonpayable',
|
|
499
|
+
inputs: [
|
|
500
|
+
{ type: 'uint8', name: 'threshold' },
|
|
501
|
+
{
|
|
502
|
+
type: 'tuple[]',
|
|
503
|
+
name: 'owners',
|
|
504
|
+
components: [
|
|
505
|
+
{ type: 'address', name: 'owner' },
|
|
506
|
+
{ type: 'uint8', name: 'weight' },
|
|
507
|
+
],
|
|
508
|
+
},
|
|
509
|
+
],
|
|
510
|
+
outputs: [],
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
name: 'MultisigInitialized',
|
|
514
|
+
type: 'event',
|
|
515
|
+
inputs: [{ type: 'address', name: 'account', indexed: true }],
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
name: 'MultisigConfigUpdated',
|
|
519
|
+
type: 'event',
|
|
520
|
+
inputs: [
|
|
521
|
+
{ type: 'address', name: 'account', indexed: true },
|
|
522
|
+
{ type: 'uint8', name: 'threshold' },
|
|
523
|
+
{
|
|
524
|
+
type: 'tuple[]',
|
|
525
|
+
name: 'owners',
|
|
526
|
+
components: [
|
|
527
|
+
{ type: 'address', name: 'owner' },
|
|
528
|
+
{ type: 'uint8', name: 'weight' },
|
|
529
|
+
],
|
|
530
|
+
},
|
|
531
|
+
],
|
|
532
|
+
},
|
|
533
|
+
{ name: 'NotMultisigAccount', type: 'error', inputs: [] },
|
|
534
|
+
{ name: 'InvalidAccount', type: 'error', inputs: [] },
|
|
535
|
+
{ name: 'InvalidConfig', type: 'error', inputs: [] },
|
|
536
|
+
{ name: 'InvalidThreshold', type: 'error', inputs: [] },
|
|
537
|
+
{ name: 'InvalidOwner', type: 'error', inputs: [] },
|
|
538
|
+
{ name: 'InvalidWeight', type: 'error', inputs: [] },
|
|
539
|
+
{ name: 'TooManyOwners', type: 'error', inputs: [] },
|
|
540
|
+
{ name: 'DuplicateOwner', type: 'error', inputs: [] },
|
|
541
|
+
{ name: 'InvalidOwnerOrder', type: 'error', inputs: [] },
|
|
542
|
+
{ name: 'AccountAlreadyInitialized', type: 'error', inputs: [] },
|
|
543
|
+
{ name: 'UnauthorizedCaller', type: 'error', inputs: [] },
|
|
544
|
+
{ name: 'SameTransactionUpdateNotAllowed', type: 'error', inputs: [] },
|
|
545
|
+
] as const
|
|
546
|
+
|
|
446
547
|
export const nonce = [
|
|
447
548
|
{
|
|
448
549
|
name: 'getNonce',
|
|
@@ -2975,6 +3076,7 @@ export const validatorConfigV2 = [
|
|
|
2975
3076
|
export const abis = [
|
|
2976
3077
|
...accountKeychain,
|
|
2977
3078
|
...addressRegistry,
|
|
3079
|
+
...nativeMultisig,
|
|
2978
3080
|
...nonce,
|
|
2979
3081
|
...receivePolicyGuard,
|
|
2980
3082
|
...signatureVerifier,
|
package/tempo/Account.ts
CHANGED
|
@@ -275,16 +275,17 @@ export declare namespace fromSecp256k1 {
|
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
/**
|
|
278
|
-
* Instantiates
|
|
278
|
+
* Instantiates an Account for a native multisig (TIP-1061) config.
|
|
279
279
|
*
|
|
280
|
-
* The returned account does not hold a key.
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
* `signatures`) through to the chain serializer, which combines the approvals
|
|
284
|
-
* into the multisig signature envelope.
|
|
280
|
+
* The returned account does not hold a key itself. Pass an initial config to
|
|
281
|
+
* derive and bootstrap an account, or pass the address of an initialized
|
|
282
|
+
* account to reconstruct it without retaining the initial config.
|
|
285
283
|
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
284
|
+
* Owners can be accounts or addresses directly, or weighted `{ owner, weight }`
|
|
285
|
+
* entries. Direct owners default to weight `1`, and `threshold` defaults to `1`.
|
|
286
|
+
* Local owner accounts are retained for signing, including nested multisigs.
|
|
287
|
+
* Address-only configs keep the external approval flow, where owner approvals
|
|
288
|
+
* are collected separately and provided via `signatures`.
|
|
288
289
|
*
|
|
289
290
|
* Accepts a raw config and normalizes it internally (via `MultisigConfig.from`),
|
|
290
291
|
* so callers don't need to call `MultisigConfig.from` themselves.
|
|
@@ -295,33 +296,67 @@ export declare namespace fromSecp256k1 {
|
|
|
295
296
|
*
|
|
296
297
|
* const account = Account.fromMultisig({
|
|
297
298
|
* threshold: 2,
|
|
298
|
-
* owners: [
|
|
299
|
-
* { owner: owner_1.address, weight: 1 },
|
|
300
|
-
* { owner: owner_2.address, weight: 1 },
|
|
301
|
-
* ],
|
|
299
|
+
* owners: [owner_1, owner_2],
|
|
302
300
|
* })
|
|
303
301
|
*
|
|
304
|
-
* //
|
|
305
|
-
* // inferred from it, so no `multisig` field is needed.
|
|
302
|
+
* // The multisig config is inferred from the account.
|
|
306
303
|
* const request = await client.prepareTransactionRequest({ account, ...rest })
|
|
307
304
|
*
|
|
308
|
-
*
|
|
309
|
-
* // need to be re-passed to `sendTransaction`.
|
|
310
|
-
* const transaction = await client.sendTransaction({
|
|
311
|
-
* ...request,
|
|
312
|
-
* signatures: [signature_1, signature_2],
|
|
313
|
-
* })
|
|
305
|
+
* const transaction = await client.signTransaction(request)
|
|
314
306
|
* ```
|
|
315
307
|
*
|
|
316
|
-
* @param
|
|
308
|
+
* @param value Initial multisig config or initialized multisig address.
|
|
317
309
|
* @returns Multisig account.
|
|
318
310
|
*/
|
|
319
|
-
export function fromMultisig(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
311
|
+
export function fromMultisig(
|
|
312
|
+
config: fromMultisig.Config,
|
|
313
|
+
): MultisigAccount<MultisigConfig.Config>
|
|
314
|
+
export function fromMultisig(
|
|
315
|
+
address: Address.Address,
|
|
316
|
+
): MultisigAccount<undefined>
|
|
317
|
+
export function fromMultisig(value: fromMultisig.Parameters): MultisigAccount
|
|
318
|
+
export function fromMultisig(value: fromMultisig.Parameters): MultisigAccount {
|
|
319
|
+
const config = (() => {
|
|
320
|
+
if (typeof value === 'string') return undefined
|
|
321
|
+
const ownerEntries = value.owners.map((value) =>
|
|
322
|
+
typeof value === 'string' || 'address' in value
|
|
323
|
+
? { owner: value, weight: 1 }
|
|
324
|
+
: value,
|
|
325
|
+
)
|
|
326
|
+
return MultisigConfig.from({
|
|
327
|
+
...value,
|
|
328
|
+
owners: ownerEntries.map(({ owner, weight }) => ({
|
|
329
|
+
owner: typeof owner === 'string' ? owner : owner.address,
|
|
330
|
+
weight,
|
|
331
|
+
})),
|
|
332
|
+
threshold: value.threshold ?? 1,
|
|
333
|
+
})
|
|
334
|
+
})()
|
|
335
|
+
const address = Address.checksum(
|
|
336
|
+
typeof value === 'string' ? value : MultisigConfig.getAddress(config!),
|
|
337
|
+
)
|
|
338
|
+
const ownerAccounts =
|
|
339
|
+
typeof value === 'string'
|
|
340
|
+
? []
|
|
341
|
+
: value.owners.flatMap((value) => {
|
|
342
|
+
const owner =
|
|
343
|
+
typeof value === 'string' || 'address' in value
|
|
344
|
+
? value
|
|
345
|
+
: value.owner
|
|
346
|
+
return typeof owner === 'string' ? [] : [parseAccount(owner)]
|
|
347
|
+
})
|
|
348
|
+
const owners =
|
|
349
|
+
config?.owners.flatMap(({ owner }) => {
|
|
350
|
+
const account = ownerAccounts.find((account) =>
|
|
351
|
+
Address.isEqual(account.address, owner),
|
|
352
|
+
)
|
|
353
|
+
return account ? [account] : []
|
|
354
|
+
}) ?? []
|
|
355
|
+
|
|
356
|
+
const account: MultisigAccount = {
|
|
323
357
|
address,
|
|
324
|
-
config
|
|
358
|
+
config,
|
|
359
|
+
owners,
|
|
325
360
|
publicKey: '0x',
|
|
326
361
|
source: 'multisig',
|
|
327
362
|
type: 'local',
|
|
@@ -333,17 +368,201 @@ export function fromMultisig(config: MultisigConfig.Config): MultisigAccount {
|
|
|
333
368
|
},
|
|
334
369
|
async signTransaction(transaction, options) {
|
|
335
370
|
const { serializer = Transaction.serialize } = options ?? {}
|
|
336
|
-
|
|
371
|
+
const request = transaction as Transaction.TransactionSerializableTempo
|
|
372
|
+
if (owners.length === 0)
|
|
373
|
+
return (await serializer(transaction as never)) as Hex.Hex
|
|
374
|
+
|
|
375
|
+
const presign = {
|
|
376
|
+
...request,
|
|
377
|
+
signatures: undefined,
|
|
378
|
+
...(request.feePayerSignature === undefined
|
|
379
|
+
? {}
|
|
380
|
+
: { feePayerSignature: null }),
|
|
381
|
+
}
|
|
382
|
+
const payload = keccak256(await serializer(presign as never))
|
|
383
|
+
const requestMultisig = request.multisig
|
|
384
|
+
const requestAccount = requestMultisig
|
|
385
|
+
? typeof requestMultisig === 'string'
|
|
386
|
+
? requestMultisig
|
|
387
|
+
: MultisigConfig.getAddress(requestMultisig)
|
|
388
|
+
: address
|
|
389
|
+
|
|
390
|
+
if (!Address.isEqual(requestAccount, address)) {
|
|
391
|
+
const state = request.multisigOwnerStates?.find((state) =>
|
|
392
|
+
Address.isEqual(state.account, address),
|
|
393
|
+
)
|
|
394
|
+
if (state && !state.initialized)
|
|
395
|
+
throw new Error('Nested multisig owners must be initialized.')
|
|
396
|
+
const parentDigest = MultisigConfig.getSignPayload({
|
|
397
|
+
...(typeof requestMultisig === 'string'
|
|
398
|
+
? { account: requestMultisig }
|
|
399
|
+
: { initialConfig: requestMultisig! }),
|
|
400
|
+
payload,
|
|
401
|
+
version: request.multisigVersion,
|
|
402
|
+
})
|
|
403
|
+
return SignatureEnvelope.serialize(
|
|
404
|
+
await signMultisig(account, {
|
|
405
|
+
payload: parentDigest,
|
|
406
|
+
states: request.multisigOwnerStates,
|
|
407
|
+
version: state?.version,
|
|
408
|
+
}),
|
|
409
|
+
)
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const keyAuthorizationSignature = request.keyAuthorization?.signature
|
|
413
|
+
const keyAuthorizationInitializes =
|
|
414
|
+
keyAuthorizationSignature?.type === 'multisig' &&
|
|
415
|
+
typeof keyAuthorizationSignature.init !== 'undefined'
|
|
416
|
+
const signature = await signMultisig(account, {
|
|
417
|
+
init:
|
|
418
|
+
typeof config !== 'undefined' &&
|
|
419
|
+
!request.nonce &&
|
|
420
|
+
!request.nonceKey &&
|
|
421
|
+
!keyAuthorizationInitializes,
|
|
422
|
+
payload,
|
|
423
|
+
signatures: request.signatures?.map((signature) =>
|
|
424
|
+
SignatureEnvelope.from(signature),
|
|
425
|
+
),
|
|
426
|
+
states: request.multisigOwnerStates,
|
|
427
|
+
version: request.multisigVersion,
|
|
428
|
+
})
|
|
429
|
+
return (await serializer(
|
|
430
|
+
transaction as never,
|
|
431
|
+
signature as never,
|
|
432
|
+
)) as Hex.Hex
|
|
337
433
|
},
|
|
338
434
|
async signTypedData() {
|
|
339
435
|
throw new Error('`signTypedData` is not supported for multisig accounts.')
|
|
340
436
|
},
|
|
341
437
|
}
|
|
438
|
+
return account
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export declare namespace fromMultisig {
|
|
442
|
+
export type Owner =
|
|
443
|
+
| Address.Address
|
|
444
|
+
| LocalAccount
|
|
445
|
+
| (Omit<MultisigConfig.Owner, 'owner'> & {
|
|
446
|
+
owner: Address.Address | LocalAccount
|
|
447
|
+
})
|
|
448
|
+
|
|
449
|
+
export type Config = Omit<MultisigConfig.Config, 'owners' | 'threshold'> & {
|
|
450
|
+
owners: readonly Owner[]
|
|
451
|
+
threshold?: number | undefined
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export type Parameters = Address.Address | Config
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export type MultisigAccount<
|
|
458
|
+
config extends MultisigConfig.Config | undefined =
|
|
459
|
+
| MultisigConfig.Config
|
|
460
|
+
| undefined,
|
|
461
|
+
> = LocalAccount<'multisig'> & {
|
|
462
|
+
/** Normalized initial config, or `undefined` when instantiated from an address. */
|
|
463
|
+
config: config
|
|
464
|
+
/** @internal Local owner accounts available for signing. */
|
|
465
|
+
owners: readonly LocalAccount[]
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function isMultisigAccount(account: LocalAccount): account is MultisigAccount {
|
|
469
|
+
return account.source === 'multisig'
|
|
342
470
|
}
|
|
343
471
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
472
|
+
async function signMultisig(
|
|
473
|
+
account: MultisigAccount,
|
|
474
|
+
parameters: {
|
|
475
|
+
init?: boolean | undefined
|
|
476
|
+
payload: Hex.Hex
|
|
477
|
+
signatures?: readonly SignatureEnvelope.SignatureEnvelope[] | undefined
|
|
478
|
+
states?: readonly Transaction.MultisigOwnerState[] | undefined
|
|
479
|
+
version?: bigint | undefined
|
|
480
|
+
},
|
|
481
|
+
): Promise<SignatureEnvelope.Multisig> {
|
|
482
|
+
const {
|
|
483
|
+
init = false,
|
|
484
|
+
payload,
|
|
485
|
+
signatures: providedSignatures = [],
|
|
486
|
+
states = [],
|
|
487
|
+
version = 0n,
|
|
488
|
+
} = parameters
|
|
489
|
+
const state = states.find((state) =>
|
|
490
|
+
Address.isEqual(state.account, account.address),
|
|
491
|
+
)
|
|
492
|
+
const currentConfig = state?.config ?? account.config
|
|
493
|
+
if (!currentConfig)
|
|
494
|
+
throw new Error('Current multisig config is required for local signing.')
|
|
495
|
+
const digest = MultisigConfig.getSignPayload({
|
|
496
|
+
account: account.address,
|
|
497
|
+
payload,
|
|
498
|
+
version,
|
|
499
|
+
})
|
|
500
|
+
const signatures = [...providedSignatures]
|
|
501
|
+
const signedOwners = new Set<Address.Address>()
|
|
502
|
+
let weight = 0
|
|
503
|
+
|
|
504
|
+
for (const signature of providedSignatures) {
|
|
505
|
+
const address = SignatureEnvelope.extractAddress({
|
|
506
|
+
payload: digest,
|
|
507
|
+
signature,
|
|
508
|
+
}).toLowerCase() as Address.Address
|
|
509
|
+
const owner = currentConfig.owners.find((owner) =>
|
|
510
|
+
Address.isEqual(owner.owner, address),
|
|
511
|
+
)
|
|
512
|
+
if (!owner || signedOwners.has(address)) continue
|
|
513
|
+
signedOwners.add(address)
|
|
514
|
+
weight += Number(owner.weight)
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
for (const owner of currentConfig.owners) {
|
|
518
|
+
const address = owner.owner.toLowerCase() as Address.Address
|
|
519
|
+
if (signedOwners.has(address)) continue
|
|
520
|
+
const ownerAccount = account.owners.find((account) =>
|
|
521
|
+
Address.isEqual(account.address, owner.owner),
|
|
522
|
+
)
|
|
523
|
+
if (!ownerAccount) continue
|
|
524
|
+
|
|
525
|
+
if (isMultisigAccount(ownerAccount)) {
|
|
526
|
+
const state = states.find((state) =>
|
|
527
|
+
Address.isEqual(state.account, ownerAccount.address),
|
|
528
|
+
)
|
|
529
|
+
if (state && !state.initialized)
|
|
530
|
+
throw new Error('Nested multisig owners must be initialized.')
|
|
531
|
+
signatures.push(
|
|
532
|
+
await signMultisig(ownerAccount, {
|
|
533
|
+
payload: digest,
|
|
534
|
+
states,
|
|
535
|
+
version: state?.version,
|
|
536
|
+
}),
|
|
537
|
+
)
|
|
538
|
+
} else {
|
|
539
|
+
if (!ownerAccount.sign)
|
|
540
|
+
throw new Error('Multisig owner account cannot sign.')
|
|
541
|
+
signatures.push(
|
|
542
|
+
SignatureEnvelope.from(await ownerAccount.sign({ hash: digest })),
|
|
543
|
+
)
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
signedOwners.add(address)
|
|
547
|
+
weight += Number(owner.weight)
|
|
548
|
+
if (weight >= Number(currentConfig.threshold)) break
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (weight < Number(currentConfig.threshold))
|
|
552
|
+
throw new Error('Local multisig owners do not meet the threshold.')
|
|
553
|
+
|
|
554
|
+
if (init && !account.config)
|
|
555
|
+
throw new Error('Initial multisig config is required for bootstrap.')
|
|
556
|
+
return SignatureEnvelope.from({
|
|
557
|
+
account: account.address,
|
|
558
|
+
...(init ? { init: account.config } : {}),
|
|
559
|
+
signatures: SignatureEnvelope.sortMultisigApprovals({
|
|
560
|
+
account: account.address,
|
|
561
|
+
payload,
|
|
562
|
+
signatures,
|
|
563
|
+
version,
|
|
564
|
+
}),
|
|
565
|
+
}) as SignatureEnvelope.Multisig
|
|
347
566
|
}
|
|
348
567
|
|
|
349
568
|
/**
|
|
@@ -538,11 +757,44 @@ function isAccessKeyAccount(
|
|
|
538
757
|
return account.source === 'accessKey' && 'accessKeyAddress' in account
|
|
539
758
|
}
|
|
540
759
|
|
|
760
|
+
/** @internal */
|
|
761
|
+
export function getKeyAuthorizationSignPayload(
|
|
762
|
+
account: LocalAccount,
|
|
763
|
+
parameters: signKeyAuthorization.Parameters,
|
|
764
|
+
): Hex.Hex {
|
|
765
|
+
const { admin, chainId, expiry, key, limits, scopes, witness } = parameters
|
|
766
|
+
const { accessKeyAddress, keyType: type } = resolveAccessKey(key)
|
|
767
|
+
const boundFields =
|
|
768
|
+
isAccessKeyAccount(account) || isMultisigAccount(account)
|
|
769
|
+
? { account: account.address }
|
|
770
|
+
: {}
|
|
771
|
+
const restrictions = admin ? {} : { expiry, limits, scopes }
|
|
772
|
+
return KeyAuthorization.getSignPayload({
|
|
773
|
+
address: accessKeyAddress,
|
|
774
|
+
chainId,
|
|
775
|
+
type,
|
|
776
|
+
witness,
|
|
777
|
+
...(admin ? { isAdmin: true } : {}),
|
|
778
|
+
...boundFields,
|
|
779
|
+
...restrictions,
|
|
780
|
+
} as never)
|
|
781
|
+
}
|
|
782
|
+
|
|
541
783
|
export async function signKeyAuthorization(
|
|
542
784
|
account: LocalAccount,
|
|
543
785
|
parameters: signKeyAuthorization.Parameters,
|
|
544
786
|
): Promise<signKeyAuthorization.ReturnValue> {
|
|
545
|
-
const {
|
|
787
|
+
const {
|
|
788
|
+
admin,
|
|
789
|
+
chainId,
|
|
790
|
+
expiry,
|
|
791
|
+
key,
|
|
792
|
+
limits,
|
|
793
|
+
multisig: multisigState,
|
|
794
|
+
scopes,
|
|
795
|
+
signatures,
|
|
796
|
+
witness,
|
|
797
|
+
} = parameters
|
|
546
798
|
const { accessKeyAddress, keyType: type } = resolveAccessKey(key)
|
|
547
799
|
|
|
548
800
|
// When the signer is an admin access key, the authorization must be
|
|
@@ -550,24 +802,36 @@ export async function signKeyAuthorization(
|
|
|
550
802
|
// on behalf of, so the signed payload cannot be replayed against another
|
|
551
803
|
// account. [TIP-1049]
|
|
552
804
|
const isAccessKey = isAccessKeyAccount(account)
|
|
553
|
-
const
|
|
805
|
+
const isMultisig = isMultisigAccount(account)
|
|
806
|
+
const boundFields =
|
|
807
|
+
isAccessKey || isMultisig ? { account: account.address } : {}
|
|
554
808
|
|
|
555
809
|
// Admin key authorizations are unrestricted and must not carry expiry,
|
|
556
810
|
// limits, or call scopes (the protocol rejects them). [TIP-1049]
|
|
557
811
|
const restrictions = admin ? {} : { expiry, limits, scopes }
|
|
558
812
|
|
|
559
|
-
const hash =
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
813
|
+
const hash = getKeyAuthorizationSignPayload(account, parameters)
|
|
814
|
+
const signature = await (async () => {
|
|
815
|
+
if (isAccessKey) return account.sign({ hash, raw: true })
|
|
816
|
+
if (isMultisig) {
|
|
817
|
+
if (!multisigState)
|
|
818
|
+
throw new Error(
|
|
819
|
+
'Multisig state is required to sign a key authorization.',
|
|
820
|
+
)
|
|
821
|
+
return SignatureEnvelope.serialize(
|
|
822
|
+
await signMultisig(account, {
|
|
823
|
+
init: multisigState.init,
|
|
824
|
+
payload: hash,
|
|
825
|
+
signatures: signatures?.map((signature) =>
|
|
826
|
+
SignatureEnvelope.from(signature),
|
|
827
|
+
),
|
|
828
|
+
states: multisigState.states,
|
|
829
|
+
version: multisigState.version,
|
|
830
|
+
}),
|
|
831
|
+
)
|
|
832
|
+
}
|
|
833
|
+
return account.sign!({ hash })
|
|
834
|
+
})()
|
|
571
835
|
return KeyAuthorization.from({
|
|
572
836
|
address: accessKeyAddress,
|
|
573
837
|
chainId,
|
|
@@ -585,7 +849,6 @@ export declare namespace signKeyAuthorization {
|
|
|
585
849
|
KeyAuthorization.KeyAuthorization,
|
|
586
850
|
'chainId' | 'expiry' | 'limits' | 'scopes' | 'witness'
|
|
587
851
|
> & {
|
|
588
|
-
key: resolveAccessKey.Parameters
|
|
589
852
|
/**
|
|
590
853
|
* Whether to authorize the key as an admin key. Admin keys are
|
|
591
854
|
* unrestricted and can manage the account's other access keys; `expiry`,
|
|
@@ -594,6 +857,17 @@ export declare namespace signKeyAuthorization {
|
|
|
594
857
|
* [TIP-1049](https://tips.sh/1049)
|
|
595
858
|
*/
|
|
596
859
|
admin?: boolean | undefined
|
|
860
|
+
key: resolveAccessKey.Parameters
|
|
861
|
+
/** @internal Current state used when a multisig account signs the authorization. */
|
|
862
|
+
multisig?:
|
|
863
|
+
| {
|
|
864
|
+
init: boolean
|
|
865
|
+
states?: readonly Transaction.MultisigOwnerState[] | undefined
|
|
866
|
+
version: bigint
|
|
867
|
+
}
|
|
868
|
+
| undefined
|
|
869
|
+
/** Serialized approvals from external multisig owners. */
|
|
870
|
+
signatures?: readonly SignatureEnvelope.Serialized[] | undefined
|
|
597
871
|
}
|
|
598
872
|
|
|
599
873
|
type ReturnValue = KeyAuthorization.Signed
|
|
@@ -674,17 +948,21 @@ function fromBase(parameters: fromBase.Parameters): Account_base {
|
|
|
674
948
|
|
|
675
949
|
const payload = keccak256(await serializer(presign))
|
|
676
950
|
|
|
677
|
-
// Native multisig (TIP-1061): return this owner's approval
|
|
678
|
-
// primitive signature over the multisig owner approval digest
|
|
951
|
+
// Native multisig (TIP-1061): return this owner's approval, a serialized
|
|
952
|
+
// primitive signature over the multisig owner approval digest, instead of
|
|
679
953
|
// a full serialized transaction. Approvals are combined later in
|
|
680
954
|
// `sendTransaction({ signatures })`.
|
|
681
|
-
const multisig =
|
|
682
|
-
|
|
683
|
-
|
|
955
|
+
const { multisig, multisigVersion } = transaction as {
|
|
956
|
+
multisig?: Address.Address | MultisigConfig.Config | undefined
|
|
957
|
+
multisigVersion?: bigint | undefined
|
|
958
|
+
}
|
|
684
959
|
if (multisig) {
|
|
685
960
|
const digest = MultisigConfig.getSignPayload({
|
|
961
|
+
...(typeof multisig === 'string'
|
|
962
|
+
? { account: multisig }
|
|
963
|
+
: { initialConfig: multisig }),
|
|
686
964
|
payload,
|
|
687
|
-
|
|
965
|
+
version: multisigVersion,
|
|
688
966
|
})
|
|
689
967
|
return await sign({ hash: digest, raw: true })
|
|
690
968
|
}
|
package/tempo/Addresses.ts
CHANGED
|
@@ -4,6 +4,7 @@ export const accountKeychain = '0xaAAAaaAA00000000000000000000000000000000'
|
|
|
4
4
|
export const accountRegistrar = '0x7702ac0000000000000000000000000000000000'
|
|
5
5
|
export const addressRegistry = '0xfdc0000000000000000000000000000000000000'
|
|
6
6
|
export const feeManager = '0xfeec000000000000000000000000000000000000'
|
|
7
|
+
export const nativeMultisig = '0xAACC000000000000000000000000000000000000'
|
|
7
8
|
export const nonceManager = '0x4e4F4E4345000000000000000000000000000000'
|
|
8
9
|
export const pathUsd = '0x20c0000000000000000000000000000000000000'
|
|
9
10
|
export const receivePolicyGuard = '0xB10C000000000000000000000000000000000000'
|
package/tempo/Decorator.ts
CHANGED
|
@@ -10,6 +10,7 @@ import * as dexActions from './actions/dex.js'
|
|
|
10
10
|
import * as earnActions from './actions/earn.js'
|
|
11
11
|
import * as faucetActions from './actions/faucet.js'
|
|
12
12
|
import * as feeActions from './actions/fee.js'
|
|
13
|
+
import * as multisigActions from './actions/multisig.js'
|
|
13
14
|
import * as nonceActions from './actions/nonce.js'
|
|
14
15
|
import * as policyActions from './actions/policy.js'
|
|
15
16
|
import * as receivePolicyActions from './actions/receivePolicy.js'
|
|
@@ -1926,8 +1927,8 @@ type DecoratorBase<
|
|
|
1926
1927
|
* assetToken: '0x...',
|
|
1927
1928
|
* gateway: '0x...',
|
|
1928
1929
|
* recipient: '0x...',
|
|
1929
|
-
* recoveryRecipient: '0x...',
|
|
1930
1930
|
* shareAmountMin: 99_500_000n,
|
|
1931
|
+
* tempoRefundRecipient: '0x...',
|
|
1931
1932
|
* vault: '0x...',
|
|
1932
1933
|
* vaultAssetAmountMin: 99_000_000n,
|
|
1933
1934
|
* zoneId: 7,
|
|
@@ -2157,9 +2158,9 @@ type DecoratorBase<
|
|
|
2157
2158
|
* const prepared = await parentClient.earn.privateRedeem.prepare({
|
|
2158
2159
|
* gateway: '0x...',
|
|
2159
2160
|
* recipient: '0x...',
|
|
2160
|
-
* recoveryRecipient: '0x...',
|
|
2161
2161
|
* shareAmount: 100_000_000n,
|
|
2162
2162
|
* slippageBps: 50,
|
|
2163
|
+
* tempoRefundRecipient: '0x...',
|
|
2163
2164
|
* vault: '0x...',
|
|
2164
2165
|
* zoneId: 7,
|
|
2165
2166
|
* })
|
|
@@ -2363,6 +2364,44 @@ type DecoratorBase<
|
|
|
2363
2364
|
parameters: faucetActions.fundSync.Parameters,
|
|
2364
2365
|
) => Promise<faucetActions.fundSync.ReturnValue>
|
|
2365
2366
|
}
|
|
2367
|
+
multisig: {
|
|
2368
|
+
/**
|
|
2369
|
+
* Gets the current configuration for an initialized multisig account.
|
|
2370
|
+
*
|
|
2371
|
+
* @param parameters - Parameters.
|
|
2372
|
+
* @returns The current version, threshold, and owners.
|
|
2373
|
+
*/
|
|
2374
|
+
getConfig: (
|
|
2375
|
+
parameters: multisigActions.getConfig.Parameters,
|
|
2376
|
+
) => Promise<multisigActions.getConfig.ReturnValue>
|
|
2377
|
+
/**
|
|
2378
|
+
* Checks whether an address is an initialized native multisig account.
|
|
2379
|
+
*
|
|
2380
|
+
* @param parameters - Parameters.
|
|
2381
|
+
* @returns Whether the account is initialized.
|
|
2382
|
+
*/
|
|
2383
|
+
isInitialized: (
|
|
2384
|
+
parameters: multisigActions.isInitialized.Parameters,
|
|
2385
|
+
) => Promise<multisigActions.isInitialized.ReturnValue>
|
|
2386
|
+
/**
|
|
2387
|
+
* Replaces the current configuration for a native multisig account.
|
|
2388
|
+
*
|
|
2389
|
+
* @param parameters - New configuration and transaction parameters.
|
|
2390
|
+
* @returns The transaction hash.
|
|
2391
|
+
*/
|
|
2392
|
+
updateConfig: (
|
|
2393
|
+
parameters: multisigActions.updateConfig.Parameters<chain, account>,
|
|
2394
|
+
) => Promise<multisigActions.updateConfig.ReturnValue>
|
|
2395
|
+
/**
|
|
2396
|
+
* Replaces a native multisig configuration and waits for confirmation.
|
|
2397
|
+
*
|
|
2398
|
+
* @param parameters - New configuration and transaction parameters.
|
|
2399
|
+
* @returns The update event and transaction receipt.
|
|
2400
|
+
*/
|
|
2401
|
+
updateConfigSync: (
|
|
2402
|
+
parameters: multisigActions.updateConfigSync.Parameters<chain, account>,
|
|
2403
|
+
) => Promise<multisigActions.updateConfigSync.ReturnValue>
|
|
2404
|
+
}
|
|
2366
2405
|
nonce: {
|
|
2367
2406
|
/**
|
|
2368
2407
|
* Gets the nonce for an account and nonce key.
|
|
@@ -5783,6 +5822,10 @@ export type Decorator<
|
|
|
5783
5822
|
DecoratorBase<chain, account>['faucet'],
|
|
5784
5823
|
typeof faucetActions
|
|
5785
5824
|
>
|
|
5825
|
+
multisig: DecorateNamespace<
|
|
5826
|
+
DecoratorBase<chain, account>['multisig'],
|
|
5827
|
+
typeof multisigActions
|
|
5828
|
+
>
|
|
5786
5829
|
nonce: DecorateNamespace<
|
|
5787
5830
|
DecoratorBase<chain, account>['nonce'],
|
|
5788
5831
|
typeof nonceActions
|
|
@@ -5854,6 +5897,7 @@ export function decorator() {
|
|
|
5854
5897
|
'getRemainingLimit',
|
|
5855
5898
|
'isAdmin',
|
|
5856
5899
|
'isWitnessBurned',
|
|
5900
|
+
'prepareAuthorization',
|
|
5857
5901
|
'revoke',
|
|
5858
5902
|
'revokeSync',
|
|
5859
5903
|
'signAuthorization',
|
|
@@ -5952,6 +5996,12 @@ export function decorator() {
|
|
|
5952
5996
|
'withdrawExactSync',
|
|
5953
5997
|
]),
|
|
5954
5998
|
faucet: bindActions(client, faucetActions, ['fund', 'fundSync']),
|
|
5999
|
+
multisig: bindActions(client, multisigActions, [
|
|
6000
|
+
'getConfig',
|
|
6001
|
+
'isInitialized',
|
|
6002
|
+
'updateConfig',
|
|
6003
|
+
'updateConfigSync',
|
|
6004
|
+
]),
|
|
5955
6005
|
nonce: bindActions(client, nonceActions, [
|
|
5956
6006
|
'getNonce',
|
|
5957
6007
|
'watchNonceIncremented',
|