@beclab/olaresid 0.1.1 → 0.1.3
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.
- package/CLI.md +1300 -0
- package/README.md +40 -31
- package/TAG.md +589 -0
- package/dist/abi/RootResolver2ABI.d.ts +54 -0
- package/dist/abi/RootResolver2ABI.d.ts.map +1 -0
- package/dist/abi/RootResolver2ABI.js +240 -0
- package/dist/abi/RootResolver2ABI.js.map +1 -0
- package/dist/business/index.d.ts +302 -0
- package/dist/business/index.d.ts.map +1 -0
- package/dist/business/index.js +1211 -0
- package/dist/business/index.js.map +1 -0
- package/dist/business/tag-context.d.ts +219 -0
- package/dist/business/tag-context.d.ts.map +1 -0
- package/dist/business/tag-context.js +560 -0
- package/dist/business/tag-context.js.map +1 -0
- package/dist/cli.js +2102 -39
- package/dist/cli.js.map +1 -1
- package/dist/debug.d.ts.map +1 -1
- package/dist/debug.js +14 -2
- package/dist/debug.js.map +1 -1
- package/dist/index.d.ts +51 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +241 -12
- package/dist/index.js.map +1 -1
- package/dist/utils/crypto-utils.d.ts +130 -0
- package/dist/utils/crypto-utils.d.ts.map +1 -0
- package/dist/utils/crypto-utils.js +402 -0
- package/dist/utils/crypto-utils.js.map +1 -0
- package/dist/utils/error-parser.d.ts +35 -0
- package/dist/utils/error-parser.d.ts.map +1 -0
- package/dist/utils/error-parser.js +202 -0
- package/dist/utils/error-parser.js.map +1 -0
- package/dist/utils/olares-id.d.ts +36 -0
- package/dist/utils/olares-id.d.ts.map +1 -0
- package/dist/utils/olares-id.js +52 -0
- package/dist/utils/olares-id.js.map +1 -0
- package/dist/utils/tag-abi-codec.d.ts +69 -0
- package/dist/utils/tag-abi-codec.d.ts.map +1 -0
- package/dist/utils/tag-abi-codec.js +144 -0
- package/dist/utils/tag-abi-codec.js.map +1 -0
- package/dist/utils/tag-type-builder.d.ts +158 -0
- package/dist/utils/tag-type-builder.d.ts.map +1 -0
- package/dist/utils/tag-type-builder.js +410 -0
- package/dist/utils/tag-type-builder.js.map +1 -0
- package/examples/crypto-utilities.ts +140 -0
- package/examples/domain-context.ts +80 -0
- package/examples/generate-mnemonic.ts +149 -0
- package/examples/index.ts +1 -1
- package/examples/ip.ts +171 -0
- package/examples/legacy.ts +10 -10
- package/examples/list-wallets.ts +81 -0
- package/examples/olares-id-format.ts +197 -0
- package/examples/quasar-demo/.eslintrc.js +23 -0
- package/examples/quasar-demo/.quasar/app.js +43 -0
- package/examples/quasar-demo/.quasar/client-entry.js +38 -0
- package/examples/quasar-demo/.quasar/client-prefetch.js +130 -0
- package/examples/quasar-demo/.quasar/quasar-user-options.js +16 -0
- package/examples/quasar-demo/README.md +49 -0
- package/examples/quasar-demo/index.html +11 -0
- package/examples/quasar-demo/package-lock.json +6407 -0
- package/examples/quasar-demo/package.json +36 -0
- package/examples/quasar-demo/quasar.config.js +73 -0
- package/examples/quasar-demo/src/App.vue +13 -0
- package/examples/quasar-demo/src/css/app.scss +1 -0
- package/examples/quasar-demo/src/layouts/MainLayout.vue +21 -0
- package/examples/quasar-demo/src/pages/IndexPage.vue +905 -0
- package/examples/quasar-demo/src/router/index.ts +25 -0
- package/examples/quasar-demo/src/router/routes.ts +11 -0
- package/examples/quasar-demo/tsconfig.json +28 -0
- package/examples/register-subdomain.ts +152 -0
- package/examples/rsa-keypair.ts +148 -0
- package/examples/tag-builder.ts +235 -0
- package/examples/tag-management.ts +534 -0
- package/examples/tag-nested-tuple.ts +190 -0
- package/examples/tag-simple.ts +149 -0
- package/examples/tag-tagger.ts +217 -0
- package/examples/test-nested-tuple-conversion.ts +143 -0
- package/examples/test-type-bytes-parser.ts +70 -0
- package/examples/transfer-domain.ts +197 -0
- package/examples/wallet-management.ts +196 -0
- package/package.json +24 -15
- package/src/abi/RootResolver2ABI.ts +237 -0
- package/src/business/index.ts +1492 -0
- package/src/business/tag-context.ts +747 -0
- package/src/cli.ts +2772 -39
- package/src/debug.ts +17 -2
- package/src/index.ts +313 -17
- package/src/utils/crypto-utils.ts +459 -0
- package/src/utils/error-parser.ts +225 -0
- package/src/utils/olares-id.ts +49 -0
- package/src/utils/tag-abi-codec.ts +158 -0
- package/src/utils/tag-type-builder.ts +469 -0
- package/tsconfig.json +1 -1
package/src/cli.ts
CHANGED
|
@@ -1,7 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import OlaresID
|
|
3
|
+
import OlaresID, {
|
|
4
|
+
createRsaKeyPair,
|
|
5
|
+
pemToDer,
|
|
6
|
+
derToPem,
|
|
7
|
+
ipv4ToBytes4,
|
|
8
|
+
bytes4ToIpv4,
|
|
9
|
+
generateMnemonic,
|
|
10
|
+
getEthereumAddressFromMnemonic,
|
|
11
|
+
getEVMPrivateKeyFromMnemonic,
|
|
12
|
+
getDIDFromMnemonic,
|
|
13
|
+
generateDIDKeyData,
|
|
14
|
+
deriveDIDFromMnemonic,
|
|
15
|
+
TagTypeBuilder
|
|
16
|
+
} from './index';
|
|
4
17
|
import { debug } from './debug';
|
|
18
|
+
import { normalizeToDomain } from './utils/olares-id';
|
|
19
|
+
import * as fs from 'fs';
|
|
20
|
+
import * as path from 'path';
|
|
21
|
+
|
|
22
|
+
// CLI Version - read from package.json
|
|
23
|
+
const packageJson = JSON.parse(
|
|
24
|
+
fs.readFileSync(path.join(__dirname, '../package.json'), 'utf-8')
|
|
25
|
+
);
|
|
26
|
+
const CLI_VERSION = packageJson.version;
|
|
5
27
|
|
|
6
28
|
// 预设的网络配置
|
|
7
29
|
const NETWORKS = {
|
|
@@ -9,13 +31,17 @@ const NETWORKS = {
|
|
|
9
31
|
rpc: 'https://sepolia.optimism.io',
|
|
10
32
|
contractDid: '0xe2D7c3a9013960E04d4E9F5F9B63fff37eEd97A8',
|
|
11
33
|
contractRootResolver: '0xeF727cb066Fee98F88Db84555830063b4A24ddfc',
|
|
12
|
-
contractAbiType: '0x7386fCBae6Ad4CCE1499d9153D99bc950B589718'
|
|
34
|
+
contractAbiType: '0x7386fCBae6Ad4CCE1499d9153D99bc950B589718',
|
|
35
|
+
contractRootResolver2: '0xcbC02aa08c77a374eC0D5A0403E108b7573d96e8',
|
|
36
|
+
supportSvcUrl: 'https://api-test.olares.com/did/support'
|
|
13
37
|
},
|
|
14
38
|
mainnet: {
|
|
15
39
|
rpc: 'https://optimism-rpc.publicnode.com',
|
|
16
40
|
contractDid: '0x5DA4Fa8E567d86e52Ef8Da860de1be8f54cae97D',
|
|
17
41
|
contractRootResolver: '0xE2EABA0979277A90511F8873ae1e8cA26B54E740',
|
|
18
|
-
contractAbiType: '0x9ae3F16bD99294Af1784beB1a0A5C84bf2636365'
|
|
42
|
+
contractAbiType: '0x9ae3F16bD99294Af1784beB1a0A5C84bf2636365',
|
|
43
|
+
contractRootResolver2: '0x7e7961aB771cA942CE4DB6e79579e016a33Dc95B',
|
|
44
|
+
supportSvcUrl: 'https://api.olares.com/did/support'
|
|
19
45
|
}
|
|
20
46
|
};
|
|
21
47
|
|
|
@@ -25,16 +51,23 @@ interface CliOptions {
|
|
|
25
51
|
contractDid?: string;
|
|
26
52
|
contractResolver?: string;
|
|
27
53
|
contractAbi?: string;
|
|
54
|
+
contractRootResolver2?: string;
|
|
55
|
+
supportSvcUrl?: string;
|
|
28
56
|
json: boolean;
|
|
29
57
|
verbose: boolean;
|
|
30
58
|
debug: boolean;
|
|
31
59
|
debugLevel: string;
|
|
32
60
|
help: boolean;
|
|
61
|
+
output?: string;
|
|
62
|
+
keyLength?: number;
|
|
63
|
+
words?: number;
|
|
33
64
|
}
|
|
34
65
|
|
|
35
66
|
function parseArgs(): {
|
|
36
67
|
command: string;
|
|
68
|
+
subCommand?: string;
|
|
37
69
|
domain?: string;
|
|
70
|
+
value?: string;
|
|
38
71
|
options: CliOptions;
|
|
39
72
|
} {
|
|
40
73
|
const args = process.argv.slice(2);
|
|
@@ -48,7 +81,19 @@ function parseArgs(): {
|
|
|
48
81
|
};
|
|
49
82
|
|
|
50
83
|
let command = '';
|
|
84
|
+
let subCommand: string | undefined;
|
|
51
85
|
let domain: string | undefined;
|
|
86
|
+
let value: string | undefined;
|
|
87
|
+
|
|
88
|
+
// Commands that don't have subcommands - next arg is domain directly
|
|
89
|
+
const commandsWithoutSubcommand = [
|
|
90
|
+
'info',
|
|
91
|
+
'owner',
|
|
92
|
+
'is-owner',
|
|
93
|
+
'transfer',
|
|
94
|
+
'fetch',
|
|
95
|
+
'fetch-domain'
|
|
96
|
+
];
|
|
52
97
|
|
|
53
98
|
for (let i = 0; i < args.length; i++) {
|
|
54
99
|
const arg = args[i];
|
|
@@ -56,7 +101,7 @@ function parseArgs(): {
|
|
|
56
101
|
if (arg === '--help' || arg === '-h') {
|
|
57
102
|
options.help = true;
|
|
58
103
|
} else if (arg === '--version' || arg === '-V') {
|
|
59
|
-
console.log(
|
|
104
|
+
console.log(CLI_VERSION);
|
|
60
105
|
process.exit(0);
|
|
61
106
|
} else if (arg === '--network' || arg === '-n') {
|
|
62
107
|
options.network = args[++i] || 'sepolia';
|
|
@@ -68,6 +113,16 @@ function parseArgs(): {
|
|
|
68
113
|
options.contractResolver = args[++i];
|
|
69
114
|
} else if (arg === '--contract-abi') {
|
|
70
115
|
options.contractAbi = args[++i];
|
|
116
|
+
} else if (arg === '--contract-resolver2') {
|
|
117
|
+
options.contractRootResolver2 = args[++i];
|
|
118
|
+
} else if (arg === '--support-svc-url') {
|
|
119
|
+
options.supportSvcUrl = args[++i];
|
|
120
|
+
} else if (arg === '--output' || arg === '-o') {
|
|
121
|
+
options.output = args[++i];
|
|
122
|
+
} else if (arg === '--key-length') {
|
|
123
|
+
options.keyLength = parseInt(args[++i], 10);
|
|
124
|
+
} else if (arg === '--words' || arg === '-w') {
|
|
125
|
+
options.words = parseInt(args[++i], 10);
|
|
71
126
|
} else if (arg === '--json' || arg === '-j') {
|
|
72
127
|
options.json = true;
|
|
73
128
|
} else if (arg === '--verbose' || arg === '-v') {
|
|
@@ -79,31 +134,113 @@ function parseArgs(): {
|
|
|
79
134
|
} else if (!command) {
|
|
80
135
|
command = arg;
|
|
81
136
|
} else if (
|
|
82
|
-
!
|
|
83
|
-
(command
|
|
137
|
+
!subCommand &&
|
|
138
|
+
!commandsWithoutSubcommand.includes(command)
|
|
84
139
|
) {
|
|
140
|
+
// Only set subCommand if the command requires one
|
|
141
|
+
subCommand = arg;
|
|
142
|
+
} else if (!domain) {
|
|
85
143
|
domain = arg;
|
|
144
|
+
} else if (!value) {
|
|
145
|
+
value = arg;
|
|
86
146
|
}
|
|
87
147
|
}
|
|
88
148
|
|
|
89
|
-
return { command, domain, options };
|
|
149
|
+
return { command, subCommand, domain, value, options };
|
|
90
150
|
}
|
|
91
151
|
|
|
92
152
|
function showHelp(): void {
|
|
93
153
|
console.log(`
|
|
94
|
-
DID CLI Tool
|
|
154
|
+
DID CLI Tool v${CLI_VERSION}
|
|
95
155
|
|
|
96
156
|
USAGE:
|
|
97
|
-
did-cli <command> [arguments] [options]
|
|
157
|
+
did-cli <command> [subcommand] [arguments] [options]
|
|
98
158
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
help Show this help message
|
|
159
|
+
NOTE:
|
|
160
|
+
Olares ID Format: You can use @ instead of the first dot in domain names.
|
|
161
|
+
Example: alice@example.com is equivalent to alice.example.com
|
|
162
|
+
Both formats work identically in all commands!
|
|
104
163
|
|
|
105
|
-
|
|
106
|
-
|
|
164
|
+
COMMANDS:
|
|
165
|
+
Query Commands:
|
|
166
|
+
info <domain> Get domain metadata
|
|
167
|
+
owner <domain> Get domain owner address
|
|
168
|
+
is-owner <domain> Check if you are the domain owner (requires PRIVATE_KEY_OR_MNEMONIC)
|
|
169
|
+
|
|
170
|
+
RSA Key Commands:
|
|
171
|
+
rsa generate Generate a new RSA key pair
|
|
172
|
+
rsa get <domain> Get RSA public key for domain
|
|
173
|
+
rsa set <domain> <file> Set RSA public key from PEM file (requires PRIVATE_KEY_OR_MNEMONIC)
|
|
174
|
+
rsa remove <domain> Remove RSA public key (requires PRIVATE_KEY_OR_MNEMONIC)
|
|
175
|
+
|
|
176
|
+
IP Commands:
|
|
177
|
+
ip get <domain> Get DNS A record (IPv4)
|
|
178
|
+
ip set <domain> <ip> Set DNS A record (requires PRIVATE_KEY_OR_MNEMONIC)
|
|
179
|
+
ip remove <domain> Remove DNS A record (requires PRIVATE_KEY_OR_MNEMONIC)
|
|
180
|
+
|
|
181
|
+
Subdomain Commands:
|
|
182
|
+
subdomain register <parent> <label>
|
|
183
|
+
Register a new subdomain (requires PRIVATE_KEY_OR_MNEMONIC)
|
|
184
|
+
Use MNEMONIC env var for subdomain owner or auto-generates one
|
|
185
|
+
|
|
186
|
+
Transfer Commands:
|
|
187
|
+
transfer <domain> Transfer domain ownership to a new owner (requires PRIVATE_KEY_OR_MNEMONIC)
|
|
188
|
+
Use MNEMONIC env var for new owner or auto-generates one
|
|
189
|
+
|
|
190
|
+
Wallet Management Commands:
|
|
191
|
+
wallet evm add <domain> Add EVM wallet to domain (requires PRIVATE_KEY_OR_MNEMONIC & EVM_PRIVATE_KEY)
|
|
192
|
+
wallet evm remove <domain> Remove EVM wallet from domain (requires PRIVATE_KEY_OR_MNEMONIC & EVM_PRIVATE_KEY)
|
|
193
|
+
wallet evm list <domain> List all EVM wallets for domain
|
|
194
|
+
wallet solana add <domain> Add Solana wallet to domain (requires PRIVATE_KEY_OR_MNEMONIC & SOLANA_PRIVATE_KEY)
|
|
195
|
+
wallet solana remove <domain>
|
|
196
|
+
Remove Solana wallet from domain (requires PRIVATE_KEY_OR_MNEMONIC & SOLANA_PRIVATE_KEY)
|
|
197
|
+
wallet solana list <domain>
|
|
198
|
+
List all Solana wallets for domain
|
|
199
|
+
|
|
200
|
+
Tag Management Commands:
|
|
201
|
+
tag define <domain> <tag-name> <type>
|
|
202
|
+
Define a new tag type (requires PRIVATE_KEY_OR_MNEMONIC)
|
|
203
|
+
Supported types: string, uint8, uint256, int8, int256, bool, address, bytes, bytes32
|
|
204
|
+
Array types: string[], uint8[], etc.
|
|
205
|
+
tag set <domain> <tag-name> <value>
|
|
206
|
+
Set tag value (requires PRIVATE_KEY_OR_MNEMONIC)
|
|
207
|
+
Value can be a string or JSON for arrays/objects
|
|
208
|
+
tag get <domain> <tag-name>
|
|
209
|
+
Get tag value (read-only)
|
|
210
|
+
tag remove <domain> <tag-name>
|
|
211
|
+
Remove tag value (requires PRIVATE_KEY_OR_MNEMONIC)
|
|
212
|
+
tag list <domain> List all tags with values for domain (read-only)
|
|
213
|
+
tag list-defined <domain> List all defined tag types for domain (read-only)
|
|
214
|
+
tag set-tagger <domain> <tag-name> <address>
|
|
215
|
+
Set tagger address for a tag (requires PRIVATE_KEY_OR_MNEMONIC)
|
|
216
|
+
tag get-tagger <domain> <tag-name>
|
|
217
|
+
Get tagger address for a tag (read-only)
|
|
218
|
+
|
|
219
|
+
Operator Commands:
|
|
220
|
+
operator get Get current operator address
|
|
221
|
+
operator set <address> Set operator address (requires PRIVATE_KEY_OR_MNEMONIC)
|
|
222
|
+
|
|
223
|
+
Crypto Utility Commands:
|
|
224
|
+
crypto generate Generate a new mnemonic phrase (--words option)
|
|
225
|
+
Saves to file, use --output to specify file path
|
|
226
|
+
crypto address Get Ethereum address from mnemonic (requires MNEMONIC env var)
|
|
227
|
+
crypto did Get DID from mnemonic (requires MNEMONIC env var)
|
|
228
|
+
crypto privatekey Get EVM private key from mnemonic (requires MNEMONIC env var)
|
|
229
|
+
Saves to file, use --output to specify file path
|
|
230
|
+
crypto derive Derive all keys from mnemonic (requires MNEMONIC env var)
|
|
231
|
+
Saves to file, use --output to specify file path
|
|
232
|
+
|
|
233
|
+
Utility Commands:
|
|
234
|
+
convert pem-to-der <file> Convert PEM file to DER hex
|
|
235
|
+
convert der-to-pem <hex> Convert DER hex to PEM
|
|
236
|
+
convert ip-to-bytes <ip> Convert IPv4 to bytes4
|
|
237
|
+
convert bytes-to-ip <hex> Convert bytes4 to IPv4
|
|
238
|
+
|
|
239
|
+
Legacy Commands:
|
|
240
|
+
fetch <domain> Fetch domain information (alias: fetch-domain)
|
|
241
|
+
fetch-all Fetch all domains from contract
|
|
242
|
+
config Show network configurations
|
|
243
|
+
help Show this help message
|
|
107
244
|
|
|
108
245
|
OPTIONS:
|
|
109
246
|
-n, --network <network> Network to use (sepolia|mainnet) [default: sepolia]
|
|
@@ -111,6 +248,12 @@ OPTIONS:
|
|
|
111
248
|
--contract-did <address> Custom DID contract address
|
|
112
249
|
--contract-resolver <address> Custom RootResolver contract address
|
|
113
250
|
--contract-abi <address> Custom ABIType contract address
|
|
251
|
+
--contract-resolver2 <address> Custom RootResolver2 contract address
|
|
252
|
+
--support-svc-url <url> Custom support service URL
|
|
253
|
+
-o, --output <file> Output file path (for generate commands)
|
|
254
|
+
--key-length <bits> RSA key length in bits [default: 2048]
|
|
255
|
+
-w, --words <count> Mnemonic word count: 12|15|18|21|24 [default: 12]
|
|
256
|
+
-j, --json Output in JSON format
|
|
114
257
|
-v, --verbose Enable verbose debug output
|
|
115
258
|
--debug Enable debug output
|
|
116
259
|
--debug-level <level> Set debug level (debug|info|warn|error) [default: info]
|
|
@@ -118,12 +261,130 @@ OPTIONS:
|
|
|
118
261
|
-V, --version Show version number
|
|
119
262
|
|
|
120
263
|
EXAMPLES:
|
|
121
|
-
|
|
122
|
-
did-cli
|
|
123
|
-
did-cli
|
|
124
|
-
|
|
125
|
-
did-cli
|
|
126
|
-
|
|
264
|
+
# Query domain info
|
|
265
|
+
did-cli info example.olares.com --network mainnet
|
|
266
|
+
did-cli owner example.olares.com
|
|
267
|
+
export PRIVATE_KEY_OR_MNEMONIC=0xYOUR_PRIVATE_KEY
|
|
268
|
+
did-cli is-owner example.olares.com
|
|
269
|
+
|
|
270
|
+
# Olares ID format (use @ instead of first dot - like email addresses!)
|
|
271
|
+
# Both formats work identically: alice.example.com = alice@example.com
|
|
272
|
+
did-cli info alice@example.com
|
|
273
|
+
did-cli owner bob@sub.example.com
|
|
274
|
+
did-cli rsa get user@domain.com
|
|
275
|
+
did-cli ip set alice@example.com 192.168.1.100
|
|
276
|
+
did-cli tag get alice@example.com email
|
|
277
|
+
|
|
278
|
+
# RSA key management
|
|
279
|
+
did-cli rsa generate --output ./my-key.pem --key-length 4096
|
|
280
|
+
did-cli rsa get example.olares.com
|
|
281
|
+
did-cli rsa set example.olares.com ./public-key.pem
|
|
282
|
+
did-cli rsa remove example.olares.com
|
|
283
|
+
|
|
284
|
+
# IP management
|
|
285
|
+
did-cli ip get example.olares.com
|
|
286
|
+
did-cli ip set example.olares.com 192.168.1.100
|
|
287
|
+
did-cli ip remove example.olares.com
|
|
288
|
+
|
|
289
|
+
# Subdomain management (auto-generate mnemonic for subdomain owner)
|
|
290
|
+
export PRIVATE_KEY_OR_MNEMONIC=0xYOUR_PRIVATE_KEY
|
|
291
|
+
did-cli subdomain register parent.com child
|
|
292
|
+
did-cli subdomain register parent.com child --words 24
|
|
293
|
+
|
|
294
|
+
# Subdomain management (use existing mnemonic for subdomain owner)
|
|
295
|
+
export MNEMONIC="your twelve word mnemonic here"
|
|
296
|
+
did-cli subdomain register parent.com child
|
|
297
|
+
|
|
298
|
+
# Subdomain management (JSON output)
|
|
299
|
+
did-cli subdomain register parent.com child --json
|
|
300
|
+
|
|
301
|
+
# Transfer domain ownership (auto-generate mnemonic for new owner)
|
|
302
|
+
export PRIVATE_KEY_OR_MNEMONIC=0xYOUR_PRIVATE_KEY
|
|
303
|
+
did-cli transfer example.com
|
|
304
|
+
did-cli transfer example.com --words 24
|
|
305
|
+
|
|
306
|
+
# Transfer domain ownership (use existing mnemonic for new owner)
|
|
307
|
+
export MNEMONIC="your twelve word mnemonic here"
|
|
308
|
+
did-cli transfer example.com
|
|
309
|
+
|
|
310
|
+
# Crypto utilities
|
|
311
|
+
did-cli crypto generate --words 12
|
|
312
|
+
did-cli crypto generate --words 24 --output ./custom-path.txt
|
|
313
|
+
export MNEMONIC="your twelve word mnemonic here"
|
|
314
|
+
did-cli crypto address
|
|
315
|
+
did-cli crypto did
|
|
316
|
+
did-cli crypto privatekey --output ./my-private-key.txt
|
|
317
|
+
did-cli crypto derive --output ./my-keys.txt
|
|
318
|
+
|
|
319
|
+
# Wallet management
|
|
320
|
+
export PRIVATE_KEY_OR_MNEMONIC=0xYOUR_PRIVATE_KEY
|
|
321
|
+
|
|
322
|
+
# Add EVM wallet
|
|
323
|
+
export EVM_PRIVATE_KEY=0xWALLET_PRIVATE_KEY
|
|
324
|
+
did-cli wallet evm add example.com
|
|
325
|
+
|
|
326
|
+
# Remove EVM wallet
|
|
327
|
+
did-cli wallet evm remove example.com
|
|
328
|
+
|
|
329
|
+
# List EVM wallets
|
|
330
|
+
did-cli wallet evm list example.com
|
|
331
|
+
|
|
332
|
+
# Add Solana wallet (base58 format)
|
|
333
|
+
export SOLANA_PRIVATE_KEY="5J7W..."
|
|
334
|
+
did-cli wallet solana add example.com
|
|
335
|
+
|
|
336
|
+
# Add Solana wallet (JSON array format from Phantom)
|
|
337
|
+
export SOLANA_PRIVATE_KEY='[1,2,3,...]'
|
|
338
|
+
did-cli wallet solana add example.com
|
|
339
|
+
|
|
340
|
+
# List Solana wallets
|
|
341
|
+
did-cli wallet solana list example.com
|
|
342
|
+
|
|
343
|
+
# Tag management
|
|
344
|
+
export PRIVATE_KEY_OR_MNEMONIC=0xYOUR_PRIVATE_KEY
|
|
345
|
+
|
|
346
|
+
# Define a simple tag
|
|
347
|
+
did-cli tag define example.com email string
|
|
348
|
+
|
|
349
|
+
# Set tagger (usually yourself)
|
|
350
|
+
did-cli tag set-tagger example.com email 0xYourAddress
|
|
351
|
+
|
|
352
|
+
# Set tag value
|
|
353
|
+
did-cli tag set example.com email "user@example.com"
|
|
354
|
+
|
|
355
|
+
# Get tag value
|
|
356
|
+
did-cli tag get example.com email
|
|
357
|
+
|
|
358
|
+
# List all tags
|
|
359
|
+
did-cli tag list example.com
|
|
360
|
+
|
|
361
|
+
# Array type (quote to prevent shell interpretation)
|
|
362
|
+
did-cli tag define example.com links "string[]"
|
|
363
|
+
did-cli tag set-tagger example.com links 0xYourAddress
|
|
364
|
+
did-cli tag set example.com links '["https://x.com","https://github.com"]'
|
|
365
|
+
|
|
366
|
+
# Remove tag
|
|
367
|
+
did-cli tag remove example.com email
|
|
368
|
+
|
|
369
|
+
# Operator management
|
|
370
|
+
did-cli operator get
|
|
371
|
+
did-cli operator set 0x1234...
|
|
372
|
+
|
|
373
|
+
# Utilities
|
|
374
|
+
did-cli convert pem-to-der ./public-key.pem
|
|
375
|
+
did-cli convert ip-to-bytes 192.168.1.1
|
|
376
|
+
did-cli convert bytes-to-ip 0xc0a80101
|
|
377
|
+
|
|
378
|
+
ENVIRONMENT VARIABLES:
|
|
379
|
+
PRIVATE_KEY_OR_MNEMONIC Private key (0x...) or mnemonic phrase for signing transactions
|
|
380
|
+
(required for write operations)
|
|
381
|
+
MNEMONIC Mnemonic phrase for generating owner identity
|
|
382
|
+
(used in subdomain registration, domain transfer, and crypto utilities)
|
|
383
|
+
EVM_PRIVATE_KEY EVM wallet private key for wallet management operations
|
|
384
|
+
(required for wallet evm add/remove commands)
|
|
385
|
+
SOLANA_PRIVATE_KEY Solana wallet private key for wallet management operations
|
|
386
|
+
Format: base58 string or JSON array (e.g., "[1,2,3,...]")
|
|
387
|
+
(required for wallet solana add/remove commands)
|
|
127
388
|
`);
|
|
128
389
|
}
|
|
129
390
|
|
|
@@ -194,29 +455,2501 @@ async function fetchDomain(domain: string, options: CliOptions): Promise<void> {
|
|
|
194
455
|
}
|
|
195
456
|
}
|
|
196
457
|
|
|
197
|
-
|
|
198
|
-
|
|
458
|
+
// ============================================================================
|
|
459
|
+
// Helper Functions
|
|
460
|
+
// ============================================================================
|
|
199
461
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
462
|
+
function getConsole(options: CliOptions) {
|
|
463
|
+
let config;
|
|
464
|
+
if (
|
|
465
|
+
options.rpc &&
|
|
466
|
+
options.contractDid &&
|
|
467
|
+
options.contractResolver &&
|
|
468
|
+
options.contractAbi &&
|
|
469
|
+
options.contractRootResolver2 &&
|
|
470
|
+
options.supportSvcUrl
|
|
471
|
+
) {
|
|
472
|
+
config = {
|
|
473
|
+
rpc: options.rpc,
|
|
474
|
+
contractDid: options.contractDid,
|
|
475
|
+
contractRootResolver: options.contractResolver,
|
|
476
|
+
contractAbiType: options.contractAbi,
|
|
477
|
+
contractRootResolver2: options.contractRootResolver2,
|
|
478
|
+
supportSvcUrl: options.supportSvcUrl
|
|
479
|
+
};
|
|
480
|
+
} else if (NETWORKS[options.network as keyof typeof NETWORKS]) {
|
|
481
|
+
config = NETWORKS[options.network as keyof typeof NETWORKS];
|
|
482
|
+
} else {
|
|
483
|
+
throw new Error(`Unknown network: ${options.network}`);
|
|
203
484
|
}
|
|
204
485
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
486
|
+
return OlaresID.createConsole(
|
|
487
|
+
config.rpc,
|
|
488
|
+
config.contractDid,
|
|
489
|
+
config.contractRootResolver,
|
|
490
|
+
config.contractAbiType,
|
|
491
|
+
config.contractRootResolver2,
|
|
492
|
+
config.supportSvcUrl
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function getPrivateKeyOrMnemonic(): string {
|
|
497
|
+
const key = process.env.PRIVATE_KEY_OR_MNEMONIC;
|
|
498
|
+
if (!key) {
|
|
499
|
+
console.error(
|
|
500
|
+
'❌ Error: Private key or mnemonic is required for this operation'
|
|
501
|
+
);
|
|
502
|
+
console.error(
|
|
503
|
+
'Please set PRIVATE_KEY_OR_MNEMONIC environment variable'
|
|
504
|
+
);
|
|
505
|
+
console.error(
|
|
506
|
+
'Example: export PRIVATE_KEY_OR_MNEMONIC=0xYOUR_PRIVATE_KEY'
|
|
507
|
+
);
|
|
508
|
+
console.error(
|
|
509
|
+
'Or: export PRIVATE_KEY_OR_MNEMONIC="your twelve word mnemonic phrase here"'
|
|
510
|
+
);
|
|
511
|
+
process.exit(1);
|
|
512
|
+
}
|
|
513
|
+
return key;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// ============================================================================
|
|
517
|
+
// Domain Info Commands
|
|
518
|
+
// ============================================================================
|
|
519
|
+
|
|
520
|
+
async function getDomainInfo(
|
|
521
|
+
domain: string,
|
|
522
|
+
options: CliOptions
|
|
523
|
+
): Promise<void> {
|
|
524
|
+
try {
|
|
525
|
+
const didConsole = getConsole(options);
|
|
526
|
+
const domainContext = didConsole.domain(domain);
|
|
527
|
+
const metaInfo = await domainContext.getMetaInfo();
|
|
528
|
+
|
|
529
|
+
if (options.json) {
|
|
530
|
+
console.log(JSON.stringify(metaInfo, null, 2));
|
|
531
|
+
} else {
|
|
532
|
+
console.log('📋 Domain Metadata:');
|
|
533
|
+
console.log(` Name: ${metaInfo.name}`);
|
|
534
|
+
console.log(` DID: ${metaInfo.did}`);
|
|
535
|
+
console.log(` Token ID: ${metaInfo.id}`);
|
|
536
|
+
console.log(` Note: ${metaInfo.note}`);
|
|
537
|
+
console.log(` Allow Subdomain: ${metaInfo.allowSubdomain}`);
|
|
538
|
+
}
|
|
539
|
+
} catch (error) {
|
|
540
|
+
console.error(
|
|
541
|
+
'❌ Error:',
|
|
542
|
+
error instanceof Error ? error.message : String(error)
|
|
543
|
+
);
|
|
544
|
+
process.exit(1);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
async function getDomainOwner(
|
|
549
|
+
domain: string,
|
|
550
|
+
options: CliOptions
|
|
551
|
+
): Promise<void> {
|
|
552
|
+
try {
|
|
553
|
+
const didConsole = getConsole(options);
|
|
554
|
+
const domainContext = didConsole.domain(domain);
|
|
555
|
+
const owner = await domainContext.getOwner();
|
|
556
|
+
|
|
557
|
+
if (options.json) {
|
|
558
|
+
console.log(JSON.stringify({ owner }, null, 2));
|
|
559
|
+
} else {
|
|
560
|
+
console.log(`👤 Owner: ${owner}`);
|
|
561
|
+
}
|
|
562
|
+
} catch (error) {
|
|
563
|
+
console.error(
|
|
564
|
+
'❌ Error:',
|
|
565
|
+
error instanceof Error ? error.message : String(error)
|
|
566
|
+
);
|
|
567
|
+
process.exit(1);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
async function checkIsOwner(
|
|
572
|
+
domain: string,
|
|
573
|
+
options: CliOptions
|
|
574
|
+
): Promise<void> {
|
|
575
|
+
try {
|
|
576
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
577
|
+
const didConsole = getConsole(options);
|
|
578
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
579
|
+
|
|
580
|
+
const domainContext = didConsole.domain(domain);
|
|
581
|
+
const isOwner = await domainContext.isOwner();
|
|
582
|
+
|
|
583
|
+
if (options.json) {
|
|
584
|
+
console.log(JSON.stringify({ isOwner }, null, 2));
|
|
585
|
+
} else {
|
|
586
|
+
console.log(
|
|
587
|
+
isOwner ? '✅ You are the owner' : '❌ You are not the owner'
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
} catch (error) {
|
|
591
|
+
console.error(
|
|
592
|
+
'❌ Error:',
|
|
593
|
+
error instanceof Error ? error.message : String(error)
|
|
594
|
+
);
|
|
595
|
+
process.exit(1);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// ============================================================================
|
|
600
|
+
// RSA Key Commands
|
|
601
|
+
// ============================================================================
|
|
602
|
+
|
|
603
|
+
async function generateRsaKey(options: CliOptions): Promise<void> {
|
|
604
|
+
try {
|
|
605
|
+
const keyLength = options.keyLength || 2048;
|
|
606
|
+
const keyPair = await createRsaKeyPair(keyLength);
|
|
607
|
+
|
|
608
|
+
if (options.output) {
|
|
609
|
+
// Save to files
|
|
610
|
+
const publicKeyFile = options.output;
|
|
611
|
+
const privateKeyFile = options.output.replace(
|
|
612
|
+
/\.pem$/,
|
|
613
|
+
'-private.pem'
|
|
614
|
+
);
|
|
615
|
+
|
|
616
|
+
fs.writeFileSync(publicKeyFile, keyPair.rsaPublicKey);
|
|
617
|
+
fs.writeFileSync(privateKeyFile, keyPair.rsaPrivateKey);
|
|
618
|
+
|
|
619
|
+
console.log(`✅ RSA key pair generated (${keyLength} bits)`);
|
|
620
|
+
console.log(`📄 Public key: ${publicKeyFile}`);
|
|
621
|
+
console.log(`🔐 Private key: ${privateKeyFile}`);
|
|
622
|
+
} else {
|
|
623
|
+
// When no output file is specified, still save to default files for security
|
|
624
|
+
const defaultPublicFile = './rsa-public.pem';
|
|
625
|
+
const defaultPrivateFile = './rsa-private.pem';
|
|
626
|
+
fs.writeFileSync(defaultPublicFile, keyPair.rsaPublicKey);
|
|
627
|
+
fs.writeFileSync(defaultPrivateFile, keyPair.rsaPrivateKey);
|
|
628
|
+
|
|
629
|
+
if (options.json) {
|
|
630
|
+
console.log(
|
|
631
|
+
JSON.stringify(
|
|
632
|
+
{
|
|
633
|
+
keyLength: keyLength,
|
|
634
|
+
publicKeyFile: defaultPublicFile,
|
|
635
|
+
privateKeyFile: defaultPrivateFile
|
|
636
|
+
},
|
|
637
|
+
null,
|
|
638
|
+
2
|
|
639
|
+
)
|
|
640
|
+
);
|
|
641
|
+
} else {
|
|
642
|
+
console.log(`✅ RSA key pair generated (${keyLength} bits)`);
|
|
643
|
+
console.log(`📄 Public key: ${defaultPublicFile}`);
|
|
644
|
+
console.log(`🔐 Private key: ${defaultPrivateFile}`);
|
|
645
|
+
console.log('\n⚠️ SECURITY WARNING:');
|
|
646
|
+
console.log(' • Keep the private key secure! Never share it!');
|
|
647
|
+
console.log(
|
|
648
|
+
' • Delete the file after copying to a secure location'
|
|
649
|
+
);
|
|
650
|
+
console.log(` • Command: rm ${defaultPrivateFile}`);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
} catch (error) {
|
|
654
|
+
console.error(
|
|
655
|
+
'❌ Error:',
|
|
656
|
+
error instanceof Error ? error.message : String(error)
|
|
657
|
+
);
|
|
658
|
+
process.exit(1);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
async function getRsaKey(domain: string, options: CliOptions): Promise<void> {
|
|
663
|
+
try {
|
|
664
|
+
const didConsole = getConsole(options);
|
|
665
|
+
const domainContext = didConsole.domain(domain);
|
|
666
|
+
const rsaKey = await domainContext.getRSAPublicKey();
|
|
667
|
+
|
|
668
|
+
if (!rsaKey) {
|
|
669
|
+
console.log('❌ No RSA public key set for this domain');
|
|
670
|
+
process.exit(1);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
if (options.json) {
|
|
674
|
+
console.log(JSON.stringify({ rsaPublicKey: rsaKey }, null, 2));
|
|
675
|
+
} else {
|
|
676
|
+
console.log('📄 RSA Public Key:');
|
|
677
|
+
console.log(rsaKey);
|
|
678
|
+
}
|
|
679
|
+
} catch (error) {
|
|
680
|
+
console.error(
|
|
681
|
+
'❌ Error:',
|
|
682
|
+
error instanceof Error ? error.message : String(error)
|
|
683
|
+
);
|
|
684
|
+
process.exit(1);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
async function setRsaKey(
|
|
689
|
+
domain: string,
|
|
690
|
+
pemFile: string,
|
|
691
|
+
options: CliOptions
|
|
692
|
+
): Promise<void> {
|
|
693
|
+
try {
|
|
694
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
695
|
+
const didConsole = getConsole(options);
|
|
696
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
697
|
+
|
|
698
|
+
// Read PEM file
|
|
699
|
+
if (!fs.existsSync(pemFile)) {
|
|
700
|
+
console.error(`❌ Error: File not found: ${pemFile}`);
|
|
701
|
+
process.exit(1);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
const rsaPublicKey = fs.readFileSync(pemFile, 'utf-8');
|
|
705
|
+
const domainContext = didConsole.domain(domain);
|
|
706
|
+
const result = await domainContext.setRSAPublicKey(rsaPublicKey);
|
|
707
|
+
|
|
708
|
+
if (result.success) {
|
|
709
|
+
console.log('✅ RSA public key set successfully');
|
|
710
|
+
console.log(`📝 Transaction: ${result.transactionHash}`);
|
|
711
|
+
if (result.gasUsed) {
|
|
712
|
+
console.log(`⛽ Gas used: ${result.gasUsed.toString()}`);
|
|
713
|
+
}
|
|
714
|
+
} else {
|
|
715
|
+
console.error(`❌ Failed: ${result.error}`);
|
|
716
|
+
process.exit(1);
|
|
717
|
+
}
|
|
718
|
+
} catch (error) {
|
|
719
|
+
console.error(
|
|
720
|
+
'❌ Error:',
|
|
721
|
+
error instanceof Error ? error.message : String(error)
|
|
722
|
+
);
|
|
723
|
+
process.exit(1);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
async function removeRsaKey(
|
|
728
|
+
domain: string,
|
|
729
|
+
options: CliOptions
|
|
730
|
+
): Promise<void> {
|
|
731
|
+
try {
|
|
732
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
733
|
+
const didConsole = getConsole(options);
|
|
734
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
735
|
+
|
|
736
|
+
const domainContext = didConsole.domain(domain);
|
|
737
|
+
const result = await domainContext.removeRSAPublicKey();
|
|
738
|
+
|
|
739
|
+
if (result.success) {
|
|
740
|
+
console.log('✅ RSA public key removed successfully');
|
|
741
|
+
console.log(`📝 Transaction: ${result.transactionHash}`);
|
|
742
|
+
if (result.gasUsed) {
|
|
743
|
+
console.log(`⛽ Gas used: ${result.gasUsed.toString()}`);
|
|
744
|
+
}
|
|
745
|
+
} else {
|
|
746
|
+
console.error(`❌ Failed: ${result.error}`);
|
|
747
|
+
process.exit(1);
|
|
748
|
+
}
|
|
749
|
+
} catch (error) {
|
|
750
|
+
console.error(
|
|
751
|
+
'❌ Error:',
|
|
752
|
+
error instanceof Error ? error.message : String(error)
|
|
753
|
+
);
|
|
754
|
+
process.exit(1);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// ============================================================================
|
|
759
|
+
// IP Commands
|
|
760
|
+
// ============================================================================
|
|
761
|
+
|
|
762
|
+
async function getIP(domain: string, options: CliOptions): Promise<void> {
|
|
763
|
+
try {
|
|
764
|
+
const didConsole = getConsole(options);
|
|
765
|
+
const domainContext = didConsole.domain(domain);
|
|
766
|
+
const ip = await domainContext.getIP();
|
|
767
|
+
|
|
768
|
+
if (!ip) {
|
|
769
|
+
console.log('❌ No IP address set for this domain');
|
|
770
|
+
process.exit(1);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
if (options.json) {
|
|
774
|
+
console.log(JSON.stringify({ ip }, null, 2));
|
|
775
|
+
} else {
|
|
776
|
+
console.log(`🌐 IP Address: ${ip}`);
|
|
777
|
+
}
|
|
778
|
+
} catch (error) {
|
|
779
|
+
console.error(
|
|
780
|
+
'❌ Error:',
|
|
781
|
+
error instanceof Error ? error.message : String(error)
|
|
782
|
+
);
|
|
783
|
+
process.exit(1);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
async function setIP(
|
|
788
|
+
domain: string,
|
|
789
|
+
ip: string,
|
|
790
|
+
options: CliOptions
|
|
791
|
+
): Promise<void> {
|
|
792
|
+
try {
|
|
793
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
794
|
+
const didConsole = getConsole(options);
|
|
795
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
796
|
+
|
|
797
|
+
const domainContext = didConsole.domain(domain);
|
|
798
|
+
const result = await domainContext.setIP(ip);
|
|
799
|
+
|
|
800
|
+
if (result.success) {
|
|
801
|
+
console.log(`✅ IP address set to ${ip}`);
|
|
802
|
+
console.log(`📝 Transaction: ${result.transactionHash}`);
|
|
803
|
+
if (result.gasUsed) {
|
|
804
|
+
console.log(`⛽ Gas used: ${result.gasUsed.toString()}`);
|
|
805
|
+
}
|
|
806
|
+
} else {
|
|
807
|
+
console.error(`❌ Failed: ${result.error}`);
|
|
808
|
+
process.exit(1);
|
|
809
|
+
}
|
|
810
|
+
} catch (error) {
|
|
811
|
+
console.error(
|
|
812
|
+
'❌ Error:',
|
|
813
|
+
error instanceof Error ? error.message : String(error)
|
|
814
|
+
);
|
|
815
|
+
process.exit(1);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
async function removeIP(domain: string, options: CliOptions): Promise<void> {
|
|
820
|
+
try {
|
|
821
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
822
|
+
const didConsole = getConsole(options);
|
|
823
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
824
|
+
|
|
825
|
+
const domainContext = didConsole.domain(domain);
|
|
826
|
+
const result = await domainContext.removeIP();
|
|
827
|
+
|
|
828
|
+
if (result.success) {
|
|
829
|
+
console.log('✅ IP address removed successfully');
|
|
830
|
+
console.log(`📝 Transaction: ${result.transactionHash}`);
|
|
831
|
+
if (result.gasUsed) {
|
|
832
|
+
console.log(`⛽ Gas used: ${result.gasUsed.toString()}`);
|
|
833
|
+
}
|
|
834
|
+
} else {
|
|
835
|
+
console.error(`❌ Failed: ${result.error}`);
|
|
836
|
+
process.exit(1);
|
|
837
|
+
}
|
|
838
|
+
} catch (error) {
|
|
839
|
+
console.error(
|
|
840
|
+
'❌ Error:',
|
|
841
|
+
error instanceof Error ? error.message : String(error)
|
|
842
|
+
);
|
|
843
|
+
process.exit(1);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// ============================================================================
|
|
848
|
+
// Operator Commands
|
|
849
|
+
// ============================================================================
|
|
850
|
+
|
|
851
|
+
async function getOperator(options: CliOptions): Promise<void> {
|
|
852
|
+
try {
|
|
853
|
+
const didConsole = getConsole(options);
|
|
854
|
+
const operator = await didConsole.getOperator();
|
|
855
|
+
|
|
856
|
+
if (options.json) {
|
|
857
|
+
console.log(JSON.stringify({ operator }, null, 2));
|
|
858
|
+
} else {
|
|
859
|
+
console.log(`👔 Operator: ${operator}`);
|
|
860
|
+
}
|
|
861
|
+
} catch (error) {
|
|
862
|
+
console.error(
|
|
863
|
+
'❌ Error:',
|
|
864
|
+
error instanceof Error ? error.message : String(error)
|
|
865
|
+
);
|
|
866
|
+
process.exit(1);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
async function setOperator(
|
|
871
|
+
address: string,
|
|
872
|
+
options: CliOptions
|
|
873
|
+
): Promise<void> {
|
|
874
|
+
try {
|
|
875
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
876
|
+
const didConsole = getConsole(options);
|
|
877
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
878
|
+
|
|
879
|
+
const result = await didConsole.setOperator(address);
|
|
880
|
+
|
|
881
|
+
if (result.success) {
|
|
882
|
+
console.log(`✅ Operator set to ${address}`);
|
|
883
|
+
console.log(`📝 Transaction: ${result.transactionHash}`);
|
|
884
|
+
if (result.gasUsed) {
|
|
885
|
+
console.log(`⛽ Gas used: ${result.gasUsed.toString()}`);
|
|
212
886
|
}
|
|
213
|
-
|
|
214
|
-
|
|
887
|
+
} else {
|
|
888
|
+
console.error(`❌ Failed: ${result.error}`);
|
|
889
|
+
process.exit(1);
|
|
890
|
+
}
|
|
891
|
+
} catch (error) {
|
|
892
|
+
console.error(
|
|
893
|
+
'❌ Error:',
|
|
894
|
+
error instanceof Error ? error.message : String(error)
|
|
895
|
+
);
|
|
896
|
+
process.exit(1);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
215
899
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
900
|
+
// ============================================================================
|
|
901
|
+
// Conversion Utilities
|
|
902
|
+
// ============================================================================
|
|
903
|
+
|
|
904
|
+
function convertPemToDer(pemFile: string, options: CliOptions): void {
|
|
905
|
+
try {
|
|
906
|
+
if (!fs.existsSync(pemFile)) {
|
|
907
|
+
console.error(`❌ Error: File not found: ${pemFile}`);
|
|
219
908
|
process.exit(1);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
const pem = fs.readFileSync(pemFile, 'utf-8');
|
|
912
|
+
const der = pemToDer(pem);
|
|
913
|
+
|
|
914
|
+
if (options.json) {
|
|
915
|
+
console.log(JSON.stringify({ der }, null, 2));
|
|
916
|
+
} else {
|
|
917
|
+
console.log('🔄 DER Hex:');
|
|
918
|
+
console.log(der);
|
|
919
|
+
}
|
|
920
|
+
} catch (error) {
|
|
921
|
+
console.error(
|
|
922
|
+
'❌ Error:',
|
|
923
|
+
error instanceof Error ? error.message : String(error)
|
|
924
|
+
);
|
|
925
|
+
process.exit(1);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
function convertDerToPem(derHex: string, options: CliOptions): void {
|
|
930
|
+
try {
|
|
931
|
+
const pem = derToPem(derHex);
|
|
932
|
+
|
|
933
|
+
if (options.json) {
|
|
934
|
+
console.log(JSON.stringify({ pem }, null, 2));
|
|
935
|
+
} else {
|
|
936
|
+
console.log('🔄 PEM:');
|
|
937
|
+
console.log(pem);
|
|
938
|
+
}
|
|
939
|
+
} catch (error) {
|
|
940
|
+
console.error(
|
|
941
|
+
'❌ Error:',
|
|
942
|
+
error instanceof Error ? error.message : String(error)
|
|
943
|
+
);
|
|
944
|
+
process.exit(1);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
function convertIpToBytes(ip: string, options: CliOptions): void {
|
|
949
|
+
try {
|
|
950
|
+
const bytes = ipv4ToBytes4(ip);
|
|
951
|
+
|
|
952
|
+
if (options.json) {
|
|
953
|
+
console.log(JSON.stringify({ ip, bytes }, null, 2));
|
|
954
|
+
} else {
|
|
955
|
+
console.log(`🔄 ${ip} → ${bytes}`);
|
|
956
|
+
}
|
|
957
|
+
} catch (error) {
|
|
958
|
+
console.error(
|
|
959
|
+
'❌ Error:',
|
|
960
|
+
error instanceof Error ? error.message : String(error)
|
|
961
|
+
);
|
|
962
|
+
process.exit(1);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
function convertBytesToIp(bytes: string, options: CliOptions): void {
|
|
967
|
+
try {
|
|
968
|
+
const ip = bytes4ToIpv4(bytes);
|
|
969
|
+
|
|
970
|
+
if (options.json) {
|
|
971
|
+
console.log(JSON.stringify({ bytes, ip }, null, 2));
|
|
972
|
+
} else {
|
|
973
|
+
console.log(`🔄 ${bytes} → ${ip}`);
|
|
974
|
+
}
|
|
975
|
+
} catch (error) {
|
|
976
|
+
console.error(
|
|
977
|
+
'❌ Error:',
|
|
978
|
+
error instanceof Error ? error.message : String(error)
|
|
979
|
+
);
|
|
980
|
+
process.exit(1);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
// ============================================================================
|
|
985
|
+
// Subdomain Commands
|
|
986
|
+
// ============================================================================
|
|
987
|
+
|
|
988
|
+
async function registerSubdomain(
|
|
989
|
+
parentDomain: string,
|
|
990
|
+
subdomain: string,
|
|
991
|
+
options: CliOptions
|
|
992
|
+
): Promise<void> {
|
|
993
|
+
try {
|
|
994
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
995
|
+
const didConsole = getConsole(options);
|
|
996
|
+
|
|
997
|
+
// Initialize with signer
|
|
998
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
999
|
+
|
|
1000
|
+
const domain = didConsole.domain(parentDomain);
|
|
1001
|
+
|
|
1002
|
+
// Get or generate mnemonic for subdomain owner
|
|
1003
|
+
let mnemonic: string;
|
|
1004
|
+
const subdomainMnemonic = process.env.MNEMONIC;
|
|
1005
|
+
|
|
1006
|
+
if (subdomainMnemonic) {
|
|
1007
|
+
mnemonic = subdomainMnemonic;
|
|
1008
|
+
console.log('📝 Using mnemonic from MNEMONIC environment variable');
|
|
1009
|
+
} else {
|
|
1010
|
+
const wordCount = options.words || 12;
|
|
1011
|
+
if (![12, 15, 18, 21, 24].includes(wordCount)) {
|
|
1012
|
+
console.error(
|
|
1013
|
+
'❌ Error: Word count must be one of: 12, 15, 18, 21, 24'
|
|
1014
|
+
);
|
|
1015
|
+
process.exit(1);
|
|
1016
|
+
}
|
|
1017
|
+
mnemonic = generateMnemonic(wordCount);
|
|
1018
|
+
|
|
1019
|
+
// Save mnemonic to file
|
|
1020
|
+
const mnemonicFile = './subdomain-mnemonic.txt';
|
|
1021
|
+
fs.writeFileSync(mnemonicFile, mnemonic, 'utf-8');
|
|
1022
|
+
|
|
1023
|
+
console.log(
|
|
1024
|
+
`🔑 Generated ${wordCount}-word mnemonic for subdomain owner`
|
|
1025
|
+
);
|
|
1026
|
+
console.log(`📄 Mnemonic saved to: ${mnemonicFile}`);
|
|
1027
|
+
console.log('\n⚠️ SECURITY WARNING:');
|
|
1028
|
+
console.log(
|
|
1029
|
+
' • Keep this mnemonic secure! It controls the subdomain!'
|
|
1030
|
+
);
|
|
1031
|
+
console.log(
|
|
1032
|
+
' • Store it in a safe place (paper backup, hardware wallet, etc.)'
|
|
1033
|
+
);
|
|
1034
|
+
console.log(
|
|
1035
|
+
' • Delete the file after copying to a secure location'
|
|
1036
|
+
);
|
|
1037
|
+
console.log(` • Command: rm ${mnemonicFile}`);
|
|
1038
|
+
console.log('\n💡 To use this mnemonic for future operations:');
|
|
1039
|
+
console.log(` export MNEMONIC="$(cat ${mnemonicFile})"\n`);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
// Register subdomain
|
|
1043
|
+
console.log(`📋 Registering subdomain: ${subdomain}.${parentDomain}`);
|
|
1044
|
+
console.log('⏳ Submitting transaction...\n');
|
|
1045
|
+
|
|
1046
|
+
const result = await domain.registerSubdomain(subdomain, mnemonic);
|
|
1047
|
+
|
|
1048
|
+
if (result.success) {
|
|
1049
|
+
if (options.json) {
|
|
1050
|
+
console.log(
|
|
1051
|
+
JSON.stringify(
|
|
1052
|
+
{
|
|
1053
|
+
success: true,
|
|
1054
|
+
subdomain: result.data.subdomain,
|
|
1055
|
+
fullDomainName: result.data.fullDomainName,
|
|
1056
|
+
owner: result.data.owner,
|
|
1057
|
+
did: result.data.did,
|
|
1058
|
+
transactionHash: result.transactionHash,
|
|
1059
|
+
gasUsed: result.gasUsed?.toString(),
|
|
1060
|
+
blockNumber: result.blockNumber
|
|
1061
|
+
},
|
|
1062
|
+
null,
|
|
1063
|
+
2
|
|
1064
|
+
)
|
|
1065
|
+
);
|
|
1066
|
+
} else {
|
|
1067
|
+
console.log('✅ Subdomain registered successfully!\n');
|
|
1068
|
+
console.log('═'.repeat(60));
|
|
1069
|
+
console.log('Registration Details:');
|
|
1070
|
+
console.log('═'.repeat(60));
|
|
1071
|
+
console.log(`Subdomain label: ${result.data.subdomain}`);
|
|
1072
|
+
console.log(
|
|
1073
|
+
`Full domain name: ${result.data.fullDomainName}`
|
|
1074
|
+
);
|
|
1075
|
+
console.log(`Owner address: ${result.data.owner}`);
|
|
1076
|
+
console.log(`DID: ${result.data.did}`);
|
|
1077
|
+
console.log(`Transaction hash: ${result.transactionHash}`);
|
|
1078
|
+
console.log(
|
|
1079
|
+
`Gas used: ${result.gasUsed?.toString() || 'N/A'}`
|
|
1080
|
+
);
|
|
1081
|
+
console.log(
|
|
1082
|
+
`Block number: ${result.blockNumber || 'N/A'}`
|
|
1083
|
+
);
|
|
1084
|
+
console.log('═'.repeat(60));
|
|
1085
|
+
|
|
1086
|
+
const explorerUrl =
|
|
1087
|
+
options.network === 'mainnet'
|
|
1088
|
+
? `https://optimistic.etherscan.io/tx/${result.transactionHash}`
|
|
1089
|
+
: `https://sepolia-optimism.etherscan.io/tx/${result.transactionHash}`;
|
|
1090
|
+
console.log(`\n🔗 View on block explorer:`);
|
|
1091
|
+
console.log(` ${explorerUrl}\n`);
|
|
1092
|
+
}
|
|
1093
|
+
} else {
|
|
1094
|
+
console.error('❌ Subdomain registration failed!');
|
|
1095
|
+
console.error(` Error: ${result.error}`);
|
|
1096
|
+
process.exit(1);
|
|
1097
|
+
}
|
|
1098
|
+
} catch (error) {
|
|
1099
|
+
console.error(
|
|
1100
|
+
'❌ Error:',
|
|
1101
|
+
error instanceof Error ? error.message : String(error)
|
|
1102
|
+
);
|
|
1103
|
+
if (options.debug && error instanceof Error && error.stack) {
|
|
1104
|
+
console.error('\nStack trace:');
|
|
1105
|
+
console.error(error.stack);
|
|
1106
|
+
}
|
|
1107
|
+
process.exit(1);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
/**
|
|
1112
|
+
* Transfer domain ownership to a new owner
|
|
1113
|
+
*/
|
|
1114
|
+
async function transferDomain(
|
|
1115
|
+
domain: string,
|
|
1116
|
+
options: CliOptions
|
|
1117
|
+
): Promise<void> {
|
|
1118
|
+
try {
|
|
1119
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
1120
|
+
const didConsole = getConsole(options);
|
|
1121
|
+
|
|
1122
|
+
// Initialize with current owner's signer
|
|
1123
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
1124
|
+
|
|
1125
|
+
const domainContext = didConsole.domain(domain);
|
|
1126
|
+
|
|
1127
|
+
// Get or generate mnemonic for new owner
|
|
1128
|
+
let mnemonic: string;
|
|
1129
|
+
const newOwnerMnemonic = process.env.MNEMONIC;
|
|
1130
|
+
|
|
1131
|
+
if (newOwnerMnemonic) {
|
|
1132
|
+
mnemonic = newOwnerMnemonic;
|
|
1133
|
+
console.log(
|
|
1134
|
+
'📝 Using mnemonic from MNEMONIC environment variable for new owner'
|
|
1135
|
+
);
|
|
1136
|
+
} else {
|
|
1137
|
+
const wordCount = options.words || 12;
|
|
1138
|
+
if (![12, 15, 18, 21, 24].includes(wordCount)) {
|
|
1139
|
+
console.error(
|
|
1140
|
+
'❌ Error: Word count must be one of: 12, 15, 18, 21, 24'
|
|
1141
|
+
);
|
|
1142
|
+
process.exit(1);
|
|
1143
|
+
}
|
|
1144
|
+
mnemonic = generateMnemonic(wordCount);
|
|
1145
|
+
|
|
1146
|
+
// Save mnemonic to file
|
|
1147
|
+
const mnemonicFile = './transfer-new-owner-mnemonic.txt';
|
|
1148
|
+
fs.writeFileSync(mnemonicFile, mnemonic, 'utf-8');
|
|
1149
|
+
|
|
1150
|
+
console.log(
|
|
1151
|
+
`🔑 Generated ${wordCount}-word mnemonic for new owner`
|
|
1152
|
+
);
|
|
1153
|
+
console.log(`📄 Mnemonic saved to: ${mnemonicFile}`);
|
|
1154
|
+
console.log('\n⚠️ SECURITY WARNING:');
|
|
1155
|
+
console.log(
|
|
1156
|
+
' • Keep this mnemonic secure! It controls the domain!'
|
|
1157
|
+
);
|
|
1158
|
+
console.log(
|
|
1159
|
+
' • Store it in a safe place (paper backup, hardware wallet, etc.)'
|
|
1160
|
+
);
|
|
1161
|
+
console.log(
|
|
1162
|
+
' • Delete the file after copying to a secure location'
|
|
1163
|
+
);
|
|
1164
|
+
console.log(` • Command: rm ${mnemonicFile}`);
|
|
1165
|
+
console.log('\n💡 To use this mnemonic for future operations:');
|
|
1166
|
+
console.log(` export MNEMONIC="$(cat ${mnemonicFile})"\n`);
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// Transfer domain
|
|
1170
|
+
console.log(`📋 Transferring domain: ${domain}`);
|
|
1171
|
+
console.log('⏳ Submitting transactions...\n');
|
|
1172
|
+
|
|
1173
|
+
const result = await domainContext.transfer(mnemonic);
|
|
1174
|
+
|
|
1175
|
+
if (result.success) {
|
|
1176
|
+
if (options.json) {
|
|
1177
|
+
console.log(
|
|
1178
|
+
JSON.stringify(
|
|
1179
|
+
{
|
|
1180
|
+
success: true,
|
|
1181
|
+
domain: domain,
|
|
1182
|
+
newOwner: result.data.newOwner,
|
|
1183
|
+
newDid: result.data.newDid,
|
|
1184
|
+
transferTxHash: result.data.transferTxHash,
|
|
1185
|
+
setDidTxHash: result.data.setDidTxHash
|
|
1186
|
+
},
|
|
1187
|
+
null,
|
|
1188
|
+
2
|
|
1189
|
+
)
|
|
1190
|
+
);
|
|
1191
|
+
} else {
|
|
1192
|
+
console.log('✅ Domain transfer successful!\n');
|
|
1193
|
+
console.log('Transaction Details:');
|
|
1194
|
+
console.log(' Domain:', domain);
|
|
1195
|
+
console.log(' New Owner:', result.data.newOwner);
|
|
1196
|
+
console.log(' New DID:', result.data.newDid);
|
|
1197
|
+
console.log(' Transfer Tx:', result.data.transferTxHash);
|
|
1198
|
+
console.log(' Set DID Tx:', result.data.setDidTxHash);
|
|
1199
|
+
if (!newOwnerMnemonic) {
|
|
1200
|
+
console.log(
|
|
1201
|
+
'\n📝 New owner mnemonic saved to: ./transfer-new-owner-mnemonic.txt'
|
|
1202
|
+
);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
} else {
|
|
1206
|
+
console.error('❌ Transfer failed:', result.error);
|
|
1207
|
+
process.exit(1);
|
|
1208
|
+
}
|
|
1209
|
+
} catch (error) {
|
|
1210
|
+
console.error('❌ Failed:', error);
|
|
1211
|
+
if (error instanceof Error) {
|
|
1212
|
+
console.error(' Message:', error.message);
|
|
1213
|
+
}
|
|
1214
|
+
process.exit(1);
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
/**
|
|
1219
|
+
* Crypto utility: Generate mnemonic
|
|
1220
|
+
*/
|
|
1221
|
+
async function cryptoGenerate(options: CliOptions): Promise<void> {
|
|
1222
|
+
try {
|
|
1223
|
+
const wordCount = options.words || 12;
|
|
1224
|
+
if (![12, 15, 18, 21, 24].includes(wordCount)) {
|
|
1225
|
+
console.error(
|
|
1226
|
+
'❌ Error: Word count must be one of: 12, 15, 18, 21, 24'
|
|
1227
|
+
);
|
|
1228
|
+
process.exit(1);
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
const mnemonic = generateMnemonic(wordCount);
|
|
1232
|
+
|
|
1233
|
+
// Save mnemonic to file
|
|
1234
|
+
const outputFile = options.output || './mnemonic.txt';
|
|
1235
|
+
fs.writeFileSync(outputFile, mnemonic, 'utf-8');
|
|
1236
|
+
|
|
1237
|
+
if (options.json) {
|
|
1238
|
+
console.log(
|
|
1239
|
+
JSON.stringify(
|
|
1240
|
+
{
|
|
1241
|
+
words: wordCount,
|
|
1242
|
+
savedTo: outputFile
|
|
1243
|
+
},
|
|
1244
|
+
null,
|
|
1245
|
+
2
|
|
1246
|
+
)
|
|
1247
|
+
);
|
|
1248
|
+
} else {
|
|
1249
|
+
console.log(`🔑 Generated ${wordCount}-word mnemonic`);
|
|
1250
|
+
console.log(`📄 Mnemonic saved to: ${outputFile}`);
|
|
1251
|
+
console.log('\n⚠️ SECURITY WARNING:');
|
|
1252
|
+
console.log(
|
|
1253
|
+
' • Keep this mnemonic secure! It controls all derived keys!'
|
|
1254
|
+
);
|
|
1255
|
+
console.log(
|
|
1256
|
+
' • Store it in a safe place (paper backup, hardware wallet, etc.)'
|
|
1257
|
+
);
|
|
1258
|
+
console.log(
|
|
1259
|
+
' • Delete the file after copying to a secure location'
|
|
1260
|
+
);
|
|
1261
|
+
console.log(` • Command: rm ${outputFile}`);
|
|
1262
|
+
console.log('\n💡 To use the mnemonic:');
|
|
1263
|
+
console.log(` export MNEMONIC="$(cat ${outputFile})"`);
|
|
1264
|
+
}
|
|
1265
|
+
} catch (error) {
|
|
1266
|
+
console.error('❌ Failed:', error);
|
|
1267
|
+
if (error instanceof Error) {
|
|
1268
|
+
console.error(' Message:', error.message);
|
|
1269
|
+
}
|
|
1270
|
+
process.exit(1);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
/**
|
|
1275
|
+
* Get mnemonic from environment variable
|
|
1276
|
+
*/
|
|
1277
|
+
function getMnemonic(): string {
|
|
1278
|
+
const mnemonic = process.env.MNEMONIC;
|
|
1279
|
+
if (!mnemonic) {
|
|
1280
|
+
console.error('❌ Error: MNEMONIC environment variable is required');
|
|
1281
|
+
console.error('Please set MNEMONIC environment variable');
|
|
1282
|
+
console.error(
|
|
1283
|
+
'Example: export MNEMONIC="your twelve word mnemonic phrase here"'
|
|
1284
|
+
);
|
|
1285
|
+
console.error(
|
|
1286
|
+
'\n⚠️ Important: Always use quotes for mnemonic phrases!'
|
|
1287
|
+
);
|
|
1288
|
+
process.exit(1);
|
|
1289
|
+
}
|
|
1290
|
+
return mnemonic;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
/**
|
|
1294
|
+
* Crypto utility: Get Ethereum address from mnemonic
|
|
1295
|
+
*/
|
|
1296
|
+
async function cryptoGetAddress(options: CliOptions): Promise<void> {
|
|
1297
|
+
try {
|
|
1298
|
+
const mnemonic = getMnemonic();
|
|
1299
|
+
const address = await getEthereumAddressFromMnemonic(mnemonic);
|
|
1300
|
+
|
|
1301
|
+
if (options.json) {
|
|
1302
|
+
console.log(
|
|
1303
|
+
JSON.stringify(
|
|
1304
|
+
{
|
|
1305
|
+
address: address
|
|
1306
|
+
},
|
|
1307
|
+
null,
|
|
1308
|
+
2
|
|
1309
|
+
)
|
|
1310
|
+
);
|
|
1311
|
+
} else {
|
|
1312
|
+
console.log('🏠 Ethereum Address:');
|
|
1313
|
+
console.log(` ${address}`);
|
|
1314
|
+
}
|
|
1315
|
+
} catch (error) {
|
|
1316
|
+
console.error('❌ Failed:', error);
|
|
1317
|
+
if (error instanceof Error) {
|
|
1318
|
+
console.error(' Message:', error.message);
|
|
1319
|
+
}
|
|
1320
|
+
process.exit(1);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
/**
|
|
1325
|
+
* Crypto utility: Get DID from mnemonic
|
|
1326
|
+
*/
|
|
1327
|
+
async function cryptoGetDID(options: CliOptions): Promise<void> {
|
|
1328
|
+
try {
|
|
1329
|
+
const mnemonic = getMnemonic();
|
|
1330
|
+
const did = await getDIDFromMnemonic(mnemonic);
|
|
1331
|
+
|
|
1332
|
+
if (options.json) {
|
|
1333
|
+
console.log(
|
|
1334
|
+
JSON.stringify(
|
|
1335
|
+
{
|
|
1336
|
+
did: did
|
|
1337
|
+
},
|
|
1338
|
+
null,
|
|
1339
|
+
2
|
|
1340
|
+
)
|
|
1341
|
+
);
|
|
1342
|
+
} else {
|
|
1343
|
+
console.log('🆔 DID:');
|
|
1344
|
+
console.log(` ${did}`);
|
|
1345
|
+
}
|
|
1346
|
+
} catch (error) {
|
|
1347
|
+
console.error('❌ Failed:', error);
|
|
1348
|
+
if (error instanceof Error) {
|
|
1349
|
+
console.error(' Message:', error.message);
|
|
1350
|
+
}
|
|
1351
|
+
process.exit(1);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
/**
|
|
1356
|
+
* Crypto utility: Get EVM private key from mnemonic
|
|
1357
|
+
*/
|
|
1358
|
+
async function cryptoGetPrivateKey(options: CliOptions): Promise<void> {
|
|
1359
|
+
try {
|
|
1360
|
+
const mnemonic = getMnemonic();
|
|
1361
|
+
const privateKey = await getEVMPrivateKeyFromMnemonic(mnemonic);
|
|
1362
|
+
|
|
1363
|
+
// Save private key to file
|
|
1364
|
+
const outputFile = options.output || './private-key.txt';
|
|
1365
|
+
fs.writeFileSync(outputFile, privateKey, 'utf-8');
|
|
1366
|
+
|
|
1367
|
+
if (options.json) {
|
|
1368
|
+
console.log(
|
|
1369
|
+
JSON.stringify(
|
|
1370
|
+
{
|
|
1371
|
+
savedTo: outputFile
|
|
1372
|
+
},
|
|
1373
|
+
null,
|
|
1374
|
+
2
|
|
1375
|
+
)
|
|
1376
|
+
);
|
|
1377
|
+
} else {
|
|
1378
|
+
console.log('🔑 EVM Private Key generated');
|
|
1379
|
+
console.log(`📄 Private key saved to: ${outputFile}`);
|
|
1380
|
+
console.log('\n⚠️ SECURITY WARNING:');
|
|
1381
|
+
console.log(' • Keep this private key secure! Never share it!');
|
|
1382
|
+
console.log(
|
|
1383
|
+
' • Delete the file after copying to a secure location'
|
|
1384
|
+
);
|
|
1385
|
+
console.log(` • Command: rm ${outputFile}`);
|
|
1386
|
+
}
|
|
1387
|
+
} catch (error) {
|
|
1388
|
+
console.error('❌ Failed:', error);
|
|
1389
|
+
if (error instanceof Error) {
|
|
1390
|
+
console.error(' Message:', error.message);
|
|
1391
|
+
}
|
|
1392
|
+
process.exit(1);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
/**
|
|
1397
|
+
* Crypto utility: Derive all keys from mnemonic
|
|
1398
|
+
*/
|
|
1399
|
+
async function cryptoDerive(options: CliOptions): Promise<void> {
|
|
1400
|
+
try {
|
|
1401
|
+
const mnemonic = getMnemonic();
|
|
1402
|
+
const { owner, did } = await deriveDIDFromMnemonic(mnemonic);
|
|
1403
|
+
const privateKey = await getEVMPrivateKeyFromMnemonic(mnemonic);
|
|
1404
|
+
|
|
1405
|
+
// Save all keys to file
|
|
1406
|
+
const outputFile = options.output || './derived-keys.txt';
|
|
1407
|
+
const fileContent = `Ethereum Address: ${owner}\nDID: ${did}\nPrivate Key: ${privateKey}`;
|
|
1408
|
+
fs.writeFileSync(outputFile, fileContent, 'utf-8');
|
|
1409
|
+
|
|
1410
|
+
if (options.json) {
|
|
1411
|
+
console.log(
|
|
1412
|
+
JSON.stringify(
|
|
1413
|
+
{
|
|
1414
|
+
address: owner,
|
|
1415
|
+
did: did,
|
|
1416
|
+
savedTo: outputFile
|
|
1417
|
+
},
|
|
1418
|
+
null,
|
|
1419
|
+
2
|
|
1420
|
+
)
|
|
1421
|
+
);
|
|
1422
|
+
} else {
|
|
1423
|
+
console.log('🔐 Derived Keys:');
|
|
1424
|
+
console.log(' Address:', owner);
|
|
1425
|
+
console.log(' DID:', did);
|
|
1426
|
+
console.log(`\n📄 All keys saved to: ${outputFile}`);
|
|
1427
|
+
console.log('\n⚠️ SECURITY WARNING:');
|
|
1428
|
+
console.log(' • Keep these credentials secure! Never share them!');
|
|
1429
|
+
console.log(
|
|
1430
|
+
' • Private key included in file - handle with extreme care!'
|
|
1431
|
+
);
|
|
1432
|
+
console.log(
|
|
1433
|
+
' • Delete the file after copying to a secure location'
|
|
1434
|
+
);
|
|
1435
|
+
console.log(` • Command: rm ${outputFile}`);
|
|
1436
|
+
}
|
|
1437
|
+
} catch (error) {
|
|
1438
|
+
console.error('❌ Failed:', error);
|
|
1439
|
+
if (error instanceof Error) {
|
|
1440
|
+
console.error(' Message:', error.message);
|
|
1441
|
+
}
|
|
1442
|
+
process.exit(1);
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
// ============================================================================
|
|
1447
|
+
// Wallet Management Commands
|
|
1448
|
+
// ============================================================================
|
|
1449
|
+
|
|
1450
|
+
async function walletEvm(
|
|
1451
|
+
action: string,
|
|
1452
|
+
domain: string,
|
|
1453
|
+
options: CliOptions
|
|
1454
|
+
): Promise<void> {
|
|
1455
|
+
try {
|
|
1456
|
+
const didConsole = getConsole(options);
|
|
1457
|
+
const domainContext = didConsole.domain(domain);
|
|
1458
|
+
|
|
1459
|
+
switch (action) {
|
|
1460
|
+
case 'add': {
|
|
1461
|
+
const evmPrivateKey = process.env.EVM_PRIVATE_KEY;
|
|
1462
|
+
if (!evmPrivateKey) {
|
|
1463
|
+
console.error(
|
|
1464
|
+
'❌ Error: EVM_PRIVATE_KEY environment variable is required'
|
|
1465
|
+
);
|
|
1466
|
+
console.error(
|
|
1467
|
+
' Set it with: export EVM_PRIVATE_KEY="0x..."'
|
|
1468
|
+
);
|
|
1469
|
+
process.exit(1);
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
1473
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
1474
|
+
|
|
1475
|
+
console.log(`\n💼 Adding EVM wallet to domain: ${domain}`);
|
|
1476
|
+
const result = await domainContext.addEVMWallet(evmPrivateKey);
|
|
1477
|
+
|
|
1478
|
+
if (result.success) {
|
|
1479
|
+
if (options.json) {
|
|
1480
|
+
console.log(
|
|
1481
|
+
JSON.stringify(
|
|
1482
|
+
{
|
|
1483
|
+
success: true,
|
|
1484
|
+
domain,
|
|
1485
|
+
address: result.data?.address,
|
|
1486
|
+
transactionHash: result.transactionHash,
|
|
1487
|
+
gasUsed: result.gasUsed?.toString(),
|
|
1488
|
+
blockNumber: result.blockNumber
|
|
1489
|
+
},
|
|
1490
|
+
null,
|
|
1491
|
+
2
|
|
1492
|
+
)
|
|
1493
|
+
);
|
|
1494
|
+
} else {
|
|
1495
|
+
console.log(`\n✅ EVM wallet added successfully!`);
|
|
1496
|
+
console.log(` Address: ${result.data?.address}`);
|
|
1497
|
+
console.log(
|
|
1498
|
+
` Transaction: ${result.transactionHash}`
|
|
1499
|
+
);
|
|
1500
|
+
console.log(
|
|
1501
|
+
` Gas used: ${result.gasUsed?.toString()}`
|
|
1502
|
+
);
|
|
1503
|
+
}
|
|
1504
|
+
} else {
|
|
1505
|
+
console.error(`\n❌ Failed: ${result.error}`);
|
|
1506
|
+
process.exit(1);
|
|
1507
|
+
}
|
|
1508
|
+
break;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
case 'remove': {
|
|
1512
|
+
const evmPrivateKey = process.env.EVM_PRIVATE_KEY;
|
|
1513
|
+
if (!evmPrivateKey) {
|
|
1514
|
+
console.error(
|
|
1515
|
+
'❌ Error: EVM_PRIVATE_KEY environment variable is required'
|
|
1516
|
+
);
|
|
1517
|
+
console.error(
|
|
1518
|
+
' Set it with: export EVM_PRIVATE_KEY="0x..."'
|
|
1519
|
+
);
|
|
1520
|
+
process.exit(1);
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
1524
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
1525
|
+
|
|
1526
|
+
console.log(`\n🗑️ Removing EVM wallet from domain: ${domain}`);
|
|
1527
|
+
const result = await domainContext.removeEVMWallet(
|
|
1528
|
+
evmPrivateKey
|
|
1529
|
+
);
|
|
1530
|
+
|
|
1531
|
+
if (result.success) {
|
|
1532
|
+
if (options.json) {
|
|
1533
|
+
console.log(
|
|
1534
|
+
JSON.stringify(
|
|
1535
|
+
{
|
|
1536
|
+
success: true,
|
|
1537
|
+
domain,
|
|
1538
|
+
address: result.data?.address,
|
|
1539
|
+
transactionHash: result.transactionHash,
|
|
1540
|
+
gasUsed: result.gasUsed?.toString(),
|
|
1541
|
+
blockNumber: result.blockNumber
|
|
1542
|
+
},
|
|
1543
|
+
null,
|
|
1544
|
+
2
|
|
1545
|
+
)
|
|
1546
|
+
);
|
|
1547
|
+
} else {
|
|
1548
|
+
console.log(`\n✅ EVM wallet removed successfully!`);
|
|
1549
|
+
console.log(` Address: ${result.data?.address}`);
|
|
1550
|
+
console.log(
|
|
1551
|
+
` Transaction: ${result.transactionHash}`
|
|
1552
|
+
);
|
|
1553
|
+
}
|
|
1554
|
+
} else {
|
|
1555
|
+
console.error(`\n❌ Failed: ${result.error}`);
|
|
1556
|
+
process.exit(1);
|
|
1557
|
+
}
|
|
1558
|
+
break;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
case 'list': {
|
|
1562
|
+
console.log(`\n📋 Listing EVM wallets for domain: ${domain}`);
|
|
1563
|
+
const wallets = await domainContext.getEVMWallets();
|
|
1564
|
+
|
|
1565
|
+
if (options.json) {
|
|
1566
|
+
console.log(
|
|
1567
|
+
JSON.stringify(
|
|
1568
|
+
{
|
|
1569
|
+
domain,
|
|
1570
|
+
wallets,
|
|
1571
|
+
count: wallets.length
|
|
1572
|
+
},
|
|
1573
|
+
null,
|
|
1574
|
+
2
|
|
1575
|
+
)
|
|
1576
|
+
);
|
|
1577
|
+
} else {
|
|
1578
|
+
if (wallets.length === 0) {
|
|
1579
|
+
console.log(` No EVM wallets found`);
|
|
1580
|
+
} else {
|
|
1581
|
+
console.log(` Found ${wallets.length} wallet(s):`);
|
|
1582
|
+
wallets.forEach((addr, i) => {
|
|
1583
|
+
console.log(` ${i + 1}. ${addr}`);
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
break;
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
default:
|
|
1591
|
+
console.error(`❌ Unknown action: ${action}`);
|
|
1592
|
+
console.error(' Valid actions: add, remove, list');
|
|
1593
|
+
process.exit(1);
|
|
1594
|
+
}
|
|
1595
|
+
} catch (error) {
|
|
1596
|
+
console.error(
|
|
1597
|
+
'❌ Error:',
|
|
1598
|
+
error instanceof Error ? error.message : String(error)
|
|
1599
|
+
);
|
|
1600
|
+
process.exit(1);
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
async function walletSolana(
|
|
1605
|
+
action: string,
|
|
1606
|
+
domain: string,
|
|
1607
|
+
options: CliOptions
|
|
1608
|
+
): Promise<void> {
|
|
1609
|
+
try {
|
|
1610
|
+
const didConsole = getConsole(options);
|
|
1611
|
+
const domainContext = didConsole.domain(domain);
|
|
1612
|
+
|
|
1613
|
+
switch (action) {
|
|
1614
|
+
case 'add': {
|
|
1615
|
+
const solanaPrivateKey = process.env.SOLANA_PRIVATE_KEY;
|
|
1616
|
+
if (!solanaPrivateKey) {
|
|
1617
|
+
console.error(
|
|
1618
|
+
'❌ Error: SOLANA_PRIVATE_KEY environment variable is required'
|
|
1619
|
+
);
|
|
1620
|
+
console.error(
|
|
1621
|
+
' Set it with: export SOLANA_PRIVATE_KEY="[1,2,3,...]"'
|
|
1622
|
+
);
|
|
1623
|
+
console.error(
|
|
1624
|
+
' Or: export SOLANA_PRIVATE_KEY="base58string"'
|
|
1625
|
+
);
|
|
1626
|
+
process.exit(1);
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
1630
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
1631
|
+
|
|
1632
|
+
console.log(`\n💼 Adding Solana wallet to domain: ${domain}`);
|
|
1633
|
+
const result = await domainContext.addSolanaWallet(
|
|
1634
|
+
solanaPrivateKey
|
|
1635
|
+
);
|
|
1636
|
+
|
|
1637
|
+
if (result.success) {
|
|
1638
|
+
if (options.json) {
|
|
1639
|
+
console.log(
|
|
1640
|
+
JSON.stringify(
|
|
1641
|
+
{
|
|
1642
|
+
success: true,
|
|
1643
|
+
domain,
|
|
1644
|
+
address: result.data?.address,
|
|
1645
|
+
addressHex: result.data?.addressHex,
|
|
1646
|
+
transactionHash: result.transactionHash,
|
|
1647
|
+
gasUsed: result.gasUsed?.toString(),
|
|
1648
|
+
blockNumber: result.blockNumber
|
|
1649
|
+
},
|
|
1650
|
+
null,
|
|
1651
|
+
2
|
|
1652
|
+
)
|
|
1653
|
+
);
|
|
1654
|
+
} else {
|
|
1655
|
+
console.log(`\n✅ Solana wallet added successfully!`);
|
|
1656
|
+
console.log(` Address: ${result.data?.address}`);
|
|
1657
|
+
console.log(
|
|
1658
|
+
` Transaction: ${result.transactionHash}`
|
|
1659
|
+
);
|
|
1660
|
+
console.log(
|
|
1661
|
+
` Gas used: ${result.gasUsed?.toString()}`
|
|
1662
|
+
);
|
|
1663
|
+
}
|
|
1664
|
+
} else {
|
|
1665
|
+
console.error(`\n❌ Failed: ${result.error}`);
|
|
1666
|
+
process.exit(1);
|
|
1667
|
+
}
|
|
1668
|
+
break;
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
case 'remove': {
|
|
1672
|
+
const solanaPrivateKey = process.env.SOLANA_PRIVATE_KEY;
|
|
1673
|
+
if (!solanaPrivateKey) {
|
|
1674
|
+
console.error(
|
|
1675
|
+
'❌ Error: SOLANA_PRIVATE_KEY environment variable is required'
|
|
1676
|
+
);
|
|
1677
|
+
console.error(
|
|
1678
|
+
' Set it with: export SOLANA_PRIVATE_KEY="[1,2,3,...]"'
|
|
1679
|
+
);
|
|
1680
|
+
console.error(
|
|
1681
|
+
' Or: export SOLANA_PRIVATE_KEY="base58string"'
|
|
1682
|
+
);
|
|
1683
|
+
process.exit(1);
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
1687
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
1688
|
+
|
|
1689
|
+
console.log(
|
|
1690
|
+
`\n🗑️ Removing Solana wallet from domain: ${domain}`
|
|
1691
|
+
);
|
|
1692
|
+
const result = await domainContext.removeSolanaWallet(
|
|
1693
|
+
solanaPrivateKey
|
|
1694
|
+
);
|
|
1695
|
+
|
|
1696
|
+
if (result.success) {
|
|
1697
|
+
if (options.json) {
|
|
1698
|
+
console.log(
|
|
1699
|
+
JSON.stringify(
|
|
1700
|
+
{
|
|
1701
|
+
success: true,
|
|
1702
|
+
domain,
|
|
1703
|
+
address: result.data?.address,
|
|
1704
|
+
addressHex: result.data?.addressHex,
|
|
1705
|
+
transactionHash: result.transactionHash,
|
|
1706
|
+
gasUsed: result.gasUsed?.toString(),
|
|
1707
|
+
blockNumber: result.blockNumber
|
|
1708
|
+
},
|
|
1709
|
+
null,
|
|
1710
|
+
2
|
|
1711
|
+
)
|
|
1712
|
+
);
|
|
1713
|
+
} else {
|
|
1714
|
+
console.log(`\n✅ Solana wallet removed successfully!`);
|
|
1715
|
+
console.log(` Address: ${result.data?.address}`);
|
|
1716
|
+
console.log(
|
|
1717
|
+
` Transaction: ${result.transactionHash}`
|
|
1718
|
+
);
|
|
1719
|
+
}
|
|
1720
|
+
} else {
|
|
1721
|
+
console.error(`\n❌ Failed: ${result.error}`);
|
|
1722
|
+
process.exit(1);
|
|
1723
|
+
}
|
|
1724
|
+
break;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
case 'list': {
|
|
1728
|
+
console.log(
|
|
1729
|
+
`\n📋 Listing Solana wallets for domain: ${domain}`
|
|
1730
|
+
);
|
|
1731
|
+
const wallets = await domainContext.getSolanaWallets();
|
|
1732
|
+
|
|
1733
|
+
if (options.json) {
|
|
1734
|
+
console.log(
|
|
1735
|
+
JSON.stringify(
|
|
1736
|
+
{
|
|
1737
|
+
domain,
|
|
1738
|
+
wallets,
|
|
1739
|
+
count: wallets.length
|
|
1740
|
+
},
|
|
1741
|
+
null,
|
|
1742
|
+
2
|
|
1743
|
+
)
|
|
1744
|
+
);
|
|
1745
|
+
} else {
|
|
1746
|
+
if (wallets.length === 0) {
|
|
1747
|
+
console.log(` No Solana wallets found`);
|
|
1748
|
+
} else {
|
|
1749
|
+
console.log(` Found ${wallets.length} wallet(s):`);
|
|
1750
|
+
wallets.forEach((addr, i) => {
|
|
1751
|
+
console.log(` ${i + 1}. ${addr}`);
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
break;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
default:
|
|
1759
|
+
console.error(`❌ Unknown action: ${action}`);
|
|
1760
|
+
console.error(' Valid actions: add, remove, list');
|
|
1761
|
+
process.exit(1);
|
|
1762
|
+
}
|
|
1763
|
+
} catch (error) {
|
|
1764
|
+
console.error(
|
|
1765
|
+
'❌ Error:',
|
|
1766
|
+
error instanceof Error ? error.message : String(error)
|
|
1767
|
+
);
|
|
1768
|
+
process.exit(1);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
// ========================================
|
|
1773
|
+
// Tag Management Functions
|
|
1774
|
+
// ========================================
|
|
1775
|
+
|
|
1776
|
+
/**
|
|
1777
|
+
* Define a simple tag type
|
|
1778
|
+
*/
|
|
1779
|
+
async function tagDefine(
|
|
1780
|
+
domain: string,
|
|
1781
|
+
tagName: string,
|
|
1782
|
+
typeString: string,
|
|
1783
|
+
options: CliOptions
|
|
1784
|
+
): Promise<void> {
|
|
1785
|
+
try {
|
|
1786
|
+
const didConsole = getConsole(options);
|
|
1787
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
1788
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
1789
|
+
|
|
1790
|
+
const domainContext = didConsole.domain(domain);
|
|
1791
|
+
const tagCtx = domainContext.tag();
|
|
1792
|
+
|
|
1793
|
+
console.log(`\n📝 Defining tag "${tagName}" for domain: ${domain}`);
|
|
1794
|
+
console.log(` Type: ${typeString}`);
|
|
1795
|
+
|
|
1796
|
+
// Parse type string and create TagTypeBuilder
|
|
1797
|
+
let tagType: TagTypeBuilder;
|
|
1798
|
+
|
|
1799
|
+
// Support simple types: string, uint8, uint256, int8, int256, bool, address, bytes, bytes32
|
|
1800
|
+
// Match pattern: (type)(size)(array)?
|
|
1801
|
+
// Examples: uint8, string[], bytes32[]
|
|
1802
|
+
const match = typeString.match(
|
|
1803
|
+
/^(uint|int|bytes|string|bool|address)(\d*)(\[\])?$/
|
|
1804
|
+
);
|
|
1805
|
+
if (!match) {
|
|
1806
|
+
throw new Error(
|
|
1807
|
+
`Invalid type string: ${typeString}. Supported: string, uint8, uint256, int8, int256, bool, address, bytes, bytes32, and arrays (e.g., string[], uint8[])`
|
|
1808
|
+
);
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
const [, baseType, size, isArray] = match;
|
|
1812
|
+
|
|
1813
|
+
// Create base type
|
|
1814
|
+
switch (baseType) {
|
|
1815
|
+
case 'string':
|
|
1816
|
+
tagType = TagTypeBuilder.string();
|
|
1817
|
+
break;
|
|
1818
|
+
case 'uint':
|
|
1819
|
+
const uintSize = size ? parseInt(size) : 256;
|
|
1820
|
+
tagType = TagTypeBuilder.uint(uintSize);
|
|
1821
|
+
break;
|
|
1822
|
+
case 'int':
|
|
1823
|
+
const intSize = size ? parseInt(size) : 256;
|
|
1824
|
+
tagType = TagTypeBuilder.int(intSize);
|
|
1825
|
+
break;
|
|
1826
|
+
case 'bool':
|
|
1827
|
+
tagType = TagTypeBuilder.bool();
|
|
1828
|
+
break;
|
|
1829
|
+
case 'address':
|
|
1830
|
+
tagType = TagTypeBuilder.address();
|
|
1831
|
+
break;
|
|
1832
|
+
case 'bytes':
|
|
1833
|
+
if (size) {
|
|
1834
|
+
const bytesSize = parseInt(size);
|
|
1835
|
+
tagType = TagTypeBuilder.fixedBytes(bytesSize);
|
|
1836
|
+
} else {
|
|
1837
|
+
tagType = TagTypeBuilder.bytes();
|
|
1838
|
+
}
|
|
1839
|
+
break;
|
|
1840
|
+
default:
|
|
1841
|
+
throw new Error(`Unsupported type: ${baseType}`);
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
// Wrap in array if needed
|
|
1845
|
+
if (isArray) {
|
|
1846
|
+
tagType = TagTypeBuilder.array(tagType);
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
const result = await tagCtx.defineTag(tagName, tagType);
|
|
1850
|
+
|
|
1851
|
+
if (result.success) {
|
|
1852
|
+
if (options.json) {
|
|
1853
|
+
console.log(
|
|
1854
|
+
JSON.stringify(
|
|
1855
|
+
{
|
|
1856
|
+
success: true,
|
|
1857
|
+
domain,
|
|
1858
|
+
tagName,
|
|
1859
|
+
type: typeString,
|
|
1860
|
+
transactionHash: result.transactionHash,
|
|
1861
|
+
gasUsed: result.gasUsed?.toString(),
|
|
1862
|
+
blockNumber: result.blockNumber
|
|
1863
|
+
},
|
|
1864
|
+
null,
|
|
1865
|
+
2
|
|
1866
|
+
)
|
|
1867
|
+
);
|
|
1868
|
+
} else {
|
|
1869
|
+
console.log(`\n✅ Tag "${tagName}" defined successfully`);
|
|
1870
|
+
console.log(` Transaction: ${result.transactionHash}`);
|
|
1871
|
+
if (options.verbose) {
|
|
1872
|
+
console.log(` Block: ${result.blockNumber}`);
|
|
1873
|
+
console.log(` Gas used: ${result.gasUsed?.toString()}`);
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
} else {
|
|
1877
|
+
console.error(`\n❌ Failed to define tag`);
|
|
1878
|
+
process.exit(1);
|
|
1879
|
+
}
|
|
1880
|
+
} catch (error) {
|
|
1881
|
+
console.error(
|
|
1882
|
+
'❌ Error:',
|
|
1883
|
+
error instanceof Error ? error.message : String(error)
|
|
1884
|
+
);
|
|
1885
|
+
process.exit(1);
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
/**
|
|
1890
|
+
* Set tag value
|
|
1891
|
+
*/
|
|
1892
|
+
async function tagSet(
|
|
1893
|
+
domain: string,
|
|
1894
|
+
tagName: string,
|
|
1895
|
+
valueStr: string,
|
|
1896
|
+
options: CliOptions
|
|
1897
|
+
): Promise<void> {
|
|
1898
|
+
try {
|
|
1899
|
+
const didConsole = getConsole(options);
|
|
1900
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
1901
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
1902
|
+
|
|
1903
|
+
const domainContext = didConsole.domain(domain);
|
|
1904
|
+
const tagCtx = domainContext.tag();
|
|
1905
|
+
|
|
1906
|
+
console.log(`\n📝 Setting tag "${tagName}" for domain: ${domain}`);
|
|
1907
|
+
console.log(` Value: ${valueStr}`);
|
|
1908
|
+
|
|
1909
|
+
// Try to parse value as JSON, otherwise use as string
|
|
1910
|
+
let value: any;
|
|
1911
|
+
try {
|
|
1912
|
+
value = JSON.parse(valueStr);
|
|
1913
|
+
} catch {
|
|
1914
|
+
value = valueStr;
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
const result = await tagCtx.setTag(domain, tagName, value);
|
|
1918
|
+
|
|
1919
|
+
if (result.success) {
|
|
1920
|
+
if (options.json) {
|
|
1921
|
+
console.log(
|
|
1922
|
+
JSON.stringify(
|
|
1923
|
+
{
|
|
1924
|
+
success: true,
|
|
1925
|
+
domain,
|
|
1926
|
+
tagName,
|
|
1927
|
+
value,
|
|
1928
|
+
transactionHash: result.transactionHash,
|
|
1929
|
+
gasUsed: result.gasUsed?.toString(),
|
|
1930
|
+
blockNumber: result.blockNumber
|
|
1931
|
+
},
|
|
1932
|
+
null,
|
|
1933
|
+
2
|
|
1934
|
+
)
|
|
1935
|
+
);
|
|
1936
|
+
} else {
|
|
1937
|
+
console.log(`\n✅ Tag "${tagName}" set successfully`);
|
|
1938
|
+
console.log(` Transaction: ${result.transactionHash}`);
|
|
1939
|
+
if (options.verbose) {
|
|
1940
|
+
console.log(` Block: ${result.blockNumber}`);
|
|
1941
|
+
console.log(` Gas used: ${result.gasUsed?.toString()}`);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
} else {
|
|
1945
|
+
console.error(`\n❌ Failed to set tag`);
|
|
1946
|
+
process.exit(1);
|
|
1947
|
+
}
|
|
1948
|
+
} catch (error) {
|
|
1949
|
+
console.error(
|
|
1950
|
+
'❌ Error:',
|
|
1951
|
+
error instanceof Error ? error.message : String(error)
|
|
1952
|
+
);
|
|
1953
|
+
process.exit(1);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
/**
|
|
1958
|
+
* Get tag value
|
|
1959
|
+
*/
|
|
1960
|
+
async function tagGet(
|
|
1961
|
+
domain: string,
|
|
1962
|
+
tagName: string,
|
|
1963
|
+
options: CliOptions
|
|
1964
|
+
): Promise<void> {
|
|
1965
|
+
try {
|
|
1966
|
+
const didConsole = getConsole(options);
|
|
1967
|
+
const domainContext = didConsole.domain(domain);
|
|
1968
|
+
const tagCtx = domainContext.tag();
|
|
1969
|
+
|
|
1970
|
+
console.log(`\n📖 Getting tag "${tagName}" for domain: ${domain}`);
|
|
1971
|
+
|
|
1972
|
+
const value = await tagCtx.getTag(domain, tagName);
|
|
1973
|
+
|
|
1974
|
+
if (value !== null && value !== undefined) {
|
|
1975
|
+
if (options.json) {
|
|
1976
|
+
console.log(
|
|
1977
|
+
JSON.stringify(
|
|
1978
|
+
{
|
|
1979
|
+
success: true,
|
|
1980
|
+
domain,
|
|
1981
|
+
tagName,
|
|
1982
|
+
value
|
|
1983
|
+
},
|
|
1984
|
+
(_, v) => (typeof v === 'bigint' ? v.toString() : v),
|
|
1985
|
+
2
|
|
1986
|
+
)
|
|
1987
|
+
);
|
|
1988
|
+
} else {
|
|
1989
|
+
console.log(`\n✅ Tag value:`);
|
|
1990
|
+
if (typeof value === 'object') {
|
|
1991
|
+
console.log(
|
|
1992
|
+
` ${JSON.stringify(
|
|
1993
|
+
value,
|
|
1994
|
+
(_, v) =>
|
|
1995
|
+
typeof v === 'bigint' ? v.toString() : v,
|
|
1996
|
+
2
|
|
1997
|
+
)}`
|
|
1998
|
+
);
|
|
1999
|
+
} else {
|
|
2000
|
+
console.log(` ${value}`);
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
} else {
|
|
2004
|
+
if (options.json) {
|
|
2005
|
+
console.log(
|
|
2006
|
+
JSON.stringify({
|
|
2007
|
+
success: true,
|
|
2008
|
+
domain,
|
|
2009
|
+
tagName,
|
|
2010
|
+
value: null
|
|
2011
|
+
})
|
|
2012
|
+
);
|
|
2013
|
+
} else {
|
|
2014
|
+
console.log(
|
|
2015
|
+
`\n Tag "${tagName}" has no value (or does not exist)`
|
|
2016
|
+
);
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
} catch (error) {
|
|
2020
|
+
console.error(
|
|
2021
|
+
'❌ Error:',
|
|
2022
|
+
error instanceof Error ? error.message : String(error)
|
|
2023
|
+
);
|
|
2024
|
+
process.exit(1);
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
/**
|
|
2029
|
+
* Remove tag value
|
|
2030
|
+
*/
|
|
2031
|
+
async function tagRemove(
|
|
2032
|
+
domain: string,
|
|
2033
|
+
tagName: string,
|
|
2034
|
+
options: CliOptions
|
|
2035
|
+
): Promise<void> {
|
|
2036
|
+
try {
|
|
2037
|
+
const didConsole = getConsole(options);
|
|
2038
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
2039
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
2040
|
+
|
|
2041
|
+
const domainContext = didConsole.domain(domain);
|
|
2042
|
+
const tagCtx = domainContext.tag();
|
|
2043
|
+
|
|
2044
|
+
console.log(`\n🗑️ Removing tag "${tagName}" for domain: ${domain}`);
|
|
2045
|
+
|
|
2046
|
+
const result = await tagCtx.removeTag(domain, tagName);
|
|
2047
|
+
|
|
2048
|
+
if (result.success) {
|
|
2049
|
+
if (options.json) {
|
|
2050
|
+
console.log(
|
|
2051
|
+
JSON.stringify(
|
|
2052
|
+
{
|
|
2053
|
+
success: true,
|
|
2054
|
+
domain,
|
|
2055
|
+
tagName,
|
|
2056
|
+
transactionHash: result.transactionHash,
|
|
2057
|
+
gasUsed: result.gasUsed?.toString(),
|
|
2058
|
+
blockNumber: result.blockNumber
|
|
2059
|
+
},
|
|
2060
|
+
null,
|
|
2061
|
+
2
|
|
2062
|
+
)
|
|
2063
|
+
);
|
|
2064
|
+
} else {
|
|
2065
|
+
console.log(`\n✅ Tag "${tagName}" value removed successfully`);
|
|
2066
|
+
console.log(` Transaction: ${result.transactionHash}`);
|
|
2067
|
+
if (options.verbose) {
|
|
2068
|
+
console.log(` Block: ${result.blockNumber}`);
|
|
2069
|
+
console.log(` Gas used: ${result.gasUsed?.toString()}`);
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
} else {
|
|
2073
|
+
console.error(`\n❌ Failed to remove tag`);
|
|
2074
|
+
process.exit(1);
|
|
2075
|
+
}
|
|
2076
|
+
} catch (error) {
|
|
2077
|
+
console.error(
|
|
2078
|
+
'❌ Error:',
|
|
2079
|
+
error instanceof Error ? error.message : String(error)
|
|
2080
|
+
);
|
|
2081
|
+
process.exit(1);
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
/**
|
|
2086
|
+
* List all tags for a domain
|
|
2087
|
+
*/
|
|
2088
|
+
async function tagList(domain: string, options: CliOptions): Promise<void> {
|
|
2089
|
+
try {
|
|
2090
|
+
const didConsole = getConsole(options);
|
|
2091
|
+
const domainContext = didConsole.domain(domain);
|
|
2092
|
+
|
|
2093
|
+
console.log(`\n📋 Listing all tags for domain: ${domain}`);
|
|
2094
|
+
|
|
2095
|
+
const tags = await domainContext.getAllTags();
|
|
2096
|
+
|
|
2097
|
+
if (options.json) {
|
|
2098
|
+
console.log(
|
|
2099
|
+
JSON.stringify(
|
|
2100
|
+
{
|
|
2101
|
+
success: true,
|
|
2102
|
+
domain,
|
|
2103
|
+
count: tags.length,
|
|
2104
|
+
tags
|
|
2105
|
+
},
|
|
2106
|
+
(_, v) => (typeof v === 'bigint' ? v.toString() : v),
|
|
2107
|
+
2
|
|
2108
|
+
)
|
|
2109
|
+
);
|
|
2110
|
+
} else {
|
|
2111
|
+
console.log(`\n✅ Found ${tags.length} tags:\n`);
|
|
2112
|
+
for (const tag of tags) {
|
|
2113
|
+
console.log(` Tag: "${tag.name}"`);
|
|
2114
|
+
if (typeof tag.value === 'object' && tag.value !== null) {
|
|
2115
|
+
console.log(
|
|
2116
|
+
` Value: ${JSON.stringify(tag.value, (_, v) =>
|
|
2117
|
+
typeof v === 'bigint' ? v.toString() : v
|
|
2118
|
+
)}`
|
|
2119
|
+
);
|
|
2120
|
+
} else {
|
|
2121
|
+
console.log(` Value: ${tag.value}`);
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
} catch (error) {
|
|
2126
|
+
console.error(
|
|
2127
|
+
'❌ Error:',
|
|
2128
|
+
error instanceof Error ? error.message : String(error)
|
|
2129
|
+
);
|
|
2130
|
+
process.exit(1);
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
/**
|
|
2135
|
+
* List all defined tag types for a domain
|
|
2136
|
+
*/
|
|
2137
|
+
async function tagListDefined(
|
|
2138
|
+
domain: string,
|
|
2139
|
+
options: CliOptions
|
|
2140
|
+
): Promise<void> {
|
|
2141
|
+
try {
|
|
2142
|
+
const didConsole = getConsole(options);
|
|
2143
|
+
const domainContext = didConsole.domain(domain);
|
|
2144
|
+
|
|
2145
|
+
console.log(`\n📋 Listing defined tag types for domain: ${domain}`);
|
|
2146
|
+
|
|
2147
|
+
const tags = await domainContext.getDefinedTags();
|
|
2148
|
+
|
|
2149
|
+
if (options.json) {
|
|
2150
|
+
console.log(
|
|
2151
|
+
JSON.stringify(
|
|
2152
|
+
{
|
|
2153
|
+
success: true,
|
|
2154
|
+
domain,
|
|
2155
|
+
count: tags.length,
|
|
2156
|
+
tags
|
|
2157
|
+
},
|
|
2158
|
+
null,
|
|
2159
|
+
2
|
|
2160
|
+
)
|
|
2161
|
+
);
|
|
2162
|
+
} else {
|
|
2163
|
+
console.log(`\n✅ Found ${tags.length} defined tag types:\n`);
|
|
2164
|
+
for (const tagName of tags) {
|
|
2165
|
+
console.log(` - ${tagName}`);
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
} catch (error) {
|
|
2169
|
+
console.error(
|
|
2170
|
+
'❌ Error:',
|
|
2171
|
+
error instanceof Error ? error.message : String(error)
|
|
2172
|
+
);
|
|
2173
|
+
process.exit(1);
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
/**
|
|
2178
|
+
* Set tagger for a tag
|
|
2179
|
+
*/
|
|
2180
|
+
async function tagSetTagger(
|
|
2181
|
+
domain: string,
|
|
2182
|
+
tagName: string,
|
|
2183
|
+
taggerAddress: string,
|
|
2184
|
+
options: CliOptions
|
|
2185
|
+
): Promise<void> {
|
|
2186
|
+
try {
|
|
2187
|
+
const didConsole = getConsole(options);
|
|
2188
|
+
const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
|
|
2189
|
+
await didConsole.setSigner(privateKeyOrMnemonic);
|
|
2190
|
+
|
|
2191
|
+
const domainContext = didConsole.domain(domain);
|
|
2192
|
+
|
|
2193
|
+
console.log(
|
|
2194
|
+
`\n🔐 Setting tagger for tag "${tagName}" in domain: ${domain}`
|
|
2195
|
+
);
|
|
2196
|
+
console.log(` Tagger address: ${taggerAddress}`);
|
|
2197
|
+
|
|
2198
|
+
const result = await domainContext.setTagger(tagName, taggerAddress);
|
|
2199
|
+
|
|
2200
|
+
if (result.success) {
|
|
2201
|
+
if (options.json) {
|
|
2202
|
+
console.log(
|
|
2203
|
+
JSON.stringify(
|
|
2204
|
+
{
|
|
2205
|
+
success: true,
|
|
2206
|
+
domain,
|
|
2207
|
+
tagName,
|
|
2208
|
+
taggerAddress,
|
|
2209
|
+
transactionHash: result.transactionHash,
|
|
2210
|
+
gasUsed: result.gasUsed?.toString(),
|
|
2211
|
+
blockNumber: result.blockNumber
|
|
2212
|
+
},
|
|
2213
|
+
null,
|
|
2214
|
+
2
|
|
2215
|
+
)
|
|
2216
|
+
);
|
|
2217
|
+
} else {
|
|
2218
|
+
console.log(`\n✅ Tagger set successfully`);
|
|
2219
|
+
console.log(` Transaction: ${result.transactionHash}`);
|
|
2220
|
+
if (options.verbose) {
|
|
2221
|
+
console.log(` Block: ${result.blockNumber}`);
|
|
2222
|
+
console.log(` Gas used: ${result.gasUsed?.toString()}`);
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
} else {
|
|
2226
|
+
console.error(`\n❌ Failed to set tagger`);
|
|
2227
|
+
process.exit(1);
|
|
2228
|
+
}
|
|
2229
|
+
} catch (error) {
|
|
2230
|
+
console.error(
|
|
2231
|
+
'❌ Error:',
|
|
2232
|
+
error instanceof Error ? error.message : String(error)
|
|
2233
|
+
);
|
|
2234
|
+
process.exit(1);
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
/**
|
|
2239
|
+
* Get tagger for a tag
|
|
2240
|
+
*/
|
|
2241
|
+
async function tagGetTagger(
|
|
2242
|
+
domain: string,
|
|
2243
|
+
tagName: string,
|
|
2244
|
+
options: CliOptions
|
|
2245
|
+
): Promise<void> {
|
|
2246
|
+
try {
|
|
2247
|
+
const didConsole = getConsole(options);
|
|
2248
|
+
const domainContext = didConsole.domain(domain);
|
|
2249
|
+
const tagCtx = domainContext.tag();
|
|
2250
|
+
|
|
2251
|
+
console.log(
|
|
2252
|
+
`\n🔍 Getting tagger for tag "${tagName}" in domain: ${domain}`
|
|
2253
|
+
);
|
|
2254
|
+
|
|
2255
|
+
const taggerAddress = await tagCtx.getTagger(tagName);
|
|
2256
|
+
|
|
2257
|
+
if (options.json) {
|
|
2258
|
+
console.log(
|
|
2259
|
+
JSON.stringify(
|
|
2260
|
+
{
|
|
2261
|
+
success: true,
|
|
2262
|
+
domain,
|
|
2263
|
+
tagName,
|
|
2264
|
+
taggerAddress
|
|
2265
|
+
},
|
|
2266
|
+
null,
|
|
2267
|
+
2
|
|
2268
|
+
)
|
|
2269
|
+
);
|
|
2270
|
+
} else {
|
|
2271
|
+
console.log(`\n✅ Tagger address: ${taggerAddress}`);
|
|
2272
|
+
}
|
|
2273
|
+
} catch (error) {
|
|
2274
|
+
console.error(
|
|
2275
|
+
'❌ Error:',
|
|
2276
|
+
error instanceof Error ? error.message : String(error)
|
|
2277
|
+
);
|
|
2278
|
+
process.exit(1);
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
async function main(): Promise<void> {
|
|
2283
|
+
const parsed = parseArgs();
|
|
2284
|
+
const { command, subCommand, value, options } = parsed;
|
|
2285
|
+
// Support Olares ID format (user@domain.com) by converting to standard domain format
|
|
2286
|
+
const domain = parsed.domain ? normalizeToDomain(parsed.domain) : undefined;
|
|
2287
|
+
|
|
2288
|
+
if (options.help || !command || command === 'help') {
|
|
2289
|
+
showHelp();
|
|
2290
|
+
return;
|
|
2291
|
+
}
|
|
2292
|
+
|
|
2293
|
+
// Set debug options
|
|
2294
|
+
if (options.verbose || options.debug) {
|
|
2295
|
+
debug.enable();
|
|
2296
|
+
debug.setLevel(options.debugLevel as any);
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
try {
|
|
2300
|
+
switch (command) {
|
|
2301
|
+
// Query commands
|
|
2302
|
+
case 'info':
|
|
2303
|
+
if (!domain) {
|
|
2304
|
+
console.error('❌ Error: Domain argument is required');
|
|
2305
|
+
console.error('Usage: did-cli info <domain>');
|
|
2306
|
+
process.exit(1);
|
|
2307
|
+
}
|
|
2308
|
+
await getDomainInfo(domain, options);
|
|
2309
|
+
break;
|
|
2310
|
+
|
|
2311
|
+
case 'owner':
|
|
2312
|
+
if (!domain) {
|
|
2313
|
+
console.error('❌ Error: Domain argument is required');
|
|
2314
|
+
console.error('Usage: did-cli owner <domain>');
|
|
2315
|
+
process.exit(1);
|
|
2316
|
+
}
|
|
2317
|
+
await getDomainOwner(domain, options);
|
|
2318
|
+
break;
|
|
2319
|
+
|
|
2320
|
+
case 'is-owner':
|
|
2321
|
+
if (!domain) {
|
|
2322
|
+
console.error('❌ Error: Domain argument is required');
|
|
2323
|
+
console.error('Usage: did-cli is-owner <domain>');
|
|
2324
|
+
console.error(
|
|
2325
|
+
'Note: Set PRIVATE_KEY_OR_MNEMONIC environment variable first'
|
|
2326
|
+
);
|
|
2327
|
+
process.exit(1);
|
|
2328
|
+
}
|
|
2329
|
+
await checkIsOwner(domain, options);
|
|
2330
|
+
break;
|
|
2331
|
+
|
|
2332
|
+
// Transfer command
|
|
2333
|
+
case 'transfer':
|
|
2334
|
+
if (!domain) {
|
|
2335
|
+
console.error('❌ Error: Domain argument is required');
|
|
2336
|
+
console.error('Usage: did-cli transfer <domain>');
|
|
2337
|
+
console.error('Options: --words 12|24 (default: 12)');
|
|
2338
|
+
console.error(
|
|
2339
|
+
'Note: Set PRIVATE_KEY_OR_MNEMONIC environment variable first'
|
|
2340
|
+
);
|
|
2341
|
+
console.error(
|
|
2342
|
+
'Optional: Set MNEMONIC environment variable for new owner (auto-generates if not set)'
|
|
2343
|
+
);
|
|
2344
|
+
process.exit(1);
|
|
2345
|
+
}
|
|
2346
|
+
await transferDomain(domain, options);
|
|
2347
|
+
break;
|
|
2348
|
+
|
|
2349
|
+
// RSA commands
|
|
2350
|
+
case 'rsa':
|
|
2351
|
+
if (!subCommand) {
|
|
2352
|
+
console.error('❌ Error: RSA subcommand is required');
|
|
2353
|
+
console.error(
|
|
2354
|
+
'Usage: did-cli rsa <generate|get|set|remove> [args]'
|
|
2355
|
+
);
|
|
2356
|
+
process.exit(1);
|
|
2357
|
+
}
|
|
2358
|
+
switch (subCommand) {
|
|
2359
|
+
case 'generate':
|
|
2360
|
+
await generateRsaKey(options);
|
|
2361
|
+
break;
|
|
2362
|
+
case 'get':
|
|
2363
|
+
if (!domain) {
|
|
2364
|
+
console.error(
|
|
2365
|
+
'❌ Error: Domain argument is required'
|
|
2366
|
+
);
|
|
2367
|
+
process.exit(1);
|
|
2368
|
+
}
|
|
2369
|
+
await getRsaKey(domain, options);
|
|
2370
|
+
break;
|
|
2371
|
+
case 'set':
|
|
2372
|
+
if (!domain || !value) {
|
|
2373
|
+
console.error(
|
|
2374
|
+
'❌ Error: Domain and PEM file path are required'
|
|
2375
|
+
);
|
|
2376
|
+
console.error(
|
|
2377
|
+
'Usage: did-cli rsa set <domain> <pem-file>'
|
|
2378
|
+
);
|
|
2379
|
+
console.error(
|
|
2380
|
+
'Note: Set PRIVATE_KEY_OR_MNEMONIC environment variable first'
|
|
2381
|
+
);
|
|
2382
|
+
process.exit(1);
|
|
2383
|
+
}
|
|
2384
|
+
await setRsaKey(domain, value, options);
|
|
2385
|
+
break;
|
|
2386
|
+
case 'remove':
|
|
2387
|
+
if (!domain) {
|
|
2388
|
+
console.error(
|
|
2389
|
+
'❌ Error: Domain argument is required'
|
|
2390
|
+
);
|
|
2391
|
+
process.exit(1);
|
|
2392
|
+
}
|
|
2393
|
+
await removeRsaKey(domain, options);
|
|
2394
|
+
break;
|
|
2395
|
+
default:
|
|
2396
|
+
console.error(
|
|
2397
|
+
`❌ Unknown RSA subcommand: ${subCommand}`
|
|
2398
|
+
);
|
|
2399
|
+
process.exit(1);
|
|
2400
|
+
}
|
|
2401
|
+
break;
|
|
2402
|
+
|
|
2403
|
+
// IP commands
|
|
2404
|
+
case 'ip':
|
|
2405
|
+
if (!subCommand) {
|
|
2406
|
+
console.error('❌ Error: IP subcommand is required');
|
|
2407
|
+
console.error('Usage: did-cli ip <get|set|remove> [args]');
|
|
2408
|
+
process.exit(1);
|
|
2409
|
+
}
|
|
2410
|
+
switch (subCommand) {
|
|
2411
|
+
case 'get':
|
|
2412
|
+
if (!domain) {
|
|
2413
|
+
console.error(
|
|
2414
|
+
'❌ Error: Domain argument is required'
|
|
2415
|
+
);
|
|
2416
|
+
process.exit(1);
|
|
2417
|
+
}
|
|
2418
|
+
await getIP(domain, options);
|
|
2419
|
+
break;
|
|
2420
|
+
case 'set':
|
|
2421
|
+
if (!domain || !value) {
|
|
2422
|
+
console.error(
|
|
2423
|
+
'❌ Error: Domain and IP address are required'
|
|
2424
|
+
);
|
|
2425
|
+
console.error(
|
|
2426
|
+
'Usage: did-cli ip set <domain> <ip-address>'
|
|
2427
|
+
);
|
|
2428
|
+
console.error(
|
|
2429
|
+
'Note: Set PRIVATE_KEY_OR_MNEMONIC environment variable first'
|
|
2430
|
+
);
|
|
2431
|
+
process.exit(1);
|
|
2432
|
+
}
|
|
2433
|
+
await setIP(domain, value, options);
|
|
2434
|
+
break;
|
|
2435
|
+
case 'remove':
|
|
2436
|
+
if (!domain) {
|
|
2437
|
+
console.error(
|
|
2438
|
+
'❌ Error: Domain argument is required'
|
|
2439
|
+
);
|
|
2440
|
+
process.exit(1);
|
|
2441
|
+
}
|
|
2442
|
+
await removeIP(domain, options);
|
|
2443
|
+
break;
|
|
2444
|
+
default:
|
|
2445
|
+
console.error(
|
|
2446
|
+
`❌ Unknown IP subcommand: ${subCommand}`
|
|
2447
|
+
);
|
|
2448
|
+
process.exit(1);
|
|
2449
|
+
}
|
|
2450
|
+
break;
|
|
2451
|
+
|
|
2452
|
+
// Subdomain commands
|
|
2453
|
+
case 'subdomain':
|
|
2454
|
+
if (!subCommand) {
|
|
2455
|
+
console.error('❌ Error: Subdomain subcommand is required');
|
|
2456
|
+
console.error(
|
|
2457
|
+
'Usage: did-cli subdomain <register> <parent-domain> <subdomain-label>'
|
|
2458
|
+
);
|
|
2459
|
+
process.exit(1);
|
|
2460
|
+
}
|
|
2461
|
+
switch (subCommand) {
|
|
2462
|
+
case 'register':
|
|
2463
|
+
if (!domain || !value) {
|
|
2464
|
+
console.error(
|
|
2465
|
+
'❌ Error: Parent domain and subdomain label are required'
|
|
2466
|
+
);
|
|
2467
|
+
console.error(
|
|
2468
|
+
'Usage: did-cli subdomain register <parent-domain> <subdomain-label>'
|
|
2469
|
+
);
|
|
2470
|
+
console.error(
|
|
2471
|
+
'Options: --words 12|24 (default: 12)'
|
|
2472
|
+
);
|
|
2473
|
+
console.error(
|
|
2474
|
+
'Note: Set PRIVATE_KEY_OR_MNEMONIC environment variable first'
|
|
2475
|
+
);
|
|
2476
|
+
console.error(
|
|
2477
|
+
'Optional: Set MNEMONIC environment variable for subdomain owner (auto-generates if not set)'
|
|
2478
|
+
);
|
|
2479
|
+
process.exit(1);
|
|
2480
|
+
}
|
|
2481
|
+
await registerSubdomain(domain, value, options);
|
|
2482
|
+
break;
|
|
2483
|
+
default:
|
|
2484
|
+
console.error(
|
|
2485
|
+
`❌ Unknown subdomain subcommand: ${subCommand}`
|
|
2486
|
+
);
|
|
2487
|
+
process.exit(1);
|
|
2488
|
+
}
|
|
2489
|
+
break;
|
|
2490
|
+
|
|
2491
|
+
// Operator commands
|
|
2492
|
+
case 'operator':
|
|
2493
|
+
if (!subCommand) {
|
|
2494
|
+
console.error('❌ Error: Operator subcommand is required');
|
|
2495
|
+
console.error('Usage: did-cli operator <get|set> [args]');
|
|
2496
|
+
process.exit(1);
|
|
2497
|
+
}
|
|
2498
|
+
switch (subCommand) {
|
|
2499
|
+
case 'get':
|
|
2500
|
+
await getOperator(options);
|
|
2501
|
+
break;
|
|
2502
|
+
case 'set':
|
|
2503
|
+
if (!domain) {
|
|
2504
|
+
console.error(
|
|
2505
|
+
'❌ Error: Operator address is required'
|
|
2506
|
+
);
|
|
2507
|
+
console.error(
|
|
2508
|
+
'Usage: did-cli operator set <address>'
|
|
2509
|
+
);
|
|
2510
|
+
console.error(
|
|
2511
|
+
'Note: Set PRIVATE_KEY_OR_MNEMONIC environment variable first'
|
|
2512
|
+
);
|
|
2513
|
+
process.exit(1);
|
|
2514
|
+
}
|
|
2515
|
+
await setOperator(domain, options);
|
|
2516
|
+
break;
|
|
2517
|
+
default:
|
|
2518
|
+
console.error(
|
|
2519
|
+
`❌ Unknown operator subcommand: ${subCommand}`
|
|
2520
|
+
);
|
|
2521
|
+
process.exit(1);
|
|
2522
|
+
}
|
|
2523
|
+
break;
|
|
2524
|
+
|
|
2525
|
+
// Crypto utilities
|
|
2526
|
+
case 'crypto':
|
|
2527
|
+
if (!subCommand) {
|
|
2528
|
+
console.error('❌ Error: Crypto subcommand is required');
|
|
2529
|
+
console.error(
|
|
2530
|
+
'Usage: did-cli crypto <generate|address|did|privatekey|derive> [mnemonic]'
|
|
2531
|
+
);
|
|
2532
|
+
process.exit(1);
|
|
2533
|
+
}
|
|
2534
|
+
switch (subCommand) {
|
|
2535
|
+
case 'generate':
|
|
2536
|
+
await cryptoGenerate(options);
|
|
2537
|
+
break;
|
|
2538
|
+
case 'address':
|
|
2539
|
+
await cryptoGetAddress(options);
|
|
2540
|
+
break;
|
|
2541
|
+
case 'did':
|
|
2542
|
+
await cryptoGetDID(options);
|
|
2543
|
+
break;
|
|
2544
|
+
case 'privatekey':
|
|
2545
|
+
await cryptoGetPrivateKey(options);
|
|
2546
|
+
break;
|
|
2547
|
+
case 'derive':
|
|
2548
|
+
await cryptoDerive(options);
|
|
2549
|
+
break;
|
|
2550
|
+
default:
|
|
2551
|
+
console.error(
|
|
2552
|
+
`❌ Unknown crypto subcommand: ${subCommand}`
|
|
2553
|
+
);
|
|
2554
|
+
console.error(
|
|
2555
|
+
'Available: generate, address, did, privatekey, derive'
|
|
2556
|
+
);
|
|
2557
|
+
process.exit(1);
|
|
2558
|
+
}
|
|
2559
|
+
break;
|
|
2560
|
+
|
|
2561
|
+
// Conversion utilities
|
|
2562
|
+
case 'convert':
|
|
2563
|
+
if (!subCommand) {
|
|
2564
|
+
console.error('❌ Error: Conversion type is required');
|
|
2565
|
+
console.error(
|
|
2566
|
+
'Usage: did-cli convert <pem-to-der|der-to-pem|ip-to-bytes|bytes-to-ip> <value>'
|
|
2567
|
+
);
|
|
2568
|
+
process.exit(1);
|
|
2569
|
+
}
|
|
2570
|
+
switch (subCommand) {
|
|
2571
|
+
case 'pem-to-der':
|
|
2572
|
+
if (!domain) {
|
|
2573
|
+
console.error(
|
|
2574
|
+
'❌ Error: PEM file path is required'
|
|
2575
|
+
);
|
|
2576
|
+
process.exit(1);
|
|
2577
|
+
}
|
|
2578
|
+
convertPemToDer(domain, options);
|
|
2579
|
+
break;
|
|
2580
|
+
case 'der-to-pem':
|
|
2581
|
+
if (!domain) {
|
|
2582
|
+
console.error(
|
|
2583
|
+
'❌ Error: DER hex string is required'
|
|
2584
|
+
);
|
|
2585
|
+
process.exit(1);
|
|
2586
|
+
}
|
|
2587
|
+
convertDerToPem(domain, options);
|
|
2588
|
+
break;
|
|
2589
|
+
case 'ip-to-bytes':
|
|
2590
|
+
if (!domain) {
|
|
2591
|
+
console.error('❌ Error: IP address is required');
|
|
2592
|
+
process.exit(1);
|
|
2593
|
+
}
|
|
2594
|
+
convertIpToBytes(domain, options);
|
|
2595
|
+
break;
|
|
2596
|
+
case 'bytes-to-ip':
|
|
2597
|
+
if (!domain) {
|
|
2598
|
+
console.error(
|
|
2599
|
+
'❌ Error: Bytes4 hex string is required'
|
|
2600
|
+
);
|
|
2601
|
+
process.exit(1);
|
|
2602
|
+
}
|
|
2603
|
+
convertBytesToIp(domain, options);
|
|
2604
|
+
break;
|
|
2605
|
+
default:
|
|
2606
|
+
console.error(
|
|
2607
|
+
`❌ Unknown conversion type: ${subCommand}`
|
|
2608
|
+
);
|
|
2609
|
+
process.exit(1);
|
|
2610
|
+
}
|
|
2611
|
+
break;
|
|
2612
|
+
|
|
2613
|
+
case 'wallet':
|
|
2614
|
+
if (!subCommand) {
|
|
2615
|
+
console.error('❌ Error: Wallet subcommand is required');
|
|
2616
|
+
console.error(
|
|
2617
|
+
'Usage: did-cli wallet <evm|solana> <add|remove|list> <domain>'
|
|
2618
|
+
);
|
|
2619
|
+
process.exit(1);
|
|
2620
|
+
}
|
|
2621
|
+
|
|
2622
|
+
switch (subCommand) {
|
|
2623
|
+
case 'evm':
|
|
2624
|
+
if (!domain || !value) {
|
|
2625
|
+
console.error(
|
|
2626
|
+
'❌ Error: wallet evm requires <action> and <domain>'
|
|
2627
|
+
);
|
|
2628
|
+
console.error(
|
|
2629
|
+
'Usage: did-cli wallet evm <add|remove|list> <domain>'
|
|
2630
|
+
);
|
|
2631
|
+
process.exit(1);
|
|
2632
|
+
}
|
|
2633
|
+
await walletEvm(domain, value, options);
|
|
2634
|
+
break;
|
|
2635
|
+
case 'solana':
|
|
2636
|
+
if (!domain || !value) {
|
|
2637
|
+
console.error(
|
|
2638
|
+
'❌ Error: wallet solana requires <action> and <domain>'
|
|
2639
|
+
);
|
|
2640
|
+
console.error(
|
|
2641
|
+
'Usage: did-cli wallet solana <add|remove|list> <domain>'
|
|
2642
|
+
);
|
|
2643
|
+
process.exit(1);
|
|
2644
|
+
}
|
|
2645
|
+
await walletSolana(domain, value, options);
|
|
2646
|
+
break;
|
|
2647
|
+
default:
|
|
2648
|
+
console.error(`❌ Unknown wallet type: ${subCommand}`);
|
|
2649
|
+
console.error(
|
|
2650
|
+
'Usage: did-cli wallet <evm|solana> <add|remove|list> <domain>'
|
|
2651
|
+
);
|
|
2652
|
+
process.exit(1);
|
|
2653
|
+
}
|
|
2654
|
+
break;
|
|
2655
|
+
|
|
2656
|
+
// Tag commands
|
|
2657
|
+
case 'tag':
|
|
2658
|
+
if (!subCommand) {
|
|
2659
|
+
console.error('❌ Error: Tag subcommand is required');
|
|
2660
|
+
console.error(
|
|
2661
|
+
'Usage: did-cli tag <define|set|get|remove|list|list-defined|set-tagger|get-tagger> [args]'
|
|
2662
|
+
);
|
|
2663
|
+
process.exit(1);
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
switch (subCommand) {
|
|
2667
|
+
case 'define':
|
|
2668
|
+
if (!domain || !value) {
|
|
2669
|
+
console.error(
|
|
2670
|
+
'❌ Error: tag define requires <domain>, <tag-name> and <type>'
|
|
2671
|
+
);
|
|
2672
|
+
console.error(
|
|
2673
|
+
'Usage: did-cli tag define <domain> <tag-name> <type>'
|
|
2674
|
+
);
|
|
2675
|
+
console.error(
|
|
2676
|
+
' Supported types: string, uint8, uint256, int8, int256, bool, address, bytes, bytes32'
|
|
2677
|
+
);
|
|
2678
|
+
console.error(
|
|
2679
|
+
' Array types: string[], uint8[], etc.'
|
|
2680
|
+
);
|
|
2681
|
+
console.error(
|
|
2682
|
+
'\nNote: Set PRIVATE_KEY_OR_MNEMONIC environment variable first'
|
|
2683
|
+
);
|
|
2684
|
+
process.exit(1);
|
|
2685
|
+
}
|
|
2686
|
+
// For define command: domain=tagName, value=type
|
|
2687
|
+
// We need to get the actual domain from the previous positional arg
|
|
2688
|
+
// This is a bit tricky with current parsing, let's handle it
|
|
2689
|
+
{
|
|
2690
|
+
const args = process.argv.slice(2);
|
|
2691
|
+
const defineIdx = args.indexOf('define');
|
|
2692
|
+
if (defineIdx >= 0 && args.length > defineIdx + 3) {
|
|
2693
|
+
const actualDomain = args[defineIdx + 1];
|
|
2694
|
+
const tagName = args[defineIdx + 2];
|
|
2695
|
+
const typeString = args[defineIdx + 3];
|
|
2696
|
+
await tagDefine(
|
|
2697
|
+
actualDomain,
|
|
2698
|
+
tagName,
|
|
2699
|
+
typeString,
|
|
2700
|
+
options
|
|
2701
|
+
);
|
|
2702
|
+
} else {
|
|
2703
|
+
console.error(
|
|
2704
|
+
'❌ Error: Missing arguments for tag define'
|
|
2705
|
+
);
|
|
2706
|
+
console.error(
|
|
2707
|
+
'Usage: did-cli tag define <domain> <tag-name> <type>'
|
|
2708
|
+
);
|
|
2709
|
+
process.exit(1);
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
break;
|
|
2713
|
+
|
|
2714
|
+
case 'set':
|
|
2715
|
+
if (!domain || !value) {
|
|
2716
|
+
console.error(
|
|
2717
|
+
'❌ Error: tag set requires <domain>, <tag-name> and <value>'
|
|
2718
|
+
);
|
|
2719
|
+
console.error(
|
|
2720
|
+
'Usage: did-cli tag set <domain> <tag-name> <value>'
|
|
2721
|
+
);
|
|
2722
|
+
console.error(
|
|
2723
|
+
' Value can be a string or JSON (e.g., \'["item1","item2"]\' for arrays)'
|
|
2724
|
+
);
|
|
2725
|
+
console.error(
|
|
2726
|
+
'\nNote: Set PRIVATE_KEY_OR_MNEMONIC environment variable first'
|
|
2727
|
+
);
|
|
2728
|
+
process.exit(1);
|
|
2729
|
+
}
|
|
2730
|
+
{
|
|
2731
|
+
const args = process.argv.slice(2);
|
|
2732
|
+
const setIdx = args.indexOf('set');
|
|
2733
|
+
if (setIdx >= 0 && args.length > setIdx + 3) {
|
|
2734
|
+
const actualDomain = args[setIdx + 1];
|
|
2735
|
+
const tagName = args[setIdx + 2];
|
|
2736
|
+
const valueStr = args[setIdx + 3];
|
|
2737
|
+
await tagSet(
|
|
2738
|
+
actualDomain,
|
|
2739
|
+
tagName,
|
|
2740
|
+
valueStr,
|
|
2741
|
+
options
|
|
2742
|
+
);
|
|
2743
|
+
} else {
|
|
2744
|
+
console.error(
|
|
2745
|
+
'❌ Error: Missing arguments for tag set'
|
|
2746
|
+
);
|
|
2747
|
+
console.error(
|
|
2748
|
+
'Usage: did-cli tag set <domain> <tag-name> <value>'
|
|
2749
|
+
);
|
|
2750
|
+
process.exit(1);
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
break;
|
|
2754
|
+
|
|
2755
|
+
case 'get':
|
|
2756
|
+
if (!domain) {
|
|
2757
|
+
console.error(
|
|
2758
|
+
'❌ Error: tag get requires <domain> and <tag-name>'
|
|
2759
|
+
);
|
|
2760
|
+
console.error(
|
|
2761
|
+
'Usage: did-cli tag get <domain> <tag-name>'
|
|
2762
|
+
);
|
|
2763
|
+
process.exit(1);
|
|
2764
|
+
}
|
|
2765
|
+
{
|
|
2766
|
+
const args = process.argv.slice(2);
|
|
2767
|
+
const getIdx = args.indexOf('get');
|
|
2768
|
+
if (getIdx >= 0 && args.length > getIdx + 2) {
|
|
2769
|
+
const actualDomain = args[getIdx + 1];
|
|
2770
|
+
const tagName = args[getIdx + 2];
|
|
2771
|
+
await tagGet(actualDomain, tagName, options);
|
|
2772
|
+
} else {
|
|
2773
|
+
console.error(
|
|
2774
|
+
'❌ Error: Missing arguments for tag get'
|
|
2775
|
+
);
|
|
2776
|
+
console.error(
|
|
2777
|
+
'Usage: did-cli tag get <domain> <tag-name>'
|
|
2778
|
+
);
|
|
2779
|
+
process.exit(1);
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
break;
|
|
2783
|
+
|
|
2784
|
+
case 'remove':
|
|
2785
|
+
if (!domain) {
|
|
2786
|
+
console.error(
|
|
2787
|
+
'❌ Error: tag remove requires <domain> and <tag-name>'
|
|
2788
|
+
);
|
|
2789
|
+
console.error(
|
|
2790
|
+
'Usage: did-cli tag remove <domain> <tag-name>'
|
|
2791
|
+
);
|
|
2792
|
+
console.error(
|
|
2793
|
+
'\nNote: Set PRIVATE_KEY_OR_MNEMONIC environment variable first'
|
|
2794
|
+
);
|
|
2795
|
+
process.exit(1);
|
|
2796
|
+
}
|
|
2797
|
+
{
|
|
2798
|
+
const args = process.argv.slice(2);
|
|
2799
|
+
const removeIdx = args.indexOf('remove');
|
|
2800
|
+
if (removeIdx >= 0 && args.length > removeIdx + 2) {
|
|
2801
|
+
const actualDomain = args[removeIdx + 1];
|
|
2802
|
+
const tagName = args[removeIdx + 2];
|
|
2803
|
+
await tagRemove(actualDomain, tagName, options);
|
|
2804
|
+
} else {
|
|
2805
|
+
console.error(
|
|
2806
|
+
'❌ Error: Missing arguments for tag remove'
|
|
2807
|
+
);
|
|
2808
|
+
console.error(
|
|
2809
|
+
'Usage: did-cli tag remove <domain> <tag-name>'
|
|
2810
|
+
);
|
|
2811
|
+
process.exit(1);
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
break;
|
|
2815
|
+
|
|
2816
|
+
case 'list':
|
|
2817
|
+
if (!domain) {
|
|
2818
|
+
console.error(
|
|
2819
|
+
'❌ Error: Domain argument is required'
|
|
2820
|
+
);
|
|
2821
|
+
console.error('Usage: did-cli tag list <domain>');
|
|
2822
|
+
process.exit(1);
|
|
2823
|
+
}
|
|
2824
|
+
await tagList(domain, options);
|
|
2825
|
+
break;
|
|
2826
|
+
|
|
2827
|
+
case 'list-defined':
|
|
2828
|
+
if (!domain) {
|
|
2829
|
+
console.error(
|
|
2830
|
+
'❌ Error: Domain argument is required'
|
|
2831
|
+
);
|
|
2832
|
+
console.error(
|
|
2833
|
+
'Usage: did-cli tag list-defined <domain>'
|
|
2834
|
+
);
|
|
2835
|
+
process.exit(1);
|
|
2836
|
+
}
|
|
2837
|
+
await tagListDefined(domain, options);
|
|
2838
|
+
break;
|
|
2839
|
+
|
|
2840
|
+
case 'set-tagger':
|
|
2841
|
+
if (!domain || !value) {
|
|
2842
|
+
console.error(
|
|
2843
|
+
'❌ Error: tag set-tagger requires <domain>, <tag-name> and <tagger-address>'
|
|
2844
|
+
);
|
|
2845
|
+
console.error(
|
|
2846
|
+
'Usage: did-cli tag set-tagger <domain> <tag-name> <tagger-address>'
|
|
2847
|
+
);
|
|
2848
|
+
console.error(
|
|
2849
|
+
'\nNote: Set PRIVATE_KEY_OR_MNEMONIC environment variable first'
|
|
2850
|
+
);
|
|
2851
|
+
process.exit(1);
|
|
2852
|
+
}
|
|
2853
|
+
{
|
|
2854
|
+
const args = process.argv.slice(2);
|
|
2855
|
+
const setTaggerIdx = args.indexOf('set-tagger');
|
|
2856
|
+
if (
|
|
2857
|
+
setTaggerIdx >= 0 &&
|
|
2858
|
+
args.length > setTaggerIdx + 3
|
|
2859
|
+
) {
|
|
2860
|
+
const actualDomain = args[setTaggerIdx + 1];
|
|
2861
|
+
const tagName = args[setTaggerIdx + 2];
|
|
2862
|
+
const taggerAddress = args[setTaggerIdx + 3];
|
|
2863
|
+
await tagSetTagger(
|
|
2864
|
+
actualDomain,
|
|
2865
|
+
tagName,
|
|
2866
|
+
taggerAddress,
|
|
2867
|
+
options
|
|
2868
|
+
);
|
|
2869
|
+
} else {
|
|
2870
|
+
console.error(
|
|
2871
|
+
'❌ Error: Missing arguments for tag set-tagger'
|
|
2872
|
+
);
|
|
2873
|
+
console.error(
|
|
2874
|
+
'Usage: did-cli tag set-tagger <domain> <tag-name> <tagger-address>'
|
|
2875
|
+
);
|
|
2876
|
+
process.exit(1);
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
break;
|
|
2880
|
+
|
|
2881
|
+
case 'get-tagger':
|
|
2882
|
+
if (!domain) {
|
|
2883
|
+
console.error(
|
|
2884
|
+
'❌ Error: tag get-tagger requires <domain> and <tag-name>'
|
|
2885
|
+
);
|
|
2886
|
+
console.error(
|
|
2887
|
+
'Usage: did-cli tag get-tagger <domain> <tag-name>'
|
|
2888
|
+
);
|
|
2889
|
+
process.exit(1);
|
|
2890
|
+
}
|
|
2891
|
+
{
|
|
2892
|
+
const args = process.argv.slice(2);
|
|
2893
|
+
const getTaggerIdx = args.indexOf('get-tagger');
|
|
2894
|
+
if (
|
|
2895
|
+
getTaggerIdx >= 0 &&
|
|
2896
|
+
args.length > getTaggerIdx + 2
|
|
2897
|
+
) {
|
|
2898
|
+
const actualDomain = args[getTaggerIdx + 1];
|
|
2899
|
+
const tagName = args[getTaggerIdx + 2];
|
|
2900
|
+
await tagGetTagger(
|
|
2901
|
+
actualDomain,
|
|
2902
|
+
tagName,
|
|
2903
|
+
options
|
|
2904
|
+
);
|
|
2905
|
+
} else {
|
|
2906
|
+
console.error(
|
|
2907
|
+
'❌ Error: Missing arguments for tag get-tagger'
|
|
2908
|
+
);
|
|
2909
|
+
console.error(
|
|
2910
|
+
'Usage: did-cli tag get-tagger <domain> <tag-name>'
|
|
2911
|
+
);
|
|
2912
|
+
process.exit(1);
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
break;
|
|
2916
|
+
|
|
2917
|
+
default:
|
|
2918
|
+
console.error(
|
|
2919
|
+
`❌ Unknown tag subcommand: ${subCommand}`
|
|
2920
|
+
);
|
|
2921
|
+
console.error(
|
|
2922
|
+
'Usage: did-cli tag <define|set|get|remove|list|list-defined|set-tagger|get-tagger> [args]'
|
|
2923
|
+
);
|
|
2924
|
+
process.exit(1);
|
|
2925
|
+
}
|
|
2926
|
+
break;
|
|
2927
|
+
|
|
2928
|
+
// Legacy commands
|
|
2929
|
+
case 'fetch':
|
|
2930
|
+
case 'fetch-domain':
|
|
2931
|
+
if (!domain) {
|
|
2932
|
+
console.error('❌ Error: Domain argument is required');
|
|
2933
|
+
console.error('Usage: did-cli fetch <domain> [options]');
|
|
2934
|
+
process.exit(1);
|
|
2935
|
+
}
|
|
2936
|
+
await fetchDomain(domain, options);
|
|
2937
|
+
break;
|
|
2938
|
+
|
|
2939
|
+
default:
|
|
2940
|
+
console.error(`❌ Unknown command: ${command}`);
|
|
2941
|
+
console.error('Run "did-cli help" for usage information');
|
|
2942
|
+
process.exit(1);
|
|
2943
|
+
}
|
|
2944
|
+
} catch (error) {
|
|
2945
|
+
console.error(
|
|
2946
|
+
'❌ Error:',
|
|
2947
|
+
error instanceof Error ? error.message : String(error)
|
|
2948
|
+
);
|
|
2949
|
+
if (debug.isEnabled()) {
|
|
2950
|
+
debug.error('Full error details:', error);
|
|
2951
|
+
}
|
|
2952
|
+
process.exit(1);
|
|
220
2953
|
}
|
|
221
2954
|
}
|
|
222
2955
|
|