Skip to content

Commit a8ec48f

Browse files
author
Bengt Lofgren
committed
attended rest of comments
1 parent aa9dbd4 commit a8ec48f

File tree

20 files changed

+465
-66
lines changed

20 files changed

+465
-66
lines changed

solana/Cargo.lock

Lines changed: 12 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: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ overflow-checks = true
6161
# lto = "fat"
6262
# codegen-units = 1
6363

64-
# [profile.release.build-override]
65-
# opt-level = 3
66-
# incremental = false
67-
# codegen-units = 1
64+
[profile.release.build-override]
65+
opt-level = 3
66+
incremental = false
67+
codegen-units = 1
6868

6969
[workspace.lints.clippy]
7070
correctness = { priority = -1, level = "warn"}

solana/clippy.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,4 @@ disallowed-methods = [
44
{ path = "std::option::Option::map_or", reason = "prefer `map_or_else` for lazy evaluation" },
55
{ path = "std::option::Option::ok_or", reason = "prefer `ok_or_else` for lazy evaluation" },
66
{ path = "std::option::Option::unwrap_or", reason = "prefer `unwrap_or_else` for lazy evaluation" },
7-
]
8-
9-
allow-expect-in-tests = true
7+
]

solana/modules/matching-engine-testing/Cargo.toml

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,10 @@ repository.workspace = true
1010
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1111

1212
[features]
13-
default = ["no-idl"]
14-
no-entrypoint = []
15-
no-idl = []
16-
no-log-ix-name = []
17-
cpi = ["no-entrypoint"]
1813
mainnet = ["matching-engine/mainnet", "common/mainnet"]
1914
testnet = ["matching-engine/testnet", "common/testnet"]
2015
localnet = ["matching-engine/localnet", "common/localnet"]
2116
integration-test = ["localnet"]
22-
idl-build = [
23-
"localnet",
24-
"common/idl-build",
25-
"anchor-lang/idl-build",
26-
"anchor-spl/idl-build"
27-
]
2817

2918
[dev-dependencies]
3019
matching-engine.workspace = true

