Skip to content

Commit

Permalink
feat: Implement balanced xcall manager
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonAndell committed Nov 16, 2023
1 parent 8dc6222 commit 7a9a212
Show file tree
Hide file tree
Showing 29 changed files with 1,410 additions and 96 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cw-codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
uses: taiki-e/install-action@cargo-llvm-cov

- name: Generate code coverage
run: cargo llvm-cov --lcov --output-path lcov.info --package cw-asset-manager --package cw-hub-bnusd
run: cargo llvm-cov --lcov --output-path lcov.info --package cw-asset-manager --package cw-hub-bnusd --package cw-xcall-manager

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
Expand Down
28 changes: 28 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ members = [
# "contracts/core-contracts/*",
"contracts/token-contracts/cw-hub-bnusd",
"contracts/core-contracts/cw-asset-manager",
"contracts/core-contracts/cw-xcall-manager",
"contracts/cw-common",
]

Expand Down
1 change: 1 addition & 0 deletions contracts/core-contracts/cw-asset-manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ debug_print = {workspace=true}
[dev-dependencies]
cw-multi-test = "0.16.4"
cw20-base = "1.0.1"
cw-xcall-manager = { path = "../cw-xcall-manager" }
cw-xcall-multi = {package="cw-xcall", git="https://github.com/icon-project/xcall-multi.git", branch="main", features=["library"]}
cw-xcall-lib={package="cw-xcall-lib", git="https://github.com/icon-project/xcall-multi.git", branch="main", features = ["library"]}
cw-common-ibc = { git = "https://github.com/icon-project/IBC-Integration.git", branch = "main", package = "cw-common"}
Expand Down
122 changes: 76 additions & 46 deletions contracts/core-contracts/cw-asset-manager/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ use std::str::FromStr;

use cosmwasm_std::{ensure, ensure_eq, entry_point};
use cosmwasm_std::{
to_binary, Addr, Binary, Deps, DepsMut, Env, Event, MessageInfo, QueryRequest, Response,
StdResult, SubMsg, Uint128, WasmMsg, WasmQuery,
to_binary, Addr, Binary, Deps, DepsMut, Env, Event, MessageInfo, Response, StdResult, SubMsg,
Uint128, WasmMsg,
};
use cw2::set_contract_version;
use cw20::{AllowanceResponse, Cw20ExecuteMsg, Cw20QueryMsg};

use cw_common::asset_manager_msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
use cw_common::helpers::{get_protocols, verify_protocol};
use cw_common::network_address::IconAddressValidation;
use cw_common::network_address::NetworkAddress;
use cw_common::x_call_msg::{GetNetworkAddress, XCallMsg};
use cw_common::x_call_msg::XCallMsg;
use cw_common::xcall_data_types::Deposit;

use crate::constants::SUCCESS_REPLY_MSG;
Expand All @@ -35,7 +36,12 @@ pub fn instantiate(
.map_err(ContractError::Std)?;
OWNER.save(deps.storage, &info.sender)?;

setup(deps, msg.source_xcall, msg.destination_asset_manager)
setup(
deps,
msg.source_xcall,
msg.destination_asset_manager,
msg.manager,
)
}

