Skip to content

Commit

Permalink
feat: implemented on_ack_packet
Browse files Browse the repository at this point in the history
  • Loading branch information
srdtrk committed Jun 4, 2024
1 parent 7553aae commit e8d4630
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 8 deletions.
97 changes: 90 additions & 7 deletions contracts/ics20-transfer/src/ibc/relay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,21 @@ pub fn on_recv_packet(
/// Will return an error if the acknowledgement cannot be processed.
#[allow(clippy::needless_pass_by_value)]
pub fn on_acknowledgement_packet(
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
_packet: ibc::Packet,
_ack: Binary,
_relayer: String,
deps: DepsMut,
env: Env,
info: MessageInfo,
packet: ibc::Packet,
ack: Binary,
relayer: String,
) -> Result<Response, ContractError> {
todo!()
match cosmwasm_std::from_json(ack)? {
Ics20Ack::Result(result) => {
on_acknowledgement_packet::success(deps, env, info, packet, result, relayer)
}
Ics20Ack::Error(err) => {
on_acknowledgement_packet::error(deps, env, info, packet, err, relayer)
}
}
}

/// Handles the callback for the `on_timeout_packet` IBC handler.
Expand All @@ -152,3 +159,79 @@ pub fn on_timeout_packet(
) -> Result<Response, ContractError> {
todo!()
}

mod on_acknowledgement_packet {
use cosmwasm_std::HexBinary;

use super::{
ibc, state, utils, Binary, ContractError, CosmosMsg, DepsMut, Env, Ics20Ack, Ics20Packet,
MessageInfo, Response, TransferError, WasmMsg,
};

#[allow(clippy::needless_pass_by_value)]
pub fn success(
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
_packet: ibc::Packet,
result: Binary,
_relayer: String,
) -> Result<Response, ContractError> {
if result.as_slice() != Ics20Ack::SUCCESS_BYTES {
return Err(
TransferError::UnknownAcknowledgement(HexBinary::from(result).to_hex()).into(),
);
}

Ok(Response::default())
}

#[allow(clippy::needless_pass_by_value)]
pub fn error(
deps: DepsMut,
env: Env,
_info: MessageInfo,
packet: ibc::Packet,
_err: String,
_relayer: String,
) -> Result<Response, ContractError> {
let ics20_packet: Ics20Packet = cosmwasm_std::from_json(packet.data)?;

let port_id = utils::apps::contract_port_id(&env.contract.address)?;
if packet.source_port != port_id {
return Err(TransferError::unexpected_port_id(port_id, packet.source_port).into());
}

let base_denom = utils::transfer::parse_voucher_denom(
&ics20_packet.denom,
port_id.as_str(),
packet.source_channel.as_str(),
)?;

// Refund the escrowed balance.
state::ESCROW.update(
deps.storage,
(packet.source_channel.as_str(), base_denom),
|escrowed_bal| -> Result<_, ContractError> {
let mut escrowed_bal = escrowed_bal.unwrap_or_default();
escrowed_bal = escrowed_bal.checked_sub(ics20_packet.amount).map_err(|_| {
TransferError::insufficient_funds_in_escrow(escrowed_bal, ics20_packet.amount)
})?;
Ok(escrowed_bal)
},
)?;

let cw20_msg: CosmosMsg = WasmMsg::Execute {
contract_addr: base_denom.to_string(),
msg: cosmwasm_std::to_json_binary(&cw20::Cw20ExecuteMsg::Transfer {
recipient: ics20_packet.sender,
amount: ics20_packet.amount,
})?,
funds: vec![],
}
.into();

// NOTE: If the refund fails, the packet cannot be acknowledged and must be retried.
Ok(Response::new().add_message(cw20_msg))
}
}
2 changes: 2 additions & 0 deletions packages/shared/src/types/transfer/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub enum TransferError {
InsufficientFundsInEscrow { escrowed: String, requested: String },
#[error("reentrancy safeguard")]
Reentrancy,
#[error("unknown acknowledgement: {0}")]
UnknownAcknowledgement(String),
}

impl TransferError {
Expand Down
5 changes: 4 additions & 1 deletion packages/shared/src/types/transfer/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ pub struct Ics20Packet {
pub type Ics20Ack = AcknowledgementData;

impl Ics20Ack {
/// The wrapped bytes for a successful ICS20 acknowledgement.
pub const SUCCESS_BYTES: &'static [u8] = b"1";

/// Creates a successful ICS20 acknowledgement.
#[must_use]
pub fn success() -> Self {
Self::Result(b"1".into())
Self::Result(Self::SUCCESS_BYTES.into())
}

/// Creates an error ICS20 acknowledgement.
Expand Down

0 comments on commit e8d4630

Please sign in to comment.