From c26b369aa2f0db4fc2c9f12189a80e39a60c35db Mon Sep 17 00:00:00 2001 From: NZT48 Date: Mon, 21 Apr 2025 18:50:52 +0200 Subject: [PATCH 01/11] New clean start for staking precompiles implementation --- Cargo.lock | 27 + Cargo.toml | 18 +- precompiles/parachain-staking/Cargo.toml | 57 + .../parachain-staking/StakingInterface.sol | 305 ++++ precompiles/parachain-staking/src/lib.rs | 128 ++ runtime/Cargo.toml | 5 +- runtime/src/lib.rs | 1310 ++++++++--------- runtime/src/precompiles.rs | 66 +- 8 files changed, 1220 insertions(+), 696 deletions(-) create mode 100644 precompiles/parachain-staking/Cargo.toml create mode 100644 precompiles/parachain-staking/StakingInterface.sol create mode 100644 precompiles/parachain-staking/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index cd0c231..062bf28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6739,6 +6739,7 @@ dependencies = [ "pallet-evm-accounts", "pallet-evm-precompile-assets-erc20", "pallet-evm-precompile-modexp", + "pallet-evm-precompile-parachain-staking", "pallet-evm-precompile-sha3fips", "pallet-evm-precompile-simple", "pallet-identity", @@ -7778,6 +7779,32 @@ dependencies = [ "num", ] +[[package]] +name = "pallet-evm-precompile-parachain-staking" +version = "1.0.0" +dependencies = [ + "derive_more", + "fp-evm", + "frame-support 28.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.11.0)", + "frame-system 28.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.11.0)", + "log", + "num_enum 0.5.11", + "pallet-balances 28.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.11.0)", + "pallet-evm", + "pallet-parachain-staking", + "pallet-timestamp 27.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.11.0)", + "parity-scale-codec", + "precompile-utils", + "rustc-hex", + "scale-info", + "serde", + "sha3 0.10.8", + "sp-core 28.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.11.0)", + "sp-io 30.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.11.0)", + "sp-runtime 31.0.1 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.11.0)", + "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.11.0)", +] + [[package]] name = "pallet-evm-precompile-sha3fips" version = "2.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index f001abb..bf40ca4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,11 +2,7 @@ panic = "unwind" [workspace] -members = [ - "node", - "pallets/*", - "runtime", -] +members = ["node", "pallets/*", "runtime"] resolver = "2" @@ -31,11 +27,13 @@ jsonrpsee = { version = "0.22.5", features = ["server"] } libsecp256k1 = { version = "0.7", default-features = false, features = [ "hmac", "static-context", -]} +] } log = { version = "0.4.20", default-features = false } num_enum = { version = "0.5.3", default-features = false } sha3 = { version = "0.10.1", default-features = false } -scale-info = { version = "2.3.1", default-features = false, features = [ "derive" ] } +scale-info = { version = "2.3.1", default-features = false, features = [ + "derive", +] } similar-asserts = { version = "1.1.0" } slices = "0.2.0" smallvec = "1.10.0" @@ -144,7 +142,9 @@ fc-storage = { git = "https://github.com/polkadot-evm/frontier", branch = "polka fc-mapping-sync = { git = "https://github.com/polkadot-evm/frontier", branch = "polkadot-v1.11.0" } fp-evm = { git = "https://github.com/polkadot-evm/frontier", branch = "polkadot-v1.11.0", default-features = false } fp-rpc = { git = "https://github.com/polkadot-evm/frontier", default-features = false, branch = "polkadot-v1.11.0" } -fp-self-contained = { git = "https://github.com/polkadot-evm/frontier", default-features = false, branch = "polkadot-v1.11.0", features = ["serde"] } +fp-self-contained = { git = "https://github.com/polkadot-evm/frontier", default-features = false, branch = "polkadot-v1.11.0", features = [ + "serde", +] } # Cumulus cumulus-client-cli = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.11.0" } @@ -186,7 +186,7 @@ xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/par # Staking substrate-fixed = { git = "https://github.com/encointer/substrate-fixed", default-features = false } pallet-parachain-staking = { path = "pallets/parachain-staking", default-features = false } -#pallet-evm-precompile-parachain-staking = { path = "precompiles/parachain-staking", default-features = false } +pallet-evm-precompile-parachain-staking = { path = "precompiles/parachain-staking", default-features = false } # num-integer = { version = "0.1", default-features = false } # sp-consensus-slots = { git = "https://github.com/paritytech/polkadot-sdk", default-features = false, branch = "release-polkadot-v1.11.0" } diff --git a/precompiles/parachain-staking/Cargo.toml b/precompiles/parachain-staking/Cargo.toml new file mode 100644 index 0000000..58a0c99 --- /dev/null +++ b/precompiles/parachain-staking/Cargo.toml @@ -0,0 +1,57 @@ +[package] +name = "pallet-evm-precompile-parachain-staking" +authors = { workspace = true } +description = "A Precompile to make parachain staking accessible to pallet-evm" +edition = "2021" +version = "1.0.0" + +[dependencies] +log = { workspace = true } +num_enum = { workspace = true } +rustc-hex = { workspace = true } + +# Local +pallet-parachain-staking = { workspace = true } + +# Substrate +frame-support = { workspace = true } +frame-system = { workspace = true } +codec = { workspace = true, features = ["max-encoded-len"] } +# sp-consensus-slots = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-std = { workspace = true } +sp-runtime = { workspace = true } + +# Frontier +fp-evm = { workspace = true } +pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } +precompile-utils = { workspace = true } + +[dev-dependencies] +derive_more = { workspace = true } +serde = { workspace = true } +sha3 = { workspace = true } + +# Frontier +precompile-utils = { workspace = true, features = ["std", "testing"] } + +# Substrate +pallet-balances = { workspace = true, features = ["insecure_zero_ed", "std"] } +pallet-timestamp = { workspace = true, features = ["std"] } +scale-info = { workspace = true, features = ["derive", "std"] } +sp-runtime = { workspace = true, features = ["std"] } + +[features] +default = ["std"] +std = [ + "fp-evm/std", + "frame-support/std", + "frame-system/std", + "pallet-parachain-staking/std", + "codec/std", + "precompile-utils/std", + #"sp-consensus-slots/std", + "sp-core/std", + "sp-std/std", +] diff --git a/precompiles/parachain-staking/StakingInterface.sol b/precompiles/parachain-staking/StakingInterface.sol new file mode 100644 index 0000000..ec93905 --- /dev/null +++ b/precompiles/parachain-staking/StakingInterface.sol @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.8.3; + +/// @dev The ParachainStaking contract's address. +address constant PARACHAIN_STAKING_ADDRESS = 0x0000000000000000000000000000000000000800; + +/// @dev The ParachainStaking contract's instance. +ParachainStaking constant PARACHAIN_STAKING_CONTRACT = ParachainStaking( + PARACHAIN_STAKING_ADDRESS +); + +/// @author The Moonbeam Team +/// @title Pallet Parachain Staking Interface +/// @dev The interface through which solidity contracts will interact with Parachain Staking +/// We follow this same interface including four-byte function selectors, in the precompile that +/// wraps the pallet +/// @custom:address 0x0000000000000000000000000000000000000800 +interface ParachainStaking { + /// @dev Check whether the specified address is currently a staking delegator + /// @custom:selector fd8ab482 + /// @param delegator the address that we want to confirm is a delegator + /// @return A boolean confirming whether the address is a delegator + function isDelegator(address delegator) external view returns (bool); + + /// @dev Check whether the specified address is currently a collator candidate + /// @custom:selector d51b9e93 + /// @param candidate the address that we want to confirm is a collator andidate + /// @return A boolean confirming whether the address is a collator candidate + function isCandidate(address candidate) external view returns (bool); + + /// @dev Check whether the specifies address is currently a part of the active set + /// @custom:selector 740d7d2a + /// @param candidate the address that we want to confirm is a part of the active set + /// @return A boolean confirming whether the address is a part of the active set + function isSelectedCandidate( + address candidate + ) external view returns (bool); + + /// @dev Total points awarded to all collators in a particular round + /// @custom:selector 9799b4e7 + /// @param round the round for which we are querying the points total + /// @return The total points awarded to all collators in the round + function points(uint256 round) external view returns (uint256); + + /// @dev Total points awarded to a specific collator in a particular round. + /// A value of `0` may signify that no blocks were produced or that the storage for that round has been removed + /// @custom:selector bfea66ac + /// @param round the round for which we are querying the awarded points + /// @param candidate The candidate to whom the points are awarded + /// @return The total points awarded to the collator for the provided round + function awardedPoints( + uint32 round, + address candidate + ) external view returns (uint32); + + /// @dev The amount delegated in support of the candidate by the delegator + /// @custom:selector a73e51bc + /// @param delegator Who made this delegation + /// @param candidate The candidate for which the delegation is in support of + /// @return The amount of the delegation in support of the candidate by the delegator + function delegationAmount( + address delegator, + address candidate + ) external view returns (uint256); + + /// @dev Whether the delegation is in the top delegations + /// @custom:selector 91cc8657 + /// @param delegator Who made this delegation + /// @param candidate The candidate for which the delegation is in support of + /// @return If delegation is in top delegations (is counted) + function isInTopDelegations( + address delegator, + address candidate + ) external view returns (bool); + + /// @dev Get the minimum delegation amount + /// @custom:selector 02985992 + /// @return The minimum delegation amount + function minDelegation() external view returns (uint256); + + /// @dev Get the CandidateCount weight hint + /// @custom:selector a9a981a3 + /// @return The CandidateCount weight hint + function candidateCount() external view returns (uint256); + + /// @dev Get the current round number + /// @custom:selector 146ca531 + /// @return The current round number + function round() external view returns (uint256); + + /// @dev Get the CandidateDelegationCount weight hint + /// @custom:selector 2ec087eb + /// @param candidate The address for which we are querying the nomination count + /// @return The number of nominations backing the collator + function candidateDelegationCount( + address candidate + ) external view returns (uint32); + + /// @dev Get the CandidateAutoCompoundingDelegationCount weight hint + /// @custom:selector 905f0806 + /// @param candidate The address for which we are querying the auto compounding + /// delegation count + /// @return The number of auto compounding delegations + function candidateAutoCompoundingDelegationCount( + address candidate + ) external view returns (uint32); + + /// @dev Get the DelegatorDelegationCount weight hint + /// @custom:selector 067ec822 + /// @param delegator The address for which we are querying the delegation count + /// @return The number of delegations made by the delegator + function delegatorDelegationCount( + address delegator + ) external view returns (uint256); + + /// @dev Get the selected candidates for the current round + /// @custom:selector bcf868a6 + /// @return The selected candidate accounts + function selectedCandidates() external view returns (address[] memory); + + /// @dev Whether there exists a pending request for a delegation made by a delegator + /// @custom:selector 3b16def8 + /// @param delegator the delegator that made the delegation + /// @param candidate the candidate for which the delegation was made + /// @return Whether a pending request exists for such delegation + function delegationRequestIsPending( + address delegator, + address candidate + ) external view returns (bool); + + /// @dev Whether there exists a pending exit for candidate + /// @custom:selector 43443682 + /// @param candidate the candidate for which the exit request was made + /// @return Whether a pending request exists for such delegation + function candidateExitIsPending( + address candidate + ) external view returns (bool); + + /// @dev Whether there exists a pending bond less request made by a candidate + /// @custom:selector d0deec11 + /// @param candidate the candidate which made the request + /// @return Whether a pending bond less request was made by the candidate + function candidateRequestIsPending( + address candidate + ) external view returns (bool); + + /// @dev Returns the percent value of auto-compound set for a delegation + /// @custom:selector b4d4c7fd + /// @param delegator the delegator that made the delegation + /// @param candidate the candidate for which the delegation was made + /// @return Percent of rewarded amount that is auto-compounded on each payout + function delegationAutoCompound( + address delegator, + address candidate + ) external view returns (uint8); + + /// @dev Join the set of collator candidates + /// @custom:selector 1f2f83ad + /// @param amount The amount self-bonded by the caller to become a collator candidate + /// @param candidateCount The number of candidates in the CandidatePool + function joinCandidates(uint256 amount, uint256 candidateCount) external; + + /// @dev Request to leave the set of collator candidates + /// @custom:selector b1a3c1b7 + /// @param candidateCount The number of candidates in the CandidatePool + function scheduleLeaveCandidates(uint256 candidateCount) external; + + /// @dev Execute due request to leave the set of collator candidates + /// @custom:selector 3867f308 + /// @param candidate The candidate address for which the pending exit request will be executed + /// @param candidateDelegationCount The number of delegations for the candidate to be revoked + function executeLeaveCandidates( + address candidate, + uint256 candidateDelegationCount + ) external; + + /// @dev Cancel request to leave the set of collator candidates + /// @custom:selector 9c76ebb4 + /// @param candidateCount The number of candidates in the CandidatePool + function cancelLeaveCandidates(uint256 candidateCount) external; + + /// @dev Temporarily leave the set of collator candidates without unbonding + /// @custom:selector a6485ccd + function goOffline() external; + + /// @dev Rejoin the set of collator candidates if previously had called `goOffline` + /// @custom:selector 6e5b676b + function goOnline() external; + + /// @dev Request to bond more for collator candidates + /// @custom:selector a52c8643 + /// @param more The additional amount self-bonded + function candidateBondMore(uint256 more) external; + + /// @dev Request to bond less for collator candidates + /// @custom:selector 60744ae0 + /// @param less The amount to be subtracted from self-bond and unreserved + function scheduleCandidateBondLess(uint256 less) external; + + /// @dev Execute pending candidate bond request + /// @custom:selector 2e290290 + /// @param candidate The address for the candidate for which the request will be executed + function executeCandidateBondLess(address candidate) external; + + /// @dev Cancel pending candidate bond request + /// @custom:selector b5ad5f07 + function cancelCandidateBondLess() external; + + /// @notice DEPRECATED use delegateWithAutoCompound instead for lower weight and better UX + /// @dev Make a delegation in support of a collator candidate + /// @custom:selector 829f5ee3 + /// @param candidate The address of the supported collator candidate + /// @param amount The amount bonded in support of the collator candidate + /// @param candidateDelegationCount The number of delegations in support of the candidate + /// @param delegatorDelegationCount The number of existing delegations by the caller + function delegate( + address candidate, + uint256 amount, + uint256 candidateDelegationCount, + uint256 delegatorDelegationCount + ) external; + + /// @dev Make a delegation in support of a collator candidate + /// @custom:selector 4b8bc9bf + /// @param candidate The address of the supported collator candidate + /// @param amount The amount bonded in support of the collator candidate + /// @param autoCompound The percent of reward that should be auto-compounded + /// @param candidateDelegationCount The number of delegations in support of the candidate + /// @param candidateAutoCompoundingDelegationCount The number of auto-compounding delegations + /// in support of the candidate + /// @param delegatorDelegationCount The number of existing delegations by the caller + function delegateWithAutoCompound( + address candidate, + uint256 amount, + uint8 autoCompound, + uint256 candidateDelegationCount, + uint256 candidateAutoCompoundingDelegationCount, + uint256 delegatorDelegationCount + ) external; + + /// @dev Request to revoke an existing delegation + /// @custom:selector 1a1c740c + /// @param candidate The address of the collator candidate which will no longer be supported + function scheduleRevokeDelegation(address candidate) external; + + /// @dev Bond more for delegators with respect to a specific collator candidate + /// @custom:selector 0465135b + /// @param candidate The address of the collator candidate for which delegation shall increase + /// @param more The amount by which the delegation is increased + function delegatorBondMore(address candidate, uint256 more) external; + + /// @dev Request to bond less for delegators with respect to a specific collator candidate + /// @custom:selector c172fd2b + /// @param candidate The address of the collator candidate for which delegation shall decrease + /// @param less The amount by which the delegation is decreased (upon execution) + function scheduleDelegatorBondLess( + address candidate, + uint256 less + ) external; + + /// @dev Execute pending delegation request (if exists && is due) + /// @custom:selector e98c8abe + /// @param delegator The address of the delegator + /// @param candidate The address of the candidate + function executeDelegationRequest( + address delegator, + address candidate + ) external; + + /// @dev Cancel pending delegation request (already made in support of input by caller) + /// @custom:selector c90eee83 + /// @param candidate The address of the candidate + function cancelDelegationRequest(address candidate) external; + + /// @dev Sets an auto-compound value for a delegation + /// @custom:selector faa1786f + /// @param candidate The address of the supported collator candidate + /// @param value The percent of reward that should be auto-compounded + /// @param candidateAutoCompoundingDelegationCount The number of auto-compounding delegations + /// in support of the candidate + /// @param delegatorDelegationCount The number of existing delegations by the caller + function setAutoCompound( + address candidate, + uint8 value, + uint256 candidateAutoCompoundingDelegationCount, + uint256 delegatorDelegationCount + ) external; + + /// @dev Fetch the total staked amount of a delegator, regardless of the + /// candidate. + /// @custom:selector e6861713 + /// @param delegator Address of the delegator. + /// @return Total amount of stake. + function getDelegatorTotalStaked( + address delegator + ) external view returns (uint256); + + /// @dev Fetch the total staked towards a candidate. + /// @custom:selector bc5a1043 + /// @param candidate Address of the candidate. + /// @return Total amount of stake. + function getCandidateTotalCounted( + address candidate + ) external view returns (uint256); +} diff --git a/precompiles/parachain-staking/src/lib.rs b/precompiles/parachain-staking/src/lib.rs new file mode 100644 index 0000000..f2155a1 --- /dev/null +++ b/precompiles/parachain-staking/src/lib.rs @@ -0,0 +1,128 @@ +// Copyright 2019-2022 PureStake Inc. +// Copyright 2022 Stake Technologies +// Copyright 2022 TraceLabs +// This file is part of AssetsERC20 package, originally developed by Purestake Inc. +// AssetsERC20 package used in NeuroWeb Parachain 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. + +// 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 AssetsERC20. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(test, feature(assert_matches))] + +use fp_evm::{IsPrecompileResult, PrecompileHandle, PrecompileOutput}; +use frame_support::traits::fungibles::approvals::Inspect as ApprovalInspect; +use frame_support::traits::fungibles::metadata::Inspect as MetadataInspect; +use frame_support::traits::fungibles::Inspect; +use frame_support::traits::OriginTrait; +use frame_support::{ + dispatch::{GetDispatchInfo, PostDispatchInfo}, + sp_runtime::traits::StaticLookup, +}; +use pallet_evm::{AddressMapping, PrecompileSet}; +use precompile_utils::{ + keccak256, revert, succeed, Address, Bytes, EvmData, EvmDataWriter, EvmResult, + FunctionModifier, LogExt, LogsBuilder, PrecompileHandleExt, RuntimeHelper, +}; +use sp_runtime::traits::{Bounded, Dispatchable, Zero}; + +use sp_core::{Get, H160, U256}; +use sp_std::{ + convert::{TryFrom, TryInto}, + marker::PhantomData, +}; + +pub type BalanceOf = ::Balance; + +#[precompile_utils::generate_function_selector] +#[derive(Debug, PartialEq)] +pub enum Action { + MinDelegation = "min_delegation()", + Round = "round()", +} +pub struct ParachainStakingPrecompileSet(PhantomData); + +impl ParachainStakingPrecompileSet { + pub fn new() -> Self { + Self(PhantomData) + } +} + +impl PrecompileSet for ParachainStakingPrecompileSet +where + Runtime: pallet_parachain_staking::Config + pallet_evm::Config + frame_system::Config, + Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, + ::RuntimeOrigin: From>, + BalanceOf: TryFrom + Into + EvmData, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: OriginTrait, +{ + fn execute(&self, handle: &mut impl PrecompileHandle) -> Option> { + let selector = match handle.read_selector() { + Ok(selector) => selector, + Err(e) => return Some(Err(e)), + }; + + if let Err(err) = handle.check_function_modifier(match selector { + Action::MinDelegation | Action::Round => FunctionModifier::NonPayable, + _ => FunctionModifier::View, + }) { + return Some(Err(err)); + } + + let result = match selector { + Action::MinDelegation => Self::min_delegation(handle), + Action::Round => Self::round(handle), + }; + + return Some(result); + } + + fn is_precompile(&self, _address: H160, _gas: u64) -> IsPrecompileResult { + IsPrecompileResult::Answer { + is_precompile: true, + extra_cost: 0, + } + } +} + +impl ParachainStakingPrecompileSet +where + Runtime: pallet_parachain_staking::Config + pallet_evm::Config + frame_system::Config, + Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, + ::RuntimeOrigin: From>, + BalanceOf: TryFrom + Into + EvmData, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: OriginTrait, +{ + fn min_delegation(handle: &mut impl PrecompileHandle) -> EvmResult { + // Fetch info. + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + let min_nomination: u128 = + <::MinDelegation as Get< + BalanceOf, + >>::get() + .try_into() + .map_err(|_| revert("Amount is too large for provided balance type"))?; + + // Build output. + Ok(succeed(EvmDataWriter::new().write(min_nomination).build())) + } + + fn round(handle: &mut impl PrecompileHandle) -> EvmResult { + // Fetch info. + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + let round: u32 = >::round().current; + + // Build output. + Ok(succeed(EvmDataWriter::new().write(round).build())) + } +} diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index a280edc..dc5ef60 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -68,7 +68,9 @@ xcm-executor = { workspace = true } # Cumulus cumulus-pallet-aura-ext = { workspace = true } cumulus-pallet-dmp-queue = { workspace = true } -cumulus-pallet-parachain-system = { workspace = true, features = ["parameterized-consensus-hook"] } +cumulus-pallet-parachain-system = { workspace = true, features = [ + "parameterized-consensus-hook", +] } cumulus-pallet-xcm = { workspace = true } cumulus-pallet-xcmp-queue = { workspace = true } cumulus-primitives-aura = { workspace = true } @@ -88,6 +90,7 @@ pallet-evm-precompile-assets-erc20 = { workspace = true } pallet-evm-precompile-simple = { workspace = true } pallet-evm-precompile-modexp = { workspace = true } pallet-evm-precompile-sha3fips = { workspace = true } +pallet-evm-precompile-parachain-staking = { workspace = true } pallet-ethereum = { workspace = true } fp-rpc = { workspace = true } fp-self-contained = { workspace = true } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index f0202ea..138d70c 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -14,42 +14,40 @@ use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use smallvec::smallvec; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H160, H256, U256}; +use sp_runtime::Percent; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, DispatchResult, + create_runtime_str, generic, impl_opaque_keys, traits::{ - AccountIdConversion, IdentityLookup, BlakeTwo256, Block as BlockT, - ConvertInto, DispatchInfoOf, Dispatchable, IdentifyAccount, - PostDispatchInfoOf, UniqueSaturatedInto, Verify, - }, - transaction_validity::{ - TransactionSource, TransactionValidity, TransactionValidityError + AccountIdConversion, BlakeTwo256, Block as BlockT, ConvertInto, DispatchInfoOf, + Dispatchable, IdentifyAccount, IdentityLookup, PostDispatchInfoOf, UniqueSaturatedInto, + Verify, }, - ApplyExtrinsicResult, MultiSignature, RuntimeDebug, + transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, + ApplyExtrinsicResult, DispatchResult, MultiSignature, RuntimeDebug, }; -use sp_runtime::Percent; use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use codec::{Encode, Decode, MaxEncodedLen}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - ord_parameter_types, - construct_runtime, parameter_types, transactional, + construct_runtime, + dispatch::DispatchClass, genesis_builder_helper::{build_state, get_preset}, + ord_parameter_types, parameter_types, traits::{ - tokens::{PayFromAccount, UnityAssetBalanceConversion}, fungible::{Balanced, Credit, HoldConsideration, Inspect}, - AsEnsureOriginWithArg, Currency as PalletCurrency, EqualPrivilegeOnly, EitherOfDiverse, - Everything, FindAuthor, ReservableCurrency, Imbalance, InstanceFilter, OnUnbalanced, ConstBool, - ConstU128, ConstU32, ConstU64, ConstU8, WithdrawReasons, OnFinalize, LinearStoragePrice, - ExistenceRequirement, TransformOrigin + tokens::{PayFromAccount, UnityAssetBalanceConversion}, + AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, + Currency as PalletCurrency, EitherOfDiverse, EqualPrivilegeOnly, Everything, + ExistenceRequirement, FindAuthor, Imbalance, InstanceFilter, LinearStoragePrice, + OnFinalize, OnUnbalanced, ReservableCurrency, TransformOrigin, WithdrawReasons, }, - dispatch::DispatchClass, + transactional, weights::{ - constants::WEIGHT_REF_TIME_PER_SECOND, - ConstantMultiplier, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, - WeightToFeePolynomial, + constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, Weight, WeightToFeeCoefficient, + WeightToFeeCoefficients, WeightToFeePolynomial, }, ConsensusEngineId, PalletId, }; @@ -66,22 +64,24 @@ use xcm_config::XcmOriginToTransactDispatchOrigin; pub use sp_runtime::BuildStorage; // Polkadot Imports -use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +pub use pallet_parachain_staking; use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; -pub use pallet_parachain_staking; +use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; // XCM Imports use xcm::latest::prelude::BodyId; // Frontier +use fp_rpc::TransactionStatus; +use pallet_ethereum::{ + Call::transact, EthereumBlockHashMapping, PostLogContent, Transaction as EthereumTransaction, +}; use pallet_evm::{ - EnsureAddressRoot, EnsureAddressNever, Account as EVMAccount, EVMFungibleAdapter, - FeeCalculator, OnChargeEVMTransaction as OnChargeEVMTransactionT, Runner + Account as EVMAccount, EVMFungibleAdapter, EnsureAddressNever, EnsureAddressRoot, + FeeCalculator, OnChargeEVMTransaction as OnChargeEVMTransactionT, Runner, }; -use pallet_ethereum::{Call::transact, PostLogContent, EthereumBlockHashMapping, Transaction as EthereumTransaction}; -use fp_rpc::TransactionStatus; use pallet_evm_accounts::{EvmAddressMapping, MergeAccount}; use pallet_evm_precompile_assets_erc20::AddressToAssetId; use pallet_identity::legacy::IdentityInfo; @@ -196,8 +196,8 @@ const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); /// We allow for 2 seconds of compute with a 6 second average block. const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( - WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), - cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64, + WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), + cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64, ); pub const fn deposit(items: u32, bytes: u32) -> Balance { @@ -330,7 +330,7 @@ parameter_types! { } impl pallet_balances::Config for Runtime { - type MaxLocks = ConstU32<50>; + type MaxLocks = ConstU32<50>; /// The type for recording an account's balance. type Balance = Balance; /// The ubiquitous event type. @@ -343,13 +343,12 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = RuntimeHoldReason; type RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = (); - type MaxFreezes = ConstU32<1>; + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<1>; } pub struct CollatorsIncentivesPot; -impl OnUnbalanced> for CollatorsIncentivesPot -{ +impl OnUnbalanced> for CollatorsIncentivesPot { fn on_nonzero_unbalanced(amount: Credit) { let staking_pot = CollatorsIncentivesPalletId::get().into_account_truncating(); let _ = Balances::resolve(&staking_pot, amount); @@ -357,17 +356,15 @@ impl OnUnbalanced> for CollatorsIncentivesPot } pub struct FutureAuctionsPot; -impl OnUnbalanced> for FutureAuctionsPot -{ +impl OnUnbalanced> for FutureAuctionsPot { fn on_nonzero_unbalanced(amount: Credit) { let future_auctions_pot = FutureAuctionsPalletId::get().into_account_truncating(); - let _ = Balances::resolve(&future_auctions_pot, amount); - } + let _ = Balances::resolve(&future_auctions_pot, amount); + } } pub struct DkgIncentivesPot; -impl OnUnbalanced> for DkgIncentivesPot -{ +impl OnUnbalanced> for DkgIncentivesPot { fn on_nonzero_unbalanced(amount: Credit) { let dkg_incentives_pot = DkgIncentivesPalletId::get().into_account_truncating(); let _ = Balances::resolve(&dkg_incentives_pot, amount); @@ -375,18 +372,15 @@ impl OnUnbalanced> for DkgIncentivesPot } pub struct TreasuryPot; -impl OnUnbalanced> for TreasuryPot -{ +impl OnUnbalanced> for TreasuryPot { fn on_nonzero_unbalanced(amount: Credit) { let treasury_port = TreasuryPalletId::get().into_account_truncating(); let _ = Balances::resolve(&treasury_port, amount); } } - pub struct DealWithFees; -impl OnUnbalanced> for DealWithFees -{ +impl OnUnbalanced> for DealWithFees { // this is called for substrate-based transactions fn on_unbalanceds(mut fees_then_tips: impl Iterator>) { if let Some(mut fees) = fees_then_tips.next() { @@ -416,7 +410,6 @@ impl OnUnbalanced> for DealWithFees let (dkg_incentives_fees, collators_incentives_fees) = split.0.ration(50, 50); let (future_auctions_fees, treasury_fees) = split.1.ration(75, 25); - >::on_unbalanced(treasury_fees); >::on_unbalanced(collators_incentives_fees); >::on_unbalanced(future_auctions_fees); @@ -464,7 +457,6 @@ type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< UNINCLUDED_SEGMENT_CAPACITY, >; - impl parachain_info::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {} @@ -488,12 +480,12 @@ impl cumulus_pallet_dmp_queue::Config for Runtime { } parameter_types! { - /// The amount of weight (if any) which should be provided to the message queue for - /// servicing enqueued items. - /// - /// This may be legitimately `None` in the case that you will call - /// `ServiceQueues::service_queues` manually. - pub MessageQueueServiceWeight: Weight = + /// The amount of weight (if any) which should be provided to the message queue for + /// servicing enqueued items. + /// + /// This may be legitimately `None` in the case that you will call + /// `ServiceQueues::service_queues` manually. + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block; /// The maximum number of stale pages (i.e. of overweight messages) allowed before culling /// can happen. Once there are more stale pages than this, then historical pages may be @@ -603,7 +595,7 @@ impl pallet_scheduler::Config for Runtime { parameter_types! { pub const MinVestedTransfer: Balance = 15 * OTP; pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = - WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); + WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); } impl pallet_vesting::Config for Runtime { @@ -647,99 +639,104 @@ impl pallet_treasury::Config for Runtime { type SpendOrigin = frame_support::traits::NeverEnsureOrigin; type AssetKind = (); - type Beneficiary = AccountId; - type BeneficiaryLookup = IdentityLookup; - type Paymaster = PayFromAccount; - type BalanceConverter = UnityAssetBalanceConversion; - type PayoutPeriod = ConstU32<0>; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = BenchmarkHelper; + type Beneficiary = AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU32<0>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = BenchmarkHelper; } pub struct MergeAccountEvm; impl MergeAccount for MergeAccountEvm { -#[transactional] -fn merge_account(source: &AccountId, dest: &AccountId) -> DispatchResult { - // unreserve all reserved currency - >::unreserve(source, Balances::reserved_balance(source)); - - // transfer all free to dest - match Balances::transfer(&source, &dest, Balances::free_balance(source), ExistenceRequirement::AllowDeath,) { - Ok(_) => Ok(()), - Err(e) => Err(e), - } - } + #[transactional] + fn merge_account(source: &AccountId, dest: &AccountId) -> DispatchResult { + // unreserve all reserved currency + >::unreserve(source, Balances::reserved_balance(source)); + + // transfer all free to dest + match Balances::transfer( + &source, + &dest, + Balances::free_balance(source), + ExistenceRequirement::AllowDeath, + ) { + Ok(_) => Ok(()), + Err(e) => Err(e), + } + } } impl pallet_evm_accounts::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; type ChainId = ChainId; - type AddressMapping = EvmAddressMapping; - type MergeAccount = MergeAccountEvm; - type WeightInfo = weights::evm_accounts_weights::WeightInfo; + type AddressMapping = EvmAddressMapping; + type MergeAccount = MergeAccountEvm; + type WeightInfo = weights::evm_accounts_weights::WeightInfo; } parameter_types! { - pub DefaultBaseFeePerGas: U256 = U256::from(16); + pub DefaultBaseFeePerGas: U256 = U256::from(16); pub DefaultElasticity: Permill = Permill::from_parts(125_000); } pub struct BaseFeeThreshold; impl pallet_base_fee::BaseFeeThreshold for BaseFeeThreshold { - fn lower() -> Permill { - Permill::zero() - } - fn ideal() -> Permill { - Permill::from_parts(500_000) - } - fn upper() -> Permill { - Permill::from_parts(1_000_000) - } + fn lower() -> Permill { + Permill::zero() + } + fn ideal() -> Permill { + Permill::from_parts(500_000) + } + fn upper() -> Permill { + Permill::from_parts(1_000_000) + } } impl pallet_base_fee::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Threshold = BaseFeeThreshold; - type DefaultBaseFeePerGas = DefaultBaseFeePerGas; - type DefaultElasticity = DefaultElasticity; + type RuntimeEvent = RuntimeEvent; + type Threshold = BaseFeeThreshold; + type DefaultBaseFeePerGas = DefaultBaseFeePerGas; + type DefaultElasticity = DefaultElasticity; } type FungibleAccountId = ::AccountId; -type BalanceFor = +type BalanceFor = <::Currency as Inspect>>::Balance; pub struct OnChargeEVMTransaction(sp_std::marker::PhantomData); impl OnChargeEVMTransactionT for OnChargeEVMTransaction where - T: pallet_evm::Config, - T::Currency: Balanced, + T: pallet_evm::Config, + T::Currency: Balanced, OU: OnUnbalanced>, - U256: UniqueSaturatedInto> + U256: UniqueSaturatedInto>, { - type LiquidityInfo = Option>; - - fn withdraw_fee(who: &H160, fee: U256) -> Result> { - EVMFungibleAdapter::<::Currency, ()>::withdraw_fee(who, fee) - } - - fn correct_and_deposit_fee( - who: &H160, - corrected_fee: U256, - base_fee: U256, - already_withdrawn: Self::LiquidityInfo, - ) -> Self::LiquidityInfo { + type LiquidityInfo = Option>; + + fn withdraw_fee(who: &H160, fee: U256) -> Result> { + EVMFungibleAdapter::<::Currency, ()>::withdraw_fee(who, fee) + } + + fn correct_and_deposit_fee( + who: &H160, + corrected_fee: U256, + base_fee: U256, + already_withdrawn: Self::LiquidityInfo, + ) -> Self::LiquidityInfo { ::Currency, OU> as OnChargeEVMTransactionT< T, - >>::correct_and_deposit_fee(who, corrected_fee, base_fee, already_withdrawn) - } + >>::correct_and_deposit_fee(who, corrected_fee, base_fee, already_withdrawn) + } - fn pay_priority_fee(tip: Self::LiquidityInfo) { - if let Some(tip) = tip { - OU::on_unbalanced(tip); - } - } + fn pay_priority_fee(tip: Self::LiquidityInfo) { + if let Some(tip) = tip { + OU::on_unbalanced(tip); + } + } } /// Current approximation of the gas/s consumption considering @@ -759,7 +756,8 @@ impl> FindAuthor for FindAuthorTruncated { I: 'a + IntoIterator, { if let Some(author_index) = F::find_author(digests) { - let authority_id = pallet_aura::Authorities::::get()[author_index as usize].clone(); + let authority_id = + pallet_aura::Authorities::::get()[author_index as usize].clone(); return Some(H160::from_slice(&authority_id.encode()[4..24])); } @@ -773,34 +771,34 @@ parameter_types! { pub PrecompilesValue: FrontierPrecompiles = FrontierPrecompiles::<_>::new(); pub WeightPerGas: Weight = Weight::from_parts(WEIGHT_PER_GAS, 0); /// The amount of gas per pov. A ratio of 4 if we convert ref_time to gas and we compare - /// it with the pov_size for a block. E.g. - /// ceil( - /// (max_extrinsic.ref_time() / max_extrinsic.proof_size()) / WEIGHT_PER_GAS - /// ) - pub const GasLimitPovSizeRatio: u64 = 4; + /// it with the pov_size for a block. E.g. + /// ceil( + /// (max_extrinsic.ref_time() / max_extrinsic.proof_size()) / WEIGHT_PER_GAS + /// ) + pub const GasLimitPovSizeRatio: u64 = 4; } impl pallet_evm::Config for Runtime { - type Currency = Balances; - type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; - type BlockGasLimit = BlockGasLimit; - type ChainId = ChainId; - type BlockHashMapping = EthereumBlockHashMapping; - type Runner = pallet_evm::runner::stack::Runner; + type BlockGasLimit = BlockGasLimit; + type ChainId = ChainId; + type BlockHashMapping = EthereumBlockHashMapping; + type Runner = pallet_evm::runner::stack::Runner; type CallOrigin = EnsureAddressRoot; - type WithdrawOrigin = EnsureAddressNever; - type AddressMapping = EvmAddressMapping; + type WithdrawOrigin = EnsureAddressNever; + type AddressMapping = EvmAddressMapping; - type FeeCalculator = BaseFee; - type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type FeeCalculator = BaseFee; + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; type WeightPerGas = WeightPerGas; - type OnChargeTransaction = OnChargeEVMTransaction; + type OnChargeTransaction = OnChargeEVMTransaction; type OnCreate = (); - type FindAuthor = FindAuthorTruncated; - type PrecompilesType = FrontierPrecompiles; - type PrecompilesValue = PrecompilesValue; + type FindAuthor = FindAuthorTruncated; + type PrecompilesType = FrontierPrecompiles; + type PrecompilesValue = PrecompilesValue; type GasLimitPovSizeRatio = GasLimitPovSizeRatio; type SuicideQuickClearLimit = ConstU32<0>; type Timestamp = Timestamp; @@ -808,12 +806,12 @@ impl pallet_evm::Config for Runtime { } parameter_types! { - pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; } impl pallet_ethereum::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type StateRoot = pallet_ethereum::IntermediateStateRoot; + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; type PostLogContent = PostBlockAndTxnHashes; type ExtraDataLength = ConstU32<30>; } @@ -848,31 +846,31 @@ impl AddressToAssetId for Runtime { } parameter_types! { - pub const AssetDeposit: Balance = 100 * OTP; - pub const ApprovalDeposit: Balance = 0; - pub const StringLimit: u32 = 50; - pub const MetadataDepositBase: Balance = 10 * OTP; - pub const MetadataDepositPerByte: Balance = 1 * OTP; + pub const AssetDeposit: Balance = 100 * OTP; + pub const ApprovalDeposit: Balance = 0; + pub const StringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = 10 * OTP; + pub const MetadataDepositPerByte: Balance = 1 * OTP; } impl pallet_assets::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Balance = u128; - type AssetId = AssetId; + type RuntimeEvent = RuntimeEvent; + type Balance = u128; + type AssetId = AssetId; type AssetIdParameter = codec::Compact; - type Currency = Balances; + type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; - type ForceOrigin = EnsureRoot; - type AssetDeposit = AssetDeposit; - type AssetAccountDeposit = ConstU128; - type MetadataDepositBase = MetadataDepositBase; - type MetadataDepositPerByte = MetadataDepositPerByte; - type ApprovalDeposit = ApprovalDeposit; - type StringLimit = StringLimit; - type Freezer = (); - type Extra = (); + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type AssetAccountDeposit = ConstU128; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = StringLimit; + type Freezer = (); + type Extra = (); type CallbackHandle = (); - type WeightInfo = pallet_assets::weights::SubstrateWeight; + type WeightInfo = pallet_assets::weights::SubstrateWeight; type RemoveItemsLimit = ConstU32<656>; } @@ -898,290 +896,286 @@ impl pallet_xc_asset_config::Config for Runtime { } parameter_types! { - pub const PreimageMaxSize: u32 = 4096 * 1024; - pub const PreimageBaseDeposit: Balance = deposit(2, 64); - pub const PreimageByteDeposit: Balance = 1 * MILLIOTP; + pub const PreimageMaxSize: u32 = 4096 * 1024; + pub const PreimageBaseDeposit: Balance = deposit(2, 64); + pub const PreimageByteDeposit: Balance = 1 * MILLIOTP; pub const PreimageHoldReason: RuntimeHoldReason = - RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); + RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); } impl pallet_preimage::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type ManagerOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; type WeightInfo = pallet_preimage::weights::SubstrateWeight; type Consideration = HoldConsideration< - AccountId, - Balances, - PreimageHoldReason, - LinearStoragePrice, - >; + AccountId, + Balances, + PreimageHoldReason, + LinearStoragePrice, + >; } impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = pallet_utility::weights::SubstrateWeight; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = pallet_utility::weights::SubstrateWeight; } parameter_types! { - pub const CouncilMotionDuration: BlockNumber = 3 * DAYS; - pub const CouncilMaxProposals: u32 = 100; - pub const CouncilMaxMembers: u32 = 5; + pub const CouncilMotionDuration: BlockNumber = 3 * DAYS; + pub const CouncilMaxProposals: u32 = 100; + pub const CouncilMaxMembers: u32 = 5; pub MaxCollectivesProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block; } type CouncilCollective = pallet_collective::Instance1; impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type Proposal = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type MotionDuration = CouncilMotionDuration; - type MaxProposals = CouncilMaxProposals; - type MaxMembers = CouncilMaxMembers; - type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type MotionDuration = CouncilMotionDuration; + type MaxProposals = CouncilMaxProposals; + type MaxMembers = CouncilMaxMembers; + type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; type SetMembersOrigin = EnsureRoot; type WeightInfo = pallet_collective::weights::SubstrateWeight; type MaxProposalWeight = MaxCollectivesProposalWeight; } parameter_types! { - pub const LaunchPeriod: BlockNumber = 5 * DAYS; - pub const VotingPeriod: BlockNumber = 5 * DAYS; + pub const LaunchPeriod: BlockNumber = 5 * DAYS; + pub const VotingPeriod: BlockNumber = 5 * DAYS; pub const VotingLockingPeriod: BlockNumber = 1 * DAYS; - pub const FastTrackVotingPeriod: BlockNumber = 3 * HOURS; - pub const MinimumDeposit: Balance = 1000 * OTP; - pub const EnactmentPeriod: BlockNumber = 2 * DAYS; - pub const CooloffPeriod: BlockNumber = 7 * DAYS; - pub const MaxProposals: u32 = 100; + pub const FastTrackVotingPeriod: BlockNumber = 3 * HOURS; + pub const MinimumDeposit: Balance = 1000 * OTP; + pub const EnactmentPeriod: BlockNumber = 2 * DAYS; + pub const CooloffPeriod: BlockNumber = 7 * DAYS; + pub const MaxProposals: u32 = 100; } type EnsureRootOrTwoFiftsOfCouncil = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, >; type EnsureRootOrThreeFiftsOfCouncil = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, >; type EnsureRootOrFourFiftsOfCouncil = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, >; impl pallet_democracy::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type EnactmentPeriod = EnactmentPeriod; - type LaunchPeriod = LaunchPeriod; - type VotingPeriod = VotingPeriod; - type VoteLockingPeriod = VotingLockingPeriod; // Same as EnactmentPeriod - type MinimumDeposit = MinimumDeposit; - /// A straight majority of the council can decide what their next motion is. - type ExternalOrigin = EnsureRootOrTwoFiftsOfCouncil; - /// A super-majority can have the next scheduled referendum be a straight majority-carries vote. - type ExternalMajorityOrigin = EnsureRootOrThreeFiftsOfCouncil; - /// A unanimous council can have the next scheduled referendum be a straight default-carries - /// (NTB) vote. - type ExternalDefaultOrigin = EnsureRootOrThreeFiftsOfCouncil; - type SubmitOrigin = EnsureSigned; - /// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote - /// be tabled immediately and with a shorter voting/enactment period. - type FastTrackOrigin = EnsureRootOrThreeFiftsOfCouncil; - type InstantOrigin = EnsureRootOrFourFiftsOfCouncil; - type InstantAllowed = frame_support::traits::ConstBool; - type FastTrackVotingPeriod = FastTrackVotingPeriod; - // To cancel a proposal which has been passed, 3/5 of the council must agree to it. - type CancellationOrigin = EnsureRootOrThreeFiftsOfCouncil; - // To cancel a proposal before it has been passed, the technical committee must be unanimous or - // Root must agree. - type CancelProposalOrigin = EnsureRootOrThreeFiftsOfCouncil; - type BlacklistOrigin = EnsureRoot; - // Any single technical committee member may veto a coming council proposal, however they can - // only do it once and it lasts only for the cool-off period. - type VetoOrigin = pallet_collective::EnsureMember; - type CooloffPeriod = CooloffPeriod; - type Slash = Treasury; - type Scheduler = Scheduler; - type PalletsOrigin = OriginCaller; - type MaxVotes = ConstU32<100>; - type MaxProposals = MaxProposals; - type Preimages = Preimage; - type MaxDeposits = ConstU32<100>; - type MaxBlacklisted = ConstU32<100>; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type EnactmentPeriod = EnactmentPeriod; + type LaunchPeriod = LaunchPeriod; + type VotingPeriod = VotingPeriod; + type VoteLockingPeriod = VotingLockingPeriod; // Same as EnactmentPeriod + type MinimumDeposit = MinimumDeposit; + /// A straight majority of the council can decide what their next motion is. + type ExternalOrigin = EnsureRootOrTwoFiftsOfCouncil; + /// A super-majority can have the next scheduled referendum be a straight majority-carries vote. + type ExternalMajorityOrigin = EnsureRootOrThreeFiftsOfCouncil; + /// A unanimous council can have the next scheduled referendum be a straight default-carries + /// (NTB) vote. + type ExternalDefaultOrigin = EnsureRootOrThreeFiftsOfCouncil; + type SubmitOrigin = EnsureSigned; + /// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote + /// be tabled immediately and with a shorter voting/enactment period. + type FastTrackOrigin = EnsureRootOrThreeFiftsOfCouncil; + type InstantOrigin = EnsureRootOrFourFiftsOfCouncil; + type InstantAllowed = frame_support::traits::ConstBool; + type FastTrackVotingPeriod = FastTrackVotingPeriod; + // To cancel a proposal which has been passed, 3/5 of the council must agree to it. + type CancellationOrigin = EnsureRootOrThreeFiftsOfCouncil; + // To cancel a proposal before it has been passed, the technical committee must be unanimous or + // Root must agree. + type CancelProposalOrigin = EnsureRootOrThreeFiftsOfCouncil; + type BlacklistOrigin = EnsureRoot; + // Any single technical committee member may veto a coming council proposal, however they can + // only do it once and it lasts only for the cool-off period. + type VetoOrigin = pallet_collective::EnsureMember; + type CooloffPeriod = CooloffPeriod; + type Slash = Treasury; + type Scheduler = Scheduler; + type PalletsOrigin = OriginCaller; + type MaxVotes = ConstU32<100>; + type MaxProposals = MaxProposals; + type Preimages = Preimage; + type MaxDeposits = ConstU32<100>; + type MaxBlacklisted = ConstU32<100>; type WeightInfo = pallet_democracy::weights::SubstrateWeight; } parameter_types! { - pub const BasicDeposit: Balance = deposit(1, 258); // 258 bytes on-chain - pub const ByteDeposit: Balance = deposit(0, 1); - pub const SubAccountDeposit: Balance = deposit(1, 53); // 53 bytes on-chain - pub const MaxSubAccounts: u32 = 100; - pub const MaxAdditionalFields: u32 = 100; - pub const MaxRegistrars: u32 = 20; + pub const BasicDeposit: Balance = deposit(1, 258); // 258 bytes on-chain + pub const ByteDeposit: Balance = deposit(0, 1); + pub const SubAccountDeposit: Balance = deposit(1, 53); // 53 bytes on-chain + pub const MaxSubAccounts: u32 = 100; + pub const MaxAdditionalFields: u32 = 100; + pub const MaxRegistrars: u32 = 20; } impl pallet_identity::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type BasicDeposit = BasicDeposit; - type ByteDeposit = ByteDeposit; - type SubAccountDeposit = SubAccountDeposit; - type MaxSubAccounts = MaxSubAccounts; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type BasicDeposit = BasicDeposit; + type ByteDeposit = ByteDeposit; + type SubAccountDeposit = SubAccountDeposit; + type MaxSubAccounts = MaxSubAccounts; type IdentityInformation = IdentityInfo; - type MaxRegistrars = MaxRegistrars; - type Slashed = Treasury; - type ForceOrigin = EnsureRootOrThreeFiftsOfCouncil; - type RegistrarOrigin = EnsureRootOrThreeFiftsOfCouncil; + type MaxRegistrars = MaxRegistrars; + type Slashed = Treasury; + type ForceOrigin = EnsureRootOrThreeFiftsOfCouncil; + type RegistrarOrigin = EnsureRootOrThreeFiftsOfCouncil; type OffchainSignature = Signature; type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRootOrThreeFiftsOfCouncil; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; - type WeightInfo = pallet_identity::weights::SubstrateWeight; + type WeightInfo = pallet_identity::weights::SubstrateWeight; } parameter_types! { - // One storage item; key size 32, value size 8; . - pub const ProxyDepositBase: Balance = deposit(1, 8); - // Additional storage item size of 33 bytes. - pub const ProxyDepositFactor: Balance = deposit(0, 33); - pub const AnnouncementDepositBase: Balance = deposit(1, 8); - pub const AnnouncementDepositFactor: Balance = deposit(0, 66); + // One storage item; key size 32, value size 8; . + pub const ProxyDepositBase: Balance = deposit(1, 8); + // Additional storage item size of 33 bytes. + pub const ProxyDepositFactor: Balance = deposit(0, 33); + pub const AnnouncementDepositBase: Balance = deposit(1, 8); + pub const AnnouncementDepositFactor: Balance = deposit(0, 66); } /// The type used to represent the kinds of proxying allowed. #[derive( - Copy, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - Encode, - Decode, - RuntimeDebug, - MaxEncodedLen, - scale_info::TypeInfo, + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + RuntimeDebug, + MaxEncodedLen, + scale_info::TypeInfo, )] pub enum ProxyType { - Any, - NonTransfer, - Governance, + Any, + NonTransfer, + Governance, } impl Default for ProxyType { - fn default() -> Self { - Self::Any - } + fn default() -> Self { + Self::Any + } } impl InstanceFilter for ProxyType { - fn filter(&self, c: &RuntimeCall) -> bool { - match self { - ProxyType::Any => true, - ProxyType::NonTransfer => !matches!( - c, - RuntimeCall::Balances(..) | - RuntimeCall::Assets(..) | - RuntimeCall::Vesting(pallet_vesting::Call::vested_transfer { .. }) - ), - ProxyType::Governance => matches!( - c, - RuntimeCall::Democracy(..) | - RuntimeCall::Council(..) | - RuntimeCall::Treasury(..) - ), - } - } - fn is_superset(&self, o: &Self) -> bool { - match (self, o) { - (x, y) if x == y => true, - (ProxyType::Any, _) => true, - (_, ProxyType::Any) => false, - (ProxyType::NonTransfer, _) => true, - _ => false, - } - } + fn filter(&self, c: &RuntimeCall) -> bool { + match self { + ProxyType::Any => true, + ProxyType::NonTransfer => !matches!( + c, + RuntimeCall::Balances(..) + | RuntimeCall::Assets(..) + | RuntimeCall::Vesting(pallet_vesting::Call::vested_transfer { .. }) + ), + ProxyType::Governance => matches!( + c, + RuntimeCall::Democracy(..) | RuntimeCall::Council(..) | RuntimeCall::Treasury(..) + ), + } + } + fn is_superset(&self, o: &Self) -> bool { + match (self, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + (ProxyType::NonTransfer, _) => true, + _ => false, + } + } } impl pallet_proxy::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type Currency = Balances; - type ProxyType = ProxyType; - type ProxyDepositBase = ProxyDepositBase; - type ProxyDepositFactor = ProxyDepositFactor; - type MaxProxies = ConstU32<32>; - type WeightInfo = pallet_proxy::weights::SubstrateWeight; - type MaxPending = ConstU32<32>; - type CallHasher = BlakeTwo256; - type AnnouncementDepositBase = AnnouncementDepositBase; - type AnnouncementDepositFactor = AnnouncementDepositFactor; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + type ProxyDepositBase = ProxyDepositBase; + type ProxyDepositFactor = ProxyDepositFactor; + type MaxProxies = ConstU32<32>; + type WeightInfo = pallet_proxy::weights::SubstrateWeight; + type MaxPending = ConstU32<32>; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = AnnouncementDepositBase; + type AnnouncementDepositFactor = AnnouncementDepositFactor; } parameter_types! { - /// Default fixed percent a collator takes off the top of due rewards - pub const DefaultCollatorCommission: Perbill = Perbill::from_percent(33); - /// Default percent of inflation set aside for parachain bond every round - pub const DefaultParachainBondReservePercent: Percent = Percent::from_percent(0); - pub const MinDelegation: Balance = 100 * OTP; - pub const MinDelegatorStk: Balance = 100 * OTP; - pub const MinCandidateStk: Balance = 100000 * OTP; + /// Default fixed percent a collator takes off the top of due rewards + pub const DefaultCollatorCommission: Perbill = Perbill::from_percent(33); + /// Default percent of inflation set aside for parachain bond every round + pub const DefaultParachainBondReservePercent: Percent = Percent::from_percent(0); + pub const MinDelegation: Balance = 100 * OTP; + pub const MinDelegatorStk: Balance = 100 * OTP; + pub const MinCandidateStk: Balance = 100000 * OTP; } ord_parameter_types! { - pub const StakingPot: AccountId = - AccountIdConversion::::into_account_truncating(&CollatorsIncentivesPalletId::get()); + pub const StakingPot: AccountId = + AccountIdConversion::::into_account_truncating(&CollatorsIncentivesPalletId::get()); } - impl pallet_parachain_staking::Config for Runtime { - type RuntimeEvent = RuntimeEvent; + type RuntimeEvent = RuntimeEvent; type RuntimeHoldReason = RuntimeHoldReason; - type PayMaster = StakingPot; + type PayMaster = StakingPot; type Balance = Balance; - type Currency = Balances; - type MonetaryGovernanceOrigin = EnsureRootOrFourFiftsOfCouncil; - /// Minimum round length is 2 minutes (10 * 6 second block times) - type MinBlocksPerRound = ConstU32<{3 * HOURS}>; - /// Rounds before the collator leaving the candidates request can be executed - type LeaveCandidatesDelay = ConstU32<{ 4 * 7 }>; - /// Rounds before the candidate bond increase/decrease can be executed - type CandidateBondLessDelay = ConstU32<{ 4 * 7 }>; - /// Rounds before the delegator exit can be executed - type LeaveDelegatorsDelay = ConstU32<{ 4 * 7 }>; - /// Rounds before the delegator revocation can be executed - type RevokeDelegationDelay = ConstU32<{ 4 * 7 }>; - /// Rounds before the delegator bond increase/decrease can be executed - type DelegationBondLessDelay = ConstU32<{ 4 * 7 }>; - /// Rounds before the reward is paid - type RewardPaymentDelay = ConstU32<2>; - /// Minimum collators selected per round, default at genesis and minimum forever after + type Currency = Balances; + type MonetaryGovernanceOrigin = EnsureRootOrFourFiftsOfCouncil; + /// Minimum round length is 2 minutes (10 * 6 second block times) + type MinBlocksPerRound = ConstU32<{ 3 * HOURS }>; + /// Rounds before the collator leaving the candidates request can be executed + type LeaveCandidatesDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the candidate bond increase/decrease can be executed + type CandidateBondLessDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the delegator exit can be executed + type LeaveDelegatorsDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the delegator revocation can be executed + type RevokeDelegationDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the delegator bond increase/decrease can be executed + type DelegationBondLessDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the reward is paid + type RewardPaymentDelay = ConstU32<2>; + /// Minimum collators selected per round, default at genesis and minimum forever after /// TODO: Incerease this after release - type MinSelectedCandidates = ConstU32<1>; - /// Maximum top delegations per candidate - type MaxTopDelegationsPerCandidate = ConstU32<300>; - /// Maximum bottom delegations per candidate - type MaxBottomDelegationsPerCandidate = ConstU32<50>; - /// Maximum delegations per delegator - type MaxDelegationsPerDelegator = ConstU32<100>; - /// Minimum stake required to be reserved to be a candidate - type MinCandidateStk = MinCandidateStk; - /// Minimum stake for any registered on-chain account to delegate - type MinDelegation = MinDelegation; + type MinSelectedCandidates = ConstU32<1>; + /// Maximum top delegations per candidate + type MaxTopDelegationsPerCandidate = ConstU32<300>; + /// Maximum bottom delegations per candidate + type MaxBottomDelegationsPerCandidate = ConstU32<50>; + /// Maximum delegations per delegator + type MaxDelegationsPerDelegator = ConstU32<100>; + /// Minimum stake required to be reserved to be a candidate + type MinCandidateStk = MinCandidateStk; + /// Minimum stake for any registered on-chain account to delegate + type MinDelegation = MinDelegation; /// Minimum stake for any registered on-chain account to be a delegator type MinDelegatorStk = MinDelegatorStk; - // We use the default implementation, so we leave () here. + // We use the default implementation, so we leave () here. type OnCollatorPayout = (); - // We use the default implementation, so we leave () here. - type PayoutCollatorReward = (); // We use the default implementation, so we leave () here. - type OnNewRound = (); - type WeightInfo = weights::pallet_parachain_staking::WeightInfo; + type PayoutCollatorReward = (); + // We use the default implementation, so we leave () here. + type OnNewRound = (); + type WeightInfo = weights::pallet_parachain_staking::WeightInfo; } - // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub struct Runtime @@ -1222,7 +1216,7 @@ construct_runtime!( MessageQueue: pallet_message_queue = 34, // Frontier - EVM: pallet_evm::{Pallet, Config, Call, Storage, Event} = 50, + EVM: pallet_evm::{Pallet, Config, Call, Storage, Event} = 50, Ethereum: pallet_ethereum::{Pallet, Call, Storage, Event, Config, Origin} = 51, EvmAccounts: pallet_evm_accounts::{Pallet, Call, Storage, Event} = 52, BaseFee: pallet_base_fee::{Pallet, Call, Storage, Config, Event} = 53, @@ -1257,59 +1251,62 @@ mod benches { ); } - impl fp_self_contained::SelfContainedCall for RuntimeCall { - type SignedInfo = H160; - - fn is_self_contained(&self) -> bool { - match self { - RuntimeCall::Ethereum(call) => call.is_self_contained(), - _ => false, - } - } - - fn check_self_contained(&self) -> Option> { - match self { - RuntimeCall::Ethereum(call) => call.check_self_contained(), - _ => None, - } - } - - fn validate_self_contained( - &self, - info: &Self::SignedInfo, - dispatch_info: &DispatchInfoOf, - len: usize, - ) -> Option { - match self { - RuntimeCall::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len), - _ => None, - } - } - - fn pre_dispatch_self_contained( - &self, - info: &Self::SignedInfo, + type SignedInfo = H160; + + fn is_self_contained(&self) -> bool { + match self { + RuntimeCall::Ethereum(call) => call.is_self_contained(), + _ => false, + } + } + + fn check_self_contained(&self) -> Option> { + match self { + RuntimeCall::Ethereum(call) => call.check_self_contained(), + _ => None, + } + } + + fn validate_self_contained( + &self, + info: &Self::SignedInfo, dispatch_info: &DispatchInfoOf, len: usize, - ) -> Option> { - match self { - RuntimeCall::Ethereum(call) => call.pre_dispatch_self_contained(info, dispatch_info, len), - _ => None, - } - } - - fn apply_self_contained( - self, - info: Self::SignedInfo, - ) -> Option>> { - match self { - call @ RuntimeCall::Ethereum(pallet_ethereum::Call::transact { .. }) => Some(call.dispatch( - RuntimeOrigin::from(pallet_ethereum::RawOrigin::EthereumTransaction(info)), - )), - _ => None, - } - } + ) -> Option { + match self { + RuntimeCall::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len), + _ => None, + } + } + + fn pre_dispatch_self_contained( + &self, + info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option> { + match self { + RuntimeCall::Ethereum(call) => { + call.pre_dispatch_self_contained(info, dispatch_info, len) + } + _ => None, + } + } + + fn apply_self_contained( + self, + info: Self::SignedInfo, + ) -> Option>> { + match self { + call @ RuntimeCall::Ethereum(pallet_ethereum::Call::transact { .. }) => { + Some(call.dispatch(RuntimeOrigin::from( + pallet_ethereum::RawOrigin::EthereumTransaction(info), + ))) + } + _ => None, + } + } } /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. @@ -1361,7 +1358,8 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = fp_self_contained::UncheckedExtrinsic; +pub type UncheckedExtrinsic = + fp_self_contained::UncheckedExtrinsic; /// Extrinsic type that has already been checked. pub type CheckedExtrinsic = generic::CheckedExtrinsic; @@ -1415,12 +1413,12 @@ impl_runtime_apis! { } fn metadata_at_version(version: u32) -> Option { - Runtime::metadata_at_version(version) - } + Runtime::metadata_at_version(version) + } - fn metadata_versions() -> Vec { - Runtime::metadata_versions() - } + fn metadata_versions() -> Vec { + Runtime::metadata_versions() + } } impl sp_block_builder::BlockBuilder for Runtime { @@ -1461,55 +1459,55 @@ impl_runtime_apis! { } impl fp_rpc::EthereumRuntimeRPCApi for Runtime { - fn chain_id() -> u64 { - ::ChainId::get() - } - - fn account_basic(address: H160) -> EVMAccount { - let (account, _) = EVM::account_basic(&address); - account - } - - fn gas_price() -> U256 { - let (gas_price, _) = ::FeeCalculator::min_gas_price(); - gas_price - } - - fn account_code_at(address: H160) -> Vec { - pallet_evm::AccountCodes::::get(address) - } - - fn author() -> H160 { - >::find_author() - } - - fn storage_at(address: H160, index: U256) -> H256 { - let mut tmp = [0u8; 32]; - index.to_big_endian(&mut tmp); + fn chain_id() -> u64 { + ::ChainId::get() + } + + fn account_basic(address: H160) -> EVMAccount { + let (account, _) = EVM::account_basic(&address); + account + } + + fn gas_price() -> U256 { + let (gas_price, _) = ::FeeCalculator::min_gas_price(); + gas_price + } + + fn account_code_at(address: H160) -> Vec { + pallet_evm::AccountCodes::::get(address) + } + + fn author() -> H160 { + >::find_author() + } + + fn storage_at(address: H160, index: U256) -> H256 { + let mut tmp = [0u8; 32]; + index.to_big_endian(&mut tmp); pallet_evm::AccountStorages::::get(address, H256::from_slice(&tmp[..])) - } - - fn call( - from: H160, - to: H160, - data: Vec, - value: U256, - gas_limit: U256, - max_fee_per_gas: Option, - max_priority_fee_per_gas: Option, - nonce: Option, - estimate: bool, - access_list: Option)>>, - ) -> Result { + } + + fn call( + from: H160, + to: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, + ) -> Result { use pallet_evm::GasWeightMapping as _; - let config = if estimate { - let mut config = ::config().clone(); - config.estimate = true; - Some(config) - } else { - None - }; + let config = if estimate { + let mut config = ::config().clone(); + config.estimate = true; + Some(config) + } else { + None + }; let is_transactional = false; let validate = true; @@ -1541,179 +1539,179 @@ impl_runtime_apis! { } else { gas_limit.low_u64() }; - let without_base_extrinsic_weight = true; - - let (weight_limit, proof_size_base_cost) = - match ::GasWeightMapping::gas_to_weight( - gas_limit, - without_base_extrinsic_weight - ) { - weight_limit if weight_limit.proof_size() > 0 => { - (Some(weight_limit), Some(estimated_transaction_len as u64)) - } - _ => (None, None), - }; - - ::Runner::call( - from, - to, - data, - value, - gas_limit.unique_saturated_into(), - max_fee_per_gas, - max_priority_fee_per_gas, - nonce, - access_list.unwrap_or_default(), - is_transactional, - validate, - weight_limit, - proof_size_base_cost, - config.as_ref().unwrap_or(::config()), - ).map_err(|err| err.error.into()) - } - - fn create( - from: H160, - data: Vec, - value: U256, - gas_limit: U256, - max_fee_per_gas: Option, - max_priority_fee_per_gas: Option, - nonce: Option, - estimate: bool, - access_list: Option)>>, - ) -> Result { - use pallet_evm::GasWeightMapping as _; - - let config = if estimate { - let mut config = ::config().clone(); - config.estimate = true; - Some(config) - } else { - None - }; + let without_base_extrinsic_weight = true; + + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + gas_limit, + without_base_extrinsic_weight + ) { + weight_limit if weight_limit.proof_size() > 0 => { + (Some(weight_limit), Some(estimated_transaction_len as u64)) + } + _ => (None, None), + }; + + ::Runner::call( + from, + to, + data, + value, + gas_limit.unique_saturated_into(), + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), + is_transactional, + validate, + weight_limit, + proof_size_base_cost, + config.as_ref().unwrap_or(::config()), + ).map_err(|err| err.error.into()) + } + + fn create( + from: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, + ) -> Result { + use pallet_evm::GasWeightMapping as _; + + let config = if estimate { + let mut config = ::config().clone(); + config.estimate = true; + Some(config) + } else { + None + }; let is_transactional = false; let validate = true; - let mut estimated_transaction_len = data.len() + - // from: 20 - // value: 32 - // gas_limit: 32 - // nonce: 32 - // 1 byte transaction action variant - // chain id 8 bytes - // 65 bytes signature - 190; - - if max_fee_per_gas.is_some() { - estimated_transaction_len += 32; - } - if max_priority_fee_per_gas.is_some() { - estimated_transaction_len += 32; - } - if access_list.is_some() { - estimated_transaction_len += access_list.encoded_size(); - } - - - let gas_limit = if gas_limit > U256::from(u64::MAX) { - u64::MAX - } else { - gas_limit.low_u64() - }; - let without_base_extrinsic_weight = true; - - let (weight_limit, proof_size_base_cost) = - match ::GasWeightMapping::gas_to_weight( - gas_limit, - without_base_extrinsic_weight - ) { - weight_limit if weight_limit.proof_size() > 0 => { - (Some(weight_limit), Some(estimated_transaction_len as u64)) - } - _ => (None, None), - }; - - ::Runner::create( - from, - data, - value, - gas_limit.unique_saturated_into(), - max_fee_per_gas, - max_priority_fee_per_gas, - nonce, - access_list.unwrap_or_default(), + let mut estimated_transaction_len = data.len() + + // from: 20 + // value: 32 + // gas_limit: 32 + // nonce: 32 + // 1 byte transaction action variant + // chain id 8 bytes + // 65 bytes signature + 190; + + if max_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if max_priority_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if access_list.is_some() { + estimated_transaction_len += access_list.encoded_size(); + } + + + let gas_limit = if gas_limit > U256::from(u64::MAX) { + u64::MAX + } else { + gas_limit.low_u64() + }; + let without_base_extrinsic_weight = true; + + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + gas_limit, + without_base_extrinsic_weight + ) { + weight_limit if weight_limit.proof_size() > 0 => { + (Some(weight_limit), Some(estimated_transaction_len as u64)) + } + _ => (None, None), + }; + + ::Runner::create( + from, + data, + value, + gas_limit.unique_saturated_into(), + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), is_transactional, validate, - weight_limit, - proof_size_base_cost, - config.as_ref().unwrap_or(::config()), - ).map_err(|err| err.error.into()) - } - - fn current_transaction_statuses() -> Option> { - pallet_ethereum::CurrentTransactionStatuses::::get() - } - - fn current_block() -> Option { - pallet_ethereum::CurrentBlock::::get() - } - - fn current_receipts() -> Option> { - pallet_ethereum::CurrentReceipts::::get() - } - - fn current_all() -> ( - Option, - Option>, - Option> - ) { - ( - pallet_ethereum::CurrentBlock::::get(), - pallet_ethereum::CurrentReceipts::::get(), - pallet_ethereum::CurrentTransactionStatuses::::get() - ) - } - - fn extrinsic_filter( - xts: Vec<::Extrinsic>, - ) -> Vec { - xts.into_iter().filter_map(|xt| match xt.0.function { - RuntimeCall::Ethereum(transact { transaction }) => Some(transaction), - _ => None - }).collect::>() - } - - fn elasticity() -> Option { + weight_limit, + proof_size_base_cost, + config.as_ref().unwrap_or(::config()), + ).map_err(|err| err.error.into()) + } + + fn current_transaction_statuses() -> Option> { + pallet_ethereum::CurrentTransactionStatuses::::get() + } + + fn current_block() -> Option { + pallet_ethereum::CurrentBlock::::get() + } + + fn current_receipts() -> Option> { + pallet_ethereum::CurrentReceipts::::get() + } + + fn current_all() -> ( + Option, + Option>, + Option> + ) { + ( + pallet_ethereum::CurrentBlock::::get(), + pallet_ethereum::CurrentReceipts::::get(), + pallet_ethereum::CurrentTransactionStatuses::::get() + ) + } + + fn extrinsic_filter( + xts: Vec<::Extrinsic>, + ) -> Vec { + xts.into_iter().filter_map(|xt| match xt.0.function { + RuntimeCall::Ethereum(transact { transaction }) => Some(transaction), + _ => None + }).collect::>() + } + + fn elasticity() -> Option { Some(pallet_base_fee::Elasticity::::get()) - } + } fn gas_limit_multiplier_support() {} fn pending_block( - xts: Vec<::Extrinsic>, - ) -> (Option, Option>) { - for ext in xts.into_iter() { - let _ = Executive::apply_extrinsic(ext); - } + xts: Vec<::Extrinsic>, + ) -> (Option, Option>) { + for ext in xts.into_iter() { + let _ = Executive::apply_extrinsic(ext); + } - Ethereum::on_finalize(System::block_number() + 1); + Ethereum::on_finalize(System::block_number() + 1); - ( - pallet_ethereum::CurrentBlock::::get(), - pallet_ethereum::CurrentTransactionStatuses::::get() - ) - } - } + ( + pallet_ethereum::CurrentBlock::::get(), + pallet_ethereum::CurrentTransactionStatuses::::get() + ) + } + } impl fp_rpc::ConvertTransactionRuntimeApi for Runtime { - fn convert_transaction(transaction: EthereumTransaction) -> ::Extrinsic { - UncheckedExtrinsic::new_unsigned( - pallet_ethereum::Call::::transact { transaction }.into(), - ) - } - } + fn convert_transaction(transaction: EthereumTransaction) -> ::Extrinsic { + UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ) + } + } impl sp_session::SessionKeys for Runtime { fn generate_session_keys(seed: Option>) -> Vec { @@ -1747,35 +1745,35 @@ impl_runtime_apis! { TransactionPayment::query_fee_details(uxt, len) } fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } } impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi - for Runtime - { - fn query_call_info( - call: RuntimeCall, - len: u32, - ) -> pallet_transaction_payment::RuntimeDispatchInfo { - TransactionPayment::query_call_info(call, len) - } - fn query_call_fee_details( - call: RuntimeCall, - len: u32, - ) -> pallet_transaction_payment::FeeDetails { - TransactionPayment::query_call_fee_details(call, len) - } + for Runtime + { + fn query_call_info( + call: RuntimeCall, + len: u32, + ) -> pallet_transaction_payment::RuntimeDispatchInfo { + TransactionPayment::query_call_info(call, len) + } + fn query_call_fee_details( + call: RuntimeCall, + len: u32, + ) -> pallet_transaction_payment::FeeDetails { + TransactionPayment::query_call_fee_details(call, len) + } fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } - } + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { @@ -1786,20 +1784,20 @@ impl_runtime_apis! { #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { - let weight = Executive::try_runtime_upgrade(checks).unwrap(); + let weight = Executive::try_runtime_upgrade(checks).unwrap(); (weight, RuntimeBlockWeights::get().max_block) } fn execute_block( - block: Block, - state_root_check: bool, - signature_check: bool, - select: frame_try_runtime::TryStateSelect, - ) -> Weight { - // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to - // have a backtrace here. - Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap() - } + block: Block, + state_root_check: bool, + signature_check: bool, + select: frame_try_runtime::TryStateSelect, + ) -> Weight { + // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to + // have a backtrace here. + Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap() + } } impl sp_genesis_builder::GenesisBuilder for Runtime { @@ -1810,7 +1808,7 @@ impl_runtime_apis! { fn get_preset(id: &Option) -> Option> { get_preset::(id, |_| None) } - + fn preset_names() -> Vec { vec![] } @@ -1842,7 +1840,7 @@ impl_runtime_apis! { impl frame_system_benchmarking::Config for Runtime {} use frame_support::traits::{TrackedStorageKey, WhitelistedStorageKeys}; - let whitelist = AllPalletsWithSystem::whitelisted_storage_keys(); + let whitelist = AllPalletsWithSystem::whitelisted_storage_keys(); let mut batches = Vec::::new(); let params = (&config, &whitelist); diff --git a/runtime/src/precompiles.rs b/runtime/src/precompiles.rs index 081427f..1873477 100644 --- a/runtime/src/precompiles.rs +++ b/runtime/src/precompiles.rs @@ -1,9 +1,13 @@ -use pallet_evm::{ExitRevert, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle, PrecompileResult, PrecompileSet}; +use pallet_evm::{ + ExitRevert, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle, + PrecompileResult, PrecompileSet, +}; use sp_core::H160; use sp_std::marker::PhantomData; use pallet_evm_precompile_assets_erc20::{AddressToAssetId, Erc20AssetsPrecompileSet}; use pallet_evm_precompile_modexp::Modexp; +use pallet_evm_precompile_parachain_staking::ParachainStakingPrecompileSet; use pallet_evm_precompile_sha3fips::Sha3FIPS256; use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; @@ -15,29 +19,30 @@ pub struct FrontierPrecompiles(PhantomData); impl FrontierPrecompiles where - R: pallet_evm::Config, + R: pallet_evm::Config, { - pub fn new() -> Self { - Self(Default::default()) - } - /// Return all addresses that contain precompiles. This can be used to populate dummy code + pub fn new() -> Self { + Self(Default::default()) + } + /// Return all addresses that contain precompiles. This can be used to populate dummy code /// under the precompile. pub fn used_addresses() -> impl Iterator { - sp_std::vec![1, 2, 3, 4, 5, 1024, 1025] + sp_std::vec![1, 2, 3, 4, 5, 1024, 1025, 2048] .into_iter() .map(hash) } } impl PrecompileSet for FrontierPrecompiles where - Erc20AssetsPrecompileSet: PrecompileSet, - R: pallet_evm::Config - + pallet_assets::Config + Erc20AssetsPrecompileSet: PrecompileSet, + ParachainStakingPrecompileSet: PrecompileSet, + R: pallet_evm::Config + + pallet_assets::Config + AddressToAssetId<::AssetId>, { - fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { - let address = handle.code_address(); - if let IsPrecompileResult::Answer { is_precompile, .. } = + fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { + let address = handle.code_address(); + if let IsPrecompileResult::Answer { is_precompile, .. } = self.is_precompile(address, u64::MAX) { if is_precompile && address > hash(9) && handle.context().address != address { @@ -47,25 +52,26 @@ where })); } } - match address { - // Ethereum precompiles : - a if a == hash(1) => Some(ECRecover::execute(handle)), - a if a == hash(2) => Some(Sha256::execute(handle)), - a if a == hash(3) => Some(Ripemd160::execute(handle)), - a if a == hash(4) => Some(Identity::execute(handle)), - a if a == hash(5) => Some(Modexp::execute(handle)), - // Non-Frontier specific nor Ethereum precompiles : - a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)), - a if a == hash(1025) => Some(ECRecoverPublicKey::execute(handle)), - // If the address matches asset prefix, the we route through the asset precompile set + match address { + // Ethereum precompiles : + a if a == hash(1) => Some(ECRecover::execute(handle)), + a if a == hash(2) => Some(Sha256::execute(handle)), + a if a == hash(3) => Some(Ripemd160::execute(handle)), + a if a == hash(4) => Some(Identity::execute(handle)), + a if a == hash(5) => Some(Modexp::execute(handle)), + // Non-Frontier specific nor Ethereum precompiles : + a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)), + a if a == hash(1025) => Some(ECRecoverPublicKey::execute(handle)), + a if a == hash(2048) => ParachainStakingPrecompileSet::::new().execute(handle), + // If the address matches asset prefix, the we route through the asset precompile set a if &a.to_fixed_bytes()[0..4] == ASSET_PRECOMPILE_ADDRESS_PREFIX => { Erc20AssetsPrecompileSet::::new().execute(handle) } - _ => None, - } - } + _ => None, + } + } - fn is_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult { + fn is_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult { let assets_precompile = match Erc20AssetsPrecompileSet::::new().is_precompile(address, gas) { IsPrecompileResult::Answer { is_precompile, .. } => is_precompile, @@ -80,5 +86,5 @@ where } fn hash(a: u64) -> H160 { - H160::from_low_u64_be(a) -} \ No newline at end of file + H160::from_low_u64_be(a) +} From fcb11a0348c792c5930b5d556f69058f06057983 Mon Sep 17 00:00:00 2001 From: NZT48 Date: Mon, 21 Apr 2025 19:09:02 +0200 Subject: [PATCH 02/11] Implement points and candidate_count getters --- precompiles/parachain-staking/src/lib.rs | 37 ++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/precompiles/parachain-staking/src/lib.rs b/precompiles/parachain-staking/src/lib.rs index f2155a1..0507b7a 100644 --- a/precompiles/parachain-staking/src/lib.rs +++ b/precompiles/parachain-staking/src/lib.rs @@ -31,7 +31,7 @@ use frame_support::{ }; use pallet_evm::{AddressMapping, PrecompileSet}; use precompile_utils::{ - keccak256, revert, succeed, Address, Bytes, EvmData, EvmDataWriter, EvmResult, + keccak256, revert, succeed, Address, Bytes, EvmData, EvmDataReader, EvmDataWriter, EvmResult, FunctionModifier, LogExt, LogsBuilder, PrecompileHandleExt, RuntimeHelper, }; use sp_runtime::traits::{Bounded, Dispatchable, Zero}; @@ -48,6 +48,8 @@ pub type BalanceOf = ::Bal #[derive(Debug, PartialEq)] pub enum Action { MinDelegation = "min_delegation()", + Points = "points(uint256)", + CandidateCount = "candidate_count()", Round = "round()", } pub struct ParachainStakingPrecompileSet(PhantomData); @@ -73,7 +75,10 @@ where }; if let Err(err) = handle.check_function_modifier(match selector { - Action::MinDelegation | Action::Round => FunctionModifier::NonPayable, + Action::MinDelegation + | Action::Points + | Action::CandidateCount + | Action::Round => FunctionModifier::NonPayable, _ => FunctionModifier::View, }) { return Some(Err(err)); @@ -81,7 +86,10 @@ where let result = match selector { Action::MinDelegation => Self::min_delegation(handle), + Action::Points => Self::points(handle), + Action::CandidateCount => return Some(Self::candidate_count(handle)), Action::Round => Self::round(handle), + _ => return Some(Err(revert("Deprecated function"))), }; return Some(result); @@ -117,6 +125,31 @@ where Ok(succeed(EvmDataWriter::new().write(min_nomination).build())) } + fn points(handle: &mut impl PrecompileHandle) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + let round = input.read::()?; + + // Fetch info. + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + let points: u32 = pallet_parachain_staking::Pallet::::points(round); + + // Build output. + Ok(succeed(EvmDataWriter::new().write(points).build())) + } + + fn candidate_count(handle: &mut impl PrecompileHandle) -> EvmResult { + // Fetch info. + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + let candidate_count: u32 = >::candidate_pool() + .0 + .len() as u32; + + // Build output. + Ok(succeed(EvmDataWriter::new().write(candidate_count).build())) + } + fn round(handle: &mut impl PrecompileHandle) -> EvmResult { // Fetch info. handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; From 4c89b1bb4b8c6ca602bf50dc65f84c85c42d5094 Mon Sep 17 00:00:00 2001 From: NZT48 Date: Mon, 21 Apr 2025 19:41:06 +0200 Subject: [PATCH 03/11] Implement getter for candidate and delegator delegation count --- precompiles/parachain-staking/src/lib.rs | 90 ++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 5 deletions(-) diff --git a/precompiles/parachain-staking/src/lib.rs b/precompiles/parachain-staking/src/lib.rs index 0507b7a..8e9a1b0 100644 --- a/precompiles/parachain-staking/src/lib.rs +++ b/precompiles/parachain-staking/src/lib.rs @@ -35,11 +35,10 @@ use precompile_utils::{ FunctionModifier, LogExt, LogsBuilder, PrecompileHandleExt, RuntimeHelper, }; use sp_runtime::traits::{Bounded, Dispatchable, Zero}; - use sp_core::{Get, H160, U256}; use sp_std::{ convert::{TryFrom, TryInto}, - marker::PhantomData, + marker::PhantomData, vec::Vec }; pub type BalanceOf = ::Balance; @@ -51,6 +50,8 @@ pub enum Action { Points = "points(uint256)", CandidateCount = "candidate_count()", Round = "round()", + CandidateDelegationCount = "candidate_delegation_count(address)", + DelegatorDelegationCount = "delegator_delegation_count(address)", } pub struct ParachainStakingPrecompileSet(PhantomData); @@ -78,8 +79,10 @@ where Action::MinDelegation | Action::Points | Action::CandidateCount - | Action::Round => FunctionModifier::NonPayable, - _ => FunctionModifier::View, + | Action::Round + | Action::CandidateDelegationCount + | Action::DelegatorDelegationCount => FunctionModifier::View, + _ => FunctionModifier::NonPayable, }) { return Some(Err(err)); } @@ -89,7 +92,12 @@ where Action::Points => Self::points(handle), Action::CandidateCount => return Some(Self::candidate_count(handle)), Action::Round => Self::round(handle), - _ => return Some(Err(revert("Deprecated function"))), + Action::CandidateDelegationCount => { + return Some(Self::candidate_delegation_count(handle)) + }, + Action::DelegatorDelegationCount => { + return Some(Self::delegator_delegation_count(handle)) + } }; return Some(result); @@ -158,4 +166,76 @@ where // Build output. Ok(succeed(EvmDataWriter::new().write(round).build())) } + + fn candidate_delegation_count( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + let address = input.read::
()?.0; + let address = Runtime::AddressMapping::into_account_id(address); + + // Fetch info. + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + let result = if let Some(state) = + >::candidate_info(&address) + { + let candidate_delegation_count: u32 = state.delegation_count; + + log::trace!( + target: "staking-precompile", + "Result from pallet is {:?}", + candidate_delegation_count + ); + candidate_delegation_count + } else { + log::trace!( + target: "staking-precompile", + "Candidate {:?} not found, so delegation count is 0", + address + ); + 0u32 + }; + + // Build output. + Ok(succeed(EvmDataWriter::new().write(result).build())) + } + + fn delegator_delegation_count( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + let address = input.read::
()?.0; + let address = Runtime::AddressMapping::into_account_id(address); + + // Fetch info. + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + let result = if let Some(state) = + >::delegator_state(&address) + { + let delegator_delegation_count: u32 = state.delegations.0.len() as u32; + + log::trace!( + target: "staking-precompile", + "Result from pallet is {:?}", + delegator_delegation_count + ); + + delegator_delegation_count + } else { + log::trace!( + target: "staking-precompile", + "Delegator {:?} not found, so delegation count is 0", + address + ); + 0u32 + }; + + // Build output. + Ok(succeed(EvmDataWriter::new().write(result).build())) + } + } From 1457c2fa9e090181a9547453c5ff9262c30f2102 Mon Sep 17 00:00:00 2001 From: NZT48 Date: Mon, 21 Apr 2025 20:34:59 +0200 Subject: [PATCH 04/11] Implement join candidates --- precompiles/parachain-staking/src/lib.rs | 53 +++++++++++++++++------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/precompiles/parachain-staking/src/lib.rs b/precompiles/parachain-staking/src/lib.rs index 8e9a1b0..dfc2f20 100644 --- a/precompiles/parachain-staking/src/lib.rs +++ b/precompiles/parachain-staking/src/lib.rs @@ -34,11 +34,12 @@ use precompile_utils::{ keccak256, revert, succeed, Address, Bytes, EvmData, EvmDataReader, EvmDataWriter, EvmResult, FunctionModifier, LogExt, LogsBuilder, PrecompileHandleExt, RuntimeHelper, }; -use sp_runtime::traits::{Bounded, Dispatchable, Zero}; use sp_core::{Get, H160, U256}; +use sp_runtime::traits::{Bounded, Dispatchable, Zero}; use sp_std::{ convert::{TryFrom, TryInto}, - marker::PhantomData, vec::Vec + marker::PhantomData, + vec::Vec, }; pub type BalanceOf = ::Balance; @@ -52,6 +53,7 @@ pub enum Action { Round = "round()", CandidateDelegationCount = "candidate_delegation_count(address)", DelegatorDelegationCount = "delegator_delegation_count(address)", + JoinCandidates = "join_candidates(uint256,uint256)", } pub struct ParachainStakingPrecompileSet(PhantomData); @@ -67,6 +69,7 @@ where Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, ::RuntimeOrigin: From>, BalanceOf: TryFrom + Into + EvmData, + Runtime::RuntimeCall: From>, <::RuntimeCall as Dispatchable>::RuntimeOrigin: OriginTrait, { fn execute(&self, handle: &mut impl PrecompileHandle) -> Option> { @@ -77,12 +80,12 @@ where if let Err(err) = handle.check_function_modifier(match selector { Action::MinDelegation - | Action::Points - | Action::CandidateCount - | Action::Round - | Action::CandidateDelegationCount + | Action::Points + | Action::CandidateCount + | Action::Round + | Action::CandidateDelegationCount | Action::DelegatorDelegationCount => FunctionModifier::View, - _ => FunctionModifier::NonPayable, + Action::JoinCandidates => FunctionModifier::NonPayable, }) { return Some(Err(err)); } @@ -90,14 +93,11 @@ where let result = match selector { Action::MinDelegation => Self::min_delegation(handle), Action::Points => Self::points(handle), - Action::CandidateCount => return Some(Self::candidate_count(handle)), + Action::CandidateCount => Self::candidate_count(handle), Action::Round => Self::round(handle), - Action::CandidateDelegationCount => { - return Some(Self::candidate_delegation_count(handle)) - }, - Action::DelegatorDelegationCount => { - return Some(Self::delegator_delegation_count(handle)) - } + Action::CandidateDelegationCount => Self::candidate_delegation_count(handle), + Action::DelegatorDelegationCount => Self::delegator_delegation_count(handle), + Action::JoinCandidates => Self::join_candidates(handle), }; return Some(result); @@ -117,6 +117,7 @@ where Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, ::RuntimeOrigin: From>, BalanceOf: TryFrom + Into + EvmData, + Runtime::RuntimeCall: From>, <::RuntimeCall as Dispatchable>::RuntimeOrigin: OriginTrait, { fn min_delegation(handle: &mut impl PrecompileHandle) -> EvmResult { @@ -238,4 +239,28 @@ where Ok(succeed(EvmDataWriter::new().write(result).build())) } + fn join_candidates(handle: &mut impl PrecompileHandle) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + + // Read input. + input.expect_arguments(2)?; + let bond: BalanceOf = input.read()?; + let candidate_count = input.read()?; + + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + RuntimeHelper::::try_dispatch( + handle, + Some(origin).into(), + pallet_parachain_staking::Call::::join_candidates { + bond, + candidate_count, + }, + )?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } } From eea601165ae2beef7004abcd04684ff124371824 Mon Sep 17 00:00:00 2001 From: NZT48 Date: Mon, 21 Apr 2025 20:43:40 +0200 Subject: [PATCH 05/11] Implement delegate precompile call --- precompiles/parachain-staking/src/lib.rs | 29 +++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/precompiles/parachain-staking/src/lib.rs b/precompiles/parachain-staking/src/lib.rs index dfc2f20..30aba19 100644 --- a/precompiles/parachain-staking/src/lib.rs +++ b/precompiles/parachain-staking/src/lib.rs @@ -54,6 +54,7 @@ pub enum Action { CandidateDelegationCount = "candidate_delegation_count(address)", DelegatorDelegationCount = "delegator_delegation_count(address)", JoinCandidates = "join_candidates(uint256,uint256)", + Delegate = "delegate(address,uint256,uint256,uint256)", } pub struct ParachainStakingPrecompileSet(PhantomData); @@ -85,7 +86,7 @@ where | Action::Round | Action::CandidateDelegationCount | Action::DelegatorDelegationCount => FunctionModifier::View, - Action::JoinCandidates => FunctionModifier::NonPayable, + Action::Delegate | Action::JoinCandidates => FunctionModifier::NonPayable, }) { return Some(Err(err)); } @@ -98,6 +99,7 @@ where Action::CandidateDelegationCount => Self::candidate_delegation_count(handle), Action::DelegatorDelegationCount => Self::delegator_delegation_count(handle), Action::JoinCandidates => Self::join_candidates(handle), + Action::Delegate => Self::delegate(handle), }; return Some(result); @@ -263,4 +265,29 @@ where Ok(succeed(EvmDataWriter::new().write(true).build())) } + + fn delegate(handle: &mut impl PrecompileHandle) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(4)?; + let candidate = Runtime::AddressMapping::into_account_id(input.read::
()?.0); + let amount: BalanceOf = input.read()?; + let candidate_delegation_count = input.read()?; + let delegation_count = input.read()?; + + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::delegate { + candidate, + amount, + candidate_delegation_count, + delegation_count, + }; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } } From 88d6ee840049ae7c16f1eb6aa5e20517c90b913d Mon Sep 17 00:00:00 2001 From: NZT48 Date: Mon, 21 Apr 2025 21:18:06 +0200 Subject: [PATCH 06/11] Implement DelegatorBondMore, DelegatorBondMore, CancelDelegationRequest --- precompiles/parachain-staking/src/lib.rs | 78 +++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/precompiles/parachain-staking/src/lib.rs b/precompiles/parachain-staking/src/lib.rs index 30aba19..f5b101b 100644 --- a/precompiles/parachain-staking/src/lib.rs +++ b/precompiles/parachain-staking/src/lib.rs @@ -55,6 +55,9 @@ pub enum Action { DelegatorDelegationCount = "delegator_delegation_count(address)", JoinCandidates = "join_candidates(uint256,uint256)", Delegate = "delegate(address,uint256,uint256,uint256)", + DelegatorBondMore = "delegator_bond_more(address,uint256)", + ExecuteDelegationRequest = "execute_delegation_request(address,address)", + CancelDelegationRequest = "cancel_delegation_request(address)", } pub struct ParachainStakingPrecompileSet(PhantomData); @@ -86,7 +89,11 @@ where | Action::Round | Action::CandidateDelegationCount | Action::DelegatorDelegationCount => FunctionModifier::View, - Action::Delegate | Action::JoinCandidates => FunctionModifier::NonPayable, + Action::Delegate + | Action::JoinCandidates + | Action::DelegatorBondMore + | Action::ExecuteDelegationRequest + | Action::CancelDelegationRequest => FunctionModifier::NonPayable, }) { return Some(Err(err)); } @@ -100,6 +107,9 @@ where Action::DelegatorDelegationCount => Self::delegator_delegation_count(handle), Action::JoinCandidates => Self::join_candidates(handle), Action::Delegate => Self::delegate(handle), + Action::DelegatorBondMore => Self::delegator_bond_more(handle), + Action::ExecuteDelegationRequest => Self::execute_delegation_request(handle), + Action::CancelDelegationRequest => Self::cancel_delegation_request(handle), }; return Some(result); @@ -290,4 +300,70 @@ where Ok(succeed(EvmDataWriter::new().write(true).build())) } + + fn delegator_bond_more(handle: &mut impl PrecompileHandle) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(2)?; + let candidate = input.read::
()?.0; + let candidate = Runtime::AddressMapping::into_account_id(candidate); + let more: BalanceOf = input.read()?; + + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = + pallet_parachain_staking::Call::::delegator_bond_more { candidate, more }; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + + fn execute_delegation_request( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(2)?; + let delegator = input.read::
()?.0; + let delegator = Runtime::AddressMapping::into_account_id(delegator); + let candidate = input.read::
()?.0; + let candidate = Runtime::AddressMapping::into_account_id(candidate); + + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::execute_delegation_request { + delegator, + candidate, + }; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + + fn cancel_delegation_request( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + let candidate = input.read::
()?.0; + let candidate = Runtime::AddressMapping::into_account_id(candidate); + + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = + pallet_parachain_staking::Call::::cancel_delegation_request { candidate }; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } } From cde78347498778d67a16c2c2a29691b84380391d Mon Sep 17 00:00:00 2001 From: NZT48 Date: Mon, 21 Apr 2025 21:33:59 +0200 Subject: [PATCH 07/11] Implement schedule, execute and cancel leave delegators --- precompiles/parachain-staking/src/lib.rs | 57 ++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/precompiles/parachain-staking/src/lib.rs b/precompiles/parachain-staking/src/lib.rs index f5b101b..42274f5 100644 --- a/precompiles/parachain-staking/src/lib.rs +++ b/precompiles/parachain-staking/src/lib.rs @@ -55,6 +55,9 @@ pub enum Action { DelegatorDelegationCount = "delegator_delegation_count(address)", JoinCandidates = "join_candidates(uint256,uint256)", Delegate = "delegate(address,uint256,uint256,uint256)", + ScheduleLeaveDelegators = "schedule_leave_delegators()", + ExecuteLeaveDelegators = "execute_leave_delegators(address,uint256)", + CancelLeaveDelegators = "cancel_leave_delegators()", DelegatorBondMore = "delegator_bond_more(address,uint256)", ExecuteDelegationRequest = "execute_delegation_request(address,address)", CancelDelegationRequest = "cancel_delegation_request(address)", @@ -91,6 +94,9 @@ where | Action::DelegatorDelegationCount => FunctionModifier::View, Action::Delegate | Action::JoinCandidates + | Action::ScheduleLeaveDelegators + | Action::ExecuteLeaveDelegators + | Action::CancelLeaveDelegators | Action::DelegatorBondMore | Action::ExecuteDelegationRequest | Action::CancelDelegationRequest => FunctionModifier::NonPayable, @@ -107,6 +113,9 @@ where Action::DelegatorDelegationCount => Self::delegator_delegation_count(handle), Action::JoinCandidates => Self::join_candidates(handle), Action::Delegate => Self::delegate(handle), + Action::ScheduleLeaveDelegators => Self::schedule_leave_delegators(handle), + Action::ExecuteLeaveDelegators => Self::execute_leave_delegators(handle), + Action::CancelLeaveDelegators => Self::cancel_leave_delegators(handle), Action::DelegatorBondMore => Self::delegator_bond_more(handle), Action::ExecuteDelegationRequest => Self::execute_delegation_request(handle), Action::CancelDelegationRequest => Self::cancel_delegation_request(handle), @@ -301,6 +310,54 @@ where Ok(succeed(EvmDataWriter::new().write(true).build())) } + fn schedule_leave_delegators( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::schedule_leave_delegators {}; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + + fn execute_leave_delegators(handle: &mut impl PrecompileHandle) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(2)?; + let delegator = input.read::
()?.0; + let delegator = Runtime::AddressMapping::into_account_id(delegator); + let delegation_count = input.read()?; + + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::execute_leave_delegators { + delegator, + delegation_count, + }; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + + fn cancel_leave_delegators(handle: &mut impl PrecompileHandle) -> EvmResult { + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::cancel_leave_delegators {}; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + fn delegator_bond_more(handle: &mut impl PrecompileHandle) -> EvmResult { let mut input = EvmDataReader::new_skip_selector(handle.input())?; // Read input. From 83c4b848d748757a84fc2993a332f6919dead4ef Mon Sep 17 00:00:00 2001 From: NZT48 Date: Mon, 21 Apr 2025 21:57:45 +0200 Subject: [PATCH 08/11] Implement additional functions --- precompiles/parachain-staking/src/lib.rs | 149 +++++++++++++++++++++-- 1 file changed, 141 insertions(+), 8 deletions(-) diff --git a/precompiles/parachain-staking/src/lib.rs b/precompiles/parachain-staking/src/lib.rs index 42274f5..f450770 100644 --- a/precompiles/parachain-staking/src/lib.rs +++ b/precompiles/parachain-staking/src/lib.rs @@ -54,10 +54,16 @@ pub enum Action { CandidateDelegationCount = "candidate_delegation_count(address)", DelegatorDelegationCount = "delegator_delegation_count(address)", JoinCandidates = "join_candidates(uint256,uint256)", + ScheduleCandidateBondLess = "schedule_candidate_bond_less(uint256)", + CandidateBondMore = "candidate_bond_more(uint256)", + ExecuteCandidateBondLess = "execute_candidate_bond_less(address)", + CancelCandidateBondLess = "cancel_candidate_bond_less()", Delegate = "delegate(address,uint256,uint256,uint256)", ScheduleLeaveDelegators = "schedule_leave_delegators()", ExecuteLeaveDelegators = "execute_leave_delegators(address,uint256)", CancelLeaveDelegators = "cancel_leave_delegators()", + ScheduleRevokeDelegation = "schedule_revoke_delegation(address)", + ScheduleDelegatorBondLess = "schedule_delegator_bond_less(address,uint256)", DelegatorBondMore = "delegator_bond_more(address,uint256)", ExecuteDelegationRequest = "execute_delegation_request(address,address)", CancelDelegationRequest = "cancel_delegation_request(address)", @@ -94,9 +100,15 @@ where | Action::DelegatorDelegationCount => FunctionModifier::View, Action::Delegate | Action::JoinCandidates + | Action::ScheduleCandidateBondLess + | Action::CandidateBondMore + | Action::ExecuteCandidateBondLess + | Action::CancelCandidateBondLess | Action::ScheduleLeaveDelegators | Action::ExecuteLeaveDelegators | Action::CancelLeaveDelegators + | Action::ScheduleRevokeDelegation + | Action::ScheduleDelegatorBondLess | Action::DelegatorBondMore | Action::ExecuteDelegationRequest | Action::CancelDelegationRequest => FunctionModifier::NonPayable, @@ -112,10 +124,16 @@ where Action::CandidateDelegationCount => Self::candidate_delegation_count(handle), Action::DelegatorDelegationCount => Self::delegator_delegation_count(handle), Action::JoinCandidates => Self::join_candidates(handle), + Action::ScheduleCandidateBondLess => Self::schedule_candidate_bond_less(handle), + Action::CandidateBondMore => Self::candidate_bond_more(handle), + Action::ExecuteCandidateBondLess => Self::execute_candidate_bond_less(handle), + Action::CancelCandidateBondLess => Self::cancel_candidate_bond_less(handle), Action::Delegate => Self::delegate(handle), Action::ScheduleLeaveDelegators => Self::schedule_leave_delegators(handle), Action::ExecuteLeaveDelegators => Self::execute_leave_delegators(handle), Action::CancelLeaveDelegators => Self::cancel_leave_delegators(handle), + Action::ScheduleRevokeDelegation => Self::schedule_revoke_delegation(handle), + Action::ScheduleDelegatorBondLess => Self::schedule_delegator_bond_less(handle), Action::DelegatorBondMore => Self::delegator_bond_more(handle), Action::ExecuteDelegationRequest => Self::execute_delegation_request(handle), Action::CancelDelegationRequest => Self::cancel_delegation_request(handle), @@ -271,15 +289,85 @@ where { // Build call with origin. let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::join_candidates { + bond, + candidate_count, + }; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + + fn candidate_bond_more(handle: &mut impl PrecompileHandle) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + let more: BalanceOf = input.read()?; + + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::candidate_bond_more { more }; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + + fn schedule_candidate_bond_less( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + let less: BalanceOf = input.read()?; + + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = + pallet_parachain_staking::Call::::schedule_candidate_bond_less { less }; - RuntimeHelper::::try_dispatch( - handle, - Some(origin).into(), - pallet_parachain_staking::Call::::join_candidates { - bond, - candidate_count, - }, - )?; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + + fn execute_candidate_bond_less( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + let candidate = input.read::
()?.0; + let candidate = Runtime::AddressMapping::into_account_id(candidate); + + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::execute_candidate_bond_less { + candidate, + }; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + + fn cancel_candidate_bond_less( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::cancel_candidate_bond_less {}; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; } Ok(succeed(EvmDataWriter::new().write(true).build())) @@ -358,6 +446,51 @@ where Ok(succeed(EvmDataWriter::new().write(true).build())) } + fn schedule_revoke_delegation( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + let collator = input.read::
()?.0; + let collator = Runtime::AddressMapping::into_account_id(collator); + + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = + pallet_parachain_staking::Call::::schedule_revoke_delegation { collator }; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + + fn schedule_delegator_bond_less( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(2)?; + let candidate = input.read::
()?.0; + let candidate = Runtime::AddressMapping::into_account_id(candidate); + let less: BalanceOf = input.read()?; + + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::schedule_delegator_bond_less { + candidate, + less, + }; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + fn delegator_bond_more(handle: &mut impl PrecompileHandle) -> EvmResult { let mut input = EvmDataReader::new_skip_selector(handle.input())?; // Read input. From 14f8aaf3b8e401a424fa14c0592b6d282c612710 Mon Sep 17 00:00:00 2001 From: NZT48 Date: Mon, 21 Apr 2025 22:10:46 +0200 Subject: [PATCH 09/11] Final calls --- precompiles/parachain-staking/src/lib.rs | 100 +++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/precompiles/parachain-staking/src/lib.rs b/precompiles/parachain-staking/src/lib.rs index f450770..4ed2953 100644 --- a/precompiles/parachain-staking/src/lib.rs +++ b/precompiles/parachain-staking/src/lib.rs @@ -54,6 +54,11 @@ pub enum Action { CandidateDelegationCount = "candidate_delegation_count(address)", DelegatorDelegationCount = "delegator_delegation_count(address)", JoinCandidates = "join_candidates(uint256,uint256)", + ScheduleLeaveCandidates = "schedule_leave_candidates(uint256)", + ExecuteLeaveCandidates = "execute_leave_candidates(address,uint256)", + CancelLeaveCandidates = "cancel_leave_candidates(uint256)", + GoOffline = "go_offline()", + GoOnline = "go_online()", ScheduleCandidateBondLess = "schedule_candidate_bond_less(uint256)", CandidateBondMore = "candidate_bond_more(uint256)", ExecuteCandidateBondLess = "execute_candidate_bond_less(address)", @@ -100,6 +105,11 @@ where | Action::DelegatorDelegationCount => FunctionModifier::View, Action::Delegate | Action::JoinCandidates + | Action::ScheduleLeaveCandidates + | Action::ExecuteLeaveCandidates + | Action::CancelLeaveCandidates + | Action::GoOffline + | Action::GoOnline | Action::ScheduleCandidateBondLess | Action::CandidateBondMore | Action::ExecuteCandidateBondLess @@ -124,6 +134,11 @@ where Action::CandidateDelegationCount => Self::candidate_delegation_count(handle), Action::DelegatorDelegationCount => Self::delegator_delegation_count(handle), Action::JoinCandidates => Self::join_candidates(handle), + Action::ScheduleLeaveCandidates => Self::schedule_leave_candidates(handle), + Action::ExecuteLeaveCandidates => Self::execute_leave_candidates(handle), + Action::CancelLeaveCandidates => Self::cancel_leave_candidates(handle), + Action::GoOffline => Self::go_offline(handle), + Action::GoOnline => Self::go_online(handle), Action::ScheduleCandidateBondLess => Self::schedule_candidate_bond_less(handle), Action::CandidateBondMore => Self::candidate_bond_more(handle), Action::ExecuteCandidateBondLess => Self::execute_candidate_bond_less(handle), @@ -300,6 +315,91 @@ where Ok(succeed(EvmDataWriter::new().write(true).build())) } + fn schedule_leave_candidates( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + let candidate_count = input.read()?; + + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::schedule_leave_candidates { + candidate_count, + }; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + + fn execute_leave_candidates(handle: &mut impl PrecompileHandle) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + let candidate = input.read::
()?.0; + let candidate = Runtime::AddressMapping::into_account_id(candidate); + let candidate_delegation_count = input.read()?; + + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::execute_leave_candidates { + candidate, + candidate_delegation_count, + }; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + + fn cancel_leave_candidates(handle: &mut impl PrecompileHandle) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + let candidate_count = input.read()?; + + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::cancel_leave_candidates { + candidate_count, + }; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + + fn go_offline(handle: &mut impl PrecompileHandle) -> EvmResult { + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::go_offline {}; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + + fn go_online(handle: &mut impl PrecompileHandle) -> EvmResult { + { + // Build call with origin. + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let call = pallet_parachain_staking::Call::::go_online {}; + + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + } + + Ok(succeed(EvmDataWriter::new().write(true).build())) + } + fn candidate_bond_more(handle: &mut impl PrecompileHandle) -> EvmResult { let mut input = EvmDataReader::new_skip_selector(handle.input())?; // Read input. From 10883d622838a86f802cfc9f095a55a129a92165 Mon Sep 17 00:00:00 2001 From: NZT48 Date: Mon, 21 Apr 2025 22:25:09 +0200 Subject: [PATCH 10/11] Addd is delegator, is candidate and is selected candidate --- precompiles/parachain-staking/src/lib.rs | 55 ++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/precompiles/parachain-staking/src/lib.rs b/precompiles/parachain-staking/src/lib.rs index 4ed2953..bc434b9 100644 --- a/precompiles/parachain-staking/src/lib.rs +++ b/precompiles/parachain-staking/src/lib.rs @@ -53,6 +53,9 @@ pub enum Action { Round = "round()", CandidateDelegationCount = "candidate_delegation_count(address)", DelegatorDelegationCount = "delegator_delegation_count(address)", + IsDelegator = "is_delegator(address)", + IsCandidate = "is_candidate(address)", + IsSelectedCandidate = "is_selected_candidate(address)", JoinCandidates = "join_candidates(uint256,uint256)", ScheduleLeaveCandidates = "schedule_leave_candidates(uint256)", ExecuteLeaveCandidates = "execute_leave_candidates(address,uint256)", @@ -98,6 +101,9 @@ where if let Err(err) = handle.check_function_modifier(match selector { Action::MinDelegation + | Action::IsDelegator + | Action::IsCandidate + | Action::IsSelectedCandidate | Action::Points | Action::CandidateCount | Action::Round @@ -128,6 +134,9 @@ where let result = match selector { Action::MinDelegation => Self::min_delegation(handle), + Action::IsDelegator => Self::is_delegator(handle), + Action::IsCandidate => Self::is_candidate(handle), + Action::IsSelectedCandidate => Self::is_selected_candidate(handle), Action::Points => Self::points(handle), Action::CandidateCount => Self::candidate_count(handle), Action::Round => Self::round(handle), @@ -188,6 +197,52 @@ where Ok(succeed(EvmDataWriter::new().write(min_nomination).build())) } + fn is_delegator(handle: &mut impl PrecompileHandle) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + let address = input.read::
()?.0; + let address = Runtime::AddressMapping::into_account_id(address); + + // Fetch info. + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + let is_delegator = pallet_parachain_staking::Pallet::::is_delegator(&address); + + // Build output. + Ok(succeed(EvmDataWriter::new().write(is_delegator).build())) + } + + fn is_candidate(handle: &mut impl PrecompileHandle) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + let address = input.read::
()?.0; + let address = Runtime::AddressMapping::into_account_id(address); + + // Fetch info. + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + let is_candidate = pallet_parachain_staking::Pallet::::is_candidate(&address); + + // Build output. + Ok(succeed(EvmDataWriter::new().write(is_candidate).build())) + } + + fn is_selected_candidate(handle: &mut impl PrecompileHandle) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + let address = input.read::
()?.0; + let address = Runtime::AddressMapping::into_account_id(address); + + // Fetch info. + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + let is_selected = + pallet_parachain_staking::Pallet::::is_selected_candidate(&address); + + // Build output. + Ok(succeed(EvmDataWriter::new().write(is_selected).build())) + } + fn points(handle: &mut impl PrecompileHandle) -> EvmResult { let mut input = EvmDataReader::new_skip_selector(handle.input())?; // Read input. From 915b9fec2945c0f83f9cae1aba3d1def5326d96d Mon Sep 17 00:00:00 2001 From: NZT48 Date: Mon, 21 Apr 2025 23:06:45 +0200 Subject: [PATCH 11/11] Update staking solidity interface --- Cargo.lock | 2 +- precompiles/parachain-staking/Cargo.toml | 4 +- .../parachain-staking/StakingInterface.sol | 260 ++++++------------ precompiles/parachain-staking/src/lib.rs | 105 +++++-- 4 files changed, 165 insertions(+), 206 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 062bf28..69a1644 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7781,7 +7781,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-parachain-staking" -version = "1.0.0" +version = "2.0.0" dependencies = [ "derive_more", "fp-evm", diff --git a/precompiles/parachain-staking/Cargo.toml b/precompiles/parachain-staking/Cargo.toml index 58a0c99..8551418 100644 --- a/precompiles/parachain-staking/Cargo.toml +++ b/precompiles/parachain-staking/Cargo.toml @@ -3,7 +3,7 @@ name = "pallet-evm-precompile-parachain-staking" authors = { workspace = true } description = "A Precompile to make parachain staking accessible to pallet-evm" edition = "2021" -version = "1.0.0" +version = "2.0.0" [dependencies] log = { workspace = true } @@ -17,7 +17,6 @@ pallet-parachain-staking = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } codec = { workspace = true, features = ["max-encoded-len"] } -# sp-consensus-slots = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-std = { workspace = true } @@ -51,7 +50,6 @@ std = [ "pallet-parachain-staking/std", "codec/std", "precompile-utils/std", - #"sp-consensus-slots/std", "sp-core/std", "sp-std/std", ] diff --git a/precompiles/parachain-staking/StakingInterface.sol b/precompiles/parachain-staking/StakingInterface.sol index ec93905..5ecf3ef 100644 --- a/precompiles/parachain-staking/StakingInterface.sol +++ b/precompiles/parachain-staking/StakingInterface.sol @@ -1,214 +1,160 @@ // SPDX-License-Identifier: GPL-3.0-only -pragma solidity >=0.8.3; - -/// @dev The ParachainStaking contract's address. -address constant PARACHAIN_STAKING_ADDRESS = 0x0000000000000000000000000000000000000800; - -/// @dev The ParachainStaking contract's instance. -ParachainStaking constant PARACHAIN_STAKING_CONTRACT = ParachainStaking( - PARACHAIN_STAKING_ADDRESS -); - -/// @author The Moonbeam Team -/// @title Pallet Parachain Staking Interface -/// @dev The interface through which solidity contracts will interact with Parachain Staking -/// We follow this same interface including four-byte function selectors, in the precompile that -/// wraps the pallet -/// @custom:address 0x0000000000000000000000000000000000000800 +pragma solidity >=0.8.0; + +/** + * @author The Moonbeam Team, modified by: OriginTrail Team + * @title The interface through which solidity contracts will interact with Parachain Staking + * We follow this same interface including four-byte function selectors, in the precompile that + * wraps the pallet + * Address : 0x0000000000000000000000000000000000000800 + */ + interface ParachainStaking { /// @dev Check whether the specified address is currently a staking delegator - /// @custom:selector fd8ab482 + /// Selector: 1f030587 /// @param delegator the address that we want to confirm is a delegator /// @return A boolean confirming whether the address is a delegator - function isDelegator(address delegator) external view returns (bool); + function is_delegator(address delegator) external view returns (bool); /// @dev Check whether the specified address is currently a collator candidate - /// @custom:selector d51b9e93 + /// Selector: 8545c833 /// @param candidate the address that we want to confirm is a collator andidate /// @return A boolean confirming whether the address is a collator candidate - function isCandidate(address candidate) external view returns (bool); + function is_candidate(address candidate) external view returns (bool); /// @dev Check whether the specifies address is currently a part of the active set - /// @custom:selector 740d7d2a + /// Selector: 8f6d27c7 /// @param candidate the address that we want to confirm is a part of the active set /// @return A boolean confirming whether the address is a part of the active set - function isSelectedCandidate( + function is_selected_candidate( address candidate ) external view returns (bool); /// @dev Total points awarded to all collators in a particular round - /// @custom:selector 9799b4e7 + /// Selector: 9799b4e7 /// @param round the round for which we are querying the points total /// @return The total points awarded to all collators in the round function points(uint256 round) external view returns (uint256); - /// @dev Total points awarded to a specific collator in a particular round. - /// A value of `0` may signify that no blocks were produced or that the storage for that round has been removed - /// @custom:selector bfea66ac - /// @param round the round for which we are querying the awarded points - /// @param candidate The candidate to whom the points are awarded - /// @return The total points awarded to the collator for the provided round - function awardedPoints( - uint32 round, - address candidate - ) external view returns (uint32); - - /// @dev The amount delegated in support of the candidate by the delegator - /// @custom:selector a73e51bc - /// @param delegator Who made this delegation - /// @param candidate The candidate for which the delegation is in support of - /// @return The amount of the delegation in support of the candidate by the delegator - function delegationAmount( - address delegator, - address candidate - ) external view returns (uint256); - - /// @dev Whether the delegation is in the top delegations - /// @custom:selector 91cc8657 - /// @param delegator Who made this delegation - /// @param candidate The candidate for which the delegation is in support of - /// @return If delegation is in top delegations (is counted) - function isInTopDelegations( - address delegator, - address candidate - ) external view returns (bool); - /// @dev Get the minimum delegation amount - /// @custom:selector 02985992 + /// Selector: 72ce8933 /// @return The minimum delegation amount - function minDelegation() external view returns (uint256); + function min_delegation() external view returns (uint256); /// @dev Get the CandidateCount weight hint - /// @custom:selector a9a981a3 + /// Selector: 4b1c4c29 /// @return The CandidateCount weight hint - function candidateCount() external view returns (uint256); + function candidate_count() external view returns (uint256); /// @dev Get the current round number - /// @custom:selector 146ca531 + /// Selector: 146ca531 /// @return The current round number function round() external view returns (uint256); /// @dev Get the CandidateDelegationCount weight hint - /// @custom:selector 2ec087eb + /// Selector: 815b796c /// @param candidate The address for which we are querying the nomination count /// @return The number of nominations backing the collator - function candidateDelegationCount( - address candidate - ) external view returns (uint32); - - /// @dev Get the CandidateAutoCompoundingDelegationCount weight hint - /// @custom:selector 905f0806 - /// @param candidate The address for which we are querying the auto compounding - /// delegation count - /// @return The number of auto compounding delegations - function candidateAutoCompoundingDelegationCount( + function candidate_delegation_count( address candidate - ) external view returns (uint32); + ) external view returns (uint256); /// @dev Get the DelegatorDelegationCount weight hint - /// @custom:selector 067ec822 + /// Selector: fbc51bca /// @param delegator The address for which we are querying the delegation count /// @return The number of delegations made by the delegator - function delegatorDelegationCount( + function delegator_delegation_count( address delegator ) external view returns (uint256); - /// @dev Get the selected candidates for the current round - /// @custom:selector bcf868a6 - /// @return The selected candidate accounts - function selectedCandidates() external view returns (address[] memory); - /// @dev Whether there exists a pending request for a delegation made by a delegator - /// @custom:selector 3b16def8 + /// Selector: 192e1db3 /// @param delegator the delegator that made the delegation /// @param candidate the candidate for which the delegation was made /// @return Whether a pending request exists for such delegation - function delegationRequestIsPending( + function delegation_request_is_pending( address delegator, address candidate ) external view returns (bool); + /// @dev Whether there exists a pending exit for delegator + /// Selector: dc3ec64b + /// @param delegator the delegator that made the exit request + /// @return Whether a pending exit exists for delegator + function delegator_exit_is_pending( + address delegator + ) external view returns (bool); + /// @dev Whether there exists a pending exit for candidate - /// @custom:selector 43443682 + /// Selector: eb613b8a /// @param candidate the candidate for which the exit request was made /// @return Whether a pending request exists for such delegation - function candidateExitIsPending( + function candidate_exit_is_pending( address candidate ) external view returns (bool); /// @dev Whether there exists a pending bond less request made by a candidate - /// @custom:selector d0deec11 + /// Selector: 26ab05fb /// @param candidate the candidate which made the request /// @return Whether a pending bond less request was made by the candidate - function candidateRequestIsPending( + function candidate_request_is_pending( address candidate ) external view returns (bool); - /// @dev Returns the percent value of auto-compound set for a delegation - /// @custom:selector b4d4c7fd - /// @param delegator the delegator that made the delegation - /// @param candidate the candidate for which the delegation was made - /// @return Percent of rewarded amount that is auto-compounded on each payout - function delegationAutoCompound( - address delegator, - address candidate - ) external view returns (uint8); - /// @dev Join the set of collator candidates - /// @custom:selector 1f2f83ad + /// Selector: 0a1bff60 /// @param amount The amount self-bonded by the caller to become a collator candidate /// @param candidateCount The number of candidates in the CandidatePool - function joinCandidates(uint256 amount, uint256 candidateCount) external; + function join_candidates(uint256 amount, uint256 candidateCount) external; /// @dev Request to leave the set of collator candidates - /// @custom:selector b1a3c1b7 + /// Selector: 60afbac6 /// @param candidateCount The number of candidates in the CandidatePool - function scheduleLeaveCandidates(uint256 candidateCount) external; + function schedule_leave_candidates(uint256 candidateCount) external; /// @dev Execute due request to leave the set of collator candidates - /// @custom:selector 3867f308 + /// Selector: 3fdc4c30 /// @param candidate The candidate address for which the pending exit request will be executed /// @param candidateDelegationCount The number of delegations for the candidate to be revoked - function executeLeaveCandidates( + function execute_leave_candidates( address candidate, uint256 candidateDelegationCount ) external; /// @dev Cancel request to leave the set of collator candidates - /// @custom:selector 9c76ebb4 + /// Selector: 0880b3e2 /// @param candidateCount The number of candidates in the CandidatePool - function cancelLeaveCandidates(uint256 candidateCount) external; + function cancel_leave_candidates(uint256 candidateCount) external; /// @dev Temporarily leave the set of collator candidates without unbonding - /// @custom:selector a6485ccd - function goOffline() external; + /// Selector: 767e0450 + function go_offline() external; - /// @dev Rejoin the set of collator candidates if previously had called `goOffline` - /// @custom:selector 6e5b676b - function goOnline() external; + /// @dev Rejoin the set of collator candidates if previously had called `go_offline` + /// Selector: d2f73ceb + function go_online() external; /// @dev Request to bond more for collator candidates - /// @custom:selector a52c8643 + /// Selector: c57bd3a8 /// @param more The additional amount self-bonded - function candidateBondMore(uint256 more) external; + function candidate_bond_more(uint256 more) external; /// @dev Request to bond less for collator candidates - /// @custom:selector 60744ae0 + /// Selector: 034c47bc /// @param less The amount to be subtracted from self-bond and unreserved - function scheduleCandidateBondLess(uint256 less) external; + function schedule_candidate_bond_less(uint256 less) external; /// @dev Execute pending candidate bond request - /// @custom:selector 2e290290 + /// Selector: a9a2b8b7 /// @param candidate The address for the candidate for which the request will be executed - function executeCandidateBondLess(address candidate) external; + function execute_candidate_bond_less(address candidate) external; /// @dev Cancel pending candidate bond request - /// @custom:selector b5ad5f07 - function cancelCandidateBondLess() external; + /// Selector: 583d0fdc + function cancel_candidate_bond_less() external; - /// @notice DEPRECATED use delegateWithAutoCompound instead for lower weight and better UX /// @dev Make a delegation in support of a collator candidate - /// @custom:selector 829f5ee3 + /// Selector: 829f5ee3 /// @param candidate The address of the supported collator candidate /// @param amount The amount bonded in support of the collator candidate /// @param candidateDelegationCount The number of delegations in support of the candidate @@ -220,86 +166,54 @@ interface ParachainStaking { uint256 delegatorDelegationCount ) external; - /// @dev Make a delegation in support of a collator candidate - /// @custom:selector 4b8bc9bf - /// @param candidate The address of the supported collator candidate - /// @param amount The amount bonded in support of the collator candidate - /// @param autoCompound The percent of reward that should be auto-compounded - /// @param candidateDelegationCount The number of delegations in support of the candidate - /// @param candidateAutoCompoundingDelegationCount The number of auto-compounding delegations - /// in support of the candidate - /// @param delegatorDelegationCount The number of existing delegations by the caller - function delegateWithAutoCompound( - address candidate, - uint256 amount, - uint8 autoCompound, - uint256 candidateDelegationCount, - uint256 candidateAutoCompoundingDelegationCount, + /// @dev Request to leave the set of delegators + /// Selector: 65a5bbd0 + function schedule_leave_delegators() external; + + /// @dev Execute request to leave the set of delegators and revoke all delegations + /// Selector: a84a7468 + /// @param delegator The leaving delegator + /// @param delegatorDelegationCount The number of active delegations to be revoked by delegator + function execute_leave_delegators( + address delegator, uint256 delegatorDelegationCount ) external; + /// @dev Cancel request to leave the set of delegators + /// Selector: 2a987643 + function cancel_leave_delegators() external; + /// @dev Request to revoke an existing delegation - /// @custom:selector 1a1c740c + /// Selector: 22266e75 /// @param candidate The address of the collator candidate which will no longer be supported - function scheduleRevokeDelegation(address candidate) external; + function schedule_revoke_delegation(address candidate) external; /// @dev Bond more for delegators with respect to a specific collator candidate - /// @custom:selector 0465135b + /// Selector: f8331108 /// @param candidate The address of the collator candidate for which delegation shall increase /// @param more The amount by which the delegation is increased - function delegatorBondMore(address candidate, uint256 more) external; + function delegator_bond_more(address candidate, uint256 more) external; /// @dev Request to bond less for delegators with respect to a specific collator candidate - /// @custom:selector c172fd2b + /// Selector: 00043acf /// @param candidate The address of the collator candidate for which delegation shall decrease /// @param less The amount by which the delegation is decreased (upon execution) - function scheduleDelegatorBondLess( + function schedule_delegator_bond_less( address candidate, uint256 less ) external; /// @dev Execute pending delegation request (if exists && is due) - /// @custom:selector e98c8abe + /// Selector: e42366a6 /// @param delegator The address of the delegator /// @param candidate The address of the candidate - function executeDelegationRequest( + function execute_delegation_request( address delegator, address candidate ) external; /// @dev Cancel pending delegation request (already made in support of input by caller) - /// @custom:selector c90eee83 + /// Selector: 7284cf50 /// @param candidate The address of the candidate - function cancelDelegationRequest(address candidate) external; - - /// @dev Sets an auto-compound value for a delegation - /// @custom:selector faa1786f - /// @param candidate The address of the supported collator candidate - /// @param value The percent of reward that should be auto-compounded - /// @param candidateAutoCompoundingDelegationCount The number of auto-compounding delegations - /// in support of the candidate - /// @param delegatorDelegationCount The number of existing delegations by the caller - function setAutoCompound( - address candidate, - uint8 value, - uint256 candidateAutoCompoundingDelegationCount, - uint256 delegatorDelegationCount - ) external; - - /// @dev Fetch the total staked amount of a delegator, regardless of the - /// candidate. - /// @custom:selector e6861713 - /// @param delegator Address of the delegator. - /// @return Total amount of stake. - function getDelegatorTotalStaked( - address delegator - ) external view returns (uint256); - - /// @dev Fetch the total staked towards a candidate. - /// @custom:selector bc5a1043 - /// @param candidate Address of the candidate. - /// @return Total amount of stake. - function getCandidateTotalCounted( - address candidate - ) external view returns (uint256); + function cancel_delegation_request(address candidate) external; } diff --git a/precompiles/parachain-staking/src/lib.rs b/precompiles/parachain-staking/src/lib.rs index bc434b9..a58b8b2 100644 --- a/precompiles/parachain-staking/src/lib.rs +++ b/precompiles/parachain-staking/src/lib.rs @@ -1,45 +1,22 @@ -// Copyright 2019-2022 PureStake Inc. -// Copyright 2022 Stake Technologies -// Copyright 2022 TraceLabs -// This file is part of AssetsERC20 package, originally developed by Purestake Inc. -// AssetsERC20 package used in NeuroWeb Parachain 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. - -// 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 AssetsERC20. If not, see . +// Copyright 2019-2025 PureStake Inc. +// Copyright 2025 TraceLabs #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(test, feature(assert_matches))] use fp_evm::{IsPrecompileResult, PrecompileHandle, PrecompileOutput}; -use frame_support::traits::fungibles::approvals::Inspect as ApprovalInspect; -use frame_support::traits::fungibles::metadata::Inspect as MetadataInspect; -use frame_support::traits::fungibles::Inspect; +use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; use frame_support::traits::OriginTrait; -use frame_support::{ - dispatch::{GetDispatchInfo, PostDispatchInfo}, - sp_runtime::traits::StaticLookup, -}; use pallet_evm::{AddressMapping, PrecompileSet}; use precompile_utils::{ - keccak256, revert, succeed, Address, Bytes, EvmData, EvmDataReader, EvmDataWriter, EvmResult, - FunctionModifier, LogExt, LogsBuilder, PrecompileHandleExt, RuntimeHelper, + revert, succeed, Address, EvmData, EvmDataReader, EvmDataWriter, EvmResult, FunctionModifier, + PrecompileHandleExt, RuntimeHelper, }; use sp_core::{Get, H160, U256}; -use sp_runtime::traits::{Bounded, Dispatchable, Zero}; +use sp_runtime::traits::Dispatchable; use sp_std::{ convert::{TryFrom, TryInto}, marker::PhantomData, - vec::Vec, }; pub type BalanceOf = ::Balance; @@ -56,6 +33,8 @@ pub enum Action { IsDelegator = "is_delegator(address)", IsCandidate = "is_candidate(address)", IsSelectedCandidate = "is_selected_candidate(address)", + CandidateExitIsPending = "candidate_exit_is_pending(address)", + CandidateRequestIsPending = "candidate_request_is_pending(address)", JoinCandidates = "join_candidates(uint256,uint256)", ScheduleLeaveCandidates = "schedule_leave_candidates(uint256)", ExecuteLeaveCandidates = "execute_leave_candidates(address,uint256)", @@ -107,6 +86,8 @@ where | Action::Points | Action::CandidateCount | Action::Round + | Action::CandidateExitIsPending + | Action::CandidateRequestIsPending | Action::CandidateDelegationCount | Action::DelegatorDelegationCount => FunctionModifier::View, Action::Delegate @@ -142,6 +123,8 @@ where Action::Round => Self::round(handle), Action::CandidateDelegationCount => Self::candidate_delegation_count(handle), Action::DelegatorDelegationCount => Self::delegator_delegation_count(handle), + Action::CandidateExitIsPending => Self::candidate_exit_is_pending(handle), + Action::CandidateRequestIsPending => Self::candidate_request_is_pending(handle), Action::JoinCandidates => Self::join_candidates(handle), Action::ScheduleLeaveCandidates => Self::schedule_leave_candidates(handle), Action::ExecuteLeaveCandidates => Self::execute_leave_candidates(handle), @@ -348,6 +331,70 @@ where Ok(succeed(EvmDataWriter::new().write(result).build())) } + fn candidate_exit_is_pending( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + + // Only argument is candidate + let candidate = Runtime::AddressMapping::into_account_id(input.read::
()?.0); + + // Fetch info. + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + + // If we are not able to get delegator state, we return false + // Users can call `is_candidate` to determine when this happens + let pending = if let Some(state) = + >::candidate_info(&candidate) + { + state.is_leaving() + } else { + log::trace!( + target: "staking-precompile", + "Candidate state for {:?} not found, so pending exit is false", + candidate + ); + false + }; + + // Build output. + Ok(succeed(EvmDataWriter::new().write(pending).build())) + } + + fn candidate_request_is_pending( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + let mut input = EvmDataReader::new_skip_selector(handle.input())?; + // Read input. + input.expect_arguments(1)?; + + // Only argument is candidate + let candidate = Runtime::AddressMapping::into_account_id(input.read::
()?.0); + + // Fetch info. + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + + // If we are not able to get candidate metadata, we return false + // Users can call `is_candidate` to determine when this happens + let pending = if let Some(state) = + >::candidate_info(&candidate) + { + state.request.is_some() + } else { + log::trace!( + target: "staking-precompile", + "Candidate metadata for {:?} not found, so pending request is false", + candidate + ); + false + }; + + // Build output. + Ok(succeed(EvmDataWriter::new().write(pending).build())) + } + fn join_candidates(handle: &mut impl PrecompileHandle) -> EvmResult { let mut input = EvmDataReader::new_skip_selector(handle.input())?;