Compare commits
58 Commits
feature/nova
...
v0.12.1
| Author | SHA1 | Date | |
|---|---|---|---|
| c3d908642a | |||
| f84bac18a1 | |||
| 0cef1abbb2 | |||
| 1871c6b2e3 | |||
| 75ad2a113f | |||
| 1d1496aa49 | |||
| a48e06fe51 | |||
| 614b99a36e | |||
| d8cb6199e0 | |||
| 424c1695b3 | |||
| 3ceb6d711f | |||
| 23d2279549 | |||
| 84d1909b18 | |||
| 29a22e95e6 | |||
| 0e0f9ed270 | |||
| 4c0c0bc49f | |||
| ea350ef7dd | |||
| 112820ad7b | |||
| fe27cbe7e2 | |||
| bd892e00bd | |||
| 8d2863e085 | |||
| 89cb931775 | |||
| 0f58fb6437 | |||
| 837575c8d3 | |||
| 4cbe789f42 | |||
| 822c993f24 | |||
| 9480233ca3 | |||
| 72944905cd | |||
| effb756e2f | |||
| 583f5083e5 | |||
| 941e91d250 | |||
| 0f1b9d138e | |||
| 265696103c | |||
| 22ce25d821 | |||
| 363f784714 | |||
| 1f360a5a27 | |||
| ea3f2e9beb | |||
| 84924133b5 | |||
| 860afc9086 | |||
| 0aab508633 | |||
| bdfce8f663 | |||
| b5bb09588d | |||
| 983322d273 | |||
| e761989c6a | |||
| bc981873ff | |||
| 8e99ae8979 | |||
| ed2b515a83 | |||
| aca31dbaac | |||
| f8fb6f524e | |||
| 036369226b | |||
| 4972ad8c53 | |||
| a09581eea9 | |||
| 4d447706fc | |||
| 6c6e16035a | |||
| 96aa814a61 | |||
| 1fbf437786 | |||
| 852d12b440 | |||
| 865759254f |
@@ -0,0 +1,3 @@
|
||||
unreleased=true
|
||||
future-release=v0.12.1
|
||||
since-tag=v0.11.0
|
||||
@@ -0,0 +1 @@
|
||||
2.7.5
|
||||
+240
-868
File diff suppressed because it is too large
Load Diff
Generated
+36
-30
@@ -240,6 +240,14 @@ version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d6dff4a1892b54d70af377bf7a17064192e822865791d812957f21e3108c325"
|
||||
|
||||
[[package]]
|
||||
name = "bandwidth-claim-contract"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base-x"
|
||||
version = "0.2.8"
|
||||
@@ -612,7 +620,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "client-core"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
dependencies = [
|
||||
"config",
|
||||
"crypto",
|
||||
@@ -899,9 +907,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-crypto"
|
||||
version = "1.0.0-beta2"
|
||||
version = "1.0.0-beta3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c16b255449b3f5cd7fa4b79acd5225b5185655261087a3d8aaac44f88a0e23e9"
|
||||
checksum = "a380b87642204557629c9b72988c47b55fbfe6d474960adba56b22331504956a"
|
||||
dependencies = [
|
||||
"digest 0.9.0",
|
||||
"ed25519-zebra",
|
||||
@@ -912,18 +920,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-derive"
|
||||
version = "1.0.0-beta2"
|
||||
version = "1.0.0-beta3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abad1a6ff427a2f66890a4dce6354b4563cd07cee91a942300e011c921c09ed2"
|
||||
checksum = "866713b2fe13f23038c7d8824c3059d1f28dd94685fb406d1533c4eeeefeefae"
|
||||
dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-std"
|
||||
version = "1.0.0-beta2"
|
||||
version = "1.0.0-beta3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1660ee3d5734672e1eb4f0ceda403e2d83345e15143a48845f340f3252ce99a6"
|
||||
checksum = "8dbb9939b31441dfa9af3ec9740c8a24d585688401eff1b6b386abb7ad0d10a8"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"cosmwasm-crypto",
|
||||
@@ -1084,6 +1092,7 @@ dependencies = [
|
||||
"blake3",
|
||||
"bs58",
|
||||
"cipher",
|
||||
"config",
|
||||
"digest 0.9.0",
|
||||
"ed25519-dalek",
|
||||
"generic-array 0.14.4",
|
||||
@@ -1093,6 +1102,7 @@ dependencies = [
|
||||
"nymsphinx-types",
|
||||
"pemstore",
|
||||
"rand 0.7.3",
|
||||
"subtle-encoding",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
@@ -1659,14 +1669,6 @@ dependencies = [
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "erc20-bridge-contract"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "error-chain"
|
||||
version = "0.12.4"
|
||||
@@ -3571,7 +3573,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "0.11.0"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"client-core",
|
||||
@@ -3605,7 +3607,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client-wasm"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
dependencies = [
|
||||
"coconut-interface",
|
||||
"console_error_panic_hook",
|
||||
@@ -3629,8 +3631,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-gateway"
|
||||
version = "0.11.0"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"bandwidth-claim-contract",
|
||||
"bip39",
|
||||
"bs58",
|
||||
"clap",
|
||||
@@ -3642,7 +3645,6 @@ dependencies = [
|
||||
"dashmap",
|
||||
"dirs",
|
||||
"dotenv",
|
||||
"erc20-bridge-contract",
|
||||
"futures",
|
||||
"gateway-client",
|
||||
"gateway-requests",
|
||||
@@ -3672,7 +3674,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-mixnode"
|
||||
version = "0.11.0"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"clap",
|
||||
@@ -3694,7 +3696,6 @@ dependencies = [
|
||||
"rocket",
|
||||
"serde",
|
||||
"serial_test",
|
||||
"subtle-encoding",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"toml",
|
||||
@@ -3707,7 +3708,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-requester"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"dirs",
|
||||
@@ -3728,7 +3729,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "0.11.0"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"client-core",
|
||||
@@ -3763,7 +3764,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-validator-api"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -3972,10 +3973,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "okapi"
|
||||
version = "0.6.0-alpha-1"
|
||||
version = "0.7.0-rc.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb085e00daf8d75b9dbf0ffdb4738e69503e28898d9641fa8bdc6ad536c7bcf4"
|
||||
checksum = "ce66b6366e049880a35c378123fddb630b1a1a3c37fa1ca70caaf4a09f6e2893"
|
||||
dependencies = [
|
||||
"log",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -5212,10 +5214,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rocket_okapi"
|
||||
version = "0.7.0-alpha-1"
|
||||
version = "0.8.0-rc.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b2f4f48fb070f9f6c56d5663df5fa8a514406207744f4abd84661bfb24efd7d"
|
||||
checksum = "0025aa04994af8cd8e1fcdd5a73579a395c941ae090ecb0a39b41cca7e237a20"
|
||||
dependencies = [
|
||||
"either",
|
||||
"log",
|
||||
"okapi",
|
||||
"rocket",
|
||||
"rocket_okapi_codegen",
|
||||
@@ -5226,9 +5230,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rocket_okapi_codegen"
|
||||
version = "0.7.0-alpha-1"
|
||||
version = "0.8.0-rc.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ccf1550e1c806461a6b08e2ab64eb10701d41bf50bde59ab9aa3a57ab14d41"
|
||||
checksum = "dc114779fc27afb78179233e966f469e47fd7a98dc15181cff2574cdddb65612"
|
||||
dependencies = [
|
||||
"darling 0.13.0",
|
||||
"proc-macro2",
|
||||
@@ -7271,7 +7275,9 @@ dependencies = [
|
||||
"config",
|
||||
"cosmwasm-std",
|
||||
"cw-storage-plus",
|
||||
"getrandom 0.2.3",
|
||||
"mixnet-contract",
|
||||
"rand 0.8.4",
|
||||
"schemars",
|
||||
"serde",
|
||||
"thiserror",
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ members = [
|
||||
"common/config",
|
||||
"common/credentials",
|
||||
"common/crypto",
|
||||
"common/erc20-bridge-contract",
|
||||
"common/bandwidth-claim-contract",
|
||||
"common/mixnet-contract",
|
||||
"common/mixnode-common",
|
||||
"common/network-defaults",
|
||||
|
||||
@@ -1,25 +1,36 @@
|
||||
all: clippy test fmt
|
||||
clippy: clippy-main clippy-contracts clippy-wallet
|
||||
all: clippy-all test fmt
|
||||
happy: clippy-happy test fmt
|
||||
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet
|
||||
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet
|
||||
test: test-main test-contracts test-wallet
|
||||
fmt: fmt-main fmt-contracts fmt-wallet
|
||||
|
||||
clippy-main:
|
||||
clippy-happy-main:
|
||||
cargo clippy
|
||||
|
||||
clippy-contracts:
|
||||
cargo clippy --manifest-path contracts/Cargo.toml
|
||||
clippy-happy-contracts:
|
||||
cargo clippy --manifest-path contracts/Cargo.toml --target wasm32-unknown-unknown
|
||||
|
||||
clippy-wallet:
|
||||
clippy-happy-wallet:
|
||||
cargo clippy --manifest-path nym-wallet/Cargo.toml
|
||||
|
||||
clippy-all-main:
|
||||
cargo clippy --all-features -- -D warnings
|
||||
|
||||
clippy-all-contracts:
|
||||
cargo clippy --manifest-path contracts/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
|
||||
|
||||
clippy-all-wallet:
|
||||
cargo clippy --manifest-path nym-wallet/Cargo.toml --all-features -- -D warnings
|
||||
|
||||
test-main:
|
||||
cargo test
|
||||
cargo test --all-features
|
||||
|
||||
test-contracts:
|
||||
cargo test --manifest-path contracts/Cargo.toml
|
||||
cargo test --manifest-path contracts/Cargo.toml --all-features
|
||||
|
||||
test-wallet:
|
||||
cargo test --manifest-path nym-wallet/Cargo.toml
|
||||
cargo test --manifest-path nym-wallet/Cargo.toml --all-features
|
||||
|
||||
fmt-main:
|
||||
cargo fmt --all
|
||||
@@ -29,3 +40,6 @@ fmt-contracts:
|
||||
|
||||
fmt-wallet:
|
||||
cargo fmt --manifest-path nym-wallet/Cargo.toml --all
|
||||
|
||||
wasm:
|
||||
RUSTFLAGS='-C link-arg=-s' cargo build --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
|
||||
|
||||
@@ -40,13 +40,13 @@ Node, node operator and delegator rewards are determined according to the princi
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=R">|global share of rewards available, starts at 2% of the reward pool.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=R_{i}">|node reward for mixnode `i`.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=\sigma_{i}">|ratio of total node stake (node bond + all delegations) to the token circulating supply.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=\lambda_{i}">|ratio of stake operator has plaged to their node to the token circulating supply.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=\omega_{i}">|fraction of total effort undertaken by node `i`, set to `1/k` in testnet Milhon.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=k">|number of nodes stakeholders are incentivised to create, set by the validators, a matter of governance. Currently determined by the `active set` size, and set to 5000 in testnet Milhon.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=\lambda_{i}">|ratio of stake operator has pledged to their node to the token circulating supply.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=\omega_{i}">|fraction of total effort undertaken by node `i`, set to `1/k`.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=k">|number of nodes stakeholders are incentivised to create, set by the validators, a matter of governance. Currently determined by the `reward set` size, and set to 720 in testnet Sandbox.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=\alpha">|Sybil attack resistance parameter - the higher this parameter is set the stronger the reduction in competitivness gets for a Sybil attacker.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=PM_{i}">|declared profit margin of operator `i`, defaults to 10% in testnet Milhon.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=PM_{i}">|declared profit margin of operator `i`, defaults to 10% in.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=PF_{i}">|uptime of node `i`, scaled to 0 - 1, for the rewarding epoch
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=PP_{i}">|cost of operating node `i` for the duration of the rewarding eopoch, set to 40 Nym for testnet Milhon.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=PP_{i}">|cost of operating node `i` for the duration of the rewarding eopoch, set to 40 NYMT.
|
||||
|
||||
Node reward for node `i` is determined as:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "client-core"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -117,6 +117,10 @@ impl<T: NymConfig> Config<T> {
|
||||
self.client.id = id;
|
||||
}
|
||||
|
||||
pub fn with_testnet_mode(&mut self, testnet_mode: bool) {
|
||||
self.client.testnet_mode = testnet_mode;
|
||||
}
|
||||
|
||||
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
|
||||
self.client.gateway_id = id.into();
|
||||
}
|
||||
@@ -153,6 +157,10 @@ impl<T: NymConfig> Config<T> {
|
||||
self.client.id.clone()
|
||||
}
|
||||
|
||||
pub fn get_testnet_mode(&self) -> bool {
|
||||
self.client.testnet_mode
|
||||
}
|
||||
|
||||
pub fn get_nym_root_directory(&self) -> PathBuf {
|
||||
self.client.nym_root_directory.clone()
|
||||
}
|
||||
@@ -273,6 +281,11 @@ pub struct Client<T> {
|
||||
/// ID specifies the human readable ID of this particular client.
|
||||
id: String,
|
||||
|
||||
/// Indicates whether this client is running in a testnet mode, thus attempting
|
||||
/// to claim bandwidth without presenting bandwidth credentials.
|
||||
#[serde(default)]
|
||||
testnet_mode: bool,
|
||||
|
||||
/// Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
validator_api_urls: Vec<Url>,
|
||||
|
||||
@@ -335,6 +348,7 @@ impl<T: NymConfig> Default for Client<T> {
|
||||
Client {
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
id: "".to_string(),
|
||||
testnet_mode: false,
|
||||
validator_api_urls: default_api_endpoints(),
|
||||
private_identity_key_file: Default::default(),
|
||||
public_identity_key_file: Default::default(),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "0.11.0"
|
||||
version = "0.12.1"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
edition = "2018"
|
||||
rust-version = "1.56"
|
||||
@@ -48,6 +48,7 @@ network-defaults = { path = "../../common/network-defaults" }
|
||||
|
||||
[features]
|
||||
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"]
|
||||
eth = []
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1.0" # for the "textsend" example
|
||||
|
||||
@@ -5,7 +5,7 @@ pub(crate) fn config_template() -> &'static str {
|
||||
// While using normal toml marshalling would have been way simpler with less overhead,
|
||||
// I think it's useful to have comments attached to the saved config file to explain behaviour of
|
||||
// particular fields.
|
||||
// Note: any changes to the template must be reflected in the appropriate structs in verloc.
|
||||
// Note: any changes to the template must be reflected in the appropriate structs.
|
||||
r#"
|
||||
# This is a TOML config file.
|
||||
# For more information, see https://github.com/toml-lang/toml
|
||||
@@ -19,6 +19,10 @@ version = '{{ client.version }}'
|
||||
# Human readable ID of this particular client.
|
||||
id = '{{ client.id }}'
|
||||
|
||||
# Indicates whether this client is running in a testnet mode, thus attempting
|
||||
# to claim bandwidth without presenting bandwidth credentials.
|
||||
testnet_mode = {{ client.testnet_mode }}
|
||||
|
||||
# Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
validator_api_urls = [
|
||||
{{#each client.validator_api_urls }}
|
||||
|
||||
@@ -207,6 +207,10 @@ impl NymClient {
|
||||
Some(bandwidth_controller),
|
||||
);
|
||||
|
||||
if self.config.get_base().get_testnet_mode() {
|
||||
gateway_client.set_testnet_mode(true)
|
||||
}
|
||||
|
||||
gateway_client
|
||||
.authenticate_and_start()
|
||||
.await
|
||||
|
||||
@@ -31,6 +31,11 @@ use url::Url;
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::commands::override_config;
|
||||
#[cfg(feature = "eth")]
|
||||
use crate::commands::{
|
||||
DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY, ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
||||
TESTNET_MODE_ARG_NAME,
|
||||
};
|
||||
|
||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
let app = App::new("init")
|
||||
@@ -66,18 +71,27 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
.hidden(true) // this will prevent this flag from being displayed in `--help`
|
||||
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
|
||||
);
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
#[cfg(feature = "eth")]
|
||||
let app = app
|
||||
.arg(Arg::with_name("eth_endpoint")
|
||||
.long("eth_endpoint")
|
||||
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
|
||||
.arg(
|
||||
Arg::with_name(TESTNET_MODE_ARG_NAME)
|
||||
.long(TESTNET_MODE_ARG_NAME)
|
||||
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
||||
)
|
||||
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
||||
.long(ETH_ENDPOINT_ARG_NAME)
|
||||
.help("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 --testnet-mode instead")
|
||||
.takes_value(true)
|
||||
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_ENDPOINT)
|
||||
.required(true))
|
||||
.arg(Arg::with_name("eth_private_key")
|
||||
.long("eth_private_key")
|
||||
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
|
||||
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
|
||||
.long(ETH_PRIVATE_KEY_ARG_NAME)
|
||||
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
||||
.takes_value(true)
|
||||
.required(true));
|
||||
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_PRIVATE_KEY)
|
||||
.required(true)
|
||||
);
|
||||
|
||||
app
|
||||
}
|
||||
|
||||
@@ -5,6 +5,18 @@ use crate::client::config::{Config, SocketType};
|
||||
use clap::ArgMatches;
|
||||
use url::Url;
|
||||
|
||||
pub(crate) const TESTNET_MODE_ARG_NAME: &str = "testnet-mode";
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
pub(crate) const ETH_ENDPOINT_ARG_NAME: &str = "eth_endpoint";
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
pub(crate) const ETH_PRIVATE_KEY_ARG_NAME: &str = "eth_private_key";
|
||||
#[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;
|
||||
@@ -44,12 +56,24 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
if let Some(eth_endpoint) = matches.value_of("eth_endpoint") {
|
||||
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT_ARG_NAME) {
|
||||
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
||||
} else {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
|
||||
}
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
if let Some(eth_private_key) = matches.value_of("eth_private_key") {
|
||||
if let Some(eth_private_key) = matches.value_of(ETH_PRIVATE_KEY_ARG_NAME) {
|
||||
config.get_base_mut().with_eth_private_key(eth_private_key);
|
||||
} else {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
|
||||
}
|
||||
|
||||
if !cfg!(feature = "eth") || matches.is_present(TESTNET_MODE_ARG_NAME) {
|
||||
config.get_base_mut().with_testnet_mode(true)
|
||||
}
|
||||
|
||||
config
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
use crate::client::config::Config;
|
||||
use crate::client::NymClient;
|
||||
use crate::commands::override_config;
|
||||
#[cfg(feature = "eth")]
|
||||
use crate::commands::{ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME, TESTNET_MODE_ARG_NAME};
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use config::NymConfig;
|
||||
use log::*;
|
||||
@@ -39,15 +41,21 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
.help("Port for the socket (if applicable) to listen on")
|
||||
.takes_value(true)
|
||||
);
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
#[cfg(feature = "eth")]
|
||||
let app = app
|
||||
.arg(Arg::with_name("eth_endpoint")
|
||||
.long("eth_endpoint")
|
||||
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
|
||||
.arg(
|
||||
Arg::with_name(TESTNET_MODE_ARG_NAME)
|
||||
.long(TESTNET_MODE_ARG_NAME)
|
||||
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
||||
)
|
||||
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
||||
.long(ETH_ENDPOINT_ARG_NAME)
|
||||
.help("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 --testnet-mode instead")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("eth_private_key")
|
||||
.long("eth_private_key")
|
||||
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
|
||||
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
|
||||
.long(ETH_PRIVATE_KEY_ARG_NAME)
|
||||
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
||||
.takes_value(true));
|
||||
|
||||
app
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "0.11.0"
|
||||
version = "0.12.1"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
rust-version = "1.56"
|
||||
@@ -43,6 +43,7 @@ network-defaults = { path = "../../common/network-defaults" }
|
||||
|
||||
[features]
|
||||
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"]
|
||||
eth = []
|
||||
|
||||
[build-dependencies]
|
||||
vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] }
|
||||
@@ -5,7 +5,7 @@ pub(crate) fn config_template() -> &'static str {
|
||||
// While using normal toml marshalling would have been way simpler with less overhead,
|
||||
// I think it's useful to have comments attached to the saved config file to explain behaviour of
|
||||
// particular fields.
|
||||
// Note: any changes to the template must be reflected in the appropriate structs in verloc.
|
||||
// Note: any changes to the template must be reflected in the appropriate structs.
|
||||
r#"
|
||||
# This is a TOML config file.
|
||||
# For more information, see https://github.com/toml-lang/toml
|
||||
@@ -19,6 +19,10 @@ version = '{{ client.version }}'
|
||||
# Human readable ID of this particular client.
|
||||
id = '{{ client.id }}'
|
||||
|
||||
# Indicates whether this client is running in a testnet mode, thus attempting
|
||||
# to claim bandwidth without presenting bandwidth credentials.
|
||||
testnet_mode = {{ client.testnet_mode }}
|
||||
|
||||
# Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
validator_api_urls = [
|
||||
{{#each client.validator_api_urls }}
|
||||
|
||||
@@ -195,6 +195,10 @@ impl NymClient {
|
||||
Some(bandwidth_controller),
|
||||
);
|
||||
|
||||
if self.config.get_base().get_testnet_mode() {
|
||||
gateway_client.set_testnet_mode(true)
|
||||
}
|
||||
|
||||
gateway_client
|
||||
.authenticate_and_start()
|
||||
.await
|
||||
|
||||
@@ -29,6 +29,11 @@ use url::Url;
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::commands::override_config;
|
||||
#[cfg(feature = "eth")]
|
||||
use crate::commands::{
|
||||
DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY, ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
||||
TESTNET_MODE_ARG_NAME,
|
||||
};
|
||||
|
||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
let app = App::new("init")
|
||||
@@ -66,18 +71,27 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
.hidden(true) // this will prevent this flag from being displayed in `--help`
|
||||
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
|
||||
);
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
#[cfg(feature = "eth")]
|
||||
let app = app
|
||||
.arg(Arg::with_name("eth_endpoint")
|
||||
.long("eth_endpoint")
|
||||
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
|
||||
.arg(
|
||||
Arg::with_name(TESTNET_MODE_ARG_NAME)
|
||||
.long(TESTNET_MODE_ARG_NAME)
|
||||
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
||||
)
|
||||
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
||||
.long(ETH_ENDPOINT_ARG_NAME)
|
||||
.help("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 --testnet-mode instead")
|
||||
.takes_value(true)
|
||||
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_ENDPOINT)
|
||||
.required(true))
|
||||
.arg(Arg::with_name("eth_private_key")
|
||||
.long("eth_private_key")
|
||||
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
|
||||
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
|
||||
.long(ETH_PRIVATE_KEY_ARG_NAME)
|
||||
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
||||
.takes_value(true)
|
||||
.required(true));
|
||||
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_PRIVATE_KEY)
|
||||
.required(true)
|
||||
);
|
||||
|
||||
app
|
||||
}
|
||||
|
||||
@@ -9,6 +9,18 @@ pub(crate) mod init;
|
||||
pub(crate) mod run;
|
||||
pub(crate) mod upgrade;
|
||||
|
||||
pub(crate) const TESTNET_MODE_ARG_NAME: &str = "testnet-mode";
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
pub(crate) const ETH_ENDPOINT_ARG_NAME: &str = "eth_endpoint";
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
pub(crate) const ETH_PRIVATE_KEY_ARG_NAME: &str = "eth_private_key";
|
||||
#[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 parse_validators(raw: &str) -> Vec<Url> {
|
||||
raw.split(',')
|
||||
.map(|raw_validator| {
|
||||
@@ -40,12 +52,24 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
if let Some(eth_endpoint) = matches.value_of("eth_endpoint") {
|
||||
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT_ARG_NAME) {
|
||||
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
||||
} else {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
|
||||
}
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
if let Some(eth_private_key) = matches.value_of("eth_private_key") {
|
||||
if let Some(eth_private_key) = matches.value_of(ETH_PRIVATE_KEY_ARG_NAME) {
|
||||
config.get_base_mut().with_eth_private_key(eth_private_key);
|
||||
} else {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
|
||||
}
|
||||
|
||||
if !cfg!(feature = "eth") || matches.is_present(TESTNET_MODE_ARG_NAME) {
|
||||
config.get_base_mut().with_testnet_mode(true)
|
||||
}
|
||||
|
||||
config
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
use crate::client::config::Config;
|
||||
use crate::client::NymClient;
|
||||
use crate::commands::override_config;
|
||||
#[cfg(feature = "eth")]
|
||||
use crate::commands::{ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME, TESTNET_MODE_ARG_NAME};
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use config::NymConfig;
|
||||
use log::*;
|
||||
@@ -45,15 +47,21 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
.help("Port for the socket to listen on")
|
||||
.takes_value(true)
|
||||
);
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
#[cfg(feature = "eth")]
|
||||
let app = app
|
||||
.arg(Arg::with_name("eth_endpoint")
|
||||
.long("eth_endpoint")
|
||||
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
|
||||
.arg(
|
||||
Arg::with_name(TESTNET_MODE_ARG_NAME)
|
||||
.long(TESTNET_MODE_ARG_NAME)
|
||||
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
||||
)
|
||||
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
||||
.long(ETH_ENDPOINT_ARG_NAME)
|
||||
.help("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 --testnet-mode instead")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("eth_private_key")
|
||||
.long("eth_private_key")
|
||||
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
|
||||
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
|
||||
.long(ETH_PRIVATE_KEY_ARG_NAME)
|
||||
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
||||
.takes_value(true));
|
||||
|
||||
app
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "nym-client-wasm"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jedrzej Stuczynski <andrew@nymtech.net>"]
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
edition = "2018"
|
||||
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"]
|
||||
license = "Apache-2.0"
|
||||
|
||||
@@ -27,6 +27,7 @@ const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_millis(1_500);
|
||||
#[wasm_bindgen]
|
||||
pub struct NymClient {
|
||||
validator_server: Url,
|
||||
testnet_mode: bool,
|
||||
|
||||
// TODO: technically this doesn't need to be an Arc since wasm is run on a single thread
|
||||
// however, once we eventually combine this code with the native-client's, it will make things
|
||||
@@ -72,6 +73,7 @@ impl NymClient {
|
||||
|
||||
on_message: None,
|
||||
on_gateway_connect: None,
|
||||
testnet_mode: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +86,11 @@ impl NymClient {
|
||||
self.on_gateway_connect = Some(on_connect)
|
||||
}
|
||||
|
||||
pub fn set_testnet_mode(&mut self, testnet_mode: bool) {
|
||||
console_log!("Setting testnet mode to {}", testnet_mode);
|
||||
self.testnet_mode = testnet_mode;
|
||||
}
|
||||
|
||||
fn self_recipient(&self) -> Recipient {
|
||||
Recipient::new(
|
||||
*self.identity.public_key(),
|
||||
@@ -101,6 +108,8 @@ impl NymClient {
|
||||
|
||||
// Right now it's impossible to have async exported functions to take `&self` rather than self
|
||||
pub async fn initial_setup(self) -> Self {
|
||||
let testnet_mode = self.testnet_mode;
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
let bandwidth_controller = Some(BandwidthController::new(
|
||||
vec![self.validator_server.clone()],
|
||||
@@ -126,6 +135,10 @@ impl NymClient {
|
||||
bandwidth_controller,
|
||||
);
|
||||
|
||||
if testnet_mode {
|
||||
gateway_client.set_testnet_mode(true)
|
||||
}
|
||||
|
||||
gateway_client
|
||||
.authenticate_and_start()
|
||||
.await
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "erc20-bridge-contract"
|
||||
name = "bandwidth-claim-contract"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
@@ -40,6 +40,7 @@ const DEFAULT_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5);
|
||||
|
||||
pub struct GatewayClient {
|
||||
authenticated: bool,
|
||||
testnet_mode: bool,
|
||||
bandwidth_remaining: i64,
|
||||
gateway_address: String,
|
||||
gateway_identity: identity::PublicKey,
|
||||
@@ -75,6 +76,7 @@ impl GatewayClient {
|
||||
) -> Self {
|
||||
GatewayClient {
|
||||
authenticated: false,
|
||||
testnet_mode: false,
|
||||
bandwidth_remaining: 0,
|
||||
gateway_address,
|
||||
gateway_identity,
|
||||
@@ -90,6 +92,10 @@ impl GatewayClient {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_testnet_mode(&mut self, testnet_mode: bool) {
|
||||
self.testnet_mode = testnet_mode
|
||||
}
|
||||
|
||||
// TODO: later convert into proper builder methods
|
||||
pub fn with_reconnection_on_failure(&mut self, should_reconnect_on_failure: bool) {
|
||||
self.should_reconnect_on_failure = should_reconnect_on_failure
|
||||
@@ -119,6 +125,7 @@ impl GatewayClient {
|
||||
|
||||
GatewayClient {
|
||||
authenticated: false,
|
||||
testnet_mode: false,
|
||||
bandwidth_remaining: 0,
|
||||
gateway_address,
|
||||
gateway_identity,
|
||||
@@ -513,6 +520,17 @@ impl GatewayClient {
|
||||
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? {
|
||||
ServerResponse::Bandwidth { available_total } => Ok(available_total),
|
||||
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
|
||||
_ => Err(GatewayClientError::UnexpectedResponse),
|
||||
}?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn claim_bandwidth(&mut self) -> Result<(), GatewayClientError> {
|
||||
if !self.authenticated {
|
||||
return Err(GatewayClientError::NotAuthenticated);
|
||||
@@ -525,6 +543,10 @@ impl GatewayClient {
|
||||
}
|
||||
|
||||
warn!("Not enough bandwidth. Trying to get more bandwidth, this might take a while");
|
||||
if self.testnet_mode {
|
||||
info!("The client is running in testnet mode - attempting to claim bandwidth without a credential");
|
||||
return self.try_claim_testnet_bandwidth().await;
|
||||
}
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
let credential = self
|
||||
|
||||
@@ -33,7 +33,7 @@ prost = { version = "0.9", default-features = false, optional = true }
|
||||
flate2 = { version = "1.0.20", optional = true }
|
||||
sha2 = { version = "0.9.5", optional = true }
|
||||
itertools = { version = "0.10", optional = true }
|
||||
cosmwasm-std = { version = "1.0.0-beta2", optional = true }
|
||||
cosmwasm-std = { version = "1.0.0-beta3", optional = true }
|
||||
ts-rs = {version = "5.1", optional = true}
|
||||
|
||||
[features]
|
||||
|
||||
@@ -64,7 +64,8 @@ pub trait VestingSigningClient {
|
||||
|
||||
async fn create_periodic_vesting_account(
|
||||
&self,
|
||||
address: &str,
|
||||
owner_address: &str,
|
||||
staking_address: Option<String>,
|
||||
start_time: Option<u64>,
|
||||
amount: Coin,
|
||||
) -> Result<ExecuteResult, NymdError>;
|
||||
@@ -271,13 +272,15 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
|
||||
}
|
||||
async fn create_periodic_vesting_account(
|
||||
&self,
|
||||
address: &str,
|
||||
owner_address: &str,
|
||||
staking_address: Option<String>,
|
||||
start_time: Option<u64>,
|
||||
amount: Coin,
|
||||
) -> Result<ExecuteResult, NymdError> {
|
||||
let fee = self.operation_fee(Operation::CreatePeriodicVestingAccount);
|
||||
let req = VestingExecuteMsg::CreateAccount {
|
||||
address: address.to_string(),
|
||||
owner_address: owner_address.to_string(),
|
||||
staking_address,
|
||||
start_time,
|
||||
};
|
||||
self.client
|
||||
|
||||
@@ -202,14 +202,28 @@ impl DirectSecp256k1HdWalletBuilder {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use network_defaults::BECH32_PREFIX;
|
||||
|
||||
#[test]
|
||||
fn generating_account_addresses() {
|
||||
let (addr1, addr2, addr3) = match BECH32_PREFIX {
|
||||
"punk" => (
|
||||
"punk1jw6mp7d5xqc7w6xm79lha27glmd0vdt32a3fj2",
|
||||
"punk1h5hgn94nsq4kh99rjj794hr5h5q6yfm22mcqqn",
|
||||
"punk17n9flp6jflljg6fp05dsy07wcprf2uuujse962",
|
||||
),
|
||||
"nymt" => (
|
||||
"nymt1jw6mp7d5xqc7w6xm79lha27glmd0vdt339me94",
|
||||
"nymt1h5hgn94nsq4kh99rjj794hr5h5q6yfm23rjshv",
|
||||
"nymt17n9flp6jflljg6fp05dsy07wcprf2uuufgn4d4",
|
||||
),
|
||||
_ => panic!("Test needs to be updated with new bech32 prefix"),
|
||||
};
|
||||
// test vectors produced from our js wallet
|
||||
let mnemonic_address = vec![
|
||||
("crush minute paddle tobacco message debate cabin peace bar jacket execute twenty winner view sure mask popular couch penalty fragile demise fresh pizza stove", "punk1jw6mp7d5xqc7w6xm79lha27glmd0vdt32a3fj2"),
|
||||
("acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel", "punk1h5hgn94nsq4kh99rjj794hr5h5q6yfm22mcqqn"),
|
||||
("step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball", "punk17n9flp6jflljg6fp05dsy07wcprf2uuujse962")
|
||||
("crush minute paddle tobacco message debate cabin peace bar jacket execute twenty winner view sure mask popular couch penalty fragile demise fresh pizza stove", addr1),
|
||||
("acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel", addr2),
|
||||
("step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball", addr3)
|
||||
];
|
||||
|
||||
for (mnemonic, address) in mnemonic_address.into_iter() {
|
||||
|
||||
@@ -19,7 +19,9 @@ x25519-dalek = "1.1"
|
||||
ed25519-dalek = "1.0"
|
||||
log = "0.4"
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
subtle-encoding = { version = "0.5", features = ["bech32-preview"]}
|
||||
|
||||
# internal
|
||||
nymsphinx-types = { path = "../nymsphinx/types" }
|
||||
pemstore = { path = "../../common/pemstore" }
|
||||
config = { path="../../common/config" }
|
||||
|
||||
@@ -189,6 +189,13 @@ impl PrivateKey {
|
||||
let sig = expanded_secret_key.sign(message, &public_key.0);
|
||||
Signature(sig)
|
||||
}
|
||||
|
||||
/// Signs text with the provided Ed25519 private key, returning a base58 signature
|
||||
pub fn sign_text(&self, text: &str) -> String {
|
||||
let signature_bytes = self.sign(text.as_ref()).to_bytes();
|
||||
let signature = bs58::encode(signature_bytes).into_string();
|
||||
signature
|
||||
}
|
||||
}
|
||||
|
||||
impl PemStorableKey for PrivateKey {
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
use config::defaults;
|
||||
use subtle_encoding::bech32;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Bech32Error {
|
||||
DecodeFailed(String),
|
||||
WrongPrefix(String),
|
||||
}
|
||||
|
||||
/// Try to decode the address (to make sure it's a valid bech32 encoding)
|
||||
pub fn try_bech32_decode(address: &str) -> Result<String, Bech32Error> {
|
||||
match bech32::decode(address) {
|
||||
Err(e) => Err(Bech32Error::DecodeFailed(e.to_string())),
|
||||
Ok((prefix, _)) => Ok(prefix),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_bech32_prefix(address: &str) -> Result<(), Bech32Error> {
|
||||
let prefix = try_bech32_decode(address)?;
|
||||
|
||||
if prefix == defaults::BECH32_PREFIX {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Bech32Error::WrongPrefix(format!(
|
||||
"your bech32 address prefix should be {}, not {}",
|
||||
defaults::BECH32_PREFIX,
|
||||
prefix
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
mod decoding_bech32_addresses {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn total_crap_fails() {
|
||||
let res = try_bech32_decode("crap");
|
||||
assert_eq!(
|
||||
Err(Bech32Error::DecodeFailed("bad encoding".to_string())),
|
||||
res
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_checksum_fails() {
|
||||
let chopped_address = "punk1h3w4nj7kny5dfyjw2le4vm74z03v9vd4dstpu"; // this has the final "0" chopped off
|
||||
let res = try_bech32_decode(chopped_address);
|
||||
assert_eq!(
|
||||
Err(Bech32Error::DecodeFailed("checksum mismatch".to_string())),
|
||||
res
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn good_address_returns_prefix() {
|
||||
let prefix = try_bech32_decode("punk1h3w4nj7kny5dfyjw2le4vm74z03v9vd4dstpu0");
|
||||
assert_eq!(Ok("punk".to_string()), prefix);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod ensuring_correct_bech32_prefix {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn wrong_prefix_fails() {
|
||||
assert_eq!(
|
||||
Err(Bech32Error::WrongPrefix(
|
||||
"your bech32 address prefix should be nymt, not punk".to_string()
|
||||
)),
|
||||
validate_bech32_prefix("punk1h3w4nj7kny5dfyjw2le4vm74z03v9vd4dstpu0")
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn correct_prefix_works() {
|
||||
assert_eq!(
|
||||
Ok(()),
|
||||
validate_bech32_prefix("nymt1z9egw0knv47nmur0p8vk4rcx59h9gg4zuxrrr9")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod asymmetric;
|
||||
pub mod bech32_address_validation;
|
||||
pub mod crypto_hash;
|
||||
pub mod hkdf;
|
||||
pub mod hmac;
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2018"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
cosmwasm-std = "1.0.0-beta2"
|
||||
cosmwasm-std = "1.0.0-beta3"
|
||||
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_repr = "0.1"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
fn main() {
|
||||
match option_env!("NETWORK") {
|
||||
Some("milhon") => println!("cargo:rustc-cfg=network=\"milhon\"",),
|
||||
None | Some("sandbox") => println!("cargo:rustc-cfg=network=\"sandbox\"",),
|
||||
Some("qa") => println!("cargo:rustc-cfg=network=\"qa\""),
|
||||
_ => panic!("No such network"),
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,15 @@ use time::OffsetDateTime;
|
||||
use url::Url;
|
||||
|
||||
pub mod eth_contract;
|
||||
#[cfg(network = "milhon")]
|
||||
pub mod milhon;
|
||||
#[cfg(network = "sandbox")]
|
||||
pub mod sandbox;
|
||||
|
||||
#[cfg(network = "milhon")]
|
||||
pub use milhon::*;
|
||||
#[cfg(network = "sandbox")]
|
||||
pub use sandbox::*;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ValidatorDetails {
|
||||
@@ -38,6 +47,7 @@ impl ValidatorDetails {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(network = "milhon")]
|
||||
pub fn default_validators() -> Vec<ValidatorDetails> {
|
||||
vec![
|
||||
ValidatorDetails::new(
|
||||
@@ -48,6 +58,14 @@ pub fn default_validators() -> Vec<ValidatorDetails> {
|
||||
]
|
||||
}
|
||||
|
||||
#[cfg(network = "sandbox")]
|
||||
pub fn default_validators() -> Vec<ValidatorDetails> {
|
||||
vec![ValidatorDetails::new(
|
||||
"https://sandbox-validator.nymtech.net",
|
||||
Some("https://sandbox-validator.nymtech.net/api"),
|
||||
)]
|
||||
}
|
||||
|
||||
pub fn default_nymd_endpoints() -> Vec<Url> {
|
||||
default_validators()
|
||||
.iter()
|
||||
@@ -62,10 +80,7 @@ pub fn default_api_endpoints() -> Vec<Url> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "punk10pyejy66429refv3g35g2t7am0was7yalwrzen";
|
||||
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = "";
|
||||
pub const REWARDING_VALIDATOR_ADDRESS: &str = "punk1v9qauwdq5terag6uvfsdytcs2d0sdmfdy7hgk3";
|
||||
|
||||
// Ethereum constants used for token bridge
|
||||
/// How much bandwidth (in bytes) one token can buy
|
||||
const BYTES_PER_TOKEN: u64 = 1024 * 1024 * 1024;
|
||||
/// How many ERC20 tokens should be burned to buy bandwidth
|
||||
@@ -73,20 +88,10 @@ pub const TOKENS_TO_BURN: u64 = 10;
|
||||
/// Default bandwidth (in bytes) that we try to buy
|
||||
pub const BANDWIDTH_VALUE: u64 = TOKENS_TO_BURN * BYTES_PER_TOKEN;
|
||||
|
||||
// Ethereum constants used for token bridge
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102");
|
||||
pub const ETH_MIN_BLOCK_DEPTH: usize = 7;
|
||||
pub const COSMOS_CONTRACT_ADDRESS: &str = "punk1jld76tqw4wnpfenmay2xkv86nr3j0w426eka82";
|
||||
// Name of the event triggered by the eth contract. If the event name is changed,
|
||||
// this would also need to be changed; It is currently tested against the json abi
|
||||
pub const ETH_EVENT_NAME: &str = "Burned";
|
||||
pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode";
|
||||
|
||||
/// Defaults Cosmos Hub/ATOM path
|
||||
pub const COSMOS_DERIVATION_PATH: &str = "m/44'/118'/0'/0/0";
|
||||
pub const BECH32_PREFIX: &str = "punk";
|
||||
pub const DENOM: &str = "upunk";
|
||||
// as set by validators in their configs
|
||||
// (note that the 'amount' postfix is relevant here as the full gas price also includes denom)
|
||||
pub const GAS_PRICE_AMOUNT: f64 = 0.025;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub const BECH32_PREFIX: &str = "punk";
|
||||
pub const DENOM: &str = "upunk";
|
||||
|
||||
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "punk10pyejy66429refv3g35g2t7am0was7yalwrzen";
|
||||
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = "";
|
||||
pub const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = "punk1jld76tqw4wnpfenmay2xkv86nr3j0w426eka82";
|
||||
pub const REWARDING_VALIDATOR_ADDRESS: &str = "punk1v9qauwdq5terag6uvfsdytcs2d0sdmfdy7hgk3";
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102");
|
||||
|
||||
// Name of the event triggered by the eth contract. If the event name is changed,
|
||||
// this would also need to be changed; It is currently tested against the json abi
|
||||
pub const ETH_EVENT_NAME: &str = "Burned";
|
||||
pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode";
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub const BECH32_PREFIX: &str = "nymt";
|
||||
pub const DENOM: &str = "unymt";
|
||||
|
||||
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "nymt1ghd753shjuwexxywmgs4xz7x2q732vcnstz02j";
|
||||
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = "nymt1nc5tatafv6eyq7llkr2gv50ff9e22mnfp9pc5s";
|
||||
pub const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = "nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv";
|
||||
pub const REWARDING_VALIDATOR_ADDRESS: &str = "nymt17zujduc46wvkwvp6f062mm5xhr7jc3fewvqu9e";
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102");
|
||||
|
||||
// Name of the event triggered by the eth contract. If the event name is changed,
|
||||
// this would also need to be changed; It is currently tested against the json abi
|
||||
pub const ETH_EVENT_NAME: &str = "Burned";
|
||||
pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode";
|
||||
Generated
+85
-39
@@ -45,6 +45,27 @@ version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d6dff4a1892b54d70af377bf7a17064192e822865791d812957f21e3108c325"
|
||||
|
||||
[[package]]
|
||||
name = "bandwidth-claim"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bandwidth-claim-contract",
|
||||
"config",
|
||||
"cosmwasm-std",
|
||||
"cosmwasm-storage",
|
||||
"schemars",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bandwidth-claim-contract"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.0"
|
||||
@@ -215,24 +236,11 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "cosmos_contract"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"config",
|
||||
"cosmwasm-std",
|
||||
"cosmwasm-storage",
|
||||
"erc20-bridge-contract",
|
||||
"schemars",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-crypto"
|
||||
version = "1.0.0-beta2"
|
||||
version = "1.0.0-beta3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c16b255449b3f5cd7fa4b79acd5225b5185655261087a3d8aaac44f88a0e23e9"
|
||||
checksum = "a380b87642204557629c9b72988c47b55fbfe6d474960adba56b22331504956a"
|
||||
dependencies = [
|
||||
"digest 0.9.0",
|
||||
"ed25519-zebra",
|
||||
@@ -243,18 +251,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-derive"
|
||||
version = "1.0.0-beta2"
|
||||
version = "1.0.0-beta3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abad1a6ff427a2f66890a4dce6354b4563cd07cee91a942300e011c921c09ed2"
|
||||
checksum = "866713b2fe13f23038c7d8824c3059d1f28dd94685fb406d1533c4eeeefeefae"
|
||||
dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-schema"
|
||||
version = "1.0.0-beta2"
|
||||
version = "1.0.0-beta3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe52b19d45fe3f8359db6cc24df44dbe05e5ae32539afc0f5b7f790a21aa6fd0"
|
||||
checksum = "818b928263c09a3269c2bed22494a62107a43ef87900e273af8ad2cb9f7e4440"
|
||||
dependencies = [
|
||||
"schemars",
|
||||
"serde_json",
|
||||
@@ -262,9 +270,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-std"
|
||||
version = "1.0.0-beta2"
|
||||
version = "1.0.0-beta3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1660ee3d5734672e1eb4f0ceda403e2d83345e15143a48845f340f3252ce99a6"
|
||||
checksum = "8dbb9939b31441dfa9af3ec9740c8a24d585688401eff1b6b386abb7ad0d10a8"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"cosmwasm-crypto",
|
||||
@@ -278,9 +286,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-storage"
|
||||
version = "1.0.0-beta2"
|
||||
version = "1.0.0-beta3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf3b4efe3b4f86df668520a02e9a29c23eea99b64dfcacb0e59b98346418af7f"
|
||||
checksum = "b4a4e55f0d64fed54cd2202301b8d466af8de044589247dabd77a4222f52f749"
|
||||
dependencies = [
|
||||
"cosmwasm-std",
|
||||
"serde",
|
||||
@@ -309,6 +317,7 @@ dependencies = [
|
||||
"blake3",
|
||||
"bs58",
|
||||
"cipher",
|
||||
"config",
|
||||
"digest 0.9.0",
|
||||
"ed25519-dalek",
|
||||
"generic-array 0.14.4",
|
||||
@@ -317,7 +326,8 @@ dependencies = [
|
||||
"log",
|
||||
"nymsphinx-types",
|
||||
"pemstore",
|
||||
"rand",
|
||||
"rand 0.7.3",
|
||||
"subtle-encoding",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
@@ -448,7 +458,7 @@ checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"ed25519",
|
||||
"rand",
|
||||
"rand 0.7.3",
|
||||
"serde",
|
||||
"sha2",
|
||||
"zeroize",
|
||||
@@ -504,14 +514,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "erc20-bridge-contract"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
@@ -590,8 +592,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.10.2+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -854,8 +858,8 @@ dependencies = [
|
||||
"cw-storage-plus",
|
||||
"fixed",
|
||||
"mixnet-contract",
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
"rand 0.7.3",
|
||||
"rand_chacha 0.2.2",
|
||||
"schemars",
|
||||
"serde",
|
||||
"thiserror",
|
||||
@@ -1063,9 +1067,21 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom 0.1.16",
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_chacha 0.2.2",
|
||||
"rand_core 0.5.1",
|
||||
"rand_hc",
|
||||
"rand_hc 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.3",
|
||||
"rand_hc 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1078,6 +1094,16 @@ dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.6.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
@@ -1103,7 +1129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9e9532ada3929fb8b2e9dbe28d1e06c9b2cc65813f074fcb6bd5fbefeff9d56"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"rand",
|
||||
"rand 0.7.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1115,6 +1141,15 @@ dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
|
||||
dependencies = [
|
||||
"rand_core 0.6.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
@@ -1295,7 +1330,7 @@ dependencies = [
|
||||
"hmac",
|
||||
"lioness",
|
||||
"log",
|
||||
"rand",
|
||||
"rand 0.7.3",
|
||||
"rand_distr",
|
||||
"sha2",
|
||||
"subtle 2.4.1",
|
||||
@@ -1328,6 +1363,15 @@ version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "subtle-encoding"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945"
|
||||
dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.81"
|
||||
@@ -1514,7 +1558,9 @@ dependencies = [
|
||||
"config",
|
||||
"cosmwasm-std",
|
||||
"cw-storage-plus",
|
||||
"getrandom 0.2.3",
|
||||
"mixnet-contract",
|
||||
"rand 0.8.4",
|
||||
"schemars",
|
||||
"serde",
|
||||
"thiserror",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[workspace]
|
||||
members = ["erc20-bridge", "mixnet", "vesting"]
|
||||
members = ["bandwidth-claim", "mixnet", "vesting"]
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "cosmos_contract"
|
||||
name = "bandwidth-claim"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
@@ -8,18 +8,14 @@ edition = "2018"
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[features]
|
||||
# for more explicit tests, cargo test --features=backtraces
|
||||
backtraces = ["cosmwasm-std/backtraces"]
|
||||
|
||||
[dev-dependencies]
|
||||
config = { path = "../../common/config"}
|
||||
|
||||
[dependencies]
|
||||
erc20-bridge-contract = { path = "../../common/erc20-bridge-contract" }
|
||||
bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" }
|
||||
|
||||
cosmwasm-std = "1.0.0-beta2"
|
||||
cosmwasm-storage = "1.0.0-beta2"
|
||||
cosmwasm-std = "1.0.0-beta3"
|
||||
cosmwasm-storage = "1.0.0-beta3"
|
||||
|
||||
schemars = "0.8"
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
@@ -12,7 +12,7 @@ use cosmwasm_std::{
|
||||
};
|
||||
|
||||
use crate::error::ContractError;
|
||||
use erc20_bridge_contract::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
|
||||
use bandwidth_claim_contract::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
|
||||
|
||||
/// Instantiate the contract.
|
||||
///
|
||||
@@ -61,10 +61,10 @@ pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response,
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use bandwidth_claim_contract::payment::PagedPaymentResponse;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
|
||||
use cosmwasm_std::{coins, from_binary};
|
||||
use erc20_bridge_contract::payment::PagedPaymentResponse;
|
||||
|
||||
#[test]
|
||||
fn initialize_contract() {
|
||||
@@ -4,8 +4,8 @@
|
||||
use cosmwasm_std::{Deps, Order, StdResult};
|
||||
|
||||
use crate::storage::payments_read;
|
||||
use erc20_bridge_contract::keys::PublicKey;
|
||||
use erc20_bridge_contract::payment::{PagedPaymentResponse, Payment};
|
||||
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;
|
||||
@@ -6,7 +6,7 @@ use cosmwasm_storage::{bucket, bucket_read, Bucket, ReadonlyBucket};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use erc20_bridge_contract::payment::Payment;
|
||||
use bandwidth_claim_contract::payment::Payment;
|
||||
|
||||
// buckets
|
||||
const PREFIX_PAYMENTS: &[u8] = b"payments";
|
||||
@@ -35,8 +35,8 @@ pub fn status(storage: &mut dyn Storage) -> Bucket<Status> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::support::tests::helpers;
|
||||
use bandwidth_claim_contract::keys::PublicKey;
|
||||
use cosmwasm_std::testing::MockStorage;
|
||||
use erc20_bridge_contract::keys::PublicKey;
|
||||
|
||||
#[test]
|
||||
fn payments_single_read_retrieval() {
|
||||
+3
-3
@@ -4,11 +4,11 @@
|
||||
#[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};
|
||||
use erc20_bridge_contract::keys::PublicKey;
|
||||
use erc20_bridge_contract::msg::InstantiateMsg;
|
||||
use erc20_bridge_contract::payment::Payment;
|
||||
|
||||
pub fn init_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>> {
|
||||
let mut deps = mock_dependencies();
|
||||
+2
-2
@@ -5,7 +5,7 @@ use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
||||
|
||||
use crate::error::ContractError;
|
||||
use crate::storage::{payments, status, Status};
|
||||
use erc20_bridge_contract::payment::{LinkPaymentData, Payment};
|
||||
use bandwidth_claim_contract::payment::{LinkPaymentData, Payment};
|
||||
|
||||
pub(crate) fn link_payment(
|
||||
deps: DepsMut,
|
||||
@@ -49,8 +49,8 @@ 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};
|
||||
use erc20_bridge_contract::keys::PublicKey;
|
||||
|
||||
#[test]
|
||||
fn bad_signature_payment() {
|
||||
@@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
../.env
|
||||
|
||||
#Hardhat files
|
||||
cache
|
||||
artifacts
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
skipFiles: [
|
||||
'CosmosToken.sol',
|
||||
'Gravity.sol'
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
# 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`
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../../build-info/6dfbc7f87ae3c2727d63a3fba8d02a41.json"
|
||||
}
|
||||
+297
File diff suppressed because one or more lines are too long
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../../build-info/6dfbc7f87ae3c2727d63a3fba8d02a41.json"
|
||||
}
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
{
|
||||
"_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": {}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../../../build-info/6dfbc7f87ae3c2727d63a3fba8d02a41.json"
|
||||
}
|
||||
+233
@@ -0,0 +1,233 @@
|
||||
{
|
||||
"_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": {}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../build-info/6dfbc7f87ae3c2727d63a3fba8d02a41.json"
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"_format": "hh-sol-artifact-1",
|
||||
"contractName": "Context",
|
||||
"sourceName": "@openzeppelin/contracts/utils/Context.sol",
|
||||
"abi": [],
|
||||
"bytecode": "0x",
|
||||
"deployedBytecode": "0x",
|
||||
"linkReferences": {},
|
||||
"deployedLinkReferences": {}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"_format": "hh-sol-artifact-1",
|
||||
"contractName": "SafeMath",
|
||||
"sourceName": "@openzeppelin/contracts/math/SafeMath.sol",
|
||||
"abi": [],
|
||||
"bytecode": "0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212207ceb5b9e8bb631a9723802d1487d75b0f9db1e57e569e37561e9d35cd45a718c64736f6c63430006060033",
|
||||
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212207ceb5b9e8bb631a9723802d1487d75b0f9db1e57e569e37561e9d35cd45a718c64736f6c63430006060033",
|
||||
"linkReferences": {},
|
||||
"deployedLinkReferences": {}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
|
||||
}
|
||||
+297
File diff suppressed because one or more lines are too long
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
|
||||
}
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
{
|
||||
"_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": {}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"_format": "hh-sol-artifact-1",
|
||||
"contractName": "SafeERC20",
|
||||
"sourceName": "@openzeppelin/contracts/token/ERC20/SafeERC20.sol",
|
||||
"abi": [],
|
||||
"bytecode": "0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220a10ad72c41cead301751dbbfdbfa8dc0de387237baaadf00c593410d921ba53164736f6c63430006060033",
|
||||
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220a10ad72c41cead301751dbbfdbfa8dc0de387237baaadf00c593410d921ba53164736f6c63430006060033",
|
||||
"linkReferences": {},
|
||||
"deployedLinkReferences": {}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"_format": "hh-sol-artifact-1",
|
||||
"contractName": "Address",
|
||||
"sourceName": "@openzeppelin/contracts/utils/Address.sol",
|
||||
"abi": [],
|
||||
"bytecode": "0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf51151e2a4e160194baa49fc39a27bad1253743e398fefe6fb6935ec7d37a5e64736f6c63430006060033",
|
||||
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf51151e2a4e160194baa49fc39a27bad1253743e398fefe6fb6935ec7d37a5e64736f6c63430006060033",
|
||||
"linkReferences": {},
|
||||
"deployedLinkReferences": {}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"_format": "hh-sol-artifact-1",
|
||||
"contractName": "Context",
|
||||
"sourceName": "@openzeppelin/contracts/utils/Context.sol",
|
||||
"abi": [],
|
||||
"bytecode": "0x",
|
||||
"deployedBytecode": "0x",
|
||||
"linkReferences": {},
|
||||
"deployedLinkReferences": {}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"_format": "hh-sol-artifact-1",
|
||||
"contractName": "ReentrancyGuard",
|
||||
"sourceName": "@openzeppelin/contracts/utils/ReentrancyGuard.sol",
|
||||
"abi": [
|
||||
{
|
||||
"inputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
}
|
||||
],
|
||||
"bytecode": "0x",
|
||||
"deployedBytecode": "0x",
|
||||
"linkReferences": {},
|
||||
"deployedLinkReferences": {}
|
||||
}
|
||||
+222
File diff suppressed because one or more lines are too long
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
|
||||
}
|
||||
+325
File diff suppressed because one or more lines are too long
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
|
||||
}
|
||||
+678
File diff suppressed because one or more lines are too long
@@ -0,0 +1,403 @@
|
||||
{
|
||||
"_format": "hh-sol-cache-2",
|
||||
"files": {
|
||||
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/contracts/BandwidthGenerator.sol": {
|
||||
"lastModificationDate": 1639657373736,
|
||||
"contentHash": "ac31a05f19ad88d4c28011a830d29b56",
|
||||
"sourceName": "contracts/BandwidthGenerator.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.6.6",
|
||||
"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/math/SafeMath.sol"
|
||||
],
|
||||
"versionPragmas": [
|
||||
"0.6.6"
|
||||
],
|
||||
"artifacts": [
|
||||
"BandwidthGenerator"
|
||||
]
|
||||
},
|
||||
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/contracts/CosmosToken.sol": {
|
||||
"lastModificationDate": 1639657191231,
|
||||
"contentHash": "0f05f96ee3c1151b6cd4b699aa3167e9",
|
||||
"sourceName": "contracts/CosmosToken.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.6.6",
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
"abi",
|
||||
"evm.bytecode",
|
||||
"evm.deployedBytecode",
|
||||
"evm.methodIdentifiers"
|
||||
],
|
||||
"": [
|
||||
"ast"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
"@openzeppelin/contracts/token/ERC20/ERC20.sol"
|
||||
],
|
||||
"versionPragmas": [
|
||||
"^0.6.6"
|
||||
],
|
||||
"artifacts": [
|
||||
"CosmosERC20"
|
||||
]
|
||||
},
|
||||
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/contracts/Gravity.sol": {
|
||||
"lastModificationDate": 1639657191231,
|
||||
"contentHash": "eaa1cd71cea24d419ef5f67a66dc672e",
|
||||
"sourceName": "contracts/Gravity.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.6.6",
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
"abi",
|
||||
"evm.bytecode",
|
||||
"evm.deployedBytecode",
|
||||
"evm.methodIdentifiers"
|
||||
],
|
||||
"": [
|
||||
"ast"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
"@openzeppelin/contracts/math/SafeMath.sol",
|
||||
"@openzeppelin/contracts/token/ERC20/IERC20.sol",
|
||||
"@openzeppelin/contracts/token/ERC20/SafeERC20.sol",
|
||||
"@openzeppelin/contracts/utils/Address.sol",
|
||||
"@openzeppelin/contracts/utils/ReentrancyGuard.sol",
|
||||
"./CosmosToken.sol"
|
||||
],
|
||||
"versionPragmas": [
|
||||
"^0.6.6"
|
||||
],
|
||||
"artifacts": [
|
||||
"Gravity"
|
||||
]
|
||||
},
|
||||
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/access/Ownable.sol": {
|
||||
"lastModificationDate": 1639657303711,
|
||||
"contentHash": "6748815a5b45c4aeeda56819f41190e0",
|
||||
"sourceName": "@openzeppelin/contracts/access/Ownable.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.6.6",
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
"abi",
|
||||
"evm.bytecode",
|
||||
"evm.deployedBytecode",
|
||||
"evm.methodIdentifiers"
|
||||
],
|
||||
"": [
|
||||
"ast"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
"../utils/Context.sol"
|
||||
],
|
||||
"versionPragmas": [
|
||||
">=0.6.0 <0.8.0"
|
||||
],
|
||||
"artifacts": [
|
||||
"Ownable"
|
||||
]
|
||||
},
|
||||
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/math/SafeMath.sol": {
|
||||
"lastModificationDate": 1639657303763,
|
||||
"contentHash": "e03e12206057e809eb76c5f681170c32",
|
||||
"sourceName": "@openzeppelin/contracts/math/SafeMath.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.6.6",
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
"abi",
|
||||
"evm.bytecode",
|
||||
"evm.deployedBytecode",
|
||||
"evm.methodIdentifiers"
|
||||
],
|
||||
"": [
|
||||
"ast"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"imports": [],
|
||||
"versionPragmas": [
|
||||
">=0.6.0 <0.8.0"
|
||||
],
|
||||
"artifacts": [
|
||||
"SafeMath"
|
||||
]
|
||||
},
|
||||
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol": {
|
||||
"lastModificationDate": 1639657303507,
|
||||
"contentHash": "8065b340476f61365c076897199425f1",
|
||||
"sourceName": "@openzeppelin/contracts/token/ERC20/ERC20.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.6.6",
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
"abi",
|
||||
"evm.bytecode",
|
||||
"evm.deployedBytecode",
|
||||
"evm.methodIdentifiers"
|
||||
],
|
||||
"": [
|
||||
"ast"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
"../../utils/Context.sol",
|
||||
"./IERC20.sol",
|
||||
"../../math/SafeMath.sol"
|
||||
],
|
||||
"versionPragmas": [
|
||||
">=0.6.0 <0.8.0"
|
||||
],
|
||||
"artifacts": [
|
||||
"ERC20"
|
||||
]
|
||||
},
|
||||
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/utils/Context.sol": {
|
||||
"lastModificationDate": 1639657303395,
|
||||
"contentHash": "2adbd82f6d055a4751566d4671512b03",
|
||||
"sourceName": "@openzeppelin/contracts/utils/Context.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.6.6",
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
"abi",
|
||||
"evm.bytecode",
|
||||
"evm.deployedBytecode",
|
||||
"evm.methodIdentifiers"
|
||||
],
|
||||
"": [
|
||||
"ast"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"imports": [],
|
||||
"versionPragmas": [
|
||||
">=0.6.0 <0.8.0"
|
||||
],
|
||||
"artifacts": [
|
||||
"Context"
|
||||
]
|
||||
},
|
||||
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol": {
|
||||
"lastModificationDate": 1639657303639,
|
||||
"contentHash": "e0a41531d159d3a32f84b7a3ecf9fabb",
|
||||
"sourceName": "@openzeppelin/contracts/token/ERC20/IERC20.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.6.6",
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
"abi",
|
||||
"evm.bytecode",
|
||||
"evm.deployedBytecode",
|
||||
"evm.methodIdentifiers"
|
||||
],
|
||||
"": [
|
||||
"ast"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"imports": [],
|
||||
"versionPragmas": [
|
||||
">=0.6.0 <0.8.0"
|
||||
],
|
||||
"artifacts": [
|
||||
"IERC20"
|
||||
]
|
||||
},
|
||||
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/token/ERC20/SafeERC20.sol": {
|
||||
"lastModificationDate": 1639657303759,
|
||||
"contentHash": "33e22842646d746e5c4124c2fdc051aa",
|
||||
"sourceName": "@openzeppelin/contracts/token/ERC20/SafeERC20.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.6.6",
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
"abi",
|
||||
"evm.bytecode",
|
||||
"evm.deployedBytecode",
|
||||
"evm.methodIdentifiers"
|
||||
],
|
||||
"": [
|
||||
"ast"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
"./IERC20.sol",
|
||||
"../../math/SafeMath.sol",
|
||||
"../../utils/Address.sol"
|
||||
],
|
||||
"versionPragmas": [
|
||||
">=0.6.0 <0.8.0"
|
||||
],
|
||||
"artifacts": [
|
||||
"SafeERC20"
|
||||
]
|
||||
},
|
||||
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/utils/Address.sol": {
|
||||
"lastModificationDate": 1639657303363,
|
||||
"contentHash": "7aa46886ff5abe7515496208a5e2ce5a",
|
||||
"sourceName": "@openzeppelin/contracts/utils/Address.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.6.6",
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
"abi",
|
||||
"evm.bytecode",
|
||||
"evm.deployedBytecode",
|
||||
"evm.methodIdentifiers"
|
||||
],
|
||||
"": [
|
||||
"ast"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"imports": [],
|
||||
"versionPragmas": [
|
||||
">=0.6.2 <0.8.0"
|
||||
],
|
||||
"artifacts": [
|
||||
"Address"
|
||||
]
|
||||
},
|
||||
"/home/max/dev/nymtech/nym/contracts/basic-bandwidth-generation/node_modules/@openzeppelin/contracts/utils/ReentrancyGuard.sol": {
|
||||
"lastModificationDate": 1639657303747,
|
||||
"contentHash": "1c60f58cee45c61469e1aea31e4dd879",
|
||||
"sourceName": "@openzeppelin/contracts/utils/ReentrancyGuard.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.6.6",
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
"abi",
|
||||
"evm.bytecode",
|
||||
"evm.deployedBytecode",
|
||||
"evm.methodIdentifiers"
|
||||
],
|
||||
"": [
|
||||
"ast"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"imports": [],
|
||||
"versionPragmas": [
|
||||
">=0.6.0 <0.8.0"
|
||||
],
|
||||
"artifacts": [
|
||||
"ReentrancyGuard"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
pragma solidity 0.6.6;
|
||||
|
||||
import "./CosmosToken.sol";
|
||||
import "./Gravity.sol";
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import "@openzeppelin/contracts/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.
|
||||
*
|
||||
* 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;
|
||||
|
||||
event BBCredentialPurchased(
|
||||
uint256 Bandwidth,
|
||||
uint256 indexed VerificationKey,
|
||||
bytes SignedVerificationKey,
|
||||
bytes32 indexed CosmosRecipient
|
||||
);
|
||||
|
||||
event RatioChanged(
|
||||
uint256 indexed NewBytesPerToken
|
||||
);
|
||||
|
||||
/**
|
||||
* @param _erc20 Address of the erc20NYM deployed through the Gravity Bridge.
|
||||
* @param _gravityBridge Address of the deployed Gravity Bridge.
|
||||
*/
|
||||
constructor(CosmosERC20 _erc20, Gravity _gravityBridge) public {
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 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, bytes32 _cosmosRecipient) public {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
pragma solidity ^0.6.6;
|
||||
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 CosmosERC20 is ERC20 {
|
||||
/* canonical amount */
|
||||
// uint256 MAX_UINT = 2**256 - 1;
|
||||
|
||||
/* unit testing amount */
|
||||
uint256 HALF_MAX_UINT = 2**256 / 2;
|
||||
|
||||
constructor(
|
||||
address _gravityAddress,
|
||||
string memory _name,
|
||||
string memory _symbol,
|
||||
uint8 _decimals
|
||||
) public ERC20(_name, _symbol) {
|
||||
_setupDecimals(_decimals);
|
||||
_mint(_gravityAddress, HALF_MAX_UINT);
|
||||
}
|
||||
|
||||
function mintForUnitTesting(address _to, uint _amount) public {
|
||||
_mint(_to, _amount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,601 @@
|
||||
pragma solidity ^0.6.6;
|
||||
|
||||
import "@openzeppelin/contracts/math/SafeMath.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
|
||||
import "@openzeppelin/contracts/utils/Address.sol";
|
||||
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
|
||||
import "./CosmosToken.sol";
|
||||
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
contract Gravity is ReentrancyGuard {
|
||||
using SafeMath for uint256;
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
// 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;
|
||||
|
||||
// These are set once at initialization
|
||||
bytes32 public state_gravityId;
|
||||
uint256 public state_powerThreshold;
|
||||
|
||||
// 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,
|
||||
bytes32 indexed _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,
|
||||
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(
|
||||
address[] memory _validators,
|
||||
uint256[] memory _powers,
|
||||
uint256 _valsetNonce,
|
||||
bytes32 _gravityId
|
||||
) public pure {
|
||||
makeCheckpoint(_validators, _powers, _valsetNonce, _gravityId);
|
||||
}
|
||||
|
||||
function testCheckValidatorSignatures(
|
||||
address[] memory _currentValidators,
|
||||
uint256[] memory _currentPowers,
|
||||
uint8[] memory _v,
|
||||
bytes32[] memory _r,
|
||||
bytes32[] memory _s,
|
||||
bytes32 _theHash,
|
||||
uint256 _powerThreshold
|
||||
) public pure {
|
||||
checkValidatorSignatures(
|
||||
_currentValidators,
|
||||
_currentPowers,
|
||||
_v,
|
||||
_r,
|
||||
_s,
|
||||
_theHash,
|
||||
_powerThreshold
|
||||
);
|
||||
}
|
||||
|
||||
// END TEST FIXTURES
|
||||
|
||||
function lastBatchNonce(address _erc20Address) public view returns (uint256) {
|
||||
return state_lastBatchNonces[_erc20Address];
|
||||
}
|
||||
|
||||
function lastLogicCallNonce(bytes32 _invalidation_id) public view returns (uint256) {
|
||||
return state_invalidationMapping[_invalidation_id];
|
||||
}
|
||||
|
||||
// Utility function to verify geth style signatures
|
||||
function verifySig(
|
||||
address _signer,
|
||||
bytes32 _theHash,
|
||||
uint8 _v,
|
||||
bytes32 _r,
|
||||
bytes32 _s
|
||||
) private pure returns (bool) {
|
||||
bytes32 messageDigest =
|
||||
keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _theHash));
|
||||
return _signer == ecrecover(messageDigest, _v, _r, _s);
|
||||
}
|
||||
|
||||
// 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(
|
||||
address[] memory _validators,
|
||||
uint256[] memory _powers,
|
||||
uint256 _valsetNonce,
|
||||
bytes32 _gravityId
|
||||
) private pure returns (bytes32) {
|
||||
// bytes32 encoding of the string "checkpoint"
|
||||
bytes32 methodName = 0x636865636b706f696e7400000000000000000000000000000000000000000000;
|
||||
|
||||
bytes32 checkpoint =
|
||||
keccak256(abi.encode(_gravityId, methodName, _valsetNonce, _validators, _powers));
|
||||
|
||||
return checkpoint;
|
||||
}
|
||||
|
||||
function checkValidatorSignatures(
|
||||
// The current validator set and their powers
|
||||
address[] memory _currentValidators,
|
||||
uint256[] memory _currentPowers,
|
||||
// The current validator's signatures
|
||||
uint8[] memory _v,
|
||||
bytes32[] memory _r,
|
||||
bytes32[] memory _s,
|
||||
// This is what we are checking they have signed
|
||||
bytes32 _theHash,
|
||||
uint256 _powerThreshold
|
||||
) private pure {
|
||||
uint256 cumulativePower = 0;
|
||||
|
||||
for (uint256 i = 0; i < _currentValidators.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 (_v[i] != 0) {
|
||||
// Check that the current validator has signed off on the hash
|
||||
require(
|
||||
verifySig(_currentValidators[i], _theHash, _v[i], _r[i], _s[i]),
|
||||
"Validator signature does not match."
|
||||
);
|
||||
|
||||
// Sum up cumulative power
|
||||
cumulativePower = cumulativePower + _currentPowers[i];
|
||||
|
||||
// Break early to avoid wasting gas
|
||||
if (cumulativePower > _powerThreshold) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that there was enough power
|
||||
require(
|
||||
cumulativePower > _powerThreshold,
|
||||
"Submitted validator set signatures do not have enough power."
|
||||
);
|
||||
// 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 state_powerThreshold of the current valset over
|
||||
// the new valset.
|
||||
function updateValset(
|
||||
// The new version of the validator set
|
||||
address[] memory _newValidators,
|
||||
uint256[] memory _newPowers,
|
||||
uint256 _newValsetNonce,
|
||||
// The current validators that approve the change
|
||||
address[] memory _currentValidators,
|
||||
uint256[] memory _currentPowers,
|
||||
uint256 _currentValsetNonce,
|
||||
// These are arrays of the parts of the current validator's signatures
|
||||
uint8[] memory _v,
|
||||
bytes32[] memory _r,
|
||||
bytes32[] memory _s
|
||||
) public nonReentrant {
|
||||
// CHECKS
|
||||
|
||||
// Check that the valset nonce is greater than the old one
|
||||
require(
|
||||
_newValsetNonce > _currentValsetNonce,
|
||||
"New valset nonce must be greater than the current nonce"
|
||||
);
|
||||
|
||||
// Check that new validators and powers set is well-formed
|
||||
require(_newValidators.length == _newPowers.length, "Malformed new validator set");
|
||||
|
||||
// Check that current validators, powers, and signatures (v,r,s) set is well-formed
|
||||
require(
|
||||
_currentValidators.length == _currentPowers.length &&
|
||||
_currentValidators.length == _v.length &&
|
||||
_currentValidators.length == _r.length &&
|
||||
_currentValidators.length == _s.length,
|
||||
"Malformed current validator set"
|
||||
);
|
||||
|
||||
// Check that the supplied current validator set matches the saved checkpoint
|
||||
require(
|
||||
makeCheckpoint(
|
||||
_currentValidators,
|
||||
_currentPowers,
|
||||
_currentValsetNonce,
|
||||
state_gravityId
|
||||
) == state_lastValsetCheckpoint,
|
||||
"Supplied current validators and powers do not match checkpoint."
|
||||
);
|
||||
|
||||
// Check that enough current validators have signed off on the new validator set
|
||||
bytes32 newCheckpoint =
|
||||
makeCheckpoint(_newValidators, _newPowers, _newValsetNonce, state_gravityId);
|
||||
|
||||
checkValidatorSignatures(
|
||||
_currentValidators,
|
||||
_currentPowers,
|
||||
_v,
|
||||
_r,
|
||||
_s,
|
||||
newCheckpoint,
|
||||
state_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 = _newValsetNonce;
|
||||
|
||||
// LOGS
|
||||
state_lastEventNonce = state_lastEventNonce.add(1);
|
||||
emit ValsetUpdatedEvent(_newValsetNonce, state_lastEventNonce, _newValidators, _newPowers);
|
||||
}
|
||||
|
||||
// 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 state_powerThreshold of the current valset over
|
||||
// the batch.
|
||||
function submitBatch(
|
||||
// The validators that approve the batch
|
||||
address[] memory _currentValidators,
|
||||
uint256[] memory _currentPowers,
|
||||
uint256 _currentValsetNonce,
|
||||
// These are arrays of the parts of the validators signatures
|
||||
uint8[] memory _v,
|
||||
bytes32[] memory _r,
|
||||
bytes32[] memory _s,
|
||||
// The batch of transactions
|
||||
uint256[] memory _amounts,
|
||||
address[] memory _destinations,
|
||||
uint256[] memory _fees,
|
||||
uint256 _batchNonce,
|
||||
address _tokenContract,
|
||||
// a block height beyond which this batch is not valid
|
||||
// used to provide a fee-free timeout
|
||||
uint256 _batchTimeout
|
||||
) public nonReentrant {
|
||||
// CHECKS scoped to reduce stack depth
|
||||
{
|
||||
// Check that the batch nonce is higher than the last nonce for this token
|
||||
require(
|
||||
state_lastBatchNonces[_tokenContract] < _batchNonce,
|
||||
"New batch nonce must be greater than the current nonce"
|
||||
);
|
||||
|
||||
// Check that the block height is less than the timeout height
|
||||
require(
|
||||
block.number < _batchTimeout,
|
||||
"Batch timeout must be greater than the current block height"
|
||||
);
|
||||
|
||||
// Check that current validators, powers, and signatures (v,r,s) set is well-formed
|
||||
require(
|
||||
_currentValidators.length == _currentPowers.length &&
|
||||
_currentValidators.length == _v.length &&
|
||||
_currentValidators.length == _r.length &&
|
||||
_currentValidators.length == _s.length,
|
||||
"Malformed current validator set"
|
||||
);
|
||||
|
||||
// Check that the supplied current validator set matches the saved checkpoint
|
||||
require(
|
||||
makeCheckpoint(
|
||||
_currentValidators,
|
||||
_currentPowers,
|
||||
_currentValsetNonce,
|
||||
state_gravityId
|
||||
) == state_lastValsetCheckpoint,
|
||||
"Supplied current validators and powers do not match checkpoint."
|
||||
);
|
||||
|
||||
// Check that the transaction batch is well-formed
|
||||
require(
|
||||
_amounts.length == _destinations.length && _amounts.length == _fees.length,
|
||||
"Malformed batch of transactions"
|
||||
);
|
||||
|
||||
// Check that enough current validators have signed off on the transaction batch and valset
|
||||
checkValidatorSignatures(
|
||||
_currentValidators,
|
||||
_currentPowers,
|
||||
_v,
|
||||
_r,
|
||||
_s,
|
||||
// Get hash of the transaction batch and checkpoint
|
||||
keccak256(
|
||||
abi.encode(
|
||||
state_gravityId,
|
||||
// bytes32 encoding of "transactionBatch"
|
||||
0x7472616e73616374696f6e426174636800000000000000000000000000000000,
|
||||
_amounts,
|
||||
_destinations,
|
||||
_fees,
|
||||
_batchNonce,
|
||||
_tokenContract,
|
||||
_batchTimeout
|
||||
)
|
||||
),
|
||||
state_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.add(_fees[i]);
|
||||
}
|
||||
|
||||
// Send transaction fees to msg.sender
|
||||
IERC20(_tokenContract).safeTransfer(msg.sender, totalFee);
|
||||
}
|
||||
}
|
||||
|
||||
// LOGS scoped to reduce stack depth
|
||||
{
|
||||
state_lastEventNonce = state_lastEventNonce.add(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
|
||||
address[] memory _currentValidators,
|
||||
uint256[] memory _currentPowers,
|
||||
uint256 _currentValsetNonce,
|
||||
// These are arrays of the parts of the validators signatures
|
||||
uint8[] memory _v,
|
||||
bytes32[] memory _r,
|
||||
bytes32[] memory _s,
|
||||
LogicCallArgs memory _args
|
||||
) public nonReentrant {
|
||||
// CHECKS scoped to reduce stack depth
|
||||
{
|
||||
// Check that the call has not timed out
|
||||
require(block.number < _args.timeOut, "Timed out");
|
||||
|
||||
// Check that the invalidation nonce is higher than the last nonce for this invalidation Id
|
||||
require(
|
||||
state_invalidationMapping[_args.invalidationId] < _args.invalidationNonce,
|
||||
"New invalidation nonce must be greater than the current nonce"
|
||||
);
|
||||
|
||||
// Check that current validators, powers, and signatures (v,r,s) set is well-formed
|
||||
require(
|
||||
_currentValidators.length == _currentPowers.length &&
|
||||
_currentValidators.length == _v.length &&
|
||||
_currentValidators.length == _r.length &&
|
||||
_currentValidators.length == _s.length,
|
||||
"Malformed current validator set"
|
||||
);
|
||||
|
||||
// Check that the supplied current validator set matches the saved checkpoint
|
||||
require(
|
||||
makeCheckpoint(
|
||||
_currentValidators,
|
||||
_currentPowers,
|
||||
_currentValsetNonce,
|
||||
state_gravityId
|
||||
) == state_lastValsetCheckpoint,
|
||||
"Supplied current validators and powers do not match checkpoint."
|
||||
);
|
||||
|
||||
// Check that the token transfer list is well-formed
|
||||
require(
|
||||
_args.transferAmounts.length == _args.transferTokenContracts.length,
|
||||
"Malformed list of token transfers"
|
||||
);
|
||||
|
||||
// Check that the fee list is well-formed
|
||||
require(
|
||||
_args.feeAmounts.length == _args.feeTokenContracts.length,
|
||||
"Malformed list of fees"
|
||||
);
|
||||
}
|
||||
|
||||
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(
|
||||
_currentValidators,
|
||||
_currentPowers,
|
||||
_v,
|
||||
_r,
|
||||
_s,
|
||||
// Get hash of the transaction batch and checkpoint
|
||||
argsHash,
|
||||
state_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.add(1);
|
||||
emit LogicCallEvent(
|
||||
_args.invalidationId,
|
||||
_args.invalidationNonce,
|
||||
returnData,
|
||||
state_lastEventNonce
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function sendToCosmos(
|
||||
address _tokenContract,
|
||||
bytes32 _destination,
|
||||
uint256 _amount
|
||||
) public nonReentrant {
|
||||
IERC20(_tokenContract).safeTransferFrom(msg.sender, address(this), _amount);
|
||||
state_lastEventNonce = state_lastEventNonce.add(1);
|
||||
emit SendToCosmosEvent(
|
||||
_tokenContract,
|
||||
msg.sender,
|
||||
_destination,
|
||||
_amount,
|
||||
state_lastEventNonce
|
||||
);
|
||||
}
|
||||
|
||||
function deployERC20(
|
||||
string memory _cosmosDenom,
|
||||
string memory _name,
|
||||
string memory _symbol,
|
||||
uint8 _decimals
|
||||
) public {
|
||||
// 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.add(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,
|
||||
// How much voting power is needed to approve operations
|
||||
uint256 _powerThreshold,
|
||||
// The validator set
|
||||
address[] memory _validators,
|
||||
uint256[] memory _powers
|
||||
) public {
|
||||
// CHECKS
|
||||
|
||||
// Check that validators, powers, and signatures (v,r,s) set is well-formed
|
||||
require(_validators.length == _powers.length, "Malformed current validator set");
|
||||
|
||||
// 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 > _powerThreshold) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
require(
|
||||
cumulativePower > _powerThreshold,
|
||||
"Submitted validator set signatures do not have enough power."
|
||||
);
|
||||
|
||||
bytes32 newCheckpoint = makeCheckpoint(_validators, _powers, 0, _gravityId);
|
||||
|
||||
// ACTIONS
|
||||
|
||||
state_gravityId = _gravityId;
|
||||
state_powerThreshold = _powerThreshold;
|
||||
state_lastValsetCheckpoint = newCheckpoint;
|
||||
|
||||
// LOGS
|
||||
|
||||
emit ValsetUpdatedEvent(state_lastValsetNonce, state_lastEventNonce, _validators, _powers);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
require("@nomiclabs/hardhat-etherscan");
|
||||
require("@nomiclabs/hardhat-truffle5");
|
||||
require("@nomiclabs/hardhat-web3");
|
||||
require('dotenv').config({ path: require('find-config')('.env') });
|
||||
|
||||
/**
|
||||
* @type import('hardhat/config').HardhatUserConfig
|
||||
*/
|
||||
module.exports = {
|
||||
solidity: {
|
||||
version: "0.6.6",
|
||||
settings: {
|
||||
optimizer: {
|
||||
enabled: true
|
||||
}
|
||||
} },
|
||||
paths: {
|
||||
artifacts: "./artifacts/contracts"
|
||||
},
|
||||
networks: {
|
||||
// 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"
|
||||
// },
|
||||
},
|
||||
etherscan: {
|
||||
// Your API key for Etherscan
|
||||
// Obtain one at https://etherscan.io/
|
||||
apiKey: process.env.ETHERSCAN_API_KEY
|
||||
}
|
||||
};
|
||||
+20391
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
||||
"@nomiclabs/hardhat-etherscan": "^2.1.6",
|
||||
"@nomiclabs/hardhat-waffle": "^2.0.1",
|
||||
"chai": "^4.3.4",
|
||||
"ethereum-waffle": "^3.4.0",
|
||||
"ethers": "^5.4.7",
|
||||
"hardhat": "^2.6.4",
|
||||
"solidity-coverage": "^0.7.17"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nomiclabs/hardhat-truffle5": "^2.0.2",
|
||||
"@nomiclabs/hardhat-web3": "^2.0.0",
|
||||
"@openzeppelin/contracts": "^4.4.1",
|
||||
"@openzeppelin/test-helpers": "^0.5.15",
|
||||
"dotenv": "^10.0.0",
|
||||
"find-config": "^1.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
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('Gravity');
|
||||
const CosmosToken = artifacts.require('CosmosERC20');
|
||||
|
||||
|
||||
contract('BandwidthGenerator', (accounts) => {
|
||||
let bandwidthGenerator;
|
||||
let gravity;
|
||||
let erc20token;
|
||||
let owner = accounts[0];
|
||||
let user = accounts[1];
|
||||
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,
|
||||
1,
|
||||
[owner],
|
||||
[10]
|
||||
);
|
||||
|
||||
// deploy erc20 NYM from bridge
|
||||
await gravity.deployERC20(
|
||||
'eNYM',
|
||||
'NYMERC20',
|
||||
'NYM',
|
||||
18
|
||||
);
|
||||
|
||||
// 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());
|
||||
});
|
||||
});
|
||||
|
||||
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("", 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],
|
||||
constants.ZERO_BYTES32,
|
||||
{ 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: constants.ZERO_BYTES32
|
||||
});
|
||||
|
||||
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: constants.ZERO_BYTES32,
|
||||
_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],
|
||||
constants.ZERO_BYTES32,
|
||||
{ from: user }
|
||||
);
|
||||
|
||||
let newexpectedBandwidthInMB = ((11500000000000000000*initialRatio)/10**18);
|
||||
|
||||
await expectEvent.inTransaction(tx.tx, bandwidthGenerator, 'BBCredentialPurchased', {
|
||||
Bandwidth: newexpectedBandwidthInMB.toString(),
|
||||
VerificationKey: '15',
|
||||
SignedVerificationKey: '0x39530a00eae2a5aac8144209ccac917ae56bf4a9589544cb0020f92fee35a3ba39530a00eae2a5aac8144209ccac917ae56bf4a9589544cb0020f92fee35a3ba',
|
||||
CosmosRecipient: constants.ZERO_BYTES32
|
||||
});
|
||||
|
||||
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: constants.ZERO_BYTES32,
|
||||
_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],
|
||||
constants.ZERO_BYTES32,
|
||||
{ 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],
|
||||
constants.ZERO_BYTES32,
|
||||
{ from: user }
|
||||
);
|
||||
|
||||
let expectedBandwidthInMB = ((oneToken/10**18)*newRatio);
|
||||
|
||||
await expectEvent.inTransaction(tx.tx, bandwidthGenerator, 'BBCredentialPurchased', {
|
||||
Bandwidth: expectedBandwidthInMB.toString(),
|
||||
VerificationKey: '15',
|
||||
SignedVerificationKey: '0x39530a00eae2a5aac8144209ccac917ae56bf4a9589544cb0020f92fee35a3ba39530a00eae2a5aac8144209ccac917ae56bf4a9589544cb0020f92fee35a3ba',
|
||||
CosmosRecipient: constants.ZERO_BYTES32
|
||||
});
|
||||
|
||||
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: constants.ZERO_BYTES32,
|
||||
_amount: oneToken
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -15,17 +15,13 @@ exclude = [
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[features]
|
||||
# for more explicit tests, cargo test --features=backtraces
|
||||
backtraces = ["cosmwasm-std/backtraces"]
|
||||
|
||||
[dependencies]
|
||||
mixnet-contract = { path = "../../common/mixnet-contract" }
|
||||
config = { path = "../../common/config"}
|
||||
vesting-contract = { path = "../vesting" }
|
||||
|
||||
cosmwasm-std = "1.0.0-beta2"
|
||||
cosmwasm-storage = "1.0.0-beta2"
|
||||
cosmwasm-std = "1.0.0-beta3"
|
||||
cosmwasm-storage = "1.0.0-beta3"
|
||||
cw-storage-plus = "0.10.3"
|
||||
|
||||
bs58 = "0.4.0"
|
||||
@@ -34,7 +30,7 @@ serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
thiserror = { version = "1.0.23" }
|
||||
|
||||
[dev-dependencies]
|
||||
cosmwasm-schema = "1.0.0-beta2"
|
||||
cosmwasm-schema = "1.0.0-beta3"
|
||||
fixed = "1.1"
|
||||
rand_chacha = "0.2"
|
||||
rand = "0.7"
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# stable
|
||||
newline_style = "unix"
|
||||
hard_tabs = false
|
||||
tab_spaces = 4
|
||||
|
||||
# unstable... should we require `rustup run nightly cargo fmt` ?
|
||||
# or just update the style guide when they are stable?
|
||||
#fn_single_line = true
|
||||
#format_code_in_doc_comments = true
|
||||
#overflow_delimited_expr = true
|
||||
#reorder_impl_items = true
|
||||
#struct_field_align_threshold = 20
|
||||
#struct_lit_single_line = true
|
||||
#report_todo = "Always"
|
||||
|
||||
@@ -282,14 +282,13 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, Cont
|
||||
}
|
||||
#[entry_point]
|
||||
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
todo!("ACTIVE_STATE_WORK_FACTOR to State");
|
||||
// Ok(Default::default())
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::support::tests::test_helpers;
|
||||
use crate::support::tests;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
|
||||
use cosmwasm_std::{coins, from_binary};
|
||||
@@ -323,7 +322,7 @@ pub mod tests {
|
||||
// Contract balance should match what we initialized it as
|
||||
assert_eq!(
|
||||
coins(0, DENOM),
|
||||
test_helpers::query_contract_balance(env.contract.address, deps)
|
||||
tests::queries::query_contract_balance(env.contract.address, deps)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,6 +220,7 @@ pub(crate) fn _try_remove_delegation_from_mixnode(
|
||||
mod tests {
|
||||
use cosmwasm_std::coins;
|
||||
|
||||
use crate::support::tests;
|
||||
use crate::support::tests::test_helpers;
|
||||
|
||||
use super::storage;
|
||||
@@ -280,7 +281,6 @@ mod tests {
|
||||
mod mix_stake_delegation {
|
||||
use super::*;
|
||||
use crate::mixnodes::transactions::try_remove_mixnode;
|
||||
use crate::support::tests::test_helpers::good_mixnode_bond;
|
||||
use cosmwasm_std::coin;
|
||||
use cosmwasm_std::testing::mock_env;
|
||||
use cosmwasm_std::testing::mock_info;
|
||||
@@ -306,8 +306,11 @@ mod tests {
|
||||
fn succeeds_for_existing_node() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
let identity =
|
||||
test_helpers::add_mixnode(mixnode_owner, good_mixnode_bond(), deps.as_mut());
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
let delegation = coin(123, DENOM);
|
||||
assert!(try_delegate_to_mixnode(
|
||||
@@ -344,8 +347,11 @@ mod tests {
|
||||
fn fails_if_node_unbonded() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
let identity =
|
||||
test_helpers::add_mixnode(mixnode_owner, good_mixnode_bond(), deps.as_mut());
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
try_remove_mixnode(deps.as_mut(), mock_info(mixnode_owner, &[])).unwrap();
|
||||
assert_eq!(
|
||||
@@ -365,10 +371,17 @@ mod tests {
|
||||
fn succeeds_if_node_rebonded() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
test_helpers::add_mixnode(mixnode_owner, good_mixnode_bond(), deps.as_mut());
|
||||
test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
try_remove_mixnode(deps.as_mut(), mock_info(mixnode_owner, &[])).unwrap();
|
||||
let identity =
|
||||
test_helpers::add_mixnode(mixnode_owner, good_mixnode_bond(), deps.as_mut());
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation = coin(123, DENOM);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
assert!(try_delegate_to_mixnode(
|
||||
@@ -405,8 +418,11 @@ mod tests {
|
||||
fn is_possible_for_an_already_delegated_node() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
let identity =
|
||||
test_helpers::add_mixnode(mixnode_owner, good_mixnode_bond(), deps.as_mut());
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
let delegation1 = coin(100, DENOM);
|
||||
let delegation2 = coin(50, DENOM);
|
||||
@@ -451,8 +467,11 @@ mod tests {
|
||||
fn block_height_is_updated_on_new_delegation() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
let identity =
|
||||
test_helpers::add_mixnode(mixnode_owner, good_mixnode_bond(), deps.as_mut());
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
let delegation = coin(100, DENOM);
|
||||
let env1 = mock_env();
|
||||
@@ -493,8 +512,11 @@ mod tests {
|
||||
fn block_height_is_not_updated_on_different_delegator() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
let identity =
|
||||
test_helpers::add_mixnode(mixnode_owner, good_mixnode_bond(), deps.as_mut());
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner1 = Addr::unchecked("sender1");
|
||||
let delegation_owner2 = Addr::unchecked("sender2");
|
||||
let delegation1 = coin(100, DENOM);
|
||||
@@ -545,8 +567,11 @@ mod tests {
|
||||
fn is_disallowed_for_already_delegated_node_if_it_unbonded() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
let identity =
|
||||
test_helpers::add_mixnode(mixnode_owner, good_mixnode_bond(), deps.as_mut());
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
@@ -574,10 +599,16 @@ mod tests {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner1 = "bob";
|
||||
let mixnode_owner2 = "fred";
|
||||
let identity1 =
|
||||
test_helpers::add_mixnode(mixnode_owner1, good_mixnode_bond(), deps.as_mut());
|
||||
let identity2 =
|
||||
test_helpers::add_mixnode(mixnode_owner2, good_mixnode_bond(), deps.as_mut());
|
||||
let identity1 = test_helpers::add_mixnode(
|
||||
mixnode_owner1,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let identity2 = test_helpers::add_mixnode(
|
||||
mixnode_owner2,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
assert!(try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
@@ -624,8 +655,11 @@ mod tests {
|
||||
fn is_allowed_by_multiple_users() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
let identity =
|
||||
test_helpers::add_mixnode(mixnode_owner, good_mixnode_bond(), deps.as_mut());
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation1 = coin(123, DENOM);
|
||||
let delegation2 = coin(234, DENOM);
|
||||
assert!(try_delegate_to_mixnode(
|
||||
@@ -655,8 +689,11 @@ mod tests {
|
||||
fn delegation_is_not_removed_if_node_unbonded() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
let identity =
|
||||
test_helpers::add_mixnode(mixnode_owner, good_mixnode_bond(), deps.as_mut());
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
let delegation_amount = coin(100, DENOM);
|
||||
try_delegate_to_mixnode(
|
||||
@@ -692,7 +729,7 @@ mod tests {
|
||||
use cosmwasm_std::Uint128;
|
||||
|
||||
use crate::mixnodes::transactions::try_remove_mixnode;
|
||||
use crate::support::tests::test_helpers::good_mixnode_bond;
|
||||
use crate::support::tests;
|
||||
|
||||
use super::storage;
|
||||
use super::*;
|
||||
@@ -701,8 +738,11 @@ mod tests {
|
||||
fn fails_if_delegation_never_existed() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
let identity =
|
||||
test_helpers::add_mixnode(mixnode_owner, good_mixnode_bond(), deps.as_mut());
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
assert_eq!(
|
||||
Err(ContractError::NoMixnodeDelegationFound {
|
||||
@@ -721,8 +761,11 @@ mod tests {
|
||||
fn succeeds_if_delegation_existed() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
let identity =
|
||||
test_helpers::add_mixnode(mixnode_owner, good_mixnode_bond(), deps.as_mut());
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
@@ -763,8 +806,11 @@ mod tests {
|
||||
fn succeeds_if_delegation_existed_even_if_node_unbonded() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
let identity =
|
||||
test_helpers::add_mixnode(mixnode_owner, good_mixnode_bond(), deps.as_mut());
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
@@ -795,8 +841,11 @@ mod tests {
|
||||
fn total_delegation_is_preserved_if_only_some_undelegate() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
let identity =
|
||||
test_helpers::add_mixnode(mixnode_owner, good_mixnode_bond(), deps.as_mut());
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner1 = Addr::unchecked("sender1");
|
||||
let delegation_owner2 = Addr::unchecked("sender2");
|
||||
let delegation1 = coin(123, DENOM);
|
||||
|
||||
@@ -50,6 +50,7 @@ pub(crate) fn query_owns_gateway(
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
use crate::contract::execute;
|
||||
use crate::support::tests;
|
||||
use crate::support::tests::test_helpers;
|
||||
use cosmwasm_std::testing::{mock_env, mock_info};
|
||||
|
||||
@@ -66,7 +67,7 @@ pub(crate) mod tests {
|
||||
let limit = 2;
|
||||
for n in 0..1000 {
|
||||
let key = format!("bond{}", n);
|
||||
test_helpers::add_gateway(&key, test_helpers::good_gateway_bond(), deps.as_mut());
|
||||
test_helpers::add_gateway(&key, tests::fixtures::good_gateway_pledge(), deps.as_mut());
|
||||
}
|
||||
|
||||
let page1 = query_gateways_paged(deps.as_ref(), None, Option::from(limit)).unwrap();
|
||||
@@ -78,7 +79,7 @@ pub(crate) mod tests {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
for n in 0..1000 {
|
||||
let key = format!("bond{}", n);
|
||||
test_helpers::add_gateway(&key, test_helpers::good_gateway_bond(), deps.as_mut());
|
||||
test_helpers::add_gateway(&key, tests::fixtures::good_gateway_pledge(), deps.as_mut());
|
||||
}
|
||||
|
||||
// query without explicitly setting a limit
|
||||
@@ -92,7 +93,7 @@ pub(crate) mod tests {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
for n in 0..1000 {
|
||||
let key = format!("bond{}", n);
|
||||
test_helpers::add_gateway(&key, test_helpers::good_gateway_bond(), deps.as_mut());
|
||||
test_helpers::add_gateway(&key, tests::fixtures::good_gateway_pledge(), deps.as_mut());
|
||||
}
|
||||
|
||||
// query with a crazily high limit in an attempt to use too many resources
|
||||
@@ -111,7 +112,7 @@ pub(crate) mod tests {
|
||||
let mut exec_data = (0..4)
|
||||
.map(|i| {
|
||||
let sender = format!("nym-addr{}", i);
|
||||
let (msg, identity) = test_helpers::valid_bond_gateway_msg(&sender);
|
||||
let (msg, identity) = tests::messages::valid_bond_gateway_msg(&sender);
|
||||
(msg, (sender, identity))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@@ -122,7 +123,7 @@ pub(crate) mod tests {
|
||||
|
||||
let info = mock_info(
|
||||
&sender_identities[0].0.clone(),
|
||||
&test_helpers::good_gateway_bond(),
|
||||
&tests::fixtures::good_gateway_pledge(),
|
||||
);
|
||||
execute(deps.as_mut(), mock_env(), info, messages[0].clone()).unwrap();
|
||||
|
||||
@@ -135,7 +136,7 @@ pub(crate) mod tests {
|
||||
// save another
|
||||
let info = mock_info(
|
||||
&sender_identities[1].0.clone(),
|
||||
&test_helpers::good_gateway_bond(),
|
||||
&tests::fixtures::good_gateway_pledge(),
|
||||
);
|
||||
execute(deps.as_mut(), mock_env(), info, messages[1].clone()).unwrap();
|
||||
|
||||
@@ -145,7 +146,7 @@ pub(crate) mod tests {
|
||||
|
||||
let info = mock_info(
|
||||
&sender_identities[2].0.clone(),
|
||||
&test_helpers::good_gateway_bond(),
|
||||
&tests::fixtures::good_gateway_pledge(),
|
||||
);
|
||||
execute(deps.as_mut(), mock_env(), info, messages[2].clone()).unwrap();
|
||||
|
||||
@@ -167,7 +168,7 @@ pub(crate) mod tests {
|
||||
// save another one
|
||||
let info = mock_info(
|
||||
&sender_identities[3].0.clone(),
|
||||
&test_helpers::good_gateway_bond(),
|
||||
&tests::fixtures::good_gateway_pledge(),
|
||||
);
|
||||
execute(deps.as_mut(), mock_env(), info, messages[3].clone()).unwrap();
|
||||
|
||||
@@ -191,13 +192,17 @@ pub(crate) mod tests {
|
||||
assert!(res.gateway.is_none());
|
||||
|
||||
// mixnode was added to "bob", "fred" still does not own one
|
||||
test_helpers::add_gateway("bob", test_helpers::good_gateway_bond(), deps.as_mut());
|
||||
test_helpers::add_gateway("bob", tests::fixtures::good_gateway_pledge(), deps.as_mut());
|
||||
|
||||
let res = query_owns_gateway(deps.as_ref(), "fred".to_string()).unwrap();
|
||||
assert!(res.gateway.is_none());
|
||||
|
||||
// "fred" now owns a gateway!
|
||||
test_helpers::add_gateway("fred", test_helpers::good_gateway_bond(), deps.as_mut());
|
||||
test_helpers::add_gateway(
|
||||
"fred",
|
||||
tests::fixtures::good_gateway_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
let res = query_owns_gateway(deps.as_ref(), "fred".to_string()).unwrap();
|
||||
assert!(res.gateway.is_some());
|
||||
|
||||
@@ -35,7 +35,7 @@ pub(crate) fn gateways<'a>() -> IndexedMap<'a, IdentityKeyRef<'a>, GatewayBond,
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::storage;
|
||||
use crate::support::tests::test_helpers;
|
||||
use crate::support::tests;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::MockStorage;
|
||||
use cosmwasm_std::StdResult;
|
||||
@@ -57,8 +57,8 @@ mod tests {
|
||||
#[test]
|
||||
fn gateway_single_read_retrieval() {
|
||||
let mut storage = MockStorage::new();
|
||||
let bond1 = test_helpers::gateway_bond_fixture("owner1");
|
||||
let bond2 = test_helpers::gateway_bond_fixture("owner2");
|
||||
let bond1 = tests::fixtures::gateway_bond_fixture("owner1");
|
||||
let bond2 = tests::fixtures::gateway_bond_fixture("owner2");
|
||||
storage::gateways()
|
||||
.save(&mut storage, "bond1", &bond1)
|
||||
.unwrap();
|
||||
@@ -91,7 +91,7 @@ mod tests {
|
||||
block_height: 12_345,
|
||||
gateway: Gateway {
|
||||
identity_key: node_identity.clone(),
|
||||
..test_helpers::gateway_fixture()
|
||||
..tests::fixtures::gateway_fixture()
|
||||
},
|
||||
proxy: None,
|
||||
};
|
||||
|
||||
@@ -209,6 +209,7 @@ pub mod tests {
|
||||
use crate::contract::{execute, query, INITIAL_GATEWAY_PLEDGE};
|
||||
use crate::error::ContractError;
|
||||
use crate::gateways::transactions::validate_gateway_pledge;
|
||||
use crate::support::tests;
|
||||
use crate::support::tests::test_helpers;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::attr;
|
||||
@@ -225,7 +226,7 @@ pub mod tests {
|
||||
// if we fail validation (by say not sending enough funds
|
||||
let insufficient_bond = Into::<u128>::into(INITIAL_GATEWAY_PLEDGE) - 1;
|
||||
let info = mock_info("anyone", &coins(insufficient_bond, DENOM));
|
||||
let (msg, _) = test_helpers::valid_bond_gateway_msg("anyone");
|
||||
let (msg, _) = tests::messages::valid_bond_gateway_msg("anyone");
|
||||
|
||||
// we are informed that we didn't send enough funds
|
||||
let result = execute(deps.as_mut(), mock_env(), info, msg);
|
||||
@@ -251,8 +252,8 @@ pub mod tests {
|
||||
assert_eq!(0, page.nodes.len());
|
||||
|
||||
// if we send enough funds
|
||||
let info = mock_info("anyone", &test_helpers::good_gateway_bond());
|
||||
let (msg, identity) = test_helpers::valid_bond_gateway_msg("anyone");
|
||||
let info = mock_info("anyone", &tests::fixtures::good_gateway_pledge());
|
||||
let (msg, identity) = tests::messages::valid_bond_gateway_msg("anyone");
|
||||
|
||||
// we get back a message telling us everything was OK
|
||||
let execute_response = execute(deps.as_mut(), mock_env(), info, msg);
|
||||
@@ -273,18 +274,18 @@ pub mod tests {
|
||||
assert_eq!(
|
||||
&Gateway {
|
||||
identity_key: identity,
|
||||
..test_helpers::gateway_fixture()
|
||||
..tests::fixtures::gateway_fixture()
|
||||
},
|
||||
page.nodes[0].gateway()
|
||||
);
|
||||
|
||||
// if there was already a gateway bonded by particular user
|
||||
let info = mock_info("foomper", &test_helpers::good_gateway_bond());
|
||||
let (msg, _) = test_helpers::valid_bond_gateway_msg("foomper");
|
||||
let info = mock_info("foomper", &tests::fixtures::good_gateway_pledge());
|
||||
let (msg, _) = tests::messages::valid_bond_gateway_msg("foomper");
|
||||
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
|
||||
|
||||
let info = mock_info("foomper", &test_helpers::good_gateway_bond());
|
||||
let (msg, _) = test_helpers::valid_bond_gateway_msg("foomper");
|
||||
let info = mock_info("foomper", &tests::fixtures::good_gateway_pledge());
|
||||
let (msg, _) = tests::messages::valid_bond_gateway_msg("foomper");
|
||||
|
||||
// it fails
|
||||
let execute_response = execute(deps.as_mut(), mock_env(), info, msg);
|
||||
@@ -293,12 +294,12 @@ pub mod tests {
|
||||
// bonding fails if the user already owns a mixnode
|
||||
test_helpers::add_mixnode(
|
||||
"mixnode-owner",
|
||||
test_helpers::good_mixnode_bond(),
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
let info = mock_info("mixnode-owner", &test_helpers::good_gateway_bond());
|
||||
let (msg, _) = test_helpers::valid_bond_gateway_msg("mixnode-owner");
|
||||
let info = mock_info("mixnode-owner", &tests::fixtures::good_gateway_pledge());
|
||||
let (msg, _) = tests::messages::valid_bond_gateway_msg("mixnode-owner");
|
||||
|
||||
let execute_response = execute(deps.as_mut(), mock_env(), info, msg);
|
||||
assert_eq!(execute_response, Err(ContractError::AlreadyOwnsMixnode));
|
||||
@@ -308,8 +309,8 @@ pub mod tests {
|
||||
let msg = ExecuteMsg::UnbondMixnode {};
|
||||
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
|
||||
|
||||
let info = mock_info("mixnode-owner", &test_helpers::good_gateway_bond());
|
||||
let (msg, _) = test_helpers::valid_bond_gateway_msg("mixnode-owner");
|
||||
let info = mock_info("mixnode-owner", &tests::fixtures::good_gateway_pledge());
|
||||
let (msg, _) = tests::messages::valid_bond_gateway_msg("mixnode-owner");
|
||||
|
||||
let execute_response = execute(deps.as_mut(), mock_env(), info, msg);
|
||||
assert!(execute_response.is_ok());
|
||||
@@ -322,7 +323,7 @@ pub mod tests {
|
||||
fn adding_gateway_without_existing_owner() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
|
||||
let info = mock_info("gateway-owner", &test_helpers::good_gateway_bond());
|
||||
let info = mock_info("gateway-owner", &tests::fixtures::good_gateway_pledge());
|
||||
|
||||
// before the execution the node had no associated owner
|
||||
assert!(storage::gateways()
|
||||
@@ -332,7 +333,7 @@ pub mod tests {
|
||||
.unwrap()
|
||||
.is_none());
|
||||
|
||||
let (msg, identity) = test_helpers::valid_bond_gateway_msg("gateway-owner");
|
||||
let (msg, identity) = tests::messages::valid_bond_gateway_msg("gateway-owner");
|
||||
|
||||
// it's all fine, owner is saved
|
||||
let execute_response = execute(deps.as_mut(), mock_env(), info, msg);
|
||||
@@ -357,19 +358,19 @@ pub mod tests {
|
||||
|
||||
let identity = test_helpers::add_gateway(
|
||||
"gateway-owner",
|
||||
test_helpers::good_gateway_bond(),
|
||||
tests::fixtures::good_gateway_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
// request fails giving the existing owner address in the message
|
||||
let info = mock_info(
|
||||
"gateway-owner-pretender",
|
||||
&test_helpers::good_gateway_bond(),
|
||||
&tests::fixtures::good_gateway_pledge(),
|
||||
);
|
||||
let msg = ExecuteMsg::BondGateway {
|
||||
gateway: Gateway {
|
||||
identity_key: identity,
|
||||
..test_helpers::gateway_fixture()
|
||||
..tests::fixtures::gateway_fixture()
|
||||
},
|
||||
owner_signature: "foomp".to_string(),
|
||||
};
|
||||
@@ -389,12 +390,12 @@ pub mod tests {
|
||||
|
||||
test_helpers::add_gateway(
|
||||
"gateway-owner",
|
||||
test_helpers::good_gateway_bond(),
|
||||
tests::fixtures::good_gateway_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
let info = mock_info("gateway-owner", &test_helpers::good_gateway_bond());
|
||||
let (msg, _) = test_helpers::valid_bond_gateway_msg("gateway-owner");
|
||||
let info = mock_info("gateway-owner", &tests::fixtures::good_gateway_pledge());
|
||||
let (msg, _) = tests::messages::valid_bond_gateway_msg("gateway-owner");
|
||||
|
||||
let res = execute(deps.as_mut(), mock_env(), info, msg);
|
||||
assert_eq!(Err(ContractError::AlreadyOwnsGateway), res);
|
||||
@@ -418,7 +419,7 @@ pub mod tests {
|
||||
);
|
||||
|
||||
// let's add a node owned by bob
|
||||
test_helpers::add_gateway("bob", test_helpers::good_gateway_bond(), deps.as_mut());
|
||||
test_helpers::add_gateway("bob", tests::fixtures::good_gateway_pledge(), deps.as_mut());
|
||||
|
||||
// attempt to unbond fred's node, which doesn't exist
|
||||
let info = mock_info("fred", &[]);
|
||||
@@ -432,18 +433,21 @@ pub mod tests {
|
||||
);
|
||||
|
||||
// bob's node is still there
|
||||
let nodes = test_helpers::get_gateways(&mut deps);
|
||||
let nodes = tests::queries::get_gateways(&mut deps);
|
||||
assert_eq!(1, nodes.len());
|
||||
|
||||
let first_node = &nodes[0];
|
||||
assert_eq!(&Addr::unchecked("bob"), first_node.owner());
|
||||
|
||||
// add a node owned by fred
|
||||
let fred_identity =
|
||||
test_helpers::add_gateway("fred", test_helpers::good_gateway_bond(), deps.as_mut());
|
||||
let fred_identity = test_helpers::add_gateway(
|
||||
"fred",
|
||||
tests::fixtures::good_gateway_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
// let's make sure we now have 2 nodes:
|
||||
assert_eq!(2, test_helpers::get_gateways(&mut deps).len());
|
||||
assert_eq!(2, tests::queries::get_gateways(&mut deps).len());
|
||||
|
||||
// unbond fred's node
|
||||
let info = mock_info("fred", &[]);
|
||||
@@ -466,7 +470,7 @@ pub mod tests {
|
||||
// we should see a funds transfer from the contract back to fred
|
||||
let expected_message = BankMsg::Send {
|
||||
to_address: String::from(info.sender),
|
||||
amount: test_helpers::good_gateway_bond(),
|
||||
amount: tests::fixtures::good_gateway_pledge(),
|
||||
};
|
||||
|
||||
// run the executor and check that we got back the correct results
|
||||
@@ -477,7 +481,7 @@ pub mod tests {
|
||||
assert_eq!(remove_fred, expected);
|
||||
|
||||
// only 1 node now exists, owned by bob:
|
||||
let gateway_bonds = test_helpers::get_gateways(&mut deps);
|
||||
let gateway_bonds = tests::queries::get_gateways(&mut deps);
|
||||
assert_eq!(1, gateway_bonds.len());
|
||||
assert_eq!(&Addr::unchecked("bob"), gateway_bonds[0].owner());
|
||||
}
|
||||
@@ -486,8 +490,8 @@ pub mod tests {
|
||||
fn removing_gateway_clears_ownership() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
|
||||
let info = mock_info("gateway-owner", &test_helpers::good_gateway_bond());
|
||||
let (bond_msg, identity) = test_helpers::valid_bond_gateway_msg("gateway-owner");
|
||||
let info = mock_info("gateway-owner", &tests::fixtures::good_gateway_pledge());
|
||||
let (bond_msg, identity) = tests::messages::valid_bond_gateway_msg("gateway-owner");
|
||||
execute(deps.as_mut(), mock_env(), info, bond_msg.clone()).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -515,7 +519,7 @@ pub mod tests {
|
||||
.is_none());
|
||||
|
||||
// and since it's removed, it can be reclaimed
|
||||
let info = mock_info("gateway-owner", &test_helpers::good_gateway_bond());
|
||||
let info = mock_info("gateway-owner", &tests::fixtures::good_gateway_pledge());
|
||||
|
||||
assert!(execute(deps.as_mut(), mock_env(), info, bond_msg).is_ok());
|
||||
assert_eq!(
|
||||
@@ -538,7 +542,7 @@ pub mod tests {
|
||||
assert_eq!(result, Err(ContractError::NoBondFound));
|
||||
|
||||
// you must send at least 100 coins...
|
||||
let mut bond = test_helpers::good_gateway_bond();
|
||||
let mut bond = tests::fixtures::good_gateway_pledge();
|
||||
bond[0].amount = INITIAL_GATEWAY_PLEDGE.checked_sub(Uint128::new(1)).unwrap();
|
||||
let result = validate_gateway_pledge(bond.clone(), INITIAL_GATEWAY_PLEDGE);
|
||||
assert_eq!(
|
||||
@@ -550,18 +554,18 @@ pub mod tests {
|
||||
);
|
||||
|
||||
// more than that is still fine
|
||||
let mut bond = test_helpers::good_gateway_bond();
|
||||
let mut bond = tests::fixtures::good_gateway_pledge();
|
||||
bond[0].amount = INITIAL_GATEWAY_PLEDGE + Uint128::new(1);
|
||||
let result = validate_gateway_pledge(bond.clone(), INITIAL_GATEWAY_PLEDGE);
|
||||
assert!(result.is_ok());
|
||||
|
||||
// it must be sent in the defined denom!
|
||||
let mut bond = test_helpers::good_gateway_bond();
|
||||
let mut bond = tests::fixtures::good_gateway_pledge();
|
||||
bond[0].denom = "baddenom".to_string();
|
||||
let result = validate_gateway_pledge(bond.clone(), INITIAL_GATEWAY_PLEDGE);
|
||||
assert_eq!(result, Err(ContractError::WrongDenom {}));
|
||||
|
||||
let mut bond = test_helpers::good_gateway_bond();
|
||||
let mut bond = tests::fixtures::good_gateway_pledge();
|
||||
bond[0].denom = "foomp".to_string();
|
||||
let result = validate_gateway_pledge(bond.clone(), INITIAL_GATEWAY_PLEDGE);
|
||||
assert_eq!(result, Err(ContractError::WrongDenom {}));
|
||||
|
||||
@@ -64,9 +64,9 @@ pub fn query_owns_mixnode(deps: Deps, address: String) -> StdResult<MixOwnership
|
||||
pub(crate) mod tests {
|
||||
use super::storage;
|
||||
use super::*;
|
||||
use crate::contract::execute;
|
||||
use crate::mixnodes::storage::BOND_PAGE_DEFAULT_LIMIT;
|
||||
use crate::support::tests::test_helpers;
|
||||
use crate::{contract::execute, support::tests};
|
||||
use cosmwasm_std::testing::{mock_env, mock_info};
|
||||
|
||||
#[test]
|
||||
@@ -82,7 +82,7 @@ pub(crate) mod tests {
|
||||
let limit = 2;
|
||||
for n in 0..1000 {
|
||||
let key = format!("bond{}", n);
|
||||
test_helpers::add_mixnode(&key, test_helpers::good_mixnode_bond(), deps.as_mut());
|
||||
test_helpers::add_mixnode(&key, tests::fixtures::good_mixnode_pledge(), deps.as_mut());
|
||||
}
|
||||
|
||||
let page1 = query_mixnodes_paged(deps.as_ref(), None, Option::from(limit)).unwrap();
|
||||
@@ -94,7 +94,7 @@ pub(crate) mod tests {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
for n in 0..1000 {
|
||||
let key = format!("bond{}", n);
|
||||
test_helpers::add_mixnode(&key, test_helpers::good_mixnode_bond(), deps.as_mut());
|
||||
test_helpers::add_mixnode(&key, tests::fixtures::good_mixnode_pledge(), deps.as_mut());
|
||||
}
|
||||
|
||||
// query without explicitly setting a limit
|
||||
@@ -108,7 +108,7 @@ pub(crate) mod tests {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
for n in 0..1000 {
|
||||
let key = format!("bond{}", n);
|
||||
test_helpers::add_mixnode(&key, test_helpers::good_mixnode_bond(), deps.as_mut());
|
||||
test_helpers::add_mixnode(&key, tests::fixtures::good_mixnode_pledge(), deps.as_mut());
|
||||
}
|
||||
|
||||
// query with a crazily high limit in an attempt to use too many resources
|
||||
@@ -127,7 +127,7 @@ pub(crate) mod tests {
|
||||
let mut exec_data = (0..4)
|
||||
.map(|i| {
|
||||
let sender = format!("nym-addr{}", i);
|
||||
let (msg, identity) = test_helpers::valid_bond_mixnode_msg(&sender);
|
||||
let (msg, identity) = tests::messages::valid_bond_mixnode_msg(&sender);
|
||||
(msg, (sender, identity))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@@ -138,7 +138,7 @@ pub(crate) mod tests {
|
||||
|
||||
let info = mock_info(
|
||||
&sender_identities[0].0.clone(),
|
||||
&test_helpers::good_mixnode_bond(),
|
||||
&tests::fixtures::good_mixnode_pledge(),
|
||||
);
|
||||
execute(deps.as_mut(), mock_env(), info, messages[0].clone()).unwrap();
|
||||
|
||||
@@ -151,7 +151,7 @@ pub(crate) mod tests {
|
||||
// save another
|
||||
let info = mock_info(
|
||||
&sender_identities[1].0.clone(),
|
||||
&test_helpers::good_mixnode_bond(),
|
||||
&tests::fixtures::good_mixnode_pledge(),
|
||||
);
|
||||
execute(deps.as_mut(), mock_env(), info, messages[1].clone()).unwrap();
|
||||
|
||||
@@ -161,7 +161,7 @@ pub(crate) mod tests {
|
||||
|
||||
let info = mock_info(
|
||||
&sender_identities[2].0.clone(),
|
||||
&test_helpers::good_mixnode_bond(),
|
||||
&tests::fixtures::good_mixnode_pledge(),
|
||||
);
|
||||
execute(deps.as_mut(), mock_env(), info, messages[2].clone()).unwrap();
|
||||
|
||||
@@ -183,7 +183,7 @@ pub(crate) mod tests {
|
||||
// save another one
|
||||
let info = mock_info(
|
||||
&sender_identities[3].0.clone(),
|
||||
&test_helpers::good_mixnode_bond(),
|
||||
&tests::fixtures::good_mixnode_pledge(),
|
||||
);
|
||||
execute(deps.as_mut(), mock_env(), info, messages[3].clone()).unwrap();
|
||||
|
||||
@@ -207,13 +207,17 @@ pub(crate) mod tests {
|
||||
assert!(res.mixnode.is_none());
|
||||
|
||||
// mixnode was added to "bob", "fred" still does not own one
|
||||
test_helpers::add_mixnode("bob", test_helpers::good_mixnode_bond(), deps.as_mut());
|
||||
test_helpers::add_mixnode("bob", tests::fixtures::good_mixnode_pledge(), deps.as_mut());
|
||||
|
||||
let res = query_owns_mixnode(deps.as_ref(), "fred".to_string()).unwrap();
|
||||
assert!(res.mixnode.is_none());
|
||||
|
||||
// "fred" now owns a mixnode!
|
||||
test_helpers::add_mixnode("fred", test_helpers::good_mixnode_bond(), deps.as_mut());
|
||||
test_helpers::add_mixnode(
|
||||
"fred",
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
let res = query_owns_mixnode(deps.as_ref(), "fred".to_string()).unwrap();
|
||||
assert!(res.mixnode.is_some());
|
||||
|
||||
@@ -137,7 +137,7 @@ pub(crate) fn read_full_mixnode_bond(
|
||||
mod tests {
|
||||
use super::super::storage;
|
||||
use super::*;
|
||||
use crate::support::tests::test_helpers;
|
||||
use crate::support::tests;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::MockStorage;
|
||||
use cosmwasm_std::{coin, Addr, Uint128};
|
||||
@@ -147,8 +147,8 @@ mod tests {
|
||||
#[test]
|
||||
fn mixnode_single_read_retrieval() {
|
||||
let mut storage = MockStorage::new();
|
||||
let bond1 = test_helpers::stored_mixnode_bond_fixture("owner1");
|
||||
let bond2 = test_helpers::stored_mixnode_bond_fixture("owner2");
|
||||
let bond1 = tests::fixtures::stored_mixnode_bond_fixture("owner1");
|
||||
let bond2 = tests::fixtures::stored_mixnode_bond_fixture("owner2");
|
||||
mixnodes().save(&mut storage, "bond1", &bond1).unwrap();
|
||||
mixnodes().save(&mut storage, "bond2", &bond2).unwrap();
|
||||
|
||||
@@ -178,7 +178,7 @@ mod tests {
|
||||
block_height: 12_345,
|
||||
mix_node: MixNode {
|
||||
identity_key: node_identity.clone(),
|
||||
..test_helpers::mix_node_fixture()
|
||||
..tests::fixtures::mix_node_fixture()
|
||||
},
|
||||
profit_margin_percent: None,
|
||||
proxy: None,
|
||||
|
||||
@@ -239,6 +239,7 @@ pub mod tests {
|
||||
use crate::contract::{execute, query, INITIAL_MIXNODE_PLEDGE};
|
||||
use crate::error::ContractError;
|
||||
use crate::mixnodes::transactions::validate_mixnode_pledge;
|
||||
use crate::support::tests;
|
||||
use crate::support::tests::test_helpers;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::attr;
|
||||
@@ -256,7 +257,7 @@ pub mod tests {
|
||||
// if we don't send enough funds
|
||||
let insufficient_bond = Into::<u128>::into(INITIAL_MIXNODE_PLEDGE) - 1;
|
||||
let info = mock_info("anyone", &coins(insufficient_bond, DENOM));
|
||||
let (msg, _) = test_helpers::valid_bond_mixnode_msg("anyone");
|
||||
let (msg, _) = tests::messages::valid_bond_mixnode_msg("anyone");
|
||||
|
||||
// we are informed that we didn't send enough funds
|
||||
let result = execute(deps.as_mut(), mock_env(), info, msg);
|
||||
@@ -282,8 +283,8 @@ pub mod tests {
|
||||
assert_eq!(0, page.nodes.len());
|
||||
|
||||
// if we send enough funds
|
||||
let info = mock_info("anyone", &test_helpers::good_mixnode_bond());
|
||||
let (msg, identity) = test_helpers::valid_bond_mixnode_msg("anyone");
|
||||
let info = mock_info("anyone", &tests::fixtures::good_mixnode_pledge());
|
||||
let (msg, identity) = tests::messages::valid_bond_mixnode_msg("anyone");
|
||||
|
||||
// we get back a message telling us everything was OK
|
||||
let execute_response = execute(deps.as_mut(), mock_env(), info, msg);
|
||||
@@ -304,18 +305,18 @@ pub mod tests {
|
||||
assert_eq!(
|
||||
&MixNode {
|
||||
identity_key: identity,
|
||||
..test_helpers::mix_node_fixture()
|
||||
..tests::fixtures::mix_node_fixture()
|
||||
},
|
||||
page.nodes[0].mix_node()
|
||||
);
|
||||
|
||||
// if there was already a mixnode bonded by particular user
|
||||
let info = mock_info("foomper", &test_helpers::good_mixnode_bond());
|
||||
let (msg, _) = test_helpers::valid_bond_mixnode_msg("foomper");
|
||||
let info = mock_info("foomper", &tests::fixtures::good_mixnode_pledge());
|
||||
let (msg, _) = tests::messages::valid_bond_mixnode_msg("foomper");
|
||||
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
|
||||
|
||||
let info = mock_info("foomper", &test_helpers::good_mixnode_bond());
|
||||
let (msg, _) = test_helpers::valid_bond_mixnode_msg("foomper");
|
||||
let info = mock_info("foomper", &tests::fixtures::good_mixnode_pledge());
|
||||
let (msg, _) = tests::messages::valid_bond_mixnode_msg("foomper");
|
||||
|
||||
// it fails
|
||||
let execute_response = execute(deps.as_mut(), mock_env(), info, msg);
|
||||
@@ -324,12 +325,12 @@ pub mod tests {
|
||||
// bonding fails if the user already owns a gateway
|
||||
test_helpers::add_gateway(
|
||||
"gateway-owner",
|
||||
test_helpers::good_gateway_bond(),
|
||||
tests::fixtures::good_gateway_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
let info = mock_info("gateway-owner", &test_helpers::good_mixnode_bond());
|
||||
let (msg, _) = test_helpers::valid_bond_mixnode_msg("gateway-owner");
|
||||
let info = mock_info("gateway-owner", &tests::fixtures::good_mixnode_pledge());
|
||||
let (msg, _) = tests::messages::valid_bond_mixnode_msg("gateway-owner");
|
||||
|
||||
let execute_response = execute(deps.as_mut(), mock_env(), info, msg);
|
||||
assert_eq!(execute_response, Err(ContractError::AlreadyOwnsGateway));
|
||||
@@ -339,8 +340,8 @@ pub mod tests {
|
||||
let msg = ExecuteMsg::UnbondGateway {};
|
||||
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
|
||||
|
||||
let info = mock_info("gateway-owner", &test_helpers::good_mixnode_bond());
|
||||
let (msg, _) = test_helpers::valid_bond_mixnode_msg("gateway-owner");
|
||||
let info = mock_info("gateway-owner", &tests::fixtures::good_mixnode_pledge());
|
||||
let (msg, _) = tests::messages::valid_bond_mixnode_msg("gateway-owner");
|
||||
|
||||
let execute_response = execute(deps.as_mut(), mock_env(), info, msg);
|
||||
assert!(execute_response.is_ok());
|
||||
@@ -350,10 +351,10 @@ pub mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn adding_mixnode_without_existing_owner() {
|
||||
fn adding_mixnode_without_existing_owner_succeeds() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
|
||||
let info = mock_info("mix-owner", &test_helpers::good_mixnode_bond());
|
||||
let info = mock_info("mix-owner", &tests::fixtures::good_mixnode_pledge());
|
||||
|
||||
// before the execution the node had no associated owner
|
||||
assert!(storage::mixnodes()
|
||||
@@ -363,7 +364,7 @@ pub mod tests {
|
||||
.unwrap()
|
||||
.is_none());
|
||||
|
||||
let (msg, identity) = test_helpers::valid_bond_mixnode_msg("mix-owner");
|
||||
let (msg, identity) = tests::messages::valid_bond_mixnode_msg("mix-owner");
|
||||
|
||||
// it's all fine, owner is saved
|
||||
let execute_response = execute(deps.as_mut(), mock_env(), info, msg);
|
||||
@@ -383,21 +384,24 @@ pub mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn adding_mixnode_with_existing_owner() {
|
||||
fn adding_mixnode_with_existing_owner_fails() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
|
||||
let identity = test_helpers::add_mixnode(
|
||||
"mix-owner",
|
||||
test_helpers::good_mixnode_bond(),
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
// request fails giving the existing owner address in the message
|
||||
let info = mock_info("mix-owner-pretender", &test_helpers::good_mixnode_bond());
|
||||
let info = mock_info(
|
||||
"mix-owner-pretender",
|
||||
&tests::fixtures::good_mixnode_pledge(),
|
||||
);
|
||||
let msg = ExecuteMsg::BondMixnode {
|
||||
mix_node: MixNode {
|
||||
identity_key: identity,
|
||||
..test_helpers::mix_node_fixture()
|
||||
..tests::fixtures::mix_node_fixture()
|
||||
},
|
||||
owner_signature: "foomp".to_string(),
|
||||
};
|
||||
@@ -412,17 +416,17 @@ pub mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn adding_mixnode_with_existing_unchanged_owner() {
|
||||
fn adding_mixnode_with_existing_unchanged_owner_fails() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
|
||||
test_helpers::add_mixnode(
|
||||
"mix-owner",
|
||||
test_helpers::good_mixnode_bond(),
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
let info = mock_info("mix-owner", &test_helpers::good_mixnode_bond());
|
||||
let (msg, _) = test_helpers::valid_bond_mixnode_msg("mix-owner");
|
||||
let info = mock_info("mix-owner", &tests::fixtures::good_mixnode_pledge());
|
||||
let (msg, _) = tests::messages::valid_bond_mixnode_msg("mix-owner");
|
||||
|
||||
let res = execute(deps.as_mut(), mock_env(), info, msg);
|
||||
assert_eq!(Err(ContractError::AlreadyOwnsMixnode), res);
|
||||
@@ -437,7 +441,11 @@ pub mod tests {
|
||||
mixnet_params_storage::LAYERS.load(&deps.storage).unwrap(),
|
||||
);
|
||||
|
||||
test_helpers::add_mixnode("mix1", test_helpers::good_mixnode_bond(), deps.as_mut());
|
||||
test_helpers::add_mixnode(
|
||||
"mix1",
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
LayerDistribution {
|
||||
@@ -466,7 +474,7 @@ pub mod tests {
|
||||
);
|
||||
|
||||
// let's add a node owned by bob
|
||||
test_helpers::add_mixnode("bob", test_helpers::good_mixnode_bond(), deps.as_mut());
|
||||
test_helpers::add_mixnode("bob", tests::fixtures::good_mixnode_pledge(), deps.as_mut());
|
||||
|
||||
// attempt to un-register fred's node, which doesn't exist
|
||||
let info = mock_info("fred", &[]);
|
||||
@@ -480,16 +488,19 @@ pub mod tests {
|
||||
);
|
||||
|
||||
// bob's node is still there
|
||||
let nodes = test_helpers::get_mix_nodes(&mut deps);
|
||||
let nodes = tests::queries::get_mix_nodes(&mut deps);
|
||||
assert_eq!(1, nodes.len());
|
||||
assert_eq!("bob", nodes[0].owner().clone());
|
||||
|
||||
// add a node owned by fred
|
||||
let fred_identity =
|
||||
test_helpers::add_mixnode("fred", test_helpers::good_mixnode_bond(), deps.as_mut());
|
||||
let fred_identity = test_helpers::add_mixnode(
|
||||
"fred",
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
// let's make sure we now have 2 nodes:
|
||||
assert_eq!(2, test_helpers::get_mix_nodes(&mut deps).len());
|
||||
assert_eq!(2, tests::queries::get_mix_nodes(&mut deps).len());
|
||||
|
||||
// un-register fred's node
|
||||
let info = mock_info("fred", &[]);
|
||||
@@ -511,7 +522,7 @@ pub mod tests {
|
||||
// we should see a funds transfer from the contract back to fred
|
||||
let expected_message = BankMsg::Send {
|
||||
to_address: String::from(info.sender),
|
||||
amount: test_helpers::good_mixnode_bond(),
|
||||
amount: tests::fixtures::good_mixnode_pledge(),
|
||||
};
|
||||
|
||||
// run the executor and check that we got back the correct results
|
||||
@@ -522,7 +533,7 @@ pub mod tests {
|
||||
assert_eq!(remove_fred, expected);
|
||||
|
||||
// only 1 node now exists, owned by bob:
|
||||
let mix_node_bonds = test_helpers::get_mix_nodes(&mut deps);
|
||||
let mix_node_bonds = tests::queries::get_mix_nodes(&mut deps);
|
||||
assert_eq!(1, mix_node_bonds.len());
|
||||
assert_eq!(&Addr::unchecked("bob"), mix_node_bonds[0].owner());
|
||||
}
|
||||
@@ -531,8 +542,8 @@ pub mod tests {
|
||||
fn removing_mixnode_clears_ownership() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
|
||||
let info = mock_info("mix-owner", &test_helpers::good_mixnode_bond());
|
||||
let (bond_msg, identity) = test_helpers::valid_bond_mixnode_msg("mix-owner");
|
||||
let info = mock_info("mix-owner", &tests::fixtures::good_mixnode_pledge());
|
||||
let (bond_msg, identity) = tests::messages::valid_bond_mixnode_msg("mix-owner");
|
||||
execute(deps.as_mut(), mock_env(), info, bond_msg.clone()).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -560,7 +571,7 @@ pub mod tests {
|
||||
.is_none());
|
||||
|
||||
// and since it's removed, it can be reclaimed
|
||||
let info = mock_info("mix-owner", &test_helpers::good_mixnode_bond());
|
||||
let info = mock_info("mix-owner", &tests::fixtures::good_mixnode_pledge());
|
||||
|
||||
assert!(execute(deps.as_mut(), mock_env(), info, bond_msg).is_ok());
|
||||
assert_eq!(
|
||||
@@ -583,7 +594,7 @@ pub mod tests {
|
||||
assert_eq!(result, Err(ContractError::NoBondFound));
|
||||
|
||||
// you must send at least 100 coins...
|
||||
let mut bond = test_helpers::good_mixnode_bond();
|
||||
let mut bond = tests::fixtures::good_mixnode_pledge();
|
||||
bond[0].amount = INITIAL_MIXNODE_PLEDGE.checked_sub(Uint128::new(1)).unwrap();
|
||||
let result = validate_mixnode_pledge(bond.clone(), INITIAL_MIXNODE_PLEDGE);
|
||||
assert_eq!(
|
||||
@@ -595,18 +606,18 @@ pub mod tests {
|
||||
);
|
||||
|
||||
// more than that is still fine
|
||||
let mut bond = test_helpers::good_mixnode_bond();
|
||||
let mut bond = tests::fixtures::good_mixnode_pledge();
|
||||
bond[0].amount = INITIAL_MIXNODE_PLEDGE + Uint128::new(1);
|
||||
let result = validate_mixnode_pledge(bond.clone(), INITIAL_MIXNODE_PLEDGE);
|
||||
assert!(result.is_ok());
|
||||
|
||||
// it must be sent in the defined denom!
|
||||
let mut bond = test_helpers::good_mixnode_bond();
|
||||
let mut bond = tests::fixtures::good_mixnode_pledge();
|
||||
bond[0].denom = "baddenom".to_string();
|
||||
let result = validate_mixnode_pledge(bond.clone(), INITIAL_MIXNODE_PLEDGE);
|
||||
assert_eq!(result, Err(ContractError::WrongDenom {}));
|
||||
|
||||
let mut bond = test_helpers::good_mixnode_bond();
|
||||
let mut bond = tests::fixtures::good_mixnode_pledge();
|
||||
bond[0].denom = "foomp".to_string();
|
||||
let result = validate_mixnode_pledge(bond.clone(), INITIAL_MIXNODE_PLEDGE);
|
||||
assert_eq!(result, Err(ContractError::WrongDenom {}));
|
||||
@@ -615,12 +626,15 @@ pub mod tests {
|
||||
#[test]
|
||||
fn choose_layer_mix_node() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let alice_identity =
|
||||
test_helpers::add_mixnode("alice", test_helpers::good_mixnode_bond(), deps.as_mut());
|
||||
let alice_identity = test_helpers::add_mixnode(
|
||||
"alice",
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let bob_identity =
|
||||
test_helpers::add_mixnode("bob", test_helpers::good_mixnode_bond(), deps.as_mut());
|
||||
test_helpers::add_mixnode("bob", tests::fixtures::good_mixnode_pledge(), deps.as_mut());
|
||||
|
||||
let bonded_mix_nodes = test_helpers::get_mix_nodes(&mut deps);
|
||||
let bonded_mix_nodes = tests::queries::get_mix_nodes(&mut deps);
|
||||
let alice_node = bonded_mix_nodes
|
||||
.iter()
|
||||
.find(|m| m.owner == "alice")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user