Dry run on Ethereum#1711
Conversation
|
Not sure we can use tenderly in our API, Is it free an available for public use? |
Just create a virtual testnet and expose a public endpoint, which can be incrementally synced with the parent (actual) network. I assume the fee is already covered by our team subscription. |
I think we can just use |
It depends on performing an actual dry run to obtain the receipt logs with failure details (indicating which command failed). |
|
@yrong do you want to merge this still? |
Yeah, I’ve resolved the conflicts and still want to merge it. I think it should be valuable for L2 transfers. That said, I’m still planning to set up a local Anvil node and expose it for dry-running, since we canceled the Tenderly subscription to reduce costs, mentioned in #1711 (comment) |
| import type { ToEthereumTransferResult, ToPolkadotTransferResult } from "./history" | ||
|
|
||
| type IGatewayProxy = { | ||
| getFunction(name: "v2_dispatch"): { |
There was a problem hiding this comment.
This should exist on gatewayV2: IGatewayV2, if not you should add it there instead of creating a new interface.
| const forkedProviderApiKey = | ||
| process.env.FORKED_PROVIDER_API_KEY || | ||
| process.env.NEXT_PUBLIC_FORKED_PROVIDER_API_KEY | ||
| const forkedProvider = context.ethereumProvider.createProvider( | ||
| process.env.FORKED_PROVIDER_URL || | ||
| process.env.NEXT_PUBLIC_FORKED_PROVIDER_URL || | ||
| "https://fork-mainnet.snowbridge.network", |
There was a problem hiding this comment.
This needs to be passed in through the registry or config like the subsquid url.
There was a problem hiding this comment.
I assume the API key is a sensitive credential and shouldn't be stored in the registry. Unlike Subsquid, which is effectively read-only, the dry-run node exposes state-mutating methods such as set_storage and set_block_time, so we should protect access to it with an API key.
| logs.push({ | ||
| kind: ValidationKind.Error, | ||
| reason: ValidationReason.FeeEstimationError, | ||
| message: ethereumDryRunError, |
There was a problem hiding this comment.
These error messages are displayed to the user. I rather you console.error the full error message and return a user friendly message here.
| const forkedProviderApiKey = | ||
| process.env.FORKED_PROVIDER_API_KEY || | ||
| process.env.NEXT_PUBLIC_FORKED_PROVIDER_API_KEY | ||
| const forkedProvider = context.ethereumProvider.createProvider( |
There was a problem hiding this comment.
Instead of creating a provider for each transfer can we cache this in the context with all the other connections?
| const forkedProviderApiKey = | ||
| process.env.FORKED_PROVIDER_API_KEY || | ||
| process.env.NEXT_PUBLIC_FORKED_PROVIDER_API_KEY |
There was a problem hiding this comment.
This needs to be provided via the environment config, not env vars. Just like how we get the rpc node url and key.
| const forkedProviderApiKey = | ||
| process.env.FORKED_PROVIDER_API_KEY || | ||
| process.env.NEXT_PUBLIC_FORKED_PROVIDER_API_KEY | ||
| const forkedProvider = context.ethereumProvider.createProvider( |
There was a problem hiding this comment.
This anvil provider should be cached and kept on the context.
There was a problem hiding this comment.
This seems to be a duplicate of the comment at #1711 (comment), and has already been addressed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
During the review, AI identified another issue: the L2 bridge fee shown in the fee breakdown should not be denominated in ETH, but in the transfer asset itself. @alistair-singh Could you take a look and let me know if that makes sense, or whether it would have any impact on how the UI displays fees? |
Dry run on Ethereum
Validates Snowbridge V2 transfers end-to-end by simulating the resulting
Gateway.v2_dispatchagainst a forked Ethereum node, surfacing reverts, CommandFailed events, and L1Adapter DepositCallInvoked / DepositCallFailed outcomes before the user signs anything.For Polkadot → Ethereum (L1 and L2) transfers, after the source / AH / BridgeHub Polkadot dry-runs succeed, the SDK now:
v2_dispatch(commands, agentID, nonce)tx whose commands mirror what the relayer would submit to mainnet (UnlockNativeToken + optional CallContract).FORKED_PROVIDER_URL) using impersonation of the gateway proxy asfrom.CommandFailedevent and the L1 Adapter'sDepositCallInvoked/DepositCallFailedevents, surfacing failures via the existingValidationLogmechanism.Fix fee estimation for parachain→L2 V2 transfers
The SDK's fee estimation XCM used legacy
BuyExecution+InitiateReserveWithdraw, but the Polkadot SDK executor actually insertsPayFees+InitiateTransfer+AliasOrigininto the forwarded XCM. These V5 instructions have significantly higher benchmarked weights (remote_fees handling, asset reanchoring, XCMP queuing), causingqueryWeightToAssetFeeto underestimate fees.buildResultXcmAssetHubERC20TransferFromParachainV2: builds the actual forwarded XCM shape (8 instructions:WithdrawAsset×3,PayFees,AliasOrigin,SetAppendix,InitiateTransfer,SetTopic), matching the executor's output exactly.supportsV2gating: the V2 function is only used for parachains withfeatures.supportsV2: true(currently Hydration 2034).Parachain→L2 transfer support
ERC20FromParachaintransfer class for parachain→L2 routes.erc20ToL2.ts→erc20FromAH.tsrename for consistency.buildRegistry.tsupdated to generate routes for v2-enabled parachains (v2_parachainsconfig).Production test
https://app.snowbridge.network/activity#0x7128106c3cf6c505bc38ce4c58bfa05fded5a73bda54f9b634757627186705be