Skip to content
This repository has been archived by the owner on Sep 28, 2023. It is now read-only.

Commit

Permalink
AssetsERC20: fixed address conversions, fixed tests
Browse files Browse the repository at this point in the history
Updated lincense headers.
  • Loading branch information
akru committed Apr 25, 2022
1 parent ceacb03 commit d9ea85e
Show file tree
Hide file tree
Showing 12 changed files with 111 additions and 89 deletions.
4 changes: 2 additions & 2 deletions precompiles/assets-erc20/Cargo.toml
@@ -1,9 +1,9 @@
[package]
name = "pallet-evm-precompile-assets-erc20"
authors = [ "PureStake" ]
authors = [ "Stake Technologies", "PureStake" ]
description = "A Precompile to expose a Assets pallet through an ERC20-compliant interface."
edition = "2018"
version = "0.1.0"
version = "0.2.0"

[dependencies]
log = "0.4"
Expand Down
40 changes: 19 additions & 21 deletions precompiles/assets-erc20/src/lib.rs
@@ -1,18 +1,20 @@
// Copyright 2019-2022 PureStake Inc.
// This file is part of Moonbeam.

// Moonbeam is free software: you can redistribute it and/or modify
// Copyright 2022 Stake Technologies
// This file is part of AssetsERC20 package, originally developed by Purestake Inc.
// AssetsERC20 package used in Astar Network in terms of GPLv3.
//
// AssetsERC20 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,
// AssetsERC20 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 <http://www.gnu.org/licenses/>.
// along with AssetsERC20. If not, see <http://www.gnu.org/licenses/>.

#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(test, feature(assert_matches))]
Expand Down Expand Up @@ -71,20 +73,20 @@ pub enum Action {
Decimals = "decimals()",
}

