@byreal-io/byreal-cli-realclaw 0.3.13 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +57 -4
  2. package/dist/index.cjs +1104 -142
  3. package/package.json +3 -2
package/dist/index.cjs CHANGED
@@ -969,7 +969,7 @@ var require_command = __commonJS({
969
969
  var EventEmitter = require("node:events").EventEmitter;
970
970
  var childProcess = require("node:child_process");
971
971
  var path3 = require("node:path");
972
- var fs2 = require("node:fs");
972
+ var fs3 = require("node:fs");
973
973
  var process3 = require("node:process");
974
974
  var { Argument: Argument2, humanReadableArgName } = require_argument();
975
975
  var { CommanderError: CommanderError2 } = require_error();
@@ -1902,10 +1902,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
1902
1902
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1903
1903
  function findFile(baseDir, baseName) {
1904
1904
  const localBin = path3.resolve(baseDir, baseName);
1905
- if (fs2.existsSync(localBin)) return localBin;
1905
+ if (fs3.existsSync(localBin)) return localBin;
1906
1906
  if (sourceExt.includes(path3.extname(baseName))) return void 0;
1907
1907
  const foundExt = sourceExt.find(
1908
- (ext) => fs2.existsSync(`${localBin}${ext}`)
1908
+ (ext) => fs3.existsSync(`${localBin}${ext}`)
1909
1909
  );
1910
1910
  if (foundExt) return `${localBin}${foundExt}`;
1911
1911
  return void 0;
@@ -1917,7 +1917,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1917
1917
  if (this._scriptPath) {
1918
1918
  let resolvedScriptPath;
1919
1919
  try {
1920
- resolvedScriptPath = fs2.realpathSync(this._scriptPath);
1920
+ resolvedScriptPath = fs3.realpathSync(this._scriptPath);
1921
1921
  } catch (err2) {
1922
1922
  resolvedScriptPath = this._scriptPath;
1923
1923
  }
@@ -3029,11 +3029,11 @@ var require_commander = __commonJS({
3029
3029
  });
3030
3030
 
3031
3031
  // src/core/constants.ts
3032
- var INJECTED_VERSION, VERSION, CLI_NAME, NPM_PACKAGE, API_BASE_URL, API_ENDPOINTS, SOLANA_RPC_URL, SOLANA_CLUSTER, JUPITER_API_KEY, JUP_PAID_BASE, JUP_FREE_BASE, TITAN_API_URL, TITAN_AUTH_TOKEN, DFLOW_PAID_URL, DFLOW_FREE_URL, DFLOW_API_KEY, CONFIG_DIR, CONFIG_FILE, DEFAULTS, TABLE_CHARS, LOGO, EXPERIMENTAL_WARNING, DEFAULT_CONFIG, DIR_PERMISSIONS;
3032
+ var INJECTED_VERSION, VERSION, CLI_NAME, NPM_PACKAGE, API_BASE_URL, API_ENDPOINTS, SOLANA_RPC_URL, SOLANA_CLUSTER, JUPITER_API_KEY, JUP_PAID_BASE, JUP_FREE_BASE, TITAN_API_URL, TITAN_AUTH_TOKEN, DFLOW_PAID_URL, DFLOW_FREE_URL, DFLOW_API_KEY, CONFIG_DIR, CONFIG_FILE, SOLANA_MAINNET_CAIP2, PRIVY_API_BASE_PATH_DEFAULT, PRIVY_PROXY_URL_ENV, PRIVY_API_BASE_PATH_ENV, AGENT_TOKEN_ENV, REALCLAW_CONFIG_PATH, SKILL_AGENT_TOKEN_CONFIG_PATH, LEGACY_AGENT_TOKEN_PATH, PRIVY_STRATEGY_ID, PRIVY_STRATEGY_NAME, DEFAULTS, TABLE_CHARS, LOGO, EXPERIMENTAL_WARNING, DEFAULT_CONFIG, DIR_PERMISSIONS;
3033
3033
  var init_constants = __esm({
3034
3034
  "src/core/constants.ts"() {
3035
3035
  "use strict";
3036
- INJECTED_VERSION = true ? "0.3.13" : void 0;
3036
+ INJECTED_VERSION = true ? "0.4.1" : void 0;
3037
3037
  VERSION = INJECTED_VERSION ?? process.env.npm_package_version ?? "0.0.0";
3038
3038
  CLI_NAME = "byreal-cli";
3039
3039
  NPM_PACKAGE = "@byreal-io/byreal-cli-realclaw";
@@ -3077,6 +3077,16 @@ var init_constants = __esm({
3077
3077
  DFLOW_API_KEY = process.env.DFLOW_API_KEY;
3078
3078
  CONFIG_DIR = "~/.config/byreal";
3079
3079
  CONFIG_FILE = "config.json";
3080
+ SOLANA_MAINNET_CAIP2 = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
3081
+ PRIVY_API_BASE_PATH_DEFAULT = "/byreal/api/privy-proxy/v1";
3082
+ PRIVY_PROXY_URL_ENV = process.env.PRIVY_PROXY_URL;
3083
+ PRIVY_API_BASE_PATH_ENV = process.env.PRIVY_API_BASE_PATH;
3084
+ AGENT_TOKEN_ENV = process.env.AGENT_TOKEN;
3085
+ REALCLAW_CONFIG_PATH = "~/.openclaw/realclaw-config.json";
3086
+ SKILL_AGENT_TOKEN_CONFIG_PATH = "~/.openclaw/skills/agent-token/scripts/config.json";
3087
+ LEGACY_AGENT_TOKEN_PATH = "~/.openclaw/agent_token";
3088
+ PRIVY_STRATEGY_ID = "byreal_cli";
3089
+ PRIVY_STRATEGY_NAME = "Byreal CLI";
3080
3090
  DEFAULTS = {
3081
3091
  OUTPUT_FORMAT: "table",
3082
3092
  LIST_LIMIT: 100,
@@ -20229,7 +20239,7 @@ var require_constants = __commonJS({
20229
20239
  // node_modules/node-gyp-build/node-gyp-build.js
20230
20240
  var require_node_gyp_build = __commonJS({
20231
20241
  "node_modules/node-gyp-build/node-gyp-build.js"(exports2, module2) {
20232
- var fs2 = require("fs");
20242
+ var fs3 = require("fs");
20233
20243
  var path3 = require("path");
20234
20244
  var os3 = require("os");
20235
20245
  var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
@@ -20290,7 +20300,7 @@ var require_node_gyp_build = __commonJS({
20290
20300
  };
20291
20301
  function readdirSync(dir) {
20292
20302
  try {
20293
- return fs2.readdirSync(dir);
20303
+ return fs3.readdirSync(dir);
20294
20304
  } catch (err2) {
20295
20305
  return [];
20296
20306
  }
@@ -20384,7 +20394,7 @@ var require_node_gyp_build = __commonJS({
20384
20394
  return typeof window !== "undefined" && window.process && window.process.type === "renderer";
20385
20395
  }
20386
20396
  function isAlpine(platform2) {
20387
- return platform2 === "linux" && fs2.existsSync("/etc/alpine-release");
20397
+ return platform2 === "linux" && fs3.existsSync("/etc/alpine-release");
20388
20398
  }
20389
20399
  load.parseTags = parseTags;
20390
20400
  load.matchTags = matchTags;
@@ -36092,19 +36102,19 @@ var require_file_uri_to_path = __commonJS({
36092
36102
  // node_modules/bindings/bindings.js
36093
36103
  var require_bindings = __commonJS({
36094
36104
  "node_modules/bindings/bindings.js"(exports2, module2) {
36095
- var fs2 = require("fs");
36105
+ var fs3 = require("fs");
36096
36106
  var path3 = require("path");
36097
36107
  var fileURLToPath = require_file_uri_to_path();
36098
36108
  var join4 = path3.join;
36099
36109
  var dirname = path3.dirname;
36100
- var exists = fs2.accessSync && function(path4) {
36110
+ var exists = fs3.accessSync && function(path4) {
36101
36111
  try {
36102
- fs2.accessSync(path4);
36112
+ fs3.accessSync(path4);
36103
36113
  } catch (e) {
36104
36114
  return false;
36105
36115
  }
36106
36116
  return true;
36107
- } || fs2.existsSync || path3.existsSync;
36117
+ } || fs3.existsSync || path3.existsSync;
36108
36118
  var defaults = {
36109
36119
  arrow: process.env.NODE_BINDINGS_ARROW || " \u2192 ",
36110
36120
  compiled: process.env.NODE_BINDINGS_COMPILED_DIR || "compiled",
@@ -37826,6 +37836,117 @@ function configInvalidError(reason) {
37826
37836
  retryable: false
37827
37837
  });
37828
37838
  }
37839
+ function privyNotConfiguredError() {
37840
+ return new ByrealError({
37841
+ code: ErrorCodes.PRIVY_NOT_CONFIGURED,
37842
+ type: "AUTH",
37843
+ message: "Privy signing is not configured. The --execute flag requires a Privy agent token and proxy URL.",
37844
+ suggestions: [
37845
+ {
37846
+ action: "setup-realclaw",
37847
+ description: "Place ~/.openclaw/realclaw-config.json with baseUrl and wallets[]"
37848
+ },
37849
+ {
37850
+ action: "setup-legacy",
37851
+ description: "Or place ~/.openclaw/agent_token plus a Privy proxy URL in ~/.config/byreal/config.json",
37852
+ command: "byreal-cli config set privy_proxy_url <url>"
37853
+ },
37854
+ {
37855
+ action: "fallback-unsigned",
37856
+ description: "Or drop --execute to keep the default behavior of emitting an unsigned transaction for an external signer"
37857
+ }
37858
+ ],
37859
+ retryable: false
37860
+ });
37861
+ }
37862
+ function privyWalletNotFoundError(walletAddress) {
37863
+ return new ByrealError({
37864
+ code: ErrorCodes.PRIVY_WALLET_NOT_FOUND,
37865
+ type: "AUTH",
37866
+ message: `No Privy agent token found for wallet address ${walletAddress}.`,
37867
+ details: { walletAddress },
37868
+ suggestions: [
37869
+ {
37870
+ action: "check-config",
37871
+ description: 'Confirm ~/.openclaw/realclaw-config.json has a wallets[] entry with type="solana" matching this address'
37872
+ },
37873
+ {
37874
+ action: "fallback-unsigned",
37875
+ description: "Or drop --execute to skip Privy signing and emit an unsigned transaction (the default)"
37876
+ }
37877
+ ],
37878
+ retryable: false
37879
+ });
37880
+ }
37881
+ function privyAuthError(message) {
37882
+ return new ByrealError({
37883
+ code: ErrorCodes.PRIVY_AUTH_FAILED,
37884
+ type: "AUTH",
37885
+ message: `Privy authentication failed: ${message}`,
37886
+ suggestions: [
37887
+ {
37888
+ action: "check-token",
37889
+ description: "Verify that your agent token is valid and not expired. Tokens are revoked after grant revocation."
37890
+ }
37891
+ ],
37892
+ retryable: false
37893
+ });
37894
+ }
37895
+ function privyBadRequestError(message) {
37896
+ return new ByrealError({
37897
+ code: ErrorCodes.PRIVY_BAD_REQUEST,
37898
+ type: "VALIDATION",
37899
+ message: `Privy proxy rejected request: ${message}`,
37900
+ retryable: false
37901
+ });
37902
+ }
37903
+ function privyRateLimitedError() {
37904
+ return new ByrealError({
37905
+ code: ErrorCodes.PRIVY_RATE_LIMITED,
37906
+ type: "NETWORK",
37907
+ message: "Privy proxy rate-limited the request. Please retry later.",
37908
+ retryable: true
37909
+ });
37910
+ }
37911
+ function privyUpstreamError(message, retryable = true) {
37912
+ return new ByrealError({
37913
+ code: ErrorCodes.PRIVY_UPSTREAM_ERROR,
37914
+ type: "NETWORK",
37915
+ message: `Privy proxy upstream error: ${message}`,
37916
+ retryable
37917
+ });
37918
+ }
37919
+ function privyTimeoutError(timeoutMs) {
37920
+ return new ByrealError({
37921
+ code: ErrorCodes.PRIVY_TIMEOUT,
37922
+ type: "NETWORK",
37923
+ message: `Privy proxy did not respond within ${timeoutMs}ms.`,
37924
+ retryable: true
37925
+ });
37926
+ }
37927
+ function privyBusinessError(retCode, retMsg) {
37928
+ return new ByrealError({
37929
+ code: ErrorCodes.PRIVY_BUSINESS_ERROR,
37930
+ type: "BUSINESS",
37931
+ message: `Privy business error retCode=${retCode}: ${retMsg}`,
37932
+ details: { retCode, retMsg },
37933
+ retryable: false
37934
+ });
37935
+ }
37936
+ function conflictingFlagsError(flagA, flagB) {
37937
+ return new ByrealError({
37938
+ code: ErrorCodes.INVALID_PARAMETER,
37939
+ type: "VALIDATION",
37940
+ message: `Conflicting flags: ${flagA} and ${flagB} cannot be used together.`,
37941
+ suggestions: [
37942
+ {
37943
+ action: "pick-one",
37944
+ description: `Use either ${flagA} or ${flagB}, not both.`
37945
+ }
37946
+ ],
37947
+ retryable: false
37948
+ });
37949
+ }
37829
37950
  function formatErrorForOutput(error) {
37830
37951
  if (error instanceof ByrealError) {
37831
37952
  return {
@@ -37860,6 +37981,15 @@ var init_errors = __esm({
37860
37981
  POSITION_NOT_FOUND: "POSITION_NOT_FOUND",
37861
37982
  // Auth errors
37862
37983
  MISSING_WALLET_ADDRESS: "MISSING_WALLET_ADDRESS",
37984
+ // Privy signing errors
37985
+ PRIVY_NOT_CONFIGURED: "PRIVY_NOT_CONFIGURED",
37986
+ PRIVY_WALLET_NOT_FOUND: "PRIVY_WALLET_NOT_FOUND",
37987
+ PRIVY_AUTH_FAILED: "PRIVY_AUTH_FAILED",
37988
+ PRIVY_BAD_REQUEST: "PRIVY_BAD_REQUEST",
37989
+ PRIVY_RATE_LIMITED: "PRIVY_RATE_LIMITED",
37990
+ PRIVY_UPSTREAM_ERROR: "PRIVY_UPSTREAM_ERROR",
37991
+ PRIVY_TIMEOUT: "PRIVY_TIMEOUT",
37992
+ PRIVY_BUSINESS_ERROR: "PRIVY_BUSINESS_ERROR",
37863
37993
  // Config errors
37864
37994
  CONFIG_NOT_FOUND: "CONFIG_NOT_FOUND",
37865
37995
  CONFIG_INVALID: "CONFIG_INVALID",
@@ -37956,6 +38086,12 @@ function loadConfig() {
37956
38086
  ...parsed.defaults || {}
37957
38087
  }
37958
38088
  };
38089
+ if (typeof parsed.privy_proxy_url === "string" && parsed.privy_proxy_url) {
38090
+ config3.privy_proxy_url = parsed.privy_proxy_url;
38091
+ }
38092
+ if (typeof parsed.privy_api_base_path === "string" && parsed.privy_api_base_path) {
38093
+ config3.privy_api_base_path = parsed.privy_api_base_path;
38094
+ }
37959
38095
  return ok(config3);
37960
38096
  } catch (e) {
37961
38097
  if (e instanceof SyntaxError) {
@@ -38044,6 +38180,20 @@ function validateConfigValue(key, value) {
38044
38180
  }
38045
38181
  return ok(num);
38046
38182
  }
38183
+ case "privy_proxy_url": {
38184
+ try {
38185
+ new URL(value);
38186
+ return ok(value.replace(/\/+$/, ""));
38187
+ } catch {
38188
+ return err(validationError("privy_proxy_url must be a valid URL", "privy_proxy_url"));
38189
+ }
38190
+ }
38191
+ case "privy_api_base_path": {
38192
+ if (!value.startsWith("/")) {
38193
+ return err(validationError("privy_api_base_path must start with /", "privy_api_base_path"));
38194
+ }
38195
+ return ok(value.replace(/\/+$/, ""));
38196
+ }
38047
38197
  default:
38048
38198
  return ok(value);
38049
38199
  }
@@ -38062,7 +38212,9 @@ var init_config = __esm({
38062
38212
  "rpc_url",
38063
38213
  "cluster",
38064
38214
  "defaults.priority_fee_micro_lamports",
38065
- "defaults.slippage_bps"
38215
+ "defaults.slippage_bps",
38216
+ "privy_proxy_url",
38217
+ "privy_api_base_path"
38066
38218
  ]);
38067
38219
  }
38068
38220
  });
@@ -62373,9 +62525,9 @@ var require_workspace = __commonJS({
62373
62525
  programName = (0, camelcase_1.default)(programName);
62374
62526
  if (workspaceCache[programName])
62375
62527
  return workspaceCache[programName];
62376
- const fs2 = require("fs");
62528
+ const fs3 = require("fs");
62377
62529
  const path3 = require("path");
62378
- const anchorToml = toml.parse(fs2.readFileSync("Anchor.toml"));
62530
+ const anchorToml = toml.parse(fs3.readFileSync("Anchor.toml"));
62379
62531
  const clusterId = anchorToml.provider.cluster;
62380
62532
  const programs = (_a = anchorToml.programs) === null || _a === void 0 ? void 0 : _a[clusterId];
62381
62533
  let programEntry;
@@ -62389,16 +62541,16 @@ var require_workspace = __commonJS({
62389
62541
  programId = programEntry.address;
62390
62542
  } else {
62391
62543
  const idlDirPath = path3.join("target", "idl");
62392
- const fileName = fs2.readdirSync(idlDirPath).find((name) => (0, camelcase_1.default)(path3.parse(name).name) === programName);
62544
+ const fileName = fs3.readdirSync(idlDirPath).find((name) => (0, camelcase_1.default)(path3.parse(name).name) === programName);
62393
62545
  if (!fileName) {
62394
62546
  throw new Error(`Failed to find IDL of program \`${programName}\``);
62395
62547
  }
62396
62548
  idlPath = path3.join(idlDirPath, fileName);
62397
62549
  }
62398
- if (!fs2.existsSync(idlPath)) {
62550
+ if (!fs3.existsSync(idlPath)) {
62399
62551
  throw new Error(`${idlPath} doesn't exist. Did you run \`anchor build\`?`);
62400
62552
  }
62401
- const idl = JSON.parse(fs2.readFileSync(idlPath));
62553
+ const idl = JSON.parse(fs3.readFileSync(idlPath));
62402
62554
  if (programId) {
62403
62555
  idl.address = programId;
62404
62556
  }
@@ -84780,6 +84932,30 @@ init_config();
84780
84932
  var import_cli_table3 = __toESM(require_cli_table3(), 1);
84781
84933
  init_constants();
84782
84934
 
84935
+ // src/core/confirm.ts
84936
+ init_errors();
84937
+ function resolveExecutionMode(options) {
84938
+ if (options.dryRun && options.execute) {
84939
+ throw conflictingFlagsError("--dry-run", "--execute");
84940
+ }
84941
+ if (options.dryRun) return "dry-run";
84942
+ if (options.execute) return "execute";
84943
+ return "unsigned-tx";
84944
+ }
84945
+ function printDryRunBanner() {
84946
+ console.error(source_default.yellow.bold("\n[DRY RUN] No transaction will be generated\n"));
84947
+ }
84948
+ function printPrivySignBanner() {
84949
+ console.error(
84950
+ source_default.green.bold(
84951
+ "\n[PRIVY SIGN] Signing and broadcasting via Privy wallet\n"
84952
+ )
84953
+ );
84954
+ }
84955
+
84956
+ // src/cli/output/formatters.ts
84957
+ init_errors();
84958
+
84783
84959
  // src/core/amounts.ts
84784
84960
  function uiToRaw(uiAmount, decimals) {
84785
84961
  const parts = uiAmount.split(".");
@@ -84816,6 +84992,18 @@ function outputJson(data, startTime) {
84816
84992
  function outputErrorJson(error) {
84817
84993
  console.log(JSON.stringify({ success: false, error }, null, 2));
84818
84994
  }
84995
+ function safeResolveExecutionMode(options, format) {
84996
+ try {
84997
+ return resolveExecutionMode(options);
84998
+ } catch (e) {
84999
+ if (e instanceof ByrealError) {
85000
+ if (format === "json") outputErrorJson(e.toJSON());
85001
+ else outputErrorTable(e.toJSON());
85002
+ process.exit(1);
85003
+ }
85004
+ throw e;
85005
+ }
85006
+ }
84819
85007
  function createTable(headers) {
84820
85008
  return new import_cli_table3.default({
84821
85009
  head: headers.map((h) => source_default.cyan.bold(h)),
@@ -85051,6 +85239,12 @@ function outputConfigList(config3) {
85051
85239
  ["defaults.priority_fee_micro_lamports", String(config3.defaults.priority_fee_micro_lamports)],
85052
85240
  ["defaults.slippage_bps", String(config3.defaults.slippage_bps)]
85053
85241
  );
85242
+ if (config3.privy_proxy_url) {
85243
+ table.push(["privy_proxy_url", config3.privy_proxy_url]);
85244
+ }
85245
+ if (config3.privy_api_base_path) {
85246
+ table.push(["privy_api_base_path", config3.privy_api_base_path]);
85247
+ }
85054
85248
  console.log(table.toString());
85055
85249
  }
85056
85250
  function outputConfigValue(key, value) {
@@ -85547,6 +85741,31 @@ function outputRewardOrderResult(result) {
85547
85741
  console.log();
85548
85742
  }
85549
85743
  }
85744
+ function outputTransactionResult(signature) {
85745
+ console.log(source_default.green("\n Transaction submitted (not yet finalized)"));
85746
+ console.log(source_default.gray(` Signature: ${signature}`));
85747
+ console.log(source_default.blue(` https://solscan.io/tx/${signature}
85748
+ `));
85749
+ }
85750
+ function outputMultiBroadcastResult(result) {
85751
+ const total = result.results.length;
85752
+ const headline = result.failCount === 0 ? source_default.green(`
85753
+ ${total} transactions submitted (not yet finalized)`) : source_default.yellow(
85754
+ `
85755
+ ${result.successCount}/${total} transactions submitted (${result.failCount} failed at submission)`
85756
+ );
85757
+ console.log(headline);
85758
+ for (const r of result.results) {
85759
+ const idx = `[${r.index + 1}/${total}]`;
85760
+ if (r.signature) {
85761
+ console.log(source_default.gray(` ${idx} ${r.signature}`));
85762
+ console.log(source_default.blue(` ${idx} https://solscan.io/tx/${r.signature}`));
85763
+ } else {
85764
+ console.log(source_default.red(` ${idx} failed: ${r.error ?? "unknown error"}`));
85765
+ }
85766
+ }
85767
+ console.log();
85768
+ }
85550
85769
 
85551
85770
  // src/cli/commands/pools.ts
85552
85771
  async function listPools2(options, globalOptions) {
@@ -86104,12 +86323,38 @@ byreal-cli catalog show dex.pool.list
86104
86323
  | -v, --version | Show version |
86105
86324
  | -h, --help | Show help |
86106
86325
 
86326
+ ## Three Execution Modes (write commands)
86327
+
86328
+ Every write command (\`swap execute\`, \`positions open/close/increase/decrease/claim/claim-rewards/claim-bonus/copy\`, all plugin write commands like \`jup swap\` / \`dflow swap\` / \`titan swap\` / \`kamino deposit/withdraw\` / \`rent reclaim\` / \`sweep execute\`) supports three modes:
86329
+
86330
+ | Mode | Flag | What it does | Output |
86331
+ |------|------|--------------|--------|
86332
+ | **unsigned-tx** (default) | (none) | Emit base64 unsigned transaction(s) so an external signer can take over | \`{ unsignedTransactions: [...] }\` (identical to the pre-Privy CLI) |
86333
+ | **execute** | \`--execute\` | Sign + broadcast on-chain via Privy proxy | \`{ signature: "<txid>", explorer: "https://solscan.io/tx/<txid>" }\` (single tx) or \`{ results: [{index, signature?, error?}], successCount, failCount }\` (multi-tx) |
86334
+ | **dry-run** | \`--dry-run\` | Preview only \u2014 no transaction generated, no signing | Preview JSON / table |
86335
+
86336
+ \`--dry-run\` and \`--execute\` are mutually exclusive (CLI errors on both).
86337
+
86338
+ **Backward-compatible default**: every write command still emits unsigned transactions by default. To sign + broadcast through the Byreal Privy proxy, add \`--execute\` explicitly.
86339
+
86340
+ ### Privy Configuration
86341
+
86342
+ \`--execute\` requires a Privy agent token + proxy URL. Sources (highest precedence first):
86343
+
86344
+ 1. Env vars: \`AGENT_TOKEN\`, \`PRIVY_PROXY_URL\`, \`PRIVY_API_BASE_PATH\`
86345
+ 2. \`~/.openclaw/realclaw-config.json\` \u2014 \`{ baseUrl, apiBasePath?, wallets: [{ address, token, type: "solana" | "evm" }] }\`. The CLI picks the wallet whose \`address\` matches \`--wallet-address\` and whose \`type === "solana"\`.
86346
+ 3. Legacy: \`~/.openclaw/agent_token\` (single-token file) plus \`~/.config/byreal/config.json#privy_proxy_url\` (or \`byreal-cli config set privy_proxy_url <url>\`).
86347
+
86348
+ If Privy is not configured, \`--execute\` fails with \`PRIVY_NOT_CONFIGURED\` and includes actionable suggestions (configure realclaw / configure legacy / drop \`--execute\` to keep the default unsigned output). The CLI never silently degrades.
86349
+
86350
+ If \`--wallet-address\` does not match any \`type=solana\` entry in \`realclaw-config.json\`, the CLI fails with \`PRIVY_WALLET_NOT_FOUND\` (rather than fall back to a different wallet's token).
86351
+
86107
86352
  ## Hard Constraints (Do NOT violate)
86108
86353
 
86109
86354
  1. **\`-o json\` only for parsing** \u2014 when you need to extract values for the next command. When the user wants to **see** results, omit it \u2014 the CLI has built-in tables, K-line charts, and formatted analysis. Never fetch JSON then re-draw them yourself.
86110
86355
  2. **Never truncate on-chain data** \u2014 always display the FULL string for: transaction signatures, mint addresses, pool addresses, NFT addresses, wallet addresses. Never use \`xxx...yyy\`.
86111
- 3. **Never request or display private keys** \u2014 the CLI does not handle private keys. All write commands output unsigned transactions.
86112
- 4. **\`--wallet-address\` required for all write commands** \u2014 the user must provide their Solana wallet public key. No local wallet setup or keypair storage. Preview with \`--dry-run\` first, remove \`--dry-run\` to generate the unsigned transaction.
86356
+ 3. **Never request or display private keys** \u2014 the CLI does not store private keys locally. Signing is performed by the Privy proxy via the agent token; private keys live in Privy.
86357
+ 4. **\`--wallet-address\` required for all write commands** \u2014 the user must provide their Solana wallet public key. Default mode emits an unsigned transaction (back-compat); add \`--execute\` to sign + broadcast via Privy, or \`--dry-run\` to preview.
86113
86358
  5. **Large amounts (> $10,000)**: Require explicit user confirmation
86114
86359
  6. **High slippage (> 200 bps)**: Warn user before proceeding
86115
86360
  7. **Token amounts use UI format** \u2014 \`--amount 0.1\` means 0.1 tokens, not lamports. The CLI auto-resolves decimals from mint address. Never convert manually. Use \`--raw\` only for raw units.
@@ -86136,7 +86381,8 @@ Present on-chain data first, then external context, then synthesize how external
86136
86381
  | List tokens | \`byreal-cli tokens list\` |
86137
86382
  | Global stats | \`byreal-cli overview\` |
86138
86383
  | Swap preview | \`byreal-cli swap execute --input-mint <mint> --output-mint <mint> --amount <amount> --dry-run\` |
86139
- | Swap execute | \`byreal-cli swap execute --input-mint <mint> --output-mint <mint> --amount <amount> --wallet-address <addr>\` |
86384
+ | Swap (unsigned) | \`byreal-cli swap execute --input-mint <mint> --output-mint <mint> --amount <amount> --wallet-address <addr>\` |
86385
+ | Swap (sign + broadcast) | \`byreal-cli swap execute --input-mint <mint> --output-mint <mint> --amount <amount> --wallet-address <addr> --execute\` |
86140
86386
  | List positions | \`byreal-cli positions list\` |
86141
86387
  | Open position (USD) | \`byreal-cli positions open --pool <addr> --price-lower <p> --price-upper <p> --amount-usd <usd> --wallet-address <addr>\` |
86142
86388
  | Open position (token) | \`byreal-cli positions open --pool <addr> --price-lower <p> --price-upper <p> --base <token> --amount <amount> --wallet-address <addr>\` |
@@ -86194,13 +86440,23 @@ For detailed parameter info on any command, run: \`byreal-cli catalog show <capa
86194
86440
  - **Incentive rewards** \u2192 \`positions claim-rewards\` (team-added pool incentives)
86195
86441
  - **Copy bonus** \u2192 \`positions claim-bonus\` (referral rewards from copy trading)
86196
86442
 
86197
- ### Claim Rewards / Bonus: 3-Step Flow
86198
- \`claim-rewards\` and \`claim-bonus\` require a multi-step flow (backend co-signs):
86199
- 1. **Preview**: \`positions claim-rewards --dry-run --wallet-address <addr> -o json\`
86200
- 2. **Generate unsigned tx**: \`positions claim-rewards --wallet-address <addr> -o json\` \u2192 returns \`orderCode\` + \`unsignedTransactions\` (each with \`txPayload\`, \`txCode\`)
86201
- 3. **Submit signed tx**: After wallet signs each \`txPayload\`, call \`positions submit-rewards --order-code "ORD_xxx" --signed-payloads '[{"txCode":"TX_xxx","poolAddress":"...","signedTx":"<base64>"}]' --wallet-address <addr>\`
86443
+ ### Claim Rewards / Bonus: One-Shot Atomic Command (with --execute)
86444
+
86445
+ When \`--execute\` is set, \`claim-rewards\` and \`claim-bonus\` are atomic. The CLI internally does encode \u2192 Privy sign \u2192 backend submit, returns the final order result. **Do not chain skills or call \`submit-rewards\` manually when running with \`--execute\`.**
86446
+
86447
+ \`\`\`
86448
+ byreal-cli positions claim-rewards --wallet-address <addr> --execute -o json
86449
+ # \u2192 { orderCode, txList: [...], claimTokenList: [...] }
86450
+ \`\`\`
86451
+
86452
+ \`txList\` contains the on-chain signatures the backend broadcast. \`claimTokenList\` shows which tokens were claimed.
86453
+
86454
+ **Default multi-step flow** (no \`--execute\` flag \u2014 back-compat for external signers):
86455
+ 1. \`positions claim-rewards --wallet-address <addr> -o json\` \u2192 returns \`{ orderCode, unsignedTransactions: [{ poolAddress, txPayload, txCode, tokens }] }\`
86456
+ 2. External signer signs each \`txPayload\`
86457
+ 3. \`positions submit-rewards --order-code <orderCode> --signed-payloads '[{"txCode":"...","poolAddress":"...","signedTx":"<base64>"}]' --wallet-address <addr>\`
86202
86458
 
86203
- **Critical**: Do NOT skip Step 3 \u2014 without \`submit-rewards\`, signed transactions are never broadcast. The \`orderCode\` ties steps together. For \`claim-bonus\`: same flow, replace \`claim-rewards\` with \`claim-bonus\` in Step 1-2.
86459
+ The multi-step flow is the default for backward compatibility; if Privy is configured, prefer \`--execute\` for the one-shot atomic command.
86204
86460
 
86205
86461
  ### Copy Bonus Epochs
86206
86462
  - **Accruing**: Current epoch, bonus accumulating
@@ -86211,7 +86467,7 @@ For detailed parameter info on any command, run: \`byreal-cli catalog show <capa
86211
86467
  \`positions open --dry-run\` and \`positions increase --dry-run\` automatically check wallet balance. If insufficient, response includes \`balanceWarnings\` (deficit) and \`walletBalances\` (all available tokens) \u2014 no need to run \`wallet balance\` separately.
86212
86468
 
86213
86469
  ### Config Keys
86214
- Supported keys for \`config get/set\`: rpc_url, cluster, defaults.slippage_bps, defaults.priority_fee_micro_lamports
86470
+ Supported keys for \`config get/set\`: rpc_url, cluster, defaults.slippage_bps, defaults.priority_fee_micro_lamports, privy_proxy_url, privy_api_base_path
86215
86471
 
86216
86472
  ## Workflow: Finding Investment Opportunities
86217
86473
 
@@ -86229,7 +86485,7 @@ When the user asks about investment opportunities, potential pools, or yield far
86229
86485
  - USD budget: \`positions open --pool <id> --price-lower <p> --price-upper <p> --amount-usd <usd> --dry-run -o json\`
86230
86486
  - Token amount: \`positions open --pool <id> --price-lower <p> --price-upper <p> --base MintA --amount <amt> --dry-run -o json\`
86231
86487
  4. **If insufficient balance**: dry-run response includes \`balanceWarnings\` (deficit) + \`walletBalances\` (all tokens). Pick a swap source from ANY token in the wallet (prefer highest USD balance, stablecoins/SOL for lower slippage), swap to cover the deficit. **Wait 3-5 seconds** after swap before re-running dry-run (RPC propagation delay).
86232
- 5. **Execute**: remove \`--dry-run\`, add \`--wallet-address <addr>\` to generate the unsigned transaction
86488
+ 5. **Run for real**: drop \`--dry-run\` (keep \`--wallet-address <addr>\`). The default emits an unsigned base64 transaction \`{ unsignedTransactions: [...] }\` for an external signer (back-compat). Add \`--execute\` to sign + broadcast via Privy directly \u2192 \`{ signature, explorer }\`.
86233
86489
 
86234
86490
  ## Workflow: Increase/Decrease Liquidity
86235
86491
 
@@ -86239,12 +86495,12 @@ When user wants to add more liquidity to an existing position or partially withd
86239
86495
  1. \`byreal-cli positions list -o json\` \u2014 find the position's NFT mint address
86240
86496
  2. \`byreal-cli positions increase --nft-mint <nft-mint> --amount-usd <usd> --dry-run -o json\` \u2014 preview (includes balance check)
86241
86497
  3. If insufficient balance \u2192 swap to get required tokens (see "Insufficient Balance" workflow)
86242
- 4. \`byreal-cli positions increase --nft-mint <nft-mint> --amount-usd <usd> --wallet-address <addr> -o json\` \u2014 generate unsigned transaction
86498
+ 4. \`byreal-cli positions increase --nft-mint <nft-mint> --amount-usd <usd> --wallet-address <addr> -o json\` \u2014 emit unsigned tx (default). Add \`--execute\` to sign + broadcast via Privy.
86243
86499
 
86244
86500
  **Decrease liquidity** (partial withdrawal):
86245
86501
  1. \`byreal-cli positions list -o json\` \u2014 find the position's NFT mint address
86246
86502
  2. \`byreal-cli positions decrease --nft-mint <nft-mint> --percentage 50 --dry-run -o json\` \u2014 preview how much you'll receive
86247
- 3. \`byreal-cli positions decrease --nft-mint <nft-mint> --percentage 50 --wallet-address <addr> -o json\` \u2014 generate unsigned transaction
86503
+ 3. \`byreal-cli positions decrease --nft-mint <nft-mint> --percentage 50 --wallet-address <addr> -o json\` \u2014 emit unsigned tx (default). Add \`--execute\` to sign + broadcast via Privy.
86248
86504
 
86249
86505
  **Key distinction**: Use \`decrease\` to partially withdraw while keeping the position open. Use \`close\` to fully exit and burn the NFT.
86250
86506
 
@@ -86290,14 +86546,15 @@ When user asks vague questions like "\u6709\u4EC0\u4E48\u4ED3\u4F4D\u53EF\u4EE5
86290
86546
 
86291
86547
  Default to \`byreal-cli swap execute\`. Fall back to \`jup swap\` / \`dflow swap\` only if Byreal returns no route, or the user names an aggregator explicitly.
86292
86548
 
86293
- ## Workflow: Jupiter / DFlow Swap
86549
+ ## Workflow: Jupiter / Titan / DFlow Swap
86294
86550
 
86295
86551
  \`\`\`
86296
- byreal-cli jup swap --input-mint <mint> --output-mint <mint> --amount <amt> [--dry-run] --wallet-address <addr>
86297
- byreal-cli dflow swap --input-mint <mint> --output-mint <mint> --amount <amt> [--dry-run] --wallet-address <addr>
86552
+ byreal-cli jup swap --input-mint <mint> --output-mint <mint> --amount <amt> [--dry-run|--execute] --wallet-address <addr>
86553
+ byreal-cli titan swap --input-mint <mint> --output-mint <mint> --amount <amt> [--dry-run|--execute] --wallet-address <addr>
86554
+ byreal-cli dflow swap --input-mint <mint> --output-mint <mint> --amount <amt> [--dry-run|--execute] --wallet-address <addr>
86298
86555
  \`\`\`
86299
86556
 
86300
- Output: \`{ unsignedTransactions: [base64] }\`. DFlow optionally reads \`DFLOW_API_KEY\`.
86557
+ Default (no flag) emits \`{ unsignedTransactions: [base64] }\` for back-compat. \`--execute\` signs + broadcasts via Privy \u2192 output \`{ signature, explorer }\`. DFlow optionally reads \`DFLOW_API_KEY\`. Titan reads \`TITAN_AUTH_TOKEN\` if proxy unreachable.
86301
86558
 
86302
86559
  ## Workflow: Idle Yield with Kamino
86303
86560
 
@@ -86410,17 +86667,311 @@ async function resolveDecimals(mint) {
86410
86667
  return decimals;
86411
86668
  }
86412
86669
 
86413
- // src/core/confirm.ts
86414
- function resolveExecutionMode(options) {
86415
- if (options.dryRun) return "dry-run";
86416
- return "execute";
86670
+ // src/plugins/jupiter/commands.ts
86671
+ init_errors();
86672
+
86673
+ // src/privy/config.ts
86674
+ var fs2 = __toESM(require("node:fs"), 1);
86675
+ init_constants();
86676
+ init_config();
86677
+ init_security();
86678
+ function loadRealclawConfig() {
86679
+ const path3 = expandTilde(REALCLAW_CONFIG_PATH);
86680
+ if (!fs2.existsSync(path3)) return null;
86681
+ try {
86682
+ const content = fs2.readFileSync(path3, "utf-8");
86683
+ const parsed = JSON.parse(content);
86684
+ if (!parsed || typeof parsed !== "object") return null;
86685
+ const out = {};
86686
+ const obj = parsed;
86687
+ if (typeof obj.baseUrl === "string" && obj.baseUrl) out.baseUrl = obj.baseUrl;
86688
+ if (typeof obj.apiBasePath === "string" && obj.apiBasePath)
86689
+ out.apiBasePath = obj.apiBasePath;
86690
+ if (Array.isArray(obj.wallets)) {
86691
+ const wallets = [];
86692
+ for (const raw of obj.wallets) {
86693
+ if (!raw || typeof raw !== "object") continue;
86694
+ const w = raw;
86695
+ if (typeof w.address === "string" && typeof w.token === "string" && (w.type === "solana" || w.type === "evm")) {
86696
+ wallets.push({
86697
+ address: w.address,
86698
+ token: w.token,
86699
+ type: w.type
86700
+ });
86701
+ }
86702
+ }
86703
+ if (wallets.length > 0) out.wallets = wallets;
86704
+ }
86705
+ return out;
86706
+ } catch {
86707
+ return null;
86708
+ }
86417
86709
  }
86418
- function printDryRunBanner() {
86419
- console.log(source_default.yellow.bold("\n[DRY RUN] No transaction will be generated\n"));
86710
+ function loadSkillAgentTokenConfig() {
86711
+ const path3 = expandTilde(SKILL_AGENT_TOKEN_CONFIG_PATH);
86712
+ if (!fs2.existsSync(path3)) return null;
86713
+ try {
86714
+ const content = fs2.readFileSync(path3, "utf-8");
86715
+ const parsed = JSON.parse(content);
86716
+ if (!parsed || typeof parsed !== "object") return null;
86717
+ const obj = parsed;
86718
+ const out = {};
86719
+ if (typeof obj.baseUrl === "string" && obj.baseUrl) out.baseUrl = obj.baseUrl;
86720
+ if (typeof obj.apiBasePath === "string" && obj.apiBasePath)
86721
+ out.apiBasePath = obj.apiBasePath;
86722
+ return out;
86723
+ } catch {
86724
+ return null;
86725
+ }
86726
+ }
86727
+ function loadAgentToken(walletAddress) {
86728
+ const envToken = AGENT_TOKEN_ENV?.trim();
86729
+ if (envToken) return envToken;
86730
+ const realclaw = loadRealclawConfig();
86731
+ if (realclaw?.wallets && realclaw.wallets.length > 0) {
86732
+ const solWallets = realclaw.wallets.filter((w) => w.type === "solana");
86733
+ if (solWallets.length > 0) {
86734
+ if (walletAddress) {
86735
+ const match = solWallets.find((w) => w.address === walletAddress);
86736
+ if (match) return match.token;
86737
+ return null;
86738
+ }
86739
+ return solWallets[0].token;
86740
+ }
86741
+ }
86742
+ try {
86743
+ const path3 = expandTilde(LEGACY_AGENT_TOKEN_PATH);
86744
+ if (fs2.existsSync(path3)) {
86745
+ const content = fs2.readFileSync(path3, "utf-8").trim();
86746
+ if (content.length > 0) return content;
86747
+ }
86748
+ } catch {
86749
+ }
86750
+ return null;
86751
+ }
86752
+ function loadPrivyConfig() {
86753
+ let proxyUrl;
86754
+ let apiBasePath;
86755
+ if (PRIVY_PROXY_URL_ENV) proxyUrl = PRIVY_PROXY_URL_ENV;
86756
+ if (PRIVY_API_BASE_PATH_ENV) apiBasePath = PRIVY_API_BASE_PATH_ENV;
86757
+ if (!proxyUrl || !apiBasePath) {
86758
+ const realclaw = loadRealclawConfig();
86759
+ if (realclaw) {
86760
+ if (!proxyUrl && realclaw.baseUrl) proxyUrl = realclaw.baseUrl;
86761
+ if (!apiBasePath && realclaw.apiBasePath) apiBasePath = realclaw.apiBasePath;
86762
+ }
86763
+ }
86764
+ if (!proxyUrl || !apiBasePath) {
86765
+ const skill = loadSkillAgentTokenConfig();
86766
+ if (skill) {
86767
+ if (!proxyUrl && skill.baseUrl) proxyUrl = skill.baseUrl;
86768
+ if (!apiBasePath && skill.apiBasePath) apiBasePath = skill.apiBasePath;
86769
+ }
86770
+ }
86771
+ if (!proxyUrl || !apiBasePath) {
86772
+ const cfgResult = loadConfig();
86773
+ if (cfgResult.ok) {
86774
+ const cfg = cfgResult.value;
86775
+ if (!proxyUrl && cfg.privy_proxy_url) proxyUrl = cfg.privy_proxy_url;
86776
+ if (!apiBasePath && cfg.privy_api_base_path)
86777
+ apiBasePath = cfg.privy_api_base_path;
86778
+ }
86779
+ }
86780
+ if (!proxyUrl) return null;
86781
+ return {
86782
+ proxyUrl: proxyUrl.replace(/\/+$/, ""),
86783
+ apiBasePath: (apiBasePath || PRIVY_API_BASE_PATH_DEFAULT).replace(/\/+$/, "")
86784
+ };
86420
86785
  }
86421
86786
 
86422
- // src/plugins/jupiter/commands.ts
86787
+ // src/privy/client.ts
86788
+ init_constants();
86789
+ init_types();
86423
86790
  init_errors();
86791
+
86792
+ // src/privy/types.ts
86793
+ function isBgwEnvelope(env2) {
86794
+ return env2 !== null && typeof env2 === "object" && "result" in env2 && typeof env2.result === "object";
86795
+ }
86796
+ function unwrapEnvelope(env2) {
86797
+ if (isBgwEnvelope(env2)) return env2.result;
86798
+ return env2;
86799
+ }
86800
+
86801
+ // src/privy/client.ts
86802
+ var SIGN_PATH = "/sign/solana-transaction";
86803
+ var SIGN_TIMEOUT_MS = DEFAULTS.REQUEST_TIMEOUT_MS;
86804
+ async function privyPost(token, config3, path3, body) {
86805
+ const url = `${config3.proxyUrl}${config3.apiBasePath}${path3}`;
86806
+ if (process.env.DEBUG) {
86807
+ console.error(`[DEBUG] Privy POST ${url}`);
86808
+ }
86809
+ let res;
86810
+ try {
86811
+ res = await fetch(url, {
86812
+ method: "POST",
86813
+ headers: {
86814
+ "Content-Type": "application/json",
86815
+ Authorization: `Bearer ${token}`,
86816
+ "User-Agent": "byreal-cli"
86817
+ },
86818
+ body: JSON.stringify(body),
86819
+ signal: AbortSignal.timeout(SIGN_TIMEOUT_MS)
86820
+ });
86821
+ } catch (e) {
86822
+ if (e instanceof DOMException && e.name === "TimeoutError") {
86823
+ return err(privyTimeoutError(SIGN_TIMEOUT_MS));
86824
+ }
86825
+ const msg = e?.message ?? "Network error";
86826
+ return err(privyUpstreamError(msg, true));
86827
+ }
86828
+ if (res.status === 401 || res.status === 403) {
86829
+ const text = await res.text().catch(() => "");
86830
+ return err(privyAuthError(text || `HTTP ${res.status}`));
86831
+ }
86832
+ if (res.status === 422) {
86833
+ const text = await res.text().catch(() => "");
86834
+ return err(privyBadRequestError(text || `HTTP ${res.status}`));
86835
+ }
86836
+ if (res.status === 429) {
86837
+ return err(privyRateLimitedError());
86838
+ }
86839
+ if (!res.ok) {
86840
+ const text = await res.text().catch(() => "");
86841
+ return err(privyUpstreamError(`HTTP ${res.status}: ${text}`, res.status >= 500));
86842
+ }
86843
+ let raw;
86844
+ try {
86845
+ raw = await res.json();
86846
+ } catch {
86847
+ return err(privyUpstreamError("Invalid JSON response from Privy proxy"));
86848
+ }
86849
+ const envelope = unwrapEnvelope(raw);
86850
+ if (process.env.DEBUG) {
86851
+ console.error(
86852
+ `[DEBUG] Privy response: success=${envelope.success} retCode=${envelope.retCode} retMsg=${envelope.retMsg ?? ""}`
86853
+ );
86854
+ }
86855
+ if (envelope.retCode !== 0 || envelope.success === false) {
86856
+ const retMsg = envelope.retMsg ?? "";
86857
+ return err(privyBusinessError(envelope.retCode, retMsg));
86858
+ }
86859
+ if (envelope.data === null || envelope.data === void 0) {
86860
+ return err(privyUpstreamError("Empty data in Privy proxy response"));
86861
+ }
86862
+ return ok(envelope.data);
86863
+ }
86864
+ async function signTransaction(token, config3, unsignedTx) {
86865
+ const body = {
86866
+ transaction: unsignedTx,
86867
+ broadcast: false,
86868
+ strategyId: PRIVY_STRATEGY_ID,
86869
+ strategyName: PRIVY_STRATEGY_NAME
86870
+ };
86871
+ const result = await privyPost(
86872
+ token,
86873
+ config3,
86874
+ SIGN_PATH,
86875
+ body
86876
+ );
86877
+ if (!result.ok) return result;
86878
+ const nested = result.value.data?.signed_transaction;
86879
+ if (nested) return ok(nested);
86880
+ const flat = result.value.signedTransaction;
86881
+ if (flat) return ok(flat);
86882
+ return err(privyUpstreamError("No signed_transaction in Privy response"));
86883
+ }
86884
+ async function signAndBroadcast(token, config3, unsignedTx, caip2) {
86885
+ const body = {
86886
+ transaction: unsignedTx,
86887
+ broadcast: true,
86888
+ caip2,
86889
+ strategyId: PRIVY_STRATEGY_ID,
86890
+ strategyName: PRIVY_STRATEGY_NAME
86891
+ };
86892
+ const result = await privyPost(
86893
+ token,
86894
+ config3,
86895
+ SIGN_PATH,
86896
+ body
86897
+ );
86898
+ if (!result.ok) return result;
86899
+ if (!result.value.hash) {
86900
+ return err(privyUpstreamError("No transaction hash in Privy broadcast response"));
86901
+ }
86902
+ return ok(result.value.hash);
86903
+ }
86904
+
86905
+ // src/privy/execute.ts
86906
+ init_constants();
86907
+ init_types();
86908
+ init_errors();
86909
+ function getPrivyContext(walletAddress) {
86910
+ const config3 = loadPrivyConfig();
86911
+ if (!config3) return null;
86912
+ const token = loadAgentToken(walletAddress);
86913
+ if (!token) {
86914
+ if (walletAddress) {
86915
+ const realclaw = loadRealclawConfig();
86916
+ const hasSolWallets = realclaw?.wallets?.some((w) => w.type === "solana") ?? false;
86917
+ if (hasSolWallets) {
86918
+ throw privyWalletNotFoundError(walletAddress);
86919
+ }
86920
+ }
86921
+ return null;
86922
+ }
86923
+ return { token, config: config3, caip2: SOLANA_MAINNET_CAIP2 };
86924
+ }
86925
+ function requirePrivyContext(walletAddress) {
86926
+ const ctx = getPrivyContext(walletAddress);
86927
+ if (!ctx) throw privyNotConfiguredError();
86928
+ return ctx;
86929
+ }
86930
+ async function privyBroadcastOne(ctx, unsignedTx) {
86931
+ if (process.env.DEBUG) {
86932
+ console.error(source_default.gray("[DEBUG] Privy: signing + broadcasting transaction..."));
86933
+ }
86934
+ const r = await signAndBroadcast(ctx.token, ctx.config, unsignedTx, ctx.caip2);
86935
+ if (!r.ok) return r;
86936
+ return ok({ signature: r.value });
86937
+ }
86938
+ async function privyBroadcastMany(ctx, unsignedTxs) {
86939
+ const results = [];
86940
+ let successCount = 0;
86941
+ let failCount = 0;
86942
+ for (let i = 0; i < unsignedTxs.length; i++) {
86943
+ if (process.env.DEBUG) {
86944
+ console.error(
86945
+ source_default.gray(`[DEBUG] Privy: broadcasting tx ${i + 1}/${unsignedTxs.length}...`)
86946
+ );
86947
+ }
86948
+ const r = await signAndBroadcast(ctx.token, ctx.config, unsignedTxs[i], ctx.caip2);
86949
+ if (r.ok) {
86950
+ results.push({ index: i, signature: r.value });
86951
+ successCount++;
86952
+ } else {
86953
+ results.push({ index: i, error: r.error.message });
86954
+ failCount++;
86955
+ }
86956
+ }
86957
+ return ok({ results, successCount, failCount });
86958
+ }
86959
+ async function privySignMany(ctx, unsignedTxs) {
86960
+ const signedTxs = [];
86961
+ for (let i = 0; i < unsignedTxs.length; i++) {
86962
+ if (process.env.DEBUG) {
86963
+ console.error(
86964
+ source_default.gray(`[DEBUG] Privy: signing tx ${i + 1}/${unsignedTxs.length} (no broadcast)...`)
86965
+ );
86966
+ }
86967
+ const r = await signTransaction(ctx.token, ctx.config, unsignedTxs[i]);
86968
+ if (!r.ok) return r;
86969
+ signedTxs.push({ index: i, signedTx: r.value });
86970
+ }
86971
+ return ok({ signedTxs });
86972
+ }
86973
+
86974
+ // src/plugins/jupiter/commands.ts
86424
86975
  init_constants();
86425
86976
 
86426
86977
  // src/plugins/jupiter/api.ts
@@ -86765,11 +87316,11 @@ function fallbackHint(route) {
86765
87316
  return null;
86766
87317
  }
86767
87318
  function createJupSwapCommand() {
86768
- return new Command("swap").description("Swap tokens via Jupiter aggregator").requiredOption("--input-mint <address>", "Input token mint address").requiredOption("--output-mint <address>", "Output token mint address").requiredOption("--amount <amount>", "Amount to swap (UI amount, decimals auto-resolved)").option("--slippage <bps>", "Slippage tolerance in basis points").option("--raw", "Amount is already in raw (smallest unit) format").option("--dry-run", "Preview the swap without generating a transaction").action(async (options, cmdObj) => {
87319
+ return new Command("swap").description("Swap tokens via Jupiter aggregator").requiredOption("--input-mint <address>", "Input token mint address").requiredOption("--output-mint <address>", "Output token mint address").requiredOption("--amount <amount>", "Amount to swap (UI amount, decimals auto-resolved)").option("--slippage <bps>", "Slippage tolerance in basis points").option("--raw", "Amount is already in raw (smallest unit) format").option("--dry-run", "Preview the swap without generating a transaction").option("--execute", "Sign + broadcast on-chain via Privy (default emits unsigned tx for back-compat)").action(async (options, cmdObj) => {
86769
87320
  const globalOptions = cmdObj.optsWithGlobals();
86770
87321
  const format = globalOptions.output;
86771
87322
  const startTime = Date.now();
86772
- const mode = resolveExecutionMode(options);
87323
+ const mode = safeResolveExecutionMode(options, format);
86773
87324
  const walletAddress = globalOptions.walletAddress;
86774
87325
  if (!walletAddress) {
86775
87326
  const e = missingWalletAddressError();
@@ -86831,7 +87382,7 @@ Error: ${msg}`));
86831
87382
  console.log(table.toString());
86832
87383
  const hint = fallbackHint(getLastRoute());
86833
87384
  if (hint) console.error(source_default.gray(`[byreal] ${hint}`));
86834
- console.log(source_default.yellow("\n Remove --dry-run to generate the unsigned transaction"));
87385
+ console.log(source_default.yellow("\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy."));
86835
87386
  }
86836
87387
  return;
86837
87388
  }
@@ -86844,8 +87395,31 @@ Error: ${msg}`));
86844
87395
  format === "json" ? outputErrorJson(swapResult.error) : outputErrorTable(swapResult.error);
86845
87396
  process.exit(1);
86846
87397
  }
86847
- console.log(JSON.stringify({ unsignedTransactions: [swapResult.value.swapTransaction] }));
87398
+ const base64 = swapResult.value.swapTransaction;
87399
+ if (mode === "unsigned-tx") {
87400
+ console.log(JSON.stringify({ unsignedTransactions: [base64] }));
87401
+ return;
87402
+ }
87403
+ const ctx = requirePrivyContext(walletAddress);
87404
+ printPrivySignBanner();
87405
+ const broadcast = await privyBroadcastOne(ctx, base64);
87406
+ if (!broadcast.ok) {
87407
+ format === "json" ? outputErrorJson(broadcast.error.toJSON()) : outputErrorTable(broadcast.error.toJSON());
87408
+ process.exit(1);
87409
+ }
87410
+ if (format === "json") {
87411
+ outputJson({
87412
+ signature: broadcast.value.signature,
87413
+ explorer: `https://solscan.io/tx/${broadcast.value.signature}`
87414
+ }, startTime);
87415
+ } else {
87416
+ outputTransactionResult(broadcast.value.signature);
87417
+ }
86848
87418
  } catch (e) {
87419
+ if (e instanceof ByrealError) {
87420
+ format === "json" ? outputErrorJson(e.toJSON()) : outputErrorTable(e.toJSON());
87421
+ process.exit(1);
87422
+ }
86849
87423
  const message = e.message || "Jupiter swap failed";
86850
87424
  format === "json" ? outputErrorJson({ code: "API_ERROR", type: "NETWORK", message, retryable: true }) : console.error(source_default.red(`
86851
87425
  Error: ${message}`));
@@ -87196,11 +87770,11 @@ Error: ${msg}`));
87196
87770
  return walletAddress;
87197
87771
  }
87198
87772
  function createKaminoDepositCommand() {
87199
- return new Command("deposit").description("Deposit tokens to Kamino Lend").requiredOption("--amount <amount>", "Amount to deposit (UI amount, e.g. 2.0)").option("--mint <address>", "Token mint address", USDC_MINT).option("--reserve <address>", "Reserve address (auto-resolved from mint if omitted)").option("--market <address>", "Market address", KAMINO_MAIN_MARKET).option("--dry-run", "Preview without generating a transaction").action(async (options, cmdObj) => {
87773
+ return new Command("deposit").description("Deposit tokens to Kamino Lend").requiredOption("--amount <amount>", "Amount to deposit (UI amount, e.g. 2.0)").option("--mint <address>", "Token mint address", USDC_MINT).option("--reserve <address>", "Reserve address (auto-resolved from mint if omitted)").option("--market <address>", "Market address", KAMINO_MAIN_MARKET).option("--dry-run", "Preview without generating a transaction").option("--execute", "Sign + broadcast on-chain via Privy (default emits unsigned tx for back-compat)").action(async (options, cmdObj) => {
87200
87774
  const globalOptions = cmdObj.optsWithGlobals();
87201
87775
  const format = globalOptions.output;
87202
87776
  const startTime = Date.now();
87203
- const mode = resolveExecutionMode(options);
87777
+ const mode = safeResolveExecutionMode(options, format);
87204
87778
  const walletAddress = validateWallet(globalOptions.walletAddress, format);
87205
87779
  try {
87206
87780
  const reserve = options.reserve ?? resolveReserve(options.mint, options.market);
@@ -87226,7 +87800,7 @@ function createKaminoDepositCommand() {
87226
87800
  );
87227
87801
  console.log(source_default.cyan.bold("\n Kamino Deposit Preview\n"));
87228
87802
  console.log(table.toString());
87229
- console.log(source_default.yellow("\n Remove --dry-run to generate the unsigned transaction"));
87803
+ console.log(source_default.yellow("\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy."));
87230
87804
  }
87231
87805
  return;
87232
87806
  }
@@ -87240,8 +87814,31 @@ function createKaminoDepositCommand() {
87240
87814
  format === "json" ? outputErrorJson(result.error) : outputErrorTable(result.error);
87241
87815
  process.exit(1);
87242
87816
  }
87243
- console.log(JSON.stringify({ unsignedTransactions: [result.value.transaction] }));
87817
+ const base64 = result.value.transaction;
87818
+ if (mode === "unsigned-tx") {
87819
+ console.log(JSON.stringify({ unsignedTransactions: [base64] }));
87820
+ return;
87821
+ }
87822
+ const ctx = requirePrivyContext(walletAddress);
87823
+ printPrivySignBanner();
87824
+ const broadcast = await privyBroadcastOne(ctx, base64);
87825
+ if (!broadcast.ok) {
87826
+ format === "json" ? outputErrorJson(broadcast.error.toJSON()) : outputErrorTable(broadcast.error.toJSON());
87827
+ process.exit(1);
87828
+ }
87829
+ if (format === "json") {
87830
+ outputJson({
87831
+ signature: broadcast.value.signature,
87832
+ explorer: `https://solscan.io/tx/${broadcast.value.signature}`
87833
+ }, startTime);
87834
+ } else {
87835
+ outputTransactionResult(broadcast.value.signature);
87836
+ }
87244
87837
  } catch (e) {
87838
+ if (e instanceof ByrealError) {
87839
+ format === "json" ? outputErrorJson(e.toJSON()) : outputErrorTable(e.toJSON());
87840
+ process.exit(1);
87841
+ }
87245
87842
  const message = e.message || "Kamino deposit failed";
87246
87843
  format === "json" ? outputErrorJson({ code: "API_ERROR", type: "NETWORK", message, retryable: true }) : console.error(source_default.red(`
87247
87844
  Error: ${message}`));
@@ -87250,11 +87847,11 @@ Error: ${message}`));
87250
87847
  });
87251
87848
  }
87252
87849
  function createKaminoWithdrawCommand() {
87253
- return new Command("withdraw").description("Withdraw tokens from Kamino Lend").requiredOption("--amount <amount>", "Amount to withdraw (UI amount, e.g. 2.0)").option("--mint <address>", "Token mint address", USDC_MINT).option("--reserve <address>", "Reserve address (auto-resolved from mint if omitted)").option("--market <address>", "Market address", KAMINO_MAIN_MARKET).option("--dry-run", "Preview without generating a transaction").action(async (options, cmdObj) => {
87850
+ return new Command("withdraw").description("Withdraw tokens from Kamino Lend").requiredOption("--amount <amount>", "Amount to withdraw (UI amount, e.g. 2.0)").option("--mint <address>", "Token mint address", USDC_MINT).option("--reserve <address>", "Reserve address (auto-resolved from mint if omitted)").option("--market <address>", "Market address", KAMINO_MAIN_MARKET).option("--dry-run", "Preview without generating a transaction").option("--execute", "Sign + broadcast on-chain via Privy (default emits unsigned tx for back-compat)").action(async (options, cmdObj) => {
87254
87851
  const globalOptions = cmdObj.optsWithGlobals();
87255
87852
  const format = globalOptions.output;
87256
87853
  const startTime = Date.now();
87257
- const mode = resolveExecutionMode(options);
87854
+ const mode = safeResolveExecutionMode(options, format);
87258
87855
  const walletAddress = validateWallet(globalOptions.walletAddress, format);
87259
87856
  try {
87260
87857
  const reserve = options.reserve ?? resolveReserve(options.mint, options.market);
@@ -87280,7 +87877,7 @@ function createKaminoWithdrawCommand() {
87280
87877
  );
87281
87878
  console.log(source_default.cyan.bold("\n Kamino Withdraw Preview\n"));
87282
87879
  console.log(table.toString());
87283
- console.log(source_default.yellow("\n Remove --dry-run to generate the unsigned transaction"));
87880
+ console.log(source_default.yellow("\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy."));
87284
87881
  }
87285
87882
  return;
87286
87883
  }
@@ -87294,8 +87891,31 @@ function createKaminoWithdrawCommand() {
87294
87891
  format === "json" ? outputErrorJson(result.error) : outputErrorTable(result.error);
87295
87892
  process.exit(1);
87296
87893
  }
87297
- console.log(JSON.stringify({ unsignedTransactions: [result.value.transaction] }));
87894
+ const base64 = result.value.transaction;
87895
+ if (mode === "unsigned-tx") {
87896
+ console.log(JSON.stringify({ unsignedTransactions: [base64] }));
87897
+ return;
87898
+ }
87899
+ const ctx = requirePrivyContext(walletAddress);
87900
+ printPrivySignBanner();
87901
+ const broadcast = await privyBroadcastOne(ctx, base64);
87902
+ if (!broadcast.ok) {
87903
+ format === "json" ? outputErrorJson(broadcast.error.toJSON()) : outputErrorTable(broadcast.error.toJSON());
87904
+ process.exit(1);
87905
+ }
87906
+ if (format === "json") {
87907
+ outputJson({
87908
+ signature: broadcast.value.signature,
87909
+ explorer: `https://solscan.io/tx/${broadcast.value.signature}`
87910
+ }, startTime);
87911
+ } else {
87912
+ outputTransactionResult(broadcast.value.signature);
87913
+ }
87298
87914
  } catch (e) {
87915
+ if (e instanceof ByrealError) {
87916
+ format === "json" ? outputErrorJson(e.toJSON()) : outputErrorTable(e.toJSON());
87917
+ process.exit(1);
87918
+ }
87299
87919
  const message = e.message || "Kamino withdraw failed";
87300
87920
  format === "json" ? outputErrorJson({ code: "API_ERROR", type: "NETWORK", message, retryable: true }) : console.error(source_default.red(`
87301
87921
  Error: ${message}`));
@@ -87606,11 +88226,11 @@ async function findEmptyAccounts(connection, owner, programId, exceptions) {
87606
88226
 
87607
88227
  // src/plugins/rent/commands.ts
87608
88228
  function createRentReclaimCommand() {
87609
- return new Command("reclaim").description("Close empty token accounts to reclaim SOL rent").option("--dry-run", "Scan and report without generating transactions").option("--include-token2022", "Also close empty Token-2022 accounts").option("--exclude <mints>", "Comma-separated mint addresses to never close").action(async (options, cmdObj) => {
88229
+ return new Command("reclaim").description("Close empty token accounts to reclaim SOL rent").option("--dry-run", "Scan and report without generating transactions").option("--execute", "Sign + broadcast on-chain via Privy (default emits unsigned tx for back-compat)").option("--include-token2022", "Also close empty Token-2022 accounts").option("--exclude <mints>", "Comma-separated mint addresses to never close").action(async (options, cmdObj) => {
87610
88230
  const globalOptions = cmdObj.optsWithGlobals();
87611
88231
  const format = globalOptions.output;
87612
88232
  const startTime = Date.now();
87613
- const mode = resolveExecutionMode(options);
88233
+ const mode = safeResolveExecutionMode(options, format);
87614
88234
  const walletAddress = globalOptions.walletAddress;
87615
88235
  if (!walletAddress) {
87616
88236
  const e = missingWalletAddressError();
@@ -87669,13 +88289,33 @@ Error: ${msg}`));
87669
88289
  acctTable.push([a.pubkey, a.mint, progLabel]);
87670
88290
  }
87671
88291
  console.log(acctTable.toString());
87672
- console.log(source_default.yellow("\n Remove --dry-run to generate the unsigned transaction(s)"));
88292
+ console.log(source_default.yellow("\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy."));
87673
88293
  }
87674
88294
  return;
87675
88295
  }
87676
88296
  const txs = await buildCloseTransactions(walletAddress, scan.emptyAccounts);
87677
- console.log(JSON.stringify({ unsignedTransactions: txs }));
88297
+ if (mode === "unsigned-tx") {
88298
+ console.log(JSON.stringify({ unsignedTransactions: txs }));
88299
+ return;
88300
+ }
88301
+ const ctx = requirePrivyContext(walletAddress);
88302
+ printPrivySignBanner();
88303
+ const broadcast = await privyBroadcastMany(ctx, txs);
88304
+ if (!broadcast.ok) {
88305
+ format === "json" ? outputErrorJson(broadcast.error.toJSON()) : outputErrorTable(broadcast.error.toJSON());
88306
+ process.exit(1);
88307
+ }
88308
+ if (format === "json") {
88309
+ outputJson(broadcast.value, startTime);
88310
+ } else {
88311
+ outputMultiBroadcastResult(broadcast.value);
88312
+ }
88313
+ if (broadcast.value.failCount > 0) process.exit(1);
87678
88314
  } catch (e) {
88315
+ if (e instanceof ByrealError) {
88316
+ format === "json" ? outputErrorJson(e.toJSON()) : outputErrorTable(e.toJSON());
88317
+ process.exit(1);
88318
+ }
87679
88319
  const message = e.message || "Rent reclaim failed";
87680
88320
  format === "json" ? outputErrorJson({ code: "RPC_ERROR", type: "SYSTEM", message, retryable: true }) : console.error(source_default.red(`
87681
88321
  Error: ${message}`));
@@ -87848,11 +88488,11 @@ async function executeSweep(params) {
87848
88488
 
87849
88489
  // src/plugins/consolidate/commands.ts
87850
88490
  function createSweepExecuteCommand() {
87851
- return new Command("execute").description("Consolidate dust tokens into USDC (or SOL)").option("--target-mint <address>", "Target token to consolidate into", "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v").option("--max-value-usd <amount>", "Only sweep tokens below this USD value", "0.5").option("--exclude <mints>", "Comma-separated mint addresses to skip").option("--dry-run", "Preview consolidation plan without generating transactions").action(async (options, cmdObj) => {
88491
+ return new Command("execute").description("Consolidate dust tokens into USDC (or SOL)").option("--target-mint <address>", "Target token to consolidate into", "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v").option("--max-value-usd <amount>", "Only sweep tokens below this USD value", "0.5").option("--exclude <mints>", "Comma-separated mint addresses to skip").option("--dry-run", "Preview consolidation plan without generating transactions").option("--execute", "Sign + broadcast on-chain via Privy (default emits unsigned tx for back-compat)").action(async (options, cmdObj) => {
87852
88492
  const globalOptions = cmdObj.optsWithGlobals();
87853
88493
  const format = globalOptions.output;
87854
88494
  const startTime = Date.now();
87855
- const mode = resolveExecutionMode(options);
88495
+ const mode = safeResolveExecutionMode(options, format);
87856
88496
  const walletAddress = globalOptions.walletAddress;
87857
88497
  if (!walletAddress) {
87858
88498
  const e = missingWalletAddressError();
@@ -87936,7 +88576,7 @@ Error: ${msg}`));
87936
88576
  ]);
87937
88577
  }
87938
88578
  console.log(tokenTable.toString());
87939
- console.log(source_default.yellow("\n Remove --dry-run to generate the unsigned transactions"));
88579
+ console.log(source_default.yellow("\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy."));
87940
88580
  }
87941
88581
  return;
87942
88582
  }
@@ -87961,12 +88601,36 @@ Error: ${msg}`));
87961
88601
  }
87962
88602
  return;
87963
88603
  }
87964
- console.log(JSON.stringify({
87965
- unsignedTransactions: swapTransactions,
87966
- swapCount: swapTransactions.length,
87967
- ...failures.length > 0 ? { failures } : {}
87968
- }));
88604
+ if (mode === "unsigned-tx") {
88605
+ console.log(JSON.stringify({
88606
+ unsignedTransactions: swapTransactions,
88607
+ swapCount: swapTransactions.length,
88608
+ ...failures.length > 0 ? { failures } : {}
88609
+ }));
88610
+ return;
88611
+ }
88612
+ const ctx = requirePrivyContext(walletAddress);
88613
+ printPrivySignBanner();
88614
+ const broadcast = await privyBroadcastMany(ctx, swapTransactions);
88615
+ if (!broadcast.ok) {
88616
+ format === "json" ? outputErrorJson(broadcast.error.toJSON()) : outputErrorTable(broadcast.error.toJSON());
88617
+ process.exit(1);
88618
+ }
88619
+ if (format === "json") {
88620
+ outputJson({ ...broadcast.value, ...failures.length > 0 ? { failures } : {} }, startTime);
88621
+ } else {
88622
+ outputMultiBroadcastResult(broadcast.value);
88623
+ if (failures.length > 0) {
88624
+ console.log(source_default.gray(` ${failures.length} token(s) skipped (failed to quote):`));
88625
+ for (const f of failures) console.log(source_default.gray(` ${f.mint}: ${f.reason}`));
88626
+ }
88627
+ }
88628
+ if (broadcast.value.failCount > 0) process.exit(1);
87969
88629
  } catch (e) {
88630
+ if (e instanceof ByrealError) {
88631
+ format === "json" ? outputErrorJson(e.toJSON()) : outputErrorTable(e.toJSON());
88632
+ process.exit(1);
88633
+ }
87970
88634
  const message = e.message || "Token consolidation failed";
87971
88635
  format === "json" ? outputErrorJson({ code: "API_ERROR", type: "NETWORK", message, retryable: true }) : console.error(source_default.red(`
87972
88636
  Error: ${message}`));
@@ -88223,11 +88887,11 @@ function fallbackHint2(route) {
88223
88887
  return null;
88224
88888
  }
88225
88889
  function createTitanSwapCommand() {
88226
- return new Command("swap").description("Swap tokens via Titan Exchange aggregator").requiredOption("--input-mint <address>", "Input token mint address").requiredOption("--output-mint <address>", "Output token mint address").requiredOption("--amount <amount>", "Amount to swap (UI amount, decimals auto-resolved)").option("--swap-mode <mode>", "Swap mode: ExactIn or ExactOut", "ExactIn").option("--slippage <bps>", "Slippage tolerance in basis points").option("--raw", "Amount is already in raw (smallest unit) format").option("--dry-run", "Preview the swap without generating a transaction").action(async (options, cmdObj) => {
88890
+ return new Command("swap").description("Swap tokens via Titan Exchange aggregator").requiredOption("--input-mint <address>", "Input token mint address").requiredOption("--output-mint <address>", "Output token mint address").requiredOption("--amount <amount>", "Amount to swap (UI amount, decimals auto-resolved)").option("--swap-mode <mode>", "Swap mode: ExactIn or ExactOut", "ExactIn").option("--slippage <bps>", "Slippage tolerance in basis points").option("--raw", "Amount is already in raw (smallest unit) format").option("--dry-run", "Preview the swap without generating a transaction").option("--execute", "Sign + broadcast on-chain via Privy (default emits unsigned tx for back-compat)").action(async (options, cmdObj) => {
88227
88891
  const globalOptions = cmdObj.optsWithGlobals();
88228
88892
  const format = globalOptions.output;
88229
88893
  const startTime = Date.now();
88230
- const mode = resolveExecutionMode(options);
88894
+ const mode = safeResolveExecutionMode(options, format);
88231
88895
  const walletAddress = globalOptions.walletAddress;
88232
88896
  if (!walletAddress) {
88233
88897
  const e = missingWalletAddressError();
@@ -88293,12 +88957,35 @@ Error: ${msg}`));
88293
88957
  console.log(table.toString());
88294
88958
  const hint = fallbackHint2(getLastRoute2());
88295
88959
  if (hint) console.error(source_default.gray(`[byreal] ${hint}`));
88296
- console.log(source_default.yellow("\n Remove --dry-run to generate the unsigned transaction"));
88960
+ console.log(source_default.yellow("\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy."));
88297
88961
  }
88298
88962
  return;
88299
88963
  }
88300
- console.log(JSON.stringify({ unsignedTransactions: [quote.transaction] }));
88964
+ const base64 = quote.transaction;
88965
+ if (mode === "unsigned-tx") {
88966
+ console.log(JSON.stringify({ unsignedTransactions: [base64] }));
88967
+ return;
88968
+ }
88969
+ const ctx = requirePrivyContext(walletAddress);
88970
+ printPrivySignBanner();
88971
+ const broadcast = await privyBroadcastOne(ctx, base64);
88972
+ if (!broadcast.ok) {
88973
+ format === "json" ? outputErrorJson(broadcast.error.toJSON()) : outputErrorTable(broadcast.error.toJSON());
88974
+ process.exit(1);
88975
+ }
88976
+ if (format === "json") {
88977
+ outputJson({
88978
+ signature: broadcast.value.signature,
88979
+ explorer: `https://solscan.io/tx/${broadcast.value.signature}`
88980
+ }, startTime);
88981
+ } else {
88982
+ outputTransactionResult(broadcast.value.signature);
88983
+ }
88301
88984
  } catch (e) {
88985
+ if (e instanceof ByrealError) {
88986
+ format === "json" ? outputErrorJson(e.toJSON()) : outputErrorTable(e.toJSON());
88987
+ process.exit(1);
88988
+ }
88302
88989
  const message = e.message || "Titan swap failed";
88303
88990
  format === "json" ? outputErrorJson({ code: "API_ERROR", type: "NETWORK", message, retryable: true }) : console.error(source_default.red(`
88304
88991
  Error: ${message}`));
@@ -88473,11 +89160,11 @@ function fallbackHint3(route) {
88473
89160
  return null;
88474
89161
  }
88475
89162
  function createDFlowSwapCommand() {
88476
- return new Command("swap").description("Swap tokens via DFlow order-flow aggregator").requiredOption("--input-mint <address>", "Input token mint address").requiredOption("--output-mint <address>", "Output token mint address").requiredOption("--amount <amount>", "Amount to swap (UI amount, decimals auto-resolved)").option("--slippage <bps>", "Slippage tolerance in basis points").option("--raw", "Amount is already in raw (smallest unit) format").option("--dry-run", "Preview the swap without generating a transaction").action(async (options, cmdObj) => {
89163
+ return new Command("swap").description("Swap tokens via DFlow order-flow aggregator").requiredOption("--input-mint <address>", "Input token mint address").requiredOption("--output-mint <address>", "Output token mint address").requiredOption("--amount <amount>", "Amount to swap (UI amount, decimals auto-resolved)").option("--slippage <bps>", "Slippage tolerance in basis points").option("--raw", "Amount is already in raw (smallest unit) format").option("--dry-run", "Preview the swap without generating a transaction").option("--execute", "Sign + broadcast on-chain via Privy (default emits unsigned tx for back-compat)").action(async (options, cmdObj) => {
88477
89164
  const globalOptions = cmdObj.optsWithGlobals();
88478
89165
  const format = globalOptions.output;
88479
89166
  const startTime = Date.now();
88480
- const mode = resolveExecutionMode(options);
89167
+ const mode = safeResolveExecutionMode(options, format);
88481
89168
  const walletAddress = globalOptions.walletAddress;
88482
89169
  if (!walletAddress) {
88483
89170
  const e = missingWalletAddressError();
@@ -88543,12 +89230,35 @@ Error: ${msg}`));
88543
89230
  console.log(table.toString());
88544
89231
  const hint = fallbackHint3(getLastRoute3());
88545
89232
  if (hint) console.error(source_default.gray(`[byreal] ${hint}`));
88546
- console.log(source_default.yellow("\n Remove --dry-run to generate the unsigned transaction"));
89233
+ console.log(source_default.yellow("\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy."));
88547
89234
  }
88548
89235
  return;
88549
89236
  }
88550
- console.log(JSON.stringify({ unsignedTransactions: [quote.transaction] }));
89237
+ const base64 = quote.transaction;
89238
+ if (mode === "unsigned-tx") {
89239
+ console.log(JSON.stringify({ unsignedTransactions: [base64] }));
89240
+ return;
89241
+ }
89242
+ const ctx = requirePrivyContext(walletAddress);
89243
+ printPrivySignBanner();
89244
+ const broadcast = await privyBroadcastOne(ctx, base64);
89245
+ if (!broadcast.ok) {
89246
+ format === "json" ? outputErrorJson(broadcast.error.toJSON()) : outputErrorTable(broadcast.error.toJSON());
89247
+ process.exit(1);
89248
+ }
89249
+ if (format === "json") {
89250
+ outputJson({
89251
+ signature: broadcast.value.signature,
89252
+ explorer: `https://solscan.io/tx/${broadcast.value.signature}`
89253
+ }, startTime);
89254
+ } else {
89255
+ outputTransactionResult(broadcast.value.signature);
89256
+ }
88551
89257
  } catch (e) {
89258
+ if (e instanceof ByrealError) {
89259
+ format === "json" ? outputErrorJson(e.toJSON()) : outputErrorTable(e.toJSON());
89260
+ process.exit(1);
89261
+ }
88552
89262
  const message = e.message || "DFlow swap failed";
88553
89263
  format === "json" ? outputErrorJson({ code: "API_ERROR", type: "NETWORK", message, retryable: true }) : console.error(source_default.red(`
88554
89264
  Error: ${message}`));
@@ -89316,21 +90026,38 @@ async function resolveUiAmounts(quote) {
89316
90026
  uiOutAmount: rawToUi(quote.outAmount, outputDecimals)
89317
90027
  };
89318
90028
  }
90029
+ function emitError(format, error) {
90030
+ if (error instanceof ByrealError) {
90031
+ if (format === "json") {
90032
+ outputErrorJson(error.toJSON());
90033
+ } else {
90034
+ outputErrorTable(error.toJSON());
90035
+ }
90036
+ } else {
90037
+ const message = error?.message ?? "Unknown error";
90038
+ if (format === "json") {
90039
+ outputErrorJson({ code: "UNKNOWN_ERROR", type: "SYSTEM", message, retryable: false });
90040
+ } else {
90041
+ console.error(source_default.red(`
90042
+ Error: ${message}`));
90043
+ }
90044
+ }
90045
+ process.exit(1);
90046
+ }
89319
90047
  function createSwapExecuteCommand() {
89320
- return new Command("execute").description("Preview or generate a swap transaction").requiredOption("--input-mint <address>", "Input token mint address").requiredOption("--output-mint <address>", "Output token mint address").requiredOption("--amount <amount>", "Amount to swap (UI amount, decimals auto-resolved)").option("--swap-mode <mode>", "Swap mode: in or out", "in").option("--slippage <bps>", "Slippage tolerance in basis points").option("--raw", "Amount is already in raw (smallest unit) format").option("--dry-run", "Preview the swap without generating a transaction").action(async (options, cmdObj) => {
90048
+ return new Command("execute").description("Preview, sign, or emit a swap transaction").requiredOption("--input-mint <address>", "Input token mint address").requiredOption("--output-mint <address>", "Output token mint address").requiredOption("--amount <amount>", "Amount to swap (UI amount, decimals auto-resolved)").option("--swap-mode <mode>", "Swap mode: in or out", "in").option("--slippage <bps>", "Slippage tolerance in basis points").option("--raw", "Amount is already in raw (smallest unit) format").option("--dry-run", "Preview the swap without generating a transaction").option("--execute", "Sign + broadcast on-chain via Privy (default emits unsigned tx for back-compat)").action(async (options, cmdObj) => {
89321
90049
  const globalOptions = cmdObj.optsWithGlobals();
89322
90050
  const format = globalOptions.output;
89323
90051
  const startTime = Date.now();
89324
- const mode = resolveExecutionMode(options);
90052
+ let mode;
90053
+ try {
90054
+ mode = resolveExecutionMode(options);
90055
+ } catch (e) {
90056
+ emitError(format, e);
90057
+ }
89325
90058
  const userPublicKey = globalOptions.walletAddress;
89326
90059
  if (!userPublicKey) {
89327
- const err2 = missingWalletAddressError();
89328
- if (format === "json") {
89329
- outputErrorJson(err2.toJSON());
89330
- } else {
89331
- outputErrorTable(err2.toJSON());
89332
- }
89333
- process.exit(1);
90060
+ emitError(format, missingWalletAddressError());
89334
90061
  }
89335
90062
  try {
89336
90063
  new import_web3124.PublicKey(userPublicKey);
@@ -89361,12 +90088,12 @@ Error: Invalid wallet address: ${userPublicKey}`));
89361
90088
  userPublicKey
89362
90089
  });
89363
90090
  if (!quoteResult.ok) {
89364
- if (format === "json") {
89365
- outputErrorJson(quoteResult.error);
89366
- } else {
89367
- outputErrorTable(quoteResult.error);
89368
- }
89369
- process.exit(1);
90091
+ emitError(format, new ByrealError({
90092
+ code: quoteResult.error.code,
90093
+ type: quoteResult.error.type,
90094
+ message: quoteResult.error.message,
90095
+ retryable: quoteResult.error.retryable
90096
+ }));
89370
90097
  }
89371
90098
  const quote = quoteResult.value;
89372
90099
  const { uiInAmount, uiOutAmount } = await resolveUiAmounts(quote);
@@ -89389,7 +90116,7 @@ Error: Invalid wallet address: ${userPublicKey}`));
89389
90116
  outputJson({ mode: "dry-run", ...quote, uiInAmount, uiOutAmount, inAmountUsd, outAmountUsd }, startTime);
89390
90117
  } else {
89391
90118
  outputSwapQuoteTable(quote, uiInAmount, uiOutAmount);
89392
- console.log(source_default.yellow("\n Remove --dry-run to generate the unsigned transaction"));
90119
+ console.log(source_default.yellow("\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy."));
89393
90120
  }
89394
90121
  return;
89395
90122
  }
@@ -89403,16 +90130,30 @@ Error: ${errMsg}`));
89403
90130
  }
89404
90131
  process.exit(1);
89405
90132
  }
89406
- console.log(JSON.stringify({ unsignedTransactions: [quote.transaction] }));
89407
- } catch (e) {
89408
- const message = e.message || "Failed to resolve token decimals";
90133
+ if (mode === "unsigned-tx") {
90134
+ console.log(JSON.stringify({ unsignedTransactions: [quote.transaction] }));
90135
+ return;
90136
+ }
90137
+ const ctx = requirePrivyContext(userPublicKey);
90138
+ printPrivySignBanner();
90139
+ const broadcast = await privyBroadcastOne(ctx, quote.transaction);
90140
+ if (!broadcast.ok) {
90141
+ emitError(format, broadcast.error);
90142
+ }
89409
90143
  if (format === "json") {
89410
- outputErrorJson({ code: "VALIDATION_ERROR", type: "VALIDATION", message, retryable: false });
90144
+ outputJson(
90145
+ {
90146
+ signature: broadcast.value.signature,
90147
+ explorer: `https://solscan.io/tx/${broadcast.value.signature}`,
90148
+ quote: { ...quote, uiInAmount, uiOutAmount }
90149
+ },
90150
+ startTime
90151
+ );
89411
90152
  } else {
89412
- console.error(source_default.red(`
89413
- Error: ${message}`));
90153
+ outputTransactionResult(broadcast.value.signature);
89414
90154
  }
89415
- process.exit(1);
90155
+ } catch (e) {
90156
+ emitError(format, e);
89416
90157
  }
89417
90158
  });
89418
90159
  }
@@ -89628,11 +90369,11 @@ function createPositionsOpenCommand() {
89628
90369
  ).option(
89629
90370
  "--amount-usd <usd>",
89630
90371
  "Investment amount in USD (auto-calculates token split, mutually exclusive with --amount)"
89631
- ).option("--slippage <bps>", "Slippage tolerance in basis points").option("--raw", "Amount is already in raw (smallest unit) format").option("--dry-run", "Preview the position without opening").action(async (options, cmdObj) => {
90372
+ ).option("--slippage <bps>", "Slippage tolerance in basis points").option("--raw", "Amount is already in raw (smallest unit) format").option("--dry-run", "Preview the position without opening").option("--execute", "Sign + broadcast on-chain via Privy (default emits unsigned tx for back-compat)").action(async (options, cmdObj) => {
89632
90373
  const globalOptions = cmdObj.optsWithGlobals();
89633
90374
  const format = globalOptions.output;
89634
90375
  const startTime = Date.now();
89635
- const mode = resolveExecutionMode(options);
90376
+ const mode = safeResolveExecutionMode(options, format);
89636
90377
  const walletAddress = globalOptions.walletAddress;
89637
90378
  if (!walletAddress) {
89638
90379
  const err2 = missingWalletAddressError();
@@ -89876,7 +90617,7 @@ function createPositionsOpenCommand() {
89876
90617
  } else {
89877
90618
  console.log(source_default.green("\n Balance check: sufficient"));
89878
90619
  console.log(
89879
- source_default.yellow("\n Remove --dry-run to generate the unsigned transaction")
90620
+ source_default.yellow("\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy.")
89880
90621
  );
89881
90622
  }
89882
90623
  }
@@ -89892,7 +90633,29 @@ function createPositionsOpenCommand() {
89892
90633
  otherAmountMax
89893
90634
  });
89894
90635
  const base64 = serializeTransaction(result.transaction);
89895
- console.log(JSON.stringify({ unsignedTransactions: [base64] }));
90636
+ if (mode === "unsigned-tx") {
90637
+ console.log(JSON.stringify({ unsignedTransactions: [base64] }));
90638
+ return;
90639
+ }
90640
+ const ctx = requirePrivyContext(walletAddress);
90641
+ printPrivySignBanner();
90642
+ const broadcast = await privyBroadcastOne(ctx, base64);
90643
+ if (!broadcast.ok) {
90644
+ if (format === "json") outputErrorJson(broadcast.error.toJSON());
90645
+ else outputErrorTable(broadcast.error.toJSON());
90646
+ process.exit(1);
90647
+ }
90648
+ if (format === "json") {
90649
+ outputJson(
90650
+ {
90651
+ signature: broadcast.value.signature,
90652
+ explorer: `https://solscan.io/tx/${broadcast.value.signature}`
90653
+ },
90654
+ startTime
90655
+ );
90656
+ } else {
90657
+ outputTransactionResult(broadcast.value.signature);
90658
+ }
89896
90659
  } catch (e) {
89897
90660
  const message = e.message || "Unknown SDK error";
89898
90661
  if (format === "json") {
@@ -89923,11 +90686,11 @@ function createPositionsIncreaseCommand() {
89923
90686
  ).option(
89924
90687
  "--amount-usd <usd>",
89925
90688
  "Investment amount in USD (auto-calculates token split, mutually exclusive with --amount)"
89926
- ).option("--slippage <bps>", "Slippage tolerance in basis points").option("--raw", "Amount is already in raw (smallest unit) format").option("--dry-run", "Preview without executing").action(async (options, cmdObj) => {
90689
+ ).option("--slippage <bps>", "Slippage tolerance in basis points").option("--raw", "Amount is already in raw (smallest unit) format").option("--dry-run", "Preview without executing").option("--execute", "Sign + broadcast on-chain via Privy (default emits unsigned tx for back-compat)").action(async (options, cmdObj) => {
89927
90690
  const globalOptions = cmdObj.optsWithGlobals();
89928
90691
  const format = globalOptions.output;
89929
90692
  const startTime = Date.now();
89930
- const mode = resolveExecutionMode(options);
90693
+ const mode = safeResolveExecutionMode(options, format);
89931
90694
  const walletAddress = globalOptions.walletAddress;
89932
90695
  if (!walletAddress) {
89933
90696
  const err2 = missingWalletAddressError();
@@ -90174,7 +90937,7 @@ Error: ${errMsg}`));
90174
90937
  } else {
90175
90938
  console.log(source_default.green("\n Balance check: sufficient"));
90176
90939
  console.log(
90177
- source_default.yellow("\n Remove --dry-run to generate the unsigned transaction")
90940
+ source_default.yellow("\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy.")
90178
90941
  );
90179
90942
  }
90180
90943
  }
@@ -90188,7 +90951,29 @@ Error: ${errMsg}`));
90188
90951
  otherAmountMax
90189
90952
  });
90190
90953
  const base64 = serializeTransaction(result.transaction);
90191
- console.log(JSON.stringify({ unsignedTransactions: [base64] }));
90954
+ if (mode === "unsigned-tx") {
90955
+ console.log(JSON.stringify({ unsignedTransactions: [base64] }));
90956
+ return;
90957
+ }
90958
+ const ctx = requirePrivyContext(walletAddress);
90959
+ printPrivySignBanner();
90960
+ const broadcast = await privyBroadcastOne(ctx, base64);
90961
+ if (!broadcast.ok) {
90962
+ if (format === "json") outputErrorJson(broadcast.error.toJSON());
90963
+ else outputErrorTable(broadcast.error.toJSON());
90964
+ process.exit(1);
90965
+ }
90966
+ if (format === "json") {
90967
+ outputJson(
90968
+ {
90969
+ signature: broadcast.value.signature,
90970
+ explorer: `https://solscan.io/tx/${broadcast.value.signature}`
90971
+ },
90972
+ startTime
90973
+ );
90974
+ } else {
90975
+ outputTransactionResult(broadcast.value.signature);
90976
+ }
90192
90977
  } catch (e) {
90193
90978
  const message = e.message || "Unknown SDK error";
90194
90979
  if (format === "json") {
@@ -90213,11 +90998,11 @@ function createPositionsDecreaseCommand() {
90213
90998
  return new Command("decrease").description("Remove part of the liquidity from a position (keeps position open)").requiredOption("--nft-mint <address>", "Position NFT mint address").option("--percentage <1-100>", "Percentage of liquidity to remove").option(
90214
90999
  "--amount-usd <usd>",
90215
91000
  "USD amount of liquidity to remove (mutually exclusive with --percentage)"
90216
- ).option("--slippage <bps>", "Slippage tolerance in basis points").option("--dry-run", "Preview without executing").action(async (options, cmdObj) => {
91001
+ ).option("--slippage <bps>", "Slippage tolerance in basis points").option("--dry-run", "Preview without executing").option("--execute", "Sign + broadcast on-chain via Privy (default emits unsigned tx for back-compat)").action(async (options, cmdObj) => {
90217
91002
  const globalOptions = cmdObj.optsWithGlobals();
90218
91003
  const format = globalOptions.output;
90219
91004
  const startTime = Date.now();
90220
- const mode = resolveExecutionMode(options);
91005
+ const mode = safeResolveExecutionMode(options, format);
90221
91006
  const hasPercentage = options.percentage !== void 0;
90222
91007
  const hasAmountUsd = options.amountUsd !== void 0;
90223
91008
  if (hasPercentage && hasAmountUsd) {
@@ -90403,7 +91188,7 @@ Error: ${errMsg}`));
90403
91188
  } else {
90404
91189
  outputPositionDecreasePreview(previewData);
90405
91190
  console.log(
90406
- source_default.yellow("\n Remove --dry-run to generate the unsigned transaction")
91191
+ source_default.yellow("\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy.")
90407
91192
  );
90408
91193
  }
90409
91194
  return;
@@ -90425,7 +91210,29 @@ Error: ${errMsg}`));
90425
91210
  });
90426
91211
  }
90427
91212
  const base64 = serializeTransaction(result.transaction);
90428
- console.log(JSON.stringify({ unsignedTransactions: [base64] }));
91213
+ if (mode === "unsigned-tx") {
91214
+ console.log(JSON.stringify({ unsignedTransactions: [base64] }));
91215
+ return;
91216
+ }
91217
+ const ctx = requirePrivyContext(walletAddress);
91218
+ printPrivySignBanner();
91219
+ const broadcast = await privyBroadcastOne(ctx, base64);
91220
+ if (!broadcast.ok) {
91221
+ if (format === "json") outputErrorJson(broadcast.error.toJSON());
91222
+ else outputErrorTable(broadcast.error.toJSON());
91223
+ process.exit(1);
91224
+ }
91225
+ if (format === "json") {
91226
+ outputJson(
91227
+ {
91228
+ signature: broadcast.value.signature,
91229
+ explorer: `https://solscan.io/tx/${broadcast.value.signature}`
91230
+ },
91231
+ startTime
91232
+ );
91233
+ } else {
91234
+ outputTransactionResult(broadcast.value.signature);
91235
+ }
90429
91236
  } catch (e) {
90430
91237
  const message = e.message || "Unknown SDK error";
90431
91238
  if (format === "json") {
@@ -90447,11 +91254,11 @@ SDK Error: ${message}`));
90447
91254
  });
90448
91255
  }
90449
91256
  function createPositionsCloseCommand() {
90450
- return new Command("close").description("Close a position (remove all liquidity)").requiredOption("--nft-mint <address>", "Position NFT mint address").option("--slippage <bps>", "Slippage tolerance in basis points").option("--dry-run", "Preview the close without executing").action(async (options, cmdObj) => {
91257
+ return new Command("close").description("Close a position (remove all liquidity)").requiredOption("--nft-mint <address>", "Position NFT mint address").option("--slippage <bps>", "Slippage tolerance in basis points").option("--dry-run", "Preview the close without executing").option("--execute", "Sign + broadcast on-chain via Privy (default emits unsigned tx for back-compat)").action(async (options, cmdObj) => {
90451
91258
  const globalOptions = cmdObj.optsWithGlobals();
90452
91259
  const format = globalOptions.output;
90453
91260
  const startTime = Date.now();
90454
- const mode = resolveExecutionMode(options);
91261
+ const mode = safeResolveExecutionMode(options, format);
90455
91262
  const walletAddress = globalOptions.walletAddress;
90456
91263
  if (!walletAddress) {
90457
91264
  const err2 = missingWalletAddressError();
@@ -90525,7 +91332,7 @@ Error: ${errMsg}`));
90525
91332
  } else {
90526
91333
  outputPositionClosePreview(previewData);
90527
91334
  console.log(
90528
- source_default.yellow("\n Remove --dry-run to generate the unsigned transaction")
91335
+ source_default.yellow("\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy.")
90529
91336
  );
90530
91337
  }
90531
91338
  return;
@@ -90538,7 +91345,29 @@ Error: ${errMsg}`));
90538
91345
  slippage
90539
91346
  });
90540
91347
  const base64 = serializeTransaction(result.transaction);
90541
- console.log(JSON.stringify({ unsignedTransactions: [base64] }));
91348
+ if (mode === "unsigned-tx") {
91349
+ console.log(JSON.stringify({ unsignedTransactions: [base64] }));
91350
+ return;
91351
+ }
91352
+ const ctx = requirePrivyContext(walletAddress);
91353
+ printPrivySignBanner();
91354
+ const broadcast = await privyBroadcastOne(ctx, base64);
91355
+ if (!broadcast.ok) {
91356
+ if (format === "json") outputErrorJson(broadcast.error.toJSON());
91357
+ else outputErrorTable(broadcast.error.toJSON());
91358
+ process.exit(1);
91359
+ }
91360
+ if (format === "json") {
91361
+ outputJson(
91362
+ {
91363
+ signature: broadcast.value.signature,
91364
+ explorer: `https://solscan.io/tx/${broadcast.value.signature}`
91365
+ },
91366
+ startTime
91367
+ );
91368
+ } else {
91369
+ outputTransactionResult(broadcast.value.signature);
91370
+ }
90542
91371
  } catch (e) {
90543
91372
  const message = e.message || "Unknown SDK error";
90544
91373
  if (format === "json") {
@@ -90563,11 +91392,11 @@ function createPositionsClaimCommand() {
90563
91392
  return new Command("claim").description("Claim accumulated fees from positions").requiredOption(
90564
91393
  "--nft-mints <addresses>",
90565
91394
  "Comma-separated NFT mint addresses (from positions list)"
90566
- ).option("--dry-run", "Preview the claim without executing").action(async (options, cmdObj) => {
91395
+ ).option("--dry-run", "Preview the claim without executing").option("--execute", "Sign + broadcast on-chain via Privy (default emits unsigned tx for back-compat)").action(async (options, cmdObj) => {
90567
91396
  const globalOptions = cmdObj.optsWithGlobals();
90568
91397
  const format = globalOptions.output;
90569
91398
  const startTime = Date.now();
90570
- const mode = resolveExecutionMode(options);
91399
+ const mode = safeResolveExecutionMode(options, format);
90571
91400
  const walletAddress = globalOptions.walletAddress;
90572
91401
  if (!walletAddress) {
90573
91402
  const err2 = missingWalletAddressError();
@@ -90671,20 +91500,53 @@ Error: ${errMsg}`));
90671
91500
  outputJson({ mode: "dry-run", entries: enrichedEntries }, startTime);
90672
91501
  } else {
90673
91502
  outputPositionClaimPreview(enrichedEntries);
90674
- console.log(source_default.yellow("\n Remove --dry-run to generate the unsigned transaction(s)"));
91503
+ console.log(source_default.yellow("\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy."));
90675
91504
  }
90676
91505
  return;
90677
91506
  }
90678
91507
  const unsignedTransactions = entries.map((entry) => entry.txPayload);
90679
- console.log(JSON.stringify({ unsignedTransactions }));
91508
+ if (mode === "unsigned-tx") {
91509
+ console.log(JSON.stringify({ unsignedTransactions }));
91510
+ return;
91511
+ }
91512
+ try {
91513
+ const ctx = requirePrivyContext(walletAddress);
91514
+ printPrivySignBanner();
91515
+ const broadcast = await privyBroadcastMany(ctx, unsignedTransactions);
91516
+ if (!broadcast.ok) {
91517
+ if (format === "json") outputErrorJson(broadcast.error.toJSON());
91518
+ else outputErrorTable(broadcast.error.toJSON());
91519
+ process.exit(1);
91520
+ }
91521
+ if (format === "json") {
91522
+ outputJson(broadcast.value, startTime);
91523
+ } else {
91524
+ outputMultiBroadcastResult(broadcast.value);
91525
+ }
91526
+ if (broadcast.value.failCount > 0) process.exit(1);
91527
+ } catch (e) {
91528
+ if (e instanceof ByrealError) {
91529
+ if (format === "json") outputErrorJson(e.toJSON());
91530
+ else outputErrorTable(e.toJSON());
91531
+ } else {
91532
+ const message = e.message || "Unknown error";
91533
+ if (format === "json") {
91534
+ outputErrorJson({ code: "UNKNOWN_ERROR", type: "SYSTEM", message, retryable: false });
91535
+ } else {
91536
+ console.error(source_default.red(`
91537
+ Error: ${message}`));
91538
+ }
91539
+ }
91540
+ process.exit(1);
91541
+ }
90680
91542
  });
90681
91543
  }
90682
91544
  function createPositionsClaimRewardsCommand() {
90683
- return new Command("claim-rewards").description("Claim incentive rewards from positions").option("--dry-run", "Preview unclaimed rewards without claiming").action(async (options, cmdObj) => {
91545
+ return new Command("claim-rewards").description("Claim incentive rewards from positions").option("--dry-run", "Preview unclaimed rewards without claiming").option("--execute", "Sign via Privy and submit to backend (default emits unsigned tx for external signers)").action(async (options, cmdObj) => {
90684
91546
  const globalOptions = cmdObj.optsWithGlobals();
90685
91547
  const format = globalOptions.output;
90686
91548
  const startTime = Date.now();
90687
- const mode = resolveExecutionMode(options);
91549
+ const mode = safeResolveExecutionMode(options, format);
90688
91550
  const walletAddress = globalOptions.walletAddress;
90689
91551
  if (!walletAddress) {
90690
91552
  const err2 = missingWalletAddressError();
@@ -90744,7 +91606,7 @@ function createPositionsClaimRewardsCommand() {
90744
91606
  console.log(source_default.gray("\n No unclaimed incentive rewards.\n"));
90745
91607
  } else {
90746
91608
  console.log(
90747
- source_default.yellow("\n Remove --dry-run to generate the unsigned transaction(s)")
91609
+ source_default.yellow("\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy.")
90748
91610
  );
90749
91611
  }
90750
91612
  }
@@ -90762,6 +91624,7 @@ function createPositionsClaimRewardsCommand() {
90762
91624
  return;
90763
91625
  }
90764
91626
  const positionAddresses = [...new Set(allRewards.map((r) => r.positionAddress))];
91627
+ if (mode === "execute") requirePrivyContext(walletAddress);
90765
91628
  const encodeResult = await api.encodeReward({
90766
91629
  walletAddress,
90767
91630
  positionAddresses,
@@ -90787,14 +91650,52 @@ function createPositionsClaimRewardsCommand() {
90787
91650
  }
90788
91651
  return;
90789
91652
  }
90790
- const txPayloads = rewardEncodeItems.map((item) => ({
90791
- poolAddress: item.poolAddress,
90792
- txPayload: item.txPayload,
90793
- txCode: item.txCode,
90794
- tokens: item.rewardClaimInfo
90795
- }));
90796
- console.log(JSON.stringify({ orderCode, unsignedTransactions: txPayloads }));
91653
+ if (mode === "unsigned-tx") {
91654
+ const txPayloads = rewardEncodeItems.map((item) => ({
91655
+ poolAddress: item.poolAddress,
91656
+ txPayload: item.txPayload,
91657
+ txCode: item.txCode,
91658
+ tokens: item.rewardClaimInfo
91659
+ }));
91660
+ console.log(JSON.stringify({ orderCode, unsignedTransactions: txPayloads }));
91661
+ return;
91662
+ }
91663
+ const ctx = requirePrivyContext(walletAddress);
91664
+ printPrivySignBanner();
91665
+ const signResult = await privySignMany(
91666
+ ctx,
91667
+ rewardEncodeItems.map((item) => item.txPayload)
91668
+ );
91669
+ if (!signResult.ok) {
91670
+ if (format === "json") outputErrorJson(signResult.error.toJSON());
91671
+ else outputErrorTable(signResult.error.toJSON());
91672
+ process.exit(1);
91673
+ }
91674
+ const submitResult = await api.submitRewardOrder({
91675
+ orderCode,
91676
+ walletAddress,
91677
+ signedTxPayload: rewardEncodeItems.map((item, i) => ({
91678
+ txCode: item.txCode,
91679
+ poolAddress: item.poolAddress,
91680
+ signedTx: signResult.value.signedTxs[i].signedTx
91681
+ }))
91682
+ });
91683
+ if (!submitResult.ok) {
91684
+ if (format === "json") outputErrorJson(submitResult.error);
91685
+ else outputErrorTable(submitResult.error);
91686
+ process.exit(1);
91687
+ }
91688
+ if (format === "json") {
91689
+ outputJson(submitResult.value, startTime);
91690
+ } else {
91691
+ outputRewardOrderResult(submitResult.value);
91692
+ }
90797
91693
  } catch (e) {
91694
+ if (e instanceof ByrealError) {
91695
+ if (format === "json") outputErrorJson(e.toJSON());
91696
+ else outputErrorTable(e.toJSON());
91697
+ process.exit(1);
91698
+ }
90798
91699
  const message = e.message || "Unknown error";
90799
91700
  if (format === "json") {
90800
91701
  outputErrorJson({ code: "SDK_ERROR", type: "SYSTEM", message, retryable: false });
@@ -90810,11 +91711,11 @@ Error: ${message}`));
90810
91711
  });
90811
91712
  }
90812
91713
  function createPositionsClaimBonusCommand() {
90813
- return new Command("claim-bonus").description("Claim CopyFarmer bonus rewards").option("--dry-run", "Preview claimable bonus without claiming").action(async (options, cmdObj) => {
91714
+ return new Command("claim-bonus").description("Claim CopyFarmer bonus rewards").option("--dry-run", "Preview claimable bonus without claiming").option("--execute", "Sign via Privy and submit to backend (default emits unsigned tx for external signers)").action(async (options, cmdObj) => {
90814
91715
  const globalOptions = cmdObj.optsWithGlobals();
90815
91716
  const format = globalOptions.output;
90816
91717
  const startTime = Date.now();
90817
- const mode = resolveExecutionMode(options);
91718
+ const mode = safeResolveExecutionMode(options, format);
90818
91719
  const walletAddress = globalOptions.walletAddress;
90819
91720
  if (!walletAddress) {
90820
91721
  const err2 = missingWalletAddressError();
@@ -90865,7 +91766,7 @@ function createPositionsClaimBonusCommand() {
90865
91766
  outputBonusPreview(overview, epochs);
90866
91767
  if (canClaim) {
90867
91768
  console.log(
90868
- source_default.yellow(` Remove --dry-run to claim $${claimableEpoch.totalBonusUsd} bonus
91769
+ source_default.yellow(` Remove --dry-run to emit an unsigned tx; add --execute to claim $${claimableEpoch.totalBonusUsd} bonus via Privy.
90869
91770
  `)
90870
91771
  );
90871
91772
  } else {
@@ -90885,6 +91786,7 @@ function createPositionsClaimBonusCommand() {
90885
91786
  }
90886
91787
  return;
90887
91788
  }
91789
+ if (mode === "execute") requirePrivyContext(walletAddress);
90888
91790
  const encodeResult = await api.encodeReward({
90889
91791
  walletAddress,
90890
91792
  positionAddresses: [],
@@ -90910,14 +91812,52 @@ function createPositionsClaimBonusCommand() {
90910
91812
  }
90911
91813
  return;
90912
91814
  }
90913
- const txPayloads = rewardEncodeItems.map((item) => ({
90914
- poolAddress: item.poolAddress,
90915
- txPayload: item.txPayload,
90916
- txCode: item.txCode,
90917
- tokens: item.rewardClaimInfo
90918
- }));
90919
- console.log(JSON.stringify({ orderCode, unsignedTransactions: txPayloads }));
91815
+ if (mode === "unsigned-tx") {
91816
+ const txPayloads = rewardEncodeItems.map((item) => ({
91817
+ poolAddress: item.poolAddress,
91818
+ txPayload: item.txPayload,
91819
+ txCode: item.txCode,
91820
+ tokens: item.rewardClaimInfo
91821
+ }));
91822
+ console.log(JSON.stringify({ orderCode, unsignedTransactions: txPayloads }));
91823
+ return;
91824
+ }
91825
+ const ctx = requirePrivyContext(walletAddress);
91826
+ printPrivySignBanner();
91827
+ const signResult = await privySignMany(
91828
+ ctx,
91829
+ rewardEncodeItems.map((item) => item.txPayload)
91830
+ );
91831
+ if (!signResult.ok) {
91832
+ if (format === "json") outputErrorJson(signResult.error.toJSON());
91833
+ else outputErrorTable(signResult.error.toJSON());
91834
+ process.exit(1);
91835
+ }
91836
+ const submitResult = await api.submitRewardOrder({
91837
+ orderCode,
91838
+ walletAddress,
91839
+ signedTxPayload: rewardEncodeItems.map((item, i) => ({
91840
+ txCode: item.txCode,
91841
+ poolAddress: item.poolAddress,
91842
+ signedTx: signResult.value.signedTxs[i].signedTx
91843
+ }))
91844
+ });
91845
+ if (!submitResult.ok) {
91846
+ if (format === "json") outputErrorJson(submitResult.error);
91847
+ else outputErrorTable(submitResult.error);
91848
+ process.exit(1);
91849
+ }
91850
+ if (format === "json") {
91851
+ outputJson(submitResult.value, startTime);
91852
+ } else {
91853
+ outputRewardOrderResult(submitResult.value);
91854
+ }
90920
91855
  } catch (e) {
91856
+ if (e instanceof ByrealError) {
91857
+ if (format === "json") outputErrorJson(e.toJSON());
91858
+ else outputErrorTable(e.toJSON());
91859
+ process.exit(1);
91860
+ }
90921
91861
  const message = e.message || "Unknown error";
90922
91862
  if (format === "json") {
90923
91863
  outputErrorJson({ code: "SDK_ERROR", type: "SYSTEM", message, retryable: false });
@@ -91181,11 +92121,11 @@ function createTopPositionsCommand() {
91181
92121
  function createCopyPositionCommand() {
91182
92122
  return new Command("copy").description(
91183
92123
  "Copy an existing position with referral bonus"
91184
- ).requiredOption("--position <address>", "Position PDA address to copy").requiredOption("--amount-usd <usd>", "Investment amount in USD").option("--slippage <bps>", "Slippage tolerance in basis points").option("--dry-run", "Preview the copy without executing").action(async (options, cmdObj) => {
92124
+ ).requiredOption("--position <address>", "Position PDA address to copy").requiredOption("--amount-usd <usd>", "Investment amount in USD").option("--slippage <bps>", "Slippage tolerance in basis points").option("--dry-run", "Preview the copy without executing").option("--execute", "Sign + broadcast on-chain via Privy (default emits unsigned tx for back-compat)").action(async (options, cmdObj) => {
91185
92125
  const globalOptions = cmdObj.optsWithGlobals();
91186
92126
  const format = globalOptions.output;
91187
92127
  const startTime = Date.now();
91188
- const mode = resolveExecutionMode(options);
92128
+ const mode = safeResolveExecutionMode(options, format);
91189
92129
  const walletAddress = globalOptions.walletAddress;
91190
92130
  if (!walletAddress) {
91191
92131
  const err2 = missingWalletAddressError();
@@ -91368,7 +92308,7 @@ Error: ${errMsg}`));
91368
92308
  console.log(source_default.green("\n Balance check: sufficient"));
91369
92309
  console.log(
91370
92310
  source_default.yellow(
91371
- "\n Remove --dry-run to generate the unsigned transaction"
92311
+ "\n Remove --dry-run to emit an unsigned transaction; add --execute to sign + broadcast via Privy."
91372
92312
  )
91373
92313
  );
91374
92314
  }
@@ -91386,7 +92326,29 @@ Error: ${errMsg}`));
91386
92326
  refererPosition: options.position
91387
92327
  });
91388
92328
  const base64 = serializeTransaction(result.transaction);
91389
- console.log(JSON.stringify({ unsignedTransactions: [base64] }));
92329
+ if (mode === "unsigned-tx") {
92330
+ console.log(JSON.stringify({ unsignedTransactions: [base64] }));
92331
+ return;
92332
+ }
92333
+ const ctx = requirePrivyContext(walletAddress);
92334
+ printPrivySignBanner();
92335
+ const broadcast = await privyBroadcastOne(ctx, base64);
92336
+ if (!broadcast.ok) {
92337
+ if (format === "json") outputErrorJson(broadcast.error.toJSON());
92338
+ else outputErrorTable(broadcast.error.toJSON());
92339
+ process.exit(1);
92340
+ }
92341
+ if (format === "json") {
92342
+ outputJson(
92343
+ {
92344
+ signature: broadcast.value.signature,
92345
+ explorer: `https://solscan.io/tx/${broadcast.value.signature}`
92346
+ },
92347
+ startTime
92348
+ );
92349
+ } else {
92350
+ outputTransactionResult(broadcast.value.signature);
92351
+ }
91390
92352
  } catch (e) {
91391
92353
  const message = e.message || "Unknown SDK error";
91392
92354
  if (format === "json") {