Skip to content

Commit 8e451aa

Browse files
committed
solana: fix beneficiary for reserved sequence
1 parent 2746d80 commit 8e451aa

File tree

6 files changed

+45
-87
lines changed

6 files changed

+45
-87
lines changed

solana/programs/matching-engine/src/composite/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ impl<'info> VaaDigest for ClosePreparedOrderResponse<'info> {
566566
#[derive(Accounts)]
567567
pub struct ReserveFastFillSequence<'info> {
568568
#[account(mut)]
569-
payer: Signer<'info>,
569+
pub payer: Signer<'info>,
570570

571571
pub fast_order_path: FastOrderPath<'info>,
572572

solana/programs/matching-engine/src/processor/auction/execute_fast_order/mod.rs

+25-24
Original file line numberDiff line numberDiff line change
@@ -99,32 +99,33 @@ fn handle_execute_fast_order<'info>(
9999
// init auction fee. The executor will get these funds instead.
100100
//
101101
// We check that this is a legitimate token account.
102-
if utils::checked_deserialize_token_account(initial_offer_token, &custody_token.mint)
102+
if utils::checked_deserialize_token_account(initial_offer_token, &common::USDC_MINT)
103103
.is_some()
104-
&& best_offer_token.key() != initial_offer_token.key()
105104
{
106-
// Pay the auction initiator their fee.
107-
token::transfer(
108-
CpiContext::new_with_signer(
109-
token_program.to_account_info(),
110-
token::Transfer {
111-
from: custody_token.to_account_info(),
112-
to: initial_offer_token.to_account_info(),
113-
authority: auction.to_account_info(),
114-
},
115-
&[auction_signer_seeds],
116-
),
117-
init_auction_fee,
118-
)?;
105+
if best_offer_token.key() != initial_offer_token.key() {
106+
// Pay the auction initiator their fee.
107+
token::transfer(
108+
CpiContext::new_with_signer(
109+
token_program.to_account_info(),
110+
token::Transfer {
111+
from: custody_token.to_account_info(),
112+
to: initial_offer_token.to_account_info(),
113+
authority: auction.to_account_info(),
114+
},
115+
&[auction_signer_seeds],
116+
),
117+
init_auction_fee,
118+
)?;
119119

120-
// Because the initial offer token was paid this fee, we account for it here.
121-
remaining_custodied_amount =
122-
remaining_custodied_amount.saturating_sub(init_auction_fee);
123-
} else {
124-
// Add it to the reimbursement.
125-
deposit_and_fee = deposit_and_fee
126-
.checked_add(init_auction_fee)
127-
.ok_or_else(|| MatchingEngineError::U64Overflow)?;
120+
// Because the initial offer token was paid this fee, we account for it here.
121+
remaining_custodied_amount =
122+
remaining_custodied_amount.saturating_sub(init_auction_fee);
123+
} else {
124+
// Add it to the reimbursement.
125+
deposit_and_fee = deposit_and_fee
126+
.checked_add(init_auction_fee)
127+
.ok_or_else(|| MatchingEngineError::U64Overflow)?;
128+
}
128129
}
129130

130131
// Return the security deposit and the fee to the highest bidder.
@@ -152,7 +153,7 @@ fn handle_execute_fast_order<'info>(
152153
// Otherwise, send the deposit and fee to the best offer token. If the best offer token
153154
// doesn't exist at this point (which would be unusual), we will reserve these funds
154155
// for the executor token.
155-
if utils::checked_deserialize_token_account(best_offer_token, &custody_token.mint)
156+
if utils::checked_deserialize_token_account(best_offer_token, &common::USDC_MINT)
156157
.is_some()
157158
{
158159
token::transfer(

solana/programs/matching-engine/src/processor/auction/offer/improve.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ pub fn improve_offer(ctx: Context<ImproveOffer>, offer_price: u64) -> Result<()>
7979
// If the best offer token happens to be closed, we will just keep the funds in the
8080
// auction custody account. The executor token account will collect these funds when the
8181
// order is executed.
82-
if utils::checked_deserialize_token_account(best_offer_token, &custody_token.mint)
82+
if utils::checked_deserialize_token_account(best_offer_token, &common::USDC_MINT)
8383
.is_some()
8484
{
8585
token::transfer(

solana/programs/matching-engine/src/processor/auction/settle/complete.rs

+16-14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::{
22
error::MatchingEngineError,
33
events::SettledTokenAccountInfo,
44
state::{Auction, AuctionStatus, PreparedOrderResponse},
5+
utils,
56
};
67
use anchor_lang::prelude::*;
78
use anchor_spl::{
@@ -116,23 +117,24 @@ fn handle_settle_auction_complete(
116117
let (executor_result, best_offer_result) = match execute_penalty {
117118
None => {
118119
// If the token account happens to not exist anymore, we will revert.
119-
match TokenAccount::try_deserialize(&mut &best_offer_token.data.borrow()[..]) {
120-
Ok(best_offer) => (
121-
None, // executor_result
122-
TokenAccountResult {
123-
balance_before: best_offer.amount,
124-
amount: repayment,
125-
}
126-
.into(),
127-
),
128-
Err(err) => return Err(err),
129-
}
120+
let best_offer =
121+
utils::checked_deserialize_token_account(best_offer_token, &common::USDC_MINT)
122+
.ok_or_else(|| MatchingEngineError::BestOfferTokenRequired)?;
123+
124+
(
125+
None, // executor_result
126+
TokenAccountResult {
127+
balance_before: best_offer.amount,
128+
amount: repayment,
129+
}
130+
.into(),
131+
)
130132
}
131133
_ => {
132134
// If the token account happens to not exist anymore, we will give everything to the
133135
// executor.
134-
match TokenAccount::try_deserialize(&mut &best_offer_token.data.borrow()[..]) {
135-
Ok(best_offer) => {
136+
match utils::checked_deserialize_token_account(best_offer_token, &common::USDC_MINT) {
137+
Some(best_offer) => {
136138
if executor_token.key() == best_offer_token.key() {
137139
(
138140
None, // executor_result
@@ -179,7 +181,7 @@ fn handle_settle_auction_complete(
179181
)
180182
}
181183
}
182-
Err(_) => (
184+
None => (
183185
TokenAccountResult {
184186
balance_before: executor_token.amount,
185187
amount: repayment,

solana/programs/matching-engine/src/processor/fast_fill/reserve_sequence/active_auction.rs

+1-46
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::{composite::*, error::MatchingEngineError, state::AuctionConfig};
22
use anchor_lang::prelude::*;
3-
use anchor_spl::token;
43

54
#[derive(Accounts)]
65
pub struct ReserveFastFillSequenceActiveAuction<'info> {
@@ -27,56 +26,12 @@ pub struct ReserveFastFillSequenceActiveAuction<'info> {
2726
}
2827
)]
2928
auction_config: Account<'info, AuctionConfig>,
30-
31-
/// Best offer token account, whose owner will be the beneficiary of the reserved fast fill
32-
/// sequence account when it is closed.
33-
///
34-
/// CHECK: This account may not exist. If it does, it should equal the best offer token pubkey
35-
/// in the auction account.
36-
#[account(
37-
constraint = {
38-
// We know from the auction constraint that the auction is active, so the auction info
39-
// is safe to unwrap.
40-
let info = reserve_sequence.auction.info.as_ref().unwrap();
41-
42-
// Best offer token must equal the one in the auction account.
43-
//
44-
// NOTE: Unwrapping the auction info is safe because we know this is an active auction.
45-
require_keys_eq!(
46-
best_offer_token.key(),
47-
info.best_offer_token,
48-
MatchingEngineError::BestOfferTokenMismatch
49-
);
50-
51-
true
52-
}
53-
)]
54-
best_offer_token: UncheckedAccount<'info>,
55-
56-
/// CHECK: If the best offer token does not exist anymore, this executor will be the beneficiary
57-
/// of the reserved fast fill sequence account when it is closed. Otherwise, this account must
58-
/// equal the best offer token account's owner.
59-
executor: UncheckedAccount<'info>,
6029
}
6130

6231
pub fn reserve_fast_fill_sequence_active_auction(
6332
ctx: Context<ReserveFastFillSequenceActiveAuction>,
6433
) -> Result<()> {
65-
let best_offer_token = &ctx.accounts.best_offer_token;
66-
let beneficiary = ctx.accounts.executor.key();
67-
68-
// If the token account does exist, we will constrain that the executor is the best offer token.
69-
if let Ok(token) =
70-
token::TokenAccount::try_deserialize(&mut &best_offer_token.data.borrow()[..])
71-
{
72-
require_keys_eq!(
73-
*best_offer_token.owner,
74-
token::ID,
75-
ErrorCode::ConstraintTokenTokenProgram
76-
);
77-
require_keys_eq!(token.owner, beneficiary, ErrorCode::ConstraintTokenOwner);
78-
}
79-
34+
let beneficiary = ctx.accounts.reserve_sequence.payer.key();
8035
let fast_vaa_hash = ctx.accounts.reserve_sequence.auction.vaa_hash;
8136

8237
super::set_reserved_sequence_data(

solana/ts/tests/04__interaction.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,7 @@ describe("Matching Engine <> Token Router", function () {
10911091
const { success, result } = await invokeReserveFastFillSequence(
10921092
ix,
10931093
fastVaaAccount,
1094-
playerOne.publicKey,
1094+
payer.publicKey,
10951095
testOpts,
10961096
);
10971097

0 commit comments

Comments
 (0)