ibc_app_transfer/handler/
send_transfer.rs1use ibc_app_transfer_types::error::TokenTransferError;
2use ibc_app_transfer_types::events::TransferEvent;
3use ibc_app_transfer_types::msgs::transfer::MsgTransfer;
4use ibc_app_transfer_types::{is_sender_chain_source, MODULE_ID_STR};
5use ibc_core::channel::context::{SendPacketExecutionContext, SendPacketValidationContext};
6use ibc_core::channel::handler::{send_packet_execute, send_packet_validate};
7use ibc_core::channel::types::packet::Packet;
8use ibc_core::handler::types::events::MessageEvent;
9use ibc_core::host::types::path::{ChannelEndPath, SeqSendPath};
10use ibc_core::primitives::prelude::*;
11use ibc_core::router::types::event::ModuleEvent;
12
13use crate::context::{TokenTransferExecutionContext, TokenTransferValidationContext};
14
15pub fn send_transfer<SendPacketCtx, TokenCtx>(
17 send_packet_ctx_a: &mut SendPacketCtx,
18 token_ctx_a: &mut TokenCtx,
19 msg: MsgTransfer,
20) -> Result<(), TokenTransferError>
21where
22 SendPacketCtx: SendPacketExecutionContext,
23 TokenCtx: TokenTransferExecutionContext,
24{
25 send_transfer_validate(send_packet_ctx_a, token_ctx_a, msg.clone())?;
26 send_transfer_execute(send_packet_ctx_a, token_ctx_a, msg)
27}
28
29pub fn send_transfer_validate<SendPacketCtx, TokenCtx>(
31 send_packet_ctx_a: &SendPacketCtx,
32 token_ctx_a: &TokenCtx,
33 msg: MsgTransfer,
34) -> Result<(), TokenTransferError>
35where
36 SendPacketCtx: SendPacketValidationContext,
37 TokenCtx: TokenTransferValidationContext,
38{
39 token_ctx_a.can_send_coins()?;
40
41 let chan_end_path_on_a = ChannelEndPath::new(&msg.port_id_on_a, &msg.chan_id_on_a);
42 let chan_end_on_a = send_packet_ctx_a.channel_end(&chan_end_path_on_a)?;
43
44 let port_id_on_b = chan_end_on_a.counterparty().port_id().clone();
45 let chan_id_on_b = chan_end_on_a
46 .counterparty()
47 .channel_id()
48 .ok_or_else(|| TokenTransferError::MissingDestinationChannel {
49 port_id: msg.port_id_on_a.clone(),
50 channel_id: msg.chan_id_on_a.clone(),
51 })?
52 .clone();
53
54 let seq_send_path_on_a = SeqSendPath::new(&msg.port_id_on_a, &msg.chan_id_on_a);
55 let sequence = send_packet_ctx_a.get_next_sequence_send(&seq_send_path_on_a)?;
56
57 let token = &msg.packet_data.token;
58
59 let sender = token_ctx_a.sender_account(&msg.packet_data.sender)?;
60
61 if is_sender_chain_source(
62 msg.port_id_on_a.clone(),
63 msg.chan_id_on_a.clone(),
64 &token.denom,
65 ) {
66 token_ctx_a.escrow_coins_validate(
67 &sender,
68 &msg.port_id_on_a,
69 &msg.chan_id_on_a,
70 token,
71 &msg.packet_data.memo,
72 )?;
73 } else {
74 token_ctx_a.burn_coins_validate(&sender, token, &msg.packet_data.memo)?;
75 }
76
77 let packet = {
78 let data = serde_json::to_vec(&msg.packet_data)
79 .expect("PacketData's infallible Serialize impl failed");
80
81 Packet {
82 seq_on_a: sequence,
83 port_id_on_a: msg.port_id_on_a,
84 chan_id_on_a: msg.chan_id_on_a,
85 port_id_on_b,
86 chan_id_on_b,
87 data,
88 timeout_height_on_b: msg.timeout_height_on_b,
89 timeout_timestamp_on_b: msg.timeout_timestamp_on_b,
90 }
91 };
92
93 send_packet_validate(send_packet_ctx_a, &packet)?;
94
95 Ok(())
96}
97
98pub fn send_transfer_execute<SendPacketCtx, TokenCtx>(
100 send_packet_ctx_a: &mut SendPacketCtx,
101 token_ctx_a: &mut TokenCtx,
102 msg: MsgTransfer,
103) -> Result<(), TokenTransferError>
104where
105 SendPacketCtx: SendPacketExecutionContext,
106 TokenCtx: TokenTransferExecutionContext,
107{
108 let chan_end_path_on_a = ChannelEndPath::new(&msg.port_id_on_a, &msg.chan_id_on_a);
109 let chan_end_on_a = send_packet_ctx_a.channel_end(&chan_end_path_on_a)?;
110
111 let port_on_b = chan_end_on_a.counterparty().port_id().clone();
112 let chan_on_b = chan_end_on_a
113 .counterparty()
114 .channel_id()
115 .ok_or_else(|| TokenTransferError::MissingDestinationChannel {
116 port_id: msg.port_id_on_a.clone(),
117 channel_id: msg.chan_id_on_a.clone(),
118 })?
119 .clone();
120
121 let seq_send_path_on_a = SeqSendPath::new(&msg.port_id_on_a, &msg.chan_id_on_a);
123 let sequence = send_packet_ctx_a.get_next_sequence_send(&seq_send_path_on_a)?;
124
125 let token = &msg.packet_data.token;
126
127 let sender = token_ctx_a.sender_account(&msg.packet_data.sender)?;
128
129 if is_sender_chain_source(
130 msg.port_id_on_a.clone(),
131 msg.chan_id_on_a.clone(),
132 &token.denom,
133 ) {
134 token_ctx_a.escrow_coins_execute(
135 &sender,
136 &msg.port_id_on_a,
137 &msg.chan_id_on_a,
138 token,
139 &msg.packet_data.memo,
140 )?;
141 } else {
142 token_ctx_a.burn_coins_execute(&sender, token, &msg.packet_data.memo)?;
143 }
144
145 let packet = {
146 let data = {
147 serde_json::to_vec(&msg.packet_data)
148 .expect("PacketData's infallible Serialize impl failed")
149 };
150
151 Packet {
152 seq_on_a: sequence,
153 port_id_on_a: msg.port_id_on_a,
154 chan_id_on_a: msg.chan_id_on_a,
155 port_id_on_b: port_on_b,
156 chan_id_on_b: chan_on_b,
157 data,
158 timeout_height_on_b: msg.timeout_height_on_b,
159 timeout_timestamp_on_b: msg.timeout_timestamp_on_b,
160 }
161 };
162
163 send_packet_execute(send_packet_ctx_a, packet)?;
164
165 {
166 send_packet_ctx_a.log_message(format!(
167 "IBC fungible token transfer: {} --({})--> {}",
168 msg.packet_data.sender, token, msg.packet_data.receiver
169 ))?;
170
171 let transfer_event = TransferEvent {
172 sender: msg.packet_data.sender,
173 receiver: msg.packet_data.receiver,
174 amount: msg.packet_data.token.amount,
175 denom: msg.packet_data.token.denom,
176 memo: msg.packet_data.memo,
177 };
178 send_packet_ctx_a.emit_ibc_event(ModuleEvent::from(transfer_event).into())?;
179
180 send_packet_ctx_a.emit_ibc_event(MessageEvent::Module(MODULE_ID_STR.to_string()).into())?;
181 }
182
183 Ok(())
184}