use std::fmt;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::encoding::Binary;
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, JsonSchema)]
pub struct HumanAddr(pub String);
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, JsonSchema)]
pub struct CanonicalAddr(pub Binary);
impl HumanAddr {
pub fn as_str(&self) -> &str {
&self.0
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl fmt::Display for HumanAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self.0)
}
}
impl From<&str> for HumanAddr {
fn from(addr: &str) -> Self {
HumanAddr(addr.to_string())
}
}
impl From<&HumanAddr> for HumanAddr {
fn from(addr: &HumanAddr) -> Self {
HumanAddr(addr.0.to_string())
}
}
impl CanonicalAddr {
pub fn as_slice(&self) -> &[u8] {
&self.0.as_slice()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl fmt::Display for CanonicalAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, JsonSchema)]
pub struct Env {
pub block: BlockInfo,
pub message: MessageInfo,
pub contract: ContractInfo,
}
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, JsonSchema)]
pub struct BlockInfo {
pub height: i64,
pub time: i64,
pub chain_id: String,
}
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, JsonSchema)]
pub struct MessageInfo {
pub signer: CanonicalAddr,
pub sent_funds: Option<Vec<Coin>>,
}
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, JsonSchema)]
pub struct ContractInfo {
pub address: CanonicalAddr,
pub balance: Option<Vec<Coin>>,
}
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, JsonSchema)]
pub struct Coin {
pub denom: String,
pub amount: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum CosmosMsg {
Send {
from_address: HumanAddr,
to_address: HumanAddr,
amount: Vec<Coin>,
},
Contract {
contract_addr: HumanAddr,
msg: Binary,
send: Option<Vec<Coin>>,
},
Opaque {
data: Binary,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum ContractResult {
Ok(Response),
Err(String),
}
impl ContractResult {
pub fn unwrap(self) -> Response {
match self {
ContractResult::Err(msg) => panic!("Unexpected error: {}", msg),
ContractResult::Ok(res) => res,
}
}
pub fn is_err(&self) -> bool {
match self {
ContractResult::Err(_) => true,
_ => false,
}
}
}
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, JsonSchema)]
pub struct LogAttribute {
pub key: String,
pub value: String,
}
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, JsonSchema)]
pub struct Response {
pub messages: Vec<CosmosMsg>,
pub log: Vec<LogAttribute>,
pub data: Option<Binary>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum QueryResult {
Ok(Binary),
Err(String),
}
impl QueryResult {
pub fn unwrap(self) -> Binary {
match self {
QueryResult::Err(msg) => panic!("Unexpected error: {}", msg),
QueryResult::Ok(res) => res,
}
}
pub fn is_err(&self) -> bool {
match self {
QueryResult::Err(_) => true,
_ => false,
}
}
}
pub fn coin(amount: &str, denom: &str) -> Vec<Coin> {
vec![Coin {
amount: amount.to_string(),
denom: denom.to_string(),
}]
}
pub fn log(key: &str, value: &str) -> LogAttribute {
LogAttribute {
key: key.to_string(),
value: value.to_string(),
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::serde::{from_slice, to_vec};
#[test]
fn can_deser_error_result() {
let fail = ContractResult::Err("foobar".to_string());
let bin = to_vec(&fail).expect("encode contract result");
println!("error: {}", std::str::from_utf8(&bin).unwrap());
let back: ContractResult = from_slice(&bin).expect("decode contract result");
assert_eq!(fail, back);
}
#[test]
fn can_deser_ok_result() {
let send = ContractResult::Ok(Response {
messages: vec![CosmosMsg::Send {
from_address: HumanAddr("me".to_string()),
to_address: HumanAddr("you".to_string()),
amount: coin("1015", "earth"),
}],
log: vec![LogAttribute {
key: "action".to_string(),
value: "release".to_string(),
}],
data: None,
});
let bin = to_vec(&send).expect("encode contract result");
println!("ok: {}", std::str::from_utf8(&bin).unwrap());
let back: ContractResult = from_slice(&bin).expect("decode contract result");
assert_eq!(send, back);
}
}