Skip to content

feat: Add emergency_withdraw to farming-pool contract#45

Merged
prodbycorne merged 1 commit into
SmartDropLabs:mainfrom
simplicityf:feat/admin-withdrawal
Jun 27, 2026
Merged

feat: Add emergency_withdraw to farming-pool contract#45
prodbycorne merged 1 commit into
SmartDropLabs:mainfrom
simplicityf:feat/admin-withdrawal

Conversation

@simplicityf

Copy link
Copy Markdown
Contributor

Related Issue

Closes #24

Problem

The existing pause mechanism prevents new operations when a critical vulnerability is discovered, but leaves staked and locked tokens permanently inaccessible. There was no admin path to return funds to users during an emergency.

Solution

Introduces emergency_withdraw, an admin-only function callable exclusively while the pool is paused. It returns all tokens held for a given user (both the lock position and the stake balance), preserves any accrued credits in a new BankedCredits storage key for a future claim mechanism, and emits a fully auditable emrg_exit event.

Changes

types.rs

  • Added PoolError — a #[contracterror] enum with NotPaused = 13 and NoActiveStake = 14
  • Added DataKey::BankedCredits(Address) — persistent storage key for credits preserved after an emergency withdrawal

lib.rs

  • emergency_withdraw(env, user) -> Result<i128, PoolError> — transfers both the lock position amount and the stake amount back to the user, writes any banked credits to BankedCredits storage before removing the records, and emits ("pool", "emrg_exit") with (admin, user, total_returned)
  • get_banked_credits(env, user) -> i128 — public query for credits saved by a prior emergency withdrawal; returns 0 if none
  • set_banked_credits — private helper that writes to BankedCredits with TTL bump

test.rs

  • test_emergency_withdraw_while_paused — locks 600 tokens, stakes 400, triggers credit checkpoints (8 000 credits total), pauses, calls emergency_withdraw, asserts all 1 000 tokens returned, position and stake records cleared, and 8 000 credits preserved in get_banked_credits
  • test_emergency_withdraw_while_unpaused_returns_not_paused — asserts Err(PoolError::NotPaused) when called on a live pool

Safeguards

Safeguard How it's enforced
Admin-only get_admin(&env).require_auth() at function entry
Paused-only Returns Err(PoolError::NotPaused) if !pool_is_paused — prevents routine extraction of user funds
Credits preserved Banked credits are written to BankedCredits before position/stake records are removed
Fully auditable emrg_exit event emitted for every withdrawal with (admin, user, amount)

Test results

0

…rios

- Created a new test snapshot for the `transfer_admin` event in the factory contract, ensuring the correct event emission when transferring admin rights.
- Added a test snapshot for emergency withdrawal while the farming pool is paused, verifying that the correct state is maintained.
- Introduced a test snapshot for emergency withdrawal when the pool is unpaused, confirming that the withdrawal process behaves as expected.
@prodbycorne prodbycorne merged commit 383d92e into SmartDropLabs:main Jun 27, 2026
1 check failed
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.

Add emergency withdrawal function for admin to return funds during crisis

2 participants