Compare commits

...

58 Commits

Author SHA1 Message Date
Dave Hrycyszyn c3d908642a Merge branch 'release/v1.12.1' of github.com:nymtech/nym into release/v0.12.1 2021-12-23 13:15:02 +00:00
Dave Hrycyszyn f84bac18a1 Changelog for 0.12.1 2021-12-23 13:14:51 +00:00
Bogdan-Ștefan Neacșu 0cef1abbb2 Update mixnode version 2021-12-23 15:05:11 +02:00
Tommy Verrall 1871c6b2e3 Merge pull request #998 from nymtech/feature/wallet-update-version
Update wallet version
2021-12-23 10:01:13 +00:00
Tommy Verrall 75ad2a113f Update wallet version
- keep all the binaries aligned
2021-12-23 10:00:13 +00:00
Bogdan-Ștefan Neacşu 1d1496aa49 Make the separation between testnet-mode and erc20 bandwidth mode clearer (#994)
* Make the separation between testnet-mode and erc20 bandwidth mode more clear

* Update Cargo.toml

* Remove eth bw from native client under a feature flag

* Remove eth bw from socks5 client under a feature flag

* Remove eth bw from gateway under a feature flag

* Update gateway version

* Fix coconut build warnings
2021-12-23 11:55:01 +02:00
Tommy Verrall a48e06fe51 Fix wallet build instructions (#997)
* Fix wallet build instructions

- Supplying the .env file requirement

* re-added the admin - address
2021-12-23 11:54:34 +02:00
Drazen Urch 614b99a36e Differentiate staking and ownership (#961)
* Differentiate staking and ownership

* Ownership transfer, tests

* Consistent random keys

* Improve account tests

* Update Cargo.lock

* Make everybody happy

Co-authored-by: Drazen Urch <durch@users.noreply.guthub.com>
2021-12-22 13:22:46 +01:00
dependabot[bot] d8cb6199e0 Bump @openzeppelin/contracts in /contracts/basic-bandwidth-generation (#983)
Bumps [@openzeppelin/contracts](https://github.com/OpenZeppelin/openzeppelin-contracts) from 3.4.0 to 4.4.1.
- [Release notes](https://github.com/OpenZeppelin/openzeppelin-contracts/releases)
- [Changelog](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md)
- [Commits](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v3.4.0...v4.4.1)

---
updated-dependencies:
- dependency-name: "@openzeppelin/contracts"
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-22 11:42:37 +01:00
Tommy Verrall 424c1695b3 Merge pull request #991 from nymtech/feature/change-wallet-version
Update wallet to align with versioning on nodes and gateways
2021-12-21 11:39:12 +00:00
Tommy Verrall 3ceb6d711f Update wallet to align with versioning on nodes and gateways 2021-12-21 11:38:13 +00:00
Dave Hrycyszyn 23d2279549 Merge branch 'develop' of github.com:nymtech/nym into develop 2021-12-21 11:21:28 +00:00
Dave Hrycyszyn 84d1909b18 Changelog for v0.12.0 2021-12-21 11:21:20 +00:00
Dave Hrycyszyn 29a22e95e6 Adding github_changelog_generator config files 2021-12-21 11:21:00 +00:00
Jess 0e0f9ed270 Update README.md 2021-12-21 10:34:29 +00:00
Jess 4c0c0bc49f Update README.md 2021-12-21 10:33:32 +00:00
Tommy Verrall ea350ef7dd Merge pull request #990 from nymtech/feature/fix-success-text
Fix success view messages.
2021-12-21 10:16:41 +00:00
Bogdan-Ștefan Neacșu 112820ad7b Fix rebase going wrong 2021-12-21 12:15:07 +02:00
Tommy Verrall fe27cbe7e2 Fix success view messages. 2021-12-21 10:07:35 +00:00
Bogdan-Ștefan Neacșu bd892e00bd Switch to sandbox as default build 2021-12-21 11:16:30 +02:00
Dave Hrycyszyn 8d2863e085 Back down on caching and we're good to redeploy 2021-12-20 18:01:19 +00:00
Dave Hrycyszyn 89cb931775 Cranking caching back up 2021-12-20 17:25:29 +00:00
Dave Hrycyszyn 0f58fb6437 Cutting client-side caching from 3.5 minutes to 5 seconds 2021-12-20 16:40:26 +00:00
Dave Hrycyszyn 837575c8d3 Knocking down cache interval some more 2021-12-20 15:19:48 +00:00
Dave Hrycyszyn 4cbe789f42 Merge branch 'develop' of github.com:nymtech/nym into develop 2021-12-20 15:13:29 +00:00
Dave Hrycyszyn 822c993f24 Setting cache to 2 seconds for explorer api 2021-12-20 15:13:22 +00:00
Bogdan-Ștefan Neacşu 9480233ca3 Feature/enable signature check (#989)
* Revert "Do not set proxy only for this time"

This reverts commit 47946ad79e.

* Reinstate signature check

* Enable migrate entry point
2021-12-20 16:09:42 +02:00
Dave Hrycyszyn 72944905cd Knocking down cache validation time 2021-12-20 14:08:49 +00:00
Dave Hrycyszyn effb756e2f Setting mixnode cache refresh to 30 seconds 2021-12-20 14:07:40 +00:00
Dave Hrycyszyn 583f5083e5 Merge branch 'develop' of github.com:nymtech/nym into develop 2021-12-20 14:00:04 +00:00
Dave Hrycyszyn 941e91d250 Re-enabling owner signature form on settings page 2021-12-20 13:59:52 +00:00
Bogdan-Ștefan Neacşu 0f1b9d138e Update mixnet contract address (#988) 2021-12-20 15:52:34 +02:00
mfahampshire 265696103c updated env sample 2021-12-20 13:58:38 +01:00
Bogdan-Ștefan Neacşu 22ce25d821 Fix verloc print (#987) 2021-12-20 12:52:32 +02:00
Dave Hrycyszyn 363f784714 Changing build command to match readme 2021-12-20 10:51:47 +00:00
Dave Hrycyszyn 1f360a5a27 Knocking validator-api refresh interval to 30 seconds 2021-12-20 10:36:43 +00:00
Dave Hrycyszyn ea3f2e9beb Moving country data refresh interval 15 minutes again 2021-12-20 10:35:04 +00:00
Dave Hrycyszyn 84924133b5 Knocking down the mixnode refresh interval to 30 seconds 2021-12-20 10:30:45 +00:00
Dave Hrycyszyn 860afc9086 Removing unused signing test module 2021-12-20 09:30:36 +00:00
Dave Hrycyszyn 0aab508633 Removing Dalek stuff, jst has already built this using cw apis 2021-12-19 16:18:08 +00:00
Dave Hrycyszyn bdfce8f663 Merge branch 'develop' of github.com:nymtech/nym into develop 2021-12-19 15:55:20 +00:00
Dave Hrycyszyn b5bb09588d Fixing Cargo.lock 2021-12-19 15:55:13 +00:00
Dave Hrycyszyn 983322d273 Feature/refactor mixnet contract test helpers (#986)
* Refactored test helpers

* Renaming mixnode "bond" coins to "pledge"

* Renaming gateway "bond" coins to "pledge"

* ibid

* Commenting out new tests, they will go in next PR
2021-12-19 15:54:11 +00:00
Dave Hrycyszyn e761989c6a Making the terminology consistent between mixnode/gateway output and … (#985)
* Making the terminology consistent between mixnode/gateway output and wallet display

* [ci skip] Generate TS types
2021-12-18 13:12:10 +00:00
futurechimp bc981873ff [ci skip] Generate TS types 2021-12-18 12:54:44 +00:00
Dave Hrycyszyn 8e99ae8979 Feature/add wallet to gateway init (#984)
* Moving sign_text method into common/crypto to dry it up

* Moved bech32 address validation into common/crypto

* ibid

* Gateway now requires a --wallet-address arg on init
2021-12-18 12:45:55 +00:00
Dave Hrycyszyn ed2b515a83 Feature/add wallet address to init (#982)
* Add a --wallet-adress parameter to init

* Rearranging signing code locations

* A bit more refactoring

* ibid

* Exiting if the stored bech32 address isn't valid at node start

* A few docs comments

* Moved crypto crate up to root src level

* Friendlier startup messages for node verification code

* Switching punk and nymt addresses in test
2021-12-18 10:44:30 +00:00
Fouad aca31dbaac Feature/wallet settings area (#974)
* set up Settings component

* Update network defaults

* Short node identity signature check

Fix tests

* Do not set proxy only for this time

* Update contract addresses

* file restructure

* file updates

* add settings tab panels

* update them color for nym fee

* rework layout

* update bond form to include signature and profit percent

* create info tooltip + make status component optional

* fix overflow

* update sys vars tab

* get mixnode bond details

* use mixnode id in settings

* set up profit percentage value on sys vars tab

* profit percentage styling

* add fix for delegations list

* fix unbond UI bug

* minor style updates

* dont allow profit percent on gateway bonding

* webpack prod fix

* update profit percentage from settings area

* hardcode signature for profit percentage update

Co-authored-by: Bogdan-Ștefan Neacșu <bogdan@nymtech.net>
2021-12-18 07:54:53 +00:00
Mx f8fb6f524e Move cleaned up smart contracts to main code repo (#929)
* moved contracts from gitlab to main codebase

* added missing event param

* removed erroneous  from description

* updates:
* changed maths of token -> MB conversion
* new tests for changed maths
* length check on cosmos address
* begun code doc

* code documentation

* small comment cleanup

* cont. w tests, may have found bug in maths re: using not whole tokens: investigating

* finished code doc

* included requested changes to contract

* change to maths operations, shrunk test error to < .9

* updates:
* updated tests
* updated readme

* removed commented out code, changed variable name to be more informative

* removed unnecessary byte32 length check
2021-12-18 01:32:47 +00:00
Bogdan-Ștefan Neacşu 036369226b Bump version to 0.12.0 (#980) 2021-12-18 01:13:30 +00:00
Bogdan-Ștefan Neacşu 4972ad8c53 Feature/rename erc20 (#979)
* Rename erc20-bridge to bandwidth-claim

* Rename contract constant in network defaults
2021-12-18 01:13:11 +00:00
Dave Hrycyszyn a09581eea9 Removed web wallet (#978) 2021-12-18 01:09:57 +00:00
Tommy Verrall 4d447706fc Update message to bond mixnode (#981)
- This prevents the user navigating to the deprecated web-wallet.
2021-12-17 17:51:07 +00:00
Jędrzej Stuczyński 6c6e16035a Feature/optional bandwidth bypass (#965)
* Removed outdated constant

* ClaimFreeTestnetBandwidth ClientControlRequest

* Configuration option for the testnet mode in gateway

* Made testnet mode deserialize to default value if not present

* Fixed testnet mode override

* Testnet config options for clients and validator api

* Changed error message for when gateway is not using testnet mode

* Incorporated testnet mode into gateway client

* Activating testnet mode based on config values

* Allowing clippy warnings

* Fixed use of moved value in wasm build

Co-authored-by: Bogdan-Ștefan Neacșu <bogdan@nymtech.net>
2021-12-17 18:55:33 +02:00
Tommy Verrall 96aa814a61 Merge pull request #977 from nymtech/bugfix/network-explorer-uptime-graph
Network Explorer: fix uptime history display to use new API response
2021-12-17 14:30:04 +00:00
Mark Sinclair 1fbf437786 Network Explorer: fix uptime history display to use new API response 2021-12-17 13:41:41 +00:00
Bogdan-Ștefan Neacşu 852d12b440 Make develop branch agnostic of the network (#976)
* Make develop branch agnostic of the network

* Update network defaults

* Short node identity signature check

Fix tests

* Do not set proxy only for this time

* Update contract addresses

* Network Explorer: configure URLs with `.env` file

* Network Explorer API improvements:
- upgrade `okapi` for swagger generation across multiple resources
- switched `GET mix-node` to `GET mix-nodes`
- added error message when no geolocation env var is set and process continues

* Network Explorer improvements:
- fix up API urls after Network Explorer API changes
- set currency denominations in `.env` file
- set API endpoints in `.env` file

* Network Explorer: change prod env to round robin DNS

* Update test

Co-authored-by: Mark Sinclair <mmsinclair@gmail.com>
2021-12-17 15:36:35 +02:00
Bogdan-Ștefan Neacşu 865759254f Fix windows fmt (#975) 2021-12-17 13:23:44 +02:00
291 changed files with 27271 additions and 29157 deletions
+3
View File
@@ -0,0 +1,3 @@
unreleased=true
future-release=v0.12.1
since-tag=v0.11.0
+1
View File
@@ -0,0 +1 @@
2.7.5
+240 -868
View File
File diff suppressed because it is too large Load Diff
Generated
+36 -30
View File
@@ -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
View File
@@ -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",
+23 -9
View File
@@ -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
+5 -5
View File
@@ -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 -1
View File
@@ -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"
+14
View File
@@ -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(),
+2 -1
View File
@@ -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 -1
View File
@@ -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 }}
+4
View File
@@ -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
+22 -8
View File
@@ -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
}
+26 -2
View File
@@ -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
+15 -7
View File
@@ -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
+2 -1
View File
@@ -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 -1
View File
@@ -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 }}
+4
View File
@@ -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
+22 -8
View File
@@ -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
}
+26 -2
View File
@@ -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
+15 -7
View File
@@ -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 -1
View File
@@ -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"
+13
View File
@@ -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,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() {
+2
View File
@@ -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")
)
}
}
}
+1
View File
@@ -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;
+1 -1
View File
@@ -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"
+11
View File
@@ -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"),
}
}
+19 -14
View File
@@ -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;
+17
View File
@@ -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";
+17
View File
@@ -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";
+85 -39
View File
@@ -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 -1
View File
@@ -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() {
@@ -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();
@@ -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`
@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../../build-info/6dfbc7f87ae3c2727d63a3fba8d02a41.json"
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../../build-info/6dfbc7f87ae3c2727d63a3fba8d02a41.json"
}
@@ -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": {}
}
@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../../../build-info/6dfbc7f87ae3c2727d63a3fba8d02a41.json"
}
@@ -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": {}
}
@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/6dfbc7f87ae3c2727d63a3fba8d02a41.json"
}
@@ -0,0 +1,10 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "Context",
"sourceName": "@openzeppelin/contracts/utils/Context.sol",
"abi": [],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}
@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
}
@@ -0,0 +1,10 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "SafeMath",
"sourceName": "@openzeppelin/contracts/math/SafeMath.sol",
"abi": [],
"bytecode": "0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212207ceb5b9e8bb631a9723802d1487d75b0f9db1e57e569e37561e9d35cd45a718c64736f6c63430006060033",
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212207ceb5b9e8bb631a9723802d1487d75b0f9db1e57e569e37561e9d35cd45a718c64736f6c63430006060033",
"linkReferences": {},
"deployedLinkReferences": {}
}
@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
}
@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
}
@@ -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": {}
}
@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
}
@@ -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": {}
}
@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
}
@@ -0,0 +1,10 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "Address",
"sourceName": "@openzeppelin/contracts/utils/Address.sol",
"abi": [],
"bytecode": "0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf51151e2a4e160194baa49fc39a27bad1253743e398fefe6fb6935ec7d37a5e64736f6c63430006060033",
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf51151e2a4e160194baa49fc39a27bad1253743e398fefe6fb6935ec7d37a5e64736f6c63430006060033",
"linkReferences": {},
"deployedLinkReferences": {}
}
@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
}
@@ -0,0 +1,10 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "Context",
"sourceName": "@openzeppelin/contracts/utils/Context.sol",
"abi": [],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}
@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
}
@@ -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": {}
}
@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/10e5405221d21329b74f12bf00d0cd2d.json"
}
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
}
};
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
});
});
});
});
+3 -7
View File
@@ -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"
-15
View File
@@ -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"
+3 -4
View File
@@ -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);
+15 -10
View File
@@ -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());
+4 -4
View File
@@ -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,
};
+39 -35
View File
@@ -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());
+4 -4
View File
@@ -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,
+57 -43
View File
@@ -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