1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

            
4
// Tanssi is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Tanssi is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Tanssi.  If not, see <http://www.gnu.org/licenses/>
16

            
17
use {
18
    frame_support::{
19
        assert_ok,
20
        weights::{Weight, WeightToFee},
21
    },
22
    frontier_template_emulated_chain::FrontierTemplateParaPallet,
23
    parity_scale_codec::Encode,
24
    simple_template_emulated_chain::SimpleTemplateParaPallet,
25
    westend_emulated_chain::WestendRelayPallet,
26
    westend_system_emulated_network::{
27
        DanceboxPara as Dancebox, FrontierTemplatePara as FrontierTemplate,
28
        SimpleTemplatePara as SimpleTemplate, WestendRelay as Westend,
29
    },
30
    xcm::{
31
        latest::prelude::{Junctions::*, *},
32
        VersionedLocation, VersionedXcm,
33
    },
34
    xcm_builder::{ParentIsPreset, SiblingParachainConvertsVia},
35
    xcm_emulator::{
36
        assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, TestExt,
37
    },
38
    xcm_executor::traits::ConvertLocation,
39
};
40

            
41
#[test]
42
1
fn transact_sudo_from_relay_hits_barrier_dancebox_without_buy_exec() {
43
1
    let call = <Dancebox as Chain>::RuntimeCall::Configuration(pallet_configuration::Call::<
44
1
        <Dancebox as Chain>::Runtime,
45
1
    >::set_max_collators {
46
1
        new: 50,
47
1
    })
48
1
    .encode()
49
1
    .into();
50
1

            
51
1
    // XcmPallet send arguments
52
1
    let sudo_origin = <Westend as Chain>::RuntimeOrigin::root();
53
1
    let dancebox_para_destination: VersionedLocation =
54
1
        Westend::child_location_of(Dancebox::para_id()).into();
55
1

            
56
1
    let weight_limit = WeightLimit::Unlimited;
57
1
    let fallback_max_weight = Some(Weight::from_parts(1000000000, 200000));
58
1
    let origin_kind = OriginKind::Superuser;
59
1
    let check_origin = None;
60
1

            
61
1
    let xcm = VersionedXcm::from(Xcm(vec![
62
1
        UnpaidExecution {
63
1
            weight_limit,
64
1
            check_origin,
65
1
        },
66
1
        Transact {
67
1
            fallback_max_weight,
68
1
            origin_kind,
69
1
            call,
70
1
        },
71
1
    ]));
72
1

            
73
1
    // Send XCM message from Relay Chain
74
1
    Westend::execute_with(|| {
75
1
        assert_ok!(<Westend as WestendRelayPallet>::XcmPallet::send(
76
1
            sudo_origin,
77
1
            bx!(dancebox_para_destination),
78
1
            bx!(xcm),
79
1
        ));
80

            
81
        type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
82

            
83
1
        assert_expected_events!(
84
            Westend,
85
            vec![
86
1
                RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {},
87
            ]
88
        );
89
1
    });
90
1

            
91
1
    // Receive XCM message in Assets Parachain
92
1
    Dancebox::execute_with(|| {
93
1
        Dancebox::assert_dmp_queue_error();
94
1
    });
95
1
}
96

            
97
#[test]
98
1
fn transact_sudo_from_relay_does_not_have_sudo_power() {
99
1
    let call = <Dancebox as Chain>::RuntimeCall::Configuration(pallet_configuration::Call::<
100
1
        <Dancebox as Chain>::Runtime,
101
1
    >::set_max_collators {
102
1
        new: 50,
103
1
    })
104
1
    .encode()
105
1
    .into();
106
1

            
107
1
    // XcmPallet send arguments
108
1
    let sudo_origin = <Westend as Chain>::RuntimeOrigin::root();
109
1
    let dancebox_para_destination: VersionedLocation =
110
1
        Westend::child_location_of(Dancebox::para_id()).into();
111
1

            
112
1
    let fallback_max_weight = Some(Weight::from_parts(1000000000, 200000));
113
1
    let origin_kind = OriginKind::Superuser;
114
1

            
115
1
    let buy_execution_fee_amount =
116
1
        dancebox_runtime::WeightToFee::weight_to_fee(&Weight::from_parts(10_000_000_000, 300_000));
117
1

            
118
1
    let buy_execution_fee = Asset {
119
1
        id: dancebox_runtime::xcm_config::SelfReserve::get().into(),
120
1
        fun: Fungible(buy_execution_fee_amount),
121
1
    };
122
1

            
123
1
    let xcm = VersionedXcm::from(Xcm(vec![
124
1
        WithdrawAsset(vec![buy_execution_fee.clone()].into()),
125
1
        BuyExecution {
126
1
            fees: buy_execution_fee.clone(),
127
1
            weight_limit: Unlimited,
128
1
        },
129
1
        Transact {
130
1
            fallback_max_weight,
131
1
            origin_kind,
132
1
            call,
133
1
        },
134
1
    ]));
135
1

            
136
1
    // Send XCM message from Relay Chain
137
1
    Westend::execute_with(|| {
138
1
        assert_ok!(<Westend as WestendRelayPallet>::XcmPallet::send(
139
1
            sudo_origin,
140
1
            bx!(dancebox_para_destination),
141
1
            bx!(xcm),
142
1
        ));
143

            
144
        type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
145

            
146
1
        assert_expected_events!(
147
            Westend,
148
            vec![
149
1
                RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {},
150
            ]
151
        );
152
1
    });
153
1

            
154
1
    // Receive XCM message in Assets Parachain
155
1
    Dancebox::execute_with(|| {
156
1
        Dancebox::assert_dmp_queue_incomplete(None);
157
1
    });
158
1
}
159

            
160
#[test]
161
1
fn transact_sudo_from_relay_has_signed_origin_powers() {
162
1
    let call = <Dancebox as Chain>::RuntimeCall::System(frame_system::Call::<
163
1
        <Dancebox as Chain>::Runtime,
164
1
    >::remark_with_event {
165
1
        remark: b"Test".to_vec(),
166
1
    })
167
1
    .encode()
168
1
    .into();
169
1

            
170
1
    // XcmPallet send arguments
171
1
    let sudo_origin = <Westend as Chain>::RuntimeOrigin::root();
172
1
    let dancebox_para_destination: VersionedLocation =
173
1
        Westend::child_location_of(Dancebox::para_id()).into();
174
1

            
175
1
    let fallback_max_weight = Some(Weight::from_parts(1000000000, 200000));
176
1
    let origin_kind = OriginKind::SovereignAccount;
177
1

            
178
1
    let buy_execution_fee_amount = dancebox_runtime::WeightToFee::weight_to_fee(
179
1
        &Weight::from_parts(10_000_000_000_000, 300_000),
180
1
    );
181
1

            
182
1
    let buy_execution_fee = Asset {
183
1
        id: dancebox_runtime::xcm_config::SelfReserve::get().into(),
184
1
        fun: Fungible(buy_execution_fee_amount),
185
1
    };
186
1

            
187
1
    let xcm = VersionedXcm::from(Xcm(vec![
188
1
        WithdrawAsset(vec![buy_execution_fee.clone()].into()),
189
1
        BuyExecution {
190
1
            fees: buy_execution_fee.clone(),
191
1
            weight_limit: Unlimited,
192
1
        },
193
1
        Transact {
194
1
            fallback_max_weight,
195
1
            origin_kind,
196
1
            call,
197
1
        },
198
1
    ]));
199
1

            
200
1
    // Send XCM message from Relay Chain
201
1
    Westend::execute_with(|| {
202
1
        assert_ok!(<Westend as WestendRelayPallet>::XcmPallet::send(
203
1
            sudo_origin,
204
1
            bx!(dancebox_para_destination),
205
1
            bx!(xcm),
206
1
        ));
207

            
208
        type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
209

            
210
1
        assert_expected_events!(
211
            Westend,
212
            vec![
213
1
                RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {},
214
            ]
215
        );
216
1
    });
217
1

            
218
1
    // Receive XCM message in Assets Parachain
219
1
    Dancebox::execute_with(|| {
220
        type RuntimeEvent = <Dancebox as Chain>::RuntimeEvent;
221
1
        assert_expected_events!(
222
            Dancebox,
223
            vec![
224
1
                RuntimeEvent::System(
225
1
                    frame_system::Event::Remarked {
226
1
                        sender,
227
1
                        ..
228
1
                    }) => {
229
1
                    sender: *sender == ParentIsPreset::<dancebox_runtime::AccountId>::convert_location(&Location::parent()).unwrap(),
230
                },
231
            ]
232
        );
233
1
    });
234
1
}
235

            
236
#[test]
237
1
fn transact_sudo_from_frontier_has_signed_origin_powers() {
238
1
    let call = <Dancebox as Chain>::RuntimeCall::System(frame_system::Call::<
239
1
        <Dancebox as Chain>::Runtime,
240
1
    >::remark_with_event {
241
1
        remark: b"Test".to_vec(),
242
1
    })
243
1
    .encode()
244
1
    .into();
245
1

            
246
1
    // XcmPallet send arguments
247
1
    let sudo_origin = <FrontierTemplate as Chain>::RuntimeOrigin::root();
248
1
    let dancebox_para_destination: VersionedLocation = Location {
249
1
        parents: 1,
250
1
        interior: X1([Parachain(Dancebox::para_id().into())].into()),
251
1
    }
252
1
    .into();
253
1

            
254
1
    let fallback_max_weight = Some(Weight::from_parts(1000000000, 200000));
255
1
    let origin_kind = OriginKind::SovereignAccount;
256
1

            
257
1
    let buy_execution_fee_amount = dancebox_runtime::WeightToFee::weight_to_fee(
258
1
        &Weight::from_parts(10_000_000_000_000, 300_000),
259
1
    );
260
1

            
261
1
    let buy_execution_fee = Asset {
262
1
        id: dancebox_runtime::xcm_config::SelfReserve::get().into(),
263
1
        fun: Fungible(buy_execution_fee_amount),
264
1
    };
265
1

            
266
1
    let xcm = VersionedXcm::from(Xcm(vec![
267
1
        WithdrawAsset(vec![buy_execution_fee.clone()].into()),
268
1
        BuyExecution {
269
1
            fees: buy_execution_fee.clone(),
270
1
            weight_limit: Unlimited,
271
1
        },
272
1
        Transact {
273
1
            fallback_max_weight,
274
1
            origin_kind,
275
1
            call,
276
1
        },
277
1
    ]));
278
1

            
279
1
    // Send XCM message from Frontier Template
280
1
    FrontierTemplate::execute_with(|| {
281
1
        assert_ok!(
282
1
            <FrontierTemplate as FrontierTemplateParaPallet>::PolkadotXcm::send(
283
1
                sudo_origin,
284
1
                bx!(dancebox_para_destination),
285
1
                bx!(xcm),
286
1
            )
287
1
        );
288

            
289
        type RuntimeEvent = <FrontierTemplate as Chain>::RuntimeEvent;
290

            
291
1
        assert_expected_events!(
292
            FrontierTemplate,
293
            vec![
294
1
                RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {},
295
            ]
296
        );
297
1
    });
298
1

            
299
1
    // Receive XCM message in Assets Parachain
300
1
    Dancebox::execute_with(|| {
301
        type RuntimeEvent = <Dancebox as Chain>::RuntimeEvent;
302
1
        assert_expected_events!(
303
            Dancebox,
304
            vec![
305
1
                RuntimeEvent::System(
306
1
                    frame_system::Event::Remarked {
307
1
                        sender,
308
1
                        ..
309
1
                    }) => {
310
1
                    sender: *sender ==  SiblingParachainConvertsVia::<polkadot_parachain_primitives::primitives::Sibling, dancebox_runtime::AccountId>::convert_location(
311
1
                        &Location{ parents: 1, interior: X1([Parachain(2001u32)].into())}
312
1
                    ).unwrap(),
313
                },
314
            ]
315
        );
316
1
    });
317
1
}
318

            
319
#[test]
320
1
fn transact_sudo_from_simple_has_signed_origin_powers() {
321
1
    let call = <Dancebox as Chain>::RuntimeCall::System(frame_system::Call::<
322
1
        <Dancebox as Chain>::Runtime,
323
1
    >::remark_with_event {
324
1
        remark: b"Test".to_vec(),
325
1
    })
326
1
    .encode()
327
1
    .into();
328
1

            
329
1
    // XcmPallet send arguments
330
1
    let sudo_origin = <SimpleTemplate as Chain>::RuntimeOrigin::root();
331
1
    let dancebox_para_destination: VersionedLocation = Location {
332
1
        parents: 1,
333
1
        interior: X1([Parachain(Dancebox::para_id().into())].into()),
334
1
    }
335
1
    .into();
336
1

            
337
1
    let fallback_max_weight = Some(Weight::from_parts(1000000000, 200000));
338
1
    let origin_kind = OriginKind::SovereignAccount;
339
1

            
340
1
    let buy_execution_fee_amount = dancebox_runtime::WeightToFee::weight_to_fee(
341
1
        &Weight::from_parts(10_000_000_000_000, 300_000),
342
1
    );
343
1

            
344
1
    let buy_execution_fee = Asset {
345
1
        id: dancebox_runtime::xcm_config::SelfReserve::get().into(),
346
1
        fun: Fungible(buy_execution_fee_amount),
347
1
    };
348
1

            
349
1
    let xcm = VersionedXcm::from(Xcm(vec![
350
1
        WithdrawAsset(vec![buy_execution_fee.clone()].into()),
351
1
        BuyExecution {
352
1
            fees: buy_execution_fee.clone(),
353
1
            weight_limit: Unlimited,
354
1
        },
355
1
        Transact {
356
1
            fallback_max_weight,
357
1
            origin_kind,
358
1
            call,
359
1
        },
360
1
    ]));
361
1

            
362
1
    // Send XCM message from Relay Chain
363
1
    SimpleTemplate::execute_with(|| {
364
1
        assert_ok!(
365
1
            <SimpleTemplate as SimpleTemplateParaPallet>::PolkadotXcm::send(
366
1
                sudo_origin,
367
1
                bx!(dancebox_para_destination),
368
1
                bx!(xcm),
369
1
            )
370
1
        );
371

            
372
        type RuntimeEvent = <SimpleTemplate as Chain>::RuntimeEvent;
373

            
374
1
        assert_expected_events!(
375
            SimpleTemplate,
376
            vec![
377
1
                RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {},
378
            ]
379
        );
380
1
    });
381
1

            
382
1
    // Receive XCM message in Assets Parachain
383
1
    Dancebox::execute_with(|| {
384
        type RuntimeEvent = <Dancebox as Chain>::RuntimeEvent;
385
1
        assert_expected_events!(
386
            Dancebox,
387
            vec![
388
1
                RuntimeEvent::System(
389
1
                    frame_system::Event::Remarked {
390
1
                        sender,
391
1
                        ..
392
1
                    }) => {
393
1
                    sender: *sender ==  SiblingParachainConvertsVia::<polkadot_parachain_primitives::primitives::Sibling, dancebox_runtime::AccountId>::convert_location(
394
1
                        &Location{ parents: 1, interior: X1([Parachain(2002u32)].into())}
395
1
                    ).unwrap(),
396
                },
397
            ]
398
        );
399
1
    });
400
1
}