tempo.ts 0.7.6 → 0.8.1

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 (150) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/chains.d.ts +6 -20
  3. package/dist/chains.d.ts.map +1 -1
  4. package/dist/chains.js +14 -15
  5. package/dist/chains.js.map +1 -1
  6. package/dist/ox/KeyAuthorization.d.ts +356 -0
  7. package/dist/ox/KeyAuthorization.d.ts.map +1 -0
  8. package/dist/ox/KeyAuthorization.js +360 -0
  9. package/dist/ox/KeyAuthorization.js.map +1 -0
  10. package/dist/ox/SignatureEnvelope.d.ts +21 -6
  11. package/dist/ox/SignatureEnvelope.d.ts.map +1 -1
  12. package/dist/ox/SignatureEnvelope.js +43 -3
  13. package/dist/ox/SignatureEnvelope.js.map +1 -1
  14. package/dist/ox/Transaction.d.ts +5 -1
  15. package/dist/ox/Transaction.d.ts.map +1 -1
  16. package/dist/ox/Transaction.js +5 -0
  17. package/dist/ox/Transaction.js.map +1 -1
  18. package/dist/ox/TransactionEnvelopeAA.d.ts +9 -0
  19. package/dist/ox/TransactionEnvelopeAA.d.ts.map +1 -1
  20. package/dist/ox/TransactionEnvelopeAA.js +17 -4
  21. package/dist/ox/TransactionEnvelopeAA.js.map +1 -1
  22. package/dist/ox/TransactionRequest.d.ts +7 -1
  23. package/dist/ox/TransactionRequest.d.ts.map +1 -1
  24. package/dist/ox/TransactionRequest.js +12 -0
  25. package/dist/ox/TransactionRequest.js.map +1 -1
  26. package/dist/ox/index.d.ts +1 -0
  27. package/dist/ox/index.d.ts.map +1 -1
  28. package/dist/ox/index.js +1 -0
  29. package/dist/ox/index.js.map +1 -1
  30. package/dist/prool/Instance.js +1 -1
  31. package/dist/prool/Instance.js.map +1 -1
  32. package/{src/prool/internal → dist/prool}/chain.json +4 -2
  33. package/dist/viem/Abis.d.ts +319 -6
  34. package/dist/viem/Abis.d.ts.map +1 -1
  35. package/dist/viem/Abis.js +199 -7
  36. package/dist/viem/Abis.js.map +1 -1
  37. package/dist/viem/Account.d.ts +103 -14
  38. package/dist/viem/Account.d.ts.map +1 -1
  39. package/dist/viem/Account.js +177 -23
  40. package/dist/viem/Account.js.map +1 -1
  41. package/dist/viem/Actions/account.d.ts.map +1 -1
  42. package/dist/viem/Actions/account.js +4 -5
  43. package/dist/viem/Actions/account.js.map +1 -1
  44. package/dist/viem/Actions/amm.d.ts +72 -0
  45. package/dist/viem/Actions/amm.d.ts.map +1 -1
  46. package/dist/viem/Actions/dex.d.ts +156 -4
  47. package/dist/viem/Actions/dex.d.ts.map +1 -1
  48. package/dist/viem/Actions/fee.d.ts +4 -0
  49. package/dist/viem/Actions/fee.d.ts.map +1 -1
  50. package/dist/viem/Actions/reward.d.ts +158 -0
  51. package/dist/viem/Actions/reward.d.ts.map +1 -1
  52. package/dist/viem/Actions/reward.js +54 -0
  53. package/dist/viem/Actions/reward.js.map +1 -1
  54. package/dist/viem/Actions/token.d.ts +585 -0
  55. package/dist/viem/Actions/token.d.ts.map +1 -1
  56. package/dist/viem/Actions/token.js +2 -2
  57. package/dist/viem/Actions/token.js.map +1 -1
  58. package/dist/viem/Addresses.d.ts +1 -1
  59. package/dist/viem/Addresses.d.ts.map +1 -1
  60. package/dist/viem/Addresses.js +1 -1
  61. package/dist/viem/Addresses.js.map +1 -1
  62. package/dist/viem/Chain.d.ts +35 -0
  63. package/dist/viem/Chain.d.ts.map +1 -1
  64. package/dist/viem/Chain.js +37 -0
  65. package/dist/viem/Chain.js.map +1 -1
  66. package/dist/viem/Decorator.d.ts +74 -0
  67. package/dist/viem/Decorator.d.ts.map +1 -1
  68. package/dist/viem/Decorator.js +3 -0
  69. package/dist/viem/Decorator.js.map +1 -1
  70. package/dist/viem/Formatters.d.ts.map +1 -1
  71. package/dist/viem/Formatters.js +8 -7
  72. package/dist/viem/Formatters.js.map +1 -1
  73. package/dist/viem/Storage.d.ts +1 -0
  74. package/dist/viem/Storage.d.ts.map +1 -1
  75. package/dist/viem/Storage.js +21 -0
  76. package/dist/viem/Storage.js.map +1 -1
  77. package/dist/viem/TokenIds.d.ts +1 -1
  78. package/dist/viem/TokenIds.d.ts.map +1 -1
  79. package/dist/viem/TokenIds.js +1 -1
  80. package/dist/viem/TokenIds.js.map +1 -1
  81. package/dist/viem/Transaction.d.ts +9 -1
  82. package/dist/viem/Transaction.d.ts.map +1 -1
  83. package/dist/viem/Transaction.js +2 -1
  84. package/dist/viem/Transaction.js.map +1 -1
  85. package/dist/viem/WebAuthnP256.d.ts +4 -1
  86. package/dist/viem/WebAuthnP256.d.ts.map +1 -1
  87. package/dist/viem/WebAuthnP256.js +3 -1
  88. package/dist/viem/WebAuthnP256.js.map +1 -1
  89. package/dist/wagmi/Actions/reward.d.ts +44 -0
  90. package/dist/wagmi/Actions/reward.d.ts.map +1 -1
  91. package/dist/wagmi/Actions/reward.js +49 -0
  92. package/dist/wagmi/Actions/reward.js.map +1 -1
  93. package/dist/wagmi/Connector.d.ts +25 -8
  94. package/dist/wagmi/Connector.d.ts.map +1 -1
  95. package/dist/wagmi/Connector.js +120 -27
  96. package/dist/wagmi/Connector.js.map +1 -1
  97. package/dist/wagmi/Hooks/reward.d.ts +32 -0
  98. package/dist/wagmi/Hooks/reward.d.ts.map +1 -1
  99. package/dist/wagmi/Hooks/reward.js +39 -0
  100. package/dist/wagmi/Hooks/reward.js.map +1 -1
  101. package/package.json +3 -2
  102. package/src/chains.ts +14 -15
  103. package/src/ox/KeyAuthorization.test.ts +1332 -0
  104. package/src/ox/KeyAuthorization.ts +542 -0
  105. package/src/ox/SignatureEnvelope.test.ts +624 -0
  106. package/src/ox/SignatureEnvelope.ts +89 -9
  107. package/src/ox/Transaction.test.ts +214 -0
  108. package/src/ox/Transaction.ts +13 -1
  109. package/src/ox/TransactionEnvelopeAA.test.ts +164 -4
  110. package/src/ox/TransactionEnvelopeAA.ts +36 -3
  111. package/src/ox/TransactionRequest.ts +22 -1
  112. package/src/ox/e2e.test.ts +612 -5
  113. package/src/ox/index.ts +1 -0
  114. package/src/prool/Instance.ts +1 -1
  115. package/src/prool/chain.json +238 -0
  116. package/src/server/Handler.test.ts +20 -36
  117. package/src/viem/Abis.ts +200 -7
  118. package/src/viem/Account.test.ts +444 -0
  119. package/src/viem/Account.ts +355 -42
  120. package/src/viem/Actions/account.ts +3 -5
  121. package/src/viem/Actions/amm.test.ts +4 -4
  122. package/src/viem/Actions/reward.test.ts +84 -0
  123. package/src/viem/Actions/reward.ts +73 -0
  124. package/src/viem/Actions/token.test.ts +8 -8
  125. package/src/viem/Actions/token.ts +2 -2
  126. package/src/viem/Addresses.ts +1 -1
  127. package/src/viem/Chain.test.ts +168 -0
  128. package/src/viem/Chain.ts +37 -1
  129. package/src/viem/Decorator.ts +84 -0
  130. package/src/viem/Formatters.ts +8 -7
  131. package/src/viem/Storage.ts +22 -0
  132. package/src/viem/TokenIds.ts +1 -1
  133. package/src/viem/Transaction.ts +14 -2
  134. package/src/viem/WebAuthnP256.ts +8 -2
  135. package/src/viem/e2e.test.ts +299 -96
  136. package/src/wagmi/Actions/amm.test.ts +2 -2
  137. package/src/wagmi/Actions/reward.test.ts +36 -0
  138. package/src/wagmi/Actions/reward.ts +91 -0
  139. package/src/wagmi/Connector.test.ts +1 -1
  140. package/src/wagmi/Connector.ts +184 -54
  141. package/src/wagmi/Hooks/amm.test.ts +4 -4
  142. package/src/wagmi/Hooks/fee.test.ts +10 -4
  143. package/src/wagmi/Hooks/reward.test.ts +72 -0
  144. package/src/wagmi/Hooks/reward.ts +68 -0
  145. package/src/wagmi/Hooks/token.test.ts +0 -488
  146. package/dist/viem/internal/account.d.ts +0 -21
  147. package/dist/viem/internal/account.d.ts.map +0 -1
  148. package/dist/viem/internal/account.js +0 -61
  149. package/dist/viem/internal/account.js.map +0 -1
  150. package/src/viem/internal/account.ts +0 -89
