lib/ibc.sh.
Attestation light client
An attestation light client verifies IBC packets using ECDSA signatures from a registered set of off-chain attestors. There are two implementations: Go (cosmos/ibc-go) for the Cosmos side and Solidity (cosmos/solidity-ibc-eureka) for the EVM side. Each client is initialized with a list of attestor Ethereum addresses and a quorum threshold. When a packet arrives with an attestation proof, the light client:- Validates that the proof value is non-empty and the path has exactly one element.
- Looks up the trusted consensus timestamp stored at
proofHeight. - Decodes the proof into
attestationDataandsignatures. - Recomputes the expected digest:
sha256(0x02 || sha256(attested_data)). - For each signature: recovers the signer address via ECDSA, checks it against the registered attestor set, and rejects duplicates. Verifies that
signatures.length >= minRequiredSigs. - Decodes
attestationDataas aPacketAttestationand verifies the attested height matchesproofHeight. - Checks that the packet commitment is present in the attested packets array, matching on both the keccak256 hash of the path and the commitment value.
What the script does
1. Generate or read the attestor keystore
Both light clients are initialized with the attestor’s Ethereum address. The script first ensures the keystore exists, generating a new one if needed, then reads the address from it:ibc/local/.ibc-attestor/ibc-attestor-keystore and reused by the attestor services started in a later step.
Ethereum addresses configured in the light client must be in EIP-55 checksummed format.
2. Create the Cosmos-side client
The Cosmos-side client verifies EVM packets on the Cosmos chain. It is initialized with:- The attestor’s Ethereum address
- The current EVM block height and timestamp as the initial trusted state
client-state.json(template):
consensus-state.json(template):
COSMOS_CLIENT_ID in the format attestations-N.
3. Create and register the EVM-side client
The EVM-side client verifies Cosmos packets on the EVM chain. It is a Solidity contract (AttestationLightClient) deployed from prebuilt bytecode and registered with the ICS26Router.
The script initializes it with:
- The attestor’s Ethereum address
- The current Cosmos block height and timestamp as the initial trusted state
ICS26Router on the EVM chain. The CounterpartyInfo passed to addClient includes the Cosmos client ID, so the EVM client knows its counterparty at registration time:
EVM_CLIENT_ID, in the format client-N) is assigned by the router on registration.
Output: EVM_CLIENT_ID in the format client-N.
4. Register the Cosmos-side counterparty
With both client IDs now known, the script registers the Cosmos-side counterparty. This is the on-chain record that maps the Cosmos attestation client to its EVM peer:addClient time (the Cosmos client ID is passed in the CounterpartyInfo). The Cosmos client registers its counterparty here after the EVM client ID is known.
Configuration reference
Cosmos client state
Cosmos consensus state
EVM client constructor
Applying this to your own setup
Initial trusted state
The initial height and timestamp anchor the light client to a specific point in the counterparty chain’s history.Quorum threshold
The demo usesmin_required_sigs: 1 because there is a single attestor. For production, set this to the threshold of your attestor set. It is recommended to use a threshold of greater than 1.
roleManager in production
The demo passes address(0) as the roleManager, which allows anyone to submit proofs. For production, pass the ICS26Router proxy address so only the router can submit proofs to the light client.