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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//! # Abstract Api Base
//!
//! `abstract_core::adapter` implements shared functionality that's useful for creating new Abstract adapters.
//!
//! ## Description
//! An Abstract adapter contract is a contract that is allowed to perform actions on a [proxy](crate::proxy) contract.
//! It is not migratable and its functionality is shared between users, meaning that all users call the same contract address to perform operations on the Account.
//! The adapter structure is well-suited for implementing standard interfaces to external services like dexes, lending platforms, etc.

use crate::base::{
    ExecuteMsg as MiddlewareExecMsg, InstantiateMsg as MiddlewareInstantiateMsg,
    QueryMsg as MiddlewareQueryMsg,
};
use cosmwasm_schema::QueryResponses;
use cosmwasm_std::{Addr, Empty};
use serde::Serialize;

pub type ExecuteMsg<Request = Empty, ReceiveMsg = Empty> =
    MiddlewareExecMsg<BaseExecuteMsg, AdapterRequestMsg<Request>, ReceiveMsg>;
pub type QueryMsg<ModuleMsg = Empty> = MiddlewareQueryMsg<BaseQueryMsg, ModuleMsg>;
pub type InstantiateMsg<ModuleMsg = Empty> =
    MiddlewareInstantiateMsg<BaseInstantiateMsg, ModuleMsg>;

/// Trait indicates that the type is used as an app message
/// in the [`ExecuteMsg`] enum.
/// Enables [`Into<ExecuteMsg>`] for BOOT fn-generation support.
pub trait AdapterExecuteMsg: Serialize {}

impl<T: AdapterExecuteMsg, R: Serialize> From<T> for ExecuteMsg<T, R> {
    fn from(adapter_msg: T) -> Self {
        Self::Module(AdapterRequestMsg {
            proxy_address: None,
            request: adapter_msg,
        })
    }
}

impl AdapterExecuteMsg for Empty {}

/// Trait indicates that the type is used as an api message
/// in the [`QueryMsg`] enum.
/// Enables [`Into<QueryMsg>`] for BOOT fn-generation support.
pub trait AdapterQueryMsg: Serialize {}

impl<T: AdapterQueryMsg> From<T> for QueryMsg<T> {
    fn from(app: T) -> Self {
        Self::Module(app)
    }
}

impl AdapterQueryMsg for Empty {}

/// Used by Abstract to instantiate the contract
/// The contract is then registered on the version control contract using [`crate::version_control::ExecuteMsg::ProposeModules`].
#[cosmwasm_schema::cw_serde]
pub struct BaseInstantiateMsg {
    /// Used to easily perform address translation
    pub ans_host_address: String,
    /// Used to verify senders
    pub version_control_address: String,
}

impl<RequestMsg, ReceiveMsg> From<BaseExecuteMsg>
    for MiddlewareExecMsg<BaseExecuteMsg, RequestMsg, ReceiveMsg>
{
    fn from(adapter_msg: BaseExecuteMsg) -> Self {
        Self::Base(adapter_msg)
    }
}

impl<RequestMsg, Request, BaseExecMsg> From<AdapterRequestMsg<RequestMsg>>
    for MiddlewareExecMsg<BaseExecMsg, AdapterRequestMsg<RequestMsg>, Request>
{
    fn from(request_msg: AdapterRequestMsg<RequestMsg>) -> Self {
        Self::Module(request_msg)
    }
}

/// An adapter request.
/// If proxy is None, then the sender must be an Account manager and the proxy address is extrapolated from the Account id.
#[cosmwasm_schema::cw_serde]
pub struct AdapterRequestMsg<Request> {
    pub proxy_address: Option<String>,
    /// The actual request
    pub request: Request,
}

impl<Request: Serialize> AdapterRequestMsg<Request> {
    pub fn new(proxy_address: Option<String>, request: Request) -> Self {
        Self {
            proxy_address,
            request,
        }
    }
}

/// Configuration message for the adapter
#[cosmwasm_schema::cw_serde]
#[cfg_attr(feature = "interface", derive(cw_orch::ExecuteFns))]
#[cfg_attr(feature = "interface", impl_into(ExecuteMsg<T>))]
pub enum BaseExecuteMsg {
    /// Add or remove authorized addresses
    /// If an authorized address is both in to_add and to_remove, it will be removed.
    UpdateAuthorizedAddresses {
        to_add: Vec<String>,
        to_remove: Vec<String>,
    },
    /// Remove the adapter
    Remove {},
}

/// Query adapter message
#[cosmwasm_schema::cw_serde]
#[derive(QueryResponses)]
#[cfg_attr(feature = "interface", derive(cw_orch::QueryFns))]
#[cfg_attr(feature = "interface", impl_into(QueryMsg<ModuleMsg>))]
pub enum BaseQueryMsg {
    /// Returns [`AdapterConfigResponse`].
    #[returns(AdapterConfigResponse)]
    Config {},
    /// Returns [`AuthorizedAddressesResponse`].
    #[returns(AuthorizedAddressesResponse)]
    AuthorizedAddresses { proxy_address: String },
}

impl<T> From<BaseQueryMsg> for QueryMsg<T> {
    fn from(base: BaseQueryMsg) -> Self {
        Self::Base(base)
    }
}

#[cosmwasm_schema::cw_serde]
pub struct AdapterConfigResponse {
    pub version_control_address: Addr,
    pub ans_host_address: Addr,
    pub dependencies: Vec<String>,
}

#[cosmwasm_schema::cw_serde]
pub struct AuthorizedAddressesResponse {
    /// Contains all authorized addresses
    pub addresses: Vec<Addr>,
}