@@ -37,6 +37,22 @@ const signature_webauthn = SignatureEnvelope.from({
37
37
  },
38
38
  })
39
39
 
40
+ // Keychain signatures with different inner types
41
+ const signature_keychain_secp256k1 = SignatureEnvelope.from({
42
+ userAddress: '0x1234567890123456789012345678901234567890',
43
+ inner: SignatureEnvelope.from(signature_secp256k1),
44
+ })
45
+
46
+ const signature_keychain_p256 = SignatureEnvelope.from({
47
+ userAddress: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd',
48
+ inner: signature_p256,
49
+ })
50
+
51
+ const signature_keychain_webauthn = SignatureEnvelope.from({
52
+ userAddress: '0xfedcbafedcbafedcbafedcbafedcbafedcbafedc',
53
+ inner: signature_webauthn,
54
+ })
55
+
40
56
  describe('assert', () => {
41
57
  describe('secp256k1', () => {
42
58
  test('behavior: validates valid signature', () => {
@@ -383,6 +399,47 @@ describe('assert', () => {
383
399
  })
384
400
  })
385
401
 
402
+ describe('keychain', () => {
403
+ test('behavior: validates valid keychain with secp256k1 inner', () => {
404
+ expect(() =>
405
+ SignatureEnvelope.assert(signature_keychain_secp256k1),
406
+ ).not.toThrow()
407
+ })
408
+
409
+ test('behavior: validates valid keychain with p256 inner', () => {
410
+ expect(() =>
411
+ SignatureEnvelope.assert(signature_keychain_p256),
412
+ ).not.toThrow()
413
+ })
414
+
415
+ test('behavior: validates valid keychain with webAuthn inner', () => {
416
+ expect(() =>
417
+ SignatureEnvelope.assert(signature_keychain_webauthn),
418
+ ).not.toThrow()
419
+ })
420
+
421
+ test('behavior: validates keychain without explicit type', () => {
422
+ const { type: _, ...signatureWithoutType } = signature_keychain_secp256k1
423
+ expect(() => SignatureEnvelope.assert(signatureWithoutType)).not.toThrow()
424
+ })
425
+
426
+ test('error: throws on invalid inner signature', () => {
427
+ expect(() =>
428
+ SignatureEnvelope.assert({
429
+ userAddress: '0x1234567890123456789012345678901234567890',
430
+ inner: SignatureEnvelope.from({
431
+ r: 0n,
432
+ s: 0n,
433
+ yParity: 2,
434
+ }),
435
+ type: 'keychain',
436
+ } as any),
437
+ ).toThrowErrorMatchingInlineSnapshot(
438
+ `[Signature.InvalidYParityError: Value \`2\` is an invalid y-parity value. Y-parity must be 0 or 1.]`,
439
+ )
440
+ })
441
+ })
442
+
386
443
  test('error: throws on invalid envelope', () => {
387
444
  expect(() =>
388
445
  SignatureEnvelope.assert({} as any),
@@ -549,6 +606,86 @@ describe('deserialize', () => {
549
606
  )
550
607
  })
551
608
  })
609
+
610
+ describe('keychain', () => {
611
+ test('behavior: deserializes keychain signature with secp256k1 inner', () => {
612
+ const serialized = SignatureEnvelope.serialize(
613
+ signature_keychain_secp256k1,
614
+ )
615
+ const deserialized = SignatureEnvelope.deserialize(serialized)
616
+
617
+ expect(deserialized).toMatchObject({
618
+ userAddress: signature_keychain_secp256k1.userAddress,
619
+ inner: SignatureEnvelope.from(signature_secp256k1),
620
+ type: 'keychain',
621
+ })
622
+ })
623
+
624
+ test('behavior: deserializes keychain signature with p256 inner', () => {
625
+ const serialized = SignatureEnvelope.serialize(signature_keychain_p256)
626
+ const deserialized = SignatureEnvelope.deserialize(serialized)
627
+
628
+ expect(deserialized).toMatchInlineSnapshot(`
629
+ {
630
+ "inner": {
631
+ "prehash": true,
632
+ "publicKey": {
633
+ "prefix": 4,
634
+ "x": 78495282704852028275327922540131762143565388050940484317945369745559774511861n,
635
+ "y": 8109764566587999957624872393871720746996669263962991155166704261108473113504n,
636
+ },
637
+ "signature": {
638
+ "r": 92602584010956101470289867944347135737570451066466093224269890121909314569518n,
639
+ "s": 54171125190222965779385658110416711469231271457324878825831748147306957269813n,
640
+ },
641
+ "type": "p256",
642
+ },
643
+ "type": "keychain",
644
+ "userAddress": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
645
+ }
646
+ `)
647
+ })
648
+
649
+ test('behavior: deserializes keychain signature with webAuthn inner', () => {
650
+ const serialized = SignatureEnvelope.serialize(
651
+ signature_keychain_webauthn,
652
+ )
653
+ const deserialized = SignatureEnvelope.deserialize(serialized)
654
+
655
+ expect(deserialized).toMatchInlineSnapshot(`
656
+ {
657
+ "inner": {
658
+ "metadata": {
659
+ "authenticatorData": "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000",
660
+ "clientDataJSON": "{"type":"webauthn.get","challenge":"3q2-7w","origin":"http://localhost","crossOrigin":false}",
661
+ },
662
+ "publicKey": {
663
+ "prefix": 4,
664
+ "x": 78495282704852028275327922540131762143565388050940484317945369745559774511861n,
665
+ "y": 8109764566587999957624872393871720746996669263962991155166704261108473113504n,
666
+ },
667
+ "signature": {
668
+ "r": 92602584010956101470289867944347135737570451066466093224269890121909314569518n,
669
+ "s": 54171125190222965779385658110416711469231271457324878825831748147306957269813n,
670
+ },
671
+ "type": "webAuthn",
672
+ },
673
+ "type": "keychain",
674
+ "userAddress": "0xfedcbafedcbafedcbafedcbafedcbafedcbafedc",
675
+ }
676
+ `)
677
+ })
678
+
679
+ test('error: throws on invalid keychain signature length', () => {
680
+ // Keychain signature too short (must be at least 21 bytes: 1 type + 20 address)
681
+ const invalidSig = `0x03${'00'.repeat(10)}` as const
682
+ expect(() =>
683
+ SignatureEnvelope.deserialize(invalidSig),
684
+ ).toThrowErrorMatchingInlineSnapshot(
685
+ `[Hex.SliceOffsetOutOfBoundsError: Slice starting at offset \`20\` is out-of-bounds (size: \`10\`).]`,
686
+ )
687
+ })
688
+ })
552
689
  })
553
690
 
554
691
  describe('from', () => {
@@ -636,6 +773,38 @@ describe('from', () => {
636
773
  expect(envelope.type).toBe('webAuthn')
637
774
  })
638
775
  })
776
+
777
+ describe('keychain', () => {
778
+ test('behavior: coerces from hex string with secp256k1 inner', () => {
779
+ const serialized = SignatureEnvelope.serialize(
780
+ signature_keychain_secp256k1,
781
+ )
782
+ const envelope = SignatureEnvelope.from(serialized)
783
+
784
+ expect(envelope).toMatchObject({
785
+ userAddress: signature_keychain_secp256k1.userAddress,
786
+ inner: SignatureEnvelope.from(signature_secp256k1),
787
+ type: 'keychain',
788
+ })
789
+ })
790
+
791
+ test('behavior: coerces from hex string with p256 inner', () => {
792
+ const serialized = SignatureEnvelope.serialize(signature_keychain_p256)
793
+ const envelope = SignatureEnvelope.from(serialized)
794
+
795
+ expect(envelope).toMatchObject({
796
+ userAddress: signature_keychain_p256.userAddress,
797
+ type: 'keychain',
798
+ })
799
+ })
800
+
801
+ test('behavior: adds type to object', () => {
802
+ const { type: _, ...withoutType } = signature_keychain_secp256k1
803
+ const envelope = SignatureEnvelope.from(withoutType)
804
+
805
+ expect(envelope.type).toBe('keychain')
806
+ })
807
+ })
639
808
  })
