1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use crate::{Abstract, AbstractInterfaceError, IbcClient, IbcHost, VersionControl};
use abstract_std::{IBC_CLIENT, IBC_HOST};
use cw_orch::prelude::*;
pub struct AbstractIbc<Chain: CwEnv> {
    pub client: IbcClient<Chain>,
    pub host: IbcHost<Chain>,
}

impl<Chain: CwEnv> AbstractIbc<Chain> {
    pub fn new(chain: &Chain) -> Self {
        let ibc_client = IbcClient::new(IBC_CLIENT, chain.clone());
        let ibc_host = IbcHost::new(IBC_HOST, chain.clone());
        Self {
            client: ibc_client,
            host: ibc_host,
        }
    }

    pub fn upload(&self) -> Result<(), crate::AbstractInterfaceError> {
        self.client.upload()?;
        self.host.upload()?;
        Ok(())
    }

    pub fn instantiate(&self, abstr: &Abstract<Chain>, admin: &Addr) -> Result<(), CwOrchError> {
        self.client.instantiate(
            &abstract_std::ibc_client::InstantiateMsg {
                ans_host_address: abstr.ans_host.addr_str()?,
                version_control_address: abstr.version_control.addr_str()?,
            },
            Some(admin),
            None,
        )?;

        self.host.instantiate(
            &abstract_std::ibc_host::InstantiateMsg {
                ans_host_address: abstr.ans_host.addr_str()?,
                account_factory_address: abstr.account_factory.addr_str()?,
                version_control_address: abstr.version_control.addr_str()?,
            },
            Some(admin),
            None,
        )?;
        Ok(())
    }

    pub fn register(
        &self,
        version_control: &VersionControl<Chain>,
    ) -> Result<(), AbstractInterfaceError> {
        version_control.register_natives(vec![
            (
                self.client.as_instance(),
                ibc_client::contract::CONTRACT_VERSION.to_string(),
            ),
            (
                self.host.as_instance(),
                ibc_host::contract::CONTRACT_VERSION.to_string(),
            ),
        ])
    }
}

#[cfg(feature="interchain")]
// Helpers to create connection with another chain
pub mod connection {
    use super::*;
    use cw_orch_interchain::prelude::*;
    use cw_orch_interchain::InterchainError;
    use abstract_std::account_factory::ExecuteMsgFns;
    use abstract_std::ibc_client::ExecuteMsgFns as _;
    use abstract_std::ibc_client::QueryMsgFns;
    use abstract_std::ibc_host::ExecuteMsgFns as _;
    use abstract_std::objects::chain_name::ChainName;
    use cw_orch_polytone::Polytone;
    /// This is used for creating a testing connection between two Abstract connections using an existing polytone connection
    ///
    /// You usually don't need this function on actual networks if you're not an Abstract maintainer
    pub fn abstract_ibc_connection_with<Chain: IbcQueryHandler, IBC: InterchainEnv<Chain>>(
        abstr: &Abstract<Chain>,
        interchain: &IBC,
        dest: &Abstract<Chain>,
        polytone_src: &Polytone<Chain>,
    ) -> Result<(), InterchainError> {
        // First we register client and host respectively
        let chain1_id = abstr.ibc.client.get_chain().chain_id();
        let chain1_name = ChainName::from_chain_id(&chain1_id);

        let chain2_id = dest.ibc.client.get_chain().chain_id();
        let chain2_name = ChainName::from_chain_id(&chain2_id);

        // First, we register the host with the client.
        // We register the polytone note with it because they are linked
        // This triggers an IBC message that is used to get back the proxy address
        let proxy_tx_result = abstr.ibc.client.register_infrastructure(
            chain2_name.to_string(),
            dest.ibc.host.address()?.to_string(),
            polytone_src.note.address()?.to_string(),
        )?;
        // We make sure the IBC execution is done so that the proxy address is saved inside the Abstract contract
        interchain.check_ibc(&chain1_id, proxy_tx_result)?;

        // Finally, we get the proxy address and register the proxy with the ibc host for the dest chain
        let proxy_address = abstr.ibc.client.host(chain2_name.to_string())?;

        dest.ibc.host.register_chain_proxy(
            chain1_name.to_string(),
            proxy_address.remote_polytone_proxy.unwrap(),
        )?;

        dest.account_factory.update_config(
            None,
            Some(dest.ibc.host.address()?.to_string()),
            None,
            None,
        )?;

        Ok(())
    }
}