Repository navigation
mobile: send and deploy Braavos accounts as the extension does - #796
Conversation
Main taught the extension to deploy funded Braavos counterfactuals (f20125d); the mobile core still treated every Braavos record as view only, so the accounts parity test failed on the new recovery hint and the apps could not act for a Braavos account at all. The core now follows braavos-compatibility.ts, braavos-deployment-gate.ts, deployment.ts and account-signer.ts: - A deployed account is read at one accepted block: its class must be a Braavos implementation this wallet signs for, this wallet's key the first Stark signer, and any 2FA signer's requested removal expired by the block's timestamp. Invokes carry a bare [r, s]. - An undeployed account deploys only through its own reviewed deployment (BraavosDeployFirst); the base class never deploys. - The modern deployment class deploys with the extended authorization [r, s, ...params, aux_r, aux_s], parameters signed first. Its estimate is signed for real over the query-version hash, since the constructor checks the authorization even when estimated. Krusty hashes version 3 only, so sign.rs composes that hash; a test pins it to Krusty's. The static view-only flag is gone from the core and both apps: every record passes the one signing gate and the plan decides on chain. Braavos keys are still not offered as Nostr multisig co-signers. scripts/mobile-transactions-braavos.ts captures the extension's own path (sends, legacy implementation, expired 2FA removal, deployments, and each refusal); transactions_braavos_parity.rs replays it and requires the same request bodies, signature arrays, signed-hash count and hashes.
Follow-ups from review: a get_signers length near usize::MAX now reads as malformed instead of overflowing; the query-hash composition test also compares a non-zero nonce against Krusty, since nonce and DA mode were both zero; the unreachable Braavos arm in deploy_probed is gone (submit_probed already refuses an undeployed Braavos send); and comments and verification notes no longer describe the removed view-only gate.
A base class, an unrecognised signing class, a wrong first key, an active 2FA signer, and a malformed get_signers list used to become a fee-failed review. Confirm is OutOfOrder while can_confirm is false, so the sentence never reached the user. The review step now fails with that code, after the same reads the extension throws on. A modern-class deployment still quotes, and Ready reviews are unchanged. The parity test requires every review-time refusal to be that failure. Co-authored-by: Ryan <Ryun1@users.noreply.github.com>
ensureAccountDeployed used the Ready refusal when the record has no deployment. A Braavos base class that reached that arm would have said the account was an Argent class this wallet does not deploy. Co-authored-by: Ryan <Ryun1@users.noreply.github.com>
Krusty only hashes version 3, so the query bit is composed locally. The existing test checks that composer at version 3. This one checks the estimate hash is that composer with the query bit set, and not the broadcast hash. Co-authored-by: Ryan <Ryun1@users.noreply.github.com>
A load-balanced node answers JSON-RPC 24, or "block not found", when it has not seen the accepted block the previous call pinned. The extension retries that whole decision three times. Argent and Braavos share the pin, so both do. A third miss still fails closed, and a contract-not-found does not retry. Co-authored-by: Ryan <Ryun1@users.noreply.github.com>
The flag is gone. The plan test, the accounts module note, and the account docs still described it, and the multisig comment still explained the exclusion as view-only. plan.rs stays under the 500-line cap (493), so it does not need a split. Co-authored-by: Ryan <Ryun1@users.noreply.github.com>
cargo test stops at the first failing target, so accounts_parity hid history_parity and history_parity hid privacy_parity. --no-fail-fast runs the rest. A failing binary still fails the job. Co-authored-by: Ryan <Ryun1@users.noreply.github.com>
Co-authored-by: Ryan <Ryun1@users.noreply.github.com>
Review follow-ups. sign_hash_for_account signs a host-supplied hash with no class or signer check, so it refuses Braavos records again: a Braavos signature is made only inside a send plan, after the account's live class and signers are read (the extension's requireLiveAuthorizableClass refuses the same states). The Braavos deployment estimate's signatures at review no longer renew the idle window (plan_sign takes renew; the confirmed re-estimate and the deployment still renew), so a review stays passive as reads are. block_at gets its own doc comment back from nonce.
PR SummaryHigh Risk Overview Undeployed Braavos no longer auto-deploys inside Send; review/submit return Android wires the new failure codes and always opens Send/Deploy; account catalog and generated assets include Braavos class hashes. Tests/fixtures add extension Braavos transaction vectors, shared Reviewed by Cursor Bugbot for commit e69a7a5. Bugbot is set up for automated code reviews on this repo. Configure here. |
Ports the extension's Braavos support (f20125d and the deploy-first gate) to the mobile core and apps, and fixes the
corejob'saccounts_parityfailure (the recovery hint for a funded modern-class Braavos counterfactual).What changes
get_signersmust list this wallet's key first; an active 2FA signer refuses unless its deferred removal expired by the block timestamp. Invokes sign[r, s].BraavosDeployFirst("Deploy this account first (Settings → Deploy account)."); the base class isBraavosNotDeployable.[r, s, ...11 params, aux_r, aux_s], params signed first. The estimate is signed for real over the query-version hash (the Braavos constructor checks it even when estimated) — the one place a review signs. Krusty only hashes v3, sosend/sign.rscomposes the query hash; a unit test pins it to Krusty at v3 and the fixture pins the query hash.AccountInfo.viewOnly,SendError.ViewOnlyAccount,sendRefusal, its copy). Braavos keys stay out of Nostr multisig co-signers. Private-balance reads now admit Braavos, as the extension and Ready already do.Parity
scripts/mobile-transactions-braavos.tsruns the extension's real path intoextension-transactions-braavos*.json(6 scenarios, 8 refusals);tests/transactions_braavos_parity.rsrequires identical request bodies, signature arrays, signed-hash count and transaction hashes. Docs:mobile/docs/braavos.md.Verification
cargo fmt/clippy -D warnings, Kotlin lint, TS types/lint,bun run test(3303, incl. fixture drift).history_parity(4, mobile lacksdirection/tokenAddresson activity entries),privacy_parity(tokens-65),check:files(accounts-parity-families.json> 500 lines), one@bramble/terminalswap-route test.