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: arbitrum network cost estimate #464

Closed
wants to merge 4 commits into from
Closed

Conversation

gzeoneth
Copy link
Contributor

@gzeoneth gzeoneth commented Jan 3, 2024

@gzeoneth gzeoneth requested a review from a team as a code owner January 3, 2024 14:57
return {
perL2TxFee: gasData[0],
perL1CalldataFee: gasData[1],
perL1CalldataFee: perL1CalldataByte.div(16),
Copy link
Member

@jsy1218 jsy1218 Jan 4, 2024

Choose a reason for hiding this comment

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

This is great catch! I took a look at OVM_GasPriceOracle, where we borrow the code to calculate L1 gas. Indeed the result has the factor of 16 multiplied.

You might notice that for Arbitrum gas estimate, smart-order-router should use the arbitrum L1 gas estimate, instead of optimism one. As a follow-up, Uniswap internally probably will need to use the gasEstimateL1Component, assuming this is pretty accurate estimate of the calldata costs that Arbitrum Sequencer posts to L1?

Copy link
Contributor Author

@gzeoneth gzeoneth Jan 4, 2024

Choose a reason for hiding this comment

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

that’s correct for a more accurate estimate but would require an extra rpc call, also note that it return in terms of L2 gas which should be multiplied with L2 gas price (instead of L1)

Copy link
Member

Choose a reason for hiding this comment

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

I thought gasEstimateL1Component returns both L1 gas estimate, as well as L2 base fee?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

gasEstimateL1Component returns 3 things

  1. gasEstimateForL1: an estimate of the amount of gas needed for the l1 component of this tx
  2. l2BaseFee: the l2 base fee
  3. l1BaseFeeEstimate: ArbOS's l1 estimate of the l1 base fee

gasEstimateForL1 is how much L2 gas we charge for the L1 calldata cost
so if you want to calculate feeForL1, that would be gasEstimateForL1 * l2BaseFee

Comment on lines -253 to -258
if ([ChainId.ARBITRUM_ONE, ChainId.ARBITRUM_GOERLI].includes(chainId)) {
l2toL1FeeInWei = calculateArbitrumToL1FeeFromCalldata(
route.methodParameters!.calldata,
l2GasData as ArbitrumGasData
)[1];
} else if (
Copy link
Member

@jsy1218 jsy1218 Jan 4, 2024

Choose a reason for hiding this comment

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

I actually think there's no double counting of L1 fees here, although the reason is a bit complex.

You probably noticed two codepaths that invokes calculateGasUsed:

  1. EthEstimateGasSimulator.ethEstimateGas
  2. TenderlySimulator.simulateTransaction

Those two codepaths are actually mutually exclusive to each other, due to the check in FallbackTenderlySimulator.simulateTransaction. Then inside EthEstimateGasSimulator.ethEstimateGas, from Arbitrum doc, I see the node returns the entire transaction fee at the specified L2 gas price. I assume it does not include the L1 calldata posting costs. For Tenderly simulation, I'm a bit less certain if they include the L1 fee as well.

Taking a step back, the change inside calculateGasUsed will likely have no effect, if your experience is such that you notice the abnormally high gas cost using the Uniswap web interface, not mobile, because only mobile requests a best swap quote with simulation, not web interface. The reason is a bit complex.

calculateGasUsed is only going to be invoked when upstream requests smart order router to get a best swap route with forked net simulation. The code is inside AlphaRouter. Majority of the Arbitrum abnormal high gas cost report I see is the web app screenshot, so it means the Arbitrum gas cost is not recomputed inside gas-factory-helpers, but only once inside V3HeuristicGasModelFactory

Copy link
Contributor Author

@gzeoneth gzeoneth Jan 4, 2024

Choose a reason for hiding this comment

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

I assume it does not include the L1 calldata posting costs.

This is incorrect, unlike Optimism, Arbitrum charge L2 gas for L1 calldata posting costs. For example, a normal transfer cost 21000 L2 gas to execute and say 100000 L2 gas for L1 calldata, Arbitrum require the user to sign a transaction with at least 121000 gas to be included onchain. The RPC method "eth_estimateGas" on an Arbitrum node return the TOTAL L2 gas required, that is L2 execution gas + L1 calldata gas which for the above example would be 121000. As far as I know, tenderly also have the same behavior (that the gas estimate include L1 calldata gas)

Copy link
Contributor Author

@gzeoneth gzeoneth Jan 4, 2024

Choose a reason for hiding this comment

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

In fact I don't really see why we need calculateArbitrumToL1FeeFromCalldata anywhere except for display purpose (show user L1 and L2 fee split) because the gas estimation would have returned the total already. Unless you are hardcoding the execution gas somewhere and want to have a more accurate L1 fee added to it.

Copy link
Member

Choose a reason for hiding this comment

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

This is incorrect, unlike Optimism, Arbitrum charge L2 gas for L1 calldata posting costs.

This is good to know. This assumption is embedded in sor gas model. Let me think through how to fix this assumption.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am running the cli quoter, estimatedGasUsed seems to be wrong but I cannot figure out where it come from. If it uses eth_estimateGas it should return a much higher number.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah it does not do eth_estimateGas, it was semi-hardcoded in the gas model

Copy link
Contributor Author

@gzeoneth gzeoneth Jan 4, 2024

Choose a reason for hiding this comment

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

I think I am not familiar with the SOR enough to properly fix this quickly, but would be nice if we can ship the div(16) fix first to make the number at least much more reasonable. Thanks for the quick response btw.

Copy link
Member

Choose a reason for hiding this comment

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

Agree, there's a bit of urgency. Let's ship this tomorrow during EST/PST business hours. I can help create a replicated PR within
https://github.com/Uniswap/smart-order-router, so all the tests should pass.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Cool, feel free to cherrypick my commit

Copy link
Member

Choose a reason for hiding this comment

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

#466 replicated here

@jsy1218
Copy link
Member

jsy1218 commented Jan 4, 2024

This is great stuff, thanks for the PR! Anecdotally, I saw a report, where the smart-order-router computed gas cost is about 130k, meanwhile the actual gas cost should be more than 3m. This means a factor of more than 24. Meanwhile this PR should address some discrepancies, I can see there's more to address.

Most likely the fix will concentrate in V3HeuristicGasModelFactory. One thing on top of my mind is that smart order router does not compress the calldata for any L2 chains, but the L1 format calldata. That obviously will also inflate the gas cost by the compression ratio.

@jsy1218
Copy link
Member

jsy1218 commented Jan 4, 2024

Also would be great if you can add some unit test coverages.

@gzeoneth
Copy link
Contributor Author

gzeoneth commented Jan 4, 2024

This is great stuff, thanks for the PR! Anecdotally, I saw a report, where the smart-order-router computed gas cost is about 130k, meanwhile the actual gas cost should be more than 3m. This means a factor of more than 24. Meanwhile this PR should address some discrepancies, I can see there's more to address.

Most likely the fix will concentrate in V3HeuristicGasModelFactory.

It can be more than 16x because Arbitrum charge L1 calldata gas after compression, the naive 16 gas a bytes formula does not account for that. Using gasEstimateL1Component would give a closer estimate.

Also would be great if you can add some unit test coverages.

Tbh I don't know how to properly test this repo since some unit tests are failing before my changes

@jsy1218
Copy link
Member

jsy1218 commented Jan 4, 2024

Also would be great if you can add some unit test coverages.

Tbh I don't know how to properly test this repo since some unit tests are failing before my changes

We've hardened the repo by adding some test suites in the github CI. In order for all the tests to run successfully from your forked repo, you will need to create new repository secrets, for the following secrets used in https://github.com/Uniswap/smart-order-router/blob/main/.github/workflows/tests.yml:

  JSON_RPC_PROVIDER: ${{ secrets.JSON_RPC_PROVIDER }}
  JSON_RPC_PROVIDER_GORLI: ${{ secrets.JSON_RPC_PROVIDER_GORLI }}
  JSON_RPC_PROVIDER_OPTIMISM: ${{ secrets.JSON_RPC_PROVIDER_OPTIMISM }}
  JSON_RPC_PROVIDER_OPTIMISM_GOERLI: ${{ secrets.JSON_RPC_PROVIDER_OPTIMISM_GOERLI }}
  JSON_RPC_PROVIDER_ARBITRUM_ONE: ${{ secrets.JSON_RPC_PROVIDER_ARBITRUM_ONE }}
  JSON_RPC_PROVIDER_ARBITRUM_GOERLI: ${{ secrets.JSON_RPC_PROVIDER_ARBITRUM_GOERLI }}
  JSON_RPC_PROVIDER_POLYGON: ${{ secrets.JSON_RPC_PROVIDER_POLYGON }}
  JSON_RPC_PROVIDER_POLYGON_MUMBAI: ${{ secrets.JSON_RPC_PROVIDER_POLYGON_MUMBAI }}
  JSON_RPC_PROVIDER_CELO: ${{ secrets.JSON_RPC_PROVIDER_CELO }}
  JSON_RPC_PROVIDER_CELO_ALFAJORES: ${{ secrets.JSON_RPC_PROVIDER_CELO_ALFAJORES }}
  JSON_RPC_PROVIDER_BNB: ${{ secrets.JSON_RPC_PROVIDER_BNB }}
  JSON_RPC_PROVIDER_AVALANCHE: ${{ secrets.JSON_RPC_PROVIDER_AVALANCHE }}
  JSON_RPC_PROVIDER_BASE: ${{ secrets.JSON_RPC_PROVIDER_BASE }}
  TENDERLY_BASE_URL: ${{ secrets.TENDERLY_BASE_URL }}
  TENDERLY_USER: ${{ secrets.TENDERLY_USER }}
  TENDERLY_PROJECT: ${{ secrets.TENDERLY_PROJECT }}
  TENDERLY_ACCESS_KEY: ${{ secrets.TENDERLY_ACCESS_KEY }}

However, I can see a bit urgency in fix the Arbitrum gas estimate, so can help by replicating this PR as a https://github.com/Uniswap/smart-order-router repo, since the repo contains all those secrets already.

Copy link
Contributor

@cgkol cgkol left a comment

Choose a reason for hiding this comment

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

Thank you for the PR!

Shall we also add some unit tests before we go through with this?

@@ -250,12 +250,8 @@ export async function calculateGasUsed(
const gasPriceWei = route.gasPriceWei;
// calculate L2 to L1 security fee if relevant
let l2toL1FeeInWei = BigNumber.from(0);
if ([ChainId.ARBITRUM_ONE, ChainId.ARBITRUM_GOERLI].includes(chainId)) {
l2toL1FeeInWei = calculateArbitrumToL1FeeFromCalldata(
Copy link
Contributor

Choose a reason for hiding this comment

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

can we also delete the function definition since its not used anywhere else?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is exported so idk

Copy link
Member

Choose a reason for hiding this comment

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

Instead of deleting calculateArbitrumToL1FeeFromCalldata, I think we will want to refactor the same code inside V3HeuristicGasModelFactory.

@gzeoneth
Copy link
Contributor Author

gzeoneth commented Jan 4, 2024

pushed some unit test

jsy1218 added a commit that referenced this pull request Jan 4, 2024
jsy1218 added a commit that referenced this pull request Jan 5, 2024
@jsy1218
Copy link
Member

jsy1218 commented Jan 5, 2024

This PR can be closed with the replicated #466

Thank you @gzeoneth again for the contribution!

@jsy1218 jsy1218 closed this Jan 5, 2024
BitAI-dev pushed a commit to BitAI-dev/smart-order-router that referenced this pull request Jan 20, 2025
BitAI-dev pushed a commit to Taiki-ops/smart-order-router that referenced this pull request Jan 20, 2025
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