merge develop

This commit is contained in:
fmtabbara
2021-12-16 10:09:23 +00:00
57 changed files with 1486 additions and 714 deletions
+2
View File
@@ -22,6 +22,8 @@ jobs:
node-version: '14'
- run: npm install
continue-on-error: true
- name: Set environment from the example
run: cp .env.prod .env
- run: npm run test
continue-on-error: true
- run: npm run build
+31
View File
@@ -0,0 +1,31 @@
all: clippy test fmt
clippy: clippy-main clippy-contracts clippy-wallet
test: test-main test-contracts test-wallet
fmt: fmt-main fmt-contracts fmt-wallet
clippy-main:
cargo clippy
clippy-contracts:
cargo clippy --manifest-path contracts/Cargo.toml
clippy-wallet:
cargo clippy --manifest-path nym-wallet/Cargo.toml
test-main:
cargo test
test-contracts:
cargo test --manifest-path contracts/Cargo.toml
test-wallet:
cargo test --manifest-path nym-wallet/Cargo.toml
fmt-main:
cargo fmt --all
fmt-contracts:
cargo fmt --manifest-path contracts/Cargo.toml --all
fmt-wallet:
cargo fmt --manifest-path nym-wallet/Cargo.toml --all
@@ -94,6 +94,7 @@ impl Client<SigningNymdClient> {
config.mixnet_contract_address.clone(),
config.vesting_contract_address.clone(),
mnemonic.clone(),
None,
)?;
Ok(Client {
@@ -114,6 +115,7 @@ impl Client<SigningNymdClient> {
self.mixnet_contract_address.clone(),
self.vesting_contract_address.clone(),
self.mnemonic.clone().unwrap(),
None,
)?;
Ok(())
}
@@ -4,7 +4,7 @@
use crate::nymd::cosmwasm_client::helpers::create_pagination;
use crate::nymd::cosmwasm_client::types::{
Account, Code, CodeDetails, Contract, ContractCodeHistoryEntry, ContractCodeId,
SequenceResponse,
SequenceResponse, SimulateResponse,
};
use crate::nymd::error::NymdError;
use async_trait::async_trait;
@@ -14,15 +14,19 @@ use cosmrs::proto::cosmos::auth::v1beta1::{
use cosmrs::proto::cosmos::bank::v1beta1::{
QueryAllBalancesRequest, QueryAllBalancesResponse, QueryBalanceRequest, QueryBalanceResponse,
};
use cosmrs::proto::cosmos::tx::v1beta1::{
SimulateRequest, SimulateResponse as ProtoSimulateResponse,
};
use cosmrs::proto::cosmwasm::wasm::v1::*;
use cosmrs::rpc::endpoint::block::Response as BlockResponse;
use cosmrs::rpc::endpoint::broadcast;
use cosmrs::rpc::endpoint::tx::Response as TxResponse;
use cosmrs::rpc::query::Query;
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, Denom};
use cosmrs::{tx, AccountId, Coin, Denom, Tx};
use prost::Message;
use serde::{Deserialize, Serialize};
use std::convert::{TryFrom, TryInto};
@@ -49,6 +53,11 @@ pub trait CosmWasmClient: rpc::Client {
let res = self.abci_query(path, buf, None, false).await?;
match res.code {
AbciCode::Err(code) => return Err(NymdError::AbciError(code, res.log)),
AbciCode::Ok => (),
}
Ok(Res::decode(res.value.as_ref())?)
}
@@ -388,4 +397,27 @@ pub trait CosmWasmClient: rpc::Client {
Ok(serde_json::from_slice(&res.data)?)
}
// 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
#[allow(deprecated)]
async fn query_simulate(
&self,
tx: Option<Tx>,
tx_bytes: Vec<u8>,
) -> Result<SimulateResponse, NymdError> {
let path = Some("/cosmos.tx.v1beta1.Service/Simulate".parse().unwrap());
let req = SimulateRequest {
tx: tx.map(Into::into),
tx_bytes,
};
let res = self
.make_abci_query::<_, ProtoSimulateResponse>(path, req)
.await?;
res.try_into()
}
}
@@ -3,6 +3,7 @@
use crate::nymd::error::NymdError;
use crate::nymd::wallet::DirectSecp256k1HdWallet;
use crate::nymd::GasPrice;
use cosmrs::rpc::{Error as TendermintRpcError, HttpClient, HttpClientUrl};
use std::convert::TryInto;
@@ -23,9 +24,10 @@ where
pub fn connect_with_signer<U>(
endpoint: U,
signer: DirectSecp256k1HdWallet,
gas_price: Option<GasPrice>,
) -> Result<signing_client::Client, NymdError>
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{
signing_client::Client::connect_with_signer(endpoint, signer)
signing_client::Client::connect_with_signer(endpoint, signer, gas_price)
}
@@ -1,30 +1,94 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::convert::TryInto;
use async_trait::async_trait;
use cosmrs::bank::MsgSend;
use cosmrs::distribution::MsgWithdrawDelegatorReward;
use cosmrs::proto::cosmos::tx::signing::v1beta1::SignMode;
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, Coin, Tx};
use log::debug;
use serde::Serialize;
use sha2::Digest;
use sha2::Sha256;
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 async_trait::async_trait;
use cosmrs::bank::MsgSend;
use cosmrs::distribution::MsgWithdrawDelegatorReward;
use cosmrs::rpc::endpoint::broadcast;
use cosmrs::rpc::{Error as TendermintRpcError, HttpClient, HttpClientUrl, SimpleRequest};
use cosmrs::staking::{MsgDelegate, MsgUndelegate};
use cosmrs::tx::{Fee, Msg, SignDoc, SignerInfo};
use cosmrs::{cosmwasm, rpc, tx, AccountId, Any, Coin};
use log::debug;
use serde::Serialize;
use sha2::Digest;
use sha2::Sha256;
use std::convert::TryInto;
use crate::nymd::{CosmosCoin, GasPrice};
// 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,
];
#[async_trait]
pub trait SigningCosmWasmClient: CosmWasmClient {
fn signer(&self) -> &DirectSecp256k1HdWallet;
fn gas_price(&self) -> &GasPrice;
fn signer_public_key(&self, signer_address: &AccountId) -> Option<tx::SignerPublicKey> {
let signer_accounts = self.signer().try_derive_accounts().ok()?;
let account_from_signer = signer_accounts
.iter()
.find(|account| &account.address == signer_address)?;
let public_key = account_from_signer.public_key;
Some(public_key.into())
}
async fn simulate(
&self,
signer_address: &AccountId,
messages: Vec<Any>,
memo: impl Into<String> + Send + 'static,
) -> Result<SimulateResponse, NymdError> {
let public_key = self.signer_public_key(signer_address);
let sequence_response = self.get_sequence(signer_address).await?;
let partial_tx = Tx {
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
}
async fn upload(
&self,
sender_address: &AccountId,
@@ -52,6 +116,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
.check_response()?;
let logs = parse_raw_logs(tx_res.deliver_tx.log)?;
let gas_info = GasInfo::new(tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used);
// TODO: should those strings be extracted into some constants?
// the reason I think unwrap here is fine is that if the transaction succeeded and those
@@ -71,6 +136,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
code_id,
logs,
transaction_hash: tx_res.hash,
gas_info,
})
}
@@ -114,6 +180,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
.check_response()?;
let logs = parse_raw_logs(tx_res.deliver_tx.log)?;
let gas_info = GasInfo::new(tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used);
// TODO: should those strings be extracted into some constants?
// the reason I think unwrap here is fine is that if the transaction succeeded and those
@@ -129,6 +196,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
contract_address,
logs,
transaction_hash: tx_res.hash,
gas_info,
})
}
@@ -153,9 +221,12 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
.await?
.check_response()?;
let gas_info = GasInfo::new(tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used);
Ok(ChangeAdminResult {
logs: parse_raw_logs(tx_res.deliver_tx.log)?,
transaction_hash: tx_res.hash,
gas_info,
})
}
@@ -178,9 +249,12 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
.await?
.check_response()?;
let gas_info = GasInfo::new(tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used);
Ok(ChangeAdminResult {
logs: parse_raw_logs(tx_res.deliver_tx.log)?,
transaction_hash: tx_res.hash,
gas_info,
})
}
@@ -210,9 +284,12 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
.await?
.check_response()?;
let gas_info = GasInfo::new(tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used);
Ok(MigrateResult {
logs: parse_raw_logs(tx_res.deliver_tx.log)?,
transaction_hash: tx_res.hash,
gas_info,
})
}
@@ -242,9 +319,12 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
.await?
.check_response()?;
let gas_info = GasInfo::new(tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used);
Ok(ExecuteResult {
logs: parse_raw_logs(tx_res.deliver_tx.log)?,
transaction_hash: tx_res.hash,
gas_info,
})
}
@@ -279,14 +359,12 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
.await?
.check_response()?;
debug!(
"gas wanted: {:?}, gas used: {:?}",
tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used
);
let gas_info = GasInfo::new(tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used);
Ok(ExecuteResult {
logs: parse_raw_logs(tx_res.deliver_tx.log)?,
transaction_hash: tx_res.hash,
gas_info,
})
}
@@ -400,6 +478,43 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
.check_response()
}
// in this particular case we cannot generalise the argument to `&str` due to lifetime constraints
#[allow(clippy::ptr_arg)]
async fn determine_transaction_fee(
&self,
signer_address: &AccountId,
messages: &[Any],
fee: Fee,
memo: &String,
) -> Result<tx::Fee, NymdError> {
let fee = match fee {
Fee::Manual(fee) => fee,
Fee::Auto(multiplier) => {
debug!("Trying to simulate gas costs...");
// from what I've seen in manual testing, gas estimation does not exist if transaction
// fails to get executed (for example if you send 'BondMixnode" with invalid signature)
let gas_estimation = self
.simulate(signer_address, messages.to_vec(), memo.clone())
.await?
.gas_info
.ok_or(NymdError::GasEstimationFailure)?
.gas_used;
let multiplier = multiplier.unwrap_or(DEFAULT_SIMULATED_GAS_MULTIPLIER);
let gas = ((gas_estimation.value() as f32 * multiplier) as u64).into();
debug!("Gas estimation: {}", gas_estimation);
debug!("Multiplying the estimation by {}", multiplier);
debug!("Final gas limit used: {}", gas);
let fee = self.gas_price() * gas;
tx::Fee::from_amount_and_gas(fee, gas)
}
};
debug!("Fee used for the transaction: {:?}", fee);
Ok(fee)
}
/// Broadcast a transaction, returning immediately.
async fn sign_and_broadcast_async(
&self,
@@ -408,6 +523,10 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
fee: Fee,
memo: impl Into<String> + Send + 'static,
) -> Result<broadcast::tx_async::Response, NymdError> {
let memo = memo.into();
let fee = self
.determine_transaction_fee(signer_address, &messages, fee, &memo)
.await?;
let tx_raw = self.sign(signer_address, messages, fee, memo).await?;
let tx_bytes = tx_raw
.to_bytes()
@@ -424,6 +543,10 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
fee: Fee,
memo: impl Into<String> + Send + 'static,
) -> Result<broadcast::tx_sync::Response, NymdError> {
let memo = memo.into();
let fee = self
.determine_transaction_fee(signer_address, &messages, fee, &memo)
.await?;
let tx_raw = self.sign(signer_address, messages, fee, memo).await?;
let tx_bytes = tx_raw
.to_bytes()
@@ -440,6 +563,11 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
fee: Fee,
memo: impl Into<String> + Send + 'static,
) -> Result<broadcast::tx_commit::Response, NymdError> {
let memo = memo.into();
let fee = self
.determine_transaction_fee(signer_address, &messages, fee, &memo)
.await?;
let tx_raw = self.sign(signer_address, messages, fee, memo).await?;
let tx_bytes = tx_raw
.to_bytes()
@@ -452,7 +580,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
&self,
signer_address: &AccountId,
messages: Vec<Any>,
fee: Fee,
fee: tx::Fee,
memo: impl Into<String> + Send + 'static,
signer_data: SignerData,
) -> Result<tx::Raw, NymdError> {
@@ -490,7 +618,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
&self,
signer_address: &AccountId,
messages: Vec<Any>,
fee: Fee,
fee: tx::Fee,
memo: impl Into<String> + Send + 'static,
) -> Result<tx::Raw, NymdError> {
// TODO: Future optimisation: rather than grabbing current account_number and sequence
@@ -508,22 +636,28 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Client {
rpc_client: HttpClient,
signer: DirectSecp256k1HdWallet,
gas_price: GasPrice,
}
impl Client {
pub fn connect_with_signer<U>(
endpoint: U,
signer: DirectSecp256k1HdWallet,
gas_price: Option<GasPrice>,
) -> Result<Self, NymdError>
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{
let rpc_client = HttpClient::new(endpoint)?;
Ok(Client { rpc_client, signer })
Ok(Client {
rpc_client,
signer,
gas_price: gas_price.unwrap_or_default(),
})
}
}
@@ -545,4 +679,8 @@ impl SigningCosmWasmClient for Client {
fn signer(&self) -> &DirectSecp256k1HdWallet {
&self.signer
}
fn gas_price(&self) -> &GasPrice {
&self.gas_price
}
}
@@ -7,15 +7,19 @@ use crate::nymd::cosmwasm_client::logs::Log;
use crate::nymd::error::NymdError;
use cosmrs::crypto::PublicKey;
use cosmrs::proto::cosmos::auth::v1beta1::BaseAccount;
use cosmrs::proto::cosmos::base::abci::v1beta1::{
GasInfo as ProtoGasInfo, Result as ProtoAbciResult,
};
use cosmrs::proto::cosmos::tx::v1beta1::SimulateResponse as ProtoSimulateResponse;
use cosmrs::proto::cosmwasm::wasm::v1::{
CodeInfoResponse, ContractCodeHistoryEntry as ProtoContractCodeHistoryEntry,
ContractCodeHistoryOperationType, ContractInfo as ProtoContractInfo,
};
use cosmrs::tendermint::chain;
use cosmrs::tx::{AccountNumber, SequenceNumber};
use cosmrs::tendermint::{abci, chain};
use cosmrs::tx::{AccountNumber, Gas, SequenceNumber};
use cosmrs::{tx, AccountId, Coin};
use serde::Serialize;
use std::convert::TryFrom;
use std::convert::{TryFrom, TryInto};
pub type ContractCodeId = u64;
@@ -215,6 +219,101 @@ impl TryFrom<ProtoContractCodeHistoryEntry> for ContractCodeHistoryEntry {
}
}
#[derive(Debug)]
pub struct GasInfo {
/// GasWanted is the maximum units of work we allow this tx to perform.
pub gas_wanted: Gas,
/// GasUsed is the amount of gas actually consumed.
pub gas_used: Gas,
}
impl From<ProtoGasInfo> for GasInfo {
fn from(value: ProtoGasInfo) -> Self {
GasInfo {
gas_wanted: value.gas_wanted.into(),
gas_used: value.gas_used.into(),
}
}
}
impl GasInfo {
pub fn new(gas_wanted: Gas, gas_used: Gas) -> Self {
GasInfo {
gas_wanted,
gas_used,
}
}
}
#[derive(Debug)]
pub struct AbciResult {
/// Data is any data returned from message or handler execution. It MUST be
/// length prefixed in order to separate data from multiple message executions.
pub data: Vec<u8>,
/// Log contains the log information from message or handler execution.
// todo: try to parse into Log?
pub log: String,
/// Events contains a slice of Event objects that were emitted during message
/// or handler execution.
pub events: Vec<abci::Event>,
}
impl TryFrom<ProtoAbciResult> for AbciResult {
type Error = NymdError;
fn try_from(value: ProtoAbciResult) -> Result<Self, Self::Error> {
let mut events = Vec::with_capacity(value.events.len());
for proto_event in value.events.into_iter() {
let type_str = proto_event.r#type;
let mut attributes = Vec::with_capacity(proto_event.attributes.len());
for proto_attribute in proto_event.attributes.into_iter() {
let stringified_ked = String::from_utf8(proto_attribute.key)
.map_err(|_| NymdError::DeserializationError("EventAttributeKey".to_owned()))?;
let stringified_value = String::from_utf8(proto_attribute.value)
.map_err(|_| NymdError::DeserializationError("EventAttributeKey".to_owned()))?;
attributes.push(abci::tag::Tag {
key: stringified_ked.parse().unwrap(),
value: stringified_value.parse().unwrap(),
})
}
events.push(abci::Event {
type_str,
attributes,
})
}
Ok(AbciResult {
data: value.data,
log: value.log,
events,
})
}
}
#[derive(Debug)]
pub struct SimulateResponse {
pub gas_info: Option<GasInfo>,
pub result: Option<AbciResult>,
}
impl TryFrom<ProtoSimulateResponse> for SimulateResponse {
type Error = NymdError;
fn try_from(value: ProtoSimulateResponse) -> Result<Self, Self::Error> {
Ok(SimulateResponse {
gas_info: value.gas_info.map(|gas_info| gas_info.into()),
result: value.result.map(|result| result.try_into()).transpose()?,
})
}
}
// ##############################################################################
// types specific to the signing client (perhaps they should go to separate file)
// ##############################################################################
@@ -248,6 +347,8 @@ pub struct UploadResult {
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: tx::Hash,
pub gas_info: GasInfo,
}
#[derive(Debug)]
@@ -274,6 +375,8 @@ pub struct InstantiateResult {
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: tx::Hash,
pub gas_info: GasInfo,
}
#[derive(Debug)]
@@ -282,6 +385,8 @@ pub struct ChangeAdminResult {
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: tx::Hash,
pub gas_info: GasInfo,
}
#[derive(Debug)]
@@ -290,6 +395,8 @@ pub struct MigrateResult {
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: tx::Hash,
pub gas_info: GasInfo,
}
#[derive(Debug)]
@@ -298,4 +405,6 @@ pub struct ExecuteResult {
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: tx::Hash,
pub gas_info: GasInfo,
}
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::nymd::cosmwasm_client::types::ContractCodeId;
use cosmrs::tendermint::block;
use cosmrs::tendermint::{abci, block};
use cosmrs::{bip32, tx, AccountId};
use std::io;
use thiserror::Error;
@@ -102,6 +102,12 @@ pub enum NymdError {
#[error("The provided gas price is malformed")]
MalformedGasPrice,
#[error("Failed to estimate gas price for the transaction")]
GasEstimationFailure,
#[error("Abci query failed with code {0} - {1}")]
AbciError(u32, abci::Log),
}
impl NymdError {
@@ -30,7 +30,7 @@ pub enum Operation {
UnbondGateway,
UnbondGatewayOnBehalf,
UpdateStateParams,
UpdateContractSettings,
BeginMixnodeRewarding,
FinishMixnodeRewarding,
@@ -68,7 +68,7 @@ impl fmt::Display for Operation {
Operation::UndelegateFromMixnodeOnBehalf => {
f.write_str("UndelegateFromMixnodeOnBehalf")
}
Operation::UpdateStateParams => f.write_str("UpdateStateParams"),
Operation::UpdateContractSettings => f.write_str("UpdateContractSettings"),
Operation::BeginMixnodeRewarding => f.write_str("BeginMixnodeRewarding"),
Operation::FinishMixnodeRewarding => f.write_str("FinishMixnodeRewarding"),
Operation::TrackUnbondGateway => f.write_str("TrackUnbondGateway"),
@@ -104,7 +104,7 @@ impl Operation {
Operation::UnbondGateway => 175_000u64.into(),
Operation::UnbondGatewayOnBehalf => 200_000u64.into(),
Operation::UpdateStateParams => 175_000u64.into(),
Operation::UpdateContractSettings => 175_000u64.into(),
Operation::BeginMixnodeRewarding => 175_000u64.into(),
Operation::FinishMixnodeRewarding => 175_000u64.into(),
Operation::TrackUnbondGateway => 175_000u64.into(),
@@ -125,9 +125,8 @@ impl Operation {
Fee::from_amount_and_gas(fee, gas_limit)
}
pub(crate) fn determine_fee(&self, gas_price: &GasPrice, gas_limit: Option<Gas>) -> Fee {
let gas_limit = gas_limit.unwrap_or_else(|| self.default_gas_limit());
Self::determine_custom_fee(gas_price, gas_limit)
pub fn default_fee(&self, gas_price: &GasPrice) -> Fee {
Self::determine_custom_fee(gas_price, self.default_gas_limit())
}
}
@@ -0,0 +1,33 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmrs::tx;
pub mod gas_price;
pub mod helpers;
pub const DEFAULT_SIMULATED_GAS_MULTIPLIER: f32 = 1.3;
#[derive(Debug, Clone)]
pub enum Fee {
Manual(tx::Fee),
Auto(Option<f32>),
}
impl From<tx::Fee> for Fee {
fn from(fee: tx::Fee) -> Self {
Fee::Manual(fee)
}
}
impl From<f32> for Fee {
fn from(multiplier: f32) -> Self {
Fee::Auto(Some(multiplier))
}
}
impl Default for Fee {
fn default() -> Self {
Fee::Auto(Some(DEFAULT_SIMULATED_GAS_MULTIPLIER))
}
}
@@ -7,11 +7,12 @@ use crate::nymd::cosmwasm_client::types::{
MigrateResult, SequenceResponse, UploadResult,
};
use crate::nymd::error::NymdError;
use crate::nymd::fee_helpers::Operation;
use crate::nymd::wallet::DirectSecp256k1HdWallet;
use cosmrs::rpc::endpoint::broadcast;
use cosmrs::rpc::{Error as TendermintRpcError, HttpClientUrl};
use cosmwasm_std::{Coin, Uint128};
pub use fee::gas_price::GasPrice;
use fee::helpers::Operation;
use mixnet_contract::{
ContractStateParams, Delegation, ExecuteMsg, Gateway, GatewayBond, GatewayOwnershipResponse,
IdentityKey, LayerDistribution, MixNode, MixNodeBond, MixOwnershipResponse,
@@ -20,38 +21,37 @@ use mixnet_contract::{
PagedMixnodeResponse, QueryMsg, RewardingIntervalResponse,
};
use serde::Serialize;
use std::collections::HashMap;
use std::convert::TryInto;
pub use crate::nymd::cosmwasm_client::client::CosmWasmClient;
pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient;
pub use crate::nymd::gas_price::GasPrice;
pub use crate::nymd::fee::Fee;
use crate::nymd::fee::DEFAULT_SIMULATED_GAS_MULTIPLIER;
pub use cosmrs::rpc::HttpClient as QueryNymdClient;
pub use cosmrs::tendermint::block::Height;
pub use cosmrs::tendermint::hash;
pub use cosmrs::tendermint::Time as TendermintTime;
pub use cosmrs::tx::{Fee, Gas};
pub use cosmrs::tx::{self, Gas};
pub use cosmrs::Coin as CosmosCoin;
pub use cosmrs::{AccountId, Decimal, Denom};
pub use signing_client::Client as SigningNymdClient;
use std::collections::HashMap;
pub use traits::{VestingQueryClient, VestingSigningClient};
pub mod cosmwasm_client;
pub mod error;
pub mod fee_helpers;
pub mod gas_price;
pub mod fee;
pub mod traits;
pub mod wallet;
pub use traits::{VestingQueryClient, VestingSigningClient};
#[derive(Debug)]
pub struct NymdClient<C> {
client: C,
mixnet_contract_address: Option<AccountId>,
vesting_contract_address: Option<AccountId>,
client_address: Option<Vec<AccountId>>,
gas_price: GasPrice,
custom_gas_limits: HashMap<Operation, Gas>,
simulated_gas_multiplier: f32,
}
impl NymdClient<QueryNymdClient> {
@@ -68,8 +68,8 @@ impl NymdClient<QueryNymdClient> {
mixnet_contract_address: Some(mixnet_contract_address),
vesting_contract_address: Some(vesting_contract_address),
client_address: None,
gas_price: Default::default(),
custom_gas_limits: Default::default(),
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
})
}
}
@@ -81,6 +81,7 @@ impl NymdClient<SigningNymdClient> {
mixnet_contract_address: Option<AccountId>,
vesting_contract_address: Option<AccountId>,
signer: DirectSecp256k1HdWallet,
gas_price: Option<GasPrice>,
) -> Result<NymdClient<SigningNymdClient>, NymdError>
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
@@ -92,12 +93,12 @@ impl NymdClient<SigningNymdClient> {
.collect();
Ok(NymdClient {
client: SigningNymdClient::connect_with_signer(endpoint, signer)?,
client: SigningNymdClient::connect_with_signer(endpoint, signer, gas_price)?,
mixnet_contract_address,
vesting_contract_address,
client_address: Some(client_address),
gas_price: Default::default(),
custom_gas_limits: Default::default(),
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
})
}
@@ -106,6 +107,7 @@ impl NymdClient<SigningNymdClient> {
mixnet_contract_address: Option<AccountId>,
vesting_contract_address: Option<AccountId>,
mnemonic: bip39::Mnemonic,
gas_price: Option<GasPrice>,
) -> Result<NymdClient<SigningNymdClient>, NymdError>
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
@@ -118,33 +120,17 @@ impl NymdClient<SigningNymdClient> {
.collect();
Ok(NymdClient {
client: SigningNymdClient::connect_with_signer(endpoint, wallet)?,
client: SigningNymdClient::connect_with_signer(endpoint, wallet, gas_price)?,
mixnet_contract_address,
vesting_contract_address,
client_address: Some(client_address),
gas_price: Default::default(),
custom_gas_limits: Default::default(),
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
})
}
}
impl<C> NymdClient<C> {
pub fn set_gas_price(&mut self, gas_price: GasPrice) {
self.gas_price = gas_price
}
pub fn set_custom_gas_limit(&mut self, operation: Operation, limit: Gas) {
self.custom_gas_limits.insert(operation, limit);
}
pub fn get_gas_price(&self) -> GasPrice {
self.gas_price.clone()
}
pub fn get_custom_gas_limits(&self) -> HashMap<Operation, Gas> {
self.custom_gas_limits.clone()
}
pub fn mixnet_contract_address(&self) -> Result<&AccountId, NymdError> {
self.mixnet_contract_address
.as_ref()
@@ -172,6 +158,46 @@ impl<C> NymdClient<C> {
&self.client_address.as_ref().unwrap()[0]
}
pub fn gas_price(&self) -> &GasPrice
where
C: SigningCosmWasmClient,
{
self.client.gas_price()
}
pub fn set_custom_gas_limit(&mut self, operation: Operation, limit: Gas)
where
C: SigningCosmWasmClient + Sync,
{
self.custom_gas_limits.insert(operation, limit);
}
pub fn operation_fee(&self, operation: Operation) -> Fee
where
C: SigningCosmWasmClient + Sync,
{
if let Some(&gas_limit) = self.custom_gas_limits.get(&operation) {
Operation::determine_custom_fee(self.client.gas_price(), gas_limit).into()
} else {
Fee::Auto(Some(self.simulated_gas_multiplier))
}
}
pub fn repeated_operation_fee(&self, operation: Operation, count: u64) -> Fee
where
C: SigningCosmWasmClient + Sync,
{
if let Some(&gas_limit) = self.custom_gas_limits.get(&operation) {
Operation::determine_custom_fee(
self.client.gas_price(),
(gas_limit.value() * count).into(),
)
.into()
} else {
Fee::Auto(Some(self.simulated_gas_multiplier))
}
}
pub async fn account_sequence(&self) -> Result<SequenceResponse, NymdError>
where
C: SigningCosmWasmClient + Sync,
@@ -179,25 +205,6 @@ impl<C> NymdClient<C> {
self.client.get_sequence(self.address()).await
}
pub fn get_fee(&self, operation: Operation) -> Fee {
let gas_limit = self.custom_gas_limits.get(&operation).cloned();
operation.determine_fee(&self.gas_price, gas_limit)
}
pub fn get_fee_multiple(&self, operation: Operation, times: u64) -> Fee {
let default_gas_limit = operation.default_gas_limit();
let gas_limit_unit = self
.custom_gas_limits
.get(&operation)
.unwrap_or(&default_gas_limit);
let gas_limit = Gas::from(gas_limit_unit.value() * times);
Operation::determine_custom_fee(&self.gas_price, gas_limit)
}
pub fn calculate_custom_fee(&self, gas_limit: impl Into<Gas>) -> Fee {
Operation::determine_custom_fee(&self.gas_price, gas_limit.into())
}
pub async fn get_current_block_timestamp(&self) -> Result<TendermintTime, NymdError>
where
C: CosmWasmClient + Sync,
@@ -483,7 +490,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::Send);
let fee = self.operation_fee(Operation::Send);
self.client
.send_tokens(self.address(), recipient, amount, fee, memo)
.await
@@ -498,7 +505,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee_multiple(Operation::Send, msgs.len() as u64);
let fee = self.repeated_operation_fee(Operation::Send, msgs.len() as u64);
self.client
.send_tokens_multiple(self.address(), msgs, fee, memo)
.await
@@ -546,7 +553,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::Upload);
let fee = self.operation_fee(Operation::Upload);
self.client
.upload(self.address(), wasm_code, fee, memo)
.await
@@ -564,7 +571,7 @@ impl<C> NymdClient<C> {
C: SigningCosmWasmClient + Sync,
M: ?Sized + Serialize + Sync,
{
let fee = self.get_fee(Operation::Init);
let fee = self.operation_fee(Operation::Init);
self.client
.instantiate(self.address(), code_id, msg, label, fee, memo, options)
.await
@@ -579,7 +586,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::ChangeAdmin);
let fee = self.operation_fee(Operation::ChangeAdmin);
self.client
.update_admin(self.address(), contract_address, new_admin, fee, memo)
.await
@@ -593,7 +600,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::ChangeAdmin);
let fee = self.operation_fee(Operation::ChangeAdmin);
self.client
.clear_admin(self.address(), contract_address, fee, memo)
.await
@@ -610,7 +617,7 @@ impl<C> NymdClient<C> {
C: SigningCosmWasmClient + Sync,
M: ?Sized + Serialize + Sync,
{
let fee = self.get_fee(Operation::Migrate);
let fee = self.operation_fee(Operation::Migrate);
self.client
.migrate(self.address(), contract_address, code_id, fee, msg, memo)
.await
@@ -626,7 +633,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::BondMixnode);
let fee = self.operation_fee(Operation::BondMixnode);
let req = ExecuteMsg::BondMixnode {
mix_node: mixnode,
@@ -655,7 +662,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::BondMixnodeOnBehalf);
let fee = self.operation_fee(Operation::BondMixnodeOnBehalf);
let req = ExecuteMsg::BondMixnodeOnBehalf {
mix_node: mixnode,
@@ -682,7 +689,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee_multiple(
let fee = self.repeated_operation_fee(
Operation::BondMixnodeOnBehalf,
mixnode_bonds_with_sigs.len() as u64,
);
@@ -717,7 +724,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::UnbondMixnode);
let fee = self.operation_fee(Operation::UnbondMixnode);
let req = ExecuteMsg::UnbondMixnode {};
self.client
@@ -737,7 +744,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::UnbondMixnodeOnBehalf);
let fee = self.operation_fee(Operation::UnbondMixnodeOnBehalf);
let req = ExecuteMsg::UnbondMixnodeOnBehalf { owner };
self.client
@@ -761,7 +768,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::DelegateToMixnode);
let fee = self.operation_fee(Operation::DelegateToMixnode);
let req = ExecuteMsg::DelegateToMixnode {
mix_identity: mix_identity.to_string(),
@@ -789,7 +796,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::DelegateToMixnodeOnBehalf);
let fee = self.operation_fee(Operation::DelegateToMixnodeOnBehalf);
let req = ExecuteMsg::DelegateToMixnodeOnBehalf {
mix_identity: mix_identity.to_string(),
@@ -815,7 +822,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee_multiple(
let fee = self.repeated_operation_fee(
Operation::DelegateToMixnodeOnBehalf,
mixnode_delegations.len() as u64,
);
@@ -852,7 +859,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::UndelegateFromMixnode);
let fee = self.operation_fee(Operation::UndelegateFromMixnode);
let req = ExecuteMsg::UndelegateFromMixnode {
mix_identity: mix_identity.to_string(),
@@ -878,7 +885,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::UndelegateFromMixnodeOnBehalf);
let fee = self.operation_fee(Operation::UndelegateFromMixnodeOnBehalf);
let req = ExecuteMsg::UndelegateFromMixnodeOnBehalf {
mix_identity: mix_identity.to_string(),
@@ -906,7 +913,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::BondGateway);
let fee = self.operation_fee(Operation::BondGateway);
let req = ExecuteMsg::BondGateway {
gateway,
@@ -935,7 +942,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::BondGatewayOnBehalf);
let fee = self.operation_fee(Operation::BondGatewayOnBehalf);
let req = ExecuteMsg::BondGatewayOnBehalf {
gateway,
@@ -962,7 +969,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee_multiple(
let fee = self.repeated_operation_fee(
Operation::BondGatewayOnBehalf,
gateway_bonds_with_sigs.len() as u64,
);
@@ -997,7 +1004,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::UnbondGateway);
let fee = self.operation_fee(Operation::UnbondGateway);
let req = ExecuteMsg::UnbondGateway {};
self.client
@@ -1018,7 +1025,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::UnbondGatewayOnBehalf);
let fee = self.operation_fee(Operation::UnbondGatewayOnBehalf);
let req = ExecuteMsg::UnbondGatewayOnBehalf { owner };
self.client
@@ -1040,7 +1047,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::UpdateStateParams);
let fee = self.operation_fee(Operation::UpdateContractSettings);
let req = ExecuteMsg::UpdateContractStateParams(new_params);
self.client
@@ -1062,7 +1069,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::BeginMixnodeRewarding);
let fee = self.operation_fee(Operation::BeginMixnodeRewarding);
let req = ExecuteMsg::BeginMixnodeRewarding {
rewarding_interval_nonce,
@@ -1086,7 +1093,7 @@ impl<C> NymdClient<C> {
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::FinishMixnodeRewarding);
let fee = self.operation_fee(Operation::FinishMixnodeRewarding);
let req = ExecuteMsg::FinishMixnodeRewarding {
rewarding_interval_nonce,
@@ -52,8 +52,8 @@ pub trait VestingQueryClient {
async fn delegated_vesting(
&self,
block_time: Option<Timestamp>,
vesting_account_address: &str,
block_time: Option<Timestamp>,
) -> Result<Coin, NymdError>;
}
@@ -162,8 +162,8 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
async fn delegated_vesting(
&self,
block_time: Option<Timestamp>,
vesting_account_address: &str,
block_time: Option<Timestamp>,
) -> Result<Coin, NymdError> {
let request = VestingQueryMsg::GetDelegatedVesting {
vesting_account_address: vesting_account_address.to_string(),
@@ -4,11 +4,11 @@
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_helpers::Operation;
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::{Gateway, IdentityKey, MixNode};
use mixnet_contract::{Gateway, IdentityKey, IdentityKeyRef, MixNode};
use vesting_contract::messages::ExecuteMsg as VestingExecuteMsg;
#[async_trait]
@@ -16,9 +16,10 @@ pub trait VestingSigningClient {
async fn vesting_bond_gateway(
&self,
gateway: Gateway,
pledge: Coin,
owner_signature: &str,
pledge: Coin,
) -> Result<ExecuteResult, NymdError>;
async fn vesting_unbond_gateway(&self) -> Result<ExecuteResult, NymdError>;
async fn vesting_track_unbond_gateway(
@@ -30,8 +31,8 @@ pub trait VestingSigningClient {
async fn vesting_bond_mixnode(
&self,
mix_node: MixNode,
pledge: Coin,
owner_signature: &str,
pledge: Coin,
) -> Result<ExecuteResult, NymdError>;
async fn vesting_unbond_mixnode(&self) -> Result<ExecuteResult, NymdError>;
@@ -40,6 +41,7 @@ pub trait VestingSigningClient {
owner: &str,
amount: Coin,
) -> Result<ExecuteResult, NymdError>;
async fn withdraw_vested_coins(&self, amount: Coin) -> Result<ExecuteResult, NymdError>;
async fn vesting_track_undelegation(
@@ -49,15 +51,15 @@ pub trait VestingSigningClient {
amount: Coin,
) -> Result<ExecuteResult, NymdError>;
async fn vesting_delegate_to_mixnode(
async fn vesting_delegate_to_mixnode<'a>(
&self,
mix_identity: IdentityKey,
amount: Coin,
mix_identity: IdentityKeyRef<'a>,
amount: &Coin,
) -> Result<ExecuteResult, NymdError>;
async fn vesting_undelegate_from_mixnode(
async fn vesting_undelegate_from_mixnode<'a>(
&self,
mix_identity: IdentityKey,
mix_identity: IdentityKeyRef<'a>,
) -> Result<ExecuteResult, NymdError>;
async fn create_periodic_vesting_account(
@@ -73,10 +75,10 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
async fn vesting_bond_gateway(
&self,
gateway: Gateway,
pledge: Coin,
owner_signature: &str,
pledge: Coin,
) -> Result<ExecuteResult, NymdError> {
let fee = self.get_fee(Operation::BondGateway);
let fee = self.operation_fee(Operation::BondGateway);
let req = VestingExecuteMsg::BondGateway {
gateway,
owner_signature: owner_signature.to_string(),
@@ -94,7 +96,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
}
async fn vesting_unbond_gateway(&self) -> Result<ExecuteResult, NymdError> {
let fee = self.get_fee(Operation::UnbondGateway);
let fee = self.operation_fee(Operation::UnbondGateway);
let req = VestingExecuteMsg::UnbondGateway {};
self.client
.execute(
@@ -113,7 +115,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
owner: &str,
amount: Coin,
) -> Result<ExecuteResult, NymdError> {
let fee = self.get_fee(Operation::TrackUnbondGateway);
let fee = self.operation_fee(Operation::TrackUnbondGateway);
let req = VestingExecuteMsg::TrackUnbondGateway {
owner: owner.to_string(),
amount,
@@ -133,10 +135,10 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
async fn vesting_bond_mixnode(
&self,
mix_node: MixNode,
pledge: Coin,
owner_signature: &str,
pledge: Coin,
) -> Result<ExecuteResult, NymdError> {
let fee = self.get_fee(Operation::BondMixnode);
let fee = self.operation_fee(Operation::BondMixnode);
let req = VestingExecuteMsg::BondMixnode {
mix_node,
owner_signature: owner_signature.to_string(),
@@ -154,7 +156,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
}
async fn vesting_unbond_mixnode(&self) -> Result<ExecuteResult, NymdError> {
let fee = self.get_fee(Operation::UnbondMixnode);
let fee = self.operation_fee(Operation::UnbondMixnode);
let req = VestingExecuteMsg::UnbondMixnode {};
self.client
.execute(
@@ -173,7 +175,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
owner: &str,
amount: Coin,
) -> Result<ExecuteResult, NymdError> {
let fee = self.get_fee(Operation::TrackUnbondMixnode);
let fee = self.operation_fee(Operation::TrackUnbondMixnode);
let req = VestingExecuteMsg::TrackUnbondMixnode {
owner: owner.to_string(),
amount,
@@ -191,7 +193,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
}
async fn withdraw_vested_coins(&self, amount: Coin) -> Result<ExecuteResult, NymdError> {
let fee = self.get_fee(Operation::WithdrawVestedCoins);
let fee = self.operation_fee(Operation::WithdrawVestedCoins);
let req = VestingExecuteMsg::WithdrawVestedCoins { amount };
self.client
.execute(
@@ -211,7 +213,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
mix_identity: IdentityKey,
amount: Coin,
) -> Result<ExecuteResult, NymdError> {
let fee = self.get_fee(Operation::TrackUndelegation);
let fee = self.operation_fee(Operation::TrackUndelegation);
let req = VestingExecuteMsg::TrackUndelegation {
owner: address.to_string(),
mix_identity,
@@ -228,13 +230,15 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
)
.await
}
async fn vesting_delegate_to_mixnode(
async fn vesting_delegate_to_mixnode<'a>(
&self,
mix_identity: IdentityKey,
amount: Coin,
mix_identity: IdentityKeyRef<'a>,
amount: &Coin,
) -> Result<ExecuteResult, NymdError> {
let fee = self.get_fee(Operation::DelegateToMixnode);
let req = VestingExecuteMsg::DelegateToMixnode { mix_identity };
let fee = self.operation_fee(Operation::DelegateToMixnode);
let req = VestingExecuteMsg::DelegateToMixnode {
mix_identity: mix_identity.into(),
};
self.client
.execute(
self.address(),
@@ -242,16 +246,18 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
&req,
fee,
"VestingContract::DeledateToMixnode",
vec![cosmwasm_coin_to_cosmos_coin(amount)],
vec![cosmwasm_coin_to_cosmos_coin(amount.to_owned())],
)
.await
}
async fn vesting_undelegate_from_mixnode(
async fn vesting_undelegate_from_mixnode<'a>(
&self,
mix_identity: IdentityKey,
mix_identity: IdentityKeyRef<'a>,
) -> Result<ExecuteResult, NymdError> {
let fee = self.get_fee(Operation::UndelegateFromMixnode);
let req = VestingExecuteMsg::UndelegateFromMixnode { mix_identity };
let fee = self.operation_fee(Operation::UndelegateFromMixnode);
let req = VestingExecuteMsg::UndelegateFromMixnode {
mix_identity: mix_identity.into(),
};
self.client
.execute(
self.address(),
@@ -269,7 +275,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
start_time: Option<u64>,
amount: Coin,
) -> Result<ExecuteResult, NymdError> {
let fee = self.get_fee(Operation::CreatePeriodicVestingAccount);
let fee = self.operation_fee(Operation::CreatePeriodicVestingAccount);
let req = VestingExecuteMsg::CreateAccount {
address: address.to_string(),
start_time,
@@ -10,7 +10,7 @@ use cosmrs::tx::SignDoc;
use cosmrs::{tx, AccountId};
/// Derivation information required to derive a keypair and an address from a mnemonic.
#[derive(Debug)]
#[derive(Debug, Clone)]
struct Secp256k1Derivation {
hd_path: DerivationPath,
prefix: String,
@@ -40,7 +40,7 @@ impl AccountData {
type Secp256k1Keypair = (SigningKey, PublicKey);
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct DirectSecp256k1HdWallet {
/// Base secret
secret: bip39::Mnemonic,
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use ed25519_dalek::ed25519::signature::Signature as SignatureTrait;
pub use ed25519_dalek::ed25519::signature::Signature as SignatureTrait;
pub use ed25519_dalek::SignatureError;
pub use ed25519_dalek::{Verifier, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH};
use nymsphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH};
+44 -9
View File
@@ -56,32 +56,68 @@ pub enum Layer {
#[derive(Debug, Clone, JsonSchema, PartialEq, Serialize, Deserialize, Copy)]
pub struct NodeRewardParams {
period_reward_pool: Uint128,
k: Uint128,
rewarded_set_size: Uint128,
active_set_size: Uint128,
reward_blockstamp: u64,
circulating_supply: Uint128,
uptime: Uint128,
sybil_resistance_percent: u8,
in_active_set: bool,
active_set_work_factor: u8,
}
impl NodeRewardParams {
#[allow(clippy::too_many_arguments)]
pub fn new(
period_reward_pool: u128,
k: u128,
rewarded_set_size: u128,
active_set_size: u128,
reward_blockstamp: u64,
circulating_supply: u128,
uptime: u128,
sybil_resistance_percent: u8,
in_active_set: bool,
active_set_work_factor: u8,
) -> NodeRewardParams {
NodeRewardParams {
period_reward_pool: Uint128::new(period_reward_pool),
k: Uint128::new(k),
rewarded_set_size: Uint128::new(rewarded_set_size),
active_set_size: Uint128::new(active_set_size),
reward_blockstamp,
circulating_supply: Uint128::new(circulating_supply),
uptime: Uint128::new(uptime),
sybil_resistance_percent,
in_active_set,
active_set_work_factor,
}
}
pub fn omega(&self) -> U128 {
// As per keybase://chat/nymtech#tokeneconomics/1179
let denom = self.active_set_work_factor() * U128::from_num(self.rewarded_set_size())
- (self.active_set_work_factor() - ONE) * U128::from_num(self.idle_nodes().u128());
if self.in_active_set() {
// work_active = factor / (factor * self.network.k[month] - (factor - 1) * idle_nodes)
self.active_set_work_factor() / denom * self.rewarded_set_size()
} else {
// work_idle = 1 / (factor * self.network.k[month] - (factor - 1) * idle_nodes)
ONE / denom * self.rewarded_set_size()
}
}
pub fn idle_nodes(&self) -> Uint128 {
self.rewarded_set_size - self.active_set_size
}
pub fn active_set_work_factor(&self) -> U128 {
U128::from_num(self.active_set_work_factor)
}
pub fn in_active_set(&self) -> bool {
self.in_active_set
}
pub fn performance(&self) -> U128 {
U128::from_num(self.uptime.u128()) / U128::from_num(100)
}
@@ -98,8 +134,8 @@ impl NodeRewardParams {
self.period_reward_pool.u128()
}
pub fn k(&self) -> u128 {
self.k.u128()
pub fn rewarded_set_size(&self) -> u128 {
self.rewarded_set_size.u128()
}
pub fn circulating_supply(&self) -> u128 {
@@ -115,7 +151,7 @@ impl NodeRewardParams {
}
pub fn one_over_k(&self) -> U128 {
ONE / U128::from_num(self.k.u128())
ONE / U128::from_num(self.rewarded_set_size.u128())
}
pub fn alpha(&self) -> U128 {
@@ -315,14 +351,13 @@ impl MixNodeBond {
}
pub fn reward(&self, params: &NodeRewardParams) -> NodeRewardResult {
// Assuming uniform work distribution across the network this is one_over_k * k
let omega_k = ONE;
let lambda = self.lambda(params);
let sigma = self.sigma(params);
let reward = params.performance()
* params.period_reward_pool()
* (sigma * omega_k + params.alpha() * lambda * sigma * params.k())
* (sigma * params.omega()
+ params.alpha() * lambda * sigma * params.rewarded_set_size())
/ (ONE + params.alpha());
NodeRewardResult {
+6
View File
@@ -50,6 +50,7 @@ pub struct ContractStateParams {
// subset of rewarded mixnodes that are actively receiving mix traffic
// used to handle shorter-term (e.g. hourly) fluctuations of demand
pub mixnode_active_set_size: u32,
pub active_set_work_factor: u8,
}
impl Display for ContractStateParams {
@@ -74,6 +75,11 @@ impl Display for ContractStateParams {
f,
"mixnode active set size: {}",
self.mixnode_active_set_size
)?;
write!(
f,
"mixnode active set work factor: {}",
self.active_set_work_factor
)
}
}
+4 -6
View File
@@ -37,11 +37,7 @@ pub const INITIAL_MIXNODE_ACTIVE_SET_SIZE: u32 = 100;
pub const INITIAL_REWARD_POOL: u128 = 250_000_000_000_000;
pub const EPOCH_REWARD_PERCENT: u8 = 2; // Used to calculate epoch reward pool
pub const DEFAULT_SYBIL_RESISTANCE_PERCENT: u8 = 30;
// We'll be assuming a few more things, profit margin and cost function. Since we don't have reliable package measurement, we'll be using uptime. We'll also set the value of 1 Nym to 1 $, to be able to translate epoch costs to Nyms. We'll also assume a cost of 40$ per epoch(month), converting that to Nym at our 1$ rate translates to 40_000_000 uNyms
// question to @durch: where do we need it (if at all)?
#[allow(dead_code)]
pub const DEFAULT_COST_PER_EPOCH: u32 = 40_000_000;
pub const DEFAULT_ACTIVE_SET_WORK_FACTOR: u8 = 10;
fn default_initial_state(
owner: Addr,
@@ -56,6 +52,7 @@ fn default_initial_state(
minimum_gateway_pledge: INITIAL_GATEWAY_PLEDGE,
mixnode_rewarded_set_size: INITIAL_MIXNODE_REWARDED_SET_SIZE,
mixnode_active_set_size: INITIAL_MIXNODE_ACTIVE_SET_SIZE,
active_set_work_factor: DEFAULT_ACTIVE_SET_WORK_FACTOR,
},
rewarding_interval_starting_block: env.block.height,
latest_rewarding_interval_nonce: 0,
@@ -285,7 +282,8 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, Cont
}
#[entry_point]
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
Ok(Default::default())
todo!("ACTIVE_STATE_WORK_FACTOR to State");
// Ok(Default::default())
}
#[cfg(test)]
@@ -55,6 +55,7 @@ pub(crate) mod tests {
minimum_gateway_pledge: 456u128.into(),
mixnode_rewarded_set_size: 1000,
mixnode_active_set_size: 500,
active_set_work_factor: 10,
},
rewarding_interval_starting_block: 123,
latest_rewarding_interval_nonce: 0,
@@ -60,6 +60,7 @@ pub mod tests {
minimum_gateway_pledge: INITIAL_GATEWAY_PLEDGE,
mixnode_rewarded_set_size: 100,
mixnode_active_set_size: 50,
active_set_work_factor: 10,
};
// sanity check to ensure new_params are different than the default ones
+11 -13
View File
@@ -251,10 +251,6 @@ pub(crate) fn try_reward_next_mixnode_delegators(
}
}
// Note: if any changes are made to this function or anything it is calling down the stack,
// for example delegation reward distribution, the gas limits must be retested and both
// validator-api/src/rewarding/mod.rs::{MIXNODE_REWARD_OP_BASE_GAS_LIMIT, PER_MIXNODE_DELEGATION_GAS_INCREASE}
// must be updated appropriately.
pub(crate) fn try_reward_mixnode(
deps: DepsMut,
env: Env,
@@ -1088,12 +1084,11 @@ pub mod tests {
let rewarding_validator_address = current_state.rewarding_validator_address;
let period_reward_pool = (INITIAL_REWARD_POOL / 100) * EPOCH_REWARD_PERCENT as u128;
assert_eq!(period_reward_pool, 5_000_000_000_000);
let k = 200; // Imagining our active set size is 200
let rewarded_set_size = 200; // Imagining our reward set size is 200
let active_set_size = 100;
let active_set_work_factor = 10;
let circulating_supply = storage::circulating_supply(&deps.storage).unwrap().u128();
assert_eq!(circulating_supply, 750_000_000_000_000u128);
// mut_reward_pool(deps.as_mut().storage)
// .save(&Uint128::new(period_reward_pool))
// .unwrap();
let node_owner: Addr = Addr::unchecked("alice");
let node_identity = test_helpers::add_mixnode(
@@ -1136,11 +1131,14 @@ pub mod tests {
let mut params = NodeRewardParams::new(
period_reward_pool,
k,
rewarded_set_size,
active_set_size,
0,
circulating_supply,
mix_1_uptime,
DEFAULT_SYBIL_RESISTANCE_PERCENT,
true,
active_set_work_factor,
);
params.set_reward_blockstamp(env.block.height);
@@ -1157,7 +1155,7 @@ pub mod tests {
mix_1_reward_result.lambda(),
U128::from_num(0.0000133333333333)
);
assert_eq!(mix_1_reward_result.reward().int(), 102646153);
assert_eq!(mix_1_reward_result.reward().int(), 186562237);
let mix1_operator_profit = mix_1.operator_reward(&params);
@@ -1165,9 +1163,9 @@ pub mod tests {
let mix1_delegator2_reward = mix_1.reward_delegation(Uint128::new(2000_000000), &params);
assert_eq!(mix1_operator_profit, U128::from_num(74455384));
assert_eq!(mix1_delegator1_reward, U128::from_num(22552615));
assert_eq!(mix1_delegator2_reward, U128::from_num(5638153));
assert_eq!(mix1_operator_profit, U128::from_num(120609230));
assert_eq!(mix1_delegator1_reward, U128::from_num(52762405));
assert_eq!(mix1_delegator2_reward, U128::from_num(13190601));
let pre_reward_bond =
test_helpers::read_mixnode_pledge_amount(&deps.storage, &node_identity)
+3
View File
@@ -247,10 +247,13 @@ pub mod test_helpers {
NodeRewardParams::new(
(INITIAL_REWARD_POOL / 100) * EPOCH_REWARD_PERCENT as u128,
50 as u128,
25 as u128,
0,
TOTAL_SUPPLY - INITIAL_REWARD_POOL,
uptime,
DEFAULT_SYBIL_RESISTANCE_PERCENT,
true,
10,
)
}
+3
View File
@@ -0,0 +1,3 @@
EXPLORER_API_URL=https://testnet-milhon-explorer.nymtech.net
VALIDATOR_API_URL=https://testnet-milhon-validator1.nymtech.net
BIG_DIPPER_URL=https://testnet-milhon-blocks.nymtech.net
+3
View File
@@ -0,0 +1,3 @@
EXPLORER_API_URL=https://testnet-milhon-explorer.nymtech.net
VALIDATOR_API_URL=https://testnet-milhon-validator1.nymtech.net
BIG_DIPPER_URL=https://testnet-milhon-blocks.nymtech.net
+60
View File
@@ -50,6 +50,7 @@
"clean-webpack-plugin": "^4.0.0",
"css-loader": "^6.2.0",
"css-minimizer-webpack-plugin": "^3.0.2",
"dotenv-webpack": "^7.0.3",
"eslint": "7.32.0",
"eslint-config-airbnb": "18.2.1",
"eslint-config-prettier": "8.3.0",
@@ -6198,6 +6199,39 @@
"tslib": "^2.0.3"
}
},
"node_modules/dotenv-defaults": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz",
"integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==",
"dev": true,
"dependencies": {
"dotenv": "^8.2.0"
}
},
"node_modules/dotenv-defaults/node_modules/dotenv": {
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz",
"integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"node_modules/dotenv-webpack": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-7.0.3.tgz",
"integrity": "sha512-O0O9pOEwrk+n1zzR3T2uuXRlw64QxHSPeNN1GaiNBloQFNaCUL9V8jxSVz4jlXXFP/CIqK8YecWf8BAvsSgMjw==",
"dev": true,
"dependencies": {
"dotenv-defaults": "^2.0.2"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"webpack": "^4 || ^5"
}
},
"node_modules/ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@@ -21882,6 +21916,32 @@
"tslib": "^2.0.3"
}
},
"dotenv-defaults": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz",
"integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==",
"dev": true,
"requires": {
"dotenv": "^8.2.0"
},
"dependencies": {
"dotenv": {
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz",
"integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==",
"dev": true
}
}
},
"dotenv-webpack": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-7.0.3.tgz",
"integrity": "sha512-O0O9pOEwrk+n1zzR3T2uuXRlw64QxHSPeNN1GaiNBloQFNaCUL9V8jxSVz4jlXXFP/CIqK8YecWf8BAvsSgMjw==",
"dev": true,
"requires": {
"dotenv-defaults": "^2.0.2"
}
},
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+1
View File
@@ -45,6 +45,7 @@
"clean-webpack-plugin": "^4.0.0",
"css-loader": "^6.2.0",
"css-minimizer-webpack-plugin": "^3.0.2",
"dotenv-webpack": "^7.0.3",
"eslint": "7.32.0",
"eslint-config-airbnb": "18.2.1",
"eslint-config-prettier": "8.3.0",
+3 -4
View File
@@ -1,8 +1,7 @@
// master APIs
export const MASTER_URL = 'https://testnet-milhon-explorer.nymtech.net';
export const MASTER_VALIDATOR_URL =
'https://testnet-milhon-validator1.nymtech.net';
export const BIG_DIPPER = 'https://testnet-milhon-blocks.nymtech.net';
export const MASTER_URL = process.env.EXPLORER_API_URL;
export const MASTER_VALIDATOR_URL = process.env.VALIDATOR_API_URL;
export const BIG_DIPPER = process.env.BIG_DIPPER_URL;
// specific API routes
export const MIXNODE_PING = `${MASTER_URL}/api/ping`;
+3
View File
@@ -5,6 +5,7 @@ const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const WebpackFavicons = require('webpack-favicons');
const Dotenv = require('dotenv-webpack');
module.exports = {
entry: './src/index.tsx',
@@ -78,6 +79,8 @@ module.exports = {
new WebpackFavicons({
src: 'src/logo.svg',
}),
new Dotenv(),
],
output: {
path: path.resolve(__dirname, 'dist'),
@@ -21,7 +21,7 @@ use erc20_bridge_contract::payment::LinkPaymentData;
use gateway_client::bandwidth::eth_contract;
use network_defaults::{COSMOS_CONTRACT_ADDRESS, DENOM, ETH_EVENT_NAME, ETH_MIN_BLOCK_DEPTH};
use validator_client::nymd::{
AccountId, CosmosCoin, Decimal, Denom, Fee, Gas, NymdClient, SigningNymdClient,
AccountId, CosmosCoin, Decimal, Denom, NymdClient, SigningNymdClient,
};
pub(crate) struct ERC20Bridge {
@@ -45,6 +45,7 @@ impl ERC20Bridge {
AccountId::from_str(COSMOS_CONTRACT_ADDRESS).ok(),
None,
mnemonic,
None,
)
.expect("Could not create nymd client");
@@ -106,7 +107,6 @@ impl ERC20Bridge {
denom: Denom::from_str(DENOM).unwrap(),
amount: Decimal::from(100000u64),
};
let fee = Fee::from_amount_and_gas(coin.clone(), Gas::from(500000));
let req = ExecuteMsg::LinkPayment {
data: LinkPaymentData::new(
credential.verification_key().to_bytes(),
@@ -120,7 +120,7 @@ impl ERC20Bridge {
// it's ok to unwrap here, as the address is
contract_address,
&req,
fee,
Default::default(),
"Linking payment",
vec![coin],
)
+148 -144
View File
@@ -57,9 +57,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.45"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7"
checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
[[package]]
name = "arrayref"
@@ -89,9 +89,9 @@ dependencies = [
[[package]]
name = "async-trait"
version = "0.1.51"
version = "0.1.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e"
checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
dependencies = [
"proc-macro2",
"quote",
@@ -154,9 +154,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "az"
version = "1.1.2"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6dff4a1892b54d70af377bf7a17064192e822865791d812957f21e3108c325"
checksum = "f771a5d1f5503f7f4279a30f3643d3421ba149848b89ecaaec0ea2acf04a5ac4"
[[package]]
name = "base64"
@@ -331,9 +331,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "bytemuck"
version = "1.7.2"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b"
checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f"
[[package]]
name = "byteorder"
@@ -394,9 +394,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.71"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
dependencies = [
"jobserver",
]
@@ -448,19 +448,6 @@ dependencies = [
"keystream",
]
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"serde",
"winapi",
]
[[package]]
name = "cipher"
version = "0.3.0"
@@ -696,9 +683,9 @@ dependencies = [
[[package]]
name = "cosmwasm-crypto"
version = "1.0.0-beta2"
version = "1.0.0-beta3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c16b255449b3f5cd7fa4b79acd5225b5185655261087a3d8aaac44f88a0e23e9"
checksum = "a380b87642204557629c9b72988c47b55fbfe6d474960adba56b22331504956a"
dependencies = [
"digest 0.9.0",
"ed25519-zebra",
@@ -709,18 +696,18 @@ dependencies = [
[[package]]
name = "cosmwasm-derive"
version = "1.0.0-beta2"
version = "1.0.0-beta3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abad1a6ff427a2f66890a4dce6354b4563cd07cee91a942300e011c921c09ed2"
checksum = "866713b2fe13f23038c7d8824c3059d1f28dd94685fb406d1533c4eeeefeefae"
dependencies = [
"syn",
]
[[package]]
name = "cosmwasm-std"
version = "1.0.0-beta2"
version = "1.0.0-beta3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1660ee3d5734672e1eb4f0ceda403e2d83345e15143a48845f340f3252ce99a6"
checksum = "8dbb9939b31441dfa9af3ec9740c8a24d585688401eff1b6b386abb7ad0d10a8"
dependencies = [
"base64",
"cosmwasm-crypto",
@@ -743,9 +730,9 @@ dependencies = [
[[package]]
name = "crc32fast"
version = "1.2.1"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836"
dependencies = [
"cfg-if 1.0.0",
]
@@ -872,7 +859,7 @@ checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a"
dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa",
"itoa 0.4.8",
"matches",
"phf 0.8.0",
"proc-macro2",
@@ -909,6 +896,12 @@ dependencies = [
"cipher",
]
[[package]]
name = "cty"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
[[package]]
name = "curve25519-dalek"
version = "3.2.0"
@@ -990,9 +983,9 @@ dependencies = [
[[package]]
name = "der"
version = "0.4.4"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28e98c534e9c8a0483aa01d6f6913bc063de254311bd267c9cf535e9b70e15b2"
checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4"
dependencies = [
"const-oid",
]
@@ -1010,14 +1003,14 @@ dependencies = [
[[package]]
name = "derive_more"
version = "0.99.16"
version = "0.99.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40eebddd2156ce1bb37b20bbe5151340a31828b1f2d22ba4141f3531710e38df"
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
dependencies = [
"convert_case",
"proc-macro2",
"quote",
"rustc_version",
"rustc_version 0.4.0",
"syn",
]
@@ -1160,9 +1153,9 @@ dependencies = [
[[package]]
name = "ed25519"
version = "1.2.0"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4620d40f6d2601794401d6dd95a5cf69b6c157852539470eeda433a99b3c0efc"
checksum = "74e1069e39f1454367eb2de793ed062fac4c35c2934b76a81d90dd9abcd28816"
dependencies = [
"signature",
]
@@ -1225,9 +1218,9 @@ checksum = "53dd2e43a7d32952a6054141ee0d75183958620e84e5eab045de362dff13dc99"
[[package]]
name = "encoding_rs"
version = "0.8.29"
version = "0.8.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746"
checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df"
dependencies = [
"cfg-if 1.0.0",
]
@@ -1286,7 +1279,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92"
dependencies = [
"memoffset",
"rustc_version",
"rustc_version 0.3.3",
]
[[package]]
@@ -1303,9 +1296,9 @@ dependencies = [
[[package]]
name = "fixed"
version = "1.10.0"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d333a26ec13a023c6dff4b7584de4d323cfee2e508f5dd2bbee6669e4f7efdf"
checksum = "80a9a8cb2e34880a498f09367089339bda5e12d6f871640f947850f7113058c0"
dependencies = [
"az",
"bytemuck",
@@ -1631,9 +1624,9 @@ dependencies = [
[[package]]
name = "getset"
version = "0.1.1"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24b328c01a4d71d2d8173daa93562a73ab0fe85616876f02500f53d82948c504"
checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9"
dependencies = [
"proc-macro-error",
"proc-macro2",
@@ -1843,9 +1836,9 @@ dependencies = [
[[package]]
name = "h2"
version = "0.3.7"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55"
checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd"
dependencies = [
"bytes",
"fnv",
@@ -1937,9 +1930,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hex-literal"
version = "0.3.3"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21e4590e13640f19f249fe3e4eca5113bc4289f2497710378190e7f4bd96f45b"
checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0"
[[package]]
name = "hkd32"
@@ -1997,7 +1990,7 @@ checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
dependencies = [
"bytes",
"fnv",
"itoa",
"itoa 0.4.8",
]
[[package]]
@@ -2025,9 +2018,9 @@ checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
[[package]]
name = "httpdate"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "humantime"
@@ -2047,9 +2040,9 @@ dependencies = [
[[package]]
name = "hyper"
version = "0.14.14"
version = "0.14.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b"
checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55"
dependencies = [
"bytes",
"futures-channel",
@@ -2060,7 +2053,7 @@ dependencies = [
"http-body",
"httparse",
"httpdate",
"itoa",
"itoa 0.4.8",
"pin-project-lite",
"socket2",
"tokio",
@@ -2227,9 +2220,9 @@ dependencies = [
[[package]]
name = "itertools"
version = "0.10.1"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
@@ -2240,6 +2233,12 @@ version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "javascriptcore-rs"
version = "0.14.0"
@@ -2328,9 +2327,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.107"
version = "0.2.112"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
[[package]]
name = "libm"
@@ -2370,9 +2369,9 @@ dependencies = [
[[package]]
name = "loom"
version = "0.5.2"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2b9df80a3804094bf49bb29881d18f6f05048db72127e84e09c26fc7c2324f5"
checksum = "edc5c7d328e32cc4954e8e01193d7f0ef5ab257b5090b70a964e099a36034309"
dependencies = [
"cfg-if 1.0.0",
"generator",
@@ -2420,9 +2419,9 @@ dependencies = [
[[package]]
name = "matchers"
version = "0.0.1"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
dependencies = [
"regex-automata",
]
@@ -2447,9 +2446,9 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "memoffset"
version = "0.6.4"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg 1.0.1",
]
@@ -2577,9 +2576,9 @@ dependencies = [
[[package]]
name = "ndk-sys"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d"
checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121"
[[package]]
name = "network-defaults"
@@ -2587,7 +2586,7 @@ version = "0.1.0"
dependencies = [
"hex-literal",
"serde",
"time 0.3.4",
"time 0.3.5",
"url",
]
@@ -2709,6 +2708,7 @@ dependencies = [
"cosmwasm-std",
"credentials",
"dirs",
"eyre",
"mixnet-contract",
"rand 0.6.5",
"serde",
@@ -2779,9 +2779,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.8.0"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
[[package]]
name = "opaque-debug"
@@ -2797,9 +2797,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "open"
version = "2.0.1"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b46b233de7d83bc167fe43ae2dda3b5b84e80e09cceba581e4decb958a4896bf"
checksum = "176ee4b630d174d2da8241336763bb459281dddc0f4d87f72c3b1efc9a6109b7"
dependencies = [
"pathdiff",
"winapi",
@@ -2827,9 +2827,9 @@ checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
[[package]]
name = "openssl-sys"
version = "0.9.70"
version = "0.9.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6517987b3f8226b5da3661dad65ff7f300cc59fb5ea8333ca191fc65fde3edf"
checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
dependencies = [
"autocfg 1.0.1",
"cc",
@@ -3040,9 +3040,9 @@ dependencies = [
[[package]]
name = "phf"
version = "0.10.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9fc3db1018c4b59d7d582a739436478b6035138b6aecbce989fc91c3e98409f"
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
dependencies = [
"phf_macros 0.10.0",
"phf_shared 0.10.0",
@@ -3169,9 +3169,9 @@ dependencies = [
[[package]]
name = "pkg-config"
version = "0.3.22"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
[[package]]
name = "pmutil"
@@ -3277,9 +3277,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
[[package]]
name = "proc-macro2"
version = "1.0.32"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1"
dependencies = [
"unicode-xid",
]
@@ -3541,11 +3541,21 @@ dependencies = [
[[package]]
name = "raw-window-handle"
version = "0.3.3"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211"
checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76"
dependencies = [
"libc",
"raw-window-handle 0.4.2",
]
[[package]]
name = "raw-window-handle"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fba75eee94a9d5273a68c9e1e105d9cffe1ef700532325788389e5a83e2522b7"
dependencies = [
"cty",
]
[[package]]
@@ -3638,9 +3648,9 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.11.6"
version = "0.11.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66d2927ca2f685faf0fc620ac4834690d29e7abb153add10f5812eef20b5e280"
checksum = "07bea77bc708afa10e59905c3d4af7c8fd43c9214251673095ff8b14345fcbc5"
dependencies = [
"base64",
"bytes",
@@ -3687,7 +3697,7 @@ dependencies = [
"objc",
"objc-foundation",
"objc_id",
"raw-window-handle",
"raw-window-handle 0.3.4",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
@@ -3729,6 +3739,15 @@ dependencies = [
"semver 0.11.0",
]
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver 1.0.4",
]
[[package]]
name = "rustls"
version = "0.19.1"
@@ -3756,15 +3775,15 @@ dependencies = [
[[package]]
name = "rustversion"
version = "1.0.5"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
[[package]]
name = "ryu"
version = "1.0.5"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "same-file"
@@ -3787,9 +3806,9 @@ dependencies = [
[[package]]
name = "schemars"
version = "0.8.6"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409"
checksum = "c6b5a3c80cea1ab61f4260238409510e814e38b4b563c06044edf91e7dc070e3"
dependencies = [
"dyn-clone",
"schemars_derive",
@@ -3799,9 +3818,9 @@ dependencies = [
[[package]]
name = "schemars_derive"
version = "0.8.6"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8"
checksum = "41ae4dce13e8614c46ac3c38ef1c0d668b101df6ac39817aebdaa26642ddae9b"
dependencies = [
"proc-macro2",
"quote",
@@ -3900,18 +3919,18 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.130"
version = "1.0.131"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde-json-wasm"
version = "0.3.1"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50eef3672ec8fa45f3457fd423ba131117786784a895548021976117c1ded449"
checksum = "042ac496d97e5885149d34139bad1d617192770d7eb8f1866da2317ff4501853"
dependencies = [
"serde",
]
@@ -3927,9 +3946,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.130"
version = "1.0.131"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2"
dependencies = [
"proc-macro2",
"quote",
@@ -3949,11 +3968,11 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.69"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8"
checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5"
dependencies = [
"itoa",
"itoa 1.0.1",
"ryu",
"serde",
]
@@ -3976,7 +3995,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97"
dependencies = [
"dtoa",
"itoa",
"itoa 0.4.8",
"serde",
"url",
]
@@ -3988,7 +4007,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9"
dependencies = [
"form_urlencoded",
"itoa",
"itoa 0.4.8",
"ryu",
"serde",
]
@@ -4510,7 +4529,7 @@ dependencies = [
"ndk-sys",
"objc",
"parking_lot",
"raw-window-handle",
"raw-window-handle 0.3.4",
"scopeguard",
"serde",
"unicode-segmentation",
@@ -4520,9 +4539,9 @@ dependencies = [
[[package]]
name = "tar"
version = "0.4.37"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6f5515d3add52e0bbdcad7b83c388bb36ba7b754dda3b5f5bc2d38640cdba5c"
checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6"
dependencies = [
"filetime",
"libc",
@@ -4552,7 +4571,7 @@ dependencies = [
"open",
"percent-encoding",
"rand 0.8.4",
"raw-window-handle",
"raw-window-handle 0.3.4",
"rfd",
"semver 1.0.4",
"serde",
@@ -4660,7 +4679,7 @@ checksum = "fcb9b79594f22b6ed0cc8362e0dfde5b7969962de3cd8ca683de702e59e8221b"
dependencies = [
"html5ever",
"kuchiki",
"phf 0.10.0",
"phf 0.10.1",
"proc-macro2",
"quote",
"serde",
@@ -4686,13 +4705,12 @@ dependencies = [
[[package]]
name = "tendermint"
version = "0.23.0"
version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d1cdb0236becb17ab35a2ed1566503e412fd910944dc940239857bb7663652"
checksum = "9015fdeab074f9b8f97dcb89c2bb2ec8537c89423e95551e8d7ecdfbab58a329"
dependencies = [
"async-trait",
"bytes",
"chrono",
"ed25519",
"ed25519-dalek",
"flex-error",
@@ -4712,14 +4730,15 @@ dependencies = [
"subtle 2.4.1",
"subtle-encoding",
"tendermint-proto",
"time 0.3.5",
"zeroize",
]
[[package]]
name = "tendermint-config"
version = "0.23.0"
version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a1f94250d30e3011130a09756b05985d8dbfbd562cf261b5a17e36d89a37992"
checksum = "a2b2e6d4442bab49319dbacdfd79c5929bc6e0b35d1e0d959ff5b79fddf3f018"
dependencies = [
"flex-error",
"serde",
@@ -4731,12 +4750,11 @@ dependencies = [
[[package]]
name = "tendermint-proto"
version = "0.23.0"
version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff16a7b42bdbcf31c8cd10a4cffc7631f2a301360ba3a3f71dde48eabfa5bced"
checksum = "da86f6e52ced9c2f24c4ae57662ce8a44dd90ee7bc47bae27a710b02d48e193c"
dependencies = [
"bytes",
"chrono",
"flex-error",
"num-derive",
"num-traits",
@@ -4745,17 +4763,17 @@ dependencies = [
"serde",
"serde_bytes",
"subtle-encoding",
"time 0.3.5",
]
[[package]]
name = "tendermint-rpc"
version = "0.23.0"
version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7842dcd5edb60b077572aa92ff8b29fc810b9b463310f9810a2607474130db4"
checksum = "50f5f4875c36798e5590894a5176cf8d75e4bc81ec34ced1b9a87609e7d56861"
dependencies = [
"async-trait",
"bytes",
"chrono",
"flex-error",
"futures",
"getrandom 0.1.16",
@@ -4773,6 +4791,7 @@ dependencies = [
"tendermint-config",
"tendermint-proto",
"thiserror",
"time 0.3.5",
"tokio",
"tracing",
"url",
@@ -4838,9 +4857,9 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.4"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99beeb0daeac2bd1e86ac2c21caddecb244b39a093594da1a661ec2060c7aedd"
checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad"
dependencies = [
"libc",
"time-macros",
@@ -4854,11 +4873,10 @@ checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6"
[[package]]
name = "tokio"
version = "1.13.0"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee"
checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838"
dependencies = [
"autocfg 1.0.1",
"bytes",
"libc",
"memchr",
@@ -4871,9 +4889,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
version = "1.5.1"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "114383b041aa6212c579467afa0075fbbdd0718de036100bc0ba7961d8cb9095"
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
dependencies = [
"proc-macro2",
"quote",
@@ -4973,36 +4991,22 @@ dependencies = [
"tracing-core",
]
[[package]]
name = "tracing-serde"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b"
dependencies = [
"serde",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.2.25"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71"
checksum = "245da694cc7fc4729f3f418b304cb57789f1bed2a78c575407ab8a23f53cb4d3"
dependencies = [
"ansi_term",
"chrono",
"lazy_static",
"matchers",
"regex",
"serde",
"serde_json",
"sharded-slab",
"smallvec 1.7.0",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
"tracing-serde",
]
[[package]]
+1
View File
@@ -26,6 +26,7 @@ thiserror = "1.0"
tendermint-rpc = "0.23.0"
url = "2.0"
rand = "0.6.5"
eyre = "0.6.5"
cosmrs = { git = "https://github.com/cosmos/cosmos-rust", rev="e5a1872083abb3d88fa62dda966e7f5408deba58", features = ["rpc", "bip32", "cosmwasm"] }
+10 -14
View File
@@ -1,5 +1,6 @@
// This should be moved out of the wallet, and used as a primary coin type throughout the codebase
use crate::error::BackendError;
use ::config::defaults::DENOM;
use cosmrs::Decimal;
use cosmrs::Denom as CosmosDenom;
@@ -12,8 +13,6 @@ use std::ops::{Add, Sub};
use std::str::FromStr;
use validator_client::nymd::{CosmosCoin, GasPrice};
use crate::format_err;
#[cfg_attr(test, derive(ts_rs::TS))]
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub enum Denom {
@@ -33,19 +32,16 @@ impl fmt::Display for Denom {
}
impl FromStr for Denom {
type Err = String;
type Err = BackendError;
fn from_str(s: &str) -> Result<Denom, String> {
fn from_str(s: &str) -> Result<Denom, BackendError> {
let s = s.to_lowercase();
if s == DENOM.to_lowercase() || s == "minor" {
Ok(Denom::Minor)
} else if s == DENOM[1..].to_lowercase() || s == "major" {
Ok(Denom::Major)
} else {
Err(format_err!(format!(
"{} is not a valid denomination string",
s
)))
Err(BackendError::InvalidDenom(s))
}
}
}
@@ -169,9 +165,9 @@ impl Coin {
}
impl TryFrom<Coin> for CosmWasmCoin {
type Error = String;
type Error = BackendError;
fn try_from(coin: Coin) -> Result<CosmWasmCoin, String> {
fn try_from(coin: Coin) -> Result<CosmWasmCoin, Self::Error> {
Ok(CosmWasmCoin::new(
Uint128::try_from(coin.amount.as_str()).unwrap().u128(),
coin.denom.to_string(),
@@ -180,15 +176,15 @@ impl TryFrom<Coin> for CosmWasmCoin {
}
impl TryFrom<Coin> for CosmosCoin {
type Error = String;
type Error = BackendError;
fn try_from(coin: Coin) -> Result<CosmosCoin, String> {
fn try_from(coin: Coin) -> Result<CosmosCoin, BackendError> {
match Decimal::from_str(&coin.amount) {
Ok(d) => Ok(CosmosCoin {
amount: d,
denom: CosmosDenom::from_str(&coin.denom.to_string()).unwrap(),
denom: CosmosDenom::from_str(&coin.denom.to_string())?,
}),
Err(e) => Err(format_err!(e)),
Err(e) => Err(e.into()),
}
}
}
+29 -3
View File
@@ -1,21 +1,47 @@
use serde::{Serialize, Serializer};
use thiserror::Error;
use validator_client::nymd::error::NymdError;
#[derive(Error, Debug)]
pub enum BackendError {
#[error("Error parsing bip39 mnemonic")]
#[error("{source}")]
Bip39Error {
#[from]
source: bip39::Error,
},
#[error("Error parsing into tendermint Url")]
#[error("{source}")]
TendermintError {
#[from]
source: tendermint_rpc::Error,
},
#[error("Error getting balances")]
#[error("{source}")]
NymdError {
#[from]
source: NymdError,
},
#[error("{source}")]
CosmwasmStd {
#[from]
source: cosmwasm_std::StdError,
},
#[error("{source}")]
ErrorReport {
#[from]
source: eyre::Report,
},
#[error("Client has not been initialized yet, connect with mnemonic to initialize")]
ClientNotInitialized,
#[error("No balance available for address {0}")]
NoBalance(String),
#[error("{0} is not a valid denomination string")]
InvalidDenom(String),
}
impl Serialize for BackendError {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
+47 -44
View File
@@ -7,7 +7,7 @@ use mixnet_contract::{Gateway, MixNode};
use std::sync::Arc;
use tauri::Menu;
use tokio::sync::RwLock;
use validator_client::nymd::fee_helpers::Operation;
use validator_client::nymd::fee::helpers::Operation;
mod coin;
mod config;
@@ -18,47 +18,50 @@ mod state;
mod utils;
use crate::menu::AddDefaultSubmenus;
use crate::operations::account::*;
use crate::operations::admin::*;
use crate::operations::bond::*;
use crate::operations::delegate::*;
use crate::operations::send::*;
use crate::utils::*;
use crate::operations::mixnet;
use crate::operations::vesting;
use crate::state::State;
#[cfg(test)]
use crate::coin::{Coin, Denom};
#[macro_export]
macro_rules! format_err {
($e:expr) => {
format!("line {}: {}", line!(), $e)
};
}
fn main() {
tauri::Builder::default()
.manage(Arc::new(RwLock::new(State::default())))
.invoke_handler(tauri::generate_handler![
connect_with_mnemonic,
get_balance,
minor_to_major,
major_to_minor,
owns_gateway,
owns_mixnode,
bond_mixnode,
unbond_mixnode,
bond_gateway,
unbond_gateway,
delegate_to_mixnode,
undelegate_from_mixnode,
send,
create_new_account,
get_fee,
get_contract_settings,
update_contract_settings,
get_reverse_mix_delegations_paged,
mixnet::account::connect_with_mnemonic,
mixnet::account::create_new_account,
mixnet::account::get_balance,
mixnet::admin::get_contract_settings,
mixnet::admin::update_contract_settings,
mixnet::bond::bond_gateway,
mixnet::bond::bond_mixnode,
mixnet::bond::unbond_gateway,
mixnet::bond::unbond_mixnode,
mixnet::bond::mixnode_bond_details,
mixnet::bond::gateway_bond_details,
mixnet::delegate::delegate_to_mixnode,
mixnet::delegate::get_reverse_mix_delegations_paged,
mixnet::delegate::undelegate_from_mixnode,
mixnet::send::send,
utils::get_approximate_fee,
utils::major_to_minor,
utils::minor_to_major,
utils::owns_gateway,
utils::owns_mixnode,
vesting::bond::vesting_bond_gateway,
vesting::bond::vesting_bond_mixnode,
vesting::bond::vesting_unbond_gateway,
vesting::bond::vesting_unbond_mixnode,
vesting::delegate::vesting_delegate_to_mixnode,
vesting::delegate::vesting_undelegate_from_mixnode,
vesting::queries::locked_coins,
vesting::queries::spendable_coins,
vesting::queries::vesting_coins,
vesting::queries::vested_coins,
vesting::queries::vesting_start_time,
vesting::queries::vesting_end_time,
vesting::queries::original_vesting,
vesting::queries::delegated_free,
vesting::queries::delegated_vesting,
])
.menu(Menu::new().add_default_app_submenu_if_macos())
.run(tauri::generate_context!())
@@ -69,15 +72,15 @@ fn main() {
mod test {
ts_rs::export! {
mixnet_contract::MixNode => "../src/types/rust/mixnode.ts",
crate::Coin => "../src/types/rust/coin.ts",
crate::Balance => "../src/types/rust/balance.ts",
crate::coin::Coin => "../src/types/rust/coin.ts",
crate::mixnet::account::Balance => "../src/types/rust/balance.ts",
mixnet_contract::Gateway => "../src/types/rust/gateway.ts",
crate::TauriTxResult => "../src/types/rust/tauritxresult.ts",
crate::TransactionDetails => "../src/types/rust/transactiondetails.ts",
validator_client::nymd::fee_helpers::Operation => "../src/types/rust/operation.ts",
crate::Denom => "../src/types/rust/denom.ts",
crate::DelegationResult => "../src/types/rust/delegationresult.ts",
crate::Account => "../src/types/rust/account.ts",
crate::TauriContractStateParams => "../src/types/rust/stateparams.ts"
crate::mixnet::send::TauriTxResult => "../src/types/rust/tauritxresult.ts",
crate::mixnet::send::TransactionDetails => "../src/types/rust/transactiondetails.ts",
validator_client::nymd::fee::helpers::Operation => "../src/types/rust/operation.ts",
crate::coin::Denom => "../src/types/rust/denom.ts",
crate::utils::DelegationResult => "../src/types/rust/delegationresult.ts",
crate::mixnet::account::Account => "../src/types/rust/account.ts",
crate::mixnet::admin::TauriContractStateParams => "../src/types/rust/stateparams.ts"
}
}
@@ -1,66 +0,0 @@
use crate::coin::Coin;
use crate::format_err;
use crate::state::State;
use crate::{Gateway, MixNode};
use cosmwasm_std::Coin as CosmWasmCoin;
use std::convert::TryInto;
use std::sync::Arc;
use tokio::sync::RwLock;
#[tauri::command]
pub async fn bond_gateway(
gateway: Gateway,
pledge: Coin,
owner_signature: String,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), String> {
let r_state = state.read().await;
let pledge: CosmWasmCoin = match pledge.try_into() {
Ok(b) => b,
Err(e) => return Err(format_err!(e)),
};
let client = r_state.client()?;
match client.bond_gateway(gateway, owner_signature, pledge).await {
Ok(_result) => Ok(()),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn unbond_gateway(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<(), String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.unbond_gateway().await {
Ok(_result) => Ok(()),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn unbond_mixnode(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<(), String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.unbond_mixnode().await {
Ok(_result) => Ok(()),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn bond_mixnode(
mixnode: MixNode,
owner_signature: String,
pledge: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), String> {
let r_state = state.read().await;
let pledge: CosmWasmCoin = match pledge.try_into() {
Ok(b) => b,
Err(e) => return Err(format_err!(e)),
};
let client = r_state.client()?;
match client.bond_mixnode(mixnode, owner_signature, pledge).await {
Ok(_result) => Ok(()),
Err(e) => Err(format_err!(e)),
}
}
@@ -1,68 +0,0 @@
use crate::coin::Coin;
use crate::format_err;
use crate::state::State;
use cosmwasm_std::Coin as CosmWasmCoin;
use mixnet_contract::PagedDelegatorDelegationsResponse;
use serde::{Deserialize, Serialize};
use std::convert::TryInto;
use std::sync::Arc;
use tokio::sync::RwLock;
#[cfg_attr(test, derive(ts_rs::TS))]
#[derive(Serialize, Deserialize)]
pub struct DelegationResult {
source_address: String,
target_address: String,
amount: Option<Coin>,
}
#[tauri::command]
pub async fn delegate_to_mixnode(
identity: &str,
amount: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, String> {
let r_state = state.read().await;
let delegation: CosmWasmCoin = match amount.try_into() {
Ok(b) => b,
Err(e) => return Err(format_err!(e)),
};
let client = r_state.client()?;
match client.delegate_to_mixnode(identity, &delegation).await {
Ok(_result) => Ok(DelegationResult {
source_address: client.address().to_string(),
target_address: identity.to_string(),
amount: Some(delegation.into()),
}),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn undelegate_from_mixnode(
identity: &str,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.remove_mixnode_delegation(identity).await {
Ok(_result) => Ok(DelegationResult {
source_address: client.address().to_string(),
target_address: identity.to_string(),
amount: None,
}),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn get_reverse_mix_delegations_paged(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<PagedDelegatorDelegationsResponse, String> {
let r_state = state.read().await;
let client = r_state.client()?;
client
.get_delegator_delegations_paged(client.address().to_string(), None, None)
.await
.map_err(|err| format_err!(err))
}
@@ -1,7 +1,7 @@
use crate::client;
use crate::coin::{Coin, Denom};
use crate::config::Config;
use crate::error::BackendError;
use crate::format_err;
use crate::state::State;
use bip39::{Language, Mnemonic};
use serde::{Deserialize, Serialize};
@@ -30,26 +30,16 @@ pub struct Balance {
pub async fn connect_with_mnemonic(
mnemonic: String,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Account, String> {
let mnemonic = match Mnemonic::from_str(&mnemonic) {
Ok(mnemonic) => mnemonic,
Err(e) => return Err(BackendError::from(e).to_string()),
};
let client;
{
) -> Result<Account, BackendError> {
let mnemonic = Mnemonic::from_str(&mnemonic)?;
let client = {
let r_state = state.read().await;
client = _connect_with_mnemonic(mnemonic, &r_state.config());
}
_connect_with_mnemonic(mnemonic, &r_state.config())
};
let contract_address = match client.mixnet_contract_address() {
Ok(address) => address.to_string(),
Err(e) => return Err(format_err!(e)),
};
let contract_address = client.mixnet_contract_address()?.to_string();
let client_address = client.address().to_string();
let denom = match client.denom() {
Ok(denom) => denom,
Err(e) => return Err(format_err!(e)),
};
let denom = client.denom()?;
let account = Account {
contract_address,
@@ -65,10 +55,10 @@ pub async fn connect_with_mnemonic(
}
#[tauri::command]
pub async fn get_balance(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<Balance, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.get_balance(client.address()).await {
pub async fn get_balance(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Balance, BackendError> {
match client!(state).get_balance(client!(state).address()).await {
Ok(Some(coin)) => {
let coin = Coin::new(
&coin.amount.to_string(),
@@ -79,18 +69,17 @@ pub async fn get_balance(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<
printable_balance: coin.to_major().to_string(),
})
}
Ok(None) => Err(format!(
"No balance available for address {}",
client.address()
Ok(None) => Err(BackendError::NoBalance(
client!(state).address().to_string(),
)),
Err(e) => Err(BackendError::from(e).to_string()),
Err(e) => Err(BackendError::from(e)),
}
}
#[tauri::command]
pub async fn create_new_account(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Account, String> {
) -> Result<Account, BackendError> {
let rand_mnemonic = random_mnemonic();
let mut client = connect_with_mnemonic(rand_mnemonic.to_string(), state).await?;
client.mnemonic = Some(rand_mnemonic.to_string());
@@ -108,6 +97,7 @@ fn _connect_with_mnemonic(mnemonic: Mnemonic, config: &Config) -> NymdClient<Sig
Some(AccountId::from_str(&config.get_mixnet_contract_address()).unwrap()),
None,
mnemonic,
None,
) {
Ok(client) => client,
Err(e) => panic!("{}", e),
@@ -1,4 +1,5 @@
use crate::format_err;
use crate::client;
use crate::error::BackendError;
use crate::state::State;
use cosmwasm_std::Uint128;
use mixnet_contract::ContractStateParams;
@@ -14,6 +15,7 @@ pub struct TauriContractStateParams {
minimum_gateway_pledge: String,
mixnode_rewarded_set_size: u32,
mixnode_active_set_size: u32,
active_set_work_factor: u8,
}
impl From<ContractStateParams> for TauriContractStateParams {
@@ -23,12 +25,13 @@ impl From<ContractStateParams> for TauriContractStateParams {
minimum_gateway_pledge: p.minimum_gateway_pledge.to_string(),
mixnode_rewarded_set_size: p.mixnode_rewarded_set_size,
mixnode_active_set_size: p.mixnode_active_set_size,
active_set_work_factor: p.active_set_work_factor,
}
}
}
impl TryFrom<TauriContractStateParams> for ContractStateParams {
type Error = Box<dyn std::error::Error>;
type Error = BackendError;
fn try_from(p: TauriContractStateParams) -> Result<ContractStateParams, Self::Error> {
Ok(ContractStateParams {
@@ -36,6 +39,7 @@ impl TryFrom<TauriContractStateParams> for ContractStateParams {
minimum_gateway_pledge: Uint128::try_from(p.minimum_gateway_pledge.as_str())?,
mixnode_rewarded_set_size: p.mixnode_rewarded_set_size,
mixnode_active_set_size: p.mixnode_active_set_size,
active_set_work_factor: p.active_set_work_factor,
})
}
}
@@ -43,31 +47,18 @@ impl TryFrom<TauriContractStateParams> for ContractStateParams {
#[tauri::command]
pub async fn get_contract_settings(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<TauriContractStateParams, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.get_contract_settings().await {
Ok(params) => Ok(params.into()),
Err(e) => Err(format_err!(e)),
}
) -> Result<TauriContractStateParams, BackendError> {
Ok(client!(state).get_contract_settings().await?.into())
}
#[tauri::command]
pub async fn update_contract_settings(
params: TauriContractStateParams,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<TauriContractStateParams, String> {
let r_state = state.read().await;
let client = r_state.client()?;
let mixnet_contract_settings_params: ContractStateParams = match params.try_into() {
Ok(mixnet_contract_settings_params) => mixnet_contract_settings_params,
Err(e) => return Err(format_err!(e)),
};
match client
) -> Result<TauriContractStateParams, BackendError> {
let mixnet_contract_settings_params: ContractStateParams = params.try_into()?;
client!(state)
.update_contract_settings(mixnet_contract_settings_params.clone())
.await
{
Ok(_) => Ok(mixnet_contract_settings_params.into()),
Err(e) => Err(format_err!(e)),
}
.await?;
Ok(mixnet_contract_settings_params.into())
}
@@ -0,0 +1,71 @@
use crate::client;
use crate::coin::Coin;
use crate::error::BackendError;
use crate::state::State;
use crate::{Gateway, MixNode};
use mixnet_contract::{GatewayBond, MixNodeBond};
use std::convert::TryInto;
use std::sync::Arc;
use tokio::sync::RwLock;
#[tauri::command]
pub async fn bond_gateway(
gateway: Gateway,
pledge: Coin,
owner_signature: String,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), BackendError> {
client!(state)
.bond_gateway(gateway, owner_signature, pledge.try_into()?)
.await?;
Ok(())
}
#[tauri::command]
pub async fn unbond_gateway(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), BackendError> {
client!(state).unbond_gateway().await?;
Ok(())
}
#[tauri::command]
pub async fn unbond_mixnode(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), BackendError> {
client!(state).unbond_mixnode().await?;
Ok(())
}
#[tauri::command]
pub async fn bond_mixnode(
mixnode: MixNode,
owner_signature: String,
pledge: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), BackendError> {
client!(state)
.bond_mixnode(mixnode, owner_signature, pledge.try_into()?)
.await?;
Ok(())
}
#[tauri::command]
pub async fn mixnode_bond_details(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Option<MixNodeBond>, BackendError> {
let guard = state.read().await;
let client = guard.client()?;
let bond = client.owns_mixnode(client.address()).await?;
Ok(bond)
}
#[tauri::command]
pub async fn gateway_bond_details(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Option<GatewayBond>, BackendError> {
let guard = state.read().await;
let client = guard.client()?;
let bond = client.owns_gateway(client.address()).await?;
Ok(bond)
}
@@ -0,0 +1,51 @@
use crate::client;
use crate::coin::Coin;
use crate::error::BackendError;
use crate::state::State;
use crate::utils::DelegationResult;
use cosmwasm_std::Coin as CosmWasmCoin;
use mixnet_contract::PagedDelegatorDelegationsResponse;
use std::convert::TryInto;
use std::sync::Arc;
use tokio::sync::RwLock;
#[tauri::command]
pub async fn delegate_to_mixnode(
identity: &str,
amount: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, BackendError> {
let delegation: CosmWasmCoin = amount.try_into()?;
client!(state)
.delegate_to_mixnode(identity, &delegation)
.await?;
Ok(DelegationResult::new(
&client!(state).address().to_string(),
identity,
Some(delegation.into()),
))
}
#[tauri::command]
pub async fn undelegate_from_mixnode(
identity: &str,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, BackendError> {
client!(state).remove_mixnode_delegation(identity).await?;
Ok(DelegationResult::new(
&client!(state).address().to_string(),
identity,
None,
))
}
#[tauri::command]
pub async fn get_reverse_mix_delegations_paged(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<PagedDelegatorDelegationsResponse, BackendError> {
Ok(
client!(state)
.get_delegator_delegations_paged(client!(state).address().to_string(), None, None)
.await?,
)
}
@@ -0,0 +1,5 @@
pub mod account;
pub mod admin;
pub mod bond;
pub mod delegate;
pub mod send;
@@ -1,5 +1,6 @@
use crate::client;
use crate::coin::Coin;
use crate::format_err;
use crate::error::BackendError;
use crate::state::State;
use serde::{Deserialize, Serialize};
use std::convert::TryInto;
@@ -47,26 +48,18 @@ pub async fn send(
amount: Coin,
memo: String,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<TauriTxResult, String> {
let address = match AccountId::from_str(address) {
Ok(addy) => addy,
Err(e) => return Err(format_err!(e)),
};
let cosmos_amount: CosmosCoin = match amount.clone().try_into() {
Ok(b) => b,
Err(e) => return Err(format_err!(e)),
};
let r_state = state.read().await;
let client = r_state.client()?;
match client.send(&address, vec![cosmos_amount], memo).await {
Ok(result) => Ok(TauriTxResult::new(
result,
TransactionDetails {
from_address: client.address().to_string(),
to_address: address.to_string(),
amount,
},
)),
Err(e) => Err(format_err!(e)),
}
) -> Result<TauriTxResult, BackendError> {
let address = AccountId::from_str(address)?;
let cosmos_amount: CosmosCoin = amount.clone().try_into()?;
let result = client!(state)
.send(&address, vec![cosmos_amount], memo)
.await?;
Ok(TauriTxResult::new(
result,
TransactionDetails {
from_address: client!(state).address().to_string(),
to_address: address.to_string(),
amount,
},
))
}
+2 -5
View File
@@ -1,5 +1,2 @@
pub mod account;
pub mod admin;
pub mod bond;
pub mod delegate;
pub mod send;
pub mod mixnet;
pub mod vesting;
@@ -0,0 +1,51 @@
use crate::client;
use crate::coin::Coin;
use crate::error::BackendError;
use crate::state::State;
use crate::{Gateway, MixNode};
use std::convert::TryInto;
use std::sync::Arc;
use tokio::sync::RwLock;
use validator_client::nymd::VestingSigningClient;
#[tauri::command]
pub async fn vesting_bond_gateway(
gateway: Gateway,
pledge: Coin,
owner_signature: String,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), BackendError> {
client!(state)
.vesting_bond_gateway(gateway, &owner_signature, pledge.try_into()?)
.await?;
Ok(())
}
#[tauri::command]
pub async fn vesting_unbond_gateway(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), BackendError> {
client!(state).vesting_unbond_gateway().await?;
Ok(())
}
#[tauri::command]
pub async fn vesting_unbond_mixnode(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), BackendError> {
client!(state).vesting_unbond_mixnode().await?;
Ok(())
}
#[tauri::command]
pub async fn vesting_bond_mixnode(
mixnode: MixNode,
owner_signature: String,
pledge: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), BackendError> {
client!(state)
.vesting_bond_mixnode(mixnode, &owner_signature, pledge.try_into()?)
.await?;
Ok(())
}
@@ -0,0 +1,42 @@
use crate::client;
use crate::coin::Coin;
use crate::error::BackendError;
use crate::state::State;
use crate::utils::DelegationResult;
use cosmwasm_std::Coin as CosmWasmCoin;
use std::convert::TryInto;
use std::sync::Arc;
use tokio::sync::RwLock;
use validator_client::nymd::VestingSigningClient;
#[tauri::command]
pub async fn vesting_delegate_to_mixnode(
identity: &str,
amount: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, BackendError> {
let delegation: CosmWasmCoin = amount.try_into()?;
client!(state)
.vesting_delegate_to_mixnode(identity, &delegation)
.await?;
Ok(DelegationResult::new(
&client!(state).address().to_string(),
identity,
Some(delegation.into()),
))
}
#[tauri::command]
pub async fn vesting_undelegate_from_mixnode(
identity: &str,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, BackendError> {
client!(state)
.vesting_undelegate_from_mixnode(identity)
.await?;
Ok(DelegationResult::new(
&client!(state).address().to_string(),
identity,
None,
))
}
@@ -0,0 +1,3 @@
pub mod bond;
pub mod delegate;
pub mod queries;
@@ -0,0 +1,146 @@
use crate::client;
use crate::coin::Coin;
use crate::error::BackendError;
use crate::state::State;
use cosmwasm_std::Timestamp;
use std::sync::Arc;
use tokio::sync::RwLock;
use validator_client::nymd::VestingQueryClient;
#[tauri::command]
pub async fn locked_coins(
address: &str,
block_time: Option<u64>,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Coin, BackendError> {
Ok(
client!(state)
.locked_coins(address, block_time.map(Timestamp::from_seconds))
.await?
.into(),
)
}
#[tauri::command]
pub async fn spendable_coins(
vesting_account_address: &str,
block_time: Option<u64>,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Coin, BackendError> {
Ok(
client!(state)
.spendable_coins(
vesting_account_address,
block_time.map(Timestamp::from_seconds),
)
.await?
.into(),
)
}
#[tauri::command]
pub async fn vested_coins(
vesting_account_address: &str,
block_time: Option<u64>,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Coin, BackendError> {
Ok(
client!(state)
.vested_coins(
vesting_account_address,
block_time.map(Timestamp::from_seconds),
)
.await?
.into(),
)
}
#[tauri::command]
pub async fn vesting_coins(
vesting_account_address: &str,
block_time: Option<u64>,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Coin, BackendError> {
Ok(
client!(state)
.vesting_coins(
vesting_account_address,
block_time.map(Timestamp::from_seconds),
)
.await?
.into(),
)
}
#[tauri::command]
pub async fn vesting_start_time(
vesting_account_address: &str,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<u64, BackendError> {
Ok(
client!(state)
.vesting_start_time(vesting_account_address)
.await?
.seconds(),
)
}
#[tauri::command]
pub async fn vesting_end_time(
vesting_account_address: &str,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<u64, BackendError> {
Ok(
client!(state)
.vesting_end_time(vesting_account_address)
.await?
.seconds(),
)
}
#[tauri::command]
pub async fn original_vesting(
vesting_account_address: &str,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Coin, BackendError> {
Ok(
client!(state)
.original_vesting(vesting_account_address)
.await?
.into(),
)
}
#[tauri::command]
pub async fn delegated_free(
vesting_account_address: &str,
block_time: Option<u64>,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Coin, BackendError> {
Ok(
client!(state)
.delegated_free(
vesting_account_address,
block_time.map(Timestamp::from_seconds),
)
.await?
.into(),
)
}
#[tauri::command]
pub async fn delegated_vesting(
block_time: Option<u64>,
vesting_account_address: &str,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Coin, BackendError> {
Ok(
client!(state)
.delegated_vesting(
vesting_account_address,
block_time.map(Timestamp::from_seconds),
)
.await?
.into(),
)
}
+13 -4
View File
@@ -1,4 +1,5 @@
use crate::config::Config;
use crate::error::BackendError;
use validator_client::nymd::{NymdClient, SigningNymdClient};
#[derive(Default)]
@@ -8,10 +9,11 @@ pub struct State {
}
impl State {
pub fn client(&self) -> Result<&NymdClient<SigningNymdClient>, String> {
self.signing_client.as_ref().ok_or_else(|| {
"Client has not been initialized yet, connect with mnemonic to initialize".to_string()
})
pub fn client(&self) -> Result<&NymdClient<SigningNymdClient>, BackendError> {
self
.signing_client
.as_ref()
.ok_or(BackendError::ClientNotInitialized)
}
pub fn config(&self) -> Config {
@@ -22,3 +24,10 @@ impl State {
self.signing_client = Some(signing_client)
}
}
#[macro_export]
macro_rules! client {
($state:ident) => {
$state.read().await.client()?
};
}
+49 -26
View File
@@ -1,54 +1,77 @@
use crate::client;
use crate::coin::{Coin, Denom};
use crate::format_err;
use crate::error::BackendError;
use crate::state::State;
use crate::Operation;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use tokio::sync::RwLock;
#[tauri::command]
pub fn major_to_minor(amount: &str) -> Result<Coin, String> {
pub fn major_to_minor(amount: &str) -> Coin {
let coin = Coin::new(amount, &Denom::Major);
Ok(coin.to_minor())
coin.to_minor()
}
#[tauri::command]
pub fn minor_to_major(amount: &str) -> Result<Coin, String> {
pub fn minor_to_major(amount: &str) -> Coin {
let coin = Coin::new(amount, &Denom::Minor);
Ok(coin.to_major())
coin.to_major()
}
#[tauri::command]
pub async fn owns_mixnode(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<bool, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.owns_mixnode(client.address()).await {
Ok(o) => Ok(o.is_some()),
Err(e) => Err(format_err!(e)),
}
pub async fn owns_mixnode(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<bool, BackendError> {
Ok(
client!(state)
.owns_mixnode(client!(state).address())
.await?
.is_some(),
)
}
#[tauri::command]
pub async fn owns_gateway(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<bool, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.owns_gateway(client.address()).await {
Ok(o) => Ok(o.is_some()),
Err(e) => Err(format_err!(e)),
}
pub async fn owns_gateway(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<bool, BackendError> {
Ok(
client!(state)
.owns_gateway(client!(state).address())
.await?
.is_some(),
)
}
// NOTE: this uses OUTDATED defaults that might have no resemblance with the reality
// as for the actual transaction, the gas cost is being simulated beforehand
#[tauri::command]
pub async fn get_fee(
pub async fn get_approximate_fee(
operation: Operation,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Coin, String> {
let r_state = state.read().await;
let client = r_state.client()?;
let fee = client.get_fee(operation);
) -> Result<Coin, BackendError> {
let approximate_fee = operation.default_fee(client!(state).gas_price());
let mut coin = Coin::new("0", &Denom::Major);
for f in fee.amount {
for f in approximate_fee.amount {
coin = coin + f.into();
}
Ok(coin)
}
#[cfg_attr(test, derive(ts_rs::TS))]
#[derive(Serialize, Deserialize)]
pub struct DelegationResult {
source_address: String,
target_address: String,
amount: Option<Coin>,
}
impl DelegationResult {
pub fn new(source_address: &str, target_address: &str, amount: Option<Coin>) -> DelegationResult {
DelegationResult {
source_address: source_address.to_string(),
target_address: target_address.to_string(),
amount,
}
}
}
+4 -1
View File
@@ -23,7 +23,10 @@ export const minorToMajor = async (amount: string): Promise<Coin> => await invok
export const majorToMinor = async (amount: string): Promise<Coin> => await invoke('major_to_minor', { amount })
export const getGasFee = async (operation: Operation): Promise<Coin> => await invoke('get_fee', { operation })
// NOTE: this uses OUTDATED defaults that might have no resemblance with the reality
// as for the actual transaction, the gas cost is being simulated beforehand
export const getGasFee = async (operation: Operation): Promise<Coin> =>
await invoke('get_approximate_fee', { operation })
export const delegate = async ({
type,
@@ -139,7 +139,7 @@ export const ApiList = () => {
<ListItem>
<DocEntry
function={{
name: 'get_fee',
name: 'get_approximate_fee',
args: [{ name: 'operation', type: 'str' }],
}}
/>
+1 -1
View File
@@ -16,7 +16,7 @@ export type Operation =
| "BondGatewayOnBehalf"
| "UnbondGateway"
| "UnbondGatewayOnBehalf"
| "UpdateStateParams"
| "UpdateContractSettings"
| "BeginMixnodeRewarding"
| "FinishMixnodeRewarding"
| "TrackUnbondGateway"
+1
View File
@@ -3,4 +3,5 @@ export interface TauriContractStateParams {
minimum_gateway_pledge: string;
mixnode_rewarded_set_size: number;
mixnode_active_set_size: number;
active_set_work_factor: number;
}
@@ -189,7 +189,7 @@ impl PacketPreparer {
if gateways.into_inner().len() < minimum_full_routes {
info!(
"Minimal topology is still not offline. Going to check again in {:?}",
"Minimal topology is still not online. Going to check again in {:?}",
initialisation_backoff
);
tokio::time::sleep(initialisation_backoff).await;
@@ -217,7 +217,7 @@ impl PacketPreparer {
}
info!(
"Minimal topology is still not offline. Going to check again in {:?}",
"Minimal topology is still not online. Going to check again in {:?}",
initialisation_backoff
);
tokio::time::sleep(initialisation_backoff).await;
+8 -34
View File
@@ -2,10 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::config::Config;
use crate::rewarding::{
error::RewardingError, MixnodeToReward, MIXNODE_REWARD_OP_BASE_GAS_LIMIT,
PER_MIXNODE_DELEGATION_GAS_INCREASE, REWARDING_GAS_LIMIT_MULTIPLIER,
};
use crate::rewarding::{error::RewardingError, MixnodeToReward};
use config::defaults::DEFAULT_VALIDATOR_API_PORT;
use mixnet_contract::{
ContractStateParams, Delegation, ExecuteMsg, GatewayBond, IdentityKey, MixNodeBond,
@@ -211,19 +208,6 @@ impl<C> Client<C> {
.await
}
async fn estimate_mixnode_reward_fees(&self, nodes: usize, total_delegations: usize) -> Fee {
let base_gas_limit = MIXNODE_REWARD_OP_BASE_GAS_LIMIT * nodes as u64
+ PER_MIXNODE_DELEGATION_GAS_INCREASE * total_delegations as u64;
let total_gas_limit = (base_gas_limit as f64 * REWARDING_GAS_LIMIT_MULTIPLIER) as u64;
self.0
.read()
.await
.nymd
.calculate_custom_fee(total_gas_limit)
}
pub(crate) async fn begin_mixnode_rewarding(
&self,
rewarding_interval_nonce: u32,
@@ -269,15 +253,13 @@ impl<C> Client<C> {
let further_calls = node.total_delegations / MIXNODE_DELEGATORS_PAGE_LIMIT;
// start with the base call to reward operator and first page of delegators
let fee = self
.estimate_mixnode_reward_fees(1, MIXNODE_DELEGATORS_PAGE_LIMIT)
.await;
let msgs = vec![(node.to_reward_execute_msg(rewarding_interval_nonce), vec![])];
let memo = format!(
"operator + {} delegators rewarding",
MIXNODE_DELEGATORS_PAGE_LIMIT
);
self.execute_multiple_with_retry(msgs, fee, memo).await?;
self.execute_multiple_with_retry(msgs, Default::default(), memo)
.await?;
// reward rest of delegators
let mut remaining_delegators = node.total_delegations - MIXNODE_DELEGATORS_PAGE_LIMIT;
@@ -287,12 +269,10 @@ impl<C> Client<C> {
);
for _ in 0..further_calls {
let delegators_in_call = remaining_delegators.min(MIXNODE_DELEGATORS_PAGE_LIMIT);
let fee = self
.estimate_mixnode_reward_fees(1, delegators_in_call)
.await;
let msgs = vec![delegator_rewarding_msg.clone()];
let memo = format!("rewarding another {} delegators", delegators_in_call);
self.execute_multiple_with_retry(msgs, fee, memo).await?;
self.execute_multiple_with_retry(msgs, Default::default(), memo)
.await?;
remaining_delegators -= MIXNODE_DELEGATORS_PAGE_LIMIT;
}
@@ -310,16 +290,13 @@ impl<C> Client<C> {
{
// the fee is a tricky subject here because we don't know exactly how many delegators we missed,
// let's aim for the worst case scenario and assume it was the entire page
let fee = self
.estimate_mixnode_reward_fees(1, MIXNODE_DELEGATORS_PAGE_LIMIT)
.await;
let delegator_rewarding_msg = (
node.to_next_delegator_reward_execute_msg(rewarding_interval_nonce),
vec![],
);
let memo = "rewarding delegators".to_string();
self.execute_multiple_with_retry(vec![delegator_rewarding_msg], fee, memo)
self.execute_multiple_with_retry(vec![delegator_rewarding_msg], Default::default(), memo)
.await
}
@@ -331,10 +308,6 @@ impl<C> Client<C> {
where
C: SigningCosmWasmClient + Sync,
{
let total_delegations = nodes.iter().map(|node| node.total_delegations).sum();
let fee = self
.estimate_mixnode_reward_fees(nodes.len(), total_delegations)
.await;
let msgs: Vec<(ExecuteMsg, _)> = nodes
.iter()
.map(|node| node.to_reward_execute_msg(rewarding_interval_nonce))
@@ -343,7 +316,8 @@ impl<C> Client<C> {
let memo = format!("rewarding {} mixnodes", msgs.len());
self.execute_multiple_with_retry(msgs, fee, memo).await
self.execute_multiple_with_retry(msgs, Default::default(), memo)
.await
}
async fn execute_multiple_with_retry<M>(
+99 -51
View File
@@ -10,6 +10,7 @@ use crate::storage::models::{
FailedMixnodeRewardChunk, PossiblyUnrewardedMixnode, RewardingReport,
};
use crate::storage::ValidatorApiStorage;
use config::defaults::DENOM;
use log::{error, info};
use mixnet_contract::mixnode::NodeRewardParams;
use mixnet_contract::{ExecuteMsg, IdentityKey, RewardingStatus, MIXNODE_DELEGATORS_PAGE_LIMIT};
@@ -22,21 +23,15 @@ use validator_client::nymd::SigningNymdClient;
pub(crate) mod epoch;
pub(crate) mod error;
// the actual base cost is around 125_000, but let's give ourselves a bit of safety net in case
// we introduce some tiny contract changes that would bump that value up
pub(crate) const MIXNODE_REWARD_OP_BASE_GAS_LIMIT: u64 = 150_000;
// For each delegation reward we perform a read and a write is being executed,
// which are the most costly parts involved in process. Both of them are ~1000 sdk gas in cost.
// However, experimentally it looks like first delegation adds total of additional ~3000 of sdk gas
// cost and each subsequent about ~2500.
// Therefore, since base cost is not tuned to the bare minimum, let's treat all of delegations as extra
// 2750 of sdk gas.
pub(crate) const PER_MIXNODE_DELEGATION_GAS_INCREASE: u64 = 2750;
// Another safety net in case of contract changes,
// the calculated total gas limit is going to get multiplied by that value.
pub(crate) const REWARDING_GAS_LIMIT_MULTIPLIER: f64 = 1.05;
struct EpochRewardParams {
reward_pool: u128,
circulating_supply: u128,
sybil_resistance_percent: u8,
rewarded_set_size: u32,
active_set_size: u32,
period_reward_pool: u128,
active_set_work_factor: u8,
}
#[derive(Debug, Clone)]
pub(crate) struct MixnodeToReward {
@@ -50,7 +45,6 @@ pub(crate) struct MixnodeToReward {
}
impl MixnodeToReward {
/// Somewhat clumsy way of feature gatting tokenomics payments. In a tokenomics scenario this will never be None at reward time. We leverage that to Into a different ExecuteMsg variant
fn params(&self) -> NodeRewardParams {
self.params
}
@@ -123,6 +117,24 @@ impl Rewarder {
}
}
async fn epoch_reward_params(&self) -> Result<EpochRewardParams, RewardingError> {
let state = self.nymd_client.get_contract_settings().await?;
let reward_pool = self.nymd_client.get_reward_pool().await?;
let epoch_reward_percent = self.nymd_client.get_epoch_reward_percent().await?;
let epoch_reward_params = EpochRewardParams {
reward_pool,
circulating_supply: self.nymd_client.get_circulating_supply().await?,
sybil_resistance_percent: self.nymd_client.get_sybil_resistance_percent().await?,
rewarded_set_size: state.mixnode_rewarded_set_size,
active_set_size: state.mixnode_active_set_size,
period_reward_pool: (reward_pool / 100) * epoch_reward_percent as u128,
active_set_work_factor: state.active_set_work_factor,
};
Ok(epoch_reward_params)
}
/// Obtains the current number of delegators that have delegated their stake towards this particular mixnode.
///
/// # Arguments
@@ -158,21 +170,21 @@ impl Rewarder {
// and the lack of port data / verloc data will eventually be balanced out anyway
// by people hesitating to delegate to nodes without them and thus those nodes disappearing
// from the active set (once introduced)
let state = self.nymd_client.get_contract_settings().await?;
let reward_pool = self.nymd_client.get_reward_pool().await?;
let circulating_supply = self.nymd_client.get_circulating_supply().await?;
let sybil_resistance_percent = self.nymd_client.get_sybil_resistance_percent().await?;
let epoch_reward_percent = self.nymd_client.get_epoch_reward_percent().await?;
// TODO: question to @durch: is k active set or 'rewarded' set?
let k = state.mixnode_active_set_size;
let period_reward_pool = (reward_pool / 100) * epoch_reward_percent as u128;
let epoch_reward_params = self.epoch_reward_params().await?;
info!("Rewarding pool stats");
info!("-- Reward pool: {} unym", reward_pool);
info!("---- Epoch reward pool: {} unym", period_reward_pool);
info!("-- Circulating supply: {} unym", circulating_supply);
info!(
"-- Reward pool: {} {}",
epoch_reward_params.reward_pool, DENOM
);
info!(
"---- Epoch reward pool: {} {}",
epoch_reward_params.period_reward_pool, DENOM
);
info!(
"-- Circulating supply: {} {}",
epoch_reward_params.circulating_supply, DENOM
);
// 1. get list of 'rewarded' nodes
// 2. for each of them determine their delegator count
@@ -187,7 +199,9 @@ impl Rewarder {
}
let mut eligible_nodes = Vec::with_capacity(nodes_with_delegations.len());
for (rewarded_node, total_delegations) in nodes_with_delegations {
for (i, (rewarded_node, total_delegations)) in
nodes_with_delegations.into_iter().enumerate()
{
let uptime = self
.storage
.get_average_mixnode_uptime_in_interval(
@@ -201,12 +215,16 @@ impl Rewarder {
identity: rewarded_node.mix_node.identity_key,
total_delegations,
params: NodeRewardParams::new(
period_reward_pool,
k.into(),
epoch_reward_params.period_reward_pool,
epoch_reward_params.rewarded_set_size.into(),
epoch_reward_params.active_set_size.into(),
// Reward blockstamp gets set in the contract call
0,
circulating_supply,
epoch_reward_params.circulating_supply,
uptime.u8().into(),
sybil_resistance_percent,
epoch_reward_params.sybil_resistance_percent,
i < epoch_reward_params.active_set_size as usize,
epoch_reward_params.active_set_work_factor,
),
})
}
@@ -257,6 +275,23 @@ impl Rewarder {
(unrewarded, further_delegators_present)
}
// Utility function to print to the stdout rewarding progress
fn print_rewarding_progress(&self, total_rewarded: usize, out_of: usize, is_retry: bool) {
let percentage = total_rewarded as f32 * 100.0 / out_of as f32;
if is_retry {
info!(
"Resent rewarding transaction for {} / {} mixnodes\t{:.2}%",
total_rewarded, out_of, percentage
);
} else {
info!(
"Sent rewarding transaction for {} / {} mixnodes\t{:.2}%",
total_rewarded, out_of, percentage
);
}
}
/// Using the list of mixnodes eligible for rewards, chunks it into pre-defined sized-chunks
/// and gives out the rewards by calling the smart contract.
///
@@ -271,12 +306,26 @@ impl Rewarder {
/// # Arguments
///
/// * `eligible_mixnodes`: list of the nodes that are eligible to receive rewards.
/// * `rewarding_interval_nonce`: nonce associated with the current rewarding interval
/// * `rewarding_interval_nonce`: nonce associated with the current rewarding interval.
/// * `retry`: flag to indicate whether this is a retry attempt for rewarding particular nodes.
async fn distribute_rewards_to_mixnodes(
&self,
eligible_mixnodes: &[MixnodeToReward],
rewarding_interval_nonce: u32,
retry: bool,
) -> Option<Vec<FailedMixnodeRewardChunkDetails>> {
if retry {
info!(
"Attempting to retry rewarding {} mixnodes...",
eligible_mixnodes.len()
)
} else {
info!(
"Attempting to reward {} mixnodes...",
eligible_mixnodes.len()
)
}
let mut failed_chunks = Vec::new();
// construct chunks such that we reward at most MIXNODE_DELEGATORS_PAGE_LIMIT delegators per block
@@ -336,17 +385,14 @@ impl Rewarder {
}
total_rewarded += 1;
let percentage = total_rewarded as f32 * 100.0 / eligible_mixnodes.len() as f32;
info!(
"Rewarded {} / {} mixnodes\t{:.2}%",
total_rewarded,
eligible_mixnodes.len(),
percentage
);
self.print_rewarding_progress(total_rewarded, eligible_mixnodes.len(), retry);
}
// then we move onto the chunks
for mix_chunk in batch_rewarded {
if mix_chunk.is_empty() {
continue;
}
if let Err(err) = self
.nymd_client
.reward_mixnodes_with_single_page_of_delegators(
@@ -369,13 +415,7 @@ impl Rewarder {
}
total_rewarded += mix_chunk.len();
let percentage = total_rewarded as f32 * 100.0 / eligible_mixnodes.len() as f32;
info!(
"Rewarded {} / {} mixnodes\t{:.2}%",
total_rewarded,
eligible_mixnodes.len(),
percentage
);
self.print_rewarding_progress(total_rewarded, eligible_mixnodes.len(), retry);
}
if failed_chunks.is_empty() {
@@ -399,7 +439,15 @@ impl Rewarder {
nodes: &[MixnodeToReward],
rewarding_interval_nonce: u32,
) {
let mut total_resent = 0;
for missed_node in nodes {
total_resent += 1;
info!(
"Sending rewarding transaction for missed delegators ({} / {} mixnodes re-checked)",
total_resent,
nodes.len()
);
if let Err(err) = self
.nymd_client
.reward_mix_delegators(missed_node, rewarding_interval_nonce)
@@ -442,7 +490,7 @@ impl Rewarder {
.begin_mixnode_rewarding(current_rewarding_nonce + 1)
.await?;
failure_data.mixnodes = self
.distribute_rewards_to_mixnodes(&eligible_mixnodes, current_rewarding_nonce + 1)
.distribute_rewards_to_mixnodes(&eligible_mixnodes, current_rewarding_nonce + 1, false)
.await;
let mut nodes_to_verify = eligible_mixnodes;
@@ -463,7 +511,7 @@ impl Rewarder {
if !unrewarded.is_empty() {
// no need to save failure data as we already know about those from the very first run
self.distribute_rewards_to_mixnodes(&unrewarded, current_rewarding_nonce + 1)
self.distribute_rewards_to_mixnodes(&unrewarded, current_rewarding_nonce + 1, true)
.await;
}