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
    crate::{
19
        assert_expected_events,
20
        tests::common::xcm::{
21
            mocknets::{
22
                DanceboxPara as Dancebox, DanceboxParaPallet, EthereumEmptyReceiver,
23
                EthereumSender, FrontierTemplatePara as FrontierTemplate,
24
                FrontierTemplateParaPallet, WestendEmptyReceiver, WestendRelay as Westend,
25
                WestendRelayPallet, WestendSender,
26
            },
27
            *,
28
        },
29
    },
30
    container_chain_template_frontier_runtime::currency::UNIT as FRONTIER_DEV,
31
    frame_support::{
32
        assert_ok,
33
        weights::{Weight, WeightToFee},
34
    },
35
    staging_xcm::{
36
        latest::prelude::{Junctions::X1, *},
37
        VersionedLocation, VersionedXcm,
38
    },
39
    staging_xcm_executor::traits::ConvertLocation,
40
    westend_runtime_constants::currency::UNITS as WND,
41
    xcm_emulator::Chain,
42
};
43

            
44
#[test]
45
1
fn using_sovereign_works_from_tanssi() {
46
1
    // XcmPallet send arguments
47
1
    let sudo_origin = <Dancebox as Chain>::RuntimeOrigin::root();
48
1
    let relay_destination: VersionedLocation = Location::parent().into();
49
1

            
50
1
    let buy_execution_fee_amount = westend_runtime_constants::fee::WeightToFee::weight_to_fee(
51
1
        &Weight::from_parts(10_000_000_000, 300_000),
52
1
    );
53
1

            
54
1
    let buy_execution_fee = Asset {
55
1
        id: Location::here().into(),
56
1
        fun: Fungible(buy_execution_fee_amount),
57
1
    };
58
1

            
59
1
    let xcm = VersionedXcm::from(Xcm(vec![
60
1
        WithdrawAsset(vec![buy_execution_fee.clone()].into()),
61
1
        BuyExecution {
62
1
            fees: buy_execution_fee.clone(),
63
1
            weight_limit: Unlimited,
64
1
        },
65
1
        DepositAsset {
66
1
            assets: Wild(AllCounted(1)),
67
1
            beneficiary: AccountId32 {
68
1
                network: None,
69
1
                id: WestendEmptyReceiver::get().into(),
70
1
            }
71
1
            .into(),
72
1
        },
73
1
    ]));
74
1

            
75
1
    Westend::execute_with(|| {
76
1
        // We also need to transfer first sufficient amount to the sovereign
77
1
        let sovereign_account =
78
1
            westend_runtime::xcm_config::LocationConverter::convert_location(&Location {
79
1
                parents: 0,
80
1
                interior: X1([Parachain(2000u32)].into()),
81
1
            })
82
1
            .unwrap();
83
1

            
84
1
        let origin = <Westend as Chain>::RuntimeOrigin::signed(WestendSender::get());
85
1
        assert_ok!(
86
1
            <Westend as WestendRelayPallet>::Balances::transfer_allow_death(
87
1
                origin,
88
1
                sp_runtime::MultiAddress::Id(sovereign_account),
89
1
                100 * WND
90
1
            )
91
1
        );
92
        // Assert empty receiver has 0 funds
93
1
        assert_eq!(
94
1
            <Westend as Chain>::System::account(WestendEmptyReceiver::get())
95
1
                .data
96
1
                .free,
97
1
            0
98
1
        );
99
1
    });
100
1

            
101
1
    // Send XCM message from Dancebox
102
1
    Dancebox::execute_with(|| {
103
1
        assert_ok!(<Dancebox as DanceboxParaPallet>::PolkadotXcm::send(
104
1
            sudo_origin,
105
1
            bx!(relay_destination),
106
1
            bx!(xcm),
107
1
        ));
108

            
109
        type RuntimeEvent = <Dancebox as Chain>::RuntimeEvent;
110

            
111
1
        assert_expected_events!(
112
            Dancebox,
113
            vec![
114
1
                RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {},
115
            ]
116
        );
117
1
    });
118
1

            
119
1
    // Receive XCM message in Relay
120
1
    Westend::execute_with(|| {
121
        type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
122
1
        assert_expected_events!(
123
            Westend,
124
            vec![
125
1
                RuntimeEvent::MessageQueue(
126
1
                    pallet_message_queue::Event::Processed {
127
1
                        success,
128
1
                        ..
129
1
                    }) => {
130
1
                    success: *success,
131
                },
132
            ]
133
        );
134
        // Assert empty receiver received funds
135
1
        assert!(
136
1
            <Westend as Chain>::System::account(WestendEmptyReceiver::get())
137
1
                .data
138
1
                .free
139
1
                > 0
140
1
        );
141
1
    });
142
1
}
143

            
144
#[test]
145
1
fn using_sovereign_works_from_tanssi_frontier_template() {
146
1
    // XcmPallet send arguments
147
1
    let sudo_origin = <Dancebox as Chain>::RuntimeOrigin::root();
148
1
    let frontier_destination: VersionedLocation = Location {
149
1
        parents: 1,
150
1
        interior: X1([Parachain(2001)].into()),
151
1
    }
152
1
    .into();
153
1

            
154
1
    let buy_execution_fee_amount =
155
1
        container_chain_template_frontier_runtime::WeightToFee::weight_to_fee(&Weight::from_parts(
156
1
            10_000_000_000,
157
1
            300_000,
158
1
        ));
159
1

            
160
1
    let buy_execution_fee = Asset {
161
1
        id: container_chain_template_frontier_runtime::xcm_config::SelfReserve::get().into(),
162
1
        fun: Fungible(buy_execution_fee_amount),
163
1
    };
164
1

            
165
1
    let xcm = VersionedXcm::from(Xcm(vec![
166
1
        WithdrawAsset(vec![buy_execution_fee.clone()].into()),
167
1
        BuyExecution {
168
1
            fees: buy_execution_fee.clone(),
169
1
            weight_limit: Unlimited,
170
1
        },
171
1
        DepositAsset {
172
1
            assets: Wild(AllCounted(1)),
173
1
            beneficiary: AccountKey20 {
174
1
                network: None,
175
1
                key: EthereumEmptyReceiver::get().into(),
176
1
            }
177
1
            .into(),
178
1
        },
179
1
    ]));
180
1

            
181
1
    FrontierTemplate::execute_with(|| {
182
1
        // We also need to transfer first sufficient amount to the sovereign
183
1
        let sovereign_account =
184
1
            container_chain_template_frontier_runtime::xcm_config::LocationToAccountId::convert_location(&Location {
185
1
                parents: 1,
186
1
                interior: X1([Parachain(2000u32)].into()),
187
1
            })
188
1
            .unwrap();
189
1

            
190
1
        let origin = <FrontierTemplate as Chain>::RuntimeOrigin::signed(EthereumSender::get());
191
1
        assert_ok!(
192
1
            <FrontierTemplate as FrontierTemplateParaPallet>::Balances::transfer_allow_death(
193
1
                origin,
194
1
                sovereign_account,
195
1
                100 * FRONTIER_DEV
196
1
            )
197
1
        );
198
        // Assert empty receiver has 0 funds
199
1
        assert_eq!(
200
1
            <FrontierTemplate as FrontierTemplateParaPallet>::System::account(
201
1
                EthereumEmptyReceiver::get()
202
1
            )
203
1
            .data
204
1
            .free,
205
1
            0
206
1
        );
207
1
    });
208
1

            
209
1
    // Send XCM message from Dancebox
210
1
    Dancebox::execute_with(|| {
211
1
        assert_ok!(<Dancebox as DanceboxParaPallet>::PolkadotXcm::send(
212
1
            sudo_origin,
213
1
            bx!(frontier_destination),
214
1
            bx!(xcm),
215
1
        ));
216

            
217
        type RuntimeEvent = <Dancebox as Chain>::RuntimeEvent;
218

            
219
1
        assert_expected_events!(
220
            Dancebox,
221
            vec![
222
1
                RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {},
223
1
                RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {},
224
            ]
225
        );
226
1
    });
227
1

            
228
1
    FrontierTemplate::execute_with(|| {
229
1
        FrontierTemplate::assert_xcmp_queue_success(None);
230
1
        // Assert empty receiver received funds
231
1
        assert!(
232
1
            <FrontierTemplate as FrontierTemplateParaPallet>::System::account(
233
1
                EthereumEmptyReceiver::get()
234
1
            )
235
1
            .data
236
1
            .free
237
1
                > 0
238
1
        );
239
1
    });
240
1
}