use std::fmt::Debug;
use abstract_interface::{AbstractInterfaceError, RegisteredModule};
use abstract_std::{account, adapter, ibc_client, ibc_host};
use cosmwasm_std::to_json_binary;
use cw_orch::{contract::Contract, prelude::*};
use cw_orch_interchain::{core::SuccessNestedPacketsFlow, prelude::*};
use serde::{de::DeserializeOwned, Serialize};
use crate::{client::AbstractClientResult, remote_account::RemoteAccount};
pub struct RemoteApplication<Chain: IbcQueryHandler, IBC: InterchainEnv<Chain>, M> {
remote_account: RemoteAccount<Chain, IBC>,
module: M,
}
impl<
Chain: IbcQueryHandler,
IBC: InterchainEnv<Chain>,
M: RegisteredModule + ExecutableContract + QueryableContract + ContractInstance<Chain>,
> RemoteApplication<Chain, IBC, M>
{
pub(crate) fn new(
remote_account: RemoteAccount<Chain, IBC>,
module: M,
) -> AbstractClientResult<Self> {
remote_account.module_addresses(vec![M::module_id().to_string()])?;
Ok(Self {
remote_account,
module,
})
}
pub fn account(&self) -> &RemoteAccount<Chain, IBC> {
&self.remote_account
}
pub fn execute(
&self,
execute: &M::ExecuteMsg,
funds: Vec<Coin>,
) -> AbstractClientResult<SuccessNestedPacketsFlow<Chain, Empty>> {
self.remote_account
.execute_on_account(vec![account::ExecuteMsg::ExecuteOnModule {
module_id: M::module_id().to_owned(),
exec_msg: to_json_binary(execute).map_err(AbstractInterfaceError::from)?,
funds,
}])
}
pub fn admin_execute(
&self,
execute: &M::ExecuteMsg,
) -> AbstractClientResult<SuccessNestedPacketsFlow<Chain, Empty>> {
self.remote_account
.execute_on_account(vec![account::ExecuteMsg::AdminExecuteOnModule {
module_id: M::module_id().to_owned(),
msg: to_json_binary(execute).map_err(AbstractInterfaceError::from)?,
}])
}
pub fn query<G: DeserializeOwned + Serialize + Debug>(
&self,
query: &M::QueryMsg,
) -> AbstractClientResult<G> {
self.module.query(query).map_err(Into::into)
}
pub fn module<T: RegisteredModule + From<Contract<Chain>>>(&self) -> AbstractClientResult<T> {
self.remote_account.module()
}
pub fn address(&self) -> AbstractClientResult<Addr> {
self.module.address().map_err(Into::into)
}
}
impl<Chain: IbcQueryHandler, IBC: InterchainEnv<Chain>, M: ContractInstance<Chain>>
RemoteApplication<Chain, IBC, M>
{
pub fn authorize_on_adapters(&self, adapter_ids: &[&str]) -> AbstractClientResult<()> {
let mut account_msgs = vec![];
for module_id in adapter_ids {
account_msgs.push(account::ExecuteMsg::ExecuteOnModule {
module_id: module_id.to_string(),
exec_msg: to_json_binary(&adapter::ExecuteMsg::<Empty>::Base(
adapter::BaseExecuteMsg {
account_address: None,
msg: adapter::AdapterBaseMsg::UpdateAuthorizedAddresses {
to_add: vec![],
to_remove: vec![],
},
},
))
.map_err(Into::<CwOrchError>::into)?,
funds: vec![],
})
}
let _ = self.remote_account.ibc_client_execute(
ibc_client::ExecuteMsg::RemoteAction {
host_chain: self.remote_account.host_chain_id(),
action: ibc_host::HostAction::Dispatch { account_msgs },
},
vec![],
)?;
Ok(())
}
}
impl<
Chain: IbcQueryHandler,
IBC: InterchainEnv<Chain>,
M: QueryableContract + ContractInstance<Chain>,
> QueryableContract for RemoteApplication<Chain, IBC, M>
{
type QueryMsg = M::QueryMsg;
}
impl<
Chain: IbcQueryHandler,
IBC: InterchainEnv<Chain>,
M: QueryableContract + ContractInstance<Chain>,
> ContractInstance<Chain> for RemoteApplication<Chain, IBC, M>
{
fn as_instance(&self) -> &Contract<Chain> {
self.module.as_instance()
}
fn as_instance_mut(&mut self) -> &mut Contract<Chain> {
self.module.as_instance_mut()
}
}