Skip to content

pre fund contract [WIP] #15

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 66 additions & 3 deletions frame/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ use scale_info::TypeInfo;
// Substrate
use frame_support::{
dispatch::{DispatchResultWithPostInfo, Pays, PostDispatchInfo},
ensure,
storage::KeyPrefixIterator,
traits::{
fungible::{Balanced, Credit, Debt},
Expand All @@ -103,9 +104,8 @@ use fp_account::AccountId20;
use fp_evm::GenesisAccount;
pub use fp_evm::{
Account, AccountProvider, CallInfo, CreateInfo, ExecutionInfoV2 as ExecutionInfo,
FeeCalculator, IsPrecompileResult, LinearCostPrecompile, Log, Precompile, PrecompileFailure,
PrecompileHandle, PrecompileOutput, PrecompileResult, PrecompileSet,
TransactionValidationError, Vicinity,
FeeCalculator, IsPrecompileResult, Log, Precompile, PrecompileFailure, PrecompileHandle,
PrecompileOutput, PrecompileResult, PrecompileSet, TransactionValidationError, Vicinity,
};

pub use self::{
Expand Down Expand Up @@ -413,6 +413,7 @@ pub mod pallet {
access_list: Vec<(H160, Vec<H256>)>,
) -> DispatchResultWithPostInfo {
T::CallOrigin::ensure_address_origin(&source, origin)?;
Self::ensure_balance_for_contract_creation(&source)?;

let whitelist = <WhitelistedCreators<T>>::get();
let whitelist_disabled = <DisableWhitelistCheck<T>>::get();
Expand Down Expand Up @@ -453,6 +454,15 @@ pub mod pallet {
value: create_address,
..
} => {
let mini_balance = <<T as Config>::Currency as Currency<
<<T as Config>::AccountProvider as AccountProvider>::AccountId,
>>::minimum_balance();
T::Currency::transfer(
&T::AddressMapping::into_account_id(source),
&T::AddressMapping::into_account_id(create_address),
mini_balance,
ExistenceRequirement::AllowDeath,
)?;
Pallet::<T>::deposit_event(Event::<T>::Created {
address: create_address,
});
Expand Down Expand Up @@ -504,6 +514,7 @@ pub mod pallet {
access_list: Vec<(H160, Vec<H256>)>,
) -> DispatchResultWithPostInfo {
T::CallOrigin::ensure_address_origin(&source, origin)?;
Self::ensure_balance_for_contract_creation(&source)?;

let whitelist = <WhitelistedCreators<T>>::get();
let whitelist_disabled = <DisableWhitelistCheck<T>>::get();
Expand Down Expand Up @@ -545,6 +556,15 @@ pub mod pallet {
value: create_address,
..
} => {
let mini_balance = <<T as Config>::Currency as Currency<
<<T as Config>::AccountProvider as AccountProvider>::AccountId,
>>::minimum_balance();
T::Currency::transfer(
&T::AddressMapping::into_account_id(source),
&T::AddressMapping::into_account_id(create_address),
mini_balance,
ExistenceRequirement::AllowDeath,
)?;
Pallet::<T>::deposit_event(Event::<T>::Created {
address: create_address,
});
Expand Down Expand Up @@ -643,6 +663,10 @@ pub mod pallet {
Undefined,
/// Origin is not allowed to perform the operation.
NotAllowed,
/// Not enough balance to pay existential deposit
BalanceLowForExistentialDeposit,
/// Token transfer to new contract failed
TransferToNewContractFailed,
/// Address not allowed to deploy contracts either via CREATE or CALL(CREATE).
CreateOriginNotAllowed,
}
Expand Down Expand Up @@ -1095,6 +1119,45 @@ impl<T: Config> Pallet<T> {

T::FindAuthor::find_author(pre_runtime_digests).unwrap_or_default()
}

/// Ensure balance to pre fund contract creation.
pub fn ensure_balance_for_contract_creation(source: &H160) -> Result<(), Error<T>> {
let account_id = T::AddressMapping::into_account_id(*source);
let balance =
T::Currency::reducible_balance(&account_id, Preservation::Preserve, Fortitude::Polite);

let balance = UniqueSaturatedInto::<u64>::unique_saturated_into(balance);

let mini_balance = <<T as Config>::Currency as Currency<
<<T as Config>::AccountProvider as AccountProvider>::AccountId,
>>::minimum_balance();

let mini_balance = UniqueSaturatedInto::<u64>::unique_saturated_into(mini_balance);

ensure!(
balance >= mini_balance,
Error::<T>::BalanceLowForExistentialDeposit
);
Ok(())
}

/// transfer existential deposit to new contract
pub fn transfer_minimal_to_new_contract(
source: &H160,
create_address: &H160,
) -> Result<(), Error<T>> {
let mini_balance = <<T as Config>::Currency as Currency<
<<T as Config>::AccountProvider as AccountProvider>::AccountId,
>>::minimum_balance();
T::Currency::transfer(
&T::AddressMapping::into_account_id(*source),
&T::AddressMapping::into_account_id(*create_address),
mini_balance,
ExistenceRequirement::AllowDeath,
)
.map_err(|_| Error::<T>::TransferToNewContractFailed)?;
Ok(())
}
}

/// Handle withdrawing, refunding and depositing of transaction fees.
Expand Down
45 changes: 40 additions & 5 deletions frame/evm/src/runner/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,10 @@ where
proof_size_base_cost: Option<u64>,
config: &evm::Config,
) -> Result<CreateInfo, RunnerError<Self::Error>> {
Pallet::<T>::ensure_balance_for_contract_creation(&source).map_err(|_| RunnerError {
error: Error::<T>::BalanceLow,
weight: Weight::zero(),
})?;
let measured_proof_size_before = get_proof_size().unwrap_or_default();
let (_, weight) = T::FeeCalculator::min_gas_price();

Expand Down Expand Up @@ -609,7 +613,7 @@ where
)?;
}
let precompiles = T::PrecompilesValue::get();
Self::execute(
let result = Self::execute(
source,
value,
gas_limit,
Expand All @@ -628,7 +632,21 @@ where
executor.transact_create(source, value, init, gas_limit, access_list);
(reason, address)
},
)
);
if let Ok(CreateInfo {
exit_reason: ExitReason::Succeed(_),
value: create_address,
..
}) = &result
{
Pallet::<T>::transfer_minimal_to_new_contract(&source, create_address).map_err(
|_| RunnerError {
error: Error::<T>::BalanceLow,
weight: Weight::default(),
},
)?;
}
result
}

fn create2(
Expand All @@ -649,6 +667,10 @@ where
proof_size_base_cost: Option<u64>,
config: &evm::Config,
) -> Result<CreateInfo, RunnerError<Self::Error>> {
Pallet::<T>::ensure_balance_for_contract_creation(&source).map_err(|_| RunnerError {
error: Error::<T>::BalanceLow,
weight: Weight::zero(),
})?;
let measured_proof_size_before = get_proof_size().unwrap_or_default();
let (_, weight) = T::FeeCalculator::min_gas_price();

Expand All @@ -662,7 +684,6 @@ where
weight: Weight::zero(),
});
}

Self::validate(
source,
None,
Expand All @@ -681,7 +702,7 @@ where
}
let precompiles = T::PrecompilesValue::get();
let code_hash = H256::from(sp_io::hashing::keccak_256(&init));
Self::execute(
let result = Self::execute(
source,
value,
gas_limit,
Expand All @@ -704,7 +725,21 @@ where
executor.transact_create2(source, value, init, salt, gas_limit, access_list);
(reason, address)
},
)
);
if let Ok(CreateInfo {
exit_reason: ExitReason::Succeed(_),
value: create_address,
..
}) = &result
{
Pallet::<T>::transfer_minimal_to_new_contract(&source, create_address).map_err(
|_| RunnerError {
error: Error::<T>::BalanceLow,
weight: Weight::default(),
},
)?;
}
result
}
}

Expand Down
Loading