ox 1.7.4 → 1.7.5

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.
Files changed (105) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/core/AbiEvent.d.ts.map +1 -1
  3. package/dist/core/AbiEvent.js +10 -9
  4. package/dist/core/AbiEvent.js.map +1 -1
  5. package/dist/core/Blobs.d.ts.map +1 -1
  6. package/dist/core/Blobs.js +6 -2
  7. package/dist/core/Blobs.js.map +1 -1
  8. package/dist/core/Signature.d.ts +6 -5
  9. package/dist/core/Signature.d.ts.map +1 -1
  10. package/dist/core/Signature.js +17 -7
  11. package/dist/core/Signature.js.map +1 -1
  12. package/dist/core/Siwe.d.ts.map +1 -1
  13. package/dist/core/Siwe.js +21 -1
  14. package/dist/core/Siwe.js.map +1 -1
  15. package/dist/tempo/KeyAuthorization.d.ts +42 -38
  16. package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
  17. package/dist/tempo/KeyAuthorization.js +24 -4
  18. package/dist/tempo/KeyAuthorization.js.map +1 -1
  19. package/dist/tempo/MultisigConfig.d.ts +18 -15
  20. package/dist/tempo/MultisigConfig.d.ts.map +1 -1
  21. package/dist/tempo/MultisigConfig.js +49 -20
  22. package/dist/tempo/MultisigConfig.js.map +1 -1
  23. package/dist/tempo/MultisigOperation.d.ts +3 -2
  24. package/dist/tempo/MultisigOperation.d.ts.map +1 -1
  25. package/dist/tempo/MultisigOperation.js +20 -100
  26. package/dist/tempo/MultisigOperation.js.map +1 -1
  27. package/dist/tempo/MultisigSimulation.d.ts +2 -49
  28. package/dist/tempo/MultisigSimulation.d.ts.map +1 -1
  29. package/dist/tempo/MultisigSimulation.js +18 -46
  30. package/dist/tempo/MultisigSimulation.js.map +1 -1
  31. package/dist/tempo/SignatureEnvelope.d.ts +72 -140
  32. package/dist/tempo/SignatureEnvelope.d.ts.map +1 -1
  33. package/dist/tempo/SignatureEnvelope.js +130 -181
  34. package/dist/tempo/SignatureEnvelope.js.map +1 -1
  35. package/dist/tempo/TransactionRequest.d.ts +4 -2
  36. package/dist/tempo/TransactionRequest.d.ts.map +1 -1
  37. package/dist/tempo/TransactionRequest.js +6 -1
  38. package/dist/tempo/TransactionRequest.js.map +1 -1
  39. package/dist/tempo/index.d.ts +3 -1
  40. package/dist/tempo/index.d.ts.map +1 -1
  41. package/dist/tempo/index.js +3 -1
  42. package/dist/tempo/index.js.map +1 -1
  43. package/dist/zod/tempo/AuthorizationTempo.d.ts +350 -10
  44. package/dist/zod/tempo/AuthorizationTempo.d.ts.map +1 -1
  45. package/dist/zod/tempo/KeyAuthorization.d.ts +242 -422
  46. package/dist/zod/tempo/KeyAuthorization.d.ts.map +1 -1
  47. package/dist/zod/tempo/KeyAuthorization.js +29 -31
  48. package/dist/zod/tempo/KeyAuthorization.js.map +1 -1
  49. package/dist/zod/tempo/MultisigSimulation.d.ts +8 -76
  50. package/dist/zod/tempo/MultisigSimulation.d.ts.map +1 -1
  51. package/dist/zod/tempo/MultisigSimulation.js +3 -37
  52. package/dist/zod/tempo/MultisigSimulation.js.map +1 -1
  53. package/dist/zod/tempo/RpcSchemaTempo.d.ts +284 -228
  54. package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
  55. package/dist/zod/tempo/SignatureEnvelope.d.ts +105 -3
  56. package/dist/zod/tempo/SignatureEnvelope.d.ts.map +1 -1
  57. package/dist/zod/tempo/SignatureEnvelope.js +21 -9
  58. package/dist/zod/tempo/SignatureEnvelope.js.map +1 -1
  59. package/dist/zod/tempo/Transaction.d.ts +676 -448
  60. package/dist/zod/tempo/Transaction.d.ts.map +1 -1
  61. package/dist/zod/tempo/TransactionRequest.d.ts +590 -473
  62. package/dist/zod/tempo/TransactionRequest.d.ts.map +1 -1
  63. package/dist/zod/tempo/TransactionRequest.js +8 -0
  64. package/dist/zod/tempo/TransactionRequest.js.map +1 -1
  65. package/dist/zod/tempo/TxEnvelopeTempo.d.ts +327 -213
  66. package/dist/zod/tempo/TxEnvelopeTempo.d.ts.map +1 -1
  67. package/dist/zod/tempo/ZoneRpcAuthentication.d.ts +105 -3
  68. package/dist/zod/tempo/ZoneRpcAuthentication.d.ts.map +1 -1
  69. package/package.json +1 -1
  70. package/src/core/AbiEvent.ts +11 -9
  71. package/src/core/Blobs.ts +6 -2
  72. package/src/core/Signature.ts +41 -11
  73. package/src/core/Siwe.ts +20 -1
  74. package/src/core/_test/AbiEvent.test.ts +45 -0
  75. package/src/core/_test/Blobs.test.ts +22 -0
  76. package/src/core/_test/Signature.test.ts +166 -0
  77. package/src/core/_test/Siwe.test.ts +100 -1
  78. package/src/tempo/AuthorizationTempo.test.ts +8 -4
  79. package/src/tempo/KeyAuthorization.test-d.ts +16 -63
  80. package/src/tempo/KeyAuthorization.test.ts +69 -11
  81. package/src/tempo/KeyAuthorization.ts +107 -63
  82. package/src/tempo/MultisigConfig.test.ts +44 -20
  83. package/src/tempo/MultisigConfig.ts +65 -23
  84. package/src/tempo/MultisigOperation.test.ts +79 -550
  85. package/src/tempo/MultisigOperation.ts +31 -146
  86. package/src/tempo/MultisigSimulation.test-d.ts +2 -2
  87. package/src/tempo/MultisigSimulation.test.ts +21 -110
  88. package/src/tempo/MultisigSimulation.ts +25 -99
  89. package/src/tempo/SignatureEnvelope.test-d.ts +29 -47
  90. package/src/tempo/SignatureEnvelope.test.ts +328 -541
  91. package/src/tempo/SignatureEnvelope.ts +196 -291
  92. package/src/tempo/Transaction.test.ts +4 -4
  93. package/src/tempo/TransactionRequest.test.ts +17 -80
  94. package/src/tempo/TransactionRequest.ts +19 -2
  95. package/src/tempo/index.ts +3 -1
  96. package/src/tempo/multisig.e2e.test.ts +321 -860
  97. package/src/version.ts +1 -1
  98. package/src/zod/tempo/KeyAuthorization.ts +50 -39
  99. package/src/zod/tempo/MultisigSimulation.ts +3 -48
  100. package/src/zod/tempo/SignatureEnvelope.ts +46 -35
  101. package/src/zod/tempo/TransactionRequest.ts +14 -0
  102. package/src/zod/tempo/_test/KeyAuthorization.test.ts +69 -20
  103. package/src/zod/tempo/_test/MultisigSimulation.test.ts +6 -31
  104. package/src/zod/tempo/_test/SignatureEnvelope.test.ts +118 -85
  105. package/src/zod/tempo/_test/TransactionRequest.test.ts +9 -19
@@ -324,6 +324,53 @@ describe('createMessage', () => {
324
324
  `)
325
325
  })
326
326
 
327
+ test('behavior: uri with no path (authority only)', () => {
328
+ vi.useFakeTimers()
329
+ vi.setSystemTime(new Date(Date.UTC(2023, 1, 1)))
330
+
331
+ expect(Siwe.createMessage({ ...message, uri: 'https://example.com' }))
332
+ .toMatchInlineSnapshot(`
333
+ "example.com wants you to sign in with your Ethereum account:
334
+ 0xA0Cf798816D4b9b9866b5330EEa46a18382f251e
335
+
336
+
337
+ URI: https://example.com
338
+ Version: 1
339
+ Chain ID: 1
340
+ Nonce: foobarbaz
341
+ Issued At: 2023-02-01T00:00:00.000Z"
342
+ `)
343
+
344
+ vi.useRealTimers()
345
+ })
346
+
347
+ test('behavior: resources entry with no path (authority only)', () => {
348
+ vi.useFakeTimers()
349
+ vi.setSystemTime(new Date(Date.UTC(2023, 1, 1)))
350
+
351
+ expect(
352
+ Siwe.createMessage({
353
+ ...message,
354
+ resources: ['https://example.com', 'https://example.com/foo'],
355
+ }),
356
+ ).toMatchInlineSnapshot(`
357
+ "example.com wants you to sign in with your Ethereum account:
358
+ 0xA0Cf798816D4b9b9866b5330EEa46a18382f251e
359
+
360
+
361
+ URI: https://example.com/path
362
+ Version: 1
363
+ Chain ID: 1
364
+ Nonce: foobarbaz
365
+ Issued At: 2023-02-01T00:00:00.000Z
366
+ Resources:
367
+ - https://example.com
368
+ - https://example.com/foo"
369
+ `)
370
+
371
+ vi.useRealTimers()
372
+ })
373
+
327
374
  test('behavior: invalid version', () => {
328
375
  expect(() =>
329
376
  // @ts-expect-error
@@ -373,7 +420,7 @@ describe('createMessage', () => {
373
420
  - Every resource must be a RFC 3986 URI.
374
421
  - See https://www.rfc-editor.org/rfc/rfc3986
375
422
 
376
- Provided value: https://example.com]
423
+ Provided value: foo]
377
424
  `)
378
425
  })
379
426
 
@@ -426,6 +473,58 @@ describe('isUri', () => {
426
473
  )
427
474
  })
428
475
 
476
+ test('behavior: authority with empty path (bare origin)', () => {
477
+ expect(Siwe.isUri('https://example.com')).toMatchInlineSnapshot(
478
+ `"https://example.com"`,
479
+ )
480
+ })
481
+
482
+ test('behavior: authority with empty path and port', () => {
483
+ expect(Siwe.isUri('https://example.com:8080')).toMatchInlineSnapshot(
484
+ `"https://example.com:8080"`,
485
+ )
486
+ })
487
+
488
+ test('behavior: authority with empty path and query', () => {
489
+ expect(Siwe.isUri('https://example.com?a=1')).toMatchInlineSnapshot(
490
+ `"https://example.com?a=1"`,
491
+ )
492
+ })
493
+
494
+ test('behavior: authority with empty path and fragment', () => {
495
+ expect(Siwe.isUri('https://example.com#top')).toMatchInlineSnapshot(
496
+ `"https://example.com#top"`,
497
+ )
498
+ })
499
+
500
+ test('behavior: authority with empty path (non-http scheme)', () => {
501
+ expect(Siwe.isUri('ipfs://bafybeiabc')).toMatchInlineSnapshot(
502
+ `"ipfs://bafybeiabc"`,
503
+ )
504
+ })
505
+
506
+ test('behavior: authority variants with empty path', () => {
507
+ expect([
508
+ Siwe.isUri('https://[2001:db8::1]'),
509
+ Siwe.isUri('https://user:pass@example.com:8080'),
510
+ Siwe.isUri('foo://[v1.fe]'),
511
+ ]).toMatchInlineSnapshot(`
512
+ [
513
+ "https://[2001:db8::1]",
514
+ "https://user:pass@example.com:8080",
515
+ "foo://[v1.fe]",
516
+ ]
517
+ `)
518
+ })
519
+
520
+ test.each([
521
+ 'https://example.com:bad',
522
+ 'https://[:::]',
523
+ 'https://user@@example.com',
524
+ ])('behavior: invalid authority with empty path `%s`', (uri) => {
525
+ expect(Siwe.isUri(uri)).toMatchInlineSnapshot(`false`)
526
+ })
527
+
429
528
  test('behavior: check for illegal characters', () => {
430
529
  expect(Siwe.isUri('^')).toBeFalsy()
431
530
  })
