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

Feat/au precompile #1080

Merged
merged 15 commits into from
Dec 6, 2023
31 changes: 31 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ pallet-evm-precompile-substrate-ecdsa = { path = "./precompiles/substrate-ecdsa"
pallet-evm-precompile-xcm = { path = "./precompiles/xcm", default-features = false }
pallet-evm-precompile-xvm = { path = "./precompiles/xvm", default-features = false }
pallet-evm-precompile-dapps-staking = { path = "./precompiles/dapps-staking", default-features = false }
pallet-evm-precompile-unified-accounts = { path = "./precompiles/unified-accounts", default-features = false }

pallet-chain-extension-dapps-staking = { path = "./chain-extensions/dapps-staking", default-features = false }
pallet-chain-extension-xvm = { path = "./chain-extensions/xvm", default-features = false }
Expand Down
62 changes: 62 additions & 0 deletions precompiles/unified-accounts/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
[package]
name = "pallet-evm-precompile-unified-accounts"
description = "Evm Precompile for AU"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
repository.workspace = true

[dependencies]
hex = { workspace = true }
log = { workspace = true }
num_enum = { workspace = true }
precompile-utils = { workspace = true }

# Substrate
frame-support = { workspace = true }
frame-system = { workspace = true }
parity-scale-codec = { workspace = true, features = ["max-encoded-len"] }
sp-core = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }

# Frontier
fp-evm = { workspace = true }
pallet-evm = { workspace = true }
pallet-unified-accounts = { workspace = true }

# Astar
astar-primitives = { workspace = true }

[dev-dependencies]
derive_more = { workspace = true }
hex-literal = { workspace = true }
scale-info = { workspace = true }
serde = { workspace = true }

precompile-utils = { workspace = true, features = ["testing"] }

ethers = { workspace = true }
libsecp256k1 = { workspace = true, features = ["hmac", "static-context"] }
pallet-balances = { workspace = true, features = ["std"] }
pallet-timestamp = { workspace = true }
sp-runtime = { workspace = true }

[features]
default = ["std"]
std = [
"parity-scale-codec/std",
"pallet-unified-accounts/std",
"fp-evm/std",
"frame-support/std",
"frame-system/std",
"pallet-evm/std",
"precompile-utils/std",
"sp-core/std",
"sp-std/std",
"sp-io/std",
"sp-runtime/std",
"astar-primitives/std",
]
28 changes: 28 additions & 0 deletions precompiles/unified-accounts/UnifiedAccounts.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
pragma solidity ^0.8.0;

/**
* @title UA interface.
*/

/// Interface to the precompiled contract on Shibuya
Copy link
Member

Choose a reason for hiding this comment

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

Probably better to drop Shibuya from the comment.

And the address too, I guess. It's not tied to the interface.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah I'll drop Shibuya.
For address, it's kind of tied to interface as we have same address in all networks and we have this in every precompile interface, also easier for people to just use it right from here.

Copy link
Member

Choose a reason for hiding this comment

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

It's not tied to the .sol file as an interface.

It's tied to the implementation of this interface in our precompiles - there it's said to be the number mentioned above. But it could just as well change in the implementation without any change being required in the .sol file.

It's not a big deal, and you are right when you say it's also mentioned in other files.
I consider it to be wrong - however it is convenient.

No need to change it, it was more of a minor comment.

/// Predeployed at the address 0x0000000000000000000000000000000000005006
/// For better understanding check the source code:
/// repo: https://github.com/AstarNetwork/astar
/// code: pallets/unified-accounts/src/lib.rs
interface UnifiedAccounts {
/// Gets the evm address associated with given account id. If no mapping exists,
/// then return the default account id.
/// @param accountId: The account id for which you want the evm address for.
/// @return (mapped_address, true) if there is a mapping found otherwise (default_address, false)
function get_evm_address_or_default(
bytes32 accountId
) external view returns (address, bool);

/// Gets the account id associated with given evm address. If no mapping exists,
/// then return the default evm address.
/// @param evmAddress: The evm address for which you want the account id for.
/// @return (mapped_account, true) if there is a mapping found otherwise (default_account, false)
function get_native_address_or_default(
address evmAddress
) external view returns (bytes32, bool);
}
106 changes: 106 additions & 0 deletions precompiles/unified-accounts/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// 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/>.

