Skip to content

Commit 1bc75f1

Browse files
feat: verify/preview bulletin uploads in host (#176)
## Description ## Type - [ ] Bug fix - [x] Feature - [ ] Breaking change - [ ] Documentation - [ ] Chore ## Package - [ ] `@parity/dotns-cli` - [x] dotns-ui - [ ] Root/monorepo - [ ] Documentation ## Related Issues ## Fixes ## Checklist ### Code - [ ] Follows project style - [ ] `bun run lint` passes - [ ] `bun run format` passes - [ ] `bun run typecheck` passes ### Documentation - [ ] README updated if needed - [ ] Types updated if needed ### Breaking Changes - [ ] No breaking changes - [ ] Breaking changes documented below **Breaking changes:** ## Testing How to test: 1. 2. ## Notes --------- Co-authored-by: Siphamandla Mjoli <siphamandla@parity.io>
1 parent 97f9e90 commit 1bc75f1

35 files changed

Lines changed: 1124 additions & 945 deletions

bun.lock

Lines changed: 1 addition & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/cli/src/cli/commands/escrow.ts

Lines changed: 129 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,21 @@ import ora from "ora";
44
import type { Address } from "viem";
55
import {
66
viewEscrowPosition,
7+
listAccountPositions,
8+
totalEscrowAmount,
9+
formatPositionStatus,
10+
formatPositionsTable,
11+
cooldownRemainingSeconds,
712
releaseDomain,
813
withdrawDomain,
914
claimWithdrawal,
15+
getPendingWithdrawal,
1016
listRefunds,
1117
claimRefund,
1218
claimRefundsBatch,
1319
formatRefundEntryLine,
1420
} from "../../commands/escrow";
21+
import { listStoreNames } from "../../commands/storeManagement";
1522
import { addAuthOptions } from "./authOptions";
1623
import { prepareContext } from "../context";
1724
import { prepareReadOnlyContext } from "./lookup";
@@ -81,6 +88,10 @@ export function attachEscrowCommands(root: Command) {
8188
);
8289
console.log(chalk.gray(" released: ") + chalk.white(String(position.released)));
8390
console.log(chalk.gray(" claimed: ") + chalk.white(String(position.claimed)));
91+
const nowSeconds = BigInt(Math.floor(Date.now() / 1000));
92+
console.log(
93+
chalk.gray(" status: ") + chalk.white(formatPositionStatus(position, nowSeconds)),
94+
);
8495
if (position.withdrawAvailableAt > 0n) {
8596
const t = new Date(Number(position.withdrawAvailableAt) * 1000).toISOString();
8697
console.log(chalk.gray(" withdraw: ") + chalk.white(t));
@@ -95,6 +106,105 @@ export function attachEscrowCommands(root: Command) {
95106
},
96107
);
97108

109+
// escrow balance
110+
const balanceCommand = escrowCommand
111+
.command("balance")
112+
.description("Show the caller's claimable pull-payment balance")
113+
.option("--recipient <address>", "Recipient EVM address (defaults to caller)")
114+
.option("--json", "Output result as JSON (suppresses all other output)", false);
115+
addAuthOptions(balanceCommand).action(async (options: RefundListOptions, command: Command) => {
116+
const jsonOutput = getJsonFlag(command);
117+
try {
118+
const mergedOptions = getMergedOptions(command, options);
119+
const context = await maybeQuiet(jsonOutput, () =>
120+
prepareReadOnlyContext(mergedOptions as any),
121+
);
122+
123+
const recipient = (options.recipient ?? context.evmAddress) as Address;
124+
125+
if (!jsonOutput) console.log(chalk.bold("\n▶ Escrow balance\n"));
126+
const spinner = ora();
127+
128+
const balance = await maybeQuiet(jsonOutput, () =>
129+
getPendingWithdrawal(context.clientWrapper!, context.account.address, recipient, spinner),
130+
);
131+
132+
if (!emitJsonResult(jsonOutput, { recipient, balance: balance.toString() })) {
133+
console.log(chalk.gray(" claimable: ") + chalk.green(formatWeiAsEther(balance) + " PAS"));
134+
console.log(chalk.green("\n✓ Complete\n"));
135+
}
136+
process.exit(0);
137+
} catch (error) {
138+
handleCommandError(jsonOutput, error);
139+
}
140+
});
141+
142+
// escrow positions
143+
const positionsCommand = escrowCommand
144+
.command("positions")
145+
.description("List all escrow positions for the caller and the total locked")
146+
.option("--recipient <address>", "Recipient EVM address (defaults to caller)")
147+
.option("--json", "Output result as JSON (suppresses all other output)", false);
148+
addAuthOptions(positionsCommand).action(async (options: RefundListOptions, command: Command) => {
149+
const jsonOutput = getJsonFlag(command);
150+
try {
151+
const mergedOptions = getMergedOptions(command, options);
152+
const context = await maybeQuiet(jsonOutput, () =>
153+
prepareReadOnlyContext(mergedOptions as any),
154+
);
155+
156+
const recipient = (options.recipient ?? context.evmAddress) as Address;
157+
158+
if (!jsonOutput) console.log(chalk.bold("\n▶ Escrow positions\n"));
159+
const spinner = ora();
160+
161+
const names = await maybeQuiet(jsonOutput, () =>
162+
listStoreNames(context.clientWrapper!, context.account.address, recipient),
163+
);
164+
const positions = await maybeQuiet(jsonOutput, () =>
165+
listAccountPositions(
166+
context.clientWrapper!,
167+
context.account.address,
168+
recipient,
169+
names,
170+
spinner,
171+
),
172+
);
173+
const total = totalEscrowAmount(positions);
174+
const nowSeconds = BigInt(Math.floor(Date.now() / 1000));
175+
176+
const handled = emitJsonResult(jsonOutput, {
177+
recipient,
178+
total: total.toString(),
179+
positions: positions.map((position) => ({
180+
domain: position.domain,
181+
tokenId: position.tokenId.toString(),
182+
amount: position.amount.toString(),
183+
released: position.released,
184+
claimed: position.claimed,
185+
withdrawAvailableAt: position.withdrawAvailableAt.toString(),
186+
status: formatPositionStatus(position, nowSeconds),
187+
cooldownSeconds: cooldownRemainingSeconds(position, nowSeconds).toString(),
188+
})),
189+
});
190+
191+
if (!handled) {
192+
if (positions.length === 0) {
193+
console.log(chalk.gray(" no escrow positions"));
194+
} else {
195+
for (const line of formatPositionsTable(positions, nowSeconds)) console.log(" " + line);
196+
}
197+
console.log(
198+
chalk.gray("\n total in escrow: ") + chalk.green(formatWeiAsEther(total) + " PAS"),
199+
);
200+
console.log(chalk.green("\n✓ Complete\n"));
201+
}
202+
process.exit(0);
203+
} catch (error) {
204+
handleCommandError(jsonOutput, error);
205+
}
206+
});
207+
98208
// escrow release <name>
99209
const releaseCommand = escrowCommand
100210
.command("release <name>")
@@ -189,6 +299,23 @@ export function attachEscrowCommands(root: Command) {
189299
if (!jsonOutput) console.log(chalk.bold("\n▶ Escrow claim-withdrawal\n"));
190300
const spinner = ora();
191301

302+
const balance = await maybeQuiet(jsonOutput, () =>
303+
getPendingWithdrawal(
304+
context.clientWrapper!,
305+
context.substrateAddress,
306+
context.evmAddress as Address,
307+
spinner,
308+
),
309+
);
310+
311+
if (balance === 0n) {
312+
if (!emitJsonResult(jsonOutput, { ok: true, txHash: null, balance: "0" })) {
313+
console.log(chalk.gray(" nothing to claim; pull-payment balance is 0"));
314+
console.log(chalk.green("\n✓ Complete\n"));
315+
}
316+
process.exit(0);
317+
}
318+
192319
const txHash = await maybeQuiet(jsonOutput, () =>
193320
claimWithdrawal(
194321
context.clientWrapper!,
@@ -198,7 +325,7 @@ export function attachEscrowCommands(root: Command) {
198325
),
199326
);
200327

201-
if (!emitJsonResult(jsonOutput, { ok: true, txHash })) {
328+
if (!emitJsonResult(jsonOutput, { ok: true, txHash, balance: balance.toString() })) {
202329
console.log(chalk.gray(" tx: ") + chalk.blue(txHash));
203330
console.log(chalk.green("\n✓ Complete\n"));
204331
}
@@ -242,7 +369,7 @@ export function attachEscrowCommands(root: Command) {
242369
throw new Error(`limit must be between 1 and ${MAX_REFUND_PAGE_SIZE}`);
243370
}
244371

245-
const recipient = (options.recipient ?? context.account.address) as Address;
372+
const recipient = (options.recipient ?? context.evmAddress) as Address;
246373

247374
if (!jsonOutput) console.log(chalk.bold("\n▶ Refund ledger\n"));
248375
const spinner = ora();

packages/cli/src/commands/auth.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,15 @@ function resolveAuthSourceFromEnv(account: string): ResolvedAuthSource | undefin
6666
return undefined;
6767
}
6868

69+
function isExplicitKeystorePath(keystorePath: string | undefined): boolean {
70+
if (keystorePath == null || keystorePath.trim().length === 0) return false;
71+
return resolveKeystorePath(keystorePath) !== resolveKeystorePath(undefined);
72+
}
73+
6974
function hasKeystoreSelectionHint(opts: AuthSource): boolean {
7075
return Boolean(
7176
(opts.account != null && String(opts.account).trim().length > 0) ||
72-
(opts.keystorePath != null && String(opts.keystorePath).trim().length > 0) ||
77+
isExplicitKeystorePath(opts.keystorePath) ||
7378
(opts.password != null && String(opts.password).trim().length > 0),
7479
);
7580
}

0 commit comments

Comments
 (0)