ox 0.14.29 → 0.14.31
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 +30 -0
- package/_cjs/core/AbiParameters.js +2 -1
- package/_cjs/core/AbiParameters.js.map +1 -1
- package/_cjs/core/internal/abiParameters.js +10 -2
- package/_cjs/core/internal/abiParameters.js.map +1 -1
- package/_cjs/tempo/KeyAuthorization.js +39 -10
- package/_cjs/tempo/KeyAuthorization.js.map +1 -1
- package/_cjs/tempo/MultisigConfig.js +26 -26
- package/_cjs/tempo/MultisigConfig.js.map +1 -1
- package/_cjs/tempo/SignatureEnvelope.js +189 -55
- package/_cjs/tempo/SignatureEnvelope.js.map +1 -1
- package/_cjs/version.js +1 -1
- package/_esm/core/AbiParameters.js +4 -1
- package/_esm/core/AbiParameters.js.map +1 -1
- package/_esm/core/internal/abiParameters.js +17 -2
- package/_esm/core/internal/abiParameters.js.map +1 -1
- package/_esm/tempo/KeyAuthorization.js +41 -9
- package/_esm/tempo/KeyAuthorization.js.map +1 -1
- package/_esm/tempo/MultisigConfig.js +53 -81
- package/_esm/tempo/MultisigConfig.js.map +1 -1
- package/_esm/tempo/SignatureEnvelope.js +202 -75
- package/_esm/tempo/SignatureEnvelope.js.map +1 -1
- package/_esm/tempo/index.js +2 -2
- package/_esm/version.js +1 -1
- package/_types/core/AbiParameters.d.ts.map +1 -1
- package/_types/core/internal/abiParameters.d.ts.map +1 -1
- package/_types/core/internal/rpcSchemas/eth.d.ts +16 -0
- package/_types/core/internal/rpcSchemas/eth.d.ts.map +1 -1
- package/_types/tempo/KeyAuthorization.d.ts +22 -16
- package/_types/tempo/KeyAuthorization.d.ts.map +1 -1
- package/_types/tempo/MultisigConfig.d.ts +43 -83
- package/_types/tempo/MultisigConfig.d.ts.map +1 -1
- package/_types/tempo/SignatureEnvelope.d.ts +62 -40
- package/_types/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/_types/tempo/index.d.ts +2 -2
- package/_types/version.d.ts +1 -1
- package/core/AbiParameters.ts +3 -1
- package/core/internal/abiParameters.ts +17 -2
- package/core/internal/rpcSchemas/eth.ts +16 -0
- package/package.json +11 -1
- package/tempo/KeyAuthorization.test-d/package.json +6 -0
- package/tempo/KeyAuthorization.test-d.ts +62 -0
- package/tempo/KeyAuthorization.test.ts +132 -0
- package/tempo/KeyAuthorization.ts +76 -29
- package/tempo/MultisigConfig.test.ts +86 -37
- package/tempo/MultisigConfig.ts +75 -132
- package/tempo/SignatureEnvelope.test-d/package.json +6 -0
- package/tempo/SignatureEnvelope.test-d.ts +97 -0
- package/tempo/SignatureEnvelope.test.ts +322 -30
- package/tempo/SignatureEnvelope.ts +314 -118
- package/tempo/e2e.test.ts +22 -207
- package/tempo/index.ts +2 -2
- package/tempo/multisig.e2e.test.ts +582 -0
- package/version.ts +1 -1
package/tempo/e2e.test.ts
CHANGED
|
@@ -14,7 +14,6 @@ import { chain, client, fundAddress, nodeEnv } from '../../test/tempo/config.js'
|
|
|
14
14
|
import {
|
|
15
15
|
AuthorizationTempo,
|
|
16
16
|
KeyAuthorization,
|
|
17
|
-
MultisigConfig,
|
|
18
17
|
Period,
|
|
19
18
|
SignatureEnvelope,
|
|
20
19
|
} from './index.js'
|
|
@@ -87,6 +86,7 @@ test('behavior: default (secp256k1)', async () => {
|
|
|
87
86
|
from,
|
|
88
87
|
keyAuthorization: __,
|
|
89
88
|
nonce,
|
|
89
|
+
gasPrice,
|
|
90
90
|
maxFeePerGas,
|
|
91
91
|
maxPriorityFeePerGas,
|
|
92
92
|
signature,
|
|
@@ -100,6 +100,7 @@ test('behavior: default (secp256k1)', async () => {
|
|
|
100
100
|
expect(chainId).toBe(chainId)
|
|
101
101
|
expect(hash).toBe(receipt.transactionHash)
|
|
102
102
|
expect(from).toBe(address)
|
|
103
|
+
expect(gasPrice).toBeDefined()
|
|
103
104
|
expect(maxFeePerGas).toBeDefined()
|
|
104
105
|
expect(maxPriorityFeePerGas).toBeDefined()
|
|
105
106
|
expect(nonce).toBeDefined()
|
|
@@ -119,7 +120,6 @@ test('behavior: default (secp256k1)', async () => {
|
|
|
119
120
|
"data": undefined,
|
|
120
121
|
"feePayerSignature": null,
|
|
121
122
|
"gas": 500000n,
|
|
122
|
-
"gasPrice": 20000000000n,
|
|
123
123
|
"nonceKey": 0n,
|
|
124
124
|
"type": "tempo",
|
|
125
125
|
"validAfter": null,
|
|
@@ -133,6 +133,7 @@ test('behavior: default (secp256k1)', async () => {
|
|
|
133
133
|
blockNumber,
|
|
134
134
|
blockHash,
|
|
135
135
|
cumulativeGasUsed,
|
|
136
|
+
effectiveGasPrice,
|
|
136
137
|
feePayer,
|
|
137
138
|
feeToken: _,
|
|
138
139
|
from,
|
|
@@ -147,6 +148,7 @@ test('behavior: default (secp256k1)', async () => {
|
|
|
147
148
|
expect(blockNumber).toBeDefined()
|
|
148
149
|
expect(blockHash).toBeDefined()
|
|
149
150
|
expect(cumulativeGasUsed).toBeDefined()
|
|
151
|
+
expect(effectiveGasPrice).toBeDefined()
|
|
150
152
|
expect(feePayer).toBeDefined()
|
|
151
153
|
expect(from).toBe(address)
|
|
152
154
|
expect(gasUsed).toBeDefined()
|
|
@@ -159,7 +161,6 @@ test('behavior: default (secp256k1)', async () => {
|
|
|
159
161
|
"blobGasPrice": undefined,
|
|
160
162
|
"blobGasUsed": undefined,
|
|
161
163
|
"contractAddress": null,
|
|
162
|
-
"effectiveGasPrice": 20000000000n,
|
|
163
164
|
"status": "success",
|
|
164
165
|
"to": "0x0000000000000000000000000000000000000000",
|
|
165
166
|
"type": "0x76",
|
|
@@ -298,6 +299,7 @@ test('behavior: default (p256)', async () => {
|
|
|
298
299
|
keyAuthorization: __,
|
|
299
300
|
hash,
|
|
300
301
|
nonce,
|
|
302
|
+
gasPrice,
|
|
301
303
|
maxFeePerGas,
|
|
302
304
|
maxPriorityFeePerGas,
|
|
303
305
|
signature,
|
|
@@ -312,6 +314,7 @@ test('behavior: default (p256)', async () => {
|
|
|
312
314
|
expect(from).toBe(address)
|
|
313
315
|
expect(hash).toBe(receipt.transactionHash)
|
|
314
316
|
expect(nonce).toBeDefined()
|
|
317
|
+
expect(gasPrice).toBeDefined()
|
|
315
318
|
expect(maxFeePerGas).toBeDefined()
|
|
316
319
|
expect(maxPriorityFeePerGas).toBeDefined()
|
|
317
320
|
expect(signature).toBeDefined()
|
|
@@ -330,7 +333,6 @@ test('behavior: default (p256)', async () => {
|
|
|
330
333
|
"data": undefined,
|
|
331
334
|
"feePayerSignature": null,
|
|
332
335
|
"gas": 500000n,
|
|
333
|
-
"gasPrice": 20000000000n,
|
|
334
336
|
"nonceKey": 0n,
|
|
335
337
|
"type": "tempo",
|
|
336
338
|
"validAfter": null,
|
|
@@ -344,6 +346,7 @@ test('behavior: default (p256)', async () => {
|
|
|
344
346
|
blockNumber,
|
|
345
347
|
blockHash,
|
|
346
348
|
cumulativeGasUsed,
|
|
349
|
+
effectiveGasPrice,
|
|
347
350
|
feePayer,
|
|
348
351
|
feeToken: _,
|
|
349
352
|
from,
|
|
@@ -358,6 +361,7 @@ test('behavior: default (p256)', async () => {
|
|
|
358
361
|
expect(blockNumber).toBeDefined()
|
|
359
362
|
expect(blockHash).toBeDefined()
|
|
360
363
|
expect(cumulativeGasUsed).toBeDefined()
|
|
364
|
+
expect(effectiveGasPrice).toBeDefined()
|
|
361
365
|
expect(feePayer).toBeDefined()
|
|
362
366
|
expect(from).toBe(address)
|
|
363
367
|
expect(gasUsed).toBeDefined()
|
|
@@ -370,7 +374,6 @@ test('behavior: default (p256)', async () => {
|
|
|
370
374
|
"blobGasPrice": undefined,
|
|
371
375
|
"blobGasUsed": undefined,
|
|
372
376
|
"contractAddress": null,
|
|
373
|
-
"effectiveGasPrice": 20000000000n,
|
|
374
377
|
"status": "success",
|
|
375
378
|
"to": "0x0000000000000000000000000000000000000000",
|
|
376
379
|
"type": "0x76",
|
|
@@ -441,6 +444,7 @@ test('behavior: default (p256 - webcrypto)', async () => {
|
|
|
441
444
|
keyAuthorization: __,
|
|
442
445
|
hash,
|
|
443
446
|
nonce,
|
|
447
|
+
gasPrice,
|
|
444
448
|
maxFeePerGas,
|
|
445
449
|
maxPriorityFeePerGas,
|
|
446
450
|
signature,
|
|
@@ -455,6 +459,7 @@ test('behavior: default (p256 - webcrypto)', async () => {
|
|
|
455
459
|
expect(from).toBeDefined()
|
|
456
460
|
expect(hash).toBe(receipt.transactionHash)
|
|
457
461
|
expect(nonce).toBeDefined()
|
|
462
|
+
expect(gasPrice).toBeDefined()
|
|
458
463
|
expect(maxFeePerGas).toBeDefined()
|
|
459
464
|
expect(maxPriorityFeePerGas).toBeDefined()
|
|
460
465
|
expect(signature).toBeDefined()
|
|
@@ -473,7 +478,6 @@ test('behavior: default (p256 - webcrypto)', async () => {
|
|
|
473
478
|
"data": undefined,
|
|
474
479
|
"feePayerSignature": null,
|
|
475
480
|
"gas": 500000n,
|
|
476
|
-
"gasPrice": 20000000000n,
|
|
477
481
|
"nonceKey": 0n,
|
|
478
482
|
"type": "tempo",
|
|
479
483
|
"validAfter": null,
|
|
@@ -487,6 +491,7 @@ test('behavior: default (p256 - webcrypto)', async () => {
|
|
|
487
491
|
blockNumber,
|
|
488
492
|
blockHash,
|
|
489
493
|
cumulativeGasUsed,
|
|
494
|
+
effectiveGasPrice,
|
|
490
495
|
feePayer,
|
|
491
496
|
feeToken: _,
|
|
492
497
|
from,
|
|
@@ -501,6 +506,7 @@ test('behavior: default (p256 - webcrypto)', async () => {
|
|
|
501
506
|
expect(blockNumber).toBeDefined()
|
|
502
507
|
expect(blockHash).toBeDefined()
|
|
503
508
|
expect(cumulativeGasUsed).toBeDefined()
|
|
509
|
+
expect(effectiveGasPrice).toBeDefined()
|
|
504
510
|
expect(feePayer).toBeDefined()
|
|
505
511
|
expect(from).toBeDefined()
|
|
506
512
|
expect(gasUsed).toBeDefined()
|
|
@@ -513,7 +519,6 @@ test('behavior: default (p256 - webcrypto)', async () => {
|
|
|
513
519
|
"blobGasPrice": undefined,
|
|
514
520
|
"blobGasUsed": undefined,
|
|
515
521
|
"contractAddress": null,
|
|
516
|
-
"effectiveGasPrice": 20000000000n,
|
|
517
522
|
"status": "success",
|
|
518
523
|
"to": "0x0000000000000000000000000000000000000000",
|
|
519
524
|
"type": "0x76",
|
|
@@ -591,6 +596,7 @@ test('behavior: default (webauthn)', async () => {
|
|
|
591
596
|
keyAuthorization: __,
|
|
592
597
|
hash,
|
|
593
598
|
nonce,
|
|
599
|
+
gasPrice,
|
|
594
600
|
maxFeePerGas,
|
|
595
601
|
maxPriorityFeePerGas,
|
|
596
602
|
transactionIndex,
|
|
@@ -605,6 +611,7 @@ test('behavior: default (webauthn)', async () => {
|
|
|
605
611
|
expect(from).toBeDefined()
|
|
606
612
|
expect(hash).toBe(receipt.transactionHash)
|
|
607
613
|
expect(nonce).toBeDefined()
|
|
614
|
+
expect(gasPrice).toBeDefined()
|
|
608
615
|
expect(maxFeePerGas).toBeDefined()
|
|
609
616
|
expect(maxPriorityFeePerGas).toBeDefined()
|
|
610
617
|
expect(signature).toBeDefined()
|
|
@@ -623,7 +630,6 @@ test('behavior: default (webauthn)', async () => {
|
|
|
623
630
|
"data": undefined,
|
|
624
631
|
"feePayerSignature": null,
|
|
625
632
|
"gas": 500000n,
|
|
626
|
-
"gasPrice": 20000000000n,
|
|
627
633
|
"nonceKey": 0n,
|
|
628
634
|
"type": "tempo",
|
|
629
635
|
"validAfter": null,
|
|
@@ -637,6 +643,7 @@ test('behavior: default (webauthn)', async () => {
|
|
|
637
643
|
blockNumber,
|
|
638
644
|
blockHash,
|
|
639
645
|
cumulativeGasUsed,
|
|
646
|
+
effectiveGasPrice,
|
|
640
647
|
feePayer,
|
|
641
648
|
feeToken: _,
|
|
642
649
|
from,
|
|
@@ -651,6 +658,7 @@ test('behavior: default (webauthn)', async () => {
|
|
|
651
658
|
expect(blockNumber).toBeDefined()
|
|
652
659
|
expect(blockHash).toBeDefined()
|
|
653
660
|
expect(cumulativeGasUsed).toBeDefined()
|
|
661
|
+
expect(effectiveGasPrice).toBeDefined()
|
|
654
662
|
expect(feePayer).toBeDefined()
|
|
655
663
|
expect(from).toBe(address)
|
|
656
664
|
expect(gasUsed).toBeDefined()
|
|
@@ -663,7 +671,6 @@ test('behavior: default (webauthn)', async () => {
|
|
|
663
671
|
"blobGasPrice": undefined,
|
|
664
672
|
"blobGasUsed": undefined,
|
|
665
673
|
"contractAddress": null,
|
|
666
|
-
"effectiveGasPrice": 20000000000n,
|
|
667
674
|
"status": "success",
|
|
668
675
|
"to": "0x0000000000000000000000000000000000000000",
|
|
669
676
|
"type": "0x76",
|
|
@@ -745,6 +752,7 @@ test('behavior: feePayerSignature (user → feePayer)', async () => {
|
|
|
745
752
|
blockNumber,
|
|
746
753
|
blockHash,
|
|
747
754
|
cumulativeGasUsed,
|
|
755
|
+
effectiveGasPrice,
|
|
748
756
|
feePayer,
|
|
749
757
|
feeToken: _,
|
|
750
758
|
from,
|
|
@@ -759,6 +767,7 @@ test('behavior: feePayerSignature (user → feePayer)', async () => {
|
|
|
759
767
|
expect(blockNumber).toBeDefined()
|
|
760
768
|
expect(blockHash).toBeDefined()
|
|
761
769
|
expect(cumulativeGasUsed).toBeDefined()
|
|
770
|
+
expect(effectiveGasPrice).toBeDefined()
|
|
762
771
|
expect(feePayer).toBe(feePayerAddress)
|
|
763
772
|
expect(from).toBe(senderAddress)
|
|
764
773
|
expect(gasUsed).toBeDefined()
|
|
@@ -771,7 +780,6 @@ test('behavior: feePayerSignature (user → feePayer)', async () => {
|
|
|
771
780
|
"blobGasPrice": undefined,
|
|
772
781
|
"blobGasUsed": undefined,
|
|
773
782
|
"contractAddress": null,
|
|
774
|
-
"effectiveGasPrice": 20000000000n,
|
|
775
783
|
"status": "success",
|
|
776
784
|
"to": "0x0000000000000000000000000000000000000000",
|
|
777
785
|
"type": "0x76",
|
|
@@ -1019,6 +1027,7 @@ describe('behavior: keyAuthorization', () => {
|
|
|
1019
1027
|
blockNumber,
|
|
1020
1028
|
blockHash,
|
|
1021
1029
|
cumulativeGasUsed,
|
|
1030
|
+
effectiveGasPrice,
|
|
1022
1031
|
feePayer,
|
|
1023
1032
|
feeToken,
|
|
1024
1033
|
from,
|
|
@@ -1033,6 +1042,7 @@ describe('behavior: keyAuthorization', () => {
|
|
|
1033
1042
|
expect(blockNumber).toBeDefined()
|
|
1034
1043
|
expect(blockHash).toBeDefined()
|
|
1035
1044
|
expect(cumulativeGasUsed).toBeDefined()
|
|
1045
|
+
expect(effectiveGasPrice).toBeDefined()
|
|
1036
1046
|
expect(feeToken).toBeDefined()
|
|
1037
1047
|
expect(feePayer).toBeDefined()
|
|
1038
1048
|
expect(gasUsed).toBeDefined()
|
|
@@ -1046,7 +1056,6 @@ describe('behavior: keyAuthorization', () => {
|
|
|
1046
1056
|
"blobGasPrice": undefined,
|
|
1047
1057
|
"blobGasUsed": undefined,
|
|
1048
1058
|
"contractAddress": null,
|
|
1049
|
-
"effectiveGasPrice": 20000000000n,
|
|
1050
1059
|
"status": "success",
|
|
1051
1060
|
"to": "0x0000000000000000000000000000000000000000",
|
|
1052
1061
|
"type": "0x76",
|
|
@@ -1238,6 +1247,7 @@ describe('behavior: keyAuthorization', () => {
|
|
|
1238
1247
|
blockNumber,
|
|
1239
1248
|
blockHash,
|
|
1240
1249
|
cumulativeGasUsed,
|
|
1250
|
+
effectiveGasPrice,
|
|
1241
1251
|
feePayer,
|
|
1242
1252
|
feeToken,
|
|
1243
1253
|
from,
|
|
@@ -1252,6 +1262,7 @@ describe('behavior: keyAuthorization', () => {
|
|
|
1252
1262
|
expect(blockNumber).toBeDefined()
|
|
1253
1263
|
expect(blockHash).toBeDefined()
|
|
1254
1264
|
expect(cumulativeGasUsed).toBeDefined()
|
|
1265
|
+
expect(effectiveGasPrice).toBeDefined()
|
|
1255
1266
|
expect(feePayer).toBeDefined()
|
|
1256
1267
|
expect(feeToken).toBeDefined()
|
|
1257
1268
|
expect(from).toBeDefined()
|
|
@@ -1265,7 +1276,6 @@ describe('behavior: keyAuthorization', () => {
|
|
|
1265
1276
|
"blobGasPrice": undefined,
|
|
1266
1277
|
"blobGasUsed": undefined,
|
|
1267
1278
|
"contractAddress": null,
|
|
1268
|
-
"effectiveGasPrice": 20000000000n,
|
|
1269
1279
|
"status": "success",
|
|
1270
1280
|
"to": "0x0000000000000000000000000000000000000000",
|
|
1271
1281
|
"type": "0x76",
|
|
@@ -2999,198 +3009,3 @@ describe('behavior: keyAuthorization', () => {
|
|
|
2999
3009
|
},
|
|
3000
3010
|
)
|
|
3001
3011
|
})
|
|
3002
|
-
|
|
3003
|
-
// TODO: unskip once TIP-1061 native multisig is deployed to the standard
|
|
3004
|
-
// localnet/testnet nodes. Until then these only pass against the dedicated
|
|
3005
|
-
// PR-5178 devnet (run with VITE_TEMPO_RPC_URL pointed at it).
|
|
3006
|
-
describe.skip('behavior: multisig (TIP-1061)', () => {
|
|
3007
|
-
// Helper: builds a fresh set of secp256k1 owners + the derived config.
|
|
3008
|
-
function setup(parameters: { count: number; threshold: number }) {
|
|
3009
|
-
const { count, threshold } = parameters
|
|
3010
|
-
const ownerKeys = Array.from({ length: count }, () => {
|
|
3011
|
-
const privateKey = Secp256k1.randomPrivateKey()
|
|
3012
|
-
const address = Address.fromPublicKey(
|
|
3013
|
-
Secp256k1.getPublicKey({ privateKey }),
|
|
3014
|
-
)
|
|
3015
|
-
return { address, privateKey } as const
|
|
3016
|
-
})
|
|
3017
|
-
|
|
3018
|
-
const genesisConfig = MultisigConfig.from({
|
|
3019
|
-
// A fresh random salt yields a distinct account each run, exercising the
|
|
3020
|
-
// salt-inclusive config-ID derivation against the node.
|
|
3021
|
-
salt: Hex.random(32),
|
|
3022
|
-
threshold,
|
|
3023
|
-
owners: ownerKeys.map((key) => ({
|
|
3024
|
-
owner: key.address,
|
|
3025
|
-
weight: 1,
|
|
3026
|
-
})),
|
|
3027
|
-
})
|
|
3028
|
-
const account = MultisigConfig.getAddress(genesisConfig)
|
|
3029
|
-
|
|
3030
|
-
return { account, genesisConfig, ownerKeys } as const
|
|
3031
|
-
}
|
|
3032
|
-
|
|
3033
|
-
// Signs the multisig owner digest with the provided owner keys, returning
|
|
3034
|
-
// primitive approval envelopes ordered strictly ascending by recovered owner
|
|
3035
|
-
// address (required by the node: "recovered owners must be strictly
|
|
3036
|
-
// ascending").
|
|
3037
|
-
function approve(parameters: {
|
|
3038
|
-
genesisConfig: MultisigConfig.Config
|
|
3039
|
-
payload: Hex.Hex
|
|
3040
|
-
signers: readonly { privateKey: Hex.Hex }[]
|
|
3041
|
-
}) {
|
|
3042
|
-
const { genesisConfig, payload, signers } = parameters
|
|
3043
|
-
const digest = MultisigConfig.getSignPayload({ payload, genesisConfig })
|
|
3044
|
-
const signatures = signers.map((signer) =>
|
|
3045
|
-
SignatureEnvelope.from(
|
|
3046
|
-
Secp256k1.sign({ payload: digest, privateKey: signer.privateKey }),
|
|
3047
|
-
),
|
|
3048
|
-
)
|
|
3049
|
-
return SignatureEnvelope.sortMultisigApprovals({
|
|
3050
|
-
genesisConfig,
|
|
3051
|
-
payload,
|
|
3052
|
-
signatures,
|
|
3053
|
-
})
|
|
3054
|
-
}
|
|
3055
|
-
|
|
3056
|
-
test('behavior: bootstrap + spend (2-of-3 secp256k1)', async () => {
|
|
3057
|
-
const { account, genesisConfig, ownerKeys } = setup({
|
|
3058
|
-
count: 3,
|
|
3059
|
-
threshold: 2,
|
|
3060
|
-
})
|
|
3061
|
-
|
|
3062
|
-
// The derived multisig account pays its own fees.
|
|
3063
|
-
await fundAddress(client, { address: account })
|
|
3064
|
-
|
|
3065
|
-
// Bootstrap (first transaction): the bootstrap config travels in the
|
|
3066
|
-
// multisig signature `init`, nonce 0.
|
|
3067
|
-
const bootstrap = TxEnvelopeTempo.from({
|
|
3068
|
-
calls: [{ to: '0x0000000000000000000000000000000000000000' }],
|
|
3069
|
-
chainId,
|
|
3070
|
-
feeToken: '0x20c0000000000000000000000000000000000001',
|
|
3071
|
-
nonce: 0n,
|
|
3072
|
-
gas: 2_000_000n,
|
|
3073
|
-
maxFeePerGas: Value.fromGwei('20'),
|
|
3074
|
-
maxPriorityFeePerGas: Value.fromGwei('10'),
|
|
3075
|
-
})
|
|
3076
|
-
|
|
3077
|
-
const bootstrap_signed = TxEnvelopeTempo.serialize(bootstrap, {
|
|
3078
|
-
signature: SignatureEnvelope.from({
|
|
3079
|
-
genesisConfig,
|
|
3080
|
-
// Initialize multisig.
|
|
3081
|
-
init: true,
|
|
3082
|
-
// Approve with 2 of the 3 owners to satisfy the threshold.
|
|
3083
|
-
signatures: approve({
|
|
3084
|
-
genesisConfig,
|
|
3085
|
-
payload: TxEnvelopeTempo.getSignPayload(bootstrap),
|
|
3086
|
-
signers: [ownerKeys[0]!, ownerKeys[1]!],
|
|
3087
|
-
}),
|
|
3088
|
-
}),
|
|
3089
|
-
})
|
|
3090
|
-
|
|
3091
|
-
const bootstrap_receipt = (await client
|
|
3092
|
-
.request({
|
|
3093
|
-
method: 'eth_sendRawTransactionSync',
|
|
3094
|
-
params: [bootstrap_signed],
|
|
3095
|
-
})
|
|
3096
|
-
.then((tx) => TransactionReceipt.fromRpc(tx as any)))!
|
|
3097
|
-
expect(bootstrap_receipt).toBeDefined()
|
|
3098
|
-
expect(bootstrap_receipt.status).toBe('success')
|
|
3099
|
-
expect(bootstrap_receipt.from).toBe(account)
|
|
3100
|
-
|
|
3101
|
-
{
|
|
3102
|
-
const response = await client
|
|
3103
|
-
.request({
|
|
3104
|
-
method: 'eth_getTransactionByHash',
|
|
3105
|
-
params: [bootstrap_receipt.transactionHash],
|
|
3106
|
-
})
|
|
3107
|
-
.then((tx) => Transaction.fromRpc(tx as any))
|
|
3108
|
-
if (!response) throw new Error()
|
|
3109
|
-
expect(response.from).toBe(account)
|
|
3110
|
-
expect(response.signature?.type).toBe('multisig')
|
|
3111
|
-
// The bootstrap config is carried by the multisig signature `init`.
|
|
3112
|
-
expect(
|
|
3113
|
-
(response.signature as SignatureEnvelope.Multisig | undefined)?.init,
|
|
3114
|
-
).toEqual(genesisConfig)
|
|
3115
|
-
}
|
|
3116
|
-
|
|
3117
|
-
// Spend (subsequent transaction): no signature `init`, nonce 1, uses the
|
|
3118
|
-
// stored config loaded by the node.
|
|
3119
|
-
const nonce = await getTransactionCount(client, {
|
|
3120
|
-
address: account,
|
|
3121
|
-
blockTag: 'pending',
|
|
3122
|
-
})
|
|
3123
|
-
|
|
3124
|
-
const spend = TxEnvelopeTempo.from({
|
|
3125
|
-
calls: [{ to: '0x0000000000000000000000000000000000000000' }],
|
|
3126
|
-
chainId,
|
|
3127
|
-
feeToken: '0x20c0000000000000000000000000000000000001',
|
|
3128
|
-
nonce: BigInt(nonce),
|
|
3129
|
-
gas: 2_000_000n,
|
|
3130
|
-
maxFeePerGas: Value.fromGwei('20'),
|
|
3131
|
-
maxPriorityFeePerGas: Value.fromGwei('10'),
|
|
3132
|
-
})
|
|
3133
|
-
|
|
3134
|
-
const spend_signed = TxEnvelopeTempo.serialize(spend, {
|
|
3135
|
-
signature: SignatureEnvelope.from({
|
|
3136
|
-
genesisConfig,
|
|
3137
|
-
// A different 2-of-3 subset still authorizes the transaction.
|
|
3138
|
-
signatures: approve({
|
|
3139
|
-
genesisConfig,
|
|
3140
|
-
payload: TxEnvelopeTempo.getSignPayload(spend),
|
|
3141
|
-
signers: [ownerKeys[1]!, ownerKeys[2]!],
|
|
3142
|
-
}),
|
|
3143
|
-
}),
|
|
3144
|
-
})
|
|
3145
|
-
|
|
3146
|
-
const spend_receipt = (await client
|
|
3147
|
-
.request({
|
|
3148
|
-
method: 'eth_sendRawTransactionSync',
|
|
3149
|
-
params: [spend_signed],
|
|
3150
|
-
})
|
|
3151
|
-
.then((tx) => TransactionReceipt.fromRpc(tx as any)))!
|
|
3152
|
-
expect(spend_receipt).toBeDefined()
|
|
3153
|
-
expect(spend_receipt.status).toBe('success')
|
|
3154
|
-
expect(spend_receipt.from).toBe(account)
|
|
3155
|
-
})
|
|
3156
|
-
|
|
3157
|
-
test('behavior: rejects below-threshold approvals', async () => {
|
|
3158
|
-
const { account, genesisConfig, ownerKeys } = setup({
|
|
3159
|
-
count: 3,
|
|
3160
|
-
threshold: 2,
|
|
3161
|
-
})
|
|
3162
|
-
|
|
3163
|
-
await fundAddress(client, { address: account })
|
|
3164
|
-
|
|
3165
|
-
const bootstrap = TxEnvelopeTempo.from({
|
|
3166
|
-
calls: [{ to: '0x0000000000000000000000000000000000000000' }],
|
|
3167
|
-
chainId,
|
|
3168
|
-
feeToken: '0x20c0000000000000000000000000000000000001',
|
|
3169
|
-
nonce: 0n,
|
|
3170
|
-
gas: 2_000_000n,
|
|
3171
|
-
maxFeePerGas: Value.fromGwei('20'),
|
|
3172
|
-
maxPriorityFeePerGas: Value.fromGwei('10'),
|
|
3173
|
-
})
|
|
3174
|
-
|
|
3175
|
-
const serialized_signed = TxEnvelopeTempo.serialize(bootstrap, {
|
|
3176
|
-
signature: SignatureEnvelope.from({
|
|
3177
|
-
genesisConfig,
|
|
3178
|
-
// Opt into bootstrap: writes `genesisConfig` into the signature `init`.
|
|
3179
|
-
init: true,
|
|
3180
|
-
// Only one approval — below the threshold of 2.
|
|
3181
|
-
signatures: approve({
|
|
3182
|
-
genesisConfig,
|
|
3183
|
-
payload: TxEnvelopeTempo.getSignPayload(bootstrap),
|
|
3184
|
-
signers: [ownerKeys[0]!],
|
|
3185
|
-
}),
|
|
3186
|
-
}),
|
|
3187
|
-
})
|
|
3188
|
-
|
|
3189
|
-
await expect(
|
|
3190
|
-
client.request({
|
|
3191
|
-
method: 'eth_sendRawTransactionSync',
|
|
3192
|
-
params: [serialized_signed],
|
|
3193
|
-
}),
|
|
3194
|
-
).rejects.toThrow()
|
|
3195
|
-
})
|
|
3196
|
-
})
|
package/tempo/index.ts
CHANGED
|
@@ -105,8 +105,8 @@ export * as KeyAuthorization from './KeyAuthorization.js'
|
|
|
105
105
|
/**
|
|
106
106
|
* Native multisig account utilities (TIP-1061).
|
|
107
107
|
*
|
|
108
|
-
* Derives stable multisig account addresses
|
|
109
|
-
*
|
|
108
|
+
* Derives stable multisig account addresses from a weighted owner
|
|
109
|
+
* configuration, and computes the owner approval digest that owners sign.
|
|
110
110
|
*
|
|
111
111
|
* [TIP-1061](https://tips.sh/1061)
|
|
112
112
|
*
|