feat: validate receiver account before sending tokens#582
Conversation
ea800ee to
a22d122
Compare
There was a problem hiding this comment.
Pull request overview
This PR adds receiver account validation for token transfer commands to reduce accidental sends to the wrong network or to non-existent accounts, while still allowing users to proceed after explicit confirmation.
Changes:
- Added common helper(s) to (1) warn on likely network mismatch and (2) check receiver existence via RPC with a confirmation prompt.
- Wired the receiver validation into
tokenssend flows (NEAR, FT, FT-call, NFT) after network selection. - Implemented “cancel” behavior by returning an empty-actions transaction (which the existing pipeline treats as a cancellation).
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/common.rs | Adds network-mismatch heuristic, RPC existence check, and shared confirmation prompt helper. |
| src/commands/tokens/send_near/mod.rs | Calls receiver validation before creating the transfer transaction. |
| src/commands/tokens/send_nft/mod.rs | Calls receiver validation before constructing the NFT transfer call. |
| src/commands/tokens/send_ft/amount_ft.rs | Calls receiver validation before building FT transfer transaction. |
| src/commands/tokens/send_ft_call/amount_ft.rs | Calls receiver validation before building FT transfer-call transaction. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| receiver_account_id, network_config.network_name | ||
| ); | ||
| return ask_if_should_proceed(); | ||
| } | ||
|
|
There was a problem hiding this comment.
The early return ask_if_should_proceed() means that when the receiver looks like it’s on the wrong network and the user chooses to proceed, the RPC existence check is never run. If the intention is to run both validations (as described in the PR description), consider prompting on the network-mismatch warning and then continuing to the existence check when the user confirms.
| .block_on(get_account_state( | ||
| network_config, | ||
| receiver_account_id, | ||
| near_primitives::types::BlockReference::latest(), | ||
| )); |
There was a problem hiding this comment.
This function performs an RPC call via get_account_state unconditionally. In offline mode (GlobalContext.offline), this will still retry (with sleeps) and slow down “offline” flows. Consider adding an offline flag parameter (or passing GlobalContext) so the existence check can be skipped when offline, while still keeping the lightweight network-suffix heuristic.
| ask_if_should_proceed() | ||
| } | ||
| // Dont block the transaction if we can't reach the RPC | ||
| Err(_) => Ok(true), |
There was a problem hiding this comment.
Err(_) => Ok(true) will silently proceed not only when the RPC is unreachable, but also for other server-side errors (e.g., misconfigured RPC URL, unexpected server response). This can hide real problems. Consider matching specifically on JsonRpcError::TransportError(_) (skip silently as intended) and returning Err(err.into()) for other error variants, similar to how account existence is handled in create_account/fund_myself_create_account/sign_as.
| Err(_) => Ok(true), | |
| Err(near_jsonrpc_client::errors::JsonRpcError::TransportError(_)) => Ok(true), | |
| Err(err) => Err(err.into()), |
| ); | ||
| ask_if_should_proceed() | ||
| } | ||
| // Dont block the transaction if we can't reach the RPC |
There was a problem hiding this comment.
Typo in comment: "Dont" → "Don't".
| // Dont block the transaction if we can't reach the RPC | |
| // Don't block the transaction if we can't reach the RPC |
| actions: vec![], | ||
| }); | ||
| } | ||
|
|
There was a problem hiding this comment.
You cannot use the user dialog in fn from previous context(). Some users use a script command that should end with "quiet".
There was a problem hiding this comment.
Added a verbosity param in validate_receiver_account_id to skip validation if in quiet mode to skip validation in fcb7f73
| }); | ||
| } | ||
|
|
||
| let amount_ft = if let crate::types::ft_properties::FungibleTokenTransferAmount::ExactAmount(ft) = &ft_transfer_amount { |
| receiver_id: receiver_account_id.clone(), | ||
| actions: vec![], | ||
| }); | ||
| } |
| receiver_id: nft_contract_account_id.clone(), | ||
| actions: vec![], | ||
| }); | ||
| } |
frolvanya
left a comment
There was a problem hiding this comment.
Thanks for the contribution!
Found few minor issues, but overall looks good to me. Still probably have to be discussed with a team which option rpc vs string check is better
Co-authored-by: Copilot <[email protected]>
vsavchyn-dev
left a comment
There was a problem hiding this comment.
LGTM, thanks for the PR!
## 🤖 New release * `near-cli-rs`: 0.26.1 -> 0.26.2 (✓ API compatible changes) <details><summary><i><b>Changelog</b></i></summary><p> <blockquote> ## [0.26.2](v0.26.1...v0.26.2) - 2026-05-08 ### Added - validate receiver account before sending tokens ([#582](#582)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/).
Adds recipient validation to the tokens subcommand (send-near, send-ft,send-ft-call, send-nft), after network selection, two checks run: a network mismatch check that warns if the receiver looks like it belongs to a different network and an rpc existence check that warns if the receiver account doesn't exist on the selected network. Both checks prompt the user for confirmation and never block, the user can always choose to proceed. If the rpc is unreachable,the existence check is skipped silently.
Fixes #581