Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions code/xcvm/cosmwasm/contracts/gateway/src/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use xc_core::{AssetId, NetworkId};
pub(crate) fn force_asset(_: auth::Admin, deps: DepsMut, msg: AssetItem) -> Result {
let config = crate::state::load(deps.storage)?;
ASSETS.save(deps.storage, msg.asset_id, &msg)?;
if msg.from_network_id == config.here_id {
if msg.network_id == config.network_id {
LOCAL_ASSETS.save(deps.storage, msg.local.clone(), &msg)?;
}
Ok(Response::new().add_event(
Expand Down Expand Up @@ -50,7 +50,7 @@ pub(crate) fn force_remove_asset(
let config = crate::state::load(deps.storage)?;
let asset = ASSETS.load(deps.storage, asset_id)?;
ASSETS.remove(deps.storage, asset_id);
if asset.from_network_id == config.here_id {
if asset.network_id == config.network_id {
LOCAL_ASSETS.remove(deps.storage, asset.local);
}
Ok(Response::new()
Expand Down
38 changes: 28 additions & 10 deletions code/xcvm/cosmwasm/contracts/gateway/src/auth.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Module with authorisation checks.
use crate::{
error::{ContractError, Result},
msg, state,
msg, network, state,
};
use cosmwasm_std::{Deps, Env, MessageInfo, Storage};
use cosmwasm_std::{Deps, Env, MessageInfo};
use xc_core::{gateway::OtherNetworkItem, NetworkId};

/// Authorisation token indicating call is authorised according to policy
Expand Down Expand Up @@ -39,28 +39,46 @@ impl Auth<policy::Contract> {

impl Auth<policy::WasmHook> {
pub(crate) fn authorise(
storage: &dyn Storage,
deps: Deps,
env: &Env,
info: &MessageInfo,
network_id: NetworkId,
) -> Result<Self> {
let this = state::load(storage)?;
let this_to_other: OtherNetworkItem =
state::NETWORK_TO_NETWORK.load(storage, (this.here_id, network_id))?;
let this = network::load_this(deps.storage)?;
let this_to_other: OtherNetworkItem = state::NETWORK_TO_NETWORK
.load(deps.storage, (this.network_id, network_id))
.map_err(|_| {
ContractError::NoConnectionInformationFromThisToOtherNetwork(
this.network_id,
network_id,
)
})?;
let prefix = this
.accounts
.map(|x| match x {
msg::Prefix::SS58(prefix) => prefix.to_string(),
msg::Prefix::Bech(prefix) => prefix,
})
.unwrap_or_default();
let sender = state::NETWORK
.load(storage, network_id)?
.load(deps.storage, network_id)?
.gateway
.ok_or(ContractError::NotAuthorized)?;
.ok_or(ContractError::GatewayForNetworkNotFound(network_id))?;

let sender = match sender {
msg::GatewayId::CosmWasm { contract, .. } => contract.to_string(),
};

let channel = this_to_other.ics_20.ok_or(ContractError::ICS20NotFound)?.source;
let hash_of_channel_and_sender =
xc_core::transport::ibc::ics20::hook::derive_intermediate_sender(
&channel, &sender, "",
&channel, &sender, &prefix,
)?;
Self::new(hash_of_channel_and_sender == info.sender && info.sender == env.contract.address)
deps.api.debug(&format!(
"xcvm::gateway:auth:: {0} {1}",
&hash_of_channel_and_sender, &info.sender
));
Self::new(hash_of_channel_and_sender == info.sender || info.sender == env.contract.address)
}
}

Expand Down
19 changes: 14 additions & 5 deletions code/xcvm/cosmwasm/contracts/gateway/src/contract/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ use xc_core::{gateway::ConfigSubMsg, CallOrigin, Displayed, Funds, InterpreterOr
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: msg::ExecuteMsg) -> Result {
use msg::ExecuteMsg;
let sender = &info.sender;
let canonical_sender = deps.api.addr_canonicalize(sender.as_str())?;
deps.api.debug(&format!(
"xcvm::gateway::execute sender on chain {}, sender cross chain {}",
sender,
&serde_json_wasm::to_string(&canonical_sender)?
));
match msg {
ExecuteMsg::Config(msg) => {
let auth = auth::Admin::authorise(deps.as_ref(), &info)?;
Expand All @@ -37,15 +44,17 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: msg::ExecuteMsg)
auth::Interpreter::authorise(deps.as_ref(), &info, msg.interpreter_origin.clone())?;

if !msg.msg.assets.0.is_empty() {
super::ibc::ics20::handle_bridge_forward(auth, deps, info, msg)
super::ibc::ics20::handle_bridge_forward(auth, deps, info, msg, env.block)
} else {
super::ibc::xcvm::handle_bridge_forward_no_assets(auth, deps, info, msg)
super::ibc::xcvm::handle_bridge_forward_no_assets(auth, deps, info, msg, env.block)
}
},
msg::ExecuteMsg::MessageHook(msg) => {
deps.api.debug(&serde_json_wasm::to_string(&msg)?);
let auth = auth::WasmHook::authorise(deps.storage, &env, &info, msg.from_network_id)?;
super::ibc::ics20::ics20_message_hook(auth, msg, env, info)
deps.api.debug(&format!("xcvm::gateway::execute::message_hook {:?}", msg));

let auth = auth::WasmHook::authorise(deps.as_ref(), &env, &info, msg.from_network_id)?;

super::ibc::ics20::ics20_message_hook(auth, deps.as_ref(), msg, env, info)
},
msg::ExecuteMsg::Shortcut(msg) => handle_shortcut(deps, env, info, msg),
}
Expand Down
65 changes: 44 additions & 21 deletions code/xcvm/cosmwasm/contracts/gateway/src/contract/ibc/ics20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
//! Allows to map asset identifiers, contracts, networks, channels, denominations from, to and on
//! each chain via contract storage, precompiles, host extensions.
//! handles PFM and IBC wasm hooks
use crate::prelude::*;
use crate::{network, prelude::*};
use cosmwasm_std::{
ensure_eq, wasm_execute, Binary, Coin, DepsMut, Env, MessageInfo, Response, Storage, SubMsg,
ensure_eq, wasm_execute, Binary, BlockInfo, Coin, Deps, DepsMut, Env, MessageInfo, Response,
Storage, SubMsg,
};
use xc_core::{
gateway::{AssetItem, ExecuteMsg, ExecuteProgramMsg, GatewayId, OtherNetworkItem},
shared::{XcPacket, XcProgram},
gateway::{AssetItem, ExecuteMsg, ExecuteProgramMsg, GatewayId},
shared::{XcFunds, XcPacket, XcProgram},
transport::ibc::{to_cw_message, IbcIcs20Route, XcMessageData},
AssetId, CallOrigin,
AssetId, CallOrigin, Displayed,
};

use crate::{
Expand All @@ -27,6 +28,7 @@ pub(crate) fn handle_bridge_forward(
deps: DepsMut,
info: MessageInfo,
msg: xc_core::gateway::BridgeForwardMsg,
block: BlockInfo,
) -> Result {
deps.api.debug(&format!(
"xcvm::gateway:: forwarding over IBC ICS20 MEMO {}",
Expand All @@ -37,17 +39,26 @@ pub(crate) fn handle_bridge_forward(
// 1. recurse on program until can with memo
// 2. as soon as see no Spawn/Transfer, stop memo and do Wasm call with remaining Packet

let (local_asset, amount) = msg.msg.assets.0.get(0).expect("proved above");

let route: IbcIcs20Route = get_route(deps.storage, msg.to, *local_asset)?;

let asset = msg
.msg
.assets
.0
.get(0)
.map(|(_, amount)| (route.on_remote_asset, *amount))
.expect("not empty");

let packet = XcPacket {
interpreter: String::from(info.sender).into_bytes(),
user_origin: msg.interpreter_origin.user_origin,
salt: msg.msg.salt,
program: msg.msg.program,
assets: msg.msg.assets,
assets: vec![asset].into(),
};

let (local_asset, amount) = packet.assets.0.get(0).expect("proved above");

let route = get_route(deps.storage, msg.to, *local_asset)?;
deps.api.debug(&format!(
"xcvm::gateway::ibc::ics20 route {}",
&serde_json_wasm::to_string(&route)?
Expand All @@ -71,7 +82,7 @@ pub(crate) fn handle_bridge_forward(

let coin = Coin::new(amount.0, route.local_native_denom.clone());

let msg = to_cw_message(coin, route, packet)?;
let msg = to_cw_message(deps.api, coin, route, packet, block)?;
deps.api.debug(&format!(
"xcvm::gateway::ibc::ics20:: payload {}",
&serde_json_wasm::to_string(&msg)?
Expand All @@ -89,19 +100,14 @@ pub fn get_route(
this_asset_id: AssetId,
) -> Result<IbcIcs20Route, ContractError> {
let this = load_this(storage)?;
let other: NetworkItem = state::NETWORK
.load(storage, to)
.map_err(|_| ContractError::UnknownTargetNetwork)?;
let this_to_other: OtherNetworkItem = state::NETWORK_TO_NETWORK
.load(storage, (this.network_id, to))
.map_err(|_| ContractError::NoConnectionInformationFromThisToOtherNetwork)?;
let other = network::load_other(storage, to)?;
let asset: AssetItem = state::assets::ASSETS
.load(storage, this_asset_id)
.map_err(|_| ContractError::AssetNotFoundById(this_asset_id))?;
let to_asset: AssetId = state::assets::NETWORK_ASSET
.load(storage, (this_asset_id, to))
.map_err(|_| ContractError::AssetCannotBeTransferredToNetwork(this_asset_id, to))?;
let gateway_to_send_to = other.gateway.ok_or(ContractError::UnsupportedNetwork)?;
let gateway_to_send_to = other.network.gateway.ok_or(ContractError::UnsupportedNetwork)?;
let gateway_to_send_to = match gateway_to_send_to {
GatewayId::CosmWasm { contract, .. } => contract,
};
Expand All @@ -110,15 +116,15 @@ pub fn get_route(
GatewayId::CosmWasm { contract, .. } => contract,
};

let channel = this_to_other.ics_20.ok_or(ContractError::ICS20NotFound)?.source;
let channel = other.connection.ics_20.ok_or(ContractError::ICS20NotFound)?.source;

Ok(IbcIcs20Route {
from_network: this.network_id,
local_native_denom: asset.local.denom(),
channel_to_send_over: channel,
gateway_to_send_to,
sender_gateway,
counterparty_timeout: this_to_other.counterparty_timeout,
counterparty_timeout: other.connection.counterparty_timeout,
ibc_ics_20_sender: this
.ibc
.ok_or(ContractError::ICS20NotFound)?
Expand All @@ -133,15 +139,32 @@ pub fn get_route(

pub(crate) fn ics20_message_hook(
_: auth::WasmHook,
deps: Deps,
msg: XcMessageData,
env: Env,
info: MessageInfo,
) -> Result<Response, ContractError> {
let packet: XcPacket = msg.packet;
ensure_anonymous(&packet.program)?;
deps.api.debug(&format!(
"xcvm::gateway::ibc::ics20:: received assets {:?}, packet assets {:?}",
&info.funds, &packet.assets
));

let assets: Result<XcFunds, ContractError> = info
.funds
.into_iter()
.map(|coin| {
let asset = crate::assets::get_local_asset_by_reference(
deps,
AssetReference::Native { denom: coin.denom },
)?;
Ok((asset.asset_id, Displayed::<u128>::from(coin.amount.u128())))
})
.collect();
let call_origin = CallOrigin::Remote { user_origin: packet.user_origin };
let execute_program =
ExecuteProgramMsg { salt: packet.salt, program: packet.program, assets: packet.assets };
ExecuteProgramMsg { salt: packet.salt, program: packet.program, assets: assets?.into() };
let msg =
ExecuteMsg::ExecuteProgramPrivileged { call_origin, execute_program, tip: info.sender };
let msg = wasm_execute(env.contract.address, &msg, Default::default())?;
Expand All @@ -153,7 +176,7 @@ fn ensure_anonymous(program: &XcProgram) -> Result<()> {
match ix {
xc_core::Instruction::Transfer { .. } => {},
xc_core::Instruction::Spawn { program, .. } => ensure_anonymous(program)?,
_ => Err(ContractError::NotAuthorized)?,
_ => Err(ContractError::AnonymousCallsCanDoOnlyLimitedSetOfActions)?,
}
}
Ok(())
Expand Down
11 changes: 6 additions & 5 deletions code/xcvm/cosmwasm/contracts/gateway/src/contract/ibc/xcvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ use crate::{
};

use cosmwasm_std::{
ensure_eq, wasm_execute, Binary, DepsMut, Env, Ibc3ChannelOpenResponse, IbcBasicResponse,
IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcChannelOpenResponse, IbcMsg,
IbcOrder, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse,
MessageInfo, Response, SubMsg,
ensure_eq, wasm_execute, Binary, BlockInfo, DepsMut, Env, Ibc3ChannelOpenResponse,
IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg,
IbcChannelOpenResponse, IbcMsg, IbcOrder, IbcPacketAckMsg, IbcPacketReceiveMsg,
IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Response, SubMsg,
};
use ibc_rs_scale::core::ics24_host::identifier::{ChannelId, ConnectionId};
use xc_core::{
Expand Down Expand Up @@ -143,6 +143,7 @@ pub(crate) fn handle_bridge_forward_no_assets(
deps: DepsMut,
info: MessageInfo,
msg: msg::BridgeForwardMsg,
block: BlockInfo,
) -> Result<Response> {
ensure_eq!(msg.msg.assets.0.len(), 0, ContractError::CannotTransferAssets);
let other = load_other(deps.storage, msg.to)?;
Expand Down Expand Up @@ -178,6 +179,6 @@ pub(crate) fn handle_bridge_forward_no_assets(
channel_id: channel_id.to_string(),
data: Binary::from(packet.encode()),
// TODO: should be a parameter or configuration
timeout: other.connection.counterparty_timeout,
timeout: other.connection.counterparty_timeout.absolute(block),
}))
}
8 changes: 6 additions & 2 deletions code/xcvm/cosmwasm/contracts/gateway/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,17 @@ pub enum ContractError {
NetworkConfig,
#[error("Unknown target network")]
UnknownTargetNetwork,
#[error("No connection information from this to other network")]
NoConnectionInformationFromThisToOtherNetwork,
#[error("No connection information from this {0} to other network {1}")]
NoConnectionInformationFromThisToOtherNetwork(NetworkId, NetworkId),

#[error("Asset {0} not found by id")]
AssetNotFoundById(AssetId),
#[error("Asset {0} cannot be transferred to network {1}")]
AssetCannotBeTransferredToNetwork(AssetId, NetworkId),
#[error("Gateway for network {0} not found")]
GatewayForNetworkNotFound(NetworkId),
#[error("Anonymous calls can do only limitet set of actions")]
AnonymousCallsCanDoOnlyLimitedSetOfActions,
}

impl From<bech32_no_std::Error> for ContractError {
Expand Down
4 changes: 2 additions & 2 deletions code/xcvm/cosmwasm/contracts/gateway/src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ pub(crate) fn force_instantiate(
gateway: Addr,
deps: DepsMut,
user_origin: Addr,
salt: Option<String>,
salt: String,
) -> Result {
let config = load_this(deps.storage)?;
let interpreter_code_id = match config.gateway.expect("expected setup") {
GatewayId::CosmWasm { interpreter_code_id, .. } => interpreter_code_id,
};
let salt = salt.map_or(<_>::default(), |x| x.into_bytes());
let salt = salt.into_bytes();

let call_origin = CallOrigin::Local { user: user_origin };
let interpreter_origin =
Expand Down
8 changes: 4 additions & 4 deletions code/xcvm/cosmwasm/contracts/gateway/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::error::{ContractError, Result};

pub fn load_this(storage: &dyn Storage) -> Result<NetworkItem> {
state::load(storage)
.and_then(|this| NETWORK.load(storage, this.here_id))
.and_then(|this| NETWORK.load(storage, this.network_id))
.map_err(|_| ContractError::NetworkConfig)
}

Expand All @@ -19,10 +19,10 @@ pub struct OtherNetwork {
pub connection: OtherNetworkItem,
}

pub fn load_other(storage: &dyn Storage, _other: NetworkId) -> Result<OtherNetwork> {
pub fn load_other(storage: &dyn Storage, other: NetworkId) -> Result<OtherNetwork> {
let this = state::load(storage)?;
let other = NETWORK.load(storage, this.here_id)?;
let connection = NETWORK_TO_NETWORK.load(storage, (this.here_id, other.network_id))?;
let other = NETWORK.load(storage, other)?;
let connection = NETWORK_TO_NETWORK.load(storage, (this.network_id, other.network_id))?;
Ok(OtherNetwork { network: other, connection })
}

Expand Down
1 change: 1 addition & 0 deletions code/xcvm/cosmwasm/contracts/gateway/src/prelude.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub use alloc::format;
pub use cosmwasm_std::{to_binary, Addr};
pub use cw_storage_plus::Map;
pub use ibc_rs_scale::core::ics24_host::identifier::{ChannelId, ConnectionId};
Expand Down
2 changes: 1 addition & 1 deletion code/xcvm/cosmwasm/contracts/interpreter/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ pub fn interpret_transfer(
assets: Funds<Balance>,
) -> Result {
let Config { gateway_address: gateway, .. } = CONFIG.load(deps.storage)?;

deps.api.debug(&format!("xcvm::interpreter:: transfer to {:?}", &to));
let recipient = match to {
Destination::Account(account) => deps.api.addr_humanize(&account)?.into_string(),
Destination::Tip => tip.into(),
Expand Down
4 changes: 2 additions & 2 deletions code/xcvm/cosmwasm/tests/src/tests/framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ impl TestVM<()> {
tx.info.clone(),
tx.gas,
xc_core::gateway::InstantiateMsg(HereItem {
here_id: self.network_id,
network_id: self.network_id,
admin: todo!(),
}),
)?;
Expand Down Expand Up @@ -274,7 +274,7 @@ impl<T> TestVM<XCVMState<T>> {
tx.gas,
xc_core::gateway::ExecuteMsg::Config(ConfigSubMsg::ForceAsset(AssetItem {
asset_id,
from_network_id: todo!("restore"),
network_id: todo!("restore"),
local: xc_core::gateway::AssetReference::Cw20 {
contract: asset_address.clone().into(),
},
Expand Down
Loading