Skip to content

Commit

Permalink
Feature/node settings apy playground (#1677) (#2738)
Browse files Browse the repository at this point in the history
* initial ui for test my node

use svg for node path

add stories for test my node

* add initial rewards calculation

* update validation for rewards playground

* init playground with default values

* get node uptime

* get mixnode reward estimation

* calculate saturation

calculate stake saturation

* Make ComputeRewardEstParam derive Debug

* set active set to be always true

Co-authored-by: Jon Häggblad <[email protected]>

Co-authored-by: Jon Häggblad <[email protected]>
  • Loading branch information
fmtabbara and octol committed Dec 21, 2022
1 parent b9fed9f commit eff1f38
Show file tree
Hide file tree
Showing 68 changed files with 672 additions and 41 deletions.
18 changes: 9 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 24 additions & 4 deletions common/client-libs/validator-client/src/validator_api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ use validator_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
};
use validator_api_requests::models::{
GatewayCoreStatusResponse, GatewayStatusReportResponse, GatewayUptimeHistoryResponse,
InclusionProbabilityResponse, MixNodeBondAnnotated, MixnodeCoreStatusResponse,
MixnodeStatusReportResponse, MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RequestError,
RewardEstimationResponse, StakeSaturationResponse, UptimeResponse,
ComputeRewardEstParam, GatewayCoreStatusResponse, GatewayStatusReportResponse,
GatewayUptimeHistoryResponse, InclusionProbabilityResponse, MixNodeBondAnnotated,
MixnodeCoreStatusResponse, MixnodeStatusReportResponse, MixnodeStatusResponse,
MixnodeUptimeHistoryResponse, RequestError, RewardEstimationResponse, StakeSaturationResponse,
UptimeResponse,
};

pub mod error;
Expand Down Expand Up @@ -365,6 +366,25 @@ impl Client {
.await
}

pub async fn compute_mixnode_reward_estimation(
&self,
mix_id: MixId,
request_body: &ComputeRewardEstParam,
) -> Result<RewardEstimationResponse, ValidatorAPIError> {
self.post_validator_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
&mix_id.to_string(),
routes::COMPUTE_REWARD_ESTIMATION,
],
NO_PARAMS,
request_body,
)
.await
}

