test(bifrost): run EVMClient against the real V6 router on an in-process EVM chain

Why

!4094 (merged) (EVM Router V6) had two production bugs in bifrost/pkg/chainclients/evm/client.go:

  1. buildOutboundTx estimated gas with a placeholder Value but packed transferOut with the real amount. V6 requires msg.value == amount, so the estimate reverted with "TC:eth amount mismatch" and the outbound was skipped forever.
  2. SignTx estimated a transferFrom before broadcasting the ERC20 approval. The estimate reverted, so the approval was never sent.

unit-tests, test-regression and the router's hardhat tests all passed, and only test-simulation caught them. The httptest mocks return the constant 0x493df for every eth_estimateGas call and never revert.

What

router_simulated_test.go (RouterSimSuite, gocheck)

  • Runs the real EVMClient, built with NewEVMClient and talking plain JSON-RPC over httptest, against the real V6 router (build/scripts/evm/router-bytecode.txt) and test token.
  • Native transferOut: the transaction is signed, broadcast and mined, and the recipient gets exactly the amount.
  • ERC20 transferOut from a vault with no allowance:
    • the first SignTx broadcasts the approval;
    • after a block, the allowance covers the amount;
    • a second SignTx signs, and the transfer executes on-chain.

simchain_test.go

  • A minimal in-process EVM chain that executes transactions and estimates gas with geth's own code over in-memory state, so reverts come back with the real reason.
  • It serves only the eth_ methods the client uses.

Why not ethclient/simulated: op-geth's simulated package imports the full geth node, which would add about 15 indirect modules to go.mod. This test chain needs no go.mod change. The trade-off is that a geth or op-geth bump may break it at compile time.

Mutation checks

  • Reintroduce bug 1: TestNativeTransferOut fails with "SignTx skipped the outbound", and the client logs TC:eth amount mismatch.
  • Reintroduce bug 2: the ERC20 test fails with "SignTx did not broadcast the approval".
  • With either bug in place, the existing mock-based suites still pass. That is the gap this test closes.

Testing

  • go test -tags=mocknet ./bifrost/pkg/chainclients/evm/ -run TestEVMPackage -check.f RouterSimSuite: 2 tests, 1.8 s. Most of that is the client's built-in wait after an approval.
  • Also passes:
    • with -race;
    • without the mocknet tag;
    • the full package (8.4 s);
    • golangci-lint v1.63.4.
  • No production code touched.

🤖 Generated with Claude Code

Merge request reports

Loading
Loading