640
809
 
641
810
  describe('getType', () => {
@@ -683,6 +852,29 @@ describe('getType', () => {
683
852
  })
684
853
  })
685
854
 
855
+ describe('keychain', () => {
856
+ test('behavior: returns explicit type', () => {
857
+ expect(SignatureEnvelope.getType(signature_keychain_secp256k1)).toBe(
858
+ 'keychain',
859
+ )
860
+ })
861
+
862
+ test('behavior: infers type from properties', () => {
863
+ const { type: _, ...signatureWithoutType } = signature_keychain_secp256k1
864
+ expect(SignatureEnvelope.getType(signatureWithoutType)).toBe('keychain')
865
+ })
866
+
867
+ test('behavior: infers type for keychain with p256 inner', () => {
868
+ const { type: _, ...signatureWithoutType } = signature_keychain_p256
869
+ expect(SignatureEnvelope.getType(signatureWithoutType)).toBe('keychain')
870
+ })
871
+
872
+ test('behavior: infers type for keychain with webAuthn inner', () => {
873
+ const { type: _, ...signatureWithoutType } = signature_keychain_webauthn
874
+ expect(SignatureEnvelope.getType(signatureWithoutType)).toBe('keychain')
875
+ })
876
+ })
877
+
686
878
  test('error: throws on invalid envelope', () => {
687
879
  expect(() =>
688
880
  SignatureEnvelope.getType({} as any),
@@ -776,6 +968,83 @@ describe('serialize', () => {
776
968
  })
777
969
  })
778
970
 
971
+ describe('keychain', () => {
972
+ test('behavior: serializes keychain signature with secp256k1 inner and type identifier', () => {
973
+ const serialized = SignatureEnvelope.serialize(
974
+ signature_keychain_secp256k1,
975
+ )
976
+
977
+ // Should be: 1 (type) + 20 (address) + 65 (secp256k1 signature)
978
+ expect(Hex.size(serialized)).toBe(1 + 20 + 65)
979
+
980
+ // First byte should be Keychain type identifier (0x03)
981
+ expect(Hex.slice(serialized, 0, 1)).toBe('0x03')
982
+
983
+ // Next 20 bytes should be the user address (without '0x')
984
+ expect(Hex.slice(serialized, 1, 21)).toBe(
985
+ signature_keychain_secp256k1.userAddress,
986
+ )
987
+ })
988
+
989
+ test('behavior: serializes keychain signature with p256 inner', () => {
990
+ const serialized = SignatureEnvelope.serialize(signature_keychain_p256)
991
+
992
+ // Should be: 1 (type) + 20 (address) + 130 (p256 signature with type)
993
+ expect(Hex.size(serialized)).toBe(1 + 20 + 130)
994
+
995
+ // First byte should be Keychain type identifier (0x03)
996
+ expect(Hex.slice(serialized, 0, 1)).toBe('0x03')
997
+
998
+ // Next 20 bytes should be the user address (without '0x')
999
+ expect(Hex.slice(serialized, 1, 21)).toBe(
1000
+ signature_keychain_p256.userAddress,
1001
+ )
1002
+
1003
+ // Next 130 bytes should be the p256 signature
1004
+ expect(Hex.slice(serialized, 21, 151)).toBe(
1005
+ SignatureEnvelope.serialize(signature_p256),
1006
+ )
1007
+ })
1008
+
1009
+ test('behavior: serializes keychain signature with webAuthn inner', () => {
1010
+ const serialized = SignatureEnvelope.serialize(
1011
+ signature_keychain_webauthn,
1012
+ )
1013
+
1014
+ // First byte should be Keychain type identifier (0x03)
1015
+ expect(Hex.slice(serialized, 0, 1)).toBe('0x03')
1016
+
1017
+ // Should contain the user address
1018
+ expect(Hex.slice(serialized, 1, 21)).toBe(
1019
+ signature_keychain_webauthn.userAddress,
1020
+ )
1021
+
1022
+ // Next N bytes should be the webAuthn signature
1023
+ expect(Hex.slice(serialized, 21)).toBe(
1024
+ SignatureEnvelope.serialize(signature_webauthn),
1025
+ )
1026
+ })
1027
+
1028
+ test('behavior: preserves userAddress and inner signature', () => {
1029
+ const serialized = SignatureEnvelope.serialize(
1030
+ signature_keychain_secp256k1,
1031
+ )
1032
+ const deserialized = SignatureEnvelope.deserialize(serialized)
1033
+
1034
+ expect(deserialized.userAddress).toBe(
1035
+ signature_keychain_secp256k1.userAddress,
1036
+ )
1037
+ expect(deserialized.inner).toMatchObject({
1038
+ type: 'secp256k1',
1039
+ signature: {
1040
+ r: signature_secp256k1.r,
1041
+ s: signature_secp256k1.s,
1042
+ yParity: signature_secp256k1.yParity,
1043
+ },
1044
+ })
1045
+ })
1046
+ })
1047
+
779
1048
  describe('roundtrip', () => {
780
1049
  describe('secp256k1', () => {
781
1050
  test('behavior: roundtrips serialize -> deserialize', () => {
@@ -869,6 +1138,72 @@ describe('serialize', () => {
869
1138
  expect(deserialized.metadata?.clientDataJSON).toBe(longClientData)
870
1139
  })
871
1140
  })
1141
+
1142
+ describe('keychain', () => {
1143
+ test('behavior: roundtrips serialize -> deserialize with secp256k1 inner', () => {
1144
+ const serialized = SignatureEnvelope.serialize(
1145
+ signature_keychain_secp256k1,
1146
+ )
1147
+ const deserialized = SignatureEnvelope.deserialize(serialized)
1148
+
1149
+ expect(deserialized).toMatchObject(signature_keychain_secp256k1)
1150
+ })
1151
+
1152
+ test('behavior: roundtrips serialize -> deserialize with p256 inner', () => {
1153
+ const serialized = SignatureEnvelope.serialize(signature_keychain_p256)
1154
+ const deserialized = SignatureEnvelope.deserialize(serialized)
1155
+
1156
+ expect(deserialized).toMatchInlineSnapshot(`
1157
+ {
1158
+ "inner": {
1159
+ "prehash": true,
1160
+ "publicKey": {
1161
+ "prefix": 4,
1162
+ "x": 78495282704852028275327922540131762143565388050940484317945369745559774511861n,
1163
+ "y": 8109764566587999957624872393871720746996669263962991155166704261108473113504n,
1164
+ },
1165
+ "signature": {
1166
+ "r": 92602584010956101470289867944347135737570451066466093224269890121909314569518n,
1167
+ "s": 54171125190222965779385658110416711469231271457324878825831748147306957269813n,
1168
+ },
1169
+ "type": "p256",
1170
+ },
1171
+ "type": "keychain",
1172
+ "userAddress": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
1173
+ }
1174
+ `)
1175
+ })
1176
+
1177
+ test('behavior: roundtrips serialize -> deserialize with webAuthn inner', () => {
1178
+ const serialized = SignatureEnvelope.serialize(
1179
+ signature_keychain_webauthn,
1180
+ )
1181
+ const deserialized = SignatureEnvelope.deserialize(serialized)
1182
+
1183
+ expect(deserialized).toMatchInlineSnapshot(`
1184
+ {
1185
+ "inner": {
1186
+ "metadata": {
1187
+ "authenticatorData": "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000",
1188
+ "clientDataJSON": "{"type":"webauthn.get","challenge":"3q2-7w","origin":"http://localhost","crossOrigin":false}",
1189
+ },
1190
+ "publicKey": {
1191
+ "prefix": 4,
1192
+ "x": 78495282704852028275327922540131762143565388050940484317945369745559774511861n,
1193
+ "y": 8109764566587999957624872393871720746996669263962991155166704261108473113504n,
1194
+ },
1195
+ "signature": {
1196
+ "r": 92602584010956101470289867944347135737570451066466093224269890121909314569518n,
1197
+ "s": 54171125190222965779385658110416711469231271457324878825831748147306957269813n,
1198
+ },
1199
+ "type": "webAuthn",
1200
+ },
1201
+ "type": "keychain",
1202
+ "userAddress": "0xfedcbafedcbafedcbafedcbafedcbafedcbafedc",
1203
+ }
1204
+ `)
1205
+ })
1206
+ })
872
1207
  })
873
1208
 
874
1209
  test('error: throws on invalid envelope', () => {
@@ -943,6 +1278,39 @@ describe('validate', () => {
943
1278
  })
944
1279
  })
945
1280
 
1281
+ describe('keychain', () => {
1282
+ test('behavior: returns true for valid keychain with secp256k1 inner', () => {
1283
+ expect(SignatureEnvelope.validate(signature_keychain_secp256k1)).toBe(
1284
+ true,
1285
+ )
1286
+ })
1287
+
1288
+ test('behavior: returns true for valid keychain with p256 inner', () => {
1289
+ expect(SignatureEnvelope.validate(signature_keychain_p256)).toBe(true)
1290
+ })
1291
+
1292
+ test('behavior: returns true for valid keychain with webAuthn inner', () => {
1293
+ expect(SignatureEnvelope.validate(signature_keychain_webauthn)).toBe(true)
1294
+ })
1295
+
1296
+ test('behavior: returns false for invalid keychain signature', () => {
1297
+ expect(
1298
+ SignatureEnvelope.validate({
1299
+ userAddress: '0x1234567890123456789012345678901234567890',
1300
+ inner: {
1301
+ signature: {
1302
+ r: 0n,
1303
+ s: 0n,
1304
+ yParity: 2,
1305
+ },
1306
+ type: 'secp256k1',
1307
+ },
1308
+ type: 'keychain',
1309
+ } as any),
1310
+ ).toBe(false)
1311
+ })
1312
+ })
1313
+
946
1314
  test('behavior: returns false for invalid envelope', () => {
947
1315
  expect(SignatureEnvelope.validate({} as any)).toBe(false)
948
1316
  })
@@ -1046,6 +1414,118 @@ describe('fromRpc', () => {
1046
1414
  })
1047
1415
  })
1048
1416
  })
