ox 0.14.29 → 0.14.30

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/tempo/e2e.test.ts CHANGED
@@ -87,6 +87,7 @@ test('behavior: default (secp256k1)', async () => {
87
87
  from,
88
88
  keyAuthorization: __,
89
89
  nonce,
90
+ gasPrice,
90
91
  maxFeePerGas,
91
92
  maxPriorityFeePerGas,
92
93
  signature,
@@ -100,6 +101,7 @@ test('behavior: default (secp256k1)', async () => {
100
101
  expect(chainId).toBe(chainId)
101
102
  expect(hash).toBe(receipt.transactionHash)
102
103
  expect(from).toBe(address)
104
+ expect(gasPrice).toBeDefined()
103
105
  expect(maxFeePerGas).toBeDefined()
104
106
  expect(maxPriorityFeePerGas).toBeDefined()
105
107
  expect(nonce).toBeDefined()
@@ -119,7 +121,6 @@ test('behavior: default (secp256k1)', async () => {
119
121
  "data": undefined,
120
122
  "feePayerSignature": null,
121
123
  "gas": 500000n,
122
- "gasPrice": 20000000000n,
123
124
  "nonceKey": 0n,
124
125
  "type": "tempo",
125
126
  "validAfter": null,
@@ -133,6 +134,7 @@ test('behavior: default (secp256k1)', async () => {
133
134
  blockNumber,
134
135
  blockHash,
135
136
  cumulativeGasUsed,
137
+ effectiveGasPrice,
136
138
  feePayer,
137
139
  feeToken: _,
138
140
  from,
@@ -147,6 +149,7 @@ test('behavior: default (secp256k1)', async () => {
147
149
  expect(blockNumber).toBeDefined()
148
150
  expect(blockHash).toBeDefined()
149
151
  expect(cumulativeGasUsed).toBeDefined()
152
+ expect(effectiveGasPrice).toBeDefined()
150
153
  expect(feePayer).toBeDefined()
151
154
  expect(from).toBe(address)
152
155
  expect(gasUsed).toBeDefined()
@@ -159,7 +162,6 @@ test('behavior: default (secp256k1)', async () => {
159
162
  "blobGasPrice": undefined,
160
163
  "blobGasUsed": undefined,
161
164
  "contractAddress": null,
162
- "effectiveGasPrice": 20000000000n,
163
165
  "status": "success",
164
166
  "to": "0x0000000000000000000000000000000000000000",
165
167
  "type": "0x76",
@@ -298,6 +300,7 @@ test('behavior: default (p256)', async () => {
298
300
  keyAuthorization: __,
299
301
  hash,
300
302
  nonce,
303
+ gasPrice,
301
304
  maxFeePerGas,
302
305
  maxPriorityFeePerGas,
303
306
  signature,
@@ -312,6 +315,7 @@ test('behavior: default (p256)', async () => {
312
315
  expect(from).toBe(address)
313
316
  expect(hash).toBe(receipt.transactionHash)
314
317
  expect(nonce).toBeDefined()
318
+ expect(gasPrice).toBeDefined()
315
319
  expect(maxFeePerGas).toBeDefined()
316
320
  expect(maxPriorityFeePerGas).toBeDefined()
317
321
  expect(signature).toBeDefined()
@@ -330,7 +334,6 @@ test('behavior: default (p256)', async () => {
330
334
  "data": undefined,
331
335
  "feePayerSignature": null,
332
336
  "gas": 500000n,
333
- "gasPrice": 20000000000n,
334
337
  "nonceKey": 0n,
335
338
  "type": "tempo",
336
339
  "validAfter": null,
@@ -344,6 +347,7 @@ test('behavior: default (p256)', async () => {
344
347
  blockNumber,
345
348
  blockHash,
346
349
  cumulativeGasUsed,
350
+ effectiveGasPrice,
347
351
  feePayer,
348
352
  feeToken: _,
349
353
  from,
@@ -358,6 +362,7 @@ test('behavior: default (p256)', async () => {
358
362
  expect(blockNumber).toBeDefined()
359
363
  expect(blockHash).toBeDefined()
360
364
  expect(cumulativeGasUsed).toBeDefined()
365
+ expect(effectiveGasPrice).toBeDefined()
361
366
  expect(feePayer).toBeDefined()
362
367
  expect(from).toBe(address)
363
368
  expect(gasUsed).toBeDefined()
@@ -370,7 +375,6 @@ test('behavior: default (p256)', async () => {
370
375
  "blobGasPrice": undefined,
371
376
  "blobGasUsed": undefined,
372
377
  "contractAddress": null,
373
- "effectiveGasPrice": 20000000000n,
374
378
  "status": "success",
375
379
  "to": "0x0000000000000000000000000000000000000000",
376
380
  "type": "0x76",
@@ -441,6 +445,7 @@ test('behavior: default (p256 - webcrypto)', async () => {
441
445
  keyAuthorization: __,
442
446
  hash,
443
447
  nonce,
448
+ gasPrice,
444
449
  maxFeePerGas,
445
450
  maxPriorityFeePerGas,
446
451
  signature,
@@ -455,6 +460,7 @@ test('behavior: default (p256 - webcrypto)', async () => {
455
460
  expect(from).toBeDefined()
456
461
  expect(hash).toBe(receipt.transactionHash)
457
462
  expect(nonce).toBeDefined()
463
+ expect(gasPrice).toBeDefined()
458
464
  expect(maxFeePerGas).toBeDefined()
459
465
  expect(maxPriorityFeePerGas).toBeDefined()
460
466
  expect(signature).toBeDefined()
@@ -473,7 +479,6 @@ test('behavior: default (p256 - webcrypto)', async () => {
473
479
  "data": undefined,
474
480
  "feePayerSignature": null,
475
481
  "gas": 500000n,
476
- "gasPrice": 20000000000n,
477
482
  "nonceKey": 0n,
478
483
  "type": "tempo",
479
484
  "validAfter": null,
@@ -487,6 +492,7 @@ test('behavior: default (p256 - webcrypto)', async () => {
487
492
  blockNumber,
488
493
  blockHash,
489
494
  cumulativeGasUsed,
495
+ effectiveGasPrice,
490
496
  feePayer,
491
497
  feeToken: _,
492
498
  from,
@@ -501,6 +507,7 @@ test('behavior: default (p256 - webcrypto)', async () => {
501
507
  expect(blockNumber).toBeDefined()
502
508
  expect(blockHash).toBeDefined()
503
509
  expect(cumulativeGasUsed).toBeDefined()
510
+ expect(effectiveGasPrice).toBeDefined()
504
511
  expect(feePayer).toBeDefined()
505
512
  expect(from).toBeDefined()
506
513
  expect(gasUsed).toBeDefined()
@@ -513,7 +520,6 @@ test('behavior: default (p256 - webcrypto)', async () => {
513
520
  "blobGasPrice": undefined,
514
521
  "blobGasUsed": undefined,
515
522
  "contractAddress": null,
516
- "effectiveGasPrice": 20000000000n,
517
523
  "status": "success",
518
524
  "to": "0x0000000000000000000000000000000000000000",
519
525
  "type": "0x76",
@@ -591,6 +597,7 @@ test('behavior: default (webauthn)', async () => {
591
597
  keyAuthorization: __,
592
598
  hash,
593
599
  nonce,
600
+ gasPrice,
594
601
  maxFeePerGas,
595
602
  maxPriorityFeePerGas,
596
603
  transactionIndex,
@@ -605,6 +612,7 @@ test('behavior: default (webauthn)', async () => {
605
612
  expect(from).toBeDefined()
606
613
  expect(hash).toBe(receipt.transactionHash)
607
614
  expect(nonce).toBeDefined()
615
+ expect(gasPrice).toBeDefined()
608
616
  expect(maxFeePerGas).toBeDefined()
609
617
  expect(maxPriorityFeePerGas).toBeDefined()
610
618
  expect(signature).toBeDefined()
@@ -623,7 +631,6 @@ test('behavior: default (webauthn)', async () => {
623
631
  "data": undefined,
624
632
  "feePayerSignature": null,
625
633
  "gas": 500000n,
626
- "gasPrice": 20000000000n,
627
634
  "nonceKey": 0n,
628
635
  "type": "tempo",
629
636
  "validAfter": null,
@@ -637,6 +644,7 @@ test('behavior: default (webauthn)', async () => {
637
644
  blockNumber,
638
645
  blockHash,
639
646
  cumulativeGasUsed,
647
+ effectiveGasPrice,
640
648
  feePayer,
641
649
  feeToken: _,
642
650
  from,
@@ -651,6 +659,7 @@ test('behavior: default (webauthn)', async () => {
651
659
  expect(blockNumber).toBeDefined()
652
660
  expect(blockHash).toBeDefined()
653
661
  expect(cumulativeGasUsed).toBeDefined()
662
+ expect(effectiveGasPrice).toBeDefined()
654
663
  expect(feePayer).toBeDefined()
655
664
  expect(from).toBe(address)
656
665
  expect(gasUsed).toBeDefined()
@@ -663,7 +672,6 @@ test('behavior: default (webauthn)', async () => {
663
672
  "blobGasPrice": undefined,
664
673
  "blobGasUsed": undefined,
665
674
  "contractAddress": null,
666
- "effectiveGasPrice": 20000000000n,
667
675
  "status": "success",
668
676
  "to": "0x0000000000000000000000000000000000000000",
669
677
  "type": "0x76",
@@ -745,6 +753,7 @@ test('behavior: feePayerSignature (user → feePayer)', async () => {
745
753
  blockNumber,
746
754
  blockHash,
747
755
  cumulativeGasUsed,
756
+ effectiveGasPrice,
748
757
  feePayer,
749
758
  feeToken: _,
750
759
  from,
@@ -759,6 +768,7 @@ test('behavior: feePayerSignature (user → feePayer)', async () => {
759
768
  expect(blockNumber).toBeDefined()
760
769
  expect(blockHash).toBeDefined()
761
770
  expect(cumulativeGasUsed).toBeDefined()
771
+ expect(effectiveGasPrice).toBeDefined()
762
772
  expect(feePayer).toBe(feePayerAddress)
763
773
  expect(from).toBe(senderAddress)
764
774
  expect(gasUsed).toBeDefined()
@@ -771,7 +781,6 @@ test('behavior: feePayerSignature (user → feePayer)', async () => {
771
781
  "blobGasPrice": undefined,
772
782
  "blobGasUsed": undefined,
773
783
  "contractAddress": null,
774
- "effectiveGasPrice": 20000000000n,
775
784
  "status": "success",
776
785
  "to": "0x0000000000000000000000000000000000000000",
777
786
  "type": "0x76",
@@ -1019,6 +1028,7 @@ describe('behavior: keyAuthorization', () => {
1019
1028
  blockNumber,
1020
1029
  blockHash,
1021
1030
  cumulativeGasUsed,
1031
+ effectiveGasPrice,
1022
1032
  feePayer,
1023
1033
  feeToken,
1024
1034
  from,
@@ -1033,6 +1043,7 @@ describe('behavior: keyAuthorization', () => {
1033
1043
  expect(blockNumber).toBeDefined()
1034
1044
  expect(blockHash).toBeDefined()
1035
1045
  expect(cumulativeGasUsed).toBeDefined()
1046
+ expect(effectiveGasPrice).toBeDefined()
1036
1047
  expect(feeToken).toBeDefined()
1037
1048
  expect(feePayer).toBeDefined()
1038
1049
  expect(gasUsed).toBeDefined()
@@ -1046,7 +1057,6 @@ describe('behavior: keyAuthorization', () => {
1046
1057
  "blobGasPrice": undefined,
1047
1058
  "blobGasUsed": undefined,
1048
1059
  "contractAddress": null,
1049
- "effectiveGasPrice": 20000000000n,
1050
1060
  "status": "success",
1051
1061
  "to": "0x0000000000000000000000000000000000000000",
1052
1062
  "type": "0x76",
@@ -1238,6 +1248,7 @@ describe('behavior: keyAuthorization', () => {
1238
1248
  blockNumber,
1239
1249
  blockHash,
1240
1250
  cumulativeGasUsed,
1251
+ effectiveGasPrice,
1241
1252
  feePayer,
1242
1253
  feeToken,
1243
1254
  from,
@@ -1252,6 +1263,7 @@ describe('behavior: keyAuthorization', () => {
1252
1263
  expect(blockNumber).toBeDefined()
1253
1264
  expect(blockHash).toBeDefined()
1254
1265
  expect(cumulativeGasUsed).toBeDefined()
1266
+ expect(effectiveGasPrice).toBeDefined()
1255
1267
  expect(feePayer).toBeDefined()
1256
1268
  expect(feeToken).toBeDefined()
1257
1269
  expect(from).toBeDefined()
@@ -1265,7 +1277,6 @@ describe('behavior: keyAuthorization', () => {
1265
1277
  "blobGasPrice": undefined,
1266
1278
  "blobGasUsed": undefined,
1267
1279
  "contractAddress": null,
1268
- "effectiveGasPrice": 20000000000n,
1269
1280
  "status": "success",
1270
1281
  "to": "0x0000000000000000000000000000000000000000",
1271
1282
  "type": "0x76",
@@ -3017,7 +3028,7 @@ describe.skip('behavior: multisig (TIP-1061)', () => {
3017
3028
 
3018
3029
  const genesisConfig = MultisigConfig.from({
3019
3030
  // A fresh random salt yields a distinct account each run, exercising the
3020
- // salt-inclusive config-ID derivation against the node.
3031
+ // salt-inclusive account derivation against the node.
3021
3032
  salt: Hex.random(32),
3022
3033
  threshold,
3023
3034
  owners: ownerKeys.map((key) => ({
@@ -3193,4 +3204,224 @@ describe.skip('behavior: multisig (TIP-1061)', () => {
3193
3204
  }),
3194
3205
  ).rejects.toThrow()
3195
3206
  })
3207
+
3208
+ test('behavior: keychain access key (authorize via AccountKeychain + spend)', async () => {
3209
+ const { account, genesisConfig, ownerKeys } = setup({
3210
+ count: 2,
3211
+ threshold: 2,
3212
+ })
3213
+
3214
+ await fundAddress(client, { address: account })
3215
+
3216
+ // Fresh secp256k1 access key for the multisig account.
3217
+ const access = (() => {
3218
+ const privateKey = Secp256k1.randomPrivateKey()
3219
+ const address = Address.fromPublicKey(
3220
+ Secp256k1.getPublicKey({ privateKey }),
3221
+ )
3222
+ return { address, privateKey } as const
3223
+ })()
3224
+
3225
+ // Bootstrap the multisig (nonce 0).
3226
+ const bootstrap = TxEnvelopeTempo.from({
3227
+ calls: [{ to: '0x0000000000000000000000000000000000000000' }],
3228
+ chainId,
3229
+ feeToken: '0x20c0000000000000000000000000000000000001',
3230
+ nonce: 0n,
3231
+ gas: 2_000_000n,
3232
+ maxFeePerGas: Value.fromGwei('20'),
3233
+ maxPriorityFeePerGas: Value.fromGwei('10'),
3234
+ })
3235
+
3236
+ const bootstrap_signed = TxEnvelopeTempo.serialize(bootstrap, {
3237
+ signature: SignatureEnvelope.from({
3238
+ genesisConfig,
3239
+ init: true,
3240
+ signatures: approve({
3241
+ genesisConfig,
3242
+ payload: TxEnvelopeTempo.getSignPayload(bootstrap),
3243
+ signers: ownerKeys,
3244
+ }),
3245
+ }),
3246
+ })
3247
+
3248
+ const bootstrap_receipt = (await client
3249
+ .request({
3250
+ method: 'eth_sendRawTransactionSync',
3251
+ params: [bootstrap_signed],
3252
+ })
3253
+ .then((tx) => TransactionReceipt.fromRpc(tx as any)))!
3254
+ expect(bootstrap_receipt.status).toBe('success')
3255
+
3256
+ // Authorize the access key (nonce 1): multisig transactions cannot carry
3257
+ // a TIP-1049 `keyAuthorization`, so the multisig account calls the
3258
+ // AccountKeychain precompile's `authorizeKey` directly.
3259
+ const authorizeKey = AbiFunction.from(
3260
+ 'function authorizeKey(address keyId, uint8 signatureType, (uint64 expiry, bool enforceLimits, (address token, uint256 amount, uint64 period)[] limits, bool allowAnyCalls, (address target, (bytes4 selector, address[] recipients)[] selectorRules)[] allowedCalls) config)',
3261
+ )
3262
+
3263
+ const authorize = TxEnvelopeTempo.from({
3264
+ calls: [
3265
+ {
3266
+ to: '0xaaaaaaaa00000000000000000000000000000000',
3267
+ data: AbiFunction.encodeData(authorizeKey, [
3268
+ access.address,
3269
+ 0, // secp256k1
3270
+ {
3271
+ expiry: 18446744073709551615n, // u64 max (never expires)
3272
+ enforceLimits: false,
3273
+ limits: [],
3274
+ allowAnyCalls: true,
3275
+ allowedCalls: [],
3276
+ },
3277
+ ]),
3278
+ },
3279
+ ],
3280
+ chainId,
3281
+ feeToken: '0x20c0000000000000000000000000000000000001',
3282
+ nonce: 1n,
3283
+ gas: 2_000_000n,
3284
+ maxFeePerGas: Value.fromGwei('20'),
3285
+ maxPriorityFeePerGas: Value.fromGwei('10'),
3286
+ })
3287
+
3288
+ const authorize_signed = TxEnvelopeTempo.serialize(authorize, {
3289
+ signature: SignatureEnvelope.from({
3290
+ genesisConfig,
3291
+ signatures: approve({
3292
+ genesisConfig,
3293
+ payload: TxEnvelopeTempo.getSignPayload(authorize),
3294
+ signers: ownerKeys,
3295
+ }),
3296
+ }),
3297
+ })
3298
+
3299
+ const authorize_receipt = (await client
3300
+ .request({
3301
+ method: 'eth_sendRawTransactionSync',
3302
+ params: [authorize_signed],
3303
+ })
3304
+ .then((tx) => TransactionReceipt.fromRpc(tx as any)))!
3305
+ expect(authorize_receipt.status).toBe('success')
3306
+ expect(authorize_receipt.from).toBe(account)
3307
+
3308
+ // Spend with the access key (nonce 2): outer keychain signature with the
3309
+ // multisig account as `userAddress` — no owner approvals involved.
3310
+ const nonce = await getTransactionCount(client, {
3311
+ address: account,
3312
+ blockTag: 'pending',
3313
+ })
3314
+
3315
+ const spend = TxEnvelopeTempo.from({
3316
+ calls: [{ to: '0x0000000000000000000000000000000000000000' }],
3317
+ chainId,
3318
+ feeToken: '0x20c0000000000000000000000000000000000001',
3319
+ nonce: BigInt(nonce),
3320
+ gas: 2_000_000n,
3321
+ maxFeePerGas: Value.fromGwei('20'),
3322
+ maxPriorityFeePerGas: Value.fromGwei('10'),
3323
+ })
3324
+
3325
+ const spend_signature = Secp256k1.sign({
3326
+ payload: TxEnvelopeTempo.getSignPayload(spend, { from: account }),
3327
+ privateKey: access.privateKey,
3328
+ })
3329
+
3330
+ const spend_signed = TxEnvelopeTempo.serialize(spend, {
3331
+ signature: SignatureEnvelope.from({
3332
+ userAddress: account,
3333
+ inner: SignatureEnvelope.from(spend_signature),
3334
+ type: 'keychain',
3335
+ }),
3336
+ })
3337
+
3338
+ const spend_receipt = (await client
3339
+ .request({
3340
+ method: 'eth_sendRawTransactionSync',
3341
+ params: [spend_signed],
3342
+ })
3343
+ .then((tx) => TransactionReceipt.fromRpc(tx as any)))!
3344
+ expect(spend_receipt.status).toBe('success')
3345
+ expect(spend_receipt.from).toBe(account)
3346
+
3347
+ {
3348
+ const response = await client
3349
+ .request({
3350
+ method: 'eth_getTransactionByHash',
3351
+ params: [spend_receipt.transactionHash],
3352
+ })
3353
+ .then((tx) => Transaction.fromRpc(tx as any))
3354
+ if (!response) throw new Error()
3355
+ expect(response.from).toBe(account)
3356
+ expect(response.signature?.type).toBe('keychain')
3357
+ expect(
3358
+ (response.signature as SignatureEnvelope.Keychain | undefined)
3359
+ ?.userAddress,
3360
+ ).toBe(account)
3361
+ }
3362
+ })
3363
+
3364
+ test('behavior: rejects `keyAuthorization` on multisig transactions', async () => {
3365
+ const { account, genesisConfig, ownerKeys } = setup({
3366
+ count: 1,
3367
+ threshold: 1,
3368
+ })
3369
+
3370
+ await fundAddress(client, { address: account })
3371
+
3372
+ const access = (() => {
3373
+ const privateKey = Secp256k1.randomPrivateKey()
3374
+ const address = Address.fromPublicKey(
3375
+ Secp256k1.getPublicKey({ privateKey }),
3376
+ )
3377
+ return { address, privateKey } as const
3378
+ })()
3379
+
3380
+ // TIP-1049 key authorizations are only valid on primitive/keychain
3381
+ // transactions; multisig accounts must call the AccountKeychain
3382
+ // precompile instead.
3383
+ const keyAuth = KeyAuthorization.from({
3384
+ address: access.address,
3385
+ chainId: BigInt(chainId),
3386
+ type: 'secp256k1',
3387
+ })
3388
+ const keyAuth_signed = KeyAuthorization.from(keyAuth, {
3389
+ signature: SignatureEnvelope.from(
3390
+ Secp256k1.sign({
3391
+ payload: KeyAuthorization.getSignPayload(keyAuth),
3392
+ privateKey: ownerKeys[0]!.privateKey,
3393
+ }),
3394
+ ),
3395
+ })
3396
+
3397
+ const bootstrap = TxEnvelopeTempo.from({
3398
+ calls: [{ to: '0x0000000000000000000000000000000000000000' }],
3399
+ chainId,
3400
+ feeToken: '0x20c0000000000000000000000000000000000001',
3401
+ keyAuthorization: keyAuth_signed,
3402
+ nonce: 0n,
3403
+ gas: 2_000_000n,
3404
+ maxFeePerGas: Value.fromGwei('20'),
3405
+ maxPriorityFeePerGas: Value.fromGwei('10'),
3406
+ })
3407
+
3408
+ const serialized_signed = TxEnvelopeTempo.serialize(bootstrap, {
3409
+ signature: SignatureEnvelope.from({
3410
+ genesisConfig,
3411
+ init: true,
3412
+ signatures: approve({
3413
+ genesisConfig,
3414
+ payload: TxEnvelopeTempo.getSignPayload(bootstrap),
3415
+ signers: ownerKeys,
3416
+ }),
3417
+ }),
3418
+ })
3419
+
3420
+ await expect(
3421
+ client.request({
3422
+ method: 'eth_sendRawTransactionSync',
3423
+ params: [serialized_signed],
3424
+ }),
3425
+ ).rejects.toThrow()
3426
+ })
3196
3427
  })
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 and permanent config IDs from a weighted
109
- * owner configuration, and computes the owner approval digest that owners sign.
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
  *
package/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** @internal */
2
- export const version = '0.14.29'
2
+ export const version = '0.14.30'