Skip to content

This is a work-in-progress solidity implementation of IBC Eureka.

License

Notifications You must be signed in to change notification settings

cosmos/solidity-ibc-eureka

Repository files navigation

IBC Eureka in Solidity Github Actions Foundry License: MIT Code Coverage

This is a work-in-progress IBC Eureka implementation in Solidity. IBC Eureka is a simplified version of the IBC protocol that is encoding agnostic.

Overview

solidity-ibc-eureka is an implementation of IBC in Solidity.

Project Structure

This project is structered as a foundry project with the following directories:

  • src/: Contains the Solidity contracts.
  • test/: Contains the Solidity tests.
  • scripts/: Contains the Solidity scripts.
  • abi/: Contains the ABIs of the contracts needed for end-to-end tests.
  • abigen/: Contains the abi generated go files for the Solidity contracts.
  • e2e/: Contains the end-to-end tests, powered by interchaintest.

Contracts

Contracts Description Status
ICS26Router.sol IBC Eureka router handles sequencing, replay protection, and timeout checks. Passes proofs to ICS02Client.sol for verification, and resolves portId for app callbacks. Provable IBC storage is stored in this contract.
ICS02Client.sol IBC Eureka light client router resolves clientId for proof verification. It also stores the counterparty information for each client.
ICS20Transfer.sol IBC Eureka transfer application to send and receive tokens to/from another Eureka transfer implementation.
ICS27Controller.sol IBC Eureka interchain accounts controller.
ICS27Host.sol IBC Eureka interchain accounts host.

Requirements

Foundry typically uses git submodules to manage contract dependencies, but this repository uses Node.js packages (via Bun) because submodules don't scale. You can install the contracts dependencies by running the following command:

bun install

You also need to have the sp1-ics07-tendermint operator binary installed on your machine to run the end-to-end tests. You can install it by running the following command:

just install-operator

Tip

Nix users can enter a development shell with all the necessary dependencies by running:

nix develop

Unit Testing

There are multiple unit tests for the solidity contracts located in the test/ directory. The tests are written in Solidity using foundry/forge.

To run all the tests, run the following command:

just test-foundry

The recipe also accepts a testname argument that will only run the test with the given name. For example:

just test-foundry test_success_sendTransfer

End to End Testing

There are several end-to-end tests in the e2e/interchaintestv8 directory. These tests are written in Go and use the interchaintest library. It spins up a local Ethereum and a Tendermint network and runs the tests found in e2e/interchaintestv8/ibc_eureka_test.go. Some of the tests use the prover network to generate the proofs, so you need to provide your SP1 network private key to .env for these tests to pass.

To prepare for running the e2e tests, you need to make sure you have done the following:

  • Installed the sp1-ics07-tendermint operator binary (see instructions above)
  • Set up an .env file (see the instructions in the .env.example file)
  • If you have made changes to the contract interfaces or types, you need to update the ABIs by running just generate-abi

Note

If you are running on a Mac with an M chip, you will need to do the following:

  • Set up Rosetta

  • Enable Rosetta for Docker (in Docker Desktop: Settings -> General -> enable "Use Rosetta for x86_64/amd64 emulation on Apple Silicon")

  • Pull the foundry image with the following command:

    docker pull --platform=linux/amd64 ghcr.io/foundry-rs/foundry:latest

Running the tests

To run the tests, run the following command:

just test-e2e $TEST_NAME

Where $TEST_NAME is the name of the test you want to run, for example:

just test-e2e TestDeploy

Linting

Before committing, you should lint your code to ensure it follows the style guide. You can do this by running the following command:

just lint

End to End Benchmarks

The contracts in this repository are benchmarked end-to-end using foundry. The following benchmarks were ran with the underlying sp1-ics07-tendermint. About ~230,000 gas is used for each light client verification (groth16), and this is included in the gas costs below for recvPacket, timeoutPacket and ackPacket. At the time of writing, proof generation takes around 1 minute. More granular and in-depth benchmarks are planned for the future.

Single Packet Benchmarks

The following benchmarks are for a single packet transfer without aggregation.

Contract Method Description Gas (groth16) Gas (plonk)
ICS26Router.sol sendPacket Initiating an IBC transfer with an ERC20. ~205,000 ~205,000
ICS26Router.sol recvPacket Receiving back an ERC20 token. ~484,000 ~563,000
ICS26Router.sol recvPacket Receiving a new Cosmos token for the first time. (Deploying an ERC20 contract) ~1,422,000 ~1,510,000
ICS26Router.sol ackPacket Acknowledging an ICS20 packet. ~370,000 ~448,000
ICS26Router.sol timeoutPacket Timing out an ICS20 packet ~458,000 ~545,000

Aggregated Packet Benchmarks

The gas costs are substantially lower when aggregating multiple packets into a single proof, as long as the packets are submitted in the same tx. Since there is no meaningful difference in gas costs between plonk and groth16 in the aggregated case, they are not separated in the table below.

ICS26Router Method Description Avg Gas (25 packets) Avg Gas (50 packets)
multicall/recvPacket Receiving back an ERC20 token. ~204,000 ~197,000
multicall/ackPacket Acknowledging an ICS20 packet. ~116,000 ~110,000

Note: These gas benchmarks are with Groth16.

License

This project is licensed under MIT.

Acknowledgements

This project was bootstrapped with this template. Implementations of IBC specifications in solidity, CosmWasm, golang, and rust were used as references.