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

fix: handle multicall revert in TokenBalancesController #5083

Merged
merged 2 commits into from
Dec 19, 2024

Conversation

bergeron
Copy link
Contributor

Explanation

When fetching erc20 token balances via the multicall3 contract, there's a case where the call can revert. Even though we pass requireSuccess=false to tryAggregate, this does not catch all errors. Specifically, trying to execute code on a target address that is not a smart contract.

There were some cases where users had tokens added with address 0x0000000000000000000000000000000000000000 which caused such a revert, preventing balances fetches from other tokens.

In addition to migrating out of state tokens we can detect as invalid, the fix here is to fallback to parallel balanceOf calls if the multicall request reverts.

References

Changelog

@metamask/assets-controllers

  • FIXED: TokenBalancesController was fixed to fetch erc20 token balances even if there's an invalid token in state whose address does not point to a smart contract.

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've highlighted breaking changes using the "BREAKING" category above as appropriate
  • I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes

@bergeron bergeron requested a review from a team as a code owner December 19, 2024 17:26
Comment on lines +407 to +410
!error ||
typeof error !== 'object' ||
!('code' in error) ||
error.code !== 'CALL_EXCEPTION'
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like a complicated condition. Could you elaborate a bit on your code comment on line 404 to better explain what these conditions represent?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Trying to only retry if the call reverted, and not retry on other kinds of errors that could occur. I don't know exactly what I expect those errors to be, but could be like a dead rpc connection or something.

Copy link
Contributor

@gambinish gambinish left a comment

Choose a reason for hiding this comment

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

Approved, but could you elaborate a bit on your if condition before merging plz?

@bergeron bergeron merged commit 9e83960 into main Dec 19, 2024
120 checks passed
@bergeron bergeron deleted the brian/multicall-revert branch December 19, 2024 18:29
github-merge-queue bot pushed a commit to MetaMask/metamask-extension that referenced this pull request Dec 19, 2024
## **Description**

Fixes an issue where erc20 token balances were incorrectly showing 0. On
the repro we have, we noticed a token in state with address
`0x0000000000000000000000000000000000000000` on mainnet, which is not a
valid erc20 token. This caused the multicall to revert, preventing other
balances from updating.

There's a fix in the controller here:
MetaMask/core#5083 which will fall back to
parallel `balanceOf` calls if the multicall reverts.

And we're also doing a migration here to remove zero address tokens on
mainnet.

[![Open in GitHub
Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29361?quickstart=1)

## **Related issues**

## **Manual testing steps**

The current version of the wallet should not allow importing an invalid
erc20 address through any mechanism, so not easy to reproduce naturally.

The migration can be tested by checking out an older version like `git
checkout v12.9.0 `, upgrading to this branch, verifying the migration
ran in background logs, and that your tokens remain.

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
bergeron added a commit to MetaMask/metamask-extension that referenced this pull request Dec 19, 2024
Fixes an issue where erc20 token balances were incorrectly showing 0. On
the repro we have, we noticed a token in state with address
`0x0000000000000000000000000000000000000000` on mainnet, which is not a
valid erc20 token. This caused the multicall to revert, preventing other
balances from updating.

There's a fix in the controller here:
MetaMask/core#5083 which will fall back to
parallel `balanceOf` calls if the multicall reverts.

And we're also doing a migration here to remove zero address tokens on
mainnet.

[![Open in GitHub
Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29361?quickstart=1)

The current version of the wallet should not allow importing an invalid
erc20 address through any mechanism, so not easy to reproduce naturally.

The migration can be tested by checking out an older version like `git
checkout v12.9.0 `, upgrading to this branch, verifying the migration
ran in background logs, and that your tokens remain.

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

<!-- [screenshots/recordings] -->

<!-- [screenshots/recordings] -->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants