@provablehq/shield-swap-cli 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/{balances-6SU4DCKM.js → balances-DLTR4XDL.js} +2 -2
  2. package/dist/{chunk-2OT6LZPW.js → chunk-44Q5ILLQ.js} +4 -13
  3. package/dist/chunk-44Q5ILLQ.js.map +1 -0
  4. package/dist/{collect-G3GNFL57.js → collect-NKT6HDTX.js} +2 -2
  5. package/dist/index.js +11 -11
  6. package/dist/{liquidity-RB5MKGPA.js → liquidity-QT6SH5QM.js} +2 -2
  7. package/dist/{liquidity-e2e-WCTSSZYS.js → liquidity-e2e-ESPF2D2R.js} +2 -2
  8. package/dist/{mint-6OKWODQG.js → mint-6DUIALMW.js} +2 -2
  9. package/dist/{pools-NWQNFJ7W.js → pools-R6XCND5N.js} +2 -2
  10. package/dist/{positions-MILT3BRU.js → positions-ATNNIP4M.js} +2 -2
  11. package/dist/session.d.ts +4 -18
  12. package/dist/session.js +1 -3
  13. package/dist/{setup-OR4NAV56.js → setup-MMZETJXP.js} +6 -22
  14. package/dist/setup-MMZETJXP.js.map +1 -0
  15. package/dist/{swap-W72XGG7Y.js → swap-YDGSUXXR.js} +2 -2
  16. package/dist/{swap-concurrent-IHGWJMST.js → swap-concurrent-ZNCLLVJ5.js} +2 -2
  17. package/dist/{swap-history-43E4JZUO.js → swap-history-HGN6QX42.js} +2 -2
  18. package/package.json +3 -3
  19. package/dist/chunk-2OT6LZPW.js.map +0 -1
  20. package/dist/setup-OR4NAV56.js.map +0 -1
  21. /package/dist/{balances-6SU4DCKM.js.map → balances-DLTR4XDL.js.map} +0 -0
  22. /package/dist/{collect-G3GNFL57.js.map → collect-NKT6HDTX.js.map} +0 -0
  23. /package/dist/{liquidity-RB5MKGPA.js.map → liquidity-QT6SH5QM.js.map} +0 -0
  24. /package/dist/{liquidity-e2e-WCTSSZYS.js.map → liquidity-e2e-ESPF2D2R.js.map} +0 -0
  25. /package/dist/{mint-6OKWODQG.js.map → mint-6DUIALMW.js.map} +0 -0
  26. /package/dist/{pools-NWQNFJ7W.js.map → pools-R6XCND5N.js.map} +0 -0
  27. /package/dist/{positions-MILT3BRU.js.map → positions-ATNNIP4M.js.map} +0 -0
  28. /package/dist/{swap-W72XGG7Y.js.map → swap-YDGSUXXR.js.map} +0 -0
  29. /package/dist/{swap-concurrent-IHGWJMST.js.map → swap-concurrent-ZNCLLVJ5.js.map} +0 -0
  30. /package/dist/{swap-history-43E4JZUO.js.map → swap-history-HGN6QX42.js.map} +0 -0
@@ -15,7 +15,7 @@ import {
15
15
  import {
16
16
  formatAmount,
17
17
  loadSession
18
- } from "./chunk-2OT6LZPW.js";
18
+ } from "./chunk-44Q5ILLQ.js";
19
19
 
20
20
  // src/commands/balances.ts
