diff --git a/Cargo.lock b/Cargo.lock index 53c24f0..f6a283c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -164,6 +164,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + [[package]] name = "arrayvec" version = "0.7.4" @@ -297,7 +303,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "tracing", - "uuid 1.5.0", + "uuid 1.10.0", ] [[package]] @@ -479,11 +485,11 @@ dependencies = [ "http-body 0.4.5", "http-body 1.0.0", "hyper 0.14.27", - "hyper-rustls", + "hyper-rustls 0.24.2", "once_cell", "pin-project-lite", "pin-utils", - "rustls", + "rustls 0.21.9", "tokio", "tracing", ] @@ -570,6 +576,20 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base-api-types" +version = "0.1.0" +dependencies = [ + "ethers", + "hex", + "hex-literal", + "poem", + "poem-openapi", + "serde", + "serde_json", + "test-case", +] + [[package]] name = "base16ct" version = "0.2.0" @@ -832,8 +852,9 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits", + "serde", "wasm-bindgen", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1238,6 +1259,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" dependencies = [ "powerfmt", + "serde", ] [[package]] @@ -1575,7 +1597,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "reqwest", + "reqwest 0.11.24", "serde", "serde_json", "syn 2.0.39", @@ -1637,7 +1659,7 @@ checksum = "abbac2c890bdbe0f1b8e549a53b00e2c4c1de86bb077c1094d1f38cdf9381a56" dependencies = [ "chrono", "ethers-core", - "reqwest", + "reqwest 0.11.24", "semver", "serde", "serde_json", @@ -1662,7 +1684,7 @@ dependencies = [ "futures-locks", "futures-util", "instant", - "reqwest", + "reqwest 0.11.24", "serde", "serde_json", "thiserror", @@ -1695,7 +1717,7 @@ dependencies = [ "jsonwebtoken", "once_cell", "pin-project", - "reqwest", + "reqwest 0.11.24", "serde", "serde_json", "thiserror", @@ -1861,9 +1883,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -2392,6 +2414,7 @@ dependencies = [ "pin-project-lite", "smallvec", "tokio", + "want", ] [[package]] @@ -2404,10 +2427,27 @@ dependencies = [ "http 0.2.11", "hyper 0.14.27", "log", - "rustls", + "rustls 0.21.9", "rustls-native-certs", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.3.1", + "hyper-util", + "rustls 0.23.12", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.0", + "tower-service", ] [[package]] @@ -2423,6 +2463,22 @@ dependencies = [ "tokio-native-tls", ] +[[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.3.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.5" @@ -2430,12 +2486,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" dependencies = [ "bytes", + "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.0", "hyper 1.3.1", "pin-project-lite", + "socket2 0.5.5", "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -2469,9 +2530,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -2529,6 +2590,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] @@ -2539,6 +2601,7 @@ checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown 0.14.2", + "serde", ] [[package]] @@ -2832,7 +2895,7 @@ checksum = "83a4c4718a371ddfb7806378f23617876eea8b82e5ff1324516bcd283249d9ea" dependencies = [ "base64 0.21.5", "hyper 0.14.27", - "hyper-tls", + "hyper-tls 0.5.0", "indexmap 1.9.3", "ipnet", "metrics", @@ -2875,6 +2938,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -3003,6 +3076,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.45" @@ -3186,7 +3265,7 @@ dependencies = [ "opentelemetry-http", "opentelemetry-semantic-conventions", "opentelemetry_sdk", - "reqwest", + "reqwest 0.11.24", "rmp", "thiserror", "url", @@ -3202,7 +3281,7 @@ dependencies = [ "bytes", "http 0.2.11", "opentelemetry", - "reqwest", + "reqwest 0.11.24", ] [[package]] @@ -3325,7 +3404,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -3399,9 +3478,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" @@ -4020,8 +4099,8 @@ dependencies = [ "http 0.2.11", "http-body 0.4.5", "hyper 0.14.27", - "hyper-rustls", - "hyper-tls", + "hyper-rustls 0.24.2", + "hyper-tls 0.5.0", "ipnet", "js-sys", "log", @@ -4030,16 +4109,16 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", + "rustls 0.21.9", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 0.1.2", - "system-configuration", + "system-configuration 0.5.1", "tokio", "tokio-native-tls", - "tokio-rustls", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", @@ -4049,6 +4128,65 @@ dependencies = [ "winreg", ] +[[package]] +name = "reqwest" +version = "0.12.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.5", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.3.1", + "hyper-rustls 0.27.3", + "hyper-tls 0.6.0", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "mime_guess", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 2.1.3", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "system-configuration 0.6.1", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + +[[package]] +name = "reqwest-middleware" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562ceb5a604d3f7c885a792d42c199fd8af239d0a51b2fa6a78aafa092452b04" +dependencies = [ + "anyhow", + "async-trait", + "http 1.1.0", + "reqwest 0.12.7", + "serde", + "thiserror", + "tower-service", +] + [[package]] name = "rfc6979" version = "0.4.0" @@ -4222,10 +4360,23 @@ checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" dependencies = [ "log", "ring 0.17.5", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.102.7", + "subtle", + "zeroize", +] + [[package]] name = "rustls-native-certs" version = "0.6.3" @@ -4233,7 +4384,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "schannel", "security-framework", ] @@ -4247,6 +4398,22 @@ dependencies = [ "base64 0.21.5", ] +[[package]] +name = "rustls-pemfile" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -4257,6 +4424,17 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustls-webpki" +version = "0.102.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" +dependencies = [ + "ring 0.17.5", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -4437,6 +4615,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "serde_spanned" version = "0.6.4" @@ -4458,6 +4647,36 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.1.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "serde_yaml" version = "0.9.29" @@ -4683,8 +4902,8 @@ dependencies = [ "once_cell", "paste", "percent-encoding", - "rustls", - "rustls-pemfile", + "rustls 0.21.9", + "rustls-pemfile 1.0.4", "serde", "serde_json", "sha2", @@ -4930,7 +5149,7 @@ dependencies = [ "fs2", "hex", "once_cell", - "reqwest", + "reqwest 0.11.24", "semver", "serde", "serde_json", @@ -4985,7 +5204,18 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", "core-foundation", - "system-configuration-sys", + "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.4.1", + "core-foundation", + "system-configuration-sys 0.6.0", ] [[package]] @@ -4998,6 +5228,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" @@ -5019,7 +5259,7 @@ dependencies = [ "opentelemetry-datadog", "opentelemetry-http", "opentelemetry_sdk", - "reqwest", + "reqwest 0.11.24", "serde", "serde_json", "thiserror", @@ -5122,12 +5362,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.30" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", + "num-conv", "powerfmt", "serde", "time-core", @@ -5142,10 +5383,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] @@ -5219,7 +5461,18 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.9", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls 0.23.12", + "rustls-pki-types", "tokio", ] @@ -5242,9 +5495,9 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls", + "rustls 0.21.9", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tungstenite", "webpki-roots 0.25.2", ] @@ -5328,6 +5581,27 @@ dependencies = [ "winnow", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "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.2" @@ -5478,7 +5752,7 @@ dependencies = [ "httparse", "log", "rand", - "rustls", + "rustls 0.21.9", "sha1", "thiserror", "url", @@ -5496,6 +5770,7 @@ dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", + "base-api-types", "base64 0.21.5", "bigdecimal 0.4.2", "chrono", @@ -5521,7 +5796,7 @@ dependencies = [ "postgres-docker-utils", "rand", "regex", - "reqwest", + "reqwest 0.11.24", "serde", "serde_json", "sha3", @@ -5536,11 +5811,27 @@ dependencies = [ "tracing", "tracing-error", "tracing-subscriber", + "tx-sitter-client", "url", "uuid 0.8.2", "version", ] +[[package]] +name = "tx-sitter-client" +version = "0.1.0" +dependencies = [ + "base-api-types", + "reqwest 0.12.7", + "reqwest-middleware", + "serde", + "serde_json", + "serde_repr", + "serde_with", + "url", + "uuid 1.10.0", +] + [[package]] name = "typenum" version = "1.17.0" @@ -5580,6 +5871,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -5649,9 +5949,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.1" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -5688,9 +5988,13 @@ dependencies = [ [[package]] name = "uuid" -version = "1.5.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +dependencies = [ + "getrandom", + "serde", +] [[package]] name = "valuable" @@ -5839,7 +6143,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" dependencies = [ - "rustls-webpki", + "rustls-webpki 0.101.7", ] [[package]] @@ -5897,7 +6201,37 @@ version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", ] [[package]] @@ -5906,7 +6240,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -5915,13 +6249,29 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "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]] @@ -5930,42 +6280,90 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[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_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "winnow" version = "0.5.19" diff --git a/Cargo.toml b/Cargo.toml index 94d4f81..1e44094 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,8 @@ aws-types = "1.2.1" # Internal postgres-docker-utils = { path = "crates/postgres-docker-utils" } +base-api-types = { path = "crates/base-api-types" } +tx-sitter-client = { path = "crates/tx-sitter-client" } # Company telemetry-batteries = { git = "https://github.com/worldcoin/telemetry-batteries", rev = "e0891328b29d9f85df037633feccca2f74a291a6" } diff --git a/README.md b/README.md index 494031d..7d3a328 100644 --- a/README.md +++ b/README.md @@ -62,3 +62,26 @@ Therefore I recommend [cargo-nextest](https://nexte.st/) as it runs all the test cargo nextest run --workspace ``` can be used instead. + +## Client + +Client crate is located in `creates/tx-sitter-client`. It is generated using official OpenAPI generator with modified template files. Modified template files are located in `client-template/` directory. Possible files to overwrite could be fined here https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator/src/main/resources/rust. + +To generate client OpenAPI spec schema is required. To get one just run tx-sitter and then call `/schema.yaml` endpoint. To download schema you can use curl for example: + +```shell +curl http://localhost:3000/schema.yml > schema.yaml +``` + +Client generation is done by using default OpenAPI tools. You can install generator or use docker image as shown below: + +```shell +docker run --rm -v "${PWD}:/local" --user "$(id -u):$(id -g)" -- openapitools/openapi-generator-cli generate \ + -i /local/schema.yaml \ + -g rust \ + -o /local/crates/tx-sitter-client \ + -t /local/client-template \ + --skip-validate-spec \ + --additional-properties=packageName=tx-sitter-client,supportMiddleware=true,useSingleRequestParameter=true,avoidBoxedModels=true \ + --type-mappings=address=base_api_types::Address,decimal-u256=base_api_types::DecimalU256,h256=base_api_types::H256,bytes=base_api_types::HexBytes,hex-u256=base_api_types::HexU256 +``` \ No newline at end of file diff --git a/client-template/Cargo.mustache b/client-template/Cargo.mustache new file mode 100644 index 0000000..84590be --- /dev/null +++ b/client-template/Cargo.mustache @@ -0,0 +1,76 @@ +[package] +name = "{{{packageName}}}" +version = "{{#lambdaVersion}}{{{packageVersion}}}{{/lambdaVersion}}" +{{#infoEmail}} +authors = ["{{{.}}}"] +{{/infoEmail}} +{{^infoEmail}} +authors = ["OpenAPI Generator team and contributors"] +{{/infoEmail}} +{{#appDescription}} +description = "{{{.}}}" +{{/appDescription}} +{{#licenseInfo}} +license = "{{.}}" +{{/licenseInfo}} +{{^licenseInfo}} +# Override this license by providing a License Object in the OpenAPI. +license = "Unlicense" +{{/licenseInfo}} +edition = "2021" +{{#publishRustRegistry}} +publish = ["{{.}}"] +{{/publishRustRegistry}} +{{#repositoryUrl}} +repository = "{{.}}" +{{/repositoryUrl}} +{{#documentationUrl}} +documentation = "{{.}}" +{{/documentationUrl}} +{{#homePageUrl}} +homepage = "{{.}} +{{/homePageUrl}} + +[dependencies] +serde = { version = "^1.0", features = ["derive"] } +base-api-types = { path = "../base-api-types" } +{{#serdeWith}} +serde_with = { version = "^3.8", default-features = false, features = ["base64", "std", "macros"] } +{{/serdeWith}} +serde_json = "^1.0" +serde_repr = "^0.1" +url = "^2.5" +uuid = { version = "^1.8", features = ["serde", "v4"] } +{{#hyper}} +{{#hyper0x}} +hyper = { version = "~0.14", features = ["full"] } +hyper-tls = "~0.5" +{{/hyper0x}} +{{^hyper0x}} +hyper = { version = "^1.3.1", features = ["full"] } +hyper-util = { version = "0.1.5", features = ["client", "client-legacy", "http1", "http2"] } +http-body-util = { version = "0.1.2" } +{{/hyper0x}} +http = "~0.2" +base64 = "~0.7.0" +futures = "^0.3" +{{/hyper}} +{{#withAWSV4Signature}} +aws-sigv4 = "0.3.0" +http = "0.2.5" +secrecy = "0.8.0" +{{/withAWSV4Signature}} +{{#reqwest}} +{{^supportAsync}} +reqwest = { version = "^0.12", features = ["json", "blocking", "multipart"] } +{{#supportMiddleware}} +reqwest-middleware = { version = "^0.3", features = ["json", "blocking", "multipart"] } +{{/supportMiddleware}} +{{/supportAsync}} +{{#supportAsync}} +reqwest = { version = "^0.12", features = ["json", "multipart"] } +{{#supportMiddleware}} +reqwest-middleware = { version = "^0.3", features = ["json", "multipart"] } +{{/supportMiddleware}} +{{/supportAsync}} +{{/reqwest}} \ No newline at end of file diff --git a/client-template/README.mustache b/client-template/README.mustache new file mode 100644 index 0000000..ef0edf0 --- /dev/null +++ b/client-template/README.mustache @@ -0,0 +1,57 @@ +# Rust API client for {{{packageName}}} + +> [!CAUTION] +> This whole client is generated. Please read README in top directory of repo. + +{{#appDescriptionWithNewLines}} +{{{.}}} +{{/appDescriptionWithNewLines}} + +{{#infoUrl}} +For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}) +{{/infoUrl}} + +## Overview + +This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [openapi-spec](https://openapis.org) from a remote server, you can easily generate an API client. + +- API version: {{{appVersion}}} +- Package version: {{{packageVersion}}} +{{^hideGenerationTimestamp}} +- Build date: {{{generatedDate}}} +{{/hideGenerationTimestamp}} +- Generator version: {{generatorVersion}} +- Build package: `{{{generatorClass}}}` + +## Installation + +Put the package under your project folder in a directory named `{{packageName}}` and add the following to `Cargo.toml` under `[dependencies]`: + +``` +{{{packageName}}} = { path = "./{{{packageName}}}" } +``` + +## Documentation for API Endpoints + +All URIs are relative to *{{{basePath}}}* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{{classname}}}* | [**{{{operationId}}}**]({{{apiDocPath}}}{{classname}}.md#{{{operationIdLowerCase}}}) | **{{{httpMethod}}}** {{{path}}} | {{{summary}}} +{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} + +## Documentation For Models + +{{#models}}{{#model}} - [{{{classname}}}]({{{modelDocPath}}}{{{classname}}}.md) +{{/model}}{{/models}} + +To get access to the crate's generated documentation, use: + +``` +cargo doc --open +``` + +## Author + +{{#apiInfo}}{{#apis}}{{#-last}}{{{infoEmail}}} +{{/-last}}{{/apis}}{{/apiInfo}} \ No newline at end of file diff --git a/client-template/reqwest/configuration.mustache b/client-template/reqwest/configuration.mustache new file mode 100644 index 0000000..24e8f12 --- /dev/null +++ b/client-template/reqwest/configuration.mustache @@ -0,0 +1,141 @@ +{{>partial_header}} + +{{#withAWSV4Signature}} +use std::time::SystemTime; +use aws_sigv4::http_request::{sign, SigningSettings, SigningParams, SignableRequest}; +use http; +use secrecy::{SecretString, ExposeSecret}; +{{/withAWSV4Signature}} + +#[derive(Debug, Clone)] +pub struct Configuration { + pub base_path: String, + pub user_agent: Option, + pub client: {{#supportMiddleware}}reqwest_middleware::ClientWithMiddleware{{/supportMiddleware}}{{^supportMiddleware}}reqwest{{^supportAsync}}::blocking{{/supportAsync}}::Client{{/supportMiddleware}}, + pub basic_auth: Option, + pub oauth_access_token: Option, + pub bearer_access_token: Option, + pub api_key: Option, + {{#withAWSV4Signature}} + pub aws_v4_key: Option, + {{/withAWSV4Signature}} + // TODO: take an oauth2 token source, similar to the go one +} + +pub type BasicAuth = (String, Option); + +#[derive(Debug, Clone)] +pub struct ApiKey { + pub prefix: Option, + pub key: String, +} + +{{#withAWSV4Signature}} +#[derive(Debug, Clone)] +pub struct AWSv4Key { + pub access_key: String, + pub secret_key: SecretString, + pub region: String, + pub service: String, +} + +impl AWSv4Key { + pub fn sign(&self, uri: &str, method: &str, body: &str) -> Result, aws_sigv4::http_request::Error> { + let request = http::Request::builder() + .uri(uri) + .method(method) + .body(body).unwrap(); + let signing_settings = SigningSettings::default(); + let signing_params = SigningParams::builder() + .access_key(self.access_key.as_str()) + .secret_key(self.secret_key.expose_secret().as_str()) + .region(self.region.as_str()) + .service_name(self.service.as_str()) + .time(SystemTime::now()) + .settings(signing_settings) + .build() + .unwrap(); + let signable_request = SignableRequest::from(&request); + let (mut signing_instructions, _signature) = sign(signable_request, &signing_params)?.into_parts(); + let mut additional_headers = Vec::<(String, String)>::new(); + if let Some(new_headers) = signing_instructions.take_headers() { + for (name, value) in new_headers.into_iter() { + additional_headers.push((name.expect("header should have name").to_string(), + value.to_str().expect("header value should be a string").to_string())); + } + } + Ok(additional_headers) + } +} +{{/withAWSV4Signature}} + +impl Default for Configuration { + fn default() -> Self { + Configuration { + base_path: "{{{basePath}}}".to_owned(), + user_agent: {{#httpUserAgent}}Some("{{{.}}}".to_owned()){{/httpUserAgent}}{{^httpUserAgent}}Some("OpenAPI-Generator/{{{version}}}/rust".to_owned()){{/httpUserAgent}}, + client: {{#supportMiddleware}}reqwest_middleware::ClientBuilder::new(reqwest{{^supportAsync}}::blocking{{/supportAsync}}::Client::new()).build(){{/supportMiddleware}}{{^supportMiddleware}}reqwest{{^supportAsync}}::blocking{{/supportAsync}}::Client::new(){{/supportMiddleware}}, + basic_auth: None, + oauth_access_token: None, + bearer_access_token: None, + api_key: None, +{{#withAWSV4Signature}} aws_v4_key: None,{{/withAWSV4Signature}} + } + } +} + +pub struct ConfigurationBuilder { + pub base_path: Option, + pub user_agent: Option, + pub basic_auth: Option, +} + +impl ConfigurationBuilder { + pub fn new() -> ConfigurationBuilder { + ConfigurationBuilder { + base_path: None, + user_agent: None, + basic_auth: None, + } + } + + pub fn base_path(mut self, base_path: String) -> Self { + self.base_path = Some(base_path); + self + } + + pub fn user_agent(mut self, user_agent: String) -> Self { + self.user_agent = Some(user_agent); + self + } + + pub fn basic_auth(mut self, user: String, pass: Option) -> Self { + self.basic_auth = Some((user, pass)); + self + } + + pub fn build(self) -> Configuration { + let mut conf: Configuration = Default::default(); + + if let Some(base_path) = self.base_path { + conf.base_path = base_path; + } + + if let Some(user_agent) = self.user_agent { + conf.user_agent = Some(user_agent); + } + + if let Some(basic_auth) = self.basic_auth { + conf.basic_auth = Some(basic_auth); + } + + conf + } +} + +impl Default for ConfigurationBuilder { + fn default() -> Self { + Self::new() + } +} + diff --git a/crates/base-api-types/Cargo.toml b/crates/base-api-types/Cargo.toml new file mode 100644 index 0000000..ed50c4c --- /dev/null +++ b/crates/base-api-types/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "base-api-types" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ethers = { version = "2.0.11" } +poem = { version = "3", features = ["eyre06"] } +poem-openapi = { version = "5", features = [ + "openapi-explorer", + "rapidoc", + "redoc", + "swagger-ui", +] } +serde = "1.0.136" +serde_json = "1.0.91" + +[dev-dependencies] +hex = "0.4.3" +hex-literal = "0.4.1" +test-case = "3.1.0" diff --git a/src/types/wrappers/address.rs b/crates/base-api-types/src/address.rs similarity index 62% rename from src/types/wrappers/address.rs rename to crates/base-api-types/src/address.rs index a0eccd5..5f52305 100644 --- a/src/types/wrappers/address.rs +++ b/crates/base-api-types/src/address.rs @@ -1,55 +1,23 @@ -use ethers::types::Address; use poem_openapi::registry::{MetaSchema, MetaSchemaRef}; use poem_openapi::types::{ParseError, ParseFromJSON, ToJSON}; use serde::{Deserialize, Serialize}; -use sqlx::database::HasValueRef; -use sqlx::Database; #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(transparent)] -pub struct AddressWrapper(pub Address); +pub struct Address(pub ethers::types::Address); -impl<'r, DB> sqlx::Decode<'r, DB> for AddressWrapper -where - DB: Database, - Vec: sqlx::Decode<'r, DB>, -{ - fn decode( - value: >::ValueRef, - ) -> Result { - let bytes = as sqlx::Decode>::decode(value)?; - - let address = Address::from_slice(&bytes); - - Ok(Self(address)) - } -} - -impl sqlx::Type for AddressWrapper -where - Vec: sqlx::Type, -{ - fn type_info() -> DB::TypeInfo { - as sqlx::Type>::type_info() - } - - fn compatible(ty: &DB::TypeInfo) -> bool { - *ty == Self::type_info() - } -} - -impl From
for AddressWrapper { - fn from(value: Address) -> Self { +impl From for Address { + fn from(value: ethers::types::Address) -> Self { Self(value) } } -impl poem_openapi::types::Type for AddressWrapper { +impl poem_openapi::types::Type for Address { const IS_REQUIRED: bool = true; - type RawValueType = Address; + type RawValueType = ethers::types::Address; - type RawElementValueType = Address; + type RawElementValueType = ethers::types::Address; fn name() -> std::borrow::Cow<'static, str> { "string(address)".into() @@ -78,7 +46,7 @@ impl poem_openapi::types::Type for AddressWrapper { } } -impl ParseFromJSON for AddressWrapper { +impl ParseFromJSON for Address { fn parse_from_json( value: Option, ) -> poem_openapi::types::ParseResult { @@ -91,7 +59,7 @@ impl ParseFromJSON for AddressWrapper { } } -impl ToJSON for AddressWrapper { +impl ToJSON for Address { fn to_json(&self) -> Option { serde_json::to_value(self).ok() } @@ -106,7 +74,7 @@ mod tests { #[test] fn deserialize() { - let address: AddressWrapper = serde_json::from_str( + let address: Address = serde_json::from_str( r#""1Ed53d680B8890DAe2a63f673a85fFDE1FD5C7a2""#, ) .unwrap(); diff --git a/src/types/wrappers/decimal_u256.rs b/crates/base-api-types/src/decimal_u256.rs similarity index 71% rename from src/types/wrappers/decimal_u256.rs rename to crates/base-api-types/src/decimal_u256.rs index d32aa65..dc495dc 100644 --- a/src/types/wrappers/decimal_u256.rs +++ b/crates/base-api-types/src/decimal_u256.rs @@ -4,8 +4,6 @@ use ethers::types::U256; use poem_openapi::registry::{MetaSchema, MetaSchemaRef}; use poem_openapi::types::{ParseError, ParseFromJSON, ToJSON}; use serde::{Deserialize, Serialize}; -use sqlx::database::{HasArguments, HasValueRef}; -use sqlx::Database; #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct DecimalU256(pub U256); @@ -33,51 +31,6 @@ impl<'de> Deserialize<'de> for DecimalU256 { } } -impl<'r, DB> sqlx::Decode<'r, DB> for DecimalU256 -where - DB: Database, - [u8; 32]: sqlx::Decode<'r, DB>, -{ - fn decode( - value: >::ValueRef, - ) -> Result { - let bytes = <[u8; 32] as sqlx::Decode>::decode(value)?; - - let value = U256::from_big_endian(&bytes); - - Ok(Self(value)) - } -} - -impl sqlx::Type for DecimalU256 -where - [u8; 32]: sqlx::Type, -{ - fn type_info() -> DB::TypeInfo { - <[u8; 32] as sqlx::Type>::type_info() - } - - fn compatible(ty: &DB::TypeInfo) -> bool { - *ty == Self::type_info() - } -} - -impl<'q, DB> sqlx::Encode<'q, DB> for DecimalU256 -where - DB: Database, - [u8; 32]: sqlx::Encode<'q, DB>, -{ - fn encode_by_ref( - &self, - buf: &mut >::ArgumentBuffer, - ) -> sqlx::encode::IsNull { - let mut bytes = [0u8; 32]; - self.0.to_big_endian(&mut bytes); - - <[u8; 32] as sqlx::Encode>::encode_by_ref(&bytes, buf) - } -} - impl From for DecimalU256 { fn from(value: U256) -> Self { Self(value) @@ -91,7 +44,7 @@ impl poem_openapi::types::Type for DecimalU256 { type RawElementValueType = Self; - fn name() -> std::borrow::Cow<'static, str> { + fn name() -> Cow<'static, str> { "string(decimal-u256)".into() } diff --git a/src/types/wrappers/h256.rs b/crates/base-api-types/src/h256.rs similarity index 55% rename from src/types/wrappers/h256.rs rename to crates/base-api-types/src/h256.rs index 069f536..19ce04d 100644 --- a/src/types/wrappers/h256.rs +++ b/crates/base-api-types/src/h256.rs @@ -1,64 +1,12 @@ -use ethers::types::H256; use poem_openapi::registry::{MetaSchema, MetaSchemaRef}; use poem_openapi::types::{ParseError, ParseFromJSON, ToJSON}; use serde::{Deserialize, Serialize}; -use sqlx::database::{HasArguments, HasValueRef}; -use sqlx::postgres::{PgHasArrayType, PgTypeInfo}; -use sqlx::Database; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(transparent)] -pub struct H256Wrapper(pub H256); +pub struct H256(pub ethers::types::H256); -impl<'r, DB> sqlx::Decode<'r, DB> for H256Wrapper -where - DB: Database, - [u8; 32]: sqlx::Decode<'r, DB>, -{ - fn decode( - value: >::ValueRef, - ) -> Result { - let bytes = <[u8; 32] as sqlx::Decode>::decode(value)?; - - let value = H256::from_slice(&bytes); - - Ok(Self(value)) - } -} - -impl<'q, DB> sqlx::Encode<'q, DB> for H256Wrapper -where - DB: Database, - [u8; 32]: sqlx::Encode<'q, DB>, -{ - fn encode_by_ref( - &self, - buf: &mut >::ArgumentBuffer, - ) -> sqlx::encode::IsNull { - <[u8; 32] as sqlx::Encode>::encode_by_ref(&self.0 .0, buf) - } -} - -impl PgHasArrayType for H256Wrapper { - fn array_type_info() -> PgTypeInfo { - <[u8; 32] as PgHasArrayType>::array_type_info() - } -} - -impl sqlx::Type for H256Wrapper -where - [u8; 32]: sqlx::Type, -{ - fn type_info() -> DB::TypeInfo { - <[u8; 32] as sqlx::Type>::type_info() - } - - fn compatible(ty: &DB::TypeInfo) -> bool { - *ty == Self::type_info() - } -} - -impl poem_openapi::types::Type for H256Wrapper { +impl poem_openapi::types::Type for H256 { const IS_REQUIRED: bool = true; type RawValueType = Self; @@ -95,7 +43,7 @@ impl poem_openapi::types::Type for H256Wrapper { } } -impl ParseFromJSON for H256Wrapper { +impl ParseFromJSON for H256 { fn parse_from_json( value: Option, ) -> poem_openapi::types::ParseResult { @@ -109,7 +57,7 @@ impl ParseFromJSON for H256Wrapper { } } -impl ToJSON for H256Wrapper { +impl ToJSON for H256 { fn to_json(&self) -> Option { serde_json::to_value(self.0).ok() } diff --git a/src/types/wrappers/hex_bytes.rs b/crates/base-api-types/src/hex_bytes.rs similarity index 97% rename from src/types/wrappers/hex_bytes.rs rename to crates/base-api-types/src/hex_bytes.rs index 02dbbe8..85681e0 100644 --- a/src/types/wrappers/hex_bytes.rs +++ b/crates/base-api-types/src/hex_bytes.rs @@ -3,7 +3,7 @@ use poem_openapi::registry::{MetaSchema, MetaSchemaRef}; use poem_openapi::types::{ParseError, ParseFromJSON, ToJSON}; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(transparent)] pub struct HexBytes(pub Bytes); diff --git a/src/types/wrappers/hex_u256.rs b/crates/base-api-types/src/hex_u256.rs similarity index 66% rename from src/types/wrappers/hex_u256.rs rename to crates/base-api-types/src/hex_u256.rs index 63f4a5f..ca61c64 100644 --- a/src/types/wrappers/hex_u256.rs +++ b/crates/base-api-types/src/hex_u256.rs @@ -2,58 +2,11 @@ use ethers::types::U256; use poem_openapi::registry::{MetaSchema, MetaSchemaRef}; use poem_openapi::types::{ParseError, ParseFromJSON, ToJSON}; use serde::{Deserialize, Serialize}; -use sqlx::database::{HasArguments, HasValueRef}; -use sqlx::Database; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(transparent)] pub struct HexU256(pub U256); -impl<'r, DB> sqlx::Decode<'r, DB> for HexU256 -where - DB: Database, - [u8; 32]: sqlx::Decode<'r, DB>, -{ - fn decode( - value: >::ValueRef, - ) -> Result { - let bytes = <[u8; 32] as sqlx::Decode>::decode(value)?; - - let value = U256::from_big_endian(&bytes); - - Ok(Self(value)) - } -} - -impl sqlx::Type for HexU256 -where - [u8; 32]: sqlx::Type, -{ - fn type_info() -> DB::TypeInfo { - <[u8; 32] as sqlx::Type>::type_info() - } - - fn compatible(ty: &DB::TypeInfo) -> bool { - *ty == Self::type_info() - } -} - -impl<'q, DB> sqlx::Encode<'q, DB> for HexU256 -where - DB: Database, - [u8; 32]: sqlx::Encode<'q, DB>, -{ - fn encode_by_ref( - &self, - buf: &mut >::ArgumentBuffer, - ) -> sqlx::encode::IsNull { - let mut bytes = [0u8; 32]; - self.0.to_big_endian(&mut bytes); - - <[u8; 32] as sqlx::Encode>::encode_by_ref(&bytes, buf) - } -} - impl From for HexU256 { fn from(value: U256) -> Self { Self(value) diff --git a/crates/base-api-types/src/lib.rs b/crates/base-api-types/src/lib.rs new file mode 100644 index 0000000..b925b31 --- /dev/null +++ b/crates/base-api-types/src/lib.rs @@ -0,0 +1,11 @@ +mod address; +mod decimal_u256; +mod h256; +mod hex_bytes; +mod hex_u256; + +pub use address::Address; +pub use decimal_u256::DecimalU256; +pub use h256::H256; +pub use hex_bytes::HexBytes; +pub use hex_u256::HexU256; diff --git a/crates/tx-sitter-client/.gitignore b/crates/tx-sitter-client/.gitignore new file mode 100644 index 0000000..6aa1064 --- /dev/null +++ b/crates/tx-sitter-client/.gitignore @@ -0,0 +1,3 @@ +/target/ +**/*.rs.bk +Cargo.lock diff --git a/crates/tx-sitter-client/.openapi-generator-ignore b/crates/tx-sitter-client/.openapi-generator-ignore new file mode 100644 index 0000000..7484ee5 --- /dev/null +++ b/crates/tx-sitter-client/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/crates/tx-sitter-client/.openapi-generator/FILES b/crates/tx-sitter-client/.openapi-generator/FILES new file mode 100644 index 0000000..7f1a432 --- /dev/null +++ b/crates/tx-sitter-client/.openapi-generator/FILES @@ -0,0 +1,45 @@ +.gitignore +.travis.yml +Cargo.toml +README.md +docs/AdminV1Api.md +docs/CreateApiKeyResponse.md +docs/CreateRelayerRequest.md +docs/CreateRelayerResponse.md +docs/GetTxResponse.md +docs/JsonRpcVersion.md +docs/NetworkInfo.md +docs/NewNetworkInfo.md +docs/RelayerGasPriceLimit.md +docs/RelayerInfo.md +docs/RelayerUpdate.md +docs/RelayerV1Api.md +docs/RpcRequest.md +docs/SendTxRequest.md +docs/SendTxResponse.md +docs/ServiceApi.md +docs/TransactionPriority.md +docs/TxStatus.md +git_push.sh +src/apis/admin_v1_api.rs +src/apis/configuration.rs +src/apis/mod.rs +src/apis/relayer_v1_api.rs +src/apis/service_api.rs +src/lib.rs +src/models/create_api_key_response.rs +src/models/create_relayer_request.rs +src/models/create_relayer_response.rs +src/models/get_tx_response.rs +src/models/json_rpc_version.rs +src/models/mod.rs +src/models/network_info.rs +src/models/new_network_info.rs +src/models/relayer_gas_price_limit.rs +src/models/relayer_info.rs +src/models/relayer_update.rs +src/models/rpc_request.rs +src/models/send_tx_request.rs +src/models/send_tx_response.rs +src/models/transaction_priority.rs +src/models/tx_status.rs diff --git a/crates/tx-sitter-client/.openapi-generator/VERSION b/crates/tx-sitter-client/.openapi-generator/VERSION new file mode 100644 index 0000000..17f2442 --- /dev/null +++ b/crates/tx-sitter-client/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.9.0-SNAPSHOT diff --git a/crates/tx-sitter-client/.travis.yml b/crates/tx-sitter-client/.travis.yml new file mode 100644 index 0000000..22761ba --- /dev/null +++ b/crates/tx-sitter-client/.travis.yml @@ -0,0 +1 @@ +language: rust diff --git a/crates/tx-sitter-client/Cargo.toml b/crates/tx-sitter-client/Cargo.toml new file mode 100644 index 0000000..0feb7d7 --- /dev/null +++ b/crates/tx-sitter-client/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "tx-sitter-client" +version = "0.1.0" +authors = ["OpenAPI Generator team and contributors"] +description = "A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. " +# Override this license by providing a License Object in the OpenAPI. +license = "Unlicense" +edition = "2021" + +[dependencies] +serde = { version = "^1.0", features = ["derive"] } +base-api-types = { path = "../base-api-types" } +serde_with = { version = "^3.8", default-features = false, features = ["base64", "std", "macros"] } +serde_json = "^1.0" +serde_repr = "^0.1" +url = "^2.5" +uuid = { version = "^1.8", features = ["serde", "v4"] } +reqwest = { version = "^0.12", features = ["json", "multipart"] } +reqwest-middleware = { version = "^0.3", features = ["json", "multipart"] } diff --git a/crates/tx-sitter-client/README.md b/crates/tx-sitter-client/README.md new file mode 100644 index 0000000..2c0aa56 --- /dev/null +++ b/crates/tx-sitter-client/README.md @@ -0,0 +1,96 @@ +# Rust API client for tx-sitter-client + +> [!CAUTION] +> This whole client is generated. Please read README in top directory of repo. + +A transaction relayer service! + +## Operating a relayer +Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. + +### 1. Setup a network +tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. + +To see the list of currently added networks use the `GET /1/admin/networks` endpoint. + +### 2. Create a relayer +A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). + +To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. + +### 3. Create an API key +By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. + +### 4. Use the API key +Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. + +You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + + + +## Overview + +This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [openapi-spec](https://openapis.org) from a remote server, you can easily generate an API client. + +- API version: 0.1.0 +- Package version: 0.1.0 +- Generator version: 7.9.0-SNAPSHOT +- Build package: `org.openapitools.codegen.languages.RustClientCodegen` + +## Installation + +Put the package under your project folder in a directory named `tx-sitter-client` and add the following to `Cargo.toml` under `[dependencies]`: + +``` +tx-sitter-client = { path = "./tx-sitter-client" } +``` + +## Documentation for API Endpoints + +All URIs are relative to *http://localhost:3000* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +*AdminV1Api* | [**create_network**](docs/AdminV1Api.md#create_network) | **POST** /1/admin/network/{chain_id} | Create Network +*AdminV1Api* | [**create_relayer**](docs/AdminV1Api.md#create_relayer) | **POST** /1/admin/relayer | Create Relayer +*AdminV1Api* | [**get_networks**](docs/AdminV1Api.md#get_networks) | **GET** /1/admin/networks | Get Networks +*AdminV1Api* | [**get_relayer**](docs/AdminV1Api.md#get_relayer) | **GET** /1/admin/relayer/{relayer_id} | Get Relayer +*AdminV1Api* | [**get_relayers**](docs/AdminV1Api.md#get_relayers) | **GET** /1/admin/relayers | Get Relayers +*AdminV1Api* | [**relayer_create_api_key**](docs/AdminV1Api.md#relayer_create_api_key) | **POST** /1/admin/relayer/{relayer_id}/key | Create Relayer API Key +*AdminV1Api* | [**reset_relayer**](docs/AdminV1Api.md#reset_relayer) | **POST** /1/admin/relayer/{relayer_id}/reset | Reset Relayer transactions +*AdminV1Api* | [**update_relayer**](docs/AdminV1Api.md#update_relayer) | **POST** /1/admin/relayer/{relayer_id} | Update Relayer +*RelayerV1Api* | [**call_rpc**](docs/RelayerV1Api.md#call_rpc) | **POST** /1/api/{api_token}/rpc | Relayer RPC +*RelayerV1Api* | [**create_transaction**](docs/RelayerV1Api.md#create_transaction) | **POST** /1/api/{api_token}/tx | Send Transaction +*RelayerV1Api* | [**get_transaction**](docs/RelayerV1Api.md#get_transaction) | **GET** /1/api/{api_token}/tx/{tx_id} | Get Transaction +*RelayerV1Api* | [**get_transactions**](docs/RelayerV1Api.md#get_transactions) | **GET** /1/api/{api_token}/txs | Get Transactions +*ServiceApi* | [**health**](docs/ServiceApi.md#health) | **GET** /health | Health + + +## Documentation For Models + + - [CreateApiKeyResponse](docs/CreateApiKeyResponse.md) + - [CreateRelayerRequest](docs/CreateRelayerRequest.md) + - [CreateRelayerResponse](docs/CreateRelayerResponse.md) + - [GetTxResponse](docs/GetTxResponse.md) + - [JsonRpcVersion](docs/JsonRpcVersion.md) + - [NetworkInfo](docs/NetworkInfo.md) + - [NewNetworkInfo](docs/NewNetworkInfo.md) + - [RelayerGasPriceLimit](docs/RelayerGasPriceLimit.md) + - [RelayerInfo](docs/RelayerInfo.md) + - [RelayerUpdate](docs/RelayerUpdate.md) + - [RpcRequest](docs/RpcRequest.md) + - [SendTxRequest](docs/SendTxRequest.md) + - [SendTxResponse](docs/SendTxResponse.md) + - [TransactionPriority](docs/TransactionPriority.md) + - [TxStatus](docs/TxStatus.md) + + +To get access to the crate's generated documentation, use: + +``` +cargo doc --open +``` + +## Author + + diff --git a/crates/tx-sitter-client/docs/AdminV1Api.md b/crates/tx-sitter-client/docs/AdminV1Api.md new file mode 100644 index 0000000..757c572 --- /dev/null +++ b/crates/tx-sitter-client/docs/AdminV1Api.md @@ -0,0 +1,238 @@ +# \AdminV1Api + +All URIs are relative to *http://localhost:3000* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**create_network**](AdminV1Api.md#create_network) | **POST** /1/admin/network/{chain_id} | Create Network +[**create_relayer**](AdminV1Api.md#create_relayer) | **POST** /1/admin/relayer | Create Relayer +[**get_networks**](AdminV1Api.md#get_networks) | **GET** /1/admin/networks | Get Networks +[**get_relayer**](AdminV1Api.md#get_relayer) | **GET** /1/admin/relayer/{relayer_id} | Get Relayer +[**get_relayers**](AdminV1Api.md#get_relayers) | **GET** /1/admin/relayers | Get Relayers +[**relayer_create_api_key**](AdminV1Api.md#relayer_create_api_key) | **POST** /1/admin/relayer/{relayer_id}/key | Create Relayer API Key +[**reset_relayer**](AdminV1Api.md#reset_relayer) | **POST** /1/admin/relayer/{relayer_id}/reset | Reset Relayer transactions +[**update_relayer**](AdminV1Api.md#update_relayer) | **POST** /1/admin/relayer/{relayer_id} | Update Relayer + + + +## create_network + +> create_network(chain_id, new_network_info) +Create Network + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**chain_id** | **i32** | | [required] | +**new_network_info** | [**NewNetworkInfo**](NewNetworkInfo.md) | | [required] | + +### Return type + + (empty response body) + +### Authorization + +[BasicAuth](../README.md#BasicAuth) + +### HTTP request headers + +- **Content-Type**: application/json; charset=utf-8 +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## create_relayer + +> models::CreateRelayerResponse create_relayer(create_relayer_request) +Create Relayer + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**create_relayer_request** | [**CreateRelayerRequest**](CreateRelayerRequest.md) | | [required] | + +### Return type + +[**models::CreateRelayerResponse**](CreateRelayerResponse.md) + +### Authorization + +[BasicAuth](../README.md#BasicAuth) + +### HTTP request headers + +- **Content-Type**: application/json; charset=utf-8 +- **Accept**: application/json; charset=utf-8 + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## get_networks + +> Vec get_networks() +Get Networks + +### Parameters + +This endpoint does not need any parameter. + +### Return type + +[**Vec**](NetworkInfo.md) + +### Authorization + +[BasicAuth](../README.md#BasicAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json; charset=utf-8 + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## get_relayer + +> models::RelayerInfo get_relayer(relayer_id) +Get Relayer + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**relayer_id** | **String** | | [required] | + +### Return type + +[**models::RelayerInfo**](RelayerInfo.md) + +### Authorization + +[BasicAuth](../README.md#BasicAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json; charset=utf-8 + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## get_relayers + +> Vec get_relayers() +Get Relayers + +### Parameters + +This endpoint does not need any parameter. + +### Return type + +[**Vec**](RelayerInfo.md) + +### Authorization + +[BasicAuth](../README.md#BasicAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json; charset=utf-8 + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## relayer_create_api_key + +> models::CreateApiKeyResponse relayer_create_api_key(relayer_id) +Create Relayer API Key + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**relayer_id** | **String** | | [required] | + +### Return type + +[**models::CreateApiKeyResponse**](CreateApiKeyResponse.md) + +### Authorization + +[BasicAuth](../README.md#BasicAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json; charset=utf-8 + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## reset_relayer + +> reset_relayer(relayer_id) +Reset Relayer transactions + +Purges unsent transactions, useful for unstucking the relayer + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**relayer_id** | **String** | | [required] | + +### Return type + + (empty response body) + +### Authorization + +[BasicAuth](../README.md#BasicAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## update_relayer + +> update_relayer(relayer_id, relayer_update) +Update Relayer + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**relayer_id** | **String** | | [required] | +**relayer_update** | [**RelayerUpdate**](RelayerUpdate.md) | | [required] | + +### Return type + + (empty response body) + +### Authorization + +[BasicAuth](../README.md#BasicAuth) + +### HTTP request headers + +- **Content-Type**: application/json; charset=utf-8 +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/crates/tx-sitter-client/docs/CreateApiKeyResponse.md b/crates/tx-sitter-client/docs/CreateApiKeyResponse.md new file mode 100644 index 0000000..02ba449 --- /dev/null +++ b/crates/tx-sitter-client/docs/CreateApiKeyResponse.md @@ -0,0 +1,11 @@ +# CreateApiKeyResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**api_key** | **String** | Base64 encoded API key | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/docs/CreateRelayerRequest.md b/crates/tx-sitter-client/docs/CreateRelayerRequest.md new file mode 100644 index 0000000..1915353 --- /dev/null +++ b/crates/tx-sitter-client/docs/CreateRelayerRequest.md @@ -0,0 +1,12 @@ +# CreateRelayerRequest + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**name** | **String** | New relayer name | +**chain_id** | **i32** | The chain id of the relayer | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/docs/CreateRelayerResponse.md b/crates/tx-sitter-client/docs/CreateRelayerResponse.md new file mode 100644 index 0000000..6ff4f78 --- /dev/null +++ b/crates/tx-sitter-client/docs/CreateRelayerResponse.md @@ -0,0 +1,12 @@ +# CreateRelayerResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**relayer_id** | **String** | ID of the created relayer | +**address** | [**base_api_types::Address**](base_api_types::Address.md) | Address of the created relayer | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/docs/GetTxResponse.md b/crates/tx-sitter-client/docs/GetTxResponse.md new file mode 100644 index 0000000..e7230da --- /dev/null +++ b/crates/tx-sitter-client/docs/GetTxResponse.md @@ -0,0 +1,18 @@ +# GetTxResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**tx_id** | **String** | | +**to** | [**base_api_types::Address**](base_api_types::Address.md) | Hex encoded ethereum address | +**data** | Option<[**base_api_types::HexBytes**](base_api_types::HexBytes.md)> | | [optional] +**value** | [**base_api_types::DecimalU256**](base_api_types::DecimalU256.md) | A decimal 256-bit unsigned integer | [default to 0] +**gas_limit** | [**base_api_types::DecimalU256**](base_api_types::DecimalU256.md) | A decimal 256-bit unsigned integer | [default to 0] +**nonce** | **i32** | | +**tx_hash** | Option<[**base_api_types::H256**](base_api_types::H256.md)> | A hex encoded 256-bit hash | [optional][default to 0x0000000000000000000000000000000000000000000000000000000000000000] +**status** | Option<[**models::TxStatus**](TxStatus.md)> | | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/docs/JsonRpcVersion.md b/crates/tx-sitter-client/docs/JsonRpcVersion.md new file mode 100644 index 0000000..d58f109 --- /dev/null +++ b/crates/tx-sitter-client/docs/JsonRpcVersion.md @@ -0,0 +1,12 @@ +# JsonRpcVersion + +## Enum Variants + +| Name | Value | +|---- | -----| +| Variant2Period0 | 2.0 | + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/docs/NetworkInfo.md b/crates/tx-sitter-client/docs/NetworkInfo.md new file mode 100644 index 0000000..53468b3 --- /dev/null +++ b/crates/tx-sitter-client/docs/NetworkInfo.md @@ -0,0 +1,14 @@ +# NetworkInfo + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**chain_id** | **i32** | | +**name** | **String** | | +**http_rpc** | **String** | | +**ws_rpc** | **String** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/docs/NewNetworkInfo.md b/crates/tx-sitter-client/docs/NewNetworkInfo.md new file mode 100644 index 0000000..2f228eb --- /dev/null +++ b/crates/tx-sitter-client/docs/NewNetworkInfo.md @@ -0,0 +1,13 @@ +# NewNetworkInfo + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**name** | **String** | | +**http_rpc** | **String** | | +**ws_rpc** | **String** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/docs/RelayerGasPriceLimit.md b/crates/tx-sitter-client/docs/RelayerGasPriceLimit.md new file mode 100644 index 0000000..095de7a --- /dev/null +++ b/crates/tx-sitter-client/docs/RelayerGasPriceLimit.md @@ -0,0 +1,12 @@ +# RelayerGasPriceLimit + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**value** | [**base_api_types::DecimalU256**](base_api_types::DecimalU256.md) | A decimal 256-bit unsigned integer | [default to 0] +**chain_id** | **i64** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/docs/RelayerInfo.md b/crates/tx-sitter-client/docs/RelayerInfo.md new file mode 100644 index 0000000..6fe273c --- /dev/null +++ b/crates/tx-sitter-client/docs/RelayerInfo.md @@ -0,0 +1,21 @@ +# RelayerInfo + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**id** | **String** | | +**name** | **String** | | +**chain_id** | **i32** | | +**key_id** | **String** | | +**address** | [**base_api_types::Address**](base_api_types::Address.md) | Hex encoded ethereum address | +**nonce** | **i32** | | +**current_nonce** | **i32** | | +**max_inflight_txs** | **i32** | | +**max_queued_txs** | **i32** | | +**gas_price_limits** | [**Vec**](RelayerGasPriceLimit.md) | | +**enabled** | **bool** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/docs/RelayerUpdate.md b/crates/tx-sitter-client/docs/RelayerUpdate.md new file mode 100644 index 0000000..8119c82 --- /dev/null +++ b/crates/tx-sitter-client/docs/RelayerUpdate.md @@ -0,0 +1,15 @@ +# RelayerUpdate + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**relayer_name** | Option<**String**> | | [optional] +**max_inflight_txs** | Option<**i32**> | | [optional] +**max_queued_txs** | Option<**i32**> | | [optional] +**gas_price_limits** | Option<[**Vec**](RelayerGasPriceLimit.md)> | | [optional] +**enabled** | Option<**bool**> | | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/docs/RelayerV1Api.md b/crates/tx-sitter-client/docs/RelayerV1Api.md new file mode 100644 index 0000000..80e792d --- /dev/null +++ b/crates/tx-sitter-client/docs/RelayerV1Api.md @@ -0,0 +1,129 @@ +# \RelayerV1Api + +All URIs are relative to *http://localhost:3000* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**call_rpc**](RelayerV1Api.md#call_rpc) | **POST** /1/api/{api_token}/rpc | Relayer RPC +[**create_transaction**](RelayerV1Api.md#create_transaction) | **POST** /1/api/{api_token}/tx | Send Transaction +[**get_transaction**](RelayerV1Api.md#get_transaction) | **GET** /1/api/{api_token}/tx/{tx_id} | Get Transaction +[**get_transactions**](RelayerV1Api.md#get_transactions) | **GET** /1/api/{api_token}/txs | Get Transactions + + + +## call_rpc + +> serde_json::Value call_rpc(api_token, rpc_request) +Relayer RPC + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**api_token** | **String** | | [required] | +**rpc_request** | [**RpcRequest**](RpcRequest.md) | | [required] | + +### Return type + +[**serde_json::Value**](serde_json::Value.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: application/json; charset=utf-8 +- **Accept**: application/json; charset=utf-8 + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## create_transaction + +> models::SendTxResponse create_transaction(api_token, send_tx_request) +Send Transaction + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**api_token** | **String** | | [required] | +**send_tx_request** | [**SendTxRequest**](SendTxRequest.md) | | [required] | + +### Return type + +[**models::SendTxResponse**](SendTxResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: application/json; charset=utf-8 +- **Accept**: application/json; charset=utf-8 + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## get_transaction + +> models::GetTxResponse get_transaction(api_token, tx_id) +Get Transaction + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**api_token** | **String** | | [required] | +**tx_id** | **String** | | [required] | + +### Return type + +[**models::GetTxResponse**](GetTxResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json; charset=utf-8 + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## get_transactions + +> Vec get_transactions(api_token, status, unsent) +Get Transactions + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**api_token** | **String** | | [required] | +**status** | Option<[**TxStatus**](.md)> | Optional tx status to filter by | | +**unsent** | Option<**bool**> | Fetch unsent txs, overrides the status query | |[default to false] + +### Return type + +[**Vec**](GetTxResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json; charset=utf-8 + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/crates/tx-sitter-client/docs/RpcRequest.md b/crates/tx-sitter-client/docs/RpcRequest.md new file mode 100644 index 0000000..468d75c --- /dev/null +++ b/crates/tx-sitter-client/docs/RpcRequest.md @@ -0,0 +1,14 @@ +# RpcRequest + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**id** | **i32** | | +**method** | **String** | | +**params** | Option<[**serde_json::Value**](.md)> | | [optional][default to null] +**jsonrpc** | [**models::JsonRpcVersion**](JsonRpcVersion.md) | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/docs/SendTxRequest.md b/crates/tx-sitter-client/docs/SendTxRequest.md new file mode 100644 index 0000000..5ca7b44 --- /dev/null +++ b/crates/tx-sitter-client/docs/SendTxRequest.md @@ -0,0 +1,17 @@ +# SendTxRequest + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**to** | [**base_api_types::Address**](base_api_types::Address.md) | Hex encoded ethereum address | +**value** | [**base_api_types::DecimalU256**](base_api_types::DecimalU256.md) | Transaction value | [default to 0] +**data** | Option<[**base_api_types::HexBytes**](base_api_types::HexBytes.md)> | | [optional] +**gas_limit** | [**base_api_types::DecimalU256**](base_api_types::DecimalU256.md) | Transaction gas limit | [default to 0] +**priority** | Option<[**models::TransactionPriority**](TransactionPriority.md)> | | [optional] +**tx_id** | Option<**String**> | An optional transaction id. If not provided tx-sitter will generate a UUID. Can be used to provide idempotency for the transaction. | [optional] +**blobs** | Option<[**Vec>**](Vec.md)> | | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/docs/SendTxResponse.md b/crates/tx-sitter-client/docs/SendTxResponse.md new file mode 100644 index 0000000..14a4217 --- /dev/null +++ b/crates/tx-sitter-client/docs/SendTxResponse.md @@ -0,0 +1,11 @@ +# SendTxResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**tx_id** | **String** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/docs/ServiceApi.md b/crates/tx-sitter-client/docs/ServiceApi.md new file mode 100644 index 0000000..457d1e8 --- /dev/null +++ b/crates/tx-sitter-client/docs/ServiceApi.md @@ -0,0 +1,34 @@ +# \ServiceApi + +All URIs are relative to *http://localhost:3000* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**health**](ServiceApi.md#health) | **GET** /health | Health + + + +## health + +> health() +Health + +### Parameters + +This endpoint does not need any parameter. + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/crates/tx-sitter-client/docs/TransactionPriority.md b/crates/tx-sitter-client/docs/TransactionPriority.md new file mode 100644 index 0000000..72ec087 --- /dev/null +++ b/crates/tx-sitter-client/docs/TransactionPriority.md @@ -0,0 +1,16 @@ +# TransactionPriority + +## Enum Variants + +| Name | Value | +|---- | -----| +| Slowest | slowest | +| Slow | slow | +| Regular | regular | +| Fast | fast | +| Fastest | fastest | + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/docs/TxStatus.md b/crates/tx-sitter-client/docs/TxStatus.md new file mode 100644 index 0000000..413f41e --- /dev/null +++ b/crates/tx-sitter-client/docs/TxStatus.md @@ -0,0 +1,14 @@ +# TxStatus + +## Enum Variants + +| Name | Value | +|---- | -----| +| Pending | pending | +| Mined | mined | +| Finalized | finalized | + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/tx-sitter-client/git_push.sh b/crates/tx-sitter-client/git_push.sh new file mode 100644 index 0000000..f53a75d --- /dev/null +++ b/crates/tx-sitter-client/git_push.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 openapi-petstore-perl "minor update" "gitlab.com" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 +git_host=$4 + +if [ "$git_host" = "" ]; then + git_host="github.com" + echo "[INFO] No command line input provided. Set \$git_host to $git_host" +fi + +if [ "$git_user_id" = "" ]; then + git_user_id="GIT_USER_ID" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="GIT_REPO_ID" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="Minor update" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=$(git remote) +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." + git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:"${GIT_TOKEN}"@${git_host}/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' diff --git a/crates/tx-sitter-client/src/apis/admin_v1_api.rs b/crates/tx-sitter-client/src/apis/admin_v1_api.rs new file mode 100644 index 0000000..8f46b27 --- /dev/null +++ b/crates/tx-sitter-client/src/apis/admin_v1_api.rs @@ -0,0 +1,388 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + + +use reqwest; +use serde::{Deserialize, Serialize}; +use crate::{apis::ResponseContent, models}; +use super::{Error, configuration}; + +/// struct for passing parameters to the method [`create_network`] +#[derive(Clone, Debug)] +pub struct CreateNetworkParams { + pub chain_id: i32, + pub new_network_info: models::NewNetworkInfo +} + +/// struct for passing parameters to the method [`create_relayer`] +#[derive(Clone, Debug)] +pub struct CreateRelayerParams { + pub create_relayer_request: models::CreateRelayerRequest +} + +/// struct for passing parameters to the method [`get_relayer`] +#[derive(Clone, Debug)] +pub struct GetRelayerParams { + pub relayer_id: String +} + +/// struct for passing parameters to the method [`relayer_create_api_key`] +#[derive(Clone, Debug)] +pub struct RelayerCreateApiKeyParams { + pub relayer_id: String +} + +/// struct for passing parameters to the method [`reset_relayer`] +#[derive(Clone, Debug)] +pub struct ResetRelayerParams { + pub relayer_id: String +} + +/// struct for passing parameters to the method [`update_relayer`] +#[derive(Clone, Debug)] +pub struct UpdateRelayerParams { + pub relayer_id: String, + pub relayer_update: models::RelayerUpdate +} + + +/// struct for typed errors of method [`create_network`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum CreateNetworkError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`create_relayer`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum CreateRelayerError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`get_networks`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetNetworksError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`get_relayer`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetRelayerError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`get_relayers`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetRelayersError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`relayer_create_api_key`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum RelayerCreateApiKeyError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`reset_relayer`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ResetRelayerError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`update_relayer`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum UpdateRelayerError { + UnknownValue(serde_json::Value), +} + + +pub async fn create_network(configuration: &configuration::Configuration, params: CreateNetworkParams) -> Result<(), Error> { + let local_var_configuration = configuration; + + // unbox the parameters + let chain_id = params.chain_id; + let new_network_info = params.new_network_info; + + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/1/admin/network/{chain_id}", local_var_configuration.base_path, chain_id=chain_id); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_auth_conf) = local_var_configuration.basic_auth { + local_var_req_builder = local_var_req_builder.basic_auth(local_var_auth_conf.0.to_owned(), local_var_auth_conf.1.to_owned()); + }; + local_var_req_builder = local_var_req_builder.json(&new_network_info); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + Ok(()) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub async fn create_relayer(configuration: &configuration::Configuration, params: CreateRelayerParams) -> Result> { + let local_var_configuration = configuration; + + // unbox the parameters + let create_relayer_request = params.create_relayer_request; + + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/1/admin/relayer", local_var_configuration.base_path); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_auth_conf) = local_var_configuration.basic_auth { + local_var_req_builder = local_var_req_builder.basic_auth(local_var_auth_conf.0.to_owned(), local_var_auth_conf.1.to_owned()); + }; + local_var_req_builder = local_var_req_builder.json(&create_relayer_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub async fn get_networks(configuration: &configuration::Configuration) -> Result, Error> { + let local_var_configuration = configuration; + + // unbox the parameters + + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/1/admin/networks", local_var_configuration.base_path); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_auth_conf) = local_var_configuration.basic_auth { + local_var_req_builder = local_var_req_builder.basic_auth(local_var_auth_conf.0.to_owned(), local_var_auth_conf.1.to_owned()); + }; + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub async fn get_relayer(configuration: &configuration::Configuration, params: GetRelayerParams) -> Result> { + let local_var_configuration = configuration; + + // unbox the parameters + let relayer_id = params.relayer_id; + + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/1/admin/relayer/{relayer_id}", local_var_configuration.base_path, relayer_id=crate::apis::urlencode(relayer_id)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_auth_conf) = local_var_configuration.basic_auth { + local_var_req_builder = local_var_req_builder.basic_auth(local_var_auth_conf.0.to_owned(), local_var_auth_conf.1.to_owned()); + }; + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub async fn get_relayers(configuration: &configuration::Configuration) -> Result, Error> { + let local_var_configuration = configuration; + + // unbox the parameters + + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/1/admin/relayers", local_var_configuration.base_path); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_auth_conf) = local_var_configuration.basic_auth { + local_var_req_builder = local_var_req_builder.basic_auth(local_var_auth_conf.0.to_owned(), local_var_auth_conf.1.to_owned()); + }; + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub async fn relayer_create_api_key(configuration: &configuration::Configuration, params: RelayerCreateApiKeyParams) -> Result> { + let local_var_configuration = configuration; + + // unbox the parameters + let relayer_id = params.relayer_id; + + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/1/admin/relayer/{relayer_id}/key", local_var_configuration.base_path, relayer_id=crate::apis::urlencode(relayer_id)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_auth_conf) = local_var_configuration.basic_auth { + local_var_req_builder = local_var_req_builder.basic_auth(local_var_auth_conf.0.to_owned(), local_var_auth_conf.1.to_owned()); + }; + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + +/// Purges unsent transactions, useful for unstucking the relayer +pub async fn reset_relayer(configuration: &configuration::Configuration, params: ResetRelayerParams) -> Result<(), Error> { + let local_var_configuration = configuration; + + // unbox the parameters + let relayer_id = params.relayer_id; + + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/1/admin/relayer/{relayer_id}/reset", local_var_configuration.base_path, relayer_id=crate::apis::urlencode(relayer_id)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_auth_conf) = local_var_configuration.basic_auth { + local_var_req_builder = local_var_req_builder.basic_auth(local_var_auth_conf.0.to_owned(), local_var_auth_conf.1.to_owned()); + }; + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + Ok(()) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub async fn update_relayer(configuration: &configuration::Configuration, params: UpdateRelayerParams) -> Result<(), Error> { + let local_var_configuration = configuration; + + // unbox the parameters + let relayer_id = params.relayer_id; + let relayer_update = params.relayer_update; + + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/1/admin/relayer/{relayer_id}", local_var_configuration.base_path, relayer_id=crate::apis::urlencode(relayer_id)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_auth_conf) = local_var_configuration.basic_auth { + local_var_req_builder = local_var_req_builder.basic_auth(local_var_auth_conf.0.to_owned(), local_var_auth_conf.1.to_owned()); + }; + local_var_req_builder = local_var_req_builder.json(&relayer_update); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + Ok(()) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + diff --git a/crates/tx-sitter-client/src/apis/configuration.rs b/crates/tx-sitter-client/src/apis/configuration.rs new file mode 100644 index 0000000..99ff132 --- /dev/null +++ b/crates/tx-sitter-client/src/apis/configuration.rs @@ -0,0 +1,103 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + + + +#[derive(Debug, Clone)] +pub struct Configuration { + pub base_path: String, + pub user_agent: Option, + pub client: reqwest_middleware::ClientWithMiddleware, + pub basic_auth: Option, + pub oauth_access_token: Option, + pub bearer_access_token: Option, + pub api_key: Option, + // TODO: take an oauth2 token source, similar to the go one +} + +pub type BasicAuth = (String, Option); + +#[derive(Debug, Clone)] +pub struct ApiKey { + pub prefix: Option, + pub key: String, +} + + +impl Default for Configuration { + fn default() -> Self { + Configuration { + base_path: "http://localhost:3000".to_owned(), + user_agent: Some("OpenAPI-Generator/0.1.0/rust".to_owned()), + client: reqwest_middleware::ClientBuilder::new(reqwest::Client::new()).build(), + basic_auth: None, + oauth_access_token: None, + bearer_access_token: None, + api_key: None, + + } + } +} + +pub struct ConfigurationBuilder { + pub base_path: Option, + pub user_agent: Option, + pub basic_auth: Option, +} + +impl ConfigurationBuilder { + pub fn new() -> ConfigurationBuilder { + ConfigurationBuilder { + base_path: None, + user_agent: None, + basic_auth: None, + } + } + + pub fn base_path(mut self, base_path: String) -> Self { + self.base_path = Some(base_path); + self + } + + pub fn user_agent(mut self, user_agent: String) -> Self { + self.user_agent = Some(user_agent); + self + } + + pub fn basic_auth(mut self, user: String, pass: Option) -> Self { + self.basic_auth = Some((user, pass)); + self + } + + pub fn build(self) -> Configuration { + let mut conf: Configuration = Default::default(); + + if let Some(base_path) = self.base_path { + conf.base_path = base_path; + } + + if let Some(user_agent) = self.user_agent { + conf.user_agent = Some(user_agent); + } + + if let Some(basic_auth) = self.basic_auth { + conf.basic_auth = Some(basic_auth); + } + + conf + } +} + +impl Default for ConfigurationBuilder { + fn default() -> Self { + Self::new() + } +} + diff --git a/crates/tx-sitter-client/src/apis/mod.rs b/crates/tx-sitter-client/src/apis/mod.rs new file mode 100644 index 0000000..8a66d82 --- /dev/null +++ b/crates/tx-sitter-client/src/apis/mod.rs @@ -0,0 +1,106 @@ +use std::error; +use std::fmt; + +#[derive(Debug, Clone)] +pub struct ResponseContent { + pub status: reqwest::StatusCode, + pub content: String, + pub entity: Option, +} + +#[derive(Debug)] +pub enum Error { + Reqwest(reqwest::Error), + ReqwestMiddleware(reqwest_middleware::Error), + Serde(serde_json::Error), + Io(std::io::Error), + ResponseError(ResponseContent), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (module, e) = match self { + Error::Reqwest(e) => ("reqwest", e.to_string()), + Error::ReqwestMiddleware(e) => ("reqwest-middleware", e.to_string()), + Error::Serde(e) => ("serde", e.to_string()), + Error::Io(e) => ("IO", e.to_string()), + Error::ResponseError(e) => ("response", format!("status code {}", e.status)), + }; + write!(f, "error in {}: {}", module, e) + } +} + +impl error::Error for Error { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + Some(match self { + Error::Reqwest(e) => e, + Error::ReqwestMiddleware(e) => e, + Error::Serde(e) => e, + Error::Io(e) => e, + Error::ResponseError(_) => return None, + }) + } +} + +impl From for Error { + fn from(e: reqwest::Error) -> Self { + Error::Reqwest(e) + } +} + +impl From for Error { + fn from(e: reqwest_middleware::Error) -> Self { + Error::ReqwestMiddleware(e) + } +} + +impl From for Error { + fn from(e: serde_json::Error) -> Self { + Error::Serde(e) + } +} + +impl From for Error { + fn from(e: std::io::Error) -> Self { + Error::Io(e) + } +} + +pub fn urlencode>(s: T) -> String { + ::url::form_urlencoded::byte_serialize(s.as_ref().as_bytes()).collect() +} + +pub fn parse_deep_object(prefix: &str, value: &serde_json::Value) -> Vec<(String, String)> { + if let serde_json::Value::Object(object) = value { + let mut params = vec![]; + + for (key, value) in object { + match value { + serde_json::Value::Object(_) => params.append(&mut parse_deep_object( + &format!("{}[{}]", prefix, key), + value, + )), + serde_json::Value::Array(array) => { + for (i, value) in array.iter().enumerate() { + params.append(&mut parse_deep_object( + &format!("{}[{}][{}]", prefix, key, i), + value, + )); + } + }, + serde_json::Value::String(s) => params.push((format!("{}[{}]", prefix, key), s.clone())), + _ => params.push((format!("{}[{}]", prefix, key), value.to_string())), + } + } + + return params; + } + + unimplemented!("Only objects are supported with style=deepObject") +} + +pub mod admin_v1_api; +pub mod relayer_v1_api; +pub mod service_api; + +pub mod configuration; diff --git a/crates/tx-sitter-client/src/apis/relayer_v1_api.rs b/crates/tx-sitter-client/src/apis/relayer_v1_api.rs new file mode 100644 index 0000000..c228375 --- /dev/null +++ b/crates/tx-sitter-client/src/apis/relayer_v1_api.rs @@ -0,0 +1,214 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + + +use reqwest; +use serde::{Deserialize, Serialize}; +use crate::{apis::ResponseContent, models}; +use super::{Error, configuration}; + +/// struct for passing parameters to the method [`call_rpc`] +#[derive(Clone, Debug)] +pub struct CallRpcParams { + pub api_token: String, + pub rpc_request: models::RpcRequest +} + +/// struct for passing parameters to the method [`create_transaction`] +#[derive(Clone, Debug)] +pub struct CreateTransactionParams { + pub api_token: String, + pub send_tx_request: models::SendTxRequest +} + +/// struct for passing parameters to the method [`get_transaction`] +#[derive(Clone, Debug)] +pub struct GetTransactionParams { + pub api_token: String, + pub tx_id: String +} + +/// struct for passing parameters to the method [`get_transactions`] +#[derive(Clone, Debug)] +pub struct GetTransactionsParams { + pub api_token: String, + /// Optional tx status to filter by + pub status: Option, + /// Fetch unsent txs, overrides the status query + pub unsent: Option +} + + +/// struct for typed errors of method [`call_rpc`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum CallRpcError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`create_transaction`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum CreateTransactionError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`get_transaction`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetTransactionError { + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`get_transactions`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetTransactionsError { + UnknownValue(serde_json::Value), +} + + +pub async fn call_rpc(configuration: &configuration::Configuration, params: CallRpcParams) -> Result> { + let local_var_configuration = configuration; + + // unbox the parameters + let api_token = params.api_token; + let rpc_request = params.rpc_request; + + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/1/api/{api_token}/rpc", local_var_configuration.base_path, api_token=crate::apis::urlencode(api_token)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = local_var_req_builder.json(&rpc_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub async fn create_transaction(configuration: &configuration::Configuration, params: CreateTransactionParams) -> Result> { + let local_var_configuration = configuration; + + // unbox the parameters + let api_token = params.api_token; + let send_tx_request = params.send_tx_request; + + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/1/api/{api_token}/tx", local_var_configuration.base_path, api_token=crate::apis::urlencode(api_token)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = local_var_req_builder.json(&send_tx_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub async fn get_transaction(configuration: &configuration::Configuration, params: GetTransactionParams) -> Result> { + let local_var_configuration = configuration; + + // unbox the parameters + let api_token = params.api_token; + let tx_id = params.tx_id; + + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/1/api/{api_token}/tx/{tx_id}", local_var_configuration.base_path, api_token=crate::apis::urlencode(api_token), tx_id=crate::apis::urlencode(tx_id)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub async fn get_transactions(configuration: &configuration::Configuration, params: GetTransactionsParams) -> Result, Error> { + let local_var_configuration = configuration; + + // unbox the parameters + let api_token = params.api_token; + let status = params.status; + let unsent = params.unsent; + + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/1/api/{api_token}/txs", local_var_configuration.base_path, api_token=crate::apis::urlencode(api_token)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + if let Some(ref local_var_str) = status { + local_var_req_builder = local_var_req_builder.query(&[("status", &local_var_str.to_string())]); + } + if let Some(ref local_var_str) = unsent { + local_var_req_builder = local_var_req_builder.query(&[("unsent", &local_var_str.to_string())]); + } + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + diff --git a/crates/tx-sitter-client/src/apis/service_api.rs b/crates/tx-sitter-client/src/apis/service_api.rs new file mode 100644 index 0000000..e045ffa --- /dev/null +++ b/crates/tx-sitter-client/src/apis/service_api.rs @@ -0,0 +1,55 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + + +use reqwest; +use serde::{Deserialize, Serialize}; +use crate::{apis::ResponseContent, models}; +use super::{Error, configuration}; + + +/// struct for typed errors of method [`health`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum HealthError { + UnknownValue(serde_json::Value), +} + + +pub async fn health(configuration: &configuration::Configuration) -> Result<(), Error> { + let local_var_configuration = configuration; + + // unbox the parameters + + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/health", local_var_configuration.base_path); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + Ok(()) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + diff --git a/crates/tx-sitter-client/src/lib.rs b/crates/tx-sitter-client/src/lib.rs new file mode 100644 index 0000000..e152062 --- /dev/null +++ b/crates/tx-sitter-client/src/lib.rs @@ -0,0 +1,11 @@ +#![allow(unused_imports)] +#![allow(clippy::too_many_arguments)] + +extern crate serde_repr; +extern crate serde; +extern crate serde_json; +extern crate url; +extern crate reqwest; + +pub mod apis; +pub mod models; diff --git a/crates/tx-sitter-client/src/models/create_api_key_response.rs b/crates/tx-sitter-client/src/models/create_api_key_response.rs new file mode 100644 index 0000000..2b1e688 --- /dev/null +++ b/crates/tx-sitter-client/src/models/create_api_key_response.rs @@ -0,0 +1,28 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct CreateApiKeyResponse { + /// Base64 encoded API key + #[serde(rename = "apiKey")] + pub api_key: String, +} + +impl CreateApiKeyResponse { + pub fn new(api_key: String) -> CreateApiKeyResponse { + CreateApiKeyResponse { + api_key, + } + } +} + diff --git a/crates/tx-sitter-client/src/models/create_relayer_request.rs b/crates/tx-sitter-client/src/models/create_relayer_request.rs new file mode 100644 index 0000000..41b039f --- /dev/null +++ b/crates/tx-sitter-client/src/models/create_relayer_request.rs @@ -0,0 +1,32 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct CreateRelayerRequest { + /// New relayer name + #[serde(rename = "name")] + pub name: String, + /// The chain id of the relayer + #[serde(rename = "chainId")] + pub chain_id: i32, +} + +impl CreateRelayerRequest { + pub fn new(name: String, chain_id: i32) -> CreateRelayerRequest { + CreateRelayerRequest { + name, + chain_id, + } + } +} + diff --git a/crates/tx-sitter-client/src/models/create_relayer_response.rs b/crates/tx-sitter-client/src/models/create_relayer_response.rs new file mode 100644 index 0000000..af16c9b --- /dev/null +++ b/crates/tx-sitter-client/src/models/create_relayer_response.rs @@ -0,0 +1,32 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct CreateRelayerResponse { + /// ID of the created relayer + #[serde(rename = "relayerId")] + pub relayer_id: String, + /// Address of the created relayer + #[serde(rename = "address")] + pub address: base_api_types::Address, +} + +impl CreateRelayerResponse { + pub fn new(relayer_id: String, address: base_api_types::Address) -> CreateRelayerResponse { + CreateRelayerResponse { + relayer_id, + address, + } + } +} + diff --git a/crates/tx-sitter-client/src/models/get_tx_response.rs b/crates/tx-sitter-client/src/models/get_tx_response.rs new file mode 100644 index 0000000..973b9d8 --- /dev/null +++ b/crates/tx-sitter-client/src/models/get_tx_response.rs @@ -0,0 +1,52 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct GetTxResponse { + #[serde(rename = "txId")] + pub tx_id: String, + /// Hex encoded ethereum address + #[serde(rename = "to")] + pub to: base_api_types::Address, + #[serde(rename = "data", skip_serializing_if = "Option::is_none")] + pub data: Option, + /// A decimal 256-bit unsigned integer + #[serde(rename = "value")] + pub value: base_api_types::DecimalU256, + /// A decimal 256-bit unsigned integer + #[serde(rename = "gasLimit")] + pub gas_limit: base_api_types::DecimalU256, + #[serde(rename = "nonce")] + pub nonce: i32, + /// A hex encoded 256-bit hash + #[serde(rename = "txHash", skip_serializing_if = "Option::is_none")] + pub tx_hash: Option, + #[serde(rename = "status", skip_serializing_if = "Option::is_none")] + pub status: Option, +} + +impl GetTxResponse { + pub fn new(tx_id: String, to: base_api_types::Address, value: base_api_types::DecimalU256, gas_limit: base_api_types::DecimalU256, nonce: i32) -> GetTxResponse { + GetTxResponse { + tx_id, + to, + data: None, + value, + gas_limit, + nonce, + tx_hash: None, + status: None, + } + } +} + diff --git a/crates/tx-sitter-client/src/models/json_rpc_version.rs b/crates/tx-sitter-client/src/models/json_rpc_version.rs new file mode 100644 index 0000000..cffa4d1 --- /dev/null +++ b/crates/tx-sitter-client/src/models/json_rpc_version.rs @@ -0,0 +1,35 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +/// +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum JsonRpcVersion { + #[serde(rename = "2.0")] + Variant2Period0, + +} + +impl std::fmt::Display for JsonRpcVersion { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Variant2Period0 => write!(f, "2.0"), + } + } +} + +impl Default for JsonRpcVersion { + fn default() -> JsonRpcVersion { + Self::Variant2Period0 + } +} + diff --git a/crates/tx-sitter-client/src/models/mod.rs b/crates/tx-sitter-client/src/models/mod.rs new file mode 100644 index 0000000..75f702f --- /dev/null +++ b/crates/tx-sitter-client/src/models/mod.rs @@ -0,0 +1,30 @@ +pub mod create_api_key_response; +pub use self::create_api_key_response::CreateApiKeyResponse; +pub mod create_relayer_request; +pub use self::create_relayer_request::CreateRelayerRequest; +pub mod create_relayer_response; +pub use self::create_relayer_response::CreateRelayerResponse; +pub mod get_tx_response; +pub use self::get_tx_response::GetTxResponse; +pub mod json_rpc_version; +pub use self::json_rpc_version::JsonRpcVersion; +pub mod network_info; +pub use self::network_info::NetworkInfo; +pub mod new_network_info; +pub use self::new_network_info::NewNetworkInfo; +pub mod relayer_gas_price_limit; +pub use self::relayer_gas_price_limit::RelayerGasPriceLimit; +pub mod relayer_info; +pub use self::relayer_info::RelayerInfo; +pub mod relayer_update; +pub use self::relayer_update::RelayerUpdate; +pub mod rpc_request; +pub use self::rpc_request::RpcRequest; +pub mod send_tx_request; +pub use self::send_tx_request::SendTxRequest; +pub mod send_tx_response; +pub use self::send_tx_response::SendTxResponse; +pub mod transaction_priority; +pub use self::transaction_priority::TransactionPriority; +pub mod tx_status; +pub use self::tx_status::TxStatus; diff --git a/crates/tx-sitter-client/src/models/network_info.rs b/crates/tx-sitter-client/src/models/network_info.rs new file mode 100644 index 0000000..6601b77 --- /dev/null +++ b/crates/tx-sitter-client/src/models/network_info.rs @@ -0,0 +1,36 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct NetworkInfo { + #[serde(rename = "chainId")] + pub chain_id: i32, + #[serde(rename = "name")] + pub name: String, + #[serde(rename = "httpRpc")] + pub http_rpc: String, + #[serde(rename = "wsRpc")] + pub ws_rpc: String, +} + +impl NetworkInfo { + pub fn new(chain_id: i32, name: String, http_rpc: String, ws_rpc: String) -> NetworkInfo { + NetworkInfo { + chain_id, + name, + http_rpc, + ws_rpc, + } + } +} + diff --git a/crates/tx-sitter-client/src/models/new_network_info.rs b/crates/tx-sitter-client/src/models/new_network_info.rs new file mode 100644 index 0000000..dfaa156 --- /dev/null +++ b/crates/tx-sitter-client/src/models/new_network_info.rs @@ -0,0 +1,33 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct NewNetworkInfo { + #[serde(rename = "name")] + pub name: String, + #[serde(rename = "httpRpc")] + pub http_rpc: String, + #[serde(rename = "wsRpc")] + pub ws_rpc: String, +} + +impl NewNetworkInfo { + pub fn new(name: String, http_rpc: String, ws_rpc: String) -> NewNetworkInfo { + NewNetworkInfo { + name, + http_rpc, + ws_rpc, + } + } +} + diff --git a/crates/tx-sitter-client/src/models/relayer_gas_price_limit.rs b/crates/tx-sitter-client/src/models/relayer_gas_price_limit.rs new file mode 100644 index 0000000..5cb8c04 --- /dev/null +++ b/crates/tx-sitter-client/src/models/relayer_gas_price_limit.rs @@ -0,0 +1,31 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct RelayerGasPriceLimit { + /// A decimal 256-bit unsigned integer + #[serde(rename = "value")] + pub value: base_api_types::DecimalU256, + #[serde(rename = "chainId")] + pub chain_id: i64, +} + +impl RelayerGasPriceLimit { + pub fn new(value: base_api_types::DecimalU256, chain_id: i64) -> RelayerGasPriceLimit { + RelayerGasPriceLimit { + value, + chain_id, + } + } +} + diff --git a/crates/tx-sitter-client/src/models/relayer_info.rs b/crates/tx-sitter-client/src/models/relayer_info.rs new file mode 100644 index 0000000..ac7c48f --- /dev/null +++ b/crates/tx-sitter-client/src/models/relayer_info.rs @@ -0,0 +1,58 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct RelayerInfo { + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "name")] + pub name: String, + #[serde(rename = "chainId")] + pub chain_id: i32, + #[serde(rename = "keyId")] + pub key_id: String, + /// Hex encoded ethereum address + #[serde(rename = "address")] + pub address: base_api_types::Address, + #[serde(rename = "nonce")] + pub nonce: i32, + #[serde(rename = "currentNonce")] + pub current_nonce: i32, + #[serde(rename = "maxInflightTxs")] + pub max_inflight_txs: i32, + #[serde(rename = "maxQueuedTxs")] + pub max_queued_txs: i32, + #[serde(rename = "gasPriceLimits")] + pub gas_price_limits: Vec, + #[serde(rename = "enabled")] + pub enabled: bool, +} + +impl RelayerInfo { + pub fn new(id: String, name: String, chain_id: i32, key_id: String, address: base_api_types::Address, nonce: i32, current_nonce: i32, max_inflight_txs: i32, max_queued_txs: i32, gas_price_limits: Vec, enabled: bool) -> RelayerInfo { + RelayerInfo { + id, + name, + chain_id, + key_id, + address, + nonce, + current_nonce, + max_inflight_txs, + max_queued_txs, + gas_price_limits, + enabled, + } + } +} + diff --git a/crates/tx-sitter-client/src/models/relayer_update.rs b/crates/tx-sitter-client/src/models/relayer_update.rs new file mode 100644 index 0000000..613c369 --- /dev/null +++ b/crates/tx-sitter-client/src/models/relayer_update.rs @@ -0,0 +1,39 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct RelayerUpdate { + #[serde(rename = "relayerName", skip_serializing_if = "Option::is_none")] + pub relayer_name: Option, + #[serde(rename = "maxInflightTxs", skip_serializing_if = "Option::is_none")] + pub max_inflight_txs: Option, + #[serde(rename = "maxQueuedTxs", skip_serializing_if = "Option::is_none")] + pub max_queued_txs: Option, + #[serde(rename = "gasPriceLimits", skip_serializing_if = "Option::is_none")] + pub gas_price_limits: Option>, + #[serde(rename = "enabled", skip_serializing_if = "Option::is_none")] + pub enabled: Option, +} + +impl RelayerUpdate { + pub fn new() -> RelayerUpdate { + RelayerUpdate { + relayer_name: None, + max_inflight_txs: None, + max_queued_txs: None, + gas_price_limits: None, + enabled: None, + } + } +} + diff --git a/crates/tx-sitter-client/src/models/rpc_request.rs b/crates/tx-sitter-client/src/models/rpc_request.rs new file mode 100644 index 0000000..5a3eb03 --- /dev/null +++ b/crates/tx-sitter-client/src/models/rpc_request.rs @@ -0,0 +1,36 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct RpcRequest { + #[serde(rename = "id")] + pub id: i32, + #[serde(rename = "method")] + pub method: String, + #[serde(rename = "params", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")] + pub params: Option>, + #[serde(rename = "jsonrpc")] + pub jsonrpc: models::JsonRpcVersion, +} + +impl RpcRequest { + pub fn new(id: i32, method: String, jsonrpc: models::JsonRpcVersion) -> RpcRequest { + RpcRequest { + id, + method, + params: None, + jsonrpc, + } + } +} + diff --git a/crates/tx-sitter-client/src/models/send_tx_request.rs b/crates/tx-sitter-client/src/models/send_tx_request.rs new file mode 100644 index 0000000..795f80d --- /dev/null +++ b/crates/tx-sitter-client/src/models/send_tx_request.rs @@ -0,0 +1,49 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct SendTxRequest { + /// Hex encoded ethereum address + #[serde(rename = "to")] + pub to: base_api_types::Address, + /// Transaction value + #[serde(rename = "value")] + pub value: base_api_types::DecimalU256, + #[serde(rename = "data", skip_serializing_if = "Option::is_none")] + pub data: Option, + /// Transaction gas limit + #[serde(rename = "gasLimit")] + pub gas_limit: base_api_types::DecimalU256, + #[serde(rename = "priority", skip_serializing_if = "Option::is_none")] + pub priority: Option, + /// An optional transaction id. If not provided tx-sitter will generate a UUID. Can be used to provide idempotency for the transaction. + #[serde(rename = "txId", skip_serializing_if = "Option::is_none")] + pub tx_id: Option, + #[serde(rename = "blobs", skip_serializing_if = "Option::is_none")] + pub blobs: Option>>, +} + +impl SendTxRequest { + pub fn new(to: base_api_types::Address, value: base_api_types::DecimalU256, gas_limit: base_api_types::DecimalU256) -> SendTxRequest { + SendTxRequest { + to, + value, + data: None, + gas_limit, + priority: None, + tx_id: None, + blobs: None, + } + } +} + diff --git a/crates/tx-sitter-client/src/models/send_tx_response.rs b/crates/tx-sitter-client/src/models/send_tx_response.rs new file mode 100644 index 0000000..ca7b62d --- /dev/null +++ b/crates/tx-sitter-client/src/models/send_tx_response.rs @@ -0,0 +1,27 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct SendTxResponse { + #[serde(rename = "txId")] + pub tx_id: String, +} + +impl SendTxResponse { + pub fn new(tx_id: String) -> SendTxResponse { + SendTxResponse { + tx_id, + } + } +} + diff --git a/crates/tx-sitter-client/src/models/transaction_priority.rs b/crates/tx-sitter-client/src/models/transaction_priority.rs new file mode 100644 index 0000000..1f94f76 --- /dev/null +++ b/crates/tx-sitter-client/src/models/transaction_priority.rs @@ -0,0 +1,47 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +/// +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum TransactionPriority { + #[serde(rename = "slowest")] + Slowest, + #[serde(rename = "slow")] + Slow, + #[serde(rename = "regular")] + Regular, + #[serde(rename = "fast")] + Fast, + #[serde(rename = "fastest")] + Fastest, + +} + +impl std::fmt::Display for TransactionPriority { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Slowest => write!(f, "slowest"), + Self::Slow => write!(f, "slow"), + Self::Regular => write!(f, "regular"), + Self::Fast => write!(f, "fast"), + Self::Fastest => write!(f, "fastest"), + } + } +} + +impl Default for TransactionPriority { + fn default() -> TransactionPriority { + Self::Slowest + } +} + diff --git a/crates/tx-sitter-client/src/models/tx_status.rs b/crates/tx-sitter-client/src/models/tx_status.rs new file mode 100644 index 0000000..24f0f02 --- /dev/null +++ b/crates/tx-sitter-client/src/models/tx_status.rs @@ -0,0 +1,41 @@ +/* + * Tx Sitter + * + * A transaction relayer service! ## Operating a relayer Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. To see the list of currently added networks use the `GET /1/admin/networks` endpoint. ### 2. Create a relayer A relayer is an abstraction layer on top of a private key stored locally (for testing purposes only!) or using a secrets manager (currently only AWS KMS is supported). To create a relayer use the `POST /1/admin/relayer` endpoint. The data returned will contain a relayer id, make sure to copy it to the clipboard. ### 3. Create an API key By itself a relayer is not very useful. In order to send transactions one must create an API key. To do that use the `POST /1/admin/relayer/:relayer_id/key` endpoint. **Make sure to copy the API key from the response. It's not possible to recover it!** But it's always possible to create a new one. ### 4. Use the API key Once an API keys has been created it's possible to use the relayer api to, among other things, send transactions. You can use the `POST /1/api/:api_token/tx` endpoint to create a transaction. + * + * The version of the OpenAPI document: 0.1.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +/// +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum TxStatus { + #[serde(rename = "pending")] + Pending, + #[serde(rename = "mined")] + Mined, + #[serde(rename = "finalized")] + Finalized, + +} + +impl std::fmt::Display for TxStatus { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Pending => write!(f, "pending"), + Self::Mined => write!(f, "mined"), + Self::Finalized => write!(f, "finalized"), + } + } +} + +impl Default for TxStatus { + fn default() -> TxStatus { + Self::Pending + } +} + diff --git a/src/broadcast_utils.rs b/src/broadcast_utils.rs index 04d206c..ab163d9 100644 --- a/src/broadcast_utils.rs +++ b/src/broadcast_utils.rs @@ -3,7 +3,7 @@ use eyre::ContextCompat; use self::gas_estimation::FeesEstimate; use crate::app::App; -use crate::types::RelayerInfo; +use crate::db::data::RelayerInfo; pub mod gas_estimation; diff --git a/src/client.rs b/src/client.rs deleted file mode 100644 index 6806aa7..0000000 --- a/src/client.rs +++ /dev/null @@ -1,223 +0,0 @@ -use reqwest::Response; -use thiserror::Error; - -use crate::api_key::ApiKey; -use crate::types::{ - CreateApiKeyResponse, CreateRelayerRequest, CreateRelayerResponse, - GetTxResponse, NewNetworkInfo, RelayerUpdate, SendTxRequest, - SendTxResponse, -}; - -pub struct TxSitterClient { - client: reqwest::Client, - url: String, - - credentials: Option<(String, String)>, -} - -#[derive(Debug, Error)] -pub enum ClientError { - #[error("Reqwest error: {0}")] - Reqwest(#[from] reqwest::Error), - - #[error("Serialization error: {0}")] - Serde(#[from] serde_json::Error), - - #[error("API error: {0}")] - TxSitter(reqwest::StatusCode, String), - - #[error("Invalid API key: {0}")] - InvalidApiKey(eyre::Error), -} - -impl TxSitterClient { - pub fn new(url: impl ToString) -> Self { - Self { - client: reqwest::Client::new(), - url: url.to_string(), - credentials: None, - } - } - - pub fn with_credentials( - mut self, - username: impl ToString, - password: impl ToString, - ) -> Self { - self.credentials = Some((username.to_string(), password.to_string())); - self - } - - fn creds(&self) -> (&str, &str) { - self.credentials - .as_ref() - .map(|(u, p)| (u.as_str(), p.as_str())) - .unwrap_or_default() - } - - async fn post(&self, url: &str) -> Result - where - R: serde::de::DeserializeOwned, - { - let (username, password) = self.creds(); - - let response = self - .client - .post(url) - .basic_auth(username, Some(password)) - .send() - .await?; - - let response = Self::validate_response(response).await?; - - Ok(response.json().await?) - } - - async fn json_post( - &self, - url: &str, - body: T, - ) -> Result - where - T: serde::Serialize, - R: serde::de::DeserializeOwned, - { - let (username, password) = self.creds(); - - let response = self - .client - .post(url) - .json(&body) - .basic_auth(username, Some(password)) - .send() - .await?; - - let response = Self::validate_response(response).await?; - - Ok(response.json().await?) - } - - async fn json_get(&self, url: &str) -> Result - where - R: serde::de::DeserializeOwned, - { - let (username, password) = self.creds(); - - let response = self - .client - .get(url) - .basic_auth(username, Some(password)) - .send() - .await?; - - let response = Self::validate_response(response).await?; - - Ok(response.json().await?) - } - - async fn validate_response( - response: Response, - ) -> Result { - let status = response.status(); - if !status.is_success() { - let body: String = response.text().await?; - return Err(ClientError::TxSitter(status, body)); - } - - Ok(response) - } - - pub async fn create_relayer( - &self, - req: &CreateRelayerRequest, - ) -> Result { - self.json_post(&format!("{}/1/admin/relayer", self.url), req) - .await - } - - pub async fn create_relayer_api_key( - &self, - relayer_id: &str, - ) -> Result { - self.post(&format!("{}/1/admin/relayer/{relayer_id}/key", self.url,)) - .await - } - - pub async fn update_relayer( - &self, - relayer_id: &str, - relayer_update: RelayerUpdate, - ) -> Result<(), ClientError> { - let url: &str = &format!("{}/1/admin/relayer/{relayer_id}", self.url); - - let (username, password) = self.creds(); - - let response = self - .client - .post(url) - .json(&relayer_update) - .basic_auth(username, Some(password)) - .send() - .await?; - - let _response = Self::validate_response(response).await?; - - Ok(()) - } - - pub async fn send_tx( - &self, - api_key: &ApiKey, - req: &SendTxRequest, - ) -> Result { - self.json_post( - &format!( - "{}/1/api/{}/tx", - self.url, - api_key.reveal().map_err(ClientError::InvalidApiKey)? - ), - req, - ) - .await - } - - pub async fn get_tx( - &self, - api_key: &ApiKey, - tx_id: &str, - ) -> Result { - self.json_get(&format!( - "{}/1/api/{}/tx/{tx_id}", - self.url, - api_key.reveal().map_err(ClientError::InvalidApiKey)?, - tx_id = tx_id - )) - .await - } - - pub async fn create_network( - &self, - chain_id: u64, - req: &NewNetworkInfo, - ) -> Result<(), ClientError> { - let response = self - .client - .post(&format!("{}/1/admin/network/{}", self.url, chain_id)) - .json(&req) - .send() - .await?; - - Self::validate_response(response).await?; - - Ok(()) - } -} - -impl ClientError { - pub fn tx_sitter_message(&self) -> Option<&str> { - match self { - Self::TxSitter(_, s) => Some(s), - _ => None, - } - } -} diff --git a/src/db.rs b/src/db.rs index c9f7c01..a9c9390 100644 --- a/src/db.rs +++ b/src/db.rs @@ -11,13 +11,13 @@ use tracing::instrument; use crate::broadcast_utils::gas_estimation::FeesEstimate; use crate::config::DatabaseConfig; -use crate::types::wrappers::h256::H256Wrapper; -use crate::types::wrappers::hex_u256::HexU256; -use crate::types::{ - NetworkInfo, RelayerInfo, RelayerUpdate, TransactionPriority, TxStatus, -}; +use crate::db::data::{NetworkInfo, RelayerInfo}; +use crate::db::wrappers::h256::H256Wrapper; +use crate::db::wrappers::hex_u256::HexU256Wrapper; +use crate::types::{RelayerUpdateRequest, TransactionPriority, TxStatus}; pub mod data; +pub mod wrappers; use self::data::{BlockFees, NetworkStats, ReadTxData, RpcKind}; pub use self::data::{TxForEscalation, UnsentTx}; @@ -84,11 +84,11 @@ impl Database { pub async fn update_relayer( &self, id: &str, - update: &RelayerUpdate, + update: &RelayerUpdateRequest, ) -> eyre::Result<()> { let mut tx = self.pool.begin().await?; - let RelayerUpdate { + let RelayerUpdateRequest { relayer_name, max_inflight_txs, max_queued_txs, @@ -277,7 +277,7 @@ impl Database { &self, relayer_id: &str, ) -> eyre::Result { - let gas_limits: Vec<(HexU256,)> = sqlx::query_as( + let gas_limits: Vec<(HexU256Wrapper,)> = sqlx::query_as( r#" SELECT t.gas_limit FROM transactions t @@ -1341,7 +1341,8 @@ mod tests { use postgres_docker_utils::DockerContainerGuard; use super::*; - use crate::types::RelayerGasPriceLimit; + use crate::db::data::RelayerGasPriceLimit; + use crate::types::{RelayerGasPriceLimitResponse, RelayerUpdateRequest}; async fn setup_db() -> eyre::Result<(Database, DockerContainerGuard)> { let db_container = postgres_docker_utils::setup().await?; @@ -1489,11 +1490,11 @@ mod tests { db.update_relayer( relayer_id, - &RelayerUpdate { + &RelayerUpdateRequest { relayer_name: None, max_inflight_txs: Some(10), max_queued_txs: Some(20), - gas_price_limits: Some(vec![RelayerGasPriceLimit { + gas_price_limits: Some(vec![RelayerGasPriceLimitResponse { chain_id: 1, value: U256::from(10_123u64).into(), }]), diff --git a/src/db/data.rs b/src/db/data.rs index b92f1c8..861802c 100644 --- a/src/db/data.rs +++ b/src/db/data.rs @@ -3,9 +3,10 @@ use serde::{Deserialize, Serialize}; use sqlx::prelude::FromRow; use crate::broadcast_utils::gas_estimation::FeesEstimate; -use crate::types::wrappers::address::AddressWrapper; -use crate::types::wrappers::h256::H256Wrapper; -use crate::types::wrappers::hex_u256::HexU256; +use crate::db::wrappers::address::AddressWrapper; +use crate::db::wrappers::decimal_u256::DecimalU256Wrapper; +use crate::db::wrappers::h256::H256Wrapper; +use crate::db::wrappers::hex_u256::HexU256Wrapper; use crate::types::{TransactionPriority, TxStatus}; #[derive(Debug, Clone, FromRow)] @@ -14,8 +15,8 @@ pub struct UnsentTx { pub id: String, pub tx_to: AddressWrapper, pub data: Vec, - pub value: HexU256, - pub gas_limit: HexU256, + pub value: HexU256Wrapper, + pub gas_limit: HexU256Wrapper, pub priority: TransactionPriority, #[sqlx(try_from = "i64")] pub nonce: u64, @@ -31,16 +32,16 @@ pub struct TxForEscalation { pub id: String, pub tx_to: AddressWrapper, pub data: Vec, - pub value: HexU256, - pub gas_limit: HexU256, + pub value: HexU256Wrapper, + pub gas_limit: HexU256Wrapper, #[sqlx(try_from = "i64")] pub nonce: u64, pub blobs: Option>>, pub key_id: String, #[sqlx(try_from = "i64")] pub chain_id: u64, - pub initial_max_fee_per_gas: HexU256, - pub initial_max_priority_fee_per_gas: HexU256, + pub initial_max_fee_per_gas: HexU256Wrapper, + pub initial_max_priority_fee_per_gas: HexU256Wrapper, #[sqlx(try_from = "i64")] pub escalation_count: usize, } @@ -50,8 +51,8 @@ pub struct ReadTxData { pub tx_id: String, pub to: AddressWrapper, pub data: Vec, - pub value: HexU256, - pub gas_limit: HexU256, + pub value: HexU256Wrapper, + pub gas_limit: HexU256Wrapper, #[sqlx(try_from = "i64")] pub nonce: u64, pub blobs: Option>>, @@ -86,3 +87,47 @@ pub enum RpcKind { Http, Ws, } + +#[derive(Debug, Default, Clone, FromRow)] +pub struct NetworkInfo { + #[sqlx(try_from = "i64")] + pub chain_id: u64, + pub name: String, + pub http_rpc: String, + pub ws_rpc: String, +} + +#[derive(Debug, Default, Clone)] +pub struct NewNetworkInfo { + pub name: String, + pub http_rpc: String, + pub ws_rpc: String, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RelayerGasPriceLimit { + pub value: DecimalU256Wrapper, + pub chain_id: i64, +} + +#[derive(Debug, Clone, FromRow)] +pub struct RelayerInfo { + pub id: String, + pub name: String, + #[sqlx(try_from = "i64")] + pub chain_id: u64, + pub key_id: String, + pub address: AddressWrapper, + #[sqlx(try_from = "i64")] + pub nonce: u64, + #[sqlx(try_from = "i64")] + pub current_nonce: u64, + #[sqlx(try_from = "i64")] + pub max_inflight_txs: u64, + #[sqlx(try_from = "i64")] + pub max_queued_txs: u64, + #[sqlx(json)] + pub gas_price_limits: Vec, + pub enabled: bool, +} diff --git a/src/db/wrappers.rs b/src/db/wrappers.rs new file mode 100644 index 0000000..c29d381 --- /dev/null +++ b/src/db/wrappers.rs @@ -0,0 +1,22 @@ +use decimal_u256::DecimalU256Wrapper; +use hex_u256::HexU256Wrapper; + +pub mod address; +pub mod h256; +pub mod hex_bytes; + +// TODO: Remove repeated code in these 2 modules +pub mod decimal_u256; +pub mod hex_u256; + +impl From for DecimalU256Wrapper { + fn from(value: HexU256Wrapper) -> DecimalU256Wrapper { + DecimalU256Wrapper::from(value.0) + } +} + +impl From for HexU256Wrapper { + fn from(value: DecimalU256Wrapper) -> HexU256Wrapper { + HexU256Wrapper::from(value.0) + } +} diff --git a/src/db/wrappers/address.rs b/src/db/wrappers/address.rs new file mode 100644 index 0000000..7ba4377 --- /dev/null +++ b/src/db/wrappers/address.rs @@ -0,0 +1,55 @@ +use ethers::types::Address; +use serde::{Deserialize, Serialize}; +use sqlx::database::HasValueRef; +use sqlx::Database; + +#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(transparent)] +pub struct AddressWrapper(pub Address); + +impl<'r, DB> sqlx::Decode<'r, DB> for AddressWrapper +where + DB: Database, + Vec: sqlx::Decode<'r, DB>, +{ + fn decode( + value: >::ValueRef, + ) -> Result { + let bytes = as sqlx::Decode>::decode(value)?; + + let address = Address::from_slice(&bytes); + + Ok(Self(address)) + } +} + +impl sqlx::Type for AddressWrapper +where + Vec: sqlx::Type, +{ + fn type_info() -> DB::TypeInfo { + as sqlx::Type>::type_info() + } + + fn compatible(ty: &DB::TypeInfo) -> bool { + *ty == Self::type_info() + } +} + +impl From
for AddressWrapper { + fn from(value: Address) -> Self { + Self(value) + } +} + +impl From for AddressWrapper { + fn from(value: base_api_types::Address) -> Self { + Self(value.0) + } +} + +impl From for base_api_types::Address { + fn from(value: AddressWrapper) -> Self { + Self(value.0) + } +} diff --git a/src/db/wrappers/decimal_u256.rs b/src/db/wrappers/decimal_u256.rs new file mode 100644 index 0000000..ccfdb74 --- /dev/null +++ b/src/db/wrappers/decimal_u256.rs @@ -0,0 +1,96 @@ +use std::borrow::Cow; + +use base_api_types::DecimalU256; +use ethers::types::U256; +use serde::{Deserialize, Serialize}; +use sqlx::database::{HasArguments, HasValueRef}; +use sqlx::Database; + +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub struct DecimalU256Wrapper(pub U256); + +impl Serialize for DecimalU256Wrapper { + fn serialize( + &self, + serializer: S, + ) -> Result { + let s = self.0.to_string(); + serializer.serialize_str(&s) + } +} + +impl<'de> Deserialize<'de> for DecimalU256Wrapper { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s: Cow = serde::Deserialize::deserialize(deserializer)?; + + let u256 = U256::from_dec_str(&s).map_err(serde::de::Error::custom)?; + + Ok(Self(u256)) + } +} + +impl<'r, DB> sqlx::Decode<'r, DB> for DecimalU256Wrapper +where + DB: Database, + [u8; 32]: sqlx::Decode<'r, DB>, +{ + fn decode( + value: >::ValueRef, + ) -> Result { + let bytes = <[u8; 32] as sqlx::Decode>::decode(value)?; + + let value = U256::from_big_endian(&bytes); + + Ok(Self(value)) + } +} + +impl sqlx::Type for DecimalU256Wrapper +where + [u8; 32]: sqlx::Type, +{ + fn type_info() -> DB::TypeInfo { + <[u8; 32] as sqlx::Type>::type_info() + } + + fn compatible(ty: &DB::TypeInfo) -> bool { + *ty == Self::type_info() + } +} + +impl<'q, DB> sqlx::Encode<'q, DB> for DecimalU256Wrapper +where + DB: Database, + [u8; 32]: sqlx::Encode<'q, DB>, +{ + fn encode_by_ref( + &self, + buf: &mut >::ArgumentBuffer, + ) -> sqlx::encode::IsNull { + let mut bytes = [0u8; 32]; + self.0.to_big_endian(&mut bytes); + + <[u8; 32] as sqlx::Encode>::encode_by_ref(&bytes, buf) + } +} + +impl From for DecimalU256Wrapper { + fn from(value: U256) -> Self { + Self(value) + } +} + +impl From for DecimalU256Wrapper { + fn from(value: DecimalU256) -> Self { + Self(value.0) + } +} + +impl From for DecimalU256 { + fn from(value: DecimalU256Wrapper) -> Self { + Self(value.0) + } +} diff --git a/src/db/wrappers/h256.rs b/src/db/wrappers/h256.rs new file mode 100644 index 0000000..55b448e --- /dev/null +++ b/src/db/wrappers/h256.rs @@ -0,0 +1,69 @@ +use ethers::types::H256; +use serde::{Deserialize, Serialize}; +use sqlx::database::{HasArguments, HasValueRef}; +use sqlx::postgres::{PgHasArrayType, PgTypeInfo}; +use sqlx::Database; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(transparent)] +pub struct H256Wrapper(pub H256); + +impl<'r, DB> sqlx::Decode<'r, DB> for H256Wrapper +where + DB: Database, + [u8; 32]: sqlx::Decode<'r, DB>, +{ + fn decode( + value: >::ValueRef, + ) -> Result { + let bytes = <[u8; 32] as sqlx::Decode>::decode(value)?; + + let value = H256::from_slice(&bytes); + + Ok(Self(value)) + } +} + +impl<'q, DB> sqlx::Encode<'q, DB> for H256Wrapper +where + DB: Database, + [u8; 32]: sqlx::Encode<'q, DB>, +{ + fn encode_by_ref( + &self, + buf: &mut >::ArgumentBuffer, + ) -> sqlx::encode::IsNull { + <[u8; 32] as sqlx::Encode>::encode_by_ref(&self.0 .0, buf) + } +} + +impl PgHasArrayType for H256Wrapper { + fn array_type_info() -> PgTypeInfo { + <[u8; 32] as PgHasArrayType>::array_type_info() + } +} + +impl sqlx::Type for H256Wrapper +where + [u8; 32]: sqlx::Type, +{ + fn type_info() -> DB::TypeInfo { + <[u8; 32] as sqlx::Type>::type_info() + } + + fn compatible(ty: &DB::TypeInfo) -> bool { + *ty == Self::type_info() + } +} + +impl From for H256Wrapper { + fn from(value: base_api_types::H256) -> Self { + Self(value.0) + } +} + +impl From for base_api_types::H256 { + fn from(value: H256Wrapper) -> Self { + Self(value.0) + } +} diff --git a/src/db/wrappers/hex_bytes.rs b/src/db/wrappers/hex_bytes.rs new file mode 100644 index 0000000..eaffaea --- /dev/null +++ b/src/db/wrappers/hex_bytes.rs @@ -0,0 +1,31 @@ +use base_api_types::HexBytes; +use ethers::types::Bytes; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(transparent)] +pub struct HexBytesWrapper(pub Bytes); + +impl From for HexBytesWrapper { + fn from(value: HexBytes) -> Self { + Self(value.0) + } +} + +impl From for HexBytes { + fn from(value: HexBytesWrapper) -> Self { + Self(value.0) + } +} + +impl From for HexBytesWrapper { + fn from(value: Bytes) -> Self { + Self(value) + } +} + +impl From> for HexBytesWrapper { + fn from(value: Vec) -> Self { + Self(Bytes::from(value)) + } +} diff --git a/src/db/wrappers/hex_u256.rs b/src/db/wrappers/hex_u256.rs new file mode 100644 index 0000000..d026a08 --- /dev/null +++ b/src/db/wrappers/hex_u256.rs @@ -0,0 +1,78 @@ +use base_api_types::{DecimalU256, HexU256}; +use ethers::types::U256; +use serde::{Deserialize, Serialize}; +use sqlx::database::{HasArguments, HasValueRef}; +use sqlx::Database; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(transparent)] +pub struct HexU256Wrapper(pub U256); + +impl<'r, DB> sqlx::Decode<'r, DB> for HexU256Wrapper +where + DB: Database, + [u8; 32]: sqlx::Decode<'r, DB>, +{ + fn decode( + value: >::ValueRef, + ) -> Result { + let bytes = <[u8; 32] as sqlx::Decode>::decode(value)?; + + let value = U256::from_big_endian(&bytes); + + Ok(Self(value)) + } +} + +impl sqlx::Type for HexU256Wrapper +where + [u8; 32]: sqlx::Type, +{ + fn type_info() -> DB::TypeInfo { + <[u8; 32] as sqlx::Type>::type_info() + } + + fn compatible(ty: &DB::TypeInfo) -> bool { + *ty == Self::type_info() + } +} + +impl<'q, DB> sqlx::Encode<'q, DB> for HexU256Wrapper +where + DB: Database, + [u8; 32]: sqlx::Encode<'q, DB>, +{ + fn encode_by_ref( + &self, + buf: &mut >::ArgumentBuffer, + ) -> sqlx::encode::IsNull { + let mut bytes = [0u8; 32]; + self.0.to_big_endian(&mut bytes); + + <[u8; 32] as sqlx::Encode>::encode_by_ref(&bytes, buf) + } +} + +impl From for HexU256Wrapper { + fn from(value: U256) -> Self { + Self(value) + } +} + +impl From for HexU256Wrapper { + fn from(value: HexU256) -> Self { + Self(value.0) + } +} + +impl From for HexU256 { + fn from(value: HexU256Wrapper) -> Self { + Self(value.0) + } +} + +impl From for DecimalU256 { + fn from(value: HexU256Wrapper) -> Self { + Self(value.0) + } +} diff --git a/src/lib.rs b/src/lib.rs index abb94b0..ae8dbff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ pub mod api_key; pub mod app; pub mod aws; pub mod broadcast_utils; -pub mod client; pub mod config; pub mod db; pub mod keys; diff --git a/src/server.rs b/src/server.rs index 91878eb..5777d52 100644 --- a/src/server.rs +++ b/src/server.rs @@ -12,7 +12,7 @@ use poem::web::{Data, LocalAddr}; use poem::{EndpointExt, Result, Route}; use poem_openapi::param::{Path, Query}; use poem_openapi::payload::Json; -use poem_openapi::{ApiResponse, OpenApi, OpenApiService}; +use poem_openapi::{ApiResponse, OpenApi, OpenApiService, Tags}; use security::BasicAuth; use serde_json::Value; use url::Url; @@ -23,20 +23,32 @@ use crate::db::CreateResult; use crate::service::Service; use crate::task_runner::TaskRunner; use crate::types::{ - CreateApiKeyResponse, CreateRelayerRequest, CreateRelayerResponse, - GetTxResponse, NetworkInfo, NewNetworkInfo, RelayerInfo, RelayerUpdate, - RpcRequest, SendTxRequest, SendTxResponse, TxStatus, + CreateApiKeyResponse, CreateNetworkRequest, CreateRelayerRequest, + CreateRelayerResponse, GetTxResponse, NetworkResponse, RelayerResponse, + RelayerUpdateRequest, RpcRequest, SendTxRequest, SendTxResponse, TxStatus, }; mod security; mod trace_middleware; +#[derive(Tags)] +enum OpenAPITags { + AdminV1, + RelayerV1, + Service, +} + struct AdminApi; #[OpenApi(prefix_path = "/1/admin/")] impl AdminApi { /// Create Relayer - #[oai(path = "/relayer", method = "post")] + #[oai( + path = "/relayer", + method = "post", + operation_id = "create_relayer", + tag = "OpenAPITags::AdminV1" + )] async fn create_relayer( &self, basic_auth: BasicAuth, @@ -69,33 +81,43 @@ impl AdminApi { } /// Get Relayers - #[oai(path = "/relayers", method = "get")] + #[oai( + path = "/relayers", + method = "get", + operation_id = "get_relayers", + tag = "OpenAPITags::AdminV1" + )] async fn get_relayers( &self, basic_auth: BasicAuth, Data(app): Data<&Arc>, - ) -> Result>> { + ) -> Result>> { basic_auth.validate(app).await?; let relayer_info = app.db.get_relayers().await?; - Ok(Json(relayer_info)) + Ok(Json(relayer_info.into_iter().map(|v| v.into()).collect())) } /// Get Relayer - #[oai(path = "/relayer/:relayer_id", method = "get")] + #[oai( + path = "/relayer/:relayer_id", + method = "get", + operation_id = "get_relayer", + tag = "OpenAPITags::AdminV1" + )] async fn get_relayer( &self, basic_auth: BasicAuth, Data(app): Data<&Arc>, Path(relayer_id): Path, - ) -> Result> { + ) -> Result> { basic_auth.validate(app).await?; let relayer_info = app.db.get_relayer(&relayer_id).await?; match relayer_info { - Some(relayer_info) => Ok(Json(relayer_info)), + Some(relayer_info) => Ok(Json(relayer_info.into())), None => Err(poem::error::Error::from_string( "Relayer not found".to_string(), StatusCode::NOT_FOUND, @@ -104,13 +126,18 @@ impl AdminApi { } /// Update Relayer - #[oai(path = "/relayer/:relayer_id", method = "post")] + #[oai( + path = "/relayer/:relayer_id", + method = "post", + operation_id = "update_relayer", + tag = "OpenAPITags::AdminV1" + )] async fn update_relayer( &self, basic_auth: BasicAuth, Data(app): Data<&Arc>, Path(relayer_id): Path, - Json(req): Json, + Json(req): Json, ) -> Result<()> { basic_auth.validate(app).await?; @@ -122,7 +149,12 @@ impl AdminApi { /// Reset Relayer transactions /// /// Purges unsent transactions, useful for unstucking the relayer - #[oai(path = "/relayer/:relayer_id/reset", method = "post")] + #[oai( + path = "/relayer/:relayer_id/reset", + method = "post", + operation_id = "reset_relayer", + tag = "OpenAPITags::AdminV1" + )] async fn purge_unsent_txs( &self, basic_auth: BasicAuth, @@ -137,7 +169,12 @@ impl AdminApi { } /// Create Relayer API Key - #[oai(path = "/relayer/:relayer_id/key", method = "post")] + #[oai( + path = "/relayer/:relayer_id/key", + method = "post", + operation_id = "relayer_create_api_key", + tag = "OpenAPITags::AdminV1" + )] async fn create_relayer_api_key( &self, basic_auth: BasicAuth, @@ -156,13 +193,18 @@ impl AdminApi { } /// Create Network - #[oai(path = "/network/:chain_id", method = "post")] + #[oai( + path = "/network/:chain_id", + method = "post", + operation_id = "create_network", + tag = "OpenAPITags::AdminV1" + )] async fn create_network( &self, basic_auth: BasicAuth, Data(app): Data<&Arc>, Path(chain_id): Path, - Json(network): Json, + Json(network): Json, ) -> Result<()> { basic_auth.validate(app).await?; @@ -192,17 +234,22 @@ impl AdminApi { } /// Get Networks - #[oai(path = "/networks", method = "get")] + #[oai( + path = "/networks", + method = "get", + operation_id = "get_networks", + tag = "OpenAPITags::AdminV1" + )] async fn list_networks( &self, basic_auth: BasicAuth, Data(app): Data<&Arc>, - ) -> Result>> { + ) -> Result>> { basic_auth.validate(app).await?; let networks = app.db.get_networks().await?; - Ok(Json(networks)) + Ok(Json(networks.into_iter().map(|v| v.into()).collect())) } } @@ -211,7 +258,12 @@ struct RelayerApi; #[OpenApi(prefix_path = "/1/api/")] impl RelayerApi { /// Send Transaction - #[oai(path = "/:api_token/tx", method = "post")] + #[oai( + path = "/:api_token/tx", + method = "post", + operation_id = "create_transaction", + tag = "OpenAPITags::RelayerV1" + )] async fn send_tx( &self, Data(app): Data<&Arc>, @@ -312,7 +364,12 @@ impl RelayerApi { } /// Get Transaction - #[oai(path = "/:api_token/tx/:tx_id", method = "get")] + #[oai( + path = "/:api_token/tx/:tx_id", + method = "get", + operation_id = "get_transaction", + tag = "OpenAPITags::RelayerV1" + )] async fn get_tx( &self, Data(app): Data<&Arc>, @@ -336,7 +393,7 @@ impl RelayerApi { let get_tx_response = GetTxResponse { tx_id: tx.tx_id, - to: tx.to, + to: tx.to.into(), data: if tx.data.is_empty() { None } else { @@ -345,7 +402,7 @@ impl RelayerApi { value: tx.value.into(), gas_limit: tx.gas_limit.into(), nonce: tx.nonce, - tx_hash: tx.tx_hash, + tx_hash: tx.tx_hash.map(|v| v.into()), status: tx.status, }; @@ -353,7 +410,12 @@ impl RelayerApi { } /// Get Transactions - #[oai(path = "/:api_token/txs", method = "get")] + #[oai( + path = "/:api_token/txs", + method = "get", + operation_id = "get_transactions", + tag = "OpenAPITags::RelayerV1" + )] async fn get_txs( &self, Data(app): Data<&Arc>, @@ -384,7 +446,7 @@ impl RelayerApi { .into_iter() .map(|tx| GetTxResponse { tx_id: tx.tx_id, - to: tx.to, + to: tx.to.into(), data: if tx.data.is_empty() { None } else { @@ -393,7 +455,7 @@ impl RelayerApi { value: tx.value.into(), gas_limit: tx.gas_limit.into(), nonce: tx.nonce, - tx_hash: tx.tx_hash, + tx_hash: tx.tx_hash.map(|v| v.into()), status: tx.status, }) .collect(); @@ -402,7 +464,12 @@ impl RelayerApi { } /// Relayer RPC - #[oai(path = "/:api_token/rpc", method = "post")] + #[oai( + path = "/:api_token/rpc", + method = "post", + operation_id = "call_rpc", + tag = "OpenAPITags::RelayerV1" + )] async fn relayer_rpc( &self, Data(app): Data<&Arc>, @@ -453,7 +520,12 @@ enum ServiceResponse { #[OpenApi] impl ServiceApi { /// Health - #[oai(path = "/health", method = "get")] + #[oai( + path = "/health", + method = "get", + operation_id = "health", + tag = "OpenAPITags::Service" + )] async fn health(&self) -> ServiceResponse { ServiceResponse::Healthy } diff --git a/src/server/description.md b/src/server/description.md index da9f44f..1e0938e 100644 --- a/src/server/description.md +++ b/src/server/description.md @@ -1,7 +1,7 @@ A transaction relayer service! ## Operating a relayer -Below is a guide on using this service. Note that septs 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. +Below is a guide on using this service. Note that steps 1 through 4 require authentication using HTTP Basic auth. Using swagger explorer make sure to click the authorize button and use the correct credentials. Default dev creds are `admin:admin`. ### 1. Setup a network tx-sitter keeps track of supported networks in its internal database. In order to be able to create any relayers at least one network must be present. To add a network use the `POST /1/admin/networks/:chain_id` endpoint. diff --git a/src/tasks/escalate.rs b/src/tasks/escalate.rs index c863d2a..b81b04e 100644 --- a/src/tasks/escalate.rs +++ b/src/tasks/escalate.rs @@ -11,8 +11,8 @@ use futures::StreamExt; use crate::app::App; use crate::broadcast_utils::should_send_relayer_transactions; +use crate::db::data::RelayerInfo; use crate::db::TxForEscalation; -use crate::types::RelayerInfo; pub async fn escalate_txs_task(app: Arc) -> eyre::Result<()> { loop { diff --git a/src/tasks/index.rs b/src/tasks/index.rs index bb3854f..c661824 100644 --- a/src/tasks/index.rs +++ b/src/tasks/index.rs @@ -12,7 +12,7 @@ use crate::app::App; use crate::broadcast_utils::gas_estimation::{ estimate_percentile_fees, FeesEstimate, }; -use crate::types::RelayerInfo; +use crate::db::data::RelayerInfo; const BLOCK_FEE_HISTORY_SIZE: usize = 10; const FEE_PERCENTILES: [f64; 5] = [5.0, 25.0, 50.0, 75.0, 95.0]; diff --git a/src/types.rs b/src/types.rs index c56e4b1..9e15588 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,15 +1,10 @@ +use base_api_types::{Address, DecimalU256, HexBytes, H256}; use poem_openapi::{Enum, Object}; use serde::{Deserialize, Serialize}; use serde_json::Value; -use sqlx::prelude::FromRow; -use wrappers::address::AddressWrapper; -use wrappers::decimal_u256::DecimalU256; -use wrappers::h256::H256Wrapper; -use wrappers::hex_bytes::HexBytes; use crate::api_key::ApiKey; - -pub mod wrappers; +use crate::db::data::{NetworkInfo, RelayerGasPriceLimit, RelayerInfo}; #[derive( Deserialize, Serialize, Debug, Clone, Copy, Default, sqlx::Type, Enum, @@ -37,33 +32,49 @@ impl TransactionPriority { } } -#[derive(Deserialize, Serialize, Debug, Clone, FromRow, Object)] +#[derive(Deserialize, Serialize, Debug, Clone, Object)] #[serde(rename_all = "camelCase")] #[oai(rename_all = "camelCase")] -pub struct RelayerInfo { +pub struct RelayerResponse { pub id: String, pub name: String, - #[sqlx(try_from = "i64")] pub chain_id: u64, pub key_id: String, - pub address: AddressWrapper, - #[sqlx(try_from = "i64")] + pub address: Address, pub nonce: u64, - #[sqlx(try_from = "i64")] pub current_nonce: u64, - #[sqlx(try_from = "i64")] pub max_inflight_txs: u64, - #[sqlx(try_from = "i64")] pub max_queued_txs: u64, - #[sqlx(json)] - pub gas_price_limits: Vec, + pub gas_price_limits: Vec, pub enabled: bool, } -#[derive(Deserialize, Serialize, Debug, Clone, Default, Object)] +impl From for RelayerResponse { + fn from(value: RelayerInfo) -> Self { + Self { + id: value.id, + name: value.name, + chain_id: value.chain_id, + key_id: value.key_id, + address: value.address.into(), + nonce: value.nonce, + current_nonce: value.current_nonce, + max_inflight_txs: value.max_inflight_txs, + max_queued_txs: value.max_queued_txs, + gas_price_limits: value + .gas_price_limits + .into_iter() + .map(|v| v.into()) + .collect(), + enabled: value.enabled, + } + } +} + +#[derive(Deserialize, Serialize, Debug, Object)] #[serde(rename_all = "camelCase")] #[oai(rename_all = "camelCase")] -pub struct RelayerUpdate { +pub struct RelayerUpdateRequest { #[serde(default)] pub relayer_name: Option, #[serde(default)] @@ -71,19 +82,28 @@ pub struct RelayerUpdate { #[serde(default)] pub max_queued_txs: Option, #[serde(default)] - pub gas_price_limits: Option>, + pub gas_price_limits: Option>, #[serde(default)] pub enabled: Option, } -#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Object)] +#[derive(Deserialize, Serialize, Debug, Clone, Object)] #[serde(rename_all = "camelCase")] #[oai(rename_all = "camelCase")] -pub struct RelayerGasPriceLimit { +pub struct RelayerGasPriceLimitResponse { pub value: DecimalU256, pub chain_id: i64, } +impl From for RelayerGasPriceLimitResponse { + fn from(value: RelayerGasPriceLimit) -> Self { + Self { + value: value.value.into(), + chain_id: value.chain_id, + } + } +} + #[derive(Debug, Serialize, Deserialize, Object)] #[serde(rename_all = "camelCase")] #[oai(rename_all = "camelCase")] @@ -91,26 +111,36 @@ pub struct CreateApiKeyResponse { pub api_key: ApiKey, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Object)] +#[derive(Debug, Serialize, Deserialize, Object)] #[serde(rename_all = "camelCase")] #[oai(rename_all = "camelCase")] -pub struct NewNetworkInfo { +pub struct CreateNetworkRequest { pub name: String, pub http_rpc: String, pub ws_rpc: String, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, FromRow, Object)] +#[derive(Debug, Serialize, Deserialize, Object)] #[serde(rename_all = "camelCase")] #[oai(rename_all = "camelCase")] -pub struct NetworkInfo { - #[sqlx(try_from = "i64")] +pub struct NetworkResponse { pub chain_id: u64, pub name: String, pub http_rpc: String, pub ws_rpc: String, } +impl From for NetworkResponse { + fn from(value: NetworkInfo) -> Self { + Self { + chain_id: value.chain_id, + name: value.name, + http_rpc: value.http_rpc, + ws_rpc: value.ws_rpc, + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize, Object)] #[serde(rename_all = "camelCase")] #[oai(rename_all = "camelCase")] @@ -128,14 +158,14 @@ pub struct CreateRelayerResponse { /// ID of the created relayer pub relayer_id: String, /// Address of the created relayer - pub address: AddressWrapper, + pub address: Address, } #[derive(Debug, Default, Clone, Serialize, Deserialize, Object)] #[serde(rename_all = "camelCase")] #[oai(rename_all = "camelCase")] pub struct SendTxRequest { - pub to: AddressWrapper, + pub to: Address, /// Transaction value pub value: DecimalU256, #[serde(default)] @@ -185,7 +215,7 @@ pub struct SendTxResponse { #[oai(rename_all = "camelCase")] pub struct GetTxResponse { pub tx_id: String, - pub to: AddressWrapper, + pub to: Address, #[serde(default, skip_serializing_if = "Option::is_none")] pub data: Option, pub value: DecimalU256, @@ -194,7 +224,7 @@ pub struct GetTxResponse { // Sent tx data #[serde(default, skip_serializing_if = "Option::is_none")] - pub tx_hash: Option, + pub tx_hash: Option, #[serde(default)] #[oai(default)] pub status: Option, @@ -251,36 +281,6 @@ impl TxStatus { } } -impl RelayerUpdate { - pub fn with_relayer_name(mut self, relayer_name: String) -> Self { - self.relayer_name = Some(relayer_name); - self - } - - pub fn with_max_inflight_txs(mut self, max_inflight_txs: u64) -> Self { - self.max_inflight_txs = Some(max_inflight_txs); - self - } - - pub fn with_max_queued_txs(mut self, max_queued_txs: u64) -> Self { - self.max_queued_txs = Some(max_queued_txs); - self - } - - pub fn with_gas_price_limits( - mut self, - gas_price_limits: Vec, - ) -> Self { - self.gas_price_limits = Some(gas_price_limits); - self - } - - pub fn with_enabled(mut self, enabled: bool) -> Self { - self.enabled = Some(enabled); - self - } -} - #[cfg(test)] mod tests { use ethers::types::{Address, U256}; @@ -289,18 +289,18 @@ mod tests { use super::*; #[test] - fn relayer_info_serialize() { - let info = RelayerInfo { + fn relayer_response_serialize() { + let info = RelayerResponse { id: "id".to_string(), name: "name".to_string(), chain_id: 1, key_id: "key_id".to_string(), - address: AddressWrapper(Address::zero()), + address: Address::zero().into(), nonce: 0, current_nonce: 0, max_inflight_txs: 0, max_queued_txs: 0, - gas_price_limits: vec![RelayerGasPriceLimit { + gas_price_limits: vec![RelayerGasPriceLimitResponse { value: U256::zero().into(), chain_id: 1, }], @@ -338,7 +338,7 @@ mod tests { let value: U256 = parse_units("1", "ether").unwrap().into(); let request = SendTxRequest { - to: AddressWrapper(Address::zero()), + to: Address(Address::zero()), value: value.into(), data: Some(HexBytes::from(vec![0])), gas_limit: U256::zero().into(), diff --git a/src/types/wrappers.rs b/src/types/wrappers.rs deleted file mode 100644 index acff1d0..0000000 --- a/src/types/wrappers.rs +++ /dev/null @@ -1,22 +0,0 @@ -use decimal_u256::DecimalU256; -use hex_u256::HexU256; - -pub mod address; -pub mod h256; -pub mod hex_bytes; - -// TODO: Remove repeated code in these 2 modules -pub mod decimal_u256; -pub mod hex_u256; - -impl From for DecimalU256 { - fn from(value: HexU256) -> DecimalU256 { - DecimalU256::from(value.0) - } -} - -impl From for HexU256 { - fn from(value: DecimalU256) -> HexU256 { - HexU256::from(value.0) - } -} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index b6e007f..31c5367 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -32,12 +32,8 @@ pub mod prelude { pub use ethers::utils::parse_units; pub use futures::stream::FuturesUnordered; pub use futures::StreamExt; - pub use tx_sitter::api_key::ApiKey; - pub use tx_sitter::client::TxSitterClient; - pub use tx_sitter::types::{ - CreateApiKeyResponse, CreateRelayerRequest, CreateRelayerResponse, - SendTxRequest, - }; + pub use tx_sitter_client::apis::configuration::Configuration; + pub use tx_sitter_client::models::*; pub use url::Url; pub use super::*; diff --git a/tests/common/service_builder.rs b/tests/common/service_builder.rs index ed80d22..05c428e 100644 --- a/tests/common/service_builder.rs +++ b/tests/common/service_builder.rs @@ -3,12 +3,12 @@ use std::time::Duration; use ethers::utils::AnvilInstance; use tx_sitter::api_key::ApiKey; -use tx_sitter::client::TxSitterClient; use tx_sitter::config::{ Config, DatabaseConfig, KeysConfig, LocalKeysConfig, Predefined, PredefinedNetwork, PredefinedRelayer, ServerConfig, TxSitterConfig, }; use tx_sitter::service::Service; +use tx_sitter_client::apis::configuration::Configuration; use super::prelude::{ DEFAULT_ANVIL_CHAIN_ID, DEFAULT_ANVIL_PRIVATE_KEY, DEFAULT_RELAYER_ID, @@ -50,7 +50,7 @@ impl ServiceBuilder { self, anvil: &AnvilInstance, db_url: &str, - ) -> eyre::Result<(Service, TxSitterClient)> { + ) -> eyre::Result<(Service, Configuration)> { let anvil_private_key = hex::encode(DEFAULT_ANVIL_PRIVATE_KEY); let config = Config { @@ -91,9 +91,6 @@ impl ServiceBuilder { let service = Service::new(config).await?; - let client = - TxSitterClient::new(format!("http://{}", service.local_addr())); - // Awaits for estimates to be ready let mut are_estimates_ready = false; for _ in 0..30 { @@ -110,6 +107,12 @@ impl ServiceBuilder { eyre::bail!("Estimates were not ready!"); } - Ok((service, client)) + let client_config = + tx_sitter_client::apis::configuration::ConfigurationBuilder::new() + .base_path(format!("http://{}", service.local_addr())) + .basic_auth("".to_string(), Some("".to_string())) + .build(); + + Ok((service, client_config)) } } diff --git a/tests/create_relayer.rs b/tests/create_relayer.rs index 17a8233..5b8fd9e 100644 --- a/tests/create_relayer.rs +++ b/tests/create_relayer.rs @@ -1,5 +1,7 @@ mod common; +use tx_sitter_client::apis::admin_v1_api::CreateRelayerParams; + use crate::common::prelude::*; #[tokio::test] @@ -12,11 +14,16 @@ async fn create_relayer() -> eyre::Result<()> { let (_service, client) = ServiceBuilder::default().build(&anvil, &db_url).await?; - let CreateRelayerResponse { .. } = client - .create_relayer(&CreateRelayerRequest { - name: "Test relayer".to_string(), - chain_id: DEFAULT_ANVIL_CHAIN_ID, - }) + let CreateRelayerResponse { .. } = + tx_sitter_client::apis::admin_v1_api::create_relayer( + &client, + CreateRelayerParams { + create_relayer_request: CreateRelayerRequest::new( + "Test relayer".to_string(), + DEFAULT_ANVIL_CHAIN_ID as i32, + ), + }, + ) .await?; Ok(()) diff --git a/tests/disabled_relayer.rs b/tests/disabled_relayer.rs index acd05d8..f6f77fd 100644 --- a/tests/disabled_relayer.rs +++ b/tests/disabled_relayer.rs @@ -1,6 +1,9 @@ mod common; -use tx_sitter::types::RelayerUpdate; +use tx_sitter_client::apis::admin_v1_api::{ + CreateRelayerParams, RelayerCreateApiKeyParams, UpdateRelayerParams, +}; +use tx_sitter_client::apis::relayer_v1_api::CreateTransactionParams; use crate::common::prelude::*; @@ -15,37 +18,55 @@ async fn disabled_relayer() -> eyre::Result<()> { ServiceBuilder::default().build(&anvil, &db_url).await?; tracing::info!("Creating relayer"); - let CreateRelayerResponse { relayer_id, .. } = client - .create_relayer(&CreateRelayerRequest { - name: "Test relayer".to_string(), - chain_id: DEFAULT_ANVIL_CHAIN_ID, - }) + let CreateRelayerResponse { relayer_id, .. } = + tx_sitter_client::apis::admin_v1_api::create_relayer( + &client, + CreateRelayerParams { + create_relayer_request: CreateRelayerRequest::new( + "Test relayer".to_string(), + DEFAULT_ANVIL_CHAIN_ID as i32, + ), + }, + ) .await?; tracing::info!("Creating API key"); let CreateApiKeyResponse { api_key } = - client.create_relayer_api_key(&relayer_id).await?; - - tracing::info!("Disabling relayer"); - client - .update_relayer( - &relayer_id, - RelayerUpdate::default().with_enabled(false), + tx_sitter_client::apis::admin_v1_api::relayer_create_api_key( + &client, + RelayerCreateApiKeyParams { + relayer_id: relayer_id.clone(), + }, ) .await?; + tracing::info!("Disabling relayer"); + tx_sitter_client::apis::admin_v1_api::update_relayer( + &client, + UpdateRelayerParams { + relayer_id: relayer_id.clone(), + relayer_update: RelayerUpdate { + enabled: Some(false), + ..Default::default() + }, + }, + ) + .await?; + let value: U256 = parse_units("1", "ether")?.into(); - let response = client - .send_tx( - &api_key, - &SendTxRequest { + let response = tx_sitter_client::apis::relayer_v1_api::create_transaction( + &client, + CreateTransactionParams { + api_token: api_key.clone(), + send_tx_request: SendTxRequest { to: ARBITRARY_ADDRESS.into(), value: value.into(), gas_limit: U256::from(21_000).into(), ..Default::default() }, - ) - .await; + }, + ) + .await; assert!(response.is_err()); diff --git a/tests/escalation.rs b/tests/escalation.rs index 407a6ae..96d0b5d 100644 --- a/tests/escalation.rs +++ b/tests/escalation.rs @@ -1,5 +1,11 @@ mod common; +use tx_sitter_client::apis::admin_v1_api::RelayerCreateApiKeyParams; +use tx_sitter_client::apis::configuration::Configuration; +use tx_sitter_client::apis::relayer_v1_api::{ + CreateTransactionParams, GetTransactionParams, +}; + use crate::common::prelude::*; const ESCALATION_INTERVAL: Duration = Duration::from_secs(2); @@ -21,23 +27,30 @@ async fn escalation() -> eyre::Result<()> { .await?; let CreateApiKeyResponse { api_key } = - client.create_relayer_api_key(DEFAULT_RELAYER_ID).await?; - + tx_sitter_client::apis::admin_v1_api::relayer_create_api_key( + &client, + RelayerCreateApiKeyParams { + relayer_id: DEFAULT_RELAYER_ID.to_string(), + }, + ) + .await?; let provider = setup_provider(anvil.endpoint()).await?; // Send a transaction let value: U256 = parse_units("1", "ether")?.into(); - let tx = client - .send_tx( - &api_key, - &SendTxRequest { + let tx = tx_sitter_client::apis::relayer_v1_api::create_transaction( + &client, + CreateTransactionParams { + api_token: api_key.clone(), + send_tx_request: SendTxRequest { to: ARBITRARY_ADDRESS.into(), value: value.into(), gas_limit: U256::from(21_000).into(), ..Default::default() }, - ) - .await?; + }, + ) + .await?; let initial_tx_hash = get_tx_hash(&client, &api_key, &tx.tx_id).await?; @@ -70,12 +83,19 @@ async fn await_balance( } async fn get_tx_hash( - client: &TxSitterClient, - api_key: &ApiKey, + client: &Configuration, + api_key: &str, tx_id: &str, ) -> eyre::Result { loop { - let tx = client.get_tx(api_key, tx_id).await?; + let tx = tx_sitter_client::apis::relayer_v1_api::get_transaction( + client, + GetTransactionParams { + api_token: api_key.to_owned(), + tx_id: tx_id.to_owned(), + }, + ) + .await?; if let Some(tx_hash) = tx.tx_hash { return Ok(tx_hash.0); diff --git a/tests/reorg.rs b/tests/reorg.rs index 32973eb..8f32526 100644 --- a/tests/reorg.rs +++ b/tests/reorg.rs @@ -1,5 +1,8 @@ mod common; +use tx_sitter_client::apis::admin_v1_api::RelayerCreateApiKeyParams; +use tx_sitter_client::apis::relayer_v1_api::CreateTransactionParams; + use crate::common::prelude::*; #[tokio::test] @@ -16,25 +19,33 @@ async fn reorg() -> eyre::Result<()> { .await?; let CreateApiKeyResponse { api_key } = - client.create_relayer_api_key(DEFAULT_RELAYER_ID).await?; + tx_sitter_client::apis::admin_v1_api::relayer_create_api_key( + &client, + RelayerCreateApiKeyParams { + relayer_id: DEFAULT_RELAYER_ID.to_string(), + }, + ) + .await?; let provider = setup_provider(anvil.endpoint()).await?; // Send a transaction let value: U256 = parse_units("1", "ether")?.into(); - client - .send_tx( - &api_key, - &SendTxRequest { + tx_sitter_client::apis::relayer_v1_api::create_transaction( + &client, + CreateTransactionParams { + api_token: api_key.clone(), + send_tx_request: SendTxRequest { to: ARBITRARY_ADDRESS.into(), value: value.into(), gas_limit: U256::from(21_000).into(), ..Default::default() }, - ) - .await?; + }, + ) + .await?; - await_balance(&provider, value).await?; + await_balance(&provider, value, ARBITRARY_ADDRESS).await?; // Drop anvil to simulate a reorg tracing::warn!("Dropping anvil & restarting at port {anvil_port}"); @@ -43,32 +54,7 @@ async fn reorg() -> eyre::Result<()> { let anvil = AnvilBuilder::default().port(anvil_port).spawn().await?; let provider = setup_provider(anvil.endpoint()).await?; - await_balance(&provider, value).await?; + await_balance(&provider, value, ARBITRARY_ADDRESS).await?; Ok(()) } - -async fn await_balance( - provider: &Provider, - value: U256, -) -> eyre::Result<()> { - for _ in 0..24 { - let balance = match provider.get_balance(ARBITRARY_ADDRESS, None).await - { - Ok(balance) => balance, - Err(err) => { - tracing::warn!("Error getting balance: {:?}", err); - tokio::time::sleep(Duration::from_secs(3)).await; - continue; - } - }; - - if balance == value { - return Ok(()); - } else { - tokio::time::sleep(Duration::from_secs(3)).await; - } - } - - eyre::bail!("Balance not updated in time"); -} diff --git a/tests/rpc_access.rs b/tests/rpc_access.rs index 15eed04..85a3a52 100644 --- a/tests/rpc_access.rs +++ b/tests/rpc_access.rs @@ -1,5 +1,7 @@ mod common; +use tx_sitter_client::apis::admin_v1_api::RelayerCreateApiKeyParams; + use crate::common::prelude::*; #[tokio::test] @@ -13,13 +15,16 @@ async fn rpc_access() -> eyre::Result<()> { ServiceBuilder::default().build(&anvil, &db_url).await?; let CreateApiKeyResponse { api_key } = - client.create_relayer_api_key(DEFAULT_RELAYER_ID).await?; - - let rpc_url = format!( - "http://{}/1/api/{}/rpc", - service.local_addr(), - api_key.reveal()? - ); + tx_sitter_client::apis::admin_v1_api::relayer_create_api_key( + &client, + RelayerCreateApiKeyParams { + relayer_id: DEFAULT_RELAYER_ID.to_string(), + }, + ) + .await?; + + let rpc_url = + format!("http://{}/1/api/{}/rpc", service.local_addr(), api_key); let provider = Provider::new(Http::new(rpc_url.parse::()?)); diff --git a/tests/send_many_txs.rs b/tests/send_many_txs.rs index c4a4ba3..c34f605 100644 --- a/tests/send_many_txs.rs +++ b/tests/send_many_txs.rs @@ -1,5 +1,8 @@ mod common; +use tx_sitter_client::apis::admin_v1_api::RelayerCreateApiKeyParams; +use tx_sitter_client::apis::relayer_v1_api::CreateTransactionParams; + use crate::common::prelude::*; #[tokio::test] @@ -13,7 +16,13 @@ async fn send_many_txs() -> eyre::Result<()> { ServiceBuilder::default().build(&anvil, &db_url).await?; let CreateApiKeyResponse { api_key } = - client.create_relayer_api_key(DEFAULT_RELAYER_ID).await?; + tx_sitter_client::apis::admin_v1_api::relayer_create_api_key( + &client, + RelayerCreateApiKeyParams { + relayer_id: DEFAULT_RELAYER_ID.to_string(), + }, + ) + .await?; let provider = setup_provider(anvil.endpoint()).await?; @@ -26,17 +35,19 @@ async fn send_many_txs() -> eyre::Result<()> { for _ in 0..num_transfers { let client = &client; tasks.push(async { - client - .send_tx( - &api_key, - &SendTxRequest { + tx_sitter_client::apis::relayer_v1_api::create_transaction( + client, + CreateTransactionParams { + api_token: api_key.clone(), + send_tx_request: SendTxRequest { to: ARBITRARY_ADDRESS.into(), value: value.into(), gas_limit: U256::from(21_000).into(), ..Default::default() }, - ) - .await?; + }, + ) + .await?; Ok(()) }); diff --git a/tests/send_too_many_txs.rs b/tests/send_too_many_txs.rs index ded4310..e684d6a 100644 --- a/tests/send_too_many_txs.rs +++ b/tests/send_too_many_txs.rs @@ -1,6 +1,11 @@ mod common; -use tx_sitter::types::{RelayerUpdate, TransactionPriority}; +use poem::http; +use tx_sitter_client::apis::admin_v1_api::{ + CreateRelayerParams, RelayerCreateApiKeyParams, UpdateRelayerParams, +}; +use tx_sitter_client::apis::relayer_v1_api::CreateTransactionParams; +use tx_sitter_client::apis::Error; use crate::common::prelude::*; @@ -17,120 +22,153 @@ async fn send_too_many_txs() -> eyre::Result<()> { ServiceBuilder::default().build(&anvil, &db_url).await?; let CreateApiKeyResponse { api_key } = - client.create_relayer_api_key(DEFAULT_RELAYER_ID).await?; + tx_sitter_client::apis::admin_v1_api::relayer_create_api_key( + &client, + RelayerCreateApiKeyParams { + relayer_id: DEFAULT_RELAYER_ID.to_string(), + }, + ) + .await?; let CreateRelayerResponse { relayer_id: secondary_relayer_id, address: secondary_relayer_address, - } = client - .create_relayer(&CreateRelayerRequest { - name: "Secondary Relayer".to_string(), - chain_id: DEFAULT_ANVIL_CHAIN_ID, - }) - .await?; + } = tx_sitter_client::apis::admin_v1_api::create_relayer( + &client, + CreateRelayerParams { + create_relayer_request: CreateRelayerRequest { + name: "Secondary Relayer".to_string(), + chain_id: DEFAULT_ANVIL_CHAIN_ID as i32, + }, + }, + ) + .await?; let provider = setup_provider(anvil.endpoint()).await?; let init_value: U256 = parse_units("1", "ether")?.into(); // Send some funds to created relayer - client - .send_tx( - &api_key, - &SendTxRequest { + tx_sitter_client::apis::relayer_v1_api::create_transaction( + &client, + CreateTransactionParams { + api_token: api_key.clone(), + send_tx_request: SendTxRequest { to: secondary_relayer_address.clone(), value: init_value.into(), data: None, gas_limit: U256::from(21_000).into(), - priority: TransactionPriority::Regular, + priority: Some(TransactionPriority::Regular), tx_id: None, blobs: None, }, - ) - .await?; + }, + ) + .await?; tracing::info!("Waiting for secondary relayer initial balance"); - await_balance(&provider, init_value, secondary_relayer_address.0).await?; + await_balance(&provider, init_value, secondary_relayer_address.clone().0) + .await?; let CreateApiKeyResponse { api_key: secondary_api_key, - } = client.create_relayer_api_key(&secondary_relayer_id).await?; + } = tx_sitter_client::apis::admin_v1_api::relayer_create_api_key( + &client, + RelayerCreateApiKeyParams { + relayer_id: secondary_relayer_id.clone(), + }, + ) + .await?; tracing::info!("Updating relayer"); // Set max queued txs - client - .update_relayer( - &secondary_relayer_id, - RelayerUpdate::default().with_max_queued_txs(MAX_QUEUED_TXS as u64), - ) - .await?; + tx_sitter_client::apis::admin_v1_api::update_relayer( + &client, + UpdateRelayerParams { + relayer_id: secondary_relayer_id.clone(), + relayer_update: RelayerUpdate { + max_queued_txs: Some(MAX_QUEUED_TXS as i32), + ..Default::default() + }, + }, + ) + .await?; // Send a transaction let value: U256 = parse_units("0.01", "ether")?.into(); tracing::info!("Sending txs"); for _ in 0..=MAX_QUEUED_TXS { - client - .send_tx( - &secondary_api_key, - &SendTxRequest { + tx_sitter_client::apis::relayer_v1_api::create_transaction( + &client, + CreateTransactionParams { + api_token: secondary_api_key.clone(), + send_tx_request: SendTxRequest { to: ARBITRARY_ADDRESS.into(), value: value.into(), data: None, gas_limit: U256::from(21_000).into(), - priority: TransactionPriority::Regular, + priority: Some(TransactionPriority::Regular), tx_id: None, blobs: None, }, - ) - .await?; + }, + ) + .await?; } // Sending one more tx should fail - let result = client - .send_tx( - &secondary_api_key, - &SendTxRequest { + let res = tx_sitter_client::apis::relayer_v1_api::create_transaction( + &client, + CreateTransactionParams { + api_token: secondary_api_key.clone(), + send_tx_request: SendTxRequest { to: ARBITRARY_ADDRESS.into(), value: value.into(), data: None, gas_limit: U256::from(21_000).into(), - priority: TransactionPriority::Regular, + priority: Some(TransactionPriority::Regular), tx_id: None, blobs: None, }, - ) - .await; + }, + ) + .await; - // TODO: Fix checking errors by string - assert_eq!( - result.as_ref().err().and_then(|e| e.tx_sitter_message()), - Some("Relayer queue is full"), - "Result {:?} should be too many transactions", - result - ); + if let Err(Error::ResponseError(e)) = res { + assert_eq!(e.status, http::StatusCode::TOO_MANY_REQUESTS); + assert_eq!(e.content, "Relayer queue is full"); + + return Ok(()); + } // Accumulate total value + gas budget let send_value = value * (MAX_QUEUED_TXS + 1); let total_required_value = send_value + parse_units("1", "ether")?; - client - .send_tx( - &api_key, - &SendTxRequest { + tx_sitter_client::apis::relayer_v1_api::create_transaction( + &client, + CreateTransactionParams { + api_token: api_key.clone(), + send_tx_request: SendTxRequest { to: secondary_relayer_address.clone(), value: total_required_value.into(), data: None, gas_limit: U256::from(21_000).into(), - priority: TransactionPriority::Regular, + priority: Some(TransactionPriority::Regular), tx_id: None, blobs: None, }, - ) - .await?; + }, + ) + .await?; tracing::info!("Waiting for secondary relayer balance"); - await_balance(&provider, total_required_value, secondary_relayer_address.0) - .await?; + await_balance( + &provider, + total_required_value, + secondary_relayer_address.clone().0, + ) + .await?; tracing::info!("Waiting for queued up txs to be processed"); await_balance(&provider, send_value, ARBITRARY_ADDRESS).await?; diff --git a/tests/send_tx.rs b/tests/send_tx.rs index c3f76c1..8ecbd2f 100644 --- a/tests/send_tx.rs +++ b/tests/send_tx.rs @@ -1,5 +1,8 @@ mod common; +use tx_sitter_client::apis::admin_v1_api::RelayerCreateApiKeyParams; +use tx_sitter_client::apis::relayer_v1_api::CreateTransactionParams; + use crate::common::prelude::*; #[tokio::test] @@ -12,33 +15,33 @@ async fn send_tx() -> eyre::Result<()> { let (_service, client) = ServiceBuilder::default().build(&anvil, &db_url).await?; let CreateApiKeyResponse { api_key } = - client.create_relayer_api_key(DEFAULT_RELAYER_ID).await?; + tx_sitter_client::apis::admin_v1_api::relayer_create_api_key( + &client, + RelayerCreateApiKeyParams { + relayer_id: DEFAULT_RELAYER_ID.to_string(), + }, + ) + .await?; let provider = setup_provider(anvil.endpoint()).await?; // Send a transaction let value: U256 = parse_units("1", "ether")?.into(); - client - .send_tx( - &api_key, - &SendTxRequest { + tx_sitter_client::apis::relayer_v1_api::create_transaction( + &client, + CreateTransactionParams { + api_token: api_key.clone(), + send_tx_request: SendTxRequest { to: ARBITRARY_ADDRESS.into(), value: value.into(), gas_limit: U256::from(21_000).into(), ..Default::default() }, - ) - .await?; - - for _ in 0..10 { - let balance = provider.get_balance(ARBITRARY_ADDRESS, None).await?; + }, + ) + .await?; - if balance == value { - return Ok(()); - } else { - tokio::time::sleep(Duration::from_secs(5)).await; - } - } + await_balance(&provider, value, ARBITRARY_ADDRESS).await?; - panic!("Transaction was not sent") + Ok(()) } diff --git a/tests/send_tx_with_same_id.rs b/tests/send_tx_with_same_id.rs index c27c0a8..74e6a04 100644 --- a/tests/send_tx_with_same_id.rs +++ b/tests/send_tx_with_same_id.rs @@ -1,7 +1,9 @@ mod common; -use reqwest::StatusCode; -use tx_sitter::client::ClientError; +use poem::http; +use tx_sitter_client::apis::admin_v1_api::RelayerCreateApiKeyParams; +use tx_sitter_client::apis::relayer_v1_api::CreateTransactionParams; +use tx_sitter_client::apis::Error; use crate::common::prelude::*; @@ -15,41 +17,51 @@ async fn send_tx_with_same_id() -> eyre::Result<()> { let (_service, client) = ServiceBuilder::default().build(&anvil, &db_url).await?; let CreateApiKeyResponse { api_key } = - client.create_relayer_api_key(DEFAULT_RELAYER_ID).await?; + tx_sitter_client::apis::admin_v1_api::relayer_create_api_key( + &client, + RelayerCreateApiKeyParams { + relayer_id: DEFAULT_RELAYER_ID.to_string(), + }, + ) + .await?; let tx_id = Some("tx-1".to_string()); // Send a transaction let value: U256 = parse_units("1", "ether")?.into(); - client - .send_tx( - &api_key, - &SendTxRequest { + tx_sitter_client::apis::relayer_v1_api::create_transaction( + &client, + CreateTransactionParams { + api_token: api_key.clone(), + send_tx_request: SendTxRequest { to: ARBITRARY_ADDRESS.into(), value: value.into(), gas_limit: U256::from(21_000).into(), tx_id: tx_id.clone(), ..Default::default() }, - ) - .await?; + }, + ) + .await?; - let res = client - .send_tx( - &api_key, - &SendTxRequest { + let res = tx_sitter_client::apis::relayer_v1_api::create_transaction( + &client, + CreateTransactionParams { + api_token: api_key.clone(), + send_tx_request: SendTxRequest { to: ARBITRARY_ADDRESS.into(), value: value.into(), gas_limit: U256::from(21_000).into(), tx_id: tx_id.clone(), ..Default::default() }, - ) - .await; + }, + ) + .await; - if let ClientError::TxSitter(status_code, message) = res.unwrap_err() { - assert_eq!(status_code, StatusCode::CONFLICT); - assert_eq!(message, "Transaction with same id already exists."); + if let Err(Error::ResponseError(e)) = res { + assert_eq!(e.status, http::StatusCode::CONFLICT); + assert_eq!(e.content, "Transaction with same id already exists."); return Ok(()); } diff --git a/tests/send_when_insufficient_funds.rs b/tests/send_when_insufficient_funds.rs index 428952d..ba3bcbf 100644 --- a/tests/send_when_insufficient_funds.rs +++ b/tests/send_when_insufficient_funds.rs @@ -1,6 +1,9 @@ mod common; -use tx_sitter::client::ClientError; +use poem::http; +use tx_sitter_client::apis::admin_v1_api::RelayerCreateApiKeyParams; +use tx_sitter_client::apis::relayer_v1_api::CreateTransactionParams; +use tx_sitter_client::apis::Error; use crate::common::prelude::*; @@ -23,27 +26,54 @@ async fn send_when_insufficient_funds() -> eyre::Result<()> { .await?; let CreateApiKeyResponse { api_key } = - client.create_relayer_api_key(DEFAULT_RELAYER_ID).await?; + tx_sitter_client::apis::admin_v1_api::relayer_create_api_key( + &client, + RelayerCreateApiKeyParams { + relayer_id: DEFAULT_RELAYER_ID.to_string(), + }, + ) + .await?; + + let provider = setup_provider(anvil.endpoint()).await?; // Send a transaction - let value: U256 = parse_units("1", "ether")?.into(); - for _ in 0..10 { - let tx = client - .send_tx( - &api_key, - &SendTxRequest { + let value: U256 = parse_units("9999.9999", "ether")?.into(); + + tx_sitter_client::apis::relayer_v1_api::create_transaction( + &client, + CreateTransactionParams { + api_token: api_key.clone(), + send_tx_request: SendTxRequest { + to: ARBITRARY_ADDRESS.into(), + value: value.into(), + gas_limit: U256::from(21_000).into(), + ..Default::default() + }, + }, + ) + .await?; + + await_balance(&provider, value, ARBITRARY_ADDRESS).await?; + + for _ in 0..5 { + let tx = tx_sitter_client::apis::relayer_v1_api::create_transaction( + &client, + CreateTransactionParams { + api_token: api_key.clone(), + send_tx_request: SendTxRequest { to: ARBITRARY_ADDRESS.into(), value: value.into(), - gas_limit: U256::from_dec_str("1000000000000")?.into(), + gas_limit: U256::from(21_000).into(), ..Default::default() }, - ) - .await; + }, + ) + .await; - if let Err(ClientError::TxSitter(status_code, message)) = tx { - assert_eq!(status_code, reqwest::StatusCode::UNPROCESSABLE_ENTITY); + if let Err(Error::ResponseError(e)) = tx { + assert_eq!(e.status, http::StatusCode::UNPROCESSABLE_ENTITY); assert_eq!( - message, + e.content, "Relayer funds are insufficient for transaction to be mined." ); return Ok(());