1use alloc::vec::Vec;
20use core::fmt::Debug;
21use frame_support::{
22 parameter_types,
23 traits::{Contains, CrateVersion, PalletInfoData, PalletsInfoAccess},
24};
25pub use xcm::latest::{prelude::*, Weight};
26use xcm_executor::traits::{ClaimAssets, DropAssets, VersionChangeNotifier};
27pub use xcm_executor::{
28 traits::{
29 AssetExchange, AssetLock, ConvertOrigin, Enact, LockError, OnResponse, TransactAsset,
30 },
31 AssetsInHolding, Config,
32};
33
34parameter_types! {
35 pub static SubscriptionRequests: Vec<(Location, Option<(QueryId, Weight)>)> = vec![];
36 pub static MaxAssetsIntoHolding: u32 = 4;
37}
38
39pub struct TestSubscriptionService;
40
41impl VersionChangeNotifier for TestSubscriptionService {
42 fn start(
43 location: &Location,
44 query_id: QueryId,
45 max_weight: Weight,
46 _context: &XcmContext,
47 ) -> XcmResult {
48 let mut r = SubscriptionRequests::get();
49 r.push((location.clone(), Some((query_id, max_weight))));
50 SubscriptionRequests::set(r);
51 Ok(())
52 }
53 fn stop(location: &Location, _context: &XcmContext) -> XcmResult {
54 let mut r = SubscriptionRequests::get();
55 r.retain(|(l, _q)| l != location);
56 r.push((location.clone(), None));
57 SubscriptionRequests::set(r);
58 Ok(())
59 }
60 fn is_subscribed(location: &Location) -> bool {
61 let r = SubscriptionRequests::get();
62 r.iter().any(|(l, q)| l == location && q.is_some())
63 }
64}
65
66pub struct TestHolding(AssetsInHolding);
67impl Clone for TestHolding {
68 fn clone(&self) -> Self {
69 TestHolding(AssetsInHolding {
70 fungible: self
71 .0
72 .fungible
73 .iter()
74 .map(|(id, accounting)| (id.clone(), accounting.unsafe_clone()))
75 .collect(),
76 non_fungible: self.0.non_fungible.clone(),
77 })
78 }
79}
80
81impl Debug for TestHolding {
82 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83 f.debug_struct("TestHolding")
84 .field("fungible_assets", &self.0.fungible_assets_iter().collect::<Vec<_>>())
85 .field("non_fungible_assets", &self.0.non_fungible_assets_iter().collect::<Vec<_>>())
86 .finish()
87 }
88}
89
90impl PartialEq for TestHolding {
91 fn eq(&self, other: &Self) -> bool {
92 let self_fungible: Vec<_> = self.0.fungible_assets_iter().collect();
93 let other_fungible: Vec<_> = other.0.fungible_assets_iter().collect();
94 let self_non_fungible: Vec<_> = self.0.non_fungible_assets_iter().collect();
95 let other_non_fungible: Vec<_> = other.0.non_fungible_assets_iter().collect();
96
97 self_fungible == other_fungible && self_non_fungible == other_non_fungible
98 }
99}
100
101parameter_types! {
102 pub static TrappedAssets: Vec<(Location, TestHolding)> = vec![];
103}
104
105pub struct TestAssetTrap();
106
107impl DropAssets for TestAssetTrap {
108 fn drop_assets(origin: &Location, assets: AssetsInHolding, _context: &XcmContext) -> Weight {
109 let mut t: Vec<(Location, TestHolding)> = TrappedAssets::get();
110 t.push((origin.clone(), TestHolding(assets)));
111 TrappedAssets::set(t);
112 Weight::from_parts(5, 5)
113 }
114}
115
116impl ClaimAssets for TestAssetTrap {
117 fn claim_assets(
118 origin: &Location,
119 ticket: &Location,
120 what: &Assets,
121 _context: &XcmContext,
122 ) -> Option<AssetsInHolding> {
123 let mut t: Vec<(Location, TestHolding)> = TrappedAssets::get();
124 if let (0, [GeneralIndex(i)]) = ticket.unpack() {
125 if let Some((l, a)) = t.get(*i as usize) {
126 for asset in what.inner() {
127 if l == origin && a.0.contains_asset(asset) {
128 let (_, claimed) = t.swap_remove(*i as usize);
129 TrappedAssets::set(t);
130 return Some(claimed.0);
131 }
132 }
133 }
134 }
135 None
136 }
137}
138
139pub struct TestAssetExchanger;
140
141impl AssetExchange for TestAssetExchanger {
142 fn exchange_asset(
143 _origin: Option<&Location>,
144 _give: AssetsInHolding,
145 _want: &Assets,
146 _maximal: bool,
147 ) -> Result<AssetsInHolding, AssetsInHolding> {
148 Ok(AssetsInHolding::new())
149 }
150
151 fn quote_exchange_price(give: &Assets, _want: &Assets, _maximal: bool) -> Option<Assets> {
152 Some(give.clone())
153 }
154}
155
156pub struct TestPalletsInfo;
157impl PalletsInfoAccess for TestPalletsInfo {
158 fn count() -> usize {
159 2
160 }
161 fn infos() -> Vec<PalletInfoData> {
162 vec![
163 PalletInfoData {
164 index: 0,
165 name: "System",
166 module_name: "pallet_system",
167 crate_version: CrateVersion { major: 1, minor: 10, patch: 1 },
168 },
169 PalletInfoData {
170 index: 1,
171 name: "Balances",
172 module_name: "pallet_balances",
173 crate_version: CrateVersion { major: 1, minor: 42, patch: 69 },
174 },
175 ]
176 }
177}
178
179pub struct TestUniversalAliases;
180impl Contains<(Location, Junction)> for TestUniversalAliases {
181 fn contains(aliases: &(Location, Junction)) -> bool {
182 &aliases.0 == &Here.into_location() && &aliases.1 == &GlobalConsensus(ByGenesis([0; 32]))
183 }
184}
185
186parameter_types! {
187 pub static LockedAssets: Vec<(Location, Asset)> = vec![];
188}
189
190pub struct TestLockTicket(Location, Asset);
191impl Enact for TestLockTicket {
192 fn enact(self) -> Result<(), LockError> {
193 let mut locked_assets = LockedAssets::get();
194 locked_assets.push((self.0, self.1));
195 LockedAssets::set(locked_assets);
196 Ok(())
197 }
198}
199pub struct TestUnlockTicket(Location, Asset);
200impl Enact for TestUnlockTicket {
201 fn enact(self) -> Result<(), LockError> {
202 let mut locked_assets = LockedAssets::get();
203 if let Some((idx, _)) = locked_assets
204 .iter()
205 .enumerate()
206 .find(|(_, (origin, asset))| origin == &self.0 && asset == &self.1)
207 {
208 locked_assets.remove(idx);
209 }
210 LockedAssets::set(locked_assets);
211 Ok(())
212 }
213}
214pub struct TestReduceTicket;
215impl Enact for TestReduceTicket {
216 fn enact(self) -> Result<(), LockError> {
217 Ok(())
218 }
219}
220
221pub struct TestAssetLocker;
222impl AssetLock for TestAssetLocker {
223 type LockTicket = TestLockTicket;
224 type UnlockTicket = TestUnlockTicket;
225 type ReduceTicket = TestReduceTicket;
226
227 fn prepare_lock(
228 unlocker: Location,
229 asset: Asset,
230 _owner: Location,
231 ) -> Result<TestLockTicket, LockError> {
232 Ok(TestLockTicket(unlocker, asset))
233 }
234
235 fn prepare_unlock(
236 unlocker: Location,
237 asset: Asset,
238 _owner: Location,
239 ) -> Result<TestUnlockTicket, LockError> {
240 Ok(TestUnlockTicket(unlocker, asset))
241 }
242
243 fn note_unlockable(
244 _locker: Location,
245 _asset: Asset,
246 _owner: Location,
247 ) -> Result<(), LockError> {
248 Ok(())
249 }
250
251 fn prepare_reduce_unlockable(
252 _locker: Location,
253 _asset: Asset,
254 _owner: Location,
255 ) -> Result<TestReduceTicket, LockError> {
256 Ok(TestReduceTicket)
257 }
258}