Skip to content

feat: Validate beneficiary account before deleting account#596

Merged
vsavchyn-dev merged 8 commits into
mainfrom
validate-beneficiary-before-send
Jun 17, 2026
Merged

feat: Validate beneficiary account before deleting account#596
vsavchyn-dev merged 8 commits into
mainfrom
validate-beneficiary-before-send

Conversation

@FroVolod

Copy link
Copy Markdown
Collaborator

No description provided.

@github-project-automation github-project-automation Bot moved this to NEW❗ in DevTools May 23, 2026
@FroVolod FroVolod marked this pull request as ready for review May 23, 2026 08:16
@FroVolod FroVolod requested a review from a team as a code owner May 23, 2026 08:16
@FroVolod

Copy link
Copy Markdown
Collaborator Author

@race-of-sloths

@race-of-sloths

race-of-sloths commented May 23, 2026

Copy link
Copy Markdown

@FroVolod Thank you for your contribution! Your pull request is now a part of the Race of Sloths!
Weekly streak is on the road, smart strategy! Secure your streak with another PR!

Shows inviting banner with latest news.

Shows profile picture for the author of the PR

Current status: executed
Reviewer Score
@vsavchyn-dev 3

Your contribution is much appreciated with a final score of 3!
You have received 32 (30 base + 5% lifetime bonus) Sloth points for this contribution

@vsavchyn-dev received 25 Sloth Points for reviewing and scoring this pull request.

We would appreciate your feedback or contribution idea that you can submit here

What is the Race of Sloths

Race of Sloths is a friendly competition where you can participate in challenges and compete with other open-source contributors within your normal workflow

For contributors:

  • Tag @race-of-sloths inside your pull requests
  • Wait for the maintainer to review and score your pull request
  • Check out your position in the Leaderboard
  • Keep weekly and monthly streaks to reach higher positions
  • Boast your contributions with a dynamic picture of your Profile

For maintainers:

  • Score pull requests that participate in the Race of Sloths and receive a reward
  • Engage contributors with fair scoring and fast responses so they keep their streaks
  • Promote the Race to the point where the Race starts promoting you
  • Grow the community of your contributors

Feel free to check our website for additional details!

Bot commands
  • For contributors
    • Include a PR: @race-of-sloths include to enter the Race with your PR
  • For maintainers:
    • Invite contributor @race-of-sloths invite to invite the contributor to participate in a race or include it, if it's already a runner.
    • Assign points: @race-of-sloths score [1/2/3/5/8/13] to award points based on your assessment.
    • Reject this PR: @race-of-sloths exclude to send this PR back to the drawing board.
    • Exclude repo: @race-of-sloths pause to stop bot activity in this repo until @race-of-sloths unpause command is called

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds beneficiary account validation before constructing account deletion transactions, helping prevent delete actions from sending remaining funds to an invalid beneficiary.

Changes:

  • Validates the beneficiary account in the dedicated account delete-account flow.
  • Validates DeleteAccount beneficiaries when finalizing manually constructed transactions.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/commands/account/delete_account/mod.rs Adds beneficiary validation before producing the delete-account transaction.
