1
// Copyright 2024 Moonbeam Foundation.
2
// This file is part of Moonbeam.
3

            
4
// Moonbeam 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
// Moonbeam 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 Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
use crate::*;
18
use mock::*;
19

            
20
use frame_support::{assert_noop, assert_ok};
21
use precompile_utils::testing::Bob;
22
use xcm::latest::prelude::*;
23

            
24
8
fn encode_ticker(str_: &str) -> BoundedVec<u8, ConstU32<256>> {
25
8
	BoundedVec::try_from(str_.as_bytes().to_vec()).expect("too long")
26
8
}
27

            
28
8
fn encode_token_name(str_: &str) -> BoundedVec<u8, ConstU32<256>> {
29
8
	BoundedVec::try_from(str_.as_bytes().to_vec()).expect("too long")
30
8
}
31

            
32
#[test]
33
1
fn create_foreign_and_freeze_unfreeze() {
34
1
	ExtBuilder::default().build().execute_with(|| {
35
1
		// create foreign asset
36
1
		assert_ok!(EvmForeignAssets::create_foreign_asset(
37
1
			RuntimeOrigin::root(),
38
1
			1,
39
1
			Location::parent(),
40
1
			18,
41
1
			encode_ticker("MTT"),
42
1
			encode_token_name("Mytoken"),
43
1
		));
44

            
45
1
		assert_eq!(EvmForeignAssets::assets_by_id(1), Some(Location::parent()));
46
1
		assert_eq!(
47
1
			EvmForeignAssets::assets_by_location(Location::parent()),
48
1
			Some((1, AssetStatus::Active)),
49
1
		);
50
1
		expect_events(vec![crate::Event::ForeignAssetCreated {
51
1
			contract_address: H160([
52
1
				255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
53
1
			]),
54
1
			asset_id: 1,
55
1
			xcm_location: Location::parent(),
56
1
		}]);
57
1

            
58
1
		let (xcm_location, asset_id): (Location, u128) = get_asset_created_hook_invocation()
59
1
			.expect("Decoding of invocation data should not fail");
60
1
		assert_eq!(xcm_location, Location::parent());
61
1
		assert_eq!(asset_id, 1u128);
62

            
63
		// Check storage
64
1
		assert_eq!(EvmForeignAssets::assets_by_id(&1), Some(Location::parent()));
65
1
		assert_eq!(
66
1
			EvmForeignAssets::assets_by_location(&Location::parent()),
67
1
			Some((1, AssetStatus::Active))
68
1
		);
69

            
70
		// Unfreeze should return AssetNotFrozen error
71
1
		assert_noop!(
72
1
			EvmForeignAssets::unfreeze_foreign_asset(RuntimeOrigin::root(), 1),
73
1
			Error::<Test>::AssetNotFrozen
74
1
		);
75

            
76
		// Freeze should work
77
1
		assert_ok!(EvmForeignAssets::freeze_foreign_asset(
78
1
			RuntimeOrigin::root(),
79
1
			1,
80
1
			true
81
1
		),);
82
1
		assert_eq!(
83
1
			EvmForeignAssets::assets_by_location(&Location::parent()),
84
1
			Some((1, AssetStatus::FrozenXcmDepositAllowed))
85
1
		);
86

            
87
		// Should not be able to freeze an asset already frozen
88
1
		assert_noop!(
89
1
			EvmForeignAssets::freeze_foreign_asset(RuntimeOrigin::root(), 1, true),
90
1
			Error::<Test>::AssetAlreadyFrozen
91
1
		);
92

            
93
		// Unfreeze should work
94
1
		assert_ok!(EvmForeignAssets::unfreeze_foreign_asset(
95
1
			RuntimeOrigin::root(),
96
1
			1
97
1
		),);
98
1
		assert_eq!(
99
1
			EvmForeignAssets::assets_by_location(&Location::parent()),
100
1
			Some((1, AssetStatus::Active))
101
1
		);
102
1
	});
103
1
}
104

            
105
#[test]
106
1
fn test_asset_exists_error() {
107
1
	ExtBuilder::default().build().execute_with(|| {
108
1
		assert_ok!(EvmForeignAssets::create_foreign_asset(
109
1
			RuntimeOrigin::root(),
110
1
			1,
111
1
			Location::parent(),
112
1
			18,
113
1
			encode_ticker("MTT"),
114
1
			encode_token_name("Mytoken"),
115
1
		));
116
1
		assert_eq!(
117
1
			EvmForeignAssets::assets_by_id(1).unwrap(),
118
1
			Location::parent()
119
1
		);
120
1
		assert_noop!(
121
1
			EvmForeignAssets::create_foreign_asset(
122
1
				RuntimeOrigin::root(),
123
1
				1,
124
1
				Location::parent(),
125
1
				18,
126
1
				encode_ticker("MTT"),
127
1
				encode_token_name("Mytoken"),
128
1
			),
129
1
			Error::<Test>::AssetAlreadyExists
130
1
		);
131
1
	});
132
1
}
133

            
134
#[test]
135
1
fn test_regular_user_cannot_call_extrinsics() {
136
1
	ExtBuilder::default().build().execute_with(|| {
137
1
		assert_noop!(
138
1
			EvmForeignAssets::create_foreign_asset(
139
1
				RuntimeOrigin::signed(Bob.into()),
140
1
				1,
141
1
				Location::parent(),
142
1
				18,
143
1
				encode_ticker("MTT"),
144
1
				encode_token_name("Mytoken"),
145
1
			),
146
1
			sp_runtime::DispatchError::BadOrigin
147
1
		);
148

            
149
1
		assert_noop!(
150
1
			EvmForeignAssets::change_xcm_location(
151
1
				RuntimeOrigin::signed(Bob.into()),
152
1
				1,
153
1
				Location::parent()
154
1
			),
155
1
			sp_runtime::DispatchError::BadOrigin
156
1
		);
157
1
	});
158
1
}
159

            
160
#[test]
161
1
fn test_root_can_change_foreign_asset_for_asset_id() {
162
1
	ExtBuilder::default().build().execute_with(|| {
163
1
		assert_ok!(EvmForeignAssets::create_foreign_asset(
164
1
			RuntimeOrigin::root(),
165
1
			1,
166
1
			Location::parent(),
167
1
			18,
168
1
			encode_ticker("MTT"),
169
1
			encode_token_name("Mytoken"),
170
1
		));
171

            
172
1
		assert_ok!(EvmForeignAssets::change_xcm_location(
173
1
			RuntimeOrigin::root(),
174
1
			1,
175
1
			Location::here()
176
1
		));
177

            
178
		// New associations are stablished
179
1
		assert_eq!(EvmForeignAssets::assets_by_id(1).unwrap(), Location::here());
180
1
		assert_eq!(
181
1
			EvmForeignAssets::assets_by_location(Location::here()).unwrap(),
182
1
			(1, AssetStatus::Active),
183
1
		);
184

            
185
		// Old ones are deleted
186
1
		assert!(EvmForeignAssets::assets_by_location(Location::parent()).is_none());
187

            
188
1
		expect_events(vec![
189
1
			crate::Event::ForeignAssetCreated {
190
1
				contract_address: H160([
191
1
					255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
192
1
				]),
193
1
				asset_id: 1,
194
1
				xcm_location: Location::parent(),
195
1
			},
196
1
			crate::Event::ForeignAssetXcmLocationChanged {
197
1
				asset_id: 1,
198
1
				new_xcm_location: Location::here(),
199
1
			},
200
1
		])
201
1
	});
202
1
}
203

            
204
#[test]
205
1
fn test_asset_id_non_existent_error() {
206
1
	ExtBuilder::default().build().execute_with(|| {
207
1
		assert_noop!(
208
1
			EvmForeignAssets::change_xcm_location(RuntimeOrigin::root(), 1, Location::parent()),
209
1
			Error::<Test>::AssetDoesNotExist
210
1
		);
211
1
	});
212
1
}
213

            
214
#[test]
215
1
fn test_location_already_exist_error() {
216
1
	ExtBuilder::default().build().execute_with(|| {
217
1
		// Setup: create a first foreign asset taht we will try to override
218
1
		assert_ok!(EvmForeignAssets::create_foreign_asset(
219
1
			RuntimeOrigin::root(),
220
1
			1,
221
1
			Location::parent(),
222
1
			18,
223
1
			encode_ticker("MTT"),
224
1
			encode_token_name("Mytoken"),
225
1
		));
226

            
227
1
		assert_noop!(
228
1
			EvmForeignAssets::create_foreign_asset(
229
1
				RuntimeOrigin::root(),
230
1
				2,
231
1
				Location::parent(),
232
1
				18,
233
1
				encode_ticker("MTT"),
234
1
				encode_token_name("Mytoken"),
235
1
			),
236
1
			Error::<Test>::LocationAlreadyExists
237
1
		);
238

            
239
		// Setup: create a second foreign asset that will try to override the first one
240
1
		assert_ok!(EvmForeignAssets::create_foreign_asset(
241
1
			RuntimeOrigin::root(),
242
1
			2,
243
1
			Location::new(2, *&[]),
244
1
			18,
245
1
			encode_ticker("MTT"),
246
1
			encode_token_name("Mytoken"),
247
1
		));
248

            
249
1
		assert_noop!(
250
1
			EvmForeignAssets::change_xcm_location(RuntimeOrigin::root(), 2, Location::parent()),
251
1
			Error::<Test>::LocationAlreadyExists
252
1
		);
253
1
	});
254
1
}