Skip to content
Merged
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
22 changes: 21 additions & 1 deletion crates/common/src/transactions/receipt.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
use alloy_network::{AnyNetwork, AnyTransactionReceipt, Network, TransactionResponse};
use alloy_primitives::Address;
use alloy_provider::{
Provider,
network::{ReceiptResponse, TransactionBuilder},
};
use alloy_rpc_types::BlockId;
use alloy_rpc_types::{BlockId, TransactionReceipt};
use eyre::Result;
use foundry_common_fmt::{UIfmt, UIfmtReceiptExt, get_pretty_receipt_attr};
use serde::{Deserialize, Serialize};
use tempo_alloy::rpc::TempoTransactionReceipt;

/// Helper trait providing `contract_address` setter for generic `ReceiptResponse`
pub trait FoundryReceiptResponse {
/// Sets address of the created contract, or `None` if the transaction was not a deployment.
fn set_contract_address(&mut self, contract_address: Address);
}

impl FoundryReceiptResponse for TransactionReceipt {
fn set_contract_address(&mut self, contract_address: Address) {
self.contract_address = Some(contract_address);
}
}

impl FoundryReceiptResponse for TempoTransactionReceipt {
fn set_contract_address(&mut self, contract_address: Address) {
self.contract_address = Some(contract_address);
}
}

/// Helper type to carry a transaction along with an optional revert reason
#[derive(Clone, Debug, Serialize, Deserialize)]
Expand Down
22 changes: 17 additions & 5 deletions crates/evm/core/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ use crate::{
backend::{DatabaseExt, JournaledState, LocalForkId},
constants::DEFAULT_CREATE2_DEPLOYER_CODEHASH,
};
use alloy_consensus::{constants::KECCAK_EMPTY, transaction::SignerRecoverable};
use alloy_consensus::{
SignableTransaction, Signed, constants::KECCAK_EMPTY, transaction::SignerRecoverable,
};
use alloy_evm::{
EthEvmFactory, Evm, EvmEnv, EvmFactory, FromRecoveredTx, eth::EthEvmContext,
precompiles::PrecompilesMap,
};
use alloy_network::{Ethereum, Network};
use alloy_primitives::{Address, B256, Bytes, U256};
use alloy_primitives::{Address, B256, Bytes, Signature, U256};
use alloy_rlp::Decodable;
use foundry_common::FoundryTransactionBuilder;
use foundry_common::{FoundryReceiptResponse, FoundryTransactionBuilder, fmt::UIfmt};
use foundry_config::FromEvmVersion;
use foundry_fork_db::{DatabaseError, ForkBlockEnv};
use op_revm::OpHaltReason;
Expand All @@ -38,6 +40,7 @@ use revm::{
},
primitives::hardfork::SpecId,
};
use serde::{Deserialize, Serialize};
use tempo_alloy::TempoNetwork;
use tempo_chainspec::hardfork::TempoHardfork;
use tempo_evm::evm::TempoEvmFactory;
Expand Down Expand Up @@ -78,8 +81,17 @@ impl IntoInstructionResult for TempoHaltReason {
/// Foundry's supertrait associating [Network] with [FoundryEvmFactory]
pub trait FoundryEvmNetwork: Copy + Debug + Default + 'static {
type Network: Network<
TxEnvelope: Decodable + SignerRecoverable,
TransactionRequest: FoundryTransactionBuilder<Self::Network>,
TxEnvelope: Decodable
+ SignerRecoverable
+ From<Signed<<Self::Network as Network>::UnsignedTx>>
+ for<'d> Deserialize<'d>
+ Serialize
+ UIfmt,
UnsignedTx: SignableTransaction<Signature>,
TransactionRequest: FoundryTransactionBuilder<Self::Network>
+ for<'d> Deserialize<'d>
+ Serialize,
ReceiptResponse: FoundryReceiptResponse,
>;
type EvmFactory: FoundryEvmFactory<Tx: FromRecoveredTx<<Self::Network as Network>::TxEnvelope>>;
}
Expand Down
28 changes: 7 additions & 21 deletions crates/script/src/broadcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,10 @@ use foundry_common::{
shell,
};
use foundry_config::Config;
use foundry_evm::core::evm::EthEvmNetwork;
use foundry_evm::core::evm::FoundryEvmNetwork;
use foundry_wallets::{TempoAccessKeyConfig, WalletSigner, wallet_browser::signer::BrowserSigner};
use futures::{FutureExt, StreamExt, future::join_all, stream::FuturesUnordered};
use itertools::Itertools;
use serde::{Deserialize, Serialize};

