Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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: 7 additions & 2 deletions crates/autopilot-svm/src/domain/auction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use {
crate::run_loop::AuctionInfo,
chain_types::solana::{IntentHash, Pubkey},
chain_types::solana::{AppData, IntentHash, Pubkey},
};

/// Whether the order sells an exact amount or buys an exact amount.
Expand Down Expand Up @@ -31,6 +31,7 @@ pub struct Order {
pub kind: OrderKind,
pub partially_fillable: bool,
pub order_pda: Pubkey,
pub app_data: AppData,
}

/// The cut auction the loop fans out to solvers.
Expand All @@ -56,7 +57,10 @@ impl AuctionInfo for Auction {

#[cfg(test)]
mod tests {
use super::{Auction, Order, OrderKind};
use {
super::{Auction, Order, OrderKind},
chain_types::solana::AppData,
};

fn order(sell_amount: u64) -> Order {
Order {
Expand All @@ -72,6 +76,7 @@ mod tests {
kind: OrderKind::Sell,
partially_fillable: false,
order_pda: chain_types::solana::Pubkey([7; 32]),
app_data: AppData([0; 32]),
}
}

Expand Down
7 changes: 5 additions & 2 deletions crates/autopilot-svm/src/infra/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use {
crate::domain::auction::{Auction, Order, OrderKind},
anyhow::{Context, Result},
bigdecimal::{BigDecimal, ToPrimitive},
chain_types::solana::{IntentHash, Pubkey},
chain_types::solana::{AppData, IntentHash, Pubkey},
database::byte_array::ByteArray,
sqlx::PgExecutor,
};
Expand All @@ -24,6 +24,7 @@ pub struct OrderRow {
pub kind: database::solana::OrderKind,
pub partially_fillable: bool,
pub order_pda: ByteArray<32>,
pub app_data: ByteArray<32>,
}

/// Orders open for solving: unexpired, settleable by a driver, not cancelled
Expand All @@ -35,7 +36,7 @@ pub async fn open_orders(ex: impl PgExecutor<'_>, now_unix: i64) -> Result<Vec<O
const QUERY: &str = r#"
SELECT o.uid, o.owner, o.sell_token, o.buy_token, o.sell_token_account,
o.buy_token_account, o.sell_amount, o.buy_amount, o.valid_to,
o.kind, o.partially_fillable, o.order_pda
o.kind, o.partially_fillable, o.order_pda, o.app_data
FROM solana.orders o
LEFT JOIN solana.order_pda p ON p.order_uid = o.uid
WHERE o.valid_to >= $1
Expand Down Expand Up @@ -145,6 +146,7 @@ impl TryFrom<OrderRow> for Order {
},
partially_fillable: row.partially_fillable,
order_pda: Pubkey(row.order_pda.0),
app_data: AppData(row.app_data.0),
})
}
}
Expand Down Expand Up @@ -179,6 +181,7 @@ mod tests {
kind: database::solana::OrderKind::Sell,
partially_fillable: false,
order_pda: ByteArray([7; 32]),
app_data: ByteArray([0; 32]),
}
}

Expand Down
10 changes: 9 additions & 1 deletion crates/autopilot-svm/src/infra/driver/dto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use {
crate::domain::auction,
chain_types::solana::{IntentHash, Pubkey, Signature},
chain_types::solana::{AppData, IntentHash, Pubkey, Signature},
serde::{Deserialize, Serialize},
serde_with::{DisplayFromStr, serde_as},
std::collections::HashMap,
Expand Down Expand Up @@ -51,6 +51,8 @@ pub struct Order {
pub partially_fillable: bool,
#[serde_as(as = "DisplayFromStr")]
pub order_pda: Pubkey,
#[serde_as(as = "DisplayFromStr")]
pub app_data: AppData,
}

/// Whether the order sells or buys an exact amount.
Expand Down Expand Up @@ -79,6 +81,7 @@ impl From<&auction::Order> for Order {
},
partially_fillable: order.partially_fillable,
order_pda: order.order_pda,
app_data: order.app_data,
}
}
}
Expand Down Expand Up @@ -157,6 +160,7 @@ mod tests {
kind: auction::OrderKind::Sell,
partially_fillable: false,
order_pda: Pubkey([0x77; 32]),
app_data: AppData([0; 32]),
}
}

Expand All @@ -179,6 +183,10 @@ mod tests {
// u64::MAX survives as a decimal string.
assert_eq!(json["orders"][0]["sellAmount"], "18446744073709551615");
assert_eq!(json["orders"][0]["kind"], "sell");
assert_eq!(
json["orders"][0]["appData"],
"0x0000000000000000000000000000000000000000000000000000000000000000"
);
// Base58 of 32 bytes of 0x22, precomputed so this does not just
// compare the Display impl against itself.
assert_eq!(
Expand Down
50 changes: 50 additions & 0 deletions crates/chain-types/src/solana.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ pub struct Pubkey(pub [u8; 32]);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct IntentHash(pub [u8; 32]);

/// Application-specific data attached to a Solana order: 32 opaque bytes.
/// Serialized as `0x`-prefixed hex on the wire, just like [`IntentHash`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct AppData(pub [u8; 32]);

/// `0x`-prefixed hex, the wire and log rendering of an order uid.
impl fmt::Display for IntentHash {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand All @@ -35,6 +40,24 @@ impl FromStr for IntentHash {
}
}

/// `0x`-prefixed hex, the wire rendering of order `app_data`.
impl fmt::Display for AppData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buffer = const_hex::Buffer::<32, true>::new();
f.write_str(buffer.format(&self.0))
}
}

impl FromStr for AppData {
type Err = const_hex::FromHexError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut bytes = [0u8; 32];
const_hex::decode_to_slice(s.strip_prefix("0x").unwrap_or(s), &mut bytes)?;
Ok(Self(bytes))
}
}

/// Base58, the canonical Solana address rendering.
impl fmt::Display for Pubkey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down Expand Up @@ -152,3 +175,30 @@ impl Amount for u64 {
.ok_or(MathError::Overflow)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn app_data_round_trips_as_0x_hex() {
let app_data = AppData([0xAB; 32]);
let encoded = app_data.to_string();
assert_eq!(
encoded,
"0xabababababababababababababababababababababababababababababababab"
);
assert_eq!(AppData::from_str(&encoded).unwrap(), app_data);
}

#[test]
fn intent_hash_round_trips_as_0x_hex() {
let hash = IntentHash([0xCD; 32]);
let encoded = hash.to_string();
assert_eq!(
encoded,
"0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
);
assert_eq!(IntentHash::from_str(&encoded).unwrap(), hash);
}
}
1 change: 1 addition & 0 deletions crates/solana-driver/src/domain/auction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ pub struct Order {
pub side: Side,
pub partially_fillable: bool,
pub order_pda: Pubkey,
pub app_data: [u8; 32],
}

/// Direction of the trade.
Expand Down
Loading
Loading