21
21
  var USAGE = `shield-swap balances \u2014 private and public holdings per token
@@ -63,4 +63,4 @@ async function main(argv) {
63
63
  export {
64
64
  main
65
65
  };
66
- //# sourceMappingURL=balances-6SU4DCKM.js.map
66
+ //# sourceMappingURL=balances-DLTR4XDL.js.map
@@ -5,7 +5,6 @@ import {
5
5
  loadNetwork,
6
6
  generateAccount
7
7
  } from "@provablehq/veil-aleo-sdk";
8
- import { fileCredentialStore } from "@provablehq/veil-aleo-sdk/node";
9
8
  import { shieldSwapActions, parseUnits } from "@provablehq/shield-swap-sdk";
10
9
  import { fileBlindedIdentityStore } from "@provablehq/shield-swap-sdk/node";
11
10
  function resolveNetwork(explicit) {
@@ -15,7 +14,7 @@ function resolveNetwork(explicit) {
15
14
  }
16
15
  return value;
17
16
  }
18
- var NETWORK_URL = "https://api.provable.com/v2";
17
+ var NETWORK_URL = "https://edge.provable.com/api/v2";
19
18
  var STATE_ROOT = process.env.SHIELD_SWAP_STATE_DIR ?? join(process.cwd(), ".shield-swap");
20
19
  function stateDir(network) {
21
20
  return join(STATE_ROOT, network);
@@ -23,9 +22,6 @@ function stateDir(network) {
23
22
  function blindedStorePath(network) {
24
23
  return join(stateDir(network), "blinded.json");
25
24
  }
26
- function credentialsPath(network) {
27
- return join(stateDir(network), "provable-credentials.json");
28
- }
29
25
  function statePath(network) {
30
26
  return join(stateDir(network), "state.json");
31
27
  }
@@ -95,17 +91,13 @@ async function loadSession(options = {}) {
95
91
  );
96
92
  }
97
93
  const aleo = await loadNetwork(network);
98
- const scanner = aleo.createRemoteScanner();
99
94
  const { walletClient, account } = aleo.createAleoClient({
100
95
  privateKey: state.privateKey,
101
96
  networkUrl: NETWORK_URL,
102
- provingMode: "delegated",
103
- credentialStore: fileCredentialStore(credentialsPath(network)),
104
97
  // Faucet-funded accounts hold no public credits; the delegated prover
105
98
  // pays fees from its FeeMaster account. Opt out with
106
99
  // SHIELD_SWAP_FEE_MASTER=0 when the account funds its own fees.
107
- useFeeMaster: process.env.SHIELD_SWAP_FEE_MASTER !== "0",
108
- records: scanner
100
+ useFeeMaster: process.env.SHIELD_SWAP_FEE_MASTER !== "0"
109
101
  });
110
102
  const apiUrl = process.env.SHIELD_SWAP_API_URL ?? state.apiUrl;
111
103
  const blindedIdentities = fileBlindedIdentityStore(blindedStorePath(network));
@@ -122,7 +114,7 @@ async function loadSession(options = {}) {
122
114
  { cause: error }
123
115
  );
124
116
  }
125
- return { client, account, scanner, state, aleo, network, blindedIdentities };
117
+ return { client, account, state, aleo, network, blindedIdentities };
126
118
  }
127
119
  async function pollUntil(fn, attempts, intervalMs) {
128
120
  for (let i = 0; i < attempts; i++) {
@@ -165,7 +157,6 @@ export {
165
157
  NETWORK_URL,
166
158
  stateDir,
167
159
  blindedStorePath,
168
- credentialsPath,
169
160
  loadState,
170
161
  saveState,
171
162
  formatAmount,
@@ -175,4 +166,4 @@ export {
175
166
  ensureKeyMaterial,
176
167
  NeedsConfigDecisionError
177
168
  };
178
- //# sourceMappingURL=chunk-2OT6LZPW.js.map
169
+ //# sourceMappingURL=chunk-44Q5ILLQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/session.ts"],"sourcesContent":["/**\n * Shared session plumbing for the `shield-swap` command.\n *\n * Owns the state file (`./.shield-swap/<network>/state.json` by default) and\n * the client wiring, so every command starts from `loadSession()` and gets a\n * fully authenticated client plus persistent storage for the one thing that\n * must survive a crash and cannot be rediscovered: the private key, plus the\n * DEX grants tied to it.\n *\n * Exported as `@provablehq/shield-swap-cli/session` so a script driving the SDK\n * directly can share the same state file the command line writes.\n *\n * Nothing else is stored. Swap handles belong to the SDK's blinded identity\n * store, and positions are discovered from records with\n * `client.getOwnedPositions()` — a local list of either could only ever be a\n * stale copy of what the chain already knows.\n *\n * Everything is scoped by network. Nothing is shared between testnet and\n * mainnet: not the key, not the API grant, and above all not the identity\n * store, whose reservations are only meaningful against one chain.\n *\n * The state file holds a private key and API credentials — keep it out of\n * version control (`.shield-swap/` belongs in .gitignore) and treat it like\n * a wallet file.\n */\nimport { mkdirSync, readFileSync, writeFileSync, existsSync, chmodSync, renameSync } from 'node:fs'\nimport { join } from 'node:path'\nimport {\n loadNetwork,\n generateAccount,\n} from '@provablehq/veil-aleo-sdk'\nimport { shieldSwapActions, getPrivateBalances, parseUnits, DEFAULT_PROGRAM } from '@provablehq/shield-swap-sdk'\nimport { fileBlindedIdentityStore } from '@provablehq/shield-swap-sdk/node'\n\n/** The networks these scripts run against. */\nexport type Network = 'testnet' | 'mainnet'\n\n/**\n * Resolves the network from an explicit choice, the environment, or the default.\n *\n * Testnet is the default and mainnet is never reached by omission: a script has\n * to be told, because everything downstream — the DEX API host, the prover, the\n * scanner, the token registry, and the identity store — is per-network, and the\n * mainnet ones move real value.\n *\n * @param explicit A `--network` value, when a script parsed one.\n * @throws When the value is neither network, rather than silently using testnet.\n */\nexport function resolveNetwork(explicit?: string): Network {\n const value = explicit ?? process.env.SHIELD_SWAP_NETWORK ?? 'testnet'\n if (value !== 'testnet' && value !== 'mainnet') {\n throw new Error(`Unknown network \"${value}\" — use testnet or mainnet.`)\n }\n return value\n}\n\nexport const NETWORK_URL = 'https://edge.provable.com/api/v2'\n\n/** Everything that must survive between agent sessions. */\nexport type ShieldSwapState = {\n network: string\n /**\n * DEX API origin this session targets. Unset means the SDK's default\n * hosted deployment. Set by `shield-swap setup` (`--api-url` / SHIELD_SWAP_API_URL);\n * the access grant, API token, and airdrop job are scoped to one\n * deployment, so setup clears them when this changes.\n */\n apiUrl?: string\n privateKey?: string\n address?: string\n dexApiToken?: string\n accessRedeemed?: boolean\n /** Faucet job already requested for this account — prevents double-drawing on re-runs. */\n airdropJobId?: string\n}\n\nconst STATE_ROOT = process.env.SHIELD_SWAP_STATE_DIR ?? join(process.cwd(), '.shield-swap')\n\n/** Per-network state directory. Nothing is shared between networks. */\nexport function stateDir(network: Network): string {\n return join(STATE_ROOT, network)\n}\n\n/**\n * Where the blinded identity store lives for a network.\n *\n * Scoped by network because a reservation is only meaningful against the chain\n * it was checked on: counters reserved against testnet's\n * `used_blinded_addresses` say nothing about mainnet's, and one shared file\n * would hand out identities the other chain has already consumed.\n */\nexport function blindedStorePath(network: Network): string {\n return join(stateDir(network), 'blinded.json')\n}\n\nfunction statePath(network: Network): string {\n return join(stateDir(network), 'state.json')\n}\n\n/** The pre-network layout, still read for testnet so existing keys survive. */\nconst LEGACY_STATE_PATH = join(STATE_ROOT, 'state.json')\n\n/**\n * Reads a network's state file, or returns a fresh empty state.\n *\n * Falls back to the pre-network layout for testnet only, so an existing\n * `.shield-swap/state.json` keeps working; the next save writes it to the\n * network-scoped path.\n */\nexport function loadState(network: Network): ShieldSwapState {\n const path = existsSync(statePath(network))\n ? statePath(network)\n : network === 'testnet' && existsSync(LEGACY_STATE_PATH)\n ? LEGACY_STATE_PATH\n : undefined\n if (!path) return { network }\n const parsed = JSON.parse(readFileSync(path, 'utf8')) as ShieldSwapState\n // A state file that names a different network is a wrong-chain hazard: its\n // key is fine but its access grant, API token, and airdrop job are not.\n parsed.network = network\n return parsed\n}\n\n/**\n * Writes the state file atomically (temp file + rename, 0600 — it holds the\n * private key). A crash mid-write can never truncate the only copy of the\n * key and the open swap handles.\n */\nexport function saveState(state: ShieldSwapState): void {\n const network = resolveNetwork(state.network)\n mkdirSync(stateDir(network), { recursive: true })\n const target = statePath(network)\n const tmp = `${target}.tmp`\n writeFileSync(tmp, JSON.stringify(state, null, 2))\n chmodSync(tmp, 0o600)\n renameSync(tmp, target)\n}\n\n\n/**\n * Renders a raw base-unit amount in human units (\"0.0534 ETH\"), the ONLY\n * format that should ever reach the user. Raw units (wei-style integers)\n * are SDK-facing; showing them to a person misstates their balances by\n * orders of magnitude.\n */\nexport function formatAmount(amount: bigint, decimals: number, symbol?: string): string {\n const scale = 10n ** BigInt(decimals)\n const whole = amount / scale\n const frac = amount % scale\n let s = whole.toLocaleString('en-US')\n if (frac > 0n) {\n // Full precision minus trailing zeros — tiny testnet amounts live many\n // places below the decimal point and must not round away to nothing.\n const fracStr = frac.toString().padStart(decimals, '0').replace(/0+$/, '')\n if (fracStr) s += `.${fracStr}`\n }\n return symbol ? `${s} ${symbol}` : s\n}\n\n/** What {@link namedAmounts} needs of a pool's token to place an amount. */\nexport type AmountToken = { id: string; symbol: string; decimals: number }\n\n/**\n * Places caller-named amounts into a pool's own token order.\n *\n * A pool orders its tokens by id, not by anything a caller types, so `--amount0`\n * is unknowable without reading the pool first: naming a pair `USDCx:ETH` does\n * not make USDCx side 0. `--amount USDCx:0.5` names the token instead and is\n * matched here, while `--amount0`/`--amount1` stay available for callers who know\n * the order. Parsing is the inverse of {@link formatAmount}: human decimals in,\n * raw base units out. Pure and local.\n *\n * @param params.entries `--amount` values, each `<symbol|id>:<decimal>`.\n * @param params.indexed The raw `--amount0` and `--amount1` strings, in that\n * order, `undefined` where the flag was absent.\n * @param params.tokens The pool's tokens in ITS order — `[token0, token1]`.\n * @returns Raw base units per side, `undefined` where nothing named that side.\n * @throws When an entry is malformed, names a token outside the pair, or names a\n * side twice — including once by symbol and once by index, where preferring\n * either would commit an amount the caller did not ask for.\n *\n * @example\n * const { amount0, amount1 } = namedAmounts({\n * entries: ['USDCx:0.5'],\n * indexed: [undefined, undefined],\n * tokens: [token0, token1],\n * })\n */\nexport function namedAmounts(params: {\n entries: string[]\n indexed: readonly [string | undefined, string | undefined]\n tokens: readonly [AmountToken, AmountToken]\n}): { amount0: bigint | undefined; amount1: bigint | undefined } {\n const [token0, token1] = params.tokens\n const amounts: Array<bigint | undefined> = [\n params.indexed[0] ? parseUnits(params.indexed[0], token0.decimals) : undefined,\n params.indexed[1] ? parseUnits(params.indexed[1], token1.decimals) : undefined,\n ]\n // Tracked alongside so a collision can name both flags rather than just the token.\n const namedBy = [params.indexed[0] ? '--amount0' : undefined, params.indexed[1] ? '--amount1' : undefined]\n\n for (const entry of params.entries) {\n const parts = entry.split(':')\n if (parts.length !== 2 || !parts[0] || !parts[1]) {\n throw new Error(`--amount takes <symbol>:<amount>, e.g. --amount ${token0.symbol}:0.5 — got \"${entry}\"`)\n }\n const [name, value] = parts as [string, string]\n const wanted = name.trim()\n const side = [token0, token1].findIndex(\n (token) => token.symbol.toLowerCase() === wanted.toLowerCase() || token.id === wanted,\n )\n if (side === -1) {\n throw new Error(`\"${wanted}\" is not in this pool's pair — it holds ${token0.symbol} and ${token1.symbol}.`)\n }\n const token = side === 0 ? token0 : token1\n if (amounts[side] !== undefined) {\n throw new Error(`${token.symbol} is named twice, by ${namedBy[side]} and --amount ${entry}.`)\n }\n amounts[side] = parseUnits(value.trim(), token.decimals)\n namedBy[side] = `--amount ${entry}`\n }\n return { amount0: amounts[0], amount1: amounts[1] }\n}\n\n/**\n * Builds the fully wired, authenticated session from the state file.\n *\n * Requires `shield-swap setup` to have run (key material in the state file).\n * Authenticates with the DEX API on every call — the session JWT covers\n * everything including access/token management, and auto-renews on expiry.\n *\n * The Provable gateway needs no credentials: proving and record scanning work\n * from the private key alone, so nothing is registered or minted.\n */\nexport async function loadSession(options: { network?: string } = {}) {\n const network = resolveNetwork(options.network)\n const state = loadState(network)\n if (!state.privateKey) {\n throw new Error(\n `No shield-swap session found for ${network} — run \\`shield-swap setup --network ${network}\\` first (see startup.md).`,\n )\n }\n\n const aleo = await loadNetwork(network)\n // No prover or scanner URL: both default to the Provable gateway and take the\n // network from the client, so naming them here would only risk drift.\n const { walletClient, account } = aleo.createAleoClient({\n privateKey: state.privateKey,\n networkUrl: NETWORK_URL,\n // Faucet-funded accounts hold no public credits; the delegated prover\n // pays fees from its FeeMaster account. Opt out with\n // SHIELD_SWAP_FEE_MASTER=0 when the account funds its own fees.\n useFeeMaster: process.env.SHIELD_SWAP_FEE_MASTER !== '0',\n })\n // SHIELD_SWAP_API_URL overrides for one-off runs; the persistent choice\n // lives in the state file (`shield-swap setup --api-url`).\n const apiUrl = process.env.SHIELD_SWAP_API_URL ?? state.apiUrl\n // The identity store is what makes concurrent swaps safe and unclaimed swaps\n // recoverable, and it is scoped by network because a reservation is only\n // meaningful against the chain it was checked on. Every swap through this\n // client reserves and records automatically.\n const blindedIdentities = fileBlindedIdentityStore(blindedStorePath(network))\n const client = walletClient.extend(\n shieldSwapActions({ api: { baseUrl: apiUrl }, blindedIdentities }),\n )\n try {\n await client.authenticateShieldSwap()\n } catch (error) {\n // A pinned host is invisible state: it lives in a file nobody re-reads, so\n // when the deployment behind it is retired every call fails with a bare 404\n // and nothing points at the pin. Name it, and say how to drop it.\n if (!apiUrl) throw error\n const source =\n process.env.SHIELD_SWAP_API_URL === apiUrl ? 'SHIELD_SWAP_API_URL' : `apiUrl in ${statePath(network)}`\n throw new Error(\n `could not authenticate with the DEX API at ${apiUrl}, which is pinned by ${source} rather than ` +\n `derived from the network. If that deployment is gone, re-pin with \\`shield-swap setup --api-url ` +\n `<origin>\\` or clear the field to fall back to the default for ${network}.`,\n { cause: error },\n )\n }\n\n return { client, account, state, aleo, network, blindedIdentities }\n}\n\n\n\n/** Polls a predicate until it returns true or attempts run out. */\nexport async function pollUntil(fn: () => Promise<boolean>, attempts: number, intervalMs: number): Promise<boolean> {\n for (let i = 0; i < attempts; i++) {\n if (await fn()) return true\n await new Promise((r) => setTimeout(r, intervalMs))\n }\n return false\n}\n\n/**\n * Resolves key material and stores it. Priority: existing state → imported\n * key (`importKey`) → fresh generation, but only when `allowGenerate` is\n * true. Returning users keep their account; a fresh key is never created\n * silently.\n */\nexport async function ensureKeyMaterial(\n state: ShieldSwapState,\n options: { importKey?: string; allowGenerate?: boolean } = {},\n): Promise<ShieldSwapState> {\n const network = resolveNetwork(state.network)\n await loadNetwork(network) // initializes the WASM the account helpers use\n if (state.privateKey && options.importKey && options.importKey !== state.privateKey) {\n throw new Error(\n `a DIFFERENT account is already configured here (${state.address ?? 'address unknown'}). ` +\n 'Refusing to switch silently — its funds and access live on that key. To use the imported ' +\n `key instead, move or delete the state directory first, then re-run with --private-key-file.`,\n )\n }\n if (!state.privateKey) {\n if (options.importKey) {\n state.privateKey = options.importKey\n } else if (options.allowGenerate) {\n state.privateKey = generateAccount().privateKey\n } else {\n throw new NeedsConfigDecisionError()\n }\n }\n // Derive the address from the key so imported/seeded states are complete.\n const aleo = await loadNetwork(network)\n state.address = aleo.privateKeyToAccount(state.privateKey).address\n saveState(state)\n return state\n}\n\n/** Signals that setup must ask the user about existing config before creating anything. */\nexport class NeedsConfigDecisionError extends Error {\n constructor() {\n super('no key material found and none provided')\n this.name = 'NeedsConfigDecisionError'\n }\n}\n\n\n"],"mappings":"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","names":["token"]}
@@ -12,7 +12,7 @@ import {
12
12
  formatAmount,
13
13
  loadSession,
14
14
  pollUntil
15
- } from "./chunk-2OT6LZPW.js";
15
+ } from "./chunk-44Q5ILLQ.js";
16
16
 
17
17
  // src/commands/collect.ts
18
18
  var USAGE = `shield-swap collect \u2014 withdraw a position's owed tokens, and optionally close it
@@ -237,4 +237,4 @@ Collected from ${data.collected.length} of ${candidates.length} position(s).`);
237
237
  export {
238
238
  main
239
239
  };
