Skip to content

fix: let MATP holders unstake while their milestone is pending - #127

Merged
aminsammara merged 1 commit into
mainfrom
fix/matp-unstake-milestone-gate
Nov 2, 2026
Merged

aminsammara merged 1 commit into
mainfrom
fix/matp-unstake-milestone-gate

Conversation

@aminsammara

Copy link
Copy Markdown
Collaborator

The ATP withdrawal actions blocked initiate and finalize unstake for any MATP whose milestone wasn't Succeeded, with the message "Withdrawals require milestone to be achieved". The contracts have no such rule.

What the contracts do

  • Initiate: ATPWithdrawableStaker.initiateWithdraw only requires the ATP operator. The stake returns to the MATP, not to the beneficiary.
  • Finalize: Rollup.finalizeWithdraw is permissionless.
  • Claim: this is what the milestone gates. MATPCore.getClaimable returns 0 unless the milestone is Succeeded.
  • Failed milestone: the MATP reports the revoker as operator, so the beneficiary can no longer initiate.

I simulated initiateWithdraw from the beneficiary of a testnet MATP whose milestone is still pending, and it succeeds.

Change

  • Initiate: gated only when the milestone has failed, with a message saying control has passed to the revoker.
  • Finalize: no longer milestone-gated.
  • Helper: canWithdrawWithMilestone (Succeeded only) is replaced by canUnstakeWithMilestone (anything but Failed). Its doc comment states the claim/unstake distinction.

Checks

  • tsc -b passes.
  • eslint passes on the three changed files.
  • The milestone badge still shows next to the actions.

The withdrawal actions disabled both initiate and finalize unstake for
any MATP whose milestone was not Succeeded, with the message
"Withdrawals require milestone to be achieved". The contracts have no
such rule. The milestone gates claiming, not unstaking:
MATPCore.getClaimable returns 0 unless the milestone is Succeeded.
ATPWithdrawableStaker.initiateWithdraw, by contrast, only requires the
ATP's operator, and the unstaked tokens go back to the MATP, not to the
beneficiary. Finalize is permissionless on the rollup. Simulating
initiateWithdraw on Sepolia, from the beneficiary of an MATP with a
pending milestone, succeeds.

A Failed milestone is the one case that does block the beneficiary.
The MATP then reports the revoker as operator, so the beneficiary's
initiateWithdraw would revert. Initiate is now gated on that alone,
with a message that says so. Finalize is not gated at all.
@aminsammara
aminsammara requested a review from a team as a code owner October 28, 2026 15:10
@aminsammara
aminsammara merged commit 443576c into main Nov 2, 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

Development

Successfully merging this pull request may close these issues.

1 participant