@@ -7,7 +7,7 @@ use crate::{
77 constants:: DISCRIMINATOR_SIZE ,
88 error:: CustomError ,
99 event:: ExecutedRelayerRefundRoot ,
10- state:: { ExecuteRelayerRefundLeafParams , RootBundle , State , TransferLiability } ,
10+ state:: { ExecuteRelayerRefundLeafParams , RefundAccount , RootBundle , State , TransferLiability } ,
1111 utils:: { is_claimed, set_claimed, verify_merkle_proof} ,
1212} ;
1313
@@ -104,9 +104,12 @@ impl RelayerRefundLeaf {
104104 }
105105}
106106
107- pub fn execute_relayer_refund_leaf < ' info > (
108- ctx : Context < ' _ , ' _ , ' _ , ' info , ExecuteRelayerRefundLeaf < ' info > > ,
109- ) -> Result < ( ) > {
107+ pub fn execute_relayer_refund_leaf < ' c , ' info > (
108+ ctx : Context < ' _ , ' _ , ' c , ' info , ExecuteRelayerRefundLeaf < ' info > > ,
109+ ) -> Result < ( ) >
110+ where
111+ ' c : ' info ,
112+ {
110113 // Get pre-loaded instruction parameters.
111114 let instruction_params = & ctx. accounts . instruction_params ;
112115 let root_bundle_id = instruction_params. root_bundle_id ;
@@ -138,36 +141,58 @@ pub fn execute_relayer_refund_leaf<'info>(
138141 // TODO: execute remaining parts of leaf structure such as amountToReturn.
139142 // TODO: emit events.
140143
144+ if relayer_refund_leaf. refund_accounts . len ( ) != relayer_refund_leaf. refund_amounts . len ( ) {
145+ return err ! ( CustomError :: InvalidMerkleLeaf ) ;
146+ }
147+
141148 // Derive the signer seeds for the state. The vault owns the state PDA so we need to derive this to create the
142149 // signer seeds to execute the CPI transfer from the vault to the refund recipient.
143150 let state_seed_bytes = state. seed . to_le_bytes ( ) ;
144151 let seeds = & [ b"state" , state_seed_bytes. as_ref ( ) , & [ ctx. bumps . state ] ] ;
145152 let signer_seeds = & [ & seeds[ ..] ] ;
146153
154+ // Will include in the emitted event at the end if there are any claim accounts.
155+ let mut deferred_refunds = false ;
156+
147157 for ( i, amount) in relayer_refund_leaf. refund_amounts . iter ( ) . enumerate ( ) {
148- let refund_account = relayer_refund_leaf. refund_accounts [ i] ;
149158 let amount = * amount as u64 ;
150159
151- // TODO: we might be able to just use the refund_account and improve this block but it's not clear yet if that's possible.
152- let refund_account_info = ctx
153- . remaining_accounts
154- . iter ( )
155- . find ( |account| account. key == & refund_account)
156- . cloned ( )
157- . ok_or ( CustomError :: AccountNotFound ) ?;
158-
159- let transfer_accounts = TransferChecked {
160- from : ctx. accounts . vault . to_account_info ( ) ,
161- mint : ctx. accounts . mint . to_account_info ( ) ,
162- to : refund_account_info. to_account_info ( ) ,
163- authority : ctx. accounts . state . to_account_info ( ) ,
164- } ;
165- let cpi_context = CpiContext :: new_with_signer (
166- ctx. accounts . token_program . to_account_info ( ) ,
167- transfer_accounts,
168- signer_seeds,
169- ) ;
170- transfer_checked ( cpi_context, amount, ctx. accounts . mint . decimals ) ?;
160+ // Refund account holds either a regular token account or a claim account. This checks all required constraints.
161+ let refund_account = RefundAccount :: try_from_remaining_account (
162+ ctx. remaining_accounts ,
163+ i,
164+ & relayer_refund_leaf. refund_accounts [ i] ,
165+ & ctx. accounts . mint . key ( ) ,
166+ & ctx. accounts . token_program . key ( ) ,
167+ ) ?;
168+
169+ match refund_account {
170+ // Valid token account was passed, transfer the refund atomically.
171+ RefundAccount :: TokenAccount ( token_account) => {
172+ let transfer_accounts = TransferChecked {
173+ from : ctx. accounts . vault . to_account_info ( ) ,
174+ mint : ctx. accounts . mint . to_account_info ( ) ,
175+ to : token_account. to_account_info ( ) ,
176+ authority : ctx. accounts . state . to_account_info ( ) ,
177+ } ;
178+ let cpi_context = CpiContext :: new_with_signer (
179+ ctx. accounts . token_program . to_account_info ( ) ,
180+ transfer_accounts,
181+ signer_seeds,
182+ ) ;
183+ transfer_checked ( cpi_context, amount, ctx. accounts . mint . decimals ) ?;
184+ }
185+ // Valid claim account was passed, increment the claim account amount.
186+ RefundAccount :: ClaimAccount ( mut claim_account) => {
187+ claim_account. amount += amount;
188+
189+ // Indicate in the event at the end that some refunds have been deferred.
190+ deferred_refunds = true ;
191+
192+ // Persist the updated claim account (Anchor handles this only for static accounts).
193+ claim_account. exit ( ctx. program_id ) ?;
194+ }
195+ }
171196 }
172197
173198 if relayer_refund_leaf. amount_to_return > 0 {
@@ -183,6 +208,7 @@ pub fn execute_relayer_refund_leaf<'info>(
183208 leaf_id: relayer_refund_leaf. leaf_id,
184209 l2_token_address: ctx. accounts. mint. key( ) ,
185210 refund_addresses: relayer_refund_leaf. refund_accounts,
211+ deferred_refunds,
186212 caller: ctx. accounts. signer. key( ) ,
187213 } ) ;
188214
0 commit comments