240
- //# sourceMappingURL=collect-G3GNFL57.js.map
240
+ //# sourceMappingURL=collect-NKT6HDTX.js.map
package/dist/index.js CHANGED
@@ -12,47 +12,47 @@ import {
12
12
  var COMMANDS = {
13
13
  setup: {
14
14
  summary: "Set up all credentials required for Shield Swap.",
15
- load: () => import("./setup-OR4NAV56.js")
15
+ load: () => import("./setup-MMZETJXP.js")
16
16
  },
17
17
  pools: {
18
18
  summary: "List pools with their on-chain depth and whether they are tradeable.",
19
- load: () => import("./pools-NWQNFJ7W.js")
19
+ load: () => import("./pools-R6XCND5N.js")
20
20
  },
21
21
  balances: {
22
22
  summary: "Private and public holdings per token.",
23
- load: () => import("./balances-6SU4DCKM.js")
23
+ load: () => import("./balances-DLTR4XDL.js")
24
24
  },
25
25
  positions: {
26
26
  summary: "Liquidity positions held + their ranges and fees earned (with option to collect).",
27
- load: () => import("./positions-MILT3BRU.js")
27
+ load: () => import("./positions-ATNNIP4M.js")
28
28
  },
29
29
  swap: {
30
30
  summary: "Sell one token for another and claim the output.",
31
- load: () => import("./swap-W72XGG7Y.js")
31
+ load: () => import("./swap-YDGSUXXR.js")
32
32
  },
33
33
  "swap-concurrent": {
34
34
  summary: "Make multiple swaps concurrently.",
35
- load: () => import("./swap-concurrent-IHGWJMST.js")
35
+ load: () => import("./swap-concurrent-ZNCLLVJ5.js")
36
36
  },
37
37
  history: {
38
38
  summary: "Swap history and status of swaps.",
39
- load: () => import("./swap-history-43E4JZUO.js")
39
+ load: () => import("./swap-history-HGN6QX42.js")
40
40
  },
41
41
  mint: {
42
42
  summary: "Open a liquidity position over a tick range.",
43
- load: () => import("./mint-6OKWODQG.js")
43
+ load: () => import("./mint-6DUIALMW.js")
44
44
  },
45
45
  liquidity: {
46
46
  summary: "Add to an open position, or remove liquidity and book it as owed.",
47
- load: () => import("./liquidity-RB5MKGPA.js")
47
+ load: () => import("./liquidity-QT6SH5QM.js")
48
48
  },
49
49
  collect: {
50
50
  summary: "Sweep what a position is owed into records, optionally closing it.",
51
- load: () => import("./collect-G3GNFL57.js")
51
+ load: () => import("./collect-NKT6HDTX.js")
52
52
  },
53
53
  "liquidity-e2e": {
54
54
  summary: "The whole liquidity lifecycle in one run \u2014 mint through burn.",
55
- load: () => import("./liquidity-e2e-WCTSSZYS.js")
55
+ load: () => import("./liquidity-e2e-ESPF2D2R.js")
56
56
  }
57
57
  };
58
58
  function usage() {
@@ -14,7 +14,7 @@ import {
14
14
  loadSession,
15
15
  namedAmounts,
16
16
  pollUntil
17
- } from "./chunk-2OT6LZPW.js";
17
+ } from "./chunk-44Q5ILLQ.js";
18
18
 
19
19
  // src/commands/liquidity.ts
20
20
  import {
@@ -349,4 +349,4 @@ Removed ${data.liquidityRemoved} liquidity from position ${data.positionTokenId}
349
349
  export {
350
350
  main
351
351
  };
352
- //# sourceMappingURL=liquidity-RB5MKGPA.js.map
352
+ //# sourceMappingURL=liquidity-QT6SH5QM.js.map
@@ -13,7 +13,7 @@ import {
13
13
  formatAmount,
14
14
  loadSession,
15
15
  pollUntil
16
- } from "./chunk-2OT6LZPW.js";
16
+ } from "./chunk-44Q5ILLQ.js";
17
17
 
18
18
  // src/commands/liquidity-e2e.ts
19
19
  var USAGE = `shield-swap liquidity-e2e \u2014 the whole position lifecycle in one run
@@ -306,4 +306,4 @@ Round trip complete on ${data.pair} over ticks ${data.tickLower}\u2026${data.tic
306
306
  export {
307
307
  main
308
308
  };
309
- //# sourceMappingURL=liquidity-e2e-WCTSSZYS.js.map
309
+ //# sourceMappingURL=liquidity-e2e-ESPF2D2R.js.map
@@ -14,7 +14,7 @@ import {
14
14
  loadSession,
15
15
  namedAmounts,
16
16
  pollUntil
17
- } from "./chunk-2OT6LZPW.js";
17
+ } from "./chunk-44Q5ILLQ.js";
18
18
 
19
19
  // src/commands/mint.ts
20
20
  var USAGE = `shield-swap mint \u2014 open a liquidity position
@@ -250,4 +250,4 @@ Position ${data.positionTokenId} open on ${token0.symbol}/${token1.symbol}.`);
250
250
  export {
251
251
  main
252
252
  };
253
- //# sourceMappingURL=mint-6OKWODQG.js.map
253
+ //# sourceMappingURL=mint-6DUIALMW.js.map
@@ -13,7 +13,7 @@ import {
13
13
  } from "./chunk-IHYFMX5A.js";
14
14
  import {
15
15
  loadSession
16
- } from "./chunk-2OT6LZPW.js";
16
+ } from "./chunk-44Q5ILLQ.js";
17
17
 
18
18
  // src/commands/pools.ts
19
19
  function formatFee(pips) {
@@ -181,4 +181,4 @@ export {
181
181
  discoverPools,
182
182
  main
183
183
  };
184
- //# sourceMappingURL=pools-NWQNFJ7W.js.map
184
+ //# sourceMappingURL=pools-R6XCND5N.js.map
@@ -16,7 +16,7 @@ import {
16
16
  import {
17
17
  formatAmount,
18
18
  loadSession
19
- } from "./chunk-2OT6LZPW.js";
19
+ } from "./chunk-44Q5ILLQ.js";
20
20
 
21
21
  // src/commands/positions.ts
22
22
  var USAGE = `shield-swap positions \u2014 owned liquidity positions and what they are owed
@@ -131,4 +131,4 @@ ${owed.length} position(s) have something to collect \u2014 run \`shield-swap co
131
131
  export {
132
132
  main
133
133
  };
134
- //# sourceMappingURL=positions-MILT3BRU.js.map
134
+ //# sourceMappingURL=positions-ATNNIP4M.js.map
package/dist/session.d.ts CHANGED
@@ -16,7 +16,7 @@ type Network = 'testnet' | 'mainnet';
16
16
  * @throws When the value is neither network, rather than silently using testnet.
17
17
  */
18
18
  declare function resolveNetwork(explicit?: string): Network;
19
- declare const NETWORK_URL = "https://api.provable.com/v2";
19
+ declare const NETWORK_URL = "https://edge.provable.com/api/v2";
20
20
  /** Everything that must survive between agent sessions. */
21
21
  type ShieldSwapState = {
22
22
  network: string;
@@ -45,14 +45,6 @@ declare function stateDir(network: Network): string;
45
45
  * would hand out identities the other chain has already consumed.
46
46
  */
47
47
  declare function blindedStorePath(network: Network): string;
48
- /**
49
- * Where Provable API credentials live for a network.
50
- *
51
- * Separate from the state file because the SDK owns the format: `shield-swap setup`
52
- * hands `fileCredentialStore` this path and the client reads and writes it
53
- * directly, including registering a consumer when the file is absent.
54
- */
55
- declare function credentialsPath(network: Network): string;
56
48
  /**
57
49
  * Reads a network's state file, or returns a fresh empty state.
58
50
  *
@@ -121,10 +113,8 @@ declare function namedAmounts(params: {
121
113
  * Authenticates with the DEX API on every call — the session JWT covers
122
114
  * everything including access/token management, and auto-renews on expiry.
123
115
  *
124
- * Provable API credentials are not required up front: the client registers a
125
- * consumer through the credential file on first prove or scan when it holds
126
- * none — though `shield-swap setup` registers and verifies eagerly, so a session built
127
- * after setup has working credentials rather than untested ones.
116
+ * The Provable gateway needs no credentials: proving and record scanning work
117
+ * from the private key alone, so nothing is registered or minted.
128
118
  */
129
119
  declare function loadSession(options?: {
130
120
  network?: string;
@@ -133,10 +123,6 @@ declare function loadSession(options?: {
133
123
  recordProvider: _provablehq_veil_core.RecordProvider | undefined;
134
124
  } & _provablehq_veil_aleo_sdk.ProvableApiActions>;
135
125
  account: _provablehq_veil_core.LocalAccount<"privateKey">;
136
- scanner: _provablehq_veil_core.RecordProvider & {
137
- setSession: (session: _provablehq_veil_aleo_sdk.ProvableSession) => void;
138
- setAuth: (auth: _provablehq_veil_aleo_sdk.ProvableKeyedAuth) => void;
139
- };
140
126
  state: ShieldSwapState;
141
127
  aleo: _provablehq_veil_aleo_sdk.AleoSdk;
142
128
  network: Network;
@@ -159,4 +145,4 @@ declare class NeedsConfigDecisionError extends Error {
159
145
  constructor();
160
146
  }
161
147
 
162
- export { type AmountToken, NETWORK_URL, NeedsConfigDecisionError, type Network, type ShieldSwapState, blindedStorePath, credentialsPath, ensureKeyMaterial, formatAmount, loadSession, loadState, namedAmounts, pollUntil, resolveNetwork, saveState, stateDir };
148
+ export { type AmountToken, NETWORK_URL, NeedsConfigDecisionError, type Network, type ShieldSwapState, blindedStorePath, ensureKeyMaterial, formatAmount, loadSession, loadState, namedAmounts, pollUntil, resolveNetwork, saveState, stateDir };
package/dist/session.js CHANGED
@@ -2,7 +2,6 @@ import {
2
2
  NETWORK_URL,
3
3
  NeedsConfigDecisionError,
4
4
  blindedStorePath,
5
- credentialsPath,
6
5
  ensureKeyMaterial,
7
6
  formatAmount,
8
7
  loadSession,
@@ -12,12 +11,11 @@ import {
12
11
  resolveNetwork,
13
12
  saveState,
14
13
  stateDir
15
- } from "./chunk-2OT6LZPW.js";
14
+ } from "./chunk-44Q5ILLQ.js";
16
15
  export {
17
16
  NETWORK_URL,
18
17
  NeedsConfigDecisionError,
19
18
  blindedStorePath,
20
- credentialsPath,
21
19
  ensureKeyMaterial,
22
20
  formatAmount,
23
21
  loadSession,
@@ -3,7 +3,6 @@ import {
3
3
  } from "./chunk-IHYFMX5A.js";
4
4
  import {
5
5
  NeedsConfigDecisionError,
6
- credentialsPath,
7
6
  ensureKeyMaterial,
8
7
  formatAmount,
9
8
  loadSession,
@@ -12,18 +11,15 @@ import {
12
11
  resolveNetwork,
13
12
  saveState,
14
13
  stateDir
15
- } from "./chunk-2OT6LZPW.js";
14
+ } from "./chunk-44Q5ILLQ.js";
16
15
 
17
16
  // src/commands/setup.ts
18
17
  import { readFileSync } from "fs";
19
18
  import { ApiError, DEFAULT_API_URL } from "@provablehq/shield-swap-sdk";
20
- import { fileCredentialStore } from "@provablehq/veil-aleo-sdk/node";
21
19
  var USAGE = `shield-swap setup \u2014 bootstrap an account and get it funded
22
20
 
23
21
  --new generate a brand-new account
24
22
  --private-key-file <path> import an existing key, read from this file
25
- --consumer-id <id> Provable API consumer id (else self-registers)
26
- --api-key <key> Provable API key
27
23
  --invite-code <code> redeem an invite code when access is locked
28
24
  --api-url <origin> pin a DEX API deployment
29
25
  --network <testnet|mainnet> default testnet
@@ -33,7 +29,7 @@ Every step is check-then-act, so re-running resumes where a failed run stopped.
33
29
  A private key is NEVER pasted into a conversation or command history: write it
34
30
  to a file and pass --private-key-file, or export SHIELD_SWAP_PRIVATE_KEY in your
35
31
  own shell. Other environment fallbacks: SHIELD_SWAP_PRIVATE_KEY_FILE,
36
- ALEO_CONSUMER_ID, ALEO_DPS_API_KEY, SHIELD_SWAP_INVITE_CODE, SHIELD_SWAP_API_URL.
32
+ SHIELD_SWAP_INVITE_CODE, SHIELD_SWAP_API_URL.
37
33
 
38
34
  Exit codes: 0 ready \xB7 2 needs input from the user \xB7 3 airdrop still pending \xB7
39
35
  1 anything else.`;
@@ -52,11 +48,8 @@ function resolveImportKey(argv) {
52
48
  }
53
49
  async function setup(argv) {
54
50
  const inviteCode = argValue(argv, "--invite-code") ?? process.env.SHIELD_SWAP_INVITE_CODE;
55
- const consumerId = argValue(argv, "--consumer-id") ?? process.env.ALEO_CONSUMER_ID;
56
- const apiKey = argValue(argv, "--api-key") ?? process.env.ALEO_DPS_API_KEY;
57
51
  const network = resolveNetwork(argValue(argv, "--network"));
58
52
  const apiUrl = argValue(argv, "--api-url")?.replace(/\/$/, "");
59
- const credentialStore = fileCredentialStore(credentialsPath(network));
60
53
  const allowGenerate = argv.includes("--new");
61
54
  const importKey = resolveImportKey(argv);
62
55
  let state = loadState(network);
@@ -74,29 +67,20 @@ async function setup(argv) {
74
67
  } catch (err) {
75
68
  if (err instanceof NeedsConfigDecisionError) {
76
69
  console.error(
77
- "\nNEEDS_CONFIG_DECISION: no shield-swap account is configured here. Ask the user whether they already have one before creating anything. NEVER ask them to paste a private key into the conversation:\n - existing account \u2192 the user saves their key to a file themselves, then re-run\n with --private-key-file <path> (or they export SHIELD_SWAP_PRIVATE_KEY in\n their own shell). Add --consumer-id/--api-key if they have Provable API\n credentials.\n - brand new \u2192 re-run with --new\n"
70
+ "\nNEEDS_CONFIG_DECISION: no shield-swap account is configured here. Ask the user whether they already have one before creating anything. NEVER ask them to paste a private key into the conversation:\n - existing account \u2192 the user saves their key to a file themselves, then re-run\n with --private-key-file <path> (or they export SHIELD_SWAP_PRIVATE_KEY in\n - brand new \u2192 re-run with --new\n"
78
71
  );
79
72
  process.exit(2);
80
73
  }
81
74
  throw err;
82
75
  }
83
76
  console.log(`\u2713 account: ${state.address}`);
84
- if (consumerId && apiKey && !await credentialStore.load()) {
85
- await credentialStore.save({ consumerId, apiKey });
86
- }
87
- const legacy = state.provableApi;
88
- if (legacy && !await credentialStore.load()) {
89
- await credentialStore.save(legacy);
77
+ if ("provableApi" in state) {
90
78
  delete state.provableApi;
91
79
  saveState(state);
92
- console.log(`\u2713 moved Provable API credentials to ${credentialsPath(network)}`);
80
+ console.log("\u2713 dropped legacy Provable API credentials from the state file (the gateway needs none)");
93
81
  }
94
82
  const { client, account } = await loadSession({ network });
95
83
  console.log("\u2713 DEX API session established (challenge/verify)");
96
- const provable = await client.authenticateProvableApi();
97
- console.log(
98
- `\u2713 Provable API consumer: ${provable.credentials.consumerId}` + (provable.registered ? ` (registered, saved to ${credentialsPath(network)})` : "")
99
- );
100
84
  const status = await client.api.getReferralStatus();
101
85
  if (!status.has_access) {
102
86
  if (!inviteCode) {
@@ -215,4 +199,4 @@ async function main(argv) {
215
199
  export {
216
200
  main
217
201
  };
218
- //# sourceMappingURL=setup-OR4NAV56.js.map
202
+ //# sourceMappingURL=setup-MMZETJXP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/setup.ts"],"sourcesContent":["/**\n * Shield Swap account bootstrap — the startup gauntlet, idempotent.\n *\n * Run it as many times as needed; every step is check-then-act, so a failed\n * or interrupted run resumes where it stopped:\n *\n * 1. Key material — reuse the stored account, import the user's\n * existing key, or (only with --new) generate one\n * 2. DEX authentication — challenge/verify session with the account\n * 3. Provable gateway — needs no credentials; a legacy consumer pair on\n * file is kept but unused on the default gateway\n * 4. Invite code — check access; redeem a code when one is provided\n * 5. API token — mint a long-lived ss_ token for later sessions\n * 6. Airdrop — request testnet tokens when holdings are empty,\n * then poll until the PRIVATE records land\n *\n * Usage:\n * shield-swap setup --new # brand-new account\n * shield-swap setup --network mainnet --private-key-file <path> # mainnet\n * shield-swap setup --private-key-file <path> # returning user (key in a file)\n * shield-swap setup --invite-code CODE # when access is locked\n * shield-swap setup --api-url <origin> # pin a DEX API deployment\n *\n * A private key is NEVER pasted into a conversation or command history: a\n * returning user either writes it to a file and passes the path, or exports\n * SHIELD_SWAP_PRIVATE_KEY (or SHIELD_SWAP_PRIVATE_KEY_FILE) in their own\n * shell. Other environment fallbacks: SHIELD_SWAP_INVITE_CODE,\n * SHIELD_SWAP_API_URL.\n *\n * Exit codes: 0 ready · 2 needs input from the user (message says what) ·\n * 3 airdrop still pending · 1 anything else.\n *\n * State lands in ./.shield-swap/<network>/state.json (private key —\n * gitignore it, treat it like a wallet file). Nothing is shared\n * between networks, including the blinded identity store, whose reservations\n * are only meaningful against the chain they were checked on.\n *\n * Mainnet moves real value, so it is never the default: pass\n * `--network mainnet` explicitly. The airdrop step is testnet-only and refuses\n * to run on mainnet rather than pretending a faucet exists.\n */\nimport { readFileSync } from 'node:fs'\nimport { help } from '../color.js'\nimport { ApiError, DEFAULT_API_URL } from '@provablehq/shield-swap-sdk'\nimport {\n loadState,\n saveState,\n ensureKeyMaterial,\n resolveNetwork,\n stateDir,\n NeedsConfigDecisionError,\n loadSession,\n formatAmount,\n pollUntil,\n} from '../session.js'\n\nconst USAGE = `shield-swap setup — bootstrap an account and get it funded\n\n --new generate a brand-new account\n --private-key-file <path> import an existing key, read from this file\n --invite-code <code> redeem an invite code when access is locked\n --api-url <origin> pin a DEX API deployment\n --network <testnet|mainnet> default testnet\n\nEvery step is check-then-act, so re-running resumes where a failed run stopped.\n\nA private key is NEVER pasted into a conversation or command history: write it\nto a file and pass --private-key-file, or export SHIELD_SWAP_PRIVATE_KEY in your\nown shell. Other environment fallbacks: SHIELD_SWAP_PRIVATE_KEY_FILE,\nSHIELD_SWAP_INVITE_CODE, SHIELD_SWAP_API_URL.\n\nExit codes: 0 ready · 2 needs input from the user · 3 airdrop still pending ·\n1 anything else.`\n\n/**\n * Reads a `--flag value` pair out of the arguments.\n *\n * `setup` keeps its own reader rather than using the shared `flags()`: every\n * option is an optional string with an environment-variable fallback, and none\n * of them gate a transaction, so the strict unknown-flag rejection that\n * protects the spending commands would only get in the way here.\n *\n * @param argv Arguments after the subcommand name.\n * @param flag The flag to look for, leading dashes included.\n * @returns The argument that follows the flag, or undefined when it is absent.\n */\nfunction argValue(argv: string[], flag: string): string | undefined {\n const i = argv.indexOf(flag)\n return i >= 0 ? argv[i + 1] : undefined\n}\n\n/**\n * Resolves the private key to import, when the caller is restoring an account.\n *\n * The key itself never travels through a conversation or the command line: it\n * is read from a file the user wrote, or from an env var the user exported in\n * their own shell.\n *\n * @param argv Arguments after the subcommand name.\n * @returns The key to import, or undefined when this is a fresh account.\n * @throws If the named key file exists but is empty.\n */\nfunction resolveImportKey(argv: string[]): string | undefined {\n const keyFile = argValue(argv, '--private-key-file') ?? process.env.SHIELD_SWAP_PRIVATE_KEY_FILE\n if (keyFile) {\n const key = readFileSync(keyFile, 'utf8').trim()\n if (!key) throw new Error(`private key file ${keyFile} is empty`)\n return key\n }\n return process.env.SHIELD_SWAP_PRIVATE_KEY\n}\n\n/**\n * Bootstraps the account, one idempotent step at a time.\n *\n * @param argv Arguments after the subcommand name.\n */\nasync function setup(argv: string[]): Promise<void> {\n const inviteCode = argValue(argv, '--invite-code') ?? process.env.SHIELD_SWAP_INVITE_CODE\n // Flag-only on purpose: SHIELD_SWAP_API_URL stays an ephemeral per-run\n // override (see loadSession); only an explicit --api-url pins the\n // deployment and resets deployment-scoped state.\n const network = resolveNetwork(argValue(argv, '--network'))\n const apiUrl = argValue(argv, '--api-url')?.replace(/\\/$/, '')\n const allowGenerate = argv.includes('--new')\n const importKey = resolveImportKey(argv)\n\n // ── 1 + 2: key material ─────────────────────────────────────────────\n let state = loadState(network)\n console.log(`network: ${network} · state: ${stateDir(network)}`)\n\n // Pin the DEX API deployment. The access grant, API token, and airdrop\n // job all live in one deployment's database — switching deployments\n // invalidates them, so clear them and let the later steps re-derive.\n // Account key material and Provable API credentials are NOT touched\n // (chain- and prover-scoped, not DEX-scoped).\n if (apiUrl && apiUrl !== (state.apiUrl ?? DEFAULT_API_URL)) {\n state.apiUrl = apiUrl\n state.dexApiToken = undefined\n state.accessRedeemed = undefined\n state.airdropJobId = undefined\n saveState(state)\n console.log(`✓ DEX API pinned to ${state.apiUrl} (deployment-scoped state reset)`)\n }\n try {\n state = await ensureKeyMaterial(state, { importKey, allowGenerate })\n } catch (err) {\n if (err instanceof NeedsConfigDecisionError) {\n console.error(\n '\\nNEEDS_CONFIG_DECISION: no shield-swap account is configured here. Ask the user ' +\n 'whether they already have one before creating anything. NEVER ask them to paste ' +\n 'a private key into the conversation:\\n' +\n ' - existing account → the user saves their key to a file themselves, then re-run\\n' +\n ' with --private-key-file <path> (or they export SHIELD_SWAP_PRIVATE_KEY in\\n' +\n ' - brand new → re-run with --new\\n',\n )\n process.exit(2)\n }\n throw err\n }\n console.log(`✓ account: ${state.address}`)\n\n // Legacy Provable API credentials used to live in the state file. The\n // gateway needs none, so drop them rather than carry them forward.\n if ('provableApi' in state) {\n delete (state as { provableApi?: unknown }).provableApi\n saveState(state)\n console.log('✓ dropped legacy Provable API credentials from the state file (the gateway needs none)')\n }\n\n // ── 3: wire the client and authenticate with the DEX API ────────────\n // The network must be passed explicitly: loadSession defaults to testnet, so\n // omitting it would authenticate and redeem against testnet while writing\n // the results into the network-scoped state this script resolved.\n const { client, account } = await loadSession({ network })\n console.log('✓ DEX API session established (challenge/verify)')\n\n // ── 4: invite-code access gate ───────────────────────────────────────\n // Distributed invite codes are referral codes; /referral/redeem is the\n // single endpoint that unlocks an account.\n const status = await client.api.getReferralStatus()\n if (!status.has_access) {\n if (!inviteCode) {\n console.error(\n '\\nNEEDS_INVITE_CODE: this account has not redeemed an invite code, so ' +\n 'the DEX API is locked. Ask the user for their invite code, then re-run:\\n' +\n ' shield-swap setup --invite-code <code>\\n',\n )\n process.exit(2)\n }\n try {\n await client.api.redeemReferralCode(inviteCode)\n } catch (err) {\n if (!(err instanceof ApiError) || err.status !== 400) throw err\n console.error(\n `\\nINVALID_INVITE_CODE: the server rejected \"${inviteCode}\". ` +\n 'Ask the user for a valid, unused code and re-run.\\n',\n )\n process.exit(2)\n }\n state.accessRedeemed = true\n saveState(state)\n console.log('✓ code redeemed — access unlocked')\n } else {\n state.accessRedeemed = true\n saveState(state)\n console.log('✓ access already granted')\n }\n\n // ── 5: long-lived API token for later sessions ───────────────────────\n if (!state.dexApiToken) {\n const created = await client.api.createApiToken({ name: `ss-agent-${account.address.slice(5, 17)}` })\n state.dexApiToken = created.token\n saveState(state)\n console.log(`✓ minted DEX API token (${created.token_prefix}…, stored in state file)`)\n } else {\n console.log('✓ DEX API token already on file')\n }\n\n // ── 6: airdrop when the account holds nothing ────────────────────────\n // The faucet delivers PRIVATE records, so the check must scan the private\n // side; a fresh account's public balances stay zero even after funding.\n const funded = async () => {\n const balances = await client.getBalances()\n return Object.values(balances).some((b) => b.total > 0n)\n }\n if (await funded()) {\n console.log('✓ account already funded')\n } else if (network === 'mainnet') {\n // There is no mainnet faucet, and quietly skipping would leave the account\n // configured but unable to trade — a failure a user would only discover\n // when a swap could not select a record.\n throw new Error(\n `account ${account.address} holds no tokens on mainnet, and there is no faucet to draw from. ` +\n 'Fund it from an exchange or another wallet, then re-run this script to verify.',\n )\n } else {\n // Request the faucet at most once per account: the job id persists in\n // the state file, so a re-run resumes polling instead of double-drawing.\n if (!state.airdropJobId) {\n const job = await client.api.airdrop(account.address)\n state.airdropJobId = job.job_id\n saveState(state)\n console.log(`… airdrop started (job ${job.job_id})`)\n } else {\n console.log(`… resuming airdrop job ${state.airdropJobId}`)\n }\n\n // Two phases: the faucet job finishing (fast), then the record service\n // indexing the new private records (slower, asynchronous).\n let job: Awaited<ReturnType<typeof client.api.getAirdropStatus>> | null = null\n const jobDone = await pollUntil(async () => {\n job = await client.api.getAirdropStatus(state.airdropJobId!).catch(() => null)\n return job?.status === 'complete'\n }, 24, 5_000)\n if (!jobDone) {\n console.error(\n `\\nAIRDROP_PENDING: faucet job ${state.airdropJobId} has not completed yet ` +\n `(last status: ${job ? (job as { status?: string }).status : 'unknown'}). ` +\n 'Re-run `shield-swap setup` in a few minutes — it resumes this job, it does not double-request.\\n',\n )\n process.exit(3)\n }\n const rejected = (job!.results ?? []).filter((r: { status?: string }) => r.status !== 'accepted')\n if (rejected.length > 0) {\n // The job finished but some transfers failed — surface it and allow a\n // fresh request next run instead of resuming a dead job forever.\n state.airdropJobId = undefined\n saveState(state)\n console.error(\n `\\nAIRDROP_FAILED: faucet job finished with rejected transfers: ` +\n `${rejected.map((r: { symbol?: string; status?: string }) => `${r.symbol}:${r.status}`).join(', ')}. ` +\n 'Re-run `shield-swap setup` to request a fresh airdrop.\\n',\n )\n process.exit(3)\n }\n console.log('… faucet job complete — waiting for the records to become scannable')\n\n const landed = await pollUntil(funded, 36, 10_000)\n if (!landed) {\n console.error(\n '\\nAIRDROP_PENDING: the faucet finished but the records are not scannable ' +\n 'yet (the record service indexes asynchronously). Re-run `shield-swap setup` in a ' +\n 'few minutes — it resumes this job, it does not double-request.\\n',\n )\n process.exit(3)\n }\n console.log('✓ airdrop landed')\n }\n\n // ── report ────────────────────────────────────────────────────────────\n const balances = await client.getBalances()\n console.log(`\\nAccount ${account.address} is ready on ${network}:`)\n for (const entry of Object.values(balances)) {\n if (entry.total > 0n) {\n const priv = formatAmount(entry.private, entry.decimals, entry.symbol)\n const pub = formatAmount(entry.public, entry.decimals, entry.symbol)\n console.log(` ${entry.symbol}: ${priv} private, ${pub} public`)\n }\n }\n console.log(\n '\\nASK_NEXT_ACTION: setup is complete — ask the user what to do next with ONE ' +\n 'user-selectable prompt (the harness\\'s selection UI if it has one, a numbered ' +\n 'list otherwise) offering ALL SEVEN options below, in this order. Free-form ' +\n 'input stays available as the escape hatch (\"Other\"); map whatever the user ' +\n 'types onto the runbooks before improvising against the SDK. Do not pick for ' +\n 'them. Frame the setting first: Shield Swap is a private exchange on Aleo — ' +\n 'what is traded, and by whom, stays hidden on the public chain. ' +\n (network === 'mainnet'\n ? 'This account is on MAINNET: every trade below moves real funds, and there ' +\n 'is no faucet to recover from a mistake. Say so before the user picks.'\n : 'This account is on the test network, so trading uses test tokens.') +\n '\\n\\n' +\n '1. Develop on Shield Swap (developing.md). For a user building their own\\n' +\n ' dApp, trading bot, or server/agent integration rather than trading\\n' +\n ' here. If chosen, FIRST ask what they are building, then follow\\n' +\n ' developing.md — it picks the packages by where their keys live and\\n' +\n ' maps to the docs, examples, and integration caveats.\\n' +\n '2. Follow their own playbook. Ask whether they have instructions of\\n' +\n ' their own — a markdown strategy file, notes, or a memory store such\\n' +\n ' as an Obsidian vault. Their document decides WHAT to do; the runbooks\\n' +\n ' here describe HOW each step works.\\n' +\n '3. Swap tokens (swapping.md). Trade one token for another. It settles\\n' +\n ' in two steps — placing the trade, then collecting what was bought —\\n' +\n ' and both happen in one go. The natural first move for a trader.\\n' +\n '4. Several swaps at once (swapping.md, concurrency recipe). Place a\\n' +\n ' handful of trades in parallel and watch them all land — the busiest\\n' +\n ' way to exercise the exchange. First show the user which trades are\\n' +\n ' possible right now and ask how many (and which) they want; collect\\n' +\n ' each one as it lands.\\n' +\n '5. Open a liquidity position (liquidity.md). Instead of trading, become\\n' +\n ' the market: deposit a pair of tokens so other people can trade against\\n' +\n ' them. The user picks the price range their deposit works in, and while\\n' +\n ' the market price sits inside that range they earn a small cut of every\\n' +\n ' trade that passes through.\\n' +\n '6. Add or remove liquidity (liquidity.md). Top up a position, or take\\n' +\n ' some of it back out — whatever comes out becomes earnings to collect.\\n' +\n '7. Collect earnings (collecting.md). Sweep up everything the account is\\n' +\n ' owed — tokens bought in earlier swaps and the fees its liquidity\\n' +\n ' earned — into the wallet. Good to run after any trading session.\\n',\n )\n}\n\n\n/**\n * Runs the `setup` subcommand.\n *\n * Failures are reported as `SETUP_FAILED: <message>` with exit 1, which\n * startup.md documents as the signal to read the message and retry once\n * before digging — the step-specific exits (`NEEDS_CONFIG_DECISION`,\n * `NEEDS_INVITE_CODE`) leave from inside {@link setup} with their own codes.\n *\n * @param argv Arguments after the subcommand name, as the dispatcher supplies them.\n */\nexport async function main(argv: string[]): Promise<void> {\n // Checked before anything else: setup's first act is to read and migrate the\n // state file, so a --help that fell through would bootstrap the account it\n // was only asked to describe.\n if (argv.includes('--help') || argv.includes('-h')) {\n console.log(help(USAGE))\n return\n }\n try {\n await setup(argv)\n } catch (error) {\n console.error('\\nSETUP_FAILED:', error instanceof Error ? error.message : error)\n process.exit(1)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAyCA,SAAS,oBAAoB;AAE7B,SAAS,UAAU,uBAAuB;AAa1C,IAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8Bd,SAAS,SAAS,MAAgB,MAAkC;AAClE,QAAM,IAAI,KAAK,QAAQ,IAAI;AAC3B,SAAO,KAAK,IAAI,KAAK,IAAI,CAAC,IAAI;AAChC;AAaA,SAAS,iBAAiB,MAAoC;AAC5D,QAAM,UAAU,SAAS,MAAM,oBAAoB,KAAK,QAAQ,IAAI;AACpE,MAAI,SAAS;AACX,UAAM,MAAM,aAAa,SAAS,MAAM,EAAE,KAAK;AAC/C,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,oBAAoB,OAAO,WAAW;AAChE,WAAO;AAAA,EACT;AACA,SAAO,QAAQ,IAAI;AACrB;AAOA,eAAe,MAAM,MAA+B;AAClD,QAAM,aAAa,SAAS,MAAM,eAAe,KAAK,QAAQ,IAAI;AAIlE,QAAM,UAAU,eAAe,SAAS,MAAM,WAAW,CAAC;AAC1D,QAAM,SAAS,SAAS,MAAM,WAAW,GAAG,QAAQ,OAAO,EAAE;AAC7D,QAAM,gBAAgB,KAAK,SAAS,OAAO;AAC3C,QAAM,YAAY,iBAAiB,IAAI;AAGvC,MAAI,QAAQ,UAAU,OAAO;AAC7B,UAAQ,IAAI,YAAY,OAAO,kBAAe,SAAS,OAAO,CAAC,EAAE;AAOjE,MAAI,UAAU,YAAY,MAAM,UAAU,kBAAkB;AAC1D,UAAM,SAAS;AACf,UAAM,cAAc;AACpB,UAAM,iBAAiB;AACvB,UAAM,eAAe;AACrB,cAAU,KAAK;AACf,YAAQ,IAAI,4BAAuB,MAAM,MAAM,kCAAkC;AAAA,EACnF;AACA,MAAI;AACF,YAAQ,MAAM,kBAAkB,OAAO,EAAE,WAAW,cAAc,CAAC;AAAA,EACrE,SAAS,KAAK;AACZ,QAAI,eAAe,0BAA0B;AAC3C,cAAQ;AAAA,QACN;AAAA,MAMF;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM;AAAA,EACR;AACA,UAAQ,IAAI,mBAAc,MAAM,OAAO,EAAE;AAIzC,MAAI,iBAAiB,OAAO;AAC1B,WAAQ,MAAoC;AAC5C,cAAU,KAAK;AACf,YAAQ,IAAI,6FAAwF;AAAA,EACtG;AAMA,QAAM,EAAE,QAAQ,QAAQ,IAAI,MAAM,YAAY,EAAE,QAAQ,CAAC;AACzD,UAAQ,IAAI,uDAAkD;AAK9D,QAAM,SAAS,MAAM,OAAO,IAAI,kBAAkB;AAClD,MAAI,CAAC,OAAO,YAAY;AACtB,QAAI,CAAC,YAAY;AACf,cAAQ;AAAA,QACN;AAAA,MAGF;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,QAAI;AACF,YAAM,OAAO,IAAI,mBAAmB,UAAU;AAAA,IAChD,SAAS,KAAK;AACZ,UAAI,EAAE,eAAe,aAAa,IAAI,WAAW,IAAK,OAAM;AAC5D,cAAQ;AAAA,QACN;AAAA,4CAA+C,UAAU;AAAA;AAAA,MAE3D;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,iBAAiB;AACvB,cAAU,KAAK;AACf,YAAQ,IAAI,6CAAmC;AAAA,EACjD,OAAO;AACL,UAAM,iBAAiB;AACvB,cAAU,KAAK;AACf,YAAQ,IAAI,+BAA0B;AAAA,EACxC;AAGA,MAAI,CAAC,MAAM,aAAa;AACtB,UAAM,UAAU,MAAM,OAAO,IAAI,eAAe,EAAE,MAAM,YAAY,QAAQ,QAAQ,MAAM,GAAG,EAAE,CAAC,GAAG,CAAC;AACpG,UAAM,cAAc,QAAQ;AAC5B,cAAU,KAAK;AACf,YAAQ,IAAI,gCAA2B,QAAQ,YAAY,+BAA0B;AAAA,EACvF,OAAO;AACL,YAAQ,IAAI,sCAAiC;AAAA,EAC/C;AAKA,QAAM,SAAS,YAAY;AACzB,UAAMA,YAAW,MAAM,OAAO,YAAY;AAC1C,WAAO,OAAO,OAAOA,SAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE;AAAA,EACzD;AACA,MAAI,MAAM,OAAO,GAAG;AAClB,YAAQ,IAAI,+BAA0B;AAAA,EACxC,WAAW,YAAY,WAAW;AAIhC,UAAM,IAAI;AAAA,MACR,WAAW,QAAQ,OAAO;AAAA,IAE5B;AAAA,EACF,OAAO;AAGL,QAAI,CAAC,MAAM,cAAc;AACvB,YAAMC,OAAM,MAAM,OAAO,IAAI,QAAQ,QAAQ,OAAO;AACpD,YAAM,eAAeA,KAAI;AACzB,gBAAU,KAAK;AACf,cAAQ,IAAI,+BAA0BA,KAAI,MAAM,GAAG;AAAA,IACrD,OAAO;AACL,cAAQ,IAAI,+BAA0B,MAAM,YAAY,EAAE;AAAA,IAC5D;AAIA,QAAI,MAAsE;AAC1E,UAAM,UAAU,MAAM,UAAU,YAAY;AAC1C,YAAM,MAAM,OAAO,IAAI,iBAAiB,MAAM,YAAa,EAAE,MAAM,MAAM,IAAI;AAC7E,aAAO,KAAK,WAAW;AAAA,IACzB,GAAG,IAAI,GAAK;AACZ,QAAI,CAAC,SAAS;AACZ,cAAQ;AAAA,QACN;AAAA,8BAAiC,MAAM,YAAY,wCAChC,MAAO,IAA4B,SAAS,SAAS;AAAA;AAAA,MAE1E;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,YAAY,IAAK,WAAW,CAAC,GAAG,OAAO,CAAC,MAA2B,EAAE,WAAW,UAAU;AAChG,QAAI,SAAS,SAAS,GAAG;AAGvB,YAAM,eAAe;AACrB,gBAAU,KAAK;AACf,cAAQ;AAAA,QACN;AAAA,+DACK,SAAS,IAAI,CAAC,MAA4C,GAAG,EAAE,MAAM,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA,MAEtG;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,YAAQ,IAAI,+EAAqE;AAEjF,UAAM,SAAS,MAAM,UAAU,QAAQ,IAAI,GAAM;AACjD,QAAI,CAAC,QAAQ;AACX,cAAQ;AAAA,QACN;AAAA,MAGF;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,YAAQ,IAAI,uBAAkB;AAAA,EAChC;AAGA,QAAM,WAAW,MAAM,OAAO,YAAY;AAC1C,UAAQ,IAAI;AAAA,UAAa,QAAQ,OAAO,gBAAgB,OAAO,GAAG;AAClE,aAAW,SAAS,OAAO,OAAO,QAAQ,GAAG;AAC3C,QAAI,MAAM,QAAQ,IAAI;AACpB,YAAM,OAAO,aAAa,MAAM,SAAS,MAAM,UAAU,MAAM,MAAM;AACrE,YAAM,MAAM,aAAa,MAAM,QAAQ,MAAM,UAAU,MAAM,MAAM;AACnE,cAAQ,IAAI,KAAK,MAAM,MAAM,KAAK,IAAI,aAAa,GAAG,SAAS;AAAA,IACjE;AAAA,EACF;AACA,UAAQ;AAAA,IACN;AAAA,mhBAOG,YAAY,YACT,oJAEA,uEACJ;AAAA,EA4BJ;AACF;AAaA,eAAsB,KAAK,MAA+B;AAIxD,MAAI,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,GAAG;AAClD,YAAQ,IAAI,KAAK,KAAK,CAAC;AACvB;AAAA,EACF;AACA,MAAI;AACF,UAAM,MAAM,IAAI;AAAA,EAClB,SAAS,OAAO;AACd,YAAQ,MAAM,mBAAmB,iBAAiB,QAAQ,MAAM,UAAU,KAAK;AAC/E,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;","names":["balances","job"]}
@@ -13,7 +13,7 @@ import "./chunk-IHYFMX5A.js";
13
13
  import {
14
14
  formatAmount,
15
15
  loadSession
16
- } from "./chunk-2OT6LZPW.js";
16
+ } from "./chunk-44Q5ILLQ.js";
17
17
 
