feat(cardano): add Cardano chain support (Gateway) + Mithril-based 08-cardano light client#4429
Open
floor-licker wants to merge 57 commits intoinformalsystems:masterfrom
Open
Conversation
- Add crates/cardano-chain to Hermes workspace - Create CardanoChainEndpoint skeleton implementing ChainEndpoint trait - Define Cardano IBC types (Header, ClientState, ConsensusState) - Implement CIP-1852 key derivation in CardanoKeyring - Implement transaction signing with Pallas CBOR parsing - Create Gateway gRPC client with stub implementations - Add Cardano variant to ClientType enum in ibc-relayer-types - Add Cardano client prefix '08-cardano' to identifier resolution This is the foundational skeleton with ~50 ChainEndpoint methods. Most methods are stubbed with todo!() or warning logs. Compilation errors expected - will be fixed incrementally. Next steps: - Fix compilation errors (imports, trait implementations) - Implement bootstrap() for chain initialization - Wire up Gateway protobuf definitions - Implement query methods - Implement transaction submission flow
- Fix alloc::sync::Arc → std::sync::Arc - Fix Blake2b256 import to use blake2::digest::Digest - Fix tiny_bip39 module resolution - Add missing ChainEndpoint methods (ICS-29, ICS-31, ICS-28, channel upgrades) - Correct method signatures for query_upgrade, query_upgrade_error, query_ccv_consumer_id - Fix Header trait client_type() to return ClientType enum instead of String - Fix Specs construction to use Specs::Cosmos variant - Add ibc-proto dependency Remaining work: - Implement SigningKeyPair trait for CardanoSigningKeyPair - Implement ConsensusState trait for CardanoConsensusState - Implement ClientState trait for CardanoClientState - Add From trait implementations for AnyClientState/AnyConsensusState - Add Serialize/Deserialize derives
…ports - Import CrossChainQueryRequest from ibc_relayer::chain::requests - Expand wildcard import to explicit request type imports for clarity - Fix cross_chain_query method signature Remaining compilation errors down to core trait implementations: - SigningKeyPair trait for CardanoSigningKeyPair - ConsensusState trait for CardanoConsensusState - ClientState trait for CardanoClientState - From traits for Any* conversions - Serialize/Deserialize derives
- Create signing_key_pair.rs with full SigningKeyPair trait implementation - Add Serialize/Deserialize support with lazy keyring initialization - Add Clone and Debug derives to CardanoKeyring - Implement from_key_file and from_mnemonic methods - Add proper account() and sign() implementations - Include comprehensive tests for creation, signing, and serialization - Remove QueryApplicationStatusRequest from imports (doesn't exist in Hermes) - Add hdpath workspace dependency SigningKeyPair trait errors now resolved. Remaining work: - Fix Blake2b256 import in signer.rs - Fix tiny_bip39 imports in keyring.rs - Implement ConsensusState trait for CardanoConsensusState - Implement ClientState trait for CardanoClientState - Add From trait implementations for Any* conversions
- Implement ConsensusState trait for CardanoConsensusState - Add client_type(), root(), and timestamp() methods - Use lazy_static for CommitmentRoot (temporary solution) - Implement ClientState trait for CardanoClientState - Add chain_id(), client_type(), latest_height(), frozen_height(), expired() methods - Use ChainId::from_string() for proper chain ID construction - Fix KeyringError constructor calls (use encode() instead of key_generation()) - Add lazy_static dependency Next: Add Cardano variants to AnyClientState and AnyConsensusState enums in relayer crate
…on issues - Add any_conversions.rs with stub From<CardanoClientState> for AnyClientState - Add stub From<CardanoConsensusState> for AnyConsensusState - Fix Blake2b256 import (use Blake2b512 and take first 32 bytes) - Fix Pallas KeepRaw immutability by reconstructing MintedWitnessSet - Remove plutus_v3_script field (not in Pallas 0.30) - Fix tiny-bip39 package name in Cargo.toml Note: Stub implementations panic if called - proper solution requires: 1. Moving Cardano types to ibc-relayer-types 2. Adding Cardano variants to Any* enums in ibc-relayer 3. Avoiding circular dependency Remaining: 9 type mismatch errors in Error and KeyringError constructors
…or config calls to use ConfigError wrong_type, fixing KeyringError constructors to use invalid_mnemonic and key_not_found, fixing Pallas Nullable type handling using pattern matching instead of is_some, rewriting transaction signing to manually encode CBOR witness set, fixing test assertion for ChainId comparison, removing unused imports and unnecessary mut in test, resulting in zero compilation errors and all ten tests passing with ChainEndpoint trait fully implemented, SigningKeyPair trait complete with serialization, ConsensusState and ClientState traits implemented, CIP-1852 key derivation working, and transaction signing with Pallas CBOR working
…ig in ibc-relayer/src/chain/cardano/config.rs, adding Cardano variant to ChainConfig enum, updating all ChainConfig match statements to handle Cardano, adding Cardano to config deserializer with type equals Cardano, implementing required config methods for id, packet_filter, max_block_time and other interface methods, adding stub for ChainRuntime spawn which returns error until CardanoChainEndpoint is fully implemented, ensuring ibc-relayer builds successfully with all non-exhaustive pattern matches resolved
… Cardano-specific config from ChainConfig enum, initializing Gateway gRPC client with async connection to gateway URL, setting up KeyRing for Cardano signing key pairs using Ed25519 with addr prefix for Cardano addresses, implementing id and config methods to return chain identifier and config respectively, adding humantime-serde dependency for duration serialization, successfully bootstrapping Cardano chain endpoint with Gateway client and keyring ready for IBC operations
…oChainEndpoint, implementing query_application_status to retrieve latest chain height and timestamp from Gateway, implementing query_client_state to fetch and convert Cardano client state to AnyClientState, implementing query_consensus_state to retrieve consensus state at specific heights, implementing get_signer to extract Cardano address from keyring as Signer, implementing get_key to retrieve signing key pair from keyring using configured key name, adding tendermint dependency for timestamp handling, using FromStr trait to construct Signer from Cardano address string, converting Time to Timestamp for ChainStatus, successfully enabling Hermes to query Cardano chain state and access signing keys for transaction operations
…pendency resolution, adding detailed documentation in cardano module explaining why CardanoChainEndpoint cannot be directly imported into ibc-relayer due to circular dependency between ibc-cardano-chain and ibc-relayer crates, updating spawn.rs to provide clear error message directing users to run ibc-cardano-chain binary separately or integrate at application level, documenting three integration options including standalone binary, future plugin system, and workspace-level binary approach, ensuring ibc-relayer builds successfully while acknowledging architectural constraint that prevents direct ChainRuntime spawning for Cardano within Hermes library itself
…r following Penumbra pattern, move all Cardano code from separate crate into crates/relayer/src/chain/cardano/, implement CardanoChainEndpoint with Gateway client integration for UTXO queries, add CIP-1852 key derivation with slip10, implement Pallas-based transaction signing and CBOR parsing, register Cardano client type and update spawn system to properly instantiate Cardano chains, add Cardano variants to AnyClientState and AnyConsensusState enums, update all CLI commands and test framework to handle Cardano configuration
…_and_wait_commit with transaction building and signing flow, build_client_state for Cardano light client initialization with Mithril genesis key, build_header with Mithril certificate fetching from Gateway, verify_header with Mithril proof verification logic, query methods for balance, connections, channels, and packet commitments with proper async Gateway integration, add type conversion stubs for CardanoSigningKeyPair and CardanoHeader to Any types pending upstream enum support
… AnySigningKeyPair and AnyHeader, resolve architectural constraints for Hermes integration by placing types in correct crates to avoid circular dependencies
… non-exhaustive pattern match error in header processing
…n, add tonic-build for Cardano-specific proto compilation, implement query methods for client state connections channels and packets using ibc-proto types, implement signed transaction submission via CardanoMsg service, update endpoint to use new Gateway API
…p, log Gateway events for debugging, document required steps for converting Gateway events to IbcEventWithHeight
…nd header, add QueryConsensusStateRequest with revision number and height parameters, document custom proto generation requirements for BlockData endpoint, enhance balance query to extract address from keyring, add comprehensive TODO comments for proto parsing and UTXO balance aggregation
…ril_certificate methods, document required Msg service proto generation for CreateClient UpdateClient ConnectionOpen ChannelOpen RecvPacket Acknowledgement and Timeout messages, explain Mithril certificate fetching workflow including certificate chain verification and caching strategy, list all Gateway Msg services that need gRPC client generation
…dd Query service protos for BlockData and LatestHeight endpoints, add Msg service protos for CreateClient UpdateClient ConnectionOpen and ChannelOpen operations, compile five proto files including cardano tx client query connection tx and channel tx protos, enable full gRPC client generation for all Gateway services
…3 dependency to match prost version, update generated module exports to include all IBC core services (client connection channel commitment), add Cosmos dependencies (base query ics23 upgrade) and Google API protos, successfully compile all generated gRPC client code
…mport GenClientMsgClient GenConnectionMsgClient and GenChannelMsgClient from generated protos, add comprehensive message routing documentation for CreateClient UpdateClient ConnectionOpen ChannelOpen RecvPacket and Acknowledgement operations, create client instances for all three Msg services ready for message dispatch implementation
…e_url-based message dispatch for all IBC operations, implement CreateClient and UpdateClient handlers with proto deserialization and gRPC calls, implement all four ConnectionOpen handlers (Init Try Ack Confirm) with GenConnectionMsgClient, implement all four ChannelOpen handlers plus RecvPacket Acknowledgement and Timeout with GenChannelMsgClient, decode protobuf messages using prost Message trait, route to appropriate Gateway Msg service based on message type_url, add comprehensive error handling for unsupported message types
…ssage types, extract unsigned_tx from google.protobuf.Any value field in CreateClient and UpdateClient responses, extract unsigned_tx from all ConnectionOpen responses (Init Try Ack Confirm) with proper connection_id logging, extract unsigned_tx from all ChannelOpen responses with port_id and channel_id logging where available, extract unsigned_tx from packet message responses (RecvPacket Acknowledgement Timeout) with sequence number logging, add comprehensive error handling for missing unsigned_tx fields, convert CBOR hex from UTF-8 bytes with proper error messages, fix borrow checker issues by extracting packet sequence before moving msg into request, complete Phase 5 message routing and CBOR extraction pipeline
…, create comprehensive event_parser module with support for all IBC event types (client connection channel packet), parse Gateway Event and EventAttribute proto messages into Hermes IbcEvent enum variants, implement attribute extraction and parsing for ClientId ConnectionId ChannelId PortId Height Timestamp and Packet fields, add event type mapping for CreateClient UpdateClient UpgradeClient ClientMisbehaviour events, add event type mapping for ConnectionOpenInit ConnectionOpenTry ConnectionOpenAck ConnectionOpenConfirm events, add event type mapping for ChannelOpenInit ChannelOpenTry ChannelOpenAck ChannelOpenConfirm ChannelCloseInit ChannelCloseConfirm events, add event type mapping for SendPacket ReceivePacket WriteAcknowledgement AcknowledgePacket TimeoutPacket events, integrate event parser into send_messages_and_wait_commit pipeline, convert custom IbcEvent structs to proto Event format for parsing, wrap parsed events with IbcEventWithHeight, add EventAttribute error variant to Cardano error enum, complete Phase 7 event parsing implementation
…to_parser module to handle google.protobuf.Any deserialization, implement parse_client_state_from_any to extract CardanoClientState from JSON-serialized Any messages, implement parse_consensus_state_from_any to extract CardanoConsensusState with root timestamp slot and epoch fields, update query_latest_height to use real gRPC QueryLatestHeightRequest with height extraction, update query_client_state to parse client_state from Any proto message using proto_parser, update query_consensus_state to parse consensus_state from Any proto message, convert ibc_proto::Any to prost_types::Any for proto_parser compatibility, add comprehensive error handling for missing fields and invalid data, add unit tests for proto parsing functions, complete Phase 6 tasks 1-3 for BlockData ClientState and ConsensusState parsing
… update query_connection to call Gateway and decode QueryConnectionResponse with ConnectionEnd parsing and MerkleProof extraction, update query_channel to call Gateway and decode QueryChannelResponse with ChannelEnd parsing and proof support, update query_packet_commitment to call Gateway and decode QueryPacketCommitmentResponse with commitment bytes and proof, convert domain types (ConnectionId ChannelId PortId) to strings for Gateway API calls, parse protobuf responses using prost Message decode, convert ibc_proto MerkleProof to domain MerkleProof using From trait, add comprehensive error handling for missing fields and decode failures, complete Phase 6 tasks 4-6 for Connection Channel and Packet query parsing
… testnet-6 integration, define Cardano chain configuration with Gateway gRPC endpoint CIP-1852 key derivation and trust threshold, define Cheqd chain configuration with RPC and gRPC endpoints account prefix and gas settings, configure packet filtering for transfer port, add comprehensive documentation for all configuration parameters
…lemetry port conflict by moving telemetry to port 3002, ensure Hermes can successfully connect to Gateway for health checks
…os SDK pattern, add CardanoSigningKeyPair support to keys add command with CIP-1852 mnemonic derivation, add CardanoSigningKeyPair support to keys list command with proper KeyRing type annotation, implement from_mnemonic and from_key_file methods for CardanoSigningKeyPair trait, add Serialize and Deserialize derives to CardanoSigningKeyPair for JSON key file storage, store keys in Test backend at ~/.hermes/keys/cardano-testnet/keyring-test/ directory, fix config.rs list_keys to instantiate KeyRing with CardanoSigningKeyPair type parameter, fix proto_parser test assertion to use ChainId to_string method, fix event_parser unused height parameter warning, fix config.rs test to handle Cardano variant in excluded_sequences match
…ect local development network
…g, add query_packet_commitments to retrieve all packet commitments with sequences and height, add query_packet_receipt to verify packet delivery with proof support, add query_packet_acknowledgement to retrieve single acknowledgement with proof support, add query_packet_acknowledgements to retrieve all acknowledgements with sequences and height, add query_unreceived_packets to filter packets not yet received on destination chain, add query_unreceived_acknowledgements to filter acknowledgements not yet received on source chain, add query_next_sequence_receive to track expected next packet sequence number with proof support, implement all Gateway client methods with proper protobuf encoding following existing query_packet_commitment pattern, implement all endpoint methods with async Gateway calls and response parsing, enable critical packet relaying functionality required for full IBC communication between Cardano and Cosmos chains
…eration, add query_clients to retrieve all IBC client states enabling client discovery across chains, add query_connections to retrieve all connection ends enabling connection enumeration, add query_channels to retrieve all channel ends enabling channel discovery, add query_client_connections to retrieve connection IDs associated with specific client enabling client-to-connection mapping, add query_connection_channels to retrieve channel ends associated with specific connection enabling connection-to-channel mapping, implement all Gateway client methods with proper protobuf request encoding and response handling following existing query pattern, implement all endpoint methods with async Gateway calls, response decoding, and domain type conversion with error filtering, enable critical IBC primitive discovery functionality bringing Cardano to feature parity with Cosmos SDK chains for relayer operations
… automated IBC packet relaying, add CardanoEventSource with configurable polling interval to query Gateway for new IBC events, add query_events method to GatewayClient to fetch events since a given height with placeholder response types pending Gateway implementation, implement subscribe and init_event_source methods in CardanoChainEndpoint following Cosmos RPC polling pattern, add event_poll_interval configuration option with 5 second default to CardanoConfig, add public TxEventSourceCmd constructor to enable event source creation from external modules, export event_source module in cardano mod for visibility, fix Sequence dereference errors in unreceived packet queries to resolve compilation issues, enable real-time IBC event monitoring foundation for automatic packet relaying between Cardano and Cosmos chains once Gateway event endpoint is implemented
Replaced stub query_events implementation with actual gRPC call to Gateway's new event endpoint, updated build.rs to include cardano query.proto and core types.proto for protobuf generation, added ibc.core.types.v1 module to generated mod.rs to expose ResponseDeliverTx and Event types, updated CardanoEventSource to convert ibc.core.types.v1.Event to ibc.cardano.v1.Event format for event parser compatibility, implemented event flattening from ResponseDeliverTx to extract all IBC events per block
…ctions by updating CBOR encoding, adding bech32 private key support to bypass mnemonic derivation incompatibility, and fixing keyring type casting in endpoint
…mes relayer for Cardano IBC client updates, adding full domain and protobuf types for MithrilHeader with Any encode/decode support, wiring the new 2000-cardano-mithril client type through ClientType and AnyHeader enums, implementing Gateway-side header fetching via the IBCHeader gRPC query, and connecting CardanoChainEndpoint::build_header to return Mithril headers for client update operations
…nd light client architecture
…for IBC state verification, adding proof return support to query_client_state and query_consensus_state when requested, implementing query_channel_client_state via the Gateway's ChannelClientState RPC, adding query_consensus_state_heights with fallback to ConsensusStates, implementing query_txs and query_packet_events using Gateway's TransactionByHash and BlockResults endpoints with event filtering, and updating health_check to actively ping the Gateway and return proper health status on failure
…nd_messages_and_wait_check_tx to prevent async sender hard-failures, enabling query_txs for Client requests at QueryHeight::Latest by scanning recent Gateway events which unblocks ForeignClient::fetch_update_client_event and RelayPath::update_height, adding BlockSearch pagination support via query_block_search_all for packet event queries, and updating query_application_status to prefer chain-derived timestamps from headers with a safe fallback
…int by implementing event parsing for timeout_on_close_packet events with unit tests, adding Gateway client handlers for MsgChannelCloseInit and MsgChannelCloseConfirm to build channel closing transactions, and implementing MsgTimeoutOnClose transaction building for handling packet timeouts due to channel closure
Author
|
Hey @gjermundgaraba, just wondering if you might be able to take a look at this |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
cc: @fabianbormann , @nemo83 , @cardano-foundation
This PR adds a Cardano chain backend to Hermes enabling Hermes to relay IBC between Cosmos chains and Cardano.
The Cardano backend integrates through a gRPC API that exposes the Cosmos-style IBC query surfaces and transaction submission, so Hermes can implement the standard
ChainEndpointresponsibilities (queries, proofs, message building, event parsing) without requiring Cardano full-node semantics inside Hermes itself. On the light-client side, the Cosmos chain tracks Cardano using client type 08-cardano with Mithril headers (/ibc.lightclients.mithril.v1.MithrilHeader).I will avoid doing a deep dive on Mithril and Cardano consensus dynamics in this PR, but the Mithril header carries the evidence needed to authenticate a HostState update transaction, from which the verifier can extract the committed
ibc_state_rootused for IBC membership and non-membership. Once that root is known, membership and non-membership checks follow the standard ICS-23 model by verifyingprotobuf ibc.core.commitment.v1.MerkleProofbytes against the committed root. The Gateway is treated as a data availability layer for queries and proofs, while the verification on the counterparty chain is intended to be purely cryptographic. That is, this setup for Cardano maintains core IBC trust principles, and lends itself to a fully trustless bridge implementation.This integration requires a Cardano notion of “height”. In this design
Height.revision_heightis treated as a Cardano block number as surfaced by db-sync and by Mithril cardano-transactions snapshots, not a Cardano slot. Because Mithril certificates are checkpoint-based rather than per-block, Hermes includes configurable waiting behavior after Cardano transaction submission: Hermes waits until the latest certified Mithril snapshot height is greater than or equal to the inclusion height of the submitted transaction, preventing the relayer from building proofs at a height that the Cosmos-side Mithril light client can't yet verify.The PR also adds Cardano key handling using the standard Hermes keyring pattern (serialized keys under
~/.hermes/keys/...), and implements Cardano event polling and parsing needed for handshake and packet relaying flows.Existing Cosmos chain behaviour stays the same. The new functionality is isolated behind the new chain type and client types, and standard proof decoding and query flows are reused wherever possible.
Testing was performed with the existing Hermes unit test suite and additional Cardano-specific tests, and the Cardano config includes explicit parameters for Mithril waiting and logging so operational behaviour is observable rather than relying on fixed sleeps.
Attesting canonical on-chain state on Cardano is quite tricky, so the Mithril based solution (which is using STM signatures from stakepool operators to attest to transaction inclusion rather than explicit on-chain state per se) is currently the best solution available for an IBC light client. The underlying dynamic is essentially to prove transaction inclusion and then derive transaction outputs which dictate the "trusted" IBC host-state modification which that transaction made. If there's any interest in understanding more about the struggle for a Cardano canonical UTXO-set, or a Cardano notion of something like an
app_hash, or a Mithril-like service for on-chain state, this discussion is a good starting point: CIP-0165, cardano-foundation/CIPs#1083cardano-ibc-incubator
The cardano-ibc-incubator project brings IBC to Cardano. This PR contains the Hermes integration required to complete the bridge, which we are otherwise maintaining in a separate fork. Cardano integration presents a lot of unique challenges for IBC integration, to name a few: UTXO model means transaction building differs fundamentally from acccount-based chains, Cardano has no native websocket event model or RPC interface, Cardano has no analogous KV store and in fact no contract state whatsoever, finally Cardano has no consensus-signed app state root which complicates things substantially. See the repo here: https://github.com/cardano-foundation/cardano-ibc-incubator
Compatibility
CardanoChainEndpointbacked by a Cardano Gateway gRPC service for queries, txbuilding, event polling, and tx submission.
Mithril headers (
/ibc.lightclients.mithril.v1.MithrilHeader) in ibc-relayer-types.handshakes, packet relay, channel close, and timeout-on-close.
This PR adds new variants/types in public enums:
ChainConfig::CardanoClientType::CardanoAnyClientState::Mithril,AnyConsensusState::Mithril, andAnyHeaderMithril supportDesign overview
Hermes drives the normal relaying (scheduling, retries, path processing, and eventdriven progression), asks the Gateway to construct unsigned Cardano transactions for the relevant IBC messages, signs those transactions locally using the configured Cardano key, and then submits the signed transaction back through the Gateway. The Gateway is treated as a data plane for Cardano queries, transaction construction, submission, and event retrieval, and Hermes translates Gateway-returned events into Hermes internal
IbcEventmodel so the rest of the relayer logic is idiomatic.Cardano transactions are signed as Ed25519 witnesses over the CBOR (which is like JSON) transaction body and witness set, using Pallas primitives/codecs to ensure Conway-era compatibility. The integration supports two key input modes: a mnemonic path that derives the signing key using CIP‑1852, and a bech32-encoded private key (ed25519_sk...) path for environments where mnemonic derivation is incompatible or where keys originate outside Hermes tooling. Internally, the CIP‑1852 derivation uses
m/1852'/1815'/account'/2'/0', and the only user controlled component is the account index (wired to the Hermes HD path “account” value); the rest of the derivation path is fixed to match Cardano conventions.An important Cardano-specific nuance is the meaning of “height.” Hermes heights are the standard (
revision_number,revision_height), but for this integrationrevision_heightis treated as a Cardano block number as surfaced by db-sync and by Mithril cardano-transactions snapshots, not a Cardano slot number. This matters because the Cosmos-side Cardano-tracking client verifies at a snapshot/block-number notion of height, and it affects proof construction, update-client flows, and how the relayer reasons about “what is committed.” Because Mithril is checkpoint-based a Cardano transaction can be included in a block before it is covered by a Mithril-certified transaction snapshot. If Hermes immediately proceeds to the next IBC step after inclusion, it can attempt to build or use proofs at a height that the Cosmos-side Mithril client cannot yet verify. To prevent this class of false-negative failures, we treat “included” and “certified” as distinct, and wait after submission until the Gateway reports a Mithril snapshot whose certifiedblock_numberis greater than or equal to the inclusion block number of the submitted transaction. This wait is configurable through Cardano chain config knobs (timeout, polling interval, and periodic progress logging), and is intended to be observable rather than relying on fixed sleeps.On the light client side, the Cosmos chain tracks Cardano using a single client type
08-cardano, where headers are Mithril headers (/ibc.lightclients.mithril.v1.MithrilHeader). In the current model, consensus state carries the committedibc_state_rootextracted from certified HostState transaction evidence contained in the Mithril header, and membership/nonmembership verification follows the standard IBC approach by verifying ICS‑23 proofs against that committed root. The implementation avoids trying to split “consensus tracking” and “state proof verification” across multiple client IDs, because the main connection/channel logic assumes a singleclient_idis the reference point for proof verification.From a relayer plumbing perspective, the Cardano endpoint implements the query, proof, and event surfaces Hermes relies on for core relaying workflows. Proofs are handled in the canonical format Hermes expects, namely protobuf
ibc.core.commitment.v1.MerkleProofbytes, and the Cardano endpoint decodes those bytes into HermesMerkleProoftype so the standard proof-handling flow is reused.Cardano signing
A quick note on dependencies and Cargo.lock: the Cardano integration introduces a small set of new crates for transaction signing and encoding (pallas-* for Cardano CBOR/witness handling, blake2 for Cardano-style hashing, and slip10 for Ed25519 key derivation from a BIP‑39 seed). You may notice Cargo.lock grows more than the raw code diff would suggest, this is because slip10 currently pulls an older ed25519-dalek/hmac stack alongside the newer versions already used elsewhere in Hermes, so the lockfile contains both. This is a known consequence of the current choice of derivation crate and can be revisited to converge on a single crypto stack.
On key input, Hermes supports two ways to provide a Cardano signing key. You can supply a BIP‑39 mnemonic, in which case Hermes derives a key using a hardened-only SLIP‑0010 (Ed25519) path (m/1852'/1815'/account'/2'/0'). This is deterministic and convenient for local testing and relayer-managed keys, but it is not guaranteed to match the exact derivation used by all Cardano wallet stacks (many CIP‑1852 implementations use non-hardened steps for the final segments). For production and maximum interoperability, prefer importing a Cardano private key directly via the ed25519_sk... bech32 format, which avoids derivation ambiguity. The CLI still uses
--mnemonic-file, but that file may contain either a mnemonic phrase or an ed25519_sk... key, the implementation just branches depending on what it sees in the file, see that implementation atrelayer/crates/relayer/src/chain/ cardano/signing_key_pair.rs.Follow-ups
For clarity, the current feature set is prioritized to enable round-trip ICS-20 token transfers, so some non-implicated features are currently stubbed, but return clear error messages about not yet being implemented.
hermes listencli path wiringPR author checklist:
unclog. will wait for feedbackdocs/).mircea-cwill wait for feedbackReviewer checklist:
Files changedin the GitHub PR explorer.