Repository navigation
fix(transfer): refuse token transfers on a network other than the logged-in one - #236
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
✅ Cyclops Security Review: safe to mergeLast reviewed: 69c2e5d (latest) · no open findings |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 92286c21dc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
3f58003 to
2e75506
Compare
…ged-in one The wallet app, which approves a transfer whenever no access key can sign it, approves only on the chain the wallet is logged in on. Like swap, a token transfer on another --network now returns E_USAGE with a 'tempo wallet login --network <network>' cta before any lookup or prompt; dry runs still review it.
…at send time An agent transfer on another network without a key there now gets the login cta instead of a refresh one: withWallet takes a refuse hook that runs between its login and key checks. The send also re-checks the provider's logged-in chain, so a login on another chain while the prompt is open cannot redirect it.
2e75506 to
69c2e5d
Compare
|
+1 |
There was a problem hiding this comment.
Approving on behalf of @brendanjryan, who approved this pull request (head 69c2e5da8da6) with a +1 comment via Voight-Kampff.
GitHub branch protection considers pull request reviews, not +1 comments. Voight-Kampff is recording this approval on the reviewer's behalf so branch protection requirements are met.
Motivation
The accounts SDK falls back to wallet-app approval whenever the local access key cannot sign a call: no key on the selected network, scopes that miss the call, a key revoked on chain, or a failed prepare. The wallet app approves on the chain the wallet is logged in on.
swapalready refuses a--networkother than the logged-in chain for this reason (#218), but a tokentransferon another network could still be approved and sent on the logged-in chain, although its dry run, prompt, andchainIdnamed the selected one.Summary
transferwhose--networkresolves to a chain other than the wallet's logged-in chain returnsE_USAGE"Transfer not sent: wallet is logged in on , not ; log in with 'tempo wallet login --network ', then rerun the transfer." with that command as itscta, using swap'scommandErrorpattern. It applies with or without an access key there.withWallettakes arefusehook that runs between its login and key checks. Transfer passes the network refusal through it, so an agent run without a key on the selected network gets the loginctainstead of a refresh one.transferTokensalso applies the refusal itself, after argument validation and before the unlisted-token metadata read, the fee-token read, the prompt, and the send.requireChain(provider, network)checks the chain the provider loaded from the wallet store and throws aCtaError(E_USAGEwith atempo wallet login --network <network>cta, returned throughctaErrors) if another login switched it after the command's check, for example while the confirmation prompt was open.--dry-runis not refused and still reviews the transfer on the selected network.cli.tspasses the returned refusal tocontext.error, as for swap, so agents and MCP clients get thecta.Key design considerations
transfer --machis unchanged: it pays through mppx with the selected network's stored access key, which signs locally on that chain and never falls back to the wallet app (it requires a usable key there).transfer --creditsis unchanged: it signs a Coinflow permit whose typed-data chain ID is checked against the selected network before signing, so a wallet-app signature cannot move funds on another chain.CtaErrorbecause it runs belowrun, soctaErrorskeeps itscta.swaphas the same two gaps (a refreshctafor an agent run without a key there, and no send-time re-check); both helpers are reusable there in a separate change.chainId,from(throughrequireSender), and the pinned fee token.