|
1 |
| -use crate::error::MatchingEngineError; |
2 |
| -use crate::state::FastMarketOrder; |
3 | 1 | use anchor_lang::prelude::*;
|
4 | 2 | use solana_program::instruction::Instruction;
|
5 |
| -use solana_program::program_error::ProgramError; |
6 | 3 |
|
7 |
| -use super::helpers::require_min_account_infos_len; |
8 |
| -use super::FallbackMatchingEngineInstruction; |
| 4 | +use crate::{error::MatchingEngineError, state::FastMarketOrder}; |
9 | 5 |
|
10 | 6 | pub struct CloseFastMarketOrderAccounts<'ix> {
|
11 |
| - /// The fast market order account created from the initialize fast market order instruction |
| 7 | + /// The fast market order account to be closed. |
12 | 8 | pub fast_market_order: &'ix Pubkey,
|
13 |
| - /// The account that will receive the refund. CHECK: Must be a signer. |
14 |
| - /// CHECK: Must match the close account refund recipient in the fast market order account |
| 9 | + /// The account that will receive rent from the fast market order account. |
| 10 | + /// This account is the only authority that can close the fast market order. |
| 11 | + /// TODO: Rename to "refund_recipient". |
15 | 12 | pub close_account_refund_recipient: &'ix Pubkey,
|
16 | 13 | }
|
17 | 14 |
|
18 |
| -impl<'ix> CloseFastMarketOrderAccounts<'ix> { |
19 |
| - pub fn to_account_metas(&self) -> Vec<AccountMeta> { |
20 |
| - vec![ |
21 |
| - AccountMeta::new(*self.fast_market_order, false), |
22 |
| - AccountMeta::new(*self.close_account_refund_recipient, true), |
23 |
| - ] |
24 |
| - } |
25 |
| -} |
26 |
| - |
| 15 | +/// Closes the fast market order and transfers the lamports from the fast market |
| 16 | +/// order to its refund recipient. |
27 | 17 | pub struct CloseFastMarketOrder<'ix> {
|
28 | 18 | pub program_id: &'ix Pubkey,
|
29 | 19 | pub accounts: CloseFastMarketOrderAccounts<'ix>,
|
30 | 20 | }
|
31 | 21 |
|
32 | 22 | impl CloseFastMarketOrder<'_> {
|
33 | 23 | pub fn instruction(&self) -> Instruction {
|
| 24 | + let CloseFastMarketOrderAccounts { |
| 25 | + fast_market_order, |
| 26 | + close_account_refund_recipient: refund_recipient, |
| 27 | + } = self.accounts; |
| 28 | + |
34 | 29 | Instruction {
|
35 | 30 | program_id: *self.program_id,
|
36 |
| - accounts: self.accounts.to_account_metas(), |
37 |
| - data: FallbackMatchingEngineInstruction::CloseFastMarketOrder.to_vec(), |
| 31 | + accounts: vec![ |
| 32 | + AccountMeta::new(*fast_market_order, false), |
| 33 | + AccountMeta::new(*refund_recipient, true), |
| 34 | + ], |
| 35 | + data: super::FallbackMatchingEngineInstruction::CloseFastMarketOrder.to_vec(), |
38 | 36 | }
|
39 | 37 | }
|
40 | 38 | }
|
41 | 39 |
|
42 |
| -/// Closes the fast market order and transfers the lamports from the fast market order to the close account refund recipient |
43 |
| -/// |
44 |
| -/// # Arguments |
45 |
| -/// |
46 |
| -/// * `accounts` - The accounts of the fast market order and the close account refund recipient |
47 |
| -/// |
48 |
| -/// # Returns |
49 |
| -/// |
50 |
| -/// Result<()> |
51 | 40 | pub fn close_fast_market_order(accounts: &[AccountInfo]) -> Result<()> {
|
52 |
| - require_min_account_infos_len(accounts, 2)?; |
| 41 | + super::helpers::require_min_account_infos_len(accounts, 2)?; |
53 | 42 |
|
54 |
| - let fast_market_order = &accounts[0]; |
55 |
| - let close_account_refund_recipient = &accounts[1]; |
| 43 | + // We need to check the refund recipient account against what we know as the |
| 44 | + // refund recipient encoded in the fast market order account. |
| 45 | + let fast_market_order_info = &accounts[0]; |
| 46 | + let refund_recipient_info = &accounts[1]; |
56 | 47 |
|
57 |
| - // Check that the close_account_refund_recipient is a signer, otherwise someone might call this and steal the lamports |
58 |
| - if !close_account_refund_recipient.is_signer { |
59 |
| - msg!("Refund recipient (account #2) is not a signer"); |
60 |
| - return Err(ProgramError::InvalidAccountData.into()); |
61 |
| - } |
62 |
| - let fast_market_order_data = &fast_market_order.data.borrow()[..]; |
63 |
| - let fast_market_order_deserialized = FastMarketOrder::try_read(fast_market_order_data)?; |
64 |
| - // Check that the fast_market_order is owned by the close_account_refund_recipient |
65 |
| - if fast_market_order_deserialized.close_account_refund_recipient |
66 |
| - != close_account_refund_recipient.key() |
67 |
| - { |
| 48 | + let fast_market_order_data = &fast_market_order_info.data.borrow()[..]; |
| 49 | + |
| 50 | + // NOTE: We do not need to verify that the owner of this account is this |
| 51 | + // program because the lamport transfer will fail otherwise. |
| 52 | + let fast_market_order = FastMarketOrder::try_read(fast_market_order_data)?; |
| 53 | + |
| 54 | + // Check that the refund recipient provided in this instruction is the one |
| 55 | + // encoded in the fast market order account. |
| 56 | + let expected_refund_recipient_key = fast_market_order.close_account_refund_recipient; |
| 57 | + if refund_recipient_info.key != &expected_refund_recipient_key { |
68 | 58 | return Err(MatchingEngineError::MismatchingCloseAccountRefundRecipient.into()).map_err(
|
69 |
| - |e: Error| { |
70 |
| - e.with_pubkeys(( |
71 |
| - fast_market_order_deserialized.close_account_refund_recipient, |
72 |
| - close_account_refund_recipient.key(), |
73 |
| - )) |
74 |
| - }, |
| 59 | + |e: Error| e.with_pubkeys((*refund_recipient_info.key, expected_refund_recipient_key)), |
75 | 60 | );
|
76 | 61 | }
|
77 | 62 |
|
78 |
| - // First, get the current lamports value |
79 |
| - let current_recipient_lamports = **close_account_refund_recipient.lamports.borrow(); |
80 |
| - |
81 |
| - // Then, get the fast market order lamports |
82 |
| - let mut fast_market_order_lamports = fast_market_order.lamports.borrow_mut(); |
| 63 | + // This refund recipient must sign to invoke this instruction. He is the |
| 64 | + // only authority allowed to perform this action. |
| 65 | + if !refund_recipient_info.is_signer { |
| 66 | + return Err(ErrorCode::AccountNotSigner.into()) |
| 67 | + .map_err(|e: Error| e.with_account_name("refund_recipient")); |
| 68 | + } |
83 | 69 |
|
84 |
| - // Calculate the new amount |
85 |
| - let new_amount = current_recipient_lamports.saturating_add(**fast_market_order_lamports); |
| 70 | + let mut fast_market_order_info_lamports = fast_market_order_info.lamports.borrow_mut(); |
86 | 71 |
|
87 |
| - // Now update the recipient's lamports |
88 |
| - **close_account_refund_recipient.lamports.borrow_mut() = new_amount; |
| 72 | + // Move lamports to the refund recipient. |
| 73 | + let mut recipient_info_lamports = refund_recipient_info.lamports.borrow_mut(); |
| 74 | + **recipient_info_lamports = |
| 75 | + recipient_info_lamports.saturating_add(**fast_market_order_info_lamports); |
89 | 76 |
|
90 |
| - // Zero out the fast market order lamports |
91 |
| - **fast_market_order_lamports = 0; |
| 77 | + // Zero out the fast market order lamports. |
| 78 | + **fast_market_order_info_lamports = 0; |
92 | 79 |
|
93 | 80 | Ok(())
|
94 | 81 | }
|
0 commit comments