Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

solana: deprecate auction history #207

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions solana/programs/matching-engine/src/events/auction_closed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use anchor_lang::prelude::*;

use crate::state::Auction;

#[event]
#[derive(Debug)]
pub struct AuctionClosed {
pub auction: Auction,
}
3 changes: 3 additions & 0 deletions solana/programs/matching-engine/src/events/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
mod auction_closed;
pub use auction_closed::*;

mod auction_settled;
pub use auction_settled::*;

Expand Down
107 changes: 67 additions & 40 deletions solana/programs/matching-engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,46 +354,6 @@ pub mod matching_engine {
processor::settle_auction_none_local(ctx)
}

/// This instruction is used to create the first `AuctionHistory` account, whose PDA is derived
/// using ID == 0.
///
/// # Arguments
///
/// * `ctx` - `CreateFirstAuctionHistory` context.
pub fn create_first_auction_history(ctx: Context<CreateFirstAuctionHistory>) -> Result<()> {
processor::create_first_auction_history(ctx)
}

/// This instruction is used to create a new `AuctionHistory` account. The PDA is derived using
/// its ID. A new history account can be created only when the current one is full (number of
/// entries equals the hard-coded max entries).
///
/// # Arguments
///
/// * `ctx` - `CreateNewAuctionHistory` context.
pub fn create_new_auction_history(ctx: Context<CreateNewAuctionHistory>) -> Result<()> {
processor::create_new_auction_history(ctx)
}

/// This instruction is used to add a new entry to the `AuctionHistory` account if there is an
/// `Auction` with some info. Regardless of whether there is info in this account, the
/// instruction finishes its operation by closing this auction account. If the history account
/// is full, this instruction will revert and `create_new_auction_history`` will have to be
/// called to initialize another history account.
///
/// This mechanism is important for auction participants. The initial offer participant will
/// pay lamports to create the `Auction` account. This instruction allows him to reclaim some
/// lamports by closing that account. And the protocol's fee recipient will be able to claim
/// lamports by closing the empty `Auction` account it creates when he calls any of the
/// `settle_auction_none_*` instructions.
///
/// # Arguments
///
/// * `ctx` - `AddAuctionHistoryEntry` context.
pub fn add_auction_history_entry(ctx: Context<AddAuctionHistoryEntry>) -> Result<()> {
processor::add_auction_history_entry(ctx)
}

/// This instruction is used to reserve a sequence number for a fast fill. Fast fills are orders
/// that have been fulfilled and are destined for Solana and are seeded by source chain, order
/// sender and sequence number (similar to how Wormhole VAAs are identified by emitter chain,
Expand All @@ -415,6 +375,7 @@ pub mod matching_engine {
) -> Result<()> {
processor::reserve_fast_fill_sequence_active_auction(ctx)
}

