@beclab/olaresid 0.1.13 → 0.2.0

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 (181) hide show
  1. package/CLI-TREE.md +107 -0
  2. package/CLI.md +122 -1340
  3. package/README.md +30 -12
  4. package/SDK-TREE.md +151 -0
  5. package/TAG.md +95 -41
  6. package/config.json +6 -4
  7. package/dist/abi/TerminusDIDQueryABI.d.ts +397 -0
  8. package/dist/abi/TerminusDIDQueryABI.d.ts.map +1 -0
  9. package/dist/abi/TerminusDIDQueryABI.js +519 -0
  10. package/dist/abi/TerminusDIDQueryABI.js.map +1 -0
  11. package/dist/business/index.d.ts.map +1 -1
  12. package/dist/business/index.js +9 -23
  13. package/dist/business/index.js.map +1 -1
  14. package/dist/business/tag-context.d.ts +1 -0
  15. package/dist/business/tag-context.d.ts.map +1 -1
  16. package/dist/business/tag-context.js +13 -7
  17. package/dist/business/tag-context.js.map +1 -1
  18. package/dist/cli.js +177 -76
  19. package/dist/cli.js.map +1 -1
  20. package/dist/config/index.d.ts +16 -4
  21. package/dist/config/index.d.ts.map +1 -1
  22. package/dist/config/index.js +28 -14
  23. package/dist/config/index.js.map +1 -1
  24. package/dist/domain/core.d.ts +65 -0
  25. package/dist/domain/core.d.ts.map +1 -0
  26. package/dist/domain/core.js +317 -0
  27. package/dist/domain/core.js.map +1 -0
  28. package/dist/domain/index.d.ts +104 -57
  29. package/dist/domain/index.d.ts.map +1 -1
  30. package/dist/domain/index.js +188 -428
  31. package/dist/domain/index.js.map +1 -1
  32. package/dist/domain/types.d.ts +56 -0
  33. package/dist/domain/types.d.ts.map +1 -0
  34. package/dist/domain/types.js +3 -0
  35. package/dist/domain/types.js.map +1 -0
  36. package/dist/index.d.ts +80 -23
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +152 -143
  39. package/dist/index.js.map +1 -1
  40. package/dist/utils/crypto-utils.d.ts +110 -0
  41. package/dist/utils/crypto-utils.d.ts.map +1 -1
  42. package/dist/utils/crypto-utils.js +127 -8
  43. package/dist/utils/crypto-utils.js.map +1 -1
  44. package/dist/utils/error-parser.d.ts.map +1 -1
  45. package/dist/utils/error-parser.js +2 -1
  46. package/dist/utils/error-parser.js.map +1 -1
  47. package/dist/utils/event-parser.d.ts +161 -0
  48. package/dist/utils/event-parser.d.ts.map +1 -0
  49. package/dist/utils/event-parser.js +140 -0
  50. package/dist/utils/event-parser.js.map +1 -0
  51. package/dist/utils/tag-type-builder.d.ts +43 -0
  52. package/dist/utils/tag-type-builder.d.ts.map +1 -1
  53. package/dist/utils/tag-type-builder.js +122 -0
  54. package/dist/utils/tag-type-builder.js.map +1 -1
  55. package/dist/utils/tag-type-parser.d.ts +70 -0
  56. package/dist/utils/tag-type-parser.d.ts.map +1 -0
  57. package/dist/utils/tag-type-parser.js +190 -0
  58. package/dist/utils/tag-type-parser.js.map +1 -0
  59. package/examples/create-with-rpc-demo.ts +142 -0
  60. package/examples/fetch-all-flat-demo.ts +159 -0
  61. package/examples/fetch-by-indices-demo.ts +235 -0
  62. package/examples/fetch-domain-demo.ts +137 -0
  63. package/examples/fetch-domains-demo.ts +221 -0
  64. package/examples/frontend-demo/index.html +2 -2
  65. package/examples/frontend-demo/package-lock.json +4 -1
  66. package/examples/index.ts +3 -5
  67. package/jest.config.js +25 -0
  68. package/package.json +6 -2
  69. package/src/abi/TerminusDIDQueryABI.ts +516 -0
  70. package/src/business/index.ts +9 -33
  71. package/src/business/tag-context.ts +35 -7
  72. package/src/cli.ts +253 -90
  73. package/src/config/index.ts +34 -19
  74. package/src/domain/core.ts +382 -0
  75. package/src/domain/index.ts +271 -641
  76. package/src/domain/types.ts +59 -0
  77. package/src/index.ts +221 -207
  78. package/src/utils/crypto-utils.ts +205 -2
  79. package/src/utils/error-parser.ts +2 -1
  80. package/src/utils/event-parser.ts +353 -0
  81. package/src/utils/tag-type-builder.ts +138 -0
  82. package/src/utils/tag-type-parser.ts +246 -0
  83. package/tests/unit/crypto-utils.test.ts +338 -0
  84. package/tests/unit/ed25519-jwk.test.ts +201 -0
  85. package/tests/unit/event-parser.test.ts +690 -0
  86. package/tests/unit/generate-mnemonic.test.ts +268 -0
  87. package/tests/unit/olares-id-format.test.ts +321 -0
  88. package/tests/unit/tag-type-parser.test.ts +802 -0
  89. package/tests/unit/tag-types.test.ts +821 -0
  90. package/tsconfig.json +3 -2
  91. package/dist/abi/ABITypeABI.d.ts +0 -88
  92. package/dist/abi/ABITypeABI.d.ts.map +0 -1
  93. package/dist/abi/ABITypeABI.js +0 -382
  94. package/dist/abi/ABITypeABI.js.map +0 -1
  95. package/dist/abi/RegistryABI.d.ts +0 -77
  96. package/dist/abi/RegistryABI.d.ts.map +0 -1
  97. package/dist/abi/RegistryABI.js +0 -462
  98. package/dist/abi/RegistryABI.js.map +0 -1
  99. package/dist/tag/address.d.ts +0 -11
  100. package/dist/tag/address.d.ts.map +0 -1
  101. package/dist/tag/address.js +0 -44
  102. package/dist/tag/address.js.map +0 -1
  103. package/dist/tag/array.d.ts +0 -14
  104. package/dist/tag/array.d.ts.map +0 -1
  105. package/dist/tag/array.js +0 -72
  106. package/dist/tag/array.js.map +0 -1
  107. package/dist/tag/bool.d.ts +0 -11
  108. package/dist/tag/bool.d.ts.map +0 -1
  109. package/dist/tag/bool.js +0 -43
  110. package/dist/tag/bool.js.map +0 -1
  111. package/dist/tag/bytes.d.ts +0 -11
  112. package/dist/tag/bytes.d.ts.map +0 -1
  113. package/dist/tag/bytes.js +0 -37
  114. package/dist/tag/bytes.js.map +0 -1
  115. package/dist/tag/flarray.d.ts +0 -15
  116. package/dist/tag/flarray.d.ts.map +0 -1
  117. package/dist/tag/flarray.js +0 -81
  118. package/dist/tag/flarray.js.map +0 -1
  119. package/dist/tag/flbytes.d.ts +0 -11
  120. package/dist/tag/flbytes.d.ts.map +0 -1
  121. package/dist/tag/flbytes.js +0 -47
  122. package/dist/tag/flbytes.js.map +0 -1
  123. package/dist/tag/index.d.ts +0 -32
  124. package/dist/tag/index.d.ts.map +0 -1
  125. package/dist/tag/index.js +0 -121
  126. package/dist/tag/index.js.map +0 -1
  127. package/dist/tag/int.d.ts +0 -12
  128. package/dist/tag/int.d.ts.map +0 -1
  129. package/dist/tag/int.js +0 -49
  130. package/dist/tag/int.js.map +0 -1
  131. package/dist/tag/string.d.ts +0 -11
  132. package/dist/tag/string.d.ts.map +0 -1
  133. package/dist/tag/string.js +0 -37
  134. package/dist/tag/string.js.map +0 -1
  135. package/dist/tag/tag.d.ts +0 -67
  136. package/dist/tag/tag.d.ts.map +0 -1
  137. package/dist/tag/tag.js +0 -157
  138. package/dist/tag/tag.js.map +0 -1
  139. package/dist/tag/tuple.d.ts +0 -17
  140. package/dist/tag/tuple.d.ts.map +0 -1
  141. package/dist/tag/tuple.js +0 -162
  142. package/dist/tag/tuple.js.map +0 -1
  143. package/dist/tag/uint.d.ts +0 -12
  144. package/dist/tag/uint.d.ts.map +0 -1
  145. package/dist/tag/uint.js +0 -49
  146. package/dist/tag/uint.js.map +0 -1
  147. package/dist/test/did.d.ts +0 -2
  148. package/dist/test/did.d.ts.map +0 -1
  149. package/dist/test/did.js +0 -177
  150. package/dist/test/did.js.map +0 -1
  151. package/dist/utils/tag-abi-codec.d.ts +0 -69
  152. package/dist/utils/tag-abi-codec.d.ts.map +0 -1
  153. package/dist/utils/tag-abi-codec.js +0 -144
  154. package/dist/utils/tag-abi-codec.js.map +0 -1
  155. package/examples/crypto-utilities.ts +0 -140
  156. package/examples/ed25519-jwk.ts +0 -73
  157. package/examples/generate-mnemonic.ts +0 -149
  158. package/examples/legacy.ts +0 -33
  159. package/examples/olares-id-format.ts +0 -197
  160. package/examples/tag-builder.ts +0 -235
  161. package/examples/tag-nested-tuple.ts +0 -190
  162. package/examples/tag-simple.ts +0 -149
  163. package/examples/tag-tagger.ts +0 -217
  164. package/examples/test-nested-tuple-conversion.ts +0 -143
  165. package/examples/test-type-bytes-parser.ts +0 -70
  166. package/src/abi/ABITypeABI.ts +0 -379
  167. package/src/abi/RegistryABI.ts +0 -459
  168. package/src/tag/address.ts +0 -48
  169. package/src/tag/array.ts +0 -80
  170. package/src/tag/bool.ts +0 -43
  171. package/src/tag/bytes.ts +0 -38
  172. package/src/tag/flarray.ts +0 -99
  173. package/src/tag/flbytes.ts +0 -48
  174. package/src/tag/index.ts +0 -170
  175. package/src/tag/int.ts +0 -51
  176. package/src/tag/string.ts +0 -38
  177. package/src/tag/tag.ts +0 -229
  178. package/src/tag/tuple.ts +0 -193
  179. package/src/tag/uint.ts +0 -51
  180. package/src/test/did.ts +0 -346
  181. package/src/utils/tag-abi-codec.ts +0 -158