18
18
  // src/commands/swap.ts
19
19
  import { SwapOutputNotFinalizedError, parseUnits } from "@provablehq/shield-swap-sdk";
@@ -140,4 +140,4 @@ ${formatAmount(data.sold, plan.from.decimals, plan.from.symbol)} sold.`);
140
140
  export {
141
141
  main
142
142
  };
143
- //# sourceMappingURL=swap-W72XGG7Y.js.map
143
+ //# sourceMappingURL=swap-YDGSUXXR.js.map
@@ -13,7 +13,7 @@ import "./chunk-IHYFMX5A.js";
13
13
  import {
14
14
  formatAmount,
15
15
  loadSession
16
- } from "./chunk-2OT6LZPW.js";
16
+ } from "./chunk-44Q5ILLQ.js";
17
17
 
18
18
  // src/commands/swap-concurrent.ts
19
19
  import { SwapOutputNotFinalizedError, parseUnits } from "@provablehq/shield-swap-sdk";
@@ -166,4 +166,4 @@ ${landed}/${data.results.length} swaps landed.`);
166
166
  export {
167
167
  main
168
168
  };
169
- //# sourceMappingURL=swap-concurrent-IHGWJMST.js.map
169
+ //# sourceMappingURL=swap-concurrent-ZNCLLVJ5.js.map
@@ -16,7 +16,7 @@ import {
16
16
  import {
17
17
  formatAmount,
18
18
  loadSession
19
- } from "./chunk-2OT6LZPW.js";
19
+ } from "./chunk-44Q5ILLQ.js";
20
20
 