pub async fn estimate_gas<N: Network, P: Provider<N>>(
tx: &mut N::TransactionRequest,
Expand Down Expand Up @@ -265,24 +264,16 @@ impl<N: Network> SendTransactionsKind<N> {
/// State after we have bundled all
/// [`TransactionWithMetadata`](forge_script_sequence::TransactionWithMetadata) objects into a
/// single [`ScriptSequenceKind`] object containing one or more script sequences.
pub struct BundledState<N: Network>
where
N::TxEnvelope: for<'d> Deserialize<'d> + Serialize,
N::TransactionRequest: for<'d> Deserialize<'d> + Serialize,
{
pub struct BundledState<FEN: FoundryEvmNetwork> {
pub args: ScriptArgs,
pub script_config: ScriptConfig<EthEvmNetwork>,
pub script_config: ScriptConfig<FEN>,
pub script_wallets: Wallets,
pub browser_wallet: Option<BrowserSigner<N>>,
pub browser_wallet: Option<BrowserSigner<FEN::Network>>,
pub build_data: LinkedBuildData,
pub sequence: ScriptSequenceKind<N>,
pub sequence: ScriptSequenceKind<FEN::Network>,
}

impl<N: Network> BundledState<N>
where
N::TxEnvelope: for<'d> Deserialize<'d> + Serialize,
N::TransactionRequest: for<'d> Deserialize<'d> + Serialize,
{
impl<FEN: FoundryEvmNetwork> BundledState<FEN> {
pub async fn wait_for_pending(mut self) -> Result<Self> {
let progress = ScriptProgress::default();
let progress_ref = &progress;
Expand Down Expand Up @@ -317,12 +308,7 @@ where
}

/// Broadcasts transactions from all sequences.
pub async fn broadcast(mut self) -> Result<BroadcastedState<N>>
where
N::TxEnvelope: From<Signed<N::UnsignedTx>>,
N::UnsignedTx: SignableTransaction<Signature>,
N::TransactionRequest: FoundryTransactionBuilder<N>,
{
pub async fn broadcast(mut self) -> Result<BroadcastedState<FEN>> {
let required_addresses = self
.sequence
.sequences()
Expand Down
32 changes: 16 additions & 16 deletions crates/script/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
ScriptArgs, ScriptConfig, broadcast::BundledState, execute::LinkedState,
multi_sequence::MultiChainSequence, sequence::ScriptSequenceKind,
};
use alloy_network::{AnyNetwork, Ethereum};
use alloy_network::AnyNetwork;
use alloy_primitives::{B256, Bytes};
use alloy_provider::Provider;
use eyre::{OptionExt, Result};
Expand All @@ -18,7 +18,7 @@ use foundry_compilers::{
info::ContractInfo,
utils::source_files_iter,
};
use foundry_evm::{core::evm::EthEvmNetwork, traces::debug::ContractSources};
use foundry_evm::{core::evm::FoundryEvmNetwork, traces::debug::ContractSources};
use foundry_linking::Linker;
use foundry_wallets::wallet_browser::signer::BrowserSigner;
use std::{path::PathBuf, str::FromStr, sync::Arc};
Expand All @@ -41,9 +41,9 @@ impl BuildData {

/// Links contracts. Uses CREATE2 linking when possible, otherwise falls back to
/// default linking with sender nonce and address.
pub async fn link(
pub async fn link<FEN: FoundryEvmNetwork>(
self,
script_config: &ScriptConfig<EthEvmNetwork>,
script_config: &ScriptConfig<FEN>,
) -> Result<LinkedBuildData> {
let create2_deployer = script_config.evm_opts.create2_deployer;
let can_use_create2 = if let Some(fork_url) = &script_config.evm_opts.fork_url {
Expand Down Expand Up @@ -157,17 +157,17 @@ impl LinkedBuildData {
}

/// First state basically containing only inputs of the user.
pub struct PreprocessedState {
pub struct PreprocessedState<FEN: FoundryEvmNetwork> {
pub args: ScriptArgs,
pub script_config: ScriptConfig<EthEvmNetwork>,
pub script_config: ScriptConfig<FEN>,
pub script_wallets: Wallets,
pub browser_wallet: Option<BrowserSigner<Ethereum>>,
pub browser_wallet: Option<BrowserSigner<FEN::Network>>,
}

impl PreprocessedState {
impl<FEN: FoundryEvmNetwork> PreprocessedState<FEN> {
/// Parses user input and compiles the contracts depending on script target.
/// After compilation, finds exact [ArtifactId] of the target contract.
pub fn compile(self) -> Result<CompiledState> {
pub fn compile(self) -> Result<CompiledState<FEN>> {
let Self { args, script_config, script_wallets, browser_wallet } = self;
let project = script_config.config.project()?;

Expand Down Expand Up @@ -243,17 +243,17 @@ impl PreprocessedState {
}

/// State after we have determined and compiled target contract to be executed.
pub struct CompiledState {
pub struct CompiledState<FEN: FoundryEvmNetwork> {
pub args: ScriptArgs,
pub script_config: ScriptConfig<EthEvmNetwork>,
pub script_config: ScriptConfig<FEN>,
pub script_wallets: Wallets,
pub browser_wallet: Option<BrowserSigner<Ethereum>>,
pub browser_wallet: Option<BrowserSigner<FEN::Network>>,
pub build_data: BuildData,
}

impl CompiledState {
impl<FEN: FoundryEvmNetwork> CompiledState<FEN> {
/// Uses provided sender address to compute library addresses and link contracts with them.
pub async fn link(self) -> Result<LinkedState> {
pub async fn link(self) -> Result<LinkedState<FEN>> {
let Self { args, script_config, script_wallets, browser_wallet, build_data } = self;

let build_data = build_data.link(&script_config).await?;
Expand All @@ -262,7 +262,7 @@ impl CompiledState {
}

/// Tries loading the resumed state from the cache files, skipping simulation stage.
pub async fn resume(self) -> Result<BundledState<Ethereum>> {
pub async fn resume(self) -> Result<BundledState<FEN>> {
let chain = if self.args.multi {
None
} else {
Expand Down Expand Up @@ -358,7 +358,7 @@ impl CompiledState {
&self,
chain: Option<u64>,
dry_run: bool,
) -> Result<ScriptSequenceKind<Ethereum>> {
) -> Result<ScriptSequenceKind<FEN::Network>> {
if let Some(chain) = chain {
let sequence = ScriptSequence::load(
&self.script_config.config,
Expand Down
57 changes: 29 additions & 28 deletions crates/script/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ use crate::{
};
use alloy_dyn_abi::FunctionExt;
use alloy_json_abi::{Function, InternalType, JsonAbi};
use alloy_network::{AnyNetwork, Ethereum, Network};
use alloy_network::{AnyNetwork, Network, TransactionBuilder};
use alloy_primitives::{
Address, Bytes,
map::{HashMap, HashSet},
};
use alloy_provider::Provider;
use alloy_rpc_types::TransactionInput;
use alloy_rpc_types::TransactionInputKind;
use eyre::{OptionExt, Result};
use foundry_cheatcodes::Wallets;
use foundry_cli::utils::{ensure_clean_constructor, needs_setup};
Expand All @@ -24,7 +24,7 @@ use foundry_common::{
use foundry_config::NamedChain;
use foundry_debugger::Debugger;
use foundry_evm::{
core::evm::EthEvmNetwork,
core::evm::FoundryEvmNetwork,
decode::decode_console_logs,
inspectors::cheatcodes::BroadcastableTransactions,
traces::{
Expand All @@ -41,11 +41,11 @@ use yansi::Paint;

/// State after linking, contains the linked build data along with library addresses and optional
/// array of libraries that need to be predeployed.
pub struct LinkedState {
pub struct LinkedState<FEN: FoundryEvmNetwork> {
pub args: ScriptArgs,
pub script_config: ScriptConfig<EthEvmNetwork>,
pub script_config: ScriptConfig<FEN>,
pub script_wallets: Wallets,
pub browser_wallet: Option<BrowserSigner<Ethereum>>,
pub browser_wallet: Option<BrowserSigner<FEN::Network>>,
pub build_data: LinkedBuildData,
}

Expand All @@ -62,10 +62,10 @@ pub struct ExecutionData {
pub abi: JsonAbi,
}

impl LinkedState {
impl<FEN: FoundryEvmNetwork> LinkedState<FEN> {
/// Given linked and compiled artifacts, prepares data we need for execution.
/// This includes the function to call and the calldata to pass to it.
pub async fn prepare_execution(self) -> Result<PreExecutionState> {
pub async fn prepare_execution(self) -> Result<PreExecutionState<FEN>> {
let Self { args, script_config, script_wallets, browser_wallet, build_data } = self;

let target_contract = build_data.get_target_contract()?;
Expand Down Expand Up @@ -94,19 +94,19 @@ impl LinkedState {

/// Same as [LinkedState], but also contains [ExecutionData].
#[derive(Debug)]
pub struct PreExecutionState {
pub struct PreExecutionState<FEN: FoundryEvmNetwork> {
pub args: ScriptArgs,
pub script_config: ScriptConfig<EthEvmNetwork>,
pub script_config: ScriptConfig<FEN>,
pub script_wallets: Wallets,
pub browser_wallet: Option<BrowserSigner<Ethereum>>,
pub browser_wallet: Option<BrowserSigner<FEN::Network>>,
pub build_data: LinkedBuildData,
pub execution_data: ExecutionData,
}

impl PreExecutionState {
impl<FEN: FoundryEvmNetwork> PreExecutionState<FEN> {
/// Executes the script and returns the state after execution.
/// Might require executing script twice in cases when we determine sender from execution.
pub async fn execute(mut self) -> Result<ExecutedState> {
pub async fn execute(mut self) -> Result<ExecutedState<FEN>> {
let mut runner = self
.script_config
.get_runner_with_cheatcodes(
Expand Down Expand Up @@ -149,8 +149,8 @@ impl PreExecutionState {
/// Executes the script using the provided runner and returns the [ScriptResult].
pub async fn execute_with_runner(
&self,
runner: &mut ScriptRunner<EthEvmNetwork>,
) -> Result<ScriptResult<Ethereum>> {
runner: &mut ScriptRunner<FEN>,
) -> Result<ScriptResult<FEN::Network>> {
let (address, mut setup_result) = runner.setup(
&self.build_data.predeploy_libraries,
self.execution_data.bytecode.clone(),
Expand Down Expand Up @@ -190,7 +190,7 @@ impl PreExecutionState {
/// them instead.
fn maybe_new_sender(
&self,
transactions: Option<&BroadcastableTransactions<Ethereum>>,
transactions: Option<&BroadcastableTransactions<FEN::Network>>,
) -> Result<Option<Address>> {
let mut new_sender = None;

Expand Down Expand Up @@ -230,7 +230,7 @@ pub struct RpcData {

impl RpcData {
/// Iterates over script transactions and collects RPC urls.
fn from_transactions(txs: &BroadcastableTransactions<Ethereum>) -> Self {
fn from_transactions<N: Network>(txs: &BroadcastableTransactions<N>) -> Self {
let missing_rpc = txs.iter().any(|tx| tx.rpc.is_none());
let total_rpcs =
txs.iter().filter_map(|tx| tx.rpc.as_ref().cloned()).collect::<HashSet<_>>();
Expand Down Expand Up @@ -282,32 +282,33 @@ pub struct ExecutionArtifacts {
}

/// State after the script has been executed.
pub struct ExecutedState {
pub struct ExecutedState<FEN: FoundryEvmNetwork> {
pub args: ScriptArgs,
pub script_config: ScriptConfig<EthEvmNetwork>,
pub script_config: ScriptConfig<FEN>,
pub script_wallets: Wallets,
pub browser_wallet: Option<BrowserSigner<Ethereum>>,
pub browser_wallet: Option<BrowserSigner<FEN::Network>>,
pub build_data: LinkedBuildData,
pub execution_data: ExecutionData,
pub execution_result: ScriptResult<Ethereum>,
pub execution_result: ScriptResult<FEN::Network>,
}

impl ExecutedState {
impl<FEN: FoundryEvmNetwork> ExecutedState<FEN> {
/// Collects the data we need for simulation and various post-execution tasks.
pub async fn prepare_simulation(self) -> Result<PreSimulationState<Ethereum>> {
pub async fn prepare_simulation(self) -> Result<PreSimulationState<FEN>> {
let returns = self.get_returns()?;

let decoder = self.build_trace_decoder(&self.build_data.known_contracts).await?;

let mut txs: BroadcastableTransactions<Ethereum> =
let mut txs: BroadcastableTransactions<FEN::Network> =
self.execution_result.transactions.clone().unwrap_or_default();

// Ensure that unsigned transactions have both `data` and `input` populated to avoid
// issues with eth_estimateGas and eth_sendTransaction requests.
for tx in &mut txs {
if let Some(req) = tx.transaction.as_unsigned_mut() {
req.input =
TransactionInput::maybe_both(std::mem::take(&mut req.input).into_input());
if let Some(req) = tx.transaction.as_unsigned_mut()
&& let Some(input) = req.input().cloned()
{
*req = req.clone().with_input_kind(input, TransactionInputKind::Both);
}
}
let rpc_data = RpcData::from_transactions(&txs);
Expand Down Expand Up @@ -400,7 +401,7 @@ impl ExecutedState {
}
}

impl<N: Network> PreSimulationState<N> {
impl<FEN: FoundryEvmNetwork> PreSimulationState<FEN> {
pub async fn show_json(&self) -> Result<()> {
let mut result = self.execution_result.clone();

Expand Down
Loading
Loading