use crate::deps::system_contracts::load_builtin_contract;
use crate::node::ImpersonationManager;
use anvil_zksync_config::types::SystemContractsOptions;
use zksync_contracts::{
read_bootloader_code, read_sys_contract_bytecode, BaseSystemContracts,
BaseSystemContractsHashes, ContractLanguage, SystemContractCode,
};
use zksync_multivm::interface::TxExecutionMode;
use zksync_types::bytecode::BytecodeHash;
use zksync_types::{Address, ProtocolVersionId};
#[derive(Debug, Clone)]
pub struct SystemContracts {
pub protocol_version: ProtocolVersionId,
baseline_contracts: BaseSystemContracts,
playground_contracts: BaseSystemContracts,
fee_estimate_contracts: BaseSystemContracts,
baseline_impersonating_contracts: BaseSystemContracts,
fee_estimate_impersonating_contracts: BaseSystemContracts,
use_evm_emulator: bool,
pub use_zkos: bool,
}
impl SystemContracts {
pub fn from_options(
options: SystemContractsOptions,
protocol_version: ProtocolVersionId,
use_evm_emulator: bool,
use_zkos: bool,
) -> Self {
tracing::info!(
%protocol_version,
use_evm_emulator,
use_zkos,
"initializing system contracts"
);
Self {
protocol_version,
baseline_contracts: baseline_contracts(options, protocol_version, use_evm_emulator),
playground_contracts: playground(options, protocol_version, use_evm_emulator),
fee_estimate_contracts: fee_estimate_contracts(
options,
protocol_version,
use_evm_emulator,
),
baseline_impersonating_contracts: baseline_impersonating_contracts(
options,
protocol_version,
use_evm_emulator,
),
fee_estimate_impersonating_contracts: fee_estimate_impersonating_contracts(
options,
protocol_version,
use_evm_emulator,
),
use_evm_emulator,
use_zkos,
}
}
pub fn allow_no_target(&self) -> bool {
self.use_zkos || self.use_evm_emulator
}
pub fn contracts_for_l2_call(&self) -> &BaseSystemContracts {
self.contracts(TxExecutionMode::EthCall, false)
}
pub fn contracts_for_fee_estimate(&self, impersonating: bool) -> &BaseSystemContracts {
self.contracts(TxExecutionMode::EstimateFee, impersonating)
}
pub fn contracts(
&self,
execution_mode: TxExecutionMode,
impersonating: bool,
) -> &BaseSystemContracts {
match (execution_mode, impersonating) {
(TxExecutionMode::VerifyExecute, false) => &self.baseline_contracts,
(TxExecutionMode::EstimateFee, false) => &self.fee_estimate_contracts,
(TxExecutionMode::EthCall, false) => &self.playground_contracts,
(TxExecutionMode::VerifyExecute, true) => &self.baseline_impersonating_contracts,
(TxExecutionMode::EstimateFee, true) => &self.fee_estimate_impersonating_contracts,
(TxExecutionMode::EthCall, true) => {
panic!("Account impersonating with eth_call is not supported")
}
}
}
pub fn base_system_contracts_hashes(&self) -> BaseSystemContractsHashes {
self.baseline_contracts.hashes()
}
pub fn system_contracts_for_initiator(
&self,
impersonation: &ImpersonationManager,
initiator: &Address,
) -> BaseSystemContracts {
if impersonation.is_impersonating(initiator) {
tracing::info!("Executing tx from impersonated account {initiator:?}");
self.contracts(TxExecutionMode::VerifyExecute, true).clone()
} else {
self.contracts(TxExecutionMode::VerifyExecute, false)
.clone()
}
}
}
fn bsc_load_with_bootloader(
bootloader_bytecode: Vec<u8>,
options: SystemContractsOptions,
protocol_version: ProtocolVersionId,
use_evm_emulator: bool,
) -> BaseSystemContracts {
let hash = BytecodeHash::for_bytecode(&bootloader_bytecode);
let bootloader = SystemContractCode {
code: bootloader_bytecode,
hash: hash.value(),
};
let aa_bytecode = match options {
SystemContractsOptions::BuiltIn => {
load_builtin_contract(protocol_version, "DefaultAccount")
}
SystemContractsOptions::Local => {
read_sys_contract_bytecode("", "DefaultAccount", ContractLanguage::Sol)
}
SystemContractsOptions::BuiltInWithoutSecurity => {
load_builtin_contract(protocol_version, "DefaultAccountNoSecurity")
}
};
let aa_hash = BytecodeHash::for_bytecode(&aa_bytecode);
let default_aa = SystemContractCode {
code: aa_bytecode,
hash: aa_hash.value(),
};
let evm_emulator = if use_evm_emulator {
let evm_emulator_bytecode = match options {
SystemContractsOptions::Local => {
read_sys_contract_bytecode("", "EvmEmulator", ContractLanguage::Yul)
}
SystemContractsOptions::BuiltIn | SystemContractsOptions::BuiltInWithoutSecurity => {
load_builtin_contract(protocol_version, "EvmEmulator")
}
};
let evm_emulator_hash = BytecodeHash::for_bytecode(&evm_emulator_bytecode);
Some(SystemContractCode {
code: evm_emulator_bytecode,
hash: evm_emulator_hash.value(),
})
} else {
None
};
BaseSystemContracts {
bootloader,
default_aa,
evm_emulator,
}
}
fn playground(
options: SystemContractsOptions,
protocol_version: ProtocolVersionId,
use_evm_emulator: bool,
) -> BaseSystemContracts {
let bootloader_bytecode = match options {
SystemContractsOptions::BuiltIn | SystemContractsOptions::BuiltInWithoutSecurity => {
load_builtin_contract(protocol_version, "playground_batch")
}
SystemContractsOptions::Local => read_bootloader_code("playground_batch"),
};
bsc_load_with_bootloader(
bootloader_bytecode,
options,
protocol_version,
use_evm_emulator,
)
}
fn fee_estimate_contracts(
options: SystemContractsOptions,
protocol_version: ProtocolVersionId,
use_evm_emulator: bool,
) -> BaseSystemContracts {
let bootloader_bytecode = match options {
SystemContractsOptions::BuiltIn | SystemContractsOptions::BuiltInWithoutSecurity => {
load_builtin_contract(protocol_version, "fee_estimate")
}
SystemContractsOptions::Local => read_bootloader_code("fee_estimate"),
};
bsc_load_with_bootloader(
bootloader_bytecode,
options,
protocol_version,
use_evm_emulator,
)
}
fn fee_estimate_impersonating_contracts(
options: SystemContractsOptions,
protocol_version: ProtocolVersionId,
use_evm_emulator: bool,
) -> BaseSystemContracts {
let bootloader_bytecode = match options {
SystemContractsOptions::BuiltIn | SystemContractsOptions::BuiltInWithoutSecurity => {
load_builtin_contract(protocol_version, "fee_estimate_impersonating")
}
SystemContractsOptions::Local => read_bootloader_code("fee_estimate"),
};
bsc_load_with_bootloader(
bootloader_bytecode,
options,
protocol_version,
use_evm_emulator,
)
}
fn baseline_contracts(
options: SystemContractsOptions,
protocol_version: ProtocolVersionId,
use_evm_emulator: bool,
) -> BaseSystemContracts {
let bootloader_bytecode = match options {
SystemContractsOptions::BuiltIn | SystemContractsOptions::BuiltInWithoutSecurity => {
load_builtin_contract(protocol_version, "proved_batch")
}
SystemContractsOptions::Local => read_bootloader_code("proved_batch"),
};
bsc_load_with_bootloader(
bootloader_bytecode,
options,
protocol_version,
use_evm_emulator,
)
}
fn baseline_impersonating_contracts(
options: SystemContractsOptions,
protocol_version: ProtocolVersionId,
use_evm_emulator: bool,
) -> BaseSystemContracts {
let bootloader_bytecode = match options {
SystemContractsOptions::BuiltIn | SystemContractsOptions::BuiltInWithoutSecurity => {
load_builtin_contract(protocol_version, "proved_batch_impersonating")
}
SystemContractsOptions::Local => read_bootloader_code("proved_batch"),
};
bsc_load_with_bootloader(
bootloader_bytecode,
options,
protocol_version,
use_evm_emulator,
)
}