src/commands/transaction/construct_transaction/skip_action/mod.rs Adds validation for delete-account actions in constructed transactions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +85 to +90
if !crate::common::validate_receiver_account_id(
network_config,
&beneficiary_account_id,
item.global_context.verbosity,
item.global_context.offline,
)? {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, this is expected behaviour as we ask user for verification

Image

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That mentioned, do we really want to double-ask user?

@FroVolod FroVolod Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored fcd0b01

Comment on lines +32 to +38
if let near_primitives::action::Action::DeleteAccount(near_primitives::transaction::DeleteAccountAction { beneficiary_id }) = action
&& !crate::common::validate_receiver_account_id(
network_config,
beneficiary_id,
item.0.global_context.verbosity,
item.0.global_context.offline,
)? {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We ask user for verification

Image

@FroVolod FroVolod Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored fcd0b01

@FroVolod FroVolod marked this pull request as draft June 1, 2026 06:36
@FroVolod FroVolod marked this pull request as ready for review June 9, 2026 11:39
@FroVolod FroVolod marked this pull request as draft June 9, 2026 13:14
@FroVolod FroVolod marked this pull request as ready for review June 11, 2026 07:12

@vsavchyn-dev vsavchyn-dev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Despite changing how the things are with deleting account - I think this is better in terms of UX, so that nobody can screw up by deleting and loosing their funds (esp on mainnet). LGTM

Comment thread src/commands/transaction/construct_transaction/skip_action/mod.rs Outdated
scope: &<DeleteAccountAction as interactive_clap::ToInteractiveClapContextScope>::InteractiveClapContextScope,
) -> color_eyre::eyre::Result<Self> {
let beneficiary_id: near_primitives::types::AccountId = scope.beneficiary_id.clone().into();
if previous_context.signer_account_id == beneficiary_id {

@frolvanya frolvanya Jun 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's incorrect, we're removing receiver here:

Image Image

P.S: same issue in add_action_2 and 3

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, we can continue using signer, but we just need to ensure that signer == receiver for DeleteAccount action specifically to prevent:
image
https://testnet.nearblocks.io/txns/5sr9DvD1QofwT8kssoHjuzw9rpktUcsG2f9W4nhtMgXP

Also, this would ensure that only one account will be deleted at max, so #596 (comment) could be irrelevant after this fix

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary check for the low-level construct transaction flow. I suggest we don't overcomplicate things here. There is nothing bad that could happen here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a single sender == receiver check for all actions except CreateAccount that prevents a submission of incorrect tx (the whole purpose of this pr btw), so I think it's better to add this check

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we should validate it for AddKey, DeleteKey, DeployCode - also require signer == receiver

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AddKey, DeleteKey, DeployCode

Yes?

sender == receiver check for all actions except CreateAccount

I don't see how is this a problem. We don't need to do it in every single module and copy paste code everywhere. We just need to add a single check in skip_action flow

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest moving this task to another PR.

@FroVolod FroVolod marked this pull request as draft June 17, 2026 17:36
@FroVolod FroVolod marked this pull request as ready for review June 17, 2026 18:47
@vsavchyn-dev vsavchyn-dev merged commit 38ee9d2 into main Jun 17, 2026
13 checks passed
@vsavchyn-dev vsavchyn-dev deleted the validate-beneficiary-before-send branch June 17, 2026 19:08
@github-project-automation github-project-automation Bot moved this from NEW❗ to Shipped 🚀 in DevTools Jun 17, 2026
@race-of-sloths

Copy link
Copy Markdown

🥁 Score it!

@vsavchyn-dev, please score the PR with @race-of-sloths score [1/2/3/5/8/13]. The contributor deserves it.
If no scoring is provided within 24 hours, this PR will be scored as 2 🦥

@vsavchyn-dev

Copy link
Copy Markdown
Contributor

@race-of-sloths score 3

r-near added a commit that referenced this pull request Jul 2, 2026
## 🤖 New release

* `near-cli-rs`: 0.27.0 -> 0.28.0 (⚠ API breaking changes)

### ⚠ `near-cli-rs` breaking changes

```text
--- failure constructible_struct_adds_field: externally-constructible struct adds field ---

Description:
A pub struct constructible with a struct literal has a new pub field. Existing struct literals must be updated to include the new field.
        ref: https://doc.rust-lang.org/reference/expressions/struct-expr.html
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/constructible_struct_adds_field.ron

Failed in:
  field CliSignPrivateKey.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_private_key/mod.rs:5
  field InteractiveClapContextScopeForGenerateKeypair.signature_scheme in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/create_account/sponsor_by_faucet_service/add_key/autogenerate_new_keypair/mod.rs:3
  field CliSignLedger.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_ledger/mod.rs:18
  field CliSignLegacyKeychain.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_legacy_keychain/mod.rs:12
  field CliSignKeychain.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_keychain/mod.rs:9
  field SignLedgerContext.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_ledger/mod.rs:51
  field InteractiveClapContextScopeForSignSeedPhrase.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_seed_phrase/mod.rs:7
  field CliSignAccessKeyFile.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_access_key_file/mod.rs:5
  field CliGenerateKeypair.signature_scheme in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/create_account/sponsor_by_faucet_service/add_key/autogenerate_new_keypair/mod.rs:3
  field InteractiveClapContextScopeForSignPrivateKey.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_private_key/mod.rs:5
  field InteractiveClapContextScopeForSignLedger.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_ledger/mod.rs:18
  field InteractiveClapContextScopeForSignLegacyKeychain.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_legacy_keychain/mod.rs:12
  field InteractiveClapContextScopeForSignKeychain.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_keychain/mod.rs:9
  field InteractiveClapContextScopeForSignAccessKeyFile.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_access_key_file/mod.rs:5
  field CliSignSeedPhrase.nonce_index in /tmp/.tmpat9wFR/near-cli-rs/src/transaction_signature_options/sign_with_seed_phrase/mod.rs:7

--- failure enum_no_repr_variant_discriminant_changed: enum variant had its discriminant change value ---

Description:
The enum's variant had its discriminant value change. This breaks downstream code that used its value via a numeric cast like `as isize`.
        ref: https://doc.rust-lang.org/reference/items/enumerations.html#assigning-discriminant-values
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/enum_no_repr_variant_discriminant_changed.ron

Failed in:
  variant TopLevelCommandDiscriminants::Extensions 7 -> 8 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/mod.rs:60
  variant TopLevelCommandDiscriminants::Extensions 7 -> 8 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/mod.rs:60
  variant AccountActionsDiscriminants::GetPublicKey 7 -> 8 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:69
  variant AccountActionsDiscriminants::AddKey 8 -> 9 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:74
  variant AccountActionsDiscriminants::DeleteKeys 9 -> 12 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:89
  variant AccountActionsDiscriminants::ManageStorageDeposit 10 -> 13 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:94
  variant AccountActionsDiscriminants::GetPublicKey 7 -> 8 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:69
  variant AccountActionsDiscriminants::AddKey 8 -> 9 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:74
  variant AccountActionsDiscriminants::DeleteKeys 9 -> 12 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:89
  variant AccountActionsDiscriminants::ManageStorageDeposit 10 -> 13 in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:94

--- failure enum_variant_added: enum variant added on exhaustive enum ---

Description:
A publicly-visible enum without #[non_exhaustive] has a new variant.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#enum-variant-new
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/enum_variant_added.ron

Failed in:
  variant AccountActionsDiscriminants:ViewGasKeyNonces in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:64
  variant AccountActionsDiscriminants:FundGasKey in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:79
  variant AccountActionsDiscriminants:WithdrawFromGasKey in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:84
  variant AccountActionsDiscriminants:ViewGasKeyNonces in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:64
  variant AccountActionsDiscriminants:FundGasKey in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:79
  variant AccountActionsDiscriminants:WithdrawFromGasKey in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:84
  variant CliTopLevelCommand:GenerateKeypair in /tmp/.tmpat9wFR/near-cli-rs/src/commands/mod.rs:16
  variant CliAccountActions:ViewGasKeyNonces in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:27
  variant CliAccountActions:FundGasKey in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:27
  variant CliAccountActions:WithdrawFromGasKey in /tmp/.tmpat9wFR/near-cli-rs/src/commands/account/mod.rs:27
  variant TopLevelCommandDiscriminants:GenerateKeypair in /tmp/.tmpat9wFR/near-cli-rs/src/commands/mod.rs:56
  variant TopLevelCommandDiscriminants:GenerateKeypair in /tmp/.tmpat9wFR/near-cli-rs/src/commands/mod.rs:56

--- failure function_missing: pub fn removed or renamed ---

Description:
A publicly-visible function cannot be imported by its prior path. A `pub use` may have been removed, or the function itself may have been renamed or removed entirely.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/function_missing.ron

Failed in:
  function near_cli_rs::transaction_signature_options::send::sleep_after_error, previously in file /tmp/.tmppWZUdR/near-cli-rs/src/transaction_signature_options/send/mod.rs:193

--- failure trait_method_added: pub trait method added ---

Description:
A non-sealed public trait added a new method without a default implementation, which breaks downstream implementations of the trait
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#trait-new-item-no-default
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/trait_method_added.ron

Failed in:
  trait method near_cli_rs::common::RpcQueryResponseExt::gas_key_nonces_view in file /tmp/.tmpat9wFR/near-cli-rs/src/common.rs:3499
```

<details><summary><i><b>Changelog</b></i></summary><p>

<blockquote>

##
[0.28.0](v0.27.0...v0.28.0)
- 2026-07-02

### Added

- sign transactions with a gas key (nonce_index)
([#608](#608))
- gas-key support (nearcore 2.13)
([#607](#607))
- post-quantum (ML-DSA-65) key generation (draft)
([#605](#605))
- Validate beneficiary account before deleting account
([#596](#596))

### Fixed

- Fixed output information for transaction status "Started"
([#594](#594))

### Other

- Fixed NPM Trusted Publishing
([#603](#603))
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).

---------

Co-authored-by: r-near <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Shipped 🚀

Development

Successfully merging this pull request may close these issues.

7 participants