Skip to content

Commit dec820b

Browse files
committed
fix: forgot to commit the new files
1 parent f8a4f95 commit dec820b

File tree

2 files changed

+452
-0
lines changed

2 files changed

+452
-0
lines changed
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
//! Contains various definitions and items related to deploy-time linking
2+
3+
use std::{borrow::Borrow, collections::BTreeMap, path::Path};
4+
5+
use alloy_json_abi::JsonAbi;
6+
use alloy_primitives::{Address, Bytes, TxKind, B256, U256};
7+
use eyre::Context;
8+
use foundry_common::{ContractsByArtifact, TestFunctionExt, TransactionMaybeSigned};
9+
use foundry_compilers::{
10+
artifacts::Libraries, contracts::ArtifactContracts, Artifact, ArtifactId, ProjectCompileOutput,
11+
};
12+
use foundry_evm_core::decode::RevertDecoder;
13+
use foundry_linking::{Linker, LinkerError};
14+
15+
use crate::executors::{DeployResult, EvmError, Executor};
16+
17+
use super::{EvmExecutorStrategyRunner, ExecutorStrategyRunner};
18+
19+
pub struct LinkOutput {
20+
pub deployable_contracts: BTreeMap<ArtifactId, (JsonAbi, Bytes)>,
21+
pub revert_decoder: RevertDecoder,
22+
pub linked_contracts: ArtifactContracts,
23+
pub known_contracts: ContractsByArtifact,
24+
pub libs_to_deploy: Vec<Bytes>,
25+
pub libraries: Libraries,
26+
}
27+
28+
/// Type of library deployment
29+
#[derive(Debug, Clone)]
30+
pub enum DeployLibKind {
31+
/// CREATE(bytecode)
32+
Create(Bytes),
33+
34+
/// CREATE2(salt, bytecode)
35+
Create2(B256, Bytes),
36+
}
37+
38+
/// Represents the result of a library deployment
39+
#[derive(Debug)]
40+
pub struct DeployLibResult {
41+
/// Result of the deployment
42+
pub result: DeployResult,
43+
/// Equivalent transaction to deploy the given library
44+
pub tx: Option<TransactionMaybeSigned>,
45+
}
46+
47+
impl EvmExecutorStrategyRunner {
48+
pub(super) fn link_impl(
49+
&self,
50+
root: &Path,
51+
input: &ProjectCompileOutput,
52+
deployer: Address,
53+
) -> Result<LinkOutput, LinkerError> {
54+
let contracts =
55+
input.artifact_ids().map(|(id, v)| (id.with_stripped_file_prefixes(root), v)).collect();
56+
let linker = Linker::new(root, contracts);
57+
58+
// Build revert decoder from ABIs of all artifacts.
59+
let abis = linker
60+
.contracts
61+
.iter()
62+
.filter_map(|(_, contract)| contract.abi.as_ref().map(|abi| abi.borrow()));
63+
let revert_decoder = RevertDecoder::new().with_abis(abis);
64+
65+
let foundry_linking::LinkOutput { libraries, libs_to_deploy } = linker
66+
.link_with_nonce_or_address(Default::default(), deployer, 0, linker.contracts.keys())?;
67+
68+
let linked_contracts = linker.get_linked_artifacts(&libraries)?;
69+
70+
// Create a mapping of name => (abi, deployment code, Vec<library deployment code>)
71+
let mut deployable_contracts = BTreeMap::default();
72+
for (id, contract) in linked_contracts.iter() {
73+
let Some(abi) = &contract.abi else { continue };
74+
75+
// if it's a test, link it and add to deployable contracts
76+
if abi.constructor.as_ref().map(|c| c.inputs.is_empty()).unwrap_or(true)
77+
&& abi.functions().any(|func| func.name.is_any_test())
78+
{
79+
let Some(bytecode) =
80+
contract.get_bytecode_bytes().map(|b| b.into_owned()).filter(|b| !b.is_empty())
81+
else {
82+
continue;
83+
};
84+
85+
deployable_contracts.insert(id.clone(), (abi.clone(), bytecode));
86+
}
87+
}
88+
89+
let known_contracts = ContractsByArtifact::new(linked_contracts.clone());
90+
91+
Ok(LinkOutput {
92+
deployable_contracts,
93+
revert_decoder,
94+
linked_contracts,
95+
known_contracts,
96+
libs_to_deploy,
97+
libraries,
98+
})
99+
}
100+
101+
pub(super) fn deploy_library_impl(
102+
&self,
103+
executor: &mut Executor,
104+
from: Address,
105+
kind: DeployLibKind,
106+
value: U256,
107+
rd: Option<&RevertDecoder>,
108+
) -> Result<Vec<DeployLibResult>, EvmError> {
109+
let nonce = self.get_nonce(executor, from).context("retrieving sender nonce")?;
110+
111+
match kind {
112+
DeployLibKind::Create(code) => {
113+
executor.deploy(from, code.clone(), value, rd).map(|dr| {
114+
let mut request = TransactionMaybeSigned::new(Default::default());
115+
let unsigned = request.as_unsigned_mut().unwrap();
116+
unsigned.from = Some(from);
117+
unsigned.input = code.into();
118+
unsigned.nonce = Some(nonce);
119+
120+
vec![DeployLibResult { result: dr, tx: Some(request) }]
121+
})
122+
}
123+
DeployLibKind::Create2(salt, code) => {
124+
let create2_deployer = executor.create2_deployer();
125+
126+
let calldata: Bytes = [salt.as_ref(), code.as_ref()].concat().into();
127+
let result =
128+
executor.transact_raw(from, create2_deployer, calldata.clone(), value)?;
129+
let result = result.into_result(rd)?;
130+
131+
let address = result
132+
.out
133+
.as_ref()
134+
.and_then(|out| out.address().cloned())
135+
.unwrap_or_else(|| create2_deployer.create2_from_code(salt, code.as_ref()));
136+
debug!(%address, "deployed contract with create2");
137+
138+
let mut request = TransactionMaybeSigned::new(Default::default());
139+
let unsigned = request.as_unsigned_mut().unwrap();
140+
unsigned.from = Some(from);
141+
unsigned.input = calldata.into();
142+
unsigned.nonce = Some(nonce);
143+
unsigned.to = Some(TxKind::Call(create2_deployer));
144+
145+
// manually increase nonce when performing CALLs
146+
executor
147+
.set_nonce(from, nonce + 1)
148+
.context("increasing nonce after CREATE2 deployment")?;
149+
150+
Ok(vec![DeployLibResult {
151+
result: DeployResult { raw: result, address },
152+
tx: Some(request),
153+
}])
154+
}
155+
}
156+
}
157+
}

0 commit comments

Comments
 (0)