#[cfg_attr(not(feature = "library"), entry_point)]
Expand All @@ -49,12 +55,23 @@ pub fn execute(
ExecuteMsg::ConfigureXcall {
source_xcall,
destination_asset_manager,
manager,
} => {
let owner = OWNER.load(deps.storage).map_err(ContractError::Std)?;
ensure_eq!(owner, info.sender, ContractError::OnlyOwner);
setup(deps, source_xcall, destination_asset_manager)
setup(deps, source_xcall, destination_asset_manager, manager)
}
ExecuteMsg::HandleCallMessage { from, data } => {
ExecuteMsg::HandleCallMessage {
from,
data,
protocols,
} => {
let xcall_manger = X_CALL_MANAGER.load(deps.storage)?;
let res = verify_protocol(&deps, xcall_manger, protocols);
if res.is_err() {
return Err(ContractError::Unauthorized);

Check warning on line 72 in contracts/core-contracts/cw-asset-manager/src/contract.rs

View check run for this annotation

Codecov / codecov/patch

contracts/core-contracts/cw-asset-manager/src/contract.rs#L72

Added line #L72 was not covered by tests
}

exec::handle_xcall_msg(deps, env, info, from, data)
}
ExecuteMsg::ConfigureNative {
Expand Down Expand Up @@ -117,35 +134,24 @@ mod exec {
use cosmwasm_std::CosmosMsg;
use cw_ibc_rlp_lib::rlp::Encodable;

use cw_common::xcall_data_types::DepositRevert;
use cw_common::{helpers::query_network_address, xcall_data_types::DepositRevert};

use super::*;

fn query_network_address(
deps: &DepsMut,
x_call_addr: &Addr,
) -> Result<NetworkAddress, ContractError> {
let query_msg = GetNetworkAddress {};
let query = QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: x_call_addr.to_string(),
msg: to_binary(&query_msg).map_err(ContractError::Std)?,
});

deps.querier.query(&query).map_err(ContractError::Std)
}

pub fn setup(
deps: DepsMut,
source_xcall: String,
destination_asset_manager: String,
xcall_manager: Addr,
) -> Result<Response, ContractError> {
// validate source xcall
let x_call_addr = deps
.api
.addr_validate(&source_xcall)
.map_err(ContractError::Std)?;

let xcall_network_address: NetworkAddress = query_network_address(&deps, &x_call_addr)?;
let xcall_network_address: NetworkAddress =
query_network_address(&deps, &x_call_addr).unwrap();

if xcall_network_address.to_string().is_empty() {
return Err(ContractError::XAddressNotFound);
Expand All @@ -169,6 +175,7 @@ mod exec {
NID.save(deps.storage, &nid)?;
ICON_ASSET_MANAGER.save(deps.storage, &icon_asset_manager)?;
ICON_NET_ID.save(deps.storage, &icon_asset_manager.nid())?;
X_CALL_MANAGER.save(deps.storage, &xcall_manager)?;

Ok(Response::default())
}
Expand Down Expand Up @@ -253,6 +260,7 @@ mod exec {

let source_xcall = SOURCE_XCALL.load(deps.storage)?;
//create xcall msg for dispatching send call
let protocol_config = get_protocols(&deps, X_CALL_MANAGER.load(deps.storage)?).unwrap();
let xcall_message = XCallMsg::SendCallMessage {
to: dest_am.to_string().parse()?,
data: xcall_data.rlp_bytes().to_vec(),
Expand All @@ -265,8 +273,8 @@ mod exec {
.rlp_bytes()
.to_vec(),
),
sources: None,
destinations: None,
sources: Some(protocol_config.sources),
destinations: Some(protocol_config.destinations),
};

let xcall_msg = CosmosMsg::Wasm(WasmMsg::Execute {
Expand Down Expand Up @@ -497,10 +505,12 @@ mod tests {
ContractInfoResponse, ContractResult, MemoryStorage, OwnedDeps, SystemResult, Uint128,
WasmQuery,
};
use cw_common::xcall_manager_msg::QueryMsg::GetProtocols;
use cw_ibc_rlp_lib::rlp::Encodable;
use std::vec;

use cw_common::xcall_data_types::DepositRevert;
use cw_common::{asset_manager_msg::InstantiateMsg, xcall_data_types::WithdrawTo};
use cw_common::{xcall_data_types::DepositRevert, xcall_manager_msg::ProtocolConfig};

use super::*;

Expand All @@ -516,17 +526,26 @@ mod tests {
let info = mock_info("user", &[]);
//to pretend us as xcall contract during handle call execution testing
let xcall = "xcall";
let manager = "manager";

// mocking response for external query i.e. allowance
deps.querier.update_wasm(|r: &WasmQuery| match r {
WasmQuery::Smart {
contract_addr,
msg: _,
} => {
WasmQuery::Smart { contract_addr, msg } => {
if contract_addr == &xcall.to_owned() {
SystemResult::Ok(ContractResult::Ok(
to_binary(&"0x44.archway/xcall".to_owned()).unwrap(),
))
} else if contract_addr == &manager.to_owned() {
if msg == &to_binary(&GetProtocols {}).unwrap() {
return SystemResult::Ok(ContractResult::Ok(
to_binary(&ProtocolConfig {
sources: vec![],
destinations: vec![],
})
.unwrap(),
));
}
SystemResult::Ok(ContractResult::Ok(to_binary(&true).unwrap()))
} else {
//mock allowance resp
let allowance_resp = AllowanceResponse {
Expand All @@ -553,6 +572,7 @@ mod tests {
source_xcall: xcall.to_owned(),
destination_asset_manager: "0x01.icon/cxc2d01de5013778d71d99f985e4e2ff3a9b48a66c"
.to_owned(),
manager: Addr::unchecked(manager),
},
)
.unwrap();
Expand Down Expand Up @@ -696,6 +716,7 @@ mod tests {
let msg = ExecuteMsg::HandleCallMessage {
from: xcall_nw.to_string(),
data: x_deposit_revert.rlp_bytes().to_vec(),
protocols: vec![],
};

let result = execute(deps.as_mut(), env.clone(), mocked_xcall_info.clone(), msg);
Expand All @@ -715,6 +736,7 @@ mod tests {
let exe_msg = ExecuteMsg::HandleCallMessage {
from: am_nw.to_string(),
data: withdraw_msg.rlp_bytes().to_vec(),
protocols: vec![],
};
let resp = execute(
deps.as_mut(),
Expand All @@ -739,6 +761,7 @@ mod tests {
let unknown_msg = ExecuteMsg::HandleCallMessage {
from: xcall_nw.to_string(),
data: x_msg.rlp_bytes().to_vec(),
protocols: vec![],
};

//check for error due to unknown xcall handle data
Expand All @@ -763,25 +786,30 @@ mod tests {

deps.querier.update_wasm(|r: &WasmQuery| match r {
WasmQuery::Smart {
contract_addr: _,
contract_addr,
msg: _,
} => SystemResult::Ok(ContractResult::Ok(
to_binary(&ConfigResponse {
admin: "".to_string(),
pause_admin: "".to_string(),
bond_denom: "".to_string(),
liquid_token_addr: "".to_string(),
swap_contract_addr: swap.to_string(),
treasury_contract_addr: "".to_string(),
team_wallet_addr: "".to_string(),
commission_percentage: 1,
team_percentage: 1,
liquidity_percentage: 1,
delegations: vec![],
contract_state: false,
})
.unwrap(),
)),
} => {
if contract_addr == &"manager".to_owned() {
return SystemResult::Ok(ContractResult::Ok(to_binary(&true).unwrap()));
}
SystemResult::Ok(ContractResult::Ok(
to_binary(&ConfigResponse {
admin: "".to_string(),
pause_admin: "".to_string(),
bond_denom: "".to_string(),
liquid_token_addr: "".to_string(),
swap_contract_addr: swap.to_string(),
treasury_contract_addr: "".to_string(),
team_wallet_addr: "".to_string(),
commission_percentage: 1,
team_percentage: 1,
liquidity_percentage: 1,
delegations: vec![],
contract_state: false,
})
.unwrap(),
))
}
_ => todo!(),
});

Expand All @@ -806,6 +834,7 @@ mod tests {
let exe_msg = ExecuteMsg::HandleCallMessage {
from: am_nw.to_string(),
data: withdraw_msg.rlp_bytes().to_vec(),
protocols: vec![],
};
let resp = execute(
deps.as_mut(),
Expand All @@ -828,6 +857,7 @@ mod tests {
let msg = ExecuteMsg::ConfigureXcall {
source_xcall: source_xcall.to_owned(),
destination_asset_manager: destination_asset_manager.to_owned(),
manager: Addr::unchecked("manager".to_owned()),
};

let res = execute(deps.as_mut(), env.clone(), info, msg.clone());
Expand Down
3 changes: 3 additions & 0 deletions contracts/core-contracts/cw-asset-manager/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ pub enum ContractError {

#[error("Rlp Error: {error}")]
DecoderError { error: DecoderError },

#[error("Unauthorized")]
Unauthorized,
}

impl From<DecoderError> for ContractError {
Expand Down
3 changes: 2 additions & 1 deletion contracts/core-contracts/cw-asset-manager/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ pub const OWNER: Item<Addr> = Item::new("contract_owner");
pub const SOURCE_XCALL: Item<Addr> = Item::new("source_xcall_address");
pub const X_CALL_NETWORK_ADDRESS: Item<NetworkAddress> = Item::new("source_xcall_network_address");
pub const NID: Item<NetId> = Item::new("network_id");

pub const ICON_ASSET_MANAGER: Item<NetworkAddress> =
Item::new("icon_asset_manager_network_address");
pub const ICON_NET_ID: Item<NetId> = Item::new("icon_asset_manager_network_id");

pub const NATIVE_TOKEN_ADDRESS: Item<Addr> = Item::new("native_token_address");
pub const NATIVE_TOKEN_MANAGER: Item<Addr> = Item::new("native_token_manager");

pub const X_CALL_MANAGER: Item<Addr> = Item::new("xcall_manager");
Loading

0 comments on commit 7a9a212

Please sign in to comment.