@@ -179,7 +179,8 @@ fn combine_instructions(instructions: Vec<ParsedInstruction>) -> Vec<ParsedInstr
179179 }
180180 }
181181
182- // Pattern 2: CreateAccount + StakeInitialize + StakingDelegate → StakingActivate
182+ // Pattern 2: CreateAccount + StakeInitialize + StakingDelegate → StakingActivate (NATIVE)
183+ // Must check this 3-instruction pattern BEFORE the 2-instruction Marinade pattern
183184 if i + 2 < instructions. len ( ) {
184185 if let (
185186 ParsedInstruction :: StakeInitialize ( ref stake_init) ,
@@ -204,6 +205,38 @@ fn combine_instructions(instructions: Vec<ParsedInstruction>) -> Vec<ParsedInstr
204205 }
205206 }
206207 }
208+
209+ // Pattern 3: CreateAccount + StakeInitialize (without Delegate) → StakingActivate (MARINADE)
210+ // Marinade staking creates a stake account but doesn't delegate to a validator
211+ // The "validator" field stores the authorized staker address instead
212+ if i + 1 < instructions. len ( ) {
213+ if let ParsedInstruction :: StakeInitialize ( ref stake_init) = instructions[ i + 1 ] {
214+ // Check if CreateAccount target matches StakeInitialize staking address
215+ // and owner is Stake Program
216+ // Also make sure the next instruction (if any) is NOT a StakingDelegate
217+ let is_not_followed_by_delegate = i + 2 >= instructions. len ( )
218+ || !matches ! (
219+ instructions[ i + 2 ] ,
220+ ParsedInstruction :: StakingDelegate ( _)
221+ ) ;
222+
223+ if create. new_address == stake_init. staking_address
224+ && create. owner == STAKE_PROGRAM_ID
225+ && is_not_followed_by_delegate
226+ {
227+ result. push ( ParsedInstruction :: StakingActivate ( StakingActivateParams {
228+ from_address : create. from_address . clone ( ) ,
229+ staking_address : stake_init. staking_address . clone ( ) ,
230+ amount : create. amount . clone ( ) ,
231+ // For Marinade, the validator field stores the authorized staker
232+ validator : stake_init. staker . clone ( ) ,
233+ staking_type : "MARINADE" . to_string ( ) ,
234+ } ) ) ;
235+ i += 2 ; // Skip both instructions
236+ continue ;
237+ }
238+ }
239+ }
207240 }
208241
209242 // No pattern matched, keep the instruction as-is
@@ -277,4 +310,29 @@ mod tests {
277310 assert ! ( json. contains( "instructionsData" ) ) ;
278311 assert ! ( json. contains( "Transfer" ) ) ;
279312 }
313+
314+ // Marinade staking activate transaction (CreateAccount + StakeInitialize without Delegate)
315+ const MARINADE_STAKING_ACTIVATE : & str = "AuRFS0r7hJ+/+WuDQbbwdjSgxfnKOWi94EnWEha9uaBPt8VZOXiOoSiSoES34VkyBNLlLqlfK0fP3d5eJR+srQvN04gqzpOZPTVzqiomyMXqwQ6FYoQg5nEkdiDVny8SsyhRnAeDMzexkKD+3rwSGP0E+XN/2crTL6PZRnip42YFAgADBUXlebz5JTz2i0ff8fs6OlwsIbrFsjwJrhKm4FVr8ItBYnsvugEnYfm5Gbz5TLtMncgFHZ8JMpkxTTlJIzJovekAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAah2BeRN1QqmDQ3vf4qerJVf1NcinhyK2ikncAAAAAABqfVFxksXFEhjMlMPUrxf1ja7gibof1E49vZigAAAADjMtr5L6vs6LY/96RABeX9/Zr6FYdWthxalfkEs7jQgQICAgABNAAAAADgkwQAAAAAAMgAAAAAAAAABqHYF5E3VCqYNDe9/ip6slV/U1yKeHIraKSdwAAAAAADAgEEdAAAAACx+Xl4mhxH0TxI2HovJxcQ63+TJglRFzFikL1sKdr12UXlebz5JTz2i0ff8fs6OlwsIbrFsjwJrhKm4FVr8ItBAAAAAAAAAAAAAAAAAAAAAEXlebz5JTz2i0ff8fs6OlwsIbrFsjwJrhKm4FVr8ItB" ;
316+
317+ #[ test]
318+ fn test_parse_marinade_staking_activate ( ) {
319+ let bytes = BASE64_STANDARD . decode ( MARINADE_STAKING_ACTIVATE ) . unwrap ( ) ;
320+ let parsed = parse_transaction ( & bytes) . unwrap ( ) ;
321+
322+ println ! ( "Parsed instructions: {:?}" , parsed. instructions_data) ;
323+ println ! ( "Parsed JSON: {}" , serde_json:: to_string_pretty( & parsed) . unwrap( ) ) ;
324+
325+ // Should combine CreateAccount + StakeInitialize into StakingActivate(MARINADE)
326+ assert_eq ! ( parsed. instructions_data. len( ) , 1 , "Expected 1 combined instruction" ) ;
327+
328+ match & parsed. instructions_data [ 0 ] {
329+ ParsedInstruction :: StakingActivate ( params) => {
330+ assert_eq ! ( params. staking_type, "MARINADE" ) ;
331+ assert_eq ! ( params. from_address, "5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe" ) ;
332+ assert_eq ! ( params. staking_address, "7dRuGFbU2y2kijP6o1LYNzVyz4yf13MooqoionCzv5Za" ) ;
333+ assert_eq ! ( params. amount, "300000" ) ;
334+ }
335+ other => panic ! ( "Expected StakingActivate(MARINADE) instruction, got {:?}" , other) ,
336+ }
337+ }
280338}
0 commit comments