Withdraw a matured position
At maturity, principal becomes withdrawable. Before maturity, it does not — this is enforced on chain, not by interface policy.
Maturity
A position stores unlockAt, set when it opens:
unlockAt = uint64(block.timestamp) + lockDurationWithdrawal requires block.timestamp >= unlockAt. Any earlier attempt reverts:
if (block.timestamp < p.unlockAt) revert NotMatured(positionId, p.unlockAt);The interface disables the Withdraw button until then and shows a live countdown, so a control is never offered that cannot succeed.
What you receive
One transaction returns both:
function withdraw(uint256 positionId) external returns (uint256 principal, uint256 rewards)- Principal — your full staked PLOUTO, exactly as deposited.
- Rewards — any unclaimed ETH, paid in the same transaction.
There is no fee, no penalty and no rounding against you on principal. The amount returned is the amount deposited.
Steps
- Open Gravity. A matured position shows a Matured badge instead of a countdown.
- Select Withdraw.
- Sign, and watch through to Confirmed.
- The position closes and disappears from the list.
totalStakedandtotalWeightdecrease accordingly.
There is no deadline
A matured position can sit open indefinitely. It keeps its full Gravity and keeps earning, exactly as before.
There is no penalty for leaving it, and no bonus. If you want to keep earning, doing nothing is a valid choice — though you are then holding weight with no lock, which you could equally re-commit for more.
Restaking
There is no automatic roll. To continue, withdraw and stake again — a new position with a new maturity.
Note that a new position opens at the current accumulator value, so it cannot claim rewards that accrued before it existed. There is no advantage lost by the gap, but also none gained.
Withdrawing is ordered safely
Effects before interactions, throughout:
rewards = _harvest(positionId, msg.sender); // effects only, no transferprincipal = p.amount;uint256 weight = p.weight; p.amount = 0;p.weight = 0;totalStaked -= principal;totalWeight -= weight; emit Withdrawn(msg.sender, positionId, principal, rewards); IERC20(registry.ploutoToken()).safeTransfer(msg.sender, principal);if (rewards != 0) _sendEth(msg.sender, rewards);The position is closed in storage before either transfer, and the whole function is nonReentrant. Withdrawing twice reverts with PositionClosed.
If withdrawal is paused
It is not. Pausing blocks new staking only; claims and matured withdrawals continue to work. See pausing.