@@ -353,6 +353,21 @@ impl BytecodeObject {
353353 pub fn contains_placeholder ( & self , file : & str , library : & str ) -> bool {
354354 self . contains_fully_qualified_placeholder ( & format ! ( "{file}:{library}" ) )
355355 }
356+
357+ /// Strips all __$xxx$__ placeholders from the bytecode if it's an unlinked bytecode.
358+ /// by replacing them with 20 zero bytes.
359+ /// This is useful for matching bytecodes to a contract source, and for the source map,
360+ /// in which the actual address of the placeholder isn't important.
361+ pub fn strip_bytecode_placeholders ( & self ) -> Option < Bytes > {
362+ match & self {
363+ Self :: Bytecode ( bytes) => Some ( bytes. clone ( ) ) ,
364+ Self :: Unlinked ( s) => {
365+ // Replace all __$xxx$__ placeholders with 32 zero bytes
366+ let bytes = replace_placeholders_and_decode ( s) . ok ( ) ?;
367+ Some ( bytes. into ( ) )
368+ }
369+ }
370+ }
356371}
357372
358373// Returns an empty bytecode object
@@ -388,6 +403,13 @@ where
388403 }
389404}
390405
406+ // Replace all __$xxx$__ placeholders with 32 zero bytes
407+ pub fn replace_placeholders_and_decode ( s : & str ) -> Result < Vec < u8 > , hex:: FromHexError > {
408+ let re = regex:: Regex :: new ( r"_\$.{34}\$_" ) . expect ( "invalid regex" ) ;
409+ let s = re. replace_all ( s, "00" . repeat ( 40 ) ) ;
410+ hex:: decode ( s. as_bytes ( ) )
411+ }
412+
391413#[ derive( Clone , Debug , PartialEq , Eq , Serialize , Deserialize ) ]
392414pub struct DeployedBytecode {
393415 #[ serde( flatten) ]
0 commit comments