Skip to content

feat(#676): emergency withdraw for stuck XLM with 24h timelock - #710

Merged
Eniola3321 merged 2 commits into
ANYTECHS:mainfrom
ellaevans2323-pixel:feat/676-emergency-withdraw-xlm
Aug 1, 2026
Merged

feat(#676): emergency withdraw for stuck XLM with 24h timelock#710
Eniola3321 merged 2 commits into
ANYTECHS:mainfrom
ellaevans2323-pixel:feat/676-emergency-withdraw-xlm

Conversation

@ellaevans2323-pixel

Copy link
Copy Markdown
Contributor

Summary

Closes #676

Contracts may receive unintended XLM transfers that need recovery. This PR adds a two-step admin-only emergency withdrawal mechanism: the admin must first call initiate_withdraw() to start a 24-hour timelock, then after it expires call withdraw_xlm() to recover the funds.

Changes

Soroban contract (contracts/nft-contract/src/)

storage.rs

  • WITHDRAW_TIMELOCK_SECS = 86_400 (24 hours)
  • set/get/clear_withdraw_unlock_time — persists the unlock timestamp in instance storage
  • set/get_xlm_token_address — configures the XLM SAC address used for transfers

lib.rs

  • initiate_withdraw() — admin-only; stores now + 86400s as unlock time; emits withdraw_init event
  • withdraw_xlm(recipient, amount_stroops) — admin-only; checks timelock, clears it before transfer (checks-effects-interactions pattern), transfers XLM via token SAC, emits withdraw_xlm event
  • get_withdraw_unlock_time() — read-only view returning the pending unlock timestamp
  • set_xlm_token_address() — admin setter for the XLM SAC address
  • New error codes: WithdrawNotInitiated (15), WithdrawTimelockActive (16), InvalidWithdrawAmount (17), XlmTokenNotConfigured (18)

NestJS backend (src/nft/nft.controller.ts)

  • POST /nfts/admin/withdraw/initiate — prepare unsigned initiate_withdraw XDR (x-admin-secret required)
  • GET /nfts/admin/withdraw/timelock-status — query unlock time, seconds remaining, and ready flag
  • POST /nfts/admin/withdraw/execute — prepare unsigned withdraw_xlm XDR

Acceptance Criteria

  • Only admin can withdraw
  • Timelock is enforced (24h between initiate and execute)
  • withdraw_init and withdraw_xlm events are emitted
  • Admin-only endpoints documented with Swagger
  • Timelock status response includes secondsRemaining and ready flag

Soroban contract (contracts/nft-contract/src/):
- storage.rs: add WITHDRAW_TIMELOCK_SECS (86400), set/get/clear
  withdraw_unlock_time, set/get xlm_token_address
- lib.rs: add initiate_withdraw() — admin-only, stores now+24h unlock
  timestamp and emits withdraw_init event
- lib.rs: add withdraw_xlm(recipient, amount_stroops) — admin-only,
  enforces timelock, clears lock before transfer (CEI pattern),
  transfers XLM via token SAC, emits withdraw_xlm event
- lib.rs: add get_withdraw_unlock_time() view function
- lib.rs: add set_xlm_token_address() admin setter
- lib.rs: new error variants: WithdrawNotInitiated (15),
  WithdrawTimelockActive (16), InvalidWithdrawAmount (17),
  XlmTokenNotConfigured (18)
- lib.rs: emit_withdraw_initiated / emit_withdraw_xlm events added

NestJS backend (src/nft/nft.controller.ts):
- POST /nfts/admin/withdraw/initiate — prepare initiate_withdraw XDR
- GET  /nfts/admin/withdraw/timelock-status — query unlock time +
  seconds remaining + ready flag
- POST /nfts/admin/withdraw/execute — prepare withdraw_xlm XDR

Closes ANYTECHS#676
@drips-wave

drips-wave Bot commented Jul 31, 2026

Copy link
Copy Markdown

@ellaevans2323-pixel Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Eniola3321
Eniola3321 merged commit 41ec522 into ANYTECHS:main Aug 1, 2026
2 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

Development

Successfully merging this pull request may close these issues.

[Soroban] Emergency Withdraw for Stuck XLM

2 participants