1417
+
1418
+ describe('keychain', () => {
1419
+ test('behavior: converts RPC keychain signature with secp256k1 inner', () => {
1420
+ const rpc: SignatureEnvelope.KeychainRpc = {
1421
+ type: 'keychain',
1422
+ userAddress: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
1423
+ signature: {
1424
+ type: 'secp256k1',
1425
+ r: '0xa2bb71146c20ce932456c043ebb2973ed205e07cd32c35a60bdefca1285fd132',
1426
+ s: '0x7cba10692bccdbfba9a215418443c2903dbee6fe5cb55c91172e47efc607840e',
1427
+ yParity: '0x1',
1428
+ },
1429
+ }
1430
+
1431
+ const envelope = SignatureEnvelope.fromRpc(rpc)
1432
+
1433
+ expect(envelope).toMatchObject({
1434
+ type: 'keychain',
1435
+ userAddress: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
1436
+ inner: {
1437
+ type: 'secp256k1',
1438
+ signature: {
1439
+ r: 0xa2bb71146c20ce932456c043ebb2973ed205e07cd32c35a60bdefca1285fd132n,
1440
+ s: 0x7cba10692bccdbfba9a215418443c2903dbee6fe5cb55c91172e47efc607840en,
1441
+ yParity: 1,
1442
+ },
1443
+ },
1444
+ })
1445
+ })
1446
+
1447
+ test('behavior: converts RPC keychain signature with p256 inner', () => {
1448
+ const rpc: SignatureEnvelope.KeychainRpc = {
1449
+ type: 'keychain',
1450
+ userAddress: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd',
1451
+ signature: {
1452
+ prehash: true,
1453
+ pubKeyX: Hex.fromNumber(publicKey.x, { size: 32 }),
1454
+ pubKeyY: Hex.fromNumber(publicKey.y, { size: 32 }),
1455
+ r: Hex.fromNumber(p256Signature.r, { size: 32 }),
1456
+ s: Hex.fromNumber(p256Signature.s, { size: 32 }),
1457
+ type: 'p256',
1458
+ },
1459
+ }
1460
+
1461
+ const envelope = SignatureEnvelope.fromRpc(rpc)
1462
+
1463
+ expect(envelope).toMatchObject({
1464
+ type: 'keychain',
1465
+ userAddress: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd',
1466
+ inner: {
1467
+ type: 'p256',
1468
+ prehash: true,
1469
+ publicKey: {
1470
+ x: publicKey.x,
1471
+ y: publicKey.y,
1472
+ },
1473
+ signature: {
1474
+ r: p256Signature.r,
1475
+ s: p256Signature.s,
1476
+ },
1477
+ },
1478
+ })
1479
+ })
1480
+
1481
+ test('behavior: converts RPC keychain signature with webAuthn inner', () => {
1482
+ const webauthnData = WebAuthnP256.getAuthenticatorData({
1483
+ rpId: 'localhost',
1484
+ })
1485
+ const clientDataJSON = WebAuthnP256.getClientDataJSON({
1486
+ challenge: '0xdeadbeef',
1487
+ origin: 'http://localhost',
1488
+ })
1489
+
1490
+ const rpc: SignatureEnvelope.KeychainRpc = {
1491
+ type: 'keychain',
1492
+ userAddress: '0xfedcbafedcbafedcbafedcbafedcbafedcbafedc',
1493
+ signature: {
1494
+ pubKeyX: Hex.fromNumber(publicKey.x, { size: 32 }),
1495
+ pubKeyY: Hex.fromNumber(publicKey.y, { size: 32 }),
1496
+ r: Hex.fromNumber(p256Signature.r, { size: 32 }),
1497
+ s: Hex.fromNumber(p256Signature.s, { size: 32 }),
1498
+ type: 'webAuthn',
1499
+ webauthnData: Hex.concat(
1500
+ webauthnData,
1501
+ Hex.fromString(clientDataJSON),
1502
+ ),
1503
+ },
1504
+ }
1505
+
1506
+ const envelope = SignatureEnvelope.fromRpc(rpc)
1507
+
1508
+ expect(envelope).toMatchObject({
1509
+ type: 'keychain',
1510
+ userAddress: '0xfedcbafedcbafedcbafedcbafedcbafedcbafedc',
1511
+ inner: {
1512
+ type: 'webAuthn',
1513
+ metadata: {
1514
+ authenticatorData: webauthnData,
1515
+ clientDataJSON,
1516
+ },
1517
+ publicKey: {
1518
+ x: publicKey.x,
1519
+ y: publicKey.y,
1520
+ },
1521
+ signature: {
1522
+ r: p256Signature.r,
1523
+ s: p256Signature.s,
1524
+ },
1525
+ },
1526
+ })
1527
+ })
1528
+ })
1049
1529
  })
