Repository navigation
feat(cli): name the wallets that could pay a BOLT11 invoice - #73
Conversation
tee8z
left a comment
There was a problem hiding this comment.
Early review of draft fe8bc0a against master 384111d. This is not an approval, because the PR is still a draft. The design is sound: one listing call, the same can_ask gate as the picker, local checks before any credential is read, and every early return tested. One finding needs a fix (P2, inline), plus three smaller ones.
P2: without --env, the candidate flags omit the environment, so the pasted command fails again. I reproduced this against a mock API. payments send --json --org ORG --invoice lntbs10n1qqq with VOLTAGE_API_KEY set lists every wallet in the organization, and returns "flags": "--wallet WALLET_ID --org ORG". Adding those flags (with --currency btc) exits 2 with Exactly one --env is required for this operation. That error's hint points to voltage environments list, which an API key cannot run. Each listed wallet carries a required environment_id, so when scope.envs is empty, add --env {environment_id} to that candidate's flags. Every integration test passes --env, so add a case without it.
Smaller:
- The invoice amount is parsed and reported, but it is not used to filter. A BTC balance is in msats, as
amount_msatsis, so a wallet whose available BTC is less than the invoice amount is still shortlisted, even though it cannot pay. Consider aninsufficient_balancereason for BTC balances. A USD balance cannot be compared without a quote, so it can stay as it is. If you keep the current rule, please say in the docs that the amount is not checked. Invoice::parsealso returnsNonefor a valid prefix with a malformed amount, such aslnbc1p1qqq. The hint then says that the invoice "does not start with a BOLT11 prefix", which is wrong for that input. Something like "is not a BOLT11 invoice the CLI can read" covers both cases.- The no-candidate hint lists every excluded wallet, so a large organization makes a very long
hint:line. Consider limiting it to a few wallets plus a count, because--jsonalready has the fullexcludedlist.
Validation on this head, in nix develop: cargo fmt --check, cargo clippy --locked --all-targets -- -D warnings, cargo machete --with-metadata, cargo test --locked (123 unit, 105 integration) and python3 scripts/check-coverage.py passed. CRAP: 578 measured functions, none at or above 20, highest wait_for_payment at 19.60, which this PR does not change. 154 functions were unmeasured. CI is green, except the changelog check, which was pending.
Without a picker, `payments send --invoice` without `--wallet` lists the wallets in scope once and names those that are active, on the invoice's network, and hold a usable currency with funds: the available balance plus the credit limit, as the API's hold check counts them. A BTC wallet's funds must also cover the invoice's amount. A USD wallet is marked `needs_quote` and comes with the `quotes create` command for the invoice's amount. The scope flags are ready to paste. When none qualifies, the hint says why for each wallet. `--json` reports the shortlist in `error.detail`. The list is a shortlist, not a guarantee: fees and line-of-credit rules are checked only when the payment is sent. Refs #34
fe8bc0a to
ed53d14
Compare
tee8z
left a comment
There was a problem hiding this comment.
Requesting changes on ed53d14. The new funds check is right. It mirrors backend Wallet::has_sufficient_balance (available - amount >= -limit, with the wallet's single limit), and I checked that against backend origin/master c4ca979. A BTC balance must now cover amount_msats. A USD candidate gets needs_quote and a quotes create --to usd command, which matches the receive and pay guidance from #61.
P2, still open from my review of fe8bc0a: without --env, the flags omit the environment. I reproduced it again on this head. With VOLTAGE_API_KEY and --org but no --env, payments send --json --invoice lntbs10n1qqq returns "flags": "--wallet WALLET_ID --org ORG". Pasting those flags exits 2 with Exactly one --env is required for this operation, and that error's hint names voltage environments list, which an API key cannot run. The new quote command has the same gap, because a quote is created under /organizations/{org}/environments/{env}/quotes. Both use scope_flags(scope). When scope.envs is empty, append --env {environment_id} from the listed wallet (a required field of Wallet) to both. Please also add an integration case without --env.
Still open, nonblocking: the "does not start with a BOLT11 prefix" text for a malformed amount, and the uncapped list of excluded wallets in the hint.
Validation on this head, in nix develop: cargo fmt --check, cargo clippy --locked --all-targets -- -D warnings, cargo machete --with-metadata, cargo test --locked (125 unit, 105 integration) and python3 scripts/check-coverage.py passed. CRAP: 582 measured functions, none at or above 20, highest wait_for_payment at 19.60; 154 functions were unmeasured. CI is green.
dc6b548 to
ed53d14
Compare
|
Addressed tee8z's review in #77 (
|
Stack
One stack, merged bottom up:
master)wallets list --all-orgs(base fix(cli): name each candidate's environment when --env is not given #77)Problem
Off a terminal (
--json,--no-input, a script),payments send --invoicewithout--walletonly reported the missing flag. An agent then had to list wallets in every scope and guess which one could pay the invoice (#34).Behavior
Without a picker, a BOLT11 send without
--walletlists the wallets in the current scope once, with the sameGET /organizations/{org}/walletscall the picker uses, and sorts them:activeis notfalseinactivenetworkpays on the invoice's networkwrong_network--currency, or BTC or USD without itwrong_currencyavailableplus the wallet'slimit, are positiveno_balanceinsufficient_balanceFunds count the credit limit. In backend
origin/master(c4ca979),availableistotal - (holds + pending payouts)and excludes the credit line (crates/voltage_eventing/src/wallet/entity.rs:245-284;LimitAllocatedonly callsupdate_limit,projection.rs:241). A payment's hold is allowed whileavailable - amount >= -limit(Wallet::has_sufficient_balance,entity.rs:99-123, called fromcrates/wallets/src/domain/wallet/handlers/wallet_command.rs:257). So a credit wallet withavailable0 or negative can still pay, and the filter usesavailable + limit. BTC amounts are in msats and USD amounts in cents (crates/voltage_util/src/amount.rs:462-466).A USD candidate pays through a quote, so its amount is not compared with the invoice. It has
needs_quote: trueand aquotecommand,voltage quotes create --credit-line LOC --network NET --amount N --unit sats --to usd <scope> --execute(msats when the amount is not whole sats). The hint tells you to create the quote and add--quote QUOTE_ID. When a wallet has both a BTC and a USD balance that qualify, BTC is preferred.The invoice prefix gives the network:
lnbcmainnet,lntbtestnet,lntbssignet (which includes the API'smutinynet), andlnbcrtregtest, for which the API has no wallets. The amount comes from the human-readable part.--wallet is required for payment creation(exit 2). Its hint gives--wallet IDplus the scope flags for each candidate, or explains why each wallet does not qualify.--jsonputs{invoice, candidates, excluded, basis}inerror.detail. Human output omits thedetails:block, because the hint already shows the same content.docs/concepts/safety-model.mdlists this as the second exception to "a description authenticates nothing", and says that--walletkeeps it offline.--wallet, or for on-chain sends.Out of scope:
wallets list --all-orgs, which is the next PR in this stack, and the JSON negative balance, which was closed by decision on #34.Refs #34
Checks
voltage-pr-reviewself-review againstmaster, with the Rust style checklist.insufficient_balance), candidates found,--currencyfiltering, credit-limit funds (available0 or negative within the limit, and a limit fully drawn), a USD candidate's quote command (whole sats, msats, no amount, noline_of_credit_id), and preferring BTC when both qualify. Unit tests cover the BOLT11 prefixes, the amount multipliers, and malformed invoices.nix develop:cargo fmt --check,cargo clippy --locked --all-targets -- -D warnings,cargo machete --with-metadata,cargo test --locked, andpython3 scripts/check-coverage.pyall pass.ff8b488: 0 violations. The highest score is 19.60 forwait_for_payment, unchanged by this PR.