You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PodUnwrapLocker will cause financial loss for users as debond fees are applied during lock creation
Summary
The protocol's design intended to allow fee-free debonding via cooldown locking through PodUnwrapLocker, but incorrectly uses the fee-applying WeightedIndex.debond path. This results in:
Hidden Fee Deduction: Debond fees are applied during lock creation, reducing stored amounts before cooldown
Normal Withdrawal Loss: Users receive less value than deposited despite waiting full lock period
Compounded Early Penalty: Early withdrawal penalties calculate on pre-reduced amounts, amplifying losses
The root cause stems from missing a fee-exempt debond path for locker-initiated transactions, violating core protocol guarantees about cooldown withdrawals.
Root Cause
In function PodUnwrapLocker.debondAndLock (PodUnwrapLocker.sol#L76) the locker contract calls WeightedIndex.debond which applies debond fees (WeightedIndex.sol#L176-L178), contradicting the locker's design purpose of fee-free debonding:
/** * @title PodUnwrapLocker@> * @notice Allows users to debond from pods fee free with a time-lock period before they can withdraw their tokens. * The lock duration is determined by each pod's debondCooldown config setting. Users can withdraw early if they choose, * however they will realize a debondFee + 10% fee on early withdraw. */contractPodUnwrapLockerisContext, ReentrancyGuard {
// ...function debondAndLock(address_pod, uint256_amount) external nonReentrant {
// ...// Get token addresses and balances before debondingfor (uint256 i =0; i < _tokens.length; i++) {
_tokens[i] = _podTokens[i].token;
_balancesBefore[i] =IERC20(_tokens[i]).balanceOf(address(this));
}
@> _podContract.debond(_amount, newaddress[](0), newuint8[](0));
uint256[] memory _receivedAmounts =newuint256[](_tokens.length);
for (uint256 i =0; i < _tokens.length; i++) {
@> _receivedAmounts[i] =IERC20(_tokens[i]).balanceOf(address(this)) - _balancesBefore[i];
}
// ...
locks[_lockId] =LockInfo({
user: _msgSender(),
pod: _pod,
tokens: _tokens,
@> amounts: _receivedAmounts,
unlockTime: block.timestamp+ _podConfig.debondCooldown,
withdrawn: false
});
// ...
}
}
The core issue stems from using the standard debond path that applies fees, rather than implementing a dedicated fee-exempt debond mechanism for locker-initiated transactions. This violates the architectural intent of providing a fee-free cooldown withdrawal option.
Internal Pre-conditions
PodUnwrapLocker uses standard debond mechanism that applies 5% debond fee (example value)
Locked token amounts are stored post-fee deduction
Early withdrawal penalty (5.5% in example, 5% + 5% / 10) calculated on reduced amounts
External Pre-conditions
User initiates debond-lock with 1000 POD tokens (1:1 asset backing in example)
User expects full 1000 token value after lock period
Protocol advertises locker as "fee-free with cooldown"
Attack Path
User calls PodUnwrapLocker.debondAndLock(1000 POD)
Internally calls WeightedIndex.debond where applying 5% debond fees
Crazy Cyan Worm
High
PodUnwrapLocker
will cause financial loss for users as debond fees are applied during lock creationSummary
The protocol's design intended to allow fee-free debonding via cooldown locking through
PodUnwrapLocker
, but incorrectly uses the fee-applyingWeightedIndex.debond
path. This results in:The root cause stems from missing a fee-exempt debond path for locker-initiated transactions, violating core protocol guarantees about cooldown withdrawals.
Root Cause
In function
PodUnwrapLocker.debondAndLock
(PodUnwrapLocker.sol#L76
) the locker contract callsWeightedIndex.debond
which applies debond fees (WeightedIndex.sol#L176-L178
), contradicting the locker's design purpose of fee-free debonding:This results in:
Locked amounts being reduced by debond fees before storage
Normal withdrawal receiving reduced amount due to charged debond fees (
PodUnwrapLocker.withdraw
):PodUnwrapLocker.earlyWithdraw
):The core issue stems from using the standard debond path that applies fees, rather than implementing a dedicated fee-exempt debond mechanism for locker-initiated transactions. This violates the architectural intent of providing a fee-free cooldown withdrawal option.
Internal Pre-conditions
External Pre-conditions
Attack Path
PodUnwrapLocker.debondAndLock(1000 POD)
WeightedIndex.debond
where applying 5% debond feesPodUnwrapLocker
contract receives 950 underlying tokens (1:1 example rate, 5% fee applied)PodUnwrapLocker.withdraw
after required lock periodPodUnwrapLocker.earlyWithdraw
1000 - (1000 * 5.5%) = 945 tokens
950 * 5.5% = 52.25 tokens
Impact
PoC
No response
Mitigation
Implement Fee-Exempt Debond Path:
debondNoFee
function inWeightedIndex
contractPodUnwrapLocker
via modifierModify Locker Workflow:
debond
call withdebondNoFee
inPodUnwrapLocker.debondAndLock
The text was updated successfully, but these errors were encountered: