Skip to content

Commit 2c87cf9

Browse files
author
Bengt Lofgren
committed
fixed stack issue with prepare order response
1 parent 52050e6 commit 2c87cf9

27 files changed

+1227
-397
lines changed

solana/programs/matching-engine/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,13 @@
22

33
A program to facilitate the transfer of USDC between networks that allow Wormhole and CCTP bridging.
44
With the help of solvers, allowing USDC to be transferred faster than finality.
5+
6+
## Testing plan
7+
8+
The testing engine should be designed in a functional way that allows for easy testing of the program instructions.
9+
10+
The instructions passed to the testing engine should be able to be composed in a way where each instruction returns the updated state (not a mutating state).
11+
12+
This state is predictable and has the benefit of being able to be tested in isolation and mocked (to an extent) for testing.
13+
14+

solana/programs/matching-engine/src/error.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,20 @@ pub enum MatchingEngineError {
8989
AuctionHistoryFull = 0x504,
9090

9191
InvalidVerifyVaaShimProgram = 0x600,
92+
93+
// Fallback matching engine errors
94+
AccountAlreadyInitialized = 0x700,
95+
AccountNotWritable = 0x702,
96+
BorshDeserializationError = 0x704,
97+
InvalidPda = 0x706,
98+
AccountDataTooSmall = 0x708,
99+
InvalidProgram = 0x70a,
100+
TokenTransferFailed = 0x70c,
101+
InvalidMint = 0x70e,
102+
103+
#[msg("From and to router endpoints are the same")]
104+
SameEndpoints = 0x800,
105+
InvalidCctpMessage = 0x802,
92106
}
93107

94108
#[cfg(test)]

solana/programs/matching-engine/src/fallback/processor/close_fast_market_order.rs

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,22 @@ use anchor_lang::prelude::*;
33
use solana_program::instruction::Instruction;
44
use solana_program::program_error::ProgramError;
55

6+
use super::helpers::check_account_length;
67
use super::FallbackMatchingEngineInstruction;
78

89
pub struct CloseFastMarketOrderAccounts<'ix> {
10+
/// The fast market order account created from the initialise fast market order instruction
911
pub fast_market_order: &'ix Pubkey,
10-
pub refund_recipient: &'ix Pubkey,
12+
/// The account that will receive the refund. CHECK: Must be a signer.
13+
/// CHECK: Must match the close account refund recipient in the fast market order account
14+
pub close_account_refund_recipient: &'ix Pubkey,
1115
}
1216

1317
impl<'ix> CloseFastMarketOrderAccounts<'ix> {
1418
pub fn to_account_metas(&self) -> Vec<AccountMeta> {
1519
vec![
1620
AccountMeta::new(*self.fast_market_order, false),
17-
AccountMeta::new(*self.refund_recipient, false),
21+
AccountMeta::new(*self.close_account_refund_recipient, true),
1822
]
1923
}
2024
}
@@ -34,32 +38,43 @@ impl CloseFastMarketOrder<'_> {
3438
}
3539
}
3640