1050
1530
 
1051
1531
  describe('toRpc', () => {
@@ -1113,6 +1593,56 @@ describe('toRpc', () => {
1113
1593
  )
1114
1594
  })
1115
1595
  })
1596
+
1597
+ describe('keychain', () => {
1598
+ test('behavior: converts keychain signature with secp256k1 inner to RPC', () => {
1599
+ const envelope: SignatureEnvelope.Keychain = {
1600
+ type: 'keychain',
1601
+ userAddress: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
1602
+ inner: {
1603
+ signature: signature_secp256k1,
1604
+ type: 'secp256k1',
1605
+ },
1606
+ }
1607
+
1608
+ const rpc = SignatureEnvelope.toRpc(
1609
+ envelope,
1610
+ ) as SignatureEnvelope.KeychainRpc
1611
+
1612
+ expect(rpc.type).toBe('keychain')
1613
+ expect(rpc.userAddress).toBe('0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266')
1614
+ expect(rpc.signature).toMatchObject({
1615
+ r: Signature.toRpc(signature_secp256k1).r,
1616
+ s: Signature.toRpc(signature_secp256k1).s,
1617
+ yParity: Signature.toRpc(signature_secp256k1).yParity,
1618
+ type: 'secp256k1',
1619
+ })
1620
+ })
1621
+
1622
+ test('behavior: converts keychain signature with p256 inner to RPC', () => {
1623
+ const rpc = SignatureEnvelope.toRpc(
1624
+ signature_keychain_p256,
1625
+ ) as SignatureEnvelope.KeychainRpc
1626
+
1627
+ expect(rpc.type).toBe('keychain')
1628
+ expect(rpc.userAddress).toBe(signature_keychain_p256.userAddress)
1629
+ expect(rpc.signature.type).toBe('p256')
1630
+ expect(typeof rpc.signature.pubKeyX).toBe('string')
1631
+ expect(typeof rpc.signature.pubKeyY).toBe('string')
1632
+ })
1633
+
1634
+ test('behavior: converts keychain signature with webAuthn inner to RPC', () => {
1635
+ const rpc = SignatureEnvelope.toRpc(
1636
+ signature_keychain_webauthn,
1637
+ ) as SignatureEnvelope.KeychainRpc
1638
+
1639
+ expect(rpc.type).toBe('keychain')
1640
+ expect(rpc.userAddress).toBe(signature_keychain_webauthn.userAddress)
1641
+ expect(rpc.signature.type).toBe('webAuthn')
1642
+ expect(typeof rpc.signature.pubKeyX).toBe('string')
1643
+ expect(typeof rpc.signature.webauthnData).toBe('string')
1644
+ })
1645
+ })
1116
1646
  })
