sherlock-2025-07-mellow-m03
[M-03] stETH edge case in transfer rounding can cause denial of service for depositors and redeemers
Summary
stETH를 전송할 때, stETH 내부 로직으로 인해 반올림되어 요청한 것보다 1-2 wei 적은 양을 전송할 수도 있다. 하지만 Mellow는 실제로 받은 stETH의 양을 확인하지 않고 전송 요청했던 양을 그대로 내부 장부에 저장했다. 추후 토큰을 이동해야 할 때, 실제로 예치된 토큰의 수가 더 적으므로 트랜잭션이 취소될 수 있다.
Keyword
steth, rounding error, weird erc20, dos
Vulnerability
stETH를 전송할 때, stETH 내부 로직으로 인해 반올림되어 요청한 것보다 1-2 wei 적은 양을 전송할 수도 있다. (참고: stETH 문서) 따라서 stETH를 전송받거나 전송할 때, 실제로 받거나 전달된 양은 요청한 양보다 적을 수 있다.
하지만 Mellow는 토큰을 입금받을 때 정확히 유저가 정한 만큼의 토큰을 수령한 것으로 가정하고 이 값을 내부 회계에 기록한다. 유저가 입금 후 취소하는 경우 유저가 입금한 금액만큼을 돌려주려고 하지만, 실제로 컨트랙트가 받은 양은 이보다 적으로 수 있다. 토큰이 모자라면 트랜잭션이 취소될 수 있다.
function cancelDepositRequest() external nonReentrant {
address caller = _msgSender();
DepositQueueStorage storage $ = _depositQueueStorage();
Checkpoints.Checkpoint224 memory request = $.requestOf[caller];
uint256 assets = request._value;
if (assets == 0) {
revert NoPendingRequest();
}
address asset_ = asset();
(bool exists, uint32 timestamp, uint256 index) = $.prices.latestCheckpoint();
if (exists && timestamp >= request._key) {
revert ClaimableRequestExists();
}
delete $.requestOf[caller];
IVaultModule(vault()).riskManager().modifyPendingAssets(asset_, -int256(uint256(assets)));
$.requests.modify(index, -int256(assets));
@> TransferLibrary.sendAssets(asset_, caller, assets);
emit DepositRequestCanceled(caller, assets, request._key);
}Impact
입금의 취소, claim, 입출금 처리 등의 기능에 DoS를 초래할 수 있다.
Mitigation
실제로 수령한 stETH 토큰의 양을 조회한다. 이를 내부 회계 및 후속 작업 등에 사용한다.
Memo
stETH가 사용 토큰일 시 반드시 확인하도록 하자.
tags: bughunting, mellow, smart contract, solidity, severity medium, rounding error, weird erc20, dos