@@ -29,6 +29,8 @@ pub enum LinkerError {
29
29
InvalidAddress ( <Address as std:: str:: FromStr >:: Err ) ,
30
30
#[ error( "cyclic dependency found, can't link libraries via CREATE2" ) ]
31
31
CyclicDependency ,
32
+ #[ error( "failed linking {artifact}" ) ]
33
+ LinkingFailed { artifact : String } ,
32
34
}
33
35
34
36
pub struct Linker < ' a > {
@@ -265,6 +267,30 @@ impl<'a> Linker<'a> {
265
267
Ok ( contract)
266
268
}
267
269
270
+ /// Ensures that both initial and deployed bytecode are linked.
271
+ pub fn ensure_linked (
272
+ & self ,
273
+ contract : & CompactContractBytecodeCow < ' a > ,
274
+ target : & ArtifactId ,
275
+ ) -> Result < ( ) , LinkerError > {
276
+ if let Some ( bytecode) = & contract. bytecode
277
+ && bytecode. object . is_unlinked ( )
278
+ {
279
+ return Err ( LinkerError :: LinkingFailed {
280
+ artifact : target. source . to_string_lossy ( ) . into ( ) ,
281
+ } ) ;
282
+ }
283
+ if let Some ( deployed_bytecode) = & contract. deployed_bytecode
284
+ && let Some ( deployed_bytecode_obj) = & deployed_bytecode. bytecode
285
+ && deployed_bytecode_obj. object . is_unlinked ( )
286
+ {
287
+ return Err ( LinkerError :: LinkingFailed {
288
+ artifact : target. source . to_string_lossy ( ) . into ( ) ,
289
+ } ) ;
290
+ }
291
+ Ok ( ( ) )
292
+ }
293
+
268
294
pub fn get_linked_artifacts (
269
295
& self ,
270
296
libraries : & Libraries ,
@@ -685,4 +711,33 @@ mod tests {
685
711
) ;
686
712
} ) ;
687
713
}
714
+
715
+ #[ test]
716
+ fn linking_failure ( ) {
717
+ let linker = LinkerTest :: new ( "../../testdata/default/linking/simple" , true ) ;
718
+ let linker_instance =
719
+ Linker :: new ( linker. project . root ( ) , linker. output . artifact_ids ( ) . collect ( ) ) ;
720
+
721
+ // Create a libraries object with an incorrect library name that won't match any references
722
+ let mut libraries = Libraries :: default ( ) ;
723
+ libraries. libs . entry ( "default/linking/simple/Simple.t.sol" . into ( ) ) . or_default ( ) . insert (
724
+ "NonExistentLib" . to_string ( ) ,
725
+ "0x5a443704dd4b594b382c22a083e2bd3090a6fef3" . to_string ( ) ,
726
+ ) ;
727
+
728
+ // Try to link the LibraryConsumer contract with incorrect library
729
+ let artifact_id = linker_instance
730
+ . contracts
731
+ . keys ( )
732
+ . find ( |id| id. name == "LibraryConsumer" )
733
+ . expect ( "LibraryConsumer contract not found" ) ;
734
+
735
+ let contract = linker_instance. contracts . get ( artifact_id) . unwrap ( ) ;
736
+
737
+ // Verify that the artifact has unlinked bytecode
738
+ assert ! (
739
+ linker_instance. ensure_linked( contract, artifact_id) . is_err( ) ,
740
+ "Expected artifact to have unlinked bytecode"
741
+ ) ;
742
+ }
688
743
}
0 commit comments