diff --git a/Cargo.lock b/Cargo.lock index 4e7c231..4a15b94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,7 +95,7 @@ dependencies = [ "flate2", "foldhash", "futures-core", - "h2", + "h2 0.3.26", "http 0.2.12", "httparse", "httpdate", @@ -409,7 +409,7 @@ dependencies = [ "anchor-syn", "anyhow", "bs58", - "heck", + "heck 0.3.3", "proc-macro2", "quote", "serde_json", @@ -482,7 +482,7 @@ checksum = "32e8599d21995f68e296265aa5ab0c3cef582fd58afec014d01bd0bce18a4418" dependencies = [ "anchor-lang-idl-spec", "anyhow", - "heck", + "heck 0.3.3", "serde", "serde_json", "sha2 0.10.8", @@ -506,7 +506,7 @@ checksum = "564685b759db12a2424d1b2688cfdf0fec26a023813bc461274754fb0e5d97b0" dependencies = [ "anyhow", "bs58", - "heck", + "heck 0.3.3", "proc-macro2", "quote", "serde", @@ -780,6 +780,28 @@ dependencies = [ "tokio", ] +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "async-trait" version = "0.1.88" @@ -791,6 +813,12 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "atty" version = "0.2.14" @@ -808,6 +836,62 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "autotools" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef941527c41b0fc0dd48511a8154cd5fc7e29200a0ff8b7203c5d777dbc795cf" +dependencies = [ + "cc", +] + +[[package]] +name = "axum" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper 1.0.2", + "tower 0.5.2", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 1.0.2", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.74" @@ -1230,6 +1314,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1493,7 +1587,7 @@ dependencies = [ "actix-web", "argh", "drift-rs", - "env_logger 0.9.3", + "env_logger 0.11.7", "futures-util", "log", "rust_decimal", @@ -1503,7 +1597,7 @@ dependencies = [ "solana-rpc-client-api", "solana-sdk", "solana-transaction-status", - "thiserror 1.0.69", + "thiserror 2.0.12", "tokio", "tokio-tungstenite", ] @@ -1511,7 +1605,7 @@ dependencies = [ [[package]] name = "drift-idl-gen" version = "0.2.0" -source = "git+https://github.com/drift-labs/drift-rs?rev=653fff5#653fff5a7e55705bccdbb1a0762da73c5348c1d3" +source = "git+https://github.com/drift-labs/drift-rs?rev=4da4966#4da4966b935df31ec5560783cf1c8365e00ef35b" dependencies = [ "proc-macro2", "quote", @@ -1524,7 +1618,7 @@ dependencies = [ [[package]] name = "drift-pubsub-client" version = "0.1.1" -source = "git+https://github.com/drift-labs/drift-rs?rev=653fff5#653fff5a7e55705bccdbb1a0762da73c5348c1d3" +source = "git+https://github.com/drift-labs/drift-rs?rev=4da4966#4da4966b935df31ec5560783cf1c8365e00ef35b" dependencies = [ "futures-util", "gjson", @@ -1543,8 +1637,8 @@ dependencies = [ [[package]] name = "drift-rs" -version = "1.0.0-alpha.14" -source = "git+https://github.com/drift-labs/drift-rs?rev=653fff5#653fff5a7e55705bccdbb1a0762da73c5348c1d3" +version = "1.0.0-alpha.15" +source = "git+https://github.com/drift-labs/drift-rs?rev=4da4966#4da4966b935df31ec5560783cf1c8365e00ef35b" dependencies = [ "abi_stable", "ahash 0.8.11", @@ -1558,6 +1652,7 @@ dependencies = [ "env_logger 0.11.7", "futures-util", "hex", + "jupiter-swap-api-client", "log", "regex", "serde", @@ -1567,10 +1662,13 @@ dependencies = [ "solana-rpc-client-api", "solana-sdk", "solana-transaction-status", + "spl-associated-token-account", "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-tungstenite", + "yellowstone-grpc-client", + "yellowstone-grpc-proto", ] [[package]] @@ -1740,6 +1838,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2551bf44bc5f776c15044b9b94153a00198be06743e262afaaa61f11ac7523a5" +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + [[package]] name = "flate2" version = "1.1.0" @@ -1962,7 +2066,26 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap", + "indexmap 2.8.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.3.1", + "indexmap 2.8.0", "slab", "tokio", "tokio-util", @@ -2017,6 +2140,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -2095,6 +2224,29 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.3.1", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "pin-project-lite", +] + [[package]] name = "httparse" version = "1.10.1" @@ -2123,9 +2275,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.26", "http 0.2.12", - "http-body", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -2137,6 +2289,27 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.9", + "http 1.3.1", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" version = "0.24.2" @@ -2145,10 +2318,75 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper", - "rustls", + "hyper 0.14.32", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +dependencies = [ + "futures-util", + "http 1.3.1", + "hyper 1.6.0", + "hyper-util", + "rustls 0.23.26", + "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.2", + "tower-service", +] + +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper 1.6.0", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.6.0", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.6.0", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", ] [[package]] @@ -2326,6 +2564,16 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.8.0" @@ -2452,6 +2700,23 @@ dependencies = [ "serde_json", ] +[[package]] +name = "jupiter-swap-api-client" +version = "0.1.0" +source = "git+https://github.com/drift-labs/jupiter-swap-api-client#b699edf30ff1f561460579ee2504622e28f9a797" +dependencies = [ + "anyhow", + "base64 0.22.1", + "reqwest 0.12.15", + "rust_decimal", + "serde", + "serde_json", + "serde_qs", + "solana-account-decoder", + "solana-sdk", + "thiserror 2.0.12", +] + [[package]] name = "keccak" version = "0.1.5" @@ -2582,6 +2847,12 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "memchr" version = "2.7.4" @@ -2655,6 +2926,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" + [[package]] name = "native-tls" version = "0.2.14" @@ -2667,7 +2944,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] @@ -2920,6 +3197,36 @@ dependencies = [ "num", ] +[[package]] +name = "petgraph" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +dependencies = [ + "fixedbitset", + "indexmap 2.8.0", +] + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -2980,6 +3287,16 @@ dependencies = [ "zerocopy 0.8.24", ] +[[package]] +name = "prettyplease" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" +dependencies = [ + "proc-macro2", + "syn 2.0.100", +] + [[package]] name = "proc-macro-crate" version = "0.1.5" @@ -3007,6 +3324,67 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +dependencies = [ + "heck 0.5.0", + "itertools 0.12.1", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.100", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools 0.12.1", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "prost-types" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +dependencies = [ + "prost", +] + +[[package]] +name = "protobuf-src" +version = "1.1.0+21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7ac8852baeb3cc6fb83b93646fb93c0ffe5d14bf138c945ceb4b9948ee0e3c1" +dependencies = [ + "autotools", +] + [[package]] name = "ptr_meta" version = "0.1.4" @@ -3222,46 +3600,90 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.27" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "async-compression", + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-rustls 0.24.2", + "ipnet", + "js-sys", + "log", + "mime", + "mime_guess", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration 0.5.1", + "tokio", + "tokio-rustls 0.24.1", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "reqwest" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" dependencies = [ - "async-compression", - "base64 0.21.7", + "base64 0.22.1", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2", - "http 0.2.12", - "http-body", - "hyper", - "hyper-rustls", + "h2 0.4.9", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.6.0", + "hyper-rustls 0.27.5", + "hyper-tls", + "hyper-util", "ipnet", "js-sys", "log", "mime", - "mime_guess", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", + "rustls-pemfile 2.2.0", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", - "system-configuration", + "sync_wrapper 1.0.2", + "system-configuration 0.6.1", "tokio", - "tokio-rustls", - "tokio-util", + "tokio-native-tls", + "tower 0.5.2", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", - "winreg", + "windows-registry", ] [[package]] @@ -3273,7 +3695,7 @@ dependencies = [ "anyhow", "async-trait", "http 0.2.12", - "reqwest", + "reqwest 0.11.27", "serde", "task-local-extensions", "thiserror 1.0.69", @@ -3380,10 +3802,37 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.103.1", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.2.0", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -3393,6 +3842,21 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -3403,6 +3867,17 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustls-webpki" +version = "0.103.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.20" @@ -3453,7 +3928,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.9.0", - "core-foundation", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.10.0", "core-foundation-sys", "libc", "security-framework-sys", @@ -3525,6 +4013,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_qs" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd34f36fe4c5ba9654417139a9b3a20d2e1de6012ee678ad14d240c22c78d8d6" +dependencies = [ + "percent-encoding", + "serde", + "thiserror 1.0.69", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -4795,7 +5294,7 @@ dependencies = [ "bs58", "indicatif", "log", - "reqwest", + "reqwest 0.11.27", "reqwest-middleware", "semver", "serde", @@ -4831,7 +5330,7 @@ dependencies = [ "base64 0.22.1", "bs58", "jsonrpc-core", - "reqwest", + "reqwest 0.11.27", "reqwest-middleware", "semver", "serde", @@ -5890,6 +6389,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + [[package]] name = "synstructure" version = "0.13.1" @@ -5908,8 +6416,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", + "core-foundation 0.9.4", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.9.4", + "system-configuration-sys 0.6.0", ] [[package]] @@ -5922,6 +6441,16 @@ dependencies = [ "libc", ] +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tap" version = "1.0.1" @@ -6100,7 +6629,17 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls 0.23.26", "tokio", ] @@ -6163,11 +6702,114 @@ version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap", + "indexmap 2.8.0", "toml_datetime", "winnow", ] +[[package]] +name = "tonic" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.22.1", + "bytes", + "flate2", + "h2 0.4.9", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.6.0", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "prost", + "rustls-native-certs", + "rustls-pemfile 2.2.0", + "socket2", + "tokio", + "tokio-rustls 0.26.2", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", + "zstd", +] + +[[package]] +name = "tonic-build" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build", + "prost-types", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "tonic-health" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eaf34ddb812120f5c601162d5429933c9b527d901ab0e7f930d3147e33a09b2" +dependencies = [ + "async-stream", + "prost", + "tokio", + "tokio-stream", + "tonic", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" version = "0.3.3" @@ -6554,6 +7196,35 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +[[package]] +name = "windows-registry" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.53.0", +] + +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -6605,13 +7276,29 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -6624,6 +7311,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -6636,6 +7329,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -6648,12 +7347,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -6666,6 +7377,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -6678,6 +7395,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -6690,6 +7413,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -6702,6 +7431,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.7.4" @@ -6751,6 +7486,38 @@ dependencies = [ "tap", ] +[[package]] +name = "yellowstone-grpc-client" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7504e16bd8edc6af4ba11be0b42fba24ffb42b383b1373c5d26dc644a327070a" +dependencies = [ + "bytes", + "futures", + "thiserror 1.0.69", + "tonic", + "tonic-health", + "yellowstone-grpc-proto", +] + +[[package]] +name = "yellowstone-grpc-proto" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a19211525073ab3811f57f30056633011f836fd61781a1f3b24ed4404a4c214" +dependencies = [ + "anyhow", + "bincode", + "prost", + "prost-types", + "protobuf-src", + "solana-account-decoder", + "solana-sdk", + "solana-transaction-status", + "tonic", + "tonic-build", +] + [[package]] name = "yoke" version = "0.7.5" diff --git a/Cargo.toml b/Cargo.toml index d36d1f2..c10c760 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] actix-web = "*" argh = "*" -drift-rs = { git = "https://github.com/drift-labs/drift-rs", rev = "653fff5" } +drift-rs = { git = "https://github.com/drift-labs/drift-rs", rev = "4da4966" } env_logger = "*" futures-util = "*" log = "*" diff --git a/README.md b/README.md index c9ba6a2..2cf8446 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Self hosted API gateway to easily interact with Drift V2 Protocol - [`POST` Place Orders](#place-orders) - [`PATCH` Modify Orders](#modify-orders) - [`DELETE` Cancel Orders](#cancel-orders) + - [`POST` Swap](#swap-orders) - [`PUT` Atomic Cancel/Modify/Place Orders](#atomic-cancelmodifyplace-orders) - [Websocket API](#websocket-api) - [Subscribing](#subscribing) @@ -105,6 +106,14 @@ drift-gateway --dev https://api.devnet.solana.com drift-gateway https://rpc-provider.example.com --markets sol-perp,sol,weth ``` +## gRPC mode +Run gateway subscriptions with geyser gRPC updates +```bash +export GRPC_HOST="grpc.example.com" +export GRPC_X_TOKEN="aabbccddeeff112233" +drift-gateway https://rpc-provider.example.com --grpc +``` + ## Usage ⚠️ Before starting, ensure a Drift _user_ account is initialized e.g. via the drift app at https://beta.drift.trade (devnet) or https://app.drift.trade @@ -116,10 +125,13 @@ These runtime environment variables are required: | Variable | Description | Example Value | |---------------------|-------------------------------------------|------------------------------| | `DRIFT_GATEWAY_KEY` | Path to your key file or seed in Base58. Transactions will be signed with this keypair | `` or `seedBase58` | +| `GRPC_HOST` | endpoint for gRPC subscription mode | `https://grpc.example.com` +| `GRPC_X_TOKEN` | authentication token for gRPC subscription mode | `aabbccddeeff112233` | `INIT_RPC_THROTTLE` | Adds a delay (seconds) between RPC bursts during gateway startup. Useful to avoid 429/rate-limit errors. Can be set to `0`, if RPC node is highspec | `1` | ```bash -Usage: drift-gateway [--dev] [--host ] [--port ] [--delegate ] [--emulate ] +./target/release/drift-gateway --help +Usage: drift-gateway [--markets ] [--dev] [--host ] [--port ] [--ws-port ] [--keep-alive-timeout ] [--delegate ] [--emulate ] [--tx-commitment ] [--commitment ] [--default-sub-account-id ] [--skip-tx-preflight] [--extra-rpcs ] [--verbose] [--grpc] Drift gateway server @@ -147,9 +159,10 @@ Options: default sub_account_id to use (default: 0) --skip-tx-preflight skip tx preflight checks - --extra-rpc extra solana RPC urls for improved Tx broadcast + --extra-rpcs extra solana RPC urls for improved Tx broadcast --verbose enable debug logging - --help display usage information + --grpc use gRPC mode for network subscriptions + --help, help display usage information ``` ### Delegated Signing Mode @@ -679,6 +692,62 @@ $ curl localhost:8080/v2/orders/cancelAndPlace -X POST -H 'content-type: applica }' ``` +### Swap Orders + +Executes a spot token swap using Jupiter routing and liquidity aggregation. +for more info see jup docs: https://dev.jup.ag/docs/api/swap-api/quote + +**Endpoint**: `POST /v2/swap` + +**Parameters**: + +Request body: +```json +{ + "inputMarket": number, // Input spot market index + "outputMarket": number, // Output spot market index + "exactIn": boolean, // true = exactIn, false, exactOut + "amount": string, // Amount of input token to sell when exactIn=true OR amount of output token to buy when exactIn=false + "slippage": number, // Max slippage in bps + "useDirectRoutes": bool, // Direct Routes limits Jupiter routing to single hop routes only + "excludeDexes": bool, // comma separated list of dexes to exclude +} +``` +dexes: https://lite-api.jup.ag/swap/v1/program-id-to-label + +**Response**: + +Success (200): +```json +{ + "signature": string, // Transaction signature + "success": boolean // Whether the swap was successful +} +``` + +Error (400/500): +```json +{ + "code": number, // Error code + "reason": string // Error description +} +``` + +**Example**: +USDC to +```bash +curl -X POST "http://localhost:8080/v2/swap" \ + -H "Content-Type: application/json" \ + -d '{ + "inputMarket": 0, + "outputMarket": 1, + "exactIn": true, + "amount": "500.0", + "slippage": 10 + }' +``` + + ## WebSocket API Websocket API is provided for live event streams by default at port `127.0.0.1:1337` diff --git a/src/controller.rs b/src/controller.rs index c751afa..881b01c 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -10,6 +10,7 @@ use drift_rs::{ constants::ProgramData, drift_idl::{self, types::MarginRequirementType}, event_subscriber::{try_parse_log, CommitmentConfig, RpcClient}, + jupiter::{JupiterSwapApi, SwapMode}, math::{ constants::{BASE_PRECISION, MARGIN_PRECISION}, leverage::get_leverage, @@ -26,7 +27,10 @@ use drift_rs::{ utils::get_http_url, DriftClient, Pubkey, TransactionBuilder, Wallet, }; -use futures_util::{stream::FuturesOrdered, stream::FuturesUnordered, StreamExt}; +use futures_util::{ + stream::{FuturesOrdered, FuturesUnordered}, + StreamExt, +}; use log::{debug, info, warn}; use rust_decimal::Decimal; use solana_account_decoder_client_types::UiAccountEncoding; @@ -40,11 +44,12 @@ use thiserror::Error; use crate::{ types::{ - get_market_decimals, AllMarketsResponse, CancelAndPlaceRequest, CancelOrdersRequest, - GetOrdersRequest, GetOrdersResponse, GetPositionsRequest, GetPositionsResponse, Market, - MarketInfoResponse, ModifyOrdersRequest, Order, PerpPosition, PerpPositionExtended, - PlaceOrdersRequest, SolBalanceResponse, SpotPosition, TxEventsResponse, TxResponse, - UserCollateralResponse, UserLeverageResponse, UserMarginResponse, PRICE_DECIMALS, + get_market_decimals, scale_decimal_to_u64, AllMarketsResponse, CancelAndPlaceRequest, + CancelOrdersRequest, GetOrdersRequest, GetOrdersResponse, GetPositionsRequest, + GetPositionsResponse, Market, MarketInfoResponse, ModifyOrdersRequest, Order, PerpPosition, + PerpPositionExtended, PlaceOrdersRequest, SolBalanceResponse, SpotPosition, SwapRequest, + TxEventsResponse, TxResponse, UserCollateralResponse, UserLeverageResponse, + UserMarginResponse, PRICE_DECIMALS, }, websocket::map_drift_event_for_account, Context, LOG_TARGET, @@ -52,8 +57,8 @@ use crate::{ /// Default TTL in seconds of gateway tx retry /// after which gateway will no longer resubmit or monitor the tx -// ~10 slots -const DEFAULT_TX_TTL: u16 = 4; +// ~15 slots +const DEFAULT_TX_TTL: u16 = 6; pub type GatewayResult = Result; @@ -253,7 +258,7 @@ impl AppState { .map(|s| MarketId::spot(s.market_index)) .chain(all_perp.iter().map(|p| MarketId::perp(p.market_index))) .chain(open_orders.iter().map(|o| { - if (o.market_type == MarketType::Spot) { + if o.market_type == MarketType::Spot { MarketId::spot(o.market_index) } else { MarketId::perp(o.market_index) @@ -612,6 +617,68 @@ impl AppState { self.send_tx(tx, "modify_orders", ctx.ttl).await } + pub async fn swap(&self, ctx: Context, req: SwapRequest) -> GatewayResult { + let sub_account = self.resolve_sub_account(ctx.sub_account_id); + + let in_market = self + .client + .program_data() + .spot_market_config_by_index(req.input_market) + .unwrap(); + let out_market = self + .client + .program_data() + .spot_market_config_by_index(req.output_market) + .unwrap(); + + let (swap_mode, amount) = if req.exact_in { + ( + SwapMode::ExactIn, + scale_decimal_to_u64(req.amount.abs(), 10_u32.pow(in_market.decimals)), + ) + } else { + ( + SwapMode::ExactOut, + scale_decimal_to_u64(req.amount.abs(), 10_u32.pow(out_market.decimals)), + ) + }; + + let (jupiter_swap_info, account_data) = tokio::try_join!( + self.client.jupiter_swap_query( + self.wallet.authority(), + amount, + swap_mode, + req.slippage_bps, + req.input_market, + req.output_market, + req.use_direct_routes, + req.exclude_dexes, + Default::default(), + ), + self.client.get_user_account(&sub_account) + )?; + let pf = self.get_priority_fee(); + + let tx = TransactionBuilder::new( + self.client.program_data(), + sub_account, + Cow::Owned(account_data), + self.wallet.is_delegated(), + ) + .jupiter_swap( + jupiter_swap_info, + in_market, + out_market, + &Wallet::derive_associated_token_address(self.wallet.authority(), in_market), + &Wallet::derive_associated_token_address(self.wallet.authority(), out_market), + None, + None, + ) + .with_priority_fee(ctx.cu_price.unwrap_or(pf), ctx.cu_limit) + .build(); + self.send_tx(tx, "swap", ctx.ttl).await + } + pub async fn get_tx_events_for_subaccount_id( &self, ctx: Context, @@ -715,7 +782,10 @@ impl AppState { Cow::Owned(account_data), self.wallet.is_delegated(), ) - .set_max_initial_margin_ratio(margin_ratio.mantissa().abs() as u32, sub_account_id) + .set_max_initial_margin_ratio( + margin_ratio.mantissa().unsigned_abs() as u32, + sub_account_id, + ) .build(); self.send_tx(tx, "set_margin_ratio", ctx.ttl).await } @@ -787,7 +857,7 @@ impl AppState { } } - tokio::time::sleep(Duration::from_millis(400)).await; + tokio::time::sleep(Duration::from_millis(800)).await; if let Ok(Some(Ok(()))) = primary_rpc.get_signature_status(&tx_signature).await { confirmed = true; diff --git a/src/main.rs b/src/main.rs index 179f5cb..8106176 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,11 +10,11 @@ use actix_web::{ use argh::FromArgs; use drift_rs::{ types::{CommitmentConfig, MarginRequirementType, MarketId}, - Pubkey, + GrpcSubscribeOpts, Pubkey, }; use log::{debug, info, warn}; use serde_json::json; -use types::SetLeverageRequest; +use types::{SetLeverageRequest, SwapRequest}; use crate::{ controller::{create_wallet, AppState, ControllerError}, @@ -225,6 +225,21 @@ async fn get_collateral( ) } +#[post("/swap")] +async fn swap( + controller: web::Data, + body: web::Bytes, + ctx: web::Query, +) -> impl Responder { + match serde_json::from_slice::<'_, SwapRequest>(body.as_ref()) { + Ok(req) => { + debug!(target: LOG_TARGET, "request: {req:?}"); + handle_result(controller.swap(ctx.0, req).await) + } + Err(err) => handle_deser_error(err), + } +} + #[actix_web::main] async fn main() -> std::io::Result<()> { let config: GatewayConfig = argh::from_env(); @@ -238,6 +253,7 @@ async fn main() -> std::io::Result<()> { .filter_module("wsaccsub", log::LevelFilter::Debug) .filter_module("marketmap", log::LevelFilter::Debug) .filter_module("oraclemap", log::LevelFilter::Debug) + .filter_module("grpc", log::LevelFilter::Info) } else { logger.filter_module(LOG_TARGET, log::LevelFilter::Info) } @@ -269,22 +285,35 @@ async fn main() -> std::io::Result<()> { ) .await; - // start market+oracle subs - let mut markets = Vec::::default(); - if let Some(ref user_markets) = config.markets { - markets.extend(parse_markets(&state.client, user_markets).expect("valid markets")); - }; - state - .subscribe_market_data(&markets) - .await - .expect("failed to subscribe to market data updates"); - info!(target: LOG_TARGET, "subscribed to market data updates 🛜"); - - state - .sync_market_subscriptions_on_user_changes(&markets) - .await - .expect("failed to setup market subscriptions sync on user changes"); - info!(target: LOG_TARGET, "subscribed to user account updates to sync market subscriptions 🛜"); + if config.grpc { + log::info!(target: LOG_TARGET, "gRPC mode enabled ⚡️"); + state + .client + .grpc_subscribe( + std::env::var("GRPC_ENDPOINT").expect("GRPC_ENDPOINT set"), + std::env::var("GRPC_X_TOKEN").expect("GRPC_X_TOKEN set"), + GrpcSubscribeOpts::default(), + ) + .await + .expect("gRPC subscribed"); + } else { + // start market+oracle subs + let mut markets = Vec::::default(); + if let Some(ref user_markets) = config.markets { + markets.extend(parse_markets(&state.client, user_markets).expect("valid markets")); + }; + state + .subscribe_market_data(&markets) + .await + .expect("failed to subscribe to market data updates"); + info!(target: LOG_TARGET, "subscribed to market data updates 🛜"); + + state + .sync_market_subscriptions_on_user_changes(&markets) + .await + .expect("failed to setup market subscriptions sync on user changes"); + info!(target: LOG_TARGET, "subscribed to user account updates to sync market subscriptions 🛜"); + } info!( target: LOG_TARGET, @@ -358,7 +387,8 @@ async fn main() -> std::io::Result<()> { .service(get_margin_info) .service(get_leverage) .service(set_leverage) - .service(get_collateral), + .service(get_collateral) + .service(swap), ) }) .keep_alive(Duration::from_secs(config.keep_alive_timeout as u64)) @@ -469,6 +499,9 @@ struct GatewayConfig { /// enable debug logging #[argh(switch)] verbose: bool, + /// use gRPC mode for network subscriptions + #[argh(switch)] + grpc: bool, } /// Parse raw markets list from user command diff --git a/src/types.rs b/src/types.rs index 1cd6f03..303eeff 100644 --- a/src/types.rs +++ b/src/types.rs @@ -164,6 +164,18 @@ impl From for PerpPosition { } } +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct SwapRequest { + pub amount: Decimal, + pub exact_in: bool, + pub input_market: u16, + pub output_market: u16, + pub slippage_bps: u16, + pub use_direct_routes: Option, + pub exclude_dexes: Option, +} + #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct PerpPositionExtended { @@ -294,7 +306,7 @@ where #[inline] /// Convert decimal to unsigned fixed-point representation with `target` precision -fn scale_decimal_to_u64(x: Decimal, target: u32) -> u64 { +pub fn scale_decimal_to_u64(x: Decimal, target: u32) -> u64 { ((x.mantissa().unsigned_abs() * target as u128) / 10_u128.pow(x.scale())) as u64 }