From 5713701b47bfe4be9408b86eff403b2e9263b29c Mon Sep 17 00:00:00 2001 From: Kamil Koczurek Date: Mon, 4 Dec 2023 11:36:54 +0100 Subject: [PATCH] Faucet + Holesky + Stuck Tx Status + Erc20next goth default --- .env-template | 1 + Cargo.lock | 308 +++++++++++-- Cargo.toml | 5 +- agent/provider/src/provider_agent.rs | 1 + core/model/src/driver.rs | 13 + core/model/src/payment.rs | 8 +- core/payment-driver/base/src/db/models.rs | 4 + core/payment-driver/erc20/Readme.md | 1 + core/payment-driver/erc20/src/driver/cli.rs | 3 +- core/payment-driver/erc20/src/erc20/config.rs | 20 + .../erc20/src/erc20/ethereum.rs | 62 +-- core/payment-driver/erc20/src/lib.rs | 6 + core/payment-driver/erc20/src/network.rs | 23 +- core/payment-driver/erc20next/Cargo.toml | 1 + core/payment-driver/erc20next/Readme.md | 2 +- .../erc20next/config-payments.toml | 415 +++++++++++++++++- core/payment-driver/erc20next/src/driver.rs | 352 ++++++++++++++- .../erc20next/src/erc20/config.rs | 20 + .../erc20next/src/erc20/ethereum.rs | 5 + core/payment-driver/erc20next/src/lib.rs | 6 + core/payment-driver/erc20next/src/network.rs | 23 +- core/payment-driver/erc20next/src/service.rs | 45 +- core/payment-driver/erc20next/src/signer.rs | 6 +- core/payment/src/cli.rs | 9 + core/payment/src/lib.rs | 4 +- core/payment/src/processor.rs | 1 - core/serv/src/main.rs | 18 +- golem_cli/src/command/yagna.rs | 22 +- goth_tests/pyproject.toml | 5 +- 29 files changed, 1212 insertions(+), 177 deletions(-) diff --git a/.env-template b/.env-template index 8d7f0792c2..6b90d5ae09 100644 --- a/.env-template +++ b/.env-template @@ -50,6 +50,7 @@ YAGNA_DATADIR="." ## Setting any of these variables will disable DNS lookup mechanism and use custom list of nodes instead for chosen network. #MAINNET_GETH_ADDR=https://geth.golem.network:55555 #GOERLI_GETH_ADDR=https://rpc.ankr.com/eth_goerli +#HOLESKY_GETH_ADDR=https://rpc.ankr.com/eth_holesky #POLYGON_GETH_ADDR=https://bor.golem.network,https://polygon-rpc.com #MUMBAI_GETH_ADDR=https://matic-mumbai.chainstacklabs.com diff --git a/Cargo.lock b/Cargo.lock index 96e76da943..bafbac46a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -248,7 +248,9 @@ dependencies = [ "openssl", "pin-project-lite", "tokio-openssl", + "tokio-rustls 0.23.4", "tokio-util", + "webpki-roots 0.22.6", ] [[package]] @@ -672,6 +674,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rand 0.8.5", + "rustls 0.20.9", "serde", "serde_json", "serde_urlencoded", @@ -874,6 +877,45 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +[[package]] +name = "bollard" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af254ed2da4936ef73309e9597180558821cb16ae9bba4cb24ce6b612d8d80ed" +dependencies = [ + "base64 0.21.5", + "bollard-stubs", + "bytes 1.4.0", + "futures-core", + "futures-util", + "hex", + "http", + "hyper", + "hyperlocal", + "log", + "pin-project-lite", + "serde", + "serde_derive", + "serde_json", + "serde_repr", + "serde_urlencoded", + "thiserror", + "tokio", + "tokio-util", + "url", + "winapi 0.3.9", +] + +[[package]] +name = "bollard-stubs" +version = "1.42.0-rc.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602bda35f33aeb571cef387dcd4042c643a8bf689d8aaac2cc47ea24cb7bc7e0" +dependencies = [ + "serde", + "serde_with", +] + [[package]] name = "borsh" version = "1.2.0" @@ -926,7 +968,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" dependencies = [ "memchr", - "regex-automata", + "regex-automata 0.3.6", "serde", ] @@ -1914,21 +1956,65 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "erc20_payment_lib" -version = "0.3.1" -source = "git+https://github.com/golemfactory/erc20_payment_lib?rev=f3559980c8998f2865e593be73766ad2abcc11ca#f3559980c8998f2865e593be73766ad2abcc11ca" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ec0c57fe6b4a104c9c9f860d1e867dca4838085aa505625b209d8c4f931546e" +dependencies = [ + "actix-files", + "actix-web", + "async-trait", + "awc", + "chrono", + "dotenv", + "erc20_payment_lib_common", + "erc20_rpc_pool", + "fastrand", + "futures 0.3.28", + "futures-util", + "hex", + "humantime 2.1.0", + "lazy_static", + "log", + "rand 0.8.5", + "regex", + "rust_decimal", + "rustc-hex", + "secp256k1 0.27.0", + "serde", + "serde_json", + "sha3 0.10.8", + "sqlx", + "structopt", + "thunderdome", + "tokio", + "toml", + "trust-dns-resolver", + "url", + "uuid 1.4.1", + "web3", +] + +[[package]] +name = "erc20_payment_lib_common" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec6027442066984459d7e98711f91427aab622a960ab6f6d483dabcbeddbaf73" dependencies = [ "actix-files", "actix-web", "async-trait", + "awc", "chrono", "dotenv", "fastrand", "futures 0.3.28", + "futures-util", "hex", "humantime 2.1.0", "lazy_static", "log", "rand 0.8.5", + "regex", "rust_decimal", "rustc-hex", "secp256k1 0.27.0", @@ -1937,8 +2023,52 @@ dependencies = [ "sha3 0.10.8", "sqlx", "structopt", + "thunderdome", "tokio", "toml", + "trust-dns-resolver", + "url", + "uuid 1.4.1", + "web3", +] + +[[package]] +name = "erc20_rpc_pool" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd51cee570e856fe8ba5040ec1538d31482a6c106db2acc40db89a6df5110ed1" +dependencies = [ + "actix-files", + "actix-web", + "anyhow", + "async-trait", + "awc", + "bollard", + "chrono", + "dotenv", + "env_logger 0.10.0", + "erc20_payment_lib_common", + "fastrand", + "futures 0.3.28", + "futures-util", + "hex", + "humantime 2.1.0", + "lazy_static", + "log", + "rand 0.8.5", + "reqwest", + "rust_decimal", + "rustc-hex", + "secp256k1 0.27.0", + "serde", + "serde_json", + "sha3 0.10.8", + "sqlx", + "structopt", + "thunderdome", + "tokio", + "toml", + "trust-dns-resolver", "uuid 1.4.1", "web3", ] @@ -2289,9 +2419,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", ] @@ -2954,9 +3084,9 @@ dependencies = [ "futures-util", "http", "hyper", - "rustls", + "rustls 0.21.9", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", ] [[package]] @@ -2972,6 +3102,19 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "hyperlocal" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fafdf7b2b2de7c9784f76e02c0935e65a8117ec3b768644379983ab333ac98c" +dependencies = [ + "futures-util", + "hex", + "hyper", + "pin-project 1.1.3", + "tokio", +] + [[package]] name = "iana-time-zone" version = "0.1.57" @@ -3022,6 +3165,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "im" version = "15.1.0" @@ -3459,9 +3612,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memoffset" @@ -4313,9 +4466,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" @@ -4685,7 +4838,7 @@ checksum = "1fa3d084c8704911bfefb2771be2f9b6c5c0da7343a71e0021ee3c665cada738" dependencies = [ "bytes 1.4.0", "heck 0.4.1", - "itertools 0.10.5", + "itertools 0.11.0", "log", "multimap", "once_cell", @@ -4732,7 +4885,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "065717a5dfaca4a83d2fe57db3487b311365200000551d7a364e715dbf4346bc" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.11.0", "proc-macro2", "quote", "syn 2.0.32", @@ -5030,13 +5183,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.3" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata", + "regex-automata 0.4.3", "regex-syntax", ] @@ -5045,6 +5198,12 @@ name = "regex-automata" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -5053,9 +5212,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "remove_dir_all" @@ -5100,14 +5259,14 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", + "rustls 0.21.9", "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", "tokio-native-tls", - "tokio-rustls", + "tokio-rustls 0.24.1", "tower-service", "trust-dns-resolver", "url", @@ -5128,6 +5287,21 @@ dependencies = [ "quick-error", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi 0.3.9", +] + [[package]] name = "ring" version = "0.17.3" @@ -5138,7 +5312,7 @@ dependencies = [ "getrandom 0.2.10", "libc", "spin 0.9.8", - "untrusted", + "untrusted 0.9.0", "windows-sys 0.48.0", ] @@ -5281,6 +5455,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "rustls" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" +dependencies = [ + "log", + "ring 0.16.20", + "sct", + "webpki", +] + [[package]] name = "rustls" version = "0.21.9" @@ -5288,7 +5474,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" dependencies = [ "log", - "ring", + "ring 0.17.3", "rustls-webpki", "sct", ] @@ -5308,8 +5494,8 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring", - "untrusted", + "ring 0.17.3", + "untrusted 0.9.0", ] [[package]] @@ -5485,8 +5671,8 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring", - "untrusted", + "ring 0.17.3", + "untrusted 0.9.0", ] [[package]] @@ -5707,6 +5893,17 @@ dependencies = [ "thiserror", ] +[[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.32", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -5719,6 +5916,21 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89df7a26519371a3cce44fbb914c2819c84d9b897890987fa3ab096491cc0ea8" +dependencies = [ + "base64 0.13.1", + "chrono", + "hex", + "indexmap 1.9.3", + "serde", + "serde_json", + "time 0.3.9", +] + [[package]] name = "serde_yaml" version = "0.8.26" @@ -5750,7 +5962,7 @@ version = "0.5.1" source = "git+https://github.com/golemfactory/serial_test.git?branch=actix_rt_test#6a9176a54cab7e3682a05dbac3741812b221a8c5" dependencies = [ "lazy_static", - "parking_lot 0.10.2", + "parking_lot 0.11.2", "serial_test_derive 0.5.1", ] @@ -6694,6 +6906,12 @@ dependencies = [ "syn 2.0.32", ] +[[package]] +name = "thunderdome" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e170f93360bf9ae6fe3c31116bbf27adb1d054cedd6bc3d7857e34f2d98d0b" + [[package]] name = "time" version = "0.1.45" @@ -6714,6 +6932,7 @@ dependencies = [ "itoa", "libc", "num_threads", + "serde", "time-macros", ] @@ -6818,13 +7037,24 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls 0.20.9", + "tokio", + "webpki", +] + [[package]] name = "tokio-rustls" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.9", "tokio", ] @@ -7089,6 +7319,12 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -7104,7 +7340,7 @@ dependencies = [ "base64 0.21.5", "log", "once_cell", - "rustls", + "rustls 0.21.9", "rustls-webpki", "url", "webpki-roots 0.25.2", @@ -7112,12 +7348,12 @@ dependencies = [ [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna 0.4.0", + "idna 0.5.0", "percent-encoding", "serde", ] @@ -7174,7 +7410,7 @@ checksum = "e7141e445af09c8919f1d5f8a20dae0b20c3b57a45dee0d5823c6ed5d237f15a" dependencies = [ "bitflags 1.3.2", "chrono", - "rustc_version 0.2.3", + "rustc_version 0.4.0", ] [[package]] @@ -7379,8 +7615,8 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring", - "untrusted", + "ring 0.17.3", + "untrusted 0.9.0", ] [[package]] @@ -7908,6 +8144,7 @@ dependencies = [ "num-bigint 0.3.3", "num-traits", "rlp", + "rust_decimal", "serde", "serde_json", "sha3 0.8.2", @@ -9029,6 +9266,7 @@ dependencies = [ "libsqlite3-sys", "log", "metrics 0.12.1", + "num_cpus", "openssl", "openssl-probe", "serde", diff --git a/Cargo.toml b/Cargo.toml index 62dc01e57d..6adb30a6f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,6 +77,7 @@ futures = "0.3" lazy_static = "1.4" log = "0.4" metrics = "0.12" +num_cpus = "1" openssl = "0.10" openssl-probe = { version = "0.1", optional = true } serde = "1.0" @@ -228,9 +229,9 @@ members = [ # diesel 1.4.* supports up to 0.23.0, but sqlx 0.5.9 requires 0.22.0 # sqlx 0.5.10 need 0.23.2, so 0.5.9 is last version possible libsqlite3-sys = { version = "0.26.0", features = ["bundled"] } -erc20_payment_lib = { git = "https://github.com/golemfactory/erc20_payment_lib", rev = "f3559980c8998f2865e593be73766ad2abcc11ca" } +#erc20_payment_lib = { version = "0.3.2", git = "https://github.com/golemfactory/erc20_payment_lib", rev = "2fb9949b43ccedf0dfad61926d567debd2d6086f" } #erc20_payment_lib = { path = "../../payments/erc20_payment_lib/crates/erc20_payment_lib" } -#erc20_payment_lib = { version = "=0.3.1" } +erc20_payment_lib = { version = "=0.3.13" } rand = "0.8.5" url = "2.3.1" trust-dns-resolver = "0.22" diff --git a/agent/provider/src/provider_agent.rs b/agent/provider/src/provider_agent.rs index 107d7445d3..cebf811147 100644 --- a/agent/provider/src/provider_agent.rs +++ b/agent/provider/src/provider_agent.rs @@ -155,6 +155,7 @@ impl ProviderAgent { NetworkName::Rinkeby => yansi::Color::Cyan, NetworkName::Mumbai => yansi::Color::Cyan, NetworkName::Goerli => yansi::Color::Cyan, + NetworkName::Holesky => yansi::Color::Cyan, _ => yansi::Color::Red, }; log::info!("Using payment network: {}", net_color.paint(&n)); diff --git a/core/model/src/driver.rs b/core/model/src/driver.rs index 05e669a152..ef5616d379 100644 --- a/core/model/src/driver.rs +++ b/core/model/src/driver.rs @@ -53,6 +53,19 @@ pub struct PaymentDetails { pub date: Option>, } +impl Display for PaymentDetails { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "({{recipient: {}, sender: {}, amount: {}, date: {}}})", + self.recipient, + self.sender, + self.amount, + self.date.unwrap_or_default() + ) + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PaymentConfirmation { pub confirmation: Vec, diff --git a/core/model/src/payment.rs b/core/model/src/payment.rs index caf60c3a66..e7c4524149 100644 --- a/core/model/src/payment.rs +++ b/core/model/src/payment.rs @@ -31,7 +31,7 @@ pub mod local { use ya_client_model::NodeId; pub const BUS_ID: &str = "/local/payment"; - pub const DEFAULT_PAYMENT_DRIVER: &str = "erc20"; + pub const DEFAULT_PAYMENT_DRIVER: &str = "erc20next"; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct DebitNotePayment { @@ -488,6 +488,8 @@ pub mod local { Rinkeby, #[strum(props(token = "tGLM"))] Goerli, + #[strum(props(token = "tGLM"))] + Holesky, #[strum(props(token = "GLM"))] Polygon, #[strum(props(token = "tGLM"))] @@ -521,7 +523,7 @@ pub mod local { #[structopt(long, env = "YA_ACCOUNT")] pub account: Option, /// Payment driver - #[structopt(long, possible_values = DriverName::VARIANTS, default_value = DriverName::Erc20.into())] + #[structopt(long, possible_values = DriverName::VARIANTS, default_value = DriverName::Erc20Next.into())] pub driver: DriverName, /// Payment network #[structopt(long, possible_values = NetworkName::VARIANTS, default_value = NetworkName::Goerli.into())] @@ -554,7 +556,7 @@ pub mod local { fn test_cli_defaults() { let a = AccountCli::from_iter(&[""]); assert_eq!(None, a.address()); - assert_eq!("erc20", a.driver()); + assert_eq!("erc20next", a.driver()); assert_eq!("goerli", a.network()); assert_eq!("tGLM", a.token()); } diff --git a/core/payment-driver/base/src/db/models.rs b/core/payment-driver/base/src/db/models.rs index 8fe0de520f..cb53abef1c 100644 --- a/core/payment-driver/base/src/db/models.rs +++ b/core/payment-driver/base/src/db/models.rs @@ -116,6 +116,7 @@ pub enum Network { Rinkeby = 4, //Rinkeby is Ethereum testnet #[default] Goerli = 5, //Goerli is another Ethereum testnet + Holesky = 17000, //Holesky is testnet for Holesky network Mumbai = 80001, //Mumbai is testnet for Polygon network Polygon = 137, //Polygon is Polygon production network } @@ -128,6 +129,7 @@ impl FromStr for Network { "mainnet" => Ok(Network::Mainnet), "rinkeby" => Ok(Network::Rinkeby), "goerli" => Ok(Network::Goerli), + "holesky" => Ok(Network::Holesky), "polygon" => Ok(Network::Polygon), "mumbai" => Ok(Network::Mumbai), _ => Err(DbError::InvalidData(format!("Invalid network: {}", s))), @@ -141,6 +143,7 @@ impl Display for Network { Network::Mainnet => f.write_str("mainnet"), Network::Rinkeby => f.write_str("rinkeby"), Network::Goerli => f.write_str("goerli"), + Network::Holesky => f.write_str("holesky"), Network::Mumbai => f.write_str("mumbai"), Network::Polygon => f.write_str("polygon"), } @@ -167,6 +170,7 @@ where 4 => Network::Rinkeby, 5 => Network::Goerli, 137 => Network::Polygon, + 17000 => Network::Holesky, 80001 => Network::Mumbai, _ => return Err(anyhow::anyhow!("invalid value").into()), }) diff --git a/core/payment-driver/erc20/Readme.md b/core/payment-driver/erc20/Readme.md index f5434615af..00bd2db8d4 100644 --- a/core/payment-driver/erc20/Readme.md +++ b/core/payment-driver/erc20/Readme.md @@ -24,6 +24,7 @@ Networks currently supported: * mainnnet (ETH mainnet, do not use) * rinkeby (ETH testnet, good support) * goerli (ETH testnet) +* holesky (ETH testnet) * mumbai (Polygon testnet) * polygon (Polygon mainnet) diff --git a/core/payment-driver/erc20/src/driver/cli.rs b/core/payment-driver/erc20/src/driver/cli.rs index 4b7bc453d8..11e28269ae 100644 --- a/core/payment-driver/erc20/src/driver/cli.rs +++ b/core/payment-driver/erc20/src/driver/cli.rs @@ -76,7 +76,7 @@ pub async fn fund(dao: &Erc20Dao, msg: Fund) -> Result { let address = msg.address(); let network = network::network_like_to_network(msg.network()); let result = match network { - Network::Rinkeby | Network::Goerli => { + Network::Rinkeby | Network::Goerli | Network::Holesky => { let address = utils::str_to_addr(&address)?; log::info!( "Handling fund request. network={}, address={}", @@ -154,6 +154,7 @@ pub async fn transfer(dao: &Erc20Dao, msg: Transfer) -> Result "https://polygonscan.com/tx/", Network::Mainnet => "https://etherscan.io/tx/", Network::Rinkeby => "https://rinkeby.etherscan.io/tx/", + Network::Holesky => "https://holesky.etherscan.io/tx/", Network::Goerli => "https://goerli.etherscan.io/tx/", Network::Mumbai => "https://mumbai.polygonscan.com/tx/", }; diff --git a/core/payment-driver/erc20/src/erc20/config.rs b/core/payment-driver/erc20/src/erc20/config.rs index c6b36aee96..cce6215869 100644 --- a/core/payment-driver/erc20/src/erc20/config.rs +++ b/core/payment-driver/erc20/src/erc20/config.rs @@ -74,6 +74,26 @@ lazy_static! { } } }; + pub static ref HOLESKY_CONFIG: EnvConfiguration = EnvConfiguration { + glm_contract_address: utils::str_to_addr( + &env::var("HOLESKY_TGLM_CONTRACT_ADDRESS") + .unwrap_or_else(|_| "0x8888888815bf4DB87e57B609A50f938311EEd068".to_string()) + ) + .unwrap(), + glm_faucet_address: Some( + utils::str_to_addr( + &env::var("HOLESKY_TGLM_FAUCET_ADDRESS") + .unwrap_or_else(|_| "0xFACe100969FF47EB58d2CF603321B581A84bcEaC".to_string()) + ) + .unwrap() + ), + required_confirmations: { + match env::var("ERC20_HOLESKY_REQUIRED_CONFIRMATIONS").map(|s| s.parse()) { + Ok(Ok(x)) => x, + _ => 3, + } + } + }; pub static ref MUMBAI_CONFIG: EnvConfiguration = EnvConfiguration { glm_contract_address: utils::str_to_addr( &env::var("MUMBAI_TGLM_CONTRACT_ADDRESS") diff --git a/core/payment-driver/erc20/src/erc20/ethereum.rs b/core/payment-driver/erc20/src/erc20/ethereum.rs index b956f1adf2..59e603d1d3 100644 --- a/core/payment-driver/erc20/src/erc20/ethereum.rs +++ b/core/payment-driver/erc20/src/erc20/ethereum.rs @@ -534,73 +534,13 @@ async fn get_tx_receipt_with( .await .map_err(Into::into) } -/* -fn get_rpc_addr_from_env(network: Network) -> Vec { - match network { - Network::Mainnet => { - collect_rpc_addr_from("MAINNET_GETH_ADDR", "https://geth.golem.network:55555") - } - Network::Rinkeby => collect_rpc_addr_from( - "RINKEBY_GETH_ADDR", - "http://geth.testnet.golem.network:55555", - ), - Network::Goerli => { - collect_rpc_addr_from("GOERLI_GETH_ADDR", "https://rpc.ankr.com/eth_goerli") - } - Network::Polygon => collect_rpc_addr_from( - "POLYGON_GETH_ADDR", - "https://bor.golem.network,https://polygon-rpc.com", - ), - Network::Mumbai => collect_rpc_addr_from( - "MUMBAI_GETH_ADDR", - "https://matic-mumbai.chainstacklabs.com", - ), - } -} - -fn collect_rpc_addr_from(env: &str, default: &str) -> Vec { - std::env::var(env) - .ok() - .unwrap_or_else(|| default.to_string()) - .split(',') - .map(|path| path.to_string()) - .collect() -} - -async fn get_clients(network: Network) -> Result>, GenericError> { - let geth_addrs = get_rpc_addr_from_env(network); - let mut clients: Vec> = Default::default(); - - for geth_addr in geth_addrs { - { - let client_map = WEB3_CLIENT_MAP.read().await; - if let Some(client) = client_map.get(&geth_addr).cloned() { - clients.push(client); - continue; - } - } - - let transport = match web3::transports::Http::new(&geth_addr) { - Ok(t) => t, - Err(_) => continue, - }; - - let client = Web3::new(transport); - let mut client_map = WEB3_CLIENT_MAP.write().await; - client_map.insert(geth_addr, client.clone()); - - clients.push(client); - } - - Ok(clients) -} -*/ fn get_env(network: Network) -> config::EnvConfiguration { match network { Network::Mainnet => *config::MAINNET_CONFIG, Network::Rinkeby => *config::RINKEBY_CONFIG, Network::Goerli => *config::GOERLI_CONFIG, + Network::Holesky => *config::HOLESKY_CONFIG, Network::Mumbai => *config::MUMBAI_CONFIG, Network::Polygon => *config::POLYGON_MAINNET_CONFIG, } diff --git a/core/payment-driver/erc20/src/lib.rs b/core/payment-driver/erc20/src/lib.rs index 4cbe2ce4cd..b2df420367 100644 --- a/core/payment-driver/erc20/src/lib.rs +++ b/core/payment-driver/erc20/src/lib.rs @@ -19,6 +19,12 @@ pub const GOERLI_PLATFORM: &str = "erc20-goerli-tglm"; pub const GOERLI_CURRENCY_SHORT: &str = "tETH"; pub const GOERLI_CURRENCY_LONG: &str = "Goerli Ether"; +pub const HOLESKY_NETWORK: &str = "holesky"; +pub const HOLESKY_TOKEN: &str = "tGLM"; +pub const HOLESKY_PLATFORM: &str = "erc20-holesky-tglm"; +pub const HOLESKY_CURRENCY_SHORT: &str = "tETH"; +pub const HOLESKY_CURRENCY_LONG: &str = "Holesky Ether"; + pub const MUMBAI_NETWORK: &str = "mumbai"; pub const MUMBAI_TOKEN: &str = "tGLM"; pub const MUMBAI_PLATFORM: &str = "erc20-mumbai-tglm"; diff --git a/core/payment-driver/erc20/src/network.rs b/core/payment-driver/erc20/src/network.rs index 130889ba1a..520b2c811d 100644 --- a/core/payment-driver/erc20/src/network.rs +++ b/core/payment-driver/erc20/src/network.rs @@ -8,9 +8,10 @@ use ya_payment_driver::{db::models::Network as DbNetwork, driver::Network, model // Local uses use crate::{ GOERLI_CURRENCY_LONG, GOERLI_CURRENCY_SHORT, GOERLI_NETWORK, GOERLI_PLATFORM, GOERLI_TOKEN, - MAINNET_CURRENCY_LONG, MAINNET_CURRENCY_SHORT, MAINNET_NETWORK, MAINNET_PLATFORM, - MAINNET_TOKEN, MUMBAI_CURRENCY_LONG, MUMBAI_CURRENCY_SHORT, MUMBAI_NETWORK, MUMBAI_PLATFORM, - MUMBAI_TOKEN, POLYGON_MAINNET_CURRENCY_LONG, POLYGON_MAINNET_CURRENCY_SHORT, + HOLESKY_CURRENCY_LONG, HOLESKY_CURRENCY_SHORT, HOLESKY_NETWORK, HOLESKY_PLATFORM, + HOLESKY_TOKEN, MAINNET_CURRENCY_LONG, MAINNET_CURRENCY_SHORT, MAINNET_NETWORK, + MAINNET_PLATFORM, MAINNET_TOKEN, MUMBAI_CURRENCY_LONG, MUMBAI_CURRENCY_SHORT, MUMBAI_NETWORK, + MUMBAI_PLATFORM, MUMBAI_TOKEN, POLYGON_MAINNET_CURRENCY_LONG, POLYGON_MAINNET_CURRENCY_SHORT, POLYGON_MAINNET_NETWORK, POLYGON_MAINNET_PLATFORM, POLYGON_MAINNET_TOKEN, RINKEBY_CURRENCY_LONG, RINKEBY_CURRENCY_SHORT, RINKEBY_NETWORK, RINKEBY_PLATFORM, RINKEBY_TOKEN, @@ -30,6 +31,12 @@ lazy_static::lazy_static! { GOERLI_TOKEN.to_string() => GOERLI_PLATFORM.to_string() } }, + HOLESKY_NETWORK.to_string() => Network { + default_token: HOLESKY_TOKEN.to_string(), + tokens: hashmap! { + HOLESKY_TOKEN.to_string() => HOLESKY_PLATFORM.to_string() + } + }, MAINNET_NETWORK.to_string() => Network { default_token: MAINNET_TOKEN.to_string(), tokens: hashmap! { @@ -51,6 +58,7 @@ lazy_static::lazy_static! { }; pub static ref RINKEBY_DB_NETWORK: DbNetwork = DbNetwork::from_str(RINKEBY_NETWORK).unwrap(); pub static ref GOERLI_DB_NETWORK: DbNetwork = DbNetwork::from_str(GOERLI_NETWORK).unwrap(); + pub static ref HOLESKY_DB_NETWORK: DbNetwork = DbNetwork::from_str(HOLESKY_NETWORK).unwrap(); pub static ref MAINNET_DB_NETWORK: DbNetwork = DbNetwork::from_str(MAINNET_NETWORK).unwrap(); pub static ref MUMBAI_DB_NETWORK: DbNetwork = DbNetwork::from_str(MUMBAI_NETWORK).unwrap(); pub static ref POLYGON_MAINNET_DB_NETWORK: DbNetwork = DbNetwork::from_str(POLYGON_MAINNET_NETWORK).unwrap(); @@ -60,6 +68,7 @@ pub fn platform_to_network_token(platform: String) -> Result<(DbNetwork, String) match platform.as_str() { RINKEBY_PLATFORM => Ok((*RINKEBY_DB_NETWORK, RINKEBY_TOKEN.to_owned())), GOERLI_PLATFORM => Ok((*GOERLI_DB_NETWORK, GOERLI_TOKEN.to_owned())), + HOLESKY_PLATFORM => Ok((*HOLESKY_DB_NETWORK, HOLESKY_TOKEN.to_owned())), MAINNET_PLATFORM => Ok((*MAINNET_DB_NETWORK, MAINNET_TOKEN.to_owned())), MUMBAI_PLATFORM => Ok((*MUMBAI_DB_NETWORK, MUMBAI_TOKEN.to_owned())), POLYGON_MAINNET_PLATFORM => Ok(( @@ -102,6 +111,10 @@ pub fn platform_to_currency(platform: String) -> Result<(String, String), Generi GOERLI_CURRENCY_SHORT.to_owned(), GOERLI_CURRENCY_LONG.to_owned(), )), + HOLESKY_PLATFORM => Ok(( + HOLESKY_CURRENCY_SHORT.to_owned(), + HOLESKY_CURRENCY_LONG.to_owned(), + )), MAINNET_PLATFORM => Ok(( MAINNET_CURRENCY_SHORT.to_owned(), MAINNET_CURRENCY_LONG.to_owned(), @@ -131,8 +144,8 @@ pub fn get_network_token( pub fn network_like_to_network(network_like: Option) -> DbNetwork { match network_like { - Some(n) => DbNetwork::from_str(&n).unwrap_or(*GOERLI_DB_NETWORK), - None => *GOERLI_DB_NETWORK, + Some(n) => DbNetwork::from_str(&n).unwrap_or(*HOLESKY_DB_NETWORK), + None => *HOLESKY_DB_NETWORK, } } diff --git a/core/payment-driver/erc20next/Cargo.toml b/core/payment-driver/erc20next/Cargo.toml index 9e5e488b65..e6193c5ed7 100644 --- a/core/payment-driver/erc20next/Cargo.toml +++ b/core/payment-driver/erc20next/Cargo.toml @@ -39,6 +39,7 @@ web3 = { version = "0.19.0", default-features = false, features = [ "signing", "ws-tls-tokio", ] } +rust_decimal = "1" ## yagna dependencies ya-payment-driver = "0.3" diff --git a/core/payment-driver/erc20next/Readme.md b/core/payment-driver/erc20next/Readme.md index fd76dcf889..18758db925 100644 --- a/core/payment-driver/erc20next/Readme.md +++ b/core/payment-driver/erc20next/Readme.md @@ -3,7 +3,7 @@ A payment driver is an abstraction over any operations relating to funds, which includes: * Scheduling transfers to run at any point in the future. * Verifying transfers done by other parties. -* Checking acount balance. +* Checking account balance. * Reporting status of scheduled transactions and the account. The Erc20Next driver is such an abstraction built on top of the [ERC20 standard](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/). diff --git a/core/payment-driver/erc20next/config-payments.toml b/core/payment-driver/erc20next/config-payments.toml index 8f7e09a642..7b98a8bc24 100644 --- a/core/payment-driver/erc20next/config-payments.toml +++ b/core/payment-driver/erc20next/config-payments.toml @@ -8,6 +8,15 @@ process-interval-after-send = 30 # proces interval after error (in seconds) is to set how long to wait after encountering error before trying again # minimum 1 second, sensible maximum around 60 seconds process-interval-after-error = 25 + +# proces interval after missing gas or token (in seconds) +# it is starting with checking every process-interval-after-no-gas-or-token-start +# and then increasing by multiplying by process-interval-after-no-gas-or-token-increase +# up to process-interval-after-no-gas-or-token-max +process-interval-after-no-gas-or-token-start = 20 +process-interval-after-no-gas-or-token-max = 40 +process-interval-after-no-gas-or-token-increase = 1.5 + # report alive interval (in seconds) is to set how often we want to report that we are alive # minimum 1 second, maximum is capped by gather-interval report-alive-interval = 30 @@ -20,35 +29,276 @@ automatic-recover = false # set to true to not respect deadlines attached to payments ignore-deadlines = false +[chain.ethereum] +chain-name = "Ethereum" +chain-id = 1 +currency-symbol = "ETH" +priority-fee = 1.01 +max-fee-per-gas = 40.0 +gas-left-warning-limit = 1000000 +transaction-timeout = 100 +token = { address = "0x7DD9c5Cba05E151C895FDe1CF355C9A1D5DA6429", symbol = "GLM" } +confirmation-blocks = 1 +block-explorer-url = "https://etherscan.io" + +[[chain.ethereum.rpc-endpoints]] +name = "eth.llamarpc.com" +endpoint = "https://eth.llamarpc.com" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.ethereum.rpc-endpoints]] +name = "public.blastapi.io" +endpoint = "https://eth-mainnet.public.blastapi.io" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.ethereum.rpc-endpoints]] +name = "rpc.ankr.com/eth" +endpoint = "https://rpc.ankr.com/eth" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.ethereum.rpc-endpoints]] +name = "rpc.flashbots.net" +endpoint = "https://rpc.flashbots.net" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.ethereum.rpc-endpoints]] +name = "cloudflare-eth.com" +endpoint = "https://cloudflare-eth.com/" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.ethereum.rpc-endpoints]] +name = "ethereum.publicnode.com" +endpoint = "https://ethereum.publicnode.com" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.ethereum.rpc-endpoints]] +name = "chainstack" +endpoint = "https://chainstack.com/" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + + + [chain.goerli] chain-name = "Goerli" chain-id = 5 -rpc-endpoints = [ - "https://ethereum-goerli-rpc.allthatnode.com", - "https://rpc.slock.it/goerli", - "https://www.ethercluster.com/goerli", - "https://rpc.ankr.com/eth_goerli", -] currency-symbol = "tETH" -priority-fee = 1.01 -max-fee-per-gas = 300.0 +priority-fee = 0.000001 +max-fee-per-gas = 10.0 gas-left-warning-limit = 1000000 -transaction-timeout = 60 +transaction-timeout = 100 token = { address = "0x33af15c79d64b85ba14aaffaa4577949104b22e8", symbol = "tGLM" } multi-contract = { address = "0x7777784f803a7bf1d7f115f849d29ce5706da64a", max-at-once = 10 } -confirmation-blocks = 1 +faucet-client = { max-eth-allowed = 0.009, faucet-srv = "_eth-faucet._tcp", faucet-host = "faucet.testnet.golem.network", faucet-lookup-domain = "dev.golem.network", faucet-srv-port = 4001 } +mint-contract = { address = "0xCCA41b09C1F50320bFB41BD6822BD0cdBDC7d85C", max-glm-allowed = 400 } +confirmation-blocks = 0 block-explorer-url = "https://goerli.etherscan.io" +[[chain.goerli.rpc-endpoints]] +name = "eth-goerli.g.alchemy.com" +endpoint = "https://eth-goerli.g.alchemy.com/v2/demo" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.goerli.rpc-endpoints]] +name = "eth-goerli.public.blastapi.io" +endpoint = "https://eth-goerli.public.blastapi.io" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.goerli.rpc-endpoints]] +name = "eth-goerli.api.onfinality.io/public" +endpoint = "https://eth-goerli.api.onfinality.io/public" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.goerli.rpc-endpoints]] +name = "rpc.goerli.mudit.blog" +endpoint = "https://rpc.goerli.mudit.blog" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.goerli.rpc-endpoints]] +name = "endpoints.omniatech.io/v1/eth/goerli/public" +endpoint = "https://endpoints.omniatech.io/v1/eth/goerli/public" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.goerli.rpc-endpoints]] +name = "rpc.goerli.eth.gateway.fm" +endpoint = "https://rpc.goerli.eth.gateway.fm" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.goerli.rpc-endpoints]] +name = "goerli.blockpi.network/v1/rpc/public" +endpoint = "https://goerli.blockpi.network/v1/rpc/public" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.goerli.rpc-endpoints]] +name = "goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161" +endpoint = "https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.goerli.rpc-endpoints]] +name = "rpc.ankr.com/eth_goerli" +endpoint = "https://rpc.ankr.com/eth_goerli" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.goerli.rpc-endpoints]] +name = "ethereum-goerli-rpc.allthatnode.com" +endpoint = "https://ethereum-goerli-rpc.allthatnode.com" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.goerli.rpc-endpoints]] +name = "rpc.slock.it/goerli" +endpoint = "https://rpc.slock.it/goerli" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.goerli.rpc-endpoints]] +name = "www.ethercluster.com/goerli" +endpoint = "https://www.ethercluster.com/goerli" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.goerli.rpc-endpoints]] +name = "rpc.ankr.com/eth_goerli" +endpoint = "https://rpc.ankr.com/eth_goerli" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[chain.holesky] +chain-name = "Holesky" +chain-id = 17000 +currency-symbol = "tETH" +priority-fee = 0.000001 +max-fee-per-gas = 10.0 +gas-left-warning-limit = 1000000 +transaction-timeout = 100 +token = { address = "0x8888888815bf4DB87e57B609A50f938311EEd068", symbol = "tGLM" } +multi-contract = { address = "0xAaAAAaA00E1841A63342db7188abA84BDeE236c7", max-at-once = 10 } +mint-contract = { address = "0xFACe100969FF47EB58d2CF603321B581A84bcEaC", max-glm-allowed = 400 } +faucet-client = { max-eth-allowed = 0.009, faucet-srv = "_eth-faucet._tcp", faucet-host = "faucet.testnet.golem.network", faucet-lookup-domain = "dev.golem.network", faucet-srv-port = 4002 } +confirmation-blocks = 0 +block-explorer-url = "https://holesky.etherscan.io" + + + +[[chain.holesky.rpc-endpoints]] +name = "holesky.publicnode.com" +endpoint = "https://ethereum-holesky.publicnode.com" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.holesky.rpc-endpoints]] +name = "1rpc.io/holesky" +endpoint = "https://1rpc.io/holesky" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.holesky.rpc-endpoints]] +name = "rpc.ankr.com/eth_holesky" +endpoint = "https://rpc.ankr.com/eth_holesky" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.holesky.rpc-endpoints]] +name = "holesky.public.blastapi.io" +endpoint = "https://eth-holesky.public.blastapi.io" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.holesky.rpc-endpoints]] +name = "holesky.drpc.org" +endpoint = "https://holesky.drpc.org" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.holesky.rpc-endpoints]] +name = "gateway.tenderly.co" +endpoint = "https://holesky.gateway.tenderly.co" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + +[[chain.holesky.rpc-endpoints]] +name = "holesky.rpc.thirdweb.com" +endpoint = "https://holesky.rpc.thirdweb.com" +priority = 0 +max-timeout-ms = 5000 +verify-interval-secs = 60 +allowed-head-behind-secs = 120 + + + [chain.mumbai] chain-name = "Mumbai testnet" chain-id = 80001 -rpc-endpoints = [ - "https://rpc-mumbai.maticvigil.com/v1/fd04db1066cae0f44d3461ae6d6a7cbbdd46e4a5", -] -# rpc-endpoints = ["http://127.0.0.1:8545"] currency-symbol = "tMATIC" -priority-fee = 1.01 -max-fee-per-gas = 300.0 +priority-fee = 1.0 +max-fee-per-gas = 14.0 gas-left-warning-limit = 1000000 transaction-timeout = 60 token = { address = "0x2036807B0B3aaf5b1858EE822D0e111fDdac7018", symbol = "tGLM" } @@ -56,16 +306,145 @@ multi-contract = { address = "0x800010D7d0d315DCA795110ecCf0127cBd76b89f", max-a confirmation-blocks = 1 block-explorer-url = "https://mumbai.polygonscan.com" +[[chain.mumbai.rpc-endpoints]] +name = "g.alchemy.com/v2/demo" +endpoint = "https://polygon-mumbai.g.alchemy.com/v2/demo" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 60 + +[[chain.mumbai.rpc-endpoints]] +name = "blockpi.network/v1/rpc/public" +endpoint = "https://polygon-mumbai.blockpi.network/v1/rpc/public" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 60 + +[[chain.mumbai.rpc-endpoints]] +name = "public.blastapi.io/public" +endpoint = "https://polygon-testnet.public.blastapi.io" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 60 + +[[chain.mumbai.rpc-endpoints]] +name = "omniatech.io/mumbai/public" +endpoint = "https://endpoints.omniatech.io/v1/matic/mumbai/public" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 60 + +[[chain.mumbai.rpc-endpoints]] +name = "maticvigil.com/public" +endpoint = "https://rpc-mumbai.maticvigil.com" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 60 + +[[chain.mumbai.rpc-endpoints]] +name = "terminet.io/public" +endpoint = "https://polygontestapi.terminet.io/rpc" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 60 + +[[chain.mumbai.rpc-endpoints]] +name = "chainstacklabs.com/public" +endpoint = "https://matic-mumbai.chainstacklabs.com" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 60 + +[[chain.mumbai.rpc-endpoints]] +name = "archive-rpc.bwarelabs/public" +endpoint = "https://matic-testnet-archive-rpc.bwarelabs.com" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 60 + +[[chain.mumbai.rpc-endpoints]] +name = "rpc.ankr.com/public" +endpoint = "https://rpc.ankr.com/polygon_mumbai" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 60 + +[[chain.mumbai.rpc-endpoints]] +name = "lavanet.xyz" +endpoint = "https://g.w.lavanet.xyz:443/gateway/polygon1t/rpc-http/f7ee0000000000000000000000000000" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 60 + +[[chain.mumbai.rpc-endpoints]] +name = "archive.allthatnode.com" +endpoint = "https://polygon-testnet-archive.allthatnode.com:8545" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 120 + +[[chain.mumbai.rpc-endpoints]] +name = "rpc.allthatnode.com" +endpoint = "https://polygon-testnet-rpc.allthatnode.com:8545" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 120 + + [chain.polygon] chain-name = "Polygon mainnet" chain-id = 137 -rpc-endpoints = ["https://polygon-rpc.com"] currency-symbol = "MATIC" priority-fee = 30.111 max-fee-per-gas = 500.0 gas-left-warning-limit = 1000000 -transaction-timeout = 120 +transaction-timeout = 100 token = { address = "0x0B220b82F3eA3B7F6d9A1D8ab58930C064A2b5Bf", symbol = "GLM" } # multi-contract = { address = "0x50100d4faf5f3b09987dea36dc2eddd57a3e561b", max-at-once = 10 } confirmation-blocks = 1 block-explorer-url = "https://polygonscan.com" + +[[chain.polygon.rpc-endpoints]] +name = "polygon-rpc.com" +endpoint = "https://polygon-rpc.com" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 120 + +[[chain.polygon.rpc-endpoints]] +name = "maticvigil.com" +endpoint = "https://rpc-mainnet.maticvigil.com" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 120 + +[[chain.polygon.rpc-endpoints]] +name = "quiknode.pro" +endpoint = "https://rpc-mainnet.matic.quiknode.pro" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 120 + +[[chain.polygon.rpc-endpoints]] +name = "golem.network" +endpoint = "https://bor.golem.network" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 120 + +[[chain.polygon.rpc-endpoints]] +name = "allthatnode.com-archive" +endpoint = "https://polygon-mainnet-archive.allthatnode.com:8545" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 120 + +[[chain.polygon.rpc-endpoints]] +name = "allthatnode.com-norm" +endpoint = "https://polygon-mainnet-rpc.allthatnode.com:8545" +priority = 0 +max-timeout-ms = 5000 +allowed-head-behind-secs = 120 + + + diff --git a/core/payment-driver/erc20next/src/driver.rs b/core/payment-driver/erc20next/src/driver.rs index 23ccd6144f..6975716f4e 100644 --- a/core/payment-driver/erc20next/src/driver.rs +++ b/core/payment-driver/erc20next/src/driver.rs @@ -5,23 +5,26 @@ use chrono::{DateTime, Duration, Utc}; Please limit the logic in this file, use local mods to handle the calls. */ // Extrnal crates -use erc20_payment_lib::db::model::{TokenTransferDao, TxDao}; +use erc20_payment_lib::faucet_client::faucet_donate; +use erc20_payment_lib::model::{TokenTransferDao, TxDao}; use erc20_payment_lib::runtime::{ - DriverEvent, DriverEventContent, PaymentRuntime, TransferType, VerifyTransactionResult, + PaymentRuntime, TransferArgs, TransferType, VerifyTransactionResult, }; +use erc20_payment_lib::utils::{DecimalConvExt, U256ConvExt}; +use erc20_payment_lib::{DriverEvent, DriverEventContent}; use ethereum_types::H160; use ethereum_types::U256; use num_bigint::BigInt; use std::collections::HashMap; use std::str::FromStr; use std::sync::Arc; +use std::time::Instant; use tokio::sync::mpsc::Receiver; use tokio_util::task::LocalPoolHandle; use uuid::Uuid; use web3::types::H256; use ya_client_model::payment::DriverStatusProperty; -// Workspace uses use ya_payment_driver::{ account::{Accounts, AccountsArc}, bus, @@ -34,6 +37,7 @@ use ya_payment_driver::{ }; // Local uses +use crate::erc20::utils; use crate::erc20::utils::{big_dec_to_u256, u256_to_big_dec}; use crate::network::platform_to_currency; use crate::{driver::PaymentDetails, network}; @@ -103,15 +107,15 @@ impl Erc20NextDriver { let payment_id = Uuid::new_v4().to_simple().to_string(); self.payment_runtime - .transfer( - network, - sender, + .transfer(TransferArgs { + chain_name: network.to_string(), + from: sender, receiver, - TransferType::Token, + tx_type: TransferType::Token, amount, - &payment_id, + payment_id: payment_id.clone(), deadline, - ) + }) .await .map_err(|err| GenericError::new(format!("Error when inserting transfer {err:?}")))?; @@ -163,7 +167,7 @@ impl Erc20NextDriver { &self, msg: DriverStatus, ) -> Result, DriverStatusError> { - use erc20_payment_lib::runtime::StatusProperty as LibStatusProperty; + use erc20_payment_lib::StatusProperty as LibStatusProperty; // Map chain-id to network let chain_id_to_net = |id: i64| self.payment_runtime.network_name(id).unwrap().to_string(); @@ -202,7 +206,7 @@ impl Erc20NextDriver { } LibStatusProperty::CantSign { chain_id, address } => { let network = chain_id_to_net(chain_id); - Some(DriverStatusProperty::CantSign { + network_filter(&network).then(|| DriverStatusProperty::CantSign { driver: DRIVER_NAME.into(), network, address, @@ -234,6 +238,20 @@ impl Erc20NextDriver { needed_token_est: missing_token.to_string(), }) } + LibStatusProperty::TxStuck { chain_id } => { + let network = chain_id_to_net(chain_id); + network_filter(&network).then(|| DriverStatusProperty::TxStuck { + driver: DRIVER_NAME.into(), + network, + }) + } + LibStatusProperty::Web3RpcError { chain_id, .. } => { + let network = chain_id_to_net(chain_id); + network_filter(&network).then(|| DriverStatusProperty::RpcError { + driver: DRIVER_NAME.into(), + network, + }) + } }) .collect()) } @@ -243,7 +261,7 @@ impl Erc20NextDriver { token_transfer: &TokenTransferDao, tx: &TxDao, ) -> Result<(), GenericError> { - log::info!("Received event TransferFinished: {:#?}", token_transfer); + log::debug!("Received event TransferFinished: {:#?}", token_transfer); let chain_id = token_transfer.chain_id; let network_name = &self @@ -300,11 +318,11 @@ impl Erc20NextDriver { GenericError::new(format!("Malformed tx.tx_hash: {:?} {err}", tx_hash)) })?; - log::info!("name = {}", &self.get_name()); - log::info!("platform = {}", platform); - log::info!("order_id = {}", token_transfer.payment_id.as_ref().unwrap()); - log::info!("payment_details = {:#?}", payment_details); - log::info!("confirmation = {:x?}", transaction_hash); + log::info!("name: {}", &self.get_name()); + log::info!("platform: {}", platform); + log::info!("order_id: {}", token_transfer.payment_id.as_ref().unwrap()); + log::info!("payment_details: {}", payment_details); + log::info!("confirmation: 0x{}", hex::encode(&transaction_hash)); let Some(payment_id) = &token_transfer.payment_id else { return Err(GenericError::new("token_transfer.payment_id is null")); @@ -446,8 +464,302 @@ impl PaymentDriver for Erc20NextDriver { _caller: String, msg: Fund, ) -> Result { - log::info!("FUND = Not Implemented: {:?}", msg); - Ok("NOT_IMPLEMENTED".to_string()) + log::debug!("fund: {:?}", msg); + let address = msg.address(); + let network = network::network_like_to_network(msg.network()); + let result = { + let address = utils::str_to_addr(&address)?; + log::info!( + "Handling fund request. network={}, address={:#x}", + &network, + &address + ); + let chain_cfg = self + .payment_runtime + .setup + .chain_setup + .get(&(network as i64)) + .ok_or(GenericError::new(format!( + "Missing chain config for network {}", + network + )))?; + let _mint_contract_address = + chain_cfg + .faucet_setup + .mint_glm_address + .ok_or(GenericError::new(format!( + "Missing mint contract address for network {}", + network + )))?; + let mint_min_glm_allowed = + chain_cfg + .faucet_setup + .mint_max_glm_allowed + .ok_or(GenericError::new(format!( + "Missing mint min glm allowed for network {}", + network + )))?; + let faucet_client_max_eth_allowed = chain_cfg + .faucet_setup + .client_max_eth_allowed + .ok_or(GenericError::new(format!( + "Missing faucet client max eth allowed for network {}", + network + )))?; + + let starting_eth_balance = match self + .payment_runtime + .get_gas_balance(network.to_string(), address) + .await + { + Ok(balance) => { + log::info!("Gas balance is {}", balance.to_eth_str()); + balance + } + Err(err) => { + log::error!("Error getting gas balance: {}", err); + return Err(GenericError::new(format!( + "Error getting gas balance: {}", + err + ))); + } + }; + let starting_glm_balance = match self + .payment_runtime + .get_token_balance(network.to_string(), address) + .await + { + Ok(balance) => { + log::info!("tGLM balance is {}", balance.to_eth_str()); + balance + } + Err(err) => { + log::error!("Error getting tGLM balance: {}", err); + return Err(GenericError::new(format!( + "Error getting tGLM balance: {}", + err + ))); + } + }; + + let faucet_srv_prefix = + chain_cfg + .faucet_setup + .client_srv + .clone() + .ok_or(GenericError::new(format!( + "Missing faucet_srv_port for network {}", + network + )))?; + let faucet_lookup_domain = + chain_cfg + .faucet_setup + .lookup_domain + .clone() + .ok_or(GenericError::new(format!( + "Missing faucet_lookup_domain for network {}", + network + )))?; + let faucet_srv_port = + chain_cfg + .faucet_setup + .srv_port + .ok_or(GenericError::new(format!( + "Missing faucet_srv_port for network {}", + network + )))?; + let faucet_host = + chain_cfg + .faucet_setup + .client_host + .clone() + .ok_or(GenericError::new(format!( + "Missing faucet_host for network {}", + network + )))?; + + let eth_received = if starting_eth_balance + < faucet_client_max_eth_allowed + .to_u256_from_eth() + .map_err(|err| { + GenericError::new(format!( + "faucet_client_max_eth_allowed failed to convert {}", + err + )) + })? { + match faucet_donate( + &faucet_srv_prefix, + &faucet_lookup_domain, + &faucet_host, + faucet_srv_port, + address, + ) + .await + { + Ok(_) => { + log::info!("Faucet donation successful"); + } + Err(e) => { + log::error!("Error donating from faucet: {}", e); + } + } + let time_now = Instant::now(); + let mut iteration = -1; + loop { + iteration += 1; + if iteration == 0 { + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + } else { + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + } + if time_now.elapsed().as_secs() > 120 { + log::error!( + "Faucet donation not received after {} seconds", + time_now.elapsed().as_secs() + ); + return Err(GenericError::new(format!( + "Faucet donation not received after {} seconds", + time_now.elapsed().as_secs() + ))); + } + match self + .payment_runtime + .get_gas_balance(network.to_string(), address) + .await + { + Ok(current_balance) => { + if current_balance > starting_eth_balance { + log::info!( + "Received {} ETH from faucet", + (current_balance - starting_eth_balance).to_eth_str() + ); + break current_balance - starting_eth_balance; + } else { + log::info!("Waiting for ETH from faucet. Current balance: {}. Elapsed: {}/{}", current_balance.to_eth_str(), time_now.elapsed().as_secs(), 120); + } + } + Err(err) => { + log::error!("Error getting gas balance: {}", err); + } + } + } + } else { + log::info!( + "ETH balance is {} which is more than {} allowed by faucet", + starting_eth_balance.to_eth_str(), + faucet_client_max_eth_allowed + ); + U256::zero() + }; + + let glm_received = if starting_glm_balance + < mint_min_glm_allowed.to_u256_from_eth().map_err(|err| { + GenericError::new(format!("mint_min_glm_allowed failed to convert {}", err)) + })? { + match self + .payment_runtime + .mint_golem_token(&network.to_string(), address) + .await + { + Ok(_) => { + log::info!("Added mint tGLM transaction to queue {}", address); + } + Err(e) => { + log::error!("Error minting tGLM tokens for address {}: {}", address, e); + } + } + let time_now = Instant::now(); + let mut iteration = -1; + loop { + iteration += 1; + if iteration == 0 { + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + } else { + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + } + if time_now.elapsed().as_secs() > 120 { + log::error!( + "Mint transaction not finished after {} seconds", + time_now.elapsed().as_secs() + ); + return Err(GenericError::new(format!( + "Mint transaction not finished after {} seconds", + time_now.elapsed().as_secs() + ))); + } + match self + .payment_runtime + .get_token_balance(network.to_string(), address) + .await + { + Ok(current_balance) => { + if current_balance > starting_glm_balance { + log::info!( + "Created {} tGLM using mint transaction", + (current_balance - starting_glm_balance).to_eth_str() + ); + break current_balance - starting_glm_balance; + } else { + log::info!( + "Waiting for mint result. Current balance: {}. Elapsed: {}/{}", + current_balance.to_eth_str(), + time_now.elapsed().as_secs(), + 120 + ); + } + } + Err(err) => { + log::error!("Error getting tGLM balance: {}", err); + } + } + } + } else { + log::info!( + "tGLM balance is {} which is more than allowed by GLM minting contract {}", + starting_glm_balance.to_eth_str(), + mint_min_glm_allowed + ); + U256::zero() + }; + let mut str_output = if eth_received > U256::zero() || glm_received > U256::zero() { + format!( + "Successfully received {} ETH and {} tGLM", + eth_received.to_eth_str(), + glm_received.to_eth_str() + ) + } else if eth_received > U256::zero() { + format!("Successfully received {} ETH", eth_received.to_eth_str()) + } else if glm_received > U256::zero() { + format!("Successfully minted {} tGLM", glm_received.to_eth_str()) + } else { + "No funds received".to_string() + }; + let final_eth_balance = match self + .payment_runtime + .get_gas_balance(network.to_string(), address) + .await + { + Ok(balance) => { + log::info!("Gas balance is {}", balance.to_eth_str()); + balance + } + Err(err) => { + log::error!("Error getting gas balance: {}", err); + return Err(GenericError::new(format!( + "Error getting gas balance: {}", + err + ))); + } + }; + str_output += &format!( + "\nYou have {} tETH and {} tGLM", + final_eth_balance.to_eth_str(), + (starting_glm_balance + glm_received).to_eth_str() + ); + str_output + }; + log::debug!("fund completed"); + Ok(result) } async fn transfer( @@ -544,7 +856,7 @@ impl PaymentDriver for Erc20NextDriver { caller: String, msg: ValidateAllocation, ) -> Result { - log::info!("Validate_allocation: {:?}", msg); + log::debug!("Validate_allocation: {:?}", msg); let account_balance = self .get_account_balance( db, diff --git a/core/payment-driver/erc20next/src/erc20/config.rs b/core/payment-driver/erc20next/src/erc20/config.rs index c6b36aee96..cce6215869 100644 --- a/core/payment-driver/erc20next/src/erc20/config.rs +++ b/core/payment-driver/erc20next/src/erc20/config.rs @@ -74,6 +74,26 @@ lazy_static! { } } }; + pub static ref HOLESKY_CONFIG: EnvConfiguration = EnvConfiguration { + glm_contract_address: utils::str_to_addr( + &env::var("HOLESKY_TGLM_CONTRACT_ADDRESS") + .unwrap_or_else(|_| "0x8888888815bf4DB87e57B609A50f938311EEd068".to_string()) + ) + .unwrap(), + glm_faucet_address: Some( + utils::str_to_addr( + &env::var("HOLESKY_TGLM_FAUCET_ADDRESS") + .unwrap_or_else(|_| "0xFACe100969FF47EB58d2CF603321B581A84bcEaC".to_string()) + ) + .unwrap() + ), + required_confirmations: { + match env::var("ERC20_HOLESKY_REQUIRED_CONFIRMATIONS").map(|s| s.parse()) { + Ok(Ok(x)) => x, + _ => 3, + } + } + }; pub static ref MUMBAI_CONFIG: EnvConfiguration = EnvConfiguration { glm_contract_address: utils::str_to_addr( &env::var("MUMBAI_TGLM_CONTRACT_ADDRESS") diff --git a/core/payment-driver/erc20next/src/erc20/ethereum.rs b/core/payment-driver/erc20next/src/erc20/ethereum.rs index 40f3e5c00f..4961b4e658 100644 --- a/core/payment-driver/erc20next/src/erc20/ethereum.rs +++ b/core/payment-driver/erc20next/src/erc20/ethereum.rs @@ -538,6 +538,10 @@ fn get_rpc_addr_from_env(network: Network) -> Vec { Network::Goerli => { collect_rpc_addr_from("GOERLI_GETH_ADDR", "https://rpc.ankr.com/eth_goerli") } + Network::Holesky => collect_rpc_addr_from( + "HOLESKY_GETH_ADDR", + "https://ethereum-holesky.publicnode.com", + ), Network::Polygon => collect_rpc_addr_from( "POLYGON_GETH_ADDR", "https://bor.golem.network,https://polygon-rpc.com", @@ -592,6 +596,7 @@ fn get_env(network: Network) -> config::EnvConfiguration { Network::Mainnet => *config::MAINNET_CONFIG, Network::Rinkeby => *config::RINKEBY_CONFIG, Network::Goerli => *config::GOERLI_CONFIG, + Network::Holesky => *config::HOLESKY_CONFIG, Network::Mumbai => *config::MUMBAI_CONFIG, Network::Polygon => *config::POLYGON_MAINNET_CONFIG, } diff --git a/core/payment-driver/erc20next/src/lib.rs b/core/payment-driver/erc20next/src/lib.rs index f94eb5ce85..f925e8fe8b 100644 --- a/core/payment-driver/erc20next/src/lib.rs +++ b/core/payment-driver/erc20next/src/lib.rs @@ -19,6 +19,12 @@ pub const GOERLI_PLATFORM: &str = "erc20next-goerli-tglm"; pub const GOERLI_CURRENCY_SHORT: &str = "tETH"; pub const GOERLI_CURRENCY_LONG: &str = "Goerli Ether"; +pub const HOLESKY_NETWORK: &str = "holesky"; +pub const HOLESKY_TOKEN: &str = "tGLM"; +pub const HOLESKY_PLATFORM: &str = "erc20next-holesky-tglm"; +pub const HOLESKY_CURRENCY_SHORT: &str = "tETH"; +pub const HOLESKY_CURRENCY_LONG: &str = "Holesky Ether"; + pub const MUMBAI_NETWORK: &str = "mumbai"; pub const MUMBAI_TOKEN: &str = "tGLM"; pub const MUMBAI_PLATFORM: &str = "erc20next-mumbai-tglm"; diff --git a/core/payment-driver/erc20next/src/network.rs b/core/payment-driver/erc20next/src/network.rs index f7ff83426a..d69e9b46e7 100644 --- a/core/payment-driver/erc20next/src/network.rs +++ b/core/payment-driver/erc20next/src/network.rs @@ -8,9 +8,10 @@ use ya_payment_driver::{db::models::Network as DbNetwork, driver::Network, model // Local uses use crate::{ GOERLI_CURRENCY_LONG, GOERLI_CURRENCY_SHORT, GOERLI_NETWORK, GOERLI_PLATFORM, GOERLI_TOKEN, - MAINNET_CURRENCY_LONG, MAINNET_CURRENCY_SHORT, MAINNET_NETWORK, MAINNET_PLATFORM, - MAINNET_TOKEN, MUMBAI_CURRENCY_LONG, MUMBAI_CURRENCY_SHORT, MUMBAI_NETWORK, MUMBAI_PLATFORM, - MUMBAI_TOKEN, POLYGON_MAINNET_CURRENCY_LONG, POLYGON_MAINNET_CURRENCY_SHORT, + HOLESKY_CURRENCY_LONG, HOLESKY_CURRENCY_SHORT, HOLESKY_NETWORK, HOLESKY_PLATFORM, + HOLESKY_TOKEN, MAINNET_CURRENCY_LONG, MAINNET_CURRENCY_SHORT, MAINNET_NETWORK, + MAINNET_PLATFORM, MAINNET_TOKEN, MUMBAI_CURRENCY_LONG, MUMBAI_CURRENCY_SHORT, MUMBAI_NETWORK, + MUMBAI_PLATFORM, MUMBAI_TOKEN, POLYGON_MAINNET_CURRENCY_LONG, POLYGON_MAINNET_CURRENCY_SHORT, POLYGON_MAINNET_NETWORK, POLYGON_MAINNET_PLATFORM, POLYGON_MAINNET_TOKEN, RINKEBY_CURRENCY_LONG, RINKEBY_CURRENCY_SHORT, RINKEBY_NETWORK, RINKEBY_PLATFORM, RINKEBY_TOKEN, @@ -30,6 +31,12 @@ lazy_static::lazy_static! { GOERLI_TOKEN.to_string() => GOERLI_PLATFORM.to_string() } }, + HOLESKY_NETWORK.to_string() => Network { + default_token: HOLESKY_TOKEN.to_string(), + tokens: hashmap! { + HOLESKY_TOKEN.to_string() => HOLESKY_PLATFORM.to_string() + } + }, MAINNET_NETWORK.to_string() => Network { default_token: MAINNET_TOKEN.to_string(), tokens: hashmap! { @@ -51,6 +58,7 @@ lazy_static::lazy_static! { }; pub static ref RINKEBY_DB_NETWORK: DbNetwork = DbNetwork::from_str(RINKEBY_NETWORK).unwrap(); pub static ref GOERLI_DB_NETWORK: DbNetwork = DbNetwork::from_str(GOERLI_NETWORK).unwrap(); + pub static ref HOLESKY_DB_NETWORK: DbNetwork = DbNetwork::from_str(HOLESKY_NETWORK).unwrap(); pub static ref MAINNET_DB_NETWORK: DbNetwork = DbNetwork::from_str(MAINNET_NETWORK).unwrap(); pub static ref MUMBAI_DB_NETWORK: DbNetwork = DbNetwork::from_str(MUMBAI_NETWORK).unwrap(); pub static ref POLYGON_MAINNET_DB_NETWORK: DbNetwork = DbNetwork::from_str(POLYGON_MAINNET_NETWORK).unwrap(); @@ -60,6 +68,7 @@ pub fn platform_to_network_token(platform: String) -> Result<(DbNetwork, String) match platform.as_str() { RINKEBY_PLATFORM => Ok((*RINKEBY_DB_NETWORK, RINKEBY_TOKEN.to_owned())), GOERLI_PLATFORM => Ok((*GOERLI_DB_NETWORK, GOERLI_TOKEN.to_owned())), + HOLESKY_PLATFORM => Ok((*HOLESKY_DB_NETWORK, HOLESKY_TOKEN.to_owned())), MAINNET_PLATFORM => Ok((*MAINNET_DB_NETWORK, MAINNET_TOKEN.to_owned())), MUMBAI_PLATFORM => Ok((*MUMBAI_DB_NETWORK, MUMBAI_TOKEN.to_owned())), POLYGON_MAINNET_PLATFORM => Ok(( @@ -83,6 +92,10 @@ pub fn platform_to_currency(platform: String) -> Result<(String, String), Generi GOERLI_CURRENCY_SHORT.to_owned(), GOERLI_CURRENCY_LONG.to_owned(), )), + HOLESKY_PLATFORM => Ok(( + HOLESKY_CURRENCY_SHORT.to_owned(), + HOLESKY_CURRENCY_LONG.to_owned(), + )), MAINNET_PLATFORM => Ok(( MAINNET_CURRENCY_SHORT.to_owned(), MAINNET_CURRENCY_LONG.to_owned(), @@ -111,7 +124,7 @@ pub fn get_network_token(network: DbNetwork, token: Option) -> String { pub fn network_like_to_network(network_like: Option) -> DbNetwork { match network_like { - Some(n) => DbNetwork::from_str(&n).unwrap_or(*RINKEBY_DB_NETWORK), - None => *RINKEBY_DB_NETWORK, + Some(n) => DbNetwork::from_str(&n).unwrap_or(*HOLESKY_DB_NETWORK), + None => *HOLESKY_DB_NETWORK, } } diff --git a/core/payment-driver/erc20next/src/service.rs b/core/payment-driver/erc20next/src/service.rs index bf1cc1797b..753794f1c0 100644 --- a/core/payment-driver/erc20next/src/service.rs +++ b/core/payment-driver/erc20next/src/service.rs @@ -5,10 +5,11 @@ use std::{env, path::PathBuf, str::FromStr}; // External crates use erc20_payment_lib::config; -use erc20_payment_lib::config::{AdditionalOptions, MultiContractSettings}; +use erc20_payment_lib::config::{AdditionalOptions, MultiContractSettings, RpcSettings}; use erc20_payment_lib::misc::load_private_keys; -use erc20_payment_lib::runtime::PaymentRuntime; +use erc20_payment_lib::runtime::{PaymentRuntime, PaymentRuntimeArgs}; use ethereum_types::H160; +//use rust_decimal::Decimal; // Workspace uses use ya_payment_driver::{ @@ -101,7 +102,22 @@ impl Erc20NextService { let confirmations_env = format!("ERC20NEXT_{prefix}_REQUIRED_CONFIRMATIONS"); if let Ok(addr) = env::var(&rpc_env) { - chain.rpc_endpoints = addr.split(',').map(ToOwned::to_owned).collect(); + chain.rpc_endpoints = addr + .split(',') + .map(|s| RpcSettings { + names: Some(s.to_string()), + endpoints: Some(s.to_string()), + skip_validation: None, + backup_level: None, + verify_interval_secs: None, + min_interval_ms: None, + max_timeout_ms: None, + allowed_head_behind_secs: None, + max_consecutive_errors: None, + dns_source: None, + json_source: None, + }) + .collect(); log::info!( "{} rpc endpoints set to {:?}", network, @@ -109,7 +125,7 @@ impl Erc20NextService { ) } if let Ok(fee) = env::var(&priority_fee_env) { - match fee.parse::() { + match rust_decimal::Decimal::from_str(&fee) { Ok(fee) => { log::info!("{network} priority fee set to {fee}"); chain.priority_fee = fee; @@ -120,7 +136,7 @@ impl Erc20NextService { } } if let Ok(max_fee) = env::var(&max_fee_per_gas_env) { - match max_fee.parse::() { + match rust_decimal::Decimal::from_str(&max_fee) { Ok(max_fee) => { log::info!("{network} max fee per gas set to {max_fee}"); chain.max_fee_per_gas = max_fee; @@ -182,17 +198,18 @@ impl Erc20NextService { let (sender, recv) = tokio::sync::mpsc::channel(16); let pr = PaymentRuntime::new( - &private_keys, - &path.join("erc20next.sqlite"), - config, + PaymentRuntimeArgs { + secret_keys: private_keys, + db_filename: path.join("erc20next.sqlite"), + config, + conn: None, + options: Some(additional_options), + event_sender: Some(sender), + extra_testing: None, + }, signer, - None, - Some(additional_options), - Some(sender), - None, ) - .await - .unwrap(); + .await?; log::debug!("Bind erc20next driver"); let driver = Erc20NextDriver::new(pr, recv); diff --git a/core/payment-driver/erc20next/src/signer.rs b/core/payment-driver/erc20next/src/signer.rs index 8ddb699a84..ffac30ba57 100644 --- a/core/payment-driver/erc20next/src/signer.rs +++ b/core/payment-driver/erc20next/src/signer.rs @@ -65,7 +65,11 @@ impl web3::signing::Key for DummyKey { s: Default::default(), }) } else { - eprintln!("({}) {:?}", state.signed.len(), &state.signed); + log::debug!( + "Signed message: ({}) {:?}", + state.signed.len(), + &state.signed + ); Ok(Signature { v: state.signed[0] as u64, r: H256::from_slice(&state.signed[1..33]), diff --git a/core/payment/src/cli.rs b/core/payment/src/cli.rs index faa46de68a..e893d99bad 100644 --- a/core/payment/src/cli.rs +++ b/core/payment/src/cli.rs @@ -140,6 +140,15 @@ impl PaymentCli { receive: false, }) .await?; + let warn_message = r#"Sending fund request to yagna service, observe yagna log for details. +Typically operation should take less than 1 minute. + It may get stuck due to + 1. problems with web3 RPC connection + 2. unusual high gas price + 3. problems with faucet + If stuck for too long you can stop safely with Ctrl-C and try again later +"#; + log::warn!("{}", warn_message); CommandOutput::object( wallet::fund(address, account.driver(), Some(account.network()), None).await?, diff --git a/core/payment/src/lib.rs b/core/payment/src/lib.rs index 654644468c..fabfa3dfd5 100644 --- a/core/payment/src/lib.rs +++ b/core/payment/src/lib.rs @@ -66,7 +66,9 @@ impl PaymentService { } pub async fn shut_down() { - log::info!("Stopping payment service... It may take up to 10 seconds to send out all transactions. Hit Ctrl+C again to interrupt and shut down immediately."); + log::info!( + "Stopping payment service... Hit Ctrl+C again to interrupt and shut down immediately." + ); let timeout = tokio::time::timeout( *PAYMENT_SHUTDOWN_TIMEOUT, diff --git a/core/payment/src/processor.rs b/core/payment/src/processor.rs index 63268ee0fe..e5ddd3ac2c 100644 --- a/core/payment/src/processor.rs +++ b/core/payment/src/processor.rs @@ -430,7 +430,6 @@ impl PaymentProcessor { .send(driver::SignPayment(payment.clone())) .await??; - log::warn!("####### payment: {:?}, signature {:?}", payment, signature); counter!("payment.amount.sent", ya_metrics::utils::cryptocurrency_to_u64(&msg.amount), "platform" => payment_platform); // This is unconditional because at this point the invoice *has been paid*. // Whether the provider was correctly notified of this fact is another matter. diff --git a/core/serv/src/main.rs b/core/serv/src/main.rs index 8fc1848ac8..6240812cfe 100644 --- a/core/serv/src/main.rs +++ b/core/serv/src/main.rs @@ -7,6 +7,7 @@ use metrics::gauge; #[cfg(feature = "static-openssl")] extern crate openssl_probe; +use std::sync::Arc; use std::{ any::TypeId, collections::HashMap, @@ -566,6 +567,12 @@ impl ServiceCommand { ya_net::hybrid::send_bcast_new_neighbour().await }); + let number_of_workers = env::var("YAGNA_HTTP_WORKERS") + .ok() + .and_then(|x| x.parse().ok()) + .unwrap_or_else(num_cpus::get) + .clamp(1, 256); + let count_started = Arc::new(std::sync::atomic::AtomicUsize::new(0)); let server = HttpServer::new(move || { let app = App::new() .wrap(middleware::Logger::default()) @@ -574,9 +581,18 @@ impl ServiceCommand { .route("/me", web::get().to(me)) .service(forward_gsb); let rest = Services::rest(app, &context); - log::info!("Http server thread started on: {}", rest_address); + if count_started.fetch_add(1, std::sync::atomic::Ordering::Relaxed) + == number_of_workers - 1 + { + log::info!( + "All {} http workers started - listening on {}", + number_of_workers, + rest_address + ); + } rest }) + .workers(number_of_workers) // this is maximum supported timeout for our REST API .keep_alive(std::time::Duration::from_secs(*max_rest_timeout)) .bind(api_host_port.clone()) diff --git a/golem_cli/src/command/yagna.rs b/golem_cli/src/command/yagna.rs index e1cf8e9f06..7c75c8b938 100644 --- a/golem_cli/src/command/yagna.rs +++ b/golem_cli/src/command/yagna.rs @@ -54,6 +54,14 @@ lazy_static! { token: "tGLM", }, ); + erc20.insert( + NetworkName::Holesky.into(), + PaymentPlatform { + platform: "erc20-holesky-tglm", + driver: "erc20", + token: "tGLM", + }, + ); erc20.insert( NetworkName::Mumbai.into(), PaymentPlatform { @@ -102,6 +110,14 @@ lazy_static! { token: "tGLM", }, ); + erc20next.insert( + NetworkName::Holesky.into(), + PaymentPlatform { + platform: "erc20next-holesky-tglm", + driver: "erc20next", + token: "tGLM", + }, + ); erc20next.insert( NetworkName::Mumbai.into(), PaymentPlatform { @@ -127,10 +143,7 @@ lazy_static! { // Drivers are searched in order when more than one supports a given network, // so erc20next should be preferred over erc20. - // - // If ERC20NEXT_DRIVER isn't here, that's because we wish to use ERC20 on master only. This will - // be re-enabled shortly. - pub static ref DRIVERS: Vec<&'static PaymentDriver> = vec![&ERC20_DRIVER]; + pub static ref DRIVERS: Vec<&'static PaymentDriver> = vec![&ERC20NEXT_DRIVER, &ERC20_DRIVER]; } impl PaymentDriver { @@ -182,6 +195,7 @@ lazy_static! { vec![ NetworkName::Rinkeby, NetworkName::Mumbai, + NetworkName::Holesky, NetworkName::Goerli, ], ); diff --git a/goth_tests/pyproject.toml b/goth_tests/pyproject.toml index 4d5834d0ca..be328b4788 100644 --- a/goth_tests/pyproject.toml +++ b/goth_tests/pyproject.toml @@ -8,10 +8,7 @@ version = "0.1.1" description = "Integration tests for yagna" authors = ["GolemFactory "] license = "LGPL-3.0-or-later" -classifiers = [ - "Development Status :: 3 - Alpha", - "Framework :: AsyncIO", -] +classifiers = ["Development Status :: 3 - Alpha", "Framework :: AsyncIO"] repository = "https://github.com/golemfactory/yagna" documentation = "https://docs.golem.network" readme = "README.md"