fix(backend)!: derive OnRamper signed wallet addresses from caller principal#13167
Draft
AntonioVentilii wants to merge 2 commits into
Draft
fix(backend)!: derive OnRamper signed wallet addresses from caller principal#13167AntonioVentilii wants to merge 2 commits into
AntonioVentilii wants to merge 2 commits into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
sign_onramper_widget_urlwas an open signing oracle: it HMAC-signed thewallets/network_wallets/wallet_address_tagsparameters exactly as supplied by any authenticated caller, without checking the addresses belonged tomsg_caller(). An attacker could get the backend to sign their own address and phish a victim into funding it via a valid, OISY-branded OnRamper URL — the HMAC is OnRamper's sole URL-integrity check, so a valid signature reads as OISY authorization.This closes the oracle by deriving the caller's own receiving addresses server-side and signing only those. A caller can now only ever obtain a signature bound to their own wallet.
Spec:
docs/ai/spec-driven-development/specs/2026-06-22-fix-onramper-signing-oracle.md(#13164). Stacked on #13166 (the address encoders).Changes
async.sign_onramper_widget_urltakes no request; it derives the caller's BTC/ETH/ICP/SOL receiving addresses frommsg_caller()and signs them asnetworkWallets. Thecaller_is_not_anonymousguard and per-caller rate limiter are unchanged.signer/service.rs): ETH (secp256k1 schema1+ keccak/EIP-55) and SOL (Ed25519 schnorr + base58) reuse the samecanister_id = cfs_canister_idpattern as the existing BTC derivation; ICP is localprincipal2account. These are pubkey reads — no chain-fusion-signer call, noallow_signing/allowance flow, no signing fee. A chain is omitted if its derivation fails (ICP always succeeds), andAddressDerivationFailedis returned only if nothing derives.wallets/network_wallets/wallet_address_tagsfrom the request (type removed); added theAddressDerivationFailederror variant;backend.did+src/declarations/backend/regenerated vianpm run generate.buildOnramperLinkand the canister/api layer call the endpoint with the identity only;OnramperWidget.sveltedrops the address-store wiring; the now-deadmapOnramperNetworkWalletsutil andOnramper*Wallet*types are removed.docs/ai/PRODUCT.mdgains a Buy (OnRamper) section with the explicit negative guarantee.Tests
signer::servicecover the pubkey→address encoding against known vectors.tests/it/onramper.rs): anonymous rejection,SecretNotConfigured, rate limit, deterministic signing of the caller's own derived addresses, and a positive anti-oracle proof — two distinct callers get different signed content (a caller can only sign their own addresses).onramper.utils.spec.tsrewritten for the argument-less call; affected buy specs pass.cargo fmt/lint.rust.sh/lint.did.sh,npm run check(clean except a pre-existing unrelatedsol-instructions-system.utils.tserror not in this diff), scoped ESLint, and the affected vitest specs all pass. The heavy pocketIC integration suite runs in CI.Parity note: byte-for-byte parity between the backend-derived addresses and the wallet's own addresses must be confirmed on staging before the buy flow is un-gated — there is no signer wasm in the test harness to assert it automatically (by design — production never calls the signer).
BREAKING CHANGE:
sign_onramper_widget_urlno longer acceptswallets/network_wallets/wallet_address_tagsand takes no arguments; it derives and signs the caller's own addresses. Clients must stop sending wallet parameters (frontend binding regenerated in this PR).