Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic EVM revert code registration for XC20 #1001

Merged
merged 8 commits into from
Aug 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 0 additions & 21 deletions pallets/xc-asset-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,6 @@ pub mod pallet {
#[pallet::without_storage_info]
pub struct Pallet<T>(PhantomData<T>);

/// Callback definition trait for cross-chain asset registration/deregistration notifications.
pub trait XcAssetChanged<T: Config> {
/// Will be called by pallet when new asset Id has been registered
fn xc_asset_registered(asset_id: T::AssetId);

/// Will be called by pallet when asset Id has been unregistered
fn xc_asset_unregistered(asset_id: T::AssetId);
}

/// Implementation that does nothing
impl<T: Config> XcAssetChanged<T> for () {
fn xc_asset_registered(_: T::AssetId) {}
fn xc_asset_unregistered(_: T::AssetId) {}
}

/// Defines conversion between asset Id and cross-chain asset location
pub trait XcAssetLocation<AssetId> {
/// Get asset type from assetId
Expand Down Expand Up @@ -139,9 +124,6 @@ pub mod pallet {
/// a AssetLocation
type AssetId: Member + Parameter + Default + Copy + HasCompact + MaxEncodedLen;

/// Callback handling for cross-chain asset registration or unregistration.
type XcAssetChanged: XcAssetChanged<Self>;

/// The required origin for managing cross-chain asset configuration
///
/// Should most likely be root.
Expand Down Expand Up @@ -242,8 +224,6 @@ pub mod pallet {
AssetIdToLocation::<T>::insert(&asset_id, asset_location.clone());
AssetLocationToId::<T>::insert(&asset_location, asset_id);

T::XcAssetChanged::xc_asset_registered(asset_id);

Self::deposit_event(Event::AssetRegistered {
asset_location,
asset_id,
Expand Down Expand Up @@ -354,7 +334,6 @@ pub mod pallet {
AssetIdToLocation::<T>::remove(&asset_id);
AssetLocationToId::<T>::remove(&asset_location);
AssetLocationUnitsPerSecond::<T>::remove(&asset_location);
T::XcAssetChanged::xc_asset_unregistered(asset_id);

Self::deposit_event(Event::AssetRemoved {
asset_id,
Expand Down
1 change: 0 additions & 1 deletion pallets/xc-asset-config/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ type AssetId = u128;
impl pallet_xc_asset_config::Config for Test {
type RuntimeEvent = RuntimeEvent;
type AssetId = AssetId;
type XcAssetChanged = ();
type ManagerOrigin = frame_system::EnsureRoot<AccountId>;
type WeightInfo = ();
}
Expand Down
1 change: 1 addition & 0 deletions precompiles/assets-erc20/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,4 @@ std = [
"sp-runtime/std",
"sp-std/std",
]
runtime-benchmarks = []
2 changes: 2 additions & 0 deletions precompiles/assets-erc20/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ impl pallet_assets::Config for Runtime {
type RemoveItemsLimit = ConstU32<0>;
type AssetIdParameter = AssetId;
type CallbackHandle = ();
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = ();
}

// Configure a mock runtime to test the pallet.
Expand Down
2 changes: 2 additions & 0 deletions precompiles/xcm/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ impl pallet_assets::Config for Runtime {
type RemoveItemsLimit = ConstU32<0>;
type AssetIdParameter = AssetId;
type CallbackHandle = ();
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = ();
}

pub struct AssetIdConverter<AssetId>(PhantomData<AssetId>);
Expand Down
12 changes: 10 additions & 2 deletions primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ fp-evm = { workspace = true }

# Substrate dependencies
frame-support = { workspace = true }
pallet-assets = { workspace = true }
sp-core = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }
Expand All @@ -30,7 +31,11 @@ xcm = { workspace = true }
xcm-builder = { workspace = true }
xcm-executor = { workspace = true }

# Astar pallets
# Frontier dependencies
pallet-evm = { workspace = true }

# Astar pallets & dependencies
pallet-evm-precompile-assets-erc20 = { workspace = true }
pallet-xc-asset-config = { workspace = true }

[features]
Expand All @@ -52,5 +57,8 @@ std = [
"xcm-executor/std",
"pallet-xc-asset-config/std",
"fp-evm/std",
"pallet-assets/std",
"pallet-evm/std",
"pallet-evm-precompile-assets-erc20/std",
]
runtime-benchmarks = ["xcm-builder/runtime-benchmarks"]
runtime-benchmarks = ["xcm-builder/runtime-benchmarks", "pallet-assets/runtime-benchmarks"]
30 changes: 30 additions & 0 deletions primitives/src/benchmarks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// This file is part of Astar.

// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later

// Astar 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.

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

use crate::AssetId;

#[cfg(feature = "runtime-benchmarks")]
/// Benchmark helper for `pallet-assets`.
pub struct AssetsBenchmarkHelper;
impl<AssetIdParameter: From<u128>> pallet_assets::BenchmarkHelper<AssetIdParameter>
for AssetsBenchmarkHelper
{
fn create_asset_id_parameter(id: u32) -> AssetIdParameter {
AssetId::from(id).into()
}
}
56 changes: 56 additions & 0 deletions primitives/src/evm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// This file is part of Astar.

// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later

// Astar 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.

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

use crate::{AccountId, AssetId};

use frame_support::ensure;
use sp_std::marker::PhantomData;

use pallet_assets::AssetsCallback;
use pallet_evm_precompile_assets_erc20::AddressToAssetId;

/// Revert opt code. It's inserted at the precompile addresses, to make them functional in EVM.
pub const EVM_REVERT_CODE: &[u8] = &[0x60, 0x00, 0x60, 0x00, 0xfd];

/// Handler for automatic revert code registration.
///
/// When an asset is created, it automatically becomes available to the EVM via an `ERC20-like` interface.
/// In order for the precompile to work, dedicated asset address needs to have the revert code registered, otherwise the call will fail.
///
/// It is important to note that if the dedicated asset EVM address is already taken, asset creation should fail.
/// After asset has been destroyed, it is also safe to remove the revert code and free the address for future usage.
pub struct EvmRevertCodeHandler<A, R>(PhantomData<(A, R)>);
impl<A, R> AssetsCallback<AssetId, AccountId> for EvmRevertCodeHandler<A, R>
where
A: AddressToAssetId<AssetId>,
R: pallet_evm::Config,
{
fn created(id: &AssetId, _: &AccountId) -> Result<(), ()> {
let address = A::asset_id_to_address(*id);
// In case of collision, we need to cancel the asset creation.
ensure!(!pallet_evm::AccountCodes::<R>::contains_key(&address), ());
pallet_evm::AccountCodes::<R>::insert(address, EVM_REVERT_CODE.to_vec());
Ok(())
}

fn destroyed(id: &AssetId) -> Result<(), ()> {
let address = A::asset_id_to_address(*id);
pallet_evm::AccountCodes::<R>::remove(address);
Ok(())
}
}
10 changes: 8 additions & 2 deletions primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,16 @@ pub mod ethereum_checked;
/// XVM primitives.
pub mod xvm;

use sp_runtime::traits::BlakeTwo256;
/// EVM primitives.
pub mod evm;

/// Benchmark primitives
#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarks;

use sp_runtime::{
generic,
traits::{IdentifyAccount, Verify},
traits::{BlakeTwo256, IdentifyAccount, Verify},
};

/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
Expand Down
51 changes: 2 additions & 49 deletions primitives/src/xcm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@
#![cfg_attr(not(feature = "std"), no_std)]

use frame_support::{
ensure,
traits::{tokens::fungibles, Contains, ContainsPair, Get, ProcessMessageError},
traits::{tokens::fungibles, ContainsPair, Get},
weights::constants::WEIGHT_REF_TIME_PER_SECOND,
};
use sp_runtime::traits::{Bounded, Zero};
Expand All @@ -43,7 +42,7 @@ use sp_std::{borrow::Borrow, marker::PhantomData, vec::Vec};
// Polkadot imports
use xcm::latest::{prelude::*, Weight};
use xcm_builder::TakeRevenue;
use xcm_executor::traits::{MatchesFungibles, ShouldExecute, WeightTrader};
use xcm_executor::traits::{MatchesFungibles, WeightTrader};

use pallet_xc_asset_config::{ExecutionPaymentRate, XcAssetLocation};

Expand Down Expand Up @@ -271,52 +270,6 @@ impl<
}
}

/// Allows execution from `origin` if it is contained in `T` (i.e. `T::Contains(origin)`) taking
/// payments into account.
///
/// Only allows for sequence `DescendOrigin` -> `WithdrawAsset` -> `BuyExecution`
pub struct AllowPaidExecWithDescendOriginFrom<T>(PhantomData<T>);
impl<T: Contains<MultiLocation>> ShouldExecute for AllowPaidExecWithDescendOriginFrom<T> {
fn should_execute<RuntimeCall>(
origin: &MultiLocation,
message: &mut [Instruction<RuntimeCall>],
max_weight: Weight,
_weight_credit: &mut Weight,
) -> Result<(), ProcessMessageError> {
log::trace!(
target: "xcm::barriers",
"AllowPaidExecWithDescendOriginFrom origin: {:?}, message: {:?}, max_weight: {:?}, weight_credit: {:?}",
origin, message, max_weight, _weight_credit,
);
ensure!(T::contains(origin), ProcessMessageError::Unsupported);

match message
.iter_mut()
.take(3)
.collect::<Vec<_>>()
.as_mut_slice()
{
[DescendOrigin(..), WithdrawAsset(..), BuyExecution {
weight_limit: Limited(ref mut limit),
..
}] if limit.all_gte(max_weight) => {
*limit = max_weight;
Ok(())
}

[DescendOrigin(..), WithdrawAsset(..), BuyExecution {
weight_limit: ref mut limit @ Unlimited,
..
}] => {
*limit = Limited(max_weight);
Ok(())
}

_ => return Err(ProcessMessageError::Unsupported),
}
}
}

// TODO: remove this after uplift to `polkadot-v0.9.44` or beyond, and replace it with code in XCM builder.

use parity_scale_codec::{Compact, Encode};
Expand Down
Loading