diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index ab224ca7f9..680fc19298 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -353,8 +353,9 @@ jobs:
needs: ["set-tags", "build"]
timeout-minutes: 20
strategy:
+ fail-fast: false
matrix:
- chain: ["moonbase"]
+ chain: ["moonbase", "moonbeam"]
env:
GH_WORKFLOW_MATRIX_CHAIN: ${{ matrix.chain }}
DEBUG_COLORS: 1
diff --git a/Cargo.lock b/Cargo.lock
index 5524bdbe63..38af3d99df 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6517,6 +6517,7 @@ dependencies = [
"pallet-maintenance-mode",
"pallet-message-queue",
"pallet-migrations",
+ "pallet-moonbeam-lazy-migrations",
"pallet-moonbeam-orbiters",
"pallet-multisig",
"pallet-parachain-staking",
@@ -6999,6 +7000,7 @@ dependencies = [
"pallet-maintenance-mode",
"pallet-message-queue",
"pallet-migrations",
+ "pallet-moonbeam-lazy-migrations",
"pallet-moonbeam-orbiters",
"pallet-multisig",
"pallet-parachain-staking",
@@ -7388,6 +7390,7 @@ dependencies = [
"pallet-maintenance-mode",
"pallet-message-queue",
"pallet-migrations",
+ "pallet-moonbeam-lazy-migrations",
"pallet-moonbeam-orbiters",
"pallet-multisig",
"pallet-parachain-staking",
@@ -9564,6 +9567,22 @@ dependencies = [
"sp-std",
]
+[[package]]
+name = "pallet-moonbeam-lazy-migrations"
+version = "0.1.0"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "log",
+ "pallet-balances",
+ "parity-scale-codec",
+ "scale-info",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+]
+
[[package]]
name = "pallet-moonbeam-orbiters"
version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
index 951108cd26..5034a7bb0c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -92,6 +92,7 @@ pallet-moonbeam-orbiters = { path = "pallets/moonbeam-orbiters", default-feature
pallet-parachain-staking = { path = "pallets/parachain-staking", default-features = false }
pallet-proxy-genesis-companion = { path = "pallets/proxy-genesis-companion", default-features = false }
pallet-xcm-transactor = { path = "pallets/xcm-transactor", default-features = false }
+pallet-moonbeam-lazy-migrations = { path = "pallets/moonbeam-lazy-migrations", default-features = false }
precompile-utils = { path = "precompiles/utils", default-features = false }
xcm-primitives = { path = "primitives/xcm", default-features = false }
diff --git a/pallets/moonbeam-lazy-migrations/Cargo.toml b/pallets/moonbeam-lazy-migrations/Cargo.toml
new file mode 100644
index 0000000000..bd9bf72e52
--- /dev/null
+++ b/pallets/moonbeam-lazy-migrations/Cargo.toml
@@ -0,0 +1,40 @@
+[package]
+name = "pallet-moonbeam-lazy-migrations"
+authors = { workspace = true }
+description = "A pallet for performing migrations from extrinsics"
+edition = "2021"
+version = "0.1.0"
+
+[dependencies]
+log = { workspace = true }
+
+# Substrate
+frame-support = { workspace = true }
+frame-system = { workspace = true }
+parity-scale-codec = { workspace = true }
+scale-info = { workspace = true, features = ["derive"] }
+sp-core = { workspace = true }
+sp-io = { workspace = true }
+sp-runtime = { workspace = true }
+
+# Benchmarks
+frame-benchmarking = { workspace = true, optional = true }
+
+[dev-dependencies]
+pallet-balances = { workspace = true }
+frame-benchmarking = { workspace = true, features = ["std"] }
+sp-io = { workspace = true, features = ["std"] }
+
+[features]
+default = ["std"]
+std = [
+ "pallet-balances/std",
+ "frame-support/std",
+ "frame-system/std",
+ "scale-info/std",
+ "sp-core/std",
+ "sp-io/std",
+ "sp-runtime/std",
+]
+runtime-benchmarks = ["frame-benchmarking"]
+try-runtime = ["frame-support/try-runtime"]
diff --git a/pallets/moonbeam-lazy-migrations/src/lib.rs b/pallets/moonbeam-lazy-migrations/src/lib.rs
new file mode 100644
index 0000000000..9081e6a105
--- /dev/null
+++ b/pallets/moonbeam-lazy-migrations/src/lib.rs
@@ -0,0 +1,110 @@
+// Copyright 2024 Moonbeam foundation
+// This file is part of Moonbeam.
+
+// Moonbeam is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Moonbeam is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Moonbeam. If not, see .
+
+//! # Lazy Migration Pallet
+
+#![allow(non_camel_case_types)]
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg(test)]
+mod mock;
+#[cfg(test)]
+mod tests;
+
+use frame_support::pallet;
+
+pub use pallet::*;
+
+#[pallet]
+pub mod pallet {
+ use super::*;
+ use frame_support::pallet_prelude::*;
+ use frame_system::pallet_prelude::*;
+
+ const INTERMEDIATES_NODES_SIZE: u64 = 4096;
+ const MAX_LOCAL_ASSETS_STORAGE_ENTRY_SIZE: u64 =
+ (/* biggest key on moonbeam */136) + (/* biggest value on moonbeam */142);
+
+ /// Pallet for multi block migrations
+ #[pallet::pallet]
+ pub struct Pallet(PhantomData);
+
+ #[pallet::storage]
+ /// If true, it means that LocalAssets storage has been removed.
+ pub(crate) type LocalAssetsMigrationCompleted = StorageValue<_, bool, ValueQuery>;
+
+ /// Configuration trait of this pallet.
+ #[pallet::config]
+ pub trait Config: frame_system::Config {}
+
+ #[pallet::error]
+ pub enum Error {
+ /// There are no more storage entries to be removed
+ AllStorageEntriesHaveBeenRemoved,
+ }
+
+ #[pallet::call]
+ impl Pallet {
+ // TODO(rodrigo): This extrinsic should be removed once LocalAssets pallet storage is removed
+ #[pallet::call_index(0)]
+ #[pallet::weight(Weight::from_parts(0,
+ INTERMEDIATES_NODES_SIZE + (MAX_LOCAL_ASSETS_STORAGE_ENTRY_SIZE * ::from(*limit)))
+ .saturating_add(::DbWeight::get()
+ .reads_writes((*limit + 1).into(), (*limit + 1).into()))
+ )]
+ pub fn clear_local_assets_storage(
+ origin: OriginFor,
+ limit: u32,
+ ) -> DispatchResultWithPostInfo {
+ ensure_signed(origin)?;
+ ensure!(limit != 0, "Limit cannot be zero!");
+
+ let mut weight = ::DbWeight::get().reads(1);
+ ensure!(
+ !LocalAssetsMigrationCompleted::::get(),
+ Error::::AllStorageEntriesHaveBeenRemoved
+ );
+
+ let hashed_prefix = sp_io::hashing::twox_128("LocalAssets".as_bytes());
+
+ let keys_removed = match sp_io::storage::clear_prefix(&hashed_prefix, Some(limit)) {
+ sp_io::KillStorageResult::AllRemoved(value) => {
+ LocalAssetsMigrationCompleted::::set(true);
+ weight
+ .saturating_accrue(::DbWeight::get().writes(1));
+ value
+ }
+ sp_io::KillStorageResult::SomeRemaining(value) => value,
+ } as u64;
+
+ log::info!("Removed {} keys 🧹", keys_removed);
+
+ Ok(Some(
+ weight
+ .saturating_add(Weight::from_parts(
+ 0,
+ INTERMEDIATES_NODES_SIZE
+ + MAX_LOCAL_ASSETS_STORAGE_ENTRY_SIZE * keys_removed,
+ ))
+ .saturating_add(
+ ::DbWeight::get()
+ .reads_writes(keys_removed, keys_removed),
+ ),
+ )
+ .into())
+ }
+ }
+}
diff --git a/pallets/moonbeam-lazy-migrations/src/mock.rs b/pallets/moonbeam-lazy-migrations/src/mock.rs
new file mode 100644
index 0000000000..9e51e10601
--- /dev/null
+++ b/pallets/moonbeam-lazy-migrations/src/mock.rs
@@ -0,0 +1,120 @@
+// Copyright 2024 Moonbeam foundation
+// This file is part of Moonbeam.
+
+// Moonbeam is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Moonbeam is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Moonbeam. If not, see .
+
+//! A minimal runtime including the multi block migrations pallet
+
+use super::*;
+use crate as pallet_moonbeam_lazy_migrations;
+use frame_support::{
+ construct_runtime, parameter_types,
+ traits::Everything,
+ weights::{constants::RocksDbWeight, Weight},
+};
+use sp_core::H256;
+use sp_runtime::{
+ traits::{BlakeTwo256, IdentityLookup},
+ BuildStorage, Perbill,
+};
+
+pub type AccountId = u64;
+pub type Balance = u128;
+type Block = frame_system::mocking::MockBlock;
+
+// Configure a mock runtime to test the pallet.
+construct_runtime!(
+ pub enum Runtime
+ {
+ System: frame_system::{Pallet, Call, Config, Storage, Event},
+ Balances: pallet_balances::{Pallet, Call, Storage, Config, Event},
+ LazyMigrations: pallet_moonbeam_lazy_migrations::{Pallet, Call},
+ }
+);
+
+parameter_types! {
+ pub const BlockHashCount: u32 = 250;
+ pub const MaximumBlockWeight: Weight = Weight::from_parts(1024, 1);
+ pub const MaximumBlockLength: u32 = 2 * 1024;
+ pub const AvailableBlockRatio: Perbill = Perbill::one();
+ pub const SS58Prefix: u8 = 42;
+}
+impl frame_system::Config for Runtime {
+ type BaseCallFilter = Everything;
+ type DbWeight = RocksDbWeight;
+ type RuntimeOrigin = RuntimeOrigin;
+ type Nonce = u64;
+ type Block = Block;
+ type RuntimeCall = RuntimeCall;
+ type Hash = H256;
+ type Hashing = BlakeTwo256;
+ type AccountId = AccountId;
+ type Lookup = IdentityLookup;
+ type RuntimeEvent = RuntimeEvent;
+ type BlockHashCount = BlockHashCount;
+ type Version = ();
+ type PalletInfo = PalletInfo;
+ type AccountData = pallet_balances::AccountData;
+ type OnNewAccount = ();
+ type OnKilledAccount = ();
+ type SystemWeightInfo = ();
+ type BlockWeights = ();
+ type BlockLength = ();
+ type SS58Prefix = SS58Prefix;
+ type OnSetCode = ();
+ type MaxConsumers = frame_support::traits::ConstU32<16>;
+}
+
+parameter_types! {
+ pub const ExistentialDeposit: u128 = 0;
+}
+impl pallet_balances::Config for Runtime {
+ type MaxReserves = ();
+ type ReserveIdentifier = ();
+ type MaxLocks = ();
+ type Balance = Balance;
+ type RuntimeEvent = RuntimeEvent;
+ type DustRemoval = ();
+ type ExistentialDeposit = ExistentialDeposit;
+ type AccountStore = System;
+ type WeightInfo = ();
+ type RuntimeHoldReason = ();
+ type FreezeIdentifier = ();
+ type MaxHolds = ();
+ type MaxFreezes = ();
+ type RuntimeFreezeReason = ();
+}
+
+impl Config for Runtime {}
+
+/// Externality builder for pallet migration's mock runtime
+pub(crate) struct ExtBuilder;
+
+impl Default for ExtBuilder {
+ fn default() -> ExtBuilder {
+ Self
+ }
+}
+
+impl ExtBuilder {
+ pub(crate) fn build(self) -> sp_io::TestExternalities {
+ let storage = frame_system::GenesisConfig::::default()
+ .build_storage()
+ .expect("Frame system builds valid default genesis config");
+
+ let mut ext = sp_io::TestExternalities::new(storage);
+ ext.execute_with(|| System::set_block_number(1));
+ ext
+ }
+}
diff --git a/pallets/moonbeam-lazy-migrations/src/tests.rs b/pallets/moonbeam-lazy-migrations/src/tests.rs
new file mode 100644
index 0000000000..5a2bdf03a9
--- /dev/null
+++ b/pallets/moonbeam-lazy-migrations/src/tests.rs
@@ -0,0 +1,80 @@
+// Copyright 2024 Moonbeam foundation
+// This file is part of Moonbeam.
+
+// Moonbeam is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Moonbeam is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Moonbeam. If not, see .
+
+//! Unit testing
+use {
+ crate::mock::{ExtBuilder, LazyMigrations},
+ frame_support::assert_ok,
+};
+
+/// TODO(rodrigo): This test should be removed once LocalAssets pallet storage is removed
+#[test]
+fn test_call_clear_local_assets_storage() {
+ let mut context = ExtBuilder::default().build();
+
+ let pallet_prefix = sp_io::hashing::twox_128("LocalAssets".as_bytes());
+ let total_storage_entries: u8 = 5;
+
+ let gen_dummy_entry = |dummy: u8| -> [u8; 32] {
+ [pallet_prefix, sp_io::hashing::twox_128(&[dummy])]
+ .concat()
+ .try_into()
+ .unwrap()
+ };
+
+ context.execute_with(|| {
+ for i in 0u8..total_storage_entries {
+ let dummy_data = gen_dummy_entry(i);
+ sp_io::storage::set(&dummy_data, &dummy_data);
+ dbg!(sp_io::storage::exists(&dummy_data));
+ }
+ });
+
+ // Commit changes
+ let _ = context.commit_all();
+
+ // Next block
+ context.execute_with(|| {
+ // Check that the storage entries exist before attempting to remove it
+ for i in 0u8..total_storage_entries {
+ let dummy_data = gen_dummy_entry(i);
+ assert!(sp_io::storage::exists(&dummy_data));
+ }
+ // Clear all storage entries
+ assert_ok!(LazyMigrations::clear_local_assets_storage(
+ crate::mock::RuntimeOrigin::signed(1),
+ total_storage_entries.into()
+ ));
+ // Check that all storage entries got deleted
+ for i in 0u8..total_storage_entries {
+ let dummy_data = gen_dummy_entry(i);
+ assert!(!sp_io::storage::exists(&dummy_data));
+ }
+ });
+
+ // Commit changes
+ let _ = context.commit_all();
+
+ // Next block
+ context.execute_with(|| {
+ // No more storage entries to be removed (expect failure)
+ assert!(LazyMigrations::clear_local_assets_storage(
+ crate::mock::RuntimeOrigin::signed(1),
+ 1
+ )
+ .is_err())
+ });
+}
diff --git a/precompiles/assets-erc20/LocalAsset.sol b/precompiles/assets-erc20/LocalAsset.sol
deleted file mode 100644
index e0c1062fbb..0000000000
--- a/precompiles/assets-erc20/LocalAsset.sol
+++ /dev/null
@@ -1,68 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-only
-pragma solidity >=0.8.3;
-
-/// @author The Moonbeam Team
-/// @title Extension of the ERC20 interface that allows an owner
-/// @dev Contract to pilot the ERC20 contract.
-interface LocalAsset {
- /// @dev Mint tokens to an address
- /// @custom:selector 40c10f19
- /// @param to address The address to which you want to mint tokens
- /// @param value uint256 the amount of tokens to be minted
- function mint(address to, uint256 value) external returns (bool);
-
- /// @dev Burn tokens from an address
- /// @custom:selector 9dc29fac
- /// @param from address The address from which you want to burn tokens
- /// @param value uint256 the amount of tokens to be burnt
- function burn(address from, uint256 value) external returns (bool);
-
- /// @dev Freeze an account, preventing it from operating with the asset
- /// @custom:selector 8d1fdf2f
- /// @param account address The address that you want to freeze
- function freeze(address account) external returns (bool);
-
- /// @dev Unfreeze an account, letting it from operating againt with the asset
- /// @custom:selector 5ea20216
- /// @param account address The address that you want to unfreeze
- function thaw(address account) external returns (bool);
-
- /// @dev Freeze the entire asset operations
- /// @custom:selector d4937f51
- function freezeAsset() external returns (bool);
-
- /// @dev Unfreeze the entire asset operations
- /// @custom:selector 51ec2ad7
- function thawAsset() external returns (bool);
-
- /// @dev Transfer the ownership of an asset to a new account
- /// @custom:selector f2fde38b
- /// @param owner address The address of the new owner
- function transferOwnership(address owner) external returns (bool);
-
- /// @dev Specify the issuer, admin and freezer of an asset
- /// @custom:selector c7d93c59
- /// @param issuer address The address capable of issuing tokens
- /// @param admin address The address capable of burning tokens and unfreezing accounts/assets
- /// @param freezer address The address capable of freezing accounts/asset
- function setTeam(
- address issuer,
- address admin,
- address freezer
- ) external returns (bool);
-
- /// @dev Specify the name, symbol and decimals of your asset
- /// @custom:selector 37d2c2f4
- /// @param name string The name of the asset
- /// @param symbol string The symbol of the asset
- /// @param decimals uint8 The number of decimals of your asset
- function setMetadata(
- string calldata name,
- string calldata symbol,
- uint8 decimals
- ) external returns (bool);
-
- /// @dev Clear the name, symbol and decimals of your asset
- /// @custom:selector efb6d432
- function clearMetadata() external returns (bool);
-}
diff --git a/precompiles/assets-erc20/src/eip2612.rs b/precompiles/assets-erc20/src/eip2612.rs
index 0e6c2e6429..eff2b44fa7 100644
--- a/precompiles/assets-erc20/src/eip2612.rs
+++ b/precompiles/assets-erc20/src/eip2612.rs
@@ -109,11 +109,9 @@ pub type NoncesStorage = StorageDoubleMap<
ValueQuery,
>;
-pub struct Eip2612(
- PhantomData<(Runtime, IsLocal, Instance)>,
-);
+pub struct Eip2612(PhantomData<(Runtime, Instance)>);
-impl Eip2612
+impl Eip2612
where
Instance: InstanceToPrefix + 'static,
Runtime: pallet_assets::Config + pallet_evm::Config + frame_system::Config,
@@ -123,7 +121,6 @@ where
BalanceOf: TryFrom + Into + solidity::Codec,
Runtime: AccountIdAssetIdConversion>,
<::RuntimeCall as Dispatchable>::RuntimeOrigin: OriginTrait,
- IsLocal: Get,
AssetIdOf: Display,
Runtime::AccountId: Into,
{
@@ -237,7 +234,7 @@ where
NoncesStorage::::insert(address, owner, nonce + U256::one());
- Erc20AssetsPrecompileSet::::approve_inner(
+ Erc20AssetsPrecompileSet::::approve_inner(
asset_id, handle, owner, spender, value,
)?;
diff --git a/precompiles/assets-erc20/src/lib.rs b/precompiles/assets-erc20/src/lib.rs
index 1eaa26a309..e65348ee8f 100644
--- a/precompiles/assets-erc20/src/lib.rs
+++ b/precompiles/assets-erc20/src/lib.rs
@@ -23,7 +23,7 @@ use frame_support::traits::fungibles::{
approvals::Inspect as ApprovalInspect, metadata::Inspect as MetadataInspect,
roles::Inspect as RolesInspect,
};
-use frame_support::traits::{ConstBool, Get, OriginTrait};
+use frame_support::traits::{Get, OriginTrait};
use frame_support::{
dispatch::{GetDispatchInfo, PostDispatchInfo},
sp_runtime::traits::StaticLookup,
@@ -53,19 +53,12 @@ pub const SELECTOR_LOG_TRANSFER: [u8; 32] = keccak256!("Transfer(address,address
/// Solidity selector of the Approval log, which is the Keccak of the Log signature.
pub const SELECTOR_LOG_APPROVAL: [u8; 32] = keccak256!("Approval(address,address,uint256)");
-/// Length limit of strings (symbol and name).
-type GetAssetsStringLimit = >::StringLimit;
-
/// Alias for the Balance type for the provided Runtime and Instance.
pub type BalanceOf = >::Balance;
/// Alias for the Asset Id type for the provided Runtime and Instance.
pub type AssetIdOf = >::AssetId;
-/// Public types to use with the PrecompileSet
-pub type IsLocal = ConstBool;
-pub type IsForeign = ConstBool;
-
/// This trait ensure we can convert AccountIds to AssetIds
/// We will require Runtime to have this trait implemented
pub trait AccountIdAssetIdConversion {
@@ -90,23 +83,23 @@ pub trait AccountIdAssetIdConversion {
/// This means that every address that starts with 0xFFFFFFFF will go through an additional db read,
/// but the probability for this to happen is 2^-32 for random addresses
-pub struct Erc20AssetsPrecompileSet(
- PhantomData<(Runtime, IsLocal, Instance)>,
+pub struct Erc20AssetsPrecompileSet(
+ PhantomData<(Runtime, Instance)>,
);
-impl Clone for Erc20AssetsPrecompileSet {
+impl Clone for Erc20AssetsPrecompileSet {
fn clone(&self) -> Self {
Self(PhantomData)
}
}
-impl Default for Erc20AssetsPrecompileSet {
+impl Default for Erc20AssetsPrecompileSet {
fn default() -> Self {
Self(PhantomData)
}
}
-impl Erc20AssetsPrecompileSet {
+impl Erc20AssetsPrecompileSet {
pub fn new() -> Self {
Self(PhantomData)
}
@@ -114,8 +107,8 @@ impl Erc20AssetsPrecompileSet Erc20AssetsPrecompileSet
+#[precompile::test_concrete_types(mock::Runtime, pallet_assets::Instance1)]
+impl Erc20AssetsPrecompileSet
where
Instance: eip2612::InstanceToPrefix + 'static,
Runtime: pallet_assets::Config + pallet_evm::Config + frame_system::Config,
@@ -125,7 +118,6 @@ where
BalanceOf: TryFrom + Into + solidity::Codec,
Runtime: AccountIdAssetIdConversion>,
<::RuntimeCall as Dispatchable>::RuntimeOrigin: OriginTrait,
- IsLocal: Get,
AssetIdOf: Display,
Runtime::AccountId: Into,
{
@@ -521,356 +513,6 @@ where
Ok(Address(freezer))
}
- // From here: only for locals, we need to check whether we are in local assets otherwise fail
- #[precompile::public("mint(address,uint256)")]
- fn mint(
- asset_id: AssetIdOf,
- handle: &mut impl PrecompileHandle,
- to: Address,
- value: U256,
- ) -> EvmResult {
- if !IsLocal::get() {
- return Err(RevertReason::UnknownSelector.into());
- }
-
- handle.record_log_costs_manual(3, 32)?;
-
- let to: H160 = to.into();
- let value = Self::u256_to_amount(value).in_field("value")?;
-
- // Build call with origin.
- {
- let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
- let to = Runtime::AddressMapping::into_account_id(to);
-
- // Dispatch call (if enough gas).
- RuntimeHelper::::try_dispatch(
- handle,
- Some(origin).into(),
- pallet_assets::Call::::mint {
- id: asset_id.into(),
- beneficiary: Runtime::Lookup::unlookup(to),
- amount: value,
- },
- SYSTEM_ACCOUNT_SIZE,
- )?;
- }
-
- log3(
- handle.context().address,
- SELECTOR_LOG_TRANSFER,
- H160::default(),
- to,
- solidity::encode_event_data(value),
- )
- .record(handle)?;
-
- Ok(true)
- }
-
- #[precompile::public("burn(address,uint256)")]
- fn burn(
- asset_id: AssetIdOf,
- handle: &mut impl PrecompileHandle,
- from: Address,
- value: U256,
- ) -> EvmResult {
- if !IsLocal::get() {
- return Err(RevertReason::UnknownSelector.into());
- }
-
- handle.record_log_costs_manual(3, 32)?;
-
- let from: H160 = from.into();
- let value = Self::u256_to_amount(value).in_field("value")?;
-
- // Build call with origin.
- {
- let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
- let from = Runtime::AddressMapping::into_account_id(from);
-
- // Dispatch call (if enough gas).
- RuntimeHelper::::try_dispatch(
- handle,
- Some(origin).into(),
- pallet_assets::Call::::burn {
- id: asset_id.into(),
- who: Runtime::Lookup::unlookup(from),
- amount: value,
- },
- 0,
- )?;
- }
-
- log3(
- handle.context().address,
- SELECTOR_LOG_TRANSFER,
- from,
- H160::default(),
- solidity::encode_event_data(value),
- )
- .record(handle)?;
-
- Ok(true)
- }
-
- #[precompile::public("freeze(address)")]
- fn freeze(
- asset_id: AssetIdOf,
- handle: &mut impl PrecompileHandle,
- account: Address,
- ) -> EvmResult {
- if !IsLocal::get() {
- return Err(RevertReason::UnknownSelector.into());
- }
-
- let account: H160 = account.into();
-
- // Build call with origin.
- {
- let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
- let account = Runtime::AddressMapping::into_account_id(account);
-
- // Dispatch call (if enough gas).
- RuntimeHelper::::try_dispatch(
- handle,
- Some(origin).into(),
- pallet_assets::Call::::freeze {
- id: asset_id.into(),
- who: Runtime::Lookup::unlookup(account),
- },
- 0,
- )?;
- }
-
- Ok(true)
- }
-
- #[precompile::public("thaw(address)")]
- fn thaw(
- asset_id: AssetIdOf,
- handle: &mut impl PrecompileHandle,
- account: Address,
- ) -> EvmResult {
- if !IsLocal::get() {
- return Err(RevertReason::UnknownSelector.into());
- }
-
- let account: H160 = account.into();
-
- // Build call with origin.
- {
- let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
- let account = Runtime::AddressMapping::into_account_id(account);
-
- // Dispatch call (if enough gas).
- RuntimeHelper::::try_dispatch(
- handle,
- Some(origin).into(),
- pallet_assets::Call::::thaw {
- id: asset_id.into(),
- who: Runtime::Lookup::unlookup(account),
- },
- 0,
- )?;
- }
-
- Ok(true)
- }
-
- #[precompile::public("freezeAsset()")]
- #[precompile::public("freeze_asset()")]
- fn freeze_asset(
- asset_id: AssetIdOf,
- handle: &mut impl PrecompileHandle,
- ) -> EvmResult {
- if !IsLocal::get() {
- return Err(RevertReason::UnknownSelector.into());
- }
-
- // Build call with origin.
- {
- let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
-
- // Dispatch call (if enough gas).
- RuntimeHelper::::try_dispatch(
- handle,
- Some(origin).into(),
- pallet_assets::Call::::freeze_asset {
- id: asset_id.into(),
- },
- 0,
- )?;
- }
-
- Ok(true)
- }
-
- #[precompile::public("thawAsset()")]
- #[precompile::public("thaw_asset()")]
- fn thaw_asset(
- asset_id: AssetIdOf,
- handle: &mut impl PrecompileHandle,
- ) -> EvmResult {
- if !IsLocal::get() {
- return Err(RevertReason::UnknownSelector.into());
- }
-
- // Build call with origin.
- {
- let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
-
- // Dispatch call (if enough gas).
- RuntimeHelper::::try_dispatch(
- handle,
- Some(origin).into(),
- pallet_assets::Call::::thaw_asset {
- id: asset_id.into(),
- },
- 0,
- )?;
- }
-
- // Build output.
- Ok(true)
- }
-
- #[precompile::public("transferOwnership(address)")]
- #[precompile::public("transfer_ownership(address)")]
- fn transfer_ownership(
- asset_id: AssetIdOf,
- handle: &mut impl PrecompileHandle,
- owner: Address,
- ) -> EvmResult {
- if !IsLocal::get() {
- return Err(RevertReason::UnknownSelector.into());
- }
-
- let owner: H160 = owner.into();
-
- // Build call with origin.
- {
- let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
- let owner = Runtime::AddressMapping::into_account_id(owner);
-
- // Dispatch call (if enough gas).
- RuntimeHelper::::try_dispatch(
- handle,
- Some(origin).into(),
- pallet_assets::Call::::transfer_ownership {
- id: asset_id.into(),
- owner: Runtime::Lookup::unlookup(owner),
- },
- 0,
- )?;
- }
-
- Ok(true)
- }
-
- #[precompile::public("setTeam(address,address,address)")]
- #[precompile::public("set_team(address,address,address)")]
- fn set_team(
- asset_id: AssetIdOf,
- handle: &mut impl PrecompileHandle,
- issuer: Address,
- admin: Address,
- freezer: Address,
- ) -> EvmResult {
- if !IsLocal::get() {
- return Err(RevertReason::UnknownSelector.into());
- }
-
- let issuer: H160 = issuer.into();
- let admin: H160 = admin.into();
- let freezer: H160 = freezer.into();
-
- // Build call with origin.
- {
- let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
- let issuer = Runtime::AddressMapping::into_account_id(issuer);
- let admin = Runtime::AddressMapping::into_account_id(admin);
- let freezer = Runtime::AddressMapping::into_account_id(freezer);
-
- // Dispatch call (if enough gas).
- RuntimeHelper::::try_dispatch(
- handle,
- Some(origin).into(),
- pallet_assets::Call::::set_team {
- id: asset_id.into(),
- issuer: Runtime::Lookup::unlookup(issuer),
- admin: Runtime::Lookup::unlookup(admin),
- freezer: Runtime::Lookup::unlookup(freezer),
- },
- 0,
- )?;
- }
-
- Ok(true)
- }
-
- #[precompile::public("setMetadata(string,string,uint8)")]
- #[precompile::public("set_metadata(string,string,uint8)")]
- fn set_metadata(
- asset_id: AssetIdOf,
- handle: &mut impl PrecompileHandle,
- name: BoundedString>,
- symbol: BoundedString>,
- decimals: u8,
- ) -> EvmResult {
- if !IsLocal::get() {
- return Err(RevertReason::UnknownSelector.into());
- }
-
- // Build call with origin.
- {
- let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
-
- // Dispatch call (if enough gas).
- RuntimeHelper::::try_dispatch(
- handle,
- Some(origin).into(),
- pallet_assets::Call::::set_metadata {
- id: asset_id.into(),
- name: name.into(),
- symbol: symbol.into(),
- decimals,
- },
- 0,
- )?;
- }
-
- Ok(true)
- }
-
- #[precompile::public("clearMetadata()")]
- #[precompile::public("clear_metadata()")]
- fn clear_metadata(
- asset_id: AssetIdOf,
- handle: &mut impl PrecompileHandle,
- ) -> EvmResult {
- if !IsLocal::get() {
- return Err(RevertReason::UnknownSelector.into());
- }
-
- // Build call with origin.
- {
- let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
-
- // Dispatch call (if enough gas).
- RuntimeHelper::::try_dispatch(
- handle,
- Some(origin).into(),
- pallet_assets::Call::::clear_metadata {
- id: asset_id.into(),
- },
- 0,
- )?;
- }
-
- Ok(true)
- }
-
#[precompile::public("permit(address,address,uint256,uint256,uint8,bytes32,bytes32)")]
fn eip2612_permit(
asset_id: AssetIdOf,
@@ -883,7 +525,7 @@ where
r: H256,
s: H256,
) -> EvmResult {
- >::permit(
+ >::permit(
asset_id, handle, owner, spender, value, deadline, v, r, s,
)
}
@@ -895,7 +537,7 @@ where
handle: &mut impl PrecompileHandle,
owner: Address,
) -> EvmResult {
- >::nonces(asset_id, handle, owner)
+ >::nonces(asset_id, handle, owner)
}
#[precompile::public("DOMAIN_SEPARATOR()")]
@@ -904,7 +546,7 @@ where
asset_id: AssetIdOf,
handle: &mut impl PrecompileHandle,
) -> EvmResult {
- >::domain_separator(asset_id, handle)
+ >::domain_separator(asset_id, handle)
}
fn u256_to_amount(value: U256) -> MayRevert> {
diff --git a/precompiles/assets-erc20/src/mock.rs b/precompiles/assets-erc20/src/mock.rs
index 5ba6df4ccb..57ea8659eb 100644
--- a/precompiles/assets-erc20/src/mock.rs
+++ b/precompiles/assets-erc20/src/mock.rs
@@ -46,21 +46,13 @@ pub type Block = frame_system::mocking::MockBlockU32;
/// be routed to Erc20AssetsPrecompileSet being marked as foreign
pub const FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX: u32 = 0xffffffff;
-/// The local asset precompile address prefix. Addresses that match against this prefix will
-/// be routed to Erc20AssetsPrecompileSet being marked as local
-pub const LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX: u32 = 0xfffffffe;
-
parameter_types! {
pub ForeignAssetPrefix: &'static [u8] = &[0xff, 0xff, 0xff, 0xff];
- pub LocalAssetPrefix: &'static [u8] = &[0xff, 0xff, 0xff, 0xfe];
}
mock_account!(ForeignAssetId(AssetId), |value: ForeignAssetId| {
AddressInPrefixedSet(FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, value.0).into()
});
-mock_account!(LocalAssetId(AssetId), |value: LocalAssetId| {
- AddressInPrefixedSet(LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX, value.0).into()
-});
// Implement the trait, where we convert AccountId to AssetID
impl AccountIdAssetIdConversion for Runtime {
@@ -75,28 +67,12 @@ impl AccountIdAssetIdConversion for Runtime {
account.without_prefix(),
));
}
-
- if account.has_prefix_u32(LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX) {
- return Some((
- LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX.to_be_bytes().to_vec(),
- account.without_prefix(),
- ));
- }
-
None
}
// Not used for now
- fn asset_id_to_account(prefix: &[u8], asset_id: AssetId) -> AccountId {
- if prefix
- == LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX
- .to_be_bytes()
- .as_slice()
- {
- LocalAssetId(asset_id).into()
- } else {
- ForeignAssetId(asset_id).into()
- }
+ fn asset_id_to_account(_prefix: &[u8], asset_id: AssetId) -> AccountId {
+ ForeignAssetId(asset_id).into()
}
}
@@ -168,17 +144,12 @@ pub type Precompiles = PrecompileSetBuilder<
(
PrecompileSetStartingWith<
ForeignAssetPrefix,
- Erc20AssetsPrecompileSet,
- >,
- PrecompileSetStartingWith<
- LocalAssetPrefix,
- Erc20AssetsPrecompileSet,
+ Erc20AssetsPrecompileSet,
>,
),
>;
-pub type LocalPCall = Erc20AssetsPrecompileSetCall;
-pub type ForeignPCall = Erc20AssetsPrecompileSetCall;
+pub type ForeignPCall = Erc20AssetsPrecompileSetCall;
const MAX_POV_SIZE: u64 = 5 * 1024 * 1024;
/// Block Storage Limit in bytes. Set to 40KB.
@@ -224,7 +195,6 @@ impl pallet_evm::Config for Runtime {
}
type ForeignAssetInstance = pallet_assets::Instance1;
-type LocalAssetInstance = pallet_assets::Instance2;
// Required for runtime benchmarks
pallet_assets::runtime_benchmarks_enabled! {
@@ -274,30 +244,6 @@ impl pallet_assets::Config for Runtime {
}
}
-impl pallet_assets::Config for Runtime {
- type RuntimeEvent = RuntimeEvent;
- type Balance = Balance;
- type AssetId = AssetId;
- type Currency = Balances;
- type ForceOrigin = EnsureRoot;
- type AssetDeposit = AssetDeposit;
- type MetadataDepositBase = MetadataDepositBase;
- type MetadataDepositPerByte = MetadataDepositPerByte;
- type ApprovalDeposit = ApprovalDeposit;
- type StringLimit = AssetsStringLimit;
- type Freezer = ();
- type Extra = ();
- type AssetAccountDeposit = AssetAccountDeposit;
- type WeightInfo = pallet_assets::weights::SubstrateWeight;
- type RemoveItemsLimit = ConstU32<656>;
- type AssetIdParameter = AssetId;
- type CreateOrigin = AsEnsureOriginWithArg>;
- type CallbackHandle = ();
- pallet_assets::runtime_benchmarks_enabled! {
- type BenchmarkHelper = BenchmarkHelper;
- }
-}
-
// Configure a mock runtime to test the pallet.
construct_runtime!(
pub enum Runtime
@@ -307,7 +253,6 @@ construct_runtime!(
ForeignAssets: pallet_assets::,
Evm: pallet_evm,
Timestamp: pallet_timestamp,
- LocalAssets: pallet_assets::,
}
);
diff --git a/precompiles/assets-erc20/src/tests.rs b/precompiles/assets-erc20/src/tests.rs
index 5988770dbc..263b00dae0 100644
--- a/precompiles/assets-erc20/src/tests.rs
+++ b/precompiles/assets-erc20/src/tests.rs
@@ -80,17 +80,6 @@ fn selectors() {
assert!(ForeignPCall::eip2612_permit_selectors().contains(&0xd505accf));
assert!(ForeignPCall::eip2612_domain_separator_selectors().contains(&0x3644e515));
- assert!(ForeignPCall::mint_selectors().contains(&0x40c10f19));
- assert!(ForeignPCall::burn_selectors().contains(&0x9dc29fac));
- assert!(ForeignPCall::freeze_selectors().contains(&0x8d1fdf2f));
- assert!(ForeignPCall::thaw_selectors().contains(&0x5ea20216));
- assert!(ForeignPCall::freeze_asset_selectors().contains(&0xd4937f51));
- assert!(ForeignPCall::thaw_asset_selectors().contains(&0x51ec2ad7));
- assert!(ForeignPCall::transfer_ownership_selectors().contains(&0xf2fde38b));
- assert!(ForeignPCall::set_team_selectors().contains(&0xc7d93c59));
- assert!(ForeignPCall::set_metadata_selectors().contains(&0x37d2c2f4));
- assert!(ForeignPCall::clear_metadata_selectors().contains(&0xefb6d432));
-
assert_eq!(
crate::SELECTOR_LOG_TRANSFER,
&Keccak256::digest(b"Transfer(address,address,uint256)")[..]
@@ -130,17 +119,6 @@ fn modifiers() {
tester.test_view_modifier(ForeignPCall::eip2612_nonces_selectors());
tester.test_default_modifier(ForeignPCall::eip2612_permit_selectors());
tester.test_view_modifier(ForeignPCall::eip2612_domain_separator_selectors());
-
- tester.test_default_modifier(ForeignPCall::mint_selectors());
- tester.test_default_modifier(ForeignPCall::burn_selectors());
- tester.test_default_modifier(ForeignPCall::freeze_selectors());
- tester.test_default_modifier(ForeignPCall::thaw_selectors());
- tester.test_default_modifier(ForeignPCall::freeze_asset_selectors());
- tester.test_default_modifier(ForeignPCall::thaw_asset_selectors());
- tester.test_default_modifier(ForeignPCall::transfer_ownership_selectors());
- tester.test_default_modifier(ForeignPCall::set_team_selectors());
- tester.test_default_modifier(ForeignPCall::set_metadata_selectors());
- tester.test_default_modifier(ForeignPCall::clear_metadata_selectors());
});
}
@@ -649,846 +627,180 @@ fn transfer_from_non_incremental_approval() {
CryptoAlith,
Bob,
solidity::encode_event_data(U256::from(500)),
- ))
- .execute_returns(true);
-
- // We then approve 300. Non-incremental, so this is
- // the approved new value
- // Additionally, the gas used in this approval is higher because we
- // need to clear the previous one
- precompiles()
- .prepare_test(
- CryptoAlith,
- ForeignAssetId(0u128),
- ForeignPCall::approve {
- spender: Address(Bob.into()),
- value: 300.into(),
- },
- )
- .expect_cost(72171756)
- .expect_log(log3(
- ForeignAssetId(0u128),
- SELECTOR_LOG_APPROVAL,
- CryptoAlith,
- Bob,
- solidity::encode_event_data(U256::from(300)),
- ))
- .execute_returns(true);
-
- // This should fail, as now the new approved quantity is 300
- precompiles()
- .prepare_test(
- Bob, // Bob is the one sending transferFrom!
- ForeignAssetId(0u128),
- ForeignPCall::transfer_from {
- from: Address(CryptoAlith.into()),
- to: Address(Bob.into()),
- value: 500.into(),
- },
- )
- .execute_reverts(|output| {
- output
- == b"Dispatched call failed with error: Module(ModuleError { index: 2, error: [10, 0, 0, 0], \
- message: Some(\"Unapproved\") })"
- });
- });
-}
-
-#[test]
-fn transfer_from_above_allowance() {
- ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000)])
- .build()
- .execute_with(|| {
- assert_ok!(ForeignAssets::force_create(
- RuntimeOrigin::root(),
- 0u128,
- CryptoAlith.into(),
- true,
- 1
- ));
- assert_ok!(ForeignAssets::mint(
- RuntimeOrigin::signed(CryptoAlith.into()),
- 0u128,
- CryptoAlith.into(),
- 1000
- ));
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- ForeignAssetId(0u128),
- ForeignPCall::approve {
- spender: Address(Bob.into()),
- value: 300.into(),
- },
- )
- .execute_some();
-
- precompiles()
- .prepare_test(
- Bob, // Bob is the one sending transferFrom!
- ForeignAssetId(0u128),
- ForeignPCall::transfer_from {
- from: Address(CryptoAlith.into()),
- to: Address(Bob.into()),
- value: 400.into(),
- },
- )
- .execute_reverts(|output| {
- output
- == b"Dispatched call failed with error: Module(ModuleError { index: 2, error: [10, 0, 0, 0], \
- message: Some(\"Unapproved\") })"
- });
- });
-}
-
-#[test]
-fn transfer_from_self() {
- ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000)])
- .build()
- .execute_with(|| {
- assert_ok!(ForeignAssets::force_create(
- RuntimeOrigin::root(),
- 0u128,
- CryptoAlith.into(),
- true,
- 1
- ));
- assert_ok!(ForeignAssets::mint(
- RuntimeOrigin::signed(CryptoAlith.into()),
- 0u128,
- CryptoAlith.into(),
- 1000
- ));
-
- precompiles()
- .prepare_test(
- CryptoAlith, // CryptoAlith sending transferFrom herself, no need for allowance.
- ForeignAssetId(0u128),
- ForeignPCall::transfer_from {
- from: Address(CryptoAlith.into()),
- to: Address(Bob.into()),
- value: 400.into(),
- },
- )
- .expect_cost(48477756) // 1 weight => 1 gas in mock
- .expect_log(log3(
- ForeignAssetId(0u128),
- SELECTOR_LOG_TRANSFER,
- CryptoAlith,
- Bob,
- solidity::encode_event_data(U256::from(400)),
- ))
- .execute_returns(true);
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- ForeignAssetId(0u128),
- ForeignPCall::balance_of {
- who: Address(CryptoAlith.into()),
- },
- )
- .expect_cost(0) // TODO: Test db read/write costs
- .expect_no_logs()
- .execute_returns(U256::from(600));
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- ForeignAssetId(0u128),
- ForeignPCall::balance_of {
- who: Address(Bob.into()),
- },
- )
- .expect_cost(0) // TODO: Test db read/write costs
- .expect_no_logs()
- .execute_returns(U256::from(400));
- });
-}
-
-#[test]
-fn get_metadata() {
- ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
- .build()
- .execute_with(|| {
- assert_ok!(ForeignAssets::force_create(
- RuntimeOrigin::root(),
- 0u128,
- CryptoAlith.into(),
- true,
- 1
- ));
- assert_ok!(ForeignAssets::force_set_metadata(
- RuntimeOrigin::root(),
- 0u128,
- b"TestToken".to_vec(),
- b"Test".to_vec(),
- 12,
- false
- ));
-
- precompiles()
- .prepare_test(CryptoAlith, ForeignAssetId(0u128), ForeignPCall::name {})
- .expect_cost(0) // TODO: Test db read/write costs
- .expect_no_logs()
- .execute_returns(UnboundedBytes::from("TestToken"));
-
- precompiles()
- .prepare_test(CryptoAlith, ForeignAssetId(0u128), ForeignPCall::symbol {})
- .expect_cost(0) // TODO: Test db read/write costs
- .expect_no_logs()
- .execute_returns(UnboundedBytes::from("Test"));
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- ForeignAssetId(0u128),
- ForeignPCall::decimals {},
- )
- .expect_cost(0) // TODO: Test db read/write costs
- .expect_no_logs()
- .execute_returns(12u8);
- });
-}
-
-#[test]
-fn local_functions_cannot_be_accessed_by_foreign_assets() {
- ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
- .build()
- .execute_with(|| {
- assert_ok!(ForeignAssets::force_create(
- RuntimeOrigin::root(),
- 0u128,
- CryptoAlith.into(),
- true,
- 1
- ));
- assert_ok!(ForeignAssets::force_set_metadata(
- RuntimeOrigin::root(),
- 0u128,
- b"TestToken".to_vec(),
- b"Test".to_vec(),
- 12,
- false
- ));
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- ForeignAssetId(0u128),
- ForeignPCall::mint {
- to: Address(Bob.into()),
- value: 400.into(),
- },
- )
- .execute_reverts(|output| output == b"Unknown selector");
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- ForeignAssetId(0u128),
- ForeignPCall::burn {
- from: Address(Bob.into()),
- value: 400.into(),
- },
- )
- .execute_reverts(|output| output == b"Unknown selector");
- });
-}
-
-#[test]
-fn mint_local_assets() {
- ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
- .build()
- .execute_with(|| {
- assert_ok!(LocalAssets::force_create(
- RuntimeOrigin::root(),
- 0u128,
- CryptoAlith.into(),
- true,
- 1
- ));
- assert_ok!(LocalAssets::force_set_metadata(
- RuntimeOrigin::root(),
- 0u128,
- b"TestToken".to_vec(),
- b"Test".to_vec(),
- 12,
- false
- ));
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::mint {
- to: Address(Bob.into()),
- value: 400.into(),
- },
- )
- .expect_cost(27261756) // 1 weight => 1 gas in mock
- .expect_log(log3(
- LocalAssetId(0u128),
- SELECTOR_LOG_TRANSFER,
- Zero,
- Bob,
- solidity::encode_event_data(U256::from(400)),
- ))
- .execute_returns(true);
-
- precompiles()
- .prepare_test(
- Bob,
- LocalAssetId(0u128),
- LocalPCall::balance_of {
- who: Address(Bob.into()),
- },
- )
- .expect_cost(0) // TODO: Test db read/write costs
- .expect_no_logs()
- .execute_returns(U256::from(400));
- });
-}
-
-#[test]
-fn burn_local_assets() {
- ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
- .build()
- .execute_with(|| {
- assert_ok!(LocalAssets::force_create(
- RuntimeOrigin::root(),
- 0u128,
- CryptoAlith.into(),
- true,
- 1
- ));
- assert_ok!(LocalAssets::force_set_metadata(
- RuntimeOrigin::root(),
- 0u128,
- b"TestToken".to_vec(),
- b"Test".to_vec(),
- 12,
- false
- ));
- assert_ok!(LocalAssets::mint(
- RuntimeOrigin::signed(CryptoAlith.into()),
- 0u128,
- CryptoAlith.into(),
- 1000
- ));
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::burn {
- from: Address(CryptoAlith.into()),
- value: 400.into(),
- },
- )
- .expect_cost(34475756) // 1 weight => 1 gas in mock
- .expect_log(log3(
- LocalAssetId(0u128),
- SELECTOR_LOG_TRANSFER,
- CryptoAlith,
- Zero,
- solidity::encode_event_data(U256::from(400)),
- ))
- .execute_returns(true);
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::balance_of {
- who: Address(CryptoAlith.into()),
- },
- )
- .expect_cost(0) // TODO: Test db read/write costs
- .expect_no_logs()
- .execute_returns(U256::from(600));
- });
-}
-
-#[test]
-fn freeze_local_assets() {
- ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
- .build()
- .execute_with(|| {
- assert_ok!(LocalAssets::force_create(
- RuntimeOrigin::root(),
- 0u128,
- CryptoAlith.into(),
- true,
- 1
- ));
- assert_ok!(LocalAssets::force_set_metadata(
- RuntimeOrigin::root(),
- 0u128,
- b"TestToken".to_vec(),
- b"Test".to_vec(),
- 12,
- false
- ));
- assert_ok!(LocalAssets::mint(
- RuntimeOrigin::signed(CryptoAlith.into()),
- 0u128,
- Bob.into(),
- 1000
- ));
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::freeze {
- account: Address(Bob.into()),
- },
- )
- .expect_cost(18384000) // 1 weight => 1 gas in mock
- .expect_no_logs()
- .execute_returns(true);
-
- precompiles()
- .prepare_test(
- Bob,
- LocalAssetId(0u128),
- LocalPCall::transfer {
- to: Address(CryptoAlith.into()),
- value: 400.into(),
- },
- )
- .execute_reverts(|output| {
- from_utf8(&output)
- .unwrap()
- .contains("Dispatched call failed with error: ")
- && from_utf8(&output).unwrap().contains("Frozen")
- });
- });
-}
-
-#[test]
-fn thaw_local_assets() {
- ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
- .build()
- .execute_with(|| {
- assert_ok!(LocalAssets::force_create(
- RuntimeOrigin::root(),
- 0u128,
- CryptoAlith.into(),
- true,
- 1
- ));
- assert_ok!(LocalAssets::force_set_metadata(
- RuntimeOrigin::root(),
- 0u128,
- b"TestToken".to_vec(),
- b"Test".to_vec(),
- 12,
- false
- ));
- assert_ok!(LocalAssets::mint(
- RuntimeOrigin::signed(CryptoAlith.into()),
- 0u128,
- Bob.into(),
- 1000
- ));
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::freeze {
- account: Address(Bob.into()),
- },
- )
- .expect_cost(18384000) // 1 weight => 1 gas in mock
- .expect_no_logs()
- .execute_returns(true);
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::thaw {
- account: Address(Bob.into()),
- },
- )
- .expect_cost(18282000) // 1 weight => 1 gas in mock
- .expect_no_logs()
- .execute_returns(true);
-
- precompiles()
- .prepare_test(
- Bob,
- LocalAssetId(0u128),
- LocalPCall::transfer {
- to: Address(CryptoAlith.into()),
- value: 400.into(),
- },
- )
- .expect_cost(48477756) // 1 weight => 1 gas in mock
- .expect_log(log3(
- LocalAssetId(0u128),
- SELECTOR_LOG_TRANSFER,
- Bob,
- CryptoAlith,
- solidity::encode_event_data(U256::from(400)),
- ))
- .execute_returns(true);
- });
-}
-
-#[test]
-fn freeze_asset_local_asset() {
- ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
- .build()
- .execute_with(|| {
- assert_ok!(LocalAssets::force_create(
- RuntimeOrigin::root(),
- 0u128,
- CryptoAlith.into(),
- true,
- 1
- ));
- assert_ok!(LocalAssets::force_set_metadata(
- RuntimeOrigin::root(),
- 0u128,
- b"TestToken".to_vec(),
- b"Test".to_vec(),
- 12,
- false
- ));
- assert_ok!(LocalAssets::mint(
- RuntimeOrigin::signed(CryptoAlith.into()),
- 0u128,
- Bob.into(),
- 1000
- ));
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::freeze_asset {},
- )
- .expect_cost(14193000) // 1 weight => 1 gas in mock
- .expect_no_logs()
- .execute_returns(true);
-
- precompiles()
- .prepare_test(
- Bob,
- LocalAssetId(0u128),
- LocalPCall::transfer {
- to: Address(CryptoAlith.into()),
- value: 400.into(),
- },
- )
- .execute_reverts(|output| {
- from_utf8(&output)
- .unwrap()
- .contains("Dispatched call failed with error: ")
- && from_utf8(&output).unwrap().contains("AssetNotLive")
- });
- });
-}
-
-#[test]
-fn thaw_asset_local_assets() {
- ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
- .build()
- .execute_with(|| {
- assert_ok!(LocalAssets::force_create(
- RuntimeOrigin::root(),
- 0u128,
- CryptoAlith.into(),
- true,
- 1
- ));
- assert_ok!(LocalAssets::force_set_metadata(
- RuntimeOrigin::root(),
- 0u128,
- b"TestToken".to_vec(),
- b"Test".to_vec(),
- 12,
- false
- ));
- assert_ok!(LocalAssets::mint(
- RuntimeOrigin::signed(CryptoAlith.into()),
- 0u128,
- Bob.into(),
- 1000
- ));
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::freeze_asset {},
- )
- .expect_cost(14193000) // 1 weight => 1 gas in mock
- .expect_no_logs()
- .execute_returns(true);
-
- precompiles()
- .prepare_test(CryptoAlith, LocalAssetId(0u128), LocalPCall::thaw_asset {})
- .expect_cost(14263000) // 1 weight => 1 gas in mock
- .expect_no_logs()
- .execute_returns(true);
-
- precompiles()
- .prepare_test(
- Bob,
- LocalAssetId(0u128),
- LocalPCall::transfer {
- to: Address(CryptoAlith.into()),
- value: 400.into(),
- },
- )
- .expect_cost(48477756) // 1 weight => 1 gas in mock
- .expect_log(log3(
- LocalAssetId(0u128),
- SELECTOR_LOG_TRANSFER,
- Bob,
- CryptoAlith,
- solidity::encode_event_data(U256::from(400)),
- ))
- .execute_returns(true);
- });
-}
-
-#[test]
-fn transfer_ownership_local_assets() {
- ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
- .build()
- .execute_with(|| {
- assert_ok!(LocalAssets::force_create(
- RuntimeOrigin::root(),
- 0u128,
- CryptoAlith.into(),
- true,
- 1
- ));
- assert_ok!(LocalAssets::force_set_metadata(
- RuntimeOrigin::root(),
- 0u128,
- b"TestToken".to_vec(),
- b"Test".to_vec(),
- 12,
- false
- ));
+ ))
+ .execute_returns(true);
+ // We then approve 300. Non-incremental, so this is
+ // the approved new value
+ // Additionally, the gas used in this approval is higher because we
+ // need to clear the previous one
precompiles()
.prepare_test(
CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::transfer_ownership {
- owner: Address(Bob.into()),
+ ForeignAssetId(0u128),
+ ForeignPCall::approve {
+ spender: Address(Bob.into()),
+ value: 300.into(),
},
)
- .expect_cost(16042000) // 1 weight => 1 gas in mock
- .expect_no_logs()
+ .expect_cost(72171756)
+ .expect_log(log3(
+ ForeignAssetId(0u128),
+ SELECTOR_LOG_APPROVAL,
+ CryptoAlith,
+ Bob,
+ solidity::encode_event_data(U256::from(300)),
+ ))
.execute_returns(true);
- // Now Bob should be able to change ownership, and not CryptoAlith
+ // This should fail, as now the new approved quantity is 300
precompiles()
.prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::transfer_ownership {
- owner: Address(Bob.into()),
+ Bob, // Bob is the one sending transferFrom!
+ ForeignAssetId(0u128),
+ ForeignPCall::transfer_from {
+ from: Address(CryptoAlith.into()),
+ to: Address(Bob.into()),
+ value: 500.into(),
},
)
.execute_reverts(|output| {
- from_utf8(&output)
- .unwrap()
- .contains("Dispatched call failed with error: ")
- && from_utf8(&output).unwrap().contains("NoPermission")
+ output
+ == b"Dispatched call failed with error: Module(ModuleError { index: 2, error: [10, 0, 0, 0], \
+ message: Some(\"Unapproved\") })"
});
-
- precompiles()
- .prepare_test(
- Bob,
- LocalAssetId(0u128),
- LocalPCall::transfer_ownership {
- owner: Address(CryptoAlith.into()),
- },
- )
- .expect_cost(16042000) // 1 weight => 1 gas in mock
- .expect_no_logs()
- .execute_returns(true);
});
}
#[test]
-fn set_team_local_assets() {
+fn transfer_from_above_allowance() {
ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
+ .with_balances(vec![(CryptoAlith.into(), 1000)])
.build()
.execute_with(|| {
- assert_ok!(LocalAssets::force_create(
+ assert_ok!(ForeignAssets::force_create(
RuntimeOrigin::root(),
0u128,
CryptoAlith.into(),
true,
1
));
- assert_ok!(LocalAssets::force_set_metadata(
- RuntimeOrigin::root(),
+ assert_ok!(ForeignAssets::mint(
+ RuntimeOrigin::signed(CryptoAlith.into()),
0u128,
- b"TestToken".to_vec(),
- b"Test".to_vec(),
- 12,
- false
+ CryptoAlith.into(),
+ 1000
));
precompiles()
.prepare_test(
CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::set_team {
- issuer: Address(Bob.into()),
- admin: Address(Bob.into()),
- freezer: Address(Bob.into()),
+ ForeignAssetId(0u128),
+ ForeignPCall::approve {
+ spender: Address(Bob.into()),
+ value: 300.into(),
},
)
- .expect_cost(14641000) // 1 weight => 1 gas in mock
- .expect_no_logs()
- .execute_returns(true);
+ .execute_some();
- // Now Bob should be able to mint, and not CryptoAlith
precompiles()
.prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::mint {
+ Bob, // Bob is the one sending transferFrom!
+ ForeignAssetId(0u128),
+ ForeignPCall::transfer_from {
+ from: Address(CryptoAlith.into()),
to: Address(Bob.into()),
value: 400.into(),
},
)
.execute_reverts(|output| {
- from_utf8(&output)
- .unwrap()
- .contains("Dispatched call failed with error: ")
- && from_utf8(&output).unwrap().contains("NoPermission")
+ output
+ == b"Dispatched call failed with error: Module(ModuleError { index: 2, error: [10, 0, 0, 0], \
+ message: Some(\"Unapproved\") })"
});
-
- precompiles()
- .prepare_test(
- Bob,
- LocalAssetId(0u128),
- LocalPCall::mint {
- to: Address(Bob.into()),
- value: 400.into(),
- },
- )
- .expect_cost(27261756) // 1 weight => 1 gas in mock
- .expect_log(log3(
- LocalAssetId(0u128),
- SELECTOR_LOG_TRANSFER,
- Zero,
- Bob,
- solidity::encode_event_data(U256::from(400)),
- ))
- .execute_returns(true);
-
- precompiles()
- .prepare_test(
- Bob,
- LocalAssetId(0u128),
- LocalPCall::balance_of {
- who: Address(Bob.into()),
- },
- )
- .expect_cost(0) // TODO: Test db read/write costs
- .expect_no_logs()
- .execute_returns(U256::from(400));
});
}
#[test]
-fn set_metadata() {
+fn transfer_from_self() {
ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
+ .with_balances(vec![(CryptoAlith.into(), 1000)])
.build()
.execute_with(|| {
- assert_ok!(LocalAssets::force_create(
+ assert_ok!(ForeignAssets::force_create(
RuntimeOrigin::root(),
0u128,
CryptoAlith.into(),
true,
1
));
- assert_ok!(LocalAssets::force_set_metadata(
- RuntimeOrigin::root(),
+ assert_ok!(ForeignAssets::mint(
+ RuntimeOrigin::signed(CryptoAlith.into()),
0u128,
- b"TestToken".to_vec(),
- b"Test".to_vec(),
- 12,
- false
+ CryptoAlith.into(),
+ 1000
));
precompiles()
.prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::set_metadata {
- name: "TestToken".into(),
- symbol: "Test".into(),
- decimals: 12,
+ CryptoAlith, // CryptoAlith sending transferFrom herself, no need for allowance.
+ ForeignAssetId(0u128),
+ ForeignPCall::transfer_from {
+ from: Address(CryptoAlith.into()),
+ to: Address(Bob.into()),
+ value: 400.into(),
},
)
- .expect_cost(31456892) // 1 weight => 1 gas in mock
- .expect_no_logs()
+ .expect_cost(48477756) // 1 weight => 1 gas in mock
+ .expect_log(log3(
+ ForeignAssetId(0u128),
+ SELECTOR_LOG_TRANSFER,
+ CryptoAlith,
+ Bob,
+ solidity::encode_event_data(U256::from(400)),
+ ))
.execute_returns(true);
precompiles()
- .prepare_test(CryptoAlith, LocalAssetId(0u128), LocalPCall::name {})
- .expect_cost(0) // TODO: Test db read/write costs
- .expect_no_logs()
- .execute_returns(UnboundedBytes::from("TestToken"));
-
- precompiles()
- .prepare_test(CryptoAlith, LocalAssetId(0u128), LocalPCall::symbol {})
+ .prepare_test(
+ CryptoAlith,
+ ForeignAssetId(0u128),
+ ForeignPCall::balance_of {
+ who: Address(CryptoAlith.into()),
+ },
+ )
.expect_cost(0) // TODO: Test db read/write costs
.expect_no_logs()
- .execute_returns(UnboundedBytes::from("Test"));
+ .execute_returns(U256::from(600));
precompiles()
- .prepare_test(CryptoAlith, LocalAssetId(0u128), LocalPCall::decimals {})
+ .prepare_test(
+ CryptoAlith,
+ ForeignAssetId(0u128),
+ ForeignPCall::balance_of {
+ who: Address(Bob.into()),
+ },
+ )
.expect_cost(0) // TODO: Test db read/write costs
.expect_no_logs()
- .execute_returns(12u8);
+ .execute_returns(U256::from(400));
});
}
#[test]
-fn clear_metadata() {
+fn get_metadata() {
ExtBuilder::default()
.with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
.build()
.execute_with(|| {
- assert_ok!(LocalAssets::force_create(
+ assert_ok!(ForeignAssets::force_create(
RuntimeOrigin::root(),
0u128,
CryptoAlith.into(),
true,
1
));
- assert_ok!(LocalAssets::force_set_metadata(
+ assert_ok!(ForeignAssets::force_set_metadata(
RuntimeOrigin::root(),
0u128,
b"TestToken".to_vec(),
@@ -1498,46 +810,26 @@ fn clear_metadata() {
));
precompiles()
- .prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::set_metadata {
- name: "TestToken".into(),
- symbol: "Test".into(),
- decimals: 12,
- },
- )
- .expect_cost(31456892) // 1 weight => 1 gas in mock
- .expect_no_logs()
- .execute_returns(true);
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::clear_metadata {},
- )
- .expect_cost(31930000) // 1 weight => 1 gas in mock
- .expect_no_logs()
- .execute_returns(true);
-
- precompiles()
- .prepare_test(CryptoAlith, LocalAssetId(0u128), LocalPCall::name {})
+ .prepare_test(CryptoAlith, ForeignAssetId(0u128), ForeignPCall::name {})
.expect_cost(0) // TODO: Test db read/write costs
.expect_no_logs()
- .execute_returns(UnboundedBytes::from(""));
+ .execute_returns(UnboundedBytes::from("TestToken"));
precompiles()
- .prepare_test(CryptoAlith, LocalAssetId(0u128), LocalPCall::symbol {})
+ .prepare_test(CryptoAlith, ForeignAssetId(0u128), ForeignPCall::symbol {})
.expect_cost(0) // TODO: Test db read/write costs
.expect_no_logs()
- .execute_returns(UnboundedBytes::from(""));
+ .execute_returns(UnboundedBytes::from("Test"));
precompiles()
- .prepare_test(CryptoAlith, LocalAssetId(0u128), LocalPCall::decimals {})
+ .prepare_test(
+ CryptoAlith,
+ ForeignAssetId(0u128),
+ ForeignPCall::decimals {},
+ )
.expect_cost(0) // TODO: Test db read/write costs
.expect_no_logs()
- .execute_returns(0u8);
+ .execute_returns(12u8);
});
}
@@ -1566,7 +858,7 @@ fn permit_valid() {
let value: U256 = 500u16.into();
let deadline: U256 = 0u8.into(); // todo: proper timestamp
- let permit = Eip2612::::generate_permit(
+ let permit = Eip2612::::generate_permit(
ForeignAssetId(0u128).into(),
0u128,
owner,
@@ -1675,7 +967,7 @@ fn permit_valid_named_asset() {
let value: U256 = 500u16.into();
let deadline: U256 = 0u8.into(); // todo: proper timestamp
- let permit = Eip2612::::generate_permit(
+ let permit = Eip2612::::generate_permit(
ForeignAssetId(0u128).into(),
0u128,
owner,
@@ -1777,7 +1069,7 @@ fn permit_invalid_nonce() {
let value: U256 = 500u16.into();
let deadline: U256 = 0u8.into();
- let permit = Eip2612::::generate_permit(
+ let permit = Eip2612::::generate_permit(
ForeignAssetId(0u128).into(),
0u128,
owner,
@@ -1953,7 +1245,7 @@ fn permit_invalid_deadline() {
let value: U256 = 500u16.into();
let deadline: U256 = 5u8.into(); // deadline < timestamp => expired
- let permit = Eip2612::::generate_permit(
+ let permit = Eip2612::::generate_permit(
ForeignAssetId(0u128).into(),
0u128,
owner,
@@ -2323,93 +1615,13 @@ fn transfer_from_overflow() {
});
}
-#[test]
-fn mint_overflow() {
- ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
- .build()
- .execute_with(|| {
- assert_ok!(LocalAssets::force_create(
- RuntimeOrigin::root(),
- 0u128,
- CryptoAlith.into(),
- true,
- 1
- ));
- assert_ok!(LocalAssets::force_set_metadata(
- RuntimeOrigin::root(),
- 0u128,
- b"TestToken".to_vec(),
- b"Test".to_vec(),
- 12,
- false
- ));
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::mint {
- to: Address(Bob.into()),
- value: U256::from(u128::MAX) + 1,
- },
- )
- .expect_cost(1756u64) // 1 weight => 1 gas in mock
- .expect_no_logs()
- .execute_reverts(|e| e == b"value: Value is too large for balance type");
- });
-}
-
-#[test]
-fn burn_overflow() {
- ExtBuilder::default()
- .with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
- .build()
- .execute_with(|| {
- assert_ok!(LocalAssets::force_create(
- RuntimeOrigin::root(),
- 0u128,
- CryptoAlith.into(),
- true,
- 1
- ));
- assert_ok!(LocalAssets::force_set_metadata(
- RuntimeOrigin::root(),
- 0u128,
- b"TestToken".to_vec(),
- b"Test".to_vec(),
- 12,
- false
- ));
- assert_ok!(LocalAssets::mint(
- RuntimeOrigin::signed(CryptoAlith.into()),
- 0u128,
- CryptoAlith.into(),
- 1000
- ));
-
- precompiles()
- .prepare_test(
- CryptoAlith,
- LocalAssetId(0u128),
- LocalPCall::burn {
- from: Address(CryptoAlith.into()),
- value: U256::from(u128::MAX) + 1,
- },
- )
- .expect_cost(1756u64) // 1 weight => 1 gas in mock
- .expect_no_logs()
- .execute_reverts(|e| e == b"value: Value is too large for balance type");
- });
-}
-
#[test]
fn get_owner() {
ExtBuilder::default()
.with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
.build()
.execute_with(|| {
- assert_ok!(LocalAssets::force_create(
+ assert_ok!(ForeignAssets::force_create(
RuntimeOrigin::root(),
0u128,
CryptoAlith.into(),
@@ -2417,7 +1629,7 @@ fn get_owner() {
1
));
- assert_ok!(LocalAssets::transfer_ownership(
+ assert_ok!(ForeignAssets::transfer_ownership(
RuntimeOrigin::signed(CryptoAlith.into()),
0u128,
// owner
@@ -2425,7 +1637,7 @@ fn get_owner() {
));
precompiles()
- .prepare_test(CryptoAlith, LocalAssetId(0u128), ForeignPCall::owner {})
+ .prepare_test(CryptoAlith, ForeignAssetId(0u128), ForeignPCall::owner {})
.expect_cost(0)
.expect_no_logs()
.execute_returns(Address(Bob.into()));
@@ -2438,7 +1650,7 @@ fn get_issuer() {
.with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
.build()
.execute_with(|| {
- assert_ok!(LocalAssets::force_create(
+ assert_ok!(ForeignAssets::force_create(
RuntimeOrigin::root(),
0u128,
CryptoAlith.into(),
@@ -2446,7 +1658,7 @@ fn get_issuer() {
1
));
- assert_ok!(LocalAssets::set_team(
+ assert_ok!(ForeignAssets::set_team(
RuntimeOrigin::signed(CryptoAlith.into()),
0u128,
// Issuer
@@ -2458,7 +1670,7 @@ fn get_issuer() {
));
precompiles()
- .prepare_test(CryptoAlith, LocalAssetId(0u128), ForeignPCall::issuer {})
+ .prepare_test(CryptoAlith, ForeignAssetId(0u128), ForeignPCall::issuer {})
.expect_cost(0)
.expect_no_logs()
.execute_returns(Address(Bob.into()));
@@ -2471,7 +1683,7 @@ fn get_admin() {
.with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
.build()
.execute_with(|| {
- assert_ok!(LocalAssets::force_create(
+ assert_ok!(ForeignAssets::force_create(
RuntimeOrigin::root(),
0u128,
CryptoAlith.into(),
@@ -2479,7 +1691,7 @@ fn get_admin() {
1
));
- assert_ok!(LocalAssets::set_team(
+ assert_ok!(ForeignAssets::set_team(
RuntimeOrigin::signed(CryptoAlith.into()),
0u128,
// Issuer
@@ -2491,7 +1703,7 @@ fn get_admin() {
));
precompiles()
- .prepare_test(CryptoAlith, LocalAssetId(0u128), ForeignPCall::admin {})
+ .prepare_test(CryptoAlith, ForeignAssetId(0u128), ForeignPCall::admin {})
.expect_cost(0)
.expect_no_logs()
.execute_returns(Address(Bob.into()));
@@ -2504,7 +1716,7 @@ fn get_freezer() {
.with_balances(vec![(CryptoAlith.into(), 1000), (Bob.into(), 2500)])
.build()
.execute_with(|| {
- assert_ok!(LocalAssets::force_create(
+ assert_ok!(ForeignAssets::force_create(
RuntimeOrigin::root(),
0u128,
CryptoAlith.into(),
@@ -2512,7 +1724,7 @@ fn get_freezer() {
1
));
- assert_ok!(LocalAssets::set_team(
+ assert_ok!(ForeignAssets::set_team(
RuntimeOrigin::signed(CryptoAlith.into()),
0u128,
// Issuer
@@ -2524,7 +1736,7 @@ fn get_freezer() {
));
precompiles()
- .prepare_test(CryptoAlith, LocalAssetId(0u128), ForeignPCall::freezer {})
+ .prepare_test(CryptoAlith, ForeignAssetId(0u128), ForeignPCall::freezer {})
.expect_cost(0)
.expect_no_logs()
.execute_returns(Address(Bob.into()));
@@ -2534,27 +1746,7 @@ fn get_freezer() {
#[test]
fn test_solidity_interface_has_all_function_selectors_documented_and_implemented() {
check_precompile_implements_solidity_interfaces(
- &["ERC20.sol", "LocalAsset.sol", "Permit.sol"],
- LocalPCall::supports_selector,
+ &["ERC20.sol", "Permit.sol"],
+ ForeignPCall::supports_selector,
)
}
-
-#[test]
-fn test_deprecated_solidity_selectors_are_supported() {
- for deprecated_function in [
- "freeze_asset()",
- "thaw_asset()",
- "transfer_ownership(address)",
- "set_team(address,address,address)",
- "set_metadata(string,string,uint8)",
- "clear_metadata()",
- ] {
- let selector = compute_selector(deprecated_function);
- if !LocalPCall::supports_selector(selector) {
- panic!(
- "failed decoding selector 0x{:x} => '{}' as Action",
- selector, deprecated_function,
- )
- }
- }
-}
diff --git a/precompiles/utils/src/precompile_set.rs b/precompiles/utils/src/precompile_set.rs
index 0a02e1cca6..22682b4594 100644
--- a/precompiles/utils/src/precompile_set.rs
+++ b/precompiles/utils/src/precompile_set.rs
@@ -128,6 +128,7 @@ impl Into for DiscriminantResult {
#[cfg_attr(feature = "testing", derive(serde::Serialize, serde::Deserialize))]
pub enum PrecompileKind {
Single(H160),
+ Multiple(Vec),
Prefixed(Vec),
}
@@ -837,6 +838,68 @@ impl IsActivePrecompile for RevertPrecompile {
}
}
+/// Precompiles that were removed from a precompile set.
+/// Still considered precompiles but are inactive and always revert.
+pub struct RemovedPrecompilesAt(PhantomData);
+impl PrecompileSetFragment for RemovedPrecompilesAt
+where
+ A: Get>,
+{
+ #[inline(always)]
+ fn new() -> Self {
+ Self(PhantomData)
+ }
+
+ #[inline(always)]
+ fn execute(
+ &self,
+ handle: &mut impl PrecompileHandle,
+ ) -> Option {
+ if A::get().contains(&handle.code_address()) {
+ Some(Err(revert("Removed precompile")))
+ } else {
+ None
+ }
+ }
+
+ #[inline(always)]
+ fn is_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult {
+ IsPrecompileResult::Answer {
+ is_precompile: A::get().contains(&address),
+ extra_cost: 0,
+ }
+ }
+
+ #[inline(always)]
+ fn used_addresses(&self) -> Vec {
+ A::get()
+ }
+
+ fn summarize_checks(&self) -> Vec {
+ vec![PrecompileCheckSummary {
+ name: None,
+ precompile_kind: PrecompileKind::Multiple(A::get()),
+ recursion_limit: Some(0),
+ accept_delegate_call: true,
+ callable_by_smart_contract: "Reverts in all cases".into(),
+ callable_by_precompile: "Reverts in all cases".into(),
+ }]
+ }
+}
+
+impl IsActivePrecompile for RemovedPrecompilesAt
+where
+ Self: PrecompileSetFragment,
+{
+ #[inline(always)]
+ fn is_active_precompile(&self, _address: H160, _gas: u64) -> IsPrecompileResult {
+ IsPrecompileResult::Answer {
+ is_precompile: false,
+ extra_cost: 0,
+ }
+ }
+}
+
/// A precompile that was removed from a precompile set.
/// Still considered a precompile but is inactive and always revert.
pub struct RemovedPrecompileAt(PhantomData);
diff --git a/precompiles/xcm-utils/src/mock.rs b/precompiles/xcm-utils/src/mock.rs
index 14713d603c..26b9ca4308 100644
--- a/precompiles/xcm-utils/src/mock.rs
+++ b/precompiles/xcm-utils/src/mock.rs
@@ -31,7 +31,6 @@ use sp_core::{H256, U256};
use sp_io;
use sp_runtime::traits::{BlakeTwo256, IdentityLookup, TryConvert};
use sp_runtime::BuildStorage;
-use sp_std::borrow::Borrow;
use xcm::latest::Error as XcmError;
use xcm_builder::AllowUnpaidExecutionFrom;
use xcm_builder::FixedWeightBounds;
@@ -109,7 +108,7 @@ impl ConvertLocation for MockParentMultilocationToAccountConverter {
pub struct MockParachainMultilocationToAccountConverter;
impl ConvertLocation for MockParachainMultilocationToAccountConverter {
fn convert_location(location: &MultiLocation) -> Option {
- match location.borrow() {
+ match location {
MultiLocation {
parents: 1,
interior: Junctions::X1(Parachain(id)),
diff --git a/runtime/common/src/migrations.rs b/runtime/common/src/migrations.rs
index c1e6a55f67..959cba8786 100644
--- a/runtime/common/src/migrations.rs
+++ b/runtime/common/src/migrations.rs
@@ -418,6 +418,7 @@ where
//Box::new(xcm_transactor_to_xcm_v3),
// completed in runtime 2600
//Box::new(remove_min_bond_for_old_orbiter_collators),
+ // Runtime 2700
Box::new(missing_balances_migrations),
Box::new(fix_pallet_versions),
Box::new(pallet_referenda_migrate_v0_to_v1),
diff --git a/runtime/moonbase/Cargo.toml b/runtime/moonbase/Cargo.toml
index 02a6eee57d..0039ec16df 100644
--- a/runtime/moonbase/Cargo.toml
+++ b/runtime/moonbase/Cargo.toml
@@ -13,7 +13,7 @@ hex-literal = { workspace = true, optional = true }
log = { workspace = true }
num_enum = { workspace = true }
rlp = { workspace = true, optional = true }
-serde = { workspace = true, features = [ "derive" ] }
+serde = { workspace = true, features = ["derive"] }
sha3 = { workspace = true, optional = true }
smallvec = { workspace = true }
strum = { workspace = true }
@@ -36,8 +36,9 @@ pallet-crowdloan-rewards = { workspace = true }
pallet-erc20-xcm-bridge = { workspace = true }
pallet-evm-chain-id = { workspace = true }
pallet-ethereum-xcm = { workspace = true }
-pallet-maintenance-mode = { workspace = true, features = [ "xcm-support" ] }
+pallet-maintenance-mode = { workspace = true, features = ["xcm-support"] }
pallet-migrations = { workspace = true }
+pallet-moonbeam-lazy-migrations = { workspace = true }
pallet-moonbeam-orbiters = { workspace = true }
pallet-parachain-staking = { workspace = true }
pallet-proxy-genesis-companion = { workspace = true }
@@ -79,7 +80,7 @@ frame-support = { workspace = true }
frame-system = { workspace = true }
frame-system-rpc-runtime-api = { workspace = true }
pallet-assets = { workspace = true }
-pallet-balances = { workspace = true, features = [ "insecure_zero_ed" ] }
+pallet-balances = { workspace = true, features = ["insecure_zero_ed"] }
pallet-collective = { workspace = true }
pallet-conviction-voting = { workspace = true }
pallet-democracy = { workspace = true }
@@ -103,14 +104,14 @@ parity-scale-codec = { workspace = true, features = [
"max-encoded-len",
"chain-error",
] }
-scale-info = { workspace = true, features = [ "derive" ] }
+scale-info = { workspace = true, features = ["derive"] }
sp-api = { workspace = true }
sp-block-builder = { workspace = true }
sp-consensus-slots = { workspace = true }
sp-core = { workspace = true }
sp-debug-derive = { workspace = true }
sp-inherents = { workspace = true }
-sp-io = { workspace = true, features = [ "improved_panic_error_reporting" ] }
+sp-io = { workspace = true, features = ["improved_panic_error_reporting"] }
sp-offchain = { workspace = true }
sp-runtime = { workspace = true }
sp-session = { workspace = true }
@@ -122,9 +123,9 @@ sp-weights = { workspace = true }
# Frontier
fp-evm = { workspace = true }
fp-rpc = { workspace = true }
-fp-self-contained = { workspace = true, features = [ "serde" ] }
-pallet-ethereum = { workspace = true, features = [ "forbid-evm-reentrancy" ] }
-pallet-evm = { workspace = true, features = [ "forbid-evm-reentrancy" ] }
+fp-self-contained = { workspace = true, features = ["serde"] }
+pallet-ethereum = { workspace = true, features = ["forbid-evm-reentrancy"] }
+pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] }
pallet-evm-precompile-blake2 = { workspace = true }
pallet-evm-precompile-bn128 = { workspace = true }
pallet-evm-precompile-dispatch = { workspace = true }
@@ -170,8 +171,8 @@ frame-try-runtime = { workspace = true, optional = true }
[dev-dependencies]
ethereum = { workspace = true }
-hex = { workspace = true, features = [ "std" ] }
-sha3 = { workspace = true, features = [ "std" ] }
+hex = { workspace = true, features = ["std"] }
+sha3 = { workspace = true, features = ["std"] }
cumulus-primitives-parachain-inherent = { workspace = true }
cumulus-test-relay-sproof-builder = { workspace = true }
@@ -182,13 +183,13 @@ polkadot-runtime-parachains = { workspace = true }
sp-timestamp = { workspace = true }
xcm-simulator = { workspace = true }
-precompile-utils = { workspace = true, features = [ "std", "testing" ] }
+precompile-utils = { workspace = true, features = ["std", "testing"] }
[build-dependencies]
substrate-wasm-builder = { workspace = true }
[features]
-default = [ "std" ]
+default = ["std"]
std = [
"account/std",
"async-backing-primitives/std",
@@ -251,6 +252,7 @@ std = [
"pallet-identity/std",
"pallet-maintenance-mode/std",
"pallet-migrations/std",
+ "pallet-moonbeam-lazy-migrations/std",
"pallet-moonbeam-orbiters/std",
"pallet-multisig/std",
"pallet-parachain-staking/std",
@@ -296,18 +298,18 @@ std = [
]
# Must be enabled for tracing runtimes only
-evm-tracing = [ "evm-tracing-events", "moonbeam-evm-tracer", "rlp", "sha3" ]
+evm-tracing = ["evm-tracing-events", "moonbeam-evm-tracer", "rlp", "sha3"]
# Allow to print logs details (no wasm:stripped)
-force-debug = [ "sp-debug-derive/force-debug" ]
+force-debug = ["sp-debug-derive/force-debug"]
# Will be enabled by the `wasm-builder` when building the runtime for WASM.
-runtime-wasm = [ ]
+runtime-wasm = []
# A feature that should be enabled when the runtime should be build for on-chain
# deployment. This will disable stuff that shouldn't be part of the on-chain wasm
# to make it smaller like logging for example.
-on-chain-release-build = [ "sp-api/disable-logging" ]
+on-chain-release-build = ["sp-api/disable-logging"]
runtime-benchmarks = [
"cumulus-pallet-parachain-system/runtime-benchmarks",
@@ -334,6 +336,7 @@ runtime-benchmarks = [
"pallet-evm/runtime-benchmarks",
"pallet-identity/runtime-benchmarks",
"pallet-migrations/runtime-benchmarks",
+ "pallet-moonbeam-lazy-migrations/runtime-benchmarks",
"pallet-moonbeam-orbiters/runtime-benchmarks",
"pallet-multisig/runtime-benchmarks",
"pallet-parachain-staking/runtime-benchmarks",
@@ -372,6 +375,7 @@ try-runtime = [
"pallet-maintenance-mode/try-runtime",
"pallet-maintenance-mode/try-runtime",
"pallet-migrations/try-runtime",
+ "pallet-moonbeam-lazy-migrations/try-runtime",
"pallet-parachain-staking/try-runtime",
"pallet-preimage/try-runtime",
"pallet-referenda/try-runtime",
@@ -382,4 +386,4 @@ try-runtime = [
"pallet-xcm-transactor/try-runtime",
]
-moonbase-runtime-benchmarks = [ ]
+moonbase-runtime-benchmarks = []
diff --git a/runtime/moonbase/src/asset_config.rs b/runtime/moonbase/src/asset_config.rs
index 5e060c5b18..e11870bb63 100644
--- a/runtime/moonbase/src/asset_config.rs
+++ b/runtime/moonbase/src/asset_config.rs
@@ -19,8 +19,8 @@
use super::{
currency, governance, xcm_config, AccountId, AssetId, AssetManager, Assets, Balance, Balances,
- CouncilInstance, LocalAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
- FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX,
+ CouncilInstance, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
+ FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX,
};
use moonbeam_runtime_common::weights as moonbeam_weights;
@@ -54,7 +54,6 @@ const REMOVE_ITEMS_LIMIT: u32 = 656;
// Not to disrupt the previous asset instance, we assign () to Foreign
pub type ForeignAssetInstance = ();
-pub type LocalAssetInstance = pallet_assets::Instance1;
// For foreign assets, these parameters dont matter much
// as this will only be called by root with the forced arguments
@@ -116,31 +115,6 @@ impl pallet_assets::Config for Runtime {
}
}
-// Local assets
-impl pallet_assets::Config for Runtime {
- type RuntimeEvent = RuntimeEvent;
- type Balance = Balance;
- type AssetId = AssetId;
- type Currency = Balances;
- type ForceOrigin = EnsureNever;
- type AssetDeposit = AssetDeposit;
- type MetadataDepositBase = MetadataDepositBase;
- type MetadataDepositPerByte = MetadataDepositPerByte;
- type ApprovalDeposit = ApprovalDeposit;
- type StringLimit = AssetsStringLimit;
- type Freezer = ();
- type Extra = ();
- type AssetAccountDeposit = ConstU128<{ currency::deposit(1, 18) }>;
- type WeightInfo = moonbeam_weights::pallet_assets::WeightInfo;
- type RemoveItemsLimit = ConstU32<{ REMOVE_ITEMS_LIMIT }>;
- type AssetIdParameter = Compact;
- type CreateOrigin = AsEnsureOriginWithArg>;
- type CallbackHandle = ();
- pallet_assets::runtime_benchmarks_enabled! {
- type BenchmarkHelper = BenchmarkHelper;
- }
-}
-
// We instruct how to register the Assets
// In this case, we tell it to Create an Asset in pallet-assets
pub struct AssetRegistrar;
@@ -162,15 +136,6 @@ impl pallet_asset_manager::AssetRegistrar for AssetRegistrar {
min_balance,
)?;
- // TODO uncomment when we feel comfortable
- /*
- // The asset has been created. Let's put the revert code in the precompile address
- let precompile_address = Runtime::asset_id_to_account(ASSET_PRECOMPILE_ADDRESS_PREFIX, asset);
- pallet_evm::AccountCodes::::insert(
- precompile_address,
- vec![0x60, 0x00, 0x60, 0x00, 0xfd],
- );*/
-
// Lastly, the metadata
Assets::force_set_metadata(
RuntimeOrigin::root(),
@@ -182,62 +147,10 @@ impl pallet_asset_manager::AssetRegistrar for AssetRegistrar {
)
}
- #[transactional]
- fn create_local_asset(
- asset: AssetId,
- _creator: AccountId,
- min_balance: Balance,
- is_sufficient: bool,
- owner: AccountId,
- ) -> DispatchResult {
- // We create with root, because we need to decide whether we want to create the asset
- // as sufficient. Take into account this does not hold any reserved amount
- // in pallet-assets
- LocalAssets::force_create(
- RuntimeOrigin::root(),
- asset.into(),
- owner,
- is_sufficient,
- min_balance,
- )?;
-
- // No metadata needs to be set, as this can be set through regular calls
-
- // TODO: should we put the revert code?
- // The asset has been created. Let's put the revert code in the precompile address
- let precompile_address: H160 =
- Runtime::asset_id_to_account(LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX, asset).into();
- pallet_evm::AccountCodes::::insert(
- precompile_address,
- vec![0x60, 0x00, 0x60, 0x00, 0xfd],
- );
- Ok(())
- }
-
#[transactional]
fn destroy_foreign_asset(asset: AssetId) -> DispatchResult {
- // First destroy the asset
- Assets::start_destroy(RuntimeOrigin::root(), asset.into())?;
-
- // We remove the EVM revert code
- // This does not panick even if there is no code in the address
- let precompile_address: H160 =
- Runtime::asset_id_to_account(FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, asset).into();
- pallet_evm::AccountCodes::::remove(precompile_address);
- Ok(())
- }
-
- #[transactional]
- fn destroy_local_asset(asset: AssetId) -> DispatchResult {
- // First destroy the asset
- LocalAssets::start_destroy(RuntimeOrigin::root(), asset.into())?;
-
- // We remove the EVM revert code
- // This does not panick even if there is no code in the address
- let precompile_address: H160 =
- Runtime::asset_id_to_account(LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX, asset).into();
- pallet_evm::AccountCodes::::remove(precompile_address);
- Ok(())
+ // Mark the asset as destroying
+ Assets::start_destroy(RuntimeOrigin::root(), asset.into())
}
fn destroy_asset_dispatch_info_weight(asset: AssetId) -> Weight {
@@ -245,20 +158,15 @@ impl pallet_asset_manager::AssetRegistrar for AssetRegistrar {
// witness
// We need to take the dispatch info from the destroy call, which is already annotated in
// the assets pallet
- // Additionally, we need to add a DB write for removing the precompile revert code in the
- // EVM
// This is the dispatch info of destroy
- let call_weight = RuntimeCall::Assets(
+ RuntimeCall::Assets(
pallet_assets::Call::::start_destroy {
id: asset.into(),
},
)
.get_dispatch_info()
- .weight;
-
- // This is the db write
- call_weight.saturating_add(::DbWeight::get().writes(1))
+ .weight
}
}
@@ -322,9 +230,7 @@ impl AccountIdAssetIdConversion for Runtime {
let h160_account: H160 = account.into();
let mut data = [0u8; 16];
let (prefix_part, id_part) = h160_account.as_fixed_bytes().split_at(4);
- if prefix_part == FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX
- || prefix_part == LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX
- {
+ if prefix_part == FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX {
data.copy_from_slice(id_part);
let asset_id: AssetId = u128::from_be_bytes(data).into();
Some((prefix_part.to_vec(), asset_id))
diff --git a/runtime/moonbase/src/lib.rs b/runtime/moonbase/src/lib.rs
index bfeadc0359..638a90ff98 100644
--- a/runtime/moonbase/src/lib.rs
+++ b/runtime/moonbase/src/lib.rs
@@ -47,7 +47,6 @@ pub use pallet_author_slot_filter::EligibilityValue;
pub use pallet_parachain_staking::{weights::WeightInfo, InflationInfo, Range};
pub use precompiles::{
MoonbasePrecompiles, PrecompileName, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX,
- LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX,
};
use account::AccountId20;
@@ -1152,13 +1151,14 @@ impl pallet_migrations::Config for Runtime {
type XcmExecutionManager = XcmExecutionManager;
}
+impl pallet_moonbeam_lazy_migrations::Config for Runtime {}
+
/// Maintenance mode Call filter
pub struct MaintenanceFilter;
impl Contains for MaintenanceFilter {
fn contains(c: &RuntimeCall) -> bool {
match c {
RuntimeCall::Assets(_) => false,
- RuntimeCall::LocalAssets(_) => false,
RuntimeCall::Balances(_) => false,
RuntimeCall::CrowdloanRewards(_) => false,
RuntimeCall::Ethereum(_) => false,
@@ -1197,16 +1197,6 @@ impl Contains for NormalFilter {
pallet_assets::Call::finish_destroy { .. } => true,
_ => false,
},
- // We want to disable create, as we dont want users to be choosing the
- // assetId of their choice
- // We also disable destroy, as we want to route destroy through the
- // asset-manager, which guarantees the removal both at the EVM and
- // substrate side of things
- RuntimeCall::LocalAssets(method) => match method {
- pallet_assets::Call::create { .. } => false,
- pallet_assets::Call::start_destroy { .. } => false,
- _ => true,
- },
// We filter anonymous proxy as they make "reserve" inconsistent
// See: https://github.com/paritytech/substrate/blob/37cca710eed3dadd4ed5364c7686608f5175cce1/frame/proxy/src/lib.rs#L270 // editorconfig-checker-disable-line
RuntimeCall::Proxy(method) => match method {
@@ -1482,7 +1472,7 @@ construct_runtime! {
Migrations: pallet_migrations::{Pallet, Storage, Config, Event} = 32,
XcmTransactor: pallet_xcm_transactor::{Pallet, Call, Config, Storage, Event} = 33,
ProxyGenesisCompanion: pallet_proxy_genesis_companion::{Pallet, Config} = 34,
- LocalAssets: pallet_assets::::{Pallet, Call, Storage, Event} = 36,
+ // Previously 36: pallet_assets::
MoonbeamOrbiters: pallet_moonbeam_orbiters::{Pallet, Call, Storage, Event} = 37,
EthereumXcm: pallet_ethereum_xcm::{Pallet, Call, Storage, Origin} = 38,
Randomness: pallet_randomness::{Pallet, Call, Storage, Event, Inherent} = 39,
@@ -1499,6 +1489,7 @@ construct_runtime! {
Erc20XcmBridge: pallet_erc20_xcm_bridge::{Pallet} = 48,
Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 49,
AsyncBacking: pallet_async_backing::{Pallet, Storage} = 50,
+ MoonbeamLazyMigrations: pallet_moonbeam_lazy_migrations::{Pallet, Call, Storage} = 51
}
}
@@ -1736,6 +1727,10 @@ mod tests {
assert!(std::mem::size_of::>() <= CALL_ALIGN as usize);
assert!(std::mem::size_of::>() <= CALL_ALIGN as usize);
assert!(std::mem::size_of::>() <= CALL_ALIGN as usize);
+ assert!(
+ std::mem::size_of::>()
+ <= CALL_ALIGN as usize
+ );
assert!(std::mem::size_of::>() <= CALL_ALIGN as usize);
assert!(
std::mem::size_of::>()
diff --git a/runtime/moonbase/src/precompiles.rs b/runtime/moonbase/src/precompiles.rs
index 48ffdb8fdf..9e499c6553 100644
--- a/runtime/moonbase/src/precompiles.rs
+++ b/runtime/moonbase/src/precompiles.rs
@@ -15,10 +15,10 @@
// along with Moonbeam. If not, see .
use crate::{
- asset_config::{ForeignAssetInstance, LocalAssetInstance},
- xcm_config::XcmExecutorConfig,
- CouncilInstance, OpenTechCommitteeInstance, TechCommitteeInstance, TreasuryCouncilInstance,
+ asset_config::ForeignAssetInstance, xcm_config::XcmExecutorConfig, CouncilInstance,
+ OpenTechCommitteeInstance, TechCommitteeInstance, TreasuryCouncilInstance,
};
+use crate::{AssetId, H160};
use frame_support::parameter_types;
use pallet_evm_precompile_author_mapping::AuthorMappingPrecompile;
use pallet_evm_precompile_balances_erc20::{Erc20BalancesPrecompile, Erc20Metadata};
@@ -47,8 +47,9 @@ use pallet_evm_precompile_xcm_transactor::{
};
use pallet_evm_precompile_xcm_utils::{AllExceptXcmExecute, XcmUtilsPrecompile};
use pallet_evm_precompile_xtokens::XtokensPrecompile;
-use pallet_evm_precompileset_assets_erc20::{Erc20AssetsPrecompileSet, IsForeign, IsLocal};
+use pallet_evm_precompileset_assets_erc20::{AccountIdAssetIdConversion, Erc20AssetsPrecompileSet};
use precompile_utils::precompile_set::*;
+use sp_std::prelude::*;
/// ERC20 metadata for the native token.
pub struct NativeErc20Metadata;
@@ -244,6 +245,53 @@ type MoonbasePrecompilesAt = (
>,
);
+pub struct DisabledLocalAssets(sp_std::marker::PhantomData);
+
+impl sp_core::Get> for DisabledLocalAssets
+where
+ Runtime: frame_system::Config,
+ Runtime::AccountId: Into,
+ Runtime: AccountIdAssetIdConversion,
+{
+ fn get() -> Vec {
+ vec![
+ // https://moonbase.subscan.io/extrinsic/5245322-6?event=5245322-22
+ 182085191673801920759598290391359780050u128,
+ // https://moonbase.subscan.io/extrinsic/3244752-4?event=3244752-9
+ 282223684955665977914983262584256755878u128,
+ // https://moonbase.subscan.io/extrinsic/3158280-4?event=3158280-9
+ 235962050501460763853961856666389569138u128,
+ // https://moonbase.subscan.io/block/3045900?tab=event&&event=3045900-4
+ 45350527686064227409532032051821627910u128,
+ // https://moonbase.subscan.io/extrinsic/3024306-4?event=3024306-9
+ 199439015574556113723291251263369885338u128,
+ // https://moonbase.subscan.io/extrinsic/2921640-4?event=2921640-9
+ 236426850287284823323011839750645103615u128,
+ // https://moonbase.subscan.io/extrinsic/2748867-4?event=2748867-9
+ 14626673838203901761839010613793775004u128,
+ // https://moonbase.subscan.io/extrinsic/2709788-4?event=2709788-9
+ 95328064580428769161981851380106820590u128,
+ // https://moonbase.subscan.io/extrinsic/2670844-4?event=2670844-9
+ 339028723712074529056817184013808486301u128,
+ // https://moonbase.subscan.io/extrinsic/2555083-4?event=2555083-9
+ 100481493116602214283160747599845770751u128,
+ // https://moonbase.subscan.io/extrinsic/2473880-3?event=2473880-8
+ 319515966007349957795820176952936446433u128,
+ // https://moonbase.subscan.io/extrinsic/2346438-3?event=2346438-6
+ 337110116006454532607322340792629567158u128,
+ // https://moonbase.subscan.io/extrinsic/2239102-3?event=2239102-6
+ 255225902946708983196362678630947296516u128,
+ // https://moonbase.subscan.io/extrinsic/2142964-4?event=2142964-12
+ 3356866138193769031598374869367363824u128,
+ // https://moonbase.subscan.io/extrinsic/1967538-6?event=1967538-28
+ 144992676743556815849525085098140609495u128,
+ ]
+ .iter()
+ .map(|id| Runtime::asset_id_to_account(LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX, *id).into())
+ .collect()
+ }
+}
+
/// The PrecompileSet installed in the Moonbase runtime.
/// We include the nine Istanbul precompiles
/// (https://github.com/ethereum/go-ethereum/blob/3c46f557/core/vm/contracts.go#L69)
@@ -259,13 +307,9 @@ pub type MoonbasePrecompiles = PrecompileSetBuilder<
// Prefixed precompile sets (XC20)
PrecompileSetStartingWith<
ForeignAssetPrefix,
- Erc20AssetsPrecompileSet,
- (CallableByContract, CallableByPrecompile),
- >,
- PrecompileSetStartingWith<
- LocalAssetPrefix,
- Erc20AssetsPrecompileSet,
+ Erc20AssetsPrecompileSet,
(CallableByContract, CallableByPrecompile),
>,
+ RemovedPrecompilesAt>,
),
>;
diff --git a/runtime/moonbase/src/xcm_config.rs b/runtime/moonbase/src/xcm_config.rs
index dea67d2baa..01c8cf7dbd 100644
--- a/runtime/moonbase/src/xcm_config.rs
+++ b/runtime/moonbase/src/xcm_config.rs
@@ -19,8 +19,8 @@
use super::{
governance, AccountId, AssetId, AssetManager, Assets, Balance, Balances, DealWithFees,
- Erc20XcmBridge, LocalAssets, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall,
- RuntimeEvent, RuntimeOrigin, Treasury, XcmpQueue, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX,
+ Erc20XcmBridge, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall,
+ RuntimeEvent, RuntimeOrigin, Treasury, XcmpQueue,
};
use moonbeam_runtime_common::weights as moonbeam_weights;
use pallet_evm_precompileset_assets_erc20::AccountIdAssetIdConversion;
@@ -39,12 +39,11 @@ use sp_core::{ConstU32, H160, H256};
use sp_weights::Weight;
use xcm_builder::{
AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
- AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex, ConvertedConcreteId,
- CurrencyAdapter as XcmCurrencyAdapter, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin,
- FungiblesAdapter, HashedDescription, NoChecking, ParentIsPreset, RelayChainAsNative,
- SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountKey20AsNative,
- SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, WeightInfoBounds,
- WithComputedOrigin,
+ AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, CurrencyAdapter as XcmCurrencyAdapter,
+ DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FungiblesAdapter, HashedDescription,
+ NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
+ SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation,
+ TakeWeightCredit, UsingComponents, WeightInfoBounds, WithComputedOrigin,
};
use xcm::latest::prelude::*;
@@ -88,16 +87,6 @@ parameter_types! {
PalletInstance(::index() as u8)
)
};
-
- // This is the relative view of our local assets.
- // Indentified by thix prefix + generalIndex(assetId)
- // We use the RELATIVE multilocation
- pub LocalAssetsPalletLocation: MultiLocation = MultiLocation {
- parents:0,
- interior: Junctions::X1(
- PalletInstance(::index() as u8)
- )
- };
}
/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used
@@ -163,32 +152,6 @@ pub type LocalAssetTransactor = XcmCurrencyAdapter<
(),
>;
-/// Means for transacting local assets that are not the native currency
-/// This transactor uses the new reanchor logic
-pub type LocalFungiblesTransactor = FungiblesAdapter<
- // Use this fungibles implementation:
- LocalAssets,
- // Use this currency when it is a fungible asset matching the given location or name:
- (
- ConvertedConcreteId<
- AssetId,
- Balance,
- // This just tells to convert an assetId into a GeneralIndex junction prepended
- // by LocalAssetsPalletLocation
- AsPrefixedGeneralIndex,
- JustTry,
- >,
- ),
- // Convert an XCM MultiLocation into a local account id:
- LocationToAccountId,
- // Our chain's account ID type (we can't get away without mentioning it explicitly):
- AccountId,
- // We dont want to allow teleporting assets
- NoChecking,
- // The account to use for tracking teleports.
- (),
->;
-
// We use all transactors
// These correspond to
// SelfReserve asset, both pre and post 0.9.16
@@ -199,7 +162,6 @@ pub type LocalFungiblesTransactor = FungiblesAdapter<
pub type AssetTransactors = (
LocalAssetTransactor,
ForeignFungiblesTransactor,
- LocalFungiblesTransactor,
Erc20XcmBridge,
);
@@ -468,7 +430,7 @@ pub enum CurrencyId {
// Assets representing other chains native tokens
ForeignAsset(AssetId),
// Our local assets
- LocalAssetReserve(AssetId),
+ DeprecatedLocalAssetReserve(AssetId),
// Erc20 token
Erc20 { contract_address: H160 },
}
@@ -480,15 +442,8 @@ impl AccountIdToCurrencyId for Runtime {
a if a == H160::from_low_u64_be(2050).into() => CurrencyId::SelfReserve,
// the rest of the currencies, by their corresponding erc20 address
_ => match Runtime::account_to_asset_id(account) {
- // We distinguish by prefix, and depending on it we create either
- // Foreign or Local
- Some((prefix, asset_id)) => {
- if prefix == FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX.to_vec() {
- CurrencyId::ForeignAsset(asset_id)
- } else {
- CurrencyId::LocalAssetReserve(asset_id)
- }
- }
+ // A foreign asset
+ Some((_prefix, asset_id)) => CurrencyId::ForeignAsset(asset_id),
// If no known prefix is identified, we consider that it's a "real" erc20 token
// (i.e. managed by a real smart contract)
None => CurrencyId::Erc20 {
@@ -513,11 +468,7 @@ where
Some(multi)
}
CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset),
- CurrencyId::LocalAssetReserve(asset) => {
- let mut location = LocalAssetsPalletLocation::get();
- location.push_interior(Junction::GeneralIndex(asset)).ok();
- Some(location)
- }
+ CurrencyId::DeprecatedLocalAssetReserve(_) => None,
CurrencyId::Erc20 { contract_address } => {
let mut location = Erc20XcmBridgePalletLocation::get();
location
diff --git a/runtime/moonbase/tests/common/mod.rs b/runtime/moonbase/tests/common/mod.rs
index 2b615ae40d..815372b2d6 100644
--- a/runtime/moonbase/tests/common/mod.rs
+++ b/runtime/moonbase/tests/common/mod.rs
@@ -26,7 +26,7 @@ use moonbase_runtime::{asset_config::AssetRegistrarMetadata, xcm_config::AssetTy
pub use moonbase_runtime::{
currency::{GIGAWEI, SUPPLY_FACTOR, UNIT, WEI},
AccountId, AssetId, AssetManager, Assets, AsyncBacking, AuthorInherent, Balance, Balances,
- CrowdloanRewards, Ethereum, Executive, Header, InflationInfo, LocalAssets, ParachainStaking,
+ CrowdloanRewards, Ethereum, Executive, Header, InflationInfo, ParachainStaking,
ParachainSystem, Range, Runtime, RuntimeCall, RuntimeEvent, System, TransactionConverter,
TransactionPaymentAsGasPrice, UncheckedExtrinsic, HOURS, WEEKS,
};
@@ -287,18 +287,9 @@ impl ExtBuilder {
let mut ext = sp_io::TestExternalities::new(t);
- let local_assets = self.local_assets.clone();
let xcm_assets = self.xcm_assets.clone();
ext.execute_with(|| {
- // If any local assets specified, we create them here
- for (asset_id, balances, owner) in local_assets.clone() {
- LocalAssets::force_create(root_origin(), asset_id.into(), owner, true, 1).unwrap();
- for (account, balance) in balances {
- LocalAssets::mint(origin_of(owner.into()), asset_id.into(), account, balance)
- .unwrap();
- }
- }
// If any xcm assets specified, we register them here
for xcm_asset_initialization in xcm_assets {
let asset_id: AssetId = xcm_asset_initialization.asset_type.clone().into();
diff --git a/runtime/moonbase/tests/integration_test.rs b/runtime/moonbase/tests/integration_test.rs
index e836b7a6c1..5ec56d6e62 100644
--- a/runtime/moonbase/tests/integration_test.rs
+++ b/runtime/moonbase/tests/integration_test.rs
@@ -37,8 +37,7 @@ use frame_support::{
StorageHasher, Twox128,
};
use moonbase_runtime::{
- asset_config::AssetRegistrarMetadata,
- asset_config::LocalAssetInstance,
+ asset_config::{AssetRegistrarMetadata, ForeignAssetInstance},
get,
xcm_config::{AssetType, SelfReserve},
AccountId, AssetId, AssetManager, Assets, Balances, CouncilCollective, CrowdloanRewards,
@@ -61,7 +60,7 @@ use moonbeam_xcm_benchmarks::weights::XcmWeight;
use nimbus_primitives::NimbusId;
use pallet_evm::PrecompileSet;
use pallet_evm_precompileset_assets_erc20::{
- AccountIdAssetIdConversion, IsLocal, SELECTOR_LOG_APPROVAL, SELECTOR_LOG_TRANSFER,
+ AccountIdAssetIdConversion, SELECTOR_LOG_APPROVAL, SELECTOR_LOG_TRANSFER,
};
use pallet_transaction_payment::Multiplier;
use pallet_xcm_transactor::{Currency, CurrencyPayment, HrmpOperation, TransactWeights};
@@ -81,10 +80,9 @@ type XcmUtilsPCall = pallet_evm_precompile_xcm_utils::XcmUtilsPrecompileCall<
moonbase_runtime::xcm_config::XcmExecutorConfig,
>;
type XtokensPCall = pallet_evm_precompile_xtokens::XtokensPrecompileCall;
-type LocalAssetsPCall = pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSetCall<
+type ForeignAssetsPCall = pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSetCall<
Runtime,
- IsLocal,
- LocalAssetInstance,
+ ForeignAssetInstance,
>;
type XcmTransactorV1PCall =
pallet_evm_precompile_xcm_transactor::v1::XcmTransactorPrecompileV1Call;
@@ -157,11 +155,11 @@ fn verify_pallet_prefixes() {
is_pallet_prefix::("Migrations");
is_pallet_prefix::("XcmTransactor");
is_pallet_prefix::("ProxyGenesisCompanion");
- is_pallet_prefix::("LocalAssets");
is_pallet_prefix::("MoonbeamOrbiters");
is_pallet_prefix::("EthereumXcm");
is_pallet_prefix::("Randomness");
is_pallet_prefix::("TreasuryCouncilCollective");
+ is_pallet_prefix::("MoonbeamLazyMigrations");
let prefix = |pallet_name, storage_name| {
let mut res = [0u8; 32];
@@ -488,12 +486,12 @@ fn verify_pallet_indices() {
is_pallet_index::(32);
is_pallet_index::(33);
is_pallet_index::(34);
- is_pallet_index::(36);
is_pallet_index::(37);
is_pallet_index::(38);
is_pallet_index::(39);
is_pallet_index::(40);
is_pallet_index::(46);
+ is_pallet_index::(51);
}
#[test]
@@ -505,7 +503,8 @@ fn verify_reserved_indices() {
_ => panic!("metadata has been bumped, test needs to be updated"),
};
// 35: BaseFee
- let reserved = vec![35];
+ // 36: pallet_assets::
+ let reserved = vec![35, 36];
let existing = metadata
.pallets
.iter()
@@ -1312,31 +1311,6 @@ fn asset_can_be_registered() {
});
}
-#[test]
-fn local_assets_cannot_be_create_by_signed_origins() {
- ExtBuilder::default()
- .with_balances(vec![
- (AccountId::from(ALICE), 2_000 * UNIT * SUPPLY_FACTOR),
- (AccountId::from(BOB), 1_000 * UNIT * SUPPLY_FACTOR),
- ])
- .build()
- .execute_with(|| {
- assert_noop!(
- RuntimeCall::LocalAssets(
- pallet_assets::Call::::create {
- id: 11u128.into(),
- admin: AccountId::from(ALICE),
- min_balance: 1u128
- }
- )
- .dispatch(::RuntimeOrigin::signed(
- AccountId::from(ALICE)
- )),
- frame_system::Error::::CallFiltered
- );
- });
-}
-
#[test]
fn xcm_asset_erc20_precompiles_supply_and_balance() {
ExtBuilder::default()
@@ -1374,7 +1348,7 @@ fn xcm_asset_erc20_precompiles_supply_and_balance() {
.prepare_test(
ALICE,
asset_precompile_address,
- LocalAssetsPCall::total_supply {},
+ ForeignAssetsPCall::total_supply {},
)
.expect_cost(2000)
.expect_no_logs()
@@ -1385,7 +1359,7 @@ fn xcm_asset_erc20_precompiles_supply_and_balance() {
.prepare_test(
ALICE,
asset_precompile_address,
- LocalAssetsPCall::balance_of {
+ ForeignAssetsPCall::balance_of {
who: Address(ALICE.into()),
},
)
@@ -1429,7 +1403,7 @@ fn xcm_asset_erc20_precompiles_transfer() {
.prepare_test(
ALICE,
asset_precompile_address,
- LocalAssetsPCall::transfer {
+ ForeignAssetsPCall::transfer {
to: Address(BOB.into()),
value: { 400 * UNIT }.into(),
},
@@ -1449,7 +1423,7 @@ fn xcm_asset_erc20_precompiles_transfer() {
.prepare_test(
BOB,
asset_precompile_address,
- LocalAssetsPCall::balance_of {
+ ForeignAssetsPCall::balance_of {
who: Address(BOB.into()),
},
)
@@ -1493,7 +1467,7 @@ fn xcm_asset_erc20_precompiles_approve() {
.prepare_test(
ALICE,
asset_precompile_address,
- LocalAssetsPCall::approve {
+ ForeignAssetsPCall::approve {
spender: Address(BOB.into()),
value: { 400 * UNIT }.into(),
},
@@ -1513,7 +1487,7 @@ fn xcm_asset_erc20_precompiles_approve() {
.prepare_test(
BOB,
asset_precompile_address,
- LocalAssetsPCall::transfer_from {
+ ForeignAssetsPCall::transfer_from {
from: Address(ALICE.into()),
to: Address(CHARLIE.into()),
value: { 400 * UNIT }.into(),
@@ -1534,7 +1508,7 @@ fn xcm_asset_erc20_precompiles_approve() {
.prepare_test(
CHARLIE,
asset_precompile_address,
- LocalAssetsPCall::balance_of {
+ ForeignAssetsPCall::balance_of {
who: Address(CHARLIE.into()),
},
)
diff --git a/runtime/moonbase/tests/xcm_mock/mod.rs b/runtime/moonbase/tests/xcm_mock/mod.rs
index 56d396e9d5..f556bc4710 100644
--- a/runtime/moonbase/tests/xcm_mock/mod.rs
+++ b/runtime/moonbase/tests/xcm_mock/mod.rs
@@ -263,9 +263,7 @@ pub type StatemintAssets = pallet_assets::Pallet;
pub type ParachainPalletXcm = pallet_xcm::Pallet;
pub type Assets = pallet_assets::Pallet;
-pub type LocalAssets = pallet_assets::Pallet