Skip to content

Commit 2ef0c2f

Browse files
author
Bengt Lofgren
committed
added all functionality, compiles
1 parent c50bfdb commit 2ef0c2f

22 files changed

+2837
-1
lines changed

solana/Cargo.lock

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

solana/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ hex = "0.4.3"
4747
ruint = "1.9.0"
4848
cfg-if = "1.0"
4949
hex-literal = "0.4.1"
50+
bytemuck = "1.13.0"
51+
52+
wormhole-svm-shim = { git = "https://github.com/wormholelabs-xyz/wormhole.git", rev = "32cb65dd9ae11547f0e57d106b6974dc8ed5f52d" }
53+
wormhole-svm-definitions = { git = "https://github.com/wormholelabs-xyz/wormhole.git", rev = "32cb65dd9ae11547f0e57d106b6974dc8ed5f52d", features = ["borsh"] }
54+
55+
5056

5157
[profile.release]
5258
overflow-checks = true

solana/programs/matching-engine/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ solana-program.workspace = true
3939
hex.workspace = true
4040
ruint.workspace = true
4141
cfg-if.workspace = true
42+
bytemuck.workspace = true
43+
wormhole-svm-definitions.workspace = true
44+
wormhole-svm-shim.workspace = true
4245

4346
[dev-dependencies]
4447
hex-literal.workspace = true

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,22 @@ pub enum MatchingEngineError {
8787
CannotCloseAuctionYet = 0x500,
8888
AuctionHistoryNotFull = 0x502,
8989
AuctionHistoryFull = 0x504,
90+
91+
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,
90106
}
91107

