Skip to content

Commit ac35d6d

Browse files
authored
feat: iso position order returns insuff collat error (#107)
1 parent 0c60947 commit ac35d6d

File tree

1 file changed

+159
-5
lines changed

1 file changed

+159
-5
lines changed

src/swift_server.rs

Lines changed: 159 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ pub async fn process_order(
239239
uuid,
240240
},
241241
max_margin_ratio,
242+
is_isolated_deposit,
242243
) = extract_signed_message_info(signed_msg, &taker_authority, current_slot)?;
243244

244245
log::info!(
@@ -301,6 +302,7 @@ pub async fn process_order(
301302
delegate_signer,
302303
current_slot,
303304
max_margin_ratio,
305+
is_isolated_deposit,
304306
context,
305307
)
306308
.await
@@ -443,7 +445,7 @@ pub async fn deposit_trade(
443445
&req.swift_order.taker_authority,
444446
current_slot,
445447
) {
446-
Ok((_info, max_margin_ratio)) => max_margin_ratio,
448+
Ok((_info, max_margin_ratio, _is_isolated)) => max_margin_ratio,
447449
Err((_status, err)) => return (StatusCode::BAD_REQUEST, Json(err)),
448450
};
449451

@@ -1058,6 +1060,7 @@ impl ServerParams {
10581060
delegate_signer: Option<&Pubkey>,
10591061
slot: Slot,
10601062
max_margin_ratio: Option<u16>,
1063+
is_isolated_deposit: bool,
10611064
context: &RequestContext,
10621065
) -> Result<SimulationStatus, (axum::http::StatusCode, String, Option<Vec<String>>)> {
10631066
let mut sim_result = SimulationStatus::Disabled;
@@ -1189,7 +1192,10 @@ impl ServerParams {
11891192
match err.to_anchor_error_code() {
11901193
Some(code) => {
11911194
// insufficient collateral is prone to precision errors, allow the order through with some leniency
1192-
if code == ProgramError::Drift(ErrorCode::InsufficientCollateral) {
1195+
// EXCEPT for isolated deposits, where we want to return the error to the client
1196+
if code == ProgramError::Drift(ErrorCode::InsufficientCollateral)
1197+
&& !is_isolated_deposit
1198+
{
11931199
if let Some(ref logs) = res.value.logs {
11941200
if let Some(collateral_ratio) = extract_collateral_ratio(logs) {
11951201
if collateral_ratio <= COLLATERAL_BUFFER {
@@ -1518,11 +1524,24 @@ fn validate_order(
15181524
Ok(())
15191525
}
15201526

1527+
fn is_isolated_deposit(signed_msg: &SignedOrderType) -> bool {
1528+
match signed_msg {
1529+
SignedOrderType::Delegated { inner, .. } => inner
1530+
.isolated_position_deposit
1531+
.is_some_and(|amount| amount > 0),
1532+
SignedOrderType::Authority { inner, .. } => inner
1533+
.isolated_position_deposit
1534+
.is_some_and(|amount| amount > 0),
1535+
}
1536+
}
1537+
15211538
fn extract_signed_message_info(
15221539
signed_msg: &SignedOrderType,
15231540
taker_authority: &Pubkey,
15241541
current_slot: Slot,
1525-
) -> Result<(SignedMessageInfo, Option<u16>), (axum::http::StatusCode, ProcessOrderResponse)> {
1542+
) -> Result<(SignedMessageInfo, Option<u16>, bool), (axum::http::StatusCode, ProcessOrderResponse)>
1543+
{
1544+
let is_isolated = is_isolated_deposit(signed_msg);
15261545
match signed_msg {
15271546
SignedOrderType::Delegated { inner, .. } => {
15281547
validate_order(
@@ -1539,6 +1558,7 @@ fn extract_signed_message_info(
15391558
slot: inner.slot,
15401559
},
15411560
inner.max_margin_ratio,
1561+
is_isolated,
15421562
))
15431563
}
15441564
SignedOrderType::Authority { inner, .. } => {
@@ -1559,6 +1579,7 @@ fn extract_signed_message_info(
15591579
slot: inner.slot,
15601580
},
15611581
inner.max_margin_ratio,
1582+
is_isolated,
15621583
))
15631584
}
15641585
}
@@ -1872,7 +1893,7 @@ mod tests {
18721893
});
18731894

18741895
let result = extract_signed_message_info(&delegated_msg, &taker_authority, current_slot);
1875-
assert!(result.is_ok_and(|(info, _)| {
1896+
assert!(result.is_ok_and(|(info, _, _)| {
18761897
info.slot == current_slot
18771898
&& info.order_params.base_asset_amount == LAMPORTS_PER_SOL
18781899
&& info.order_params.order_type == OrderType::Market
@@ -1940,7 +1961,7 @@ mod tests {
19401961
});
19411962

19421963
let result = extract_signed_message_info(&authority_msg, &taker_authority, current_slot);
1943-
assert!(result.is_ok_and(|(info, _margin_ratio)| {
1964+
assert!(result.is_ok_and(|(info, _margin_ratio, _is_isolated)| {
19441965
info.slot == current_slot
19451966
&& info.order_params.base_asset_amount == LAMPORTS_PER_SOL
19461967
&& info.order_params.order_type == OrderType::Market
@@ -2019,6 +2040,137 @@ mod tests {
20192040
)));
20202041
}
20212042

2043+
#[test]
2044+
fn test_is_isolated_deposit() {
2045+
let taker_authority = Pubkey::new_unique();
2046+
let current_slot = 1000;
2047+
2048+
// Test delegated order with no isolated deposit
2049+
let delegated_msg = SignedOrderType::delegated(SignedMsgOrderParamsDelegateMessage {
2050+
taker_pubkey: Pubkey::new_unique(),
2051+
signed_msg_order_params: OrderParams {
2052+
market_index: 0,
2053+
market_type: MarketType::Perp,
2054+
order_type: OrderType::Market,
2055+
base_asset_amount: LAMPORTS_PER_SOL,
2056+
price: 1000,
2057+
direction: PositionDirection::Long,
2058+
..Default::default()
2059+
},
2060+
uuid: [1; 8],
2061+
slot: current_slot,
2062+
stop_loss_order_params: None,
2063+
take_profit_order_params: None,
2064+
max_margin_ratio: None,
2065+
builder_fee_tenth_bps: None,
2066+
builder_idx: None,
2067+
isolated_position_deposit: None,
2068+
});
2069+
assert!(!is_isolated_deposit(&delegated_msg));
2070+
let result = extract_signed_message_info(&delegated_msg, &taker_authority, current_slot);
2071+
assert!(result.is_ok_and(|(_, _, is_isolated)| !is_isolated));
2072+
2073+
// Test delegated order with isolated deposit of 0 (should be false)
2074+
let delegated_msg = SignedOrderType::delegated(SignedMsgOrderParamsDelegateMessage {
2075+
taker_pubkey: Pubkey::new_unique(),
2076+
signed_msg_order_params: OrderParams {
2077+
market_index: 0,
2078+
market_type: MarketType::Perp,
2079+
order_type: OrderType::Market,
2080+
base_asset_amount: LAMPORTS_PER_SOL,
2081+
price: 1000,
2082+
direction: PositionDirection::Long,
2083+
..Default::default()
2084+
},
2085+
uuid: [1; 8],
2086+
slot: current_slot,
2087+
stop_loss_order_params: None,
2088+
take_profit_order_params: None,
2089+
max_margin_ratio: None,
2090+
builder_fee_tenth_bps: None,
2091+
builder_idx: None,
2092+
isolated_position_deposit: Some(0),
2093+
});
2094+
assert!(!is_isolated_deposit(&delegated_msg));
2095+
let result = extract_signed_message_info(&delegated_msg, &taker_authority, current_slot);
2096+
assert!(result.is_ok_and(|(_, _, is_isolated)| !is_isolated));
2097+
2098+
// Test delegated order with isolated deposit > 0
2099+
let delegated_msg = SignedOrderType::delegated(SignedMsgOrderParamsDelegateMessage {
2100+
taker_pubkey: Pubkey::new_unique(),
2101+
signed_msg_order_params: OrderParams {
2102+
market_index: 0,
2103+
market_type: MarketType::Perp,
2104+
order_type: OrderType::Market,
2105+
base_asset_amount: LAMPORTS_PER_SOL,
2106+
price: 1000,
2107+
direction: PositionDirection::Long,
2108+
..Default::default()
2109+
},
2110+
uuid: [1; 8],
2111+
slot: current_slot,
2112+
stop_loss_order_params: None,
2113+
take_profit_order_params: None,
2114+
max_margin_ratio: None,
2115+
builder_fee_tenth_bps: None,
2116+
builder_idx: None,
2117+
isolated_position_deposit: Some(100_000_000), // 0.1 SOL
2118+
});
2119+
assert!(is_isolated_deposit(&delegated_msg));
2120+
let result = extract_signed_message_info(&delegated_msg, &taker_authority, current_slot);
2121+
assert!(result.is_ok_and(|(_, _, is_isolated)| is_isolated));
2122+
2123+
// Test authority order with no isolated deposit
2124+
let authority_msg = SignedOrderType::authority(SignedMsgOrderParamsMessage {
2125+
sub_account_id: 0,
2126+
signed_msg_order_params: OrderParams {
2127+
market_index: 0,
2128+
market_type: MarketType::Perp,
2129+
order_type: OrderType::Market,
2130+
base_asset_amount: LAMPORTS_PER_SOL,
2131+
price: 1000,
2132+
direction: PositionDirection::Long,
2133+
..Default::default()
2134+
},
2135+
uuid: [1; 8],
2136+
slot: current_slot,
2137+
stop_loss_order_params: None,
2138+
take_profit_order_params: None,
2139+
max_margin_ratio: None,
2140+
builder_fee_tenth_bps: None,
2141+
builder_idx: None,
2142+
isolated_position_deposit: None,
2143+
});
2144+
assert!(!is_isolated_deposit(&authority_msg));
2145+
let result = extract_signed_message_info(&authority_msg, &taker_authority, current_slot);
2146+
assert!(result.is_ok_and(|(_, _, is_isolated)| !is_isolated));
2147+
2148+
// Test authority order with isolated deposit > 0
2149+
let authority_msg = SignedOrderType::authority(SignedMsgOrderParamsMessage {
2150+
sub_account_id: 0,
2151+
signed_msg_order_params: OrderParams {
2152+
market_index: 0,
2153+
market_type: MarketType::Perp,
2154+
order_type: OrderType::Market,
2155+
base_asset_amount: LAMPORTS_PER_SOL,
2156+
price: 1000,
2157+
direction: PositionDirection::Long,
2158+
..Default::default()
2159+
},
2160+
uuid: [1; 8],
2161+
slot: current_slot,
2162+
stop_loss_order_params: None,
2163+
take_profit_order_params: None,
2164+
max_margin_ratio: None,
2165+
builder_fee_tenth_bps: None,
2166+
builder_idx: None,
2167+
isolated_position_deposit: Some(50_000_000), // 0.05 SOL
2168+
});
2169+
assert!(is_isolated_deposit(&authority_msg));
2170+
let result = extract_signed_message_info(&authority_msg, &taker_authority, current_slot);
2171+
assert!(result.is_ok_and(|(_, _, is_isolated)| is_isolated));
2172+
}
2173+
20222174
#[tokio::test]
20232175
async fn test_simulate_taker_order_rpc() {
20242176
let _ = env_logger::try_init();
@@ -2096,6 +2248,7 @@ mod tests {
20962248
Some(&delegate_pubkey),
20972249
1_000,
20982250
None,
2251+
false,
20992252
&context_primary,
21002253
)
21012254
.await;
@@ -2121,6 +2274,7 @@ mod tests {
21212274
Some(&delegate_pubkey),
21222275
1_000,
21232276
None,
2277+
false,
21242278
&context_secondary,
21252279
)
21262280
.await;

0 commit comments

Comments
 (0)