@solard/cli 0.2.17 → 0.2.19
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/package.json +2 -2
- package/src/index.ts +103 -72
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solard/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.19",
|
|
4
4
|
"description": "Command-line interface for the Solard SDK.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"bun": ">=1.1.0"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@solard/core": "0.2.
|
|
21
|
+
"@solard/core": "0.2.19",
|
|
22
22
|
"bs58": "^6.0.0",
|
|
23
23
|
"@solana/web3.js": "^1.98.4",
|
|
24
24
|
"measure-fn": "5.2.0"
|
package/src/index.ts
CHANGED
|
@@ -122,7 +122,7 @@ function friendlyCliError(error: unknown): string | null {
|
|
|
122
122
|
if (code === "MISSING_CONFIG" && error.message.includes("SLRD_MASTER_KEY")) {
|
|
123
123
|
return `${error.message}\n\nEnter the wallet password interactively, or set SLRD_MASTER_KEY for automation/CI.`;
|
|
124
124
|
}
|
|
125
|
-
return
|
|
125
|
+
return error.message.trim() || error.name;
|
|
126
126
|
}
|
|
127
127
|
function duration(value: string | undefined, fallbackMs: number): number {
|
|
128
128
|
if (!value) return fallbackMs;
|
|
@@ -323,6 +323,14 @@ function commandNeedsSigningVault(
|
|
|
323
323
|
return false;
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
+
function sweepUsage(): string {
|
|
327
|
+
return (
|
|
328
|
+
"Usage: slrd sweep --to <contact|wallet|address> --below <SOL> " +
|
|
329
|
+
"[--wallets <a,b,...>] [--keep <wallet=SOL,...>] [--simulate | --live] [--json]\n" +
|
|
330
|
+
"Compatibility: slrd sweep sol --to <destination> --max-balance-sol <SOL>"
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
|
|
326
334
|
async function storedWalletCount(): Promise<number> {
|
|
327
335
|
const { createTraderSolard } = await import("@solard/core");
|
|
328
336
|
const probe = createTraderSolard();
|
|
@@ -401,8 +409,9 @@ Backtesting
|
|
|
401
409
|
Transfers and consolidation
|
|
402
410
|
slrd transfer <contact|wallet|address> --wallet <source-wallet> --sol <amount> [--simulate-only]
|
|
403
411
|
slrd transfer <contact|wallet|address> --wallet <source-wallet> --token <USDC|mint> --amount <ui> [--simulate-only]
|
|
404
|
-
slrd sweep
|
|
405
|
-
|
|
412
|
+
slrd sweep --to <contact|wallet|address> --below <SOL> [--wallets <a,b,...>] [--keep <wallet=SOL,...>] [--simulate | --live] [--json]
|
|
413
|
+
Sweeps stored wallets strictly below the threshold; preview is the default
|
|
414
|
+
slrd sweep sol ... Compatibility alias; --max-balance-sol remains accepted
|
|
406
415
|
|
|
407
416
|
Token liquidation
|
|
408
417
|
slrd liquidate tokens [--except <token|mint>] [--wallets <a,b,...>] [--except-wallet <wallet>] [--except-wallets <a,b,...>] [--slippage-bps 1500] [--no-jupiter] [--burn-unsellable] [--simulate | --live]
|
|
@@ -2073,13 +2082,43 @@ async function main() {
|
|
|
2073
2082
|
return;
|
|
2074
2083
|
}
|
|
2075
2084
|
|
|
2076
|
-
if (command === "sweep"
|
|
2077
|
-
const
|
|
2085
|
+
if (command === "sweep") {
|
|
2086
|
+
const legacySolSyntax = values[0]?.toLowerCase() === "sol";
|
|
2087
|
+
const positionalDestination = legacySolSyntax ? values[1] : values[0];
|
|
2088
|
+
const extraValues = legacySolSyntax ? values.slice(2) : values.slice(1);
|
|
2089
|
+
if (extraValues.length > 0) {
|
|
2090
|
+
throw new Error(
|
|
2091
|
+
`${sweepUsage()}\nUnexpected argument: ${extraValues[0]}`,
|
|
2092
|
+
);
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
const destinationInput = flags.get("to") ?? positionalDestination;
|
|
2078
2096
|
if (!destinationInput || destinationInput === "true") {
|
|
2097
|
+
throw new Error(sweepUsage());
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
const below = flags.get("below");
|
|
2101
|
+
const maxBalance = flags.get("max-balance-sol");
|
|
2102
|
+
if (below === "true") {
|
|
2103
|
+
throw new Error(`--below requires a SOL amount.\n${sweepUsage()}`);
|
|
2104
|
+
}
|
|
2105
|
+
if (maxBalance === "true") {
|
|
2079
2106
|
throw new Error(
|
|
2080
|
-
|
|
2107
|
+
`--max-balance-sol requires a SOL amount.\n${sweepUsage()}`,
|
|
2081
2108
|
);
|
|
2082
2109
|
}
|
|
2110
|
+
if (
|
|
2111
|
+
below != null &&
|
|
2112
|
+
maxBalance != null &&
|
|
2113
|
+
maxBalance !== "true" &&
|
|
2114
|
+
below !== maxBalance
|
|
2115
|
+
) {
|
|
2116
|
+
throw new Error("Use either --below or --max-balance-sol, not both.");
|
|
2117
|
+
}
|
|
2118
|
+
const maxBalanceSol = below ?? maxBalance;
|
|
2119
|
+
if (!legacySolSyntax && maxBalanceSol == null) {
|
|
2120
|
+
throw new Error(`--below is required for slrd sweep.\n${sweepUsage()}`);
|
|
2121
|
+
}
|
|
2083
2122
|
|
|
2084
2123
|
const destination = resolveDestinationRef(slrd, destinationInput);
|
|
2085
2124
|
|
|
@@ -2120,17 +2159,8 @@ async function main() {
|
|
|
2120
2159
|
"Use either --keep-if-tokens or --keep-if-token, not both",
|
|
2121
2160
|
);
|
|
2122
2161
|
}
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
? "LIVE"
|
|
2126
|
-
: flags.has("simulate")
|
|
2127
|
-
? "SIMULATE"
|
|
2128
|
-
: "PLAN";
|
|
2129
|
-
if (!flags.has("json")) {
|
|
2130
|
-
emit(`SWEEP ${sweepMode} to=${destination.address}\n`);
|
|
2131
|
-
emit(
|
|
2132
|
-
`RPC hard limit ${process.env.SLRD_RPC_MAX_RPS ?? "5"} req/s\n`,
|
|
2133
|
-
);
|
|
2162
|
+
if (flags.has("simulate") && flags.has("live")) {
|
|
2163
|
+
throw new Error("Use either --simulate or --live, not both");
|
|
2134
2164
|
}
|
|
2135
2165
|
|
|
2136
2166
|
const options = {
|
|
@@ -2138,7 +2168,7 @@ async function main() {
|
|
|
2138
2168
|
excludeGroups,
|
|
2139
2169
|
excludePrefixes,
|
|
2140
2170
|
includeWallets: includeWallets.length ? includeWallets : undefined,
|
|
2141
|
-
maxBalanceSol
|
|
2171
|
+
maxBalanceSol,
|
|
2142
2172
|
keepSolByWallet,
|
|
2143
2173
|
defaultKeepSol: flags.get("default-keep-sol") ?? "0",
|
|
2144
2174
|
keepSolIfTokens: flags.get("keep-if-tokens"),
|
|
@@ -2152,34 +2182,34 @@ async function main() {
|
|
|
2152
2182
|
Math.trunc(int(flags, "rpc-delay-ms", 75) ?? 75),
|
|
2153
2183
|
),
|
|
2154
2184
|
delayMs: int(flags, "delay-ms", 0) ?? 0,
|
|
2155
|
-
onProgress:
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
);
|
|
2174
|
-
} else if (event.stage === "wallet-error") {
|
|
2175
|
-
emit(
|
|
2176
|
-
`FAIL ${event.index}/${event.total} @${event.row.walletName} ` +
|
|
2177
|
-
`${event.error}\n`,
|
|
2178
|
-
);
|
|
2185
|
+
onProgress:
|
|
2186
|
+
!flags.has("json") && flags.has("live")
|
|
2187
|
+
? (event: any) => {
|
|
2188
|
+
if (event.stage === "wallet-start") {
|
|
2189
|
+
emit(
|
|
2190
|
+
`SEND ${event.index}/${event.total} @${event.row.walletName} ` +
|
|
2191
|
+
`${formatRaw(event.row.sendLamports, 9)} SOL\n`,
|
|
2192
|
+
);
|
|
2193
|
+
} else if (event.stage === "wallet-done") {
|
|
2194
|
+
emit(
|
|
2195
|
+
`OK ${event.index}/${event.total} @${event.row.walletName}\n`,
|
|
2196
|
+
);
|
|
2197
|
+
} else if (event.stage === "wallet-error") {
|
|
2198
|
+
emit(
|
|
2199
|
+
`FAIL ${event.index}/${event.total} @${event.row.walletName} ` +
|
|
2200
|
+
`${event.error}\n`,
|
|
2201
|
+
);
|
|
2202
|
+
}
|
|
2179
2203
|
}
|
|
2180
|
-
|
|
2204
|
+
: undefined,
|
|
2181
2205
|
};
|
|
2182
2206
|
const plan = await planRegistrySolSweep(slrd, options);
|
|
2207
|
+
const sendRows = plan.rows.filter((row) => row.sendLamports > 0n);
|
|
2208
|
+
const destinationLabel = destination.contactName
|
|
2209
|
+
? `${destination.contactName} (${plan.destination})`
|
|
2210
|
+
: destination.walletName
|
|
2211
|
+
? `${destination.walletName} (${plan.destination})`
|
|
2212
|
+
: plan.destination;
|
|
2183
2213
|
|
|
2184
2214
|
const printablePlan = {
|
|
2185
2215
|
mode: flags.has("live")
|
|
@@ -2193,6 +2223,7 @@ async function main() {
|
|
|
2193
2223
|
contact: destination.contactName ?? null,
|
|
2194
2224
|
wallet: destination.walletName ?? null,
|
|
2195
2225
|
},
|
|
2226
|
+
belowSol: maxBalanceSol ?? null,
|
|
2196
2227
|
totalSendSol: formatRaw(plan.totalSendLamports, 9),
|
|
2197
2228
|
rows: plan.rows.map((row) => ({
|
|
2198
2229
|
wallet: row.walletName,
|
|
@@ -2216,36 +2247,33 @@ async function main() {
|
|
|
2216
2247
|
return;
|
|
2217
2248
|
}
|
|
2218
2249
|
|
|
2250
|
+
emit(`SWEEP SOL -> ${destinationLabel}\n`);
|
|
2251
|
+
if (maxBalanceSol != null) emit(`Threshold: < ${maxBalanceSol} SOL\n`);
|
|
2219
2252
|
emit(
|
|
2220
|
-
`
|
|
2221
|
-
`
|
|
2222
|
-
`
|
|
2253
|
+
`Scanned: ${plan.rows.length} Send: ${sendRows.length} ` +
|
|
2254
|
+
`Skipped: ${plan.rows.length - sendRows.length} ` +
|
|
2255
|
+
`Total: ${formatRaw(plan.totalSendLamports, 9)} SOL\n`,
|
|
2223
2256
|
);
|
|
2224
2257
|
|
|
2225
2258
|
for (const row of plan.rows) {
|
|
2226
2259
|
if (row.sendLamports <= 0n && !flags.has("show-skipped")) continue;
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2260
|
+
if (row.sendLamports > 0n) {
|
|
2261
|
+
emit(
|
|
2262
|
+
` @${row.walletName} ${formatRaw(row.balanceLamports, 9)} -> ` +
|
|
2263
|
+
`${formatRaw(row.sendLamports, 9)} SOL\n`,
|
|
2264
|
+
);
|
|
2265
|
+
} else {
|
|
2266
|
+
emit(
|
|
2267
|
+
` @${row.walletName} ${formatRaw(row.balanceLamports, 9)} ` +
|
|
2268
|
+
`SKIP ${row.skippedReason ?? "not-sendable"}\n`,
|
|
2269
|
+
);
|
|
2270
|
+
}
|
|
2236
2271
|
}
|
|
2237
2272
|
|
|
2238
|
-
emit(
|
|
2239
|
-
`\n${OWL} plan only; no signer was decrypted and nothing was submitted. ` +
|
|
2240
|
-
`Use --json for full details, then --simulate or --live.\n`,
|
|
2241
|
-
);
|
|
2273
|
+
emit(`\nPreview only. Add --simulate to verify or --live to send.\n`);
|
|
2242
2274
|
return;
|
|
2243
2275
|
}
|
|
2244
2276
|
|
|
2245
|
-
if (flags.has("simulate") && flags.has("live")) {
|
|
2246
|
-
throw new Error("Use either --simulate or --live, not both");
|
|
2247
|
-
}
|
|
2248
|
-
|
|
2249
2277
|
if (flags.has("simulate")) {
|
|
2250
2278
|
const results = await simulateRegistrySolSweep(slrd, plan, options);
|
|
2251
2279
|
if (flags.has("json")) {
|
|
@@ -2254,18 +2282,19 @@ async function main() {
|
|
|
2254
2282
|
const failed = results.filter(
|
|
2255
2283
|
(result) => result.error || result.simulation?.success === false,
|
|
2256
2284
|
).length;
|
|
2285
|
+
emit(`SWEEP SIMULATION -> ${destinationLabel}\n`);
|
|
2257
2286
|
emit(
|
|
2258
|
-
`
|
|
2259
|
-
`
|
|
2260
|
-
`to=${plan.destination}\n`,
|
|
2287
|
+
`Attempted: ${results.length} OK: ${results.length - failed} ` +
|
|
2288
|
+
`Failed: ${failed} Total: ${formatRaw(plan.totalSendLamports, 9)} SOL\n`,
|
|
2261
2289
|
);
|
|
2262
2290
|
for (const result of results) {
|
|
2263
2291
|
if (!result.error && result.simulation?.success !== false) continue;
|
|
2264
2292
|
emit(
|
|
2265
|
-
`FAIL
|
|
2293
|
+
` FAIL @${result.row.walletName} ` +
|
|
2266
2294
|
`${result.error ?? "simulation failed"}\n`,
|
|
2267
2295
|
);
|
|
2268
2296
|
}
|
|
2297
|
+
emit("No transactions submitted.\n");
|
|
2269
2298
|
}
|
|
2270
2299
|
return;
|
|
2271
2300
|
}
|
|
@@ -2277,14 +2306,14 @@ async function main() {
|
|
|
2277
2306
|
const failed = receipts.filter((result) =>
|
|
2278
2307
|
Boolean(result.error),
|
|
2279
2308
|
).length;
|
|
2309
|
+
emit(`SWEEP COMPLETE -> ${destinationLabel}\n`);
|
|
2280
2310
|
emit(
|
|
2281
|
-
`
|
|
2282
|
-
`
|
|
2283
|
-
`to=${plan.destination}\n`,
|
|
2311
|
+
`Attempted: ${receipts.length} OK: ${receipts.length - failed} ` +
|
|
2312
|
+
`Failed: ${failed} Planned total: ${formatRaw(plan.totalSendLamports, 9)} SOL\n`,
|
|
2284
2313
|
);
|
|
2285
2314
|
for (const result of receipts) {
|
|
2286
2315
|
if (!result.error) continue;
|
|
2287
|
-
emit(`FAIL
|
|
2316
|
+
emit(` FAIL @${result.row.walletName} ${result.error}\n`);
|
|
2288
2317
|
}
|
|
2289
2318
|
}
|
|
2290
2319
|
return;
|
|
@@ -2742,7 +2771,9 @@ async function main() {
|
|
|
2742
2771
|
);
|
|
2743
2772
|
return;
|
|
2744
2773
|
}
|
|
2745
|
-
throw new Error(
|
|
2774
|
+
throw new Error(
|
|
2775
|
+
`Unknown command: ${command}. Run "slrd help" for available commands.`,
|
|
2776
|
+
);
|
|
2746
2777
|
} finally {
|
|
2747
2778
|
slrd.close();
|
|
2748
2779
|
}
|