Skip to content

Extend reentrancy regression coverage to stake, unstake, unlock_assets, emergency_withdraw - #137

Merged
prodbycorne merged 4 commits into
SmartDropLabs:mainfrom
miraclesonly:test/reentrancy-coverage-128
Aug 18, 2026
Merged

Extend reentrancy regression coverage to stake, unstake, unlock_assets, emergency_withdraw#137
prodbycorne merged 4 commits into
SmartDropLabs:mainfrom
miraclesonly:test/reentrancy-coverage-128

Conversation

@miraclesonly

Copy link
Copy Markdown
Contributor

Summary

MockReentrantToken/MockNaiveReentrantToken were only ever wired up against lock_assets, despite stake, unstake, unlock_assets, and emergency_withdraw sharing the identical threat model (an admin-supplied, not-necessarily-trusted stake_token whose transfer is a synchronous cross-contract call). These are also exactly the four functions #70/#71/#72 flag for transfer-before-state-update ordering, so this coverage doubles as their eventual regression suite.

  • Extended both mocks with configure_reentrant_call(function, args), an optional override for which function transfer reenters with — defaults to the existing get_user_position(reentrant_user) behavior when unset, so lock_assets's existing two tests are completely untouched. Used to make each new function's probe reenter the same state-mutating function currently executing (e.g. unlock_assets reentering unlock_assets), per the acceptance criteria's callout that this is a stronger, more realistic proof than only targeting a read-only getter.
  • Added 9 new tests covering stake (top-up branch specifically), unstake, unlock_assets, and emergency_withdraw — each with a graceful-rejection (MockReentrantToken) and naive-full-revert (MockNaiveReentrantToken) variant, mirroring lock_assets's existing two tests' structure and assertions (reentry rejection + exact final-state correctness, not just "didn't panic").
  • emergency_withdraw gets two graceful tests instead of one, since it makes two separate transfers in sequence — one covering reentry during the Position-only payout, one covering reentry during the second (UserStake) payout when both exist for a user.
  • Pre-existing Position/UserStake state some tests need is seeded directly via set_position/set_user_stake under env.as_contract, not by calling lock_assets/stake first: stake_token is fixed at initialize with no setter, so a token already configured to reenter would also reenter during that setup call — harmless for the graceful mock, but fatal for the naive one (the setup call itself would trap).

Test plan

  • All 9 new tests pass, and directly assert reentry_was_rejected() — i.e. that the host actually blocked the reentrant call, not just that final state happens to look right
  • cargo test --workspace (mirroring CI's own steps exactly) — 182/182 passing across factory, farming-pool, vesting-wallet
  • cargo build --workspace --target wasm32v1-none --release — succeeds
  • cargo fmt --all -- --check — clean
  • cargo clippy --workspace --all-targets -- -D warnings — clean

Closes #128

@netlify

netlify Bot commented Aug 18, 2026

Copy link
Copy Markdown

Deploy Preview for sdcontracts ready!

Name Link
🔨 Latest commit bf5e9d5
🔍 Latest deploy log https://app.netlify.com/projects/sdcontracts/deploys/6a84bb16149e8a000769eb7f
😎 Deploy Preview https://deploy-preview-137--sdcontracts.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@miraclesonly
miraclesonly force-pushed the test/reentrancy-coverage-128 branch from eacaa27 to bf5e9d5 Compare August 18, 2026 20:05
@prodbycorne

Copy link
Copy Markdown
Contributor

good

@prodbycorne
prodbycorne merged commit 2ee7ef1 into SmartDropLabs:main Aug 18, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants