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

fix return types in asset erc20 and refactor asseterc20precompileset #990

2 changes: 1 addition & 1 deletion node/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ fn export_current_state() {

// Let it produce some blocks.
// This fails if is not a minimum of 25
thread::sleep(Duration::from_secs(25));
thread::sleep(Duration::from_secs(35));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess because of the JIT compilation issue. but the CI was complaining:(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can [hopefully] be reverted once 993 is merged.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed

assert!(
cmd.try_wait().unwrap().is_none(),
"the process should still be running"
Expand Down
150 changes: 51 additions & 99 deletions precompiles/assets-erc20/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ use frame_support::{
dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo},
sp_runtime::traits::StaticLookup,
};
use pallet_evm::{AddressMapping, Precompile, PrecompileSet};
use pallet_evm::{AddressMapping, PrecompileSet};
use precompile_utils::{
error, keccak256, Address, Bytes, EvmData, EvmDataReader, EvmDataWriter, EvmResult, Gasometer,
keccak256, Address, Bytes, EvmData, EvmDataReader, EvmDataWriter, EvmResult, Gasometer,
LogsBuilder, RuntimeHelper,
};
use sp_runtime::traits::Zero;
Expand Down Expand Up @@ -98,9 +98,13 @@ pub struct Erc20AssetsPrecompileSet<Runtime, Instance: 'static = ()>(
impl<Runtime, Instance> PrecompileSet for Erc20AssetsPrecompileSet<Runtime, Instance>
where
Instance: 'static,
Erc20AssetsPrecompile<Runtime, Instance>: Precompile,
Runtime: pallet_assets::Config<Instance> + pallet_evm::Config,
Runtime: pallet_assets::Config<Instance> + pallet_evm::Config + frame_system::Config,
Runtime::Call: Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo,
Runtime::Call: From<pallet_assets::Call<Runtime, Instance>>,
<Runtime::Call as Dispatchable>::Origin: From<Option<Runtime::AccountId>>,
BalanceOf<Runtime, Instance>: TryFrom<U256> + Into<U256> + EvmData,
Runtime: AccountIdAssetIdConversion<Runtime::AccountId, AssetIdOf<Runtime, Instance>>,
<<Runtime as frame_system::Config>::Call as Dispatchable>::Origin: OriginTrait,
{
fn execute(
address: H160,
Expand All @@ -119,52 +123,34 @@ where
// The other options is to check the asset existence in pallet-asset-manager, but
// this makes the precompiles dependent on such a pallet, which is not ideal
if !pallet_assets::Pallet::<Runtime, Instance>::total_supply(asset_id).is_zero() {
return Some(
<Erc20AssetsPrecompile<Runtime, Instance> as Precompile>::execute(
input, target_gas, context,
),
);
let result = {
let (input, selector) = match EvmDataReader::new_with_selector(input) {
Ok((input, selector)) => (input, selector),
Err(e) => return Some(Err(e)),
};

match selector {
Action::TotalSupply => Self::total_supply(asset_id, input, target_gas),
Action::BalanceOf => Self::balance_of(asset_id, input, target_gas),
Action::Allowance => Self::allowance(asset_id, input, target_gas),
Action::Approve => Self::approve(asset_id, input, target_gas, context),
Action::Transfer => Self::transfer(asset_id, input, target_gas, context),
Action::TransferFrom => {
Self::transfer_from(asset_id, input, target_gas, context)
}
Action::Name => Self::name(asset_id, target_gas),
Action::Symbol => Self::symbol(asset_id, target_gas),
Action::Decimals => Self::decimals(asset_id, target_gas),
}
};
return Some(result);
}
}
None
}
}

pub struct Erc20AssetsPrecompile<Runtime, Instance: 'static = ()>(PhantomData<(Runtime, Instance)>);

impl<Runtime, Instance> Precompile for Erc20AssetsPrecompile<Runtime, Instance>
where
Instance: 'static,
Runtime: pallet_assets::Config<Instance> + pallet_evm::Config,
Runtime::Call: Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo,
Runtime::Call: From<pallet_assets::Call<Runtime, Instance>>,
<Runtime::Call as Dispatchable>::Origin: From<Option<Runtime::AccountId>>,
BalanceOf<Runtime, Instance>: TryFrom<U256> + Into<U256> + EvmData,
Runtime: AccountIdAssetIdConversion<Runtime::AccountId, AssetIdOf<Runtime, Instance>>,
<<Runtime as frame_system::Config>::Call as Dispatchable>::Origin: OriginTrait,
{
fn execute(
input: &[u8], //Reminder this is big-endian
target_gas: Option<u64>,
context: &Context,
) -> Result<PrecompileOutput, ExitError> {
let (input, selector) = EvmDataReader::new_with_selector(input)?;

match selector {
Action::TotalSupply => Self::total_supply(input, target_gas, context),
Action::BalanceOf => Self::balance_of(input, target_gas, context),
Action::Allowance => Self::allowance(input, target_gas, context),
Action::Approve => Self::approve(input, target_gas, context),
Action::Transfer => Self::transfer(input, target_gas, context),
Action::TransferFrom => Self::transfer_from(input, target_gas, context),
Action::Name => Self::name(target_gas, context),
Action::Symbol => Self::symbol(target_gas, context),
Action::Decimals => Self::decimals(target_gas, context),
}
}
}

impl<Runtime, Instance> Erc20AssetsPrecompile<Runtime, Instance>
impl<Runtime, Instance> Erc20AssetsPrecompileSet<Runtime, Instance>
where
Instance: 'static,
Runtime: pallet_assets::Config<Instance> + pallet_evm::Config + frame_system::Config,
Expand All @@ -176,21 +162,16 @@ where
<<Runtime as frame_system::Config>::Call as Dispatchable>::Origin: OriginTrait,
{
fn total_supply(
asset_id: AssetIdOf<Runtime, Instance>,
input: EvmDataReader,
target_gas: Option<u64>,
context: &Context,
) -> EvmResult<PrecompileOutput> {
let mut gasometer = Gasometer::new(target_gas);
gasometer.record_cost(RuntimeHelper::<Runtime>::db_read_gas_cost())?;

let execution_address = Runtime::AddressMapping::into_account_id(context.address);

// Parse input.
input.expect_arguments(0)?;

let asset_id: AssetIdOf<Runtime, Instance> =
Runtime::account_to_asset_id(execution_address).ok_or(error("non-assetId address"))?;

// Fetch info.
let amount: U256 =
pallet_assets::Pallet::<Runtime, Instance>::total_issuance(asset_id).into();
Expand All @@ -205,9 +186,9 @@ where
}

fn balance_of(
asset_id: AssetIdOf<Runtime, Instance>,
mut input: EvmDataReader,
target_gas: Option<u64>,
context: &Context,
) -> EvmResult<PrecompileOutput> {
let mut gasometer = Gasometer::new(target_gas);
gasometer.record_cost(RuntimeHelper::<Runtime>::db_read_gas_cost())?;
Expand All @@ -219,12 +200,6 @@ where

// Fetch info.
let amount: U256 = {
let execution_address = Runtime::AddressMapping::into_account_id(context.address);

let asset_id: AssetIdOf<Runtime, Instance> =
Runtime::account_to_asset_id(execution_address)
.ok_or(error("non-assetId address"))?;

let owner: Runtime::AccountId = Runtime::AddressMapping::into_account_id(owner);
pallet_assets::Pallet::<Runtime, Instance>::balance(asset_id, &owner).into()
};
Expand All @@ -239,9 +214,9 @@ where
}

fn allowance(
asset_id: AssetIdOf<Runtime, Instance>,
mut input: EvmDataReader,
target_gas: Option<u64>,
context: &Context,
) -> EvmResult<PrecompileOutput> {
let mut gasometer = Gasometer::new(target_gas);
gasometer.record_cost(RuntimeHelper::<Runtime>::db_read_gas_cost())?;
Expand All @@ -254,11 +229,6 @@ where

// Fetch info.
let amount: U256 = {
let execution_address = Runtime::AddressMapping::into_account_id(context.address);
let asset_id: AssetIdOf<Runtime, Instance> =
Runtime::account_to_asset_id(execution_address)
.ok_or(error("non-assetId address"))?;

let owner: Runtime::AccountId = Runtime::AddressMapping::into_account_id(owner);
let spender: Runtime::AccountId = Runtime::AddressMapping::into_account_id(spender);

Expand All @@ -276,6 +246,7 @@ where
}

fn approve(
asset_id: AssetIdOf<Runtime, Instance>,
mut input: EvmDataReader,
target_gas: Option<u64>,
context: &Context,
Expand All @@ -290,11 +261,6 @@ where
let amount = input.read::<BalanceOf<Runtime, Instance>>()?;

{
let execution_address = Runtime::AddressMapping::into_account_id(context.address);
let asset_id: AssetIdOf<Runtime, Instance> =
Runtime::account_to_asset_id(execution_address)
.ok_or(error("non-assetId address"))?;

let origin = Runtime::AddressMapping::into_account_id(context.caller);

let spender: Runtime::AccountId = Runtime::AddressMapping::into_account_id(spender);
Expand All @@ -316,7 +282,6 @@ where
)?;
gasometer.record_cost(used_gas)?;
}

// Dispatch call (if enough gas).
let used_gas = RuntimeHelper::<Runtime>::try_dispatch(
Some(origin).into(),
Expand All @@ -329,12 +294,11 @@ where
)?;
gasometer.record_cost(used_gas)?;
}

// Build output.
Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
cost: gasometer.used_gas(),
output: vec![],
output: EvmDataWriter::new().write(true).build(),
logs: LogsBuilder::new(context.address)
.log3(
SELECTOR_LOG_APPROVAL,
Expand All @@ -347,6 +311,7 @@ where
}

fn transfer(
asset_id: AssetIdOf<Runtime, Instance>,
mut input: EvmDataReader,
target_gas: Option<u64>,
context: &Context,
Expand All @@ -362,11 +327,6 @@ where

// Build call with origin.
{
let execution_address = Runtime::AddressMapping::into_account_id(context.address);
let asset_id: AssetIdOf<Runtime, Instance> =
Runtime::account_to_asset_id(execution_address)
.ok_or(error("non-assetId address"))?;

let origin = Runtime::AddressMapping::into_account_id(context.caller);
let to = Runtime::AddressMapping::into_account_id(to);

Expand All @@ -387,7 +347,7 @@ where
Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
cost: gasometer.used_gas(),
output: vec![],
output: EvmDataWriter::new().write(true).build(),
logs: LogsBuilder::new(context.address)
.log3(
SELECTOR_LOG_TRANSFER,
Expand All @@ -400,6 +360,7 @@ where
}

fn transfer_from(
asset_id: AssetIdOf<Runtime, Instance>,
mut input: EvmDataReader,
target_gas: Option<u64>,
context: &Context,
Expand All @@ -414,16 +375,10 @@ where
let amount = input.read::<BalanceOf<Runtime, Instance>>()?;

{
let execution_address = Runtime::AddressMapping::into_account_id(context.address);
let asset_id: AssetIdOf<Runtime, Instance> =
Runtime::account_to_asset_id(execution_address)
.ok_or(error("non-assetId address"))?;
let caller: Runtime::AccountId =
Runtime::AddressMapping::into_account_id(context.caller);
let from: Runtime::AccountId = Runtime::AddressMapping::into_account_id(from.clone());
let to: Runtime::AccountId = Runtime::AddressMapping::into_account_id(to);

// If caller is "from", it can spend as much as it wants from its own balance.
let used_gas = if caller != from {
// Dispatch call (if enough gas).
RuntimeHelper::<Runtime>::try_dispatch(
Expand All @@ -450,12 +405,11 @@ where
}?;
gasometer.record_cost(used_gas)?;
}

// Build output.
Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
cost: gasometer.used_gas(),
output: vec![],
output: EvmDataWriter::new().write(true).build(),
logs: LogsBuilder::new(context.address)
.log3(
SELECTOR_LOG_TRANSFER,
Expand All @@ -467,13 +421,12 @@ where
})
}

fn name(target_gas: Option<u64>, context: &Context) -> EvmResult<PrecompileOutput> {
fn name(
asset_id: AssetIdOf<Runtime, Instance>,
target_gas: Option<u64>,
) -> EvmResult<PrecompileOutput> {
let mut gasometer = Gasometer::new(target_gas);
gasometer.record_cost(RuntimeHelper::<Runtime>::db_read_gas_cost())?;
let execution_address = Runtime::AddressMapping::into_account_id(context.address);
let asset_id: AssetIdOf<Runtime, Instance> =
Runtime::account_to_asset_id(execution_address).ok_or(error("non-assetId address"))?;

// Build output.
Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
Expand All @@ -489,13 +442,12 @@ where
})
}

fn symbol(target_gas: Option<u64>, context: &Context) -> EvmResult<PrecompileOutput> {
fn symbol(
asset_id: AssetIdOf<Runtime, Instance>,
target_gas: Option<u64>,
) -> EvmResult<PrecompileOutput> {
let mut gasometer = Gasometer::new(target_gas);
gasometer.record_cost(RuntimeHelper::<Runtime>::db_read_gas_cost())?;
let execution_address = Runtime::AddressMapping::into_account_id(context.address);
let asset_id: AssetIdOf<Runtime, Instance> =
Runtime::account_to_asset_id(execution_address).ok_or(error("non-assetId address"))?;

// Build output.
Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
Expand All @@ -511,12 +463,12 @@ where
})
}

fn decimals(target_gas: Option<u64>, context: &Context) -> EvmResult<PrecompileOutput> {
fn decimals(
asset_id: AssetIdOf<Runtime, Instance>,
target_gas: Option<u64>,
) -> EvmResult<PrecompileOutput> {
let mut gasometer = Gasometer::new(target_gas);
gasometer.record_cost(RuntimeHelper::<Runtime>::db_read_gas_cost())?;
let execution_address = Runtime::AddressMapping::into_account_id(context.address);
let asset_id: AssetIdOf<Runtime, Instance> =
Runtime::account_to_asset_id(execution_address).ok_or(error("non-assetId address"))?;

// Build output.
Ok(PrecompileOutput {
Expand Down
12 changes: 6 additions & 6 deletions precompiles/assets-erc20/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ fn approve() {
),
Some(Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
output: Default::default(),
output: EvmDataWriter::new().write(true).build(),
cost: 56999756u64,
logs: LogsBuilder::new(Account::AssetId(0u128).into())
.log3(
Expand Down Expand Up @@ -429,7 +429,7 @@ fn transfer() {
),
Some(Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
output: Default::default(),
output: EvmDataWriter::new().write(true).build(),
cost: 83206756u64, // 1 weight => 1 gas in mock
logs: LogsBuilder::new(Account::AssetId(0u128).into())
.log3(
Expand Down Expand Up @@ -578,7 +578,7 @@ fn transfer_from() {
),
Some(Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
output: Default::default(),
output: EvmDataWriter::new().write(true).build(),
cost: 107172756u64, // 1 weight => 1 gas in mock
logs: LogsBuilder::new(Account::AssetId(0u128).into())
.log3(
Expand Down Expand Up @@ -693,7 +693,7 @@ fn transfer_from_non_incremental_approval() {
),
Some(Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
output: Default::default(),
output: EvmDataWriter::new().write(true).build(),
cost: 56999756u64,
logs: LogsBuilder::new(Account::AssetId(0u128).into())
.log3(
Expand Down Expand Up @@ -726,7 +726,7 @@ fn transfer_from_non_incremental_approval() {
),
Some(Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
output: Default::default(),
output: EvmDataWriter::new().write(true).build(),
cost: 114357756u64,
logs: LogsBuilder::new(Account::AssetId(0u128).into())
.log3(
Expand Down Expand Up @@ -860,7 +860,7 @@ fn transfer_from_self() {
),
Some(Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
output: Default::default(),
output: EvmDataWriter::new().write(true).build(),
cost: 83206756u64, // 1 weight => 1 gas in mock
logs: LogsBuilder::new(Account::AssetId(0u128).into())
.log3(
Expand Down
Loading