feat(cli): add exchange-rates, crypto, discoveries, uma-providers, tokens, and internal-account update/export#705
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
|
@greptileai review |
Greptile SummaryThis PR rounds out the Grid CLI with six new command groups:
Confidence Score: 4/5Safe to merge with one fix: the All six command groups are well-structured and follow existing CLI conventions. The one gap is in cli/src/commands/exchange-rates.ts — the
|
| Filename | Overview |
|---|---|
| cli/src/client.ts | Introduces QueryParams type alias and extends buildUrl to handle string[] values as repeated query params. Logic is clean and correctly handles empty arrays (no-op) and undefined (skip). |
| cli/src/commands/exchange-rates.ts | Adds exchange-rates command with repeatable --destination-currency. The --sending-amount validation uses parseInt which silently truncates floats and accepts negatives — inconsistent with the strict /^\d+$/ + Number.isSafeInteger guard used in crypto.ts for the same class of input. |
| cli/src/commands/crypto.ts | Adds crypto estimate-fee subcommand with rigorous amount validation (regex + safe-integer check). Clean and consistent with the rest of the CLI. |
| cli/src/commands/tokens.ts | Adds tokens list/get/create/revoke commands. Imports the shared parseList utility, includes a confirmation prompt for revoke, and correctly notes the one-time clientSecret in the command description. |
| cli/src/commands/internal-accounts.ts | Adds internal-accounts update/export subcommands using the existing addSignedOptions/signedHeaders helpers. The --private-enabled boolean-string validation pattern is straightforward and correct. |
| cli/src/commands/uma-providers.ts | Adds paginated uma-providers command. --has-blocked-providers boolean flag correctly maps to `true |
| cli/src/commands/discoveries.ts | Minimal, correct discoveries command. No issues. |
| cli/src/index.ts | Wires up all six new command registrations. Straightforward additions, no issues. |
| cli/test/quick-wins.test.ts | 9 new boundary tests covering method, path, query params, body, and headers for all new commands, including validation-rejection cases. |
| cli/README.md | Documents all new commands with accurate examples and the signed-retry note for internal-accounts. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
CLI["grid CLI"] --> ER["exchange-rates\nGET /exchange-rates"]
CLI --> CR["crypto estimate-fee\nPOST /crypto/estimate-withdrawal-fee"]
CLI --> DI["discoveries\nGET /discoveries"]
CLI --> UP["uma-providers\nGET /uma-providers"]
CLI --> TK["tokens\nlist / get / create / revoke"]
CLI --> IA["internal-accounts\nupdate / export"]
ER -->|"buildUrl: string[] → repeated params"| API["Grid API"]
CR -->|"strict /^\\d+$/ + isSafeInteger"| API
DI --> API
UP --> API
TK -->|"parseList shared util"| API
IA -->|"addSignedOptions + signedHeaders\n(202 challenge flow)"| API
subgraph "Signed ops (202 challenge)"
IA
end
subgraph "Input validation"
CR
ER
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
CLI["grid CLI"] --> ER["exchange-rates\nGET /exchange-rates"]
CLI --> CR["crypto estimate-fee\nPOST /crypto/estimate-withdrawal-fee"]
CLI --> DI["discoveries\nGET /discoveries"]
CLI --> UP["uma-providers\nGET /uma-providers"]
CLI --> TK["tokens\nlist / get / create / revoke"]
CLI --> IA["internal-accounts\nupdate / export"]
ER -->|"buildUrl: string[] → repeated params"| API["Grid API"]
CR -->|"strict /^\\d+$/ + isSafeInteger"| API
DI --> API
UP --> API
TK -->|"parseList shared util"| API
IA -->|"addSignedOptions + signedHeaders\n(202 challenge flow)"| API
subgraph "Signed ops (202 challenge)"
IA
end
subgraph "Input validation"
CR
ER
end
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
cli/src/commands/exchange-rates.ts:47-53
**`parseInt` silently truncates non-integer inputs**
`parseInt("10.5", 10)` returns `10` and `parseInt("-50", 10)` returns `-50` — both are accepted without any error, even though the help text says "Sending amount in the smallest unit" (implying a positive integer). The result is that a user passing `--sending-amount 10.5` gets rate quotes for `10` instead of an error, and a negative amount is forwarded to the API. The `crypto estimate-fee` command in the same PR guards against exactly this with a `/^\d+$/` regex plus an `amount >= 1` check — the same approach should be used here for consistency and correctness.
Reviews (2): Last reviewed commit: "feat(cli): add exchange-rates, crypto, d..." | Re-trigger Greptile
2c855a7 to
bc1e0a6
Compare
fc569a6 to
da61871
Compare
Revision — addressed Greptile + Codex
|
|
@greptileai review |
| if (options.sendingAmount !== undefined) { | ||
| sendingAmount = parseInt(options.sendingAmount, 10); | ||
| if (Number.isNaN(sendingAmount)) { | ||
| output(formatError("--sending-amount must be a number")); | ||
| process.exitCode = 1; | ||
| return; | ||
| } |
There was a problem hiding this comment.
parseInt silently truncates non-integer inputs
parseInt("10.5", 10) returns 10 and parseInt("-50", 10) returns -50 — both are accepted without any error, even though the help text says "Sending amount in the smallest unit" (implying a positive integer). The result is that a user passing --sending-amount 10.5 gets rate quotes for 10 instead of an error, and a negative amount is forwarded to the API. The crypto estimate-fee command in the same PR guards against exactly this with a /^\d+$/ regex plus an amount >= 1 check — the same approach should be used here for consistency and correctness.
Prompt To Fix With AI
This is a comment left during a code review.
Path: cli/src/commands/exchange-rates.ts
Line: 47-53
Comment:
**`parseInt` silently truncates non-integer inputs**
`parseInt("10.5", 10)` returns `10` and `parseInt("-50", 10)` returns `-50` — both are accepted without any error, even though the help text says "Sending amount in the smallest unit" (implying a positive integer). The result is that a user passing `--sending-amount 10.5` gets rate quotes for `10` instead of an error, and a negative amount is forwarded to the API. The `crypto estimate-fee` command in the same PR guards against exactly this with a `/^\d+$/` regex plus an `amount >= 1` check — the same approach should be used here for consistency and correctness.
How can I resolve this? If you propose a fix, please make it concise.…kens, internal-account update/export Read/lookup commands (exchange-rates, crypto estimate-fee, discoveries, uma-providers), API token CRUD (tokens list/get/create/revoke), and the two signed internal-account operations (update, export) reusing the --wallet-signature/--request-id header support. Extends buildUrl to send array query params (exchange-rates --destination-currency). vitest boundary tests cover each.
da61871 to
b0aab72
Compare
bc1e0a6 to
cf31175
Compare

Summary
Rounds out the Grid CLI with the high-value "quick win" endpoints from the audit. Stacked on #704.
New commands
grid exchange-rates—GET /exchange-rates(--source-currency, repeatable--destination-currency,--sending-amount)grid crypto estimate-fee—POST /crypto/estimate-withdrawal-feegrid discoveries—GET /discoveries(receiving-institution lookup)grid uma-providers—GET /uma-providers(counterparty providers, paginated)grid tokens list|get|create|revoke— API token management (createreturns theclientSecretonce — noted in help/output)grid internal-accounts update|export— the two signed internal-account operations, reusing the--wallet-signature/--request-idheader support (they surface the202challenge like the other signed ops; the CLI does not compute the stamp, generate keys, or decrypt)Supporting change
buildUrlnow sends array query params as repeated keys (forexchange-rates --destination-currency).Test plan
cd cli && npm run build— clean compile.npm test— 9 new boundary tests (67 total with the rest of the stack), asserting each command's method/path/query/body/headers.Follow-up (noted, not in this PR)
customers updatecan hit a signed-retry (202) when changing email/phone for Embedded-Wallet customers; it doesn't yet accept--wallet-signature/--request-id. Worth wiring up in a follow-up (needs the signed helper positioned in the stack).