Remove eth feature, and BBBC related code (#1612)

* Remove eth feature, and BBBC related code

* Burn some more, especially clients
This commit is contained in:
Drazen Urch
2022-09-15 13:58:44 +02:00
committed by GitHub
parent e804b014a8
commit 16ef1c547b
94 changed files with 299 additions and 5316 deletions
Generated
+177 -194
View File
@@ -81,6 +81,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
@@ -92,9 +101,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.64"
version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9a8f622bcf6ff3df478e9deba3e03e4e04b300f8e6a139e192c05fa3490afc7"
checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
[[package]]
name = "arrayref"
@@ -173,23 +182,6 @@ dependencies = [
"autocfg 1.1.0",
]
[[package]]
name = "attohttpc"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e69e13a99a7e6e070bb114f7ff381e58c7ccc188630121fc4c2fe4bcf24cd072"
dependencies = [
"flate2",
"http",
"log",
"native-tls",
"openssl",
"serde",
"serde_json",
"url",
"wildmatch",
]
[[package]]
name = "atty"
version = "0.2.14"
@@ -218,9 +210,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "axum"
version = "0.5.15"
version = "0.5.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9de18bc5f2e9df8f52da03856bf40e29b747de5a84e43aefff90e3dc4a21529b"
checksum = "c9e3356844c4d6a6d6467b8da2cffb4a2820be256f50a3a386c9d152bab31043"
dependencies = [
"async-trait",
"axum-core",
@@ -247,9 +239,9 @@ dependencies = [
[[package]]
name = "axum-core"
version = "0.2.7"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4f44a0e6200e9d11a1cdc989e4b358f6e3d354fbf48478f345a17f4e43f8635"
checksum = "d9f0c0a60006f2a293d82d571f635042a72edf927539b7685bd62d361963839b"
dependencies = [
"async-trait",
"bytes",
@@ -257,6 +249,8 @@ dependencies = [
"http",
"http-body",
"mime",
"tower-layer",
"tower-service",
]
[[package]]
@@ -548,10 +542,11 @@ dependencies = [
[[package]]
name = "chrono"
version = "0.4.20"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6127248204b9aba09a362f6c930ef6a78f2c1b2215f8a7b398c06e1083f17af0"
checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
dependencies = [
"iana-time-zone",
"js-sys",
"num-integer",
"num-traits",
@@ -593,9 +588,9 @@ dependencies = [
[[package]]
name = "clap"
version = "3.2.20"
version = "3.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd"
checksum = "1ed5341b2301a26ab80be5cbdced622e80ed808483c52e45e3310a877d3b37d7"
dependencies = [
"atty",
"bitflags",
@@ -610,11 +605,11 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "3.2.4"
version = "3.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4179da71abd56c26b54dd0c248cc081c1f43b0a1a7e8448e28e57a29baa993d"
checksum = "3f7a2e0a962c45ce25afce14220bc24f9dade0a1787f185cecf96bfba7847cd8"
dependencies = [
"clap 3.2.20",
"clap 3.2.21",
]
[[package]]
@@ -623,7 +618,7 @@ version = "3.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed37b4c0c1214673eba6ad8ea31666626bf72be98ffb323067d973c48b4964b9"
dependencies = [
"clap 3.2.20",
"clap 3.2.21",
"clap_complete",
]
@@ -736,7 +731,6 @@ version = "0.1.0"
dependencies = [
"cfg-if 1.0.0",
"handlebars",
"humantime-serde",
"log",
"network-defaults",
"serde",
@@ -965,7 +959,7 @@ dependencies = [
"async-trait",
"bip39",
"cfg-if 0.1.10",
"clap 3.2.20",
"clap 3.2.21",
"coconut-interface",
"config",
"credential-storage",
@@ -988,7 +982,6 @@ version = "0.1.0"
dependencies = [
"async-trait",
"log",
"nymcoconut",
"sqlx 0.5.13",
"thiserror",
"tokio",
@@ -1139,7 +1132,6 @@ dependencies = [
"blake3",
"bs58",
"cipher 0.4.3",
"config",
"ctr 0.9.1",
"digest 0.10.3",
"ed25519-dalek",
@@ -1606,7 +1598,16 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2953d1df47ac0eb70086ccabf0275aa8da8591a28bd358ee2b52bd9f9e3ff9e9"
dependencies = [
"enum-iterator-derive",
"enum-iterator-derive 0.8.1",
]
[[package]]
name = "enum-iterator"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45a0ac4aeb3a18f92eaf09c6bb9b3ac30ff61ca95514fc58cbead1c9a6bf5401"
dependencies = [
"enum-iterator-derive 1.1.0",
]
[[package]]
@@ -1620,6 +1621,17 @@ dependencies = [
"syn",
]
[[package]]
name = "enum-iterator-derive"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "828de45d0ca18782232dfb8f3ea9cc428e8ced380eb26a520baaacfc70de39ce"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "env_logger"
version = "0.7.1"
@@ -1704,7 +1716,7 @@ name = "explorer-api"
version = "1.0.1"
dependencies = [
"chrono",
"clap 3.2.20",
"clap 3.2.21",
"humantime-serde",
"isocountry",
"itertools",
@@ -1874,11 +1886,10 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
version = "1.0.1"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
dependencies = [
"matches",
"percent-encoding",
]
@@ -2048,7 +2059,6 @@ dependencies = [
"futures",
"gateway-requests",
"getrandom 0.2.7",
"json",
"log",
"network-defaults",
"nymsphinx",
@@ -2176,9 +2186,9 @@ dependencies = [
[[package]]
name = "git2"
version = "0.15.0"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2994bee4a3a6a51eb90c218523be382fd7ea09b16380b9312e9dbe955ff7c7d1"
checksum = "d0155506aab710a86160ddb504a480d2964d7ab5b9e62419be69e0032bc5931c"
dependencies = [
"bitflags",
"libc",
@@ -2244,7 +2254,7 @@ dependencies = [
"indexmap",
"slab",
"tokio",
"tokio-util 0.7.3",
"tokio-util 0.7.4",
"tracing",
]
@@ -2579,6 +2589,20 @@ dependencies = [
"tokio-native-tls",
]
[[package]]
name = "iana-time-zone"
version = "0.1.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "237a0714f28b1ee39ccec0770ccb544eb02c9ef2c82bb096230eefcffa6468b0"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"js-sys",
"once_cell",
"wasm-bindgen",
"winapi",
]
[[package]]
name = "ident_case"
version = "1.0.1"
@@ -2723,9 +2747,9 @@ dependencies = [
[[package]]
name = "itertools"
version = "0.10.3"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
checksum = "d8bf247779e67a9082a4790b45e71ac7cfd1321331a5c856a74a9faebdab78d0"
dependencies = [
"either",
]
@@ -2760,12 +2784,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "json"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd"
[[package]]
name = "jsonrpc-core"
version = "18.0.0"
@@ -2821,9 +2839,9 @@ checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
[[package]]
name = "libgit2-sys"
version = "0.14.0+1.5.0"
version = "0.13.4+1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47a00859c70c8a4f7218e6d1cc32875c4b55f6799445b842b0d8ed5e4c3d959b"
checksum = "d0fa6563431ede25f5cc7f6d803c6afbc1c5d3ad3d4925d12c882bf2b526f5d1"
dependencies = [
"cc",
"libc",
@@ -2995,7 +3013,7 @@ dependencies = [
"log",
"nymsphinx",
"tokio",
"tokio-util 0.7.3",
"tokio-util 0.7.4",
]
[[package]]
@@ -3021,11 +3039,9 @@ version = "0.1.0"
dependencies = [
"bytes",
"crypto",
"dashmap",
"futures",
"humantime-serde",
"log",
"nonexhaustive-delayqueue",
"nymsphinx-acknowledgements",
"nymsphinx-addressing",
"nymsphinx-forwarding",
@@ -3036,7 +3052,7 @@ dependencies = [
"serde",
"task",
"tokio",
"tokio-util 0.7.3",
"tokio-util 0.7.4",
"url",
"validator-client",
"version-checker",
@@ -3058,7 +3074,7 @@ dependencies = [
"mime",
"spin 0.9.4",
"tokio",
"tokio-util 0.7.3",
"tokio-util 0.7.4",
"version_check",
]
@@ -3121,7 +3137,7 @@ version = "0.1.0"
dependencies = [
"tokio",
"tokio-stream",
"tokio-util 0.7.3",
"tokio-util 0.7.4",
]
[[package]]
@@ -3191,7 +3207,7 @@ dependencies = [
"base64",
"bip39",
"bs58",
"clap 3.2.20",
"clap 3.2.21",
"clap_complete",
"clap_complete_fig",
"dotenv",
@@ -3213,7 +3229,7 @@ dependencies = [
"bip39",
"bs58",
"cfg-if 1.0.0",
"clap 3.2.20",
"clap 3.2.21",
"comfy-table",
"cosmrs",
"cosmwasm-std",
@@ -3238,7 +3254,7 @@ dependencies = [
name = "nym-client"
version = "1.0.2"
dependencies = [
"clap 3.2.20",
"clap 3.2.21",
"client-core",
"coconut-interface",
"config",
@@ -3264,7 +3280,7 @@ dependencies = [
"topology",
"url",
"validator-client",
"vergen",
"vergen 5.1.17",
"version-checker",
"websocket-requests",
]
@@ -3275,10 +3291,9 @@ version = "1.0.2"
dependencies = [
"anyhow",
"async-trait",
"bandwidth-claim-contract",
"bip39",
"bs58",
"clap 3.2.20",
"clap 3.2.21",
"coconut-interface",
"colored",
"config",
@@ -3288,7 +3303,6 @@ dependencies = [
"dirs",
"dotenv",
"futures",
"gateway-client",
"gateway-requests",
"humantime-serde",
"log",
@@ -3308,13 +3322,12 @@ dependencies = [
"tokio",
"tokio-stream",
"tokio-tungstenite 0.14.0",
"tokio-util 0.7.3",
"tokio-util 0.7.4",
"url",
"validator-api-requests",
"validator-client",
"vergen",
"vergen 5.1.17",
"version-checker",
"web3",
]
[[package]]
@@ -3323,7 +3336,7 @@ version = "1.0.2"
dependencies = [
"anyhow",
"bs58",
"clap 3.2.20",
"clap 3.2.21",
"colored",
"config",
"crypto",
@@ -3348,12 +3361,12 @@ dependencies = [
"sysinfo",
"task",
"tokio",
"tokio-util 0.7.3",
"tokio-util 0.7.4",
"toml",
"topology",
"url",
"validator-client",
"vergen",
"vergen 5.1.17",
"version-checker",
]
@@ -3362,7 +3375,7 @@ name = "nym-network-requester"
version = "1.0.2"
dependencies = [
"async-trait",
"clap 3.2.20",
"clap 3.2.21",
"dirs",
"futures",
"ipnetwork",
@@ -3377,7 +3390,7 @@ dependencies = [
"reqwest",
"serde",
"socks5-requests",
"sqlx 0.6.1",
"sqlx 0.6.2",
"statistics-common",
"task",
"thiserror",
@@ -3399,14 +3412,13 @@ dependencies = [
"statistics-common",
"thiserror",
"tokio",
"tokio-tungstenite 0.14.0",
]
[[package]]
name = "nym-socks5-client"
version = "1.0.2"
dependencies = [
"clap 3.2.20",
"clap 3.2.21",
"client-core",
"coconut-interface",
"config",
@@ -3434,7 +3446,7 @@ dependencies = [
"topology",
"url",
"validator-client",
"vergen",
"vergen 5.1.17",
"version-checker",
]
@@ -3470,9 +3482,8 @@ version = "1.0.2"
dependencies = [
"anyhow",
"async-trait",
"attohttpc",
"cfg-if 1.0.0",
"clap 3.2.20",
"clap 3.2.21",
"coconut-bandwidth-contract-common",
"coconut-interface",
"config",
@@ -3504,12 +3515,10 @@ dependencies = [
"rocket",
"rocket_cors",
"rocket_okapi",
"rocket_sync_db_pools",
"schemars",
"serde",
"serde_json",
"sqlx 0.5.13",
"sqlx 0.6.1",
"sqlx 0.6.2",
"tap",
"task",
"thiserror",
@@ -3521,7 +3530,7 @@ dependencies = [
"url",
"validator-api-requests",
"validator-client",
"vergen",
"vergen 7.4.2",
"version-checker",
]
@@ -3664,7 +3673,7 @@ dependencies = [
"bytes",
"nymsphinx-params",
"nymsphinx-types",
"tokio-util 0.7.3",
"tokio-util 0.7.4",
]
[[package]]
@@ -3953,15 +3962,15 @@ dependencies = [
[[package]]
name = "percent-encoding"
version = "2.1.0"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "pest"
version = "2.3.0"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4"
checksum = "cb779fcf4bb850fbbb0edc96ff6cf34fd90c4b1a112ce042653280d9a7364048"
dependencies = [
"thiserror",
"ucd-trie",
@@ -3969,9 +3978,9 @@ dependencies = [
[[package]]
name = "pest_derive"
version = "2.3.0"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "905708f7f674518498c1f8d644481440f476d39ca6ecae83319bba7c6c12da91"
checksum = "502b62a6d0245378b04ffe0a7fb4f4419a4815fce813bd8a0ec89a56e07d67b1"
dependencies = [
"pest",
"pest_generator",
@@ -3979,9 +3988,9 @@ dependencies = [
[[package]]
name = "pest_generator"
version = "2.3.0"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad"
checksum = "451e629bf49b750254da26132f1a5a9d11fd8a95a3df51d15c4abd1ba154cb6c"
dependencies = [
"pest",
"pest_meta",
@@ -3992,13 +4001,13 @@ dependencies = [
[[package]]
name = "pest_meta"
version = "2.3.0"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04"
checksum = "bcec162c71c45e269dfc3fc2916eaeb97feab22993a21bcce4721d08cd7801a6"
dependencies = [
"once_cell",
"pest",
"sha-1 0.10.0",
"sha1",
]
[[package]]
@@ -4065,9 +4074,9 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]]
name = "plotters"
version = "0.3.3"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "716b4eeb6c4a1d3ecc956f75b43ec2e8e8ba80026413e70a3f41fd3313d3492b"
checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97"
dependencies = [
"num-traits",
"plotters-backend",
@@ -4267,7 +4276,7 @@ dependencies = [
"task",
"tokio",
"tokio-test",
"tokio-util 0.7.3",
"tokio-util 0.7.4",
]
[[package]]
@@ -4305,17 +4314,6 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "r2d2"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93"
dependencies = [
"log",
"parking_lot 0.12.1",
"scheduled-thread-pool",
]
[[package]]
name = "radium"
version = "0.6.2"
@@ -4740,7 +4738,7 @@ dependencies = [
"time 0.3.14",
"tokio",
"tokio-stream",
"tokio-util 0.7.3",
"tokio-util 0.7.4",
"ubyte",
"version_check",
"yansi",
@@ -4833,29 +4831,6 @@ dependencies = [
"syn",
]
[[package]]
name = "rocket_sync_db_pools"
version = "0.1.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fa48b6ab25013e9812f1b0c592741900b3a2a83c0936292e0565c0ac842f558"
dependencies = [
"r2d2",
"rocket",
"rocket_sync_db_pools_codegen",
"serde",
"tokio",
]
[[package]]
name = "rocket_sync_db_pools_codegen"
version = "0.1.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "280ef2d232923e69cb93da156972eb5476a7cce5ba44843f6608f46a4abf7aab"
dependencies = [
"devise",
"quote",
]
[[package]]
name = "rustc-hex"
version = "2.1.0"
@@ -4877,7 +4852,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver 1.0.13",
"semver 1.0.14",
]
[[package]]
@@ -4957,15 +4932,6 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "scheduled-thread-pool"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "977a7519bff143a44f842fd07e80ad1329295bd71686457f18e496736f4bf9bf"
dependencies = [
"parking_lot 0.12.1",
]
[[package]]
name = "schemars"
version = "0.8.10"
@@ -5097,9 +5063,9 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.13"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711"
checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
[[package]]
name = "semver-parser"
@@ -5423,7 +5389,6 @@ name = "socks5-requests"
version = "0.1.0"
dependencies = [
"nymsphinx-addressing",
"ordered-buffer",
"thiserror",
]
@@ -5501,6 +5466,17 @@ dependencies = [
"unicode_categories",
]
[[package]]
name = "sqlformat"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f87e292b4291f154971a43c3774364e2cbcaec599d3f5bf6fa9d122885dbc38a"
dependencies = [
"itertools",
"nom",
"unicode_categories",
]
[[package]]
name = "sqlx"
version = "0.5.13"
@@ -5513,12 +5489,12 @@ dependencies = [
[[package]]
name = "sqlx"
version = "0.6.1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "788841def501aabde58d3666fcea11351ec3962e6ea75dbcd05c84a71d68bcd1"
checksum = "9249290c05928352f71c077cc44a464d880c63f26f7534728cca008e135c0428"
dependencies = [
"sqlx-core 0.6.1",
"sqlx-macros 0.6.1",
"sqlx-core 0.6.2",
"sqlx-macros 0.6.2",
]
[[package]]
@@ -5557,7 +5533,7 @@ dependencies = [
"rustls 0.19.1",
"sha2 0.10.5",
"smallvec 1.9.0",
"sqlformat",
"sqlformat 0.1.8",
"sqlx-rt 0.5.13",
"stringprep",
"thiserror",
@@ -5569,9 +5545,9 @@ dependencies = [
[[package]]
name = "sqlx-core"
version = "0.6.1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c21d3b5e7cadfe9ba7cdc1295f72cc556c750b4419c27c219c0693198901f8e"
checksum = "dcbc16ddba161afc99e14d1713a453747a2b07fc097d2009f4c300ec99286105"
dependencies = [
"ahash",
"atoi 1.0.0",
@@ -5605,8 +5581,8 @@ dependencies = [
"rustls-pemfile",
"sha2 0.10.5",
"smallvec 1.9.0",
"sqlformat",
"sqlx-rt 0.6.1",
"sqlformat 0.2.0",
"sqlx-rt 0.6.2",
"stringprep",
"thiserror",
"tokio-stream",
@@ -5635,9 +5611,9 @@ dependencies = [
[[package]]
name = "sqlx-macros"
version = "0.6.1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4adfd2df3557bddd3b91377fc7893e8fa899e9b4061737cbade4e1bb85f1b45c"
checksum = "b850fa514dc11f2ee85be9d055c512aa866746adfacd1cb42d867d68e6a5b0d9"
dependencies = [
"dotenvy",
"either",
@@ -5646,8 +5622,8 @@ dependencies = [
"proc-macro2",
"quote",
"sha2 0.10.5",
"sqlx-core 0.6.1",
"sqlx-rt 0.6.1",
"sqlx-core 0.6.2",
"sqlx-rt 0.6.2",
"syn",
"url",
]
@@ -5665,9 +5641,9 @@ dependencies = [
[[package]]
name = "sqlx-rt"
version = "0.6.1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7be52fc7c96c136cedea840ed54f7d446ff31ad670c9dea95ebcb998530971a3"
checksum = "24c5b2d25fa654cc5f841750b8e1cdedbe21189bf9a9382ee90bfa9dd3562396"
dependencies = [
"once_cell",
"tokio",
@@ -5846,7 +5822,6 @@ version = "0.1.0"
dependencies = [
"log",
"tokio",
"tokio-util 0.7.3",
]
[[package]]
@@ -5985,18 +5960,18 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
[[package]]
name = "thiserror"
version = "1.0.34"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c1b05ca9d106ba7d2e31a9dab4a64e7be2cce415321966ea3132c49a656e252"
checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.34"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8f2591983642de85c921015f3f070c665a197ed69e417af436115e3a1407487"
checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783"
dependencies = [
"proc-macro2",
"quote",
@@ -6063,9 +6038,9 @@ dependencies = [
[[package]]
name = "tokio"
version = "1.21.0"
version = "1.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89797afd69d206ccd11fb0ea560a44bbb87731d020670e79416d442919257d42"
checksum = "0020c875007ad96677dcc890298f4b942882c5d4eb7cc8f439fc3bf813dc9c95"
dependencies = [
"autocfg 1.1.0",
"bytes",
@@ -6145,7 +6120,7 @@ dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
"tokio-util 0.7.3",
"tokio-util 0.7.4",
]
[[package]]
@@ -6203,9 +6178,9 @@ dependencies = [
[[package]]
name = "tokio-util"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45"
checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740"
dependencies = [
"bytes",
"futures-core",
@@ -6227,9 +6202,9 @@ dependencies = [
[[package]]
name = "tonic"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "498f271adc46acce75d66f639e4d35b31b2394c295c82496727dafa16d465dd2"
checksum = "11cd56bdb54ef93935a6a79dbd1d91f1ebd4c64150fd61654031fd6b8b775c91"
dependencies = [
"async-stream",
"async-trait",
@@ -6249,7 +6224,7 @@ dependencies = [
"prost-derive 0.11.0",
"tokio",
"tokio-stream",
"tokio-util 0.7.3",
"tokio-util 0.7.4",
"tower",
"tower-layer",
"tower-service",
@@ -6285,7 +6260,7 @@ dependencies = [
"rand 0.8.5",
"slab",
"tokio",
"tokio-util 0.7.3",
"tokio-util 0.7.4",
"tower-layer",
"tower-service",
"tracing",
@@ -6548,9 +6523,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
[[package]]
name = "unicode-ident"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
[[package]]
name = "unicode-normalization"
@@ -6563,15 +6538,15 @@ dependencies = [
[[package]]
name = "unicode-segmentation"
version = "1.9.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
[[package]]
name = "unicode-width"
version = "0.1.9"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "unicode-xid"
@@ -6603,13 +6578,12 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "url"
version = "2.2.2"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
checksum = "22fe195a4f217c25b25cb5058ced57059824a678474874038dc88d211bf508d3"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
"serde",
]
@@ -6697,7 +6671,7 @@ dependencies = [
"anyhow",
"cfg-if 1.0.0",
"chrono",
"enum-iterator",
"enum-iterator 0.8.1",
"getset",
"git2",
"rustc_version 0.4.0",
@@ -6705,6 +6679,23 @@ dependencies = [
"thiserror",
]
[[package]]
name = "vergen"
version = "7.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73ba753d713ec3844652ad2cb7eb56bc71e34213a14faddac7852a10ba88f61e"
dependencies = [
"anyhow",
"cfg-if 1.0.0",
"enum-iterator 1.1.3",
"getset",
"git2",
"rustc_version 0.4.0",
"rustversion",
"thiserror",
"time 0.3.14",
]
[[package]]
name = "version-checker"
version = "0.1.0"
@@ -6735,9 +6726,7 @@ dependencies = [
name = "vesting-contract-common"
version = "0.1.0"
dependencies = [
"config",
"cosmwasm-std",
"cw-storage-plus",
"mixnet-contract-common",
"schemars",
"serde",
@@ -6971,12 +6960,6 @@ dependencies = [
"serde_json",
]
[[package]]
name = "wildmatch"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee583bdc5ff1cf9db20e9db5bb3ff4c3089a8f6b8b31aff265c9aba85812db86"
[[package]]
name = "winapi"
version = "0.3.9"
+24 -7
View File
@@ -2,10 +2,10 @@ test: clippy-all cargo-test wasm fmt
test-all: test cargo-test-expensive
no-clippy: build cargo-test wasm fmt
happy: fmt clippy-happy test
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet clippy-all-connect
clippy-all: clippy-main clippy-coconut clippy-all-contracts clippy-all-wallet clippy-all-connect
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet clippy-happy-connect
cargo-test: test-main test-contracts test-wallet test-connect
cargo-test-expensive: test-main-expensive test-contracts-expensive test-wallet-expensive test-connect-expensive
cargo-test: test-main test-contracts test-wallet test-connect test-coconut
cargo-test-expensive: test-main-expensive test-contracts-expensive test-wallet-expensive test-connect-expensive test-coconut-expensive
build: build-contracts build-wallet build-main build-connect
fmt: fmt-main fmt-contracts fmt-wallet fmt-connect
@@ -21,8 +21,15 @@ clippy-happy-wallet:
clippy-happy-connect:
cargo clippy --manifest-path nym-connect/Cargo.toml
clippy-all-main:
cargo clippy --workspace --all-features -- -D warnings
clippy-main:
cargo clippy --workspace -- -D warnings
clippy-coconut:
cargo clippy --workspace --features coconut -- -D warnings
clippy-wasm:
cargo clippy --workspace --features wasm -- -D warnings
clippy-all-contracts:
cargo clippy --workspace --manifest-path contracts/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
@@ -34,10 +41,20 @@ clippy-all-connect:
cargo clippy --workspace --manifest-path nym-connect/Cargo.toml --all-features -- -D warnings
test-main:
cargo test --all-features --workspace
cargo test --workspace
test-coconut:
cargo test --workspace --features coconut
test-wasm:
cargo test --workspace --features wasm
test-main-expensive:
cargo test --all-features --workspace -- --ignored
cargo test --workspace -- --ignored
test-coconut-expensive:
cargo test --workspace --features coconut -- --ignored
test-contracts:
cargo test --manifest-path contracts/Cargo.toml --all-features
-32
View File
@@ -121,16 +121,6 @@ impl<T: NymConfig> Config<T> {
self.client.gateway_endpoint.gateway_id = id.into();
}
#[cfg(not(feature = "coconut"))]
pub fn with_eth_private_key<S: Into<String>>(&mut self, eth_private_key: S) {
self.client.eth_private_key = eth_private_key.into();
}
#[cfg(not(feature = "coconut"))]
pub fn with_eth_endpoint<S: Into<String>>(&mut self, eth_endpoint: S) {
self.client.eth_endpoint = eth_endpoint.into();
}
pub fn set_custom_validator_apis(&mut self, validator_api_urls: Vec<Url>) {
self.client.validator_api_urls = validator_api_urls;
}
@@ -209,16 +199,6 @@ impl<T: NymConfig> Config<T> {
self.client.database_path.clone()
}
#[cfg(not(feature = "coconut"))]
pub fn get_eth_endpoint(&self) -> String {
self.client.eth_endpoint.clone()
}
#[cfg(not(feature = "coconut"))]
pub fn get_eth_private_key(&self) -> String {
self.client.eth_private_key.clone()
}
// Debug getters
pub fn get_average_packet_delay(&self) -> Duration {
self.debug.average_packet_delay
@@ -342,14 +322,6 @@ pub struct Client<T> {
/// Path to the database containing bandwidth credentials of this client.
database_path: PathBuf,
/// Ethereum private key.
#[cfg(not(feature = "coconut"))]
eth_private_key: String,
/// Address to an Ethereum full node.
#[cfg(not(feature = "coconut"))]
eth_endpoint: String,
/// nym_home_directory specifies absolute path to the home nym Clients directory.
/// It is expected to use default value and hence .toml file should not redefine this field.
nym_root_directory: PathBuf,
@@ -375,10 +347,6 @@ impl<T: NymConfig> Default for Client<T> {
reply_encryption_key_store_path: Default::default(),
gateway_endpoint: Default::default(),
database_path: Default::default(),
#[cfg(not(feature = "coconut"))]
eth_private_key: "".to_string(),
#[cfg(not(feature = "coconut"))]
eth_endpoint: "".to_string(),
nym_root_directory: T::default_root_directory(),
super_struct: Default::default(),
}
-1
View File
@@ -50,7 +50,6 @@ websocket-requests = { path = "websocket-requests" }
[features]
coconut = ["coconut-interface", "credentials", "credentials/coconut", "gateway-requests/coconut", "gateway-client/coconut", "client-core/coconut"]
eth = []
[dev-dependencies]
serde_json = "1.0" # for the "textsend" example
@@ -49,12 +49,6 @@ reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
# Path to the database containing bandwidth credentials
database_path = '{{ client.database_path }}'
# Ethereum private key.
eth_private_key = '{{ client.eth_private_key }}'
# Addess to an Ethereum full node.
eth_endpoint = '{{ client.eth_endpoint }}'
##### additional client config options #####
# A gateway specific, optional, base58 stringified shared key used for
-2
View File
@@ -190,8 +190,6 @@ impl NymClient {
let bandwidth_controller = BandwidthController::new(
credential_storage::initialise_storage(self.config.get_base().get_database_path())
.await,
self.config.get_base().get_eth_endpoint(),
self.config.get_base().get_eth_private_key(),
)
.expect("Could not create bandwidth controller");
+2 -29
View File
@@ -10,9 +10,6 @@ use crate::{
commands::{override_config, OverrideConfig},
};
#[cfg(all(feature = "eth", not(feature = "coconut")))]
use crate::commands::{DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY};
#[derive(Args, Clone)]
pub(crate) struct Init {
/// Id of the nym-mixnet-client we want to create config for.
@@ -47,27 +44,9 @@ pub(crate) struct Init {
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
#[clap(long)]
enabled_credentials_mode: bool,
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
/// tokens. If you don't want to set this value, use --enabled-credentials-mode instead
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(
long,
default_value_if("enabled-credentials-mode", None, Some(DEFAULT_ETH_ENDPOINT))
)]
eth_endpoint: String,
/// Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't
/// want to set this value, use --enabled-credentials-mode instead")
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(
long,
default_value_if("enabled-credentials-mode", None, Some(DEFAULT_ETH_PRIVATE_KEY))
)]
eth_private_key: String,
}
impl From<Init> for OverrideConfig {
@@ -78,14 +57,8 @@ impl From<Init> for OverrideConfig {
port: init_config.port,
fastmode: init_config.fastmode,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
enabled_credentials_mode: init_config.enabled_credentials_mode,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_private_key: Some(init_config.eth_private_key),
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_endpoint: Some(init_config.eth_endpoint),
}
}
}
+2 -34
View File
@@ -4,13 +4,6 @@
use crate::client::config::{Config, SocketType};
use clap::{Parser, Subcommand};
#[cfg(not(feature = "coconut"))]
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
#[cfg(not(feature = "coconut"))]
pub(crate) const DEFAULT_ETH_PRIVATE_KEY: &str =
"0000000000000000000000000000000000000000000000000000000000000001";
pub(crate) mod init;
pub(crate) mod run;
pub(crate) mod upgrade;
@@ -78,14 +71,8 @@ pub(crate) struct OverrideConfig {
port: Option<u16>,
fastmode: bool,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
enabled_credentials_mode: bool,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_private_key: Option<String>,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_endpoint: Option<String>,
}
pub(crate) async fn execute(args: &Cli) {
@@ -117,32 +104,13 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
config = config.with_port(port);
}
#[cfg(all(not(feature = "eth"), not(feature = "coconut")))]
{
config
.get_base_mut()
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT.to_string());
config
.get_base_mut()
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY.to_string());
}
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
{
if args.enabled_credentials_mode {
config.get_base_mut().with_disabled_credentials(false)
}
}
#[cfg(all(feature = "eth", not(feature = "coconut")))]
{
if let Some(eth_endpoint) = args.eth_endpoint {
config.get_base_mut().with_eth_endpoint(eth_endpoint);
}
if let Some(eth_private_key) = args.eth_private_key {
config.get_base_mut().with_eth_private_key(eth_private_key);
}
}
if args.fastmode {
config.get_base_mut().set_high_default_traffic_volume();
}
+2 -21
View File
@@ -36,21 +36,9 @@ pub(crate) struct Run {
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
#[clap(long)]
enabled_credentials_mode: bool,
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
/// tokens. If you don't want to set this value, use --enabled-credentials-mode instead
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(long)]
eth_endpoint: Option<String>,
/// Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't
/// want to set this value, use --enabled-credentials-mode instead")
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(long)]
eth_private_key: Option<String>,
}
impl From<Run> for OverrideConfig {
@@ -60,15 +48,8 @@ impl From<Run> for OverrideConfig {
disable_socket: run_config.disable_socket,
port: run_config.port,
fastmode: false,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
enabled_credentials_mode: run_config.enabled_credentials_mode,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_private_key: run_config.eth_private_key,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_endpoint: run_config.eth_endpoint,
}
}
}
@@ -49,12 +49,6 @@ reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
# Path to the database containing bandwidth credentials
database_path = '{{ client.database_path }}'
# Ethereum private key.
eth_private_key = '{{ client.eth_private_key }}'
# Addess to an Ethereum full node.
eth_endpoint = '{{ client.eth_endpoint }}'
##### additional client config options #####
# A gateway specific, optional, base58 stringified shared key used for
-2
View File
@@ -191,8 +191,6 @@ impl NymClient {
let bandwidth_controller = BandwidthController::new(
credential_storage::initialise_storage(self.config.get_base().get_database_path())
.await,
self.config.get_base().get_eth_endpoint(),
self.config.get_base().get_eth_private_key(),
)
.expect("Could not create bandwidth controller");
+2 -30
View File
@@ -10,9 +10,6 @@ use crate::{
commands::{override_config, OverrideConfig},
};
#[cfg(all(feature = "eth", not(feature = "coconut")))]
use crate::commands::{DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY};
#[derive(Args, Clone)]
pub(crate) struct Init {
/// Id of the nym-mixnet-client we want to create config for.
@@ -47,27 +44,9 @@ pub(crate) struct Init {
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
#[clap(long)]
enabled_credentials_mode: bool,
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
/// tokens. If you don't want to set this value, use --enabled-credentials-mode instead
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(
long,
default_value_if("enabled-credentials-mode", None, Some(DEFAULT_ETH_ENDPOINT))
)]
eth_endpoint: String,
/// Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't
/// want to set this value, use --enabled-credentials-mode instead")
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(
long,
default_value_if("enabled-credentials-mode", None, Some(DEFAULT_ETH_PRIVATE_KEY))
)]
eth_private_key: String,
}
impl From<Init> for OverrideConfig {
@@ -76,15 +55,8 @@ impl From<Init> for OverrideConfig {
validators: init_config.validators,
port: init_config.port,
fastmode: init_config.fastmode,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
enabled_credentials_mode: init_config.enabled_credentials_mode,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_private_key: Some(init_config.eth_private_key),
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_endpoint: Some(init_config.eth_endpoint),
}
}
}
+2 -34
View File
@@ -9,13 +9,6 @@ pub mod init;
pub(crate) mod run;
pub(crate) mod upgrade;
#[cfg(not(feature = "coconut"))]
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
#[cfg(not(feature = "coconut"))]
pub(crate) const DEFAULT_ETH_PRIVATE_KEY: &str =
"0000000000000000000000000000000000000000000000000000000000000001";
fn long_version() -> String {
format!(
r#"
@@ -78,14 +71,8 @@ pub(crate) struct OverrideConfig {
port: Option<u16>,
fastmode: bool,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
enabled_credentials_mode: bool,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_private_key: Option<String>,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_endpoint: Option<String>,
}
pub(crate) async fn execute(args: &Cli) {
@@ -111,31 +98,12 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
config = config.with_port(port);
}
#[cfg(all(not(feature = "eth"), not(feature = "coconut")))]
{
config
.get_base_mut()
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT.to_string());
config
.get_base_mut()
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY.to_string());
}
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
{
if args.enabled_credentials_mode {
config.get_base_mut().with_disabled_credentials(false)
}
}
#[cfg(all(feature = "eth", not(feature = "coconut")))]
{
if let Some(eth_endpoint) = args.eth_endpoint {
config.get_base_mut().with_eth_endpoint(eth_endpoint);
}
if let Some(eth_private_key) = args.eth_private_key {
config.get_base_mut().with_eth_private_key(eth_private_key);
}
}
if args.fastmode {
config.get_base_mut().set_high_default_traffic_volume();
+2 -20
View File
@@ -40,21 +40,9 @@ pub(crate) struct Run {
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
#[clap(long)]
enabled_credentials_mode: bool,
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
/// tokens. If you don't want to set this value, use --enabled-credentials-mode instead
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(long)]
eth_endpoint: Option<String>,
/// Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't
/// want to set this value, use --enabled-credentials-mode instead
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(long)]
eth_private_key: Option<String>,
}
impl From<Run> for OverrideConfig {
@@ -64,14 +52,8 @@ impl From<Run> for OverrideConfig {
port: run_config.port,
fastmode: false,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
enabled_credentials_mode: run_config.enabled_credentials_mode,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_private_key: run_config.eth_private_key,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_endpoint: run_config.eth_endpoint,
}
}
}
+1 -2
View File
@@ -10,13 +10,12 @@ edition = "2021"
# TODO: (for this and other crates), similarly to 'tokio', import only required "futures" modules rather than
# the entire crate
futures = "0.3"
json = "0.12.4"
log = "0.4"
thiserror = "1.0"
url = "2.2"
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
secp256k1 = "0.20.3"
web3 = { version = "0.17.0", default-features = false }
web3 = { version = "0.17.0", default-features = false, optional = true }
async-trait = { version = "0.1.51" }
# internal
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
use crate::error::GatewayClientError;
use std::str::FromStr;
#[cfg(target_arch = "wasm32")]
use crate::wasm_storage::Storage;
@@ -15,6 +14,8 @@ use crate::wasm_storage::StorageError;
#[cfg(all(not(target_arch = "wasm32"), feature = "coconut"))]
use credential_storage::error::StorageError;
#[cfg(feature = "coconut")]
use std::str::FromStr;
#[cfg(feature = "coconut")]
use {
coconut_interface::Base58,
@@ -23,65 +24,12 @@ use {
},
};
#[cfg(not(feature = "coconut"))]
use {
credentials::token::bandwidth::TokenCredential,
crypto::asymmetric::identity,
network_defaults::{
eth_contract::ETH_ERC20_JSON_ABI, eth_contract::ETH_JSON_ABI, BANDWIDTH_VALUE,
ETH_BURN_FUNCTION_NAME, ETH_CONTRACT_ADDRESS, ETH_ERC20_APPROVE_FUNCTION_NAME,
ETH_ERC20_CONTRACT_ADDRESS, ETH_MIN_BLOCK_DEPTH, TOKENS_TO_BURN, UTOKENS_TO_BURN,
},
pemstore::traits::PemStorableKeyPair,
rand::rngs::OsRng,
secp256k1::SecretKey,
web3::{
contract::{Contract, Options},
ethabi::Token,
signing::{Key, SecretKeyRef},
transports::Http,
types::{Address, U256, U64},
Web3,
},
};
#[cfg(not(feature = "coconut"))]
pub fn eth_contract(web3: Web3<Http>) -> Contract<Http> {
Contract::from_json(
web3.eth(),
Address::from(ETH_CONTRACT_ADDRESS),
json::parse(ETH_JSON_ABI)
.expect("Invalid json abi")
.dump()
.as_bytes(),
)
.expect("Invalid json abi")
}
#[cfg(not(feature = "coconut"))]
pub fn eth_erc20_contract(web3: Web3<Http>) -> Contract<Http> {
Contract::from_json(
web3.eth(),
Address::from(ETH_ERC20_CONTRACT_ADDRESS),
json::parse(ETH_ERC20_JSON_ABI)
.expect("Invalid json abi")
.dump()
.as_bytes(),
)
.expect("Invalid json abi")
}
#[derive(Clone)]
pub struct BandwidthController<St: Storage> {
#[allow(dead_code)]
storage: St,
#[cfg(feature = "coconut")]
validator_endpoints: Vec<url::Url>,
#[cfg(not(feature = "coconut"))]
contract: Contract<Http>,
#[cfg(not(feature = "coconut"))]
erc20_contract: Contract<Http>,
#[cfg(not(feature = "coconut"))]
eth_private_key: SecretKey,
}
impl<St> BandwidthController<St>
@@ -97,60 +45,8 @@ where
}
#[cfg(not(feature = "coconut"))]
pub fn new(
storage: St,
eth_endpoint: String,
eth_private_key: String,
) -> Result<Self, GatewayClientError> {
// Fail early, on invalid url
let transport =
Http::new(&eth_endpoint).map_err(|_| GatewayClientError::InvalidURL(eth_endpoint))?;
let web3 = web3::Web3::new(transport);
// Fail early, on invalid abi
let contract = eth_contract(web3.clone());
let erc20_contract = eth_erc20_contract(web3);
let eth_private_key = secp256k1::SecretKey::from_str(&eth_private_key)
.map_err(|_| GatewayClientError::InvalidEthereumPrivateKey)?;
Ok(BandwidthController {
storage,
contract,
erc20_contract,
eth_private_key,
})
}
#[cfg(not(feature = "coconut"))]
async fn backup_keypair(&self, keypair: &identity::KeyPair) -> Result<(), GatewayClientError> {
self.storage
.insert_erc20_credential(
keypair.public_key().to_base58_string(),
keypair.private_key().to_base58_string(),
)
.await?;
Ok(())
}
#[cfg(not(feature = "coconut"))]
async fn restore_keypair(&self) -> Result<identity::KeyPair, GatewayClientError> {
let data = self.storage.get_next_erc20_credential().await?;
let public_key = identity::PublicKey::from_base58_string(data.public_key).unwrap();
let private_key = identity::PrivateKey::from_base58_string(data.private_key).unwrap();
Ok(identity::KeyPair::from_keys(private_key, public_key))
}
#[cfg(not(feature = "coconut"))]
async fn mark_keypair_as_spent(
&self,
keypair: &identity::KeyPair,
) -> Result<(), GatewayClientError> {
self.storage
.consume_erc20_credential(keypair.public_key().to_base58_string())
.await?;
Ok(())
pub fn new(storage: St) -> Result<Self, GatewayClientError> {
Ok(BandwidthController { storage })
}
#[cfg(feature = "coconut")]
@@ -179,206 +75,4 @@ where
&verification_key,
)?)
}
#[cfg(not(feature = "coconut"))]
pub async fn prepare_token_credential(
&self,
gateway_identity: identity::PublicKey,
gateway_owner: String,
) -> Result<TokenCredential, GatewayClientError> {
let kp = match self.restore_keypair().await {
Ok(kp) => kp,
Err(_) => {
let mut rng = OsRng;
let kp = identity::KeyPair::new(&mut rng);
self.backup_keypair(&kp).await?;
kp
}
};
let verification_key = *kp.public_key();
let signed_verification_key = kp.private_key().sign(&verification_key.to_bytes());
self.buy_token_credential(verification_key, signed_verification_key, gateway_owner)
.await?;
self.mark_keypair_as_spent(&kp).await?;
let message: Vec<u8> = verification_key
.to_bytes()
.iter()
.chain(gateway_identity.to_bytes().iter())
.copied()
.collect();
let signature = kp.private_key().sign(&message);
Ok(TokenCredential::new(
verification_key,
gateway_identity,
BANDWIDTH_VALUE,
signature,
))
}
#[cfg(not(feature = "coconut"))]
pub async fn buy_token_credential(
&self,
verification_key: identity::PublicKey,
signed_verification_key: identity::Signature,
gateway_owner: String,
) -> Result<(), GatewayClientError> {
let confirmations = if cfg!(debug_assertions) {
1
} else {
ETH_MIN_BLOCK_DEPTH
};
// 15 seconds per confirmation block + 10 seconds of network overhead + 20 seconds of wait for kill
log::info!(
"Waiting for Ethereum transaction. This should take about {} seconds",
(confirmations + 1) * 15 + 30
);
let mut options = Options::default();
let estimation = self
.erc20_contract
.estimate_gas(
ETH_ERC20_APPROVE_FUNCTION_NAME,
(
Token::Address(Address::from(ETH_CONTRACT_ADDRESS)),
Token::Uint(U256::from(UTOKENS_TO_BURN)),
),
SecretKeyRef::from(&self.eth_private_key).address(),
options.clone(),
)
.await?;
options.gas = Some(estimation);
log::info!("Calling ERC20 approve in 10 seconds with an estimated gas of {}. Kill the process if you want to abort", estimation);
#[cfg(not(target_arch = "wasm32"))]
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
#[cfg(target_arch = "wasm32")]
if let Err(err) = fluvio_wasm_timer::Delay::new(std::time::Duration::from_secs(10)).await {
log::error!(
"the timer has gone away while waiting for possible kill! - {}",
err
);
}
let recipt = self
.erc20_contract
.signed_call_with_confirmations(
ETH_ERC20_APPROVE_FUNCTION_NAME,
(
Token::Address(Address::from(ETH_CONTRACT_ADDRESS)),
Token::Uint(U256::from(UTOKENS_TO_BURN)),
),
options,
1, // One confirmation is enough, as we'll be consuming the approved token next anyway
&self.eth_private_key,
)
.await?;
if Some(U64::from(0u64)) == recipt.status {
return Err(GatewayClientError::BurnTokenError(
web3::Error::InvalidResponse(format!(
"Approve transaction status is 0 (failure): {:?}",
recipt.logs,
)),
));
} else {
log::info!(
"Approved {} tokens for bandwidth use on Ethereum",
TOKENS_TO_BURN
);
}
let mut options = Options::default();
let estimation = self
.contract
.estimate_gas(
ETH_BURN_FUNCTION_NAME,
(
Token::Uint(U256::from(UTOKENS_TO_BURN)),
Token::Uint(U256::from(&verification_key.to_bytes())),
Token::Bytes(signed_verification_key.to_bytes().to_vec()),
Token::String(gateway_owner.clone()),
),
SecretKeyRef::from(&self.eth_private_key).address(),
options.clone(),
)
.await?;
options.gas = Some(estimation);
log::info!("Generating bandwidth on ETH contract in 10 seconds with an estimated gas of {}. \
Kill the process if you want to abort. Keep in mind that if you abort now, you'll still have \
some tokens approved for bandwidth spending from the previous action. \
If you don't want that, you'll need to manually decreaseAllowance to revert the approval.", estimation);
#[cfg(not(target_arch = "wasm32"))]
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
#[cfg(target_arch = "wasm32")]
if let Err(err) = fluvio_wasm_timer::Delay::new(std::time::Duration::from_secs(10)).await {
log::error!(
"the timer has gone away while waiting for possible kill! - {}",
err
);
}
let recipt = self
.contract
.signed_call_with_confirmations(
ETH_BURN_FUNCTION_NAME,
(
Token::Uint(U256::from(UTOKENS_TO_BURN)),
Token::Uint(U256::from(&verification_key.to_bytes())),
Token::Bytes(signed_verification_key.to_bytes().to_vec()),
Token::String(gateway_owner),
),
options,
confirmations,
&self.eth_private_key,
)
.await?;
if Some(U64::from(0u64)) == recipt.status {
Err(GatewayClientError::BurnTokenError(
web3::Error::InvalidResponse(format!(
"Transaction status is 0 (failure): {:?}",
recipt.logs,
)),
))
} else {
log::info!(
"Bought bandwidth on Ethereum: {} MB",
BANDWIDTH_VALUE / 1024 / 1024
);
Ok(())
}
}
}
#[cfg(not(feature = "coconut"))]
#[cfg(test)]
mod tests {
use network_defaults::ETH_EVENT_NAME;
use super::*;
#[test]
fn parse_contract() {
let transport =
Http::new("https://rinkeby.infura.io/v3/00000000000000000000000000000000").unwrap();
let web3 = web3::Web3::new(transport);
// test no panic occurs
eth_contract(web3);
}
#[test]
fn parse_erc20_contract() {
let transport =
Http::new("https://rinkeby.infura.io/v3/00000000000000000000000000000000").unwrap();
let web3 = web3::Web3::new(transport);
// test no panic occurs
eth_erc20_contract(web3);
}
#[test]
fn check_event_name_constant_against_abi() {
let transport =
Http::new("https://rinkeby.infura.io/v3/00000000000000000000000000000000").unwrap();
let web3 = web3::Web3::new(transport);
let contract = eth_contract(web3);
assert!(contract.abi().event(ETH_EVENT_NAME).is_ok());
}
}
@@ -15,8 +15,6 @@ use crate::wasm_storage::PersistentStorage;
use coconut_interface::Credential;
#[cfg(not(target_arch = "wasm32"))]
use credential_storage::PersistentStorage;
#[cfg(not(feature = "coconut"))]
use credentials::token::bandwidth::TokenCredential;
use crypto::asymmetric::identity;
use futures::{FutureExt, SinkExt, StreamExt};
use gateway_requests::authentication::encrypted_address::EncryptedAddressBytes;
@@ -554,30 +552,6 @@ impl GatewayClient {
Ok(())
}
#[cfg(not(feature = "coconut"))]
async fn claim_token_bandwidth(
&mut self,
credential: TokenCredential,
) -> Result<(), GatewayClientError> {
let mut rng = OsRng;
let iv = IV::new_random(&mut rng);
let msg = ClientControlRequest::new_enc_token_bandwidth_credential(
&credential,
self.shared_key.as_ref().unwrap(),
iv,
)
.into();
self.bandwidth_remaining = match self.send_websocket_message(msg).await? {
ServerResponse::Bandwidth { available_total } => Ok(available_total),
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
_ => Err(GatewayClientError::UnexpectedResponse),
}?;
Ok(())
}
async fn try_claim_testnet_bandwidth(&mut self) -> Result<(), GatewayClientError> {
let msg = ClientControlRequest::ClaimFreeTestnetBandwidth.into();
self.bandwidth_remaining = match self.send_websocket_message(msg).await? {
@@ -616,17 +590,10 @@ impl GatewayClient {
.prepare_coconut_credential()
.await?;
#[cfg(not(feature = "coconut"))]
let credential = self
.bandwidth_controller
.as_ref()
.unwrap()
.prepare_token_credential(self.gateway_identity, _gateway_owner)
.await?;
return self.try_claim_testnet_bandwidth().await;
#[cfg(feature = "coconut")]
return self.claim_coconut_bandwidth(credential).await;
#[cfg(not(feature = "coconut"))]
return self.claim_token_bandwidth(credential).await;
}
fn estimate_required_bandwidth(&self, packets: &[MixPacket]) -> i64 {
@@ -26,13 +26,6 @@ pub struct CoconutCredential {
pub signature: String,
}
pub struct ERC20Credential {
pub id: i64,
pub public_key: String,
pub private_key: String,
pub consumed: bool,
}
#[async_trait]
pub trait Storage: Send + Sync {
async fn insert_coconut_credential(
@@ -47,16 +40,6 @@ pub trait Storage: Send + Sync {
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, StorageError>;
async fn remove_coconut_credential(&self, id: i64) -> Result<(), StorageError>;
async fn insert_erc20_credential(
&self,
public_key: String,
private_key: String,
) -> Result<(), StorageError>;
async fn get_next_erc20_credential(&self) -> Result<ERC20Credential, StorageError>;
async fn consume_erc20_credential(&self, public_key: String) -> Result<(), StorageError>;
}
#[async_trait]
@@ -79,20 +62,4 @@ impl Storage for PersistentStorage {
async fn remove_coconut_credential(&self, _id: i64) -> Result<(), StorageError> {
Err(StorageError::WasmNotSupported)
}
async fn insert_erc20_credential(
&self,
_public_key: String,
_private_key: String,
) -> Result<(), StorageError> {
Err(StorageError::WasmNotSupported)
}
async fn get_next_erc20_credential(&self) -> Result<ERC20Credential, StorageError> {
Err(StorageError::WasmNotSupported)
}
async fn consume_erc20_credential(&self, _public_key: String) -> Result<(), StorageError> {
Err(StorageError::WasmNotSupported)
}
}
-1
View File
@@ -9,7 +9,6 @@ edition = "2021"
[dependencies]
cfg-if = "1.0.0"
handlebars = "3.0.1"
humantime-serde = "1.0"
log = "0.4"
serde = { version = "1.0", features = ["derive"] }
toml = "0.5.6"
@@ -18,7 +18,7 @@ fixed = { version = "1.1", features = ["serde"] }
az = "1.1"
log = "0.4.14"
time = { version = "0.3.6", features = ["parsing", "formatting"] }
ts-rs = "6.1.2"
ts-rs = {version = "6.1.2", optional = true}
contracts-common = { path = "../contracts-common" }
@@ -27,4 +27,4 @@ time = { version = "0.3.5", features = ["serde", "macros"] }
[features]
default = []
generate-ts = []
generate-ts = ['ts-rs']
@@ -3,16 +3,12 @@ name = "vesting-contract-common"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cosmwasm-std = "1.0.0"
mixnet-contract-common = { path = "../mixnet-contract" }
serde = { version = "1.0", features = ["derive"] }
schemars = "0.8"
cw-storage-plus = "0.13.4"
config = { path = "../../config" }
ts-rs = "6.1.2"
ts-rs = {version = "6.1.2", optional = true}
[features]
generate-ts = []
generate-ts = ["ts-rs"]
-1
View File
@@ -7,7 +7,6 @@ edition = "2021"
[dependencies]
async-trait = { version = "0.1.51" }
nymcoconut = { path = "../nymcoconut" }
log = "0.4"
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"]}
-51
View File
@@ -17,55 +17,4 @@ impl ERC20CredentialManager {
pub(crate) fn new(connection_pool: sqlx::SqlitePool) -> Self {
ERC20CredentialManager { connection_pool }
}
/// Inserts provided signature into the database.
///
/// # Arguments
///
/// * `public_key`: Base58 representation of a public key.
/// * `private_key`: Base58 representation of a private key.
pub(crate) async fn insert_erc20_credential(
&self,
public_key: String,
private_key: String,
) -> Result<(), sqlx::Error> {
sqlx::query!(
"INSERT INTO erc20_credentials(public_key, private_key, consumed) VALUES (?, ?, ?)",
public_key,
private_key,
false,
)
.execute(&self.connection_pool)
.await?;
Ok(())
}
/// Tries to retrieve one of the stored, unused credentials.
pub(crate) async fn get_next_erc20_credential(&self) -> Result<ERC20Credential, sqlx::Error> {
sqlx::query_as!(
ERC20Credential,
"SELECT * FROM erc20_credentials WHERE consumed = false"
)
.fetch_one(&self.connection_pool)
.await
}
/// Mark a credential as being consumed.
pub(crate) async fn consume_erc20_credential(
&self,
public_key: String,
) -> Result<(), sqlx::Error> {
sqlx::query!(
r#"
UPDATE erc20_credentials
SET consumed = true
WHERE public_key = ?
"#,
public_key
)
.execute(&self.connection_pool)
.await?;
Ok(())
}
}
+1 -35
View File
@@ -4,18 +4,16 @@
*/
use crate::coconut::CoconutCredentialManager;
use crate::erc20::ERC20CredentialManager;
use crate::error::StorageError;
use crate::storage::Storage;
use crate::models::{CoconutCredential, ERC20Credential};
use crate::models::CoconutCredential;
use async_trait::async_trait;
use log::{debug, error};
use sqlx::ConnectOptions;
use std::path::{Path, PathBuf};
mod coconut;
mod erc20;
pub mod error;
mod models;
pub mod storage;
@@ -24,7 +22,6 @@ pub mod storage;
#[derive(Clone)]
pub struct PersistentStorage {
coconut_credential_manager: CoconutCredentialManager,
erc20_credential_manager: ERC20CredentialManager,
}
impl PersistentStorage {
@@ -60,7 +57,6 @@ impl PersistentStorage {
Ok(PersistentStorage {
coconut_credential_manager: CoconutCredentialManager::new(connection_pool.clone()),
erc20_credential_manager: ERC20CredentialManager::new(connection_pool),
})
}
}
@@ -104,36 +100,6 @@ impl Storage for PersistentStorage {
Ok(())
}
async fn insert_erc20_credential(
&self,
public_key: String,
private_key: String,
) -> Result<(), StorageError> {
self.erc20_credential_manager
.insert_erc20_credential(public_key, private_key)
.await?;
Ok(())
}
async fn get_next_erc20_credential(&self) -> Result<ERC20Credential, StorageError> {
let credential = self
.erc20_credential_manager
.get_next_erc20_credential()
.await?;
Ok(credential)
}
async fn consume_erc20_credential(&self, public_key: String) -> Result<(), StorageError> {
let credential = self
.erc20_credential_manager
.consume_erc20_credential(public_key)
.await?;
Ok(credential)
}
}
pub async fn initialise_storage(path: PathBuf) -> PersistentStorage {
-8
View File
@@ -10,11 +10,3 @@ pub struct CoconutCredential {
pub binding_number: String,
pub signature: String,
}
pub struct ERC20Credential {
#[allow(dead_code)]
pub id: i64,
pub public_key: String,
pub private_key: String,
pub consumed: bool,
}
+1 -19
View File
@@ -3,7 +3,7 @@
use async_trait::async_trait;
use crate::models::{CoconutCredential, ERC20Credential};
use crate::models::CoconutCredential;
use crate::StorageError;
#[async_trait]
@@ -31,22 +31,4 @@ pub trait Storage: Send + Sync {
///
/// * `signature`: Coconut credential in the form of a signature.
async fn remove_coconut_credential(&self, id: i64) -> Result<(), StorageError>;
/// Inserts provided signature into the database.
///
/// # Arguments
///
/// * `public_key`: Base58 representation of a public key.
/// * `private_key`: Base58 representation of a private key.
async fn insert_erc20_credential(
&self,
public_key: String,
private_key: String,
) -> Result<(), StorageError>;
/// Tries to retrieve one of the stored, unused credential data.
async fn get_next_erc20_credential(&self) -> Result<ERC20Credential, StorageError>;
/// Mark a credential as being consumed.
async fn consume_erc20_credential(&self, public_key: String) -> Result<(), StorageError>;
}
-1
View File
@@ -26,7 +26,6 @@ subtle-encoding = { version = "0.5", features = ["bech32-preview"]}
# internal
nymsphinx-types = { path = "../nymsphinx/types" }
pemstore = { path = "../../common/pemstore" }
config = { path="../../common/config" }
[dev-dependencies]
rand_chacha = "0.2"
-2
View File
@@ -8,7 +8,6 @@ edition = "2021"
[dependencies]
bytes = "1.0"
dashmap = "4.0"
futures = "0.3"
humantime-serde = "1.0"
log = "0.4"
@@ -19,7 +18,6 @@ tokio-util = { version = "0.7.3", features = ["codec"] }
url = "2.2"
crypto = { path = "../crypto" }
nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" }
nymsphinx-acknowledgements = { path = "../nymsphinx/acknowledgements" }
nymsphinx-addressing = { path = "../nymsphinx/addressing" }
nymsphinx-forwarding = { path = "../nymsphinx/forwarding" }
-1
View File
@@ -7,7 +7,6 @@ use std::{env::var, path::PathBuf};
use url::Url;
pub mod all;
pub mod eth_contract;
pub mod mainnet;
pub mod qa;
pub mod sandbox;
+2
View File
@@ -1,5 +1,7 @@
Ordered Buffer
==============
**CURRENTLY UNUSED**
This crate takes care of reliably and speedily turning bytes into a series of ordered message fragments on one side, and of reliably reassembling the fragments into the original message on the other.
-1
View File
@@ -8,5 +8,4 @@ edition = "2021"
[dependencies]
nymsphinx-addressing = { path = "../../../common/nymsphinx/addressing" }
ordered-buffer = {path = "../ordered-buffer"}
thiserror = "1"
-1
View File
@@ -8,7 +8,6 @@ edition = "2021"
[dependencies]
log = "0.4"
tokio = { version = "1.19.1", features = ["rt-multi-thread", "net", "signal"] }
tokio-util = { version = "0.7.3", features = ["codec"] }
[dev-dependencies]
tokio = { version = "1.19.1", features = ["rt-multi-thread", "net", "signal", "test-util", "macros"] }
+2 -83
View File
@@ -2,12 +2,6 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "Inflector"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
[[package]]
name = "aes"
version = "0.7.5"
@@ -45,18 +39,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f771a5d1f5503f7f4279a30f3643d3421ba149848b89ecaaec0ea2acf04a5ac4"
[[package]]
name = "bandwidth-claim"
version = "1.0.0"
dependencies = [
"bandwidth-claim-contract",
"cosmwasm-std",
"cosmwasm-storage",
"schemars",
"serde",
"thiserror",
]
[[package]]
name = "bandwidth-claim-contract"
version = "0.1.0"
@@ -267,7 +249,6 @@ version = "0.1.0"
dependencies = [
"cfg-if",
"handlebars",
"humantime-serde",
"log",
"network-defaults",
"serde",
@@ -367,7 +348,6 @@ name = "crypto"
version = "0.1.0"
dependencies = [
"bs58",
"config",
"ed25519-dalek",
"nymsphinx-types",
"pemstore",
@@ -894,22 +874,6 @@ dependencies = [
"digest 0.9.0",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "humantime-serde"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac34a56cfd4acddb469cc7fff187ed5ac36f498ba085caf8bbc725e3ff474058"
dependencies = [
"humantime",
"serde",
]
[[package]]
name = "idna"
version = "0.2.3"
@@ -1050,7 +1014,7 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "mixnet-contract"
version = "1.0.1"
version = "1.0.2"
dependencies = [
"az",
"bs58",
@@ -1087,7 +1051,6 @@ dependencies = [
"serde_repr",
"thiserror",
"time 0.3.6",
"ts-rs",
]
[[package]]
@@ -1660,15 +1623,6 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.30"
@@ -1741,29 +1695,6 @@ dependencies = [
"serde",
]
[[package]]
name = "ts-rs"
version = "6.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc59f479df54269b400dd95bc3b7e81623b3e4b9c70c8ca7125ab8341eafa64e"
dependencies = [
"thiserror",
"ts-rs-macros",
]
[[package]]
name = "ts-rs-macros"
version = "6.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f807fdb3151fee75df7485b901a89624358cd07a67a8fb1a5831bf5a07681ff"
dependencies = [
"Inflector",
"proc-macro2",
"quote",
"syn",
"termcolor",
]
[[package]]
name = "typenum"
version = "1.15.0"
@@ -1852,7 +1783,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vesting-contract"
version = "1.0.1"
version = "1.0.2"
dependencies = [
"cosmwasm-std",
"cw-storage-plus",
@@ -1867,13 +1798,10 @@ dependencies = [
name = "vesting-contract-common"
version = "0.1.0"
dependencies = [
"config",
"cosmwasm-std",
"cw-storage-plus",
"mixnet-contract-common",
"schemars",
"serde",
"ts-rs",
]
[[package]]
@@ -1958,15 +1886,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
+1 -1
View File
@@ -1,5 +1,5 @@
[workspace]
members = ["bandwidth-claim", "coconut-bandwidth", "mixnet", "vesting", "multisig/cw3-flex-multisig", "multisig/cw4-group", "coconut-test"]
members = ["coconut-bandwidth", "mixnet", "vesting", "multisig/cw3-flex-multisig", "multisig/cw4-group", "coconut-test"]
[profile.release]
opt-level = 3
-20
View File
@@ -1,20 +0,0 @@
[package]
name = "bandwidth-claim"
version = "1.0.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["cdylib", "rlib"]
[dev-dependencies]
[dependencies]
bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" }
cosmwasm-std = "1.0.0"
cosmwasm-storage = "1.0.0"
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = "1.0.23"
-27
View File
@@ -1,27 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{StdError, VerificationError};
use thiserror::Error;
/// Custom errors for contract failure conditions.
///
/// Add any other custom errors you like here.
/// Look at https://docs.rs/thiserror/1.0.21/thiserror/ for details.
#[derive(Error, Debug, PartialEq)]
pub enum ContractError {
#[error("{0}")]
Std(#[from] StdError),
#[error("Invalid size for signature items")]
InvalidSignatureSize,
#[error("This payment has already been claimed by someone")]
PaymentAlreadyClaimed,
#[error("Error while verifying ed25519 signature - {0}")]
VerificationError(#[from] VerificationError),
#[error("The payment is not properly signed")]
BadSignature,
}
-103
View File
@@ -1,103 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
mod error;
mod queries;
mod storage;
mod support;
mod transactions;
use cosmwasm_std::{
entry_point, to_binary, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response,
};
use crate::error::ContractError;
use bandwidth_claim_contract::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
/// Instantiate the contract.
///
/// `deps` contains Storage, API and Querier
/// `env` contains block, message and contract info
/// `msg` is the contract initialization message, sort of like a constructor call.
#[entry_point]
pub fn instantiate(
_deps: DepsMut<'_>,
_env: Env,
_info: MessageInfo,
_msg: InstantiateMsg,
) -> Result<Response, ContractError> {
Ok(Response::default())
}
/// Handle an incoming message
#[entry_point]
pub fn execute(
deps: DepsMut<'_>,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::LinkPayment { data } => transactions::link_payment(deps, env, info, data),
}
}
#[entry_point]
pub fn query(deps: Deps<'_>, _env: Env, msg: QueryMsg) -> Result<QueryResponse, ContractError> {
let query_res = match msg {
QueryMsg::GetPayments { start_after, limit } => {
to_binary(&queries::query_payments_paged(deps, start_after, limit)?)
}
};
Ok(query_res?)
}
#[entry_point]
pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
Ok(Default::default())
}
#[cfg(test)]
pub mod tests {
use super::*;
use bandwidth_claim_contract::payment::PagedPaymentResponse;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::{coins, from_binary};
const TEST_MIX_DENOM: &str = "unym";
#[test]
fn initialize_contract() {
let mut deps = mock_dependencies();
let env = mock_env();
let msg = InstantiateMsg {};
let info = mock_info("creator", &[]);
let res = instantiate(deps.as_mut(), env.clone(), info, msg).unwrap();
assert_eq!(0, res.messages.len());
// payments should be empty after initialization
let res = query(
deps.as_ref(),
env.clone(),
QueryMsg::GetPayments {
start_after: None,
limit: Option::from(2),
},
)
.unwrap();
let page: PagedPaymentResponse = from_binary(&res).unwrap();
assert_eq!(0, page.payments.len()); // there are no payments in the list when it's just been initialized
// Contract balance should match what we initialized it as
assert_eq!(
coins(0, TEST_MIX_DENOM),
vec![deps
.as_ref()
.querier
.query_balance(env.contract.address, TEST_MIX_DENOM)
.unwrap()]
);
}
}
-191
View File
@@ -1,191 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{Deps, Order, StdResult};
use crate::storage::payments_read;
use bandwidth_claim_contract::keys::PublicKey;
use bandwidth_claim_contract::payment::{PagedPaymentResponse, Payment};
const PAYMENT_PAGE_MAX_LIMIT: u32 = 100;
const PAYMENT_PAGE_DEFAULT_LIMIT: u32 = 50;
/// Adds a 0 byte to terminate the `start_after` value given. This allows CosmWasm
/// to get the succeeding key as the start of the next page.
fn calculate_start_value<B: AsRef<[u8]>>(start_after: Option<B>) -> Option<Vec<u8>> {
start_after.as_ref().map(|identity| {
identity
.as_ref()
.iter()
.cloned()
.chain(std::iter::once(0))
.collect()
})
}
pub fn query_payments_paged(
deps: Deps<'_>,
start_after: Option<PublicKey>,
limit: Option<u32>,
) -> StdResult<PagedPaymentResponse> {
let limit = limit
.unwrap_or(PAYMENT_PAGE_DEFAULT_LIMIT)
.min(PAYMENT_PAGE_MAX_LIMIT) as usize;
let start = calculate_start_value(start_after);
let payments = payments_read(deps.storage)
.range(start.as_deref(), None, Order::Ascending)
.take(limit)
.map(|res| res.map(|item| item.1))
.collect::<StdResult<Vec<Payment>>>()?;
let start_next_after = payments.last().map(|payment| payment.verification_key());
Ok(PagedPaymentResponse::new(payments, limit, start_next_after))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::storage::payments;
use crate::support::tests::helpers;
use std::convert::TryInto;
#[test]
fn payments_empty_on_init() {
let deps = helpers::init_contract();
let response = query_payments_paged(deps.as_ref(), None, Option::from(2)).unwrap();
assert_eq!(0, response.payments.len());
}
#[test]
fn payments_paged_retrieval_obeys_limits() {
let mut deps = helpers::init_contract();
let storage = deps.as_mut().storage;
let limit = 2;
for n in 0u32..10000 {
let bytes: Vec<u8> = std::iter::repeat(n.to_be_bytes())
.take(8)
.flatten()
.collect();
let verification_key = PublicKey::new(bytes.try_into().unwrap());
let payment = helpers::payment_fixture();
payments(storage)
.save(&verification_key.to_bytes(), &payment)
.unwrap();
}
let page1 = query_payments_paged(deps.as_ref(), None, Option::from(limit)).unwrap();
assert_eq!(limit, page1.payments.len() as u32);
}
#[test]
fn payments_paged_retrieval_has_default_limit() {
let mut deps = helpers::init_contract();
let storage = deps.as_mut().storage;
for n in 0u32..100 {
let bytes: Vec<u8> = std::iter::repeat(n.to_be_bytes())
.take(8)
.flatten()
.collect();
let verification_key = PublicKey::new(bytes.try_into().unwrap());
let payment = helpers::payment_fixture();
payments(storage)
.save(&verification_key.to_bytes(), &payment)
.unwrap();
}
// query without explicitly setting a limit
let page1 = query_payments_paged(deps.as_ref(), None, None).unwrap();
assert_eq!(PAYMENT_PAGE_DEFAULT_LIMIT, page1.payments.len() as u32);
}
#[test]
fn payments_paged_retrieval_has_max_limit() {
let mut deps = helpers::init_contract();
let storage = deps.as_mut().storage;
for n in 0u32..10000 {
let bytes: Vec<u8> = std::iter::repeat(n.to_be_bytes())
.take(8)
.flatten()
.collect();
let verification_key = PublicKey::new(bytes.try_into().unwrap());
let payment = helpers::payment_fixture();
payments(storage)
.save(&verification_key.to_bytes(), &payment)
.unwrap();
}
// query with a crazily high limit in an attempt to use too many resources
let crazy_limit = 1000;
let page1 = query_payments_paged(deps.as_ref(), None, Option::from(crazy_limit)).unwrap();
// we default to a decent sized upper bound instead
assert_eq!(PAYMENT_PAGE_MAX_LIMIT, page1.payments.len() as u32);
}
#[test]
fn payments_pagination_works() {
let key1 = PublicKey::new([1; 32]);
let key2 = PublicKey::new([2; 32]);
let key3 = PublicKey::new([3; 32]);
let key4 = PublicKey::new([4; 32]);
let mut deps = helpers::init_contract();
let payment = helpers::payment_fixture();
payments(&mut deps.storage)
.save(&key1.to_bytes(), &payment)
.unwrap();
let per_page = 2;
let page1 = query_payments_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
// page should have 1 result on it
assert_eq!(1, page1.payments.len());
// save another
payments(&mut deps.storage)
.save(&key2.to_bytes(), &payment)
.unwrap();
// page1 should have 2 results on it
let page1 = query_payments_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
assert_eq!(2, page1.payments.len());
payments(&mut deps.storage)
.save(&key3.to_bytes(), &payment)
.unwrap();
// page1 still has 2 results
let page1 = query_payments_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
assert_eq!(2, page1.payments.len());
// retrieving the next page should start after the last key on this page
let start_after = key2;
let page2 = query_payments_paged(
deps.as_ref(),
Option::from(start_after),
Option::from(per_page),
)
.unwrap();
assert_eq!(1, page2.payments.len());
// save another one
payments(&mut deps.storage)
.save(&key4.to_bytes(), &payment)
.unwrap();
let start_after = key2;
let page2 = query_payments_paged(
deps.as_ref(),
Option::from(start_after),
Option::from(per_page),
)
.unwrap();
// now we have 2 pages, with 2 results on the second page
assert_eq!(2, page2.payments.len());
}
}
-79
View File
@@ -1,79 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::Storage;
use cosmwasm_storage::{bucket, bucket_read, Bucket, ReadonlyBucket};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use bandwidth_claim_contract::payment::Payment;
// buckets
const PREFIX_PAYMENTS: &[u8] = b"payments";
const PREFIX_STATUS: &[u8] = b"status";
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
pub enum Status {
Unchecked,
Checked,
Spent,
}
pub fn payments(storage: &mut dyn Storage) -> Bucket<'_, Payment> {
bucket(storage, PREFIX_PAYMENTS)
}
pub fn payments_read(storage: &dyn Storage) -> ReadonlyBucket<'_, Payment> {
bucket_read(storage, PREFIX_PAYMENTS)
}
pub fn status(storage: &mut dyn Storage) -> Bucket<'_, Status> {
bucket(storage, PREFIX_STATUS)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::support::tests::helpers;
use bandwidth_claim_contract::keys::PublicKey;
use cosmwasm_std::testing::MockStorage;
#[test]
fn payments_single_read_retrieval() {
let mut storage = MockStorage::new();
let key1 = PublicKey::new([1; 32]);
let key2 = PublicKey::new([2; 32]);
let payment1 = helpers::payment_fixture();
let payment2 = helpers::payment_fixture();
payments(&mut storage)
.save(key1.as_ref(), &payment1)
.unwrap();
payments(&mut storage)
.save(key2.as_ref(), &payment2)
.unwrap();
let res1 = payments_read(&storage).load(key1.as_ref()).unwrap();
let res2 = payments_read(&storage).load(key2.as_ref()).unwrap();
assert_eq!(payment1, res1);
assert_eq!(payment2, res2);
}
#[test]
fn status_single_read_retrieval() {
let mut storage = MockStorage::new();
let key1 = PublicKey::new([1; 32]);
let key2 = PublicKey::new([2; 32]);
let status_value = Status::Unchecked;
status(&mut storage)
.save(key1.as_ref(), &status_value)
.unwrap();
status(&mut storage)
.save(key2.as_ref(), &status_value)
.unwrap();
let res1 = status(&mut storage).load(key1.as_ref()).unwrap();
assert_eq!(status_value, res1);
let res2 = status(&mut storage).load(key2.as_ref()).unwrap();
assert_eq!(status_value, res2);
}
}
@@ -1,3 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod tests;
@@ -1,28 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(test)]
pub mod helpers {
use crate::instantiate;
use bandwidth_claim_contract::keys::PublicKey;
use bandwidth_claim_contract::msg::InstantiateMsg;
use bandwidth_claim_contract::payment::Payment;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier};
use cosmwasm_std::{Empty, MemoryStorage, OwnedDeps};
pub fn init_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>> {
let mut deps = mock_dependencies();
let msg = InstantiateMsg {};
let env = mock_env();
let info = mock_info("creator", &[]);
instantiate(deps.as_mut(), env.clone(), info, msg).unwrap();
return deps;
}
pub fn payment_fixture() -> Payment {
let public_key = PublicKey::new([1; 32]);
let gateway_identity = PublicKey::new([2; 32]);
let bandwidth = 42;
Payment::new(public_key, gateway_identity, bandwidth)
}
}
@@ -1,146 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
use crate::error::ContractError;
use crate::storage::{payments, status, Status};
use bandwidth_claim_contract::payment::{LinkPaymentData, Payment};
pub(crate) fn link_payment(
deps: DepsMut<'_>,
_env: Env,
_info: MessageInfo,
data: LinkPaymentData,
) -> Result<Response, ContractError> {
let mut status_bucket = status(deps.storage);
let verification_key = data.verification_key.to_bytes();
let gateway_identity = data.gateway_identity.to_bytes();
let message: Vec<u8> = verification_key
.iter()
.chain(gateway_identity.iter())
.copied()
.collect();
let signature = data.signature.to_bytes();
if let Ok(Some(_)) = status_bucket.may_load(&verification_key) {
return Err(ContractError::PaymentAlreadyClaimed);
}
if !deps
.api
.ed25519_verify(&message, &signature, &verification_key)?
{
return Err(ContractError::BadSignature);
}
status_bucket.save(&verification_key, &Status::Unchecked)?;
payments(deps.storage).save(
&verification_key,
&Payment::new(data.verification_key, data.gateway_identity, data.bandwidth),
)?;
Ok(Response::default())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::storage::payments_read;
use crate::support::tests::helpers;
use bandwidth_claim_contract::keys::PublicKey;
use cosmwasm_std::testing::{mock_env, mock_info};
#[test]
fn bad_signature_payment() {
let mut deps = helpers::init_contract();
let env = mock_env();
let info = mock_info("owner", &[]);
let payment_data = LinkPaymentData::new([1; 32], [2; 32], 42, [3; 64]);
assert_eq!(
link_payment(deps.as_mut(), env, info, payment_data),
Err(ContractError::BadSignature)
);
}
#[test]
fn good_payment() {
let mut deps = helpers::init_contract();
let env = mock_env();
let info = mock_info("owner", &[]);
let verification_key = [
78, 142, 213, 13, 39, 169, 76, 205, 242, 206, 129, 208, 190, 51, 139, 206, 245, 199,
120, 151, 181, 250, 192, 153, 123, 104, 129, 139, 60, 254, 243, 98,
];
let gateway_identity = [
106, 76, 76, 238, 214, 177, 233, 112, 56, 33, 21, 201, 89, 42, 69, 196, 175, 56, 6,
110, 184, 167, 203, 63, 1, 167, 134, 102, 165, 215, 3, 212,
];
let bandwidth = 42;
let signature = [
200, 134, 156, 198, 113, 180, 129, 90, 70, 28, 176, 201, 35, 208, 145, 28, 15, 16, 9,
110, 148, 188, 193, 75, 157, 201, 206, 211, 128, 215, 66, 207, 175, 155, 48, 24, 171,
254, 9, 37, 108, 205, 143, 37, 77, 189, 162, 52, 44, 130, 173, 60, 220, 22, 193, 3,
111, 90, 123, 147, 206, 8, 137, 1,
];
let payment_data =
LinkPaymentData::new(verification_key, gateway_identity, bandwidth, signature);
assert!(link_payment(deps.as_mut(), env, info, payment_data).is_ok());
assert_eq!(
payments_read(&deps.storage)
.load(&verification_key)
.unwrap(),
Payment::new(
PublicKey::new(verification_key),
PublicKey::new(gateway_identity),
bandwidth
)
);
assert_eq!(
status(&mut deps.storage).load(&verification_key).unwrap(),
Status::Unchecked
)
}
#[test]
fn double_spend_protection() {
let mut deps = helpers::init_contract();
let env = mock_env();
let info = mock_info("owner", &[]);
let verification_key = [
78, 142, 213, 13, 39, 169, 76, 205, 242, 206, 129, 208, 190, 51, 139, 206, 245, 199,
120, 151, 181, 250, 192, 153, 123, 104, 129, 139, 60, 254, 243, 98,
];
let gateway_identity = [
106, 76, 76, 238, 214, 177, 233, 112, 56, 33, 21, 201, 89, 42, 69, 196, 175, 56, 6,
110, 184, 167, 203, 63, 1, 167, 134, 102, 165, 215, 3, 212,
];
let bandwidth = 42;
let signature = [
200, 134, 156, 198, 113, 180, 129, 90, 70, 28, 176, 201, 35, 208, 145, 28, 15, 16, 9,
110, 148, 188, 193, 75, 157, 201, 206, 211, 128, 215, 66, 207, 175, 155, 48, 24, 171,
254, 9, 37, 108, 205, 143, 37, 77, 189, 162, 52, 44, 130, 173, 60, 220, 22, 193, 3,
111, 90, 123, 147, 206, 8, 137, 1,
];
let payment_data =
LinkPaymentData::new(verification_key, gateway_identity, bandwidth, signature);
link_payment(deps.as_mut(), env.clone(), info.clone(), payment_data).unwrap();
// Only the verification key is used for double spending protection, the other data is irrelevant
let second_payment_data = LinkPaymentData::new(verification_key, [1; 32], 10, [2; 64]);
assert_eq!(
link_payment(deps.as_mut(), env, info, second_payment_data),
Err(ContractError::PaymentAlreadyClaimed)
)
}
}
@@ -1,7 +0,0 @@
node_modules
../.env
.to_do.md
#Hardhat files
cache
artifacts
@@ -1,6 +0,0 @@
module.exports = {
skipFiles: [
'CosmosToken.sol',
'Gravity.sol'
]
};
@@ -1,17 +0,0 @@
# Basic Bandwidth Credential Generator
This directory contains the contract and unit tests for the `BandwidthGenerator` smart contract.
This contract allows users to generate Basic Bandwidth Credentials (BBCs) on the Nym cosmos blockchain using ERC20 representations of NYM as payment, utilising the Cosmos Gravity Bridge for cross-chain payment.
BBCs are credentials that will be presented to Gateways by a Nym Client, and represent a certain amount of bandwidth which can be sent through the Nym Mixnet.
By default 1 NYM = 1 GB of bandwidth. The ratio of NYM - bandwidth is denominated in bytes, and represented in the smart contract by the `BytesPerToken` variable. This variable can be adjusted by the contract owner.
The amount of bandwidth bought is calculated according to the following formula:
`(Token amount in 'wei' * BytesPerToken) / 10**18`
## Usage
* `npm install`
* `npx hardhat compile`
* `npx hardhat test`
@@ -1,4 +0,0 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../../build-info/1f95016aa87f8376998977fedfcae017.json"
}
File diff suppressed because one or more lines are too long
@@ -1,4 +0,0 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../../build-info/1f95016aa87f8376998977fedfcae017.json"
}
@@ -1,194 +0,0 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "IERC20",
"sourceName": "@openzeppelin/contracts/token/ERC20/IERC20.sol",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}
@@ -1,4 +0,0 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../../../build-info/1f95016aa87f8376998977fedfcae017.json"
}
@@ -1,233 +0,0 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "IERC20Metadata",
"sourceName": "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}
@@ -1,4 +0,0 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/1f95016aa87f8376998977fedfcae017.json"
}
@@ -1,10 +0,0 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "Context",
"sourceName": "@openzeppelin/contracts/utils/Context.sol",
"abi": [],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}
@@ -1,549 +0,0 @@
{
"_format": "hh-sol-cache-2",
"files": {
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/contracts/BandwidthGenerator.sol": {
"lastModificationDate": 1643129770695,
"contentHash": "642b72e2d50d565db7bc994cace3f5a0",
"sourceName": "contracts/BandwidthGenerator.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [
"./CosmosToken.sol",
"./Gravity.sol",
"@openzeppelin/contracts/access/Ownable.sol",
"@openzeppelin/contracts/utils/math/SafeMath.sol"
],
"versionPragmas": [
"0.8.10"
],
"artifacts": [
"BandwidthGenerator"
]
},
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/contracts/CosmosToken.sol": {
"lastModificationDate": 1642773899716,
"contentHash": "fc5dd09fe73bc6cfece970f702a3aba1",
"sourceName": "contracts/CosmosToken.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [
"@openzeppelin/contracts/token/ERC20/ERC20.sol"
],
"versionPragmas": [
"0.8.10"
],
"artifacts": [
"CosmosERC20"
]
},
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/contracts/Gravity.sol": {
"lastModificationDate": 1642773899716,
"contentHash": "0d6dae561f7b541bafb892b8593a08ac",
"sourceName": "contracts/Gravity.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [
"@openzeppelin/contracts/token/ERC20/IERC20.sol",
"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol",
"@openzeppelin/contracts/security/ReentrancyGuard.sol",
"@openzeppelin/contracts/utils/Address.sol",
"@openzeppelin/contracts/utils/cryptography/ECDSA.sol",
"./CosmosToken.sol"
],
"versionPragmas": [
"0.8.10"
],
"artifacts": [
"Gravity"
]
},
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/access/Ownable.sol": {
"lastModificationDate": 1641812554274,
"contentHash": "4fe56b59ced59d87df6b796758f62895",
"sourceName": "@openzeppelin/contracts/access/Ownable.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [
"../utils/Context.sol"
],
"versionPragmas": [
"^0.8.0"
],
"artifacts": [
"Ownable"
]
},
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/utils/math/SafeMath.sol": {
"lastModificationDate": 1641812554378,
"contentHash": "5365090efc586b728719e562ebfed0d6",
"sourceName": "@openzeppelin/contracts/utils/math/SafeMath.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [],
"versionPragmas": [
"^0.8.0"
],
"artifacts": [
"SafeMath"
]
},
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol": {
"lastModificationDate": 1641812553614,
"contentHash": "2cd550cedf51b8d294607dad5023d717",
"sourceName": "@openzeppelin/contracts/token/ERC20/ERC20.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [
"./IERC20.sol",
"./extensions/IERC20Metadata.sol",
"../../utils/Context.sol"
],
"versionPragmas": [
"^0.8.0"
],
"artifacts": [
"ERC20"
]
},
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"lastModificationDate": 1641812554110,
"contentHash": "0eac3e1a83ee62326ca007811285b274",
"sourceName": "@openzeppelin/contracts/token/ERC20/IERC20.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [],
"versionPragmas": [
"^0.8.0"
],
"artifacts": [
"IERC20"
]
},
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
"lastModificationDate": 1641812554118,
"contentHash": "aa1be06992a99bb7393b26a6af3c4dfb",
"sourceName": "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [
"../IERC20.sol"
],
"versionPragmas": [
"^0.8.0"
],
"artifacts": [
"IERC20Metadata"
]
},
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/utils/Context.sol": {
"lastModificationDate": 1641812553346,
"contentHash": "851485d5b925529b1a2f34a0be077891",
"sourceName": "@openzeppelin/contracts/utils/Context.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [],
"versionPragmas": [
"^0.8.0"
],
"artifacts": [
"Context"
]
},
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
"lastModificationDate": 1641812554370,
"contentHash": "d37406082a74a9b6b114de522fcb6349",
"sourceName": "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [
"../IERC20.sol",
"../../../utils/Address.sol"
],
"versionPragmas": [
"^0.8.0"
],
"artifacts": [
"SafeERC20"
]
},
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/security/ReentrancyGuard.sol": {
"lastModificationDate": 1641812554322,
"contentHash": "53fbff678f378956efcb207fa748eaa6",
"sourceName": "@openzeppelin/contracts/security/ReentrancyGuard.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [],
"versionPragmas": [
"^0.8.0"
],
"artifacts": [
"ReentrancyGuard"
]
},
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/utils/Address.sol": {
"lastModificationDate": 1641812553270,
"contentHash": "c5f6c4e4df069c789e7d84b4c3011913",
"sourceName": "@openzeppelin/contracts/utils/Address.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [],
"versionPragmas": [
"^0.8.0"
],
"artifacts": [
"Address"
]
},
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/utils/cryptography/ECDSA.sol": {
"lastModificationDate": 1641812553414,
"contentHash": "197dbfaf7146845fa76331a4c9980e9f",
"sourceName": "@openzeppelin/contracts/utils/cryptography/ECDSA.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [],
"versionPragmas": [
"^0.8.0"
],
"artifacts": [
"ECDSA"
]
},
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/contracts/test-contracts/TestCosmosToken.sol": {
"lastModificationDate": 1642773899716,
"contentHash": "957b6079ee0d5a6e048fce8555c14dee",
"sourceName": "contracts/test-contracts/TestCosmosToken.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [
"@openzeppelin/contracts/token/ERC20/ERC20.sol"
],
"versionPragmas": [
"0.8.10"
],
"artifacts": [
"TestCosmosERC20"
]
},
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/contracts/test-contracts/TestGravity.sol": {
"lastModificationDate": 1642773899716,
"contentHash": "f24299c3acb20aff23914e16b7ba95e1",
"sourceName": "contracts/test-contracts/TestGravity.sol",
"solcConfig": {
"version": "0.8.10",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"ast"
]
}
}
}
},
"imports": [
"@openzeppelin/contracts/token/ERC20/IERC20.sol",
"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol",
"@openzeppelin/contracts/security/ReentrancyGuard.sol",
"@openzeppelin/contracts/utils/Address.sol",
"@openzeppelin/contracts/utils/cryptography/ECDSA.sol",
"./TestCosmosToken.sol"
],
"versionPragmas": [
"0.8.10"
],
"artifacts": [
"TestGravity"
]
}
}
}
@@ -1,12 +0,0 @@
{
"rinkeby":
{"NYM_ERC20":"0xe58c12f8bA4a28e87841b10BdEdf80A47F86BA9B",
"BANDWIDTH_GENERATOR":"0xfa2714Bf14EB5Bb887e4A54984C6F7A7e3E6c84b",
"GRAVITY":"0xe58c12f8bA4a28e87841b10BdEdf80A47F86BA9B"},
"mainnet":
{"NYM_ERC20":"0x525A8F6F3Ba4752868cde25164382BfbaE3990e1",
"NYMT":"0xE8883BAeF3869e14E4823F46662e81D4F7d2A81F",
"BANDWIDTH_GENERATOR":"0x3FfEb99acca159A182f35F9944dAf3BF41Ae8165",
"BANDWIDTH_GENERATOR_NYMT":"0xB3BF30DD53044c9050B7309031Bbf26b2cecF3be",
"GRAVITY":"0xa4108aA1Ec4967F8b52220a4f7e94A8201F2D906"}
}
@@ -1,115 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
import "./CosmosToken.sol";
import "./Gravity.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
/**
* @title BandwidthGenerator
* @dev Contract for generating Basic Bandwidth Credentials (BBCs) on the Nym cosmos blockchain,
* using ERC20 representations of NYM as payment. Utilises the Gravity Bridge for cross-chain payment.
*
* Credential generation can be switched on/off by the contract owner.
*
* Credentials represent a certain amount of bandwidth which can be sent through the Nym Mixnet.
* By default 1 NYM = 1 GB of bandwidth. The `BytesPerToken` amount can be adjusted by the contract owner.
* The amount of bandwidth bought is calculated according to the following formula:
* `(Token amount in 'wei' / 10**18) * BytesPerToken`
*/
contract BandwidthGenerator is Ownable {
using SafeMath for uint256;
CosmosERC20 public erc20;
Gravity public gravityBridge;
uint256 public BytesPerToken;
bool public credentialGenerationEnabled;
event BBCredentialPurchased(
uint256 Bandwidth,
uint256 indexed VerificationKey,
bytes SignedVerificationKey,
string CosmosRecipient
);
event RatioChanged(
uint256 indexed NewBytesPerToken
);
event CredentialGenerationSwitch(
bool Enabled
);
modifier checkEnabled() {
require(credentialGenerationEnabled, "BandwidthGenerator: credential generation isn't currently enabled");
_;
}
/**
* @param _erc20 Address of the erc20NYM deployed through the Gravity Bridge.
* @param _gravityBridge Address of the deployed Gravity Bridge.
*/
constructor(CosmosERC20 _erc20, Gravity _gravityBridge) {
require(address(_erc20) != address(0), "BandwidthGenerator: erc20 address cannot be null");
require(address(_gravityBridge) != address(0), "BandwidthGenerator: gravity bridge address cannot be null");
erc20 = _erc20;
gravityBridge = _gravityBridge;
BytesPerToken = 1073741824; // default amount set at deployment: 1 erc20NYM = 1073741824 Bytes = 1GB
credentialGenerationEnabled = true;
}
/**
* @dev Changes amount of Bytes each erc20NYM is tradable for. Can only be called by Owner.
* @param _newBytesPerTokenAmount Amount of Bytes BBC is worth per 1 erc20NYM token.
*/
function changeRatio(uint256 _newBytesPerTokenAmount) public onlyOwner {
require(_newBytesPerTokenAmount != 0, "BandwidthGenerator: price cannot be 0");
BytesPerToken = _newBytesPerTokenAmount;
emit RatioChanged(_newBytesPerTokenAmount);
}
/**
* @dev Switches credential generation on/off. Can only be called by Owner.
* @param _generation Whether credential generation is turned on/off.
*/
function credentialGenerationSwitch(bool _generation) public onlyOwner {
credentialGenerationEnabled = _generation;
emit CredentialGenerationSwitch(_generation);
}
/**
* @dev Function to create a BBC for account owning the verification key on the Nym Cosmos Blockchain
* by transfering erc20NYM via the Gravity Bridge.
* @param _amount Amount of erc20NYM tokens to spend on BBC - denominated in wei.
* @param _verificationKey Verification key of account on Nym blockchain who is purchasing BBC.
* @param _signedVerificationKey Number of erc20NYMs to spend signed by _verificationKey for auth on Cosmos Blockchain.
* @param _cosmosRecipient Address of the recipient of payment on Nym Cosmos Blockchain.
*/
function generateBasicBandwidthCredential(uint256 _amount, uint256 _verificationKey, bytes memory _signedVerificationKey, string calldata _cosmosRecipient) public checkEnabled {
require(_signedVerificationKey.length == 64, "BandwidthGenerator: Signature doesn't have 64 bytes");
erc20.transferFrom(msg.sender, address(this), _amount);
erc20.approve(address(gravityBridge), _amount);
gravityBridge.sendToCosmos(
address(erc20),
_cosmosRecipient,
_amount
);
uint256 bandwidth = bandwidthFromToken(_amount);
emit BBCredentialPurchased(
bandwidth,
_verificationKey,
_signedVerificationKey,
_cosmosRecipient
);
}
function bandwidthFromToken(uint256 _amount) public view returns (uint256) {
uint256 amountMulBytes = _amount.mul(BytesPerToken);
return amountMulBytes.div(10**18);
}
}
@@ -1,35 +0,0 @@
//SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract CosmosERC20 is ERC20 {
uint256 MAX_UINT = 2**256 - 1;
uint8 private cosmosDecimals;
address private gravityAddress;
// This override ensures we return the proper number of decimals
// for the cosmos token
function decimals() public view virtual override returns (uint8) {
return cosmosDecimals;
}
// This is not an accurate total supply. Instead this is the total supply
// of the given cosmos asset on Ethereum at this moment in time. Keeping
// a totally accurate supply would require constant updates from the Cosmos
// side, while in theory this could be piggy-backed on some existing bridge
// operation it's a lot of complextiy to add so we chose to forgoe it.
function totalSupply() public view virtual override returns (uint256) {
return MAX_UINT - balanceOf(gravityAddress);
}
constructor(
address _gravityAddress,
string memory _name,
string memory _symbol,
uint8 _decimals
) ERC20(_name, _symbol) {
cosmosDecimals = _decimals;
gravityAddress = _gravityAddress;
_mint(_gravityAddress, MAX_UINT);
}
}
@@ -1,663 +0,0 @@
//SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "./CosmosToken.sol";
error InvalidSignature();
error InvalidValsetNonce(uint256 newNonce, uint256 currentNonce);
error InvalidBatchNonce(uint256 newNonce, uint256 currentNonce);
error InvalidLogicCallNonce(uint256 newNonce, uint256 currentNonce);
error InvalidLogicCallTransfers();
error InvalidLogicCallFees();
error InvalidSendToCosmos();
error IncorrectCheckpoint();
error MalformedNewValidatorSet();
error MalformedCurrentValidatorSet();
error MalformedBatch();
error InsufficientPower(uint256 cumulativePower, uint256 powerThreshold);
error BatchTimedOut();
error LogicCallTimedOut();
// This is being used purely to avoid stack too deep errors
struct LogicCallArgs {
// Transfers out to the logic contract
uint256[] transferAmounts;
address[] transferTokenContracts;
// The fees (transferred to msg.sender)
uint256[] feeAmounts;
address[] feeTokenContracts;
// The arbitrary logic call
address logicContractAddress;
bytes payload;
// Invalidation metadata
uint256 timeOut;
bytes32 invalidationId;
uint256 invalidationNonce;
}
// This is used purely to avoid stack too deep errors
// represents everything about a given validator set
struct ValsetArgs {
// the validators in this set, represented by an Ethereum address
address[] validators;
// the powers of the given validators in the same order as above
uint256[] powers;
// the nonce of this validator set
uint256 valsetNonce;
// the reward amount denominated in the below reward token, can be
// set to zero
uint256 rewardAmount;
// the reward token, should be set to the zero address if not being used
address rewardToken;
}
// This represents a validator signature
struct Signature {
uint8 v;
bytes32 r;
bytes32 s;
}
contract Gravity is ReentrancyGuard {
using SafeERC20 for IERC20;
// The number of 'votes' required to execute a valset
// update or batch execution, set to 2/3 of 2^32
uint256 constant constant_powerThreshold = 2863311530;
// These are updated often
bytes32 public state_lastValsetCheckpoint;
mapping(address => uint256) public state_lastBatchNonces;
mapping(bytes32 => uint256) public state_invalidationMapping;
uint256 public state_lastValsetNonce = 0;
// event nonce zero is reserved by the Cosmos module as a special
// value indicating that no events have yet been submitted
uint256 public state_lastEventNonce = 1;
// This is set once at initialization
bytes32 public immutable state_gravityId;
// TransactionBatchExecutedEvent and SendToCosmosEvent both include the field _eventNonce.
// This is incremented every time one of these events is emitted. It is checked by the
// Cosmos module to ensure that all events are received in order, and that none are lost.
//
// ValsetUpdatedEvent does not include the field _eventNonce because it is never submitted to the Cosmos
// module. It is purely for the use of relayers to allow them to successfully submit batches.
event TransactionBatchExecutedEvent(
uint256 indexed _batchNonce,
address indexed _token,
uint256 _eventNonce
);
event SendToCosmosEvent(
address indexed _tokenContract,
address indexed _sender,
string _destination,
uint256 _amount,
uint256 _eventNonce
);
event ERC20DeployedEvent(
// FYI: Can't index on a string without doing a bunch of weird stuff
string _cosmosDenom,
address indexed _tokenContract,
string _name,
string _symbol,
uint8 _decimals,
uint256 _eventNonce
);
event ValsetUpdatedEvent(
uint256 indexed _newValsetNonce,
uint256 _eventNonce,
uint256 _rewardAmount,
address _rewardToken,
address[] _validators,
uint256[] _powers
);
event LogicCallEvent(
bytes32 _invalidationId,
uint256 _invalidationNonce,
bytes _returnData,
uint256 _eventNonce
);
// TEST FIXTURES
// These are here to make it easier to measure gas usage. They should be removed before production
function testMakeCheckpoint(ValsetArgs calldata _valsetArgs, bytes32 _gravityId) external pure {
makeCheckpoint(_valsetArgs, _gravityId);
}
function testCheckValidatorSignatures(
ValsetArgs calldata _currentValset,
Signature[] calldata _sigs,
bytes32 _theHash,
uint256 _powerThreshold
) external pure {
checkValidatorSignatures(_currentValset, _sigs, _theHash, _powerThreshold);
}
// END TEST FIXTURES
function lastBatchNonce(address _erc20Address) external view returns (uint256) {
return state_lastBatchNonces[_erc20Address];
}
function lastLogicCallNonce(bytes32 _invalidation_id) external view returns (uint256) {
return state_invalidationMapping[_invalidation_id];
}
// Utility function to verify geth style signatures
function verifySig(
address _signer,
bytes32 _theHash,
Signature calldata _sig
) private pure returns (bool) {
bytes32 messageDigest = keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", _theHash)
);
return _signer == ECDSA.recover(messageDigest, _sig.v, _sig.r, _sig.s);
}
// Utility function to determine that a validator set and signatures are well formed
function validateValset(ValsetArgs calldata _valset, Signature[] calldata _sigs) private pure {
// Check that current validators, powers, and signatures (v,r,s) set is well-formed
if (
_valset.validators.length != _valset.powers.length ||
_valset.validators.length != _sigs.length
) {
revert MalformedCurrentValidatorSet();
}
}
// Make a new checkpoint from the supplied validator set
// A checkpoint is a hash of all relevant information about the valset. This is stored by the contract,
// instead of storing the information directly. This saves on storage and gas.
// The format of the checkpoint is:
// h(gravityId, "checkpoint", valsetNonce, validators[], powers[])
// Where h is the keccak256 hash function.
// The validator powers must be decreasing or equal. This is important for checking the signatures on the
// next valset, since it allows the caller to stop verifying signatures once a quorum of signatures have been verified.
function makeCheckpoint(ValsetArgs memory _valsetArgs, bytes32 _gravityId)
private
pure
returns (bytes32)
{
// bytes32 encoding of the string "checkpoint"
bytes32 methodName = 0x636865636b706f696e7400000000000000000000000000000000000000000000;
bytes32 checkpoint = keccak256(
abi.encode(
_gravityId,
methodName,
_valsetArgs.valsetNonce,
_valsetArgs.validators,
_valsetArgs.powers,
_valsetArgs.rewardAmount,
_valsetArgs.rewardToken
)
);
return checkpoint;
}
function checkValidatorSignatures(
// The current validator set and their powers
ValsetArgs calldata _currentValset,
// The current validator's signatures
Signature[] calldata _sigs,
// This is what we are checking they have signed
bytes32 _theHash,
uint256 _powerThreshold
) private pure {
uint256 cumulativePower = 0;
for (uint256 i = 0; i < _currentValset.validators.length; i++) {
// If v is set to 0, this signifies that it was not possible to get a signature from this validator and we skip evaluation
// (In a valid signature, it is either 27 or 28)
if (_sigs[i].v != 0) {
// Check that the current validator has signed off on the hash
if (!verifySig(_currentValset.validators[i], _theHash, _sigs[i])) {
revert InvalidSignature();
}
// Sum up cumulative power
cumulativePower = cumulativePower + _currentValset.powers[i];
// Break early to avoid wasting gas
if (cumulativePower > _powerThreshold) {
break;
}
}
}
// Check that there was enough power
if (cumulativePower <= _powerThreshold) {
revert InsufficientPower(cumulativePower, _powerThreshold);
}
// Success
}
// This updates the valset by checking that the validators in the current valset have signed off on the
// new valset. The signatures supplied are the signatures of the current valset over the checkpoint hash
// generated from the new valset.
// Anyone can call this function, but they must supply valid signatures of constant_powerThreshold of the current valset over
// the new valset.
function updateValset(
// The new version of the validator set
ValsetArgs calldata _newValset,
// The current validators that approve the change
ValsetArgs calldata _currentValset,
// These are arrays of the parts of the current validator's signatures
Signature[] calldata _sigs
) external {
// CHECKS
// Check that the valset nonce is greater than the old one
if (_newValset.valsetNonce <= _currentValset.valsetNonce) {
revert InvalidValsetNonce({
newNonce: _newValset.valsetNonce,
currentNonce: _currentValset.valsetNonce
});
}
// Check that the valset nonce is less than a million nonces forward from the old one
// this makes it difficult for an attacker to lock out the contract by getting a single
// bad validator set through with uint256 max nonce
if (_newValset.valsetNonce > _currentValset.valsetNonce + 1000000) {
revert InvalidValsetNonce({
newNonce: _newValset.valsetNonce,
currentNonce: _currentValset.valsetNonce
});
}
// Check that new validators and powers set is well-formed
if (
_newValset.validators.length != _newValset.powers.length ||
_newValset.validators.length == 0
) {
revert MalformedNewValidatorSet();
}
// Check that current validators, powers, and signatures (v,r,s) set is well-formed
validateValset(_currentValset, _sigs);
// Check cumulative power to ensure the contract has sufficient power to actually
// pass a vote
uint256 cumulativePower = 0;
for (uint256 i = 0; i < _newValset.powers.length; i++) {
cumulativePower = cumulativePower + _newValset.powers[i];
if (cumulativePower > constant_powerThreshold) {
break;
}
}
if (cumulativePower <= constant_powerThreshold) {
revert InsufficientPower({
cumulativePower: cumulativePower,
powerThreshold: constant_powerThreshold
});
}
// Check that the supplied current validator set matches the saved checkpoint
if (makeCheckpoint(_currentValset, state_gravityId) != state_lastValsetCheckpoint) {
revert IncorrectCheckpoint();
}
// Check that enough current validators have signed off on the new validator set
bytes32 newCheckpoint = makeCheckpoint(_newValset, state_gravityId);
checkValidatorSignatures(_currentValset, _sigs, newCheckpoint, constant_powerThreshold);
// ACTIONS
// Stored to be used next time to validate that the valset
// supplied by the caller is correct.
state_lastValsetCheckpoint = newCheckpoint;
// Store new nonce
state_lastValsetNonce = _newValset.valsetNonce;
// Send submission reward to msg.sender if reward token is a valid value
if (_newValset.rewardToken != address(0) && _newValset.rewardAmount != 0) {
IERC20(_newValset.rewardToken).safeTransfer(msg.sender, _newValset.rewardAmount);
}
// LOGS
state_lastEventNonce = state_lastEventNonce + 1;
emit ValsetUpdatedEvent(
_newValset.valsetNonce,
state_lastEventNonce,
_newValset.rewardAmount,
_newValset.rewardToken,
_newValset.validators,
_newValset.powers
);
}
// submitBatch processes a batch of Cosmos -> Ethereum transactions by sending the tokens in the transactions
// to the destination addresses. It is approved by the current Cosmos validator set.
// Anyone can call this function, but they must supply valid signatures of constant_powerThreshold of the current valset over
// the batch.
function submitBatch(
// The validators that approve the batch
ValsetArgs calldata _currentValset,
// These are arrays of the parts of the validators signatures
Signature[] calldata _sigs,
// The batch of transactions
uint256[] calldata _amounts,
address[] calldata _destinations,
uint256[] calldata _fees,
uint256 _batchNonce,
address _tokenContract,
// a block height beyond which this batch is not valid
// used to provide a fee-free timeout
uint256 _batchTimeout
) external nonReentrant {
// CHECKS scoped to reduce stack depth
{
// Check that the batch nonce is higher than the last nonce for this token
if (_batchNonce <= state_lastBatchNonces[_tokenContract]) {
revert InvalidBatchNonce({
newNonce: _batchNonce,
currentNonce: state_lastBatchNonces[_tokenContract]
});
}
// Check that the batch nonce is less than one million nonces forward from the old one
// this makes it difficult for an attacker to lock out the contract by getting a single
// bad batch through with uint256 max nonce
if (_batchNonce > state_lastBatchNonces[_tokenContract] + 1000000) {
revert InvalidBatchNonce({
newNonce: _batchNonce,
currentNonce: state_lastBatchNonces[_tokenContract]
});
}
// Check that the block height is less than the timeout height
if (block.number >= _batchTimeout) {
revert BatchTimedOut();
}
// Check that current validators, powers, and signatures (v,r,s) set is well-formed
validateValset(_currentValset, _sigs);
// Check that the supplied current validator set matches the saved checkpoint
if (makeCheckpoint(_currentValset, state_gravityId) != state_lastValsetCheckpoint) {
revert IncorrectCheckpoint();
}
// Check that the transaction batch is well-formed
if (_amounts.length != _destinations.length || _amounts.length != _fees.length) {
revert MalformedBatch();
}
// Check that enough current validators have signed off on the transaction batch and valset
checkValidatorSignatures(
_currentValset,
_sigs,
// Get hash of the transaction batch and checkpoint
keccak256(
abi.encode(
state_gravityId,
// bytes32 encoding of "transactionBatch"
0x7472616e73616374696f6e426174636800000000000000000000000000000000,
_amounts,
_destinations,
_fees,
_batchNonce,
_tokenContract,
_batchTimeout
)
),
constant_powerThreshold
);
// ACTIONS
// Store batch nonce
state_lastBatchNonces[_tokenContract] = _batchNonce;
{
// Send transaction amounts to destinations
uint256 totalFee;
for (uint256 i = 0; i < _amounts.length; i++) {
IERC20(_tokenContract).safeTransfer(_destinations[i], _amounts[i]);
totalFee = totalFee + _fees[i];
}
// Send transaction fees to msg.sender
IERC20(_tokenContract).safeTransfer(msg.sender, totalFee);
}
}
// LOGS scoped to reduce stack depth
{
state_lastEventNonce = state_lastEventNonce + 1;
emit TransactionBatchExecutedEvent(_batchNonce, _tokenContract, state_lastEventNonce);
}
}
// This makes calls to contracts that execute arbitrary logic
// First, it gives the logic contract some tokens
// Then, it gives msg.senders tokens for fees
// Then, it calls an arbitrary function on the logic contract
// invalidationId and invalidationNonce are used for replay prevention.
// They can be used to implement a per-token nonce by setting the token
// address as the invalidationId and incrementing the nonce each call.
// They can be used for nonce-free replay prevention by using a different invalidationId
// for each call.
function submitLogicCall(
// The validators that approve the call
ValsetArgs calldata _currentValset,
// These are arrays of the parts of the validators signatures
Signature[] calldata _sigs,
LogicCallArgs memory _args
) external nonReentrant {
// CHECKS scoped to reduce stack depth
{
// Check that the call has not timed out
if (block.number >= _args.timeOut) {
revert LogicCallTimedOut();
}
// Check that the invalidation nonce is higher than the last nonce for this invalidation Id
if (state_invalidationMapping[_args.invalidationId] >= _args.invalidationNonce) {
revert InvalidLogicCallNonce({
newNonce: _args.invalidationNonce,
currentNonce: state_invalidationMapping[_args.invalidationId]
});
}
// note the lack of nonce skipping check, it's not needed here since an attacker
// will never be able to fill the invalidationId space, therefore a nonce lockout
// is simply not possible
// Check that current validators, powers, and signatures (v,r,s) set is well-formed
validateValset(_currentValset, _sigs);
// Check that the supplied current validator set matches the saved checkpoint
if (makeCheckpoint(_currentValset, state_gravityId) != state_lastValsetCheckpoint) {
revert IncorrectCheckpoint();
}
if (_args.transferAmounts.length != _args.transferTokenContracts.length) {
revert InvalidLogicCallTransfers();
}
if (_args.feeAmounts.length != _args.feeTokenContracts.length) {
revert InvalidLogicCallFees();
}
}
{
bytes32 argsHash = keccak256(
abi.encode(
state_gravityId,
// bytes32 encoding of "logicCall"
0x6c6f67696343616c6c0000000000000000000000000000000000000000000000,
_args.transferAmounts,
_args.transferTokenContracts,
_args.feeAmounts,
_args.feeTokenContracts,
_args.logicContractAddress,
_args.payload,
_args.timeOut,
_args.invalidationId,
_args.invalidationNonce
)
);
// Check that enough current validators have signed off on the transaction batch and valset
checkValidatorSignatures(
_currentValset,
_sigs,
// Get hash of the transaction batch and checkpoint
argsHash,
constant_powerThreshold
);
}
// ACTIONS
// Update invaldiation nonce
state_invalidationMapping[_args.invalidationId] = _args.invalidationNonce;
// Send tokens to the logic contract
for (uint256 i = 0; i < _args.transferAmounts.length; i++) {
IERC20(_args.transferTokenContracts[i]).safeTransfer(
_args.logicContractAddress,
_args.transferAmounts[i]
);
}
// Make call to logic contract
bytes memory returnData = Address.functionCall(_args.logicContractAddress, _args.payload);
// Send fees to msg.sender
for (uint256 i = 0; i < _args.feeAmounts.length; i++) {
IERC20(_args.feeTokenContracts[i]).safeTransfer(msg.sender, _args.feeAmounts[i]);
}
// LOGS scoped to reduce stack depth
{
state_lastEventNonce = state_lastEventNonce + 1;
emit LogicCallEvent(
_args.invalidationId,
_args.invalidationNonce,
returnData,
state_lastEventNonce
);
}
}
function sendToCosmos(
address _tokenContract,
string calldata _destination,
uint256 _amount
) external nonReentrant {
// we snapshot our current balance of this token
uint256 ourStartingBalance = IERC20(_tokenContract).balanceOf(address(this));
// attempt to transfer the user specified amount
IERC20(_tokenContract).safeTransferFrom(msg.sender, address(this), _amount);
// check what this particular ERC20 implementation actually gave us, since it doesn't
// have to be at all related to the _amount
uint256 ourEndingBalance = IERC20(_tokenContract).balanceOf(address(this));
// a very strange ERC20 may trigger this condition, if we didn't have this we would
// underflow, so it's mostly just an error message printer
if (ourEndingBalance <= ourStartingBalance) {
revert InvalidSendToCosmos();
}
state_lastEventNonce = state_lastEventNonce + 1;
// emit to Cosmos the actual amount our balance has changed, rather than the user
// provided amount. This protects against a small set of wonky ERC20 behavior, like
// burning on send but not tokens that for example change every users balance every day.
emit SendToCosmosEvent(
_tokenContract,
msg.sender,
_destination,
ourEndingBalance - ourStartingBalance,
state_lastEventNonce
);
}
function deployERC20(
string calldata _cosmosDenom,
string calldata _name,
string calldata _symbol,
uint8 _decimals
) external {
// Deploy an ERC20 with entire supply granted to Gravity.sol
CosmosERC20 erc20 = new CosmosERC20(address(this), _name, _symbol, _decimals);
// Fire an event to let the Cosmos module know
state_lastEventNonce = state_lastEventNonce + 1;
emit ERC20DeployedEvent(
_cosmosDenom,
address(erc20),
_name,
_symbol,
_decimals,
state_lastEventNonce
);
}
constructor(
// A unique identifier for this gravity instance to use in signatures
bytes32 _gravityId,
// The validator set, not in valset args format since many of it's
// arguments would never be used in this case
address[] memory _validators,
uint256[] memory _powers
) {
// CHECKS
// Check that validators, powers, and signatures (v,r,s) set is well-formed
if (_validators.length != _powers.length || _validators.length == 0) {
revert MalformedCurrentValidatorSet();
}
// Check cumulative power to ensure the contract has sufficient power to actually
// pass a vote
uint256 cumulativePower = 0;
for (uint256 i = 0; i < _powers.length; i++) {
cumulativePower = cumulativePower + _powers[i];
if (cumulativePower > constant_powerThreshold) {
break;
}
}
if (cumulativePower <= constant_powerThreshold) {
revert InsufficientPower({
cumulativePower: cumulativePower,
powerThreshold: constant_powerThreshold
});
}
ValsetArgs memory _valset;
_valset = ValsetArgs(_validators, _powers, 0, 0, address(0));
bytes32 newCheckpoint = makeCheckpoint(_valset, _gravityId);
// ACTIONS
state_gravityId = _gravityId;
state_lastValsetCheckpoint = newCheckpoint;
// LOGS
emit ValsetUpdatedEvent(
state_lastValsetNonce,
state_lastEventNonce,
0,
address(0),
_validators,
_powers
);
}
}
@@ -1,55 +0,0 @@
//SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
/**
* This is a slightly modified version of the cosmos erc20 contract
* which I have done for unit testing.
*
* All that has been changed is the MAX_UINT variable to allow
* me to mint some tokens more easily in unit tests, and the
* addition of the public mint() function.
*/
contract TestCosmosERC20 is ERC20 {
/* canonical amount */
// uint256 MAX_UINT = 2**256 - 1;
/* unit testing amount */
uint256 HALF_MAX_UINT = 2**256 / 2;
uint8 private cosmosDecimals;
address private gravityAddress;
// This override ensures we return the proper number of decimals
// for the cosmos token
function decimals() public view virtual override returns (uint8) {
return cosmosDecimals;
}
// This is not an accurate total supply. Instead this is the total supply
// of the given cosmos asset on Ethereum at this moment in time. Keeping
// a totally accurate supply would require constant updates from the Cosmos
// side, while in theory this could be piggy-backed on some existing bridge
// operation it's a lot of complextiy to add so we chose to forgoe it.
function totalSupply() public view virtual override returns (uint256) {
return HALF_MAX_UINT - balanceOf(gravityAddress);
}
constructor(
address _gravityAddress,
string memory _name,
string memory _symbol,
uint8 _decimals
) ERC20(_name, _symbol) {
cosmosDecimals = _decimals;
gravityAddress = _gravityAddress;
_mint(_gravityAddress, HALF_MAX_UINT);
}
// Additional function for our (nym repo) unit tests with bridge
function mintForUnitTesting(address _to, uint _amount) public {
_mint(_to, _amount);
}
}
@@ -1,671 +0,0 @@
//SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "./TestCosmosToken.sol";
/**
* This is a slightly modified version of the gravity bridge contract
* which I have done for unit testing.
*
* All that has been changed is ___
*/
error InvalidSignature();
error InvalidValsetNonce(uint256 newNonce, uint256 currentNonce);
error InvalidBatchNonce(uint256 newNonce, uint256 currentNonce);
error InvalidLogicCallNonce(uint256 newNonce, uint256 currentNonce);
error InvalidLogicCallTransfers();
error InvalidLogicCallFees();
error InvalidSendToCosmos();
error IncorrectCheckpoint();
error MalformedNewValidatorSet();
error MalformedCurrentValidatorSet();
error MalformedBatch();
error InsufficientPower(uint256 cumulativePower, uint256 powerThreshold);
error BatchTimedOut();
error LogicCallTimedOut();
// This is being used purely to avoid stack too deep errors
struct LogicCallArgs {
// Transfers out to the logic contract
uint256[] transferAmounts;
address[] transferTokenContracts;
// The fees (transferred to msg.sender)
uint256[] feeAmounts;
address[] feeTokenContracts;
// The arbitrary logic call
address logicContractAddress;
bytes payload;
// Invalidation metadata
uint256 timeOut;
bytes32 invalidationId;
uint256 invalidationNonce;
}
// This is used purely to avoid stack too deep errors
// represents everything about a given validator set
struct ValsetArgs {
// the validators in this set, represented by an Ethereum address
address[] validators;
// the powers of the given validators in the same order as above
uint256[] powers;
// the nonce of this validator set
uint256 valsetNonce;
// the reward amount denominated in the below reward token, can be
// set to zero
uint256 rewardAmount;
// the reward token, should be set to the zero address if not being used
address rewardToken;
}
// This represents a validator signature
struct Signature {
uint8 v;
bytes32 r;
bytes32 s;
}
contract TestGravity is ReentrancyGuard {
using SafeERC20 for IERC20;
// The number of 'votes' required to execute a valset
// update or batch execution, set to 2/3 of 2^32
uint256 constant constant_powerThreshold = 2863311530;
// These are updated often
bytes32 public state_lastValsetCheckpoint;
mapping(address => uint256) public state_lastBatchNonces;
mapping(bytes32 => uint256) public state_invalidationMapping;
uint256 public state_lastValsetNonce = 0;
// event nonce zero is reserved by the Cosmos module as a special
// value indicating that no events have yet been submitted
uint256 public state_lastEventNonce = 1;
// This is set once at initialization
bytes32 public immutable state_gravityId;
// TransactionBatchExecutedEvent and SendToCosmosEvent both include the field _eventNonce.
// This is incremented every time one of these events is emitted. It is checked by the
// Cosmos module to ensure that all events are received in order, and that none are lost.
//
// ValsetUpdatedEvent does not include the field _eventNonce because it is never submitted to the Cosmos
// module. It is purely for the use of relayers to allow them to successfully submit batches.
event TransactionBatchExecutedEvent(
uint256 indexed _batchNonce,
address indexed _token,
uint256 _eventNonce
);
event SendToCosmosEvent(
address indexed _tokenContract,
address indexed _sender,
string _destination,
uint256 _amount,
uint256 _eventNonce
);
event ERC20DeployedEvent(
// FYI: Can't index on a string without doing a bunch of weird stuff
string _cosmosDenom,
address indexed _tokenContract,
string _name,
string _symbol,
uint8 _decimals,
uint256 _eventNonce
);
event ValsetUpdatedEvent(
uint256 indexed _newValsetNonce,
uint256 _eventNonce,
uint256 _rewardAmount,
address _rewardToken,
address[] _validators,
uint256[] _powers
);
event LogicCallEvent(
bytes32 _invalidationId,
uint256 _invalidationNonce,
bytes _returnData,
uint256 _eventNonce
);
// TEST FIXTURES
// These are here to make it easier to measure gas usage. They should be removed before production
function testMakeCheckpoint(ValsetArgs calldata _valsetArgs, bytes32 _gravityId) external pure {
makeCheckpoint(_valsetArgs, _gravityId);
}
function testCheckValidatorSignatures(
ValsetArgs calldata _currentValset,
Signature[] calldata _sigs,
bytes32 _theHash,
uint256 _powerThreshold
) external pure {
checkValidatorSignatures(_currentValset, _sigs, _theHash, _powerThreshold);
}
// END TEST FIXTURES
function lastBatchNonce(address _erc20Address) external view returns (uint256) {
return state_lastBatchNonces[_erc20Address];
}
function lastLogicCallNonce(bytes32 _invalidation_id) external view returns (uint256) {
return state_invalidationMapping[_invalidation_id];
}
// Utility function to verify geth style signatures
function verifySig(
address _signer,
bytes32 _theHash,
Signature calldata _sig
) private pure returns (bool) {
bytes32 messageDigest = keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", _theHash)
);
return _signer == ECDSA.recover(messageDigest, _sig.v, _sig.r, _sig.s);
}
// Utility function to determine that a validator set and signatures are well formed
function validateValset(ValsetArgs calldata _valset, Signature[] calldata _sigs) private pure {
// Check that current validators, powers, and signatures (v,r,s) set is well-formed
if (
_valset.validators.length != _valset.powers.length ||
_valset.validators.length != _sigs.length
) {
revert MalformedCurrentValidatorSet();
}
}
// Make a new checkpoint from the supplied validator set
// A checkpoint is a hash of all relevant information about the valset. This is stored by the contract,
// instead of storing the information directly. This saves on storage and gas.
// The format of the checkpoint is:
// h(gravityId, "checkpoint", valsetNonce, validators[], powers[])
// Where h is the keccak256 hash function.
// The validator powers must be decreasing or equal. This is important for checking the signatures on the
// next valset, since it allows the caller to stop verifying signatures once a quorum of signatures have been verified.
function makeCheckpoint(ValsetArgs memory _valsetArgs, bytes32 _gravityId)
private
pure
returns (bytes32)
{
// bytes32 encoding of the string "checkpoint"
bytes32 methodName = 0x636865636b706f696e7400000000000000000000000000000000000000000000;
bytes32 checkpoint = keccak256(
abi.encode(
_gravityId,
methodName,
_valsetArgs.valsetNonce,
_valsetArgs.validators,
_valsetArgs.powers,
_valsetArgs.rewardAmount,
_valsetArgs.rewardToken
)
);
return checkpoint;
}
function checkValidatorSignatures(
// The current validator set and their powers
ValsetArgs calldata _currentValset,
// The current validator's signatures
Signature[] calldata _sigs,
// This is what we are checking they have signed
bytes32 _theHash,
uint256 _powerThreshold
) private pure {
uint256 cumulativePower = 0;
for (uint256 i = 0; i < _currentValset.validators.length; i++) {
// If v is set to 0, this signifies that it was not possible to get a signature from this validator and we skip evaluation
// (In a valid signature, it is either 27 or 28)
if (_sigs[i].v != 0) {
// Check that the current validator has signed off on the hash
if (!verifySig(_currentValset.validators[i], _theHash, _sigs[i])) {
revert InvalidSignature();
}
// Sum up cumulative power
cumulativePower = cumulativePower + _currentValset.powers[i];
// Break early to avoid wasting gas
if (cumulativePower > _powerThreshold) {
break;
}
}
}
// Check that there was enough power
if (cumulativePower <= _powerThreshold) {
revert InsufficientPower(cumulativePower, _powerThreshold);
}
// Success
}
// This updates the valset by checking that the validators in the current valset have signed off on the
// new valset. The signatures supplied are the signatures of the current valset over the checkpoint hash
// generated from the new valset.
// Anyone can call this function, but they must supply valid signatures of constant_powerThreshold of the current valset over
// the new valset.
function updateValset(
// The new version of the validator set
ValsetArgs calldata _newValset,
// The current validators that approve the change
ValsetArgs calldata _currentValset,
// These are arrays of the parts of the current validator's signatures
Signature[] calldata _sigs
) external {
// CHECKS
// Check that the valset nonce is greater than the old one
if (_newValset.valsetNonce <= _currentValset.valsetNonce) {
revert InvalidValsetNonce({
newNonce: _newValset.valsetNonce,
currentNonce: _currentValset.valsetNonce
});
}
// Check that the valset nonce is less than a million nonces forward from the old one
// this makes it difficult for an attacker to lock out the contract by getting a single
// bad validator set through with uint256 max nonce
if (_newValset.valsetNonce > _currentValset.valsetNonce + 1000000) {
revert InvalidValsetNonce({
newNonce: _newValset.valsetNonce,
currentNonce: _currentValset.valsetNonce
});
}
// Check that new validators and powers set is well-formed
if (
_newValset.validators.length != _newValset.powers.length ||
_newValset.validators.length == 0
) {
revert MalformedNewValidatorSet();
}
// Check that current validators, powers, and signatures (v,r,s) set is well-formed
validateValset(_currentValset, _sigs);
// Check cumulative power to ensure the contract has sufficient power to actually
// pass a vote
uint256 cumulativePower = 0;
for (uint256 i = 0; i < _newValset.powers.length; i++) {
cumulativePower = cumulativePower + _newValset.powers[i];
if (cumulativePower > constant_powerThreshold) {
break;
}
}
if (cumulativePower <= constant_powerThreshold) {
revert InsufficientPower({
cumulativePower: cumulativePower,
powerThreshold: constant_powerThreshold
});
}
// Check that the supplied current validator set matches the saved checkpoint
if (makeCheckpoint(_currentValset, state_gravityId) != state_lastValsetCheckpoint) {
revert IncorrectCheckpoint();
}
// Check that enough current validators have signed off on the new validator set
bytes32 newCheckpoint = makeCheckpoint(_newValset, state_gravityId);
checkValidatorSignatures(_currentValset, _sigs, newCheckpoint, constant_powerThreshold);
// ACTIONS
// Stored to be used next time to validate that the valset
// supplied by the caller is correct.
state_lastValsetCheckpoint = newCheckpoint;
// Store new nonce
state_lastValsetNonce = _newValset.valsetNonce;
// Send submission reward to msg.sender if reward token is a valid value
if (_newValset.rewardToken != address(0) && _newValset.rewardAmount != 0) {
IERC20(_newValset.rewardToken).safeTransfer(msg.sender, _newValset.rewardAmount);
}
// LOGS
state_lastEventNonce = state_lastEventNonce + 1;
emit ValsetUpdatedEvent(
_newValset.valsetNonce,
state_lastEventNonce,
_newValset.rewardAmount,
_newValset.rewardToken,
_newValset.validators,
_newValset.powers
);
}
// submitBatch processes a batch of Cosmos -> Ethereum transactions by sending the tokens in the transactions
// to the destination addresses. It is approved by the current Cosmos validator set.
// Anyone can call this function, but they must supply valid signatures of constant_powerThreshold of the current valset over
// the batch.
function submitBatch(
// The validators that approve the batch
ValsetArgs calldata _currentValset,
// These are arrays of the parts of the validators signatures
Signature[] calldata _sigs,
// The batch of transactions
uint256[] calldata _amounts,
address[] calldata _destinations,
uint256[] calldata _fees,
uint256 _batchNonce,
address _tokenContract,
// a block height beyond which this batch is not valid
// used to provide a fee-free timeout
uint256 _batchTimeout
) external nonReentrant {
// CHECKS scoped to reduce stack depth
{
// Check that the batch nonce is higher than the last nonce for this token
if (_batchNonce <= state_lastBatchNonces[_tokenContract]) {
revert InvalidBatchNonce({
newNonce: _batchNonce,
currentNonce: state_lastBatchNonces[_tokenContract]
});
}
// Check that the batch nonce is less than one million nonces forward from the old one
// this makes it difficult for an attacker to lock out the contract by getting a single
// bad batch through with uint256 max nonce
if (_batchNonce > state_lastBatchNonces[_tokenContract] + 1000000) {
revert InvalidBatchNonce({
newNonce: _batchNonce,
currentNonce: state_lastBatchNonces[_tokenContract]
});
}
// Check that the block height is less than the timeout height
if (block.number >= _batchTimeout) {
revert BatchTimedOut();
}
// Check that current validators, powers, and signatures (v,r,s) set is well-formed
validateValset(_currentValset, _sigs);
// Check that the supplied current validator set matches the saved checkpoint
if (makeCheckpoint(_currentValset, state_gravityId) != state_lastValsetCheckpoint) {
revert IncorrectCheckpoint();
}
// Check that the transaction batch is well-formed
if (_amounts.length != _destinations.length || _amounts.length != _fees.length) {
revert MalformedBatch();
}
// Check that enough current validators have signed off on the transaction batch and valset
checkValidatorSignatures(
_currentValset,
_sigs,
// Get hash of the transaction batch and checkpoint
keccak256(
abi.encode(
state_gravityId,
// bytes32 encoding of "transactionBatch"
0x7472616e73616374696f6e426174636800000000000000000000000000000000,
_amounts,
_destinations,
_fees,
_batchNonce,
_tokenContract,
_batchTimeout
)
),
constant_powerThreshold
);
// ACTIONS
// Store batch nonce
state_lastBatchNonces[_tokenContract] = _batchNonce;
{
// Send transaction amounts to destinations
uint256 totalFee;
for (uint256 i = 0; i < _amounts.length; i++) {
IERC20(_tokenContract).safeTransfer(_destinations[i], _amounts[i]);
totalFee = totalFee + _fees[i];
}
// Send transaction fees to msg.sender
IERC20(_tokenContract).safeTransfer(msg.sender, totalFee);
}
}
// LOGS scoped to reduce stack depth
{
state_lastEventNonce = state_lastEventNonce + 1;
emit TransactionBatchExecutedEvent(_batchNonce, _tokenContract, state_lastEventNonce);
}
}
// This makes calls to contracts that execute arbitrary logic
// First, it gives the logic contract some tokens
// Then, it gives msg.senders tokens for fees
// Then, it calls an arbitrary function on the logic contract
// invalidationId and invalidationNonce are used for replay prevention.
// They can be used to implement a per-token nonce by setting the token
// address as the invalidationId and incrementing the nonce each call.
// They can be used for nonce-free replay prevention by using a different invalidationId
// for each call.
function submitLogicCall(
// The validators that approve the call
ValsetArgs calldata _currentValset,
// These are arrays of the parts of the validators signatures
Signature[] calldata _sigs,
LogicCallArgs memory _args
) external nonReentrant {
// CHECKS scoped to reduce stack depth
{
// Check that the call has not timed out
if (block.number >= _args.timeOut) {
revert LogicCallTimedOut();
}
// Check that the invalidation nonce is higher than the last nonce for this invalidation Id
if (state_invalidationMapping[_args.invalidationId] >= _args.invalidationNonce) {
revert InvalidLogicCallNonce({
newNonce: _args.invalidationNonce,
currentNonce: state_invalidationMapping[_args.invalidationId]
});
}
// note the lack of nonce skipping check, it's not needed here since an attacker
// will never be able to fill the invalidationId space, therefore a nonce lockout
// is simply not possible
// Check that current validators, powers, and signatures (v,r,s) set is well-formed
validateValset(_currentValset, _sigs);
// Check that the supplied current validator set matches the saved checkpoint
if (makeCheckpoint(_currentValset, state_gravityId) != state_lastValsetCheckpoint) {
revert IncorrectCheckpoint();
}
if (_args.transferAmounts.length != _args.transferTokenContracts.length) {
revert InvalidLogicCallTransfers();
}
if (_args.feeAmounts.length != _args.feeTokenContracts.length) {
revert InvalidLogicCallFees();
}
}
{
bytes32 argsHash = keccak256(
abi.encode(
state_gravityId,
// bytes32 encoding of "logicCall"
0x6c6f67696343616c6c0000000000000000000000000000000000000000000000,
_args.transferAmounts,
_args.transferTokenContracts,
_args.feeAmounts,
_args.feeTokenContracts,
_args.logicContractAddress,
_args.payload,
_args.timeOut,
_args.invalidationId,
_args.invalidationNonce
)
);
// Check that enough current validators have signed off on the transaction batch and valset
checkValidatorSignatures(
_currentValset,
_sigs,
// Get hash of the transaction batch and checkpoint
argsHash,
constant_powerThreshold
);
}
// ACTIONS
// Update invaldiation nonce
state_invalidationMapping[_args.invalidationId] = _args.invalidationNonce;
// Send tokens to the logic contract
for (uint256 i = 0; i < _args.transferAmounts.length; i++) {
IERC20(_args.transferTokenContracts[i]).safeTransfer(
_args.logicContractAddress,
_args.transferAmounts[i]
);
}
// Make call to logic contract
bytes memory returnData = Address.functionCall(_args.logicContractAddress, _args.payload);
// Send fees to msg.sender
for (uint256 i = 0; i < _args.feeAmounts.length; i++) {
IERC20(_args.feeTokenContracts[i]).safeTransfer(msg.sender, _args.feeAmounts[i]);
}
// LOGS scoped to reduce stack depth
{
state_lastEventNonce = state_lastEventNonce + 1;
emit LogicCallEvent(
_args.invalidationId,
_args.invalidationNonce,
returnData,
state_lastEventNonce
);
}
}
function sendToCosmos(
address _tokenContract,
string calldata _destination,
uint256 _amount
) external nonReentrant {
// we snapshot our current balance of this token
uint256 ourStartingBalance = IERC20(_tokenContract).balanceOf(address(this));
// attempt to transfer the user specified amount
IERC20(_tokenContract).safeTransferFrom(msg.sender, address(this), _amount);
// check what this particular ERC20 implementation actually gave us, since it doesn't
// have to be at all related to the _amount
uint256 ourEndingBalance = IERC20(_tokenContract).balanceOf(address(this));
// a very strange ERC20 may trigger this condition, if we didn't have this we would
// underflow, so it's mostly just an error message printer
if (ourEndingBalance <= ourStartingBalance) {
revert InvalidSendToCosmos();
}
state_lastEventNonce = state_lastEventNonce + 1;
// emit to Cosmos the actual amount our balance has changed, rather than the user
// provided amount. This protects against a small set of wonky ERC20 behavior, like
// burning on send but not tokens that for example change every users balance every day.
emit SendToCosmosEvent(
_tokenContract,
msg.sender,
_destination,
ourEndingBalance - ourStartingBalance,
state_lastEventNonce
);
}
function deployERC20(
string calldata _cosmosDenom,
string calldata _name,
string calldata _symbol,
uint8 _decimals
) external {
// NOTE this is an edit made for the nym codebase unit tests - in the canonical bridge it is the entire token supply
// Deploy an ERC20 with half of entire supply granted to Gravity.sol
TestCosmosERC20 erc20 = new TestCosmosERC20(address(this), _name, _symbol, _decimals);
// Fire an event to let the Cosmos module know
state_lastEventNonce = state_lastEventNonce + 1;
emit ERC20DeployedEvent(
_cosmosDenom,
address(erc20),
_name,
_symbol,
_decimals,
state_lastEventNonce
);
}
constructor(
// A unique identifier for this gravity instance to use in signatures
bytes32 _gravityId,
// The validator set, not in valset args format since many of it's
// arguments would never be used in this case
address[] memory _validators,
uint256[] memory _powers
) {
// CHECKS
// Check that validators, powers, and signatures (v,r,s) set is well-formed
if (_validators.length != _powers.length || _validators.length == 0) {
revert MalformedCurrentValidatorSet();
}
// Check cumulative power to ensure the contract has sufficient power to actually
// pass a vote
uint256 cumulativePower = 0;
for (uint256 i = 0; i < _powers.length; i++) {
cumulativePower = cumulativePower + _powers[i];
if (cumulativePower > constant_powerThreshold) {
break;
}
}
if (cumulativePower <= constant_powerThreshold) {
revert InsufficientPower({
cumulativePower: cumulativePower,
powerThreshold: constant_powerThreshold
});
}
ValsetArgs memory _valset;
_valset = ValsetArgs(_validators, _powers, 0, 0, address(0));
bytes32 newCheckpoint = makeCheckpoint(_valset, _gravityId);
// ACTIONS
state_gravityId = _gravityId;
state_lastValsetCheckpoint = newCheckpoint;
// LOGS
emit ValsetUpdatedEvent(
state_lastValsetNonce,
state_lastEventNonce,
0,
address(0),
_validators,
_powers
);
}
}
@@ -1,43 +0,0 @@
require("@nomiclabs/hardhat-etherscan");
require("@nomiclabs/hardhat-truffle5");
require("@nomiclabs/hardhat-web3");
require("@nomiclabs/hardhat-ethers");
require('dotenv').config({ path: require('find-config')('.env') });
/**
* @type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
solidity: {
version: "0.8.10",
settings: {
optimizer: {
enabled: true
}
} },
// paths: {
// artifacts: "./artifacts/contracts"
// },
networks: {
localhost: {
url: "http://127.0.0.1:8545"
},
rinkeby: {
url: process.env.RINKEBY_URL, //Infura url with projectId
accounts: [process.env.PRIV_KEY], // private key of account used for contract interaction
gas: "auto",
gasPrice: "auto"
},
mainnet: {
url: process.env.MAINNET_URL, //Infura url with projectId
accounts: [process.env.PRIV_KEY], // private key of account used for contract interaction
gas: "auto",
gasPrice: "auto"
}
},
etherscan: {
// Your API key for Etherscan
// Obtain one at https://etherscan.io/
apiKey: process.env.ETHERSCAN_API_KEY
}
};
@@ -1,34 +0,0 @@
const { ethers } = require('hardhat');
const { constants } = require('@openzeppelin/test-helpers');
const contracts = require("../../contractAddresses.json");
const fs = require('file-system');
async function main() {
const BandwidthGenerator = await ethers.getContractFactory("BandwidthGenerator");
console.log('preparing to deploy contract...')
// if this is failing, check whether the ERC20 address has been manually added to the contract addresses json file
const bandwidthGenerator = await BandwidthGenerator.deploy(
contracts.mainnet.NYM_ERC20,
contracts.mainnet.GRAVITY
);
console.log('...contract successfully deployed...');
contracts.mainnet.BANDWIDTH_GENERATOR = bandwidthGenerator.address;
// the location of the json file is relative to where you are running the script from - run from root of directory
fs.writeFileSync('./contractAddresses.json', JSON.stringify(contracts), (err) => {
if (err) throw err;
});
console.log(`...bandwidthGenerator.sol deployed at ${bandwidthGenerator.address}`);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
@@ -1,6 +0,0 @@
// arguments for verification of bandwidth generator constructed with NYMT via hardhat-etherscan plugin
// npx hardhat verify --constructor-args ./scripts/mainnet/mainnet-nymt-bandwidth-args.js --network mainnet 0xB3BF30DD53044c9050B7309031Bbf26b2cecF3be
module.exports = [
"0xE8883BAeF3869e14E4823F46662e81D4F7d2A81F",
"0xa4108aA1Ec4967F8b52220a4f7e94A8201F2D906"
];
@@ -1,8 +0,0 @@
// arguments for verification of gravity contract via hardhat-etherscan plugin
// npx hardhat verify --constructor-args ./scripts/mainnet/mainnet-token-args.js --network mainnet 0xCf6DeE9947fdDc958985E5283e63d41CBC83Ff61
module.exports = [
"0xa4108aA1Ec4967F8b52220a4f7e94A8201F2D906",
"nym",
"nym",
6
];
@@ -1,30 +0,0 @@
const { ethers } = require('hardhat');
const { constants } = require('@openzeppelin/test-helpers');
const contracts = require("../../contractAddresses.json");
const fs = require('file-system');
async function main() {
const BandwidthGenerator = await ethers.getContractFactory("BandwidthGenerator");
// if this is failing, check whether the ERC20 address has been manually added to the contract addresses json file
const bandwidthGenerator = await BandwidthGenerator.deploy(
contracts.rinkeby.NYM_ERC20,
contracts.rinkeby.GRAVITY
);
console.log("deploying...");
contracts.rinkeby.BANDWIDTH_GENERATOR = bandwidthGenerator.address;
// the location of the json file is relative to where you are running the script from - run from root of directory
fs.writeFileSync('./contractAddresses.json', JSON.stringify(contracts), (err) => {
if (err) throw err;
});
console.log(`...bandwidthGenerator.sol deployed at ${bandwidthGenerator.address}`);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
@@ -1,32 +0,0 @@
const { ethers } = require('hardhat');
const { constants } = require('@openzeppelin/test-helpers');
const contracts = require("../../contractAddresses.json");
const fs = require('file-system');
async function main() {
const [deployer] = await ethers.getSigners();
console.log(deployer.address);
console.log(constants.ZERO_BYTES32);
const Gravity = await ethers.getContractFactory("Gravity");
// deploy with args from unit tests
const gravity = await Gravity.deploy(
constants.ZERO_BYTES32,
[deployer.address],
[2863311531]
);
contracts.rinkeby.GRAVITY = gravity.address;
// the location of the json file is relative to where you are running the script from - run from root of directory
fs.writeFileSync('./contractAddresses.json', JSON.stringify(contracts), (err) => {
if (err) throw err;
});
console.log(`gravity.sol deployed at ${gravity.address}`);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
@@ -1,6 +0,0 @@
// arguments for verification of gravity contract via hardhat-etherscan plugin
module.exports = [
"0x0000000000000000000000000000000000000000000000000000000000000000",
["0xf5b1B5C9b89906219Ba29a6cb12F0528c4C25D18"],
[2863311531]
];
@@ -1,7 +0,0 @@
// arguments for verification of gravity contract via hardhat-etherscan plugin
module.exports = [
"0xe58c12f8bA4a28e87841b10BdEdf80A47F86BA9B",
"test",
"tst",
6
];
@@ -1,266 +0,0 @@
const { expect } = require("chai");
const { constants, expectRevert, expectEvent } = require('@openzeppelin/test-helpers');
const { artifacts, web3 } = require("hardhat");
const BN = require('bn.js');
const BandwidthGenerator = artifacts.require('BandwidthGenerator');
const Gravity = artifacts.require('test-contracts/TestGravity');
const CosmosToken = artifacts.require('TestCosmosERC20');
contract('BandwidthGenerator', (accounts) => {
let bandwidthGenerator;
let gravity;
let erc20token;
let owner = accounts[0];
let user = accounts[1];
let cosmosRecipient = "nymt1f06hzmwf9chqewkpv93ajk6tayzp4784m2da9x"; // random sandbox testnet address
let initialRatio = 1073741824; // 1073741824 bytes = 1GB
let newRatio;
let tokenAmount = web3.utils.toWei('100'); // this is converting 100 tokens to their representation in wei: 100000000000000000000
let halfTokenAmount = web3.utils.toWei('50');
let unevenTokenAmount = web3.utils.toWei('11.5'); // 11500000000000000000
let oneToken = web3.utils.toWei('1');
before('deploy contracts', async () => {
// deploy gravity bridge with test data
gravity = await Gravity.new(
constants.ZERO_BYTES32,
[owner],
[2863311531]
);
// deploy erc20 NYM from bridge
await gravity.deployERC20(
'cosmosNYMDenomination',
'NYMERC20',
'NYM',
6
);
// grab event args for getting token address
const logs = await gravity.getPastEvents({
fromBlock: 0,
toBlock: "latest",
});
// create contract abstraction of deployed erc20NYM with address from event args
erc20token = await CosmosToken.at(logs[0].args._tokenContract);
// deploy bandwidthGenerator contract with contract address of erc20NYM & address of gravity bridge
bandwidthGenerator = await BandwidthGenerator.new(erc20token.address, gravity.address);
});
context(">> deployment parameters are valid", () => {
it("returns the correct erc20 address", async () => {
expect((await bandwidthGenerator.erc20()).toString()).to.equal((erc20token.address).toString());
});
it("returns the correct gravity address", async () => {
expect((await bandwidthGenerator.gravityBridge()).toString()).to.equal((gravity.address).toString());
});
it("returns the correct initial BytesPerToken ratio", async () => {
expect((await bandwidthGenerator.BytesPerToken()).toString()).to.equal((initialRatio).toString());
});
it("returns the correct contract admin", async () => {
expect((await bandwidthGenerator.owner()).toString()).to.equal((owner).toString());
});
it("returns the correct default generation state: true", async () => {
expect((await bandwidthGenerator.credentialGenerationEnabled())).to.equal(true);
});
});
context(">> deployment parameters are invalid", () => {
it("cannot be deployed with invalid erc20 address (zero address)", async () => {
expectRevert(
BandwidthGenerator.new(constants.ZERO_ADDRESS, gravity.address),
"BandwidthGenerator: erc20 address cannot be null"
)
});
it("cannot be deployed with invalid gravity bridge address (zero address)", async () => {
expectRevert(
BandwidthGenerator.new(erc20token.address, constants.ZERO_ADDRESS),
"BandwidthGenerator: gravity bridge address cannot be null"
)
});
});
context(">> generateBasicBandwidthCredential()", () => {
before("mint tokens & approve", async () => {
// transfer tokens to account which will create a BBCredential
await erc20token.mintForUnitTesting(user, tokenAmount);
// approve transfer to contract
await erc20token.approve(bandwidthGenerator.address,(tokenAmount),{ from: user });
});
it("transfers tokens to bridge and emits an event with the correct values: 50 erc20NYM = 50GB of bandwidth", async () => {
let tx = await bandwidthGenerator.generateBasicBandwidthCredential(
halfTokenAmount,
15,
[0x39, 0x53, 0x0a, 0x00, 0xea, 0xe2, 0xa5, 0xaa, 0xc8, 0x14, 0x42, 0x09, 0xcc, 0xac, 0x91, 0x7a, 0xe5, 0x6b, 0xf4, 0xa9, 0x58, 0x95, 0x44, 0xcb, 0x00, 0x20, 0xf9, 0x2f, 0xee, 0x35, 0xa3, 0xba,
0x39, 0x53, 0x0a, 0x00, 0xea, 0xe2, 0xa5, 0xaa, 0xc8, 0x14, 0x42, 0x09, 0xcc, 0xac, 0x91, 0x7a, 0xe5, 0x6b, 0xf4, 0xa9, 0x58, 0x95, 0x44, 0xcb, 0x00, 0x20, 0xf9, 0x2f, 0xee, 0x35, 0xa3, 0xba],
cosmosRecipient,
{ from: user }
);
let expectedBandwidthInMB = ((halfTokenAmount/10**18)*initialRatio); // 50 * (1024*1024*1024) bytes = 51200MB = 50GB of bandwidth
await expectEvent.inTransaction(tx.tx, bandwidthGenerator, 'BBCredentialPurchased', {
Bandwidth: expectedBandwidthInMB.toString(),
VerificationKey: '15',
SignedVerificationKey: '0x39530a00eae2a5aac8144209ccac917ae56bf4a9589544cb0020f92fee35a3ba39530a00eae2a5aac8144209ccac917ae56bf4a9589544cb0020f92fee35a3ba',
CosmosRecipient: cosmosRecipient
});
await expectEvent.inTransaction(tx.tx, erc20token, 'Transfer', {
from: user,
to: bandwidthGenerator.address,
});
await expectEvent.inTransaction(tx.tx, gravity, 'SendToCosmosEvent', {
_tokenContract: erc20token.address,
_sender: bandwidthGenerator.address,
_destination: cosmosRecipient,
_amount: halfTokenAmount
});
expect((await erc20token.balanceOf(bandwidthGenerator.address)).toString()).to.equal('0');
expect((await erc20token.balanceOf(user)).toString()).to.equal(halfTokenAmount.toString());
});
/**
* This can be out by a float still with amounts such as '.1'
*/
it("it transfers for uneven token amounts", async () => {
let tx = await bandwidthGenerator.generateBasicBandwidthCredential(
unevenTokenAmount,
15,
[0x39, 0x53, 0x0a, 0x00, 0xea, 0xe2, 0xa5, 0xaa, 0xc8, 0x14, 0x42, 0x09, 0xcc, 0xac, 0x91, 0x7a, 0xe5, 0x6b, 0xf4, 0xa9, 0x58, 0x95, 0x44, 0xcb, 0x00, 0x20, 0xf9, 0x2f, 0xee, 0x35, 0xa3, 0xba,
0x39, 0x53, 0x0a, 0x00, 0xea, 0xe2, 0xa5, 0xaa, 0xc8, 0x14, 0x42, 0x09, 0xcc, 0xac, 0x91, 0x7a, 0xe5, 0x6b, 0xf4, 0xa9, 0x58, 0x95, 0x44, 0xcb, 0x00, 0x20, 0xf9, 0x2f, 0xee, 0x35, 0xa3, 0xba],
cosmosRecipient,
{ from: user }
);
let newexpectedBandwidthInMB = ((11500000000000000000*initialRatio)/10**18);
await expectEvent.inTransaction(tx.tx, bandwidthGenerator, 'BBCredentialPurchased', {
Bandwidth: newexpectedBandwidthInMB.toString(),
VerificationKey: '15',
SignedVerificationKey: '0x39530a00eae2a5aac8144209ccac917ae56bf4a9589544cb0020f92fee35a3ba39530a00eae2a5aac8144209ccac917ae56bf4a9589544cb0020f92fee35a3ba',
CosmosRecipient: cosmosRecipient
});
await expectEvent.inTransaction(tx.tx, erc20token, 'Transfer', {
from: user,
to: bandwidthGenerator.address,
});
await expectEvent.inTransaction(tx.tx, gravity, 'SendToCosmosEvent', {
_tokenContract: erc20token.address,
_sender: bandwidthGenerator.address,
_destination: cosmosRecipient,
_amount: unevenTokenAmount
});
});
it("reverts when signed verification key !=64 bytes", async () => {
await erc20token.approve(bandwidthGenerator.address,(halfTokenAmount),{ from: user });
await expectRevert(
bandwidthGenerator.generateBasicBandwidthCredential(
1,
16,
[0x0a, 0x00, 0xea, 0xe2, 0xa5, 0xaa, 0xc8, 0x14, 0x42, 0x09, 0xcc, 0xac, 0x91, 0x7a, 0xe5, 0x6b, 0xf4, 0xa9, 0x58, 0x95, 0x44, 0xcb, 0x00, 0x20, 0xf9, 0x2f, 0xee, 0x35, 0xa3, 0xba,
0x39, 0x53, 0x0a, 0x00, 0xea, 0xe2, 0xa5, 0xaa, 0xc8, 0x14, 0x42, 0x09, 0xcc, 0xac, 0x91, 0x7a, 0xe5, 0x6b, 0xf4, 0xa9, 0x58, 0x95, 0x44, 0xcb, 0x00, 0x20, 0xf9, 0x2f, 0xee, 0x35, 0xa3, 0xba],
cosmosRecipient,
{ from: user }
), "BandwidthGenerator: Signature doesn't have 64 bytes"
);
});
});
context(">> changeRatio()", () => {
it("only admin can change token to MB ratio", async () => {
newRatio = 10 * initialRatio; // 10GB of bandwidth per 1 erc20NYM
await expectRevert(
bandwidthGenerator.changeRatio(newRatio, {from: user}),
"Ownable: caller is not the owner"
);
});
it("admin can change ratio, emits 'RatioChanged' event", async () => {
let tx = await bandwidthGenerator.changeRatio(newRatio, {from: owner});
await expectEvent.inTransaction(tx.tx, bandwidthGenerator, 'RatioChanged', {
NewBytesPerToken: newRatio.toString()
});
expect((await bandwidthGenerator.BytesPerToken()).toString()).to.equal((newRatio).toString());
});
it("BBCredential represents new ratio after change: 1 erc20NYM = 10GB of bandwidth", async () => {
let tx = await bandwidthGenerator.generateBasicBandwidthCredential(
oneToken,
15,
[0x39, 0x53, 0x0a, 0x00, 0xea, 0xe2, 0xa5, 0xaa, 0xc8, 0x14, 0x42, 0x09, 0xcc, 0xac, 0x91, 0x7a, 0xe5, 0x6b, 0xf4, 0xa9, 0x58, 0x95, 0x44, 0xcb, 0x00, 0x20, 0xf9, 0x2f, 0xee, 0x35, 0xa3, 0xba,
0x39, 0x53, 0x0a, 0x00, 0xea, 0xe2, 0xa5, 0xaa, 0xc8, 0x14, 0x42, 0x09, 0xcc, 0xac, 0x91, 0x7a, 0xe5, 0x6b, 0xf4, 0xa9, 0x58, 0x95, 0x44, 0xcb, 0x00, 0x20, 0xf9, 0x2f, 0xee, 0x35, 0xa3, 0xba],
cosmosRecipient,
{ from: user }
);
let expectedBandwidthInMB = ((oneToken/10**18)*newRatio);
await expectEvent.inTransaction(tx.tx, bandwidthGenerator, 'BBCredentialPurchased', {
Bandwidth: expectedBandwidthInMB.toString(),
VerificationKey: '15',
SignedVerificationKey: '0x39530a00eae2a5aac8144209ccac917ae56bf4a9589544cb0020f92fee35a3ba39530a00eae2a5aac8144209ccac917ae56bf4a9589544cb0020f92fee35a3ba',
CosmosRecipient: cosmosRecipient
});
await expectEvent.inTransaction(tx.tx, erc20token, 'Transfer', {
from: user,
to: bandwidthGenerator.address,
});
await expectEvent.inTransaction(tx.tx, gravity, 'SendToCosmosEvent', {
_tokenContract: erc20token.address,
_sender: bandwidthGenerator.address,
_destination: cosmosRecipient,
_amount: oneToken
});
});
});
context(">>credential generation admin switch", () => {
it("only admin can switch credential generation off", async () => {
await expectRevert(
bandwidthGenerator.credentialGenerationSwitch(false, { from: user }),
"Ownable: caller is not the owner"
)
});
it("admin can switch credential generation on/off & switch generates an event", async () => {
let tx = await bandwidthGenerator.credentialGenerationSwitch(false);
expect((await bandwidthGenerator.credentialGenerationEnabled())).to.equal(false);
await expectEvent.inTransaction(tx.tx, bandwidthGenerator, 'CredentialGenerationSwitch', {
Enabled: false,
});
tx = await bandwidthGenerator.credentialGenerationSwitch(true);
expect((await bandwidthGenerator.credentialGenerationEnabled())).to.equal(true);
await expectEvent.inTransaction(tx.tx, bandwidthGenerator, 'CredentialGenerationSwitch', {
Enabled: true,
});
});
it("cannot generate credentials if switch = false", async () => {
await bandwidthGenerator.credentialGenerationSwitch(false);
await expectRevert(
bandwidthGenerator.generateBasicBandwidthCredential(
oneToken,
15,
[0x39, 0x53, 0x0a, 0x00, 0xea, 0xe2, 0xa5, 0xaa, 0xc8, 0x14, 0x42, 0x09, 0xcc, 0xac, 0x91, 0x7a, 0xe5, 0x6b, 0xf4, 0xa9, 0x58, 0x95, 0x44, 0xcb, 0x00, 0x20, 0xf9, 0x2f, 0xee, 0x35, 0xa3, 0xba,
0x39, 0x53, 0x0a, 0x00, 0xea, 0xe2, 0xa5, 0xaa, 0xc8, 0x14, 0x42, 0x09, 0xcc, 0xac, 0x91, 0x7a, 0xe5, 0x6b, 0xf4, 0xa9, 0x58, 0x95, 0x44, 0xcb, 0x00, 0x20, 0xf9, 0x2f, 0xee, 0x35, 0xa3, 0xba],
cosmosRecipient,
{ from: user }
), "BandwidthGenerator: credential generation isn't currently enabled"
);
});
});
});
+42 -16
View File
@@ -4,7 +4,10 @@
[package]
name = "nym-gateway"
version = "1.0.2"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>",
]
description = "Implementation of the Nym Mixnet Gateway"
edition = "2021"
rust-version = "1.56"
@@ -28,24 +31,31 @@ once_cell = "1.7.2"
pretty_env_logger = "0.4"
rand = "0.7"
serde = { version = "1.0.104", features = ["derive"] }
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
subtle-encoding = { version = "0.5", features = ["bech32-preview"]}
sqlx = { version = "0.5", features = [
"runtime-tokio-rustls",
"sqlite",
"macros",
"migrate",
] }
subtle-encoding = { version = "0.5", features = ["bech32-preview"] }
thiserror = "1"
tokio = { version = "1.19.1", features = [ "rt-multi-thread", "net", "signal", "fs" ] }
tokio-stream = { version = "0.1.9", features = [ "fs" ] }
tokio = { version = "1.19.1", features = [
"rt-multi-thread",
"net",
"signal",
"fs",
] }
tokio-stream = { version = "0.1.9", features = ["fs"] }
tokio-tungstenite = "0.14"
tokio-util = { version = "0.7.3", features = [ "codec" ] }
url = { version = "2.2", features = [ "serde" ] }
web3 = "0.17.0"
tokio-util = { version = "0.7.3", features = ["codec"] }
url = { version = "2.2", features = ["serde"] }
# internal
coconut-interface = { path = "../common/coconut-interface" , optional = true}
coconut-interface = { path = "../common/coconut-interface", optional = true }
credentials = { path = "../common/credentials" }
config = { path = "../common/config" }
crypto = { path = "../common/crypto" }
bandwidth-claim-contract = { path = "../common/bandwidth-claim-contract" }
gateway-requests = { path = "gateway-requests" }
gateway-client = { path = "../common/client-libs/gateway-client" }
mixnet-client = { path = "../common/client-libs/mixnet-client" }
mixnode-common = { path = "../common/mixnode-common" }
network-defaults = { path = "../common/network-defaults" }
@@ -53,14 +63,30 @@ nymsphinx = { path = "../common/nymsphinx" }
pemstore = { path = "../common/pemstore" }
statistics-common = { path = "../common/statistics" }
validator-api-requests = { path = "../validator-api/validator-api-requests" }
validator-client = { path = "../common/client-libs/validator-client", features = ["nymd-client"] }
validator-client = { path = "../common/client-libs/validator-client", features = [
"nymd-client",
] }
version-checker = { path = "../common/version-checker" }
[features]
coconut = ["coconut-interface", "gateway-requests/coconut", "gateway-client/coconut", "credentials/coconut", "validator-api-requests/coconut"]
eth = []
coconut = [
"coconut-interface",
"gateway-requests/coconut",
"credentials/coconut",
"validator-api-requests/coconut",
]
[build-dependencies]
tokio = { version = "1.19.1", features = ["rt-multi-thread", "macros"] }
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] }
sqlx = { version = "0.5", features = [
"runtime-tokio-rustls",
"sqlite",
"macros",
"migrate",
] }
vergen = { version = "5", default-features = false, features = [
"build",
"git",
"rustc",
"cargo",
] }
+1 -1
View File
@@ -7,7 +7,7 @@ async fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let database_path = format!("{}/gateway-example.sqlite", out_dir);
let mut conn = SqliteConnection::connect(&*format!("sqlite://{}?mode=rwc", database_path))
let mut conn = SqliteConnection::connect(&format!("sqlite://{}?mode=rwc", database_path))
.await
.expect("Failed to create SQLx database connection");
+3 -13
View File
@@ -52,15 +52,10 @@ pub struct Init {
mnemonic: Option<String>,
/// Set this gateway to work in a enabled credentials mode that would disallow clients to bypass bandwidth credential requirement
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
#[clap(long)]
enabled_credentials_mode: Option<bool>,
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(long)]
eth_endpoint: String,
/// Enable/disable gateway anonymized statistics that get sent to a statistics aggregator server
#[clap(long)]
enabled_statistics: Option<bool>,
@@ -83,12 +78,9 @@ impl From<Init> for OverrideConfig {
validators: init_config.validators,
mnemonic: init_config.mnemonic,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
enabled_credentials_mode: init_config.enabled_credentials_mode,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_endpoint: Some(init_config.eth_endpoint),
enabled_statistics: init_config.enabled_statistics,
statistics_service_url: init_config.statistics_service_url,
}
@@ -177,10 +169,8 @@ mod tests {
mnemonic: None,
statistics_service_url: None,
enabled_statistics: None,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
enabled_credentials_mode: None,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_endpoint: "".to_string(),
};
std::env::set_var(BECH32_PREFIX, "n");
+2 -23
View File
@@ -18,8 +18,6 @@ pub(crate) mod run;
pub(crate) mod sign;
pub(crate) mod upgrade;
#[cfg(all(not(feature = "eth"), not(feature = "coconut")))]
const DEFAULT_ETH_ENDPOINT: &str = "https://rinkeby.infura.io/v3/00000000000000000000000000000000";
#[derive(Subcommand)]
pub(crate) enum Commands {
/// Initialise the gateway
@@ -52,11 +50,8 @@ pub(crate) struct OverrideConfig {
validators: Option<String>,
mnemonic: Option<String>,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
enabled_credentials_mode: Option<bool>,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_endpoint: Option<String>,
}
pub(crate) async fn execute(args: Cli) {
@@ -141,29 +136,13 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
);
}
#[cfg(all(not(feature = "eth"), not(feature = "coconut")))]
{
config = config.with_eth_endpoint(String::from(DEFAULT_ETH_ENDPOINT));
}
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
{
if let Some(enabled_credentials_mode) = args.enabled_credentials_mode {
config = config.with_disabled_credentials_mode(!enabled_credentials_mode);
}
}
#[cfg(all(feature = "eth", not(feature = "coconut")))]
{
if let Some(raw_validators) = args.validators {
config = config.with_custom_validator_nymd(parse_validators(&raw_validators));
}
if let Some(eth_endpoint) = args.eth_endpoint {
config = config.with_eth_endpoint(eth_endpoint);
}
}
config
}
+2 -10
View File
@@ -52,15 +52,10 @@ pub struct Run {
mnemonic: Option<String>,
/// Set this gateway to work in a enabled credentials mode that would disallow clients to bypass bandwidth credential requirement
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
#[clap(long)]
enabled_credentials_mode: Option<bool>,
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(long)]
eth_endpoint: Option<String>,
/// Enable/disable gateway anonymized statistics that get sent to a statistics aggregator server
#[clap(long)]
enabled_statistics: Option<bool>,
@@ -83,12 +78,9 @@ impl From<Run> for OverrideConfig {
validators: run_config.validators,
mnemonic: run_config.mnemonic,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
enabled_credentials_mode: run_config.enabled_credentials_mode,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_endpoint: run_config.eth_endpoint,
enabled_statistics: run_config.enabled_statistics,
statistics_service_url: run_config.statistics_service_url,
}
+3 -18
View File
@@ -127,7 +127,7 @@ impl Config {
self
}
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(feature = "coconut")]
pub fn with_disabled_credentials_mode(mut self, disabled_credentials_mode: bool) -> Self {
self.gateway.disabled_credentials_mode = disabled_credentials_mode;
self
@@ -158,12 +158,6 @@ impl Config {
self
}
#[cfg(not(feature = "coconut"))]
pub fn with_eth_endpoint(mut self, eth_endpoint: String) -> Self {
self.gateway.eth_endpoint = eth_endpoint;
self
}
pub fn with_listening_address<S: Into<String>>(mut self, listening_address: S) -> Self {
let listening_address_string = listening_address.into();
if let Ok(ip_addr) = listening_address_string.parse() {
@@ -237,11 +231,6 @@ impl Config {
self.gateway.public_sphinx_key_file.clone()
}
#[cfg(not(feature = "coconut"))]
pub fn get_eth_endpoint(&self) -> String {
self.gateway.eth_endpoint.clone()
}
pub fn get_enabled_statistics(&self) -> bool {
self.gateway.enabled_statistics
}
@@ -254,10 +243,12 @@ impl Config {
self.gateway.validator_api_urls.clone()
}
#[cfg(feature = "coconut")]
pub fn get_validator_nymd_endpoints(&self) -> Vec<Url> {
self.gateway.validator_nymd_urls.clone()
}
#[cfg(feature = "coconut")]
pub fn get_cosmos_mnemonic(&self) -> bip39::Mnemonic {
self.gateway.cosmos_mnemonic.clone()
}
@@ -357,10 +348,6 @@ pub struct Gateway {
/// Path to file containing public sphinx key.
public_sphinx_key_file: PathBuf,
/// Address to an Ethereum full node.
#[cfg(not(feature = "coconut"))]
eth_endpoint: String,
/// Wheather gateway collects and sends anonymized statistics
enabled_statistics: bool,
@@ -424,8 +411,6 @@ impl Default for Gateway {
public_identity_key_file: Default::default(),
private_sphinx_key_file: Default::default(),
public_sphinx_key_file: Default::default(),
#[cfg(not(feature = "coconut"))]
eth_endpoint: "".to_string(),
enabled_statistics: false,
statistics_service_url: Url::from_str("http://127.0.0.1").unwrap(),
validator_api_urls: vec![],
-3
View File
@@ -38,9 +38,6 @@ private_sphinx_key_file = '{{ gateway.private_sphinx_key_file }}'
# Path to file containing public sphinx key.
public_sphinx_key_file = '{{ gateway.public_sphinx_key_file }}'
# Addess to an Ethereum full node.
eth_endpoint = '{{ gateway.eth_endpoint }}'
##### additional gateway config options #####
# Optional address announced to the directory server for the clients to connect to.
@@ -51,18 +51,6 @@ pub(crate) enum RequestHandlingError {
#[error("Nymd Error - {0}")]
NymdError(#[from] validator_client::nymd::error::NymdError),
#[cfg(not(feature = "coconut"))]
#[error("Ethereum web3 error")]
Web3Error(#[from] web3::Error),
#[cfg(not(feature = "coconut"))]
#[error("Ethereum ABI error")]
EthAbiError(#[from] web3::ethabi::Error),
#[cfg(not(feature = "coconut"))]
#[error("Ethereum contract error")]
EthContractError(#[from] web3::contract::Error),
#[cfg(feature = "coconut")]
#[error("Validator API error - {0}")]
APIError(#[from] validator_client::ValidatorClientError),
@@ -287,18 +275,6 @@ where
String::from("gateway"),
));
}
debug!("Verifying Ethereum for token burn...");
let gateway_owner = self
.inner
.erc20_bridge
.verify_eth_events(credential.verification_key())
.await?;
self.inner
.erc20_bridge
.verify_gateway_owner(gateway_owner, &credential.gateway_identity())
.await?;
debug!("Claim the token on Cosmos, to make sure it's not spent twice...");
self.inner.erc20_bridge.claim_token(&credential).await?;
let bandwidth = Bandwidth::from(credential);
let bandwidth_value = bandwidth.value();
@@ -6,129 +6,15 @@ use bandwidth_claim_contract::msg::ExecuteMsg;
use bandwidth_claim_contract::payment::LinkPaymentData;
use credentials::token::bandwidth::TokenCredential;
use crypto::asymmetric::identity::{PublicKey, Signature, SIGNATURE_LENGTH};
use gateway_client::bandwidth::eth_contract;
use network_defaults::{ETH_EVENT_NAME, ETH_MIN_BLOCK_DEPTH};
use std::str::FromStr;
use validator_client::nymd::{AccountId, NymdClient, SigningNymdClient};
use web3::contract::tokens::Detokenize;
use web3::contract::{Contract, Error};
use web3::ethabi::Token;
use web3::transports::Http;
use web3::types::{BlockNumber, FilterBuilder, H256};
use web3::Web3;
pub(crate) struct ERC20Bridge {
// This is needed because web3's Contract doesn't sufficiently expose it's eth interface
web3: Web3<Http>,
contract: Contract<Http>,
nymd_client: NymdClient<SigningNymdClient>,
}
impl ERC20Bridge {
pub fn new(eth_endpoint: String, nymd_client: NymdClient<SigningNymdClient>) -> Self {
let transport = Http::new(&eth_endpoint).expect("Invalid Ethereum endpoint");
let web3 = Web3::new(transport);
ERC20Bridge {
contract: eth_contract(web3.clone()),
web3,
nymd_client,
}
}
pub(crate) async fn verify_eth_events(
&self,
verification_key: PublicKey,
) -> Result<String, RequestHandlingError> {
// It's safe to unwrap here, as we are guarded by a unit test that checks the event
// name constant against the contract abi
let event = self.contract.abi().event(ETH_EVENT_NAME).unwrap();
let latest_block = self.web3.eth().block_number().await?;
let check_until = if cfg!(debug_assertions) {
latest_block
} else {
latest_block - ETH_MIN_BLOCK_DEPTH
};
let filter = FilterBuilder::default()
.address(vec![self.contract.address()])
.topics(
Some(vec![event.signature()]),
Some(vec![H256::from(verification_key.to_bytes())]),
None,
None,
)
.from_block(BlockNumber::Earliest)
.to_block(BlockNumber::Number(check_until))
.build();
// Get only the first event that checks out. If the client burns more tokens with the
// same verification key, those tokens would be lost
for l in self.web3.eth().logs(filter).await? {
let log = event.parse_log(web3::ethabi::RawLog {
topics: l.topics,
data: l.data.0,
})?;
let burned_event =
Burned::from_tokens(log.params.into_iter().map(|x| x.value).collect::<Vec<_>>())?;
if burned_event.verify(verification_key) {
return Ok(burned_event.cosmos_recipient);
}
}
Err(RequestHandlingError::InvalidBandwidthCredential(
String::from("gateway"),
))
}
pub(crate) async fn verify_gateway_owner(
&self,
gateway_owner: String,
gateway_identity: &PublicKey,
) -> Result<(), RequestHandlingError> {
let owner_address = AccountId::from_str(&gateway_owner).map_err(|_| {
RequestHandlingError::InvalidBandwidthCredential(String::from("gateway"))
})?;
let gateway_bond = self
.nymd_client
.owns_gateway(&owner_address)
.await?
.ok_or_else(|| {
RequestHandlingError::InvalidBandwidthCredential(String::from("gateway"))
})?;
if gateway_bond.gateway.identity_key == gateway_identity.to_base58_string() {
Ok(())
} else {
Err(RequestHandlingError::InvalidBandwidthCredential(
String::from("gateway"),
))
}
}
pub(crate) async fn claim_token(
&self,
credential: &TokenCredential,
) -> Result<(), RequestHandlingError> {
let bandwidth_claim_contract_address = self.nymd_client.bandwidth_claim_contract_address();
let req = ExecuteMsg::LinkPayment {
data: LinkPaymentData::new(
credential.verification_key().to_bytes(),
credential.gateway_identity().to_bytes(),
credential.bandwidth(),
credential.signature_bytes(),
),
};
self.nymd_client
.execute(
bandwidth_claim_contract_address,
&req,
Default::default(),
"Linking payment",
vec![],
)
.await?;
Ok(())
}
}
#[derive(Debug)]
pub struct Burned {
/// The bandwidth bought by the client
@@ -29,9 +29,6 @@ use thiserror::Error;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_tungstenite::tungstenite::{protocol::Message, Error as WsError};
#[cfg(not(feature = "coconut"))]
use crate::node::client_handling::websocket::connection_handler::eth_events::ERC20Bridge;
#[derive(Debug, Error)]
enum InitialAuthenticationError {
#[error("Internal gateway storage error")]
@@ -76,8 +73,6 @@ pub(crate) struct FreshHandler<R, S, St> {
pub(crate) socket_connection: SocketStream<S>,
pub(crate) storage: St,
#[cfg(not(feature = "coconut"))]
pub(crate) erc20_bridge: Arc<ERC20Bridge>,
#[cfg(feature = "coconut")]
pub(crate) coconut_verifier: Arc<CoconutVerifier>,
}
@@ -101,7 +96,6 @@ where
storage: St,
active_clients_store: ActiveClientsStore,
#[cfg(feature = "coconut")] coconut_verifier: Arc<CoconutVerifier>,
#[cfg(not(feature = "coconut"))] erc20_bridge: Arc<ERC20Bridge>,
) -> Self {
FreshHandler {
rng,
@@ -113,8 +107,6 @@ where
storage,
#[cfg(feature = "coconut")]
coconut_verifier,
#[cfg(not(feature = "coconut"))]
erc20_bridge,
}
}
@@ -17,8 +17,6 @@ pub(crate) use self::fresh::FreshHandler;
mod authenticated;
#[cfg(feature = "coconut")]
pub(crate) mod coconut;
#[cfg(not(feature = "coconut"))]
pub(crate) mod eth_events;
mod fresh;
//// TODO: note for my future self to consider the following idea:
@@ -16,9 +16,6 @@ use tokio::task::JoinHandle;
#[cfg(feature = "coconut")]
use crate::node::client_handling::websocket::connection_handler::coconut::CoconutVerifier;
#[cfg(not(feature = "coconut"))]
use crate::node::client_handling::websocket::connection_handler::eth_events::ERC20Bridge;
pub(crate) struct Listener {
address: SocketAddr,
local_identity: Arc<identity::KeyPair>,
@@ -26,8 +23,6 @@ pub(crate) struct Listener {
#[cfg(feature = "coconut")]
pub(crate) coconut_verifier: Arc<CoconutVerifier>,
#[cfg(not(feature = "coconut"))]
erc20_bridge: Arc<ERC20Bridge>,
}
impl Listener {
@@ -36,7 +31,6 @@ impl Listener {
local_identity: Arc<identity::KeyPair>,
disabled_credentials_mode: bool,
#[cfg(feature = "coconut")] coconut_verifier: Arc<CoconutVerifier>,
#[cfg(not(feature = "coconut"))] erc20_bridge: ERC20Bridge,
) -> Self {
Listener {
address,
@@ -44,8 +38,6 @@ impl Listener {
disabled_credentials_mode,
#[cfg(feature = "coconut")]
coconut_verifier,
#[cfg(not(feature = "coconut"))]
erc20_bridge: Arc::new(erc20_bridge),
}
}
@@ -84,8 +76,6 @@ impl Listener {
active_clients_store.clone(),
#[cfg(feature = "coconut")]
Arc::clone(&self.coconut_verifier),
#[cfg(not(feature = "coconut"))]
Arc::clone(&self.erc20_bridge),
);
tokio::spawn(async move { handle.start_handling().await });
}
+4 -11
View File
@@ -12,6 +12,7 @@ use crate::node::storage::Storage;
use crypto::asymmetric::{encryption, identity};
use log::*;
use mixnet_client::forwarder::{MixForwardingSender, PacketForwarder};
#[cfg(feature = "coconut")]
use network_defaults::NymNetworkDetails;
use rand::seq::SliceRandom;
use rand::thread_rng;
@@ -23,10 +24,9 @@ use std::sync::Arc;
use crate::config::persistence::pathfinder::GatewayPathfinder;
#[cfg(feature = "coconut")]
use crate::node::client_handling::websocket::connection_handler::coconut::CoconutVerifier;
#[cfg(not(feature = "coconut"))]
use crate::node::client_handling::websocket::connection_handler::eth_events::ERC20Bridge;
#[cfg(feature = "coconut")]
use credentials::obtain_aggregate_verification_key;
#[cfg(feature = "coconut")]
use validator_client::nymd;
use self::storage::PersistentStorage;
@@ -181,7 +181,6 @@ where
forwarding_channel: MixForwardingSender,
active_clients_store: ActiveClientsStore,
#[cfg(feature = "coconut")] coconut_verifier: Arc<CoconutVerifier>,
#[cfg(not(feature = "coconut"))] erc20_bridge: ERC20Bridge,
) {
info!("Starting client [web]socket listener...");
@@ -196,8 +195,6 @@ where
self.config.get_disabled_credentials_mode(),
#[cfg(feature = "coconut")]
coconut_verifier,
#[cfg(not(feature = "coconut"))]
erc20_bridge,
)
.start(
forwarding_channel,
@@ -241,6 +238,7 @@ where
validator_client::ApiClient::new(validator_api.clone())
}
#[cfg(feature = "coconut")]
fn random_nymd_client(
&self,
) -> validator_client::nymd::NymdClient<validator_client::nymd::SigningNymdClient> {
@@ -311,7 +309,7 @@ where
obtain_aggregate_verification_key(&self.config.get_validator_api_endpoints())
.await
.expect("failed to contact validators to obtain their verification keys");
#[cfg(feature = "coconut")]
let nymd_client = self.random_nymd_client();
#[cfg(feature = "coconut")]
let coconut_verifier = CoconutVerifier::new(
@@ -322,9 +320,6 @@ where
)
.expect("Could not create coconut verifier");
#[cfg(not(feature = "coconut"))]
let erc20_bridge = ERC20Bridge::new(self.config.get_eth_endpoint(), nymd_client);
let mix_forwarding_channel = self.start_packet_forwarder();
let active_clients_store = ActiveClientsStore::new();
@@ -351,8 +346,6 @@ where
active_clients_store,
#[cfg(feature = "coconut")]
Arc::new(coconut_verifier),
#[cfg(not(feature = "coconut"))]
erc20_bridge,
);
info!("Finished nym gateway startup procedure - it should now be able to receive mix and client traffic!");
+1 -18
View File
@@ -732,7 +732,6 @@ version = "0.1.0"
dependencies = [
"cfg-if",
"handlebars",
"humantime-serde",
"log",
"network-defaults",
"serde",
@@ -916,7 +915,6 @@ version = "0.1.0"
dependencies = [
"async-trait",
"log",
"nymcoconut",
"sqlx",
"thiserror",
"tokio",
@@ -993,7 +991,6 @@ dependencies = [
"blake3",
"bs58",
"cipher 0.4.3",
"config",
"ctr 0.9.1",
"digest 0.10.3",
"ed25519-dalek",
@@ -1915,7 +1912,6 @@ dependencies = [
"futures",
"gateway-requests",
"getrandom 0.2.7",
"json",
"log",
"network-defaults",
"nymsphinx",
@@ -2873,12 +2869,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "json"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd"
[[package]]
name = "json-patch"
version = "0.2.6"
@@ -3209,7 +3199,6 @@ dependencies = [
"serde_repr",
"thiserror",
"time 0.3.11",
"ts-rs",
]
[[package]]
@@ -5233,7 +5222,6 @@ name = "socks5-requests"
version = "0.1.0"
dependencies = [
"nymsphinx-addressing",
"ordered-buffer",
"thiserror",
]
@@ -5637,7 +5625,6 @@ version = "0.1.0"
dependencies = [
"log",
"tokio",
"tokio-util 0.7.3",
]
[[package]]
@@ -6404,7 +6391,6 @@ dependencies = [
"mixnet-contract-common",
"schemars",
"serde",
"ts-rs",
]
[[package]]
@@ -6498,7 +6484,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vesting-contract"
version = "1.0.1"
version = "1.0.2"
dependencies = [
"cosmwasm-std",
"cw-storage-plus",
@@ -6513,13 +6499,10 @@ dependencies = [
name = "vesting-contract-common"
version = "0.1.0"
dependencies = [
"config",
"cosmwasm-std",
"cw-storage-plus",
"mixnet-contract-common",
"schemars",
"serde",
"ts-rs",
]
[[package]]
-13
View File
@@ -16,10 +16,6 @@ use crate::{
static SOCKS5_CONFIG_ID: &str = "nym-connect";
const DEFAULT_ETH_ENDPOINT: &str = "https://rinkeby.infura.io/v3/00000000000000000000000000000000";
const DEFAULT_ETH_PRIVATE_KEY: &str =
"0000000000000000000000000000000000000000000000000000000000000001";
pub fn socks5_config_id_appended_with(gateway_id: &str) -> Result<String> {
use std::fmt::Write as _;
let mut id = SOCKS5_CONFIG_ID.to_string();
@@ -125,15 +121,6 @@ pub async fn init_socks5_config(provider_address: String, chosen_gateway_id: Str
log::trace!("Creating config for id: {}", id);
let mut config = Config::new(id.as_str(), &provider_address);
// As far as I'm aware, these two are not used, they are only set because the socks5 init code
// requires them for initialising the bandwidth controller.
config
.get_base_mut()
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
config
.get_base_mut()
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
if let Ok(raw_validators) = std::env::var(config_common::defaults::var_names::API_VALIDATOR) {
config
.get_base_mut()
+2 -24
View File
@@ -769,7 +769,6 @@ version = "0.1.0"
dependencies = [
"cfg-if",
"handlebars",
"humantime-serde",
"log",
"network-defaults",
"serde",
@@ -1482,7 +1481,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
dependencies = [
"atty",
"humantime 1.3.0",
"humantime",
"log",
"regex",
"termcolor",
@@ -2316,22 +2315,6 @@ dependencies = [
"quick-error 1.2.3",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "humantime-serde"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac34a56cfd4acddb469cc7fff187ed5ac36f498ba085caf8bbc725e3ff474058"
dependencies = [
"humantime 2.1.0",
"serde",
]
[[package]]
name = "hyper"
version = "0.14.17"
@@ -2796,7 +2779,6 @@ dependencies = [
"serde_repr",
"thiserror",
"time 0.3.7",
"ts-rs",
]
[[package]]
@@ -5550,7 +5532,6 @@ dependencies = [
"mixnet-contract-common",
"schemars",
"serde",
"ts-rs",
]
[[package]]
@@ -5620,7 +5601,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vesting-contract"
version = "1.0.1"
version = "1.0.2"
dependencies = [
"cosmwasm-std",
"cw-storage-plus",
@@ -5635,13 +5616,10 @@ dependencies = [
name = "vesting-contract-common"
version = "0.1.0"
dependencies = [
"config",
"cosmwasm-std",
"cw-storage-plus",
"mixnet-contract-common",
"schemars",
"serde",
"ts-rs",
]
[[package]]
@@ -14,7 +14,6 @@ serde = { version = "1.0", features = ["derive"] }
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate", "chrono"]}
thiserror = "1"
tokio = { version = "1.4", features = [ "net", "rt-multi-thread", "macros", "time" ] }
tokio-tungstenite = "0.14"
statistics-common = { path = "../../common/statistics" }
@@ -9,7 +9,7 @@ async fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let database_path = format!("{}/network-statistics-example.sqlite", out_dir);
let mut conn = SqliteConnection::connect(&*format!("sqlite://{}?mode=rwc", database_path))
let mut conn = SqliteConnection::connect(&format!("sqlite://{}?mode=rwc", database_path))
.await
.expect("Failed to create SQLx database connection");
+4 -6
View File
@@ -45,12 +45,11 @@ tokio = { version = "1.19", features = [
tokio-stream = "0.1.9"
url = "2.2"
ts-rs = "6.1"
ts-rs = {version = "6.1", optional = true}
anyhow = "1.0"
getset = "0.1.1"
rocket_sync_db_pools = { version = "0.1.0-rc.2", default-features = false }
sqlx = { version = "0.6.1", features = [
"runtime-tokio-rustls",
"sqlite",
@@ -94,17 +93,17 @@ coconut = [
"nymcoconut",
]
no-reward = []
generate-ts = []
generate-ts = ["ts-rs"]
[build-dependencies]
tokio = { version = "1.19.1", features = ["rt-multi-thread", "macros"] }
sqlx = { version = "0.5", features = [
sqlx = { version = "0.6.2", features = [
"runtime-tokio-rustls",
"sqlite",
"macros",
"migrate",
] }
vergen = { version = "5", default-features = false, features = [
vergen = { version = "7", default-features = false, features = [
"build",
"git",
"rustc",
@@ -112,6 +111,5 @@ vergen = { version = "5", default-features = false, features = [
] }
[dev-dependencies]
attohttpc = { version = "0.18.0", features = ["json"] }
cw3 = "0.13.2"
cw-utils = "0.13.2"
+1 -1
View File
@@ -7,7 +7,7 @@ async fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let database_path = format!("{}/validator-api-example.sqlite", out_dir);
let mut conn = SqliteConnection::connect(&*format!("sqlite://{}?mode=rwc", database_path))
let mut conn = SqliteConnection::connect(&format!("sqlite://{}?mode=rwc", database_path))
.await
.expect("Failed to create SQLx database connection");
-40
View File
@@ -23,12 +23,6 @@ const DEFAULT_GATEWAY_PING_INTERVAL: Duration = Duration::from_secs(60);
const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5 * 60);
const DEFAULT_GATEWAY_CONNECTION_TIMEOUT: Duration = Duration::from_millis(2_500);
#[cfg(not(feature = "coconut"))]
const DEFAULT_ETH_ENDPOINT: &str = "https://rinkeby.infura.io/v3/00000000000000000000000000000000";
#[cfg(not(feature = "coconut"))]
const DEFAULT_ETH_PRIVATE_KEY: &str =
"0000000000000000000000000000000000000000000000000000000000000001";
const DEFAULT_TEST_ROUTES: usize = 3;
const DEFAULT_MINIMUM_TEST_ROUTES: usize = 1;
const DEFAULT_ROUTE_TEST_PACKETS: usize = 1000;
@@ -163,14 +157,6 @@ pub struct NetworkMonitor {
/// Path to the database containing bandwidth credentials of this client.
credentials_database_path: PathBuf,
/// Ethereum private key.
#[cfg(not(feature = "coconut"))]
eth_private_key: String,
/// Addess to an Ethereum full node.
#[cfg(not(feature = "coconut"))]
eth_endpoint: String,
/// Desired number of test routes to be constructed (and working) during a monitor test run.
test_routes: usize,
@@ -209,10 +195,6 @@ impl Default for NetworkMonitor {
gateway_connection_timeout: DEFAULT_GATEWAY_CONNECTION_TIMEOUT,
packet_delivery_timeout: DEFAULT_PACKET_DELIVERY_TIMEOUT,
credentials_database_path: Self::default_credentials_database_path(),
#[cfg(not(feature = "coconut"))]
eth_private_key: DEFAULT_ETH_PRIVATE_KEY.to_string(),
#[cfg(not(feature = "coconut"))]
eth_endpoint: DEFAULT_ETH_ENDPOINT.to_string(),
test_routes: DEFAULT_TEST_ROUTES,
minimum_test_routes: DEFAULT_MINIMUM_TEST_ROUTES,
route_test_packets: DEFAULT_ROUTE_TEST_PACKETS,
@@ -377,18 +359,6 @@ impl Config {
self
}
#[cfg(not(feature = "coconut"))]
pub fn with_eth_private_key(mut self, eth_private_key: String) -> Self {
self.network_monitor.eth_private_key = eth_private_key;
self
}
#[cfg(not(feature = "coconut"))]
pub fn with_eth_endpoint(mut self, eth_endpoint: String) -> Self {
self.network_monitor.eth_endpoint = eth_endpoint;
self
}
pub fn get_id(&self) -> String {
self.base.id.clone()
}
@@ -410,16 +380,6 @@ impl Config {
self.network_monitor.credentials_database_path.clone()
}
#[cfg(not(feature = "coconut"))]
pub fn get_network_monitor_eth_private_key(&self) -> String {
self.network_monitor.eth_private_key.clone()
}
#[cfg(not(feature = "coconut"))]
pub fn get_network_monitor_eth_endpoint(&self) -> String {
self.network_monitor.eth_endpoint.clone()
}
// TODO: Remove if still unused
#[allow(dead_code)]
pub fn get_rewarding_enabled(&self) -> bool {
-6
View File
@@ -57,12 +57,6 @@ packet_delivery_timeout = '{{ network_monitor.packet_delivery_timeout }}'
credentials_database_path = '{{ network_monitor.credentials_database_path }}'
# Ethereum private key.
eth_private_key = '{{ network_monitor.eth_private_key }}'
# Addess to an Ethereum full node.
eth_endpoint = '{{ network_monitor.eth_endpoint }}'
# Desired number of test routes to be constructed (and working) during a monitor test run.
test_routes = {{ network_monitor.test_routes }}
-29
View File
@@ -73,11 +73,6 @@ const KEYPAIR_ARG: &str = "keypair";
#[cfg(feature = "coconut")]
const COCONUT_ENABLED: &str = "enable-coconut";
#[cfg(not(feature = "coconut"))]
const ETH_ENDPOINT: &str = "eth_endpoint";
#[cfg(not(feature = "coconut"))]
const ETH_PRIVATE_KEY: &str = "eth_private_key";
const REWARDING_MONITOR_THRESHOLD_ARG: &str = "monitor-threshold";
const MIN_MIXNODE_RELIABILITY_ARG: &str = "min_mixnode_reliability";
@@ -199,20 +194,6 @@ fn parse_args() -> ArgMatches {
.requires_all(&[KEYPAIR_ARG, MNEMONIC_ARG, API_VALIDATORS_ARG])
.long(COCONUT_ENABLED),
);
#[cfg(not(feature = "coconut"))]
let base_app = base_app.arg(
Arg::with_name(ETH_ENDPOINT)
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
.takes_value(true)
.long(ETH_ENDPOINT),
).arg(
Arg::with_name(ETH_PRIVATE_KEY)
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
.takes_value(true)
.long(ETH_PRIVATE_KEY),
);
base_app.get_matches()
}
@@ -366,16 +347,6 @@ fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
config = config.with_keypair_path(keypair_path.into())
}
#[cfg(not(feature = "coconut"))]
if let Some(eth_private_key) = matches.value_of("eth_private_key") {
config = config.with_eth_private_key(String::from(eth_private_key));
}
#[cfg(not(feature = "coconut"))]
if let Some(eth_endpoint) = matches.value_of("eth_endpoint") {
config = config.with_eth_endpoint(String::from(eth_endpoint));
}
if matches.is_present(ENABLED_CREDENTIALS_MODE_ARG_NAME) {
config = config.with_disabled_credentials_mode(false)
}
-2
View File
@@ -83,8 +83,6 @@ impl<'a> NetworkMonitorBuilder<'a> {
let bandwidth_controller = BandwidthController::new(
credential_storage::initialise_storage(self.config.get_credentials_database_path())
.await,
self.config.get_network_monitor_eth_endpoint(),
self.config.get_network_monitor_eth_private_key(),
)
.expect("Could not create bandwidth controller");
@@ -11,7 +11,7 @@ cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegr
getset = "0.1.1"
schemars = { version = "0.8", features = ["preserve_order"] }
serde = "1.0"
ts-rs = "6.1.2"
ts-rs = {version = "6.1.2", optional = true}
coconut-interface = { path = "../../common/coconut-interface", optional = true }
mixnet-contract-common = { path= ".../../../../common/cosmwasm-smart-contracts/mixnet-contract" }
@@ -19,4 +19,4 @@ mixnet-contract-common = { path= ".../../../../common/cosmwasm-smart-contracts/m
[features]
default = []
coconut = ["coconut-interface"]
generate-ts = []
generate-ts = ["ts-rs"]