synor/sdk/cpp/include/synor/ibc.hpp
Gulshan Yadav 97add23062 feat(sdk): implement IBC SDK for all 12 languages
Implement Inter-Blockchain Communication (IBC) SDK with full ICS
protocol support across all 12 programming languages:
- JavaScript/TypeScript, Python, Go, Rust
- Java, Kotlin, Swift, Flutter/Dart
- C, C++, C#/.NET, Ruby

Features:
- Light client management (Tendermint, Solo Machine, WASM)
- Connection handshake (4-way: Init, Try, Ack, Confirm)
- Channel management with ordered/unordered support
- ICS-20 fungible token transfers
- HTLC atomic swaps with hashlock (SHA256) and timelock
- Packet relay with timeout handling
2026-01-28 12:53:46 +05:30

469 lines
11 KiB
C++

/**
* @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 <string>
#include <vector>
#include <optional>
#include <memory>
#include <cstdint>
#include <future>
#include <nlohmann/json.hpp>
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<Height> frozen_height;
static ClientState from_json(const json& j) {
ClientState state;
state.chain_id = j.at("chain_id").get<std::string>();
state.trust_level = TrustLevel::from_json(j.at("trust_level"));
state.trusting_period = j.at("trusting_period").get<uint64_t>();
state.unbonding_period = j.at("unbonding_period").get<uint64_t>();
state.max_clock_drift = j.at("max_clock_drift").get<uint64_t>();
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<std::string>(),
j.at("amount").get<std::string>(),
j.at("sender").get<std::string>(),
j.at("receiver").get<std::string>(),
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<json> responder_htlc;
static AtomicSwap from_json(const json& j) {
AtomicSwap swap;
swap.swap_id = j.at("swap_id").at("id").get<std::string>();
swap.state = swap_state_from_string(j.at("state").get<std::string>());
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<std::string> create(ClientType client_type,
const ClientState& client_state,
const json& consensus_state);
std::future<ClientState> get_state(const std::string& client_id);
std::future<std::vector<json>> list();
private:
SynorIbc& ibc_;
};
/**
* Connections sub-client
*/
class ConnectionsClient {
public:
explicit ConnectionsClient(SynorIbc& ibc) : ibc_(ibc) {}
std::future<std::string> open_init(const std::string& client_id,
const std::string& counterparty_client_id);
std::future<json> get(const std::string& connection_id);
std::future<std::vector<json>> list();
private:
SynorIbc& ibc_;
};
/**
* Channels sub-client
*/
class ChannelsClient {
public:
explicit ChannelsClient(SynorIbc& ibc) : ibc_(ibc) {}
std::future<void> bind_port(const std::string& port_id, const std::string& module);
std::future<std::string> 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<json> get(const std::string& port_id, const std::string& channel_id);
std::future<std::vector<json>> list();
private:
SynorIbc& ibc_;
};
/**
* Transfer sub-client (ICS-20)
*/
class TransferClient {
public:
explicit TransferClient(SynorIbc& ibc) : ibc_(ibc) {}
std::future<json> 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> timeout = std::nullopt,
std::optional<std::string> memo = std::nullopt);
std::future<json> 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<json> initiate(const std::string& responder,
const json& initiator_asset,
const json& responder_asset);
std::future<void> lock(const std::string& swap_id);
std::future<json> respond(const std::string& swap_id, const json& asset);
std::future<json> claim(const std::string& swap_id,
const std::vector<uint8_t>& secret);
std::future<json> refund(const std::string& swap_id);
std::future<AtomicSwap> get(const std::string& swap_id);
std::future<std::vector<AtomicSwap>> 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<json> get_chain_info();
std::future<Height> get_height();
std::future<bool> 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<json> get(const std::string& path);
std::future<json> post(const std::string& path, const json& body);
private:
void check_closed() const;
IbcConfig config_;
bool closed_ = false;
std::unique_ptr<LightClientClient> clients_;
std::unique_ptr<ConnectionsClient> connections_;
std::unique_ptr<ChannelsClient> channels_;
std::unique_ptr<TransferClient> transfer_;
std::unique_ptr<SwapsClient> swaps_;
// HTTP client implementation (pimpl)
class Impl;
std::unique_ptr<Impl> impl_;
};
} // namespace ibc
} // namespace synor
#endif // SYNOR_IBC_HPP