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

Add 1wei tolerance for bad token detection #2892

Merged
merged 3 commits into from
Aug 15, 2024

Conversation

fleupold
Copy link
Contributor

Description

This is a pretty hacky PR, but given that we didn't manage to get rid of bad token detection in the last quarter and it's not clear when we will find the ressources for it, I feel the impact this change can have may be worth its ugliness.

There are a lot of tokens (e.g. stETH, eUSD, oETH, etc.) whose transfer logic is based on "shares" (cf. eUSD transfer implementation). The logic to convert shares into token amounts requires a division which can lead to off by one error:

Relevant solidity code
function balanceOf(address _account) public view returns (uint256) {
        return getMintedEUSDByShares(_sharesOf(_account));
    }

function _transfer(
        address _sender,
        address _recipient,
        uint256 _amount
    ) internal {
        uint256 _sharesToTransfer = getSharesByMintedEUSD(_amount);
        _transferShares(_sender, _recipient, _sharesToTransfer);
        emit Transfer(_sender, _recipient, _amount);
        emit TransferShares(_sender, _recipient, _sharesToTransfer);
    }

function getMintedEUSDByShares(
        uint256 _sharesAmount
    ) public view returns (uint256) {
        uint256 totalSharesAmount = _getTotalShares();
        if (totalShares == 0) {
            return 0;
        } else {
            return
                _sharesAmount.mul(_getTotalMintedEUSD()).div(totalSharesAmount);
        }
    }

function getSharesByMintedEUSD(
        uint256 _EUSDAmount
    ) public view returns (uint256) {
        uint256 totalMintedEUSD = _getTotalMintedEUSD();
        if (totalMintedEUSD == 0) {
            return 0;
        } else {
            return _EUSDAmount.mul(_getTotalShares()).div(totalMintedEUSD);
        }
    }

Consider the following example:

  • totalMintedEUSD: 100
  • total shares: 50
  • balanceOf(A) = 4 shares = 8 eUSD

Transferring 3 eUSD would lead to transferring 1 share (3 * 50 / 100). After the transfer the user therefore has 5 shares = 10 eUSD (5 * 100 / 50) which is not in line with our expectation (8 + 3 = 11). This 1 wei discrepency is causing the bad token detector to fire.

Changes

  • Pass the balance check if the observed balance is not more than 1 wei less than expected (this also allows higher balances)

How to test

Not sure if this warrants an e2e test in and of itself (I assume it will be quite involved to deploy the token as in the example)? For now I would rely on the existing unit tests. In particular

cargo test -p shared mainnet_tokens -- --nocapture --ignored

now shows 0x0aacfbec6a24756c20d41914f2caba817c0d8521 as supported 💪

@fleupold fleupold requested a review from a team as a code owner August 14, 2024 12:53
Comment on lines 197 to 201
if balance_after_in
< computed_balance_after_in
.checked_sub(U256::one())
.unwrap_or_default()
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is equivalent

Suggested change
if balance_after_in
< computed_balance_after_in
.checked_sub(U256::one())
.unwrap_or_default()
{
if balance_after_in < computed_balance_after_in.saturating_sub(U256::one()) {

Copy link
Contributor

@sunce86 sunce86 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lg. Not sure how easy would be to write a unit test to confirm behaviour.

@MartinquaXD
Copy link
Contributor

The first idea I had was to create a forked e2e test that tries to trade the problematic token. But TBH I wouldn't worry about it given that we execute these code paths A LOT and the unit test confirms the token is okay now.

@fleupold
Copy link
Contributor Author

Lg. Not sure how easy would be to write a unit test to confirm behaviour.

There is an integration test, which has a token that was bad before and is now supported.

Copy link
Contributor

@squadgazzz squadgazzz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@fleupold fleupold merged commit f2907e8 into main Aug 15, 2024
10 checks passed
@fleupold fleupold deleted the one_wei_tolerance_in_bad_token_detection branch August 15, 2024 07:59
@github-actions github-actions bot locked and limited conversation to collaborators Aug 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants