@veil-cash/sdk 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -464
- package/SDK.md +365 -0
- package/dist/cli/index.cjs +2260 -955
- package/dist/index.cjs +561 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +486 -1
- package/dist/index.d.ts +486 -1
- package/dist/index.js +544 -27
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/skills/veil/SKILL.md +526 -0
- package/skills/veil/reference.md +231 -0
- package/src/abi.ts +172 -0
- package/src/addresses.ts +20 -2
- package/src/balance.ts +4 -4
- package/src/cli/commands/balance.ts +126 -38
- package/src/cli/commands/deposit.ts +136 -63
- package/src/cli/commands/init.ts +95 -72
- package/src/cli/commands/keypair.ts +34 -16
- package/src/cli/commands/private-balance.ts +37 -35
- package/src/cli/commands/queue-balance.ts +48 -36
- package/src/cli/commands/register.ts +67 -53
- package/src/cli/commands/status.ts +196 -70
- package/src/cli/commands/subaccount.ts +354 -0
- package/src/cli/commands/transfer.ts +62 -53
- package/src/cli/commands/withdraw.ts +32 -30
- package/src/cli/config.ts +85 -5
- package/src/cli/errors.ts +8 -0
- package/src/cli/index.ts +27 -5
- package/src/cli/output.ts +87 -0
- package/src/cli/wallet.ts +75 -16
- package/src/index.ts +41 -1
- package/src/prover.ts +3 -0
- package/src/relay.ts +36 -24
- package/src/subaccount.ts +476 -0
- package/src/types.ts +134 -0
|
@@ -5,57 +5,63 @@
|
|
|
5
5
|
import { Command } from 'commander';
|
|
6
6
|
import { buildRegisterTx, buildChangeDepositKeyTx } from '../../deposit.js';
|
|
7
7
|
import { sendTransaction, getAddress, isRegistered } from '../wallet.js';
|
|
8
|
-
import { getConfig } from '../config.js';
|
|
8
|
+
import { getConfig, resolveAddress } from '../config.js';
|
|
9
9
|
import { handleCLIError, CLIError, ErrorCode } from '../errors.js';
|
|
10
|
+
import { maskValue, printFields, printHeader, printJson, printLine, txUrl } from '../output.js';
|
|
10
11
|
|
|
11
12
|
export function createRegisterCommand(): Command {
|
|
12
13
|
const register = new Command('register')
|
|
13
14
|
.description('Register or update your deposit key on-chain')
|
|
14
|
-
.option('--
|
|
15
|
-
.option('--
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
.option('--address <address>', 'Signer address (optional if SIGNER_ADDRESS or WALLET_KEY is set in --unsigned mode)')
|
|
16
|
+
.option('--unsigned', 'Output unsigned transaction payload instead of sending')
|
|
17
|
+
.option('--force', 'Change deposit key even if already registered')
|
|
18
|
+
.option('--json', 'Output as JSON')
|
|
19
|
+
.addHelpText('after', `
|
|
20
|
+
Examples:
|
|
21
|
+
veil register
|
|
22
|
+
veil register --force
|
|
23
|
+
veil register --unsigned --address 0x...
|
|
24
|
+
SIGNER_ADDRESS=0x... veil register --unsigned
|
|
25
|
+
veil register --json
|
|
26
|
+
`)
|
|
21
27
|
.action(async (options) => {
|
|
22
28
|
const jsonOutput = options.json;
|
|
23
29
|
|
|
24
30
|
try {
|
|
25
31
|
// Get deposit key from option or env
|
|
26
|
-
const depositKey =
|
|
32
|
+
const depositKey = process.env.DEPOSIT_KEY;
|
|
27
33
|
if (!depositKey) {
|
|
28
|
-
throw new CLIError(ErrorCode.DEPOSIT_KEY_MISSING, '
|
|
34
|
+
throw new CLIError(ErrorCode.DEPOSIT_KEY_MISSING, 'DEPOSIT_KEY not set. Run "veil init" first.');
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
// Handle --unsigned mode (no wallet required, just build payload)
|
|
32
38
|
if (options.unsigned) {
|
|
33
|
-
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
throw new CLIError(ErrorCode.WALLET_KEY_MISSING, 'Must provide --address or --wallet-key for --unsigned mode');
|
|
40
|
-
}
|
|
41
|
-
address = getAddress(walletKey as `0x${string}`);
|
|
39
|
+
const resolvedAddress = resolveAddress({ address: options.address }, { required: true });
|
|
40
|
+
if (!resolvedAddress) {
|
|
41
|
+
throw new CLIError(
|
|
42
|
+
ErrorCode.WALLET_KEY_MISSING,
|
|
43
|
+
'Must provide --address, set SIGNER_ADDRESS, or set WALLET_KEY env.',
|
|
44
|
+
);
|
|
42
45
|
}
|
|
46
|
+
const address = resolvedAddress.address;
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
const
|
|
48
|
+
const rpcUrl = process.env.RPC_URL;
|
|
49
|
+
const isChange = options.force
|
|
50
|
+
? (await isRegistered(address, rpcUrl)).registered
|
|
51
|
+
: false;
|
|
52
|
+
const tx = isChange
|
|
46
53
|
? buildChangeDepositKeyTx(depositKey, address)
|
|
47
54
|
: buildRegisterTx(depositKey, address);
|
|
48
55
|
|
|
49
56
|
const payload = {
|
|
50
|
-
action:
|
|
57
|
+
action: isChange ? 'changeDepositKey' : 'register',
|
|
51
58
|
to: tx.to,
|
|
52
59
|
data: tx.data,
|
|
53
60
|
value: '0',
|
|
54
61
|
chainId: 8453,
|
|
55
62
|
};
|
|
56
63
|
|
|
57
|
-
|
|
58
|
-
process.exit(0);
|
|
64
|
+
printJson(payload);
|
|
59
65
|
return;
|
|
60
66
|
}
|
|
61
67
|
|
|
@@ -64,35 +70,35 @@ export function createRegisterCommand(): Command {
|
|
|
64
70
|
const address = getAddress(config.privateKey);
|
|
65
71
|
|
|
66
72
|
// Check if already registered
|
|
67
|
-
if (!jsonOutput)
|
|
73
|
+
if (!jsonOutput) printLine('Checking registration status...');
|
|
68
74
|
const { registered, depositKey: existingKey } = await isRegistered(address, config.rpcUrl);
|
|
69
75
|
|
|
70
76
|
// Determine if this is a new registration or a key change
|
|
71
77
|
const keysMatch = registered && existingKey === depositKey;
|
|
72
|
-
const isChange = registered && !keysMatch;
|
|
73
78
|
|
|
74
|
-
if (registered && keysMatch) {
|
|
75
|
-
// Already registered with the same key -- nothing to do
|
|
79
|
+
if (registered && keysMatch && !options.force) {
|
|
76
80
|
if (jsonOutput) {
|
|
77
|
-
|
|
81
|
+
printJson({
|
|
78
82
|
success: true,
|
|
79
83
|
alreadyRegistered: true,
|
|
80
84
|
keysMatch: true,
|
|
81
85
|
address,
|
|
82
86
|
depositKey: existingKey,
|
|
83
|
-
}
|
|
87
|
+
});
|
|
84
88
|
} else {
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
printHeader('Already Registered');
|
|
90
|
+
printFields([
|
|
91
|
+
{ label: 'Address', value: address },
|
|
92
|
+
{ label: 'Deposit key', value: maskValue(existingKey!) },
|
|
93
|
+
]);
|
|
94
|
+
printLine();
|
|
87
95
|
}
|
|
88
|
-
process.exit(0);
|
|
89
96
|
return;
|
|
90
97
|
}
|
|
91
98
|
|
|
92
|
-
if (
|
|
93
|
-
// Registered with a different key but --force not provided
|
|
99
|
+
if (registered && !keysMatch && !options.force) {
|
|
94
100
|
if (jsonOutput) {
|
|
95
|
-
|
|
101
|
+
printJson({
|
|
96
102
|
success: false,
|
|
97
103
|
alreadyRegistered: true,
|
|
98
104
|
keysMatch: false,
|
|
@@ -100,23 +106,31 @@ export function createRegisterCommand(): Command {
|
|
|
100
106
|
onChainKey: existingKey,
|
|
101
107
|
localKey: depositKey.slice(0, 40) + '...',
|
|
102
108
|
hint: 'Use --force to change deposit key',
|
|
103
|
-
}
|
|
109
|
+
});
|
|
104
110
|
} else {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
111
|
+
printLine('A different deposit key is already registered');
|
|
112
|
+
printFields([
|
|
113
|
+
{ label: 'Address', value: address },
|
|
114
|
+
{ label: 'On-chain key', value: maskValue(existingKey!) },
|
|
115
|
+
{ label: 'Local key', value: maskValue(depositKey) },
|
|
116
|
+
]);
|
|
117
|
+
printLine('');
|
|
118
|
+
printLine('Use `veil register --force` to change your deposit key on-chain.');
|
|
109
119
|
}
|
|
110
120
|
process.exit(1);
|
|
111
121
|
return;
|
|
112
122
|
}
|
|
113
123
|
|
|
124
|
+
const isChange = registered && options.force;
|
|
125
|
+
|
|
114
126
|
// Build the appropriate transaction
|
|
115
127
|
const action = isChange ? 'Changing deposit key' : 'Registering deposit key';
|
|
116
128
|
if (!jsonOutput) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
129
|
+
printLine(`${action}...`);
|
|
130
|
+
printFields([
|
|
131
|
+
{ label: 'Address', value: address },
|
|
132
|
+
{ label: 'Deposit key', value: maskValue(depositKey) },
|
|
133
|
+
]);
|
|
120
134
|
}
|
|
121
135
|
|
|
122
136
|
const tx = isChange
|
|
@@ -126,22 +140,22 @@ export function createRegisterCommand(): Command {
|
|
|
126
140
|
|
|
127
141
|
if (result.receipt.status === 'success') {
|
|
128
142
|
if (jsonOutput) {
|
|
129
|
-
|
|
143
|
+
printJson({
|
|
130
144
|
success: true,
|
|
131
145
|
action: isChange ? 'changed' : 'registered',
|
|
132
146
|
address,
|
|
133
147
|
transactionHash: result.hash,
|
|
134
148
|
blockNumber: result.receipt.blockNumber.toString(),
|
|
135
|
-
|
|
136
|
-
}, null, 2));
|
|
149
|
+
});
|
|
137
150
|
} else {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
151
|
+
printLine(isChange ? 'Deposit key changed successfully' : 'Registration successful');
|
|
152
|
+
printFields([
|
|
153
|
+
{ label: 'Transaction', value: txUrl(result.hash) },
|
|
154
|
+
{ label: 'Block', value: result.receipt.blockNumber },
|
|
155
|
+
]);
|
|
156
|
+
printLine('');
|
|
157
|
+
printLine('Next step: veil deposit <asset> <amount>');
|
|
143
158
|
}
|
|
144
|
-
process.exit(0);
|
|
145
159
|
} else {
|
|
146
160
|
throw new CLIError(ErrorCode.CONTRACT_ERROR, `Transaction reverted: ${result.hash}`);
|
|
147
161
|
}
|
|
@@ -3,13 +3,28 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { Command } from 'commander';
|
|
6
|
-
import { isRegistered, getAddress } from '../wallet.js';
|
|
6
|
+
import { isRegistered, getAddress, getWalletBalances } from '../wallet.js';
|
|
7
|
+
import { resolveAddress } from '../config.js';
|
|
7
8
|
import { checkRelayHealth } from '../../relay.js';
|
|
9
|
+
import { handleCLIError } from '../errors.js';
|
|
10
|
+
import { maskValue, printFields, printHeader, printJson, printSection } from '../output.js';
|
|
8
11
|
|
|
9
12
|
interface StatusResult {
|
|
10
13
|
walletKey: {
|
|
11
14
|
found: boolean;
|
|
12
15
|
address?: string;
|
|
16
|
+
valid?: boolean;
|
|
17
|
+
ethBalance?: string;
|
|
18
|
+
error?: string;
|
|
19
|
+
};
|
|
20
|
+
signerAddress: {
|
|
21
|
+
found: boolean;
|
|
22
|
+
address?: string;
|
|
23
|
+
valid?: boolean;
|
|
24
|
+
};
|
|
25
|
+
resolvedAddress: {
|
|
26
|
+
address?: string;
|
|
27
|
+
source?: string;
|
|
13
28
|
};
|
|
14
29
|
veilKey: {
|
|
15
30
|
found: boolean;
|
|
@@ -41,89 +56,200 @@ interface StatusResult {
|
|
|
41
56
|
export function createStatusCommand(): Command {
|
|
42
57
|
const status = new Command('status')
|
|
43
58
|
.description('Check configuration and service status')
|
|
44
|
-
.option('--
|
|
59
|
+
.option('--json', 'Output as JSON')
|
|
60
|
+
.addHelpText('after', `
|
|
61
|
+
Examples:
|
|
62
|
+
veil status
|
|
63
|
+
veil status --json
|
|
64
|
+
`)
|
|
45
65
|
.action(async (options) => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
try {
|
|
67
|
+
const result: StatusResult = {
|
|
68
|
+
walletKey: { found: false },
|
|
69
|
+
signerAddress: { found: false },
|
|
70
|
+
resolvedAddress: {},
|
|
71
|
+
veilKey: { found: false },
|
|
72
|
+
depositKey: { found: false },
|
|
73
|
+
rpcUrl: { found: false, url: 'https://mainnet.base.org' },
|
|
74
|
+
registration: { checked: false },
|
|
75
|
+
relay: { checked: false },
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Check WALLET_KEY
|
|
79
|
+
const walletKey = process.env.WALLET_KEY;
|
|
80
|
+
if (walletKey) {
|
|
81
|
+
result.walletKey.found = true;
|
|
82
|
+
try {
|
|
83
|
+
result.walletKey.address = getAddress(walletKey as `0x${string}`);
|
|
84
|
+
result.walletKey.valid = true;
|
|
85
|
+
} catch {
|
|
86
|
+
result.walletKey.valid = false;
|
|
87
|
+
result.walletKey.error = 'invalid format';
|
|
88
|
+
}
|
|
63
89
|
}
|
|
64
|
-
}
|
|
65
90
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
91
|
+
// Check SIGNER_ADDRESS
|
|
92
|
+
const signerAddress = process.env.SIGNER_ADDRESS;
|
|
93
|
+
if (signerAddress) {
|
|
94
|
+
result.signerAddress.found = true;
|
|
95
|
+
if (/^0x[a-fA-F0-9]{40}$/.test(signerAddress.trim())) {
|
|
96
|
+
result.signerAddress.valid = true;
|
|
97
|
+
result.signerAddress.address = signerAddress.trim();
|
|
98
|
+
} else {
|
|
99
|
+
result.signerAddress.valid = false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
71
102
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// Show truncated key
|
|
77
|
-
if (depositKey.length > 20) {
|
|
78
|
-
result.depositKey.key = `${depositKey.slice(0, 10)}...${depositKey.slice(-8)}`;
|
|
79
|
-
} else {
|
|
80
|
-
result.depositKey.key = depositKey;
|
|
103
|
+
// Check VEIL_KEY
|
|
104
|
+
const veilKey = process.env.VEIL_KEY;
|
|
105
|
+
if (veilKey) {
|
|
106
|
+
result.veilKey.found = true;
|
|
81
107
|
}
|
|
82
|
-
}
|
|
83
108
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
109
|
+
// Check DEPOSIT_KEY
|
|
110
|
+
const depositKey = process.env.DEPOSIT_KEY;
|
|
111
|
+
if (depositKey) {
|
|
112
|
+
result.depositKey.found = true;
|
|
113
|
+
if (depositKey.length > 20) {
|
|
114
|
+
result.depositKey.key = `${depositKey.slice(0, 10)}...${depositKey.slice(-8)}`;
|
|
115
|
+
} else {
|
|
116
|
+
result.depositKey.key = depositKey;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
91
119
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
120
|
+
// Check RPC_URL
|
|
121
|
+
const rpcUrl = process.env.RPC_URL;
|
|
122
|
+
if (rpcUrl) {
|
|
123
|
+
result.rpcUrl.found = true;
|
|
124
|
+
result.rpcUrl.url = rpcUrl;
|
|
125
|
+
}
|
|
126
|
+
const effectiveRpcUrl = rpcUrl || 'https://mainnet.base.org';
|
|
127
|
+
|
|
128
|
+
const resolvedAddress = resolveAddress({}, { required: false, allowInvalidWalletKey: true });
|
|
129
|
+
if (resolvedAddress) {
|
|
130
|
+
result.resolvedAddress.address = resolvedAddress.address;
|
|
131
|
+
result.resolvedAddress.source =
|
|
132
|
+
resolvedAddress.source === 'wallet-key'
|
|
133
|
+
? 'WALLET_KEY'
|
|
134
|
+
: resolvedAddress.source === 'signer-address'
|
|
135
|
+
? 'SIGNER_ADDRESS'
|
|
136
|
+
: '--address';
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
const walletBalances = await getWalletBalances(
|
|
140
|
+
resolvedAddress.address,
|
|
141
|
+
effectiveRpcUrl
|
|
142
|
+
);
|
|
143
|
+
result.walletKey.ethBalance = walletBalances.eth;
|
|
144
|
+
} catch {
|
|
145
|
+
// Ignore wallet balance lookup errors so status can still report config/registration
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
result.registration.checked = true;
|
|
149
|
+
try {
|
|
150
|
+
const regStatus = await isRegistered(
|
|
151
|
+
resolvedAddress.address,
|
|
152
|
+
effectiveRpcUrl
|
|
153
|
+
);
|
|
154
|
+
result.registration.registered = regStatus.registered;
|
|
155
|
+
result.registration.onChainKey = regStatus.depositKey;
|
|
156
|
+
|
|
157
|
+
if (regStatus.registered && depositKey && regStatus.depositKey) {
|
|
158
|
+
result.registration.matches =
|
|
159
|
+
regStatus.depositKey.toLowerCase() === depositKey.toLowerCase();
|
|
160
|
+
}
|
|
161
|
+
} catch (error) {
|
|
162
|
+
result.registration.error = error instanceof Error ? error.message : 'Unknown error';
|
|
107
163
|
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Check relay health
|
|
167
|
+
const relayUrl = process.env.RELAY_URL;
|
|
168
|
+
result.relay.checked = true;
|
|
169
|
+
try {
|
|
170
|
+
const health = await checkRelayHealth(relayUrl);
|
|
171
|
+
result.relay.healthy = health.status === 'ok';
|
|
172
|
+
result.relay.status = health.status;
|
|
173
|
+
result.relay.network = health.network;
|
|
108
174
|
} catch (error) {
|
|
109
|
-
result.
|
|
175
|
+
result.relay.healthy = false;
|
|
176
|
+
result.relay.error = error instanceof Error ? error.message : 'Unknown error';
|
|
110
177
|
}
|
|
111
|
-
}
|
|
112
178
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
179
|
+
if (options.json) {
|
|
180
|
+
printJson(result);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const signingValue = result.signerAddress.found
|
|
185
|
+
? result.signerAddress.valid === false
|
|
186
|
+
? 'external (SIGNER_ADDRESS invalid)'
|
|
187
|
+
: 'external (SIGNER_ADDRESS)'
|
|
188
|
+
: result.walletKey.found
|
|
189
|
+
? result.walletKey.valid === false
|
|
190
|
+
? 'local (WALLET_KEY invalid)'
|
|
191
|
+
: 'local (WALLET_KEY)'
|
|
192
|
+
: 'not configured';
|
|
193
|
+
|
|
194
|
+
printHeader('Veil CLI Status');
|
|
195
|
+
printSection('Configuration');
|
|
196
|
+
printFields([
|
|
197
|
+
{ label: 'Signing', value: signingValue },
|
|
198
|
+
{ label: 'Address', value: result.resolvedAddress.address || 'n/a' },
|
|
199
|
+
{ label: 'ETH balance', value: result.walletKey.ethBalance ? `${result.walletKey.ethBalance} ETH` : 'n/a' },
|
|
200
|
+
{ label: 'Veil key', value: result.veilKey.found ? 'configured' : 'missing' },
|
|
201
|
+
{ label: 'Deposit key', value: result.depositKey.found ? maskValue(result.depositKey.key || '') : 'missing' },
|
|
202
|
+
{ label: 'RPC URL', value: maskUrl(result.rpcUrl.url) },
|
|
203
|
+
]);
|
|
204
|
+
|
|
205
|
+
printSection('Registration');
|
|
206
|
+
if (!result.registration.checked) {
|
|
207
|
+
printFields([
|
|
208
|
+
{
|
|
209
|
+
label: 'Status',
|
|
210
|
+
value: result.walletKey.found && result.walletKey.valid === false
|
|
211
|
+
? 'skipped (invalid WALLET_KEY)'
|
|
212
|
+
: 'skipped (no WALLET_KEY or SIGNER_ADDRESS)'
|
|
213
|
+
},
|
|
214
|
+
]);
|
|
215
|
+
} else if (result.registration.error) {
|
|
216
|
+
printFields([
|
|
217
|
+
{ label: 'Error', value: result.registration.error },
|
|
218
|
+
]);
|
|
219
|
+
} else {
|
|
220
|
+
printFields([
|
|
221
|
+
{ label: 'Registered', value: result.registration.registered },
|
|
222
|
+
{ label: 'Keys match', value: result.registration.matches ?? 'n/a' },
|
|
223
|
+
{ label: 'On-chain key', value: result.registration.onChainKey ? maskValue(result.registration.onChainKey) : 'n/a' },
|
|
224
|
+
]);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
printSection('Relay');
|
|
228
|
+
if (result.relay.error) {
|
|
229
|
+
printFields([
|
|
230
|
+
{ label: 'Healthy', value: false },
|
|
231
|
+
{ label: 'Error', value: result.relay.error },
|
|
232
|
+
]);
|
|
233
|
+
} else {
|
|
234
|
+
printFields([
|
|
235
|
+
{ label: 'Healthy', value: result.relay.healthy },
|
|
236
|
+
{ label: 'Status', value: result.relay.status || 'n/a' },
|
|
237
|
+
{ label: 'Network', value: result.relay.network || 'n/a' },
|
|
238
|
+
]);
|
|
239
|
+
}
|
|
120
240
|
} catch (error) {
|
|
121
|
-
|
|
122
|
-
result.relay.error = error instanceof Error ? error.message : 'Unknown error';
|
|
241
|
+
handleCLIError(error);
|
|
123
242
|
}
|
|
124
|
-
|
|
125
|
-
console.log(JSON.stringify(result, null, 2));
|
|
126
243
|
});
|
|
127
244
|
|
|
128
245
|
return status;
|
|
129
246
|
}
|
|
247
|
+
|
|
248
|
+
function maskUrl(url: string): string {
|
|
249
|
+
try {
|
|
250
|
+
const parsed = new URL(url);
|
|
251
|
+
return parsed.origin;
|
|
252
|
+
} catch {
|
|
253
|
+
return maskValue(url);
|
|
254
|
+
}
|
|
255
|
+
}
|