@beclab/olaresid 0.1.12 → 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 (182) hide show
  1. package/CLI-TREE.md +107 -0
  2. package/CLI.md +122 -1329
  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 +1 -1
  12. package/dist/business/index.d.ts.map +1 -1
  13. package/dist/business/index.js +11 -24
  14. package/dist/business/index.js.map +1 -1
  15. package/dist/business/tag-context.d.ts +1 -0
  16. package/dist/business/tag-context.d.ts.map +1 -1
  17. package/dist/business/tag-context.js +13 -7
  18. package/dist/business/tag-context.js.map +1 -1
  19. package/dist/cli.js +238 -107
  20. package/dist/cli.js.map +1 -1
  21. package/dist/config/index.d.ts +16 -4
  22. package/dist/config/index.d.ts.map +1 -1
  23. package/dist/config/index.js +28 -14
  24. package/dist/config/index.js.map +1 -1
  25. package/dist/domain/core.d.ts +65 -0
  26. package/dist/domain/core.d.ts.map +1 -0
  27. package/dist/domain/core.js +317 -0
  28. package/dist/domain/core.js.map +1 -0
  29. package/dist/domain/index.d.ts +104 -57
  30. package/dist/domain/index.d.ts.map +1 -1
  31. package/dist/domain/index.js +188 -428
  32. package/dist/domain/index.js.map +1 -1
  33. package/dist/domain/types.d.ts +56 -0
  34. package/dist/domain/types.d.ts.map +1 -0
  35. package/dist/domain/types.js +3 -0
  36. package/dist/domain/types.js.map +1 -0
  37. package/dist/index.d.ts +81 -24
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +153 -143
  40. package/dist/index.js.map +1 -1
  41. package/dist/utils/crypto-utils.d.ts +124 -0
  42. package/dist/utils/crypto-utils.d.ts.map +1 -1
  43. package/dist/utils/crypto-utils.js +156 -8
  44. package/dist/utils/crypto-utils.js.map +1 -1
  45. package/dist/utils/error-parser.d.ts.map +1 -1
  46. package/dist/utils/error-parser.js +2 -1
  47. package/dist/utils/error-parser.js.map +1 -1
  48. package/dist/utils/event-parser.d.ts +161 -0
  49. package/dist/utils/event-parser.d.ts.map +1 -0
  50. package/dist/utils/event-parser.js +140 -0
  51. package/dist/utils/event-parser.js.map +1 -0
  52. package/dist/utils/tag-type-builder.d.ts +43 -0
  53. package/dist/utils/tag-type-builder.d.ts.map +1 -1
  54. package/dist/utils/tag-type-builder.js +122 -0
  55. package/dist/utils/tag-type-builder.js.map +1 -1
  56. package/dist/utils/tag-type-parser.d.ts +70 -0
  57. package/dist/utils/tag-type-parser.d.ts.map +1 -0
  58. package/dist/utils/tag-type-parser.js +190 -0
  59. package/dist/utils/tag-type-parser.js.map +1 -0
  60. package/examples/create-with-rpc-demo.ts +142 -0
  61. package/examples/fetch-all-flat-demo.ts +159 -0
  62. package/examples/fetch-by-indices-demo.ts +235 -0
  63. package/examples/fetch-domain-demo.ts +137 -0
  64. package/examples/fetch-domains-demo.ts +221 -0
  65. package/examples/frontend-demo/index.html +2 -2
  66. package/examples/frontend-demo/package-lock.json +4 -1
  67. package/examples/index.ts +3 -5
  68. package/jest.config.js +25 -0
  69. package/package.json +6 -2
  70. package/src/abi/TerminusDIDQueryABI.ts +516 -0
  71. package/src/business/index.ts +10 -33
  72. package/src/business/tag-context.ts +35 -7
  73. package/src/cli.ts +344 -121
  74. package/src/config/index.ts +34 -19
  75. package/src/domain/core.ts +382 -0
  76. package/src/domain/index.ts +271 -641
  77. package/src/domain/types.ts +59 -0
  78. package/src/index.ts +222 -207
  79. package/src/utils/crypto-utils.ts +239 -2
  80. package/src/utils/error-parser.ts +2 -1
  81. package/src/utils/event-parser.ts +353 -0
  82. package/src/utils/tag-type-builder.ts +138 -0
  83. package/src/utils/tag-type-parser.ts +246 -0
  84. package/tests/unit/crypto-utils.test.ts +338 -0
  85. package/tests/unit/ed25519-jwk.test.ts +201 -0
  86. package/tests/unit/event-parser.test.ts +690 -0
  87. package/tests/unit/generate-mnemonic.test.ts +268 -0
  88. package/tests/unit/olares-id-format.test.ts +321 -0
  89. package/tests/unit/tag-type-parser.test.ts +802 -0
  90. package/tests/unit/tag-types.test.ts +821 -0
  91. package/tsconfig.json +3 -2
  92. package/dist/abi/ABITypeABI.d.ts +0 -88
  93. package/dist/abi/ABITypeABI.d.ts.map +0 -1
  94. package/dist/abi/ABITypeABI.js +0 -382
  95. package/dist/abi/ABITypeABI.js.map +0 -1
  96. package/dist/abi/RegistryABI.d.ts +0 -77
  97. package/dist/abi/RegistryABI.d.ts.map +0 -1
  98. package/dist/abi/RegistryABI.js +0 -462
  99. package/dist/abi/RegistryABI.js.map +0 -1
  100. package/dist/tag/address.d.ts +0 -11
  101. package/dist/tag/address.d.ts.map +0 -1
  102. package/dist/tag/address.js +0 -44
  103. package/dist/tag/address.js.map +0 -1
  104. package/dist/tag/array.d.ts +0 -14
  105. package/dist/tag/array.d.ts.map +0 -1
  106. package/dist/tag/array.js +0 -72
  107. package/dist/tag/array.js.map +0 -1
  108. package/dist/tag/bool.d.ts +0 -11
  109. package/dist/tag/bool.d.ts.map +0 -1
  110. package/dist/tag/bool.js +0 -43
  111. package/dist/tag/bool.js.map +0 -1
  112. package/dist/tag/bytes.d.ts +0 -11
  113. package/dist/tag/bytes.d.ts.map +0 -1
  114. package/dist/tag/bytes.js +0 -37
  115. package/dist/tag/bytes.js.map +0 -1
  116. package/dist/tag/flarray.d.ts +0 -15
  117. package/dist/tag/flarray.d.ts.map +0 -1
  118. package/dist/tag/flarray.js +0 -81
  119. package/dist/tag/flarray.js.map +0 -1
  120. package/dist/tag/flbytes.d.ts +0 -11
  121. package/dist/tag/flbytes.d.ts.map +0 -1
  122. package/dist/tag/flbytes.js +0 -47
  123. package/dist/tag/flbytes.js.map +0 -1
  124. package/dist/tag/index.d.ts +0 -32
  125. package/dist/tag/index.d.ts.map +0 -1
  126. package/dist/tag/index.js +0 -121
  127. package/dist/tag/index.js.map +0 -1
  128. package/dist/tag/int.d.ts +0 -12
  129. package/dist/tag/int.d.ts.map +0 -1
  130. package/dist/tag/int.js +0 -49
  131. package/dist/tag/int.js.map +0 -1
  132. package/dist/tag/string.d.ts +0 -11
  133. package/dist/tag/string.d.ts.map +0 -1
  134. package/dist/tag/string.js +0 -37
  135. package/dist/tag/string.js.map +0 -1
  136. package/dist/tag/tag.d.ts +0 -67
  137. package/dist/tag/tag.d.ts.map +0 -1
  138. package/dist/tag/tag.js +0 -157
  139. package/dist/tag/tag.js.map +0 -1
  140. package/dist/tag/tuple.d.ts +0 -17
  141. package/dist/tag/tuple.d.ts.map +0 -1
  142. package/dist/tag/tuple.js +0 -162
  143. package/dist/tag/tuple.js.map +0 -1
  144. package/dist/tag/uint.d.ts +0 -12
  145. package/dist/tag/uint.d.ts.map +0 -1
  146. package/dist/tag/uint.js +0 -49
  147. package/dist/tag/uint.js.map +0 -1
  148. package/dist/test/did.d.ts +0 -2
  149. package/dist/test/did.d.ts.map +0 -1
  150. package/dist/test/did.js +0 -177
  151. package/dist/test/did.js.map +0 -1
  152. package/dist/utils/tag-abi-codec.d.ts +0 -69
  153. package/dist/utils/tag-abi-codec.d.ts.map +0 -1
  154. package/dist/utils/tag-abi-codec.js +0 -144
  155. package/dist/utils/tag-abi-codec.js.map +0 -1
  156. package/examples/crypto-utilities.ts +0 -140
  157. package/examples/ed25519-jwk.ts +0 -73
  158. package/examples/generate-mnemonic.ts +0 -149
  159. package/examples/legacy.ts +0 -33
  160. package/examples/olares-id-format.ts +0 -197
  161. package/examples/tag-builder.ts +0 -235
  162. package/examples/tag-nested-tuple.ts +0 -190
  163. package/examples/tag-simple.ts +0 -149
  164. package/examples/tag-tagger.ts +0 -217
  165. package/examples/test-nested-tuple-conversion.ts +0 -143
  166. package/examples/test-type-bytes-parser.ts +0 -70
  167. package/src/abi/ABITypeABI.ts +0 -379
  168. package/src/abi/RegistryABI.ts +0 -459
  169. package/src/tag/address.ts +0 -48
  170. package/src/tag/array.ts +0 -80
  171. package/src/tag/bool.ts +0 -43
  172. package/src/tag/bytes.ts +0 -38
  173. package/src/tag/flarray.ts +0 -99
  174. package/src/tag/flbytes.ts +0 -48
  175. package/src/tag/index.ts +0 -170
  176. package/src/tag/int.ts +0 -51
  177. package/src/tag/string.ts +0 -38
  178. package/src/tag/tag.ts +0 -229
  179. package/src/tag/tuple.ts +0 -193
  180. package/src/tag/uint.ts +0 -51
  181. package/src/test/did.ts +0 -346
  182. package/src/utils/tag-abi-codec.ts +0 -158
@@ -0,0 +1,690 @@
1
+ import {
2
+ parseEvents,
3
+ isTransferEvent,
4
+ isMintEvent,
5
+ isTagAddedEvent,
6
+ isTagRemovedEvent,
7
+ isTagElemUpdatedEvent,
8
+ isTagElemPushedEvent,
9
+ isTagElemPoppedEvent,
10
+ isNewTagTypeEvent,
11
+ EthLog
12
+ } from '../../src/utils/event-parser';
13
+
14
+ // ============================================================
15
+ // Mock log builders
16
+ //
17
+ // topics / data were generated by ethers.Interface.encodeEventLog()
18
+ // so they are byte-accurate representations of real on-chain logs.
19
+ // ============================================================
20
+
21
+ const ALICE = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266';
22
+ const BOB = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8';
23
+ const ZERO = '0x0000000000000000000000000000000000000000';
24
+
25
+ // uint256(keccak256(bytes(domain))) — matches the on-chain tokenIdOf() formula
26
+ const TOKEN_ID_MYTERMINUS =
27
+ 19879848525404628335667218519301564776273724019895250627053354759222278526802n;
28
+ const TOKEN_ID_ALICE_MYTERMINUS =
29
+ 24279146203655622512644202787146622025808553749677899566979293689773803127510n;
30
+
31
+ function makeLog(
32
+ overrides: Partial<EthLog> & { topics: string[]; data: string }
33
+ ): EthLog {
34
+ return {
35
+ address: '0x5DA4Fa8E567d86e52Ef8Da860de1be8f54cae97D',
36
+ blockNumber: '0x12d687', // 1234567
37
+ transactionHash:
38
+ '0xaabbccdd00000000000000000000000000000000000000000000000000000001',
39
+ transactionIndex: '0x0',
40
+ blockHash:
41
+ '0xdeadbeef00000000000000000000000000000000000000000000000000000000',
42
+ logIndex: '0x3', // 3
43
+ removed: false,
44
+ ...overrides
45
+ };
46
+ }
47
+
48
+ // ---- All 16 events ----
49
+
50
+ // 1. Transfer (mint): from=0x0, to=ALICE, tokenId=1
51
+ const MINT_LOG = makeLog({
52
+ topics: [
53
+ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
54
+ '0x0000000000000000000000000000000000000000000000000000000000000000',
55
+ '0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
56
+ '0x0000000000000000000000000000000000000000000000000000000000000001'
57
+ ],
58
+ data: '0x'
59
+ });
60
+
61
+ // 2. Transfer (transfer): from=ALICE, to=BOB, tokenId=1
62
+ const TRANSFER_LOG = makeLog({
63
+ topics: [
64
+ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
65
+ '0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
66
+ '0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8',
67
+ '0x0000000000000000000000000000000000000000000000000000000000000001'
68
+ ],
69
+ data: '0x'
70
+ });
71
+
72
+ // 3. Approval: owner=ALICE, approved=BOB, tokenId=1
73
+ const APPROVAL_LOG = makeLog({
74
+ topics: [
75
+ '0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925',
76
+ '0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
77
+ '0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8',
78
+ '0x0000000000000000000000000000000000000000000000000000000000000001'
79
+ ],
80
+ data: '0x'
81
+ });
82
+
83
+ // 4. ApprovalForAll: owner=ALICE, operator=BOB, approved=true
84
+ const APPROVAL_FOR_ALL_LOG = makeLog({
85
+ topics: [
86
+ '0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31',
87
+ '0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
88
+ '0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8'
89
+ ],
90
+ data: '0x0000000000000000000000000000000000000000000000000000000000000001'
91
+ });
92
+
93
+ // 5. Initialized: version=1
94
+ const INITIALIZED_LOG = makeLog({
95
+ topics: [
96
+ '0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2'
97
+ ],
98
+ data: '0x0000000000000000000000000000000000000000000000000000000000000001'
99
+ });
100
+
101
+ // 6. NewTagType: domain=myterminus.com, name=latestDID, abiType=0x0102, fieldNamesHash=[0xaaaa...aa]
102
+ const NEW_TAG_TYPE_LOG = makeLog({
103
+ topics: [
104
+ '0xaa8271025a5ba865c58a2d9769be8780815b52092150b6a75bd0c6f3807ef034'
105
+ ],
106
+ data: '0x000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000e6d797465726d696e75732e636f6d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000096c61746573744449440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000201020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
107
+ });
108
+
109
+ // 7. OffchainStringArray: hash=0xbbbb...bb, value=['field1','field2']
110
+ const OFFCHAIN_LOG = makeLog({
111
+ topics: [
112
+ '0xfc4832c7ea86d4e5dc86c34ae4c8c6dec2efca80fbfbf624e31b9d3cc534798f',
113
+ '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
114
+ ],
115
+ data: '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066669656c6431000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066669656c64320000000000000000000000000000000000000000000000000000'
116
+ });
117
+
118
+ // 8. OwnershipTransferStarted: previousOwner=ALICE, newOwner=BOB
119
+ const OWNERSHIP_TRANSFER_STARTED_LOG = makeLog({
120
+ topics: [
121
+ '0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700',
122
+ '0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
123
+ '0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8'
124
+ ],
125
+ data: '0x'
126
+ });
127
+
128
+ // 9. OwnershipTransferred: previousOwner=ALICE, newOwner=BOB
129
+ const OWNERSHIP_TRANSFERRED_LOG = makeLog({
130
+ topics: [
131
+ '0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0',
132
+ '0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
133
+ '0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8'
134
+ ],
135
+ data: '0x'
136
+ });
137
+
138
+ // 10. TagAdded: from=myterminus.com, to=alice.myterminus.com, name=latestDID, value=0xdeadbeef
139
+ const TAG_ADDED_LOG = makeLog({
140
+ topics: [
141
+ '0x5ca107007c1e738177f10dde04e0ee5abd1509873b6efcf24bd08abd00b2177f'
142
+ ],
143
+ data: '0x000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000e6d797465726d696e75732e636f6d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014616c6963652e6d797465726d696e75732e636f6d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000096c617465737444494400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000'
144
+ });
145
+
146
+ // 11. TagElemPopped: from=myterminus.com, to=alice.myterminus.com, name=wallets, elemPath=[0,1]
147
+ const TAG_ELEM_POPPED_LOG = makeLog({
148
+ topics: [
149
+ '0x61958e39a2b1ae93cf23e2410af0037a5b3580ce90a793e5f39d1995b6aa8300'
150
+ ],
151
+ data: '0x000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000e6d797465726d696e75732e636f6d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014616c6963652e6d797465726d696e75732e636f6d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000777616c6c65747300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001'
152
+ });
153
+
154
+ // 12. TagElemPushed: from=myterminus.com, to=alice.myterminus.com, name=wallets, elemPath=[0], value=0xcafebabe
155
+ const TAG_ELEM_PUSHED_LOG = makeLog({
156
+ topics: [
157
+ '0xfea766f86b68d35a2d7a916798fc3ab6f350d5b5c7a96e34549c91d6f9cea85f'
158
+ ],
159
+ data: '0x00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000e6d797465726d696e75732e636f6d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014616c6963652e6d797465726d696e75732e636f6d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000777616c6c65747300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004cafebabe00000000000000000000000000000000000000000000000000000000'
160
+ });
161
+
162
+ // 13. TagElemUpdated: from=myterminus.com, to=alice.myterminus.com, name=wallets, elemPath=[0], value=0xdeadbeef
163
+ const TAG_ELEM_UPDATED_LOG = makeLog({
164
+ topics: [
165
+ '0xdf2b75aeecf6e03f270e5ecbe00c9594c7cd49b6f9bcdec6a081bff6bbf29873'
166
+ ],
167
+ data: '0x00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000e6d797465726d696e75732e636f6d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014616c6963652e6d797465726d696e75732e636f6d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000777616c6c65747300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000'
168
+ });
169
+
170
+ // 14. TagRemoved: from=myterminus.com, to=alice.myterminus.com, name=latestDID
171
+ const TAG_REMOVED_LOG = makeLog({
172
+ topics: [
173
+ '0x4acaa22e43848ebfca138dbf8d5ee06f44f026980698144a20f74e3805374db2'
174
+ ],
175
+ data: '0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000e6d797465726d696e75732e636f6d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014616c6963652e6d797465726d696e75732e636f6d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000096c61746573744449440000000000000000000000000000000000000000000000'
176
+ });
177
+
178
+ // 15. TransferByParentOwner: tokenId=42
179
+ const TRANSFER_BY_PARENT_OWNER_LOG = makeLog({
180
+ topics: [
181
+ '0xfbca86852ebd6aae82b21918f5b4c7bd1a60548778b1f1ebc88fbc359e581c3d',
182
+ '0x000000000000000000000000000000000000000000000000000000000000002a'
183
+ ],
184
+ data: '0x'
185
+ });
186
+
187
+ // 16. TransferBySuperAdmin: tokenId=99
188
+ const TRANSFER_BY_SUPER_ADMIN_LOG = makeLog({
189
+ topics: [
190
+ '0x2a3326cdbd5e16d47f67bfcb2e3ebce284abaa2d49490956ec56b86cd1454fef',
191
+ '0x0000000000000000000000000000000000000000000000000000000000000063'
192
+ ],
193
+ data: '0x'
194
+ });
195
+
196
+ // 17. Upgraded: implementation=0x9fE46736...
197
+ const UPGRADED_LOG = makeLog({
198
+ topics: [
199
+ '0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b',
200
+ '0x0000000000000000000000009fe46736679d2d9a65f0992f2272de9f3c7fa6e0'
201
+ ],
202
+ data: '0x'
203
+ });
204
+
205
+ // An unrelated log (unknown topic — will be skipped)
206
+ const UNKNOWN_LOG = makeLog({
207
+ topics: [
208
+ '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
209
+ ],
210
+ data: '0x1234'
211
+ });
212
+
213
+ // ============================================================
214
+ // Tests
215
+ // ============================================================
216
+
217
+ describe('parseEvents', () => {
218
+ it('returns an empty array for empty input', () => {
219
+ expect(parseEvents([])).toEqual([]);
220
+ });
221
+
222
+ it('skips unknown logs without throwing', () => {
223
+ expect(parseEvents([UNKNOWN_LOG])).toHaveLength(0);
224
+ });
225
+
226
+ it('skips unknown logs mixed in with valid ones', () => {
227
+ const result = parseEvents([UNKNOWN_LOG, MINT_LOG, UNKNOWN_LOG]);
228
+ expect(result).toHaveLength(1);
229
+ });
230
+
231
+ // ---- ERC721 standard events ----
232
+
233
+ describe('Transfer (mint)', () => {
234
+ it('eventName is Transfer', () => {
235
+ const [e] = parseEvents([MINT_LOG]);
236
+ expect(e.eventName).toBe('Transfer');
237
+ });
238
+
239
+ it('isTransferEvent returns true', () => {
240
+ const [e] = parseEvents([MINT_LOG]);
241
+ expect(isTransferEvent(e)).toBe(true);
242
+ });
243
+
244
+ it('isMintEvent returns true when from is 0x0', () => {
245
+ const [e] = parseEvents([MINT_LOG]);
246
+ expect(isMintEvent(e)).toBe(true);
247
+ });
248
+
249
+ it('args: from=0x0, to=ALICE, tokenId=1n', () => {
250
+ const [e] = parseEvents([MINT_LOG]);
251
+ if (!isTransferEvent(e)) throw new Error();
252
+ expect(e.args.from).toBe(ZERO);
253
+ expect(e.args.to).toBe(ALICE);
254
+ expect(e.args.tokenId).toBe(1n);
255
+ });
256
+
257
+ it('tokenId field = 1n (direct)', () => {
258
+ const [e] = parseEvents([MINT_LOG]);
259
+ expect(e.tokenId).toBe(1n);
260
+ });
261
+ });
262
+
263
+ describe('Transfer (ownership transfer)', () => {
264
+ it('isMintEvent returns false when from is not 0x0', () => {
265
+ const [e] = parseEvents([TRANSFER_LOG]);
266
+ expect(isMintEvent(e)).toBe(false);
267
+ });
268
+
269
+ it('args: from=ALICE, to=BOB, tokenId=1n', () => {
270
+ const [e] = parseEvents([TRANSFER_LOG]);
271
+ if (!isTransferEvent(e)) throw new Error();
272
+ expect(e.args.from).toBe(ALICE);
273
+ expect(e.args.to).toBe(BOB);
274
+ expect(e.args.tokenId).toBe(1n);
275
+ });
276
+
277
+ it('tokenId field = 1n (direct)', () => {
278
+ const [e] = parseEvents([TRANSFER_LOG]);
279
+ expect(e.tokenId).toBe(1n);
280
+ });
281
+ });
282
+
283
+ describe('Approval', () => {
284
+ it('eventName is Approval', () => {
285
+ const [e] = parseEvents([APPROVAL_LOG]);
286
+ expect(e.eventName).toBe('Approval');
287
+ });
288
+
289
+ it('args: owner=ALICE, approved=BOB, tokenId=1n', () => {
290
+ const [e] = parseEvents([APPROVAL_LOG]);
291
+ if (e.eventName !== 'Approval') throw new Error();
292
+ expect(e.args.owner).toBe(ALICE);
293
+ expect(e.args.approved).toBe(BOB);
294
+ expect(e.args.tokenId).toBe(1n);
295
+ });
296
+
297
+ it('tokenId field = undefined (Approval does not modify domain state)', () => {
298
+ const [e] = parseEvents([APPROVAL_LOG]);
299
+ expect(e.tokenId).toBeUndefined();
300
+ });
301
+ });
302
+
303
+ describe('ApprovalForAll', () => {
304
+ it('eventName is ApprovalForAll', () => {
305
+ const [e] = parseEvents([APPROVAL_FOR_ALL_LOG]);
306
+ expect(e.eventName).toBe('ApprovalForAll');
307
+ });
308
+
309
+ it('args: owner=ALICE, operator=BOB, approved=true', () => {
310
+ const [e] = parseEvents([APPROVAL_FOR_ALL_LOG]);
311
+ if (e.eventName !== 'ApprovalForAll') throw new Error();
312
+ expect(e.args.owner).toBe(ALICE);
313
+ expect(e.args.operator).toBe(BOB);
314
+ expect(e.args.approved).toBe(true);
315
+ });
316
+
317
+ it('tokenId field = undefined (no tokenId in ApprovalForAll)', () => {
318
+ const [e] = parseEvents([APPROVAL_FOR_ALL_LOG]);
319
+ expect(e.tokenId).toBeUndefined();
320
+ });
321
+ });
322
+
323
+ // ---- UUPS / Ownable events ----
324
+
325
+ describe('Initialized', () => {
326
+ it('eventName is Initialized', () => {
327
+ const [e] = parseEvents([INITIALIZED_LOG]);
328
+ expect(e.eventName).toBe('Initialized');
329
+ });
330
+
331
+ it('args: version=1n', () => {
332
+ const [e] = parseEvents([INITIALIZED_LOG]);
333
+ if (e.eventName !== 'Initialized') throw new Error();
334
+ expect(e.args.version).toBe(1n);
335
+ });
336
+
337
+ it('tokenId field = undefined', () => {
338
+ const [e] = parseEvents([INITIALIZED_LOG]);
339
+ expect(e.tokenId).toBeUndefined();
340
+ });
341
+ });
342
+
343
+ describe('OwnershipTransferStarted', () => {
344
+ it('eventName is OwnershipTransferStarted', () => {
345
+ const [e] = parseEvents([OWNERSHIP_TRANSFER_STARTED_LOG]);
346
+ expect(e.eventName).toBe('OwnershipTransferStarted');
347
+ });
348
+
349
+ it('args: previousOwner=ALICE, newOwner=BOB', () => {
350
+ const [e] = parseEvents([OWNERSHIP_TRANSFER_STARTED_LOG]);
351
+ if (e.eventName !== 'OwnershipTransferStarted') throw new Error();
352
+ expect(e.args.previousOwner).toBe(ALICE);
353
+ expect(e.args.newOwner).toBe(BOB);
354
+ });
355
+
356
+ it('tokenId field = undefined', () => {
357
+ const [e] = parseEvents([OWNERSHIP_TRANSFER_STARTED_LOG]);
358
+ expect(e.tokenId).toBeUndefined();
359
+ });
360
+ });
361
+
362
+ describe('OwnershipTransferred', () => {
363
+ it('eventName is OwnershipTransferred', () => {
364
+ const [e] = parseEvents([OWNERSHIP_TRANSFERRED_LOG]);
365
+ expect(e.eventName).toBe('OwnershipTransferred');
366
+ });
367
+
368
+ it('args: previousOwner=ALICE, newOwner=BOB', () => {
369
+ const [e] = parseEvents([OWNERSHIP_TRANSFERRED_LOG]);
370
+ if (e.eventName !== 'OwnershipTransferred') throw new Error();
371
+ expect(e.args.previousOwner).toBe(ALICE);
372
+ expect(e.args.newOwner).toBe(BOB);
373
+ });
374
+
375
+ it('tokenId field = undefined', () => {
376
+ const [e] = parseEvents([OWNERSHIP_TRANSFERRED_LOG]);
377
+ expect(e.tokenId).toBeUndefined();
378
+ });
379
+ });
380
+
381
+ describe('Upgraded', () => {
382
+ it('eventName is Upgraded', () => {
383
+ const [e] = parseEvents([UPGRADED_LOG]);
384
+ expect(e.eventName).toBe('Upgraded');
385
+ });
386
+
387
+ it('args: implementation address is correct', () => {
388
+ const [e] = parseEvents([UPGRADED_LOG]);
389
+ if (e.eventName !== 'Upgraded') throw new Error();
390
+ expect(e.args.implementation).toBe(
391
+ '0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0'
392
+ );
393
+ });
394
+
395
+ it('tokenId field = undefined', () => {
396
+ const [e] = parseEvents([UPGRADED_LOG]);
397
+ expect(e.tokenId).toBeUndefined();
398
+ });
399
+ });
400
+
401
+ // ---- Custom transfer events ----
402
+
403
+ describe('TransferByParentOwner', () => {
404
+ it('eventName is TransferByParentOwner', () => {
405
+ const [e] = parseEvents([TRANSFER_BY_PARENT_OWNER_LOG]);
406
+ expect(e.eventName).toBe('TransferByParentOwner');
407
+ });
408
+
409
+ it('args: tokenId=42n', () => {
410
+ const [e] = parseEvents([TRANSFER_BY_PARENT_OWNER_LOG]);
411
+ if (e.eventName !== 'TransferByParentOwner') throw new Error();
412
+ expect(e.args.tokenId).toBe(42n);
413
+ });
414
+
415
+ it('tokenId field = 42n (direct)', () => {
416
+ const [e] = parseEvents([TRANSFER_BY_PARENT_OWNER_LOG]);
417
+ expect(e.tokenId).toBe(42n);
418
+ });
419
+ });
420
+
421
+ describe('TransferBySuperAdmin', () => {
422
+ it('eventName is TransferBySuperAdmin', () => {
423
+ const [e] = parseEvents([TRANSFER_BY_SUPER_ADMIN_LOG]);
424
+ expect(e.eventName).toBe('TransferBySuperAdmin');
425
+ });
426
+
427
+ it('args: tokenId=99n', () => {
428
+ const [e] = parseEvents([TRANSFER_BY_SUPER_ADMIN_LOG]);
429
+ if (e.eventName !== 'TransferBySuperAdmin') throw new Error();
430
+ expect(e.args.tokenId).toBe(99n);
431
+ });
432
+
433
+ it('tokenId field = 99n (direct)', () => {
434
+ const [e] = parseEvents([TRANSFER_BY_SUPER_ADMIN_LOG]);
435
+ expect(e.tokenId).toBe(99n);
436
+ });
437
+ });
438
+
439
+ // ---- Tag events ----
440
+
441
+ describe('NewTagType', () => {
442
+ it('eventName is NewTagType', () => {
443
+ const [e] = parseEvents([NEW_TAG_TYPE_LOG]);
444
+ expect(e.eventName).toBe('NewTagType');
445
+ expect(isNewTagTypeEvent(e)).toBe(true);
446
+ });
447
+
448
+ it('args: domain, name, abiType, fieldNamesHash', () => {
449
+ const [e] = parseEvents([NEW_TAG_TYPE_LOG]);
450
+ if (!isNewTagTypeEvent(e)) throw new Error();
451
+ expect(e.args.domain).toBe('myterminus.com');
452
+ expect(e.args.name).toBe('latestDID');
453
+ expect(e.args.abiType).toBe('0x0102');
454
+ expect(e.args.fieldNamesHash).toHaveLength(1);
455
+ expect(e.args.fieldNamesHash[0]).toBe(
456
+ '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
457
+ );
458
+ });
459
+
460
+ it('tokenId field = keccak256(domain) = TOKEN_ID_MYTERMINUS', () => {
461
+ const [e] = parseEvents([NEW_TAG_TYPE_LOG]);
462
+ expect(e.tokenId).toBe(TOKEN_ID_MYTERMINUS);
463
+ });
464
+ });
465
+
466
+ describe('TagAdded', () => {
467
+ it('eventName is TagAdded', () => {
468
+ const [e] = parseEvents([TAG_ADDED_LOG]);
469
+ expect(e.eventName).toBe('TagAdded');
470
+ expect(isTagAddedEvent(e)).toBe(true);
471
+ });
472
+
473
+ it('args: from, to, name, value', () => {
474
+ const [e] = parseEvents([TAG_ADDED_LOG]);
475
+ if (!isTagAddedEvent(e)) throw new Error();
476
+ expect(e.args.from).toBe('myterminus.com');
477
+ expect(e.args.to).toBe('alice.myterminus.com');
478
+ expect(e.args.name).toBe('latestDID');
479
+ expect(e.args.value).toBe('0xdeadbeef');
480
+ });
481
+
482
+ it('tokenId field = keccak256(to) = TOKEN_ID_ALICE_MYTERMINUS', () => {
483
+ const [e] = parseEvents([TAG_ADDED_LOG]);
484
+ expect(e.tokenId).toBe(TOKEN_ID_ALICE_MYTERMINUS);
485
+ });
486
+ });
487
+
488
+ describe('TagRemoved', () => {
489
+ it('eventName is TagRemoved', () => {
490
+ const [e] = parseEvents([TAG_REMOVED_LOG]);
491
+ expect(e.eventName).toBe('TagRemoved');
492
+ expect(isTagRemovedEvent(e)).toBe(true);
493
+ });
494
+
495
+ it('args: from, to, name', () => {
496
+ const [e] = parseEvents([TAG_REMOVED_LOG]);
497
+ if (!isTagRemovedEvent(e)) throw new Error();
498
+ expect(e.args.from).toBe('myterminus.com');
499
+ expect(e.args.to).toBe('alice.myterminus.com');
500
+ expect(e.args.name).toBe('latestDID');
501
+ });
502
+
503
+ it('tokenId field = keccak256(to) = TOKEN_ID_ALICE_MYTERMINUS', () => {
504
+ const [e] = parseEvents([TAG_REMOVED_LOG]);
505
+ expect(e.tokenId).toBe(TOKEN_ID_ALICE_MYTERMINUS);
506
+ });
507
+ });
508
+
509
+ describe('TagElemPopped', () => {
510
+ it('eventName is TagElemPopped', () => {
511
+ const [e] = parseEvents([TAG_ELEM_POPPED_LOG]);
512
+ expect(e.eventName).toBe('TagElemPopped');
513
+ expect(isTagElemPoppedEvent(e)).toBe(true);
514
+ });
515
+
516
+ it('args: from, to, name, elemPath=[0n,1n]', () => {
517
+ const [e] = parseEvents([TAG_ELEM_POPPED_LOG]);
518
+ if (!isTagElemPoppedEvent(e)) throw new Error();
519
+ expect(e.args.from).toBe('myterminus.com');
520
+ expect(e.args.to).toBe('alice.myterminus.com');
521
+ expect(e.args.name).toBe('wallets');
522
+ expect(e.args.elemPath).toEqual([0n, 1n]);
523
+ });
524
+
525
+ it('tokenId field = keccak256(to) = TOKEN_ID_ALICE_MYTERMINUS', () => {
526
+ const [e] = parseEvents([TAG_ELEM_POPPED_LOG]);
527
+ expect(e.tokenId).toBe(TOKEN_ID_ALICE_MYTERMINUS);
528
+ });
529
+ });
530
+
531
+ describe('TagElemPushed', () => {
532
+ it('eventName is TagElemPushed', () => {
533
+ const [e] = parseEvents([TAG_ELEM_PUSHED_LOG]);
534
+ expect(e.eventName).toBe('TagElemPushed');
535
+ expect(isTagElemPushedEvent(e)).toBe(true);
536
+ });
537
+
538
+ it('args: from, to, name, elemPath=[0n], value=0xcafebabe', () => {
539
+ const [e] = parseEvents([TAG_ELEM_PUSHED_LOG]);
540
+ if (!isTagElemPushedEvent(e)) throw new Error();
541
+ expect(e.args.from).toBe('myterminus.com');
542
+ expect(e.args.to).toBe('alice.myterminus.com');
543
+ expect(e.args.name).toBe('wallets');
544
+ expect(e.args.elemPath).toEqual([0n]);
545
+ expect(e.args.value).toBe('0xcafebabe');
546
+ });
547
+
548
+ it('tokenId field = keccak256(to) = TOKEN_ID_ALICE_MYTERMINUS', () => {
549
+ const [e] = parseEvents([TAG_ELEM_PUSHED_LOG]);
550
+ expect(e.tokenId).toBe(TOKEN_ID_ALICE_MYTERMINUS);
551
+ });
552
+ });
553
+
554
+ describe('TagElemUpdated', () => {
555
+ it('eventName is TagElemUpdated', () => {
556
+ const [e] = parseEvents([TAG_ELEM_UPDATED_LOG]);
557
+ expect(e.eventName).toBe('TagElemUpdated');
558
+ expect(isTagElemUpdatedEvent(e)).toBe(true);
559
+ });
560
+
561
+ it('args: from, to, name, elemPath=[0n], value=0xdeadbeef', () => {
562
+ const [e] = parseEvents([TAG_ELEM_UPDATED_LOG]);
563
+ if (!isTagElemUpdatedEvent(e)) throw new Error();
564
+ expect(e.args.from).toBe('myterminus.com');
565
+ expect(e.args.to).toBe('alice.myterminus.com');
566
+ expect(e.args.name).toBe('wallets');
567
+ expect(e.args.elemPath).toEqual([0n]);
568
+ expect(e.args.value).toBe('0xdeadbeef');
569
+ });
570
+
571
+ it('tokenId field = keccak256(to) = TOKEN_ID_ALICE_MYTERMINUS', () => {
572
+ const [e] = parseEvents([TAG_ELEM_UPDATED_LOG]);
573
+ expect(e.tokenId).toBe(TOKEN_ID_ALICE_MYTERMINUS);
574
+ });
575
+ });
576
+
577
+ describe('OffchainStringArray', () => {
578
+ it('eventName is OffchainStringArray', () => {
579
+ const [e] = parseEvents([OFFCHAIN_LOG]);
580
+ expect(e.eventName).toBe('OffchainStringArray');
581
+ });
582
+
583
+ it('args: hash=0xbbbb...bb, value=[field1, field2]', () => {
584
+ const [e] = parseEvents([OFFCHAIN_LOG]);
585
+ if (e.eventName !== 'OffchainStringArray') throw new Error();
586
+ expect(e.args.hash).toBe(
587
+ '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
588
+ );
589
+ expect(e.args.value).toEqual(['field1', 'field2']);
590
+ });
591
+
592
+ it('tokenId field = undefined', () => {
593
+ const [e] = parseEvents([OFFCHAIN_LOG]);
594
+ expect(e.tokenId).toBeUndefined();
595
+ });
596
+ });
597
+
598
+ // ---- Metadata checks ----
599
+
600
+ describe('log metadata', () => {
601
+ it('blockNumber is decoded from hex', () => {
602
+ const log = { ...MINT_LOG, blockNumber: '0x64' }; // 100
603
+ const [e] = parseEvents([log]);
604
+ expect(e.blockNumber).toBe(100);
605
+ });
606
+
607
+ it('logIndex is decoded from hex', () => {
608
+ const log = { ...MINT_LOG, logIndex: '0x5' }; // 5
609
+ const [e] = parseEvents([log]);
610
+ expect(e.logIndex).toBe(5);
611
+ });
612
+
613
+ it('transactionHash is preserved as-is', () => {
614
+ const [e] = parseEvents([MINT_LOG]);
615
+ expect(e.transactionHash).toBe(MINT_LOG.transactionHash);
616
+ });
617
+
618
+ it('raw field is the original EthLog object', () => {
619
+ const [e] = parseEvents([MINT_LOG]);
620
+ expect(e.raw).toBe(MINT_LOG);
621
+ });
622
+ });
623
+
624
+ // ---- Batch ----
625
+
626
+ describe('batch parsing', () => {
627
+ const ALL_16_LOGS = [
628
+ MINT_LOG,
629
+ TRANSFER_LOG,
630
+ APPROVAL_LOG,
631
+ APPROVAL_FOR_ALL_LOG,
632
+ INITIALIZED_LOG,
633
+ NEW_TAG_TYPE_LOG,
634
+ OFFCHAIN_LOG,
635
+ OWNERSHIP_TRANSFER_STARTED_LOG,
636
+ OWNERSHIP_TRANSFERRED_LOG,
637
+ TAG_ADDED_LOG,
638
+ TAG_ELEM_POPPED_LOG,
639
+ TAG_ELEM_PUSHED_LOG,
640
+ TAG_ELEM_UPDATED_LOG,
641
+ TAG_REMOVED_LOG,
642
+ TRANSFER_BY_PARENT_OWNER_LOG,
643
+ TRANSFER_BY_SUPER_ADMIN_LOG,
644
+ UPGRADED_LOG
645
+ ];
646
+
647
+ it('parses all 17 logs (Transfer appears twice: mint + transfer)', () => {
648
+ const result = parseEvents(ALL_16_LOGS);
649
+ expect(result).toHaveLength(17);
650
+ });
651
+
652
+ it('preserves original order', () => {
653
+ const result = parseEvents(ALL_16_LOGS);
654
+ const names = result.map((e) => e.eventName);
655
+ expect(names).toEqual([
656
+ 'Transfer',
657
+ 'Transfer',
658
+ 'Approval',
659
+ 'ApprovalForAll',
660
+ 'Initialized',
661
+ 'NewTagType',
662
+ 'OffchainStringArray',
663
+ 'OwnershipTransferStarted',
664
+ 'OwnershipTransferred',
665
+ 'TagAdded',
666
+ 'TagElemPopped',
667
+ 'TagElemPushed',
668
+ 'TagElemUpdated',
669
+ 'TagRemoved',
670
+ 'TransferByParentOwner',
671
+ 'TransferBySuperAdmin',
672
+ 'Upgraded'
673
+ ]);
674
+ });
675
+
676
+ it('unknown logs interspersed with valid ones are skipped', () => {
677
+ const mixed = [
678
+ UNKNOWN_LOG,
679
+ MINT_LOG,
680
+ UNKNOWN_LOG,
681
+ TAG_ADDED_LOG,
682
+ UNKNOWN_LOG
683
+ ];
684
+ const result = parseEvents(mixed);
685
+ expect(result).toHaveLength(2);
686
+ expect(result[0].eventName).toBe('Transfer');
687
+ expect(result[1].eventName).toBe('TagAdded');
688
+ });
689
+ });
690
+ });