@beclab/olaresid 0.1.13 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) 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 +81 -23
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +158 -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 +230 -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/tests/unit/version.test.ts +14 -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
@@ -1,662 +1,292 @@
1
- import { ethers } from 'ethers';
2
- import DIDTag from '../tag/index';
3
- import { debug } from '../debug';
4
-
5
- const getBase64 = (data: any) => {
6
- const hex = data;
7
- const arr = [];
8
- for (let i = 0; i < hex.length; i += 2) {
9
- const code = parseInt(hex.slice(i, i + 2), 16);
10
- arr.push(code);
1
+ /**
2
+ * Domain fetching functions
3
+ *
4
+ * This module provides three main functions for fetching domain data:
5
+ * 1. fetchDomain - Fetch a single domain by name or tokenId
6
+ * 2. fetchDomains - Fetch multiple domains with pagination
7
+ * 3. fetchAllFlat - Fetch all domains with flat structure
8
+ */
9
+
10
+ import {
11
+ QueryContractHelper,
12
+ collectFieldNameHashes,
13
+ batchFetchFieldNames,
14
+ parseDomain,
15
+ parseAllDomains
16
+ } from './core';
17
+ import { FlatDomainData, FetchAllOptions } from './types';
18
+ import type { DIDConsole } from '../index';
19
+
20
+ /**
21
+ * Options for fetchDomain
22
+ */
23
+ export interface FetchDomainOptions {
24
+ queryContractAddress?: string;
25
+ }
26
+
27
+ /**
28
+ * Options for fetchDomains (paginated query)
29
+ */
30
+ export interface FetchDomainsOptions {
31
+ queryContractAddress?: string;
32
+ offset: number;
33
+ limit: number;
34
+ }
35
+
36
+ /**
37
+ * Fetch a single domain by name or tokenId
38
+ *
39
+ * @param console - DIDConsole instance
40
+ * @param nameOrTokenId - Domain name (e.g., "alice.olares.com") or tokenId (hex string or bigint)
41
+ * @param options - Fetch options
42
+ * @returns Domain data or null if not found
43
+ *
44
+ * @example
45
+ * // Fetch by domain name
46
+ * const domain = await fetchDomain(console, "alice.olares.com", { queryContractAddress });
47
+ *
48
+ * // Fetch by tokenId
49
+ * const domain = await fetchDomain(console, "0x123...", { queryContractAddress });
50
+ */
51
+ export async function fetchDomain(
52
+ console: DIDConsole,
53
+ nameOrTokenId: string | bigint,
54
+ options: FetchDomainOptions = {}
55
+ ): Promise<FlatDomainData | null> {
56
+ const { queryContractAddress } = options;
57
+
58
+ if (!queryContractAddress) {
59
+ throw new Error('queryContractAddress is required');
11
60
  }
12
- debug.info(arr);
13
61
 
14
- let str = '';
15
- for (let i = 0; i < arr.length; i++) {
16
- const char = String.fromCharCode(arr[i]);
17
- str += char;
62
+ // Step 1: Create query helper
63
+ const helper = new QueryContractHelper(
64
+ queryContractAddress,
65
+ console.getProvider()
66
+ );
67
+
68
+ // Step 2: Fetch single domain (supports both name and tokenId)
69
+ const rawDomain = await helper.getDomain(nameOrTokenId);
70
+
71
+ if (!rawDomain) {
72
+ return null;
18
73
  }
19
- debug.info(str);
20
- const base64 = btoa(str);
21
- debug.info(base64);
22
-
23
- return base64;
24
- };
25
-
26
- const getHex = (data: any) => {
27
- let hex = '';
28
- for (let i = 0; i < data.length; i++) {
29
- const code = data.charCodeAt(i);
30
- let hexCode = code.toString(16);
31
- if (hexCode.length < 2) {
32
- hexCode = '0' + hexCode;
33
- }
34
- hex += hexCode;
74
+
75
+ // Step 3: Collect field name hashes from this domain's tags
76
+ const fieldNameHashes = collectFieldNameHashes([rawDomain]);
77
+
78
+ // Step 4: Batch fetch field names
79
+ const contract = console.getContractDID();
80
+ const fieldNamesMap = await batchFetchFieldNames(contract, fieldNameHashes);
81
+
82
+ // Step 5: Parse domain (no parentId calculation for single domain)
83
+ const domain = parseDomain(rawDomain, fieldNamesMap);
84
+
85
+ return domain;
86
+ }
87
+
88
+ /**
89
+ * Fetch multiple domains with pagination
90
+ * Allows you to fetch a specific range of domains with offset and limit
91
+ *
92
+ * @param console - DIDConsole instance
93
+ * @param options - Fetch options including offset and limit
94
+ * @returns Array of domains in the specified range
95
+ *
96
+ * @example
97
+ * // Fetch first 10 domains
98
+ * const domains = await fetchDomains(console, {
99
+ * queryContractAddress: "0x...",
100
+ * offset: 0,
101
+ * limit: 10
102
+ * });
103
+ *
104
+ * // Fetch next 10 domains
105
+ * const nextDomains = await fetchDomains(console, {
106
+ * queryContractAddress: "0x...",
107
+ * offset: 10,
108
+ * limit: 10
109
+ * });
110
+ */
111
+ export async function fetchDomains(
112
+ console: DIDConsole,
113
+ options: FetchDomainsOptions
114
+ ): Promise<FlatDomainData[]> {
115
+ const { queryContractAddress, offset, limit } = options;
116
+
117
+ if (!queryContractAddress) {
118
+ throw new Error('queryContractAddress is required');
35
119
  }
36
- debug.info(hex);
37
- return hex;
38
- };
39
-
40
- export namespace PackageDomain {
41
- export interface Tag {
42
- definition: any;
43
- from: string;
44
- to: string;
45
- name: string;
46
- valueFormated: any;
47
- valueSource: any;
120
+
121
+ if (offset < 0) {
122
+ throw new Error('offset must be >= 0');
48
123
  }
49
124
 
50
- export interface DomainData {
51
- id: string;
52
- name: string;
53
- did: string;
54
- note: string;
55
- allowSubdomain: boolean;
56
- owner: string;
57
- subdomains: DomainData[];
58
- tags: Tag[];
125
+ if (limit <= 0) {
126
+ throw new Error('limit must be > 0');
59
127
  }
60
128
 
61
- export interface OfficialExtendedInformation {
62
- ip: string;
63
- rsaKey: string;
64
- authenticateds: any[];
65
- latestDID: string;
129
+ // Step 1: Create query helper
130
+ const helper = new QueryContractHelper(
131
+ queryContractAddress,
132
+ console.getProvider()
133
+ );
134
+
135
+ // Step 2: Fetch domains in the specified range
136
+ const rawDomains = await helper.getAllDomains(offset, limit);
137
+
138
+ // Return empty array if no domains found
139
+ if (rawDomains.length === 0) {
140
+ return [];
66
141
  }
67
142
 
68
- export class Domain implements DomainData {
69
- id: string;
70
- name: string;
71
- did: string;
72
- note: string;
73
- allowSubdomain: boolean;
74
- owner: string;
75
- subdomains: DomainData[];
76
- tags: Tag[];
77
-
78
- constructor(
79
- id: string,
80
- name: string,
81
- did: string,
82
- note: string,
83
- allowSubdomain: boolean,
84
- owner: string,
85
- subdomains: Domain[],
86
- tags: Tag[]
87
- ) {
88
- this.id = id;
89
- this.name = name;
90
- this.did = did;
91
- this.note = note;
92
- this.allowSubdomain = allowSubdomain;
93
- this.owner = owner;
94
- this.subdomains = subdomains;
95
- this.tags = tags;
96
- }
143
+ // Step 3: Collect field name hashes
144
+ const fieldNameHashes = collectFieldNameHashes(rawDomains);
145
+
146
+ // Step 4: Batch fetch field names
147
+ const contract = console.getContractDID();
148
+ const fieldNamesMap = await batchFetchFieldNames(contract, fieldNameHashes);
149
+
150
+ // Step 5: Parse domains (with parentId calculation)
151
+ const flatDomains = parseAllDomains(rawDomains, fieldNamesMap);
152
+
153
+ return flatDomains;
154
+ }
155
+
156
+ /**
157
+ * Options for fetchDomainsByIndices
158
+ */
159
+ export interface FetchDomainsByIndicesOptions {
160
+ queryContractAddress?: string;
161
+ }
162
+
163
+ /**
164
+ * Fetch multiple domains by their indices
165
+ * Useful for fetching specific domains when you know their positions
166
+ *
167
+ * @param console - DIDConsole instance
168
+ * @param indices - Array of domain indices (e.g., [5, 6, 9, 10])
169
+ * @param options - Fetch options
170
+ * @returns Array of domains corresponding to the specified indices
171
+ *
172
+ * @example
173
+ * // Fetch domains at specific indices
174
+ * const domains = await fetchDomainsByIndices(console, [5, 6, 9, 10], {
175
+ * queryContractAddress: "0x..."
176
+ * });
177
+ *
178
+ * // Result will contain domains at positions 5, 6, 9, and 10
179
+ * // indices[0] -> domains[0], indices[1] -> domains[1], etc.
180
+ */
181
+ export async function fetchDomainsByIndices(
182
+ console: DIDConsole,
183
+ indices: number[],
184
+ options: FetchDomainsByIndicesOptions = {}
185
+ ): Promise<FlatDomainData[]> {
186
+ const { queryContractAddress } = options;
187
+
188
+ if (!queryContractAddress) {
189
+ throw new Error('queryContractAddress is required');
97
190
  }
98
191
 
99
- export const syncById = (tokenId: string, contract: ethers.Contract) =>
100
- new Promise<Domain>(async (resolve, reject) => {
101
- let meta: any | undefined = undefined;
102
- let owner: string | undefined = undefined;
103
- let times = 0;
104
- while (
105
- tokenId == undefined ||
106
- meta == undefined ||
107
- owner == undefined
108
- ) {
109
- try {
110
- meta = await contract.getMetadata(tokenId);
111
- owner = await contract.ownerOf(tokenId);
112
- } catch (error) {
113
- times++;
114
- if (times >= 5) {
115
- throw new Error('network error');
116
- }
117
- }
118
- }
119
- // debug.info('meta', meta);
120
- const domain = {
121
- id: ethers.toBeHex(tokenId),
122
- name: meta['0'],
123
- did: meta['1'],
124
- note: meta['2'],
125
- allowSubdomain: meta['3'],
126
- subdomains: [],
127
- owner: owner,
128
- tags: []
129
- } as Domain;
130
-
131
- const tags = await fetchAllTagType(domain, contract);
132
- domain.tags = tags;
133
-
134
- await fetchAllTagValue(domain, contract);
135
-
136
- resolve(domain);
137
- });
138
-
139
- export const syncByName = (name: string, contract: ethers.Contract) =>
140
- new Promise<Domain | undefined>(async (resolve, reject) => {
141
- let tokenId: string | undefined = await contract.tokenIdOf(name);
142
- debug.info('syncByName', name, tokenId);
143
- if (tokenId == undefined) {
144
- resolve(undefined);
145
- } else {
146
- resolve(await syncById(tokenId, contract));
147
- }
148
- });
149
-
150
- export const syncByIndex = (index: number, contract: ethers.Contract) =>
151
- new Promise<Domain>(async (resolve, reject) => {
152
- let tokenId: string | undefined = undefined;
153
-
154
- let times = 0;
155
- while (tokenId == undefined) {
156
- try {
157
- tokenId = await contract.tokenByIndex(index);
158
- } catch (error) {
159
- times++;
160
- if (times >= 5) {
161
- throw new Error('network error');
162
- }
163
- }
164
- }
165
- resolve(await syncById(tokenId, contract));
166
- });
167
-
168
- export const buildTree = (allDomains: Domain[]): Domain[] => {
169
- allDomains.forEach((item) => {
170
- const domains = findSubdomain(item, allDomains);
171
- item.subdomains = domains;
172
- });
173
- return allDomains.filter((item) => item.name.split('.').length == 1);
174
- };
175
-
176
- export const findSubdomain = (domain: Domain, allDomains: Domain[]) => {
177
- const arr: Domain[] = [];
178
- allDomains.forEach((item) => {
179
- if (
180
- item.name.endsWith('.' + domain.name) &&
181
- domain.name.split('.').length + 1 == item.name.split('.').length
182
- ) {
183
- const subdomains = findSubdomain(item, allDomains);
184
-
185
- item.subdomains = subdomains;
186
- arr.push(item);
187
- }
188
- });
189
- return arr;
190
- };
191
-
192
- export const findASubtree = (
193
- name: string,
194
- allDomains: Domain[]
195
- ): Domain | undefined => {
196
- for (const domain of allDomains) {
197
- if (domain.name == name) {
198
- return domain;
199
- }
200
- }
201
- return undefined;
202
- };
203
-
204
- export const findSubtreesByOwner = (
205
- owner: string,
206
- allDomains: Domain[]
207
- ): Domain[] => {
208
- let arr: Domain[] = [];
209
-
210
- arr.push(
211
- ...allDomains.filter(
212
- (d) => d.owner.toLocaleLowerCase() == owner.toLocaleLowerCase()
213
- )
192
+ if (!Array.isArray(indices) || indices.length === 0) {
193
+ throw new Error('indices must be a non-empty array');
194
+ }
195
+
196
+ if (indices.length > 100) {
197
+ throw new Error(
198
+ `Too many indices: ${indices.length}. Maximum is 100. Please split into multiple calls.`
214
199
  );
215
- for (const d of allDomains) {
216
- let subArr = findSubtreesByOwner(owner, d.subdomains);
217
- arr.push(...subArr);
200
+ }
201
+
202
+ // Validate all indices are non-negative
203
+ for (const index of indices) {
204
+ if (index < 0 || !Number.isInteger(index)) {
205
+ throw new Error(
206
+ `Invalid index: ${index}. All indices must be non-negative integers`
207
+ );
218
208
  }
209
+ }
219
210
 
220
- return arr;
221
- };
211
+ // Step 1: Create query helper
212
+ const helper = new QueryContractHelper(
213
+ queryContractAddress,
214
+ console.getProvider()
215
+ );
222
216
 
223
- export const findSubtreesByDid = (
224
- did: string,
225
- allDomains: Domain[]
226
- ): Domain[] => {
227
- let arr: Domain[] = [];
217
+ // Step 2: Fetch domains by indices (single RPC call)
218
+ const rawDomains = await helper.getDomainsByIndices(indices);
228
219
 
229
- arr.push(...allDomains.filter((d) => d.did.startsWith(did)));
230
- for (const d of allDomains) {
231
- let subArr = findSubtreesByDid(did, d.subdomains);
232
- arr.push(...subArr);
233
- }
220
+ if (rawDomains.length === 0) {
221
+ return [];
222
+ }
234
223
 
235
- return arr;
236
- };
237
-
238
- export const fetchAllTagType = (
239
- domain: Domain,
240
- contract: ethers.Contract
241
- ) =>
242
- new Promise<Tag[]>(async (resolve, reject) => {
243
- // debug.info('fetchAllTagType', domain);
244
-
245
- let d = domain.name.split('.');
246
- let fromArr = [''];
247
- for (let index = 1; index <= d.length; index++) {
248
- fromArr.push(d.slice(d.length - index).join('.'));
249
- }
250
- debug.info('fromArr', fromArr);
251
-
252
- let arr: Tag[] = [];
253
- for (const from of fromArr) {
254
- debug.group(from);
255
- let count = await contract.getDefinedTagCount(from);
256
- debug.info('count', count);
257
-
258
- for (let i = 0; i < count; i++) {
259
- let name = await contract.getDefinedTagNameByIndex(from, i);
260
- debug.info('name', name);
261
-
262
- arr.push({
263
- from: from,
264
- to: domain.name,
265
- name: name,
266
- valueFormated: undefined,
267
- valueSource: undefined
268
- } as Tag);
269
- }
270
- debug.groupEnd();
271
- }
272
- domain.tags = arr;
273
- resolve(domain.tags);
274
- });
275
-
276
- export const fetchTagStructure = (tag: Tag, contract: ethers.Contract) =>
277
- new Promise<DIDTag.TagParser>(async (resolve, reject) => {
278
- debug.info('fetchTagStructure', tag.from, tag.to, tag.name);
279
-
280
- const tagRawType = await contract.getTagABIType(tag.from, tag.name);
281
- // debug.info(`tag type raw bytes:`);
282
- // debug.info(tagRawType);
283
-
284
- const tagType = DIDTag.doFormatType(tagRawType);
285
- // debug.info(`tag type:`);
286
- // debug.info(tagType);
287
-
288
- if (
289
- (tagType as DIDTag.TagParserBase)
290
- .getAbiTypeString()
291
- .includes('tuple')
292
- ) {
293
- let [_, fieldNamesHashs] = await contract.getTagType(
294
- tag.from,
295
- tag.name
296
- );
297
- let fieldNames: any[] = [];
298
- for (let hash of fieldNamesHashs) {
299
- let blockNum = await contract.getFieldNamesEventBlock(hash);
300
- // debug.info(`field name hash: ${hash}`);
301
- // debug.info(`block num: ${blockNum}`);
302
- const events = await contract.queryFilter(
303
- 'OffchainStringArray',
304
- Number(blockNum),
305
- Number(blockNum)
306
- );
307
- for (let event of events) {
308
- // debug.info('event', event);
309
- if (hash == (event as any).args.hash) {
310
- fieldNames.push((event as any).args.value);
311
- }
312
- }
313
- }
314
- // debug.info(`found field names:`);
315
- // debug.info(fieldNames);
316
-
317
- (tagType as DIDTag.TagParserBox).setFieldNames(fieldNames, 0);
318
- }
319
-
320
- resolve(tagType);
321
- });
322
-
323
- export const fetchTagValue = (tag: Tag, contract: ethers.Contract) =>
324
- new Promise<any>(async (resolve, reject) => {
325
- try {
326
- debug.info('fetchTagValue', tag.from, tag.to, tag.name);
327
-
328
- const tagRawType = await contract.getTagABIType(
329
- tag.from,
330
- tag.name
331
- );
332
- // debug.info(`tag type raw bytes:`);
333
- // debug.info(tagRawType);
334
-
335
- const tagType = DIDTag.doFormatType(tagRawType);
336
- // debug.info(`tag type:`);
337
- // debug.info(tagType);
338
-
339
- const rawData = await contract.getTagElem(
340
- tag.from,
341
- tag.to,
342
- tag.name,
343
- []
344
- );
345
- // debug.info(`tag raw value:`);
346
- // debug.info(rawData);
347
- tag.valueSource = rawData;
348
-
349
- let data = tagType.parseValue(rawData);
350
- data = data[0];
351
- debug.info('tag value:');
352
- debug.info(data);
353
-
354
- if (
355
- (tagType as DIDTag.TagParserBase)
356
- .getAbiTypeString()
357
- .includes('tuple')
358
- ) {
359
- let [_, fieldNamesHashs] = await contract.getTagType(
360
- tag.from,
361
- tag.name
362
- );
363
- let fieldNames: any[] = [];
364
- for (let hash of fieldNamesHashs) {
365
- let blockNum = await contract.getFieldNamesEventBlock(
366
- hash
367
- );
368
- // debug.info(`field name hash: ${hash}`);
369
- // debug.info(`block num: ${blockNum}`);
370
- const events = await contract.queryFilter(
371
- 'OffchainStringArray',
372
- Number(blockNum),
373
- Number(blockNum)
374
- );
375
- for (let event of events) {
376
- // debug.info('event', event);
377
- if (hash == (event as any).args.hash) {
378
- fieldNames.push((event as any).args.value);
379
- }
380
- }
381
- }
382
- // debug.info(`found field names:`);
383
- // debug.info(fieldNames);
384
-
385
- (tagType as DIDTag.TagParserBox).setFieldNames(
386
- fieldNames,
387
- 0
388
- );
389
-
390
- data = (tagType as DIDTag.TagParserBase).hydration(rawData);
391
-
392
- // data = data[0];
393
- // debug.info('tag value with field names:');
394
- // console.dir(data, { depth: null });
395
- }
396
- let strData = data;
397
- if (data !== null && data !== undefined && typeof data !== 'string') {
398
- strData = JSON.stringify(data);
399
- }
400
- tag.valueFormated = strData;
401
- debug.info(
402
- `✅ Successfully fetched value for tag: ${tag.name}`
403
- );
404
- debug.info('✅ Updated tag data:', tag);
405
- resolve(tag);
406
- } catch (error) {
407
- debug.error(
408
- `❌ Failed to fetch value for tag "${tag.name}" (${
409
- tag.from
410
- } -> ${tag.to}): ${
411
- error instanceof Error ? error.message : String(error)
412
- }`
413
- );
414
-
415
- tag.valueFormated = null;
416
- tag.valueSource = null;
417
-
418
- resolve(tag);
419
- }
420
- });
421
-
422
- export const fetchAllTagValue = (
423
- domain: Domain,
424
- contract: ethers.Contract
425
- ) =>
426
- new Promise<Tag[]>(async (resolve, reject) => {
427
- for (const tag of domain.tags) {
428
- await fetchTagValue(tag, contract);
429
- }
430
-
431
- resolve(domain.tags);
432
- });
433
-
434
- export const defineTag = async (
435
- domain: Domain | undefined,
436
- tagName: string,
437
- value: DIDTag.TagParserBase,
438
- contract: any,
439
- providerHolder: DIDTag.ABITypeProviderHolder
440
- ) => {
441
- debug.info('abitype', await value.getAbiType(providerHolder));
442
- debug.info('field', await value.getFieldNames());
443
-
444
- await contract.defineTag(
445
- domain?.name,
446
- tagName,
447
- await value.getAbiType(providerHolder),
448
- await value.getFieldNames()
449
- );
450
- };
224
+ // Step 3: Collect field name hashes
225
+ const fieldNameHashes = collectFieldNameHashes(rawDomains);
451
226
 
452
- export const getAllSubdoamin = (domain: Domain) => {
453
- let arr: Domain[] = [];
454
- for (const d of domain.subdomains) {
455
- arr.push(...getAllSubdoamin(d));
456
- }
227
+ // Step 4: Batch fetch field names
228
+ const contract = console.getContractDID();
229
+ const fieldNamesMap = await batchFetchFieldNames(contract, fieldNameHashes);
230
+
231
+ // Step 5: Parse all domains
232
+ const domains = parseAllDomains(rawDomains, fieldNamesMap);
233
+
234
+ return domains;
235
+ }
236
+
237
+ /**
238
+ * Fetch all domains with flat structure using query contract
239
+ * Much more efficient than the old fetchAll method
240
+ *
241
+ * @param console - DIDConsole instance
242
+ * @param options - Fetch options
243
+ * @returns Array of all domains in flat structure
244
+ *
245
+ * @example
246
+ * const domains = await fetchAllFlat(console, {
247
+ * queryContractAddress: "0x...",
248
+ * batchSize: 100,
249
+ * onProgress: (current, total) => console.log(`${current}/${total}`)
250
+ * });
251
+ */
252
+ export async function fetchAllFlat(
253
+ console: DIDConsole,
254
+ options: FetchAllOptions = {}
255
+ ): Promise<FlatDomainData[]> {
256
+ const { queryContractAddress, batchSize = 100, onProgress } = options;
257
+
258
+ if (!queryContractAddress) {
259
+ throw new Error('queryContractAddress is required');
260
+ }
261
+
262
+ // Step 1: Create query helper
263
+ const helper = new QueryContractHelper(
264
+ queryContractAddress,
265
+ console.getProvider()
266
+ );
267
+
268
+ // Step 2: Get total supply
269
+ const totalSupply = await helper.getTotalSupply();
270
+ onProgress?.(0, totalSupply);
271
+
272
+ // Step 3: Fetch all domains in batches
273
+ const allRawDomains = [];
274
+ for (let offset = 0; offset < totalSupply; offset += batchSize) {
275
+ const limit = Math.min(batchSize, totalSupply - offset);
276
+ const batch = await helper.getAllDomains(offset, limit);
277
+ allRawDomains.push(...batch);
278
+ onProgress?.(Math.min(offset + batchSize, totalSupply), totalSupply);
279
+ }
280
+
281
+ // Step 4: Collect all field name hashes
282
+ const fieldNameHashes = collectFieldNameHashes(allRawDomains);
283
+
284
+ // Step 5: Batch fetch field names
285
+ const contract = console.getContractDID();
286
+ const fieldNamesMap = await batchFetchFieldNames(contract, fieldNameHashes);
287
+
288
+ // Step 6: Parse all domains (with parentId calculation)
289
+ const flatDomains = parseAllDomains(allRawDomains, fieldNamesMap);
457
290
 
458
- arr.push(...domain.subdomains);
459
-
460
- return arr;
461
- };
462
-
463
- export const fetchOfficialExtendedInformation = (
464
- domain: Domain,
465
- contract: ethers.Contract
466
- ) =>
467
- new Promise<OfficialExtendedInformation>(async (resolve, reject) => {
468
- let ip: string | undefined = undefined;
469
- let ipStr = '';
470
- try {
471
- ip = (await contract.getDnsARecord(domain.name)) as string;
472
- ipStr = `${parseInt(ip.substring(2, 4), 16)}.${parseInt(
473
- ip.substring(4, 6),
474
- 16
475
- )}.${parseInt(ip.substring(6, 8), 16)}.${parseInt(
476
- ip.substring(8, 10),
477
- 16
478
- )}`;
479
- } catch (error) {
480
- debug.info(
481
- error instanceof Error ? error.message : String(error)
482
- );
483
- }
484
-
485
- let rsaKey: any | undefined = undefined;
486
- try {
487
- rsaKey = (await contract.getRsaPubKey(domain.name)) as string;
488
- } catch (error) {
489
- debug.info(
490
- error instanceof Error ? error.message : String(error)
491
- );
492
- }
493
-
494
- let pubKey = '';
495
- try {
496
- if (rsaKey != '0x' && rsaKey != undefined) {
497
- // debug.info('rsaKey:');
498
- const str = String.fromCharCode(
499
- ...rsaKey
500
- .match(/.{1,2}/g)
501
- .map((byte: any) => parseInt(byte, 16))
502
- );
503
- const encoded = btoa(str);
504
- const base64 = getBase64(rsaKey.replaceAll('0x', ''));
505
-
506
- // debug.info(encoded);
507
- // debug.info(base64);
508
- pubKey = `-----BEGIN RSA PUBLIC KEY-----
509
- ${base64}
510
- -----END RSA PUBLIC KEY-----`;
511
- }
512
- } catch (error) {
513
- debug.error(
514
- error instanceof Error ? error.message : String(error)
515
- );
516
- }
517
-
518
- let authenticatedAddress: any[] = [];
519
- try {
520
- authenticatedAddress =
521
- await contract.getAuthenticationAddresses(domain.name);
522
- } catch (error) {
523
- debug.error(
524
- error instanceof Error ? error.message : String(error)
525
- );
526
- }
527
-
528
- // debug.info('authenticatedAddress:');
529
- // debug.info(authenticatedAddress);
530
-
531
- let latestDID = '';
532
- try {
533
- latestDID = await contract.getLatestDID(domain.name);
534
- } catch (error) {
535
- debug.info(
536
- error instanceof Error ? error.message : String(error)
537
- );
538
- }
539
- // debug.info('latestDID:', latestDID);
540
-
541
- const officialExt = {
542
- ip: ipStr,
543
- rsaKey: pubKey,
544
- authenticateds: authenticatedAddress,
545
- latestDID: latestDID
546
- };
547
- debug.info('officialExt: ', officialExt);
548
-
549
- resolve(officialExt);
550
- });
551
-
552
- export const updateIp = (
553
- domain: Domain,
554
- ipStr: string,
555
- contract: ethers.Contract
556
- ) =>
557
- new Promise<string>(async (resolve, reject) => {
558
- debug.info('updateIp', ipStr);
559
-
560
- const v2 =
561
- '((\\d{1,2})|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))\\.((\\d{1,2})|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))\\.((\\d{1,2})|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))\\.((\\d{1,2})|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))';
562
- const v3 =
563
- '((\\d{1,2})|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))\\.((\\d{1,2})|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))\\.((\\d{1,2})|(1\\d{2})|(2[0-4]\\d)|(25[0-5])).((d{1,2})|(1d{2})|(2[0-4]d)|(25[0-5]))';
564
- const reg = new RegExp(v3, 'g');
565
- const reg2 = new RegExp(v2, 'g');
566
-
567
- const isIp = ipStr.match(reg);
568
- const isIp2 = ipStr.match(reg2);
569
-
570
- if (isIp != null || isIp2 != null) {
571
- const ipArr = ipStr.split('.');
572
-
573
- const add0 = (str: string) =>
574
- str.length == 1 ? '0' + str : str;
575
- const ipBytes = `0x${add0(
576
- parseInt(ipArr[0]).toString(16)
577
- )}${add0(parseInt(ipArr[1]).toString(16))}${add0(
578
- parseInt(ipArr[2]).toString(16)
579
- )}${add0(parseInt(ipArr[3]).toString(16))}`;
580
-
581
- debug.info(ethers.getBytes(ipBytes));
582
- debug.info(ipBytes);
583
- debug.info(domain.name);
584
-
585
- await contract
586
- .setDnsARecord(domain.name, ipBytes)
587
- .then((resp) => {
588
- resolve('sumbit succeed');
589
- })
590
- .catch((error) => {
591
- debug.info('error1:');
592
- debug.info(error);
593
-
594
- reject(error.message);
595
- });
596
- } else {
597
- reject('ip format error');
598
- }
599
- });
600
-
601
- export const updateRSAPublicKey = (
602
- domain: Domain,
603
- rsaPublicKey: string,
604
- contract: ethers.Contract
605
- ) =>
606
- new Promise<string>(async (resolve, reject) => {
607
- const regex1 = new RegExp('-----BEGIN PUBLIC KEY-----', 'g');
608
- const regex2 = new RegExp('-----END PUBLIC KEY-----', 'g');
609
- const regex3 = new RegExp('\n', 'g');
610
-
611
- const keyBase64 = rsaPublicKey
612
- .replace(regex1, '')
613
- .replace(regex2, '')
614
- .replace(regex3, '');
615
-
616
- const keyHex = getHex(atob(rsaPublicKey));
617
-
618
- debug.info('keyHex:');
619
- debug.info(keyHex);
620
- debug.info(keyBase64);
621
- debug.info(rsaPublicKey);
622
-
623
- await contract
624
- .setRsaPubKey(domain.name, `0x${keyHex}`)
625
- .then((resp) => {
626
- resolve('sumbit succeed');
627
- })
628
- .catch((error) => {
629
- reject(error.message);
630
- });
631
- });
632
-
633
- export const setValue = (tag: Tag, data: any, contract: ethers.Contract) =>
634
- new Promise<string>(async (resolve, reject) => {
635
- await contract
636
- .addTag(tag.from, tag.to, tag.name, data)
637
- .then((resp) => {
638
- debug.info(resp);
639
- resolve('sumbit succeed');
640
- })
641
- .catch((error) => {
642
- reject(error.message);
643
- });
644
- });
645
-
646
- export const setTagger = (
647
- tag: Tag,
648
- tagger: string,
649
- contract: ethers.Contract
650
- ) =>
651
- new Promise<string>(async (resolve, reject) => {
652
- await contract
653
- .setTagger(tag.from, tag.name, tagger)
654
- .then((resp) => {
655
- debug.info(resp);
656
- resolve('sumbit succeed');
657
- })
658
- .catch((error) => {
659
- reject(error.message);
660
- });
661
- });
291
+ return flatDomains;
662
292
  }