Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Added ibc hooks
  • Loading branch information
Kayanski committed Nov 12, 2024
commit 337158023dbb0fc3951cbb637c5b0d257e7242e9
176 changes: 126 additions & 50 deletions framework/Cargo.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions framework/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ incremental = false

abstract-cw-multi-test = { git = "https://github.com/abstractsdk/cw-multi-test-fork", branch = "feature/add-ics20-transfer-data" }
# abstract-cw-multi-test = { path = "../../cw-multi-test" }
cw-orch-interchain-core = { git = "https://github.com/abstractsdk/cw-orchestrator", branch = "interchain/add-ics-hooks-ack" }
cw-orch-core = { git = "https://github.com/abstractsdk/cw-orchestrator", branch = "interchain/add-ics-hooks-ack" }
# cw-orch-interchain-daemon = { git = "https://github.com/abstractsdk/cw-orchestrator", branch = "interchain/add-ics-hooks-ack" }
# cw-orch-interchain-mock = { git = "https://github.com/abstractsdk/cw-orchestrator", branch = "interchain/add-ics-hooks-ack" }

[workspace.metadata.cargo-udeps.ignore]
# ensures CI doens't flag workspace-hack as unused dep
Expand Down
82 changes: 10 additions & 72 deletions framework/contracts/account/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use abstract_sdk::{
use abstract_std::{
account::{
state::{AccountInfo, WhitelistedModules, INFO, SUSPENSION_STATUS, WHITELISTED_MODULES},
ICS20PacketIdentifier, UpdateSubAccountAction,
UpdateSubAccountAction,
},
module_factory::SimulateInstallModulesResponse,
objects::{
Expand All @@ -21,10 +21,10 @@ use abstract_std::{
},
registry::state::LOCAL_ACCOUNT_SEQUENCE,
};

use cosmwasm_std::{
ensure_eq, wasm_execute, Addr, Binary, Coins, Deps, DepsMut, Env, IbcAckCallbackMsg,
IbcBasicResponse, IbcSourceCallbackMsg, IbcTimeoutCallbackMsg, MessageInfo, Reply, Response,
StdAck, StdResult,
ensure_eq, wasm_execute, Addr, Binary, Coins, Deps, DepsMut, Env, MessageInfo, Reply, Response,
StdResult,
};

pub use crate::migrate::migrate;
Expand All @@ -36,12 +36,13 @@ use crate::{
execute_msgs_with_data, execute_on_module, ica_action, remove_auth_method,
send_funds_with_actions,
},
ics20::ics20_hook_callback,
modules::{
_install_modules, install_modules,
migration::{assert_modules_dependency_requirements, upgrade_modules},
uninstall_module, MIGRATE_CONTEXT,
},
msg::{ExecuteMsg, InstantiateMsg, QueryMsg, ICS20_CALLBACKS},
msg::{ExecuteMsg, InstantiateMsg, QueryMsg, SudoMsg},
queries::{
handle_account_info_query, handle_config_query, handle_module_address_query,
handle_module_info_query, handle_module_versions_query, handle_sub_accounts_query,
Expand Down Expand Up @@ -418,78 +419,15 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {
}

#[cfg_attr(feature = "export", cosmwasm_std::entry_point)]
pub fn ibc_source_callback(
deps: DepsMut,
env: Env,
msg: IbcSourceCallbackMsg,
) -> StdResult<IbcBasicResponse> {
pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> AccountResult {
match msg {
IbcSourceCallbackMsg::Acknowledgement(IbcAckCallbackMsg {
acknowledgement,
original_packet,
relayer: _,
..
}) => {
let packet_identifier = ICS20PacketIdentifier {
channel_id: original_packet.src.channel_id,
sequence: original_packet.sequence,
};

// TODO: This needs to change to better assert the success ack
// TODO: we also need to authenticate the original packet that needs to be a packet coming from transfer ports
// TODO, this will most likely fail to or from union

// TODO: The acknowledgement actually has this structure with ibc hooks, we need to coed accordingly
// TODO: https://github.com/cosmos/ibc-apps/blob/8cb681e31589bc90b47e0ab58173a579825fd56d/modules/ibc-hooks/wasm_hook.go#L119C1-L119C86

let (outcome, stored_msgs) =
if acknowledgement.data == StdAck::success(b"\x01").to_binary() {
(
"result",
ICS20_CALLBACKS
.load(deps.storage, packet_identifier.clone())?
.into_iter()
.map(|msg| wasm_execute(&env.contract.address, &msg, vec![]))
.collect::<Result<Vec<_>, _>>()?,
)
} else {
("failure", vec![])
};
SudoMsg::IBCLifecycleComplete(msg) => ics20_hook_callback(deps, env, msg),

ICS20_CALLBACKS.remove(deps.storage, packet_identifier.clone());

Ok(IbcBasicResponse::new()
.add_attribute("action", "ibc_source_callback")
.add_attribute("outcome", outcome)
.add_messages(stored_msgs))
}
IbcSourceCallbackMsg::Timeout(IbcTimeoutCallbackMsg {
packet, relayer: _, ..
}) => {
ICS20_CALLBACKS.remove(
deps.storage,
ICS20PacketIdentifier {
channel_id: packet.src.channel_id,
sequence: packet.sequence,
},
);
Ok(IbcBasicResponse::new()
.add_attribute("action", "ibc_source_callback")
.add_attribute("outcome", "timeout"))
}
#[cfg(feature = "xion")]
SudoMsg::Xion(msg) => abstract_xion::sudo::sudo(deps, env, msg).map_err(Into::into),
}
}

#[cfg(feature = "xion")]
#[cfg_attr(feature = "export", cosmwasm_std::entry_point)]
pub fn sudo(
deps: DepsMut,
env: Env,
msg: abstract_xion::AccountSudoMsg,
) -> abstract_xion::AbstractXionResult {
abstract_xion::sudo::sudo(deps, env, msg)
}

/// Verifies that *sender* is the owner of *nft_id* of contract *nft_addr*
fn verify_nft_ownership(
deps: Deps,
Expand Down
17 changes: 4 additions & 13 deletions framework/contracts/account/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ use abstract_std::{
IBC_CLIENT, ICA_CLIENT, ICS20,
};
use cosmwasm_std::{
to_json_binary, Addr, Binary, Coin, CosmosMsg, DepsMut, Empty, Env, IbcCallbackRequest, IbcMsg,
IbcSrcCallback, IbcTimeout, MessageInfo, Response, StdError, SubMsg, WasmMsg, WasmQuery,
to_json_binary, Addr, Binary, Coin, CosmosMsg, DepsMut, Empty, Env, IbcMsg, IbcTimeout,
MessageInfo, Response, StdError, SubMsg, WasmMsg, WasmQuery,
};
use serde_json::{self, Value};

use crate::{
contract::{
Expand Down Expand Up @@ -232,23 +231,15 @@ pub fn send_funds_with_actions(
src_chain: TruncatedChainId::from_chain_id(&env.block.chain_id),
},
)
.callback(&env)
.build()?;

// Hook for sending the callback after the ack comes back
let callback = IbcCallbackRequest::source(IbcSrcCallback {
address: env.contract.address,
gas_limit: None,
});

let mut final_json: Value = action_memo.parse()?;
json_patch::merge(&mut final_json, &serde_json::to_value(callback)?);

let transfer_msg = IbcMsg::Transfer {
channel_id: ics20_channel_id.clone(),
to_address: remote_host.remote_abstract_host,
amount: funds,
timeout: IbcTimeout::with_timestamp(env.block.time.plus_seconds(PACKET_LIFETIME)),
memo: Some(final_json.to_string()),
memo: Some(action_memo),
};

Ok(Response::new().add_submessage(
Expand Down
56 changes: 56 additions & 0 deletions framework/contracts/account/src/ics20.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use abstract_std::account::ICS20PacketIdentifier;
use cosmwasm_std::{wasm_execute, DepsMut, Env, Response};

use crate::contract::AccountResult;
use crate::msg::{IBCLifecycleComplete, ICS20_CALLBACKS};

#[cfg_attr(feature = "export", cosmwasm_std::entry_point)]
pub fn ics20_hook_callback(deps: DepsMut, env: Env, msg: IBCLifecycleComplete) -> AccountResult {
match msg {
IBCLifecycleComplete::IBCAck {
channel,
sequence,
ack: _,
success,
} => {
let packet_identifier = ICS20PacketIdentifier {
channel_id: channel,
sequence,
};

// The acknowledgement has this structure with ibc hooks, we need to coed accordingly
// https://github.com/cosmos/ibc-apps/blob/8cb681e31589bc90b47e0ab58173a579825fd56d/modules/ibc-hooks/wasm_hook.go#L119C1-L119C86
let (outcome, stored_msgs) = if success {
(
"result",
ICS20_CALLBACKS
.load(deps.storage, packet_identifier.clone())?
.into_iter()
.map(|msg| wasm_execute(&env.contract.address, &msg, vec![]))
.collect::<Result<Vec<_>, _>>()?,
)
} else {
("failure", vec![])
};

ICS20_CALLBACKS.remove(deps.storage, packet_identifier.clone());

Ok(Response::new()
.add_attribute("action", "ibc_source_callback")
.add_attribute("outcome", outcome)
.add_messages(stored_msgs))
}
IBCLifecycleComplete::IBCTimeout { channel, sequence } => {
ICS20_CALLBACKS.remove(
deps.storage,
ICS20PacketIdentifier {
channel_id: channel,
sequence,
},
);
Ok(Response::new()
.add_attribute("action", "ibc_source_callback")
.add_attribute("outcome", "timeout"))
}
}
}
33 changes: 33 additions & 0 deletions framework/contracts/account/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod config;
pub mod contract;
pub mod error;
pub mod execution;
pub mod ics20;
pub mod migrate;
pub mod modules;
pub mod queries;
Expand Down Expand Up @@ -38,6 +39,38 @@ pub mod msg {

pub const ICS20_CALLBACKS: Map<ICS20PacketIdentifier, Vec<ExecuteMsg>> =
Map::new(storage_namespaces::account::ICS20_CALLBACKS);

#[cosmwasm_schema::cw_serde]
pub enum SudoMsg {
/// For IBC hooks acknoledgments
#[serde(rename = "ibc_lifecycle_complete")]
IBCLifecycleComplete(IBCLifecycleComplete),
#[cfg(feature = "xion")]
#[serde(untagged)]
Xion(abstract_xion::AccountSudoMsg),
}

#[cosmwasm_schema::cw_serde]
pub enum IBCLifecycleComplete {
#[serde(rename = "ibc_ack")]
IBCAck {
/// The source channel (osmosis side) of the IBC packet
channel: String,
/// The sequence number that the packet was sent with
sequence: u64,
/// String encoded version of the `Ack` as seen by OnAcknowledgementPacket(..)
ack: String,
/// Weather an `Ack` is a success of failure according to the transfer spec
success: bool,
},
#[serde(rename = "ibc_timeout")]
IBCTimeout {
/// The source channel (osmosis side) of the IBC packet
channel: String,
/// The sequence number that the packet was sent with
sequence: u64,
},
}
}

#[cfg(test)]
Expand Down
2 changes: 1 addition & 1 deletion framework/packages/abstract-interface/src/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ impl<Chain: CwEnv> Uploadable for AccountI<Chain> {
)
.with_migrate(::account::contract::migrate)
.with_reply(::account::contract::reply)
.with_ibc_source_callback(::account::contract::ibc_source_callback),
.with_sudo(::account::contract::sudo),
)
}
fn wasm(chain: &ChainInfoOwned) -> WasmPath {
Expand Down
8 changes: 7 additions & 1 deletion framework/packages/abstract-sdk/src/apis/ibc_memo/hooks.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::BTreeMap;

use cosmwasm_std::{from_json, to_json_binary, Addr, Binary};
use cosmwasm_std::{from_json, to_json_binary, Addr, Binary, Env};
use serde_cw_value::Value;

/// Builder for [IbcHooks](https://github.com/cosmos/ibc-apps/tree/main/modules/ibc-hooks) memo field.
Expand Down Expand Up @@ -29,6 +29,12 @@ impl HookMemoBuilder {
self
}

/// The current contract will receive a callback
/// https://github.com/cosmos/ibc-apps/blob/main/modules/ibc-hooks/README.md#interface-for-receiving-the-acks-and-timeouts
pub fn callback(self, env: &Env) -> Self {
self.callback_contract(env.contract.address.clone())
}

/// Build memo json string
pub fn build(self) -> cosmwasm_std::StdResult<String> {
let execute_wasm_value = BTreeMap::from([
Expand Down