11//! Forge test runner for multiple contracts.
22
3- use crate :: { result:: SuiteResult , ContractRunner , TestFilter , TestOptions } ;
3+ use crate :: {
4+ result:: SuiteResult , runner:: LIBRARY_DEPLOYER , ContractRunner , TestFilter , TestOptions ,
5+ } ;
46use alloy_json_abi:: { Function , JsonAbi } ;
57use alloy_primitives:: { Address , Bytes , U256 } ;
68use eyre:: Result ;
79use foundry_common:: { get_contract_name, ContractsByArtifact , TestFunctionExt } ;
8- use foundry_compilers:: { artifacts:: Libraries , Artifact , ArtifactId , ProjectCompileOutput , Solc } ;
10+ use foundry_compilers:: { artifacts:: Libraries , Artifact , ArtifactId , ProjectCompileOutput } ;
911use foundry_config:: Config ;
1012use foundry_evm:: {
1113 backend:: Backend , decode:: RevertDecoder , executors:: ExecutorBuilder , fork:: CreateFork ,
@@ -27,8 +29,6 @@ use std::{
2729pub struct TestContract {
2830 pub abi : JsonAbi ,
2931 pub bytecode : Bytes ,
30- pub libs_to_deploy : Vec < Bytes > ,
31- pub libraries : Libraries ,
3232}
3333
3434pub type DeployableContracts = BTreeMap < ArtifactId , TestContract > ;
@@ -61,8 +61,12 @@ pub struct MultiContractRunner {
6161 pub test_options : TestOptions ,
6262 /// Whether to enable call isolation
6363 pub isolation : bool ,
64- /// Output of the project compilation
65- pub output : ProjectCompileOutput ,
64+ /// Known contracts linked with computed library addresses.
65+ pub known_contracts : ContractsByArtifact ,
66+ /// Libraries to deploy.
67+ pub libs_to_deploy : Vec < Bytes > ,
68+ /// Library addresses used to link contracts.
69+ pub libraries : Libraries ,
6670}
6771
6872impl MultiContractRunner {
@@ -181,17 +185,10 @@ impl MultiContractRunner {
181185 let identifier = artifact_id. identifier ( ) ;
182186 let mut span_name = identifier. as_str ( ) ;
183187
184- let linker = Linker :: new (
185- self . config . project_paths :: < Solc > ( ) . root ,
186- self . output . artifact_ids ( ) . collect ( ) ,
187- ) ;
188- let linked_contracts = linker. get_linked_artifacts ( & contract. libraries ) . unwrap_or_default ( ) ;
189- let known_contracts = ContractsByArtifact :: new ( linked_contracts) ;
190-
191188 let cheats_config = CheatsConfig :: new (
192189 & self . config ,
193190 self . evm_opts . clone ( ) ,
194- Some ( known_contracts. clone ( ) ) ,
191+ Some ( self . known_contracts . clone ( ) ) ,
195192 None ,
196193 Some ( artifact_id. version . clone ( ) ) ,
197194 ) ;
@@ -220,12 +217,13 @@ impl MultiContractRunner {
220217 & identifier,
221218 executor,
222219 contract,
220+ & self . libs_to_deploy ,
223221 self . evm_opts . initial_balance ,
224222 self . sender ,
225223 & self . revert_decoder ,
226224 self . debug ,
227225 ) ;
228- let r = runner. run_tests ( filter, & self . test_options , known_contracts, handle) ;
226+ let r = runner. run_tests ( filter, & self . test_options , self . known_contracts . clone ( ) , handle) ;
229227
230228 debug ! ( duration=?r. duration, "executed all tests in contract" ) ;
231229
@@ -332,10 +330,19 @@ impl MultiContractRunnerBuilder {
332330 . filter_map ( |( _, contract) | contract. abi . as_ref ( ) . map ( |abi| abi. borrow ( ) ) ) ;
333331 let revert_decoder = RevertDecoder :: new ( ) . with_abis ( abis) ;
334332
333+ let LinkOutput { libraries, libs_to_deploy } = linker. link_with_nonce_or_address (
334+ Default :: default ( ) ,
335+ LIBRARY_DEPLOYER ,
336+ 0 ,
337+ linker. contracts . keys ( ) ,
338+ ) ?;
339+
340+ let linked_contracts = linker. get_linked_artifacts ( & libraries) ?;
341+
335342 // Create a mapping of name => (abi, deployment code, Vec<library deployment code>)
336343 let mut deployable_contracts = DeployableContracts :: default ( ) ;
337344
338- for ( id, contract) in linker . contracts . iter ( ) {
345+ for ( id, contract) in linked_contracts . iter ( ) {
339346 let Some ( abi) = contract. abi . as_ref ( ) else {
340347 continue ;
341348 } ;
@@ -344,35 +351,19 @@ impl MultiContractRunnerBuilder {
344351 if abi. constructor . as_ref ( ) . map ( |c| c. inputs . is_empty ( ) ) . unwrap_or ( true ) &&
345352 abi. functions ( ) . any ( |func| func. name . is_test ( ) || func. name . is_invariant_test ( ) )
346353 {
347- let LinkOutput { libs_to_deploy, libraries } = linker. link_with_nonce_or_address (
348- Default :: default ( ) ,
349- evm_opts. sender ,
350- 1 ,
351- id,
352- ) ?;
353-
354- let linked_contract = linker. link ( id, & libraries) ?;
355-
356- let Some ( bytecode) = linked_contract
357- . get_bytecode_bytes ( )
358- . map ( |b| b. into_owned ( ) )
359- . filter ( |b| !b. is_empty ( ) )
354+ let Some ( bytecode) =
355+ contract. get_bytecode_bytes ( ) . map ( |b| b. into_owned ( ) ) . filter ( |b| !b. is_empty ( ) )
360356 else {
361357 continue ;
362358 } ;
363359
364- deployable_contracts. insert (
365- id. clone ( ) ,
366- TestContract {
367- abi : abi. clone ( ) . into_owned ( ) ,
368- bytecode,
369- libs_to_deploy,
370- libraries,
371- } ,
372- ) ;
360+ deployable_contracts
361+ . insert ( id. clone ( ) , TestContract { abi : abi. clone ( ) , bytecode } ) ;
373362 }
374363 }
375364
365+ let known_contracts = ContractsByArtifact :: new ( linked_contracts) ;
366+
376367 Ok ( MultiContractRunner {
377368 contracts : deployable_contracts,
378369 evm_opts,
@@ -386,7 +377,9 @@ impl MultiContractRunnerBuilder {
386377 debug : self . debug ,
387378 test_options : self . test_options . unwrap_or_default ( ) ,
388379 isolation : self . isolation ,
389- output,
380+ known_contracts,
381+ libs_to_deploy,
382+ libraries,
390383 } )
391384 }
392385}
0 commit comments