solana/modules/matching-engine-testing/tests/testing_engine/setup.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,14 +1071,8 @@ pub async fn setup_environment(
10711071
Some(vaa_args_plural) => {
10721072
let mut vaas_test_temp = TestVaaPairs::new();
10731073
for vaa_args in vaa_args_plural {
1074-
let arbitrum_emitter_address: [u8; 32] = REGISTERED_TOKEN_ROUTERS[&Chain::Arbitrum]
1075-
.clone()
1076-
.try_into()
1077-
.expect("Failed to convert registered token router address to bytes [u8; 32]");
1078-
let ethereum_emitter_address: [u8; 32] = REGISTERED_TOKEN_ROUTERS[&Chain::Ethereum]
1079-
.clone()
1080-
.try_into()
1081-
.expect("Failed to convert registered token router address to bytes [u8; 32]");
1074+
let arbitrum_emitter_address: [u8; 32] = REGISTERED_TOKEN_ROUTERS[&Chain::Arbitrum];
1075+
let ethereum_emitter_address: [u8; 32] = REGISTERED_TOKEN_ROUTERS[&Chain::Ethereum];
10821076
let new_vaas_test = match transfer_direction {
10831077
TransferDirection::FromArbitrumToEthereum => {
10841078
create_vaas_test_with_chain_and_address(

solana/modules/matching-engine-testing/tests/utils/auction.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -437,12 +437,7 @@ impl AuctionAccounts {
437437
current_state: &TestingEngineState,
438438
testing_context: &TestingContext,
439439
) -> Self {
440-
let router_endpoints = current_state
441-
.router_endpoints()
442-
.clone()
443-
.unwrap()
444-
.endpoints
445-
.clone();
440+
let router_endpoints = current_state.router_endpoints().unwrap().endpoints.clone();
446441
let actor = testing_context.testing_actors.owner.clone();
447442
let transfer_direction = testing_context.transfer_direction;
448443
let auction_config = Pubkey::find_program_address(&[AuctionConfig::SEED_PREFIX], &ID).0;

solana/modules/matching-engine-testing/tests/utils/public_keys.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -147,18 +147,9 @@ impl ChainAddress {
147147

148148
pub fn from_registered_token_router(chain: Chain) -> Self {
149149
match chain {
150-
Chain::Arbitrum => Self::new_with_address(
151-
chain,
152-
REGISTERED_TOKEN_ROUTERS[&chain].clone().try_into().unwrap(),
153-
),
154-
Chain::Ethereum => Self::new_with_address(
155-
chain,
156-
REGISTERED_TOKEN_ROUTERS[&chain].clone().try_into().unwrap(),
157-
),
158-
Chain::Solana => Self::new_with_address(
159-
chain,
160-
REGISTERED_TOKEN_ROUTERS[&chain].clone().try_into().unwrap(),
161-
),
150+
Chain::Arbitrum => Self::new_with_address(chain, REGISTERED_TOKEN_ROUTERS[&chain]),
151+
Chain::Ethereum => Self::new_with_address(chain, REGISTERED_TOKEN_ROUTERS[&chain]),
152+
Chain::Solana => Self::new_with_address(chain, REGISTERED_TOKEN_ROUTERS[&chain]),
162153
_ => panic!("Unsupported chain"),
163154
}
164155
}

solana/modules/matching-engine-testing/tests/utils/router.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,7 @@ pub async fn add_cctp_router_endpoint_ix(
210210
system_program: anchor_lang::system_program::ID,
211211
};
212212

213-
let registered_token_router_address: [u8; 32] = REGISTERED_TOKEN_ROUTERS[&chain]
214-
.clone()
215-
.try_into()
216-
.expect("Failed to convert registered token router address to bytes [u8; 32]");
213+
let registered_token_router_address: [u8; 32] = REGISTERED_TOKEN_ROUTERS[&chain];
217214
let ix_data = AddCctpRouterEndpoint {
218215
args: AddCctpRouterEndpointArgs {
219216
chain: chain.as_chain_id(),
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "wormhole-matching-engine-api"
3+
edition.workspace = true
4+
version.workspace = true
5+
authors.workspace = true
6+
license.workspace = true
7+
homepage.workspace = true
8+
repository.workspace = true
9+
10+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
11+
12+
[dependencies]
13+
wormhole-svm-definitions.workspace = true
14+
bytemuck.workspace = true
15+
anchor-spl.workspace = true
16+
anchor-lang = { workspace = true, features = ["event-cpi", "init-if-needed"] }
17+
solana-program.workspace = true
18+
common.workspace = true
19+
20+
21+
[lints]
22+
workspace = true
23+
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
use bytemuck::{Pod, Zeroable};
2+
3+
use anchor_lang::prelude::*;
4+
use anchor_lang::Discriminator;
5+
use solana_program::keccak;
6+
use wormhole_svm_definitions::make_anchor_discriminator;
7+
8+
/// An account that represents a fast market order vaa. It is created by the signer of the transaction, and owned by the matching engine program.
9+
/// The of the account is able to close this account and redeem the lamports deposited into the account (for rent)
10+
#[derive(Debug, Copy, Clone, Pod, Zeroable)]
11+
#[repr(C)]
12+
pub struct FastMarketOrder {
13+
/// The amount of tokens sent from the source chain via the fast transfer
14+
pub amount_in: u64,
15+
/// The minimum amount of tokens to be received on the target chain via the fast transfer
16+
pub min_amount_out: u64,
17+
/// The deadline of the auction
18+
pub deadline: u32,
19+
/// The target chain (represented as a wormhole chain id)
20+
pub target_chain: u16,
21+
/// The length of the redeemer message
22+
pub redeemer_message_length: u16,
23+
/// The redeemer of the fast transfer (on the destination chain)
24+
pub redeemer: [u8; 32],
25+
/// The sender of the fast transfer (on the source chain)
26+
pub sender: [u8; 32],
27+
/// The refund address of the fast transfer
28+
pub refund_address: [u8; 32],
29+
/// The maximum fee of the fast transfer
30+
pub max_fee: u64,
31+
/// The initial auction fee of the fast transfer
32+
pub init_auction_fee: u64,
33+
/// The redeemer message of the fast transfer
34+
pub redeemer_message: [u8; 512],
35+
/// The refund recipient for the creator of the fast market order account
36+
pub close_account_refund_recipient: [u8; 32],
37+
/// The emitter address of the fast transfer
38+
pub vaa_emitter_address: [u8; 32],
39+
/// The sequence of the fast transfer vaa
40+
pub vaa_sequence: u64,
41+
/// The timestamp of the fast transfer vaa
42+
pub vaa_timestamp: u32,
43+
/// The vaa nonce, which is not used and can be set to 0
44+
pub vaa_nonce: u32,
45+
/// The source chain of the fast transfer vaa (represented as a wormhole chain id)
46+
pub vaa_emitter_chain: u16,
47+
/// The consistency level of the fast transfer vaa
48+
pub vaa_consistency_level: u8,
49+
/// Not used, but required for bytemuck serialisation
50+
_padding: [u8; 5],
51+
}
52+
53+
pub struct FastMarketOrderParams {
54+
pub amount_in: u64,
55+
pub min_amount_out: u64,
56+
pub deadline: u32,
57+
pub target_chain: u16,
58+
pub redeemer_message_length: u16,
59+
pub redeemer: [u8; 32],
60+
pub sender: [u8; 32],
61+
pub refund_address: [u8; 32],
62+
pub max_fee: u64,
63+
pub init_auction_fee: u64,
64+
pub redeemer_message: [u8; 512],
65+
pub close_account_refund_recipient: [u8; 32],
66+
pub vaa_sequence: u64,
67+
pub vaa_timestamp: u32,
68+
pub vaa_nonce: u32,
69+
pub vaa_emitter_chain: u16,
70+
pub vaa_consistency_level: u8,
71+
pub vaa_emitter_address: [u8; 32],
72+
}
73+
74+
impl FastMarketOrder {
75+
pub fn new(params: FastMarketOrderParams) -> Self {
76+
Self {
77+
amount_in: params.amount_in,
78+
min_amount_out: params.min_amount_out,
79+
deadline: params.deadline,
80+
target_chain: params.target_chain,
81+
redeemer_message_length: params.redeemer_message_length,
82+
redeemer: params.redeemer,
83+
sender: params.sender,
84+
refund_address: params.refund_address,
85+
max_fee: params.max_fee,
86+
init_auction_fee: params.init_auction_fee,
87+
redeemer_message: params.redeemer_message,
88+
close_account_refund_recipient: params.close_account_refund_recipient,
89+
vaa_sequence: params.vaa_sequence,
90+
vaa_timestamp: params.vaa_timestamp,
91+
vaa_nonce: params.vaa_nonce,
92+
vaa_emitter_chain: params.vaa_emitter_chain,
93+
vaa_consistency_level: params.vaa_consistency_level,
94+
vaa_emitter_address: params.vaa_emitter_address,
95+
_padding: [0_u8; 5],
96+
}
97+
}
98+
99+
pub const SEED_PREFIX: &'static [u8] = b"fast_market_order";
100+
101+
/// Convert the fast market order to a vec of bytes (without the discriminator)
102+
pub fn to_vec(&self) -> Vec<u8> {
103+
let payload_slice = bytemuck::bytes_of(self);
104+
let mut payload = Vec::with_capacity(payload_slice.len());
105+
payload.extend_from_slice(payload_slice);
106+
payload
107+
}
108+
109+
/// Creates an payload as expected in a fast market order vaa
110+
pub fn payload(&self) -> Vec<u8> {
111+
let mut payload = vec![];
112+
payload.push(11_u8); // This is the payload id for a fast market order
113+
payload.extend_from_slice(&self.amount_in.to_be_bytes());
114+
payload.extend_from_slice(&self.min_amount_out.to_be_bytes());
115+
payload.extend_from_slice(&self.target_chain.to_be_bytes());
116+
payload.extend_from_slice(&self.redeemer);
117+
payload.extend_from_slice(&self.sender);
118+
payload.extend_from_slice(&self.refund_address);
119+
payload.extend_from_slice(&self.max_fee.to_be_bytes());
120+
payload.extend_from_slice(&self.init_auction_fee.to_be_bytes());
121+
payload.extend_from_slice(&self.deadline.to_be_bytes());
122+
payload.extend_from_slice(&self.redeemer_message_length.to_be_bytes());
123+
if self.redeemer_message_length > 0 {
124+
payload.extend_from_slice(
125+
&self.redeemer_message[..usize::from(self.redeemer_message_length)],
126+
);
127+
}
128+
payload
129+
}
130+
131+
/// A double hash of the serialised fast market order. Used for seeds and verification.
132+
pub fn digest(&self) -> [u8; 32] {
133+
let message_hash = keccak::hashv(&[
134+
self.vaa_timestamp.to_be_bytes().as_ref(),
135+
self.vaa_nonce.to_be_bytes().as_ref(),
136+
self.vaa_emitter_chain.to_be_bytes().as_ref(),
137+
&self.vaa_emitter_address,
138+
&self.vaa_sequence.to_be_bytes(),
139+
&[self.vaa_consistency_level],
140+
self.payload().as_ref(),
141+
]);
142+
// Digest is the hash of the message
143+
keccak::hashv(&[message_hash.as_ref()])
144+
.as_ref()
145+
.try_into()
146+
.unwrap()
147+
}
148+
149+
/// Read from an account info
150+
pub fn try_read(data: &[u8]) -> Result<&Self> {
151+
if data.len() < 8 {
152+
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
153+
}
154+
let discriminator: [u8; 8] = data[0..8].try_into().unwrap();
155+
if discriminator != Self::discriminator() {
156+
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
157+
}
158+
let byte_muck_data = &data[8..];
159+
let fast_market_order = bytemuck::from_bytes::<Self>(byte_muck_data);
160+
Ok(fast_market_order)
161+
}
162+
}
163+
164+
impl Discriminator for FastMarketOrder {
165+
const DISCRIMINATOR: [u8; 8] = make_anchor_discriminator(Self::SEED_PREFIX);
166+
}
167+
168+
#[derive(Debug, Copy, Clone, Pod, Zeroable)]
169+
#[repr(C)]
170+
pub struct InitialiseFastMarketOrderData {
171+
/// The fast market order as the bytemuck struct
172+
pub fast_market_order: FastMarketOrder,
173+
/// The guardian set bump
174+
pub guardian_set_bump: u8,
175+
/// Padding to ensure bytemuck deserialization works
176+
_padding: [u8; 7],
177+
}
178+
179+
impl InitialiseFastMarketOrderData {
180+
/// Creates a new InitialiseFastMarketOrderData with padding
181+
pub fn new(fast_market_order: FastMarketOrder, guardian_set_bump: u8) -> Self {
182+
Self {
183+
fast_market_order,
184+
guardian_set_bump,
185+
_padding: [0_u8; 7],
186+
}
187+
}
188+
189+
/// Deserializes the InitialiseFastMarketOrderData from a byte slice
190+
///
191+
/// # Arguments
192+
///
193+
/// * `data` - A byte slice containing the InitialiseFastMarketOrderData
194+
///
195+
/// # Returns
196+
///
197+
/// Option<&Self> - The deserialized InitialiseFastMarketOrderData or None if the byte slice is not the correct length
198+
pub fn from_bytes(data: &[u8]) -> Option<&Self> {
199+
bytemuck::try_from_bytes::<Self>(data).ok()
200+
}
201+
}

0 commit comments

Comments
 (0)