21
21
  // src/commands/swap-history.ts
22
22
  import {
@@ -368,4 +368,4 @@ export {
368
368
  discoverIdentities,
369
369
  main
370
370
  };
371
- //# sourceMappingURL=swap-history-43E4JZUO.js.map
371
+ //# sourceMappingURL=swap-history-HGN6QX42.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@provablehq/shield-swap-cli",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Command line trader for the Shield Swap AMM DEX on Aleo.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,8 +29,8 @@
29
29
  "access": "public"
30
30
  },
31
31
  "dependencies": {
32
- "@provablehq/shield-swap-sdk": "^0.10.0",
33
- "@provablehq/veil-aleo-sdk": "^0.10.0"
32
+ "@provablehq/shield-swap-sdk": "^0.11.0",
33
+ "@provablehq/veil-aleo-sdk": "^0.11.0"
34
34
  },
35
35
  "scripts": {
36
36
  "build": "tsup",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/session.ts"],"sourcesContent":["/**\n * Shared session plumbing for the `shield-swap` command.\n *\n * Owns the state file (`./.shield-swap/<network>/state.json` by default) and\n * the client wiring, so every command starts from `loadSession()` and gets a\n * fully authenticated client plus persistent storage for the one thing that\n * must survive a crash and cannot be rediscovered: the private key, plus the\n * DEX grants tied to it.\n *\n * Exported as `@provablehq/shield-swap-cli/session` so a script driving the SDK\n * directly can share the same state file the command line writes.\n *\n * Nothing else is stored. Swap handles belong to the SDK's blinded identity\n * store, and positions are discovered from records with\n * `client.getOwnedPositions()` — a local list of either could only ever be a\n * stale copy of what the chain already knows.\n *\n * Everything is scoped by network. Nothing is shared between testnet and\n * mainnet: not the key, not the API grant, and above all not the identity\n * store, whose reservations are only meaningful against one chain.\n *\n * The state file holds a private key and API credentials — keep it out of\n * version control (`.shield-swap/` belongs in .gitignore) and treat it like\n * a wallet file.\n */\nimport { mkdirSync, readFileSync, writeFileSync, existsSync, chmodSync, renameSync } from 'node:fs'\nimport { join } from 'node:path'\nimport {\n loadNetwork,\n generateAccount,\n} from '@provablehq/veil-aleo-sdk'\nimport { fileCredentialStore } from '@provablehq/veil-aleo-sdk/node'\nimport { shieldSwapActions, getPrivateBalances, parseUnits, DEFAULT_PROGRAM } from '@provablehq/shield-swap-sdk'\nimport { fileBlindedIdentityStore } from '@provablehq/shield-swap-sdk/node'\n\n/** The networks these scripts run against. */\nexport type Network = 'testnet' | 'mainnet'\n\n/**\n * Resolves the network from an explicit choice, the environment, or the default.\n *\n * Testnet is the default and mainnet is never reached by omission: a script has\n * to be told, because everything downstream — the DEX API host, the prover, the\n * scanner, the token registry, and the identity store — is per-network, and the\n * mainnet ones move real value.\n *\n * @param explicit A `--network` value, when a script parsed one.\n * @throws When the value is neither network, rather than silently using testnet.\n */\nexport function resolveNetwork(explicit?: string): Network {\n const value = explicit ?? process.env.SHIELD_SWAP_NETWORK ?? 'testnet'\n if (value !== 'testnet' && value !== 'mainnet') {\n throw new Error(`Unknown network \"${value}\" — use testnet or mainnet.`)\n }\n return value\n}\n\nexport const NETWORK_URL = 'https://api.provable.com/v2'\n\n/** Everything that must survive between agent sessions. */\nexport type ShieldSwapState = {\n network: string\n /**\n * DEX API origin this session targets. Unset means the SDK's default\n * hosted deployment. Set by `shield-swap setup` (`--api-url` / SHIELD_SWAP_API_URL);\n * the access grant, API token, and airdrop job are scoped to one\n * deployment, so setup clears them when this changes.\n */\n apiUrl?: string\n privateKey?: string\n address?: string\n dexApiToken?: string\n accessRedeemed?: boolean\n /** Faucet job already requested for this account — prevents double-drawing on re-runs. */\n airdropJobId?: string\n}\n\nconst STATE_ROOT = process.env.SHIELD_SWAP_STATE_DIR ?? join(process.cwd(), '.shield-swap')\n\n/** Per-network state directory. Nothing is shared between networks. */\nexport function stateDir(network: Network): string {\n return join(STATE_ROOT, network)\n}\n\n/**\n * Where the blinded identity store lives for a network.\n *\n * Scoped by network because a reservation is only meaningful against the chain\n * it was checked on: counters reserved against testnet's\n * `used_blinded_addresses` say nothing about mainnet's, and one shared file\n * would hand out identities the other chain has already consumed.\n */\nexport function blindedStorePath(network: Network): string {\n return join(stateDir(network), 'blinded.json')\n}\n\n/**\n * Where Provable API credentials live for a network.\n *\n * Separate from the state file because the SDK owns the format: `shield-swap setup`\n * hands `fileCredentialStore` this path and the client reads and writes it\n * directly, including registering a consumer when the file is absent.\n */\nexport function credentialsPath(network: Network): string {\n return join(stateDir(network), 'provable-credentials.json')\n}\n\nfunction statePath(network: Network): string {\n return join(stateDir(network), 'state.json')\n}\n\n/** The pre-network layout, still read for testnet so existing keys survive. */\nconst LEGACY_STATE_PATH = join(STATE_ROOT, 'state.json')\n\n/**\n * Reads a network's state file, or returns a fresh empty state.\n *\n * Falls back to the pre-network layout for testnet only, so an existing\n * `.shield-swap/state.json` keeps working; the next save writes it to the\n * network-scoped path.\n */\nexport function loadState(network: Network): ShieldSwapState {\n const path = existsSync(statePath(network))\n ? statePath(network)\n : network === 'testnet' && existsSync(LEGACY_STATE_PATH)\n ? LEGACY_STATE_PATH\n : undefined\n if (!path) return { network }\n const parsed = JSON.parse(readFileSync(path, 'utf8')) as ShieldSwapState\n // A state file that names a different network is a wrong-chain hazard: its\n // key is fine but its access grant, API token, and airdrop job are not.\n parsed.network = network\n return parsed\n}\n\n/**\n * Writes the state file atomically (temp file + rename, 0600 — it holds the\n * private key). A crash mid-write can never truncate the only copy of the\n * key and the open swap handles.\n */\nexport function saveState(state: ShieldSwapState): void {\n const network = resolveNetwork(state.network)\n mkdirSync(stateDir(network), { recursive: true })\n const target = statePath(network)\n const tmp = `${target}.tmp`\n writeFileSync(tmp, JSON.stringify(state, null, 2))\n chmodSync(tmp, 0o600)\n renameSync(tmp, target)\n}\n\n\n/**\n * Renders a raw base-unit amount in human units (\"0.0534 ETH\"), the ONLY\n * format that should ever reach the user. Raw units (wei-style integers)\n * are SDK-facing; showing them to a person misstates their balances by\n * orders of magnitude.\n */\nexport function formatAmount(amount: bigint, decimals: number, symbol?: string): string {\n const scale = 10n ** BigInt(decimals)\n const whole = amount / scale\n const frac = amount % scale\n let s = whole.toLocaleString('en-US')\n if (frac > 0n) {\n // Full precision minus trailing zeros — tiny testnet amounts live many\n // places below the decimal point and must not round away to nothing.\n const fracStr = frac.toString().padStart(decimals, '0').replace(/0+$/, '')\n if (fracStr) s += `.${fracStr}`\n }\n return symbol ? `${s} ${symbol}` : s\n}\n\n/** What {@link namedAmounts} needs of a pool's token to place an amount. */\nexport type AmountToken = { id: string; symbol: string; decimals: number }\n\n/**\n * Places caller-named amounts into a pool's own token order.\n *\n * A pool orders its tokens by id, not by anything a caller types, so `--amount0`\n * is unknowable without reading the pool first: naming a pair `USDCx:ETH` does\n * not make USDCx side 0. `--amount USDCx:0.5` names the token instead and is\n * matched here, while `--amount0`/`--amount1` stay available for callers who know\n * the order. Parsing is the inverse of {@link formatAmount}: human decimals in,\n * raw base units out. Pure and local.\n *\n * @param params.entries `--amount` values, each `<symbol|id>:<decimal>`.\n * @param params.indexed The raw `--amount0` and `--amount1` strings, in that\n * order, `undefined` where the flag was absent.\n * @param params.tokens The pool's tokens in ITS order — `[token0, token1]`.\n * @returns Raw base units per side, `undefined` where nothing named that side.\n * @throws When an entry is malformed, names a token outside the pair, or names a\n * side twice — including once by symbol and once by index, where preferring\n * either would commit an amount the caller did not ask for.\n *\n * @example\n * const { amount0, amount1 } = namedAmounts({\n * entries: ['USDCx:0.5'],\n * indexed: [undefined, undefined],\n * tokens: [token0, token1],\n * })\n */\nexport function namedAmounts(params: {\n entries: string[]\n indexed: readonly [string | undefined, string | undefined]\n tokens: readonly [AmountToken, AmountToken]\n}): { amount0: bigint | undefined; amount1: bigint | undefined } {\n const [token0, token1] = params.tokens\n const amounts: Array<bigint | undefined> = [\n params.indexed[0] ? parseUnits(params.indexed[0], token0.decimals) : undefined,\n params.indexed[1] ? parseUnits(params.indexed[1], token1.decimals) : undefined,\n ]\n // Tracked alongside so a collision can name both flags rather than just the token.\n const namedBy = [params.indexed[0] ? '--amount0' : undefined, params.indexed[1] ? '--amount1' : undefined]\n\n for (const entry of params.entries) {\n const parts = entry.split(':')\n if (parts.length !== 2 || !parts[0] || !parts[1]) {\n throw new Error(`--amount takes <symbol>:<amount>, e.g. --amount ${token0.symbol}:0.5 — got \"${entry}\"`)\n }\n const [name, value] = parts as [string, string]\n const wanted = name.trim()\n const side = [token0, token1].findIndex(\n (token) => token.symbol.toLowerCase() === wanted.toLowerCase() || token.id === wanted,\n )\n if (side === -1) {\n throw new Error(`\"${wanted}\" is not in this pool's pair — it holds ${token0.symbol} and ${token1.symbol}.`)\n }\n const token = side === 0 ? token0 : token1\n if (amounts[side] !== undefined) {\n throw new Error(`${token.symbol} is named twice, by ${namedBy[side]} and --amount ${entry}.`)\n }\n amounts[side] = parseUnits(value.trim(), token.decimals)\n namedBy[side] = `--amount ${entry}`\n }\n return { amount0: amounts[0], amount1: amounts[1] }\n}\n\n/**\n * Builds the fully wired, authenticated session from the state file.\n *\n * Requires `shield-swap setup` to have run (key material in the state file).\n * Authenticates with the DEX API on every call — the session JWT covers\n * everything including access/token management, and auto-renews on expiry.\n *\n * Provable API credentials are not required up front: the client registers a\n * consumer through the credential file on first prove or scan when it holds\n * none — though `shield-swap setup` registers and verifies eagerly, so a session built\n * after setup has working credentials rather than untested ones.\n */\nexport async function loadSession(options: { network?: string } = {}) {\n const network = resolveNetwork(options.network)\n const state = loadState(network)\n if (!state.privateKey) {\n throw new Error(\n `No shield-swap session found for ${network} — run \\`shield-swap setup --network ${network}\\` first (see startup.md).`,\n )\n }\n\n const aleo = await loadNetwork(network)\n // Credentials reach both the prover and the scanner through one session the\n // client builds from the store, so a single JWT serves both.\n // No prover or scanner URL: both default to the Provable API and take the\n // network from the client, so naming them here would only risk drift.\n const scanner = aleo.createRemoteScanner()\n const { walletClient, account } = aleo.createAleoClient({\n privateKey: state.privateKey,\n networkUrl: NETWORK_URL,\n provingMode: 'delegated',\n credentialStore: fileCredentialStore(credentialsPath(network)),\n // Faucet-funded accounts hold no public credits; the delegated prover\n // pays fees from its FeeMaster account. Opt out with\n // SHIELD_SWAP_FEE_MASTER=0 when the account funds its own fees.\n useFeeMaster: process.env.SHIELD_SWAP_FEE_MASTER !== '0',\n records: scanner,\n })\n // SHIELD_SWAP_API_URL overrides for one-off runs; the persistent choice\n // lives in the state file (`shield-swap setup --api-url`).\n const apiUrl = process.env.SHIELD_SWAP_API_URL ?? state.apiUrl\n // The identity store is what makes concurrent swaps safe and unclaimed swaps\n // recoverable, and it is scoped by network because a reservation is only\n // meaningful against the chain it was checked on. Every swap through this\n // client reserves and records automatically.\n const blindedIdentities = fileBlindedIdentityStore(blindedStorePath(network))\n const client = walletClient.extend(\n shieldSwapActions({ api: { baseUrl: apiUrl }, blindedIdentities }),\n )\n try {\n await client.authenticateShieldSwap()\n } catch (error) {\n // A pinned host is invisible state: it lives in a file nobody re-reads, so\n // when the deployment behind it is retired every call fails with a bare 404\n // and nothing points at the pin. Name it, and say how to drop it.\n if (!apiUrl) throw error\n const source =\n process.env.SHIELD_SWAP_API_URL === apiUrl ? 'SHIELD_SWAP_API_URL' : `apiUrl in ${statePath(network)}`\n throw new Error(\n `could not authenticate with the DEX API at ${apiUrl}, which is pinned by ${source} rather than ` +\n `derived from the network. If that deployment is gone, re-pin with \\`shield-swap setup --api-url ` +\n `<origin>\\` or clear the field to fall back to the default for ${network}.`,\n { cause: error },\n )\n }\n\n return { client, account, scanner, state, aleo, network, blindedIdentities }\n}\n\n\n\n/** Polls a predicate until it returns true or attempts run out. */\nexport async function pollUntil(fn: () => Promise<boolean>, attempts: number, intervalMs: number): Promise<boolean> {\n for (let i = 0; i < attempts; i++) {\n if (await fn()) return true\n await new Promise((r) => setTimeout(r, intervalMs))\n }\n return false\n}\n\n/**\n * Resolves key material and stores it. Priority: existing state → imported\n * key (`importKey`) → fresh generation, but only when `allowGenerate` is\n * true. Returning users keep their account; a fresh key is never created\n * silently.\n */\nexport async function ensureKeyMaterial(\n state: ShieldSwapState,\n options: { importKey?: string; allowGenerate?: boolean } = {},\n): Promise<ShieldSwapState> {\n const network = resolveNetwork(state.network)\n await loadNetwork(network) // initializes the WASM the account helpers use\n if (state.privateKey && options.importKey && options.importKey !== state.privateKey) {\n throw new Error(\n `a DIFFERENT account is already configured here (${state.address ?? 'address unknown'}). ` +\n 'Refusing to switch silently — its funds and access live on that key. To use the imported ' +\n `key instead, move or delete the state directory first, then re-run with --private-key-file.`,\n )\n }\n if (!state.privateKey) {\n if (options.importKey) {\n state.privateKey = options.importKey\n } else if (options.allowGenerate) {\n state.privateKey = generateAccount().privateKey\n } else {\n throw new NeedsConfigDecisionError()\n }\n }\n // Derive the address from the key so imported/seeded states are complete.\n const aleo = await loadNetwork(network)\n state.address = aleo.privateKeyToAccount(state.privateKey).address\n saveState(state)\n return state\n}\n\n/** Signals that setup must ask the user about existing config before creating anything. */\nexport class NeedsConfigDecisionError extends Error {\n constructor() {\n super('no key material found and none provided')\n this.name = 'NeedsConfigDecisionError'\n }\n}\n\n\n"],"mappings":"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","names":["token"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/setup.ts"],"sourcesContent":["/**\n * Shield Swap account bootstrap — the startup gauntlet, idempotent.\n *\n * Run it as many times as needed; every step is check-then-act, so a failed\n * or interrupted run resumes where it stopped:\n *\n * 1. Key material — reuse the stored account, import the user's\n * existing key, or (only with --new) generate one\n * 2. DEX authentication — challenge/verify session with the account\n * 3. Provable API — reuse/import credentials, else self-register a\n * consumer for proving + scanning\n * 4. Invite code — check access; redeem a code when one is provided\n * 5. API token — mint a long-lived ss_ token for later sessions\n * 6. Airdrop — request testnet tokens when holdings are empty,\n * then poll until the PRIVATE records land\n *\n * Usage:\n * shield-swap setup --new # brand-new account\n * shield-swap setup --network mainnet --private-key-file <path> # mainnet\n * shield-swap setup --private-key-file <path> # returning user (key in a file)\n * shield-swap setup --invite-code CODE # when access is locked\n * shield-swap setup --api-url <origin> # pin a DEX API deployment\n *\n * A private key is NEVER pasted into a conversation or command history: a\n * returning user either writes it to a file and passes the path, or exports\n * SHIELD_SWAP_PRIVATE_KEY (or SHIELD_SWAP_PRIVATE_KEY_FILE) in their own\n * shell. Other environment fallbacks: ALEO_CONSUMER_ID + ALEO_DPS_API_KEY,\n * SHIELD_SWAP_INVITE_CODE, SHIELD_SWAP_API_URL.\n *\n * Exit codes: 0 ready · 2 needs input from the user (message says what) ·\n * 3 airdrop still pending · 1 anything else.\n *\n * State lands in ./.shield-swap/<network>/state.json (private key +\n * credentials — gitignore it, treat it like a wallet file). Nothing is shared\n * between networks, including the blinded identity store, whose reservations\n * are only meaningful against the chain they were checked on.\n *\n * Mainnet moves real value, so it is never the default: pass\n * `--network mainnet` explicitly. The airdrop step is testnet-only and refuses\n * to run on mainnet rather than pretending a faucet exists.\n */\nimport { readFileSync } from 'node:fs'\nimport { help } from '../color.js'\nimport { ApiError, DEFAULT_API_URL } from '@provablehq/shield-swap-sdk'\nimport { fileCredentialStore } from '@provablehq/veil-aleo-sdk/node'\nimport {\n loadState,\n saveState,\n ensureKeyMaterial,\n credentialsPath,\n resolveNetwork,\n stateDir,\n NeedsConfigDecisionError,\n loadSession,\n formatAmount,\n pollUntil,\n} from '../session.js'\n\nconst USAGE = `shield-swap setup — bootstrap an account and get it funded\n\n --new generate a brand-new account\n --private-key-file <path> import an existing key, read from this file\n --consumer-id <id> Provable API consumer id (else self-registers)\n --api-key <key> Provable API key\n --invite-code <code> redeem an invite code when access is locked\n --api-url <origin> pin a DEX API deployment\n --network <testnet|mainnet> default testnet\n\nEvery step is check-then-act, so re-running resumes where a failed run stopped.\n\nA private key is NEVER pasted into a conversation or command history: write it\nto a file and pass --private-key-file, or export SHIELD_SWAP_PRIVATE_KEY in your\nown shell. Other environment fallbacks: SHIELD_SWAP_PRIVATE_KEY_FILE,\nALEO_CONSUMER_ID, ALEO_DPS_API_KEY, SHIELD_SWAP_INVITE_CODE, SHIELD_SWAP_API_URL.\n\nExit codes: 0 ready · 2 needs input from the user · 3 airdrop still pending ·\n1 anything else.`\n\n/**\n * Reads a `--flag value` pair out of the arguments.\n *\n * `setup` keeps its own reader rather than using the shared `flags()`: every\n * option is an optional string with an environment-variable fallback, and none\n * of them gate a transaction, so the strict unknown-flag rejection that\n * protects the spending commands would only get in the way here.\n *\n * @param argv Arguments after the subcommand name.\n * @param flag The flag to look for, leading dashes included.\n * @returns The argument that follows the flag, or undefined when it is absent.\n */\nfunction argValue(argv: string[], flag: string): string | undefined {\n const i = argv.indexOf(flag)\n return i >= 0 ? argv[i + 1] : undefined\n}\n\n/**\n * Resolves the private key to import, when the caller is restoring an account.\n *\n * The key itself never travels through a conversation or the command line: it\n * is read from a file the user wrote, or from an env var the user exported in\n * their own shell.\n *\n * @param argv Arguments after the subcommand name.\n * @returns The key to import, or undefined when this is a fresh account.\n * @throws If the named key file exists but is empty.\n */\nfunction resolveImportKey(argv: string[]): string | undefined {\n const keyFile = argValue(argv, '--private-key-file') ?? process.env.SHIELD_SWAP_PRIVATE_KEY_FILE\n if (keyFile) {\n const key = readFileSync(keyFile, 'utf8').trim()\n if (!key) throw new Error(`private key file ${keyFile} is empty`)\n return key\n }\n return process.env.SHIELD_SWAP_PRIVATE_KEY\n}\n\n/**\n * Bootstraps the account, one idempotent step at a time.\n *\n * @param argv Arguments after the subcommand name.\n */\nasync function setup(argv: string[]): Promise<void> {\n const inviteCode = argValue(argv, '--invite-code') ?? process.env.SHIELD_SWAP_INVITE_CODE\n const consumerId = argValue(argv, '--consumer-id') ?? process.env.ALEO_CONSUMER_ID\n const apiKey = argValue(argv, '--api-key') ?? process.env.ALEO_DPS_API_KEY\n // Flag-only on purpose: SHIELD_SWAP_API_URL stays an ephemeral per-run\n // override (see loadSession); only an explicit --api-url pins the\n // deployment and resets deployment-scoped state.\n const network = resolveNetwork(argValue(argv, '--network'))\n const apiUrl = argValue(argv, '--api-url')?.replace(/\\/$/, '')\n const credentialStore = fileCredentialStore(credentialsPath(network))\n const allowGenerate = argv.includes('--new')\n const importKey = resolveImportKey(argv)\n\n // ── 1 + 2: key material and Provable API credentials ────────────────\n let state = loadState(network)\n console.log(`network: ${network} · state: ${stateDir(network)}`)\n\n // Pin the DEX API deployment. The access grant, API token, and airdrop\n // job all live in one deployment's database — switching deployments\n // invalidates them, so clear them and let the later steps re-derive.\n // Account key material and Provable API credentials are NOT touched\n // (chain- and prover-scoped, not DEX-scoped).\n if (apiUrl && apiUrl !== (state.apiUrl ?? DEFAULT_API_URL)) {\n state.apiUrl = apiUrl\n state.dexApiToken = undefined\n state.accessRedeemed = undefined\n state.airdropJobId = undefined\n saveState(state)\n console.log(`✓ DEX API pinned to ${state.apiUrl} (deployment-scoped state reset)`)\n }\n try {\n state = await ensureKeyMaterial(state, { importKey, allowGenerate })\n } catch (err) {\n if (err instanceof NeedsConfigDecisionError) {\n console.error(\n '\\nNEEDS_CONFIG_DECISION: no shield-swap account is configured here. Ask the user ' +\n 'whether they already have one before creating anything. NEVER ask them to paste ' +\n 'a private key into the conversation:\\n' +\n ' - existing account → the user saves their key to a file themselves, then re-run\\n' +\n ' with --private-key-file <path> (or they export SHIELD_SWAP_PRIVATE_KEY in\\n' +\n ' their own shell). Add --consumer-id/--api-key if they have Provable API\\n' +\n ' credentials.\\n' +\n ' - brand new → re-run with --new\\n',\n )\n process.exit(2)\n }\n throw err\n }\n console.log(`✓ account: ${state.address}`)\n\n // Supplied credentials win over registering a new consumer, so a returning\n // user keeps theirs. Absent both, the client registers one below. Awaited\n // because ProvableCredentialStore permits async: this store happens to be\n // synchronous, but reading a promise as a value would silently skip the seed\n // and leave the write unobserved.\n if (consumerId && apiKey && !(await credentialStore.load())) {\n await credentialStore.save({ consumerId, apiKey })\n }\n\n // Credentials used to live in the state file. Move them rather than letting\n // the client register a replacement: an API key is issued once and cannot be\n // reissued, so a fresh consumer would abandon the old one.\n const legacy = (state as { provableApi?: { consumerId: string; apiKey: string } }).provableApi\n if (legacy && !(await credentialStore.load())) {\n await credentialStore.save(legacy)\n delete (state as { provableApi?: unknown }).provableApi\n saveState(state)\n console.log(`✓ moved Provable API credentials to ${credentialsPath(network)}`)\n }\n\n // ── 3: wire the client and authenticate with the DEX API ────────────\n // The network must be passed explicitly: loadSession defaults to testnet, so\n // omitting it would authenticate, register, and redeem against testnet while\n // writing the results into the network-scoped state this script resolved.\n const { client, account } = await loadSession({ network })\n console.log('✓ DEX API session established (challenge/verify)')\n\n // Front-loaded on purpose: registration would otherwise happen on the first\n // prove or scan, and a newly issued API key is only reportable here.\n const provable = await client.authenticateProvableApi()\n console.log(\n `✓ Provable API consumer: ${provable.credentials.consumerId}` +\n (provable.registered ? ` (registered, saved to ${credentialsPath(network)})` : ''),\n )\n\n // ── 4: invite-code access gate ───────────────────────────────────────\n // Distributed invite codes are referral codes; /referral/redeem is the\n // single endpoint that unlocks an account.\n const status = await client.api.getReferralStatus()\n if (!status.has_access) {\n if (!inviteCode) {\n console.error(\n '\\nNEEDS_INVITE_CODE: this account has not redeemed an invite code, so ' +\n 'the DEX API is locked. Ask the user for their invite code, then re-run:\\n' +\n ' shield-swap setup --invite-code <code>\\n',\n )\n process.exit(2)\n }\n try {\n await client.api.redeemReferralCode(inviteCode)\n } catch (err) {\n if (!(err instanceof ApiError) || err.status !== 400) throw err\n console.error(\n `\\nINVALID_INVITE_CODE: the server rejected \"${inviteCode}\". ` +\n 'Ask the user for a valid, unused code and re-run.\\n',\n )\n process.exit(2)\n }\n state.accessRedeemed = true\n saveState(state)\n console.log('✓ code redeemed — access unlocked')\n } else {\n state.accessRedeemed = true\n saveState(state)\n console.log('✓ access already granted')\n }\n\n // ── 5: long-lived API token for later sessions ───────────────────────\n if (!state.dexApiToken) {\n const created = await client.api.createApiToken({ name: `ss-agent-${account.address.slice(5, 17)}` })\n state.dexApiToken = created.token\n saveState(state)\n console.log(`✓ minted DEX API token (${created.token_prefix}…, stored in state file)`)\n } else {\n console.log('✓ DEX API token already on file')\n }\n\n // ── 6: airdrop when the account holds nothing ────────────────────────\n // The faucet delivers PRIVATE records, so the check must scan the private\n // side; a fresh account's public balances stay zero even after funding.\n const funded = async () => {\n const balances = await client.getBalances()\n return Object.values(balances).some((b) => b.total > 0n)\n }\n if (await funded()) {\n console.log('✓ account already funded')\n } else if (network === 'mainnet') {\n // There is no mainnet faucet, and quietly skipping would leave the account\n // configured but unable to trade — a failure a user would only discover\n // when a swap could not select a record.\n throw new Error(\n `account ${account.address} holds no tokens on mainnet, and there is no faucet to draw from. ` +\n 'Fund it from an exchange or another wallet, then re-run this script to verify.',\n )\n } else {\n // Request the faucet at most once per account: the job id persists in\n // the state file, so a re-run resumes polling instead of double-drawing.\n if (!state.airdropJobId) {\n const job = await client.api.airdrop(account.address)\n state.airdropJobId = job.job_id\n saveState(state)\n console.log(`… airdrop started (job ${job.job_id})`)\n } else {\n console.log(`… resuming airdrop job ${state.airdropJobId}`)\n }\n\n // Two phases: the faucet job finishing (fast), then the record service\n // indexing the new private records (slower, asynchronous).\n let job: Awaited<ReturnType<typeof client.api.getAirdropStatus>> | null = null\n const jobDone = await pollUntil(async () => {\n job = await client.api.getAirdropStatus(state.airdropJobId!).catch(() => null)\n return job?.status === 'complete'\n }, 24, 5_000)\n if (!jobDone) {\n console.error(\n `\\nAIRDROP_PENDING: faucet job ${state.airdropJobId} has not completed yet ` +\n `(last status: ${job ? (job as { status?: string }).status : 'unknown'}). ` +\n 'Re-run `shield-swap setup` in a few minutes — it resumes this job, it does not double-request.\\n',\n )\n process.exit(3)\n }\n const rejected = (job!.results ?? []).filter((r: { status?: string }) => r.status !== 'accepted')\n if (rejected.length > 0) {\n // The job finished but some transfers failed — surface it and allow a\n // fresh request next run instead of resuming a dead job forever.\n state.airdropJobId = undefined\n saveState(state)\n console.error(\n `\\nAIRDROP_FAILED: faucet job finished with rejected transfers: ` +\n `${rejected.map((r: { symbol?: string; status?: string }) => `${r.symbol}:${r.status}`).join(', ')}. ` +\n 'Re-run `shield-swap setup` to request a fresh airdrop.\\n',\n )\n process.exit(3)\n }\n console.log('… faucet job complete — waiting for the records to become scannable')\n\n const landed = await pollUntil(funded, 36, 10_000)\n if (!landed) {\n console.error(\n '\\nAIRDROP_PENDING: the faucet finished but the records are not scannable ' +\n 'yet (the record service indexes asynchronously). Re-run `shield-swap setup` in a ' +\n 'few minutes — it resumes this job, it does not double-request.\\n',\n )\n process.exit(3)\n }\n console.log('✓ airdrop landed')\n }\n\n // ── report ────────────────────────────────────────────────────────────\n const balances = await client.getBalances()\n console.log(`\\nAccount ${account.address} is ready on ${network}:`)\n for (const entry of Object.values(balances)) {\n if (entry.total > 0n) {\n const priv = formatAmount(entry.private, entry.decimals, entry.symbol)\n const pub = formatAmount(entry.public, entry.decimals, entry.symbol)\n console.log(` ${entry.symbol}: ${priv} private, ${pub} public`)\n }\n }\n console.log(\n '\\nASK_NEXT_ACTION: setup is complete — ask the user what to do next with ONE ' +\n 'user-selectable prompt (the harness\\'s selection UI if it has one, a numbered ' +\n 'list otherwise) offering ALL SEVEN options below, in this order. Free-form ' +\n 'input stays available as the escape hatch (\"Other\"); map whatever the user ' +\n 'types onto the runbooks before improvising against the SDK. Do not pick for ' +\n 'them. Frame the setting first: Shield Swap is a private exchange on Aleo — ' +\n 'what is traded, and by whom, stays hidden on the public chain. ' +\n (network === 'mainnet'\n ? 'This account is on MAINNET: every trade below moves real funds, and there ' +\n 'is no faucet to recover from a mistake. Say so before the user picks.'\n : 'This account is on the test network, so trading uses test tokens.') +\n '\\n\\n' +\n '1. Develop on Shield Swap (developing.md). For a user building their own\\n' +\n ' dApp, trading bot, or server/agent integration rather than trading\\n' +\n ' here. If chosen, FIRST ask what they are building, then follow\\n' +\n ' developing.md — it picks the packages by where their keys live and\\n' +\n ' maps to the docs, examples, and integration caveats.\\n' +\n '2. Follow their own playbook. Ask whether they have instructions of\\n' +\n ' their own — a markdown strategy file, notes, or a memory store such\\n' +\n ' as an Obsidian vault. Their document decides WHAT to do; the runbooks\\n' +\n ' here describe HOW each step works.\\n' +\n '3. Swap tokens (swapping.md). Trade one token for another. It settles\\n' +\n ' in two steps — placing the trade, then collecting what was bought —\\n' +\n ' and both happen in one go. The natural first move for a trader.\\n' +\n '4. Several swaps at once (swapping.md, concurrency recipe). Place a\\n' +\n ' handful of trades in parallel and watch them all land — the busiest\\n' +\n ' way to exercise the exchange. First show the user which trades are\\n' +\n ' possible right now and ask how many (and which) they want; collect\\n' +\n ' each one as it lands.\\n' +\n '5. Open a liquidity position (liquidity.md). Instead of trading, become\\n' +\n ' the market: deposit a pair of tokens so other people can trade against\\n' +\n ' them. The user picks the price range their deposit works in, and while\\n' +\n ' the market price sits inside that range they earn a small cut of every\\n' +\n ' trade that passes through.\\n' +\n '6. Add or remove liquidity (liquidity.md). Top up a position, or take\\n' +\n ' some of it back out — whatever comes out becomes earnings to collect.\\n' +\n '7. Collect earnings (collecting.md). Sweep up everything the account is\\n' +\n ' owed — tokens bought in earlier swaps and the fees its liquidity\\n' +\n ' earned — into the wallet. Good to run after any trading session.\\n',\n )\n}\n\n\n/**\n * Runs the `setup` subcommand.\n *\n * Failures are reported as `SETUP_FAILED: <message>` with exit 1, which\n * startup.md documents as the signal to read the message and retry once\n * before digging — the step-specific exits (`NEEDS_CONFIG_DECISION`,\n * `NEEDS_INVITE_CODE`) leave from inside {@link setup} with their own codes.\n *\n * @param argv Arguments after the subcommand name, as the dispatcher supplies them.\n */\nexport async function main(argv: string[]): Promise<void> {\n // Checked before anything else: setup's first act is to read and migrate the\n // state file, so a --help that fell through would bootstrap the account it\n // was only asked to describe.\n if (argv.includes('--help') || argv.includes('-h')) {\n console.log(help(USAGE))\n return\n }\n try {\n await setup(argv)\n } catch (error) {\n console.error('\\nSETUP_FAILED:', error instanceof Error ? error.message : error)\n process.exit(1)\n }\n}\n"],"mappings":"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","names":["balances","job"]}