MetaMask / metamask-mobile

Mobile web browser providing access to websites that use the Ethereum blockchain
https://metamask.io
Other
2.11k stars 1.09k forks source link

1) Appending bytes to tx payload in `data` field scrambles e.g. displayed ERC20 transfer value & using `sendTransaction` to transfer ERC20s results in contract deployment #2744

Closed hilmarx closed 2 years ago

hilmarx commented 3 years ago

Describe the bug:

When sending transactions on Ethereum, e.g. an ERC transfer, you can append bytes to the encoded transfer payload. This is used by dApps to enrich the information of certain transactions with additional data. In our case, it is used to later verify on-chain that certain data which was appended to a regular ERC20 transfer was indeed signed by the user or not.

It can look something like this:


const erc20Interface = new ethers.utils.Interface(["function transfer(address recipient, uint256 amount)"])

const encodedData = erc20Interface.encodeFunctionData("transfer", [receiver, inputAmount])

const appendedData = new ethers.utils.AbiCoder().encode(
        ["address", "uint256"],
        [toCurrency, minimumReturn]
);

const concatData = encodedData + appendedData.substr(2)

const res = await provider.getSigner().sendTransaction({
        data: concatData,
        to: fromCurrency,
        gasLimit: 100000,
})

On desktop using Metamask or any other wallet, this works fine. However on Metamask mobile, the extra data which was appended to the regular erc20 encoded data seems to completely mess with the transaction, leading to the amount to be transferred to be completely messed up (Very dangerous) and the to field being undefined, resulting in the transaction trying to deploy a contract.

Screenshots

How it should look like: IMG_1733

How it actually looks like: IMG_1732

=> Sending this transaction will result in a contract being deployed which fails.

To Reproduce Check out this codebase of using sendTransaction with a regular erc20 transfer payload (without appended data):

https://github.com/gelatodigital/sorbet-finance/blob/288c42f1dbb786d510265b95aad0cff164a47607/src/components/ExchangePage/index.jsx#L617-L625

You can try it out here: https://sorbet-finance-git-fix-metamask-mobile-bug-gelato.vercel.app

It works fine, however defeats the purpose of the dApp (we need to append some additional payload to the data)

Now, check out this codebase, where we do append additional payload to the data field: https://github.com/gelatodigital/sorbet-finance/blob/fe8e198d5d2d4c32d0a838b6b9e696c5bd04e496/src/components/ExchangePage/index.jsx#L617-L630

You can try it out here: https://sorbet-finance-git-fix-metamask-mobile-bug-2-gelato.vercel.app

There you will see the bug occurs. As mentioned before, on Web Metamask and using other Wallets such as Formatic, it works fine. This issue also occurs on Mainnet, not only Matic.

Smartphone

EDIT:

Replying to @MaartenWeber14 comment.

I just checked again and I think you are right, I am talking about two separate issues here.

Issue 1) If you append data to the e.g. transfer payload, the displayed values of how will be transferred get completely scrambled as seen in the screenshots of my original comment above.

Issue 2) If you use sendTransaction, even if you dont append any extra bytes to the payload, the to address is interpreted as undefined and a contract gets deployed instead of the to address being the ERC20 token.

EerieEight commented 3 years ago

Hey all! Half of our users come through MM mobile and this issue is directly affecting them, as well.

MaartenWeber14 commented 3 years ago

@hilmarx are you sure this is caused by appending bytes to the encoded transfer payload? We are experiencing the same issue it seems. Whenever we try to transfer an amount, MM mobile says it's a transfer. But when you accept the tranfer, it tries to deploy a new contract. When inspecting the transaction, the payload is fine, but it seems the to address has been set to undefined indeed, resulting in a failed contract deployment.

However, we aren't appending anything to the payload (as far as I know). We also only have this issue on mobile. On web it works as it should. For reference, we're using WalletConnect to connect to MM and do the transfer.

Hope this thing can be fixed/cleared up soon, as MM is used by a lot of users.

hilmarx commented 3 years ago

@MaartenWeber14 thanks for your comment, you are right, I added an EDIT to my original comment above.

Gazoh commented 3 years ago

Is there any updates or workarounds?

gitpusha commented 3 years ago

Yeah would also be keen to get an update on this!

ooGwei commented 3 years ago

Still affected by this bug and appreciate any workarounds as it is directly preventing Mobile users from using a portion of a platform.

DeepakMotamarri commented 3 years ago

Appreciate any workarounds or updates on this issue

hsnGh67 commented 3 years ago

It's very important issue. No updates yet?

CodeXSky commented 3 years ago

It still have this problem when send token erc20 through walletconnect service by web3js. Anyone have solution for that?

quan32 commented 3 years ago

This bug is so serious, please update ASAP. Anyone have any temporary solution for this?

scrubotage commented 3 years ago

Following up to see if this has been addressed yet. This is impacting countless users.

1brahimsaid commented 3 years ago

Hi this issue has been plaguing me for weeks, it would be great if we could solve this soon. For now I have to use my PC each time to do this same thing I enjoy on mobile.

midas104 commented 3 years ago

This issue is caused by code that substitute value and to transaction properties by encoded transfer data(this one)

The easiest fix is to introduce case insensitive search here because contract map has vary case keys.

Possible fix

// `to` is lowercased on line #316
let asset = props.tokens.find(({ address }) => address.toLowerCase() === to);
if (!asset) {
  // try to lookup contract by lowercased address `to`
  asset = contractMap[Object.keys(contractMap).find(key => key.toLowerCase() === to) || ''];
  if (!asset) {
    try {
      asset = {};
      asset.decimals = await AssetsContractController.getTokenDecimals(to);
      asset.symbol = await AssetsContractController.getAssetSymbol(to);
      // adding `to` here as well

      asset.to = to;
    } catch (e) {
      // This could fail when requesting a transfer in other network
      // adding `to` here as well
      asset = { symbol: 'ERC20', decimals: new BN(0), to: to };
    }
  }
}
midas104 commented 3 years ago

PS My dApp is affected when try to submit transaction via WalletConnect

0xBebis commented 3 years ago

facing same issue

leon-do commented 3 years ago

same issue. waiting for a solution.

zmyqucai8 commented 3 years ago

This is a very serious problem why not solve it first?😅

mobularay commented 3 years ago

Treat this ticket to represent the 1st issue; @gantunesr will create a separate ticket for the 2nd issue. ]

Estimation for this ticket represents the 1st issue.

LouiseCat commented 3 years ago

same issue. waiting for a solution.

ptorrent commented 3 years ago

any news ?

Yuaimin commented 3 years ago

the problem is too fatal!

llioor commented 3 years ago

Big number issue? Community? +1

EtienneHelfer commented 3 years ago

Any news ? this is a huge problem and should be easy to fix

mobularay commented 3 years ago

@Hilmarx @MaartenWeber14

Thanks to your investigation and clarification with the last section of the ticket description:

Issue 1) If you append data to the e.g. transfer payload, the displayed values of how will be transferred get completely scrambled as seen in the screenshots of my original comment above.

Issue 2) If you use sendTransaction, even if you dont append any extra bytes to the payload, the to address is interpreted as undefined and a contract gets deployed instead of the to address being the ERC20 token.

Thank you for your patience and understanding. Pls keep an eye for the version updates in the next 2-4 weeks, and let us know if you encounter these issues again after upgrading to these version(s) starting mid next week.

hilmarx commented 3 years ago

sweet!

MaartenWeber14 commented 3 years ago

Thanks for the update! Looking forward to it.