@halot/cli 1.0.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 (38) hide show
  1. package/.env.example +14 -0
  2. package/README.md +374 -0
  3. package/dist/features/browse/browse.command.js +15 -0
  4. package/dist/features/jobs/job-create.command.js +57 -0
  5. package/dist/features/jobs/job-funding.service.js +95 -0
  6. package/dist/features/jobs/job-result.command.js +10 -0
  7. package/dist/features/jobs/job-watch.command.js +18 -0
  8. package/dist/features/provider/provider-init.command.js +33 -0
  9. package/dist/features/provider/provider-register.command.js +72 -0
  10. package/dist/features/provider/provider-run.command.js +148 -0
  11. package/dist/features/provider/provider-services.command.js +13 -0
  12. package/dist/features/provider/provider-stats.command.js +13 -0
  13. package/dist/features/provider/provider-update.command.js +35 -0
  14. package/dist/features/quotes/quote.command.js +13 -0
  15. package/dist/features/requester/requester-init.command.js +22 -0
  16. package/dist/features/service/service-create.command.js +57 -0
  17. package/dist/features/service/service-init.command.js +89 -0
  18. package/dist/features/service/service-list.command.js +23 -0
  19. package/dist/features/service/service-remove.command.js +21 -0
  20. package/dist/features/service/service-update.command.js +65 -0
  21. package/dist/features/verifier/verifier-init.command.js +69 -0
  22. package/dist/features/verifier/verifier-register.command.js +90 -0
  23. package/dist/features/verifier/verifier-run.command.js +143 -0
  24. package/dist/features/verifier/verifier-stats.command.js +13 -0
  25. package/dist/features/verifier/verifier-unstake.command.js +31 -0
  26. package/dist/index.js +136 -0
  27. package/dist/shared/auth/actor-headers.service.js +13 -0
  28. package/dist/shared/config/env.js +77 -0
  29. package/dist/shared/http/api-client.js +66 -0
  30. package/dist/shared/http/event-stream.js +75 -0
  31. package/dist/shared/integrations/agent-id/agent-id-register.service.js +159 -0
  32. package/dist/shared/integrations/space-id/space-id-register.service.js +467 -0
  33. package/dist/shared/integrations/zero-g/verifier-registry.service.js +55 -0
  34. package/dist/shared/output/print.util.js +10 -0
  35. package/dist/shared/wallet/authority.util.js +62 -0
  36. package/dist/shared/wallet/wallet.manager.js +41 -0
  37. package/dist/shared/workspace/workspace.service.js +192 -0
  38. package/package.json +47 -0
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AgentIdRegisterService = void 0;
4
+ exports.createZeroGAgentUri = createZeroGAgentUri;
5
+ const viem_1 = require("viem");
6
+ const accounts_1 = require("viem/accounts");
7
+ const env_1 = require("@halot/cli/shared/config/env");
8
+ const agentIdentityRegistryAbi = [
9
+ {
10
+ inputs: [{ internalType: 'string', name: 'agentURI', type: 'string' }],
11
+ name: 'register',
12
+ outputs: [{ internalType: 'uint256', name: 'agentId', type: 'uint256' }],
13
+ stateMutability: 'nonpayable',
14
+ type: 'function',
15
+ },
16
+ {
17
+ inputs: [
18
+ { internalType: 'string', name: 'agentURI', type: 'string' },
19
+ {
20
+ components: [
21
+ { internalType: 'string', name: 'metadataKey', type: 'string' },
22
+ { internalType: 'bytes', name: 'metadataValue', type: 'bytes' },
23
+ ],
24
+ internalType: 'struct MetadataEntry[]',
25
+ name: 'metadata',
26
+ type: 'tuple[]',
27
+ },
28
+ ],
29
+ name: 'register',
30
+ outputs: [{ internalType: 'uint256', name: 'agentId', type: 'uint256' }],
31
+ stateMutability: 'nonpayable',
32
+ type: 'function',
33
+ },
34
+ {
35
+ anonymous: false,
36
+ inputs: [
37
+ { indexed: true, internalType: 'uint256', name: 'agentId', type: 'uint256' },
38
+ { indexed: false, internalType: 'string', name: 'agentURI', type: 'string' },
39
+ { indexed: true, internalType: 'address', name: 'owner', type: 'address' },
40
+ ],
41
+ name: 'Registered',
42
+ type: 'event',
43
+ },
44
+ {
45
+ anonymous: false,
46
+ inputs: [
47
+ { indexed: true, internalType: 'address', name: 'from', type: 'address' },
48
+ { indexed: true, internalType: 'address', name: 'to', type: 'address' },
49
+ { indexed: true, internalType: 'uint256', name: 'tokenId', type: 'uint256' },
50
+ ],
51
+ name: 'Transfer',
52
+ type: 'event',
53
+ },
54
+ ];
55
+ function createZeroGAgentUri(rootHash) {
56
+ const env = (0, env_1.loadCliEnv)();
57
+ const gateway = env.zeroGStorageGateway;
58
+ if (gateway) {
59
+ return `${gateway}/${rootHash}`;
60
+ }
61
+ return `0g://${rootHash}`;
62
+ }
63
+ class AgentIdRegisterService {
64
+ async registerAgent(input) {
65
+ const env = (0, env_1.loadCliEnv)();
66
+ const registryAddress = input.registryAddress ?? env.agentIdRegistryAddress;
67
+ if (!registryAddress) {
68
+ throw new Error('Agent ID registration requires HALOT_AGENT_ID_REGISTRY_ADDRESS.');
69
+ }
70
+ const account = (0, accounts_1.privateKeyToAccount)(input.privateKey);
71
+ if (account.address.toLowerCase() !== input.ownerAddress.toLowerCase()) {
72
+ throw new Error('Agent ID registration wallet address does not match the configured owner address.');
73
+ }
74
+ const chain = (0, viem_1.defineChain)({
75
+ id: input.chainId,
76
+ name: '0G Chain',
77
+ nativeCurrency: {
78
+ name: '0G',
79
+ symbol: '0G',
80
+ decimals: 18,
81
+ },
82
+ rpcUrls: {
83
+ default: { http: [input.rpcUrl] },
84
+ public: { http: [input.rpcUrl] },
85
+ },
86
+ });
87
+ const publicClient = (0, viem_1.createPublicClient)({
88
+ chain,
89
+ transport: (0, viem_1.http)(input.rpcUrl),
90
+ });
91
+ const walletClient = (0, viem_1.createWalletClient)({
92
+ account,
93
+ chain,
94
+ transport: (0, viem_1.http)(input.rpcUrl),
95
+ });
96
+ const transactionHash = await this.writeRegisterTransaction({
97
+ account: account.address,
98
+ agentUri: input.agentUri,
99
+ publicClient,
100
+ registryAddress,
101
+ walletClient,
102
+ });
103
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: transactionHash });
104
+ const agentId = this.extractAgentId(receipt.logs);
105
+ return {
106
+ registryAddress,
107
+ agentId,
108
+ agentRegistry: `eip155:${input.chainId}:${registryAddress}`,
109
+ agentUri: input.agentUri,
110
+ transactionHash,
111
+ };
112
+ }
113
+ async writeRegisterTransaction(input) {
114
+ try {
115
+ const simulation = await input.publicClient.simulateContract({
116
+ account: input.account,
117
+ address: input.registryAddress,
118
+ abi: agentIdentityRegistryAbi,
119
+ functionName: 'register',
120
+ args: [input.agentUri],
121
+ });
122
+ return input.walletClient.writeContract(simulation.request);
123
+ }
124
+ catch {
125
+ const simulation = await input.publicClient.simulateContract({
126
+ account: input.account,
127
+ address: input.registryAddress,
128
+ abi: agentIdentityRegistryAbi,
129
+ functionName: 'register',
130
+ args: [input.agentUri, []],
131
+ });
132
+ return input.walletClient.writeContract(simulation.request);
133
+ }
134
+ }
135
+ extractAgentId(logs) {
136
+ const registeredLogs = (0, viem_1.parseEventLogs)({
137
+ abi: agentIdentityRegistryAbi,
138
+ eventName: 'Registered',
139
+ logs: logs,
140
+ strict: false,
141
+ });
142
+ const registeredLog = registeredLogs[0];
143
+ if (registeredLog?.args?.agentId !== undefined) {
144
+ return String(registeredLog.args.agentId);
145
+ }
146
+ const transferLogs = (0, viem_1.parseEventLogs)({
147
+ abi: agentIdentityRegistryAbi,
148
+ eventName: 'Transfer',
149
+ logs: logs,
150
+ strict: false,
151
+ });
152
+ const transferLog = transferLogs[0];
153
+ if (transferLog?.args?.tokenId !== undefined) {
154
+ return String(transferLog.args.tokenId);
155
+ }
156
+ throw new Error('Agent ID registration completed, but no Registered or Transfer event was found.');
157
+ }
158
+ }
159
+ exports.AgentIdRegisterService = AgentIdRegisterService;
@@ -0,0 +1,467 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SpaceIdRegisterService = void 0;
4
+ const utils_1 = require("@web3-name-sdk/core/utils");
5
+ const viem_1 = require("viem");
6
+ const accounts_1 = require("viem/accounts");
7
+ const env_1 = require("@halot/cli/shared/config/env");
8
+ const yearInSeconds = 31556952n;
9
+ const zeroGSpaceIdDefaults = {
10
+ tldId: 26,
11
+ chainId: 16661,
12
+ graphUrl: 'https://graphigo.prd.space.id/query',
13
+ identifier: '449205675366457712613706471770511817162982777845754732038879201565074548',
14
+ controllerAddress: '0xd7b837a0e388b4c25200983bdaa3ef3a83ca86b7',
15
+ resolverAddress: '0x6D3B3F99177FB2A5de7F9E928a9BD807bF7b5BAD',
16
+ registryAddress: '0x5dC881dDA4e4a8d312be3544AD13118D1a04Cb17',
17
+ sannAddress: '0x9af6F1244df403dAe39Eb2D0be1C3fD0B38e0789',
18
+ verifiedTldHubAddress: '0x754D6827A57334143eD5fB58C5b1A4aAe4396ba5',
19
+ verifiedTldHubRpcUrl: 'https://ethereum-rpc.publicnode.com',
20
+ defaultRpc: 'https://evmrpc.0g.ai',
21
+ };
22
+ const sidV3ControllerAbi = [
23
+ {
24
+ inputs: [{ internalType: 'uint256', name: 'realPrice', type: 'uint256' }],
25
+ name: 'SimulatePrice',
26
+ type: 'error',
27
+ },
28
+ {
29
+ inputs: [
30
+ { internalType: 'uint256', name: 'identifier', type: 'uint256' },
31
+ { internalType: 'string', name: 'name', type: 'string' },
32
+ ],
33
+ name: 'available',
34
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
35
+ stateMutability: 'view',
36
+ type: 'function',
37
+ },
38
+ {
39
+ inputs: [
40
+ { internalType: 'uint256', name: 'identifier', type: 'uint256' },
41
+ { internalType: 'string[]', name: 'names', type: 'string[]' },
42
+ { internalType: 'address', name: 'owner', type: 'address' },
43
+ { internalType: 'uint256', name: 'duration', type: 'uint256' },
44
+ { internalType: 'address', name: 'resolver', type: 'address' },
45
+ { internalType: 'bool', name: 'setTldName', type: 'bool' },
46
+ { internalType: 'bytes[]', name: 'extraData', type: 'bytes[]' },
47
+ ],
48
+ name: 'bulkRegister',
49
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
50
+ stateMutability: 'payable',
51
+ type: 'function',
52
+ },
53
+ {
54
+ inputs: [
55
+ { internalType: 'uint256', name: 'identifier', type: 'uint256' },
56
+ { internalType: 'string[]', name: 'names', type: 'string[]' },
57
+ { internalType: 'address', name: 'owner', type: 'address' },
58
+ { internalType: 'uint256', name: 'duration', type: 'uint256' },
59
+ { internalType: 'address', name: 'resolver', type: 'address' },
60
+ { internalType: 'bool', name: 'setTldName', type: 'bool' },
61
+ { internalType: 'bytes[]', name: 'extraData', type: 'bytes[]' },
62
+ ],
63
+ name: 'bulkRegisterSimulate',
64
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
65
+ stateMutability: 'payable',
66
+ type: 'function',
67
+ },
68
+ ];
69
+ const sidRegistryAbi = [
70
+ {
71
+ inputs: [{ internalType: 'bytes32', name: 'node', type: 'bytes32' }],
72
+ name: 'resolver',
73
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
74
+ stateMutability: 'view',
75
+ type: 'function',
76
+ },
77
+ ];
78
+ const verifiedTldHubAbi = [
79
+ {
80
+ inputs: [{ internalType: 'string[]', name: 'tlds', type: 'string[]' }],
81
+ name: 'getTldInfo',
82
+ outputs: [
83
+ {
84
+ components: [
85
+ { internalType: 'string', name: 'tld', type: 'string' },
86
+ { internalType: 'uint256', name: 'identifier', type: 'uint256' },
87
+ { internalType: 'uint256', name: 'chainId', type: 'uint256' },
88
+ { internalType: 'string', name: 'defaultRpc', type: 'string' },
89
+ { internalType: 'address', name: 'registry', type: 'address' },
90
+ { internalType: 'address', name: 'sann', type: 'address' },
91
+ ],
92
+ internalType: 'struct VerifiedTldHub.completeTldInfo[]',
93
+ name: '',
94
+ type: 'tuple[]',
95
+ },
96
+ ],
97
+ stateMutability: 'view',
98
+ type: 'function',
99
+ },
100
+ ];
101
+ class SpaceIdRegisterService {
102
+ async registerZeroGDomain(input) {
103
+ if (!input.domain.endsWith('.0g')) {
104
+ throw new Error('Only .0g domains are supported by this registration flow.');
105
+ }
106
+ const label = this.normalizeLabel(input.domain);
107
+ const config = await this.resolveConfig(input);
108
+ const chain = (0, viem_1.defineChain)({
109
+ id: input.chainId,
110
+ name: '0G Chain',
111
+ nativeCurrency: {
112
+ name: '0G',
113
+ symbol: '0G',
114
+ decimals: 18,
115
+ },
116
+ rpcUrls: {
117
+ default: { http: [input.rpcUrl] },
118
+ public: { http: [input.rpcUrl] },
119
+ },
120
+ });
121
+ const account = (0, accounts_1.privateKeyToAccount)(input.privateKey);
122
+ if (account.address.toLowerCase() !== input.address.toLowerCase()) {
123
+ throw new Error('SPACE ID registration wallet address does not match the configured owner address.');
124
+ }
125
+ const publicClient = (0, viem_1.createPublicClient)({
126
+ chain,
127
+ transport: (0, viem_1.http)(input.rpcUrl),
128
+ });
129
+ const walletClient = (0, viem_1.createWalletClient)({
130
+ account,
131
+ chain,
132
+ transport: (0, viem_1.http)(input.rpcUrl),
133
+ });
134
+ const available = await publicClient.readContract({
135
+ address: config.controllerAddress,
136
+ abi: sidV3ControllerAbi,
137
+ functionName: 'available',
138
+ args: [config.identifier, label],
139
+ });
140
+ if (!available) {
141
+ throw new Error('Domain is unavailable or already registered.');
142
+ }
143
+ const years = input.years ?? 1;
144
+ const duration = BigInt(years) * yearInSeconds;
145
+ const extraData = [this.encodeExtraData(false)];
146
+ const price = await this.getRentPrice(publicClient, config, label, duration, extraData);
147
+ const bufferedPrice = (price * 101n) / 100n;
148
+ const data = (0, viem_1.encodeFunctionData)({
149
+ abi: sidV3ControllerAbi,
150
+ functionName: 'bulkRegister',
151
+ args: [
152
+ config.identifier,
153
+ [label],
154
+ input.address,
155
+ duration,
156
+ config.resolverAddress,
157
+ true,
158
+ extraData,
159
+ ],
160
+ });
161
+ let gas = await publicClient.estimateGas({
162
+ account: account.address,
163
+ to: config.controllerAddress,
164
+ data,
165
+ value: bufferedPrice,
166
+ });
167
+ if (gas > 0n) {
168
+ gas = (gas * 12n) / 10n;
169
+ }
170
+ const transactionHash = await walletClient.sendTransaction({
171
+ account,
172
+ chain,
173
+ to: config.controllerAddress,
174
+ value: bufferedPrice,
175
+ data,
176
+ gas,
177
+ });
178
+ await publicClient.waitForTransactionReceipt({ hash: transactionHash });
179
+ return {
180
+ domain: input.domain,
181
+ address: input.address,
182
+ price: price.toString(),
183
+ transactionHash,
184
+ };
185
+ }
186
+ async resolveConfig(input) {
187
+ const env = (0, env_1.loadCliEnv)();
188
+ const discovered = await this.discoverZeroGConfig(input).catch(() => null);
189
+ const identifier = input.identifier
190
+ ?? env.spaceIdIdentifier
191
+ ?? discovered?.identifier
192
+ ?? zeroGSpaceIdDefaults.identifier;
193
+ const controllerAddress = input.controllerAddress
194
+ ?? env.spaceIdControllerAddress
195
+ ?? discovered?.controllerAddress
196
+ ?? zeroGSpaceIdDefaults.controllerAddress;
197
+ const resolverAddress = input.resolverAddress
198
+ ?? env.spaceIdResolverAddress
199
+ ?? discovered?.resolverAddress
200
+ ?? zeroGSpaceIdDefaults.resolverAddress;
201
+ const simulateAccount = input.simulateAccount
202
+ ?? env.spaceIdSimulateAccount;
203
+ const simulateValue = input.simulateValue ?? env.spaceIdSimulateValue;
204
+ if (!identifier || !controllerAddress || !resolverAddress) {
205
+ throw new Error('SPACE ID .0g registration requires HALOT_SPACE_ID_IDENTIFIER, HALOT_SPACE_ID_CONTROLLER_ADDRESS, and HALOT_SPACE_ID_RESOLVER_ADDRESS.');
206
+ }
207
+ return {
208
+ identifier: BigInt(identifier),
209
+ controllerAddress,
210
+ resolverAddress,
211
+ simulateAccount: simulateAccount ?? viem_1.zeroAddress,
212
+ simulateValue: (0, viem_1.parseEther)(simulateValue ?? '500'),
213
+ };
214
+ }
215
+ async discoverZeroGConfig(input) {
216
+ if (input.chainId !== zeroGSpaceIdDefaults.chainId) {
217
+ return {
218
+ identifier: zeroGSpaceIdDefaults.identifier,
219
+ controllerAddress: zeroGSpaceIdDefaults.controllerAddress,
220
+ resolverAddress: zeroGSpaceIdDefaults.resolverAddress,
221
+ };
222
+ }
223
+ const graphTld = await this.fetchGraphTld();
224
+ const verifiedTld = await this.fetchVerifiedTld();
225
+ const sampleNames = await this.fetchSampleDomains();
226
+ const resolverAddress = await this.fetchResolverAddress(verifiedTld, sampleNames);
227
+ return {
228
+ identifier: graphTld.identifier,
229
+ controllerAddress: graphTld.controllerAddr,
230
+ resolverAddress,
231
+ };
232
+ }
233
+ normalizeLabel(domain) {
234
+ const label = domain.replace(/\.0g$/iu, '');
235
+ const normalized = (0, utils_1.validateName)(label);
236
+ const characterCount = (0, utils_1.countCharacters)(normalized);
237
+ if (normalized !== label) {
238
+ throw new Error('SPACE ID label must already be normalized.');
239
+ }
240
+ if (characterCount < 3 || characterCount > 512) {
241
+ throw new Error('SPACE ID label length must be between 3 and 512 characters.');
242
+ }
243
+ return normalized;
244
+ }
245
+ encodeExtraData(usePoints, referrerAddress) {
246
+ if (!usePoints && !referrerAddress) {
247
+ return '0x';
248
+ }
249
+ const rewardHookExtraData = referrerAddress
250
+ ? (0, viem_1.encodeAbiParameters)([{ type: 'address', name: 'referrerAddress' }], [referrerAddress])
251
+ : '0x';
252
+ const pointHookExtraData = (0, viem_1.encodeAbiParameters)([{ type: 'bool', name: 'useGiftCardPoints' }], [usePoints]);
253
+ return (0, viem_1.encodeAbiParameters)([
254
+ {
255
+ components: [
256
+ { type: 'bytes', name: 'QualificationHookExtraData' },
257
+ { type: 'bytes', name: 'PriceHookExtraData' },
258
+ { type: 'bytes', name: 'PointHookExtraData' },
259
+ { type: 'bytes', name: 'RewardHookExtraData' },
260
+ ],
261
+ name: 'extraData',
262
+ type: 'tuple',
263
+ },
264
+ ], [
265
+ {
266
+ QualificationHookExtraData: '0x',
267
+ PriceHookExtraData: '0x',
268
+ PointHookExtraData: pointHookExtraData,
269
+ RewardHookExtraData: rewardHookExtraData,
270
+ },
271
+ ]);
272
+ }
273
+ async getRentPrice(publicClient, config, label, duration, extraData) {
274
+ try {
275
+ await publicClient.simulateContract({
276
+ address: config.controllerAddress,
277
+ abi: sidV3ControllerAbi,
278
+ account: config.simulateAccount,
279
+ functionName: 'bulkRegisterSimulate',
280
+ args: [
281
+ config.identifier,
282
+ [label],
283
+ config.simulateAccount,
284
+ duration,
285
+ config.resolverAddress,
286
+ false,
287
+ extraData,
288
+ ],
289
+ value: config.simulateValue,
290
+ });
291
+ }
292
+ catch (error) {
293
+ const price = this.extractSimulatedPrice(error);
294
+ if (price !== null) {
295
+ return price;
296
+ }
297
+ throw error;
298
+ }
299
+ throw new Error('SPACE ID rent price simulation did not return a price.');
300
+ }
301
+ async fetchGraphTld() {
302
+ const env = (0, env_1.loadCliEnv)();
303
+ const graphUrl = env.spaceIdGraphUrl || zeroGSpaceIdDefaults.graphUrl;
304
+ const result = await this.queryGraph(graphUrl, 'query Tld($tldIDs: [Int!]!) { Tlds(tldIDs: $tldIDs) { tldID tldName identifier chainID controllerAddr } }', { tldIDs: [zeroGSpaceIdDefaults.tldId] });
305
+ const tld = result.Tlds[0];
306
+ if (!tld) {
307
+ throw new Error('SPACE ID graph did not return the .0g TLD row.');
308
+ }
309
+ return tld;
310
+ }
311
+ async fetchSampleDomains() {
312
+ const env = (0, env_1.loadCliEnv)();
313
+ const graphUrl = env.spaceIdGraphUrl || zeroGSpaceIdDefaults.graphUrl;
314
+ const result = await this.queryGraph(graphUrl, 'query domains($input: ListDomainsInput!) { domains(input: $input) { list { name } } }', {
315
+ input: {
316
+ tldID: zeroGSpaceIdDefaults.tldId,
317
+ first: 5,
318
+ },
319
+ });
320
+ const names = result.domains.list
321
+ .map((domain) => domain.name.trim())
322
+ .filter((domain) => domain.length > 0)
323
+ .map((domain) => domain.endsWith('.0g') ? domain : `${domain}.0g`);
324
+ if (names.length === 0) {
325
+ throw new Error('SPACE ID graph did not return any registered .0g domains.');
326
+ }
327
+ return names;
328
+ }
329
+ async fetchVerifiedTld() {
330
+ const env = (0, env_1.loadCliEnv)();
331
+ const hubRpcUrl = env.spaceIdVerifiedTldHubRpcUrl || zeroGSpaceIdDefaults.verifiedTldHubRpcUrl;
332
+ const hubAddress = env.spaceIdVerifiedTldHubAddress || zeroGSpaceIdDefaults.verifiedTldHubAddress;
333
+ const publicClient = (0, viem_1.createPublicClient)({
334
+ chain: (0, viem_1.defineChain)({
335
+ id: 1,
336
+ name: 'Ethereum',
337
+ nativeCurrency: {
338
+ name: 'Ether',
339
+ symbol: 'ETH',
340
+ decimals: 18,
341
+ },
342
+ rpcUrls: {
343
+ default: { http: [hubRpcUrl] },
344
+ public: { http: [hubRpcUrl] },
345
+ },
346
+ }),
347
+ transport: (0, viem_1.http)(hubRpcUrl),
348
+ });
349
+ const rows = await publicClient.readContract({
350
+ address: hubAddress,
351
+ abi: verifiedTldHubAbi,
352
+ functionName: 'getTldInfo',
353
+ args: [['0g']],
354
+ });
355
+ const tld = rows[0];
356
+ if (!tld) {
357
+ throw new Error('Verified TLD Hub did not return the .0g TLD row.');
358
+ }
359
+ return tld;
360
+ }
361
+ async fetchResolverAddress(verifiedTld, sampleNames) {
362
+ const rpcUrl = verifiedTld.defaultRpc || zeroGSpaceIdDefaults.defaultRpc;
363
+ const chainId = Number(verifiedTld.chainId || BigInt(zeroGSpaceIdDefaults.chainId));
364
+ const registryAddress = verifiedTld.registry || zeroGSpaceIdDefaults.registryAddress;
365
+ const publicClient = (0, viem_1.createPublicClient)({
366
+ chain: (0, viem_1.defineChain)({
367
+ id: chainId,
368
+ name: '0G Chain',
369
+ nativeCurrency: {
370
+ name: '0G',
371
+ symbol: '0G',
372
+ decimals: 18,
373
+ },
374
+ rpcUrls: {
375
+ default: { http: [rpcUrl] },
376
+ public: { http: [rpcUrl] },
377
+ },
378
+ }),
379
+ transport: (0, viem_1.http)(rpcUrl),
380
+ });
381
+ const counts = new Map();
382
+ for (const sampleName of sampleNames) {
383
+ const node = (0, utils_1.tldNamehash)(sampleName, verifiedTld.identifier);
384
+ const resolver = await publicClient.readContract({
385
+ address: registryAddress,
386
+ abi: sidRegistryAbi,
387
+ functionName: 'resolver',
388
+ args: [node],
389
+ });
390
+ if (resolver === viem_1.zeroAddress) {
391
+ continue;
392
+ }
393
+ counts.set(resolver, (counts.get(resolver) ?? 0) + 1);
394
+ }
395
+ const resolver = [...counts.entries()]
396
+ .map(([address, count]) => ({ address, count }))
397
+ .sort((left, right) => right.count - left.count)[0]?.address;
398
+ return resolver ?? zeroGSpaceIdDefaults.resolverAddress;
399
+ }
400
+ extractSimulatedPrice(error) {
401
+ const visited = new Set();
402
+ const queue = [error];
403
+ while (queue.length > 0) {
404
+ const current = queue.shift();
405
+ if (!current || visited.has(current)) {
406
+ continue;
407
+ }
408
+ visited.add(current);
409
+ if (typeof current === 'object') {
410
+ const record = current;
411
+ const args = record.args;
412
+ if (Array.isArray(args) && args[0] !== undefined) {
413
+ try {
414
+ return BigInt(String(args[0]));
415
+ }
416
+ catch { }
417
+ }
418
+ const metaMessages = record.metaMessages;
419
+ if (Array.isArray(metaMessages)) {
420
+ const joined = metaMessages.filter((item) => typeof item === 'string').join('\n');
421
+ const parsed = this.parseSimulatePrice(joined);
422
+ if (parsed !== null) {
423
+ return parsed;
424
+ }
425
+ }
426
+ const shortMessage = typeof record.shortMessage === 'string' ? record.shortMessage : '';
427
+ const message = typeof record.message === 'string' ? record.message : '';
428
+ const parsed = this.parseSimulatePrice(`${shortMessage}\n${message}`);
429
+ if (parsed !== null) {
430
+ return parsed;
431
+ }
432
+ queue.push(record.cause);
433
+ queue.push(record.details);
434
+ queue.push(record.data);
435
+ }
436
+ }
437
+ return null;
438
+ }
439
+ parseSimulatePrice(message) {
440
+ const match = message.match(/SimulatePrice\(uint256 realPrice\)[\s\S]*?\[(\d+)\]/u);
441
+ if (!match?.[1]) {
442
+ return null;
443
+ }
444
+ return BigInt(match[1]);
445
+ }
446
+ async queryGraph(url, query, variables) {
447
+ const response = await fetch(url, {
448
+ method: 'POST',
449
+ headers: {
450
+ 'content-type': 'application/json',
451
+ },
452
+ body: JSON.stringify({ query, variables }),
453
+ });
454
+ const payload = await response.json();
455
+ if (!response.ok) {
456
+ throw new Error(`SPACE ID graph request failed with status ${response.status}.`);
457
+ }
458
+ if (payload.errors?.length) {
459
+ throw new Error(payload.errors.map((error) => error.message || 'Unknown SPACE ID graph error.').join(' '));
460
+ }
461
+ if (!payload.data) {
462
+ throw new Error('SPACE ID graph returned no data.');
463
+ }
464
+ return payload.data;
465
+ }
466
+ }
467
+ exports.SpaceIdRegisterService = SpaceIdRegisterService;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ZeroGVerifierRegistryService = void 0;
4
+ const ethers_1 = require("ethers");
5
+ const sdk_1 = require("@halot/sdk");
6
+ const env_1 = require("@halot/cli/shared/config/env");
7
+ const registryAbi = [
8
+ 'function upsertVerifier(uint256 categoryMask, bytes32[] allowedServiceHashes) payable',
9
+ 'function requestUnstake()',
10
+ 'function withdrawStake()',
11
+ ];
12
+ class ZeroGVerifierRegistryService {
13
+ env = (0, env_1.loadCliEnv)();
14
+ async registerVerifier(input) {
15
+ const registry = this.getRegistry(input.privateKey, input.rpcUrl);
16
+ const categoryMask = (0, sdk_1.serviceCategoriesToMask)(input.categories);
17
+ const serviceHashes = input.serviceIds.map((serviceId) => (0, sdk_1.hashText)(serviceId));
18
+ const transaction = await registry.upsertVerifier(categoryMask, serviceHashes, { value: (0, ethers_1.parseEther)(input.stakeAmount) });
19
+ const receipt = await transaction.wait();
20
+ if (!receipt || receipt.status !== 1) {
21
+ throw new Error('0G verifier registry transaction failed');
22
+ }
23
+ return { transactionHash: transaction.hash };
24
+ }
25
+ async requestUnstake(input) {
26
+ const registry = this.getRegistry(input.privateKey, input.rpcUrl);
27
+ const transaction = await registry.requestUnstake();
28
+ const receipt = await transaction.wait();
29
+ if (!receipt || receipt.status !== 1) {
30
+ throw new Error('0G verifier unstake request failed');
31
+ }
32
+ return { transactionHash: transaction.hash };
33
+ }
34
+ async withdrawStake(input) {
35
+ const registry = this.getRegistry(input.privateKey, input.rpcUrl);
36
+ const transaction = await registry.withdrawStake();
37
+ const receipt = await transaction.wait();
38
+ if (!receipt || receipt.status !== 1) {
39
+ throw new Error('0G verifier stake withdrawal failed');
40
+ }
41
+ return { transactionHash: transaction.hash };
42
+ }
43
+ getRegistry(privateKey, rpcUrl) {
44
+ const provider = new ethers_1.JsonRpcProvider(rpcUrl);
45
+ const wallet = new ethers_1.Wallet(privateKey, provider);
46
+ return new ethers_1.Contract(this.getRegistryAddress(), registryAbi, wallet);
47
+ }
48
+ getRegistryAddress() {
49
+ if (!this.env.zeroGVerifierRegistryAddress) {
50
+ throw new Error('Missing HALOT_ZERO_G_VERIFIER_REGISTRY_ADDRESS');
51
+ }
52
+ return this.env.zeroGVerifierRegistryAddress;
53
+ }
54
+ }
55
+ exports.ZeroGVerifierRegistryService = ZeroGVerifierRegistryService;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.printJson = printJson;
4
+ exports.sleep = sleep;
5
+ function printJson(value) {
6
+ console.log(JSON.stringify(value, null, 2));
7
+ }
8
+ async function sleep(ms) {
9
+ await new Promise((resolve) => setTimeout(resolve, ms));
10
+ }