// SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork use crate::{mock::*, DispatchError::BadOrigin, *}; use pezframe_support::{assert_noop, assert_ok}; use pezsnowbridge_test_utils::FAILING_NONCE; use pezsp_keyring::sr25519::Keyring; use xcm::{latest::ZAGROS_GENESIS_HASH, prelude::*}; #[test] fn register_tokens_succeeds() { new_test_ext(true).execute_with(|| { let origin = make_xcm_origin(FrontendLocation::get()); let versioned_location: VersionedLocation = Location::parent().into(); assert_ok!(EthereumSystemV2::register_token( origin, Box::new(versioned_location.clone()), Box::new(versioned_location), Default::default(), 1 )); }); } #[test] fn agent_id_from_location() { new_test_ext(true).execute_with(|| { let bob: AccountId = Keyring::Bob.into(); let origin = Location::new( 1, [ Teyrchain(1000), AccountId32 { network: Some(NetworkId::ByGenesis(ZAGROS_GENESIS_HASH)), id: bob.into(), }, ], ); let agent_id = EthereumSystemV2::location_to_message_origin(origin.clone()).unwrap(); let expected_agent_id = hex_literal::hex!("fa2d646322a1c6db25dd004f44f14f3d39a9556bed9655f372942a84a5b3d93b") .into(); assert_eq!(agent_id, expected_agent_id); }); } #[test] fn upgrade_as_root() { new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::root(); let address: H160 = [1_u8; 20].into(); let code_hash: H256 = [1_u8; 32].into(); let initializer = Initializer { params: [0; 256].into(), maximum_required_gas: 10000 }; let initializer_params_hash: H256 = blake2_256(initializer.params.as_ref()).into(); assert_ok!(EthereumSystemV2::upgrade(origin, address, code_hash, initializer)); System::assert_last_event(RuntimeEvent::EthereumSystemV2(crate::Event::Upgrade { impl_address: address, impl_code_hash: code_hash, initializer_params_hash, })); }); } #[test] fn upgrade_as_signed_fails() { new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::signed(pezsp_runtime::AccountId32::new([0; 32])); let address: H160 = Default::default(); let code_hash: H256 = Default::default(); let initializer = Initializer { params: [0; 256].into(), maximum_required_gas: 10000 }; assert_noop!(EthereumSystemV2::upgrade(origin, address, code_hash, initializer), BadOrigin); }); } #[test] fn upgrade_with_params() { new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::root(); let address: H160 = [1_u8; 20].into(); let code_hash: H256 = [1_u8; 32].into(); let initializer = Initializer { params: [0; 256].into(), maximum_required_gas: 10000 }; assert_ok!(EthereumSystemV2::upgrade(origin, address, code_hash, initializer)); }); } #[test] fn set_operating_mode() { new_test_ext(true).execute_with(|| { let origin = RuntimeOrigin::root(); let mode = OperatingMode::RejectingOutboundMessages; assert_ok!(EthereumSystemV2::set_operating_mode(origin, mode)); System::assert_last_event(RuntimeEvent::EthereumSystemV2(crate::Event::SetOperatingMode { mode, })); }); } pub struct RegisterTokenTestCase { /// Input: Location of Pezkuwi-native token relative to BH pub native: Location, } #[test] fn register_all_tokens_succeeds() { let test_cases = vec![ // HEZ RegisterTokenTestCase { native: Location::parent() }, // GLMR (Some Pezkuwi teyrchain currency) RegisterTokenTestCase { native: Location::new(1, [Teyrchain(2004)]) }, // USDT RegisterTokenTestCase { native: Location::new(1, [Teyrchain(1000), PalletInstance(50), GeneralIndex(1984)]), }, // KSM RegisterTokenTestCase { native: Location::new(2, [GlobalConsensus(Kusama)]) }, // KAR (Some Kusama teyrchain currency) RegisterTokenTestCase { native: Location::new(2, [GlobalConsensus(Kusama), Teyrchain(2000)]), }, ]; for tc in test_cases.iter() { new_test_ext(true).execute_with(|| { let origin = make_xcm_origin(FrontendLocation::get()); let versioned_location: VersionedLocation = tc.native.clone().into(); assert_ok!(EthereumSystemV2::register_token( origin, Box::new(versioned_location.clone()), Box::new(versioned_location), Default::default(), 1 )); let reanchored_location = EthereumSystemV2::reanchor(tc.native.clone()).unwrap(); let foreign_token_id = EthereumSystemV2::location_to_message_origin(tc.native.clone()).unwrap(); assert_eq!( ForeignToNativeId::::get(foreign_token_id), Some(reanchored_location.clone()) ); System::assert_last_event(RuntimeEvent::EthereumSystemV2( Event::::RegisterToken { location: reanchored_location.into(), foreign_token_id, }, )); }); } } #[test] fn register_ethereum_native_token_fails() { new_test_ext(true).execute_with(|| { let origin = make_xcm_origin(FrontendLocation::get()); let location = Location::new(2, [GlobalConsensus(Ethereum { chain_id: 11155111 })]); let versioned_location: Box = Box::new(location.clone().into()); assert_noop!( EthereumSystemV2::register_token( origin, versioned_location.clone(), versioned_location.clone(), Default::default(), 1 ), Error::::LocationConversionFailed ); }); } #[test] fn add_tip_inbound_succeeds() { new_test_ext(true).execute_with(|| { let origin = make_xcm_origin(FrontendLocation::get()); let sender: AccountId = Keyring::Alice.into(); let message_id = MessageId::Inbound(1); let amount = 1000; assert_ok!(EthereumSystemV2::add_tip(origin, sender.clone(), message_id.clone(), amount)); System::assert_last_event(RuntimeEvent::EthereumSystemV2(Event::::TipProcessed { sender: sender.clone(), message_id, amount, success: true, })); let lost_tip = LostTips::::get(sender); assert_eq!(lost_tip, 0); }); } #[test] fn add_tip_inbound_fails_when_nonce_is_consumed() { new_test_ext(true).execute_with(|| { let origin = make_xcm_origin(FrontendLocation::get()); let sender: AccountId = Keyring::Alice.into(); // In `MockOkInboundQueue`, the mocked implementation returns an error when the nonce is // equal to 3, to simulate an error condition. let message_id = MessageId::Inbound(FAILING_NONCE); let amount = 1000; assert_ok!(EthereumSystemV2::add_tip(origin, sender.clone(), message_id.clone(), amount)); System::assert_last_event(RuntimeEvent::EthereumSystemV2(Event::::TipProcessed { sender: sender.clone(), message_id, amount, success: false, })); let lost_tip = LostTips::::get(sender); assert_eq!(lost_tip, 1000); }); } #[test] fn add_tip_outbound_succeeds() { new_test_ext(true).execute_with(|| { let origin = make_xcm_origin(FrontendLocation::get()); let sender: AccountId = Keyring::Alice.into(); let message_id = MessageId::Outbound(1); let amount = 500; assert_ok!(EthereumSystemV2::add_tip(origin, sender.clone(), message_id.clone(), amount)); System::assert_last_event(RuntimeEvent::EthereumSystemV2(Event::::TipProcessed { sender: sender.clone(), message_id, amount, success: true, })); let lost_tip = LostTips::::get(sender); assert_eq!(lost_tip, 0); }); } #[test] fn add_tip_outbound_fails_when_pending_order_not_found() { new_test_ext(false).execute_with(|| { let origin = make_xcm_origin(FrontendLocation::get()); let sender: AccountId = Keyring::Alice.into(); // In `MockOkOutboundQueue`, the mocked implementation returns an error when the nonce is // equal to 3, to simulate an error condition. let message_id = MessageId::Outbound(FAILING_NONCE); let amount = 500; assert_ok!(EthereumSystemV2::add_tip(origin, sender.clone(), message_id.clone(), amount)); System::assert_last_event(RuntimeEvent::EthereumSystemV2(Event::::TipProcessed { sender: sender.clone(), message_id, amount, success: false, })); let lost_tip = LostTips::::get(sender); assert_eq!(lost_tip, 500); }); } #[test] fn add_tip_with_wrong_origin_fails() { new_test_ext(true).execute_with(|| { let invalid_origin = RuntimeOrigin::root(); let sender: AccountId = Keyring::Alice.into(); let message_id = MessageId::Inbound(1); let amount = 1000; assert_noop!( EthereumSystemV2::add_tip(invalid_origin, sender, message_id, amount), BadOrigin ); }); }