Skip to content
Closed
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
12 changes: 5 additions & 7 deletions contracts/ibc-reflect-send/src/ibc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use cosmwasm_std::{
entry_point, from_slice, to_binary, DepsMut, Env, IbcBasicResponse, IbcChannelCloseMsg,
IbcChannelConnectMsg, IbcChannelOpenMsg, IbcMsg, IbcOrder, IbcPacketAckMsg,
entry_point, entry_point_adv, from_slice, to_binary, AdvResult, DepsMut, Env, IbcBasicResponse,
IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcMsg, IbcOrder, IbcPacketAckMsg,
IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, Never, StdError, StdResult,
};

Expand Down Expand Up @@ -89,16 +89,14 @@ pub fn ibc_channel_close(
.add_attribute("channel_id", channel_id))
}

#[entry_point]
#[entry_point_adv]
/// never should be called as the other side never sends packets
pub fn ibc_packet_receive(
_deps: DepsMut,
_env: Env,
_packet: IbcPacketReceiveMsg,
) -> Result<IbcReceiveResponse, Never> {
Ok(IbcReceiveResponse::new()
.set_ack(b"{}")
.add_attribute("action", "ibc_packet_ack"))
) -> AdvResult<IbcReceiveResponse, Never> {
AdvResult::Abort
}

#[entry_point]
Expand Down
1 change: 1 addition & 0 deletions packages/derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ proc-macro = true

[features]
default = []
stargate = [ "cosmwasm-std/stargate"]

[dependencies]
syn = { version = "1.0", features = ["full"] }
Expand Down
59 changes: 59 additions & 0 deletions packages/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,62 @@ pub fn entry_point(_attr: TokenStream, mut item: TokenStream) -> TokenStream {
item.extend(entry);
item
}

/// This attribute macro generates the boilerplate required to call into the
/// contract-specific logic from the entry-points to the Wasm module.
///
/// It should be added to the contract's init, handle, migrate and query implementations
/// like this:
/// ```
/// # use cosmwasm_std::{
/// # Storage, Api, Querier, DepsMut, Deps, entry_point_adv, Env, IbcPacketReceiveMsg,
/// # IbcReceiveResponse, StdError, MessageInfo, Response, QueryResponse,
/// # };
/// #
/// # type InstantiateMsg = ();
/// # type ExecuteMsg = ();
/// # type QueryMsg = ();
///
/// #[entry_point_adv]
/// pub fn ibc_packet_receive(
/// deps: DepsMut,
/// env: Env,
/// msg: IbcPacketReceiveMsg,
/// ) -> Result<IbcReceiveResponse, StdError> {
/// # Ok(Default::default())
/// }
/// ```
///
/// This only works for ibc_packet_receive if you want to use new advanced interface
#[cfg(feature = "stargate")]
#[proc_macro_attribute]
pub fn entry_point_adv(_attr: TokenStream, mut item: TokenStream) -> TokenStream {
let cloned = item.clone();
let function = parse_macro_input!(cloned as syn::ItemFn);
let name = function.sig.ident.to_string();
// The first argument is `deps`, the rest is region pointers
let args = function.sig.inputs.len() - 1;

// E.g. "ptr0: u32, ptr1: u32, ptr2: u32, "
let typed_ptrs = (0..args).fold(String::new(), |acc, i| format!("{}ptr{}: u32, ", acc, i));
// E.g. "ptr0, ptr1, ptr2, "
let ptrs = (0..args).fold(String::new(), |acc, i| format!("{}ptr{}, ", acc, i));

let new_code = format!(
r##"
#[cfg(target_arch = "wasm32")]
mod __wasm_export_{name} {{ // new module to avoid conflict of function name
#[no_mangle]
extern "C" fn {name}({typed_ptrs}) -> u32 {{
cosmwasm_std::do_{name}_adv(&super::{name}, {ptrs})
}}
}}
"##,
name = name,
typed_ptrs = typed_ptrs,
ptrs = ptrs
);
let entry = TokenStream::from_str(&new_code).unwrap();
item.extend(entry);
item
}
2 changes: 1 addition & 1 deletion packages/std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ staking = []
backtraces = []
# stargate enables stargate-dependent messages and queries, like raw protobuf messages
# as well as ibc-related functionality
stargate = []
stargate = ["cosmwasm-derive/stargate"]
# ibc3 extends ibc messages with ibc-v3 only features. This should only be enabled on contracts
# that require these types. Without this, they get the smaller ibc-v1 API.
ibc3 = ["stargate"]
Expand Down
76 changes: 76 additions & 0 deletions packages/std/src/exports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ use crate::memory::{alloc, consume_region, release_buffer, Region};
#[cfg(feature = "abort")]
use crate::panic::install_panic_handler;
use crate::query::CustomQuery;
#[cfg(feature = "stargate")]
use crate::results::{AdvContractResult, AdvResult};
use crate::results::{ContractResult, QueryResponse, Reply, Response};
use crate::serde::{from_slice, to_vec};
use crate::types::Env;
Expand Down Expand Up @@ -86,6 +88,22 @@ macro_rules! r#try_into_contract_result {
};
}

