code4rena-2023-12-shell-protocol-l03
[L-03] User can escape fees on ERC1155 tokens
Summary
수수료 계산 divider보다 작은 양을 ERC1155 unwrap 할 시 수수료를 내지 않을 수 있다.
Keyword
arithmetic error, rounding error, precision, token decimals
Vulnerability
외부 ERC1155 역시 decimal이 다를 수 있지만, ERC20과는 다르게 decimal 18로 정규화되지 않았다. Ocean 토큰은 해당 ERC1155 토큰의 decimal과 동일한 decimal을 사용하게 된다.
function _erc1155Wrap(
address tokenAddress,
uint256 tokenId,
uint256 amount,
address userAddress,
uint256 oceanId
)
private
{
//@audit Note that there is no `_convertDecimals()` call
if (tokenAddress == address(this)) revert NO_RECURSIVE_WRAPS();
_ERC1155InteractionStatus = INTERACTION;
@> IERC1155(tokenAddress).safeTransferFrom(userAddress, address(this), tokenId, amount, "");
_ERC1155InteractionStatus = NOT_INTERACTION;
emit Erc1155Wrap(tokenAddress, tokenId, amount, userAddress, oceanId);
}수수료를 계산하는 _calculateUnwrapFee 함수에서, unwrapFeeDivisor는 최소값이 2000이므로, 사용자가 unwarp하는 금액을 2000 미만으로 할 수 있다면 수수료를 지불할 필요가 없다. 따라서 사용자가 2 decimal의 ERC1155 100개의 토큰(즉, 100e2)을 wrap 했다면, 100e2 의 토큰을 한 번에 unwarp하는 대신 5번에 걸쳐 erc1155Unwrap을 호출하여 수수료를 지불하지 않을 수 있다. 100e2의 토큰을 언랩하고 수수료로 5를 지불하는 대신, 2000씩 5번 unwrap 한다.
function _calculateUnwrapFee(uint256 unwrapAmount) private view returns (uint256 feeCharged) {
@> feeCharged = unwrapAmount / unwrapFeeDivisor;
}Impact
ERC1155 unwrap 할 시 수수료를 내지 않을 수 있다.
Mitigation
ERC1155 도 18 decimal로 정규화한다.
tags: bughunting, shell protocol, smart contract, solidity, rounding error, arithmetic error, severity low, token decimals