@@ -0,0 +1,821 @@
1
+ import { AbiCoder } from 'ethers';
2
+ import { TagTypeBuilder } from '../../src/utils/tag-type-builder';
3
+
4
+ /**
5
+ * Comprehensive tests for Tag type encoding/decoding
6
+ * Covers all tag types: basic, arrays, tuples, and nested structures
7
+ *
8
+ * Run: npm run test:unit
9
+ */
10
+
11
+ describe('Tag Type Encoding/Decoding', () => {
12
+ let abiCoder: AbiCoder;
13
+
14
+ beforeAll(() => {
15
+ abiCoder = new AbiCoder();
16
+ });
17
+
18
+ // ========================================
19
+ // Basic Types
20
+ // ========================================
21
+
22
+ describe('Basic Types', () => {
23
+ it('should handle string type', () => {
24
+ const builder = TagTypeBuilder.string();
25
+ const typeBytes = '0x' + builder.getTypeBytes();
26
+ const abiType = builder.getAbiTypeString();
27
+
28
+ expect(abiType).toBe('string');
29
+
30
+ // Parse back
31
+ const parsedType =
32
+ TagTypeBuilder.parseTypeBytesToAbiString(typeBytes);
33
+ expect(parsedType).toBe('string');
34
+
35
+ // Encode/Decode
36
+ const value = 'Hello World';
37
+ const encoded = abiCoder.encode([abiType], [value]);
38
+ const decoded = abiCoder.decode([abiType], encoded);
39
+ expect(decoded[0]).toBe(value);
40
+ });
41
+
42
+ it('should handle uint256 type', () => {
43
+ const builder = TagTypeBuilder.uint256();
44
+ const typeBytes = '0x' + builder.getTypeBytes();
45
+ const abiType = builder.getAbiTypeString();
46
+
47
+ expect(abiType).toBe('uint256');
48
+ expect(typeBytes).toBe('0x0120');
49
+
50
+ const parsedType =
51
+ TagTypeBuilder.parseTypeBytesToAbiString(typeBytes);
52
+ expect(parsedType).toBe('uint256');
53
+
54
+ const value = 12345n;
55
+ const encoded = abiCoder.encode([abiType], [value]);
56
+ const decoded = abiCoder.decode([abiType], encoded);
57
+ expect(decoded[0]).toBe(value);
58
+ });
59
+
60
+ it('should handle uint8 type', () => {
61
+ const builder = TagTypeBuilder.uint8();
62
+ const abiType = builder.getAbiTypeString();
63
+
64
+ expect(abiType).toBe('uint8');
65
+
66
+ const value = 255n;
67
+ const encoded = abiCoder.encode([abiType], [value]);
68
+ const decoded = abiCoder.decode([abiType], encoded);
69
+ expect(decoded[0]).toBe(value);
70
+ });
71
+
72
+ it('should handle int256 type', () => {
73
+ const builder = TagTypeBuilder.int256();
74
+ const abiType = builder.getAbiTypeString();
75
+
76
+ expect(abiType).toBe('int256');
77
+
78
+ const value = -12345n;
79
+ const encoded = abiCoder.encode([abiType], [value]);
80
+ const decoded = abiCoder.decode([abiType], encoded);
81
+ expect(decoded[0]).toBe(value);
82
+ });
83
+
84
+ it('should handle bool type', () => {
85
+ const builder = TagTypeBuilder.bool();
86
+ const abiType = builder.getAbiTypeString();
87
+
88
+ expect(abiType).toBe('bool');
89
+
90
+ const value = true;
91
+ const encoded = abiCoder.encode([abiType], [value]);
92
+ const decoded = abiCoder.decode([abiType], encoded);
93
+ expect(decoded[0]).toBe(value);
94
+ });
95
+
96
+ it('should handle address type', () => {
97
+ const builder = TagTypeBuilder.address();
98
+ const typeBytes = '0x' + builder.getTypeBytes();
99
+ const abiType = builder.getAbiTypeString();
100
+
101
+ expect(abiType).toBe('address');
102
+ expect(typeBytes).toBe('0x07');
103
+
104
+ const parsedType =
105
+ TagTypeBuilder.parseTypeBytesToAbiString(typeBytes);
106
+ expect(parsedType).toBe('address');
107
+
108
+ const value = '0x742d35cc6634c0532925a3b844bc9e7595f0beb0';
109
+ const encoded = abiCoder.encode([abiType], [value]);
110
+ const decoded = abiCoder.decode([abiType], encoded);
111
+ expect(decoded[0].toLowerCase()).toBe(value.toLowerCase());
112
+ });
113
+
114
+ it('should handle bytes type', () => {
115
+ const builder = TagTypeBuilder.bytes();
116
+ const abiType = builder.getAbiTypeString();
117
+
118
+ expect(abiType).toBe('bytes');
119
+
120
+ const value = '0x1234567890abcdef';
121
+ const encoded = abiCoder.encode([abiType], [value]);
122
+ const decoded = abiCoder.decode([abiType], encoded);
123
+ expect(decoded[0]).toBe(value);
124
+ });
125
+
126
+ it('should handle bytes32 type', () => {
127
+ const builder = TagTypeBuilder.bytes32();
128
+ const typeBytes = '0x' + builder.getTypeBytes();
129
+ const abiType = builder.getAbiTypeString();
130
+
131
+ expect(abiType).toBe('bytes32');
132
+ expect(typeBytes).toBe('0x0820');
133
+
134
+ const parsedType =
135
+ TagTypeBuilder.parseTypeBytesToAbiString(typeBytes);
136
+ expect(parsedType).toBe('bytes32');
137
+
138
+ const value =
139
+ '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef';
140
+ const encoded = abiCoder.encode([abiType], [value]);
141
+ const decoded = abiCoder.decode([abiType], encoded);
142
+ expect(decoded[0]).toBe(value);
143
+ });
144
+
145
+ it('should handle bytes4 type', () => {
146
+ const builder = TagTypeBuilder.fixedBytes(4);
147
+ const abiType = builder.getAbiTypeString();
148
+
149
+ expect(abiType).toBe('bytes4');
150
+
151
+ const value = '0x12345678';
152
+ const encoded = abiCoder.encode([abiType], [value]);
153
+ const decoded = abiCoder.decode([abiType], encoded);
154
+ expect(decoded[0]).toBe(value);
155
+ });
156
+ });
157
+
158
+ // ========================================
159
+ // Array Types
160
+ // ========================================
161
+
162
+ describe('Array Types', () => {
163
+ it('should handle string[] type', () => {
164
+ const builder = TagTypeBuilder.stringArray();
165
+ const typeBytes = '0x' + builder.getTypeBytes();
166
+ const abiType = builder.getAbiTypeString();
167
+
168
+ expect(abiType).toBe('string[]');
169
+
170
+ const parsedType =
171
+ TagTypeBuilder.parseTypeBytesToAbiString(typeBytes);
172
+ expect(parsedType).toBe('string[]');
173
+
174
+ const value = ['hello', 'world', 'test'];
175
+ const encoded = abiCoder.encode([abiType], [value]);
176
+ const decoded = abiCoder.decode([abiType], encoded);
177
+ expect(decoded[0]).toEqual(value);
178
+ });
179
+
180
+ it('should handle uint256[] type', () => {
181
+ const builder = TagTypeBuilder.uint256Array();
182
+ const abiType = builder.getAbiTypeString();
183
+
184
+ expect(abiType).toBe('uint256[]');
185
+
186
+ const value = [1n, 2n, 3n, 100n];
187
+ const encoded = abiCoder.encode([abiType], [value]);
188
+ const decoded = abiCoder.decode([abiType], encoded);
189
+ expect(decoded[0]).toEqual(value);
190
+ });
191
+
192
+ it('should handle address[] type', () => {
193
+ const builder = TagTypeBuilder.addressArray();
194
+ const abiType = builder.getAbiTypeString();
195
+
196
+ expect(abiType).toBe('address[]');
197
+
198
+ const value = [
199
+ '0x742d35cc6634c0532925a3b844bc9e7595f0beb0',
200
+ '0x1234567890123456789012345678901234567890'
201
+ ];
202
+ const encoded = abiCoder.encode([abiType], [value]);
203
+ const decoded = abiCoder.decode([abiType], encoded);
204
+ expect(decoded[0].map((a: string) => a.toLowerCase())).toEqual(
205
+ value.map((a) => a.toLowerCase())
206
+ );
207
+ });
208
+
209
+ it('should handle bool[] type', () => {
210
+ const builder = TagTypeBuilder.array(TagTypeBuilder.bool());
211
+ const abiType = builder.getAbiTypeString();
212
+
213
+ expect(abiType).toBe('bool[]');
214
+
215
+ const value = [true, false, true, true];
216
+ const encoded = abiCoder.encode([abiType], [value]);
217
+ const decoded = abiCoder.decode([abiType], encoded);
218
+ expect(decoded[0]).toEqual(value);
219
+ });
220
+
221
+ it('should handle fixed-length array string[3]', () => {
222
+ const builder = TagTypeBuilder.fixedArray(
223
+ TagTypeBuilder.string(),
224
+ 3
225
+ );
226
+ const typeBytes = '0x' + builder.getTypeBytes();
227
+ const abiType = builder.getAbiTypeString();
228
+
229
+ expect(abiType).toBe('string[3]');
230
+
231
+ const parsedType =
232
+ TagTypeBuilder.parseTypeBytesToAbiString(typeBytes);
233
+ expect(parsedType).toBe('string[3]');
234
+
235
+ const value = ['a', 'b', 'c'];
236
+ const encoded = abiCoder.encode([abiType], [value]);
237
+ const decoded = abiCoder.decode([abiType], encoded);
238
+ expect(decoded[0]).toEqual(value);
239
+ });
240
+ });
241
+
242
+ // ========================================
243
+ // Tuple Types
244
+ // ========================================
245
+
246
+ describe('Tuple Types', () => {
247
+ it('should handle simple tuple(string,uint8)', () => {
248
+ const builder = TagTypeBuilder.tuple({
249
+ name: TagTypeBuilder.string(),
250
+ age: TagTypeBuilder.uint8()
251
+ });
252
+ const typeBytes = '0x' + builder.getTypeBytes();
253
+ const abiType = builder.getAbiTypeString();
254
+ const fieldNames = builder.getFieldNames();
255
+
256
+ expect(abiType).toBe('tuple(string,uint8)');
257
+ expect(fieldNames).toEqual([['name', 'age']]);
258
+
259
+ const parsedType =
260
+ TagTypeBuilder.parseTypeBytesToAbiString(typeBytes);
261
+ expect(parsedType).toBe('tuple(string,uint8)');
262
+
263
+ // Array format
264
+ const value = ['Alice', 30n];
265
+ const encoded = abiCoder.encode([abiType], [value]);
266
+ const decoded = abiCoder.decode([abiType], encoded);
267
+ expect(decoded[0]).toEqual(value);
268
+ });
269
+
270
+ it('should handle tuple(address,uint256,bool)', () => {
271
+ const builder = TagTypeBuilder.tuple({
272
+ owner: TagTypeBuilder.address(),
273
+ balance: TagTypeBuilder.uint256(),
274
+ active: TagTypeBuilder.bool()
275
+ });
276
+ const abiType = builder.getAbiTypeString();
277
+ const fieldNames = builder.getFieldNames();
278
+
279
+ expect(abiType).toBe('tuple(address,uint256,bool)');
280
+ expect(fieldNames).toEqual([['owner', 'balance', 'active']]);
281
+
282
+ const value = [
283
+ '0x742d35cc6634c0532925a3b844bc9e7595f0beb0',
284
+ 1000n,
285
+ true
286
+ ];
287
+ const encoded = abiCoder.encode([abiType], [value]);
288
+ const decoded = abiCoder.decode([abiType], encoded);
289
+ expect((decoded[0][0] as string).toLowerCase()).toBe(
290
+ (value[0] as string).toLocaleLowerCase()
291
+ );
292
+ expect(decoded[0][1]).toBe(value[1]);
293
+ expect(decoded[0][2]).toBe(value[2]);
294
+ });
295
+
296
+ it('should handle nested tuple(string,tuple(uint8,bool))', () => {
297
+ const builder = TagTypeBuilder.tuple({
298
+ name: TagTypeBuilder.string(),
299
+ profile: TagTypeBuilder.tuple({
300
+ age: TagTypeBuilder.uint8(),
301
+ verified: TagTypeBuilder.bool()
302
+ })
303
+ });
304
+ const typeBytes = '0x' + builder.getTypeBytes();
305
+ const abiType = builder.getAbiTypeString();
306
+ const fieldNames = builder.getFieldNames();
307
+
308
+ expect(abiType).toBe('tuple(string,tuple(uint8,bool))');
309
+ expect(fieldNames).toEqual([
310
+ ['name', 'profile'],
311
+ ['age', 'verified']
312
+ ]);
313
+
314
+ const parsedType =
315
+ TagTypeBuilder.parseTypeBytesToAbiString(typeBytes);
316
+ expect(parsedType).toBe('tuple(string,tuple(uint8,bool))');
317
+
318
+ const value = ['Bob', [25n, false]];
319
+ const encoded = abiCoder.encode([abiType], [value]);
320
+ const decoded = abiCoder.decode([abiType], encoded);
321
+ expect(decoded[0]).toEqual(value);
322
+ });
323
+
324
+ it('should handle deeply nested tuple', () => {
325
+ const builder = TagTypeBuilder.tuple({
326
+ id: TagTypeBuilder.uint256(),
327
+ data: TagTypeBuilder.tuple({
328
+ name: TagTypeBuilder.string(),
329
+ meta: TagTypeBuilder.tuple({
330
+ created: TagTypeBuilder.uint256(),
331
+ active: TagTypeBuilder.bool()
332
+ })
333
+ })
334
+ });
335
+ const abiType = builder.getAbiTypeString();
336
+ const fieldNames = builder.getFieldNames();
337
+
338
+ expect(abiType).toBe(
339
+ 'tuple(uint256,tuple(string,tuple(uint256,bool)))'
340
+ );
341
+ expect(fieldNames).toEqual([
342
+ ['id', 'data'],
343
+ ['name', 'meta'],
344
+ ['created', 'active']
345
+ ]);
346
+
347
+ const value = [1n, ['Test', [1234567890n, true]]];
348
+ const encoded = abiCoder.encode([abiType], [value]);
349
+ const decoded = abiCoder.decode([abiType], encoded);
350
+ expect(decoded[0]).toEqual(value);
351
+ });
352
+ });
353
+
354
+ // ========================================
355
+ // Array of Tuples
356
+ // ========================================
357
+
358
+ describe('Array of Tuples', () => {
359
+ it('should handle tuple(string,uint8)[] type', () => {
360
+ const builder = TagTypeBuilder.array(
361
+ TagTypeBuilder.tuple({
362
+ name: TagTypeBuilder.string(),
363
+ age: TagTypeBuilder.uint8()
364
+ })
365
+ );
366
+ const typeBytes = '0x' + builder.getTypeBytes();
367
+ const abiType = builder.getAbiTypeString();
368
+ const fieldNames = builder.getFieldNames();
369
+
370
+ expect(abiType).toBe('tuple(string,uint8)[]');
371
+ expect(fieldNames).toEqual([['name', 'age']]);
372
+
373
+ const parsedType =
374
+ TagTypeBuilder.parseTypeBytesToAbiString(typeBytes);
375
+ expect(parsedType).toBe('tuple(string,uint8)[]');
376
+
377
+ const value = [
378
+ ['Alice', 30n],
379
+ ['Bob', 25n],
380
+ ['Charlie', 35n]
381
+ ];
382
+ const encoded = abiCoder.encode([abiType], [value]);
383
+ const decoded = abiCoder.decode([abiType], encoded);
384
+ expect(decoded[0]).toEqual(value);
385
+ });
386
+
387
+ it('should handle nested tuple array', () => {
388
+ const builder = TagTypeBuilder.array(
389
+ TagTypeBuilder.tuple({
390
+ id: TagTypeBuilder.uint256(),
391
+ data: TagTypeBuilder.tuple({
392
+ name: TagTypeBuilder.string(),
393
+ active: TagTypeBuilder.bool()
394
+ })
395
+ })
396
+ );
397
+ const abiType = builder.getAbiTypeString();
398
+ const fieldNames = builder.getFieldNames();
399
+
400
+ expect(abiType).toBe('tuple(uint256,tuple(string,bool))[]');
401
+ expect(fieldNames).toEqual([
402
+ ['id', 'data'],
403
+ ['name', 'active']
404
+ ]);
405
+
406
+ const value = [
407
+ [1n, ['Item1', true]],
408
+ [2n, ['Item2', false]]
409
+ ];
410
+ const encoded = abiCoder.encode([abiType], [value]);
411
+ const decoded = abiCoder.decode([abiType], encoded);
412
+ expect(decoded[0]).toEqual(value);
413
+ });
414
+ });
415
+
416
+ // ========================================
417
+ // Complex Mixed Types
418
+ // ========================================
419
+
420
+ describe('Complex Mixed Types', () => {
421
+ it('should handle tuple with array field', () => {
422
+ const builder = TagTypeBuilder.tuple({
423
+ name: TagTypeBuilder.string(),
424
+ tags: TagTypeBuilder.stringArray(),
425
+ count: TagTypeBuilder.uint256()
426
+ });
427
+ const abiType = builder.getAbiTypeString();
428
+
429
+ expect(abiType).toBe('tuple(string,string[],uint256)');
430
+
431
+ const value = ['Project', ['tag1', 'tag2', 'tag3'], 100n];
432
+ const encoded = abiCoder.encode([abiType], [value]);
433
+ const decoded = abiCoder.decode([abiType], encoded);
434
+ expect(decoded[0]).toEqual(value);
435
+ });
436
+
437
+ it('should handle tuple with multiple nested structures', () => {
438
+ const builder = TagTypeBuilder.tuple({
439
+ owner: TagTypeBuilder.address(),
440
+ metadata: TagTypeBuilder.tuple({
441
+ name: TagTypeBuilder.string(),
442
+ tags: TagTypeBuilder.stringArray()
443
+ }),
444
+ settings: TagTypeBuilder.tuple({
445
+ enabled: TagTypeBuilder.bool(),
446
+ maxValue: TagTypeBuilder.uint256()
447
+ })
448
+ });
449
+ const abiType = builder.getAbiTypeString();
450
+ const fieldNames = builder.getFieldNames();
451
+
452
+ expect(abiType).toBe(
453
+ 'tuple(address,tuple(string,string[]),tuple(bool,uint256))'
454
+ );
455
+ expect(fieldNames.length).toBe(3);
456
+
457
+ const value = [
458
+ '0x742d35cc6634c0532925a3b844bc9e7595f0beb0',
459
+ ['MyProject', ['web3', 'defi']],
460
+ [true, 1000n]
461
+ ];
462
+ const encoded = abiCoder.encode([abiType], [value]);
463
+ const decoded = abiCoder.decode([abiType], encoded);
464
+ expect((decoded[0][0] as string).toLowerCase()).toBe(
465
+ (value[0] as string).toLowerCase()
466
+ );
467
+ expect(decoded[0][1]).toEqual(value[1]);
468
+ expect(decoded[0][2]).toEqual(value[2]);
469
+ });
470
+ });
471
+
472
+ // ========================================
473
+ // Type Bytes Parsing
474
+ // ========================================
475
+
476
+ describe('Type Bytes Parsing', () => {
477
+ it('should parse simple type bytes correctly', () => {
478
+ expect(TagTypeBuilder.parseTypeBytesToAbiString('0x03')).toBe(
479
+ 'string'
480
+ );
481
+ expect(TagTypeBuilder.parseTypeBytesToAbiString('0x0101')).toBe(
482
+ 'uint8'
483
+ );
484
+ expect(TagTypeBuilder.parseTypeBytesToAbiString('0x0120')).toBe(
485
+ 'uint256'
486
+ );
487
+ expect(TagTypeBuilder.parseTypeBytesToAbiString('0x02')).toBe(
488
+ 'bool'
489
+ );
490
+ expect(TagTypeBuilder.parseTypeBytesToAbiString('0x07')).toBe(
491
+ 'address'
492
+ );
493
+ expect(TagTypeBuilder.parseTypeBytesToAbiString('0x09')).toBe(
494
+ 'bytes'
495
+ );
496
+ expect(TagTypeBuilder.parseTypeBytesToAbiString('0x0820')).toBe(
497
+ 'bytes32'
498
+ );
499
+ });
500
+
501
+ it('should parse array type bytes correctly', () => {
502
+ expect(TagTypeBuilder.parseTypeBytesToAbiString('0x0403')).toBe(
503
+ 'string[]'
504
+ );
505
+ expect(TagTypeBuilder.parseTypeBytesToAbiString('0x0407')).toBe(
506
+ 'address[]'
507
+ );
508
+ expect(TagTypeBuilder.parseTypeBytesToAbiString('0x040120')).toBe(
509
+ 'uint256[]'
510
+ );
511
+ });
512
+
513
+ it('should parse fixed array type bytes correctly', () => {
514
+ expect(TagTypeBuilder.parseTypeBytesToAbiString('0x05000303')).toBe(
515
+ 'string[3]'
516
+ );
517
+ expect(TagTypeBuilder.parseTypeBytesToAbiString('0x05000507')).toBe(
518
+ 'address[5]'
519
+ );
520
+ });
521
+
522
+ it('should parse simple tuple type bytes correctly', () => {
523
+ // tuple(string,uint8)
524
+ expect(
525
+ TagTypeBuilder.parseTypeBytesToAbiString('0x060002030101')
526
+ ).toBe('tuple(string,uint8)');
527
+ });
528
+
529
+ it('should parse complex tuple type bytes correctly', () => {
530
+ // tuple(string,uint8,address[],bool) - from tag-management.ts
531
+ expect(
532
+ TagTypeBuilder.parseTypeBytesToAbiString('0x060004030101040702')
533
+ ).toBe('tuple(string,uint8,address[],bool)');
534
+ });
535
+
536
+ it('should parse nested tuple type bytes correctly', () => {
537
+ // Build nested tuple and verify parsing
538
+ const builder = TagTypeBuilder.tuple({
539
+ name: TagTypeBuilder.string(),
540
+ profile: TagTypeBuilder.tuple({
541
+ age: TagTypeBuilder.uint8(),
542
+ active: TagTypeBuilder.bool()
543
+ })
544
+ });
545
+ const typeBytes = '0x' + builder.getTypeBytes();
546
+ const parsed = TagTypeBuilder.parseTypeBytesToAbiString(typeBytes);
547
+ expect(parsed).toBe('tuple(string,tuple(uint8,bool))');
548
+ });
549
+
550
+ it('should roundtrip: build -> parse -> build', () => {
551
+ const original = TagTypeBuilder.tuple({
552
+ id: TagTypeBuilder.uint256(),
553
+ data: TagTypeBuilder.stringArray(),
554
+ owner: TagTypeBuilder.address()
555
+ });
556
+
557
+ const typeBytes = '0x' + original.getTypeBytes();
558
+ const parsedAbi =
559
+ TagTypeBuilder.parseTypeBytesToAbiString(typeBytes);
560
+
561
+ expect(parsedAbi).toBe('tuple(uint256,string[],address)');
562
+ expect(parsedAbi).toBe(original.getAbiTypeString());
563
+ });
564
+ });
565
+
566
+ // ========================================
567
+ // Object to Array Conversion
568
+ // ========================================
569
+
570
+ describe('Object to Array Conversion', () => {
571
+ it('should return non-object values as-is', () => {
572
+ expect(TagTypeBuilder.convertObjectToArray('string', 'hello')).toBe(
573
+ 'hello'
574
+ );
575
+ expect(TagTypeBuilder.convertObjectToArray('uint256', 123n)).toBe(
576
+ 123n
577
+ );
578
+ expect(TagTypeBuilder.convertObjectToArray('bool', true)).toBe(
579
+ true
580
+ );
581
+ expect(TagTypeBuilder.convertObjectToArray('address', null)).toBe(
582
+ null
583
+ );
584
+ });
585
+
586
+ it('should return arrays as-is', () => {
587
+ const arr = ['Alice', 30];
588
+ expect(
589
+ TagTypeBuilder.convertObjectToArray('tuple(string,uint8)', arr)
590
+ ).toBe(arr);
591
+ });
592
+
593
+ it('should return non-tuple types as-is', () => {
594
+ const obj = { foo: 'bar' };
595
+ expect(TagTypeBuilder.convertObjectToArray('string', obj)).toBe(
596
+ obj
597
+ );
598
+ });
599
+
600
+ it('should convert simple tuple object to array', () => {
601
+ const obj = { name: 'Alice', age: 30 };
602
+ const result = TagTypeBuilder.convertObjectToArray(
603
+ 'tuple(string,uint8)',
604
+ obj
605
+ );
606
+ expect(result).toEqual(['Alice', 30]);
607
+ });
608
+
609
+ it('should convert nested tuple object to array', () => {
610
+ const obj = {
611
+ name: 'Bob',
612
+ profile: {
613
+ age: 25,
614
+ verified: true
615
+ }
616
+ };
617
+ const result = TagTypeBuilder.convertObjectToArray(
618
+ 'tuple(string,tuple(uint8,bool))',
619
+ obj
620
+ );
621
+ expect(result).toEqual(['Bob', [25, true]]);
622
+ });
623
+
624
+ it('should convert deeply nested tuple object to array', () => {
625
+ const obj = {
626
+ id: 1,
627
+ data: {
628
+ name: 'Test',
629
+ meta: {
630
+ created: 1234567890,
631
+ active: true
632
+ }
633
+ }
634
+ };
635
+ const result = TagTypeBuilder.convertObjectToArray(
636
+ 'tuple(uint256,tuple(string,tuple(uint256,bool)))',
637
+ obj
638
+ );
639
+ expect(result).toEqual([1, ['Test', [1234567890, true]]]);
640
+ });
641
+
642
+ it('should handle tuple with mixed types', () => {
643
+ const obj = {
644
+ owner: '0x1234567890123456789012345678901234567890',
645
+ balance: 1000n,
646
+ active: true
647
+ };
648
+ const result = TagTypeBuilder.convertObjectToArray(
649
+ 'tuple(address,uint256,bool)',
650
+ obj
651
+ );
652
+ expect(result).toEqual([
653
+ '0x1234567890123456789012345678901234567890',
654
+ 1000n,
655
+ true
656
+ ]);
657
+ });
658
+
659
+ it('should throw error on field count mismatch', () => {
660
+ const obj = { name: 'Alice' }; // Missing 'age' field
661
+ expect(() => {
662
+ TagTypeBuilder.convertObjectToArray('tuple(string,uint8)', obj);
663
+ }).toThrow('Tuple field count mismatch');
664
+ });
665
+
666
+ it('should convert tuple array (tuple[]) correctly', () => {
667
+ const objArray = [
668
+ {
669
+ algorithm: 0,
670
+ addr: '0x742d35cc6634c0532925a3b844bc9e7595f0beb0'
671
+ },
672
+ {
673
+ algorithm: 1,
674
+ addr: '0x1111111111111111111111111111111111111111'
675
+ }
676
+ ];
677
+ const result = TagTypeBuilder.convertObjectToArray(
678
+ 'tuple(uint8,address)[]',
679
+ objArray
680
+ );
681
+ expect(result).toEqual([
682
+ [0, '0x742d35cc6634c0532925a3b844bc9e7595f0beb0'],
683
+ [1, '0x1111111111111111111111111111111111111111']
684
+ ]);
685
+ });
686
+
687
+ it('should handle nested tuple within tuple array', () => {
688
+ const objArray = [
689
+ {
690
+ id: 1,
691
+ data: {
692
+ name: 'Alice',
693
+ active: true
694
+ }
695
+ },
696
+ {
697
+ id: 2,
698
+ data: {
699
+ name: 'Bob',
700
+ active: false
701
+ }
702
+ }
703
+ ];
704
+ const result = TagTypeBuilder.convertObjectToArray(
705
+ 'tuple(uint256,tuple(string,bool))[]',
706
+ objArray
707
+ );
708
+ expect(result).toEqual([
709
+ [1, ['Alice', true]],
710
+ [2, ['Bob', false]]
711
+ ]);
712
+ });
713
+
714
+ it('should handle empty tuple array', () => {
715
+ const objArray: any[] = [];
716
+ const result = TagTypeBuilder.convertObjectToArray(
717
+ 'tuple(uint8,address)[]',
718
+ objArray
719
+ );
720
+ expect(result).toEqual([]);
721
+ });
722
+ });
723
+
724
+ // ========================================
725
+ // Parse Tuple Field Types
726
+ // ========================================
727
+
728
+ describe('Parse Tuple Field Types', () => {
729
+ it('should parse simple tuple fields', () => {
730
+ const fields = TagTypeBuilder.parseTupleFieldTypes(
731
+ 'tuple(string,uint8)'
732
+ );
733
+ expect(fields).toEqual(['string', 'uint8']);
734
+ });
735
+
736
+ it('should parse tuple with multiple fields', () => {
737
+ const fields = TagTypeBuilder.parseTupleFieldTypes(
738
+ 'tuple(address,uint256,bool,string)'
739
+ );
740
+ expect(fields).toEqual(['address', 'uint256', 'bool', 'string']);
741
+ });
742
+
743
+ it('should parse nested tuple fields', () => {
744
+ const fields = TagTypeBuilder.parseTupleFieldTypes(
745
+ 'tuple(string,tuple(uint8,bool))'
746
+ );
747
+ expect(fields).toEqual(['string', 'tuple(uint8,bool)']);
748
+ });
749
+
750
+ it('should parse deeply nested tuple fields', () => {
751
+ const fields = TagTypeBuilder.parseTupleFieldTypes(
752
+ 'tuple(uint256,tuple(string,tuple(uint256,bool)))'
753
+ );
754
+ expect(fields).toEqual([
755
+ 'uint256',
756
+ 'tuple(string,tuple(uint256,bool))'
757
+ ]);
758
+ });
759
+
760
+ it('should parse tuple with array fields', () => {
761
+ const fields = TagTypeBuilder.parseTupleFieldTypes(
762
+ 'tuple(string,string[],uint256)'
763
+ );
764
+ expect(fields).toEqual(['string', 'string[]', 'uint256']);
765
+ });
766
+
767
+ it('should return empty array for non-tuple types', () => {
768
+ expect(TagTypeBuilder.parseTupleFieldTypes('string')).toEqual([]);
769
+ expect(TagTypeBuilder.parseTupleFieldTypes('uint256')).toEqual([]);
770
+ expect(TagTypeBuilder.parseTupleFieldTypes('address[]')).toEqual(
771
+ []
772
+ );
773
+ });
774
+ });
775
+
776
+ // ========================================
777
+ // Edge Cases
778
+ // ========================================
779
+
780
+ describe('Edge Cases', () => {
781
+ it('should handle empty string', () => {
782
+ const builder = TagTypeBuilder.string();
783
+ const abiType = builder.getAbiTypeString();
784
+
785
+ const value = '';
786
+ const encoded = abiCoder.encode([abiType], [value]);
787
+ const decoded = abiCoder.decode([abiType], encoded);
788
+ expect(decoded[0]).toBe(value);
789
+ });
790
+
791
+ it('should handle empty array', () => {
792
+ const builder = TagTypeBuilder.stringArray();
793
+ const abiType = builder.getAbiTypeString();
794
+
795
+ const value: string[] = [];
796
+ const encoded = abiCoder.encode([abiType], [value]);
797
+ const decoded = abiCoder.decode([abiType], encoded);
798
+ expect(decoded[0]).toEqual(value);
799
+ });
800
+
801
+ it('should handle zero values', () => {
802
+ const builder = TagTypeBuilder.uint256();
803
+ const abiType = builder.getAbiTypeString();
804
+
805
+ const value = 0n;
806
+ const encoded = abiCoder.encode([abiType], [value]);
807
+ const decoded = abiCoder.decode([abiType], encoded);
808
+ expect(decoded[0]).toBe(value);
809
+ });
810
+
811
+ it('should handle max uint256', () => {
812
+ const builder = TagTypeBuilder.uint256();
813
+ const abiType = builder.getAbiTypeString();
814
+
815
+ const value = 2n ** 256n - 1n;
816
+ const encoded = abiCoder.encode([abiType], [value]);
817
+ const decoded = abiCoder.decode([abiType], encoded);
818
+ expect(decoded[0]).toBe(value);
819
+ });
820
+ });
821
+ });