Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eliminate dust when wrap ERC-20 token by retaining erc20 balance in their respective decimal places #135

Closed
c4-bot-8 opened this issue Dec 7, 2023 · 4 comments
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working edited-by-warden insufficient quality report This report is not of sufficient quality primary issue Highest quality submission among a set of duplicates unsatisfactory does not satisfy C4 submission criteria; not eligible for awards

Comments

@c4-bot-8
Copy link
Contributor

c4-bot-8 commented Dec 7, 2023

Lines of code

https://github.com/code-423n4/2023-11-shellprotocol/blob/main/src/ocean/Ocean.sol#L820-L842
https://github.com/code-423n4/2023-11-shellprotocol/blob/main/src/ocean/Ocean.sol#L622-L628
https://github.com/code-423n4/2023-11-shellprotocol/blob/main/src/ocean/Ocean.sol#L1068-L1109

Vulnerability details

Impact

The creation of token dust through decimal conversion poses two key issues:

Ownership - Dust gets sent to the contract owner rather than users, despite being their rightful property.

Restricted movement - Dust accumulates and cannot be withdrawn until reaching 1 WEI minimum, inconveniencing the owner of dust.

Proof of Concept

Dust gets created when:

Users wrap ERC20 tokens into Ocean via doInteraction() or doMultipleInteractions() with the WrapErc20 interaction type.

Here the token amount gets converted, with leftovers assigned as dust sent to the owner, as seen in this snippet:

function _erc20Wrap(address tokenAddress, uint256 amount, address userAddress, uint256 outputToken) private {
        try IERC20Metadata(tokenAddress).decimals() returns (uint8 decimals) {
            /// @dev the amount passed as an argument to the external token
            uint256 transferAmount;
            /// @dev the leftover amount accumulated by the Ocean.
            uint256 dust;

            (transferAmount, dust) = _determineTransferAmount(amount, decimals);

            // If the user is unwrapping a delta, the residual dust could be
            // written to the user's ledger balance. However, it costs the
            // same amount of gas to place the dust on the owner's balance,
            // and accumulation of dust may eventually result in
            // transferrable units again.
            _grantFeeToOcean(outputToken, dust);

            SafeERC20.safeTransferFrom(IERC20(tokenAddress), userAddress, address(this), transferAmount);

            emit Erc20Wrap(tokenAddress, transferAmount, amount, dust, userAddress, outputToken);
        } catch {
            revert NO_DECIMAL_METHOD();
        }
    }

Tools Used

Manual

Recommended Mitigation Steps

Dust needs to be removed. External tokens should be stored in the Ocean ERC-1155 contract at their original precision, avoiding any decimal conversion or normalization.

Suggest to change

   function _erc20Unwrap(address tokenAddress, uint256 amount, address userAddress, uint256 inputToken) private {
        try IERC20Metadata(tokenAddress).decimals() returns (uint8 decimals) {
            uint256 feeCharged = _calculateUnwrapFee(amount);
            uint256 amountRemaining = amount - feeCharged;

-            (uint256 transferAmount, uint256 truncated) =
-                _convertDecimals(NORMALIZED_DECIMALS, decimals, amountRemaining);
-            feeCharged += truncated;

-            _grantFeeToOcean(inputToken, feeCharged);

-            SafeERC20.safeTransfer(IERC20(tokenAddress), userAddress, transferAmount);
+            SafeERC20.safeTransfer(IERC20(tokenAddress), userAddress, amountRemaining);

            emit Erc20Unwrap(tokenAddress, transferAmount, amount, feeCharged, userAddress, inputToken);
        } catch {
            revert NO_DECIMAL_METHOD();
        }
    }
``








## Assessed type

Other
@c4-bot-8 c4-bot-8 added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working labels Dec 7, 2023
c4-bot-8 added a commit that referenced this issue Dec 7, 2023
@raymondfam
Copy link

Intended per the comment:

            // If the user is unwrapping a delta, the residual dust could be
            // written to the user's ledger balance. However, it costs the
            // same amount of gas to place the dust on the owner's balance,
            // and accumulation of dust may eventually result in
            // transferrable units again.

@c4-pre-sort c4-pre-sort added the insufficient quality report This report is not of sufficient quality label Dec 9, 2023
@c4-pre-sort
Copy link

raymondfam marked the issue as insufficient quality report

@c4-pre-sort
Copy link

raymondfam marked the issue as primary issue

@c4-judge
Copy link
Contributor

0xA5DF marked the issue as unsatisfactory:
Invalid

@c4-judge c4-judge added the unsatisfactory does not satisfy C4 submission criteria; not eligible for awards label Dec 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working edited-by-warden insufficient quality report This report is not of sufficient quality primary issue Highest quality submission among a set of duplicates unsatisfactory does not satisfy C4 submission criteria; not eligible for awards
Projects
None yet
Development

No branches or pull requests

5 participants