/// This instruction is used to reserve a sequence number for a fast fill. Fast fills are orders
/// that have been fulfilled and are destined for Solana and are seeded by source chain, order
/// sender and sequence number (similar to how Wormhole VAAs are identified by emitter chain,
Expand Down Expand Up @@ -452,6 +413,72 @@ pub mod matching_engine {
pub fn close_redeemed_fast_fill(ctx: Context<CloseRedeemedFastFill>) -> Result<()> {
processor::close_redeemed_fast_fill(ctx)
}

/// This instruction is used to close an auction account after the auction has been settled and
/// the VAA's timestamp indicates the order has expired. This instruction can be called by
/// anyone to return the auction's preparer lamports from the rent required to keep this account
/// alive. The auction data will be serialized as Anchor event CPI instruction data.
///
/// # Arguments
///
/// * `ctx` - `CloseAuction` context.
pub fn close_auction(ctx: Context<CloseAuction>) -> Result<()> {
processor::close_auction(ctx)
}

// Deprecated instructions. These instructions will revert with `ErrorCode::InstructionMissing`.

/// DEPRECATED. This instruction does not exist anymore.
///
/// This instruction is used to create the first `AuctionHistory` account, whose PDA is derived
/// using ID == 0.
///
/// # Arguments
///
/// * `ctx` - `CreateFirstAuctionHistory` context.
pub fn create_first_auction_history(_ctx: Context<DeprecatedInstruction>) -> Result<()> {
err!(ErrorCode::Deprecated)
}

/// DEPRECATED. This instruction does not exist anymore.
///
/// This instruction is used to create a new `AuctionHistory` account. The PDA is derived using
/// its ID. A new history account can be created only when the current one is full (number of
/// entries equals the hard-coded max entries).
///
/// # Arguments
///
/// * `ctx` - `CreateNewAuctionHistory` context.
pub fn create_new_auction_history(_ctx: Context<DeprecatedInstruction>) -> Result<()> {
err!(ErrorCode::Deprecated)
}

/// DEPRECATED. This instruction does not exist anymore.
///
/// This instruction is used to add a new entry to the `AuctionHistory` account if there is an
/// `Auction` with some info. Regardless of whether there is info in this account, the
/// instruction finishes its operation by closing this auction account. If the history account
/// is full, this instruction will revert and `create_new_auction_history`` will have to be
/// called to initialize another history account.
///
/// This mechanism is important for auction participants. The initial offer participant will
/// pay lamports to create the `Auction` account. This instruction allows him to reclaim some
/// lamports by closing that account. And the protocol's fee recipient will be able to claim
/// lamports by closing the empty `Auction` account it creates when he calls any of the
/// `settle_auction_none_*` instructions.
///
/// # Arguments
///
/// * `ctx` - `AddAuctionHistoryEntry` context.
pub fn add_auction_history_entry(_ctx: Context<DeprecatedInstruction>) -> Result<()> {
err!(ErrorCode::Deprecated)
}
}

#[derive(Accounts)]
pub struct DeprecatedInstruction<'info> {
/// CHECK: This account is here to avoid program macro compilation errors.
_dummy: UncheckedAccount<'info>,
}

#[cfg(test)]
Expand Down
48 changes: 48 additions & 0 deletions solana/programs/matching-engine/src/processor/auction/close.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use std::ops::Deref;

use crate::{
error::MatchingEngineError,
state::{Auction, AuctionStatus},
};
use anchor_lang::prelude::*;

#[derive(Accounts)]
#[event_cpi]
pub struct CloseAuction<'info> {
#[account(
mut,
close = beneficiary,
constraint = {
require!(
matches!(auction.status, AuctionStatus::Settled {..}),
MatchingEngineError::AuctionNotSettled,
);

let expiration =
i64::from(auction.vaa_timestamp).saturating_add(crate::VAA_AUCTION_EXPIRATION_TIME);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to wait 2 hours before we're able to close the auction account? Isn't the fact that it has been Settled sufficient?

It would be nice if we were able to close auctions in the same transaction where we settle them. In order to do that with the current implementation, we would need to wait for almost two hours which we cannot afford to do as we want to get our funds back as soon as possible to optimize their utilization.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This window exists so an auction cannot start using the same VAA within that arbitrarily long window. This duration can be tightened up in the future with a matching engine upgrade, though.

Reference:

// Check to see if the deadline has expired.
let deadline = order.deadline();
let expiration =
i64::from(fast_vaa.timestamp()).saturating_add(crate::VAA_AUCTION_EXPIRATION_TIME);
require!(
(deadline == 0 || curr_time < deadline.into()) && curr_time < expiration,
MatchingEngineError::FastMarketOrderExpired,
);

require!(
Clock::get().unwrap().unix_timestamp >= expiration,
MatchingEngineError::CannotCloseAuctionYet,
);

true
}
)]
auction: Account<'info, Auction>,

/// CHECK: This account is whoever originally created the auction account (see
/// [Auction::prepared_by].
#[account(
mut,
address = auction.prepared_by,
)]
beneficiary: UncheckedAccount<'info>,
}

pub fn close_auction(ctx: Context<CloseAuction>) -> Result<()> {
emit_cpi!(crate::events::AuctionClosed {
auction: ctx.accounts.auction.deref().clone(),
});

Ok(())
}

This file was deleted.

This file was deleted.

Loading