pub async fn get_mixnode_stake_saturation(
&self,
mix_id: MixId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub const STATUS: &str = "status";
pub const REPORT: &str = "report";
pub const HISTORY: &str = "history";
pub const REWARD_ESTIMATION: &str = "reward-estimation";
pub const COMPUTE_REWARD_ESTIMATION: &str = "compute-reward-estimation";
pub const AVG_UPTIME: &str = "avg_uptime";
pub const STAKE_SATURATION: &str = "stake-saturation";
pub const INCLUSION_CHANCE: &str = "inclusion-probability";
3 changes: 1 addition & 2 deletions nym-connect/src-tauri/src/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ impl AddDefaultSubmenus for Menu {
fn add_default_app_submenus(self) -> Self {
let submenu = Submenu::new(
"Help",
Menu::new()
.add_item(CustomMenuItem::new(SHOW_LOG_WINDOW, "Show logs"))
Menu::new().add_item(CustomMenuItem::new(SHOW_LOG_WINDOW, "Show logs")),
);
self.add_submenu(submenu)
}
Expand Down
2 changes: 1 addition & 1 deletion nym-wallet/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions nym-wallet/src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ fn main() {
mixnet::rewards::claim_delegator_reward,
mixnet::rewards::claim_operator_reward,
mixnet::rewards::claim_locked_and_unlocked_delegator_reward,
mixnet::rewards::get_current_rewarding_parameters,
mixnet::send::send,
mixnet::bond::get_mixnode_uptime,
network_config::add_validator,
network_config::get_validator_api_urls,
network_config::get_validator_nymd_urls,
Expand All @@ -99,6 +101,7 @@ fn main() {
utils::get_old_and_incorrect_hardcoded_fee,
utils::try_convert_pubkey_to_mix_id,
utils::default_mixnode_cost_params,
validator_api::status::compute_mixnode_reward_estimation,
validator_api::status::gateway_core_node_status,
validator_api::status::mixnode_core_node_status,
validator_api::status::mixnode_inclusion_probability,
Expand Down
15 changes: 15 additions & 0 deletions nym-wallet/src-tauri/src/operations/mixnet/bond.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,3 +341,18 @@ pub async fn get_mix_node_description(
.json()
.await?)
}

#[tauri::command]
pub async fn get_mixnode_uptime(
mix_id: MixId,
state: tauri::State<'_, WalletState>,
) -> Result<u8, BackendError> {
log::info!(">>> Get mixnode uptime");

let guard = state.read().await;
let client = guard.current_client()?;
let uptime = client.validator_api.get_mixnode_avg_uptime(mix_id).await?;

log::info!(">>> Uptime response: {}", uptime.avg_uptime);
Ok(uptime.avg_uptime)
}
16 changes: 15 additions & 1 deletion nym-wallet/src-tauri/src/operations/mixnet/rewards.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::error::BackendError;
use crate::state::WalletState;
use crate::vesting::rewards::vesting_claim_delegator_reward;
use mixnet_contract_common::MixId;
use mixnet_contract_common::{MixId, RewardingParams};
use nym_types::transaction::TransactionExecuteResult;
use validator_client::nymd::traits::{MixnetQueryClient, MixnetSigningClient};
use validator_client::nymd::Fee;
Expand Down Expand Up @@ -95,3 +95,17 @@ pub async fn claim_locked_and_unlocked_delegator_reward(
log::trace!("<<< {:?}", res);
Ok(res)
}

#[tauri::command]
pub async fn get_current_rewarding_parameters(
state: tauri::State<'_, WalletState>,
) -> Result<RewardingParams, BackendError> {
log::info!(">>> Get current rewarding params",);

let guard = state.read().await;
let client = guard.current_client()?;

let reward_params = client.nymd.get_rewarding_parameters().await?;

Ok(reward_params)
}
31 changes: 27 additions & 4 deletions nym-wallet/src-tauri/src/operations/validator_api/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
use crate::api_client;
use crate::error::BackendError;
use crate::state::WalletState;
use mixnet_contract_common::{IdentityKeyRef, MixId};
use mixnet_contract_common::{reward_params::Performance, Coin, IdentityKeyRef, MixId, Percent};
use validator_client::models::{
GatewayCoreStatusResponse, GatewayStatusReportResponse, InclusionProbabilityResponse,
MixnodeCoreStatusResponse, MixnodeStatusResponse, RewardEstimationResponse,
StakeSaturationResponse,
ComputeRewardEstParam, GatewayCoreStatusResponse, GatewayStatusReportResponse,
InclusionProbabilityResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
RewardEstimationResponse, StakeSaturationResponse,
};

#[tauri::command]
Expand Down Expand Up @@ -59,6 +59,29 @@ pub async fn mixnode_reward_estimation(
.await?)
}

#[tauri::command]
pub async fn compute_mixnode_reward_estimation(
mix_id: u32,
performance: Option<Performance>,
pledge_amount: Option<u64>,
total_delegation: Option<u64>,
interval_operating_cost: Option<Coin>,
profit_margin_percent: Option<Percent>,
state: tauri::State<'_, WalletState>,
) -> Result<RewardEstimationResponse, BackendError> {
let request_body = ComputeRewardEstParam {
performance,
active_in_rewarded_set: Some(true),
pledge_amount,
total_delegation,
interval_operating_cost,
profit_margin_percent,
};
Ok(api_client!(state)
.compute_mixnode_reward_estimation(mix_id, &request_body)
.await?)
}

#[tauri::command]
pub async fn mixnode_stake_saturation(
mix_id: MixId,
Expand Down
2 changes: 1 addition & 1 deletion nym-wallet/src/components/AppBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const AppBar = () => {
const navigate = useNavigate();

return (
<MuiAppBar position="sticky" sx={{ boxShadow: 'none', bgcolor: 'transparent', backgroundImage: 'none', pt: 3 }}>
<MuiAppBar position="sticky" sx={{ boxShadow: 'none', bgcolor: 'transparent', backgroundImage: 'none', mt: 3 }}>
<Toolbar disableGutters>
<Grid container justifyContent="space-between" alignItems="center" flexWrap="nowrap">
<Grid item container alignItems="center" spacing={1}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { Typography } from '@mui/material';
import { SelectionChance } from '@nymproject/types';

const colorMap: { [key in SelectionChance]: string } = {
Low: 'error.main',
Good: 'warning.main',
High: 'success.main',
};

const textMap: { [key in SelectionChance]: string } = {
Low: 'Low',
Good: 'Good',
High: 'High',
};

export const InclusionProbability = ({ probability }: { probability: SelectionChance }) => (
<Typography sx={{ color: colorMap[probability] }}>{textMap[probability]}</Typography>
);
91 changes: 91 additions & 0 deletions nym-wallet/src/components/RewardsPlayground/Inputs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React, { useCallback } from 'react';
import { yupResolver } from '@hookform/resolvers/yup';
import { Button, Grid, TextField, Typography } from '@mui/material';
import { useForm } from 'react-hook-form';
import { DefaultInputValues } from 'src/pages/bonding/node-settings/apy-playground';
import { inputValidationSchema } from './inputsValidationSchema';

export type InputFields = {
label: string;
name: 'profitMargin' | 'uptime' | 'bond' | 'delegations' | 'operatorCost' | 'uptime';
isPercentage?: boolean;
}[];

export type CalculateArgs = {
bond: string;
delegations: string;
uptime: string;
profitMargin: string;
operatorCost: string;
};

const inputFields: InputFields = [
{ label: 'Profit margin', name: 'profitMargin', isPercentage: true },
{ label: 'Operator cost', name: 'operatorCost' },
{ label: 'Bond', name: 'bond' },
{ label: 'Delegations', name: 'delegations' },
{ label: 'Uptime', name: 'uptime', isPercentage: true },
];

export const Inputs = ({
onCalculate,
defaultValues,
}: {
onCalculate: (args: CalculateArgs) => Promise<void>;
defaultValues: DefaultInputValues;
}) => {
const handleCalculate = useCallback(
async (args: CalculateArgs) => {
onCalculate({
bond: args.bond,
delegations: args.delegations,
uptime: args.uptime,
profitMargin: args.profitMargin,
operatorCost: args.operatorCost,
});
},
[onCalculate],
);

const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(inputValidationSchema),
defaultValues,
});

return (
<Grid container spacing={3}>
{inputFields.map((field) => (
<Grid item xs={12} lg={2} key={field.name}>
<TextField
{...register(field.name)}
fullWidth
label={field.label}
name={field.name}
error={Boolean(errors[field.name])}
helperText={errors[field.name]?.message}
InputProps={{
endAdornment: <Typography sx={{ color: 'grey.600' }}>{field.isPercentage ? '%' : 'NYM'}</Typography>,
}}
InputLabelProps={{ shrink: true }}
/>
</Grid>
))}{' '}
<Grid item xs={12} lg={2}>
<Button
variant="contained"
disableElevation
onClick={handleSubmit(handleCalculate)}
size="large"
fullWidth
disabled={Boolean(Object.keys(errors).length)}
>
Calculate
</Button>
</Grid>
</Grid>
);
};
Loading

0 comments on commit eff1f38

Please sign in to comment.