Skip to content

fix: prevent dust attack order hijacking and set order_percent in early update#697

Open
onahprosper wants to merge 1 commit intostablefrom
fix/dust-attack-and-order-percent
Open

fix: prevent dust attack order hijacking and set order_percent in early update#697
onahprosper wants to merge 1 commit intostablefrom
fix/dust-attack-and-order-percent

Conversation

@onahprosper
Copy link
Collaborator

Description

This PR addresses two deposit processing bugs:

1. Dust/address poisoning attack vulnerability

When a deposit is detected on a receiveAddress, UpdateReceiveAddressStatus accepts any transfer amount and mutates the order to match — including dust transfers as small as $0.005. An attacker can send a dust transfer to a receiveAddress before the real deposit arrives. The system processes the dust first, rewrites the order amount from (e.g.) $5 to $0.005, transitions the order through deposited → refunding → refunded, and the real $5 deposit is left stranded.

Fix: Reject transfers with event.Value <= 0.1 (token units) before any order mutation occurs. The order stays in initiated status so the real deposit is processed normally when it arrives. This works across all chains (EVM, Tron, Starknet) since the check operates on the already-normalized token-unit value.

2. Orders stuck in settling with order_percent = 0

In ProcessPaymentOrderFromBlockchain, when an existing order (found by messageHash) is updated, the early Phase 1 update (lines 97-105) sets GatewayID and status but does not set order_percent. If validateAndPreparePaymentOrderData subsequently fails or cancels the order, the function returns early. The order now has GatewayID set (so the indexer skips it permanently on retry) but order_percent remains at the schema default of 0. When settlement is attempted, it sends 0% to the on-chain contract, which reverts, and the order is stuck in a settlingvalidated retry loop.

Fix: Include SetOrderPercent(decimal.NewFromInt(100)) in the early Phase 1 update so it's always set alongside GatewayID, regardless of whether validation succeeds.

References

N/A

Testing

Dust threshold — 5 new unit tests in services/common/indexer_test.go:

  • TestUpdateReceiveAddressStatus_DustTransferIgnored — 0.005 transfer is rejected, order stays initiated
  • TestUpdateReceiveAddressStatus_BoundaryDustIgnored — exactly 0.1 transfer is rejected (boundary)
  • TestUpdateReceiveAddressStatus_ValidTransferProcessed — 5.1 transfer passes the check and moves the order forward
  • TestUpdateReceiveAddressStatus_WrongAddressIgnored — transfer to a different address has no effect
  • TestUpdateReceiveAddressStatus_DuplicateTxHashIgnored — already-indexed txHash is skipped

Run: go test ./services/common/ -v

order_percent fix — verified by code inspection. For orders currently stuck in settling with order_percent = 0, a one-time DB update to set order_percent = 100 will unblock them via the existing stale_ops retry.

  • This change adds test coverage for new/changed/fixed functionality

Checklist

  • I have added documentation and tests for new/changed functionality in this PR
  • All active GitHub checks for tests, formatting, and security are passing
  • The correct base branch is being used, if not main

By submitting a PR, I agree to Paycrest's Contributor Code of Conduct and Contribution Guide.

- Introduced a new test file `indexer_test.go` to validate the behavior of the `UpdateReceiveAddressStatus` function.
- Implemented tests to ensure correct handling of various token transfer scenarios, including dust transfers, valid transfers, and ignored transfers based on address and duplicate transaction hashes.
- Enhanced the `UpdateReceiveAddressStatus` function to skip dust transfers, preventing address poisoning attacks.
- Updated the `ProcessPaymentOrderFromBlockchain` function to set the order percent to 100 when processing payment orders.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 19, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/dust-attack-and-order-percent

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments