ox 1.8.8 → 1.8.10

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 (83) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/core/AbiEvent.d.ts.map +1 -1
  3. package/dist/core/AbiEvent.js +32 -10
  4. package/dist/core/AbiEvent.js.map +1 -1
  5. package/dist/core/Hex.d.ts +13 -1
  6. package/dist/core/Hex.d.ts.map +1 -1
  7. package/dist/core/Hex.js +5 -3
  8. package/dist/core/Hex.js.map +1 -1
  9. package/dist/core/RpcTransport.d.ts.map +1 -1
  10. package/dist/core/RpcTransport.js +21 -14
  11. package/dist/core/RpcTransport.js.map +1 -1
  12. package/dist/core/Signature.d.ts +1 -1
  13. package/dist/core/Signature.d.ts.map +1 -1
  14. package/dist/core/Signature.js +3 -2
  15. package/dist/core/Signature.js.map +1 -1
  16. package/dist/core/TypedData.js +1 -1
  17. package/dist/core/TypedData.js.map +1 -1
  18. package/dist/core/internal/abiItem.d.ts.map +1 -1
  19. package/dist/core/internal/abiItem.js +45 -19
  20. package/dist/core/internal/abiItem.js.map +1 -1
  21. package/dist/tempo/AccountConfig.d.ts +46 -3
  22. package/dist/tempo/AccountConfig.d.ts.map +1 -1
  23. package/dist/tempo/AccountConfig.js +58 -9
  24. package/dist/tempo/AccountConfig.js.map +1 -1
  25. package/dist/tempo/AccountSimulation.d.ts +6 -2
  26. package/dist/tempo/AccountSimulation.d.ts.map +1 -1
  27. package/dist/tempo/AccountSimulation.js +15 -5
  28. package/dist/tempo/AccountSimulation.js.map +1 -1
  29. package/dist/tempo/KeyAuthorization.d.ts +14 -9
  30. package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
  31. package/dist/tempo/KeyAuthorization.js +8 -12
  32. package/dist/tempo/KeyAuthorization.js.map +1 -1
  33. package/dist/tempo/TransactionRequest.d.ts +3 -3
  34. package/dist/tempo/TransactionRequest.d.ts.map +1 -1
  35. package/dist/tempo/TransactionRequest.js +10 -6
  36. package/dist/tempo/TransactionRequest.js.map +1 -1
  37. package/dist/zod/tempo/AccountSimulation.d.ts +4 -0
  38. package/dist/zod/tempo/AccountSimulation.d.ts.map +1 -1
  39. package/dist/zod/tempo/AccountSimulation.js +2 -0
  40. package/dist/zod/tempo/AccountSimulation.js.map +1 -1
  41. package/dist/zod/tempo/KeyAuthorization.d.ts +5 -5
  42. package/dist/zod/tempo/KeyAuthorization.d.ts.map +1 -1
  43. package/dist/zod/tempo/KeyAuthorization.js +10 -13
  44. package/dist/zod/tempo/KeyAuthorization.js.map +1 -1
  45. package/dist/zod/tempo/RpcSchemaTempo.d.ts +16 -8
  46. package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
  47. package/dist/zod/tempo/Transaction.d.ts +6 -6
  48. package/dist/zod/tempo/TransactionRequest.d.ts +23 -9
  49. package/dist/zod/tempo/TransactionRequest.d.ts.map +1 -1
  50. package/dist/zod/tempo/TransactionRequest.js +13 -9
  51. package/dist/zod/tempo/TransactionRequest.js.map +1 -1
  52. package/package.json +1 -1
  53. package/src/core/AbiEvent.ts +61 -22
  54. package/src/core/Hex.ts +17 -3
  55. package/src/core/RpcTransport.ts +20 -16
  56. package/src/core/Signature.ts +5 -2
  57. package/src/core/TypedData.ts +1 -1
  58. package/src/core/_test/AbiEvent.test.ts +232 -1
  59. package/src/core/_test/AbiItem.test.ts +342 -0
  60. package/src/core/_test/Hex.test.ts +31 -0
  61. package/src/core/_test/RpcTransport.test.ts +48 -0
  62. package/src/core/_test/Signature.test.ts +42 -1
  63. package/src/core/_test/TypedData.test.ts +29 -0
  64. package/src/core/internal/abiItem.ts +59 -25
  65. package/src/tempo/AccountConfig.test-d.ts +10 -0
  66. package/src/tempo/AccountConfig.test.ts +143 -10
  67. package/src/tempo/AccountConfig.ts +80 -9
  68. package/src/tempo/AccountOperation.test.ts +32 -32
  69. package/src/tempo/AccountSimulation.test.ts +43 -0
  70. package/src/tempo/AccountSimulation.ts +19 -5
  71. package/src/tempo/KeyAuthorization.test.ts +91 -32
  72. package/src/tempo/KeyAuthorization.ts +16 -39
  73. package/src/tempo/RpcSchemaTempo.test-d.ts +2 -2
  74. package/src/tempo/TransactionRequest.test-d.ts +5 -5
  75. package/src/tempo/TransactionRequest.test.ts +11 -9
  76. package/src/tempo/TransactionRequest.ts +13 -9
  77. package/src/version.ts +1 -1
  78. package/src/zod/tempo/AccountSimulation.ts +2 -0
  79. package/src/zod/tempo/KeyAuthorization.ts +28 -46
  80. package/src/zod/tempo/TransactionRequest.ts +17 -9
  81. package/src/zod/tempo/_test/AccountOperation.test.ts +1 -1
  82. package/src/zod/tempo/_test/KeyAuthorization.test.ts +5 -5
  83. package/src/zod/tempo/_test/TransactionRequest.test.ts +12 -7
@@ -1,10 +1,60 @@
1
- import { Abi, AbiEvent, Hex } from 'ox'
1
+ import { Abi, AbiEvent, AbiParameters, Hash, Hex } from 'ox'
2
2
  import { describe, expect, test } from 'vp/test'
3
3
  import { wagmiContractConfig } from '../../../test/constants/abis.js'
4
4
  import { address } from '../../../test/constants/addresses.js'
5
5
  import { anvilMainnet } from '../../../test/prool.js'
6
6
 
7
7
  describe('assertArgs', () => {
8
+ test('behavior: non-indexed `string` and `bytes`', () => {
9
+ const abiEvent = AbiEvent.from(
10
+ 'event Message(string indexed topic, string text, bytes data, bytes32 key)',
11
+ )
12
+ const args = AbiEvent.decode(abiEvent, {
13
+ data: AbiParameters.encode(AbiParameters.from('string, bytes, bytes32'), [
14
+ 'hello',
15
+ '0xabcd',
16
+ `0x${'ab'.repeat(32)}`,
17
+ ]),
18
+ topics: [
19
+ AbiEvent.getSelector(abiEvent),
20
+ Hash.keccak256(Hex.fromString('greeting')),
21
+ ],
22
+ })
23
+
24
+ AbiEvent.assertArgs(abiEvent, args, {
25
+ data: '0xABCD',
26
+ key: `0x${'AB'.repeat(32)}`,
27
+ text: 'hello',
28
+ topic: 'greeting',
29
+ })
30
+ expect(() => AbiEvent.assertArgs(abiEvent, args, { text: 'goodbye' }))
31
+ .toThrowErrorMatchingInlineSnapshot(`
32
+ [AbiEvent.ArgsMismatchError: Given arguments do not match the expected arguments.
33
+
34
+ Event: event Message(string indexed topic, string text, bytes data, bytes32 key)
35
+ Expected Arguments:
36
+ topic: 0xb6b19d010a6e0901db334da92e3eed820e0244fba35be613232ddf8d2ee39391
37
+ text: hello
38
+ data: 0xabcd
39
+ key: 0xabababababababababababababababababababababababababababababababab
40
+ Given Arguments:
41
+ text: goodbye]
42
+ `)
43
+ expect(() => AbiEvent.assertArgs(abiEvent, args, { data: '0xab' }))
44
+ .toThrowErrorMatchingInlineSnapshot(`
45
+ [AbiEvent.ArgsMismatchError: Given arguments do not match the expected arguments.
46
+
47
+ Event: event Message(string indexed topic, string text, bytes data, bytes32 key)
48
+ Expected Arguments:
49
+ topic: 0xb6b19d010a6e0901db334da92e3eed820e0244fba35be613232ddf8d2ee39391
50
+ text: hello
51
+ data: 0xabcd
52
+ key: 0xabababababababababababababababababababababababababababababababab
53
+ Given Arguments:
54
+ data: 0xab]
55
+ `)
56
+ })
57
+
8
58
  test('default', () => {
9
59
  const abiEvent = AbiEvent.from(
10
60
  'event Transfer(address indexed from, address indexed to, uint256 value)',
@@ -934,6 +984,187 @@ describe('extractLogs', () => {
934
984
  `)
935
985
  })
936
986
 
987
+ test('behavior: filters by non-indexed `string` arguments', () => {
988
+ const message = AbiEvent.from(
989
+ 'event Message(address indexed from, string text)',
990
+ )
991
+ const log = {
992
+ data: AbiParameters.encode(AbiParameters.from('string'), ['hello']),
993
+ topics: [
994
+ AbiEvent.getSelector(message),
995
+ '0x0000000000000000000000000000000000000000000000000000000000000001',
996
+ ],
997
+ } as const
998
+
999
+ expect(
1000
+ AbiEvent.extractLogs([message], [log], { args: { text: 'goodbye' } }),
1001
+ ).toMatchInlineSnapshot(`[]`)
1002
+ expect(AbiEvent.extractLogs([message], [log], { args: { text: 'hello' } }))
1003
+ .toMatchInlineSnapshot(`
1004
+ [
1005
+ {
1006
+ "args": {
1007
+ "from": "0x0000000000000000000000000000000000000001",
1008
+ "text": "hello",
1009
+ },
1010
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000",
1011
+ "eventName": "Message",
1012
+ "topics": [
1013
+ "0x811f7cff0a3374ff67cccc3726035d34ba70410e0256818a891e4d6acc01d88e",
1014
+ "0x0000000000000000000000000000000000000000000000000000000000000001",
1015
+ ],
1016
+ },
1017
+ ]
1018
+ `)
1019
+ })
1020
+
1021
+ test('behavior: filters by unnamed non-indexed `string` arguments', () => {
1022
+ const message = AbiEvent.from('event Message(address indexed, string)')
1023
+ const log = {
1024
+ data: AbiParameters.encode(AbiParameters.from('string'), ['hello']),
1025
+ topics: [
1026
+ AbiEvent.getSelector(message),
1027
+ '0x0000000000000000000000000000000000000000000000000000000000000001',
1028
+ ],
1029
+ } as const
1030
+
1031
+ expect(
1032
+ AbiEvent.extractLogs([message], [log], { args: [null, 'goodbye'] }),
1033
+ ).toMatchInlineSnapshot(`[]`)
1034
+ expect(
1035
+ AbiEvent.extractLogs([message], [log], {
1036
+ args: ['0x0000000000000000000000000000000000000001', 'hello'],
1037
+ }),
1038
+ ).toMatchInlineSnapshot(`
1039
+ [
1040
+ {
1041
+ "args": [
1042
+ "0x0000000000000000000000000000000000000001",
1043
+ "hello",
1044
+ ],
1045
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000",
1046
+ "eventName": "Message",
1047
+ "topics": [
1048
+ "0x811f7cff0a3374ff67cccc3726035d34ba70410e0256818a891e4d6acc01d88e",
1049
+ "0x0000000000000000000000000000000000000000000000000000000000000001",
1050
+ ],
1051
+ },
1052
+ ]
1053
+ `)
1054
+ })
1055
+
1056
+ test('behavior: filters by non-indexed `bytes` and `bytes32` arguments in either case', () => {
1057
+ const payload = AbiEvent.from('event Payload(bytes data, bytes32 key)')
1058
+ const log = {
1059
+ data: AbiParameters.encode(AbiParameters.from('bytes, bytes32'), [
1060
+ '0xabcd',
1061
+ `0x${'ab'.repeat(32)}`,
1062
+ ]),
1063
+ topics: [AbiEvent.getSelector(payload)],
1064
+ } as const
1065
+
1066
+ expect(
1067
+ AbiEvent.extractLogs([payload], [log], { args: { data: '0xab' } }),
1068
+ ).toMatchInlineSnapshot(`[]`)
1069
+ expect(
1070
+ AbiEvent.extractLogs([payload], [log], {
1071
+ args: { key: `0x${'cd'.repeat(32)}` },
1072
+ }),
1073
+ ).toMatchInlineSnapshot(`[]`)
1074
+ expect(
1075
+ AbiEvent.extractLogs([payload], [log], {
1076
+ args: { data: '0xABCD', key: `0x${'AB'.repeat(32)}` },
1077
+ }),
1078
+ ).toMatchInlineSnapshot(`
1079
+ [
1080
+ {
1081
+ "args": {
1082
+ "data": "0xabcd",
1083
+ "key": "0xabababababababababababababababababababababababababababababababab",
1084
+ },
1085
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000040abababababababababababababababababababababababababababababababab0000000000000000000000000000000000000000000000000000000000000002abcd000000000000000000000000000000000000000000000000000000000000",
1086
+ "eventName": "Payload",
1087
+ "topics": [
1088
+ "0x1d7847897c7e3bd365111aaf33b5ea1cc653db465de055620fb4cde96c75147f",
1089
+ ],
1090
+ },
1091
+ ]
1092
+ `)
1093
+ })
1094
+
1095
+ test('behavior: filters by indexed `bytes` and `bytes32` arguments', () => {
1096
+ const payload = AbiEvent.from(
1097
+ 'event Payload(bytes indexed data, bytes32 indexed key)',
1098
+ )
1099
+ const log = {
1100
+ data: '0x',
1101
+ topics: [
1102
+ AbiEvent.getSelector(payload),
1103
+ Hash.keccak256('0x1234'),
1104
+ `0x${'ab'.repeat(32)}`,
1105
+ ],
1106
+ } as const
1107
+
1108
+ expect(
1109
+ AbiEvent.extractLogs([payload], [log], { args: { data: '0x5678' } }),
1110
+ ).toMatchInlineSnapshot(`[]`)
1111
+ expect(
1112
+ AbiEvent.extractLogs([payload], [log], {
1113
+ args: { data: '0x1234', key: `0x${'AB'.repeat(32)}` },
1114
+ }),
1115
+ ).toMatchInlineSnapshot(`
1116
+ [
1117
+ {
1118
+ "args": {
1119
+ "data": "0x56570de287d73cd1cb6092bb8fdee6173974955fdef345ae579ee9f475ea7432",
1120
+ "key": "0xabababababababababababababababababababababababababababababababab",
1121
+ },
1122
+ "data": "0x",
1123
+ "eventName": "Payload",
1124
+ "topics": [
1125
+ "0x1d7847897c7e3bd365111aaf33b5ea1cc653db465de055620fb4cde96c75147f",
1126
+ "0x56570de287d73cd1cb6092bb8fdee6173974955fdef345ae579ee9f475ea7432",
1127
+ "0xabababababababababababababababababababababababababababababababab",
1128
+ ],
1129
+ },
1130
+ ]
1131
+ `)
1132
+ })
1133
+
1134
+ test('behavior: non-strict mode filters indexed `string` arguments decoded from data', () => {
1135
+ const message = AbiEvent.from('event Message(string indexed text)')
1136
+ const log = {
1137
+ data: AbiParameters.encode(AbiParameters.from('string'), ['hello']),
1138
+ topics: [AbiEvent.getSelector(message)],
1139
+ } as const
1140
+
1141
+ expect(
1142
+ AbiEvent.extractLogs([message], [log], {
1143
+ args: { text: 'goodbye' },
1144
+ strict: false,
1145
+ }),
1146
+ ).toMatchInlineSnapshot(`[]`)
1147
+ expect(
1148
+ AbiEvent.extractLogs([message], [log], {
1149
+ args: { text: 'hello' },
1150
+ strict: false,
1151
+ }),
1152
+ ).toMatchInlineSnapshot(`
1153
+ [
1154
+ {
1155
+ "args": {
1156
+ "text": "hello",
1157
+ },
1158
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000",
1159
+ "eventName": "Message",
1160
+ "topics": [
1161
+ "0x51a7f65c6325882f237d4aeb43228179cfad48b868511d508e24b4437a819137",
1162
+ ],
1163
+ },
1164
+ ]
1165
+ `)
1166
+ })
1167
+
937
1168
  test('behavior: formats RPC logs', () => {
938
1169
  const transfer = AbiEvent.from(
939
1170
  'event Transfer(address indexed from, address indexed to, uint256 value)',
@@ -566,6 +566,123 @@ describe('fromAbi', () => {
566
566
  `)
567
567
  })
568
568
 
569
+ test('behavior: overloads: array of sized type with a zero digit', () => {
570
+ const abi = Abi.from(['function foo(bool x)', 'function foo(uint160[] x)'])
571
+ const item = AbiItem.fromAbi(abi, 'foo', {
572
+ args: [[1n, 2n]],
573
+ })
574
+ expect(item).toMatchInlineSnapshot(`
575
+ {
576
+ "hash": "0x7bde9aac82d6d2ebf4a41781f2948136bf4f6c8ebf8f4e48fef38fa1e84c8956",
577
+ "inputs": [
578
+ {
579
+ "name": "x",
580
+ "type": "uint160[]",
581
+ },
582
+ ],
583
+ "name": "foo",
584
+ "outputs": [],
585
+ "stateMutability": "nonpayable",
586
+ "type": "function",
587
+ }
588
+ `)
589
+ })
590
+
591
+ test('behavior: overloads: fixed-length arrays', () => {
592
+ const abi = Abi.from([
593
+ 'function foo(uint256[3] x)',
594
+ 'function foo(uint256[2] x)',
595
+ ])
596
+ const item = AbiItem.fromAbi(abi, 'foo', {
597
+ args: [[1n, 2n, 3n]],
598
+ })
599
+ expect(item).toMatchInlineSnapshot(`
600
+ {
601
+ "hash": "0x692ce76c55b41cf69172ef1ac912f391f409c4752ccbc07a9223c555ab216e8a",
602
+ "inputs": [
603
+ {
604
+ "name": "x",
605
+ "type": "uint256[3]",
606
+ },
607
+ ],
608
+ "name": "foo",
609
+ "outputs": [],
610
+ "stateMutability": "nonpayable",
611
+ "type": "function",
612
+ }
613
+ `)
614
+ })
615
+
616
+ test('behavior: overloads: tuple object with array component', () => {
617
+ const abi = Abi.from([
618
+ 'function foo((uint256[] a) x)',
619
+ 'function foo((uint256[] a, uint256 b) x)',
620
+ ])
621
+ const item = AbiItem.fromAbi(abi, 'foo', {
622
+ args: [{ a: [1n], b: 2n }],
623
+ })
624
+ expect(item).toMatchInlineSnapshot(`
625
+ {
626
+ "hash": "0x61457dec1afc1333188255223fb1db69745528cabbb7e205dbd87802866b7d4b",
627
+ "inputs": [
628
+ {
629
+ "components": [
630
+ {
631
+ "name": "a",
632
+ "type": "uint256[]",
633
+ },
634
+ {
635
+ "name": "b",
636
+ "type": "uint256",
637
+ },
638
+ ],
639
+ "name": "x",
640
+ "type": "tuple",
641
+ },
642
+ ],
643
+ "name": "foo",
644
+ "outputs": [],
645
+ "stateMutability": "nonpayable",
646
+ "type": "function",
647
+ }
648
+ `)
649
+ })
650
+
651
+ test('behavior: overloads: tuple object keys in a different order', () => {
652
+ const abi = Abi.from([
653
+ 'function foo((address a, string b) x)',
654
+ 'function foo((string a, string b) x)',
655
+ ])
656
+ const item = AbiItem.fromAbi(abi, 'foo', {
657
+ args: [{ b: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', a: 'hello' }],
658
+ })
659
+ expect(item).toMatchInlineSnapshot(`
660
+ {
661
+ "hash": "0xdd0b43b6d117718cd57f3e320a76cfbe273b4896ff11ecfa3da506a2d372773b",
662
+ "inputs": [
663
+ {
664
+ "components": [
665
+ {
666
+ "name": "a",
667
+ "type": "string",
668
+ },
669
+ {
670
+ "name": "b",
671
+ "type": "string",
672
+ },
673
+ ],
674
+ "name": "x",
675
+ "type": "tuple",
676
+ },
677
+ ],
678
+ "name": "foo",
679
+ "outputs": [],
680
+ "stateMutability": "nonpayable",
681
+ "type": "function",
682
+ }
683
+ `)
684
+ })
685
+
569
686
  test('behavior: overloads: tuple', () => {
570
687
  const abi = Abi.from([
571
688
  'function foo(uint256 foo, (string a, string b, uint256 c) bar)',
@@ -783,6 +900,125 @@ describe('fromAbi', () => {
783
900
  These types encode differently and cannot be distinguished at runtime.
784
901
  Remove one of the ambiguous items in the ABI.]
785
902
  `)
903
+
904
+ expect(() =>
905
+ AbiItem.fromAbi(
906
+ Abi.from(['function foo(address[])', 'function foo(bytes20[])']),
907
+ 'foo',
908
+ {
909
+ args: [['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e']],
910
+ },
911
+ ),
912
+ ).toThrowErrorMatchingInlineSnapshot(`
913
+ [AbiItem.AmbiguityError: Found ambiguous types in overloaded ABI Items.
914
+
915
+ \`bytes20\` in \`foo(bytes20[])\`, and
916
+ \`address\` in \`foo(address[])\`
917
+
918
+ These types encode differently and cannot be distinguished at runtime.
919
+ Remove one of the ambiguous items in the ABI.]
920
+ `)
921
+
922
+ expect(() =>
923
+ AbiItem.fromAbi(
924
+ Abi.from(['function foo(address[])', 'function foo(bytes20[])']),
925
+ 'foo',
926
+ {
927
+ args: [[]],
928
+ },
929
+ ),
930
+ ).toThrowErrorMatchingInlineSnapshot(`
931
+ [AbiItem.AmbiguityError: Found ambiguous types in overloaded ABI Items.
932
+
933
+ \`bytes20\` in \`foo(bytes20[])\`, and
934
+ \`address\` in \`foo(address[])\`
935
+
936
+ These types encode differently and cannot be distinguished at runtime.
937
+ Remove one of the ambiguous items in the ABI.]
938
+ `)
939
+
940
+ expect(() =>
941
+ AbiItem.fromAbi(
942
+ Abi.from(['function foo(address[])', 'function foo(string[])']),
943
+ 'foo',
944
+ {
945
+ args: [[]],
946
+ },
947
+ ),
948
+ ).toThrowErrorMatchingInlineSnapshot(`
949
+ [AbiItem.AmbiguityError: Found ambiguous types in overloaded ABI Items.
950
+
951
+ \`string\` in \`foo(string[])\`, and
952
+ \`address\` in \`foo(address[])\`
953
+
954
+ These types encode differently and cannot be distinguished at runtime.
955
+ Remove one of the ambiguous items in the ABI.]
956
+ `)
957
+
958
+ expect(() =>
959
+ AbiItem.fromAbi(
960
+ Abi.from(['function foo(address[2])', 'function foo(bytes20[])']),
961
+ 'foo',
962
+ {
963
+ args: [
964
+ [
965
+ '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
966
+ '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
967
+ ],
968
+ ],
969
+ },
970
+ ),
971
+ ).toThrowErrorMatchingInlineSnapshot(`
972
+ [AbiItem.AmbiguityError: Found ambiguous types in overloaded ABI Items.
973
+
974
+ \`bytes20\` in \`foo(bytes20[])\`, and
975
+ \`address\` in \`foo(address[2])\`
976
+
977
+ These types encode differently and cannot be distinguished at runtime.
978
+ Remove one of the ambiguous items in the ABI.]
979
+ `)
980
+
981
+ expect(() =>
982
+ AbiItem.fromAbi(
983
+ Abi.from([
984
+ 'function foo((address[] a))',
985
+ 'function foo((bytes20[] a))',
986
+ ]),
987
+ 'foo',
988
+ {
989
+ args: [{ a: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'] }],
990
+ },
991
+ ),
992
+ ).toThrowErrorMatchingInlineSnapshot(`
993
+ [AbiItem.AmbiguityError: Found ambiguous types in overloaded ABI Items.
994
+
995
+ \`bytes20\` in \`foo((bytes20[]))\`, and
996
+ \`address\` in \`foo((address[]))\`
997
+
998
+ These types encode differently and cannot be distinguished at runtime.
999
+ Remove one of the ambiguous items in the ABI.]
1000
+ `)
1001
+
1002
+ expect(() =>
1003
+ AbiItem.fromAbi(
1004
+ Abi.from([
1005
+ 'function foo((uint256), address[])',
1006
+ 'function foo((uint256), bytes20[])',
1007
+ ]),
1008
+ 'foo',
1009
+ {
1010
+ args: [[1n], ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e']],
1011
+ },
1012
+ ),
1013
+ ).toThrowErrorMatchingInlineSnapshot(`
1014
+ [AbiItem.AmbiguityError: Found ambiguous types in overloaded ABI Items.
1015
+
1016
+ \`bytes20\` in \`foo((uint256),bytes20[])\`, and
1017
+ \`address\` in \`foo((uint256),address[])\`
1018
+
1019
+ These types encode differently and cannot be distinguished at runtime.
1020
+ Remove one of the ambiguous items in the ABI.]
1021
+ `)
786
1022
  })
787
1023
 
788
1024
  describe('getAmbiguousTypes', () => {
@@ -970,6 +1206,99 @@ describe('fromAbi', () => {
970
1206
  ]
971
1207
  `)
972
1208
  })
1209
+
1210
+ test('arrays', () => {
1211
+ expect(
1212
+ getAmbiguousTypes(
1213
+ AbiParameters.from('address[]'),
1214
+ AbiParameters.from('bytes20[]'),
1215
+ [['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e']],
1216
+ ),
1217
+ ).toMatchInlineSnapshot(`
1218
+ [
1219
+ "address",
1220
+ "bytes20",
1221
+ ]
1222
+ `)
1223
+
1224
+ expect(
1225
+ getAmbiguousTypes(
1226
+ AbiParameters.from('address[]'),
1227
+ AbiParameters.from('bytes20[]'),
1228
+ [[]],
1229
+ ),
1230
+ ).toMatchInlineSnapshot(`
1231
+ [
1232
+ "address",
1233
+ "bytes20",
1234
+ ]
1235
+ `)
1236
+
1237
+ expect(
1238
+ getAmbiguousTypes(
1239
+ AbiParameters.from('string[2]'),
1240
+ AbiParameters.from('address[]'),
1241
+ [
1242
+ [
1243
+ '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
1244
+ '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
1245
+ ],
1246
+ ],
1247
+ ),
1248
+ ).toMatchInlineSnapshot(`
1249
+ [
1250
+ "string",
1251
+ "address",
1252
+ ]
1253
+ `)
1254
+
1255
+ expect(
1256
+ getAmbiguousTypes(
1257
+ AbiParameters.from('(address[] a)'),
1258
+ AbiParameters.from('(bytes20[] a)'),
1259
+ [{ a: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'] }],
1260
+ ),
1261
+ ).toMatchInlineSnapshot(`
1262
+ [
1263
+ "address",
1264
+ "bytes20",
1265
+ ]
1266
+ `)
1267
+
1268
+ expect(
1269
+ getAmbiguousTypes(
1270
+ AbiParameters.from('string[]'),
1271
+ AbiParameters.from('address[]'),
1272
+ [['foo', 'bar']],
1273
+ ),
1274
+ ).toBeUndefined()
1275
+
1276
+ expect(
1277
+ getAmbiguousTypes(
1278
+ AbiParameters.from('string[]'),
1279
+ AbiParameters.from('address[]'),
1280
+ [[]],
1281
+ ),
1282
+ ).toMatchInlineSnapshot(`
1283
+ [
1284
+ "string",
1285
+ "address",
1286
+ ]
1287
+ `)
1288
+
1289
+ expect(
1290
+ getAmbiguousTypes(
1291
+ AbiParameters.from('address[][]'),
1292
+ AbiParameters.from('bytes20[][]'),
1293
+ [[['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e']]],
1294
+ ),
1295
+ ).toMatchInlineSnapshot(`
1296
+ [
1297
+ "address",
1298
+ "bytes20",
1299
+ ]
1300
+ `)
1301
+ })
973
1302
  })
974
1303
 
975
1304
  describe.each([
@@ -983,6 +1312,19 @@ describe('fromAbi', () => {
983
1312
  abiParameter: { type: 'uint256[]' },
984
1313
  expected: true,
985
1314
  },
1315
+ { arg: [1n], abiParameter: { type: 'uint160[]' }, expected: true },
1316
+ { arg: [1, 2], abiParameter: { type: 'int40[2]' }, expected: true },
1317
+ {
1318
+ arg: [1n, 2n, 3n],
1319
+ abiParameter: { type: 'uint256[2]' },
1320
+ expected: false,
1321
+ },
1322
+ { arg: [[1n]], abiParameter: { type: 'uint120[][]' }, expected: true },
1323
+ {
1324
+ arg: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'],
1325
+ abiParameter: { type: 'bytes20[]' },
1326
+ expected: true,
1327
+ },
986
1328
  {
987
1329
  arg: [{ foo: 1n, bar: [{ baz: 1n }] }],
988
1330
  abiParameter: {
@@ -26,6 +26,23 @@ describe('assert', () => {
26
26
  Hex values must start with \`"0x"\` and contain only hexadecimal characters (0-9, a-f, A-F).]
27
27
  `)
28
28
  })
29
+
30
+ test('options: even', () => {
31
+ expect(() => Hex.assert('0x0', { even: true }))
32
+ .toThrowErrorMatchingInlineSnapshot(`
33
+ [Hex.InvalidLengthError: Hex value \`"0x0"\` is an odd length (1 nibbles).
34
+
35
+ It must be an even length.]
36
+ `)
37
+ expect(() => Hex.assert('0x400', { even: true }))
38
+ .toThrowErrorMatchingInlineSnapshot(`
39
+ [Hex.InvalidLengthError: Hex value \`"0x400"\` is an odd length (3 nibbles).
40
+
41
+ It must be an even length.]
42
+ `)
43
+ expect(() => Hex.assert('0x00', { even: true })).not.toThrow()
44
+ expect(() => Hex.assert('0x0', { even: false })).not.toThrow()
45
+ })
29
46
  })
30
47
 
31
48
  describe('concat', () => {
@@ -750,6 +767,20 @@ describe('validate', () => {
750
767
  expect(Hex.validate({ foo: 'bar' })).toBeFalsy()
751
768
  expect(Hex.validate(undefined)).toBeFalsy()
752
769
  })
770
+
771
+ test('options: even', () => {
772
+ expect(Hex.validate('0x', { even: true })).toMatchInlineSnapshot(`true`)
773
+ expect(Hex.validate('0x00', { even: true })).toMatchInlineSnapshot(`true`)
774
+ expect(Hex.validate('0x0400', { even: true })).toMatchInlineSnapshot(`true`)
775
+ expect(Hex.validate('0x0', { even: true })).toMatchInlineSnapshot(`false`)
776
+ expect(Hex.validate('0x400', { even: true })).toMatchInlineSnapshot(`false`)
777
+ expect(Hex.validate('0x0g', { even: true })).toMatchInlineSnapshot(`true`)
778
+ expect(
779
+ Hex.validate('0x0g', { even: true, strict: true }),
780
+ ).toMatchInlineSnapshot(`false`)
781
+ expect(Hex.validate('0xg', { even: true })).toMatchInlineSnapshot(`false`)
782
+ expect(Hex.validate('0x0', { even: false })).toMatchInlineSnapshot(`true`)
783
+ })
753
784
  })
754
785
 
755
786
  test('exports', () => {