//! IBC error types use thiserror::Error; /// Result type for IBC operations pub type IbcResult = Result; /// IBC error types #[derive(Debug, Error)] pub enum IbcError { // Client errors #[error("Client not found: {0}")] ClientNotFound(String), #[error("Client already exists: {0}")] ClientAlreadyExists(String), #[error("Invalid client state: {0}")] InvalidClientState(String), #[error("Client frozen: {0}")] ClientFrozen(String), #[error("Client expired: {0}")] ClientExpired(String), // Connection errors #[error("Connection not found: {0}")] ConnectionNotFound(String), #[error("Connection already exists: {0}")] ConnectionAlreadyExists(String), #[error("Invalid connection state: expected {expected}, got {actual}")] InvalidConnectionState { expected: String, actual: String }, #[error("Connection version mismatch: {0}")] ConnectionVersionMismatch(String), // Channel errors #[error("Channel not found: port={port}, channel={channel}")] ChannelNotFound { port: String, channel: String }, #[error("Channel already exists: port={port}, channel={channel}")] ChannelAlreadyExists { port: String, channel: String }, #[error("Invalid channel state: expected {expected}, got {actual}")] InvalidChannelState { expected: String, actual: String }, #[error("Port not bound: {0}")] PortNotBound(String), #[error("Port already bound: {0}")] PortAlreadyBound(String), // Packet errors #[error("Packet timeout: height={height}, timestamp={timestamp}")] PacketTimeout { height: u64, timestamp: u64 }, #[error("Packet already received: sequence={0}")] PacketAlreadyReceived(u64), #[error("Packet not found: sequence={0}")] PacketNotFound(u64), #[error("Invalid packet sequence: expected {expected}, got {actual}")] InvalidPacketSequence { expected: u64, actual: u64 }, #[error("Packet data too large: {size} bytes (max {max})")] PacketDataTooLarge { size: usize, max: usize }, #[error("Invalid packet data: {0}")] InvalidPacketData(String), #[error("Invalid acknowledgement: {0}")] InvalidAcknowledgement(String), // Swap errors #[error("Swap not found: {0}")] SwapNotFound(String), #[error("Invalid swap state: expected {expected}, got {actual}")] InvalidSwapState { expected: String, actual: String }, #[error("Swap timeout expired: {0}")] SwapTimeoutExpired(String), #[error("Invalid secret: {0}")] InvalidSecret(String), // Proof errors #[error("Proof verification failed: {0}")] ProofVerificationFailed(String), #[error("Invalid proof: {0}")] InvalidProof(String), #[error("Invalid proof height: expected {expected}, got {actual}")] InvalidProofHeight { expected: u64, actual: u64 }, #[error("Missing proof: {0}")] MissingProof(String), // Commitment errors #[error("Commitment not found: {0}")] CommitmentNotFound(String), #[error("Invalid commitment: {0}")] InvalidCommitment(String), // Handshake errors #[error("Handshake error: {0}")] HandshakeError(String), #[error("Invalid counterparty: {0}")] InvalidCounterparty(String), // Serialization errors #[error("Serialization error: {0}")] SerializationError(String), #[error("Deserialization error: {0}")] DeserializationError(String), // General errors #[error("Invalid identifier: {0}")] InvalidIdentifier(String), #[error("Unauthorized: {0}")] Unauthorized(String), #[error("Internal error: {0}")] Internal(String), } impl From for IbcError { fn from(err: serde_json::Error) -> Self { IbcError::SerializationError(err.to_string()) } } impl From for IbcError { fn from(err: std::io::Error) -> Self { IbcError::Internal(err.to_string()) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_error_display() { let err = IbcError::ClientNotFound("client-1".to_string()); assert!(err.to_string().contains("client-1")); let err = IbcError::PacketTimeout { height: 100, timestamp: 1000, }; assert!(err.to_string().contains("100")); } }