#![cfg(feature = "stargate")]
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::cmp::{Ord, Ordering, PartialOrd};
use std::fmt;
use crate::binary::Binary;
use crate::coins::Coin;
use crate::results::{Attribute, CosmosMsg, Empty, SubMsg};
#[non_exhaustive]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum IbcMsg {
Transfer {
channel_id: String,
to_address: String,
amount: Coin,
timeout_block: Option<IbcTimeoutBlock>,
timeout_timestamp: Option<u64>,
},
SendPacket {
channel_id: String,
data: Binary,
timeout_block: Option<IbcTimeoutBlock>,
timeout_timestamp: Option<u64>,
},
CloseChannel { channel_id: String },
}
#[non_exhaustive]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum IbcQuery {
PortId {},
ListChannels { port_id: Option<String> },
Channel {
channel_id: String,
port_id: Option<String>,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct PortIdResponse {
pub port_id: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct ListChannelsResponse {
pub channels: Vec<IbcChannel>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct ChannelResponse {
pub channel: Option<IbcChannel>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct IbcEndpoint {
pub port_id: String,
pub channel_id: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct IbcChannel {
pub endpoint: IbcEndpoint,
pub counterparty_endpoint: IbcEndpoint,
pub order: IbcOrder,
pub version: String,
pub counterparty_version: Option<String>,
pub connection_id: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub enum IbcOrder {
#[serde(rename = "ORDER_UNORDERED")]
Unordered,
#[serde(rename = "ORDER_ORDERED")]
Ordered,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct IbcTimeoutBlock {
pub revision: u64,
pub height: u64,
}
impl IbcTimeoutBlock {
pub fn is_zero(&self) -> bool {
self.revision == 0 && self.height == 0
}
}
impl PartialOrd for IbcTimeoutBlock {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for IbcTimeoutBlock {
fn cmp(&self, other: &Self) -> Ordering {
match self.revision.cmp(&other.revision) {
Ordering::Equal => self.height.cmp(&other.height),
other => other,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct IbcPacket {
pub data: Binary,
pub src: IbcEndpoint,
pub dest: IbcEndpoint,
pub sequence: u64,
pub timeout_block: Option<IbcTimeoutBlock>,
pub timeout_timestamp: Option<u64>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct IbcAcknowledgement {
pub acknowledgement: Binary,
pub original_packet: IbcPacket,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct IbcBasicResponse<T = Empty>
where
T: Clone + fmt::Debug + PartialEq + JsonSchema,
{
pub submessages: Vec<SubMsg<T>>,
pub messages: Vec<CosmosMsg<T>>,
pub attributes: Vec<Attribute>,
}
impl<T> Default for IbcBasicResponse<T>
where
T: Clone + fmt::Debug + PartialEq + JsonSchema,
{
fn default() -> Self {
IbcBasicResponse {
submessages: vec![],
messages: vec![],
attributes: vec![],
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct IbcReceiveResponse<T = Empty>
where
T: Clone + fmt::Debug + PartialEq + JsonSchema,
{
pub acknowledgement: Binary,
pub submessages: Vec<SubMsg<T>>,
pub messages: Vec<CosmosMsg<T>>,
pub attributes: Vec<Attribute>,
}
impl<T> Default for IbcReceiveResponse<T>
where
T: Clone + fmt::Debug + PartialEq + JsonSchema,
{
fn default() -> Self {
IbcReceiveResponse {
acknowledgement: Binary(vec![]),
submessages: vec![],
messages: vec![],
attributes: vec![],
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json_wasm::to_string;
#[test]
fn serialize_msg() {
let msg = IbcMsg::Transfer {
channel_id: "channel-123".to_string(),
to_address: "my-special-addr".into(),
amount: Coin::new(12345678, "uatom"),
timeout_block: None,
timeout_timestamp: Some(1234567890),
};
let encoded = to_string(&msg).unwrap();
let expected = r#"{"transfer":{"channel_id":"channel-123","to_address":"my-special-addr","amount":{"denom":"uatom","amount":"12345678"},"timeout_block":null,"timeout_timestamp":1234567890}}"#;
assert_eq!(encoded.as_str(), expected);
}
#[test]
fn ibc_timeout_block_ord() {
let epoch1a = IbcTimeoutBlock {
revision: 1,
height: 1000,
};
let epoch1b = IbcTimeoutBlock {
revision: 1,
height: 3000,
};
let epoch2a = IbcTimeoutBlock {
revision: 2,
height: 500,
};
let epoch2b = IbcTimeoutBlock {
revision: 2,
height: 2500,
};
assert!(epoch1a == epoch1a);
assert!(epoch1a < epoch1b);
assert!(epoch1b > epoch1a);
assert!(epoch2a > epoch1a);
assert!(epoch2b > epoch1a);
assert!(epoch1b > epoch1a);
assert!(epoch2a > epoch1b);
assert!(epoch2b > epoch2a);
assert!(epoch2b > epoch1b);
assert!(epoch1a < epoch1b);
assert!(epoch1b < epoch2a);
assert!(epoch2a < epoch2b);
assert!(epoch1b < epoch2b);
}
}