|
14 | 14 | // limitations under the License. |
15 | 15 |
|
16 | 16 | use crate::{ |
17 | | - create_pool_with_wnd_on, |
| 17 | + assets_balance_on, create_pool_with_wnd_on, foreign_balance_on, |
18 | 18 | imports::{ |
19 | 19 | asset_hub_westend_runtime::{ExistentialDeposit, Runtime}, |
20 | 20 | *, |
@@ -156,3 +156,173 @@ fn test_exchange_asset( |
156 | 156 | } |
157 | 157 | }); |
158 | 158 | } |
| 159 | + |
| 160 | +#[test] |
| 161 | +fn exchange_asset_from_penpal_via_asset_hub_back_to_penpal() { |
| 162 | + let sender = PenpalASender::get(); |
| 163 | + let sov_of_penpal_on_asset_hub = AssetHubWestend::sovereign_account_id_of( |
| 164 | + AssetHubWestend::sibling_location_of(PenpalA::para_id()), |
| 165 | + ); |
| 166 | + let wnd_from_parachain_pov: Location = RelayLocation::get(); |
| 167 | + let usdt_asset_hub_pov = |
| 168 | + Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())]); |
| 169 | + let usdt_penpal_pov = PenpalUsdtFromAssetHub::get(); |
| 170 | + let amount_of_wnd_to_transfer_to_ah = WESTEND_ED * 1_000_000_000; |
| 171 | + let amount_of_usdt_we_want_from_exchange = 1_000_000_000; |
| 172 | + |
| 173 | + let mut topic_id_tracker = TopicIdTracker::new(); |
| 174 | + |
| 175 | + // SA-of-Penpal-on-AHW should contain WND amount equal at least the amount that will be |
| 176 | + // transferred-in to AH Since AH is the reserve for WND |
| 177 | + AssetHubWestend::fund_accounts(vec![( |
| 178 | + sov_of_penpal_on_asset_hub.clone().into(), |
| 179 | + ASSET_HUB_WESTEND_ED + amount_of_wnd_to_transfer_to_ah, |
| 180 | + )]); |
| 181 | + // Give the sender enough WND |
| 182 | + PenpalA::mint_foreign_asset( |
| 183 | + <PenpalA as Chain>::RuntimeOrigin::signed(PenpalAssetOwner::get()), |
| 184 | + wnd_from_parachain_pov.clone(), |
| 185 | + sender.clone(), |
| 186 | + amount_of_wnd_to_transfer_to_ah, |
| 187 | + ); |
| 188 | + |
| 189 | + // We create a pool between WND and USDT in AssetHub so we can do the exchange |
| 190 | + create_pool_with_wnd_on!( |
| 191 | + AssetHubWestend, |
| 192 | + usdt_asset_hub_pov.clone(), |
| 193 | + false, |
| 194 | + AssetHubWestendSender::get(), |
| 195 | + 1_000_000_000_000, |
| 196 | + 20_000_000_000 |
| 197 | + ); |
| 198 | + |
| 199 | + // Query initial balances |
| 200 | + let sender_usdt_on_penpal_before = |
| 201 | + foreign_balance_on!(PenpalA, usdt_penpal_pov.clone(), &sender); |
| 202 | + let sender_usdt_on_ah_before = assets_balance_on!(AssetHubWestend, USDT_ID, &sender); |
| 203 | + |
| 204 | + let asset_hub_location_penpal_pov = PenpalA::sibling_location_of(AssetHubWestend::para_id()); |
| 205 | + let penpal_location_ah_pov = AssetHubWestend::sibling_location_of(PenpalA::para_id()); |
| 206 | + |
| 207 | + PenpalA::execute_with(|| { |
| 208 | + let sender_signed_origin = <PenpalA as Chain>::RuntimeOrigin::signed(sender.clone()); |
| 209 | + |
| 210 | + let local_fees_amount = 80_000_000_000_000u128; |
| 211 | + let remote_fees_amount = 200_000_000_000_000u128; |
| 212 | + |
| 213 | + let penpal_local_fees: Asset = (wnd_from_parachain_pov.clone(), local_fees_amount).into(); |
| 214 | + let ah_remote_fees: Asset = (wnd_from_parachain_pov.clone(), remote_fees_amount).into(); |
| 215 | + let penpal_remote_fees: Asset = (wnd_from_parachain_pov.clone(), remote_fees_amount).into(); |
| 216 | + let wnd_to_withdraw: Asset = |
| 217 | + (wnd_from_parachain_pov.clone(), amount_of_wnd_to_transfer_to_ah).into(); |
| 218 | + |
| 219 | + // xcm to be executed by penpal, sent by ah |
| 220 | + let xcm_back_on_penpal = Xcm(vec![ |
| 221 | + RefundSurplus, |
| 222 | + DepositAsset { assets: Wild(All), beneficiary: sender.clone().into() }, |
| 223 | + ]); |
| 224 | + // xcm to be executed by ah, sent by penpal |
| 225 | + let xcm_on_ah = Xcm(vec![ |
| 226 | + ExchangeAsset { |
| 227 | + give: Definite((wnd_from_parachain_pov.clone(), 100_000_000_000u128).into()), |
| 228 | + want: (usdt_asset_hub_pov.clone(), amount_of_usdt_we_want_from_exchange).into(), |
| 229 | + maximal: false, |
| 230 | + }, |
| 231 | + InitiateTransfer { |
| 232 | + destination: penpal_location_ah_pov, |
| 233 | + remote_fees: Some(AssetTransferFilter::ReserveDeposit( |
| 234 | + penpal_remote_fees.clone().into(), |
| 235 | + )), |
| 236 | + preserve_origin: false, |
| 237 | + assets: BoundedVec::truncate_from(vec![AssetTransferFilter::ReserveDeposit(Wild( |
| 238 | + All, |
| 239 | + ))]), |
| 240 | + remote_xcm: xcm_back_on_penpal, |
| 241 | + }, |
| 242 | + RefundSurplus, |
| 243 | + DepositAsset { assets: Wild(All), beneficiary: sender.clone().into() }, |
| 244 | + ]); |
| 245 | + // xcm to be executed locally on penpal as starting point |
| 246 | + let xcm = Xcm::<()>(vec![ |
| 247 | + WithdrawAsset(wnd_to_withdraw.into()), |
| 248 | + PayFees { asset: penpal_local_fees }, |
| 249 | + InitiateTransfer { |
| 250 | + destination: asset_hub_location_penpal_pov, |
| 251 | + remote_fees: Some(AssetTransferFilter::ReserveWithdraw( |
| 252 | + ah_remote_fees.clone().into(), |
| 253 | + )), |
| 254 | + preserve_origin: false, |
| 255 | + assets: BoundedVec::truncate_from(vec![AssetTransferFilter::ReserveWithdraw( |
| 256 | + Wild(All), |
| 257 | + )]), |
| 258 | + remote_xcm: xcm_on_ah, |
| 259 | + }, |
| 260 | + RefundSurplus, |
| 261 | + DepositAsset { assets: Wild(All), beneficiary: sender.clone().into() }, |
| 262 | + ]); |
| 263 | + // initiate transaction |
| 264 | + <PenpalA as PenpalAPallet>::PolkadotXcm::execute( |
| 265 | + sender_signed_origin, |
| 266 | + bx!(xcm::VersionedXcm::from(xcm.into())), |
| 267 | + Weight::MAX, |
| 268 | + ) |
| 269 | + .unwrap(); |
| 270 | + |
| 271 | + // verify expected events; |
| 272 | + PenpalA::assert_xcm_pallet_attempted_complete(None); |
| 273 | + |
| 274 | + let msg_sent_id = find_xcm_sent_message_id::<PenpalA>().expect("Missing Sent Event"); |
| 275 | + topic_id_tracker.insert("PenpalA_sent", msg_sent_id.into()); |
| 276 | + }); |
| 277 | + AssetHubWestend::execute_with(|| { |
| 278 | + type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent; |
| 279 | + assert_expected_events!( |
| 280 | + AssetHubWestend, |
| 281 | + vec![ |
| 282 | + RuntimeEvent::MessageQueue( |
| 283 | + pallet_message_queue::Event::Processed { success: true, .. } |
| 284 | + ) => {}, |
| 285 | + RuntimeEvent::AssetConversion( |
| 286 | + pallet_asset_conversion::Event::SwapCreditExecuted { amount_out, ..} |
| 287 | + ) => { amount_out: *amount_out == amount_of_usdt_we_want_from_exchange, }, |
| 288 | + ] |
| 289 | + ); |
| 290 | + |
| 291 | + let mq_prc_id = find_mq_processed_id::<AssetHubWestend>().expect("Missing Processed Event"); |
| 292 | + topic_id_tracker.insert("AssetHubWestend_received", mq_prc_id); |
| 293 | + let msg_sent_id = |
| 294 | + find_xcm_sent_message_id::<AssetHubWestend>().expect("Missing Sent Event"); |
| 295 | + topic_id_tracker.insert("AssetHubWestend_sent", msg_sent_id.into()); |
| 296 | + }); |
| 297 | + |
| 298 | + PenpalA::execute_with(|| { |
| 299 | + type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent; |
| 300 | + assert_expected_events!( |
| 301 | + PenpalA, |
| 302 | + vec![ |
| 303 | + RuntimeEvent::MessageQueue( |
| 304 | + pallet_message_queue::Event::Processed { success: true, .. } |
| 305 | + ) => {}, |
| 306 | + ] |
| 307 | + ); |
| 308 | + |
| 309 | + let mq_prc_id = find_mq_processed_id::<PenpalA>().expect("Missing Processed Event"); |
| 310 | + topic_id_tracker.insert("PenpalA_received", mq_prc_id); |
| 311 | + }); |
| 312 | + |
| 313 | + topic_id_tracker.assert_unique(); |
| 314 | + |
| 315 | + // Query final balances |
| 316 | + let sender_usdt_on_ah_after = assets_balance_on!(AssetHubWestend, USDT_ID, &sender); |
| 317 | + let sender_usdt_on_penpal_after = |
| 318 | + foreign_balance_on!(PenpalA, usdt_penpal_pov.clone(), &sender); |
| 319 | + |
| 320 | + // Receiver's balance is increased by usdt amount we got from exchange |
| 321 | + assert_eq!( |
| 322 | + sender_usdt_on_penpal_after, |
| 323 | + sender_usdt_on_penpal_before + amount_of_usdt_we_want_from_exchange |
| 324 | + ); |
| 325 | + // Usdt amount on senders account AH side should stay the same i.e. all usdt came from exchange |
| 326 | + // not free balance |
| 327 | + assert_eq!(sender_usdt_on_ah_before, sender_usdt_on_ah_after); |
| 328 | +} |
0 commit comments