use self::state::AccountData;
use crate::{abstract_ica::StdAck, ibc_host::HostAction, objects::account_id::AccountId};
use abstract_ica::IbcResponseMsg;
use cosmwasm_schema::QueryResponses;
use cosmwasm_std::{from_slice, Binary, Coin, CosmosMsg, StdResult, Timestamp};
pub mod state {
use super::LatestQueryResponse;
use crate::{
objects::{account_id::AccountId, ans_host::AnsHost, common_namespace::ADMIN_NAMESPACE},
ANS_HOST as ANS_HOST_KEY,
};
use cosmwasm_std::{Addr, Coin, Timestamp};
use cw_controllers::Admin;
use cw_storage_plus::{Item, Map};
#[cosmwasm_schema::cw_serde]
pub struct Config {
pub version_control_address: Addr,
pub chain: String,
}
#[cosmwasm_schema::cw_serde]
#[derive(Default)]
pub struct AccountData {
pub last_update_time: Timestamp,
pub remote_addr: Option<String>,
pub remote_balance: Vec<Coin>,
}
pub const ADMIN: Admin = Admin::new(ADMIN_NAMESPACE);
pub const CHANNELS: Map<&str, String> = Map::new("channels");
pub const CONFIG: Item<Config> = Item::new("config");
pub const ACCOUNTS: Map<(&str, AccountId), AccountData> = Map::new("accounts");
pub const LATEST_QUERIES: Map<(&str, AccountId), LatestQueryResponse> = Map::new("queries");
pub const ANS_HOST: Item<AnsHost> = Item::new(ANS_HOST_KEY);
}
#[cosmwasm_schema::cw_serde]
pub struct InstantiateMsg {
pub ans_host_address: String,
pub version_control_address: String,
pub chain: String,
}
#[cosmwasm_schema::cw_serde]
pub struct MigrateMsg {}
#[cosmwasm_schema::cw_serde]
pub struct CallbackInfo {
pub id: String,
pub receiver: String,
}
impl CallbackInfo {
pub fn to_callback_msg(self, ack_data: &Binary) -> StdResult<CosmosMsg> {
let msg: StdAck = from_slice(ack_data)?;
IbcResponseMsg { id: self.id, msg }.into_cosmos_account_msg(self.receiver)
}
}
#[cosmwasm_schema::cw_serde]
#[cfg_attr(feature = "interface", derive(cw_orch::ExecuteFns))]
pub enum ExecuteMsg {
UpdateAdmin {
admin: String,
},
UpdateConfig {
ans_host: Option<String>,
version_control: Option<String>,
},
SendFunds {
host_chain: String,
funds: Vec<Coin>,
},
Register {
host_chain: String,
},
SendPacket {
host_chain: String,
action: HostAction,
callback_info: Option<CallbackInfo>,
retries: u8,
},
RemoveHost {
host_chain: String,
},
}
#[cosmwasm_schema::cw_serde]
#[cfg_attr(feature = "interface", derive(cw_orch::QueryFns))]
#[derive(QueryResponses)]
pub enum QueryMsg {
#[returns(ConfigResponse)]
Config {},
#[returns(ListAccountsResponse)]
ListAccounts {},
#[returns(AccountResponse)]
Account {
chain: String,
account_id: AccountId,
},
#[returns(LatestQueryResponse)]
LatestQueryResult {
chain: String,
account_id: AccountId,
},
#[returns(ListChannelsResponse)]
ListChannels {},
}
#[cosmwasm_schema::cw_serde]
pub struct ConfigResponse {
pub admin: String,
pub version_control_address: String,
pub chain: String,
}
#[cosmwasm_schema::cw_serde]
pub struct ListAccountsResponse {
pub accounts: Vec<AccountInfo>,
}
#[cosmwasm_schema::cw_serde]
pub struct ListChannelsResponse {
pub channels: Vec<(String, String)>,
}
#[cosmwasm_schema::cw_serde]
pub struct LatestQueryResponse {
pub last_update_time: Timestamp,
pub response: StdAck,
}
#[cosmwasm_schema::cw_serde]
pub struct RemoteProxyResponse {
pub channel_id: String,
pub proxy_address: String,
}
#[cosmwasm_schema::cw_serde]
pub struct AccountInfo {
pub channel_id: String,
pub account_id: AccountId,
pub last_update_time: Timestamp,
pub remote_addr: Option<String>,
pub remote_balance: Vec<Coin>,
}
impl AccountInfo {
pub fn convert(channel_id: String, account_id: AccountId, input: AccountData) -> Self {
AccountInfo {
channel_id,
account_id,
last_update_time: input.last_update_time,
remote_addr: input.remote_addr,
remote_balance: input.remote_balance,
}
}
}
#[cosmwasm_schema::cw_serde]
pub struct AccountResponse {
pub last_update_time: Timestamp,
pub remote_addr: Option<String>,
pub remote_balance: Vec<Coin>,
}
impl From<AccountData> for AccountResponse {
fn from(input: AccountData) -> Self {
AccountResponse {
last_update_time: input.last_update_time,
remote_addr: input.remote_addr,
remote_balance: input.remote_balance,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use abstract_testing::prelude::*;
use cosmwasm_std::to_binary;
use speculoos::prelude::*;
#[test]
fn test_account_info_convert() {
let channel_id = "channel-123".to_string();
let input = AccountData {
last_update_time: Default::default(),
remote_addr: None,
remote_balance: vec![],
};
let expected = AccountInfo {
channel_id: channel_id.clone(),
account_id: TEST_ACCOUNT_ID,
last_update_time: input.last_update_time,
remote_addr: input.clone().remote_addr,
remote_balance: input.clone().remote_balance,
};
let actual = AccountInfo::convert(channel_id, TEST_ACCOUNT_ID, input);
assert_that!(actual).is_equal_to(expected);
}
#[test]
fn test_account_response_from() {
let input = AccountData::default();
let expected = AccountResponse {
last_update_time: input.last_update_time,
remote_addr: input.clone().remote_addr,
remote_balance: input.clone().remote_balance,
};
let actual = AccountResponse::from(input);
assert_that!(actual).is_equal_to(expected);
}
#[test]
fn test_callback_info_to_callback_msg() {
let receiver = "receiver".to_string();
let callback_id = "15".to_string();
let callback_info = CallbackInfo {
id: callback_id,
receiver,
};
let ack_data = &to_binary(&StdAck::Result(to_binary(&true).unwrap())).unwrap();
let actual = callback_info.to_callback_msg(&ack_data.clone()).unwrap();
let _funds: Vec<Coin> = vec![];
assert_that!(actual).matches(|e| {
matches!(
e,
CosmosMsg::Wasm(cosmwasm_std::WasmMsg::Execute {
contract_addr: _receiver,
msg: _,
funds: _
})
)
});
}
}