41+
/// Closes the fast market order and transfers the lamports from the fast market order to the close account refund recipient
42+
///
43+
/// # Arguments
44+
///
45+
/// * `accounts` - The accounts of the fast market order and the close account refund recipient
46+
///
47+
/// # Returns
48+
///
49+
/// Result<()>
3750
pub fn close_fast_market_order(accounts: &[AccountInfo]) -> Result<()> {
38-
if accounts.len() < 2 {
39-
return Err(ProgramError::NotEnoughAccountKeys.into());
40-
}
51+
check_account_length(accounts, 2)?;
4152

4253
let fast_market_order = &accounts[0];
43-
let refund_recipient = &accounts[1];
54+
let close_account_refund_recipient = &accounts[1];
4455

45-
if !refund_recipient.is_signer {
56+
if !close_account_refund_recipient.is_signer {
4657
msg!("Refund recipient (account #2) is not a signer");
4758
return Err(ProgramError::InvalidAccountData.into());
4859
}
4960

5061
let fast_market_order_data =
5162
FastMarketOrder::try_deserialize(&mut &fast_market_order.data.borrow()[..])?;
52-
if fast_market_order_data.refund_recipient != refund_recipient.key().as_ref() {
53-
msg!("Refund recipient (account #2) mismatch");
54-
msg!("Actual:");
55-
msg!("{:?}", refund_recipient.key.as_ref());
56-
msg!("Expected:");
57-
msg!("{:?}", fast_market_order_data.refund_recipient);
58-
return Err(ProgramError::InvalidAccountData.into());
63+
if fast_market_order_data.close_account_refund_recipient
64+
!= close_account_refund_recipient.key().as_ref()
65+
{
66+
return Err(ProgramError::InvalidAccountData.into()).map_err(|e: Error| {
67+
e.with_pubkeys((
68+
Pubkey::try_from(fast_market_order_data.close_account_refund_recipient)
69+
.expect("Failed to convert close account refund recipient to pubkey"),
70+
close_account_refund_recipient.key(),
71+
))
72+
});
5973
}
6074

75+
// Transfer the lamports from the fast market order to the close account refund recipient
6176
let mut fast_market_order_lamports = fast_market_order.lamports.borrow_mut();
62-
**refund_recipient.lamports.borrow_mut() += **fast_market_order_lamports;
77+
**close_account_refund_recipient.lamports.borrow_mut() += **fast_market_order_lamports;
6378
**fast_market_order_lamports = 0;
6479

6580
Ok(())

solana/programs/matching-engine/src/fallback/processor/errors.rs

Lines changed: 0 additions & 35 deletions
This file was deleted.

solana/programs/matching-engine/src/fallback/processor/execute_order.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::helpers::check_account_length;
12
use crate::state::{
23
Auction, AuctionConfig, AuctionStatus, Custodian, FastMarketOrder as FastMarketOrderState,
34
MessageProtocol, RouterEndpoint,
@@ -12,7 +13,6 @@ use solana_program::instruction::Instruction;
1213
use solana_program::program::invoke_signed_unchecked;
1314

1415
use super::burn_and_post::{burn_and_post, PostMessageAccounts};
15-
use super::errors::FallbackError;
1616
use super::FallbackMatchingEngineInstruction;
1717
use crate::error::MatchingEngineError;
1818

@@ -153,7 +153,11 @@ impl ExecuteOrderCctpShim<'_> {
153153
}
154154
}
155155
}
156+
156157
pub fn handle_execute_order_shim(accounts: &[AccountInfo]) -> Result<()> {
158+
// This saves stack space whereas having that in the body does not
159+
check_account_length(accounts, 31)?;
160+
157161
let program_id = &crate::ID;
158162

159163
// Get the accounts
@@ -169,8 +173,6 @@ pub fn handle_execute_order_shim(accounts: &[AccountInfo]) -> Result<()> {
169173
let initial_offer_token_account = &accounts[9];
170174
let initial_participant_account = &accounts[10];
171175
let to_router_endpoint_account = &accounts[11];
172-
// TODO: These are not used, so can I just ignore them?
173-
// TODO: Check that this is the correct program id for the post message shim program
174176
let _post_message_shim_program_account = &accounts[12];
175177
let _post_message_sequence_account = &accounts[13];
176178
let _post_message_message_account = &accounts[14];
@@ -202,7 +204,7 @@ pub fn handle_execute_order_shim(accounts: &[AccountInfo]) -> Result<()> {
202204
// Check cctp message is mutable
203205
if !cctp_message_account.is_writable {
204206
msg!("Cctp message is not writable");
205-
return Err(FallbackError::AccountNotWritable.into())
207+
return Err(MatchingEngineError::AccountNotWritable.into())
206208
.map_err(|e: Error| e.with_account_name("cctp_message"));
207209
}
208210

@@ -244,7 +246,9 @@ pub fn handle_execute_order_shim(accounts: &[AccountInfo]) -> Result<()> {
244246
let fast_market_order_seeds = [
245247
FastMarketOrderState::SEED_PREFIX,
246248
fast_market_order_digest.as_ref(),
247-
fast_market_order_zero_copy.refund_recipient.as_ref(),
249+
fast_market_order_zero_copy
250+
.close_account_refund_recipient
251+
.as_ref(),
248252
];
249253

250254
let (fast_market_order_pda, _fast_market_order_bump) =
@@ -274,8 +278,6 @@ pub fn handle_execute_order_shim(accounts: &[AccountInfo]) -> Result<()> {
274278
let mut active_auction =
275279
Auction::try_deserialize(&mut &active_auction_account.data.borrow()[..])?;
276280

277-
// TODO: Check that the auction has reached its deadline
278-
279281
// Correct way to use create_program_address with existing seeds and bump
280282
let active_auction_pda = Pubkey::create_program_address(
281283
&[
@@ -287,7 +289,7 @@ pub fn handle_execute_order_shim(accounts: &[AccountInfo]) -> Result<()> {
287289
)
288290
.map_err(|_| {
289291
msg!("Failed to create program address with known bump");
290-
FallbackError::InvalidPda
292+
MatchingEngineError::InvalidPda
291293
})?;
292294
if active_auction_pda != active_auction_account.key() {
293295
msg!("Active auction pda is invalid");
@@ -314,7 +316,7 @@ pub fn handle_execute_order_shim(accounts: &[AccountInfo]) -> Result<()> {
314316
)
315317
.map_err(|_| {
316318
msg!("Failed to create program address with known bump");
317-
FallbackError::InvalidPda
319+
MatchingEngineError::InvalidPda
318320
})?;
319321
if active_auction_custody_token_pda != active_auction_custody_token_account.key() {
320322
msg!("Active auction custody token pda is invalid");
@@ -335,6 +337,14 @@ pub fn handle_execute_order_shim(accounts: &[AccountInfo]) -> Result<()> {
335337
.map_err(|e: Error| e.with_account_name("active_auction_config"));
336338
};
337339

340+
// Check that the auction has reached its deadline
341+
let auction_info = active_auction.info.as_ref().unwrap();
342+
if auction_info.within_auction_duration(&active_auction_config.parameters) {
343+
msg!("Auction has not reached its deadline");
344+
return Err(MatchingEngineError::AuctionPeriodNotExpired.into())
345+
.map_err(|e: Error| e.with_account_name("active_auction"));
346+
}
347+
338348
// Check active auction best offer token address
339349
if active_auction_best_offer_token_account.key()
340350
!= active_auction.info.as_ref().unwrap().best_offer_token

solana/programs/matching-engine/src/fallback/processor/create_account.rs renamed to solana/programs/matching-engine/src/fallback/processor/helpers.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
use anchor_lang::prelude::*;
2+
23
use solana_program::{
34
entrypoint::ProgramResult,
45
instruction::{AccountMeta, Instruction},
56
program::invoke_signed_unchecked,
67
system_instruction,
78
};
9+
10+
#[inline(always)]
11+
pub fn check_account_length(accounts: &[AccountInfo], len: usize) -> Result<()> {
12+
if accounts.len() < len {
13+
return Err(ErrorCode::AccountNotEnoughKeys.into());
14+
}
15+
Ok(())
16+
}
17+
818
pub fn create_account_reliably(
919
payer_key: &Pubkey,
1020
account_key: &Pubkey,

0 commit comments

Comments
 (0)