@@ -348,7 +348,8 @@ describe('fromRpc', () => {
348
348
  type: 'p256',
349
349
  },
350
350
  })
351
- if (typeof result.signature === 'string') throw new Error('unreachable')
351
+ if (typeof result.signature === 'string')
352
+ throw new Error('Expected structured primitive signature')
352
353
  expect(result.signature.type).toBe('p256')
353
354
  expect(result.signature).toHaveProperty('prehash', true)
354
355
  expect(result.signature).toHaveProperty('publicKey')
@@ -371,7 +372,8 @@ describe('fromRpc', () => {
371
372
  '0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976305000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22222c226f726967696e223a2268747470733a2f2f6578616d706c652e636f6d222c2263726f73734f726967696e223a66616c73657d',
372
373
  },
373
374
  })
374
- if (typeof result.signature === 'string') throw new Error('unreachable')
375
+ if (typeof result.signature === 'string')
376
+ throw new Error('Expected structured primitive signature')
375
377
  expect(result.signature.type).toBe('webAuthn')
376
378
  expect(result.signature).toHaveProperty('metadata')
377
379
  expect(result.signature).toHaveProperty('publicKey')
@@ -996,7 +998,8 @@ describe('toRpc', () => {
996
998
  type: 'p256',
997
999
  },
998
1000
  })
999
- if (typeof result.signature === 'string') throw new Error('unreachable')
1001
+ if (typeof result.signature === 'string')
1002
+ throw new Error('Expected structured primitive signature')
1000
1003
  expect(result.signature.type).toBe('p256')
1001
1004
  })
1002
1005
 
@@ -1022,7 +1025,8 @@ describe('toRpc', () => {
1022
1025
  type: 'webAuthn',
1023
1026
  },
1024
1027
  })
1025
- if (typeof result.signature === 'string') throw new Error('unreachable')
1028
+ if (typeof result.signature === 'string')
1029
+ throw new Error('Expected structured primitive signature')
1026
1030
  expect(result.signature.type).toBe('webAuthn')
1027
1031
  })
1028
1032
  })
@@ -1,7 +1,6 @@
1
1
  import { expectTypeOf, test } from 'vp/test'
2
2
  import * as KeyAuthorization from './KeyAuthorization.js'
3
- import * as MultisigConfig from './MultisigConfig.js'
4
- import type * as SignatureEnvelope from './SignatureEnvelope.js'
3
+ import * as SignatureEnvelope from './SignatureEnvelope.js'
5
4
 
