/** * @file ibc.hpp * @brief Synor IBC SDK for C++ * * Inter-Blockchain Communication (IBC) protocol for cross-chain interoperability. */ #ifndef SYNOR_IBC_HPP #define SYNOR_IBC_HPP #include #include #include #include #include #include #include namespace synor { namespace ibc { using json = nlohmann::json; /** * IBC Height representation */ struct Height { uint64_t revision_number = 0; uint64_t revision_height = 1; bool is_zero() const { return revision_number == 0 && revision_height == 0; } Height increment() const { return Height{revision_number, revision_height + 1}; } static Height from_json(const json& j) { return Height{ j.value("revision_number", uint64_t(0)), j.value("revision_height", uint64_t(1)) }; } json to_json() const { return { {"revision_number", revision_number}, {"revision_height", revision_height} }; } }; /** * Light client types */ enum class ClientType { Tendermint, SoloMachine, Localhost, Wasm }; inline std::string to_string(ClientType type) { switch (type) { case ClientType::Tendermint: return "tendermint"; case ClientType::SoloMachine: return "solo_machine"; case ClientType::Localhost: return "localhost"; case ClientType::Wasm: return "wasm"; } return "unknown"; } /** * Trust level configuration */ struct TrustLevel { int numerator = 1; int denominator = 3; static TrustLevel from_json(const json& j) { return TrustLevel{ j.value("numerator", 1), j.value("denominator", 3) }; } json to_json() const { return {{"numerator", numerator}, {"denominator", denominator}}; } }; /** * Light client state */ struct ClientState { std::string chain_id; TrustLevel trust_level; uint64_t trusting_period; uint64_t unbonding_period; uint64_t max_clock_drift; Height latest_height; std::optional frozen_height; static ClientState from_json(const json& j) { ClientState state; state.chain_id = j.at("chain_id").get(); state.trust_level = TrustLevel::from_json(j.at("trust_level")); state.trusting_period = j.at("trusting_period").get(); state.unbonding_period = j.at("unbonding_period").get(); state.max_clock_drift = j.at("max_clock_drift").get(); state.latest_height = Height::from_json(j.at("latest_height")); if (j.contains("frozen_height") && !j["frozen_height"].is_null()) { state.frozen_height = Height::from_json(j["frozen_height"]); } return state; } json to_json() const { json j = { {"chain_id", chain_id}, {"trust_level", trust_level.to_json()}, {"trusting_period", trusting_period}, {"unbonding_period", unbonding_period}, {"max_clock_drift", max_clock_drift}, {"latest_height", latest_height.to_json()} }; if (frozen_height) { j["frozen_height"] = frozen_height->to_json(); } return j; } }; /** * Connection state */ enum class ConnectionState { Uninitialized, Init, TryOpen, Open }; /** * Channel ordering */ enum class ChannelOrder { Unordered, Ordered }; inline std::string to_string(ChannelOrder order) { return order == ChannelOrder::Ordered ? "ordered" : "unordered"; } /** * Channel state */ enum class ChannelState { Uninitialized, Init, TryOpen, Open, Closed }; /** * Timeout information */ struct Timeout { Height height; uint64_t timestamp = 0; static Timeout from_height(uint64_t h) { return Timeout{{0, h}, 0}; } static Timeout from_timestamp(uint64_t ts) { return Timeout{{}, ts}; } json to_json() const { return { {"height", height.to_json()}, {"timestamp", std::to_string(timestamp)} }; } }; /** * Transfer packet data (ICS-20) */ struct FungibleTokenPacketData { std::string denom; std::string amount; std::string sender; std::string receiver; std::string memo; bool is_native() const { return denom.find('/') == std::string::npos; } static FungibleTokenPacketData from_json(const json& j) { return FungibleTokenPacketData{ j.at("denom").get(), j.at("amount").get(), j.at("sender").get(), j.at("receiver").get(), j.value("memo", "") }; } json to_json() const { return { {"denom", denom}, {"amount", amount}, {"sender", sender}, {"receiver", receiver}, {"memo", memo} }; } }; /** * Swap state */ enum class SwapState { Pending, Locked, Completed, Refunded, Expired, Cancelled }; inline SwapState swap_state_from_string(const std::string& s) { if (s == "pending") return SwapState::Pending; if (s == "locked") return SwapState::Locked; if (s == "completed") return SwapState::Completed; if (s == "refunded") return SwapState::Refunded; if (s == "expired") return SwapState::Expired; return SwapState::Cancelled; } /** * Atomic swap */ struct AtomicSwap { std::string swap_id; SwapState state; json initiator_htlc; std::optional responder_htlc; static AtomicSwap from_json(const json& j) { AtomicSwap swap; swap.swap_id = j.at("swap_id").at("id").get(); swap.state = swap_state_from_string(j.at("state").get()); swap.initiator_htlc = j.at("initiator_htlc"); if (j.contains("responder_htlc") && !j["responder_htlc"].is_null()) { swap.responder_htlc = j["responder_htlc"]; } return swap; } }; /** * IBC SDK configuration */ struct IbcConfig { std::string api_key; std::string endpoint = "https://ibc.synor.io/v1"; std::string ws_endpoint = "wss://ibc.synor.io/v1/ws"; int timeout = 30; int retries = 3; std::string chain_id = "synor-1"; bool debug = false; }; /** * IBC exception */ class IbcException : public std::exception { public: IbcException(const std::string& message, const std::string& code = "", int status = 0) : message_(message), code_(code), status_(status) {} const char* what() const noexcept override { return message_.c_str(); } const std::string& code() const { return code_; } int status() const { return status_; } private: std::string message_; std::string code_; int status_; }; // Forward declarations class SynorIbc; /** * Light client sub-client */ class LightClientClient { public: explicit LightClientClient(SynorIbc& ibc) : ibc_(ibc) {} std::future create(ClientType client_type, const ClientState& client_state, const json& consensus_state); std::future get_state(const std::string& client_id); std::future> list(); private: SynorIbc& ibc_; }; /** * Connections sub-client */ class ConnectionsClient { public: explicit ConnectionsClient(SynorIbc& ibc) : ibc_(ibc) {} std::future open_init(const std::string& client_id, const std::string& counterparty_client_id); std::future get(const std::string& connection_id); std::future> list(); private: SynorIbc& ibc_; }; /** * Channels sub-client */ class ChannelsClient { public: explicit ChannelsClient(SynorIbc& ibc) : ibc_(ibc) {} std::future bind_port(const std::string& port_id, const std::string& module); std::future open_init(const std::string& port_id, ChannelOrder ordering, const std::string& connection_id, const std::string& counterparty_port, const std::string& version); std::future get(const std::string& port_id, const std::string& channel_id); std::future> list(); private: SynorIbc& ibc_; }; /** * Transfer sub-client (ICS-20) */ class TransferClient { public: explicit TransferClient(SynorIbc& ibc) : ibc_(ibc) {} std::future transfer(const std::string& source_port, const std::string& source_channel, const std::string& denom, const std::string& amount, const std::string& sender, const std::string& receiver, std::optional timeout = std::nullopt, std::optional memo = std::nullopt); std::future get_denom_trace(const std::string& ibc_denom); private: SynorIbc& ibc_; }; /** * Swaps sub-client (HTLC) */ class SwapsClient { public: explicit SwapsClient(SynorIbc& ibc) : ibc_(ibc) {} std::future initiate(const std::string& responder, const json& initiator_asset, const json& responder_asset); std::future lock(const std::string& swap_id); std::future respond(const std::string& swap_id, const json& asset); std::future claim(const std::string& swap_id, const std::vector& secret); std::future refund(const std::string& swap_id); std::future get(const std::string& swap_id); std::future> list_active(); private: SynorIbc& ibc_; }; /** * Main IBC client */ class SynorIbc { public: explicit SynorIbc(const IbcConfig& config); ~SynorIbc(); // Non-copyable SynorIbc(const SynorIbc&) = delete; SynorIbc& operator=(const SynorIbc&) = delete; // Movable SynorIbc(SynorIbc&&) noexcept; SynorIbc& operator=(SynorIbc&&) noexcept; const std::string& chain_id() const { return config_.chain_id; } std::future get_chain_info(); std::future get_height(); std::future health_check(); void close(); bool is_closed() const { return closed_; } LightClientClient& clients() { return *clients_; } ConnectionsClient& connections() { return *connections_; } ChannelsClient& channels() { return *channels_; } TransferClient& transfer() { return *transfer_; } SwapsClient& swaps() { return *swaps_; } // Internal HTTP methods (used by sub-clients) std::future get(const std::string& path); std::future post(const std::string& path, const json& body); private: void check_closed() const; IbcConfig config_; bool closed_ = false; std::unique_ptr clients_; std::unique_ptr connections_; std::unique_ptr channels_; std::unique_ptr transfer_; std::unique_ptr swaps_; // HTTP client implementation (pimpl) class Impl; std::unique_ptr impl_; }; } // namespace ibc } // namespace synor #endif // SYNOR_IBC_HPP