diff --git a/Cargo.lock b/Cargo.lock index 534fd9f..c8ee8fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1354,7 +1354,7 @@ dependencies = [ [[package]] name = "drift" version = "2.56.0" -source = "git+https://github.com/circuit-research/protocol-v2?branch=cargo-add-sdk#b09ba7fcad6a097e4ccd9b001289185bfdaef243" +source = "git+https://github.com/circuit-research/protocol-v2?branch=cargo-add-sdk#67b684fdc10e244119b072318cc94c0ac85438e5" dependencies = [ "anchor-lang", "anchor-spl", @@ -1407,7 +1407,7 @@ dependencies = [ [[package]] name = "drift-sdk" version = "0.1.0" -source = "git+https://github.com/circuit-research/protocol-v2?branch=cargo-add-sdk#b09ba7fcad6a097e4ccd9b001289185bfdaef243" +source = "git+https://github.com/circuit-research/protocol-v2?branch=cargo-add-sdk#67b684fdc10e244119b072318cc94c0ac85438e5" dependencies = [ "anchor-lang", "base64 0.13.1", @@ -1896,9 +1896,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" +checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" [[package]] name = "hex" @@ -2146,7 +2146,7 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" dependencies = [ - "hermit-abi 0.3.4", + "hermit-abi 0.3.5", "rustix", "windows-sys 0.52.0", ] @@ -2590,7 +2590,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.4", + "hermit-abi 0.3.5", "libc", ] @@ -4594,13 +4594,12 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", "rustix", "windows-sys 0.52.0", ] diff --git a/README.md b/README.md index c9ebf23..fcab50e 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,21 @@ Options: --dev run in devnet mode --host gateway host address --port gateway port - --delegate use delegated signing mode, provide the delegator pubkey + --ws-port gateway Ws port + --delegate use delegated signing mode, provide the delegators pubkey --emulate run the gateway in read-only mode for given authority pubkey - --help display usage information + --tx-commitment solana commitment level to use for transaction confirmation + (default: confirmed) + --commitment solana commitment level to use for state updates (default: + confirmed) + --verbose enable debug logging +``` + +## Logging +use env var to enable logging +```bash +# enable logging +RUST_LOG=gateway=debug drift-gateway .. ``` ## API Examples diff --git a/src/controller.rs b/src/controller.rs index 01f97e8..1281887 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -3,6 +3,7 @@ use std::{borrow::Cow, sync::Arc}; use drift_sdk::{ constants::{ProgramData, BASE_PRECISION}, dlob::DLOBClient, + event_subscriber::CommitmentConfig, types::{ Context, MarketId, MarketType, ModifyOrderParams, RpcSendTransactionConfig, SdkError, SdkResult, VersionedMessage, @@ -41,6 +42,8 @@ pub struct AppState { pub wallet: Wallet, pub client: Arc>, dlob_client: DLOBClient, + /// Solana tx commitment level for preflight confirmation + tx_commitment: CommitmentConfig, } impl AppState { @@ -55,14 +58,23 @@ impl AppState { pub fn default_sub_account(&self) -> Pubkey { self.wallet.default_sub_account() } - pub async fn new(endpoint: &str, devnet: bool, wallet: Wallet) -> Self { + pub async fn new( + endpoint: &str, + devnet: bool, + wallet: Wallet, + commitment: Option<(CommitmentConfig, CommitmentConfig)>, + ) -> Self { + let (state_commitment, tx_commitment) = + commitment.unwrap_or((CommitmentConfig::confirmed(), CommitmentConfig::confirmed())); let context = if devnet { Context::DevNet } else { Context::MainNet }; - let account_provider = WsAccountProvider::new(endpoint).await.expect("ws connects"); + let account_provider = WsAccountProvider::new_with_commitment(endpoint, state_commitment) + .await + .expect("ws connects"); let client = DriftClient::new(context, account_provider) .await .expect("ok"); @@ -77,6 +89,7 @@ impl AppState { wallet, client: Arc::new(client), dlob_client: DLOBClient::new(dlob_endpoint), + tx_commitment, } } @@ -317,6 +330,7 @@ impl AppState { tx, RpcSendTransactionConfig { max_retries: Some(0), + preflight_commitment: Some(self.tx_commitment.commitment), ..Default::default() }, ) diff --git a/src/main.rs b/src/main.rs index d3ddd6f..4ce4f48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ use argh::FromArgs; use log::{debug, info, warn}; use controller::{create_wallet, AppState, ControllerError}; -use drift_sdk::Pubkey; +use drift_sdk::{types::CommitmentConfig, Pubkey}; use serde_json::json; use std::{borrow::Borrow, str::FromStr, sync::Arc}; use types::{ @@ -153,7 +153,14 @@ async fn get_sol_balance(controller: web::Data) -> impl Responder { #[actix_web::main] async fn main() -> std::io::Result<()> { let config: GatewayConfig = argh::from_env(); - env_logger::Builder::from_default_env().init(); + let log_level = if config.verbose { + log::LevelFilter::Debug + } else { + log::LevelFilter::Info + }; + env_logger::Builder::from_default_env() + .filter_module(LOG_TARGET, log_level) + .init(); let secret_key = std::env::var("DRIFT_GATEWAY_KEY"); let delegate = config .delegate @@ -162,15 +169,28 @@ async fn main() -> std::io::Result<()> { .emulate .map(|ref x| Pubkey::from_str(x).expect("valid pubkey")); let wallet = create_wallet(secret_key.ok(), emulate, delegate); - let state = AppState::new(&config.rpc_host, config.dev, wallet).await; + let state_commitment = CommitmentConfig::from_str(&config.commitment) + .expect("one of: processed | confirmed | finalized"); + let tx_commitment = CommitmentConfig::from_str(&config.tx_commitment) + .expect("one of: processed | confirmed | finalized"); + + let state = AppState::new( + &config.rpc_host, + config.dev, + wallet, + Some((state_commitment, tx_commitment)), + ) + .await; info!( + target: LOG_TARGET, "🏛️ gateway listening at http://{}:{}", config.host, config.port ); if delegate.is_some() { info!( + target: LOG_TARGET, "🪪: authority: {:?}, default sub-account: {:?}, 🔑 delegate: {:?}", state.authority(), state.default_sub_account(), @@ -178,6 +198,7 @@ async fn main() -> std::io::Result<()> { ); } else { info!( + target: LOG_TARGET, "🪪: authority: {:?}, default sub-account: {:?}", state.authority(), state.default_sub_account() @@ -189,7 +210,7 @@ async fn main() -> std::io::Result<()> { let client = Box::leak(Box::new(Arc::clone(state.client.borrow()))); websocket::start_ws_server( - format!("{}:1337", &config.host).as_str(), + format!("{}:{}", &config.host, config.ws_port).as_str(), config.rpc_host.replace("http", "ws"), state.wallet.clone(), client.program_data(), @@ -198,7 +219,7 @@ async fn main() -> std::io::Result<()> { HttpServer::new(move || { App::new() - .wrap(Logger::new("%a | %s | %r | (%Dms)").log_target("gateway")) + .wrap(Logger::new("%a | %s | %r | (%Dms)").log_target(LOG_TARGET)) .app_data(web::Data::new(state.clone())) .service( web::scope("/v2") @@ -218,29 +239,6 @@ async fn main() -> std::io::Result<()> { .await } -#[derive(FromArgs)] -/// Drift gateway server -struct GatewayConfig { - /// the solana RPC URL - #[argh(positional)] - rpc_host: String, - /// run in devnet mode - #[argh(switch)] - dev: bool, - /// gateway host address - #[argh(option, default = "String::from(\"127.0.0.1\")")] - host: String, - /// gateway port - #[argh(option, default = "8080")] - port: u16, - /// use delegated signing mode, provide the delegator's pubkey - #[argh(option)] - delegate: Option, - /// run the gateway in read-only mode for given authority pubkey - #[argh(option)] - emulate: Option, -} - fn handle_result( result: Result, ) -> Either> { @@ -283,6 +281,41 @@ fn handle_deser_error(err: serde_json::Error) -> Either ))) } +#[derive(FromArgs)] +/// Drift gateway server +struct GatewayConfig { + /// the solana RPC URL + #[argh(positional)] + rpc_host: String, + /// run in devnet mode + #[argh(switch)] + dev: bool, + /// gateway host address + #[argh(option, default = "String::from(\"127.0.0.1\")")] + host: String, + /// gateway port + #[argh(option, default = "8080")] + port: u16, + /// gateway Ws port + #[argh(option, default = "1337")] + ws_port: u16, + /// use delegated signing mode, provide the delegator's pubkey + #[argh(option)] + delegate: Option, + /// run the gateway in read-only mode for given authority pubkey + #[argh(option)] + emulate: Option, + /// solana commitment level to use for transaction confirmation (default: confirmed) + #[argh(option, default = "String::from(\"confirmed\")")] + tx_commitment: String, + /// solana commitment level to use for state updates (default: confirmed) + #[argh(option, default = "String::from(\"confirmed\")")] + commitment: String, + #[argh(switch)] + /// enable debug logging + verbose: bool, +} + #[cfg(test)] mod tests { use actix_web::{http::Method, test, App}; @@ -303,7 +336,7 @@ mod tests { async fn setup_controller() -> AppState { let wallet = create_wallet(Some(get_seed()), None, None); - AppState::new(TEST_ENDPOINT, true, wallet).await + AppState::new(TEST_ENDPOINT, true, wallet, None).await } #[actix_web::test] diff --git a/src/websocket.rs b/src/websocket.rs index a2c826e..0a3e9e1 100644 --- a/src/websocket.rs +++ b/src/websocket.rs @@ -10,7 +10,7 @@ use drift_sdk::{ Pubkey, Wallet, }; use futures_util::{SinkExt, StreamExt}; -use log::{debug, info}; +use log::info; use rust_decimal::Decimal; use serde::{Deserialize, Serialize, Serializer}; use serde_json::json; @@ -20,7 +20,10 @@ use tokio::{ }; use tokio_tungstenite::{accept_async, tungstenite::Message}; -use crate::types::{get_market_decimals, Market, PRICE_DECIMALS}; +use crate::{ + types::{get_market_decimals, Market, PRICE_DECIMALS}, + LOG_TARGET, +}; /// Start the websocket server pub async fn start_ws_server( @@ -84,7 +87,7 @@ async fn accept_connection( // no double subs return; } - debug!("subscribing to events for: {}", request.sub_account_id); + info!(target: LOG_TARGET, "subscribing to events for: {}", request.sub_account_id); let sub_account_address = wallet.sub_account(request.sub_account_id as u16); @@ -125,7 +128,7 @@ async fn accept_connection( stream_handle = Some(join_handle); } Method::Unsubscribe => { - debug!("unsubscribing: {}", request.sub_account_id); + info!(target: LOG_TARGET, "unsubscribing: {}", request.sub_account_id); // TODO: support ending by channel, this ends all channels if let Some(task) = stream_handle.take() { task.abort();