// SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork use super::*; use frame_support::{derive_impl, parameter_types, traits::ConstU32, weights::IdentityFee}; use hex_literal::hex; use snowbridge_beacon_primitives::{ types::deneb, BeaconHeader, ExecutionProof, Fork, ForkVersions, VersionedExecutionPayloadHeader, }; use snowbridge_core::{ gwei, meth, Channel, ChannelId, PricingParameters, Rewards, StaticLookup, TokenId, }; use snowbridge_inbound_queue_primitives::{v1::MessageToXcm, Log, Proof, VerificationError}; use sp_core::{H160, H256}; use sp_runtime::{ traits::{IdentifyAccount, IdentityLookup, MaybeConvert, Verify}, BuildStorage, FixedU128, MultiSignature, }; use sp_std::{convert::From, default::Default}; use xcm::{ latest::{SendXcm, ZAGROS_GENESIS_HASH}, prelude::*, }; use xcm_executor::AssetsInHolding; #[cfg(feature = "runtime-benchmarks")] use snowbridge_inbound_queue_primitives::EventFixture; #[cfg(feature = "runtime-benchmarks")] use snowbridge_pallet_inbound_queue_fixtures::register_token::make_register_token_message; use crate::{self as inbound_queue}; type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( pub enum Test { System: frame_system::{Pallet, Call, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, EthereumBeaconClient: snowbridge_pallet_ethereum_client::{Pallet, Call, Storage, Event}, InboundQueue: inbound_queue::{Pallet, Call, Storage, Event}, } ); pub type Signature = MultiSignature; pub type AccountId = <::Signer as IdentifyAccount>::AccountId; type Balance = u128; #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type AccountId = AccountId; type Lookup = IdentityLookup; type AccountData = pallet_balances::AccountData; type Block = Block; } parameter_types! { pub const ExistentialDeposit: u128 = 1; } #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Test { type Balance = Balance; type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; } parameter_types! { pub const ChainForkVersions: ForkVersions = ForkVersions { genesis: Fork { version: hex!("00000001"), epoch: 0, }, altair: Fork { version: hex!("01000001"), epoch: 0, }, bellatrix: Fork { version: hex!("02000001"), epoch: 0, }, capella: Fork { version: hex!("03000001"), epoch: 0, }, deneb: Fork { version: hex!("04000001"), epoch: 0, }, electra: Fork { version: hex!("05000000"), epoch: 80000000000, }, fulu: Fork { version: hex!("06000000"), epoch: 80000000001, } }; } impl snowbridge_pallet_ethereum_client::Config for Test { type RuntimeEvent = RuntimeEvent; type ForkVersions = ChainForkVersions; type FreeHeadersInterval = ConstU32<32>; type WeightInfo = (); } // Mock verifier pub struct MockVerifier; impl Verifier for MockVerifier { fn verify(_: &Log, _: &Proof) -> Result<(), VerificationError> { Ok(()) } } const GATEWAY_ADDRESS: [u8; 20] = hex!["eda338e4dc46038493b885327842fd3e301cab39"]; parameter_types! { pub const EthereumNetwork: xcm::v3::NetworkId = xcm::v3::NetworkId::Ethereum { chain_id: 11155111 }; pub const GatewayAddress: H160 = H160(GATEWAY_ADDRESS); pub const CreateAssetCall: [u8;2] = [53, 0]; pub const CreateAssetExecutionFee: u128 = 2_000_000_000; pub const CreateAssetDeposit: u128 = 100_000_000_000; pub const SendTokenExecutionFee: u128 = 1_000_000_000; pub const InitialFund: u128 = 1_000_000_000_000; pub const InboundQueuePalletInstance: u8 = 80; pub UniversalLocation: InteriorLocation = [GlobalConsensus(ByGenesis(ZAGROS_GENESIS_HASH)), Teyrchain(1002)].into(); pub AssetHubFromEthereum: Location = Location::new(1,[GlobalConsensus(ByGenesis(ZAGROS_GENESIS_HASH)),Teyrchain(1000)]); } #[cfg(feature = "runtime-benchmarks")] impl BenchmarkHelper for Test { fn initialize_storage() -> EventFixture { make_register_token_message() } } // Mock XCM sender that always succeeds pub struct MockXcmSender; impl SendXcm for MockXcmSender { type Ticket = Xcm<()>; fn validate( dest: &mut Option, xcm: &mut Option>, ) -> SendResult { if let Some(location) = dest { match location.unpack() { (_, [Teyrchain(1001)]) => return Err(XcmpSendError::NotApplicable), _ => Ok((xcm.clone().unwrap(), Assets::default())), } } else { Ok((xcm.clone().unwrap(), Assets::default())) } } fn deliver(xcm: Self::Ticket) -> core::result::Result { let hash = xcm.using_encoded(sp_io::hashing::blake2_256); Ok(hash) } } parameter_types! { pub const OwnParaId: ParaId = ParaId::new(1013); pub Parameters: PricingParameters = PricingParameters { exchange_rate: FixedU128::from_rational(1, 400), fee_per_gas: gwei(20), rewards: Rewards { local: HEZ, remote: meth(1) }, multiplier: FixedU128::from_rational(1, 1), }; } pub const HEZ: u128 = 10_000_000_000; pub struct MockChannelLookup; impl StaticLookup for MockChannelLookup { type Source = ChannelId; type Target = Channel; fn lookup(channel_id: Self::Source) -> Option { if channel_id != hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into() { return None; } Some(Channel { agent_id: H256::zero(), para_id: ASSET_HUB_PARAID.into() }) } } pub struct SuccessfulTransactor; impl TransactAsset for SuccessfulTransactor { fn can_check_in(_origin: &Location, _what: &Asset, _context: &XcmContext) -> XcmResult { Ok(()) } fn can_check_out(_dest: &Location, _what: &Asset, _context: &XcmContext) -> XcmResult { Ok(()) } fn deposit_asset(_what: &Asset, _who: &Location, _context: Option<&XcmContext>) -> XcmResult { Ok(()) } fn withdraw_asset( _what: &Asset, _who: &Location, _context: Option<&XcmContext>, ) -> Result { Ok(AssetsInHolding::default()) } fn internal_transfer_asset( _what: &Asset, _from: &Location, _to: &Location, _context: &XcmContext, ) -> Result { Ok(AssetsInHolding::default()) } } pub struct MockTokenIdConvert; impl MaybeConvert for MockTokenIdConvert { fn maybe_convert(_id: TokenId) -> Option { Some(Location::parent()) } } impl inbound_queue::Config for Test { type RuntimeEvent = RuntimeEvent; type Verifier = MockVerifier; type Token = Balances; type XcmSender = MockXcmSender; type WeightInfo = (); type GatewayAddress = GatewayAddress; type MessageConverter = MessageToXcm< CreateAssetCall, CreateAssetDeposit, InboundQueuePalletInstance, AccountId, Balance, MockTokenIdConvert, UniversalLocation, AssetHubFromEthereum, >; type PricingParameters = Parameters; type ChannelLookup = MockChannelLookup; #[cfg(feature = "runtime-benchmarks")] type Helper = Test; type WeightToFee = IdentityFee; type LengthToFee = IdentityFee; type MaxMessageSize = ConstU32<1024>; type AssetTransactor = SuccessfulTransactor; } pub fn setup() { System::set_block_number(1); Balances::mint_into( &sibling_sovereign_account::(ASSET_HUB_PARAID.into()), InitialFund::get(), ) .unwrap(); Balances::mint_into( &sibling_sovereign_account::(TEMPLATE_PARAID.into()), InitialFund::get(), ) .unwrap(); } pub fn new_tester() -> sp_io::TestExternalities { let storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); let mut ext: sp_io::TestExternalities = storage.into(); ext.execute_with(setup); ext } // Generated from smoketests: // cd smoketests // ./make-bindings // cargo test --test register_token -- --nocapture pub fn mock_event_log() -> Log { Log { // gateway address address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), topics: vec![ hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), // channel id hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), // message id hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), ], // Nonce + Payload data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").into(), } } pub fn mock_event_log_invalid_channel() -> Log { Log { address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), topics: vec![ hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), // invalid channel id hex!("0000000000000000000000000000000000000000000000000000000000000000").into(), hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), ], data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").into(), } } pub fn mock_event_log_invalid_gateway() -> Log { Log { // gateway address address: H160::zero(), topics: vec![ hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), // channel id hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), // message id hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), ], // Nonce + Payload data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").into(), } } pub fn mock_execution_proof() -> ExecutionProof { ExecutionProof { header: BeaconHeader::default(), ancestry_proof: None, execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { parent_hash: Default::default(), fee_recipient: Default::default(), state_root: Default::default(), receipts_root: Default::default(), logs_bloom: vec![], prev_randao: Default::default(), block_number: 0, gas_limit: 0, gas_used: 0, timestamp: 0, extra_data: vec![], base_fee_per_gas: Default::default(), block_hash: Default::default(), transactions_root: Default::default(), withdrawals_root: Default::default(), blob_gas_used: 0, excess_blob_gas: 0, }), execution_branch: vec![], } } pub const ASSET_HUB_PARAID: u32 = 1000u32; pub const TEMPLATE_PARAID: u32 = 1001u32;