6
5
  const authorization = {
7
6
  address: '0x1111111111111111111111111111111111111111',
@@ -20,26 +19,18 @@ const signature = {
20
19
 
21
20
  const multisig = {
22
21
  account: '0x2222222222222222222222222222222222222222',
23
- config: MultisigConfig.from({
22
+ config: {
23
+ salt: `0x${'00'.repeat(32)}`,
24
+ version: 0n,
25
+ threshold: 1,
24
26
  owners: [
25
- {
26
- owner: '0x1111111111111111111111111111111111111111',
27
- weight: 1,
28
- },
27
+ { owner: '0x1111111111111111111111111111111111111111', weight: 1 },
29
28
  ],
30
- threshold: 1,
31
- version: 1n,
32
- }),
29
+ },
33
30
  signatures: [signature],
34
31
  type: 'multisig',
35
32
  } as const satisfies SignatureEnvelope.Multisig
36
33
 
37
- const keychain = {
38
- inner: signature,
39
- type: 'keychain',
40
- userAddress: authorization.address,
41
- } as const satisfies SignatureEnvelope.Keychain
42
-
43
34
  test('accepts primitive signatures', () => {
44
35
  const signed = KeyAuthorization.from(authorization, { signature })
45
36
 
@@ -48,51 +39,13 @@ test('accepts primitive signatures', () => {
48
39
  >()
49
40
  })
50
41
 
51
- test('accepts multisig signatures', () => {
52
- const signed = KeyAuthorization.from(authorization, { signature: multisig })
53
-
54
- expectTypeOf(signed.signature).toMatchTypeOf<
55
- KeyAuthorization.Signed['signature']
56
- >()
57
-
58
- const multisigRpc = '0xf8' as const satisfies SignatureEnvelope.MultisigRpc
59
-
60
- const rpc: KeyAuthorization.Rpc = {
61
- chainId: '0x1',
62
- expiry: null,
63
- keyId: authorization.address,
64
- keyType: authorization.type,
65
- signature: multisigRpc,
66
- }
67
-
68
- expectTypeOf(rpc).toEqualTypeOf<KeyAuthorization.Rpc>()
69
- })
70
-
71
- test('rejects keychain signatures', () => {
72
- KeyAuthorization.from(authorization, {
73
- // @ts-expect-error Key authorizations do not accept keychain signatures.
74
- signature: keychain,
75
- })
76
-
77
- const keychainRpc = {
78
- signature: {
79
- r: '0x01',
80
- s: '0x02',
81
- type: 'secp256k1',
82
- yParity: '0x0',
83
- },
84
- type: 'keychain',
85
- userAddress: authorization.address,
86
- } as const satisfies SignatureEnvelope.KeychainRpc
87
-
88
- const rpc: KeyAuthorization.Rpc = {
89
- chainId: '0x1',
90
- expiry: null,
91
- keyId: authorization.address,
92
- keyType: authorization.type,
93
- // @ts-expect-error Key authorizations do not accept keychain RPC signatures.
94
- signature: keychainRpc,
95
- }
96
-
97
- expectTypeOf(rpc).toEqualTypeOf<KeyAuthorization.Rpc>()
42
+ test('accepts multisig signatures and account-bound grants', () => {
43
+ const signed = KeyAuthorization.from(
44
+ { ...authorization, account: multisig.account, type: 'multisig' },
45
+ { signature: multisig },
46
+ )
47
+ expectTypeOf(signed).toMatchTypeOf<KeyAuthorization.Signed>()
48
+ expectTypeOf(
49
+ KeyAuthorization.toRpc(signed),
50
+ ).toMatchTypeOf<KeyAuthorization.Rpc>()
98
51
  })
@@ -78,7 +78,66 @@ const signature_keychain = {
78
78
  userAddress: address,
79
79
  } as const satisfies SignatureEnvelope.Keychain
80
80
 
81
+ describe('multisig account binding', () => {
82
+ test('rejects unbound grants before signing or encoding', () => {
83
+ const authorization = { address, chainId: 1n, type: 'multisig' } as const
84
+ const signed = {
85
+ ...authorization,
86
+ signature: SignatureEnvelope.from(signature_secp256k1),
87
+ }
88
+ for (const encode of [
89
+ () => KeyAuthorization.from(authorization),
90
+ () => KeyAuthorization.toTuple(authorization),
91
+ () => KeyAuthorization.getSignPayload(authorization),
92
+ () => KeyAuthorization.serialize(authorization),
93
+ () => KeyAuthorization.toRpc(signed),
94
+ ])
95
+ expect(encode).toThrowErrorMatchingInlineSnapshot(
96
+ `[KeyAuthorization.MissingAccountError: Multisig key grants require a parent account binding.]`,
97
+ )
98
+ })
99
+
100
+ test('rejects unbound RPC and RLP grants', () => {
101
+ const signed = KeyAuthorization.from(
102
+ { account: address, address, chainId: 1n, type: 'multisig' },
103
+ { signature: signature_secp256k1 },
104
+ )
105
+ const rpc = KeyAuthorization.toRpc(signed)
106
+ for (const account of [undefined, null])
107
+ expect(() => KeyAuthorization.fromRpc({ ...rpc, account })).toThrowError(
108
+ KeyAuthorization.MissingAccountError,
109
+ )
110
+ expect(() =>
111
+ KeyAuthorization.fromTuple([['0x01', '0x03', address]]),
112
+ ).toThrowError(KeyAuthorization.MissingAccountError)
113
+ expect(KeyAuthorization.fromRpc(rpc).account).toBe(address)
114
+ expect(
115
+ KeyAuthorization.deserialize(KeyAuthorization.serialize(signed)).account,
116
+ ).toBe(address)
117
+ })
118
+ })
119
+
81
120
  describe('from', () => {
121
+ test('accepts multisig grants and delegates', () => {
122
+ const signed = KeyAuthorization.from(
123
+ {
124
+ address,
125
+ chainId: 1n,
126
+ type: 'multisig',
127
+ account: signature_multisig.account,
128
+ },
129
+ { signature: signature_multisig },
130
+ )
131
+ expect(
132
+ KeyAuthorization.deserialize(KeyAuthorization.serialize(signed)),
133
+ ).toEqual(signed)
134
+ expect(KeyAuthorization.fromRpc(KeyAuthorization.toRpc(signed))).toEqual(
135
+ signed,
136
+ )
137
+ })
138
+ })
139
+
140
+ describe('fromRpc', () => {
82
141
  test('default', () => {
83
142
  const authorization = KeyAuthorization.from({
84
143
  address,
@@ -1112,17 +1171,16 @@ describe('getSignPayload', () => {
1112
1171
  describe('deserialize', () => {
1113
1172
  test('example: matches the frozen multisig witness vector', () => {
1114
1173
  const serialized =
1115
- '0xf8f1f85382107980941eff47bc3a10a45d4b230b5d10e37751fe6aa718808080a0535353535353535353535353535353535353535353535353535353535353535380949dba7f426b711d4893c11611eacf7cc334e7146bb89a05f897949dba7f426b711d4893c11611eacf7cc334e7146bf83ba000000000000000000000000000000000000000000000000000000000000000008001d7d6947e5f4552091a69125d5dfcb7b8c2659029395bdf01f843b8412cfed9350faf80e4115e3c4c967356b80a8e6ee42e4a49ab953c8c8a3537d8d8359bf035a9bea18f32b0da7129cdce3ce701abc09ad8919b93da21a0d57e21451b' as const
1174
+ '0xf8f1f85382107980941eff47bc3a10a45d4b230b5d10e37751fe6aa718808080a053535353535353535353535353535353535353535353535353535353535353538094c4a590afa7337e5cd5eb3aa60cacf91c5400044bb89a05f89794c4a590afa7337e5cd5eb3aa60cacf91c5400044bf83ba000000000000000000000000000000000000000000000000000000000000000008001d7d6947e5f4552091a69125d5dfcb7b8c2659029395bdf01f843b8412cfed9350faf80e4115e3c4c967356b80a8e6ee42e4a49ab953c8c8a3537d8d8359bf035a9bea18f32b0da7129cdce3ce701abc09ad8919b93da21a0d57e21451b' as const
1116
1175
  const authorization = KeyAuthorization.deserialize(serialized)
1117
1176
 
1118
1177
  expect(authorization).toMatchInlineSnapshot(`
1119
1178
  {
1120
- "account": "0x9dba7f426b711d4893c11611eacf7cc334e7146b",
1179
+ "account": "0xc4a590afa7337e5cd5eb3aa60cacf91c5400044b",
1121
1180
  "address": "0x1eff47bc3a10a45d4b230b5d10e37751fe6aa718",
1122
1181
  "chainId": 4217n,
1123
- "isAdmin": false,
1124
1182
  "signature": {
1125
- "account": "0x9dba7f426b711d4893c11611eacf7cc334e7146b",
1183
+ "account": "0xc4a590afa7337e5cd5eb3aa60cacf91c5400044b",
1126
1184
  "config": {
1127
1185
  "owners": [
1128
1186
  {
@@ -2544,11 +2602,11 @@ describe('admin keys (TIP-1049)', () => {
2544
2602
  expect((authTuple as unknown as unknown[]).length).toBe(3)
2545
2603
  })
2546
2604
 
2547
- test('fromTuple: drops orphan isAdmin without account', () => {
2605
+ test('fromTuple: preserves isAdmin without account', () => {
2548
2606
  const restored = KeyAuthorization.fromTuple([
2549
2607
  ['0x01', '0x', address, '0x', [], [], '0x', '0x01'],
2550
2608
  ])
2551
- expect(restored.isAdmin).toBeUndefined()
2609
+ expect(restored.isAdmin).toBe(true)
2552
2610
  expect(restored.account).toBeUndefined()
2553
2611
  })
2554
2612
 
@@ -2556,7 +2614,7 @@ describe('admin keys (TIP-1049)', () => {
2556
2614
  const restored = KeyAuthorization.fromTuple([
2557
2615
  ['0x01', '0x', address, '0x', [], [], '0x', '0x', account],
2558
2616
  ])
2559
- expect(restored.isAdmin).toBe(false)
2617
+ expect(restored.isAdmin).toBeUndefined()
2560
2618
  expect(restored.account).toBe(account)
2561
2619
  })
2562
2620
 
@@ -2602,7 +2660,7 @@ describe('admin keys (TIP-1049)', () => {
2602
2660
  })
2603
2661
  const serialized = KeyAuthorization.serialize(authorization)
2604
2662
  const restored = KeyAuthorization.deserialize(serialized)
2605
- expect(restored.isAdmin).toBe(false)
2663
+ expect(restored.isAdmin).toBeUndefined()
2606
2664
  expect(restored.account).toBe(account)
2607
2665
  })
2608
2666
 
@@ -2625,14 +2683,14 @@ describe('admin keys (TIP-1049)', () => {
2625
2683
  expect(restored.account).toBe(account)
2626
2684
  })
2627
2685
 
2628
- test('fromRpc: drops orphan isAdmin without account', () => {
2686
+ test('fromRpc: preserves isAdmin without account', () => {
2629
2687
  const authorization = KeyAuthorization.from(
2630
2688
  { address, chainId: 1n, type: 'secp256k1' },
2631
2689
  { signature: SignatureEnvelope.from(signature_secp256k1) },
2632
2690
  )
2633
2691
  const rpc = KeyAuthorization.toRpc(authorization)
2634
2692
  const restored = KeyAuthorization.fromRpc({ ...rpc, isAdmin: true })
2635
- expect(restored.isAdmin).toBeUndefined()
2693
+ expect(restored.isAdmin).toBe(true)
2636
2694
  expect(restored.account).toBeUndefined()
2637
2695
  })
2638
2696
 
@@ -2643,7 +2701,7 @@ describe('admin keys (TIP-1049)', () => {
2643
2701
  )
2644
2702
  const rpc = KeyAuthorization.toRpc(authorization)
2645
2703
  const restored = KeyAuthorization.fromRpc({ ...rpc, account })
2646
- expect(restored.isAdmin).toBe(false)
2704
+ expect(restored.isAdmin).toBeUndefined()
2647
2705
  expect(restored.account).toBe(account)
2648
2706
  })
2649
2707