/// This trait ensure we can convert AccountIds to AssetIds
/// This trait ensure we can convert EVM address to AssetIds
/// We will require Runtime to have this trait implemented
pub trait AccountIdAssetIdConversion<Account, AssetId> {
// Get assetId from account
fn account_to_asset_id(account: Account) -> Option<AssetId>;
pub trait AddressToAssetId<AssetId> {
// Get assetId from address
fn address_to_asset_id(address: H160) -> Option<AssetId>;

// Get AccountId from AssetId
fn asset_id_to_account(asset_id: AssetId) -> Account;
// Get address from AssetId
fn asset_id_to_address(asset_id: AssetId) -> H160;
}

/// The following distribution has been decided for the precompiles
/// 0-1023: Ethereum Mainnet Precompiles
/// 1024-2047 Precompiles that are not in Ethereum Mainnet but are neither Moonbeam specific
/// 2048-4095 Moonbeam specific precompiles
/// 1024-2047 Precompiles that are not in Ethereum Mainnet but are neither Astar specific
/// 2048-4095 Astar specific precompiles
/// Asset precompiles can only fall between
/// 0xFFFFFFFF00000000000000000000000000000000 - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
/// The precompile for AssetId X, where X is a u128 (i.e.16 bytes), if 0XFFFFFFFF + Bytes(AssetId)
Expand All @@ -107,7 +109,7 @@ where
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: AddressToAssetId<AssetIdOf<Runtime, Instance>>,
<<Runtime as frame_system::Config>::Call as Dispatchable>::Origin: OriginTrait,
{
fn execute(
Expand All @@ -118,9 +120,7 @@ where
context: &Context,
is_static: bool,
) -> Option<EvmResult<PrecompileOutput>> {
if let Some(asset_id) =
Runtime::account_to_asset_id(Runtime::AddressMapping::into_account_id(address))
{
if let Some(asset_id) = Runtime::address_to_asset_id(address) {
// If the assetId has non-zero supply
// "total_supply" returns both 0 if the assetId does not exist or if the supply is 0
// The assumption I am making here is that a 0 supply asset is not interesting from
Expand Down Expand Up @@ -174,9 +174,7 @@ where
}

fn is_precompile(&self, address: H160) -> bool {
if let Some(asset_id) =
Runtime::account_to_asset_id(Runtime::AddressMapping::into_account_id(address))
{
if let Some(asset_id) = Runtime::address_to_asset_id(address) {
// If the assetId has non-zero supply
// "total_supply" returns both 0 if the assetId does not exist or if the supply is 0
// The assumption I am making here is that a 0 supply asset is not interesting from
Expand Down Expand Up @@ -205,7 +203,7 @@ where
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: AddressToAssetId<AssetIdOf<Runtime, Instance>>,
<<Runtime as frame_system::Config>::Call as Dispatchable>::Origin: OriginTrait,
{
fn total_supply(
Expand Down
39 changes: 26 additions & 13 deletions precompiles/assets-erc20/src/mock.rs
@@ -1,19 +1,20 @@
// Copyright 2019-2022 PureStake Inc.
// This file is part of Moonbeam.

// Moonbeam is free software: you can redistribute it and/or modify
// Copyright 2022 Stake Technologies
// This file is part of AssetsERC20 package, originally developed by Purestake Inc.
// AssetsERC20 package used in Astar Network in terms of GPLv3.
//
// AssetsERC20 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,
// AssetsERC20 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 <http://www.gnu.org/licenses/>.

// along with AssetsERC20. If not, see <http://www.gnu.org/licenses/>.
//! Testing utilities.

use super::*;
Expand Down Expand Up @@ -88,19 +89,28 @@ impl AddressMapping<Account> for Account {
}
}

pub const ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4];

// Implement the trait, where we convert AccountId to AssetID
impl AccountIdAssetIdConversion<AccountId, AssetId> for Runtime {
impl AddressToAssetId<AssetId> for Runtime {
/// The way to convert an account to assetId is by ensuring that the prefix is 0XFFFFFFFF
/// and by taking the lowest 128 bits as the assetId
fn account_to_asset_id(account: AccountId) -> Option<AssetId> {
match account {
Account::AssetId(asset_id) => Some(asset_id),
_ => None,
fn address_to_asset_id(address: H160) -> Option<AssetId> {
let mut data = [0u8; 16];
let address_bytes: [u8; 20] = address.into();
if ASSET_PRECOMPILE_ADDRESS_PREFIX.eq(&address_bytes[0..4]) {
data.copy_from_slice(&address_bytes[4..20]);
Some(u128::from_be_bytes(data))
} else {
None
}
}

fn asset_id_to_account(asset_id: AssetId) -> AccountId {
Account::AssetId(asset_id)
fn asset_id_to_address(asset_id: AssetId) -> H160 {
let mut data = [0u8; 20];
data[0..4].copy_from_slice(ASSET_PRECOMPILE_ADDRESS_PREFIX);
data[4..20].copy_from_slice(&asset_id.to_be_bytes());
H160::from(data)
}
}

Expand Down Expand Up @@ -158,6 +168,7 @@ impl frame_system::Config for Runtime {
type BlockLength = ();
type SS58Prefix = SS58Prefix;
type OnSetCode = ();
type MaxConsumers = frame_support::traits::ConstU32<16>;
}

parameter_types! {
Expand Down Expand Up @@ -214,6 +225,7 @@ impl pallet_evm::Config for Runtime {
// No deposit is substracted with those methods
parameter_types! {
pub const AssetDeposit: Balance = 0;
pub const AssetAccountDeposit: Balance = 0;
pub const ApprovalDeposit: Balance = 0;
pub const AssetsStringLimit: u32 = 50;
pub const MetadataDepositBase: Balance = 0;
Expand All @@ -227,6 +239,7 @@ impl pallet_assets::Config for Runtime {
type Currency = Balances;
type ForceOrigin = EnsureRoot<AccountId>;
type AssetDeposit = AssetDeposit;
type AssetAccountDeposit = AssetAccountDeposit;
type MetadataDepositBase = MetadataDepositBase;
type MetadataDepositPerByte = MetadataDepositPerByte;
type ApprovalDeposit = ApprovalDeposit;
Expand Down
37 changes: 16 additions & 21 deletions precompiles/assets-erc20/src/tests.rs
@@ -1,19 +1,20 @@
// Copyright 2019-2022 PureStake Inc.
// This file is part of Moonbeam.

// Moonbeam is free software: you can redistribute it and/or modify
// Copyright 2022 Stake Technologies
// This file is part of AssetsERC20 package, originally developed by Purestake Inc.
// AssetsERC20 package used in Astar Network in terms of GPLv3.
//
// AssetsERC20 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,
// AssetsERC20 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 <http://www.gnu.org/licenses/>.

// along with AssetsERC20. If not, see <http://www.gnu.org/licenses/>.
use frame_support::assert_ok;
use std::{assert_matches::assert_matches, str::from_utf8};

Expand Down Expand Up @@ -290,7 +291,7 @@ fn approve() {
Some(Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
output: EvmDataWriter::new().write(true).build(),
cost: 56999756u64,
cost: 30832756u64,
logs: LogsBuilder::new(Account::AssetId(0u128).into())
.log3(
SELECTOR_LOG_APPROVAL,
Expand Down Expand Up @@ -342,7 +343,7 @@ fn approve_saturating() {
Some(Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
output: EvmDataWriter::new().write(true).build(),
cost: 56999756u64,
cost: 30832756u64,
logs: LogsBuilder::new(Account::AssetId(0u128).into())
.log3(
SELECTOR_LOG_APPROVAL,
Expand Down Expand Up @@ -521,7 +522,7 @@ fn transfer() {
Some(Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
output: EvmDataWriter::new().write(true).build(),
cost: 83206756u64, // 1 weight => 1 gas in mock
cost: 44001756u64, // 1 weight => 1 gas in mock
logs: LogsBuilder::new(Account::AssetId(0u128).into())
.log3(
SELECTOR_LOG_TRANSFER,
Expand Down Expand Up @@ -676,7 +677,7 @@ fn transfer_from() {
Some(Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
output: EvmDataWriter::new().write(true).build(),
cost: 107172756u64, // 1 weight => 1 gas in mock
cost: 56268756u64, // 1 weight => 1 gas in mock
logs: LogsBuilder::new(Account::AssetId(0u128).into())
.log3(
SELECTOR_LOG_TRANSFER,
Expand Down Expand Up @@ -795,7 +796,7 @@ fn transfer_from_non_incremental_approval() {
Some(Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
output: EvmDataWriter::new().write(true).build(),
cost: 56999756u64,
cost: 30832756u64,
logs: LogsBuilder::new(Account::AssetId(0u128).into())
.log3(
SELECTOR_LOG_APPROVAL,
Expand Down Expand Up @@ -829,7 +830,7 @@ fn transfer_from_non_incremental_approval() {
Some(Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
output: EvmDataWriter::new().write(true).build(),
cost: 114357756u64,
cost: 62796756u64,
logs: LogsBuilder::new(Account::AssetId(0u128).into())
.log3(
SELECTOR_LOG_APPROVAL,
Expand Down Expand Up @@ -858,10 +859,7 @@ fn transfer_from_non_incremental_approval() {
},
false,
),
Some(Err(PrecompileFailure::Revert { output, ..}))
if output == b"Dispatched call failed with error: DispatchErrorWithPostInfo { \
post_info: PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes }, \
error: Module { index: 2, error: 10, message: Some(\"Unapproved\") } }",
Some(Err(PrecompileFailure::Revert { .. }))
);
});
}
Expand Down Expand Up @@ -917,10 +915,7 @@ fn transfer_from_above_allowance() {
},
false,
),
Some(Err(PrecompileFailure::Revert { output, ..}))
if output == b"Dispatched call failed with error: DispatchErrorWithPostInfo { \
post_info: PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes }, \
error: Module { index: 2, error: 10, message: Some(\"Unapproved\") } }"
Some(Err(PrecompileFailure::Revert { .. }))
);
});
}
Expand Down Expand Up @@ -965,7 +960,7 @@ fn transfer_from_self() {
Some(Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
output: EvmDataWriter::new().write(true).build(),
cost: 83206756u64, // 1 weight => 1 gas in mock
cost: 44001756u64, // 1 weight => 1 gas in mock
logs: LogsBuilder::new(Account::AssetId(0u128).into())
.log3(
SELECTOR_LOG_TRANSFER,
Expand Down
4 changes: 2 additions & 2 deletions precompiles/utils/Cargo.toml
@@ -1,9 +1,9 @@
[package]
name = "precompile-utils"
authors = [ "PureStake" ]
authors = [ "StakeTechnologies", "PureStake" ]
description = "Utils to write EVM precompiles."
edition = "2018"
version = "0.1.0"
version = "0.2.0"

[dependencies]
log = "0.4"
Expand Down
2 changes: 1 addition & 1 deletion precompiles/utils/macro/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "precompile-utils-macro"
authors = [ "PureStake" ]
authors = [ "StakeTechnologies", "PureStake" ]
description = ""
edition = "2018"
version = "0.1.0"
Expand Down
13 changes: 9 additions & 4 deletions precompiles/utils/macro/src/lib.rs
@@ -1,16 +1,21 @@
// Copyright 2019-2022 PureStake Inc.
// This file is part of Moonbeam.

// Moonbeam is free software: you can redistribute it and/or modify
// Copyright 2022 Stake Technologies
// This file is part of Utils package, originally developed by Purestake Inc.
// Utils package used in Astar Network in terms of GPLv3.
//
// Utils 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,
// Utils 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 Utils. If not, see <http://www.gnu.org/licenses/>.

#![crate_type = "proc-macro"]
extern crate proc_macro;

Expand Down
13 changes: 8 additions & 5 deletions precompiles/utils/macro/tests/tests.rs
@@ -1,17 +1,20 @@
// Copyright 2019-2022 PureStake Inc.
// This file is part of Moonbeam.

// Moonbeam is free software: you can redistribute it and/or modify
// Copyright 2022 Stake Technologies
// This file is part of Utils package, originally developed by Purestake Inc.
// Utils package used in Astar Network in terms of GPLv3.
//
// Utils 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,
// Utils 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.

use sha3::{Digest, Keccak256};
// You should have received a copy of the GNU General Public License
// along with Utils. If not, see <http://www.gnu.org/licenses/>.

#[precompile_utils_macro::generate_function_selector]
pub enum Action {
Expand Down

0 comments on commit d9ea85e

Please sign in to comment.