// TODO: replace with https://doc.rust-lang.org/std/ops/trait.Try.html once stabilized
#[cfg(feature = "stargate")]
macro_rules! r#try_into_adv_contract_result {
($expr:expr) => {
match $expr {
Ok(val) => val,
Err(err) => {
return AdvContractResult::Err(err.to_string());
}
}
};
($expr:expr,) => {
$crate::try_into_adv_contract_result!($expr)
};
}

/// This should be wrapped in an external "C" export, containing a contract-specific function as an argument.
///
/// - `Q`: custom query type (see QueryRequest)
Expand Down Expand Up @@ -338,6 +356,39 @@ where
release_buffer(v) as u32
}

/// do_ibc_packet_receive is designed for use with #[entry_point_adv] to make a "C" extern
///
/// This allows us to return a new Abort type not just Ok or Err
///
/// contract_fn is called when this chain receives an IBC Packet on a channel belonging
/// to this contract
///
/// - `Q`: custom query type (see QueryRequest)
/// - `C`: custom response message type (see CosmosMsg)
/// - `E`: error type for responses
#[cfg(feature = "stargate")]
pub fn do_ibc_packet_receive_adv<Q, C, E>(
contract_fn: &dyn Fn(
DepsMut<Q>,
Env,
IbcPacketReceiveMsg,
) -> AdvResult<IbcReceiveResponse<C>, E>,
env_ptr: u32,
msg_ptr: u32,
) -> u32
where
Q: CustomQuery,
C: CustomMsg,
E: ToString,
{
#[cfg(feature = "abort")]
install_panic_handler();
let res =
_do_ibc_packet_receive_adv(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region);
let v = to_vec(&res).unwrap();
release_buffer(v) as u32
}

/// do_ibc_packet_ack is designed for use with #[entry_point] to make a "C" extern
///
/// contract_fn is called when this chain receives an IBC Acknowledgement for a packet
Expand Down Expand Up @@ -604,6 +655,31 @@ where
contract_fn(deps.as_mut(), env, msg).into()
}

#[cfg(feature = "stargate")]
fn _do_ibc_packet_receive_adv<Q, C, E>(
contract_fn: &dyn Fn(
DepsMut<Q>,
Env,
IbcPacketReceiveMsg,
) -> AdvResult<IbcReceiveResponse<C>, E>,
env_ptr: *mut Region,
msg_ptr: *mut Region,
) -> AdvContractResult<IbcReceiveResponse<C>>
where
Q: CustomQuery,
C: CustomMsg,
E: ToString,
{
let env: Vec<u8> = unsafe { consume_region(env_ptr) };
let msg: Vec<u8> = unsafe { consume_region(msg_ptr) };

let env: Env = try_into_adv_contract_result!(from_slice(&env));
let msg: IbcPacketReceiveMsg = try_into_adv_contract_result!(from_slice(&msg));

let mut deps = make_dependencies();
contract_fn(deps.as_mut(), env, msg).into()
}

#[cfg(feature = "stargate")]
fn _do_ibc_packet_ack<Q, C, E>(
contract_fn: &dyn Fn(DepsMut<Q>, Env, IbcPacketAckMsg) -> Result<IbcBasicResponse<C>, E>,
Expand Down
10 changes: 6 additions & 4 deletions packages/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ pub use crate::results::SubMsgExecutionResponse;
#[cfg(all(feature = "stargate", feature = "cosmwasm_1_2"))]
pub use crate::results::WeightedVoteOption;
pub use crate::results::{
attr, wasm_execute, wasm_instantiate, Attribute, BankMsg, ContractResult, CosmosMsg, CustomMsg,
Empty, Event, QueryResponse, Reply, ReplyOn, Response, SubMsg, SubMsgResponse, SubMsgResult,
SystemResult, WasmMsg,
attr, wasm_execute, wasm_instantiate, AdvContractResult, AdvResult, Attribute, BankMsg,
ContractResult, CosmosMsg, CustomMsg, Empty, Event, QueryResponse, Reply, ReplyOn, Response,
SubMsg, SubMsgResponse, SubMsgResult, SystemResult, WasmMsg,
};
#[cfg(feature = "staking")]
pub use crate::results::{DistributionMsg, StakingMsg};
Expand All @@ -99,7 +99,7 @@ pub use crate::exports::{do_execute, do_instantiate, do_migrate, do_query, do_re
#[cfg(all(feature = "stargate", target_arch = "wasm32"))]
pub use crate::exports::{
do_ibc_channel_close, do_ibc_channel_connect, do_ibc_channel_open, do_ibc_packet_ack,
do_ibc_packet_receive, do_ibc_packet_timeout,
do_ibc_packet_receive, do_ibc_packet_receive_adv, do_ibc_packet_timeout,
};
#[cfg(target_arch = "wasm32")]
pub use crate::imports::{ExternalApi, ExternalQuerier, ExternalStorage};
Expand All @@ -112,3 +112,5 @@ pub mod testing;
// Re-exports

pub use cosmwasm_derive::entry_point;
#[cfg(feature = "stargate")]
pub use cosmwasm_derive::entry_point_adv;
Loading