1117
1647
 
1118
1648
  describe('roundtrip: toRpc <-> fromRpc', () => {
@@ -1223,6 +1753,100 @@ describe('roundtrip: toRpc <-> fromRpc', () => {
1223
1753
  expect(roundtripped.metadata?.clientDataJSON).toBe(longClientData)
1224
1754
  })
1225
1755
  })
1756
+
1757
+ describe('keychain', () => {
1758
+ test('behavior: roundtrips toRpc -> fromRpc with secp256k1 inner', () => {
1759
+ const envelope: SignatureEnvelope.Keychain = {
1760
+ type: 'keychain',
1761
+ userAddress: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
1762
+ inner: {
1763
+ signature: signature_secp256k1,
1764
+ type: 'secp256k1',
1765
+ },
1766
+ }
1767
+
1768
+ const rpc = SignatureEnvelope.toRpc(envelope)
1769
+ const roundtripped = SignatureEnvelope.fromRpc(rpc)
1770
+
1771
+ expect(roundtripped).toMatchObject({
1772
+ type: 'keychain',
1773
+ userAddress: envelope.userAddress,
1774
+ inner: {
1775
+ type: 'secp256k1',
1776
+ signature: {
1777
+ r: signature_secp256k1.r,
1778
+ s: signature_secp256k1.s,
1779
+ yParity: signature_secp256k1.yParity,
1780
+ },
1781
+ },
1782
+ })
1783
+ })
1784
+
1785
+ test('behavior: roundtrips toRpc -> fromRpc with p256 inner', () => {
1786
+ const rpc = SignatureEnvelope.toRpc(signature_keychain_p256)
1787
+ const roundtripped = SignatureEnvelope.fromRpc(rpc)
1788
+
1789
+ expect(roundtripped).toMatchObject({
1790
+ type: 'keychain',
1791
+ userAddress: signature_keychain_p256.userAddress,
1792
+ inner: {
1793
+ type: 'p256',
1794
+ prehash: signature_p256.prehash,
1795
+ publicKey: {
1796
+ x: signature_p256.publicKey.x,
1797
+ y: signature_p256.publicKey.y,
1798
+ },
1799
+ signature: {
1800
+ r: signature_p256.signature.r,
1801
+ s: signature_p256.signature.s,
1802
+ },
1803
+ },
1804
+ })
1805
+ })
1806
+
1807
+ test('behavior: roundtrips toRpc -> fromRpc with webAuthn inner', () => {
1808
+ const rpc = SignatureEnvelope.toRpc(signature_keychain_webauthn)
1809
+ const roundtripped = SignatureEnvelope.fromRpc(rpc)
1810
+
1811
+ expect(roundtripped).toMatchObject({
1812
+ type: 'keychain',
1813
+ userAddress: signature_keychain_webauthn.userAddress,
1814
+ inner: {
1815
+ type: 'webAuthn',
1816
+ metadata: {
1817
+ authenticatorData: signature_webauthn.metadata.authenticatorData,
1818
+ clientDataJSON: signature_webauthn.metadata.clientDataJSON,
1819
+ },
1820
+ publicKey: {
1821
+ x: signature_webauthn.publicKey.x,
1822
+ y: signature_webauthn.publicKey.y,
1823
+ },
1824
+ signature: {
1825
+ r: signature_webauthn.signature.r,
1826
+ s: signature_webauthn.signature.s,
1827
+ },
1828
+ },
1829
+ })
1830
+ })
1831
+
1832
+ test('behavior: roundtrips fromRpc -> toRpc with secp256k1 inner', () => {
1833
+ const rpc: SignatureEnvelope.KeychainRpc = {
1834
+ type: 'keychain',
1835
+ userAddress: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
1836
+ signature: {
1837
+ type: 'secp256k1',
1838
+ r: '0xa2bb71146c20ce932456c043ebb2973ed205e07cd32c35a60bdefca1285fd132',
1839
+ s: '0x7cba10692bccdbfba9a215418443c2903dbee6fe5cb55c91172e47efc607840e',
1840
+ yParity: '0x1',
1841
+ },
1842
+ }
1843
+
1844
+ const envelope = SignatureEnvelope.fromRpc(rpc)
1845
+ const roundtripped = SignatureEnvelope.toRpc(envelope)
1846
+
1847
+ expect(roundtripped).toMatchObject(rpc)
1848
+ })
1849
+ })
1226
1850
  })
1227
1851
 
1228
1852
  describe('types', () => {