92108
#[cfg(test)]
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
mod processor;
2+
pub use processor::*;
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use crate::state::Custodian;
2+
use anchor_lang::prelude::*;
3+
use common::wormhole_cctp_solana::{
4+
cctp::token_messenger_minter_program::cpi::{
5+
deposit_for_burn_with_caller, DepositForBurnWithCaller, DepositForBurnWithCallerParams,
6+
},
7+
cpi::BurnAndPublishArgs,
8+
};
9+
use solana_program::program::invoke_signed_unchecked;
10+
use wormhole_svm_definitions::solana::{
11+
CORE_BRIDGE_CONFIG, CORE_BRIDGE_FEE_COLLECTOR, CORE_BRIDGE_PROGRAM_ID,
12+
POST_MESSAGE_SHIM_EVENT_AUTHORITY, POST_MESSAGE_SHIM_PROGRAM_ID,
13+
};
14+
use wormhole_svm_definitions::{
15+
find_emitter_sequence_address, find_shim_message_address, solana::Finality,
16+
};
17+
use wormhole_svm_shim::post_message;
18+
19+
// This is a helper struct to make it easier to pass in the accounts for the post_message instruction.
20+
pub struct PostMessageAccounts {
21+
pub emitter: Pubkey,
22+
pub payer: Pubkey,
23+
derived: PostMessageDerivedAccounts,
24+
}
25+
26+
impl PostMessageAccounts {
27+
pub fn new(emitter: Pubkey, payer: Pubkey) -> Self {
28+
Self {
29+
emitter,
30+
payer,
31+
derived: Self::get_derived_accounts(&emitter),
32+
}
33+
}
34+
fn get_derived_accounts(emitter: &Pubkey) -> PostMessageDerivedAccounts {
35+
PostMessageDerivedAccounts {
36+
message: find_shim_message_address(emitter, &POST_MESSAGE_SHIM_PROGRAM_ID).0,
37+
sequence: find_emitter_sequence_address(emitter, &CORE_BRIDGE_PROGRAM_ID).0,
38+
}
39+
}
40+
}
41+
42+
pub struct PostMessageDerivedAccounts {
43+
pub message: Pubkey,
44+
pub sequence: Pubkey,
45+
}
46+
47+
pub fn burn_and_post<'info>(
48+
cctp_ctx: CpiContext<'_, '_, '_, 'info, DepositForBurnWithCaller<'info>>,
49+
burn_and_publish_args: BurnAndPublishArgs,
50+
post_message_accounts: PostMessageAccounts,
51+
account_infos: &[AccountInfo],
52+
) -> Result<()> {
53+
let BurnAndPublishArgs {
54+
burn_source: _,
55+
destination_caller,
56+
destination_cctp_domain,
57+
amount,
58+
mint_recipient,
59+
wormhole_message_nonce,
60+
payload,
61+
} = burn_and_publish_args;
62+
63+
// Post message to the shim program
64+
let post_message_ix = post_message::PostMessage {
65+
program_id: &POST_MESSAGE_SHIM_PROGRAM_ID,
66+
accounts: post_message::PostMessageAccounts {
67+
emitter: &post_message_accounts.emitter,
68+
payer: &post_message_accounts.payer,
69+
wormhole_program_id: &CORE_BRIDGE_PROGRAM_ID,
70+
derived: post_message::PostMessageDerivedAccounts {
71+
message: Some(&post_message_accounts.derived.message),
72+
sequence: Some(&post_message_accounts.derived.sequence),
73+
core_bridge_config: Some(&CORE_BRIDGE_CONFIG),
74+
fee_collector: Some(&CORE_BRIDGE_FEE_COLLECTOR),
75+
event_authority: Some(&POST_MESSAGE_SHIM_EVENT_AUTHORITY),
76+
},
77+
},
78+
data: post_message::PostMessageData::new(
79+
wormhole_message_nonce,
80+
Finality::Finalized,
81+
&payload,
82+
)
83+
.unwrap(),
84+
}
85+
.instruction();
86+
87+
invoke_signed_unchecked(&post_message_ix, account_infos, &[Custodian::SIGNER_SEEDS])?;
88+
89+
// Deposit for burn
90+
deposit_for_burn_with_caller(
91+
cctp_ctx,
92+
DepositForBurnWithCallerParams {
93+
amount,
94+
destination_domain: destination_cctp_domain,
95+
mint_recipient,
96+
destination_caller,
97+
},
98+
)?;
99+
Ok(())
100+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use crate::state::FastMarketOrder;
2+
use anchor_lang::prelude::*;
3+
use solana_program::instruction::Instruction;
4+
use solana_program::program_error::ProgramError;
5+
6+
use super::helpers::check_account_length;
7+
use super::FallbackMatchingEngineInstruction;
8+
9+
pub struct CloseFastMarketOrderAccounts<'ix> {
10+
/// The fast market order account created from the initialise fast market order instruction
11+
pub fast_market_order: &'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,
15+
}
16+
17+
impl<'ix> CloseFastMarketOrderAccounts<'ix> {
18+
pub fn to_account_metas(&self) -> Vec<AccountMeta> {
19+
vec![
20+
AccountMeta::new(*self.fast_market_order, false),
21+
AccountMeta::new(*self.close_account_refund_recipient, true),
22+
]
23+
}
24+
}
25+
26+
pub struct CloseFastMarketOrder<'ix> {
27+
pub program_id: &'ix Pubkey,
28+
pub accounts: CloseFastMarketOrderAccounts<'ix>,
29+
}
30+
31+
impl CloseFastMarketOrder<'_> {
32+
pub fn instruction(&self) -> Instruction {
33+
Instruction {
34+
program_id: *self.program_id,
35+
accounts: self.accounts.to_account_metas(),
36+
data: FallbackMatchingEngineInstruction::CloseFastMarketOrder.to_vec(),
37+
}
38+
}
39+
}
40+
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<()>
50+
pub fn close_fast_market_order(accounts: &[AccountInfo]) -> Result<()> {
51+
check_account_length(accounts, 2)?;
52+
53+
let fast_market_order = &accounts[0];
54+
let close_account_refund_recipient = &accounts[1];
55+
56+
if !close_account_refund_recipient.is_signer {
57+
msg!("Refund recipient (account #2) is not a signer");
58+
return Err(ProgramError::InvalidAccountData.into());
59+
}
60+
61+
let fast_market_order_data =
62+
FastMarketOrder::try_deserialize(&mut &fast_market_order.data.borrow()[..])?;
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::from(fast_market_order_data.close_account_refund_recipient),
69+
close_account_refund_recipient.key(),
70+
))
71+
});
72+
}
73+
74+
// Transfer the lamports from the fast market order to the close account refund recipient
75+
let mut fast_market_order_lamports = fast_market_order.lamports.borrow_mut();
76+
**close_account_refund_recipient.lamports.borrow_mut() =
77+
(**close_account_refund_recipient.lamports.borrow())
78+
.saturating_add(**fast_market_order_lamports);
79+
**fast_market_order_lamports = 0;
80+
81+
Ok(())
82+
}

0 commit comments

Comments
 (0)