-
Notifications
You must be signed in to change notification settings - Fork 83
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 WalletConnect eth_signTransaction
requests handling
#1729
Conversation
eth_signTransaction
requests handling
Codecov Report
@@ Coverage Diff @@
## main #1729 +/- ##
==========================================
+ Coverage 76.51% 76.53% +0.02%
==========================================
Files 520 520
Lines 19291 19308 +17
Branches 3520 3521 +1
==========================================
+ Hits 14760 14777 +17
Misses 4459 4459
Partials 72 72
Continue to review full report at Codecov.
|
rawTx.gas = undefined | ||
rawTx.gasPrice = undefined | ||
} | ||
const tx: CeloTx = yield call(normalizer.populate.bind(normalizer), rawTx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though I tested this successfully in real conditions, do we need some gasPrice
inflation somewhere? or does contractkit do the right thing?
The wallet send flow does inflate it using:
wallet/packages/mobile/src/web3/gas.ts
Lines 33 to 47 in 1455340
async function fetchGasPrice(currency: Currency): Promise<BigNumber> { | |
const contractKit = await getContractKitAsync() | |
const [gasPriceMinimum, address] = await Promise.all([ | |
contractKit.contracts.getGasPriceMinimum(), | |
getCurrencyAddress(currency), | |
]) | |
const latestGasPrice = await gasPriceMinimum.getGasPriceMinimum(address) | |
const inflatedGasPrice = latestGasPrice.times(GAS_PRICE_INFLATION_FACTOR) | |
Logger.debug( | |
TAG, | |
'fetchGasPrice', | |
`Result price in ${currency} with inflation: ${inflatedGasPrice.toString()}` | |
) | |
return inflatedGasPrice | |
} |
But I'm not entirely familiar with this matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this eventually makes an eth_gasPrice
RPC call to the supporting Geth node. This will suggest an appropriate gas price, which by default is 5x the GPM. So this seems like it should result in a setting that will work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! Thanks for checking 💪
|
||
rawTx.feeCurrency = feeCurrencyAddress | ||
// Note: we're resetting gas and gasPrice here because if the feeCurrency has changed, we need to recalculate them | ||
rawTx.gas = undefined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One caveat here is that there are cases where gas estimation will fail even if the transaction will end up clearing. Clearing the gas may result in errors for the dApp. E.g. If a dApp developer is doing a two step approve and exchange and requesting both signatures together, they will set the gas on the second transaction because if estimateGas is run before the approve completes, execution will fail.
I saw in the Slack thread there is some mention of estimateGas
being broken for non-CELO fee currencies, but I am not aware of any issue right now. It is true though that using a non-CELO fee currency uses more gas, by about 50k, so if the caller estimates using CELO and this code switches it to cUSD, the transaction may end up with too little gas.
Of these two scenarios, failures due to clearing the gas value seem more likely to me than failures due to not clearing it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting problem, nice catch!
I think not having CELO to pay for gas is a somewhat common situation, especially for Valora users where they are encouraged to cash in cUSD/cEUR and not CELO. dApps are also usually not very good at catching it and show unhelpful errors when this happens.
My point is that the switch from CELO fee to cUSD/cEUR fee might happen somewhat often here. Don't really have the data to back it up, just my intuition (we could look it up).
How about just plain adding 50k to the gas
field when this happens? Would that help solve for both use-cases or are there other complications I might be missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
E.g. If a dApp developer is doing a two step approve and exchange and requesting both signatures together, they will set the gas on the second transaction because if estimateGas is run before the approve completes, execution will fail.
Do you mean that the dapp may call eth_signTransaction
without having called estimateGas on their end and sent individually?
So if it does that for approve and exchange, it will indeed fail for us.
Well, great catch!! 🥇
So yeah ideally we should really not touch what the dapp is providing. But since we have this bug with WalletConnect v1 utils, we have to do something.
I really like what @gnardini is proposing then.
In addition, I'll also limit the workaround to when type
is not set. Because in that case the TX data is sent as is.
See https://github.com/WalletConnect/walletconnect-monorepo/blob/c6b26481c34848dbc9c49bb0d024bda907ec4599/packages/helpers/utils/src/ethereum.ts#L45
Decided against this to avoid surprises for dapp developers. IMHO the feeCurrency adjustment is good to have even if WalletConnect was not stripping any fields. Instead I'm proposing an explicit custom field __skip_normalization
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding 50k to the gas value when setting a non-CELO fee currency seems reasonable. That should be the correct value as it is the value currently set in the intrinsicGasForAlternativeFeeCurrency
on-chain 👌
@jeanregisser I locally brought these changes into the #1412 and the e2e test around sign a transaction is passing. |
// Provide an escape hatch for dapp developers who don't want any normalization | ||
if (rawTx.__skip_normalization) { | ||
// Remove this custom field which may cause issues down the line | ||
delete rawTx.__skip_normalization | ||
tx = rawTx | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't tested this escape hatch end-to-end yet.
Could this cause issues between the dapp and Valora processing it?
Of course because of the WC v1 utils stripping fields, someone wanting to use it would have to set both type
and __skip_normalization
.
I'll document this if we decide this escape hatch is viable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything looks good to be, great job on this!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with two optional comments
const rawTx = { ...params[0] } | ||
let tx | ||
// Provide an escape hatch for dapp developers who don't want any normalization | ||
if (rawTx.__skip_normalization) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will WC strip this field out though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it will for v1 requests, so developers wanting to use it would have to set both type = null
and __skip_normalization
.
@@ -29,14 +36,56 @@ export function* handleRequest({ method, params }: { method: string; params: any | |||
yield call(unlockAccount, account) | |||
|
|||
switch (method) { | |||
case SupportedActions.eth_signTransaction: | |||
return (yield call(wallet.signTransaction.bind(wallet), params[0])) as EncodedTransaction | |||
case SupportedActions.eth_signTransaction: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we normalize eth_send and eth_sign the same way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we should, I'll open a PR applying the same logic to both.
Hey @MuckT we have verified the issue on Latest Android Internal build V:1.24.1 and Latest iOS TestFlight build V:1.24.1 and updated the status in Gsheet Sheet link : https://docs.google.com/spreadsheets/d/15nGo3iJAEVJ76wHae9PvYuWI7S2bovKAQPX_edtwPEI/edit#gid=2037765399 Observation : There is no option to connect wallet to given link and also we would require cREAL for the transaction in our account balance We have raised query for the same : Query link Devices : Google Pixel 2XL(11.0) , Google Pixel (10.0) , iPhone 12(14.7), iPhone 13 Mini (15.1.1) |
Hey @MuckT we have verified the issue on Latest iOS Test Flight build V:1.24.1 and updated the status in Gsheet Sheet link: https://docs.google.com/spreadsheets/d/15nGo3iJAEVJ76wHae9PvYuWI7S2bovKAQPX_edtwPEI/edit#gid=2037765399 Observation : There is no option to connect wallet to given link and also we would require cREAL for the transaction in our account balance We have raised query for the same : Query link Devices: iPhone XS Max (13.5.1) |
Hey @MuckT we have verified the issue on Latest Android Internal release build V:1.24.1 and updated the status in Gsheet Sheet link : https://docs.google.com/spreadsheets/d/15nGo3iJAEVJ76wHae9PvYuWI7S2bovKAQPX_edtwPEI/edit#gid=2037765399 Observation : There is no option to connect wallet to given link and also we would require cREAL for the transaction in our account balance We have raised query for the same : Query link Devices : Samsung Galaxy A8+(8.0) |
Hey @MuckT we have verified the issue on Latest Android Internal Release build V:1.24.1 and updated the status in Gsheet Sheet link: https://docs.google.com/spreadsheets/d/15nGo3iJAEVJ76wHae9PvYuWI7S2bovKAQPX_edtwPEI/edit#gid=2037765399 Observation: There is no option to connect wallet to given link and also we would require cREAL for the transaction in our account balance We have raised query for the same : Query link Devices: Redmi Note 5 Pro (9.0) |
@ValoraQA You can test mento-fi with the pre-release version here: |
Hey @MuckT we have verified the issue on Latest Android Internal Release build and Latest iOS Test Flight Internal Build V:1.24.1 and observed that we are able to swap tokens on "https://mento-fi-q5d61619k-celotools.vercel.app/" Observation: After clicking on "Swap" button it asks the transaction permission twice on the valora app Attachment : mento.mp4 Devices: OnePlus 7T (11.0) , iPhone 13 mini (15.1.1) CC: @jmrossy Thanks..!! |
Description
WalletConnect v1 utils strips some important tx fields (on the dapp side) which prevents
eth_signTransaction
calls from working.See all details in #1559.
Ideally this could/should be fixed in WalletConnect v1 utils too, but it's not clear whether such a fix would be accepted and it may take quite some time before it's released and deployed. We're discussing this in this Slack thread.
Working around it in Valora fixes the issue directly and also ensures we're more robust with missing or incorrect tx params.
Note: I'll open another PR to re-use the same logic for
eth_sendTransaction
. That one already works but the new logic added ineth_signTransaction
is a bit better and should be shared.Tested
How others should test
See above.
Related issues
Backwards compatibility
Yes