Compare commits

..

6 Commits

Author SHA1 Message Date
Jędrzej Stuczyński d6a81d9213 initial validator API-networking related things
adapted from DKG impl
2022-05-23 15:34:48 +01:00
Jędrzej Stuczyński a6db5fe704 Added STATE_DENOM network specific constant 2022-05-23 13:37:53 +01:00
Jędrzej Stuczyński fe57d08f3e actually calling dotenv at validator API startup 2022-05-23 13:36:05 +01:00
Jędrzej Stuczyński ae29b2300c optional serde support for x25519 keys 2022-05-23 13:34:28 +01:00
Jędrzej Stuczyński 7b98d62f96 optional serde support for ed25519 keys 2022-05-23 12:17:58 +01:00
Jędrzej Stuczyński 6abe95ed61 Added abci::Data field to ExecuteResult 2022-05-23 12:12:03 +01:00
195 changed files with 6390 additions and 8493 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ on:
jobs:
build:
runs-on: [ self-hosted, custom-linux ]
runs-on: [ self-hosted, custom-linux-exoscale ]
# Enable sccache via environment variable
env:
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
+1 -1
View File
@@ -4,7 +4,7 @@ on: workflow_dispatch
jobs:
build:
runs-on: [ self-hosted, custom-linux ]
runs-on: [ self-hosted, custom-linux-exoscale ]
# Enable sccache via environment variable
env:
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
+1 -3
View File
@@ -10,9 +10,7 @@ on:
jobs:
build:
runs-on: [ self-hosted, custom-linux ]
env:
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
runs-on: [ self-hosted, custom-linux-exoscale ]
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
+7 -27
View File
@@ -4,51 +4,31 @@
### Added
- all: added network compilation target to `--help` (or `--version`) commands ([#1256]).
- explorer-api: learned how to sum the delegations by owner in a new endpoint.
- gateway: Added gateway coconut verifications and validator-api communication for double spending protection ([#1261])
- mixnet-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
- network-requester: send traffic statistics from all network requesters and receive it in a special network-requester that aggregates the data and exposes it via a rest API ([#1267], [#1278]).
- validator-api: add `estimated_node_profit` and `estimated_operator_cost` to `reward-estimate` endpoint ([#1284])
- validator-api: add detailed mixnode bond endpoints, and explorer-api makes use of that data to append stake saturation.
- validator-api: add Swagger to document the REST API ([#1249]).
- validator-api: Added new endpoints for coconut spending flow and communications with coconut & multisig contracts ([#1261])
- vesting-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
- wallet: require password to switch accounts
- wallet: add simple CLI tool for decrypting and recovering the wallet file.
- wallet: added support for multiple accounts ([#1265])
- wallet: compound and claim reward endpoints for operators and delegators ([#1302])
- wallet: require password to switch accounts
- wallet: the wallet backend learned how to keep track of validator name, either hardcoded or by querying the status endpoint.
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
- validator-api: add Swagger to document the REST API ([#1249]).
- all: added network compilation target to `--help` (or `--version`) commands ([#1256]).
- network-requester: send traffic statistics from all network requesters and receive it in a special network-requester that aggregates the data and exposes it via a rest API ([#1267], [#1278]).
### Fixed
- mixnet-contract: `estimated_delegator_reward` calculation ([#1284])
- mixnet-contract: delegator and operator rewards use lambda and sigma instead of lambda_ticked and sigma_ticked ([#1284])
- vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275])
- mixnet-contract: removed `expect` in `query_delegator_reward` and queries containing invalid proxy address should now return a more human-readable error ([#1257])
- mixnet-contract: replaced integer division with fixed for performance calculations ([#1284])
- mixnet-contract: Under certain circumstances nodes could not be unbonded ([#1255](https://github.com/nymtech/nym/issues/1255)) ([#1258])
- mixnode, gateway: attempting to determine reconnection backoff to persistently failing mixnode could result in a crash ([#1260])
- vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275])
### Changed
- validator-client: created internal `Coin` type that replaces coins from `cosmrs` and `cosmwasm` for API entrypoints [[#1295]]
[#1258]: https://github.com/nymtech/nym/pull/1258
[#1249]: https://github.com/nymtech/nym/pull/1249
[#1256]: https://github.com/nymtech/nym/pull/1256
[#1257]: https://github.com/nymtech/nym/pull/1257
[#1258]: https://github.com/nymtech/nym/pull/1258
[#1260]: https://github.com/nymtech/nym/pull/1260
[#1261]: https://github.com/nymtech/nym/pull/1261
[#1265]: https://github.com/nymtech/nym/pull/1265
[#1267]: https://github.com/nymtech/nym/pull/1267
[#1275]: https://github.com/nymtech/nym/pull/1275
[#1278]: https://github.com/nymtech/nym/pull/1278
[#1284]: https://github.com/nymtech/nym/pull/1284
[#1292]: https://github.com/nymtech/nym/pull/1292
[#1295]: https://github.com/nymtech/nym/pull/1295
[#1302]: https://github.com/nymtech/nym/pull/1302
## [nym-wallet-v1.0.4](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.4) (2022-05-04)
Generated
+85 -152
View File
@@ -664,8 +664,8 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc347c19eb5b940f396ac155822caee6662f850d97306890ac3773ed76c90c5a"
dependencies = [
"prost 0.9.0",
"prost-types 0.9.0",
"prost",
"prost-types",
"tonic",
"tonic-build",
"tracing-core",
@@ -683,7 +683,7 @@ dependencies = [
"futures",
"hdrhistogram",
"humantime 2.1.0",
"prost-types 0.9.0",
"prost-types",
"serde",
"serde_json",
"thread_local",
@@ -761,29 +761,60 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "cosmos-sdk-proto"
version = "0.12.2"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f109fe191e73898d74b8020c50f86018364ad19bc30318aa074616c382b52856"
checksum = "c0254ffee603f5301d6a66963d9e1cc5091479c22e2e925e1f7689c8027a0828"
dependencies = [
"prost 0.10.3",
"prost-types 0.10.1",
"prost",
"prost-types",
"tendermint-proto",
]
[[package]]
name = "cosmos-sdk-proto"
version = "0.9.0"
source = "git+https://github.com/nymtech/cosmos-rust?branch=bugfix/account-id-length-validation#911fbe1236cfed591783ccef01018f7ccc97c496"
dependencies = [
"prost",
"prost-types",
"tendermint-proto",
]
[[package]]
name = "cosmrs"
version = "0.7.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8413275b23cb5a0734d9d1e3e33f0b5b94547c1e94776dbc3149dbf46588a533"
checksum = "505ea048e9ff2f906d6b954f9f8157d903ca468bfb301d906b40ecc25ba6838d"
dependencies = [
"bip32",
"cosmos-sdk-proto",
"cosmos-sdk-proto 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ecdsa 0.13.4",
"eyre",
"getrandom 0.2.6",
"k256 0.10.4",
"prost 0.10.3",
"prost-types 0.10.1",
"prost",
"prost-types",
"rand_core 0.6.3",
"serde",
"serde_json",
"subtle-encoding",
"tendermint",
"thiserror",
]
[[package]]
name = "cosmrs"
version = "0.4.1"
source = "git+https://github.com/nymtech/cosmos-rust?branch=bugfix/account-id-length-validation#911fbe1236cfed591783ccef01018f7ccc97c496"
dependencies = [
"bip32",
"cosmos-sdk-proto 0.9.0 (git+https://github.com/nymtech/cosmos-rust?branch=bugfix/account-id-length-validation)",
"ecdsa 0.13.4",
"eyre",
"getrandom 0.2.6",
"k256 0.10.4",
"prost",
"prost-types",
"rand_core 0.6.3",
"serde",
"serde_json",
@@ -873,6 +904,7 @@ dependencies = [
"bip39",
"cfg-if 0.1.10",
"clap 3.1.8",
"coconut-bandwidth-contract-common",
"coconut-interface",
"credential-storage",
"credentials",
@@ -906,7 +938,7 @@ version = "0.1.0"
dependencies = [
"bls12_381 0.5.0",
"coconut-interface",
"cosmrs",
"cosmrs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crypto",
"network-defaults",
"rand 0.7.3",
@@ -1149,7 +1181,6 @@ dependencies = [
"byteorder",
"digest 0.9.0",
"rand_core 0.5.1",
"serde",
"subtle 2.4.1",
"zeroize",
]
@@ -1165,42 +1196,6 @@ dependencies = [
"serde",
]
[[package]]
name = "cw-utils"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "babd2c090f39d07ce5bf2556962305e795daa048ce20a93709eb591476e4a29e"
dependencies = [
"cosmwasm-std",
"schemars",
"serde",
"thiserror",
]
[[package]]
name = "cw3"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f871854338a54c7bb094d16ffe17212b93b146d9659dbce4c9402a9b77e240ef"
dependencies = [
"cosmwasm-std",
"cw-utils",
"schemars",
"serde",
]
[[package]]
name = "cw4"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4476d6a7c13c46ed9ff260bd0e1cf648dc37b13f483822e1ff2a431f0f6ee52"
dependencies = [
"cosmwasm-std",
"cw-storage-plus",
"schemars",
"serde",
]
[[package]]
name = "darling"
version = "0.13.4"
@@ -1602,14 +1597,6 @@ dependencies = [
"uint",
]
[[package]]
name = "execute"
version = "0.1.0"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "explorer-api"
version = "1.0.1"
@@ -1617,7 +1604,6 @@ dependencies = [
"chrono",
"humantime-serde",
"isocountry",
"itertools",
"log",
"mixnet-contract-common",
"network-defaults",
@@ -1994,6 +1980,7 @@ dependencies = [
name = "gateway-requests"
version = "0.1.0"
dependencies = [
"bincode",
"bs58",
"coconut-interface",
"credentials",
@@ -2149,7 +2136,7 @@ dependencies = [
"indexmap",
"slab",
"tokio",
"tokio-util 0.7.3",
"tokio-util 0.7.1",
"tracing",
]
@@ -2397,12 +2384,11 @@ dependencies = [
"headers",
"http",
"hyper",
"hyper-rustls",
"rustls-native-certs",
"hyper-tls",
"native-tls",
"tokio",
"tokio-rustls",
"tokio-native-tls",
"tower-service",
"webpki",
]
[[package]]
@@ -2879,7 +2865,7 @@ dependencies = [
"log",
"nymsphinx",
"tokio",
"tokio-util 0.7.3",
"tokio-util 0.6.9",
]
[[package]]
@@ -2920,7 +2906,7 @@ dependencies = [
"rand 0.8.5",
"serde",
"tokio",
"tokio-util 0.7.3",
"tokio-util 0.6.9",
"url",
"validator-client",
"version-checker",
@@ -2952,18 +2938,6 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
[[package]]
name = "multisig-contract-common"
version = "0.1.0"
dependencies = [
"cosmwasm-std",
"cw-utils",
"cw3",
"cw4",
"schemars",
"serde",
]
[[package]]
name = "native-tls"
version = "0.2.10"
@@ -3010,7 +2984,7 @@ version = "0.1.0"
dependencies = [
"tokio",
"tokio-stream",
"tokio-util 0.7.3",
"tokio-util 0.6.9",
]
[[package]]
@@ -3145,7 +3119,7 @@ dependencies = [
"tokio",
"tokio-stream",
"tokio-tungstenite",
"tokio-util 0.7.3",
"tokio-util 0.6.9",
"url",
"validator-client",
"vergen",
@@ -3182,7 +3156,7 @@ dependencies = [
"serde",
"serial_test",
"tokio",
"tokio-util 0.7.3",
"tokio-util 0.6.9",
"toml",
"topology",
"url",
@@ -3208,7 +3182,6 @@ dependencies = [
"proxy-helpers",
"publicsuffix",
"rand 0.7.3",
"reqwest",
"rocket",
"serde",
"socks5-requests",
@@ -3268,7 +3241,6 @@ dependencies = [
"coconut-interface",
"config",
"console-subscriber",
"cosmwasm-std",
"credential-storage",
"credentials",
"crypto",
@@ -3280,7 +3252,6 @@ dependencies = [
"humantime-serde",
"log",
"mixnet-contract-common",
"multisig-contract-common",
"nymcoconut",
"nymsphinx",
"okapi",
@@ -3430,7 +3401,7 @@ dependencies = [
"bytes",
"nymsphinx-params",
"nymsphinx-types",
"tokio-util 0.7.3",
"tokio-util 0.6.9",
]
[[package]]
@@ -3965,17 +3936,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001"
dependencies = [
"bytes",
"prost-derive 0.9.0",
]
[[package]]
name = "prost"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc03e116981ff7d8da8e5c220e374587b98d294af7ba7dd7fda761158f00086f"
dependencies = [
"bytes",
"prost-derive 0.10.1",
"prost-derive",
]
[[package]]
@@ -3991,8 +3952,8 @@ dependencies = [
"log",
"multimap",
"petgraph",
"prost 0.9.0",
"prost-types 0.9.0",
"prost",
"prost-types",
"regex",
"tempfile",
"which",
@@ -4011,19 +3972,6 @@ dependencies = [
"syn",
]
[[package]]
name = "prost-derive"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc"
dependencies = [
"anyhow",
"itertools",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "prost-types"
version = "0.9.0"
@@ -4031,17 +3979,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a"
dependencies = [
"bytes",
"prost 0.9.0",
]
[[package]]
name = "prost-types"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68"
dependencies = [
"bytes",
"prost 0.10.3",
"prost",
]
[[package]]
@@ -4055,7 +3993,7 @@ dependencies = [
"socks5-requests",
"tokio",
"tokio-test",
"tokio-util 0.7.3",
"tokio-util 0.6.9",
]
[[package]]
@@ -5525,9 +5463,9 @@ dependencies = [
[[package]]
name = "tendermint"
version = "0.23.7"
version = "0.23.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ca881fa4dedd2b46334f13be7fbc8cc1549ba4be5a833fe4e73d1a1baaf7949"
checksum = "a9ef686b8ecd36550d0581f0989c9d8607090b23005df479d8e6ba348b5800b9"
dependencies = [
"async-trait",
"bytes",
@@ -5538,8 +5476,8 @@ dependencies = [
"k256 0.10.4",
"num-traits",
"once_cell",
"prost 0.10.3",
"prost-types 0.10.1",
"prost",
"prost-types",
"ripemd160",
"serde",
"serde_bytes",
@@ -5556,9 +5494,9 @@ dependencies = [
[[package]]
name = "tendermint-config"
version = "0.23.7"
version = "0.23.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6c56ee93f4e9b7e7daba86d171f44572e91b741084384d0ae00df7991873dfd"
checksum = "ecc127f82e7a8c7337c1f293d65a821380d3407c4c44bc979ef4da0ebc3b31ed"
dependencies = [
"flex-error",
"serde",
@@ -5570,16 +5508,16 @@ dependencies = [
[[package]]
name = "tendermint-proto"
version = "0.23.7"
version = "0.23.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71f925d74903f4abbdc4af0110635a307b3cb05b175fdff4a7247c14a4d0874"
checksum = "a9e0a0251fd81bed7420bea0f4d91c2a58f6c9fa34d5b2f70bed0ba8890de5aa"
dependencies = [
"bytes",
"flex-error",
"num-derive",
"num-traits",
"prost 0.10.3",
"prost-types 0.10.1",
"prost",
"prost-types",
"serde",
"serde_bytes",
"subtle-encoding",
@@ -5588,9 +5526,9 @@ dependencies = [
[[package]]
name = "tendermint-rpc"
version = "0.23.7"
version = "0.23.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a13e63f57ee05a1e927887191c76d1b139de9fa40c180b9f8727ee44377242a6"
checksum = "626c493e9ced3a9de37583bbd929f4b6dbd49aa513ab9b4776aa44a9332ce9b5"
dependencies = [
"async-trait",
"bytes",
@@ -5761,9 +5699,9 @@ dependencies = [
[[package]]
name = "tokio"
version = "1.19.1"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95eec79ea28c00a365f539f1961e9278fbcaf81c0ff6aaf0e93c181352446948"
checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee"
dependencies = [
"bytes",
"libc",
@@ -5824,9 +5762,9 @@ dependencies = [
[[package]]
name = "tokio-stream"
version = "0.1.9"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9"
checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3"
dependencies = [
"futures-core",
"pin-project-lite",
@@ -5871,20 +5809,20 @@ dependencies = [
"futures-sink",
"log",
"pin-project-lite",
"slab",
"tokio",
]
[[package]]
name = "tokio-util"
version = "0.7.3"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45"
checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"slab",
"tokio",
"tracing",
]
@@ -5917,8 +5855,8 @@ dependencies = [
"hyper-timeout",
"percent-encoding",
"pin-project",
"prost 0.9.0",
"prost-derive 0.9.0",
"prost",
"prost-derive",
"tokio",
"tokio-stream",
"tokio-util 0.6.9",
@@ -5969,7 +5907,7 @@ dependencies = [
"rand 0.8.5",
"slab",
"tokio",
"tokio-util 0.7.3",
"tokio-util 0.7.1",
"tower-layer",
"tower-service",
"tracing",
@@ -6258,22 +6196,18 @@ dependencies = [
"async-trait",
"base64",
"bip39",
"coconut-bandwidth-contract-common",
"coconut-interface",
"colored",
"config",
"cosmrs",
"cosmrs 0.4.1 (git+https://github.com/nymtech/cosmos-rust?branch=bugfix/account-id-length-validation)",
"cosmwasm-std",
"cw3",
"execute",
"flate2",
"futures",
"itertools",
"log",
"mixnet-contract-common",
"multisig-contract-common",
"network-defaults",
"prost 0.10.3",
"prost",
"reqwest",
"serde",
"serde_json",
@@ -6693,7 +6627,6 @@ checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f"
dependencies = [
"curve25519-dalek",
"rand_core 0.5.1",
"serde",
"zeroize",
]
-2
View File
@@ -31,12 +31,10 @@ members = [
"common/credentials",
"common/crypto",
"common/crypto/dkg",
"common/execute",
"common/bandwidth-claim-contract",
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
"common/cosmwasm-smart-contracts/contracts-common",
"common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/multisig-contract",
"common/cosmwasm-smart-contracts/vesting-contract",
"common/mixnode-common",
"common/network-defaults",
+1 -1
View File
@@ -14,7 +14,7 @@ log = "0.4"
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
serde = { version = "1.0", features = ["derive"] }
sled = "0.34"
tokio = { version = "1.19.1", features = ["macros"] }
tokio = { version = "1.4", features = ["macros"] }
url = { version ="2.2", features = ["serde"] }
# internal
@@ -6,7 +6,7 @@ use crate::client::real_messages_control::acknowledgement_control::Retransmissio
use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
use futures::StreamExt;
use log::*;
use nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue, QueueKey};
use nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue, QueueKey, TimerError};
use nymsphinx::chunking::fragment::FragmentIdentifier;
use nymsphinx::Delay as SphinxDelay;
use std::collections::HashMap;
@@ -209,11 +209,16 @@ impl ActionController {
}
// note: when the entry expires it's automatically removed from pending_acks_timers
fn handle_expired_ack_timer(&mut self, expired_ack: Expired<FragmentIdentifier>) {
fn handle_expired_ack_timer(
&mut self,
expired_ack: Result<Expired<FragmentIdentifier>, TimerError>,
) {
// I'm honestly not sure how to handle it, because getting it means other things in our
// system are already misbehaving. If we ever see this panic, then I guess we should worry
// about it. Perhaps just reschedule it at later point?
let frag_id = expired_ack.into_inner();
let frag_id = expired_ack
.expect("Tokio timer returned an error!")
.into_inner();
trace!("{} has expired", frag_id);
+2 -1
View File
@@ -15,8 +15,9 @@ rand = "0.7.3"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
url = "2.2"
tokio = { version = "1.19.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
tokio = { version = "1.4", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
coconut-bandwidth-contract-common = { path = "../../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" }
coconut-interface = { path = "../../common/coconut-interface" }
credentials = { path = "../../common/credentials" }
credential-storage = { path = "../../common/credential-storage" }
File diff suppressed because one or more lines are too long
+35 -17
View File
@@ -2,48 +2,66 @@
// SPDX-License-Identifier: Apache-2.0
use bip39::Mnemonic;
use coconut_bandwidth_contract_common::deposit::DepositData;
use std::str::FromStr;
use url::Url;
use crate::error::Result;
use crate::{MNEMONIC, NYMD_URL};
use crate::{CONTRACT_ADDRESS, MNEMONIC, NYMD_URL};
use network_defaults::{DEFAULT_NETWORK, DENOM, VOUCHER_INFO};
use validator_client::nymd::traits::CoconutBandwidthSigningClient;
use validator_client::nymd::{Coin, Fee, NymdClient, SigningNymdClient};
use coconut_bandwidth_contract_common::msg::ExecuteMsg;
use network_defaults::DEFAULT_NETWORK;
use validator_client::nymd::{
AccountId, CosmosCoin, Decimal, Denom, NymdClient, SigningNymdClient,
};
pub(crate) struct Client {
nymd_client: NymdClient<SigningNymdClient>,
denom: Denom,
contract_address: AccountId,
}
impl Client {
pub fn new() -> Self {
let nymd_url = Url::from_str(NYMD_URL).unwrap();
let mnemonic = Mnemonic::from_str(MNEMONIC).unwrap();
let nymd_client =
NymdClient::connect_with_mnemonic(DEFAULT_NETWORK, nymd_url.as_ref(), mnemonic, None)
.unwrap();
let nymd_client = NymdClient::connect_with_mnemonic(
DEFAULT_NETWORK,
nymd_url.as_ref(),
None,
None,
None,
mnemonic,
None,
)
.unwrap();
let denom = Denom::from_str(network_defaults::DENOM).unwrap();
let contract_address = AccountId::from_str(CONTRACT_ADDRESS).unwrap();
Client { nymd_client }
Client {
nymd_client,
denom,
contract_address,
}
}
pub async fn deposit(
&self,
amount: u64,
info: &str,
verification_key: String,
encryption_key: String,
fee: Option<Fee>,
) -> Result<String> {
let amount = Coin::new(amount as u128, DENOM.to_string());
let req = ExecuteMsg::DepositFunds {
data: DepositData::new(info.to_string(), verification_key, encryption_key),
};
let funds = vec![CosmosCoin {
denom: self.denom.clone(),
amount: Decimal::from(amount),
}];
Ok(self
.nymd_client
.deposit(
amount,
String::from(VOUCHER_INFO),
verification_key,
encryption_key,
fee,
)
.execute(&self.contract_address, &req, Default::default(), "", funds)
.await?
.transaction_hash
.to_string())
+1 -1
View File
@@ -55,9 +55,9 @@ impl Execute for Deposit {
let tx_hash = client
.deposit(
self.amount,
VOUCHER_INFO,
signing_keypair.public_key.clone(),
encryption_keypair.public_key.clone(),
None,
)
.await?;
+1 -1
View File
@@ -27,7 +27,7 @@ pretty_env_logger = "0.4" # for formatting log messages
rand = { version = "0.7.3", features = ["wasm-bindgen"] } # rng-related traits + some rng implementation to use
serde = { version = "1.0.104", features = ["derive"] } # for config serialization/deserialization
sled = "0.34" # for storage of replySURB decryption keys
tokio = { version = "1.19.1", features = ["rt-multi-thread", "net", "signal"] } # async runtime
tokio = { version = "1.4", features = ["rt-multi-thread", "net", "signal"] } # async runtime
tokio-tungstenite = "0.14" # websocket
## internal
+1 -1
View File
@@ -20,7 +20,7 @@ pretty_env_logger = "0.4"
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
serde = { version = "1.0", features = ["derive"] } # for config serialization/deserialization
snafu = "0.6"
tokio = { version = "1.19.1", features = ["rt-multi-thread", "net", "signal"] }
tokio = { version = "1.4", features = ["rt-multi-thread", "net", "signal"] }
url = "2.2"
# internal
+1 -1
View File
@@ -35,7 +35,7 @@ default-features = false
# non-wasm-only dependencies
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio]
version = "1.19.1"
version = "1.4"
features = ["macros", "rt", "net", "sync", "time"]
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
@@ -83,7 +83,7 @@ impl GatewayClient {
) -> Self {
GatewayClient {
authenticated: false,
disabled_credentials_mode: false,
disabled_credentials_mode: true,
bandwidth_remaining: 0,
gateway_address,
gateway_identity,
@@ -100,8 +100,8 @@ impl GatewayClient {
}
}
pub fn set_disabled_credentials_mode(&mut self, _disabled_credentials_mode: bool) {
self.disabled_credentials_mode = false;
pub fn set_disabled_credentials_mode(&mut self, disabled_credentials_mode: bool) {
self.disabled_credentials_mode = disabled_credentials_mode
}
// TODO: later convert into proper builder methods
@@ -496,6 +496,7 @@ impl GatewayClient {
self.shared_key.as_ref().unwrap(),
iv,
)
.ok_or(GatewayClientError::SerializeCredential)?
.into();
self.bandwidth_remaining = match self.send_websocket_message(msg).await? {
ServerResponse::Bandwidth { available_total } => Ok(available_total),
+2 -2
View File
@@ -9,8 +9,8 @@ edition = "2021"
[dependencies]
futures = "0.3"
log = "0.4.8"
tokio = { version = "1.19.1", features = ["time", "net", "rt"] }
tokio-util = { version = "0.7.3", features = ["codec"] }
tokio = { version = "1.4", features = ["time", "net", "rt"] }
tokio-util = { version = "0.6", features = ["codec"] }
# internal
nymsphinx = {path = "../../nymsphinx" }
@@ -10,11 +10,8 @@ rust-version = "1.56"
[dependencies]
base64 = "0.13"
colored = "2.0"
cw3 = "0.13.1"
mixnet-contract-common = { path= "../../cosmwasm-smart-contracts/mixnet-contract" }
vesting-contract-common = { path= "../../cosmwasm-smart-contracts/vesting-contract" }
coconut-bandwidth-contract-common = { path= "../../cosmwasm-smart-contracts/coconut-bandwidth-contract" }
multisig-contract-common = { path = "../../cosmwasm-smart-contracts/multisig-contract" }
vesting-contract = { path = "../../../contracts/vesting" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
@@ -22,7 +19,7 @@ reqwest = { version = "0.11", features = ["json"] }
thiserror = "1"
log = "0.4"
url = { version = "2.2", features = ["serde"] }
tokio = { version = "1.19.1", features = ["sync", "time"] }
tokio = { version = "1.10", features = ["sync", "time"] }
futures = "0.3"
coconut-interface = { path = "../../coconut-interface" }
@@ -35,13 +32,12 @@ validator-api-requests = { path = "../../../validator-api/validator-api-requests
async-trait = { version = "0.1.51", optional = true }
bip39 = { version = "1", features = ["rand"], optional = true }
config = { path = "../../config", optional = true }
cosmrs = { version = "0.7.0", features = ["rpc", "bip32", "cosmwasm"], optional = true}
prost = { version = "0.10", default-features = false, optional = true }
cosmrs = { git = "https://github.com/nymtech/cosmos-rust", branch = "bugfix/account-id-length-validation", features = ["rpc", "bip32", "cosmwasm"], optional = true}
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-beta8", optional = true }
execute = { path = "../../execute" }
[dev-dependencies]
ts-rs = "6.1.2"
+60 -108
View File
@@ -2,20 +2,16 @@
// SPDX-License-Identifier: Apache-2.0
use crate::{validator_api, ValidatorClientError};
use coconut_interface::{
BlindSignRequestBody, BlindedSignatureResponse, ExecuteReleaseFundsRequestBody,
ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse, VerificationKeyResponse,
VerifyCredentialBody, VerifyCredentialResponse,
};
use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse};
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
use url::Url;
#[cfg(feature = "nymd-client")]
use validator_api_requests::models::UptimeResponse;
use validator_api_requests::models::{
CoreNodeStatusResponse, MixnodeStatusResponse, RewardEstimationResponse,
StakeSaturationResponse,
};
#[cfg(feature = "nymd-client")]
use validator_api_requests::models::{MixNodeBondAnnotated, UptimeResponse};
#[cfg(feature = "nymd-client")]
use network_defaults::DEFAULT_NETWORK;
@@ -33,6 +29,8 @@ use mixnet_contract_common::{
};
#[cfg(feature = "nymd-client")]
use std::collections::{HashMap, HashSet};
#[cfg(feature = "nymd-client")]
use std::str::FromStr;
#[cfg(feature = "nymd-client")]
#[must_use]
@@ -41,9 +39,9 @@ pub struct Config {
network: network_defaults::all::Network,
api_url: Url,
nymd_url: Url,
mixnet_contract_address: cosmrs::AccountId,
vesting_contract_address: cosmrs::AccountId,
bandwidth_claim_contract_address: cosmrs::AccountId,
mixnet_contract_address: Option<cosmrs::AccountId>,
vesting_contract_address: Option<cosmrs::AccountId>,
erc20_bridge_contract_address: Option<cosmrs::AccountId>,
mixnode_page_limit: Option<u32>,
gateway_page_limit: Option<u32>,
@@ -53,22 +51,20 @@ pub struct Config {
#[cfg(feature = "nymd-client")]
impl Config {
pub fn new(network: network_defaults::all::Network, nymd_url: Url, api_url: Url) -> Self {
pub fn new(
network: network_defaults::all::Network,
nymd_url: Url,
api_url: Url,
mixnet_contract_address: Option<cosmrs::AccountId>,
vesting_contract_address: Option<cosmrs::AccountId>,
erc20_bridge_contract_address: Option<cosmrs::AccountId>,
) -> Self {
Config {
network,
nymd_url,
mixnet_contract_address: DEFAULT_NETWORK
.mixnet_contract_address()
.parse()
.expect("Error parsing mixnet contract address"),
vesting_contract_address: DEFAULT_NETWORK
.vesting_contract_address()
.parse()
.expect("Error parsing vesting contract address"),
bandwidth_claim_contract_address: DEFAULT_NETWORK
.bandwidth_claim_contract_address()
.parse()
.expect("Error parsing bandwidth claim contract address"),
mixnet_contract_address,
vesting_contract_address,
erc20_bridge_contract_address,
api_url,
mixnode_page_limit: None,
gateway_page_limit: None,
@@ -77,21 +73,6 @@ impl Config {
}
}
pub fn with_mixnode_contract_address(mut self, address: cosmrs::AccountId) -> Self {
self.mixnet_contract_address = address;
self
}
pub fn with_vesting_contract_address(mut self, address: cosmrs::AccountId) -> Self {
self.vesting_contract_address = address;
self
}
pub fn with_bandwidth_claim_contract_address(mut self, address: cosmrs::AccountId) -> Self {
self.bandwidth_claim_contract_address = address;
self
}
pub fn with_mixnode_page_limit(mut self, limit: Option<u32>) -> Config {
self.mixnode_page_limit = limit;
self
@@ -116,9 +97,9 @@ impl Config {
#[cfg(feature = "nymd-client")]
pub struct Client<C> {
pub network: network_defaults::all::Network,
mixnet_contract_address: cosmrs::AccountId,
vesting_contract_address: cosmrs::AccountId,
bandwidth_claim_contract_address: cosmrs::AccountId,
mixnet_contract_address: Option<cosmrs::AccountId>,
vesting_contract_address: Option<cosmrs::AccountId>,
erc20_bridge_contract_address: Option<cosmrs::AccountId>,
mnemonic: Option<bip39::Mnemonic>,
mixnode_page_limit: Option<u32>,
@@ -141,18 +122,18 @@ impl Client<SigningNymdClient> {
let nymd_client = NymdClient::connect_with_mnemonic(
config.network,
config.nymd_url.as_str(),
config.mixnet_contract_address.clone(),
config.vesting_contract_address.clone(),
config.erc20_bridge_contract_address.clone(),
mnemonic.clone(),
None,
)?
.with_mixnet_contract_address(config.mixnet_contract_address.clone())
.with_vesting_contract_address(config.vesting_contract_address.clone())
.with_bandwidth_claim_contract_address(config.bandwidth_claim_contract_address.clone());
)?;
Ok(Client {
network: config.network,
mixnet_contract_address: config.mixnet_contract_address,
vesting_contract_address: config.vesting_contract_address,
bandwidth_claim_contract_address: config.bandwidth_claim_contract_address,
erc20_bridge_contract_address: config.erc20_bridge_contract_address,
mnemonic: Some(mnemonic),
mixnode_page_limit: config.mixnode_page_limit,
gateway_page_limit: config.gateway_page_limit,
@@ -167,12 +148,12 @@ impl Client<SigningNymdClient> {
self.nymd = NymdClient::connect_with_mnemonic(
self.network,
new_endpoint.as_ref(),
self.mixnet_contract_address.clone(),
self.vesting_contract_address.clone(),
self.erc20_bridge_contract_address.clone(),
self.mnemonic.clone().unwrap(),
None,
)?
.with_mixnet_contract_address(self.mixnet_contract_address.clone())
.with_vesting_contract_address(self.vesting_contract_address.clone())
.with_bandwidth_claim_contract_address(self.bandwidth_claim_contract_address.clone());
)?;
Ok(())
}
@@ -185,15 +166,32 @@ impl Client<SigningNymdClient> {
impl Client<QueryNymdClient> {
pub fn new_query(config: Config) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
let validator_api_client = validator_api::Client::new(config.api_url.clone());
let nymd_client = NymdClient::connect(config.nymd_url.as_str())?
.with_mixnet_contract_address(config.mixnet_contract_address.clone())
.with_vesting_contract_address(config.vesting_contract_address.clone());
let nymd_client = NymdClient::connect(
config.nymd_url.as_str(),
Some(config.mixnet_contract_address.clone().unwrap_or_else(|| {
cosmrs::AccountId::from_str(DEFAULT_NETWORK.mixnet_contract_address()).unwrap()
})),
Some(config.vesting_contract_address.clone().unwrap_or_else(|| {
cosmrs::AccountId::from_str(DEFAULT_NETWORK.vesting_contract_address()).unwrap()
})),
Some(
config
.erc20_bridge_contract_address
.clone()
.unwrap_or_else(|| {
cosmrs::AccountId::from_str(
DEFAULT_NETWORK.bandwidth_claim_contract_address(),
)
.unwrap()
}),
),
)?;
Ok(Client {
network: config.network,
mixnet_contract_address: config.mixnet_contract_address,
vesting_contract_address: config.vesting_contract_address,
bandwidth_claim_contract_address: config.bandwidth_claim_contract_address,
erc20_bridge_contract_address: config.erc20_bridge_contract_address,
mnemonic: None,
mixnode_page_limit: config.mixnode_page_limit,
gateway_page_limit: config.gateway_page_limit,
@@ -205,10 +203,12 @@ impl Client<QueryNymdClient> {
}
pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> {
self.nymd = NymdClient::connect(new_endpoint.as_ref())?
.with_mixnet_contract_address(self.mixnet_contract_address.clone())
.with_vesting_contract_address(self.vesting_contract_address.clone())
.with_bandwidth_claim_contract_address(self.bandwidth_claim_contract_address.clone());
self.nymd = NymdClient::connect(
new_endpoint.as_ref(),
self.mixnet_contract_address.clone(),
self.vesting_contract_address.clone(),
self.erc20_bridge_contract_address.clone(),
)?;
Ok(())
}
}
@@ -222,10 +222,10 @@ impl<C> Client<C> {
// use case: somebody initialised client without a contract in order to upload and initialise one
// and now they want to actually use it without making new client
pub fn set_mixnet_contract_address(&mut self, mixnet_contract_address: cosmrs::AccountId) {
self.mixnet_contract_address = mixnet_contract_address
self.mixnet_contract_address = Some(mixnet_contract_address)
}
pub fn get_mixnet_contract_address(&self) -> cosmrs::AccountId {
pub fn get_mixnet_contract_address(&self) -> Option<cosmrs::AccountId> {
self.mixnet_contract_address.clone()
}
@@ -233,36 +233,18 @@ impl<C> Client<C> {
Ok(self.validator_api.get_mixnodes().await?)
}
pub async fn get_cached_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.validator_api.get_mixnodes_detailed().await?)
}
pub async fn get_cached_rewarded_mixnodes(
&self,
) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
Ok(self.validator_api.get_rewarded_mixnodes().await?)
}
pub async fn get_cached_rewarded_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.validator_api.get_rewarded_mixnodes_detailed().await?)
}
pub async fn get_cached_active_mixnodes(
&self,
) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
Ok(self.validator_api.get_active_mixnodes().await?)
}
pub async fn get_cached_active_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.validator_api.get_active_mixnodes_detailed().await?)
}
pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
Ok(self.validator_api.get_gateways().await?)
}
@@ -733,34 +715,4 @@ impl ApiClient {
) -> Result<VerificationKeyResponse, ValidatorClientError> {
Ok(self.validator_api.get_coconut_verification_key().await?)
}
pub async fn verify_bandwidth_credential(
&self,
request_body: &VerifyCredentialBody,
) -> Result<VerifyCredentialResponse, ValidatorClientError> {
Ok(self
.validator_api
.verify_bandwidth_credential(request_body)
.await?)
}
pub async fn propose_release_funds(
&self,
request_body: &ProposeReleaseFundsRequestBody,
) -> Result<ProposeReleaseFundsResponse, ValidatorClientError> {
Ok(self
.validator_api
.propose_release_funds(request_body)
.await?)
}
pub async fn execute_release_funds(
&self,
request_body: &ExecuteReleaseFundsRequestBody,
) -> Result<(), ValidatorClientError> {
Ok(self
.validator_api
.execute_release_funds(request_body)
.await?)
}
}
@@ -19,7 +19,7 @@ const CONNECTION_TEST_TIMEOUT_SEC: u64 = 2;
pub async fn run_validator_connection_test<H: BuildHasher + 'static>(
nymd_urls: impl Iterator<Item = (Network, Url)>,
api_urls: impl Iterator<Item = (Network, Url)>,
mixnet_contract_address: HashMap<Network, cosmrs::AccountId, H>,
mixnet_contract_address: HashMap<Network, Option<cosmrs::AccountId>, H>,
) -> (
HashMap<Network, Vec<(Url, bool)>>,
HashMap<Network, Vec<(Url, bool)>>,
@@ -47,15 +47,14 @@ pub async fn run_validator_connection_test<H: BuildHasher + 'static>(
fn setup_connection_tests<H: BuildHasher + 'static>(
nymd_urls: impl Iterator<Item = (Network, Url)>,
api_urls: impl Iterator<Item = (Network, Url)>,
mixnet_contract_address: HashMap<Network, cosmrs::AccountId, H>,
mixnet_contract_address: HashMap<Network, Option<cosmrs::AccountId>, H>,
) -> impl Iterator<Item = ClientForConnectionTest> {
let nymd_connection_test_clients = nymd_urls.filter_map(move |(network, url)| {
let address = mixnet_contract_address
.get(&network)
.expect("No configured contract address")
.clone();
NymdClient::<QueryNymdClient>::connect(url.as_str())
.map(|client| client.with_mixnet_contract_address(address))
NymdClient::<QueryNymdClient>::connect(url.as_str(), address, None, None)
.map(move |client| ClientForConnectionTest::Nymd(network, url, Box::new(client)))
.ok()
});
@@ -1,130 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize};
use std::fmt;
pub use cosmrs::Coin as CosmosCoin;
pub use cosmwasm_std::Coin as CosmWasmCoin;
#[derive(Serialize, Deserialize, Clone, Copy, Default, Debug, PartialEq)]
pub struct MismatchedDenoms;
// the reason the coin is created here as opposed to different place in the codebase is that
// eventually we want to either publish the cosmwasm client separately or commit it to
// some other project, like cosmrs. Either way, in that case we can't really have
// a dependency on an internal type
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq)]
pub struct Coin {
pub amount: u128,
pub denom: String,
}
impl Coin {
pub fn new<S: Into<String>>(amount: u128, denom: S) -> Self {
Coin {
amount,
denom: denom.into(),
}
}
pub fn try_add(&self, other: &Self) -> Result<Self, MismatchedDenoms> {
if self.denom != other.denom {
Err(MismatchedDenoms)
} else {
Ok(Coin {
amount: self.amount + other.amount,
denom: self.denom.clone(),
})
}
}
}
impl fmt::Display for Coin {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", self.amount, self.denom)
}
}
impl From<Coin> for CosmosCoin {
fn from(coin: Coin) -> Self {
assert!(
coin.amount <= u64::MAX as u128,
"the coin amount is higher than the maximum supported by cosmrs"
);
CosmosCoin {
denom: coin
.denom
.parse()
.expect("the coin should have had a valid denom!"),
amount: (coin.amount as u64).into(),
}
}
}
impl From<CosmosCoin> for Coin {
fn from(coin: CosmosCoin) -> Self {
Coin {
amount: coin
.amount
.to_string()
.parse()
.expect("somehow failed to parse string representation of u64"),
denom: coin.denom.to_string(),
}
}
}
impl From<Coin> for CosmWasmCoin {
fn from(coin: Coin) -> Self {
CosmWasmCoin::new(coin.amount, coin.denom)
}
}
impl From<CosmWasmCoin> for Coin {
fn from(coin: CosmWasmCoin) -> Self {
Coin {
amount: coin.amount.u128(),
denom: coin.denom,
}
}
}
pub trait CoinConverter {
type Target;
fn convert_coin(&self) -> Self::Target;
}
impl CoinConverter for CosmosCoin {
type Target = CosmWasmCoin;
fn convert_coin(&self) -> Self::Target {
CosmWasmCoin::new(
self.amount
.to_string()
.parse()
.expect("cosmos coin had an invalid amount assigned"),
self.denom.to_string(),
)
}
}
impl CoinConverter for CosmWasmCoin {
type Target = CosmosCoin;
fn convert_coin(&self) -> Self::Target {
assert!(
self.amount.u128() <= u64::MAX as u128,
"the coin amount is higher than the maximum supported by cosmrs"
);
CosmosCoin {
denom: self
.denom
.parse()
.expect("cosmwasm coin had an invalid amount assigned"),
amount: (self.amount.u128() as u64).into(),
}
}
}
@@ -1,7 +1,6 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nymd::coin::Coin;
use crate::nymd::cosmwasm_client::helpers::{create_pagination, next_page_key};
use crate::nymd::cosmwasm_client::types::{
Account, Code, CodeDetails, Contract, ContractCodeHistoryEntry, ContractCodeId,
@@ -26,7 +25,8 @@ use cosmrs::rpc::{self, HttpClient, Order};
use cosmrs::tendermint::abci::Code as AbciCode;
use cosmrs::tendermint::abci::Transaction;
use cosmrs::tendermint::{abci, block, chain};
use cosmrs::{tx, AccountId, Coin as CosmosCoin, Denom, Tx};
use cosmrs::{tx, AccountId, Coin, Denom, Tx};
use cosmwasm_std::Coin as CosmWasmCoin;
use prost::Message;
use serde::{Deserialize, Serialize};
use std::convert::{TryFrom, TryInto};
@@ -135,7 +135,7 @@ pub trait CosmWasmClient: rpc::Client {
.await?;
res.balance
.map(|proto| CosmosCoin::try_from(proto).map(Into::into))
.map(TryFrom::try_from)
.transpose()
.map_err(|_| NymdError::SerializationError("Coin".to_owned()))
}
@@ -166,12 +166,16 @@ pub trait CosmWasmClient: rpc::Client {
raw_balances
.into_iter()
.map(|proto| CosmosCoin::try_from(proto).map(Into::into))
.map(TryFrom::try_from)
.collect::<Result<_, _>>()
.map_err(|_| NymdError::SerializationError("Coins".to_owned()))
}
async fn get_total_supply(&self) -> Result<Vec<Coin>, NymdError> {
// this is annoyingly and inconsistently returning `Vec<CosmWasmCoin>` rather than
// Vec<Coin>, since cosmrs::Coin can't deal with IBC denoms.
// Presumably after https://github.com/cosmos/cosmos-rust/issues/173 is resolved,
// the code could be adjusted
async fn get_total_supply(&self) -> Result<Vec<CosmWasmCoin>, NymdError> {
let path = Some("/cosmos.bank.v1beta1.Query/TotalSupply".parse().unwrap());
let mut supply = Vec::new();
@@ -194,7 +198,12 @@ pub trait CosmWasmClient: rpc::Client {
supply
.into_iter()
.map(|proto| CosmosCoin::try_from(proto).map(Into::into))
.map(|coin| {
coin.amount.parse().map(|amount| CosmWasmCoin {
denom: coin.denom,
amount,
})
})
.collect::<Result<_, _>>()
.map_err(|_| NymdError::SerializationError("Coins".to_owned()))
}
@@ -474,9 +483,6 @@ pub trait CosmWasmClient: rpc::Client {
// deprecation warning is due to the fact the protobuf files built were based on cosmos-sdk 0.44,
// where they prefer using tx_bytes directly. However, in 0.42, which we are using at the time
// of writing this, the option does not work
// TODO: we should really stop using the `tx` argument here and use `tx_bytes` exlusively,
// however, at the time of writing this update, while our QA and mainnet networks do support it,
// sandbox is still running old version of wasmd that lacks support for `tx_bytes`
#[allow(deprecated)]
async fn query_simulate(
&self,
@@ -68,7 +68,6 @@ pub(crate) fn create_pagination(key: Vec<u8>) -> PageRequest {
offset: 0,
limit: 0,
count_total: false,
reverse: false,
}
}
@@ -22,7 +22,7 @@ pub struct Log {
/// Searches in logs for the first event of the given event type and in that event
/// for the first attribute with the given attribute key.
pub fn find_attribute<'a>(
pub(crate) fn find_attribute<'a>(
logs: &'a [Log],
event_type: &str,
attribute_key: &str,
@@ -1,14 +1,9 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nymd::cosmwasm_client::client::CosmWasmClient;
use crate::nymd::cosmwasm_client::helpers::{compress_wasm_code, CheckResponse};
use crate::nymd::cosmwasm_client::logs::{self, parse_raw_logs};
use crate::nymd::cosmwasm_client::types::*;
use crate::nymd::error::NymdError;
use crate::nymd::fee::{Fee, DEFAULT_SIMULATED_GAS_MULTIPLIER};
use crate::nymd::wallet::DirectSecp256k1HdWallet;
use crate::nymd::{Coin, GasPrice, TxResponse};
use std::convert::TryInto;
use std::time::Duration;
use async_trait::async_trait;
use cosmrs::bank::MsgSend;
use cosmrs::distribution::MsgWithdrawDelegatorReward;
@@ -17,40 +12,33 @@ use cosmrs::rpc::endpoint::broadcast;
use cosmrs::rpc::{Error as TendermintRpcError, HttpClient, HttpClientUrl, SimpleRequest};
use cosmrs::staking::{MsgDelegate, MsgUndelegate};
use cosmrs::tx::{self, Msg, SignDoc, SignerInfo};
use cosmrs::{cosmwasm, rpc, AccountId, Any, Tx};
use cosmrs::{cosmwasm, rpc, AccountId, Any, Coin, Tx};
use log::debug;
use serde::Serialize;
use sha2::Digest;
use sha2::Sha256;
use std::convert::TryInto;
use std::time::Duration;
use crate::nymd::cosmwasm_client::client::CosmWasmClient;
use crate::nymd::cosmwasm_client::helpers::{compress_wasm_code, CheckResponse};
use crate::nymd::cosmwasm_client::logs::{self, parse_raw_logs};
use crate::nymd::cosmwasm_client::types::*;
use crate::nymd::error::NymdError;
use crate::nymd::fee::{Fee, DEFAULT_SIMULATED_GAS_MULTIPLIER};
use crate::nymd::wallet::DirectSecp256k1HdWallet;
use crate::nymd::{CosmosCoin, GasPrice, TxResponse};
// we need to have **a** valid secp256k1 signature for simulation purposes.
// it doesn't matter what it is as long as it parses correctly
const DUMMY_SECP256K1_SIGNATURE: &[u8] = &[
54, 167, 169, 61, 100, 173, 231, 87, 1, 113, 179, 49, 102, 141, 67, 22, 170, 153, 52, 88, 178,
159, 200, 11, 37, 138, 76, 221, 187, 70, 104, 123, 98, 216, 190, 249, 149, 81, 1, 158, 0, 220,
32, 147, 101, 60, 64, 77, 44, 83, 221, 119, 170, 124, 109, 177, 73, 116, 46, 57, 102, 181, 98,
91,
];
const DEFAULT_BROADCAST_POLLING_RATE: Duration = Duration::from_secs(4);
const DEFAULT_BROADCAST_TIMEOUT: Duration = Duration::from_secs(60);
fn empty_fee() -> tx::Fee {
tx::Fee {
amount: vec![],
gas_limit: Default::default(),
payer: None,
granter: None,
}
}
fn single_unspecified_signer_auth(
public_key: Option<tx::SignerPublicKey>,
sequence_number: tx::SequenceNumber,
) -> tx::AuthInfo {
tx::SignerInfo {
public_key,
mode_info: tx::ModeInfo::Single(tx::mode_info::Single {
mode: SignMode::Unspecified,
}),
sequence: sequence_number,
}
.auth_info(empty_fee())
}
#[async_trait]
pub trait SigningCosmWasmClient: CosmWasmClient {
fn signer(&self) -> &DirectSecp256k1HdWallet;
@@ -76,21 +64,33 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
let sequence_response = self.get_sequence(signer_address).await?;
let partial_tx = Tx {
body: tx::Body::new(messages, memo, 0u32),
auth_info: single_unspecified_signer_auth(public_key, sequence_response.sequence),
signatures: vec![Vec::new()],
body: tx::Body {
messages,
memo: memo.into(),
timeout_height: 0u32.into(),
extension_options: vec![],
non_critical_extension_options: vec![],
},
auth_info: tx::AuthInfo {
signer_infos: vec![tx::SignerInfo {
public_key,
mode_info: tx::ModeInfo::Single(tx::mode_info::Single {
mode: SignMode::Unspecified,
}),
sequence: sequence_response.sequence,
}],
fee: tx::Fee::from_amount_and_gas(
CosmosCoin {
denom: "".parse().unwrap(),
amount: 0u64.into(),
},
0,
),
},
signatures: vec![DUMMY_SECP256K1_SIGNATURE.try_into().unwrap()],
};
self.query_simulate(Some(partial_tx), Vec::new()).await
// for completion sake, once we're able to transition into using `tx_bytes`,
// we might want to use something like this instead:
// let tx_raw: tx::Raw = cosmrs::proto::cosmos::tx::v1beta1::TxRaw {
// body_bytes: partial_tx.body.into_bytes().unwrap(),
// auth_info_bytes: partial_tx.auth_info.into_bytes().unwrap(),
// signatures: partial_tx.signatures,
// }
// .into();
// self.query_simulate(None, tx_raw.to_bytes().unwrap()).await
self.query_simulate(Some(partial_tx), Vec::new()).await
}
async fn upload(
@@ -310,7 +310,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
sender: sender_address.clone(),
contract: contract_address.clone(),
msg: serde_json::to_vec(msg)?,
funds: funds.into_iter().map(Into::into).collect(),
funds,
}
.to_any()
.map_err(|_| NymdError::SerializationError("MsgExecuteContract".to_owned()))?;
@@ -349,7 +349,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
sender: sender_address.clone(),
contract: contract_address.clone(),
msg: serde_json::to_vec(&msg)?,
funds: funds.into_iter().map(Into::into).collect(),
funds,
}
.to_any()
.map_err(|_| NymdError::SerializationError("MsgExecuteContract".to_owned()))
@@ -382,7 +382,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
let send_msg = MsgSend {
from_address: sender_address.clone(),
to_address: recipient_address.clone(),
amount: amount.into_iter().map(Into::into).collect(),
amount,
}
.to_any()
.map_err(|_| NymdError::SerializationError("MsgSend".to_owned()))?;
@@ -408,7 +408,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
MsgSend {
from_address: sender_address.clone(),
to_address,
amount: amount.into_iter().map(Into::into).collect(),
amount,
}
.to_any()
.map_err(|_| NymdError::SerializationError("MsgExecuteContract".to_owned()))
@@ -431,7 +431,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
let delegate_msg = MsgDelegate {
delegator_address: delegator_address.to_owned(),
validator_address: validator_address.to_owned(),
amount: amount.into(),
amount,
}
.to_any()
.map_err(|_| NymdError::SerializationError("MsgDelegate".to_owned()))?;
@@ -452,7 +452,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
let undelegate_msg = MsgUndelegate {
delegator_address: delegator_address.to_owned(),
validator_address: validator_address.to_owned(),
amount: amount.into(),
amount: Some(amount),
}
.to_any()
.map_err(|_| NymdError::SerializationError("MsgUndelegate".to_owned()))?;
@@ -28,7 +28,7 @@ use cosmrs::proto::cosmwasm::wasm::v1::{
use cosmrs::tendermint::abci::Data;
use cosmrs::tendermint::{abci, chain};
use cosmrs::tx::{AccountNumber, Gas, SequenceNumber};
use cosmrs::{tx, AccountId, Any, Coin as CosmosCoin};
use cosmrs::{tx, AccountId, Any, Coin};
use prost::Message;
use serde::Serialize;
use std::convert::{TryFrom, TryInto};
@@ -107,9 +107,9 @@ impl TryFrom<ProtoModuleAccount> for ModuleAccount {
#[derive(Debug)]
pub struct BaseVestingAccount {
pub base_account: Option<BaseAccount>,
pub original_vesting: Vec<CosmosCoin>,
pub delegated_free: Vec<CosmosCoin>,
pub delegated_vesting: Vec<CosmosCoin>,
pub original_vesting: Vec<Coin>,
pub delegated_free: Vec<Coin>,
pub delegated_vesting: Vec<Coin>,
pub end_time: i64,
}
@@ -184,7 +184,7 @@ impl TryFrom<ProtoDelayedVestingAccount> for DelayedVestingAccount {
#[derive(Debug)]
pub struct Period {
pub length: i64,
pub amount: Vec<CosmosCoin>,
pub amount: Vec<Coin>,
}
impl TryFrom<ProtoPeriod> for Period {
@@ -489,7 +489,7 @@ impl TryFrom<ProtoContractCodeHistoryEntry> for ContractCodeHistoryEntry {
}
}
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
#[derive(Debug)]
pub struct GasInfo {
/// GasWanted is the maximum units of work we allow this tx to perform.
pub gas_wanted: Gas,
@@ -628,7 +628,7 @@ pub struct InstantiateOptions {
/// created and before the instantiation message is executed by the contract.
///
/// Only native tokens are supported.
pub funds: Vec<CosmosCoin>,
pub funds: Vec<Coin>,
/// A bech32 encoded address of an admin account.
/// Caution: an admin has the privilege to upgrade a contract.
@@ -636,15 +636,6 @@ pub struct InstantiateOptions {
pub admin: Option<AccountId>,
}
impl InstantiateOptions {
pub fn new<T: Into<CosmosCoin>>(funds: Vec<T>, admin: Option<AccountId>) -> Self {
InstantiateOptions {
funds: funds.into_iter().map(Into::into).collect(),
admin,
}
}
}
#[derive(Debug)]
pub struct InstantiateResult {
/// The address of the newly instantiated contract
@@ -21,12 +21,9 @@ pub enum NymdError {
#[error("There was an issue with bip32 - {0}")]
Bip32Error(#[from] bip32::Error),
#[error("There was an issue with bip39 - {0}")]
#[error("There was an issue with bip32 - {0}")]
Bip39Error(#[from] bip39::Error),
#[error("There was an issue on the cosmrs side - {0}")]
CosmrsError(#[from] cosmrs::Error),
#[error("Failed to derive account address")]
AccountDerivationError,
@@ -42,10 +39,10 @@ pub enum NymdError {
#[error("There was an issue with a tendermint RPC request - {0}")]
TendermintError(#[from] TendermintRpcError),
#[error("There was an issue when attempting to serialize data ({0})")]
#[error("There was an issue when attempting to serialize data")]
SerializationError(String),
#[error("There was an issue when attempting to deserialize data ({0})")]
#[error("There was an issue when attempting to deserialize data")]
DeserializationError(String),
#[error("There was an issue when attempting to encode our protobuf data - {0}")]
@@ -124,12 +121,6 @@ pub enum NymdError {
#[error("Transaction with ID {hash} has been submitted but not yet found on the chain. You might want to check for it later. There was a total wait of {} seconds", .timeout.as_secs())]
BroadcastTimeout { hash: tx::Hash, timeout: Duration },
#[error("Cosmwasm std error: {0}")]
CosmwasmStdError(#[from] cosmwasm_std::StdError),
#[error("Coconut interface error: {0}")]
CoconutInterfaceError(#[from] coconut_interface::error::CoconutInterfaceError),
}
impl NymdError {
@@ -4,7 +4,7 @@
use crate::nymd::error::NymdError;
use config::defaults;
use cosmrs::tx::Gas;
use cosmrs::Coin;
use cosmrs::{Coin, Denom};
use cosmwasm_std::{Decimal, Fraction, Uint128};
use std::ops::Mul;
use std::str::FromStr;
@@ -13,12 +13,11 @@ use std::str::FromStr;
/// the smallest fee token unit, such as 0.012utoken.
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct GasPrice {
// I really dislike the usage of cosmwasm Decimal, but I didn't feel like implementing
// our own maths subcrate just for the purposes of calculating gas requirements
// this should definitely be rectified later on
// I really hate the combination of cosmwasm Decimal with cosmos-sdk Denom,
// but cosmos-sdk's Decimal is too basic for our needs
pub amount: Decimal,
pub denom: String,
pub denom: Denom,
}
impl<'a> Mul<Gas> for &'a GasPrice {
@@ -45,10 +44,7 @@ impl<'a> Mul<Gas> for &'a GasPrice {
assert!(amount.u128() <= u64::MAX as u128);
Coin {
denom: self
.denom
.parse()
.expect("the gas price has been created with invalid denom"),
denom: self.denom.clone(),
amount: (amount.u128() as u64).into(),
}
}
@@ -67,7 +63,9 @@ impl FromStr for GasPrice {
.parse()
.map_err(|_| NymdError::MalformedGasPrice)?;
let possible_denom = s.chars().skip(amount_len).collect::<String>();
let denom = possible_denom.trim().to_string();
let denom = possible_denom
.parse()
.map_err(|_| NymdError::MalformedGasPrice)?;
Ok(GasPrice { amount, denom })
}
@@ -108,14 +106,8 @@ mod tests {
);
assert!(".25upunk".parse::<GasPrice>().is_err());
assert_eq!(
"0.025upunk".parse::<GasPrice>().unwrap(),
"0.025 upunk".parse().unwrap()
);
let gas: GasPrice = "0.025 upunk ".parse().unwrap();
assert_eq!("upunk", gas.denom);
assert!("0.025 upunk".parse::<GasPrice>().is_err());
assert!("0.025UPUNK".parse::<GasPrice>().is_err());
}
#[test]
@@ -0,0 +1,195 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nymd::GasPrice;
use cosmrs::tx::{Fee, Gas};
use cosmrs::Coin;
use serde::{Deserialize, Serialize};
use std::fmt;
#[cfg_attr(test, derive(ts_rs::TS))]
#[cfg_attr(
test,
ts(export, export_to = "../../../nym-wallet/src/types/rust/operation.ts")
)]
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum Operation {
Upload,
Init,
Migrate,
ChangeAdmin,
Send,
BondMixnode,
BondMixnodeOnBehalf,
UnbondMixnode,
UnbondMixnodeOnBehalf,
UpdateMixnodeConfig,
DelegateToMixnode,
DelegateToMixnodeOnBehalf,
UndelegateFromMixnode,
UndelegateFromMixnodeOnBehalf,
BondGateway,
BondGatewayOnBehalf,
UnbondGateway,
UnbondGatewayOnBehalf,
UpdateContractSettings,
BeginMixnodeRewarding,
FinishMixnodeRewarding,
TrackUnbondGateway,
TrackUnbondMixnode,
WithdrawVestedCoins,
TrackUndelegation,
CreatePeriodicVestingAccount,
AdvanceCurrentInterval,
AdvanceCurrentEpoch,
WriteRewardedSet,
ClearRewardedSet,
UpdateMixnetAddress,
CheckpointMixnodes,
ReconcileDelegations,
}
pub(crate) fn calculate_fee(gas_price: &GasPrice, gas_limit: Gas) -> Coin {
gas_price * gas_limit
}
impl fmt::Display for Operation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Operation::Upload => f.write_str("Upload"),
Operation::Init => f.write_str("Init"),
Operation::Migrate => f.write_str("Migrate"),
Operation::ChangeAdmin => f.write_str("ChangeAdmin"),
Operation::Send => f.write_str("Send"),
Operation::BondMixnode => f.write_str("BondMixnode"),
Operation::BondMixnodeOnBehalf => f.write_str("BondMixnodeOnBehalf"),
Operation::UnbondMixnode => f.write_str("UnbondMixnode"),
Operation::UpdateMixnodeConfig => f.write_str("UpdateMixnodeConfig"),
Operation::UnbondMixnodeOnBehalf => f.write_str("UnbondMixnodeOnBehalf"),
Operation::BondGateway => f.write_str("BondGateway"),
Operation::BondGatewayOnBehalf => f.write_str("BondGatewayOnBehalf"),
Operation::UnbondGateway => f.write_str("UnbondGateway"),
Operation::UnbondGatewayOnBehalf => f.write_str("UnbondGatewayOnBehalf"),
Operation::DelegateToMixnode => f.write_str("DelegateToMixnode"),
Operation::DelegateToMixnodeOnBehalf => f.write_str("DelegateToMixnodeOnBehalf"),
Operation::UndelegateFromMixnode => f.write_str("UndelegateFromMixnode"),
Operation::UndelegateFromMixnodeOnBehalf => {
f.write_str("UndelegateFromMixnodeOnBehalf")
}
Operation::UpdateContractSettings => f.write_str("UpdateContractSettings"),
Operation::BeginMixnodeRewarding => f.write_str("BeginMixnodeRewarding"),
Operation::FinishMixnodeRewarding => f.write_str("FinishMixnodeRewarding"),
Operation::TrackUnbondGateway => f.write_str("TrackUnbondGateway"),
Operation::TrackUnbondMixnode => f.write_str("TrackUnbondMixnode"),
Operation::WithdrawVestedCoins => f.write_str("WithdrawVestedCoins"),
Operation::TrackUndelegation => f.write_str("TrackUndelegation"),
Operation::CreatePeriodicVestingAccount => f.write_str("CreatePeriodicVestingAccount"),
Operation::AdvanceCurrentInterval => f.write_str("AdvanceCurrentInterval"),
Operation::WriteRewardedSet => f.write_str("WriteRewardedSet"),
Operation::ClearRewardedSet => f.write_str("ClearRewardedSet"),
Operation::UpdateMixnetAddress => f.write_str("UpdateMixnetAddress"),
Operation::CheckpointMixnodes => f.write_str("CheckpointMixnodes"),
Operation::ReconcileDelegations => f.write_str("ReconcileDelegations"),
Operation::AdvanceCurrentEpoch => f.write_str("AdvanceCurrentEpoch"),
}
}
}
impl Operation {
// TODO: some value tweaking
pub fn default_gas_limit(&self) -> Gas {
match self {
Operation::Upload => 3_000_000u64.into(),
Operation::Init => 500_000u64.into(),
Operation::Migrate => 200_000u64.into(),
Operation::ChangeAdmin => 80_000u64.into(),
Operation::Send => 80_000u64.into(),
Operation::BondMixnode => 175_000u64.into(),
Operation::BondMixnodeOnBehalf => 200_000u64.into(),
Operation::UnbondMixnode => 175_000u64.into(),
Operation::UnbondMixnodeOnBehalf => 175_000u64.into(),
Operation::UpdateMixnodeConfig => 175_000u64.into(),
Operation::DelegateToMixnode => 175_000u64.into(),
Operation::DelegateToMixnodeOnBehalf => 175_000u64.into(),
Operation::UndelegateFromMixnode => 175_000u64.into(),
Operation::UndelegateFromMixnodeOnBehalf => 175_000u64.into(),
Operation::BondGateway => 175_000u64.into(),
Operation::BondGatewayOnBehalf => 200_000u64.into(),
Operation::UnbondGateway => 175_000u64.into(),
Operation::UnbondGatewayOnBehalf => 200_000u64.into(),
Operation::UpdateContractSettings => 175_000u64.into(),
Operation::BeginMixnodeRewarding => 175_000u64.into(),
Operation::FinishMixnodeRewarding => 175_000u64.into(),
Operation::TrackUnbondGateway => 175_000u64.into(),
Operation::TrackUnbondMixnode => 175_000u64.into(),
Operation::WithdrawVestedCoins => 175_000u64.into(),
Operation::TrackUndelegation => 175_000u64.into(),
Operation::CreatePeriodicVestingAccount => 175_000u64.into(),
Operation::AdvanceCurrentInterval => 175_000u64.into(),
Operation::WriteRewardedSet => 175_000u64.into(),
Operation::ClearRewardedSet => 175_000u64.into(),
Operation::UpdateMixnetAddress => 80_000u64.into(),
Operation::CheckpointMixnodes => 175_000u64.into(),
Operation::ReconcileDelegations => 500_000u64.into(),
Operation::AdvanceCurrentEpoch => 175_000u64.into(),
}
}
pub(crate) fn determine_custom_fee(gas_price: &GasPrice, gas_limit: Gas) -> Fee {
// we need to know 2 of the following 3 parameters (the third one is being implicit) in order to construct Fee:
// (source: https://docs.cosmos.network/v0.42/basics/gas-fees.html)
// - gas price
// - gas limit
// - fees
let fee = calculate_fee(gas_price, gas_limit);
Fee::from_amount_and_gas(fee, gas_limit)
}
pub fn default_fee(&self, gas_price: &GasPrice) -> Fee {
Self::determine_custom_fee(gas_price, self.default_gas_limit())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn calculating_fee() {
let expected = Coin {
denom: "upunk".parse().unwrap(),
amount: 1000u64.into(),
};
let gas_price = "1upunk".parse().unwrap();
let gas_limit = 1000u64.into();
assert_eq!(expected, calculate_fee(&gas_price, gas_limit));
let expected = Coin {
denom: "upunk".parse().unwrap(),
amount: 50u64.into(),
};
let gas_price = "0.05upunk".parse().unwrap();
let gas_limit = 1000u64.into();
assert_eq!(expected, calculate_fee(&gas_price, gas_limit));
let expected = Coin {
denom: "upunk".parse().unwrap(),
amount: 100000u64.into(),
};
let gas_price = "100upunk".parse().unwrap();
let gas_limit = 1000u64.into();
assert_eq!(expected, calculate_fee(&gas_price, gas_limit))
}
}
@@ -2,15 +2,15 @@
// SPDX-License-Identifier: Apache-2.0
use cosmrs::tx;
use serde::{Deserialize, Serialize};
pub mod gas_price;
pub mod helpers;
pub const DEFAULT_SIMULATED_GAS_MULTIPLIER: f32 = 1.3;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone)]
pub enum Fee {
Manual(#[serde(with = "sealed::TxFee")] tx::Fee),
Manual(tx::Fee),
Auto(Option<f32>),
}
@@ -31,91 +31,3 @@ impl Default for Fee {
Fee::Auto(Some(DEFAULT_SIMULATED_GAS_MULTIPLIER))
}
}
// a workaround to provide serde implementation for tx::Fee. We don't want to ever expose any of those
// types to the public and ideally they will get replaced by proper implementation inside comrs
mod sealed {
use cosmrs::tx::{self, Gas};
use cosmrs::Coin as CosmosCoin;
use cosmrs::{AccountId, Decimal as CosmosDecimal, Denom as CosmosDenom};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
fn cosmos_denom_inner_getter(val: &CosmosDenom) -> String {
val.as_ref().to_string()
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "CosmosDenom")]
struct Denom(#[serde(getter = "cosmos_denom_inner_getter")] String);
impl From<Denom> for CosmosDenom {
fn from(val: Denom) -> Self {
val.0.parse().unwrap()
}
}
fn cosmos_decimal_inner_getter(val: &CosmosDecimal) -> u64 {
// haha, this code is so disgusting. I'll make a PR on cosmrs to slightly alleviate those issues...
// note: unwrap here is fine as the to_string is just returning a stringified u64 which, well, is a valid u64
val.to_string().parse().unwrap()
}
// at the time of writing it the current cosmrs' Decimal is extremely limited...
#[derive(Serialize, Deserialize)]
#[serde(remote = "CosmosDecimal")]
struct Decimal(#[serde(getter = "cosmos_decimal_inner_getter")] u64);
impl From<Decimal> for CosmosDecimal {
fn from(val: Decimal) -> Self {
val.0.into()
}
}
#[derive(Serialize, Deserialize, Clone)]
struct Coin {
#[serde(with = "Denom")]
denom: CosmosDenom,
#[serde(with = "Decimal")]
amount: CosmosDecimal,
}
impl From<Coin> for CosmosCoin {
fn from(val: Coin) -> Self {
CosmosCoin {
denom: val.denom,
amount: val.amount,
}
}
}
impl From<CosmosCoin> for Coin {
fn from(val: CosmosCoin) -> Self {
Coin {
denom: val.denom,
amount: val.amount,
}
}
}
fn coin_vec_ser<S: Serializer>(val: &[CosmosCoin], serializer: S) -> Result<S::Ok, S::Error> {
let vec: Vec<Coin> = val.iter().cloned().map(Into::into).collect();
vec.serialize(serializer)
}
fn coin_vec_deser<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Vec<CosmosCoin>, D::Error> {
let vec: Vec<Coin> = Deserialize::deserialize(deserializer)?;
Ok(vec.iter().cloned().map(Into::into).collect())
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "tx::Fee")]
pub(super) struct TxFee {
#[serde(serialize_with = "coin_vec_ser")]
#[serde(deserialize_with = "coin_vec_deser")]
pub amount: Vec<CosmosCoin>,
pub gas_limit: Gas,
pub payer: Option<AccountId>,
pub granter: Option<AccountId>,
}
}
File diff suppressed because it is too large Load Diff
@@ -1,49 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient;
use crate::nymd::cosmwasm_client::types::ExecuteResult;
use crate::nymd::error::NymdError;
use crate::nymd::{Coin, Fee, NymdClient};
use coconut_bandwidth_contract_common::{deposit::DepositData, msg::ExecuteMsg};
use async_trait::async_trait;
#[async_trait]
pub trait CoconutBandwidthSigningClient {
async fn deposit(
&self,
amount: Coin,
info: String,
verification_key: String,
encryption_key: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
}
#[async_trait]
impl<C: SigningCosmWasmClient + Sync + Send> CoconutBandwidthSigningClient for NymdClient<C> {
async fn deposit(
&self,
amount: Coin,
info: String,
verification_key: String,
encryption_key: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let req = ExecuteMsg::DepositFunds {
data: DepositData::new(info.to_string(), verification_key, encryption_key),
};
self.client
.execute(
self.address(),
self.coconut_bandwidth_contract_address(),
&req,
fee,
"CoconutBandwidth::Deposit",
vec![amount],
)
.await
}
}
@@ -1,14 +1,8 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
mod coconut_bandwidth_signing_client;
mod multisig_query_client;
mod multisig_signing_client;
mod vesting_query_client;
mod vesting_signing_client;
pub use coconut_bandwidth_signing_client::CoconutBandwidthSigningClient;
pub use multisig_query_client::QueryClient;
pub use multisig_signing_client::MultisigSigningClient;
pub use vesting_query_client::VestingQueryClient;
pub use vesting_signing_client::VestingSigningClient;
@@ -1,24 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nymd::error::NymdError;
use crate::nymd::{CosmWasmClient, NymdClient};
use multisig_contract_common::msg::{ProposalResponse, QueryMsg};
use async_trait::async_trait;
#[async_trait]
pub trait QueryClient {
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NymdError>;
}
#[async_trait]
impl<C: CosmWasmClient + Sync + Send> QueryClient for NymdClient<C> {
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NymdError> {
let request = QueryMsg::Proposal { proposal_id };
self.client
.query_contract_smart(self.multisig_contract_address(), &request)
.await
}
}
@@ -1,116 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient;
use crate::nymd::cosmwasm_client::types::ExecuteResult;
use crate::nymd::error::NymdError;
use crate::nymd::{Fee, NymdClient};
use coconut_bandwidth_contract_common::msg::ExecuteMsg as CoconutBandwidthExecuteMsg;
use multisig_contract_common::msg::ExecuteMsg;
use async_trait::async_trait;
use cosmwasm_std::{to_binary, Coin, CosmosMsg, WasmMsg};
use cw3::Vote;
use network_defaults::DEFAULT_NETWORK;
#[async_trait]
pub trait MultisigSigningClient {
async fn propose_release_funds(
&self,
title: String,
blinded_serial_number: String,
voucher_value: u128,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
async fn vote_proposal(
&self,
proposal_id: u64,
yes: bool,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
async fn execute_proposal(
&self,
proposal_id: u64,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
}
#[async_trait]
impl<C: SigningCosmWasmClient + Sync + Send> MultisigSigningClient for NymdClient<C> {
async fn propose_release_funds(
&self,
title: String,
blinded_serial_number: String,
voucher_value: u128,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let release_funds_req = CoconutBandwidthExecuteMsg::ReleaseFunds {
funds: Coin::new(voucher_value, DEFAULT_NETWORK.denom()),
};
let release_funds_msg = CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: self.coconut_bandwidth_contract_address().to_string(),
msg: to_binary(&release_funds_req)?,
funds: vec![],
});
let req = ExecuteMsg::Propose {
title,
description: blinded_serial_number,
msgs: vec![release_funds_msg],
latest: None,
};
self.client
.execute(
self.address(),
self.multisig_contract_address(),
&req,
fee,
"Multisig::Propose::Execute::ReleaseFunds",
vec![],
)
.await
}
async fn vote_proposal(
&self,
proposal_id: u64,
vote_yes: bool,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let vote = if vote_yes { Vote::Yes } else { Vote::No };
let req = ExecuteMsg::Vote { proposal_id, vote };
self.client
.execute(
self.address(),
self.multisig_contract_address(),
&req,
fee,
"Multisig::Vote",
vec![],
)
.await
}
async fn execute_proposal(
&self,
proposal_id: u64,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let req = ExecuteMsg::Execute { proposal_id };
self.client
.execute(
self.address(),
self.multisig_contract_address(),
&req,
fee,
"Multisig::Execute",
vec![],
)
.await
}
}
@@ -1,12 +1,11 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nymd::coin::Coin;
pub use crate::nymd::cosmwasm_client::client::CosmWasmClient;
use crate::nymd::error::NymdError;
use crate::nymd::NymdClient;
use async_trait::async_trait;
use cosmwasm_std::{Coin as CosmWasmCoin, Timestamp};
use cosmwasm_std::{Coin, Timestamp};
use vesting_contract::vesting::Account;
use vesting_contract_common::{
messages::QueryMsg as VestingQueryMsg, OriginalVestingResponse, Period, PledgeData,
@@ -84,9 +83,8 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
block_time,
};
self.client
.query_contract_smart::<_, CosmWasmCoin>(self.vesting_contract_address(), &request)
.query_contract_smart(self.vesting_contract_address()?, &request)
.await
.map(Into::into)
}
async fn spendable_coins(
@@ -99,9 +97,8 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
block_time,
};
self.client
.query_contract_smart::<_, CosmWasmCoin>(self.vesting_contract_address(), &request)
.query_contract_smart(self.vesting_contract_address()?, &request)
.await
.map(Into::into)
}
async fn vested_coins(
&self,
@@ -113,9 +110,8 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
block_time,
};
self.client
.query_contract_smart::<_, CosmWasmCoin>(self.vesting_contract_address(), &request)
.query_contract_smart(self.vesting_contract_address()?, &request)
.await
.map(Into::into)
}
async fn vesting_coins(
&self,
@@ -127,9 +123,8 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
block_time,
};
self.client
.query_contract_smart::<_, CosmWasmCoin>(self.vesting_contract_address(), &request)
.query_contract_smart(self.vesting_contract_address()?, &request)
.await
.map(Into::into)
}
async fn vesting_start_time(
@@ -140,7 +135,7 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
vesting_account_address: vesting_account_address.to_string(),
};
self.client
.query_contract_smart(self.vesting_contract_address(), &request)
.query_contract_smart(self.vesting_contract_address()?, &request)
.await
}
@@ -152,7 +147,7 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
vesting_account_address: vesting_account_address.to_string(),
};
self.client
.query_contract_smart(self.vesting_contract_address(), &request)
.query_contract_smart(self.vesting_contract_address()?, &request)
.await
}
@@ -164,7 +159,7 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
vesting_account_address: vesting_account_address.to_string(),
};
self.client
.query_contract_smart(self.vesting_contract_address(), &request)
.query_contract_smart(self.vesting_contract_address()?, &request)
.await
}
@@ -178,9 +173,8 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
block_time,
};
self.client
.query_contract_smart::<_, CosmWasmCoin>(self.vesting_contract_address(), &request)
.query_contract_smart(self.vesting_contract_address()?, &request)
.await
.map(Into::into)
}
async fn delegated_vesting(
@@ -193,9 +187,8 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
block_time,
};
self.client
.query_contract_smart::<_, CosmWasmCoin>(self.vesting_contract_address(), &request)
.query_contract_smart(self.vesting_contract_address()?, &request)
.await
.map(Into::into)
}
async fn get_account(&self, address: &str) -> Result<Account, NymdError> {
@@ -203,7 +196,7 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
address: address.to_string(),
};
self.client
.query_contract_smart(self.vesting_contract_address(), &request)
.query_contract_smart(self.vesting_contract_address()?, &request)
.await
}
async fn get_mixnode_pledge(&self, address: &str) -> Result<Option<PledgeData>, NymdError> {
@@ -211,7 +204,7 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
address: address.to_string(),
};
self.client
.query_contract_smart(self.vesting_contract_address(), &request)
.query_contract_smart(self.vesting_contract_address()?, &request)
.await
}
async fn get_gateway_pledge(&self, address: &str) -> Result<Option<PledgeData>, NymdError> {
@@ -219,7 +212,7 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
address: address.to_string(),
};
self.client
.query_contract_smart(self.vesting_contract_address(), &request)
.query_contract_smart(self.vesting_contract_address()?, &request)
.await
}
@@ -228,7 +221,7 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
address: address.to_string(),
};
self.client
.query_contract_smart(self.vesting_contract_address(), &request)
.query_contract_smart(self.vesting_contract_address()?, &request)
.await
}
}
@@ -4,8 +4,10 @@
pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient;
use crate::nymd::cosmwasm_client::types::ExecuteResult;
use crate::nymd::error::NymdError;
use crate::nymd::{Coin, Fee, NymdClient};
use crate::nymd::fee::helpers::Operation;
use crate::nymd::{cosmwasm_coin_to_cosmos_coin, NymdClient};
use async_trait::async_trait;
use cosmwasm_std::Coin;
use mixnet_contract_common::{Gateway, IdentityKey, IdentityKeyRef, MixNode};
use vesting_contract_common::messages::{ExecuteMsg as VestingExecuteMsg, VestingSpecification};
@@ -14,30 +16,23 @@ pub trait VestingSigningClient {
async fn vesting_update_mixnode_config(
&self,
profix_margin_percent: u8,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
async fn update_mixnet_address(
&self,
address: &str,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
async fn update_mixnet_address(&self, address: &str) -> Result<ExecuteResult, NymdError>;
async fn vesting_bond_gateway(
&self,
gateway: Gateway,
owner_signature: &str,
pledge: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
async fn vesting_unbond_gateway(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError>;
async fn vesting_unbond_gateway(&self) -> Result<ExecuteResult, NymdError>;
async fn vesting_track_unbond_gateway(
&self,
owner: &str,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
async fn vesting_bond_mixnode(
@@ -45,42 +40,33 @@ pub trait VestingSigningClient {
mix_node: MixNode,
owner_signature: &str,
pledge: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
async fn vesting_unbond_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError>;
async fn vesting_unbond_mixnode(&self) -> Result<ExecuteResult, NymdError>;
async fn vesting_track_unbond_mixnode(
&self,
owner: &str,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
async fn withdraw_vested_coins(
&self,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
async fn withdraw_vested_coins(&self, amount: Coin) -> Result<ExecuteResult, NymdError>;
async fn vesting_track_undelegation(
&self,
address: &str,
mix_identity: IdentityKey,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
async fn vesting_delegate_to_mixnode<'a>(
&self,
mix_identity: IdentityKeyRef<'a>,
amount: Coin,
fee: Option<Fee>,
amount: &Coin,
) -> Result<ExecuteResult, NymdError>;
async fn vesting_undelegate_from_mixnode<'a>(
&self,
mix_identity: IdentityKeyRef<'a>,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
async fn create_periodic_vesting_account(
@@ -89,71 +75,27 @@ pub trait VestingSigningClient {
staking_address: Option<String>,
vesting_spec: Option<VestingSpecification>,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
}
#[async_trait]
impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient<C> {
async fn vesting_update_mixnode_config(
&self,
profit_margin_percent: u8,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let req = VestingExecuteMsg::UpdateMixnodeConfig {
profit_margin_percent,
};
self.client
.execute(
self.address(),
self.vesting_contract_address(),
&req,
fee,
"VestingContract::UpdateMixnetConfig",
vec![],
)
.await
}
async fn update_mixnet_address(
&self,
address: &str,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let req = VestingExecuteMsg::UpdateMixnetAddress {
address: address.to_string(),
};
self.client
.execute(
self.address(),
self.vesting_contract_address(),
&req,
fee,
"VestingContract::UpdateMixnetAddress",
vec![],
)
.await
}
async fn vesting_bond_gateway(
&self,
gateway: Gateway,
owner_signature: &str,
pledge: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let fee = self.operation_fee(Operation::BondGateway);
let req = VestingExecuteMsg::BondGateway {
gateway,
owner_signature: owner_signature.to_string(),
amount: pledge.into(),
amount: pledge,
};
self.client
.execute(
self.address(),
self.vesting_contract_address(),
self.vesting_contract_address()?,
&req,
fee,
"VestingContract::BondGateway",
@@ -162,13 +104,13 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
.await
}
async fn vesting_unbond_gateway(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
async fn vesting_unbond_gateway(&self) -> Result<ExecuteResult, NymdError> {
let fee = self.operation_fee(Operation::UnbondGateway);
let req = VestingExecuteMsg::UnbondGateway {};
self.client
.execute(
self.address(),
self.vesting_contract_address(),
self.vesting_contract_address()?,
&req,
fee,
"VestingContract::UnbondGateway",
@@ -181,17 +123,16 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
&self,
owner: &str,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let fee = self.operation_fee(Operation::TrackUnbondGateway);
let req = VestingExecuteMsg::TrackUnbondGateway {
owner: owner.to_string(),
amount: amount.into(),
amount,
};
self.client
.execute(
self.address(),
self.vesting_contract_address(),
self.vesting_contract_address()?,
&req,
fee,
"VestingContract::TrackUnbondGateway",
@@ -205,18 +146,17 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
mix_node: MixNode,
owner_signature: &str,
pledge: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let fee = self.operation_fee(Operation::BondMixnode);
let req = VestingExecuteMsg::BondMixnode {
mix_node,
owner_signature: owner_signature.to_string(),
amount: pledge.into(),
amount: pledge,
};
self.client
.execute(
self.address(),
self.vesting_contract_address(),
self.vesting_contract_address()?,
&req,
fee,
"VestingContract::BondMixnode",
@@ -225,13 +165,13 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
.await
}
async fn vesting_unbond_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
async fn vesting_unbond_mixnode(&self) -> Result<ExecuteResult, NymdError> {
let fee = self.operation_fee(Operation::UnbondMixnode);
let req = VestingExecuteMsg::UnbondMixnode {};
self.client
.execute(
self.address(),
self.vesting_contract_address(),
self.vesting_contract_address()?,
&req,
fee,
"VestingContract::UnbondMixnode",
@@ -244,17 +184,16 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
&self,
owner: &str,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let fee = self.operation_fee(Operation::TrackUnbondMixnode);
let req = VestingExecuteMsg::TrackUnbondMixnode {
owner: owner.to_string(),
amount: amount.into(),
amount,
};
self.client
.execute(
self.address(),
self.vesting_contract_address(),
self.vesting_contract_address()?,
&req,
fee,
"VestingContract::TrackUnbondMixnode",
@@ -262,19 +201,14 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
)
.await
}
async fn withdraw_vested_coins(
&self,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let req = VestingExecuteMsg::WithdrawVestedCoins {
amount: amount.into(),
};
async fn withdraw_vested_coins(&self, amount: Coin) -> Result<ExecuteResult, NymdError> {
let fee = self.operation_fee(Operation::WithdrawVestedCoins);
let req = VestingExecuteMsg::WithdrawVestedCoins { amount };
self.client
.execute(
self.address(),
self.vesting_contract_address(),
self.vesting_contract_address()?,
&req,
fee,
"VestingContract::WithdrawVested",
@@ -282,23 +216,23 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
)
.await
}
async fn vesting_track_undelegation(
&self,
address: &str,
mix_identity: IdentityKey,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let fee = self.operation_fee(Operation::TrackUndelegation);
let req = VestingExecuteMsg::TrackUndelegation {
owner: address.to_string(),
mix_identity,
amount: amount.into(),
amount,
};
self.client
.execute(
self.address(),
self.vesting_contract_address(),
self.vesting_contract_address()?,
&req,
fee,
"VestingContract::TrackUndelegation",
@@ -309,18 +243,17 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
async fn vesting_delegate_to_mixnode<'a>(
&self,
mix_identity: IdentityKeyRef<'a>,
amount: Coin,
fee: Option<Fee>,
amount: &Coin,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let fee = self.operation_fee(Operation::DelegateToMixnode);
let req = VestingExecuteMsg::DelegateToMixnode {
mix_identity: mix_identity.into(),
amount: amount.into(),
amount: amount.clone(),
};
self.client
.execute(
self.address(),
self.vesting_contract_address(),
self.vesting_contract_address()?,
&req,
fee,
"VestingContract::DelegateToMixnode",
@@ -328,20 +261,18 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
)
.await
}
async fn vesting_undelegate_from_mixnode<'a>(
&self,
mix_identity: IdentityKeyRef<'a>,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let fee = self.operation_fee(Operation::UndelegateFromMixnode);
let req = VestingExecuteMsg::UndelegateFromMixnode {
mix_identity: mix_identity.into(),
};
self.client
.execute(
self.address(),
self.vesting_contract_address(),
self.vesting_contract_address()?,
&req,
fee,
"VestingContract::UndelegateFromMixnode",
@@ -349,16 +280,14 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
)
.await
}
async fn create_periodic_vesting_account(
&self,
owner_address: &str,
staking_address: Option<String>,
vesting_spec: Option<VestingSpecification>,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let fee = self.operation_fee(Operation::CreatePeriodicVestingAccount);
let req = VestingExecuteMsg::CreateAccount {
owner_address: owner_address.to_string(),
staking_address,
@@ -367,11 +296,48 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
self.client
.execute(
self.address(),
self.vesting_contract_address(),
self.vesting_contract_address()?,
&req,
fee,
"VestingContract::CreatePeriodicVestingAccount",
vec![amount],
vec![cosmwasm_coin_to_cosmos_coin(amount)],
)
.await
}
async fn update_mixnet_address(&self, address: &str) -> Result<ExecuteResult, NymdError> {
let fee = self.operation_fee(Operation::UpdateMixnetAddress);
let req = VestingExecuteMsg::UpdateMixnetAddress {
address: address.to_string(),
};
self.client
.execute(
self.address(),
self.vesting_contract_address()?,
&req,
fee,
"VestingContract::UpdateMixnetAddress",
vec![],
)
.await
}
async fn vesting_update_mixnode_config(
&self,
profit_margin_percent: u8,
) -> Result<ExecuteResult, NymdError> {
let fee = self.operation_fee(Operation::UpdateMixnodeConfig);
let req = VestingExecuteMsg::UpdateMixnodeConfig {
profit_margin_percent,
};
self.client
.execute(
self.address(),
self.vesting_contract_address()?,
&req,
fee,
"VestingContract::UpdateMixnetConfig",
vec![],
)
.await
}
@@ -3,18 +3,14 @@
use crate::validator_api::error::ValidatorAPIError;
use crate::validator_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
use coconut_interface::{
BlindSignRequestBody, BlindedSignatureResponse, ExecuteReleaseFundsRequestBody,
ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse, VerificationKeyResponse,
VerifyCredentialBody, VerifyCredentialResponse,
};
use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse};
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use url::Url;
use validator_api_requests::models::{
CoreNodeStatusResponse, InclusionProbabilityResponse, MixNodeBondAnnotated,
MixnodeStatusResponse, RewardEstimationResponse, StakeSaturationResponse, UptimeResponse,
CoreNodeStatusResponse, InclusionProbabilityResponse, MixnodeStatusResponse,
RewardEstimationResponse, StakeSaturationResponse, UptimeResponse,
};
pub mod error;
@@ -89,16 +85,6 @@ impl Client {
.await
}
pub async fn get_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorAPIError> {
self.query_validator_api(
&[routes::API_VERSION, routes::MIXNODES, routes::DETAILED],
NO_PARAMS,
)
.await
}
pub async fn get_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorAPIError> {
self.query_validator_api(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS)
.await
@@ -112,21 +98,6 @@ impl Client {
.await
}
pub async fn get_active_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorAPIError> {
self.query_validator_api(
&[
routes::API_VERSION,
routes::MIXNODES,
routes::ACTIVE,
routes::DETAILED,
],
NO_PARAMS,
)
.await
}
pub async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorAPIError> {
self.query_validator_api(
&[routes::API_VERSION, routes::MIXNODES, routes::REWARDED],
@@ -135,21 +106,6 @@ impl Client {
.await
}
pub async fn get_rewarded_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorAPIError> {
self.query_validator_api(
&[
routes::API_VERSION,
routes::MIXNODES,
routes::REWARDED,
routes::DETAILED,
],
NO_PARAMS,
)
.await
}
pub async fn get_probs_mixnode_rewarded(
&self,
mixnode_id: &str,
@@ -375,57 +331,6 @@ impl Client {
)
.await
}
pub async fn verify_bandwidth_credential(
&self,
request_body: &VerifyCredentialBody,
) -> Result<VerifyCredentialResponse, ValidatorAPIError> {
self.post_validator_api(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
routes::BANDWIDTH,
routes::COCONUT_VERIFY_BANDWIDTH_CREDENTIAL,
],
NO_PARAMS,
request_body,
)
.await
}
pub async fn propose_release_funds(
&self,
request_body: &ProposeReleaseFundsRequestBody,
) -> Result<ProposeReleaseFundsResponse, ValidatorAPIError> {
self.post_validator_api(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
routes::BANDWIDTH,
routes::COCONUT_PROPOSE_RELEASE_FUNDS,
],
NO_PARAMS,
request_body,
)
.await
}
pub async fn execute_release_funds(
&self,
request_body: &ExecuteReleaseFundsRequestBody,
) -> Result<(), ValidatorAPIError> {
self.post_validator_api(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
routes::BANDWIDTH,
routes::COCONUT_EXECUTE_RELEASE_FUNDS,
],
NO_PARAMS,
request_body,
)
.await
}
}
// utility function that should solve the double slash problem in validator API forever.
@@ -7,7 +7,6 @@ pub const API_VERSION: &str = VALIDATOR_API_VERSION;
pub const MIXNODES: &str = "mixnodes";
pub const GATEWAYS: &str = "gateways";
pub const DETAILED: &str = "detailed";
pub const ACTIVE: &str = "active";
pub const REWARDED: &str = "rewarded";
@@ -17,9 +16,6 @@ pub const BANDWIDTH: &str = "bandwidth";
pub const COCONUT_BLIND_SIGN: &str = "blind-sign";
pub const COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL: &str = "partial-bandwidth-credential";
pub const COCONUT_VERIFICATION_KEY: &str = "verification-key";
pub const COCONUT_VERIFY_BANDWIDTH_CREDENTIAL: &str = "verify-bandwidth-credential";
pub const COCONUT_PROPOSE_RELEASE_FUNDS: &str = "propose-release-funds";
pub const COCONUT_EXECUTE_RELEASE_FUNDS: &str = "execute-release-funds";
pub const STATUS_ROUTES: &str = "status";
pub const MIXNODE: &str = "mixnode";
+5 -3
View File
@@ -1,7 +1,6 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nymcoconut::CoconutError;
use thiserror::Error;
#[derive(Debug, Error)]
@@ -12,6 +11,9 @@ pub enum CoconutInterfaceError {
#[error("Could not decode base 58 string - {0}")]
MalformedString(#[from] bs58::decode::Error),
#[error("Coconut error - {0}")]
CoconutError(#[from] CoconutError),
#[error("Not enough public attributes were specified")]
NotEnoughPublicAttributes,
#[error("Could not recover bandwidth value")]
InvalidBandwidth,
}
+46 -191
View File
@@ -5,158 +5,96 @@ pub mod error;
use getset::{CopyGetters, Getters};
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use error::CoconutInterfaceError;
pub use nymcoconut::*;
#[derive(Debug, Serialize, Deserialize, Getters, CopyGetters, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Getters, CopyGetters, Clone)]
pub struct Credential {
#[getset(get = "pub")]
n_params: u32,
#[getset(get = "pub")]
theta: Theta,
voucher_value: u64,
voucher_info: String,
public_attributes: Vec<Vec<u8>>,
#[getset(get = "pub")]
signature: Signature,
}
impl Credential {
pub fn new(
n_params: u32,
theta: Theta,
voucher_value: u64,
voucher_value: String,
voucher_info: String,
signature: &Signature,
) -> Credential {
let public_attributes = vec![voucher_value.into_bytes(), voucher_info.into_bytes()];
Credential {
n_params,
theta,
voucher_value,
voucher_info,
public_attributes,
signature: *signature,
}
}
pub fn blinded_serial_number(&self) -> String {
self.theta.blinded_serial_number_bs58()
}
pub fn voucher_value(&self) -> Result<u64, CoconutInterfaceError> {
let bandwidth_vec = self
.public_attributes
.get(0)
.ok_or(CoconutInterfaceError::NotEnoughPublicAttributes)?
.to_owned();
let bandwidth_str = String::from_utf8(bandwidth_vec)
.map_err(|_| CoconutInterfaceError::InvalidBandwidth)?;
let value =
u64::from_str(&bandwidth_str).map_err(|_| CoconutInterfaceError::InvalidBandwidth)?;
pub fn has_blinded_serial_number(
&self,
blinded_serial_number_bs58: &str,
) -> Result<bool, CoconutInterfaceError> {
Ok(self
.theta
.has_blinded_serial_number(blinded_serial_number_bs58)?)
}
pub fn voucher_value(&self) -> u64 {
self.voucher_value
Ok(value)
}
pub fn verify(&self, verification_key: &VerificationKey) -> bool {
let params = Parameters::new(self.n_params).unwrap();
let public_attributes = vec![
self.voucher_value.to_string().as_bytes(),
self.voucher_info.as_bytes(),
]
.iter()
.map(hash_to_scalar)
.collect::<Vec<Attribute>>();
let public_attributes = self
.public_attributes
.iter()
.map(hash_to_scalar)
.collect::<Vec<Attribute>>();
nymcoconut::verify_credential(&params, verification_key, &self.theta, &public_attributes)
}
pub fn as_bytes(&self) -> Vec<u8> {
let n_params_bytes = self.n_params.to_be_bytes();
let theta_bytes = self.theta.to_bytes();
let theta_bytes_len = theta_bytes.len();
let voucher_value_bytes = self.voucher_value.to_be_bytes();
let voucher_info_bytes = self.voucher_info.as_bytes();
let voucher_info_len = voucher_info_bytes.len();
let mut bytes = Vec::with_capacity(28 + theta_bytes_len + voucher_info_len);
bytes.extend_from_slice(&n_params_bytes);
bytes.extend_from_slice(&(theta_bytes_len as u64).to_be_bytes());
bytes.extend_from_slice(&theta_bytes);
bytes.extend_from_slice(&voucher_value_bytes);
bytes.extend_from_slice(voucher_info_bytes);
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CoconutError> {
if bytes.len() < 28 {
return Err(CoconutError::Deserialization(String::from(
"To few bytes in credential",
)));
}
let mut four_byte = [0u8; 4];
let mut eight_byte = [0u8; 8];
four_byte.copy_from_slice(&bytes[..4]);
let n_params = u32::from_be_bytes(four_byte);
eight_byte.copy_from_slice(&bytes[4..12]);
let theta_len = u64::from_be_bytes(eight_byte);
if bytes.len() < 28 + theta_len as usize {
return Err(CoconutError::Deserialization(String::from(
"To few bytes in credential",
)));
}
let theta = Theta::from_bytes(&bytes[12..12 + theta_len as usize])
.map_err(|e| CoconutError::Deserialization(e.to_string()))?;
eight_byte.copy_from_slice(&bytes[12 + theta_len as usize..20 + theta_len as usize]);
let voucher_value = u64::from_be_bytes(eight_byte);
let voucher_info = String::from_utf8(bytes[20 + theta_len as usize..].to_vec())
.map_err(|e| CoconutError::Deserialization(e.to_string()))?;
Ok(Credential {
n_params,
theta,
voucher_value,
voucher_info,
})
}
}
impl Bytable for Credential {
fn to_byte_vec(&self) -> Vec<u8> {
self.as_bytes()
}
fn try_from_byte_slice(slice: &[u8]) -> Result<Self, CoconutError> {
Credential::from_bytes(slice)
}
}
impl Base58 for Credential {}
#[derive(Serialize, Deserialize, Getters, CopyGetters)]
#[derive(Serialize, Deserialize, Debug, Getters, CopyGetters)]
pub struct VerifyCredentialBody {
#[getset(get = "pub")]
credential: Credential,
n_params: u32,
#[getset(get = "pub")]
proposal_id: u64,
theta: Theta,
public_attributes: Vec<String>,
}
impl VerifyCredentialBody {
pub fn new(credential: Credential, proposal_id: u64) -> VerifyCredentialBody {
pub fn new(
n_params: u32,
theta: &Theta,
public_attributes: &[Attribute],
) -> VerifyCredentialBody {
VerifyCredentialBody {
credential,
proposal_id,
n_params,
theta: theta.clone(),
public_attributes: public_attributes
.iter()
.map(|attr| attr.to_bs58())
.collect(),
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct VerifyCredentialResponse {
pub verification_result: bool,
}
impl VerifyCredentialResponse {
pub fn new(verification_result: bool) -> Self {
VerifyCredentialResponse {
verification_result,
}
pub fn public_attributes(&self) -> Vec<Attribute> {
self.public_attributes
.iter()
.map(|x| Attribute::try_from_bs58(x).unwrap())
.collect()
}
}
// All strings are base58 encoded representations of structs
#[derive(Clone, Serialize, Deserialize, Debug, Getters, CopyGetters)]
pub struct BlindSignRequestBody {
@@ -256,86 +194,3 @@ impl VerificationKeyResponse {
VerificationKeyResponse { key }
}
}
#[derive(Serialize, Deserialize, Getters, CopyGetters)]
pub struct ProposeReleaseFundsRequestBody {
#[getset(get = "pub")]
credential: Credential,
}
impl ProposeReleaseFundsRequestBody {
pub fn new(credential: Credential) -> Self {
ProposeReleaseFundsRequestBody { credential }
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ProposeReleaseFundsResponse {
pub proposal_id: u64,
}
impl ProposeReleaseFundsResponse {
pub fn new(proposal_id: u64) -> Self {
ProposeReleaseFundsResponse { proposal_id }
}
}
#[derive(Debug, Serialize, Deserialize, Getters, CopyGetters)]
pub struct ExecuteReleaseFundsRequestBody {
#[getset(get = "pub")]
proposal_id: u64,
}
impl ExecuteReleaseFundsRequestBody {
pub fn new(proposal_id: u64) -> Self {
ExecuteReleaseFundsRequestBody { proposal_id }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serde_coconut_credential() {
let voucher_value = 1000000u64;
let voucher_info = String::from("BandwidthVoucher");
let serial_number =
Attribute::try_from_bs58("7Rp3imcuNX3w9se9wm5th8gSvc2czsnMrGsdt5HsrycA").unwrap();
let binding_number =
Attribute::try_from_bs58("Auf8yVEgyEAWNHaXUZmimS4n9g5YiYnNYqp6F9BtBe9E").unwrap();
let signature = Signature::try_from_bs58(
"ta3pM9ffj5T6YGbwjSBp2W118rcwyP9PXStc\
7ssb91g5GQYMQHhuTNajbdZcjxUFBFL5rhED8EHpRzE8r432ss3qbPBfpNev4CdkfMkQ3wepyM7hy7q1W6Rn9WmFoZL\
ZR9j",
)
.unwrap();
let params = Parameters::new(4).unwrap();
let verification_key = VerificationKey::try_from_bs58("8CFtVVXdwLy4WHMQPE4\
woe89q3DRHoNxBSchftrEjSBPWA4r4xZv4Y9qSvS5x5bMmFtp7BX6ikECAnuXr5EjXWSsgjirZJmpS5XDUynVfht1cD\
FWGDvy2XFrRCuoCMotNXi3PoF6wYqdTR9Rqcfoj3i2H5Nid422WBaLtVoC9QNobvpvaqq6vX5PbsSyPayvU8HCXFxM6\
JjScYpbRTxQtdwefWLrk3LmXyJQBWi7c2VAhSxu9msp7VTBycqdwQNgxHETStZuwXsozxaGQ2KssVUCaaoYPR4g2RqK\
UAvtWwA7pMiAQNcbkXcbsjCgVjWaCpMWC37XA31cLcFf3zbjHD9e5tXjAcqa4M89fbFhuvvSXxowSAZ5NoWrN32kd5d\
wxJm1JW3Tt2h6yDDBe84oMy71462dZn7N78DVk2mFNGwBCibrZWA7oUzRBMfYxiQrksoFcou7QfLLd58zoNYmPQPt84\
1VpQopEBfdQ7Nf9zoXxBt3zMy7g5NsFGvzh7KTbDUyeeXrdkKJPQBs6dqaizr9sS8CPPmR4uk96vDTRh8CJ5FbSsmb8\
nP71dRvvwRZJHGzwYirMo6SXS3ZYxFuiA3mkxYuqDHCwkTWDuRCcAaztrDYRZg7VCMo4Q446AaEso5eqpeWpHZQt53E\
ZRpqmNYKASGwMhTeEHPSLgSmtoAAUcaRWpGRzYfd6kzEma8tdGLwyP4rLXgvSvtDLP37dU7YgF3LEXbGAz57U9ATy46\
6sroLpHPdaCWB8RF11wvB6Tu196JnJd2KyQBP1iUWP3rtZs3GhAF1QVcxquh8BqDZzAcpQ6wCS1P9c5GxKgww77FVF5\
Kp83XtoxSrw3GaYVyKTGxNh3vcKPR31txCjTxPaN2fg7TaPLhoQJX4YaAroFSXqrqbbRsisuHhhCeUP2YwDjHedes9y")
.unwrap();
let theta = prove_bandwidth_credential(
&params,
&verification_key,
&signature,
serial_number,
binding_number,
)
.unwrap();
let credential = Credential::new(4, theta, voucher_value, voucher_info);
let serialized_credential = credential.as_bytes();
let deserialized_credential = Credential::from_bytes(&serialized_credential).unwrap();
assert_eq!(credential, deserialized_credential);
}
}
@@ -23,9 +23,7 @@ pub const CHANGE_REWARDED_SET_EVENT_TYPE: &str = "change_rewarded_set";
pub const ADVANCE_INTERVAL_EVENT_TYPE: &str = "advance_interval";
pub const ADVANCE_EPOCH_EVENT_TYPE: &str = "advance_epoch";
pub const COMPOUND_DELEGATOR_REWARD_EVENT_TYPE: &str = "compound_delegator_reward";
pub const CLAIM_DELEGATOR_REWARD_EVENT_TYPE: &str = "claim_delegator_reward";
pub const COMPOUND_OPERATOR_REWARD_EVENT_TYPE: &str = "compound_operator_reward";
pub const CLAIM_OPERATOR_REWARD_EVENT_TYPE: &str = "claim_operator_reward";
pub const SNAPSHOT_MIXNODES_EVENT: &str = "snapshot_mixnodes";
// attributes that are used in multiple places
@@ -153,11 +151,6 @@ pub fn new_compound_operator_reward_event(owner: &Addr, amount: Uint128) -> Even
event.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_claim_operator_reward_event(owner: &Addr, amount: Uint128) -> Event {
let event = Event::new(CLAIM_OPERATOR_REWARD_EVENT_TYPE).add_attribute(OWNER_KEY, owner);
event.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_compound_delegator_reward_event(
delegator: &Addr,
proxy: &Option<Addr>,
@@ -178,26 +171,6 @@ pub fn new_compound_delegator_reward_event(
.add_attribute(DELEGATOR_KEY, delegator)
}
pub fn new_claim_delegator_reward_event(
delegator: &Addr,
proxy: &Option<Addr>,
amount: Uint128,
mix_identity: IdentityKeyRef<'_>,
) -> Event {
let mut event =
Event::new(CLAIM_DELEGATOR_REWARD_EVENT_TYPE).add_attribute(DELEGATOR_KEY, delegator);
if let Some(proxy) = proxy {
event = event.add_attribute(PROXY_KEY, proxy)
}
// coin implements Display trait and we use that implementation here
event
.add_attribute(AMOUNT_KEY, amount.to_string())
.add_attribute(DELEGATION_TARGET_KEY, mix_identity)
.add_attribute(DELEGATOR_KEY, delegator)
}
pub fn new_undelegation_event(
delegator: &Addr,
proxy: &Option<Addr>,
@@ -318,14 +318,6 @@ impl NodeRewardResult {
}
}
pub struct RewardEstimate {
pub total_node_reward: u64,
pub operator_reward: u64,
pub delegators_reward: u64,
pub node_profit: u64,
pub operator_cost: u64,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct MixNodeBond {
pub pledge_amount: Coin,
@@ -418,80 +410,63 @@ impl MixNodeBond {
/ U128::from_num(circulating_supply)
}
pub fn lambda_ticked(&self, params: &RewardParams) -> U128 {
// Ratio of a bond to the token circulating supply
self.lambda(params).min(params.one_over_k())
}
pub fn lambda(&self, params: &RewardParams) -> U128 {
// Ratio of a bond to the token circulating supply
self.pledge_to_circulating_supply(params.circulating_supply())
}
pub fn sigma_ticked(&self, params: &RewardParams) -> U128 {
// Ratio of a delegation to the the token circulating supply
self.sigma(params).min(params.one_over_k())
let pledge_to_circulating_supply_ratio =
self.pledge_to_circulating_supply(params.circulating_supply());
pledge_to_circulating_supply_ratio.min(params.one_over_k())
}
pub fn sigma(&self, params: &RewardParams) -> U128 {
// Ratio of a delegation to the the token circulating supply
self.total_bond_to_circulating_supply(params.circulating_supply())
let total_bond_to_circulating_supply_ratio =
self.total_bond_to_circulating_supply(params.circulating_supply());
total_bond_to_circulating_supply_ratio.min(params.one_over_k())
}
pub fn estimate_reward(
&self,
params: &RewardParams,
) -> Result<RewardEstimate, MixnetContractError> {
) -> Result<(u64, u64, u64), MixnetContractError> {
let total_node_reward = self
.reward(params)
.reward()
.checked_to_num::<u128>()
.unwrap_or_default();
let node_profit = self
.node_profit(params)
.checked_to_num::<u128>()
.unwrap_or_default();
let operator_cost = params
.node
.operator_cost()
.checked_to_num::<u128>()
.unwrap_or_default();
let operator_reward = self.operator_reward(params);
// Total reward has to be the sum of operator and delegator rewards
let delegators_reward = node_profit.saturating_sub(operator_reward);
let delegators_reward = total_node_reward - operator_reward;
Ok(RewardEstimate {
total_node_reward: total_node_reward.try_into()?,
operator_reward: operator_reward.try_into()?,
delegators_reward: delegators_reward.try_into()?,
node_profit: node_profit.try_into()?,
operator_cost: operator_cost.try_into()?,
})
Ok((
total_node_reward.try_into()?,
operator_reward.try_into()?,
delegators_reward.try_into()?,
))
}
// keybase://chat/nymtech#dev-core/14473
pub fn reward(&self, params: &RewardParams) -> NodeRewardResult {
let lambda_ticked = self.lambda_ticked(params);
let sigma_ticked = self.sigma_ticked(params);
let lambda = self.lambda(params);
let sigma = self.sigma(params);
let reward = params.performance()
* params.epoch_reward_pool()
* (sigma_ticked * params.omega()
+ params.alpha() * lambda_ticked * sigma_ticked * params.rewarded_set_size())
* (sigma * params.omega()
+ params.alpha() * lambda * sigma * params.rewarded_set_size())
/ (ONE + params.alpha());
// we only need regular lambda and sigma to calculate operator and delegator rewards
NodeRewardResult {
reward,
lambda: self.lambda(params),
sigma: self.sigma(params),
lambda,
sigma,
}
}
pub fn node_profit(&self, params: &RewardParams) -> U128 {
self.reward(params)
.reward()
.saturating_sub(params.node.operator_cost())
if self.reward(params).reward() < params.node.operator_cost() {
U128::from_num(0u128)
} else {
self.reward(params).reward() - params.node.operator_cost()
}
}
pub fn operator_reward(&self, params: &RewardParams) -> u128 {
@@ -499,9 +474,11 @@ impl MixNodeBond {
if reward.sigma == 0 {
return 0;
}
let profit = reward.reward.saturating_sub(params.node.operator_cost());
let profit = if reward.reward < params.node.operator_cost() {
U128::from_num(0u128)
} else {
reward.reward - params.node.operator_cost()
};
let operator_base_reward = reward.reward.min(params.node.operator_cost());
// Div by zero checked above
let operator_reward = (self.profit_margin()
@@ -99,17 +99,6 @@ pub enum ExecuteMsg {
},
// AdvanceCurrentInterval {},
AdvanceCurrentEpoch {},
ClaimOperatorReward {},
ClaimOperatorRewardOnBehalf {
owner: String,
},
ClaimDelegatorReward {
mix_identity: IdentityKey,
},
ClaimDelegatorRewardOnBehalf {
mix_identity: IdentityKey,
owner: String,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
@@ -42,7 +42,7 @@ impl NodeEpochRewards {
}
pub fn operator_cost(&self) -> U128 {
self.params.operator_cost()
U128::from_num(self.params.uptime.u128() / 100u128 * DEFAULT_OPERATOR_INTERVAL_COST as u128)
}
pub fn node_profit(&self) -> U128 {
@@ -178,15 +178,11 @@ impl NodeRewardParams {
}
pub fn operator_cost(&self) -> U128 {
self.performance() * U128::from_num(DEFAULT_OPERATOR_INTERVAL_COST)
U128::from_num(self.uptime.u128() / 100u128 * DEFAULT_OPERATOR_INTERVAL_COST as u128)
}
pub fn uptime(&self) -> Uint128 {
self.uptime
}
pub fn performance(&self) -> U128 {
U128::from_num(self.uptime.u128()) / U128::from_num(100)
pub fn uptime(&self) -> u128 {
self.uptime.u128()
}
pub fn set_reward_blockstamp(&mut self, blockstamp: u64) {
@@ -237,7 +233,7 @@ impl RewardParams {
}
pub fn performance(&self) -> U128 {
self.node.performance()
U128::from_num(self.node.uptime.u128()) / U128::from_num(100)
}
pub fn set_reward_blockstamp(&mut self, blockstamp: u64) {
@@ -260,8 +256,8 @@ impl RewardParams {
self.node.reward_blockstamp
}
pub fn uptime(&self) -> Uint128 {
self.node.uptime()
pub fn uptime(&self) -> u128 {
self.node.uptime.u128()
}
pub fn one_over_k(&self) -> U128 {
@@ -1,14 +0,0 @@
[package]
name = "multisig-contract-common"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cw-utils = { version = "0.13.1" }
cw3 = { version = "0.13.1" }
cw4 = { version = "0.13.1" }
cosmwasm-std = "1.0.0-beta6"
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
@@ -1 +0,0 @@
pub mod msg;
@@ -20,7 +20,6 @@ pub const VESTING_UPDATE_MIXNODE_CONFIG_EVENT_TYPE: &str = "vesting_update_mixno
pub const TRACK_MIXNODE_UNBOND_EVENT_TYPE: &str = "track_mixnode_unbond";
pub const TRACK_GATEWAY_UNBOND_EVENT_TYPE: &str = "track_gateway_unbond";
pub const TRACK_UNDELEGATION_EVENT_TYPE: &str = "track_undelegation";
pub const TRACK_REWARD_EVENT_TYPE: &str = "track_reaward";
// attributes that are used in multiple places
pub const OWNER_KEY: &str = "owner";
@@ -137,7 +136,3 @@ pub fn new_track_gateway_unbond_event() -> Event {
pub fn new_track_undelegation_event() -> Event {
Event::new(TRACK_UNDELEGATION_EVENT_TYPE)
}
pub fn new_track_reward_event() -> Event {
Event::new(TRACK_REWARD_EVENT_TYPE)
}
@@ -5,8 +5,6 @@ use cosmwasm_std::{Coin, Timestamp};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
pub use messages::{ExecuteMsg, InitMsg, MigrateMsg, QueryMsg};
pub mod events;
pub mod messages;
@@ -49,14 +49,6 @@ impl VestingSpecification {
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
TrackReward {
amount: Coin,
address: String,
},
ClaimOperatorReward {},
ClaimDelegatorReward {
mix_identity: String,
},
CompoundDelegatorReward {
mix_identity: String,
},
+2 -2
View File
@@ -12,9 +12,9 @@ nymcoconut = { path = "../nymcoconut" }
log = "0.4"
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"]}
thiserror = "1.0"
tokio = { version = "1.19.1", features = [ "rt-multi-thread", "net", "signal", "fs" ] }
tokio = { version = "1.4", features = [ "rt-multi-thread", "net", "signal", "fs" ] }
[build-dependencies]
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
tokio = { version = "1.19.1", features = ["rt-multi-thread", "macros"] }
tokio = { version = "1.4", features = ["rt-multi-thread", "macros"] }
+1 -1
View File
@@ -7,7 +7,7 @@ edition = "2021"
[dependencies]
bls12_381 = { version = "0.5", default-features = false, features = ["pairings", "alloc", "experimental"] }
cosmrs = { version = "0.7.0", optional = true }
cosmrs = { version = "0.4.1", optional = true }
thiserror = "1.0"
url = "2.2"
+1 -4
View File
@@ -204,10 +204,7 @@ mod test {
.to_base58_string(),
)
.unwrap(),
encryption::PrivateKey::from_bytes(
&encryption::KeyPair::new(&mut rng).private_key().to_bytes(),
)
.unwrap(),
encryption::KeyPair::new(&mut rng).private_key().clone(),
);
assert!(!BandwidthVoucher::verify_against_plain(
&[],
+16 -3
View File
@@ -51,7 +51,12 @@ pub async fn obtain_aggregate_verification_key(
let mut shares = Vec::with_capacity(validators.len());
let mut client = validator_client::ApiClient::new(validators[0].clone());
for (id, validator_url) in validators.iter().enumerate() {
let response = client.get_coconut_verification_key().await?;
indices.push(1);
shares.push(response.key);
for (id, validator_url) in validators.iter().enumerate().skip(1) {
client.change_validator_api(validator_url.clone());
let response = client.get_coconut_verification_key().await?;
indices.push((id + 1) as u64);
@@ -130,7 +135,14 @@ pub async fn obtain_aggregate_signature(
let mut validators_partial_vks: Vec<VerificationKey> = Vec::with_capacity(validators.len());
let mut client = validator_client::ApiClient::new(validators[0].clone());
for (id, validator_url) in validators.iter().enumerate() {
let validator_partial_vk = client.get_coconut_verification_key().await?;
validators_partial_vks.push(validator_partial_vk.key.clone());
let first =
obtain_partial_credential(params, attributes, &client, &validator_partial_vk.key).await?;
shares.push(SignatureShare::new(first, 1));
for (id, validator_url) in validators.iter().enumerate().skip(1) {
client.change_validator_api(validator_url.clone());
let validator_partial_vk = client.get_coconut_verification_key().await?;
validators_partial_vks.push(validator_partial_vk.key.clone());
@@ -181,7 +193,8 @@ pub fn prepare_credential_for_spending(
Ok(Credential::new(
PUBLIC_ATTRIBUTES + PRIVATE_ATTRIBUTES,
theta,
voucher_value,
voucher_value.to_string(),
voucher_info,
signature,
))
}
+5 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
#[cfg(feature = "coconut")]
use coconut_interface::CoconutError;
use coconut_interface::{error::CoconutInterfaceError, CoconutError};
use crypto::asymmetric::encryption::KeyRecoveryError;
use validator_client::ValidatorClientError;
@@ -20,6 +20,10 @@ pub enum Error {
#[error("Ran into a coconut error - {0}")]
CoconutError(#[from] CoconutError),
#[cfg(feature = "coconut")]
#[error("Ran into a coconut interface error - {0}")]
CoconutInterfaceError(#[from] CoconutInterfaceError),
#[error("Ran into a validator client error - {0}")]
ValidatorClientError(#[from] ValidatorClientError),
-11
View File
@@ -1,11 +0,0 @@
[package]
name = "execute"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
syn = { version = "1", features = ["full"] }
quote = "1"
-110
View File
@@ -1,110 +0,0 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{
parse_macro_input, Block, ExprMethodCall, FnArg, Ident, ItemFn, LitStr, ReturnType, Token,
VisPublic, Visibility,
};
#[proc_macro_attribute]
pub fn execute(attr: TokenStream, item: TokenStream) -> TokenStream {
let f = parse_macro_input!(item as ItemFn);
let target = parse_macro_input!(attr as LitStr).value();
let cl = if target == "mixnet" {
quote! {self.mixnet_contract_address()}
} else if target == "vesting" {
quote! {self.vesting_contract_address()}
} else {
panic!("Only `mixnet` and `vesting` targets are supported!")
};
let cl = proc_macro::TokenStream::from(cl);
let cl = parse_macro_input!(cl as ExprMethodCall);
let orig_f = f.clone();
let mut execute_f = f.clone();
let mut simulate_f = f.clone();
let name = f.sig.ident;
let name_str = name.to_string();
let call_args = f.sig.inputs.into_iter().filter_map(|arg| match arg {
FnArg::Receiver(_) => None,
FnArg::Typed(arg) => Some(arg.pat),
});
let execute_args = call_args.clone();
let simulate_args = call_args;
execute_f.sig.asyncness = Some(Token![async](execute_f.sig.ident.span()));
simulate_f.sig.asyncness = Some(Token![async](simulate_f.sig.ident.span()));
execute_f.vis = Visibility::Public(VisPublic {
pub_token: Token![pub](execute_f.sig.ident.span()),
});
simulate_f.vis = Visibility::Public(VisPublic {
pub_token: Token![pub](simulate_f.sig.ident.span()),
});
execute_f.sig.ident = Ident::new(
&format!("execute{}", execute_f.sig.ident),
execute_f.sig.ident.span(),
);
simulate_f.sig.ident = Ident::new(
&format!("simulate{}", simulate_f.sig.ident),
simulate_f.sig.ident.span(),
);
let execute_output = quote! {
-> Result<ExecuteResult, NymdError>
};
let o_ts = proc_macro::TokenStream::from(execute_output);
execute_f.sig.output = parse_macro_input!(o_ts as ReturnType);
let simulate_output = quote! {
-> Result<SimulateResponse, NymdError>
};
let o_ts = proc_macro::TokenStream::from(simulate_output);
simulate_f.sig.output = parse_macro_input!(o_ts as ReturnType);
let simulate_block = quote! {
{
let (msg, _fee) = self.#name(#(#simulate_args),*);
let msg = self.wrap_contract_execute_message(
#cl,
&msg,
vec![],
)?;
self.simulate(vec![msg]).await
}
};
let ts = proc_macro::TokenStream::from(simulate_block);
simulate_f.block = Box::new(parse_macro_input!(ts as Block));
let execute_block = quote! {
{
let (req, fee) = self.#name(#(#execute_args),*);
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
self.client
.execute(
self.address(),
#cl,
&req,
fee,
#name_str,
vec![],
)
.await
}
};
let ts = proc_macro::TokenStream::from(execute_block);
execute_f.block = Box::new(parse_macro_input!(ts as Block));
let out = quote! {
#orig_f
#execute_f
#simulate_f
};
out.into()
}
+2 -2
View File
@@ -14,8 +14,8 @@ humantime-serde = "1.0"
log = "0.4"
rand = "0.8"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.19.1", features = ["time", "macros", "rt", "net", "io-util"] }
tokio-util = { version = "0.7.3", features = ["codec"] }
tokio = { version = "1.4", features = ["time", "macros", "rt", "net", "io-util"] }
tokio-util = { version = "0.6", features = ["codec"] }
url = "2.2"
crypto = { path = "../crypto" }
+12 -8
View File
@@ -52,18 +52,14 @@ impl Network {
self.details().bandwidth_claim_contract_address
}
pub fn coconut_bandwidth_contract_address(&self) -> &str {
self.details().coconut_bandwidth_contract_address
}
pub fn multisig_contract_address(&self) -> &str {
self.details().multisig_contract_address
}
pub fn rewarding_validator_address(&self) -> &str {
self.details().rewarding_validator_address
}
pub fn stats_provider_network_address(&self) -> &str {
self.details().stats_provider_network_address
}
pub fn validators(&self) -> impl Iterator<Item = &ValidatorDetails> {
self.details().validators.iter()
}
@@ -101,6 +97,7 @@ pub struct NetworkDetails {
mixnet_contract_address: String,
vesting_contract_address: String,
bandwidth_claim_contract_address: String,
rewarding_validator_address: String,
validators: Vec<ValidatorDetails>,
}
@@ -112,6 +109,7 @@ impl From<&DefaultNetworkDetails<'_>> for NetworkDetails {
mixnet_contract_address: details.mixnet_contract_address.into(),
vesting_contract_address: details.vesting_contract_address.into(),
bandwidth_claim_contract_address: details.bandwidth_claim_contract_address.into(),
rewarding_validator_address: details.rewarding_validator_address.into(),
validators: details.validators.clone(),
}
}
@@ -162,6 +160,12 @@ impl SupportedNetworks {
.map(|network_details| network_details.bandwidth_claim_contract_address.as_str())
}
pub fn rewarding_validator_address(&self, network: Network) -> Option<&str> {
self.networks
.get(&network)
.map(|network_details| network_details.rewarding_validator_address.as_str())
}
pub fn validators(&self, network: Network) -> impl Iterator<Item = &ValidatorDetails> {
self.networks
.get(&network)
+6 -10
View File
@@ -51,9 +51,8 @@ pub struct DefaultNetworkDetails<'a> {
mixnet_contract_address: &'a str,
vesting_contract_address: &'a str,
bandwidth_claim_contract_address: &'a str,
coconut_bandwidth_contract_address: &'a str,
multisig_contract_address: &'a str,
rewarding_validator_address: &'a str,
stats_provider_network_address: &'a str,
validators: Vec<ValidatorDetails>,
}
@@ -64,9 +63,8 @@ static MAINNET_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> =
mixnet_contract_address: mainnet::MIXNET_CONTRACT_ADDRESS,
vesting_contract_address: mainnet::VESTING_CONTRACT_ADDRESS,
bandwidth_claim_contract_address: mainnet::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
coconut_bandwidth_contract_address: mainnet::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
multisig_contract_address: mainnet::MULTISIG_CONTRACT_ADDRESS,
rewarding_validator_address: mainnet::REWARDING_VALIDATOR_ADDRESS,
stats_provider_network_address: mainnet::STATS_PROVIDER_CLIENT_ADDRESS,
validators: mainnet::validators(),
});
@@ -77,9 +75,8 @@ static SANDBOX_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> =
mixnet_contract_address: sandbox::MIXNET_CONTRACT_ADDRESS,
vesting_contract_address: sandbox::VESTING_CONTRACT_ADDRESS,
bandwidth_claim_contract_address: sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
coconut_bandwidth_contract_address: sandbox::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
multisig_contract_address: sandbox::MULTISIG_CONTRACT_ADDRESS,
rewarding_validator_address: sandbox::REWARDING_VALIDATOR_ADDRESS,
stats_provider_network_address: sandbox::STATS_PROVIDER_CLIENT_ADDRESS,
validators: sandbox::validators(),
});
@@ -89,9 +86,8 @@ static QA_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> = Lazy::new(|| DefaultN
mixnet_contract_address: qa::MIXNET_CONTRACT_ADDRESS,
vesting_contract_address: qa::VESTING_CONTRACT_ADDRESS,
bandwidth_claim_contract_address: qa::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
coconut_bandwidth_contract_address: qa::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
multisig_contract_address: qa::MULTISIG_CONTRACT_ADDRESS,
rewarding_validator_address: qa::REWARDING_VALIDATOR_ADDRESS,
stats_provider_network_address: qa::STATS_PROVIDER_CLIENT_ADDRESS,
validators: qa::validators(),
});
@@ -154,7 +150,7 @@ pub const ETH_ERC20_APPROVE_FUNCTION_NAME: &str = "approve";
// Ethereum constants used for token bridge
/// How much bandwidth (in bytes) one token can buy
pub const BYTES_PER_UTOKEN: u64 = 1024;
const BYTES_PER_TOKEN: u64 = 1024 * 1024 * 1024;
/// Threshold for claiming more bandwidth: 1 MB
pub const REMAINING_BANDWIDTH_THRESHOLD: i64 = 1024 * 1024;
@@ -163,7 +159,7 @@ pub const TOKENS_TO_BURN: u64 = 1;
/// How many ERC20 utokens should be burned to buy bandwidth
pub const UTOKENS_TO_BURN: u64 = TOKENS_TO_BURN * 1000000;
/// Default bandwidth (in bytes) that we try to buy
pub const BANDWIDTH_VALUE: u64 = UTOKENS_TO_BURN * BYTES_PER_UTOKEN;
pub const BANDWIDTH_VALUE: u64 = TOKENS_TO_BURN * BYTES_PER_TOKEN;
pub const VOUCHER_INFO: &str = "BandwidthVoucher";
+2 -3
View File
@@ -13,15 +13,14 @@ pub(crate) const VESTING_CONTRACT_ADDRESS: &str =
"n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw";
pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str =
"n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
pub(crate) const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str =
"n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
pub(crate) const MULTISIG_CONTRACT_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
pub(crate) const _ETH_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("0000000000000000000000000000000000000000");
pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("0000000000000000000000000000000000000000");
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy";
pub(crate) const STATS_PROVIDER_CLIENT_ADDRESS: &str = "3V3me68qkEYNNShSQ5yLkrzC8rUJmcmtrTFbLKPqytEZ.7dGmnRAheEozNeGAsp9LXM8oPgS5YgJraNmYguj2t7Bn@BNjYZPxzcJwczXHHgBxCAyVJKxN6LPteDRrKapxWmexv";
pub(crate) fn validators() -> Vec<ValidatorDetails> {
vec![ValidatorDetails::new(
"https://rpc.nyx.nodes.guru/",
+2 -3
View File
@@ -13,15 +13,14 @@ pub(crate) const VESTING_CONTRACT_ADDRESS: &str =
"n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav";
pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str =
"n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
pub(crate) const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str =
"n1ghd753shjuwexxywmgs4xz7x2q732vcn7ty4yw";
pub(crate) const MULTISIG_CONTRACT_ADDRESS: &str = "n17p9rzwnnfxcjp32un9ug7yhhzgtkhvl988qccs";
pub(crate) const _ETH_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("0000000000000000000000000000000000000000");
pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("0000000000000000000000000000000000000000");
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n1tfzd4qz3a45u8p4mr5zmzv66457uwjgcl05jdq";
pub(crate) const STATS_PROVIDER_CLIENT_ADDRESS: &str = "BLFPkyQ68xtR3TmrUWJZUKJF4SVwJR23wzQEmLHi2QcZ.5zms2X4ANsgY1VB4iC9kTqvbsHWmWUNSuvTtYr4Cp5qT@ExyJVqTSrgHTwzXm2r9RawfF5qYpvZjSVN2dLTs6bnWH";
pub(crate) fn validators() -> Vec<ValidatorDetails> {
vec![ValidatorDetails::new(
"https://qa-validator.nymtech.net",
+2 -3
View File
@@ -11,15 +11,14 @@ pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "nymt1ghd753shjuwexxywmgs4xz7x2
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt14ejqjyq8um4p3xfqj74yld5waqljf88fn549lh";
pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str =
"nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv";
pub(crate) const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str =
"nymt1nz0r0au8aj6dc00wmm3ufy4g4k86rjzlgq608r";
pub(crate) const MULTISIG_CONTRACT_ADDRESS: &str = "nymt1k8re7jwz6rnnwrktnejdwkwnncte7ek7kk6fvg";
pub(crate) const _ETH_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("8e0DcFF7F3085235C32E845f3667aEB3f1e83133");
pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("E8883BAeF3869e14E4823F46662e81D4F7d2A81F");
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt1jh0s6qu6tuw9ut438836mmn7f3f2wencrnmdj4";
pub(crate) const STATS_PROVIDER_CLIENT_ADDRESS: &str = "HqYWvCcB4sswYiyMj5Q8H5oc71kLf96vfrLK3npM7stH.CoeC5dcqurgdxr5zcgU77nZBSBCc8ntCiwUivQ9TX3KT@E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM";
pub(crate) fn validators() -> Vec<ValidatorDetails> {
vec![ValidatorDetails::new(
"https://sandbox-validator.nymtech.net",
+3 -3
View File
@@ -7,6 +7,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio = { version = "1.19.1", features = [] }
tokio-stream = "0.1.9" # this one seems to be a thing until `Stream` trait is stabilised in stdlib
tokio-util = { version = "0.7.3", features = ["time"] }
tokio = { version = "1.4", features = [] }
tokio-stream = "0.1" # this one seems to be a thing until `Stream` trait is stabilised in stdlib
tokio-util = { version = "0.6", features = ["time"] }
+2 -1
View File
@@ -327,7 +327,8 @@ impl ProofCmCs {
}
}
#[derive(Debug, PartialEq)]
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub struct ProofKappaZeta {
// c
challenge: Scalar,
@@ -1,49 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use bls12_381::G2Projective;
use group::Curve;
use std::convert::TryFrom;
use std::convert::TryInto;
use crate::error::{CoconutError, Result};
use crate::traits::{Base58, Bytable};
use crate::utils::try_deserialize_g2_projective;
pub struct BlindedSerialNumber {
pub(crate) inner: G2Projective,
}
impl TryFrom<&[u8]> for BlindedSerialNumber {
type Error = CoconutError;
fn try_from(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 96 {
return Err(
CoconutError::Deserialization(
format!("Tried to deserialize blinded serial number with incorrect number of bytes, expected 96, got {}", bytes.len()),
));
}
let inner = try_deserialize_g2_projective(
&bytes.try_into().unwrap(),
CoconutError::Deserialization(
"failed to deserialize the blinded serial number (zeta)".to_string(),
),
)?;
Ok(BlindedSerialNumber { inner })
}
}
impl Bytable for BlindedSerialNumber {
fn to_byte_vec(&self) -> Vec<u8> {
self.inner.to_affine().to_compressed().to_vec()
}
fn try_from_byte_slice(slice: &[u8]) -> Result<Self> {
Self::try_from(slice)
}
}
impl Base58 for BlindedSerialNumber {}
+2 -2
View File
@@ -19,7 +19,6 @@ use crate::utils::try_deserialize_g1_projective;
use crate::Attribute;
pub mod aggregation;
pub mod double_use;
pub mod issuance;
pub mod keygen;
pub mod setup;
@@ -28,7 +27,8 @@ pub mod verification;
pub type SignerIndex = u64;
// (h, s)
#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy)]
#[cfg_attr(test, derive(PartialEq))]
pub struct Signature(pub(crate) G1Projective, pub(crate) G1Projective);
pub type PartialSignature = Signature;
+2 -15
View File
@@ -10,7 +10,6 @@ use group::{Curve, Group};
use crate::error::{CoconutError, Result};
use crate::proofs::ProofKappaZeta;
use crate::scheme::double_use::BlindedSerialNumber;
use crate::scheme::setup::Parameters;
use crate::scheme::Signature;
use crate::scheme::VerificationKey;
@@ -20,7 +19,8 @@ use crate::Attribute;
// TODO NAMING: this whole thing
// Theta
#[derive(Debug, PartialEq)]
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub struct Theta {
// blinded_message (kappa)
pub blinded_message: G2Projective,
@@ -81,12 +81,6 @@ impl Theta {
)
}
pub fn has_blinded_serial_number(&self, blinded_serial_number_bs58: &str) -> Result<bool> {
let blinded_serial_number = BlindedSerialNumber::try_from_bs58(blinded_serial_number_bs58)?;
let ret = self.blinded_serial_number.eq(&blinded_serial_number.inner);
Ok(ret)
}
// blinded message (kappa) || blinded serial number (zeta) || credential || pi_v
pub fn to_bytes(&self) -> Vec<u8> {
let blinded_message_bytes = self.blinded_message.to_affine().to_compressed();
@@ -106,13 +100,6 @@ impl Theta {
pub fn from_bytes(bytes: &[u8]) -> Result<Theta> {
Theta::try_from(bytes)
}
pub fn blinded_serial_number_bs58(&self) -> String {
let blinded_serial_nuumber = BlindedSerialNumber {
inner: self.blinded_serial_number,
};
blinded_serial_nuumber.to_bs58()
}
}
impl Bytable for Theta {
+1 -1
View File
@@ -33,5 +33,5 @@ mixnet-contract-common = { path = "../cosmwasm-smart-contracts/mixnet-contract"
path = "framing"
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio]
version = "1.19.1"
version = "1.4"
features = ["sync"]
+1 -1
View File
@@ -8,7 +8,7 @@ edition = "2021"
[dependencies]
bytes = "1.0"
tokio-util = { version = "0.7.3", features = ["codec"] }
tokio-util = { version = "0.6", features = ["codec"] }
nymsphinx-types = { path = "../types" }
nymsphinx-params = { path = "../params" }
+3 -3
View File
@@ -8,8 +8,8 @@ edition = "2021"
[dependencies]
bytes = "1.0"
tokio = { version = "1.19.1", features = [ "net", "io-util", "sync", "macros", "time", "rt-multi-thread" ] }
tokio-util = { version = "0.7.3", features = [ "io" ] } # reason for getting this guy is to to able to port to tokio 1.X more quickly by being able to use
tokio = { version = "1.4", features = [ "net", "io-util", "sync", "macros", "time", "rt-multi-thread" ] }
tokio-util = { version = "0.6", features = [ "io" ] } # reason for getting this guy is to to able to port to tokio 1.X more quickly by being able to use
# their `read_buf` [from the util crate] replacement rather than having to rethink/reimplement `AvailableReader` with the new AsyncRead trait definition.
# In the long run, the dependency should probably get removed in favour of pure-tokio implementation, but for time being it's fine.
futures = "0.3"
@@ -18,4 +18,4 @@ socks5-requests = { path = "../requests" }
ordered-buffer = { path = "../ordered-buffer" }
[dev-dependencies]
tokio-test = "0.4.2"
tokio-test = "0.4"
-13
View File
@@ -502,7 +502,6 @@ dependencies = [
"cw3-fixed-multisig",
"cw4",
"cw4-group",
"multisig-contract-common",
"schemars",
"serde",
"thiserror",
@@ -1043,18 +1042,6 @@ dependencies = [
"time 0.3.6",
]
[[package]]
name = "multisig-contract-common"
version = "0.1.0"
dependencies = [
"cosmwasm-std",
"cw-utils",
"cw3",
"cw4",
"schemars",
"serde",
]
[[package]]
name = "network-defaults"
version = "0.1.0"
-26
View File
@@ -283,32 +283,6 @@ pub fn execute(
info,
)
}
ExecuteMsg::ClaimOperatorReward {} => {
crate::rewards::transactions::try_claim_operator_reward(deps, &env, &info)
}
ExecuteMsg::ClaimOperatorRewardOnBehalf { owner } => {
crate::rewards::transactions::try_claim_operator_reward_on_behalf(
deps, &env, &info, owner,
)
}
ExecuteMsg::ClaimDelegatorReward { mix_identity } => {
crate::rewards::transactions::try_claim_delegator_reward(
deps,
&env,
&info,
&mix_identity,
)
}
ExecuteMsg::ClaimDelegatorRewardOnBehalf {
mix_identity,
owner,
} => crate::rewards::transactions::try_claim_delegator_reward_on_behalf(
deps,
&env,
&info,
owner,
&mix_identity,
),
}
}
+2 -2
View File
@@ -153,8 +153,8 @@ pub enum ContractError {
#[from]
source: MixnetContractError,
},
#[error("No rewards to claim for mixnode {identity} for {address}")]
NoRewardsToClaim { identity: String, address: String },
#[error("No rewards to claim for mixnode {identity} for delegate {delegate}")]
NoRewardsToClaim { identity: String, delegate: String },
#[error("Epoch not initialized yet!")]
EpochNotInitialized,
+9 -198
View File
@@ -15,13 +15,9 @@ use crate::mixnodes::storage::{self as mixnodes_storage, StoredMixnodeBond};
use crate::rewards::helpers;
use crate::support::helpers::is_authorized;
use config::defaults::DENOM;
use cosmwasm_std::{
coins, wasm_execute, Addr, Api, BankMsg, Coin, DepsMut, Env, MessageInfo, Order, Response,
Storage, Uint128,
};
use cosmwasm_std::{Addr, Api, Coin, DepsMut, Env, MessageInfo, Order, Response, Storage, Uint128};
use cw_storage_plus::Bound;
use mixnet_contract_common::events::{
new_claim_delegator_reward_event, new_claim_operator_reward_event,
new_compound_delegator_reward_event, new_compound_operator_reward_event,
new_mix_operator_rewarding_event, new_not_found_mix_operator_rewarding_event,
new_too_fresh_bond_mix_operator_rewarding_event, new_zero_uptime_mix_operator_rewarding_event,
@@ -31,186 +27,6 @@ use mixnet_contract_common::reward_params::{NodeEpochRewards, NodeRewardParams,
use mixnet_contract_common::{Delegation, IdentityKey, RewardingStatus};
use mixnet_contract_common::RewardingResult;
use vesting_contract_common::messages::ExecuteMsg as VestingContractExecuteMsg;
use vesting_contract_common::one_ucoin;
// All four of the below methods need to do the following things:
// 1. Calculate currently available rewards
// 2. Send the rewards back to whoever claimed them
// 3. Set the LAST_CLAIMED_HEIGHT to the current height
pub fn try_claim_operator_reward(
deps: DepsMut<'_>,
env: &Env,
info: &MessageInfo,
) -> Result<Response, ContractError> {
_try_claim_operator_reward(deps.storage, deps.api, env, &info.sender.to_string(), None)
}
pub fn try_claim_operator_reward_on_behalf(
deps: DepsMut<'_>,
env: &Env,
info: &MessageInfo,
owner: String,
) -> Result<Response, ContractError> {
_try_claim_operator_reward(
deps.storage,
deps.api,
env,
&owner,
Some(info.sender.clone()),
)
}
fn _try_claim_operator_reward(
storage: &mut dyn Storage,
api: &dyn Api,
env: &Env,
owner: &str,
proxy: Option<Addr>,
) -> Result<Response, ContractError> {
let owner = api.addr_validate(owner)?;
let bond = match crate::mixnodes::storage::mixnodes()
.idx
.owner
.item(storage, owner.clone())?
{
Some(record) => record.1,
None => return Err(ContractError::NoAssociatedMixNodeBond { owner }),
};
if proxy != bond.proxy {
return Err(ContractError::ProxyMismatch {
existing: bond
.proxy
.map_or_else(|| "None".to_string(), |a| a.as_str().to_string()),
incoming: proxy.map_or_else(|| "None".to_string(), |a| a.as_str().to_string()),
});
}
let reward = calculate_operator_reward(storage, api, &owner, &bond)?;
OPERATOR_REWARD_CLAIMED_HEIGHT.save(
storage,
(owner.to_string(), bond.identity().to_string()),
&env.block.height,
)?;
if reward.is_zero() {
return Err(ContractError::NoRewardsToClaim {
identity: bond.identity().to_string(),
address: owner.to_string(),
});
}
let return_tokens = BankMsg::Send {
to_address: proxy.as_ref().unwrap_or(&owner).to_string(),
amount: coins(reward.u128(), DENOM),
};
let mut response = Response::default()
.add_message(return_tokens)
.add_event(new_claim_operator_reward_event(&owner, reward));
if let Some(proxy) = proxy {
let msg = Some(VestingContractExecuteMsg::TrackReward {
address: owner.to_string(),
amount: Coin::new(reward.u128(), DENOM),
});
let wasm_msg = wasm_execute(proxy, &msg, vec![one_ucoin()])?;
response = response.add_message(wasm_msg);
}
Ok(response)
}
pub fn _try_claim_delegator_reward(
storage: &mut dyn Storage,
api: &dyn Api,
env: &Env,
owner: &str,
mix_identity: &str,
proxy: Option<Addr>,
) -> Result<Response, ContractError> {
let owner = api.addr_validate(owner)?;
let key = mixnet_contract_common::delegation::generate_storage_key(&owner, proxy.as_ref());
let reward = calculate_delegator_reward(storage, api, key.clone(), mix_identity)?;
DELEGATOR_REWARD_CLAIMED_HEIGHT.save(
storage,
(key, mix_identity.to_string()),
&env.block.height,
)?;
if reward.is_zero() {
return Err(ContractError::NoRewardsToClaim {
identity: mix_identity.to_string(),
address: owner.to_string(),
});
}
let return_tokens = BankMsg::Send {
to_address: proxy.as_ref().unwrap_or(&owner).to_string(),
amount: coins(reward.u128(), DENOM),
};
let mut response =
Response::default()
.add_message(return_tokens)
.add_event(new_claim_delegator_reward_event(
&owner,
&proxy,
reward,
mix_identity,
));
if let Some(proxy) = proxy {
let msg = Some(VestingContractExecuteMsg::TrackReward {
address: owner.to_string(),
amount: Coin::new(reward.u128(), DENOM),
});
let wasm_msg = wasm_execute(proxy, &msg, vec![one_ucoin()])?;
response = response.add_message(wasm_msg);
}
Ok(response)
}
pub fn try_claim_delegator_reward_on_behalf(
deps: DepsMut<'_>,
env: &Env,
info: &MessageInfo,
owner: String,
mix_identity: &str,
) -> Result<Response, ContractError> {
_try_claim_delegator_reward(
deps.storage,
deps.api,
env,
&owner,
mix_identity,
Some(info.sender.clone()),
)
}
pub fn try_claim_delegator_reward(
deps: DepsMut<'_>,
env: &Env,
info: &MessageInfo,
mix_identity: &str,
) -> Result<Response, ContractError> {
_try_claim_delegator_reward(
deps.storage,
deps.api,
env,
&info.sender.to_string(),
mix_identity,
None,
)
}
pub fn try_compound_operator_reward_on_behalf(
deps: DepsMut,
@@ -633,7 +449,7 @@ pub(crate) fn try_reward_mixnode(
let node_delegation = current_bond.total_delegation.amount;
// check if it has non-zero uptime
if params.uptime() == Uint128::zero() {
if params.uptime() == 0 {
storage::REWARDING_STATUS.save(
deps.storage,
(epoch.id(), mix_identity.clone()),
@@ -1565,7 +1381,7 @@ pub mod tests {
let mix_1 = mixnodes_storage::read_full_mixnode_bond(&deps.storage, &node_identity)
.unwrap()
.unwrap();
let mix_1_uptime = 90;
let mix_1_uptime = 100;
let epoch = Interval::init_epoch(env.clone());
save_epoch(&mut deps.storage, &epoch).unwrap();
@@ -1579,7 +1395,7 @@ pub mod tests {
params.set_reward_blockstamp(env.block.height);
assert_eq!(params.performance(), U128::from_num(0.8999999999999999));
assert_eq!(params.performance(), U128::from_num(1u32));
let mix_1_reward_result = mix_1.reward(&params);
@@ -1591,14 +1407,9 @@ pub mod tests {
mix_1_reward_result.lambda(),
U128::from_num(0.0000133333333333f64)
);
assert_eq!(mix_1_reward_result.reward().int(), 233202u128);
assert_eq!(mix_1_reward_result.reward().int(), 259114u128);
assert_eq!(mix_1.node_profit(&params).int(), 183202u128);
assert_ne!(
mix_1_reward_result.reward(),
mix_1.node_profit(&params).int()
);
assert_eq!(mix_1.node_profit(&params).int(), 203558u128);
let mix1_operator_reward = mix_1.operator_reward(&params);
@@ -1606,9 +1417,9 @@ pub mod tests {
let mix1_delegator2_reward = mix_1.reward_delegation(Uint128::new(2000_000000), &params);
assert_eq!(mix1_operator_reward, 150761);
assert_eq!(mix1_delegator1_reward, 65952);
assert_eq!(mix1_delegator2_reward, 16488);
assert_eq!(mix1_operator_reward, 167513);
assert_eq!(mix1_delegator1_reward, 73280);
assert_eq!(mix1_delegator2_reward, 18320);
assert_eq!(
mix_1_reward_result.reward().int(),
@@ -28,8 +28,6 @@ schemars = "0.8.1"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = { version = "1.0.23" }
multisig-contract-common = { path= "../../../common/cosmwasm-smart-contracts/multisig-contract" }
[dev-dependencies]
cosmwasm-schema = { version = "1.0.0-beta6" }
cw4-group = { path = "../cw4-group", version = "0.13.1" }
@@ -18,8 +18,8 @@ use cw_storage_plus::Bound;
use cw_utils::{maybe_addr, Expiration, ThresholdResponse};
use crate::error::ContractError;
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
use crate::state::{Config, CONFIG};
use multisig_contract_common::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
// version info for migration info
const CONTRACT_NAME: &str = "crates.io:cw3-flex-multisig";
@@ -499,7 +499,7 @@ mod tests {
max_voting_period: Duration,
) -> Addr {
let flex_id = app.store_code(contract_flex());
let msg = InstantiateMsg {
let msg = crate::msg::InstantiateMsg {
group_addr: group.to_string(),
threshold,
max_voting_period,
@@ -1,5 +1,6 @@
pub mod contract;
pub mod error;
pub mod msg;
pub mod state;
pub use crate::error::ContractError;
@@ -1,11 +1,7 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use cosmwasm_std::{CosmosMsg, Empty};
pub use cw3::ProposalResponse;
use cw3::Vote;
use cw4::MemberChangedHookMsg;
use cw_utils::{Duration, Expiration, Threshold};
-15
View File
@@ -4,21 +4,6 @@
2. Admin account can then delegate vested and unvested tokens to mixnodes on behalf of vesting accounts
3. Vesting accounts can withdraw vested and undelegated (spendable) coins to their addresses
### Glossary
| Term | Definition |
| ----------------------- | --------------------------------------------------------------------------------------------- |
| original vesting coins | vesting amount specified at account creation |
| vested coins | coins vested up to the current vesting period, current period excluded |
| vesting coins | *original vesting* amount minus *vested coins*, claimed rewards are not part of vesting coins |
| delegated free coins | delegated coins that have vested |
| delegated vesting coins | total delegation amount minus *delegated free* coins |
| pledged free coins | pledged coins that have vested |
| pledged vesting coins | total pledge amount minus *pledged free* coins |
| locked coins | *vesting coins* minus *delegated vesting* and *pledged vesting* coins |
| spendable coins | current vesting account balance minus *locked coins* |
### Vesting coin delegation flow
![vesting-coin-delegation](images/vesting-coin-delegation.png)
+1 -40
View File
@@ -13,8 +13,7 @@ use mixnet_contract_common::{Gateway, IdentityKey, MixNode};
use vesting_contract_common::events::{
new_ownership_transfer_event, new_periodic_vesting_account_event,
new_staking_address_update_event, new_track_gateway_unbond_event,
new_track_mixnode_unbond_event, new_track_reward_event, new_track_undelegation_event,
new_vested_coins_withdraw_event,
new_track_mixnode_unbond_event, new_track_undelegation_event, new_vested_coins_withdraw_event,
};
use vesting_contract_common::messages::{
ExecuteMsg, InitMsg, MigrateMsg, QueryMsg, VestingSpecification,
@@ -47,13 +46,6 @@ pub fn execute(
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::TrackReward { amount, address } => {
try_track_reward(deps, info, amount, &address)
}
ExecuteMsg::ClaimOperatorReward {} => try_claim_operator_reward(deps, info),
ExecuteMsg::ClaimDelegatorReward { mix_identity } => {
try_claim_delegator_reward(deps, info, mix_identity)
}
ExecuteMsg::CompoundDelegatorReward { mix_identity } => {
try_compound_delegator_reward(mix_identity, info, deps)
}
@@ -286,20 +278,6 @@ pub fn try_track_unbond_mixnode(
Ok(Response::new().add_event(new_track_mixnode_unbond_event()))
}
fn try_track_reward(
deps: DepsMut<'_>,
info: MessageInfo,
amount: Coin,
address: &str,
) -> Result<Response, ContractError> {
if info.sender != MIXNET_CONTRACT_ADDRESS.load(deps.storage)? {
return Err(ContractError::NotMixnetContract(info.sender));
}
let account = account_from_address(address, deps.storage, deps.api)?;
account.track_reward(amount, deps.storage)?;
Ok(Response::new().add_event(new_track_reward_event()))
}
fn try_track_undelegation(
address: &str,
mix_identity: IdentityKey,
@@ -336,23 +314,6 @@ fn try_compound_delegator_reward(
account.try_compound_delegator_reward(mix_identity, deps.storage)
}
fn try_claim_operator_reward(
deps: DepsMut<'_>,
info: MessageInfo,
) -> Result<Response, ContractError> {
let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
account.try_claim_operator_reward(deps.storage)
}
fn try_claim_delegator_reward(
deps: DepsMut<'_>,
info: MessageInfo,
mix_identity: String,
) -> Result<Response, ContractError> {
let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
account.try_claim_delegator_reward(mix_identity, deps.storage)
}
fn try_undelegate_from_mixnode(
mix_identity: IdentityKey,
info: MessageInfo,
@@ -8,8 +8,6 @@ pub trait MixnodeBondingAccount {
storage: &dyn Storage,
) -> Result<Response, ContractError>;
fn try_claim_operator_reward(&self, storage: &dyn Storage) -> Result<Response, ContractError>;
fn try_bond_mixnode(
&self,
mix_node: MixNode,
@@ -3,12 +3,6 @@ use cosmwasm_std::{Coin, Env, Response, Storage, Uint128};
use mixnet_contract_common::IdentityKey;
pub trait DelegatingAccount {
fn try_claim_delegator_reward(
&self,
mix_identity: IdentityKey,
storage: &dyn Storage,
) -> Result<Response, ContractError>;
fn try_compound_delegator_reward(
&self,
mix_identity: IdentityKey,
@@ -73,5 +73,4 @@ pub trait VestingAccount {
to_address: Option<Addr>,
storage: &mut dyn Storage,
) -> Result<(), ContractError>;
fn track_reward(&self, amount: Coin, storage: &mut dyn Storage) -> Result<(), ContractError>;
}
@@ -13,25 +13,6 @@ use vesting_contract_common::one_ucoin;
use super::Account;
impl DelegatingAccount for Account {
fn try_claim_delegator_reward(
&self,
mix_identity: IdentityKey,
storage: &dyn Storage,
) -> Result<Response, ContractError> {
let msg = MixnetExecuteMsg::ClaimDelegatorRewardOnBehalf {
owner: self.owner_address().to_string(),
mix_identity,
};
let compound_delegator_reward_msg = wasm_execute(
MIXNET_CONTRACT_ADDRESS.load(storage)?,
&msg,
vec![one_ucoin()],
)?;
Ok(Response::new().add_message(compound_delegator_reward_msg))
}
fn try_compound_delegator_reward(
&self,
mix_identity: IdentityKey,
@@ -14,20 +14,6 @@ use vesting_contract_common::PledgeData;
use super::Account;
impl MixnodeBondingAccount for Account {
fn try_claim_operator_reward(&self, storage: &dyn Storage) -> Result<Response, ContractError> {
let msg = MixnetExecuteMsg::ClaimOperatorRewardOnBehalf {
owner: self.owner_address().into_string(),
};
let compound_operator_reward_msg = wasm_execute(
MIXNET_CONTRACT_ADDRESS.load(storage)?,
&msg,
vec![one_ucoin()],
)?;
Ok(Response::new().add_message(compound_operator_reward_msg))
}
fn try_compound_operator_reward(
&self,
storage: &dyn Storage,
@@ -8,13 +8,6 @@ use vesting_contract_common::{OriginalVestingResponse, Period};
use super::Account;
impl VestingAccount for Account {
fn track_reward(&self, amount: Coin, storage: &mut dyn Storage) -> Result<(), ContractError> {
let current_balance = self.load_balance(storage)?;
let new_balance = current_balance + amount.amount;
self.save_balance(new_balance, storage)?;
Ok(())
}
fn locked_coins(
&self,
block_time: Option<Timestamp>,
+8 -9
View File
@@ -6,22 +6,21 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
chrono = { version = "0.4.19", features = ["serde"] }
humantime-serde = "1.0"
isocountry = "0.3.2"
itertools = "0.10.3"
log = "0.4.0"
okapi = { version = "0.7.0-rc.1", features = ["impl_json_schema"] }
pretty_env_logger = "0.4.0"
reqwest = "0.11.4"
rocket = {version = "0.5.0-rc.1", features=["json"] }
rocket_cors = { git="https://github.com/lawliet89/rocket_cors", rev="dfd3662c49e2f6fc37df35091cb94d82f7fb5915" }
rocket_okapi = { version = "0.8.0-rc.1", features = ["swagger"] }
schemars = { version = "0.8", features = ["preserve_order"] }
serde = "1.0.126"
humantime-serde = "1.0"
serde_json = "1.0.66"
tokio = {version = "1.9.0", features = ["full"] }
chrono = { version = "0.4.19", features = ["serde"] }
schemars = { version = "0.8", features = ["preserve_order"] }
okapi = { version = "0.7.0-rc.1", features = ["impl_json_schema"] }
rocket_okapi = { version = "0.8.0-rc.1", features = ["swagger"] }
log = "0.4.0"
pretty_env_logger = "0.4.0"
thiserror = "1.0.29"
tokio = {version = "1.19.1", features = ["full"] }
mixnet-contract-common = { path = "../common/cosmwasm-smart-contracts/mixnet-contract" }
network-defaults = { path = "../common/network-defaults" }
+2 -2
View File
@@ -5,13 +5,13 @@ An API that provides data for the [Network Explorer](../explorer).
Features:
- geolocates mixnodes using https://app.ipbase.com/
- geolocates mixnodes using https://freegeoip.app/
- calculates how many nodes are in each country
- proxies mixnode API requests to add HTTPS
## Running
Supply the environment variable `GEO_IP_SERVICE_API_KEY` with a key from https://app.ipbase.com/.
Supply the environment variable `GEO_IP_SERVICE_API_KEY` with a key from https://freegeoip.app/.
Run as a service and reverse proxy with `nginx` to add `https` with Lets Encrypt.
+10 -1
View File
@@ -23,10 +23,19 @@ impl ThreadsafeValidatorClient {
}
pub(crate) fn new_validator_client() -> ThreadsafeValidatorClient {
let network = DEFAULT_NETWORK;
let mixnet_contract = network.mixnet_contract_address().to_string();
let nymd_url = default_nymd_endpoints()[0].clone();
let api_url = default_api_endpoints()[0].clone();
let client_config = validator_client::Config::new(DEFAULT_NETWORK, nymd_url, api_url);
let client_config = validator_client::Config::new(
network,
nymd_url,
api_url,
Some(mixnet_contract.parse().unwrap()),
None,
None,
);
ThreadsafeValidatorClient(Arc::new(
validator_client::Client::new_query(client_config).expect("Failed to connect to nymd!"),
@@ -51,7 +51,7 @@ impl GeoLocateTask {
.state
.inner
.mixnodes
.is_location_valid(&cache_item.mix_node().identity_key)
.is_location_valid(&cache_item.mix_node.identity_key)
.await
{
// when the cached location is valid, don't locate and continue to next mix node
@@ -59,14 +59,14 @@ impl GeoLocateTask {
}
// the mix node has not been located or is the cache time has expired
match locate(&cache_item.mix_node().host).await {
match locate(&cache_item.mix_node.host).await {
Ok(geo_location) => {
let location = Location::new(geo_location);
trace!(
"{} mix nodes already located. Ip {} is located in {:#?}",
i,
cache_item.mix_node().host,
cache_item.mix_node.host,
location.three_letter_iso_country_code,
);
@@ -80,7 +80,7 @@ impl GeoLocateTask {
self.state
.inner
.mixnodes
.set_location(&cache_item.mix_node().identity_key, Some(location))
.set_location(&cache_item.mix_node.identity_key, Some(location))
.await;
// one node has been located, so return out of the loop
@@ -89,22 +89,22 @@ impl GeoLocateTask {
Err(e) => match e {
LocateError::ReqwestError(e) => warn!(
"❌ Oh no! Location for {} failed {}",
cache_item.mix_node().host, e
cache_item.mix_node.host, e
),
LocateError::NotFound(e) => {
warn!(
"❌ Location for {} not found. Response body: {}",
cache_item.mix_node().host, e
cache_item.mix_node.host, e
);
self.state
.inner
.mixnodes
.set_location(&cache_item.mix_node().identity_key, None)
.set_location(&cache_item.mix_node.identity_key, None)
.await;
},
LocateError::RateLimited(e) => warn!(
"❌ Oh no, we've been rate limited! Location for {} failed. Response body: {}",
cache_item.mix_node().host, e
cache_item.mix_node.host, e
),
},
}
@@ -129,7 +129,7 @@ enum LocateError {
async fn locate(ip: &str) -> Result<GeoLocation, LocateError> {
let api_key = ::std::env::var("GEO_IP_SERVICE_API_KEY")
.expect("Env var GEO_IP_SERVICE_API_KEY is not set");
let uri = format!("{}/?apikey={}&ip={}", crate::GEO_IP_SERVICE, api_key, ip);
let uri = format!("{}/{}?apikey={}", crate::GEO_IP_SERVICE, ip, api_key);
match reqwest::get(uri.clone()).await {
Ok(response) => {
if response.status() == 429 {
+1 -1
View File
@@ -18,7 +18,7 @@ mod state;
mod tasks;
mod validators;
const GEO_IP_SERVICE: &str = "https://api.ipbase.com/json";
const GEO_IP_SERVICE: &str = "https://api.freegeoip.app/json";
const COUNTRY_DATA_REFRESH_INTERVAL: u64 = 60 * 15; // every 15 minutes
#[tokio::main]
-19
View File
@@ -1,13 +1,9 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use itertools::Itertools;
use crate::client::ThreadsafeValidatorClient;
use mixnet_contract_common::Delegation;
use super::models::SummedDelegations;
pub(crate) async fn get_single_mixnode_delegations(
client: &ThreadsafeValidatorClient,
pubkey: &str,
@@ -25,18 +21,3 @@ pub(crate) async fn get_single_mixnode_delegations(
};
delegates
}
pub(crate) async fn get_single_mixnode_delegations_summed(
client: &ThreadsafeValidatorClient,
pubkey: &str,
) -> Vec<SummedDelegations> {
let delegations_by_owner = get_single_mixnode_delegations(client, pubkey)
.await
.into_iter()
.into_group_map_by(|delegation| delegation.owner.clone());
delegations_by_owner
.iter()
.filter_map(|(_, delegations)| SummedDelegations::from(delegations))
.collect()
}
+1 -1
View File
@@ -36,6 +36,6 @@ pub(crate) async fn retrieve_mixnode_econ_stats(
estimated_total_node_reward: reward_estimation.estimated_total_node_reward,
estimated_operator_reward: reward_estimation.estimated_operator_reward,
estimated_delegators_reward: reward_estimation.estimated_delegators_reward,
current_interval_uptime: reward_estimation.reward_params.node.uptime().u128() as u8,
current_interval_uptime: reward_estimation.reward_params.node.uptime() as u8,
})
}
+7 -25
View File
@@ -11,19 +11,16 @@ use rocket_okapi::settings::OpenApiSettings;
use mixnet_contract_common::Delegation;
use crate::mix_node::delegations::{
get_single_mixnode_delegations, get_single_mixnode_delegations_summed,
};
use crate::mix_node::delegations::get_single_mixnode_delegations;
use crate::mix_node::econ_stats::retrieve_mixnode_econ_stats;
use crate::mix_node::models::{
EconomicDynamicsStats, NodeDescription, NodeStats, PrettyDetailedMixNodeBond, SummedDelegations,
EconomicDynamicsStats, NodeDescription, NodeStats, PrettyDetailedMixNodeBond,
};
use crate::state::ExplorerApiStateContext;
pub fn mix_node_make_default_routes(settings: &OpenApiSettings) -> (Vec<Route>, OpenApi) {
openapi_get_routes_spec![
settings: get_delegations,
get_delegations_summed,
get_by_id,
get_description,
get_stats,
@@ -57,15 +54,6 @@ pub(crate) async fn get_delegations(
Json(get_single_mixnode_delegations(&state.inner.validator_client, pubkey).await)
}
#[openapi(tag = "mix_node")]
#[get("/<pubkey>/delegations/summed")]
pub(crate) async fn get_delegations_summed(
pubkey: &str,
state: &State<ExplorerApiStateContext>,
) -> Json<Vec<SummedDelegations>> {
Json(get_single_mixnode_delegations_summed(&state.inner.validator_client, pubkey).await)
}
#[openapi(tag = "mix_node")]
#[get("/<pubkey>/description")]
pub(crate) async fn get_description(
@@ -82,8 +70,8 @@ pub(crate) async fn get_description(
match state.inner.get_mix_node(pubkey).await {
Some(bond) => {
match get_mix_node_description(
&bond.mix_node().host,
&bond.mix_node().http_api_port,
&bond.mix_node.host,
&bond.mix_node.http_api_port,
)
.await
{
@@ -99,10 +87,7 @@ pub(crate) async fn get_description(
Err(e) => {
error!(
"Unable to get description for {} on {}:{} -> {}",
pubkey,
bond.mix_node().host,
bond.mix_node().http_api_port,
e
pubkey, bond.mix_node.host, bond.mix_node.http_api_port, e
);
Option::None
}
@@ -129,7 +114,7 @@ pub(crate) async fn get_stats(
trace!("No valid cache value for {}", pubkey);
match state.inner.get_mix_node(pubkey).await {
Some(bond) => {
match get_mix_node_stats(&bond.mix_node().host, &bond.mix_node().http_api_port)
match get_mix_node_stats(&bond.mix_node.host, &bond.mix_node.http_api_port)
.await
{
Ok(response) => {
@@ -144,10 +129,7 @@ pub(crate) async fn get_stats(
Err(e) => {
error!(
"Unable to get description for {} on {}:{} -> {}",
pubkey,
bond.mix_node().host,
bond.mix_node().http_api_port,
e
pubkey, bond.mix_node.host, bond.mix_node.http_api_port, e
);
Option::None
}
-66
View File
@@ -4,7 +4,6 @@
use crate::cache::Cache;
use crate::mix_nodes::location::Location;
use mixnet_contract_common::{Addr, Coin, Layer, MixNode};
use mixnet_contract_common::{Delegation, IdentityKey};
use serde::Deserialize;
use serde::Serialize;
use std::sync::Arc;
@@ -30,35 +29,6 @@ pub(crate) struct PrettyDetailedMixNodeBond {
pub layer: Layer,
pub mix_node: MixNode,
pub avg_uptime: Option<u8>,
pub stake_saturation: f32,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)]
pub struct SummedDelegations {
pub owner: Addr,
pub node_identity: IdentityKey,
pub amount: Coin,
}
impl SummedDelegations {
pub fn from(delegations: &[Delegation]) -> Option<Self> {
let owner = get_common_owner(delegations)?;
let node_identity = get_common_node_identity(delegations)?;
let denom = get_common_denom(delegations)?;
let sum = delegations
.iter()
.map(|delegation| delegation.amount.amount)
.sum();
let amount = Coin { denom, amount: sum };
Some(SummedDelegations {
owner,
node_identity,
amount,
})
}
}
pub(crate) struct MixNodeCache {
@@ -167,39 +137,3 @@ pub(crate) struct EconomicDynamicsStats {
pub(crate) current_interval_uptime: u8,
}
fn get_common_owner(delegations: &[Delegation]) -> Option<Addr> {
let owner = delegations.iter().next()?.owner();
if delegations
.iter()
.any(|delegation| delegation.owner() != owner)
{
log::warn!("Unexpected different owners when summing delegations");
return None;
}
Some(owner)
}
fn get_common_node_identity(delegations: &[Delegation]) -> Option<String> {
let node_identity = delegations.iter().next()?.node_identity();
if delegations
.iter()
.any(|delegation| delegation.node_identity() != node_identity)
{
log::warn!("Unexpected different node identities when summing delegations");
return None;
}
Some(node_identity)
}
fn get_common_denom(delegations: &[Delegation]) -> Option<String> {
let denom = delegations.iter().next()?.amount.denom.clone();
if delegations
.iter()
.any(|delegation| delegation.amount.denom != denom)
{
log::warn!("Unexpected different coin denom when summing delegations");
return None;
}
Some(denom)
}
+19 -20
View File
@@ -8,7 +8,8 @@ use std::time::{Duration, SystemTime};
use serde::Serialize;
use tokio::sync::RwLock;
use validator_client::models::{MixNodeBondAnnotated, UptimeResponse};
use mixnet_contract_common::MixNodeBond;
use validator_client::models::UptimeResponse;
use crate::cache::Cache;
use crate::mix_node::models::{MixnodeStatus, PrettyDetailedMixNodeBond};
@@ -31,7 +32,7 @@ pub(crate) struct MixNodeSummary {
#[derive(Clone, Debug)]
pub(crate) struct MixNodesResult {
pub(crate) valid_until: SystemTime,
pub(crate) all_mixnodes: HashMap<String, MixNodeBondAnnotated>,
pub(crate) all_mixnodes: HashMap<String, MixNodeBond>,
active_mixnodes: HashSet<String>,
rewarded_mixnodes: HashSet<String>,
}
@@ -60,7 +61,7 @@ impl MixNodesResult {
self.valid_until >= SystemTime::now()
}
fn get_mixnode(&self, pubkey: &str) -> Option<MixNodeBondAnnotated> {
fn get_mixnode(&self, pubkey: &str) -> Option<MixNodeBond> {
if self.is_valid() {
self.all_mixnodes.get(pubkey).cloned()
} else {
@@ -68,7 +69,7 @@ impl MixNodesResult {
}
}
fn get_mixnodes(&self) -> Option<HashMap<String, MixNodeBondAnnotated>> {
fn get_mixnodes(&self) -> Option<HashMap<String, MixNodeBond>> {
if self.is_valid() {
Some(self.all_mixnodes.clone())
} else {
@@ -127,11 +128,11 @@ impl ThreadsafeMixNodesCache {
);
}
pub(crate) async fn get_mixnode(&self, pubkey: &str) -> Option<MixNodeBondAnnotated> {
pub(crate) async fn get_mixnode(&self, pubkey: &str) -> Option<MixNodeBond> {
self.mixnodes.read().await.get_mixnode(pubkey)
}
pub(crate) async fn get_mixnodes(&self) -> Option<HashMap<String, MixNodeBondAnnotated>> {
pub(crate) async fn get_mixnodes(&self) -> Option<HashMap<String, MixNodeBond>> {
self.mixnodes.read().await.get_mixnodes()
}
@@ -150,14 +151,13 @@ impl ThreadsafeMixNodesCache {
match bond {
Some(bond) => Some(PrettyDetailedMixNodeBond {
location: location.and_then(|l| l.location.clone()),
status: mixnodes_guard.determine_node_status(&bond.mix_node().identity_key),
pledge_amount: bond.mixnode_bond.pledge_amount,
total_delegation: bond.mixnode_bond.total_delegation,
owner: bond.mixnode_bond.owner,
layer: bond.mixnode_bond.layer,
mix_node: bond.mixnode_bond.mix_node,
status: mixnodes_guard.determine_node_status(&bond.mix_node.identity_key),
pledge_amount: bond.pledge_amount,
total_delegation: bond.total_delegation,
owner: bond.owner,
layer: bond.layer,
mix_node: bond.mix_node,
avg_uptime: health.map(|m| m.avg_uptime),
stake_saturation: bond.stake_saturation,
}),
None => None,
}
@@ -172,19 +172,18 @@ impl ThreadsafeMixNodesCache {
.all_mixnodes
.values()
.map(|bond| {
let location = location_guard.get(&bond.mix_node().identity_key);
let copy = bond.mixnode_bond.clone();
let health = mixnode_health_guard.get(&bond.mix_node().identity_key);
let location = location_guard.get(&bond.mix_node.identity_key);
let copy = bond.clone();
let health = mixnode_health_guard.get(&bond.mix_node.identity_key);
PrettyDetailedMixNodeBond {
location: location.and_then(|l| l.location.clone()),
status: mixnodes_guard.determine_node_status(&bond.mix_node().identity_key),
status: mixnodes_guard.determine_node_status(&bond.mix_node.identity_key),
pledge_amount: copy.pledge_amount,
total_delegation: copy.total_delegation,
owner: copy.owner,
layer: copy.layer,
mix_node: copy.mix_node,
avg_uptime: health.map(|m| m.avg_uptime),
stake_saturation: bond.stake_saturation,
}
})
.collect()
@@ -192,14 +191,14 @@ impl ThreadsafeMixNodesCache {
pub(crate) async fn update_cache(
&self,
all_bonds: Vec<MixNodeBondAnnotated>,
all_bonds: Vec<MixNodeBond>,
rewarded_nodes: HashSet<String>,
active_nodes: HashSet<String>,
) {
let mut guard = self.mixnodes.write().await;
guard.all_mixnodes = all_bonds
.into_iter()
.map(|bond| (bond.mix_node().identity_key.to_string(), bond))
.map(|bond| (bond.mix_node.identity_key.to_string(), bond))
.collect();
guard.rewarded_mixnodes = rewarded_nodes;
guard.active_mixnodes = active_nodes;
+1 -1
View File
@@ -42,7 +42,7 @@ pub(crate) async fn index(
state.inner.ping.set_pending(pubkey).await;
// do the check
let ports = Some(port_check(&bond.mixnode_bond).await);
let ports = Some(port_check(&bond).await);
trace!("Tested mix node {}: {:?}", pubkey, ports);
let response = PingResponse {
ports,
+2 -2
View File
@@ -6,7 +6,7 @@ use log::info;
use serde::{Deserialize, Serialize};
use crate::client::ThreadsafeValidatorClient;
use validator_client::models::MixNodeBondAnnotated;
use mixnet_contract_common::MixNodeBond;
use crate::country_statistics::country_nodes_distribution::{
CountryNodesDistribution, ThreadsafeCountryNodesDistribution,
@@ -35,7 +35,7 @@ pub struct ExplorerApiState {
}
impl ExplorerApiState {
pub(crate) async fn get_mix_node(&self, pubkey: &str) -> Option<MixNodeBondAnnotated> {
pub(crate) async fn get_mix_node(&self, pubkey: &str) -> Option<MixNodeBond> {
self.mixnodes.get_mixnode(pubkey).await
}
}
+12 -12
View File
@@ -3,8 +3,8 @@
use std::future::Future;
use mixnet_contract_common::GatewayBond;
use validator_client::models::{MixNodeBondAnnotated, UptimeResponse};
use mixnet_contract_common::{GatewayBond, MixNodeBond};
use validator_client::models::UptimeResponse;
use validator_client::nymd::error::NymdError;
use validator_client::nymd::{Paging, QueryNymdClient, ValidatorResponse};
use validator_client::ValidatorClientError;
@@ -22,10 +22,10 @@ impl ExplorerApiTasks {
}
// a helper to remove duplicate code when grabbing active/rewarded/all mixnodes
async fn retrieve_mixnodes<'a, F, Fut>(&'a self, f: F) -> Vec<MixNodeBondAnnotated>
async fn retrieve_mixnodes<'a, F, Fut>(&'a self, f: F) -> Vec<MixNodeBond>
where
F: FnOnce(&'a validator_client::Client<QueryNymdClient>) -> Fut,
Fut: Future<Output = Result<Vec<MixNodeBondAnnotated>, ValidatorClientError>>,
Fut: Future<Output = Result<Vec<MixNodeBond>, ValidatorClientError>>,
{
let bonds = match f(&self.state.inner.validator_client.0).await {
Ok(result) => result,
@@ -39,9 +39,9 @@ impl ExplorerApiTasks {
bonds
}
async fn retrieve_all_mixnodes(&self) -> Vec<MixNodeBondAnnotated> {
async fn retrieve_all_mixnodes(&self) -> Vec<MixNodeBond> {
info!("About to retrieve all mixnode bonds...");
self.retrieve_mixnodes(validator_client::Client::get_cached_mixnodes_detailed)
self.retrieve_mixnodes(validator_client::Client::get_cached_mixnodes)
.await
}
@@ -77,15 +77,15 @@ impl ExplorerApiTasks {
Ok(response)
}
async fn retrieve_rewarded_mixnodes(&self) -> Vec<MixNodeBondAnnotated> {
async fn retrieve_rewarded_mixnodes(&self) -> Vec<MixNodeBond> {
info!("About to retrieve rewarded mixnode bonds...");
self.retrieve_mixnodes(validator_client::Client::get_cached_rewarded_mixnodes_detailed)
self.retrieve_mixnodes(validator_client::Client::get_cached_rewarded_mixnodes)
.await
}
async fn retrieve_active_mixnodes(&self) -> Vec<MixNodeBondAnnotated> {
async fn retrieve_active_mixnodes(&self) -> Vec<MixNodeBond> {
info!("About to retrieve active mixnode bonds...");
self.retrieve_mixnodes(validator_client::Client::get_cached_active_mixnodes_detailed)
self.retrieve_mixnodes(validator_client::Client::get_cached_active_mixnodes)
.await
}
@@ -106,13 +106,13 @@ impl ExplorerApiTasks {
.retrieve_rewarded_mixnodes()
.await
.into_iter()
.map(|bond| bond.mix_node().identity_key.clone())
.map(|bond| bond.mix_node.identity_key)
.collect();
let active_nodes = self
.retrieve_active_mixnodes()
.await
.into_iter()
.map(|bond| bond.mix_node().identity_key.clone())
.map(|bond| bond.mix_node.identity_key)
.collect();
self.state
.inner

Some files were not shown because too many files have changed in this diff Show More