#![cfg_attr(not(feature = "std"), no_std)]

use astar_primitives::evm::{UnifiedAddress, UnifiedAddressMapper};
use core::marker::PhantomData;
use fp_evm::Precompile;
use fp_evm::{PrecompileHandle, PrecompileOutput};
use frame_support::dispatch::Dispatchable;
use frame_support::traits::IsType;
use precompile_utils::{
succeed, Address, EvmDataWriter, EvmResult, FunctionModifier, PrecompileHandleExt,
};
use sp_core::{crypto::AccountId32, H256};
use sp_std::prelude::*;

#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;

#[precompile_utils::generate_function_selector]
#[derive(Debug, PartialEq)]
pub enum Action {
GetEvmAddressOrDefault = "get_evm_address_or_default(bytes32)",
GetNativeAddressOrDefault = "get_native_address_or_default(address)",
}

/// A precompile that expose AU related functions.
pub struct UnifiedAccountsPrecompile<T, UA>(PhantomData<(T, UA)>);

impl<R, UA> Precompile for UnifiedAccountsPrecompile<R, UA>
where
R: pallet_evm::Config + pallet_unified_accounts::Config,
<<R as frame_system::Config>::RuntimeCall as Dispatchable>::RuntimeOrigin:
From<Option<R::AccountId>>,
<R as frame_system::Config>::AccountId: IsType<AccountId32>,
UA: UnifiedAddressMapper<R::AccountId>,
{
fn execute(handle: &mut impl PrecompileHandle) -> EvmResult<PrecompileOutput> {
log::trace!(target: "au-precompile", "Execute input = {:?}", handle.input());

let selector = handle.read_selector()?;

handle.check_function_modifier(FunctionModifier::View)?;

match selector {
// Dispatchables
Action::GetEvmAddressOrDefault => Self::get_evm_address_or_default(handle),
Action::GetNativeAddressOrDefault => Self::get_native_address_or_default(handle),
}
}
}

impl<R, UA> UnifiedAccountsPrecompile<R, UA>
where
R: pallet_evm::Config + pallet_unified_accounts::Config,
<<R as frame_system::Config>::RuntimeCall as Dispatchable>::RuntimeOrigin:
From<Option<R::AccountId>>,
<R as frame_system::Config>::AccountId: IsType<AccountId32>,
UA: UnifiedAddressMapper<R::AccountId>,
{
fn get_evm_address_or_default(
handle: &mut impl PrecompileHandle,
) -> EvmResult<PrecompileOutput> {
let mut input = handle.read_input()?;
input.expect_arguments(1)?;
let account_id = AccountId32::new(input.read::<H256>()?.into()).into();

let output: (Address, bool) = match UA::to_h160_or_default(&account_id) {
UnifiedAddress::Mapped(address) => (address.into(), true),
UnifiedAddress::Default(address) => (address.into(), false),
};
Ok(succeed(EvmDataWriter::new().write(output).build()))
}

fn get_native_address_or_default(
handle: &mut impl PrecompileHandle,
) -> EvmResult<PrecompileOutput> {
let mut input = handle.read_input()?;
input.expect_arguments(1)?;
let evm_address = input.read::<Address>()?;

let output: (H256, bool) = match UA::to_account_id_or_default(&evm_address.into()) {
UnifiedAddress::Mapped(account_id) => (H256::from(account_id.into().as_ref()), true),
UnifiedAddress::Default(account_id) => (H256::from(account_id.into().as_ref()), false),
};
Ok(succeed(EvmDataWriter::new().write(output).build()))
}
}
Loading
Loading