diff --git a/Cargo.lock b/Cargo.lock index 822fa26726..2256ba25f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -586,7 +586,7 @@ dependencies = [ [[package]] name = "client-core" -version = "1.1.2" +version = "1.1.4" dependencies = [ "async-trait", "client-connections", @@ -3106,7 +3106,7 @@ dependencies = [ [[package]] name = "nym-cli" -version = "1.1.2" +version = "1.1.4" dependencies = [ "anyhow", "base64", @@ -3160,7 +3160,7 @@ dependencies = [ [[package]] name = "nym-client" -version = "1.1.2" +version = "1.1.4" dependencies = [ "clap 3.2.8", "client-connections", @@ -3199,7 +3199,7 @@ dependencies = [ [[package]] name = "nym-gateway" -version = "1.1.2" +version = "1.1.4" dependencies = [ "anyhow", "async-trait", @@ -3246,7 +3246,7 @@ dependencies = [ [[package]] name = "nym-mixnode" -version = "1.1.2" +version = "1.1.4" dependencies = [ "anyhow", "bs58", @@ -3288,7 +3288,7 @@ dependencies = [ [[package]] name = "nym-network-requester" -version = "1.1.2" +version = "1.1.4" dependencies = [ "async-trait", "clap 3.2.8", @@ -3320,7 +3320,7 @@ dependencies = [ [[package]] name = "nym-network-statistics" -version = "1.1.2" +version = "1.1.4" dependencies = [ "dirs", "log", @@ -3336,7 +3336,7 @@ dependencies = [ [[package]] name = "nym-socks5-client" -version = "1.1.2" +version = "1.1.4" dependencies = [ "clap 3.2.8", "client-connections", @@ -3403,7 +3403,7 @@ dependencies = [ [[package]] name = "nym-validator-api" -version = "1.1.2" +version = "1.1.4" dependencies = [ "anyhow", "async-trait", diff --git a/common/client-libs/validator-client/src/validator_api/mod.rs b/common/client-libs/validator-client/src/validator_api/mod.rs index 3cb7ae2ce9..c0775b9971 100644 --- a/common/client-libs/validator-client/src/validator_api/mod.rs +++ b/common/client-libs/validator-client/src/validator_api/mod.rs @@ -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; @@ -365,6 +366,25 @@ impl Client { .await } + pub async fn compute_mixnode_reward_estimation( + &self, + mix_id: MixId, + request_body: &ComputeRewardEstParam, + ) -> Result { + 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, diff --git a/common/client-libs/validator-client/src/validator_api/routes.rs b/common/client-libs/validator-client/src/validator_api/routes.rs index 66a822b4fd..e98f2d295a 100644 --- a/common/client-libs/validator-client/src/validator_api/routes.rs +++ b/common/client-libs/validator-client/src/validator_api/routes.rs @@ -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"; diff --git a/nym-connect/src-tauri/src/menu.rs b/nym-connect/src-tauri/src/menu.rs index fb6f88fb68..2f9be83e07 100644 --- a/nym-connect/src-tauri/src/menu.rs +++ b/nym-connect/src-tauri/src/menu.rs @@ -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) } diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index 41db8105db..9112e7a45f 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -2862,7 +2862,7 @@ dependencies = [ [[package]] name = "nym_wallet" -version = "1.1.2" +version = "1.1.4" dependencies = [ "aes-gcm", "argon2 0.3.4", diff --git a/nym-wallet/src-tauri/src/main.rs b/nym-wallet/src-tauri/src/main.rs index d34a04f920..fff95fcb40 100644 --- a/nym-wallet/src-tauri/src/main.rs +++ b/nym-wallet/src-tauri/src/main.rs @@ -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, @@ -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, diff --git a/nym-wallet/src-tauri/src/operations/mixnet/bond.rs b/nym-wallet/src-tauri/src/operations/mixnet/bond.rs index 567dc84290..c29e49b23c 100644 --- a/nym-wallet/src-tauri/src/operations/mixnet/bond.rs +++ b/nym-wallet/src-tauri/src/operations/mixnet/bond.rs @@ -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 { + 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) +} diff --git a/nym-wallet/src-tauri/src/operations/mixnet/rewards.rs b/nym-wallet/src-tauri/src/operations/mixnet/rewards.rs index 6fb8893ee9..b4a048eeea 100644 --- a/nym-wallet/src-tauri/src/operations/mixnet/rewards.rs +++ b/nym-wallet/src-tauri/src/operations/mixnet/rewards.rs @@ -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; @@ -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 { + 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) +} diff --git a/nym-wallet/src-tauri/src/operations/validator_api/status.rs b/nym-wallet/src-tauri/src/operations/validator_api/status.rs index 16c83cfb67..873a1fa0a4 100644 --- a/nym-wallet/src-tauri/src/operations/validator_api/status.rs +++ b/nym-wallet/src-tauri/src/operations/validator_api/status.rs @@ -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] @@ -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, + pledge_amount: Option, + total_delegation: Option, + interval_operating_cost: Option, + profit_margin_percent: Option, + state: tauri::State<'_, WalletState>, +) -> Result { + 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, diff --git a/nym-wallet/src/components/AppBar.tsx b/nym-wallet/src/components/AppBar.tsx index 24b2f93942..3022646798 100644 --- a/nym-wallet/src/components/AppBar.tsx +++ b/nym-wallet/src/components/AppBar.tsx @@ -15,7 +15,7 @@ export const AppBar = () => { const navigate = useNavigate(); return ( - + diff --git a/nym-wallet/src/components/RewardsPlayground/InclusionProbability.tsx b/nym-wallet/src/components/RewardsPlayground/InclusionProbability.tsx new file mode 100644 index 0000000000..d60f7886c7 --- /dev/null +++ b/nym-wallet/src/components/RewardsPlayground/InclusionProbability.tsx @@ -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 }) => ( + {textMap[probability]} +); diff --git a/nym-wallet/src/components/RewardsPlayground/Inputs.tsx b/nym-wallet/src/components/RewardsPlayground/Inputs.tsx new file mode 100644 index 0000000000..1f1dbac935 --- /dev/null +++ b/nym-wallet/src/components/RewardsPlayground/Inputs.tsx @@ -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; + 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 ( + + {inputFields.map((field) => ( + + {field.isPercentage ? '%' : 'NYM'}, + }} + InputLabelProps={{ shrink: true }} + /> + + ))}{' '} + + + + + ); +}; diff --git a/nym-wallet/src/components/RewardsPlayground/NodeDetail.tsx b/nym-wallet/src/components/RewardsPlayground/NodeDetail.tsx new file mode 100644 index 0000000000..fb8a239be0 --- /dev/null +++ b/nym-wallet/src/components/RewardsPlayground/NodeDetail.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { Card, CardContent, Divider, Stack, Typography } from '@mui/material'; +import { SelectionChance } from '@nymproject/types'; +import { InclusionProbability } from './InclusionProbability'; + +const computeSelectionProbability = (saturation: number): SelectionChance => { + if (saturation < 5) return 'Low'; + + if (saturation > 5 && saturation < 15) return 'Good'; + + return 'High'; +}; + +export const NodeDetails = ({ saturation }: { saturation?: string }) => { + if (!saturation) return null; + + return ( + + + + Stake saturation + {saturation || '- '}% + + + + Selection probability + + + + + ); +}; diff --git a/nym-wallet/src/components/RewardsPlayground/ResultsTable.tsx b/nym-wallet/src/components/RewardsPlayground/ResultsTable.tsx new file mode 100644 index 0000000000..19196c176d --- /dev/null +++ b/nym-wallet/src/components/RewardsPlayground/ResultsTable.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { + Card, + CardContent, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Typography, +} from '@mui/material'; + +export type Results = { + operator: { + daily: string; + monthly: string; + yearly: string; + }; + delegator: { + daily: string; + monthly: string; + yearly: string; + }; + total: { + daily: string; + monthly: string; + yearly: string; + }; +}; + +const tableHeader = [ + { title: 'Estimated rewards', bold: true }, + { title: 'Per day' }, + { title: 'Per month' }, + { title: 'Per year' }, +]; + +export const ResultsTable = ({ results }: { results: Results }) => { + const tableRows = [ + { title: 'Total node reward', ...results.total }, + { title: 'Operator rewards', ...results.operator }, + { title: 'Delegator rewards', ...results.delegator }, + ]; + + return ( + + + + + + + {tableHeader.map((header) => ( + + {header.title} + + ))} + + + + {tableRows.map((row) => ( + + {row.title} + {row.daily} + {row.monthly} + {row.yearly} + + ))} + +
+
+
+
+ ); +}; diff --git a/nym-wallet/src/components/RewardsPlayground/inputsValidationSchema.ts b/nym-wallet/src/components/RewardsPlayground/inputsValidationSchema.ts new file mode 100644 index 0000000000..ef5d9ecc0d --- /dev/null +++ b/nym-wallet/src/components/RewardsPlayground/inputsValidationSchema.ts @@ -0,0 +1,41 @@ +import * as Yup from 'yup'; +import { isGreaterThan, isLessThan } from 'src/utils'; + +export const inputValidationSchema = Yup.object().shape({ + profitMargin: Yup.string() + .required('profit margin is a required field') + .test('Is valid profit margin value', (value, ctx) => { + const stringValueToNumber = Math.round(Number(value)); + + if (isGreaterThan(stringValueToNumber, -1) && isLessThan(stringValueToNumber, 101)) return true; + return ctx.createError({ message: 'Profit margin must be a number from 0 and 100' }); + }), + uptime: Yup.string() + .required() + .test('Is valid uptime value', (value, ctx) => { + const stringValueToNumber = Math.round(Number(value)); + if (stringValueToNumber && isGreaterThan(stringValueToNumber, 0) && isLessThan(stringValueToNumber, 101)) + return true; + return ctx.createError({ message: 'Uptime must be a number between 0 and 100' }); + }), + bond: Yup.string() + .required() + .test('Is valid bond value', (value, ctx) => { + if (Number(value)) return true; + return ctx.createError({ message: 'Bond must be a valid number' }); + }), + delegations: Yup.string() + .required() + .test('Is valid delegation value', (value, ctx) => { + if (Number(value)) return true; + return ctx.createError({ message: 'Delegations must be a valid number' }); + }), + operatorCost: Yup.string() + .required('operator cost is a required field') + .test('Is valid operator cost value', (value, ctx) => { + const stringValueToNumber = Math.round(Number(value)); + + if (isGreaterThan(stringValueToNumber, -1) && isLessThan(stringValueToNumber, 101)) return true; + return ctx.createError({ message: 'Operator cost must be a valid number' }); + }), +}); diff --git a/nym-wallet/src/context/bonding.tsx b/nym-wallet/src/context/bonding.tsx index 7225360456..94bf5271ca 100644 --- a/nym-wallet/src/context/bonding.tsx +++ b/nym-wallet/src/context/bonding.tsx @@ -24,7 +24,6 @@ import { vestingBondMixNode, vestingUnbondGateway, vestingUnbondMixnode, - getPendingEpochEvents, updateMixnodeCostParams as updateMixnodeCostParamsRequest, vestingUpdateMixnodeCostParams as updateMixnodeVestingCostParamsRequest, getNodeDescription as getNodeDescriptionRequest, @@ -36,6 +35,7 @@ import { getMixnodeAvgUptime, getMixnodeRewardEstimation, getGatewayReport, + getMixnodeUptime, } from '../requests'; import { useCheckOwnership } from '../hooks/useCheckOwnership'; import { AppContext } from './main'; @@ -71,10 +71,12 @@ export type TBondedMixnode = { verlocPort: number; version: string; isUnbonding: boolean; + uptime: number; }; export interface TBondedGateway { - name: string; + name?: string; + id: number; identityKey: string; ip: string; bond: DecCoin; @@ -154,14 +156,18 @@ export const BondingContextProvider = ({ children }: { children?: React.ReactNod status: MixnodeStatus; stakeSaturation: string; estimatedRewards?: DecCoin; + uptime: number; } = { status: 'not_found', stakeSaturation: '0', + uptime: 0, }; try { const statusResponse = await getMixnodeStatus(mixId); + const uptime = await getMixnodeUptime(mixId); additionalDetails.status = statusResponse.status; + additionalDetails.uptime = uptime; } catch (e) { Console.log('getMixnodeStatus fails', e); } @@ -259,7 +265,8 @@ export const BondingContextProvider = ({ children }: { children?: React.ReactNod rewarding_details, bond_information: { mix_id }, } = data; - const { status, stakeSaturation, estimatedRewards } = await getAdditionalMixnodeDetails(mix_id); + + const { status, stakeSaturation, estimatedRewards, uptime } = await getAdditionalMixnodeDetails(mix_id); const setProbabilities = await getSetProbabilities(mix_id); const nodeDescription = await getNodeDescription( bond_information.mix_node.host, @@ -267,6 +274,7 @@ export const BondingContextProvider = ({ children }: { children?: React.ReactNod ); const routingScore = await getAvgUptime(); setBondedNode({ + id: data.bond_information.mix_id, name: nodeDescription?.name, mixId: mix_id, identityKey: bond_information.mix_node.identity_key, @@ -279,6 +287,7 @@ export const BondingContextProvider = ({ children }: { children?: React.ReactNod delegators: rewarding_details.unique_delegations, proxy: bond_information.proxy, operatorRewards, + uptime, status, stakeSaturation, operatorCost: decCoinToDisplay(rewarding_details.cost_params.interval_operating_cost), diff --git a/nym-wallet/src/context/mocks/bonding.tsx b/nym-wallet/src/context/mocks/bonding.tsx index 95e770850b..f38168ee28 100644 --- a/nym-wallet/src/context/mocks/bonding.tsx +++ b/nym-wallet/src/context/mocks/bonding.tsx @@ -7,8 +7,8 @@ import { mockSleep } from './utils'; const SLEEP_MS = 1000; const bondedMixnodeMock: TBondedMixnode = { - name: 'Monster node', mixId: 1, + name: 'Monster node', identityKey: '7mjM2fYbtN6kxMwp1TrmQ4VwPks3URR5pBgWPWhzT98F', stake: { denom: 'nym', amount: '1234' }, bond: { denom: 'nym', amount: '1234' }, @@ -28,9 +28,11 @@ const bondedMixnodeMock: TBondedMixnode = { verlocPort: 1790, version: '1.0.2', isUnbonding: false, + uptime: 1, }; const bondedGatewayMock: TBondedGateway = { + id: 1, name: 'Monster node', identityKey: 'WayM2fYbtN6kxMwp1TrmQ4VwPks3URR5pBgWPWhzT98F', ip: '112.43.234.57', diff --git a/nym-wallet/src/pages/bonding/node-settings/NodeSettings.tsx b/nym-wallet/src/pages/bonding/node-settings/NodeSettings.tsx index da50bc2d2d..798993dc49 100644 --- a/nym-wallet/src/pages/bonding/node-settings/NodeSettings.tsx +++ b/nym-wallet/src/pages/bonding/node-settings/NodeSettings.tsx @@ -10,13 +10,14 @@ import { LoadingModal } from 'src/components/Modals/LoadingModal'; import { NymCard } from 'src/components'; import { PageLayout } from 'src/layouts'; import { Tabs } from 'src/components/Tabs'; -import { useBondingContext, BondingContextProvider } from 'src/context'; +import { useBondingContext, BondingContextProvider, TBondedMixnode } from 'src/context'; import { AppContext, urls } from 'src/context/main'; import { NodeGeneralSettings } from './settings-pages/general-settings'; import { NodeUnbondPage } from './settings-pages/NodeUnbondPage'; import { createNavItems } from './node-settings.constant'; import { isMixnode } from 'src/types'; +import { ApyPlayground } from './apy-playground'; export const NodeSettings = () => { const theme = useTheme(); @@ -123,6 +124,7 @@ export const NodeSettings = () => { {value === 'Unbond' && bondedNode && ( )} + {value === 'Playground' && bondedNode && } {confirmationDetails && confirmationDetails.status === 'success' && ( { + const { enqueueSnackbar } = useSnackbar(); + + const [results, setResults] = useState({ + total: { daily: '-', monthly: '-', yearly: '-' }, + operator: { daily: '-', monthly: '-', yearly: '-' }, + delegator: { daily: '-', monthly: '-', yearly: '-' }, + }); + + const [defaultInputValues, setDefaultInputValues] = useState(); + const [stakeSaturation, setStakeSaturation] = useState(); + const [isLoading, setIsLoading] = useState(true); + + const initialise = async (node: TBondedMixnode) => { + try { + const delegations = await getDelegationSummary(); + + const { estimation } = await computeEstimate({ + mixId: node.mixId, + uptime: node.uptime.toString(), + profitMargin: node.profitMargin, + operatorCost: node.operatorCost.amount, + totalDelegation: delegations.total_delegations.amount, + pledgeAmount: node.bond.amount, + }); + + setResults( + handleCalculatePeriodRewards({ + estimatedOperatorReward: estimation.operator, + estimatedDelegatorsReward: estimation.delegates, + }), + ); + + setStakeSaturation(node.stakeSaturation); + + setDefaultInputValues({ + profitMargin: node.profitMargin, + uptime: (node.uptime || 0).toString(), + bond: node.bond.amount || '', + delegations: delegations.total_delegations.amount, + operatorCost: node.operatorCost.amount, + }); + setIsLoading(false); + } catch (e) { + enqueueSnackbar(e as string, { variant: 'error' }); + } + }; + + useEffect(() => { + if (bondedNode) { + initialise(bondedNode); + } + }, []); + + if (isLoading) return ; + + const handleCalculateEstimate = async ({ bond, delegations, uptime, profitMargin, operatorCost }: CalculateArgs) => { + try { + const { estimation, reward_params } = await computeEstimate({ + mixId: bondedNode.mixId, + uptime: uptime, + profitMargin: profitMargin, + operatorCost: operatorCost, + totalDelegation: delegations, + pledgeAmount: bond, + }); + + const estimationResult = handleCalculatePeriodRewards({ + estimatedOperatorReward: estimation.operator, + estimatedDelegatorsReward: estimation.delegates, + }); + + const computedStakeSaturation = computeStakeSaturation( + bond, + delegations, + reward_params.interval.stake_saturation_point, + ); + + setStakeSaturation(computedStakeSaturation); + setResults(estimationResult); + } catch (e) { + console.log(e); + } + }; + + return ( + + + Playground + + + This is your parameters playground - change the parameters below to see the node specific estimations in the + table + + {defaultInputValues && ( + + + Estimation calculator + + } + /> + + + + + )} + + + + + + + + + + ); +}; diff --git a/nym-wallet/src/pages/bonding/node-settings/apy-playground/utils.tsx b/nym-wallet/src/pages/bonding/node-settings/apy-playground/utils.tsx new file mode 100644 index 0000000000..bc99898b45 --- /dev/null +++ b/nym-wallet/src/pages/bonding/node-settings/apy-playground/utils.tsx @@ -0,0 +1,66 @@ +import { decimalToPercentage, percentToDecimal } from '@nymproject/types'; +import { computeMixnodeRewardEstimation } from 'src/requests'; + +const SCALE_FACTOR = 1_000_000; + +export const computeStakeSaturation = (bond: string, delegations: string, stakeSaturationPoint: string) => { + const res = ((+bond + +delegations) * SCALE_FACTOR) / +stakeSaturationPoint; + return decimalToPercentage(res.toFixed(18).toString()); +}; + +export const computeEstimate = async ({ + mixId, + uptime, + pledgeAmount, + totalDelegation, + profitMargin, + operatorCost, +}: { + mixId: number; + uptime: string; + pledgeAmount: string; + totalDelegation: string; + profitMargin: string; + operatorCost: string; +}) => { + const computedEstimate = await computeMixnodeRewardEstimation({ + mixId: mixId, + performance: percentToDecimal(uptime), + pledgeAmount: Math.round(+pledgeAmount * SCALE_FACTOR), + totalDelegation: Math.round(+totalDelegation * SCALE_FACTOR), + profitMarginPercent: percentToDecimal(profitMargin), + intervalOperatingCost: { denom: 'unym', amount: Math.round(+operatorCost * SCALE_FACTOR).toString() }, + }); + + return computedEstimate; +}; + +export const handleCalculatePeriodRewards = ({ + estimatedOperatorReward, + estimatedDelegatorsReward, +}: { + estimatedOperatorReward: string; + estimatedDelegatorsReward: string; +}) => { + const dailyOperatorReward = (+estimatedOperatorReward / SCALE_FACTOR) * 24; // epoch_reward * 1 epoch_per_hour * 24 hours + const dailyDelegatorReward = (+estimatedDelegatorsReward / SCALE_FACTOR) * 24; + const dailyTotal = dailyOperatorReward + dailyDelegatorReward; + + return { + total: { + daily: dailyTotal.toFixed(3).toString(), + monthly: (dailyTotal * 30).toFixed(3).toString(), + yearly: (dailyTotal * 365).toFixed(3).toString(), + }, + operator: { + daily: dailyOperatorReward.toFixed(3).toString(), + monthly: (dailyOperatorReward * 30).toFixed(3).toString(), + yearly: (dailyOperatorReward * 365).toFixed(3).toString(), + }, + delegator: { + daily: dailyDelegatorReward.toFixed(3).toString(), + monthly: (dailyDelegatorReward * 30).toFixed(3).toString(), + yearly: (dailyDelegatorReward * 365).toFixed(3).toString(), + }, + }; +}; diff --git a/nym-wallet/src/pages/bonding/node-settings/node-settings.constant.tsx b/nym-wallet/src/pages/bonding/node-settings/node-settings.constant.tsx index f00409a182..0e8b6204fd 100644 --- a/nym-wallet/src/pages/bonding/node-settings/node-settings.constant.tsx +++ b/nym-wallet/src/pages/bonding/node-settings/node-settings.constant.tsx @@ -1,5 +1,5 @@ export const createNavItems = (isMixnode: boolean) => { const navItems = ['Unbond']; - if (isMixnode) return ['General', ...navItems]; + if (isMixnode) return ['General', 'Playground', ...navItems]; return navItems; }; diff --git a/nym-wallet/src/requests/queries.ts b/nym-wallet/src/requests/queries.ts index 5fba51beec..640fc79abb 100644 --- a/nym-wallet/src/requests/queries.ts +++ b/nym-wallet/src/requests/queries.ts @@ -8,6 +8,7 @@ import { RewardEstimationResponse, WrappedDelegationEvent, PendingIntervalEvent, + Coin, } from '@nymproject/types'; import { Interval, TGatewayReport, TNodeDescription } from 'src/types'; import { invokeWrapper } from './wrapper'; @@ -51,3 +52,17 @@ export const getPendingIntervalEvents = async () => export const getGatewayReport = async (identity: string) => invokeWrapper('gateway_report', { identity }); + +export const computeMixnodeRewardEstimation = async (args: { + mixId: number; + performance: string; + pledgeAmount: number; + totalDelegation: number; + profitMarginPercent: string; + intervalOperatingCost: { denom: 'unym'; amount: string }; +}) => { + console.log(args); + + return invokeWrapper('compute_mixnode_reward_estimation', args); +}; +export const getMixnodeUptime = async (mixId: number) => invokeWrapper('get_mixnode_uptime', { mixId }); diff --git a/nym-wallet/src/requests/rewards.ts b/nym-wallet/src/requests/rewards.ts index 5c8c63e34e..36b90838e7 100644 --- a/nym-wallet/src/requests/rewards.ts +++ b/nym-wallet/src/requests/rewards.ts @@ -1,4 +1,4 @@ -import { Fee, FeeDetails, TransactionExecuteResult } from '@nymproject/types'; +import { Fee, FeeDetails, RewardingParams, TransactionExecuteResult } from '@nymproject/types'; import { invokeWrapper } from './wrapper'; export const claimOperatorReward = async (fee?: Fee) => @@ -9,3 +9,6 @@ export const claimDelegatorRewards = async (mixId: number, fee?: FeeDetails) => mixId, fee: fee?.fee, }); + +export const getCurrentRewardingParameter = async () => + invokeWrapper('get_current_rewarding_parameters', {}); diff --git a/nym-wallet/src/types/rust/AppEnv.ts b/nym-wallet/src/types/rust/AppEnv.ts index 3f47419469..861ecd9ef5 100644 --- a/nym-wallet/src/types/rust/AppEnv.ts +++ b/nym-wallet/src/types/rust/AppEnv.ts @@ -1,2 +1,5 @@ - -export interface AppEnv { ADMIN_ADDRESS: string | null, SHOW_TERMINAL: string | null, ENABLE_QA_MODE: string | null, } \ No newline at end of file +export interface AppEnv { + ADMIN_ADDRESS: string | null; + SHOW_TERMINAL: string | null; + ENABLE_QA_MODE: string | null; +} diff --git a/nym-wallet/src/types/rust/Network.ts b/nym-wallet/src/types/rust/Network.ts index fd31bccafa..f8615cd992 100644 --- a/nym-wallet/src/types/rust/Network.ts +++ b/nym-wallet/src/types/rust/Network.ts @@ -1,2 +1 @@ - -export type Network = "QA" | "SANDBOX" | "MAINNET"; \ No newline at end of file +export type Network = 'QA' | 'SANDBOX' | 'MAINNET'; diff --git a/nym-wallet/src/types/rust/StateParams.ts b/nym-wallet/src/types/rust/StateParams.ts index 85c362a3b2..c9420f50dc 100644 --- a/nym-wallet/src/types/rust/StateParams.ts +++ b/nym-wallet/src/types/rust/StateParams.ts @@ -1,3 +1,7 @@ -import type { DecCoin } from "../../../../ts-packages/types/src/types/rust/DecCoin"; +import type { DecCoin } from '../../../../ts-packages/types/src/types/rust/DecCoin'; -export interface TauriContractStateParams { minimum_mixnode_pledge: DecCoin, minimum_gateway_pledge: DecCoin, minimum_mixnode_delegation: DecCoin | null, } \ No newline at end of file +export interface TauriContractStateParams { + minimum_mixnode_pledge: DecCoin; + minimum_gateway_pledge: DecCoin; + minimum_mixnode_delegation: DecCoin | null; +} diff --git a/nym-wallet/src/types/rust/ValidatorUrl.ts b/nym-wallet/src/types/rust/ValidatorUrl.ts index 9c74679bac..801e045a00 100644 --- a/nym-wallet/src/types/rust/ValidatorUrl.ts +++ b/nym-wallet/src/types/rust/ValidatorUrl.ts @@ -1,2 +1,4 @@ - -export interface ValidatorUrl { url: string, name: string | null, } \ No newline at end of file +export interface ValidatorUrl { + url: string; + name: string | null; +} diff --git a/nym-wallet/src/types/rust/ValidatorUrls.ts b/nym-wallet/src/types/rust/ValidatorUrls.ts index 3a104150b1..98ca799fb5 100644 --- a/nym-wallet/src/types/rust/ValidatorUrls.ts +++ b/nym-wallet/src/types/rust/ValidatorUrls.ts @@ -1,3 +1,5 @@ -import type { ValidatorUrl } from "./ValidatorUrl"; +import type { ValidatorUrl } from './ValidatorUrl'; -export interface ValidatorUrls { urls: Array, } \ No newline at end of file +export interface ValidatorUrls { + urls: Array; +} diff --git a/ts-packages/mui-theme/src/theme/theme.ts b/ts-packages/mui-theme/src/theme/theme.ts index a12e706e9e..bb4dcae533 100644 --- a/ts-packages/mui-theme/src/theme/theme.ts +++ b/ts-packages/mui-theme/src/theme/theme.ts @@ -84,6 +84,7 @@ export const getDesignTokens = (mode: PaletteMode): ThemeOptions => { ].join(','), fontSize: 14, fontWeightRegular: 500, + fontWeightMedium: 600, button: { textTransform: 'none', fontWeight: '600', diff --git a/ts-packages/types/src/types/rust/Account.ts b/ts-packages/types/src/types/rust/Account.ts index ea0586828f..da0afb666e 100644 --- a/ts-packages/types/src/types/rust/Account.ts +++ b/ts-packages/types/src/types/rust/Account.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { CurrencyDenom } from './CurrencyDenom'; export interface Account { diff --git a/ts-packages/types/src/types/rust/AccountEntry.ts b/ts-packages/types/src/types/rust/AccountEntry.ts index f6ad1b53a9..472a9befcd 100644 --- a/ts-packages/types/src/types/rust/AccountEntry.ts +++ b/ts-packages/types/src/types/rust/AccountEntry.ts @@ -1,3 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + export interface AccountEntry { id: string; address: string; diff --git a/ts-packages/types/src/types/rust/AccountWithMnemonic.ts b/ts-packages/types/src/types/rust/AccountWithMnemonic.ts index 6b3757bdab..edbf9b9de6 100644 --- a/ts-packages/types/src/types/rust/AccountWithMnemonic.ts +++ b/ts-packages/types/src/types/rust/AccountWithMnemonic.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { Account } from './Account'; export interface AccountWithMnemonic { diff --git a/ts-packages/types/src/types/rust/Balance.ts b/ts-packages/types/src/types/rust/Balance.ts index ba6be26651..fe11917327 100644 --- a/ts-packages/types/src/types/rust/Balance.ts +++ b/ts-packages/types/src/types/rust/Balance.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; export interface Balance { diff --git a/ts-packages/types/src/types/rust/Coin.ts b/ts-packages/types/src/types/rust/Coin.ts index dda00291d7..493c2e6b41 100644 --- a/ts-packages/types/src/types/rust/Coin.ts +++ b/ts-packages/types/src/types/rust/Coin.ts @@ -1,3 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + export interface Coin { denom: string; amount: bigint; diff --git a/ts-packages/types/src/types/rust/CosmosFee.ts b/ts-packages/types/src/types/rust/CosmosFee.ts index 54c0f689bc..d77c4d3dd8 100644 --- a/ts-packages/types/src/types/rust/CosmosFee.ts +++ b/ts-packages/types/src/types/rust/CosmosFee.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { Coin } from './Coin'; export interface CosmosFee { diff --git a/ts-packages/types/src/types/rust/CurrencyDenom.ts b/ts-packages/types/src/types/rust/CurrencyDenom.ts index 04760b4fd7..3e7696c28d 100644 --- a/ts-packages/types/src/types/rust/CurrencyDenom.ts +++ b/ts-packages/types/src/types/rust/CurrencyDenom.ts @@ -1 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + export type CurrencyDenom = 'unknown' | 'nym' | 'nymt' | 'nyx' | 'nyxt'; diff --git a/ts-packages/types/src/types/rust/DecCoin.ts b/ts-packages/types/src/types/rust/DecCoin.ts index d2b1b4dd69..9411bf358b 100644 --- a/ts-packages/types/src/types/rust/DecCoin.ts +++ b/ts-packages/types/src/types/rust/DecCoin.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { CurrencyDenom } from './CurrencyDenom'; export type DecCoin = { denom: CurrencyDenom; amount: string }; diff --git a/ts-packages/types/src/types/rust/Delegation.ts b/ts-packages/types/src/types/rust/Delegation.ts index 18d6df201f..58de13e6cc 100644 --- a/ts-packages/types/src/types/rust/Delegation.ts +++ b/ts-packages/types/src/types/rust/Delegation.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; export interface Delegation { diff --git a/ts-packages/types/src/types/rust/DelegationEvent.ts b/ts-packages/types/src/types/rust/DelegationEvent.ts index d9e2c0a21d..30ff21943f 100644 --- a/ts-packages/types/src/types/rust/DelegationEvent.ts +++ b/ts-packages/types/src/types/rust/DelegationEvent.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; import type { DelegationEventKind } from './DelegationEventKind'; diff --git a/ts-packages/types/src/types/rust/DelegationEventKind.ts b/ts-packages/types/src/types/rust/DelegationEventKind.ts index a1db5fac12..a242220102 100644 --- a/ts-packages/types/src/types/rust/DelegationEventKind.ts +++ b/ts-packages/types/src/types/rust/DelegationEventKind.ts @@ -1 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + export type DelegationEventKind = 'Delegate' | 'Undelegate'; diff --git a/ts-packages/types/src/types/rust/DelegationResult.ts b/ts-packages/types/src/types/rust/DelegationResult.ts index f6d29d9435..d8f8a77ce3 100644 --- a/ts-packages/types/src/types/rust/DelegationResult.ts +++ b/ts-packages/types/src/types/rust/DelegationResult.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; export interface DelegationResult { diff --git a/ts-packages/types/src/types/rust/DelegationSummaryResponse.ts b/ts-packages/types/src/types/rust/DelegationSummaryResponse.ts index 0cb9346c59..21e85d513b 100644 --- a/ts-packages/types/src/types/rust/DelegationSummaryResponse.ts +++ b/ts-packages/types/src/types/rust/DelegationSummaryResponse.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; import type { DelegationWithEverything } from './DelegationWithEverything'; diff --git a/ts-packages/types/src/types/rust/DelegationWithEverything.ts b/ts-packages/types/src/types/rust/DelegationWithEverything.ts index 0d3423a133..ecf949c5ae 100644 --- a/ts-packages/types/src/types/rust/DelegationWithEverything.ts +++ b/ts-packages/types/src/types/rust/DelegationWithEverything.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; import type { DelegationEvent } from './DelegationEvent'; import type { MixNodeCostParams } from './MixNodeCostParams'; diff --git a/ts-packages/types/src/types/rust/Fee.ts b/ts-packages/types/src/types/rust/Fee.ts index 5a7a0af56e..1e3f747e92 100644 --- a/ts-packages/types/src/types/rust/Fee.ts +++ b/ts-packages/types/src/types/rust/Fee.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { CosmosFee } from './CosmosFee'; export type Fee = { Manual: CosmosFee } | { Auto: number | null }; diff --git a/ts-packages/types/src/types/rust/FeeDetails.ts b/ts-packages/types/src/types/rust/FeeDetails.ts index 60bcd4cae5..7db283dbc1 100644 --- a/ts-packages/types/src/types/rust/FeeDetails.ts +++ b/ts-packages/types/src/types/rust/FeeDetails.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; import type { Fee } from './Fee'; diff --git a/ts-packages/types/src/types/rust/Gas.ts b/ts-packages/types/src/types/rust/Gas.ts index e207dcb1e1..2b93e47509 100644 --- a/ts-packages/types/src/types/rust/Gas.ts +++ b/ts-packages/types/src/types/rust/Gas.ts @@ -1,3 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + export interface Gas { gas_units: bigint; } diff --git a/ts-packages/types/src/types/rust/GasInfo.ts b/ts-packages/types/src/types/rust/GasInfo.ts index fd5b21e582..3e34323018 100644 --- a/ts-packages/types/src/types/rust/GasInfo.ts +++ b/ts-packages/types/src/types/rust/GasInfo.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { Gas } from './Gas'; export interface GasInfo { diff --git a/ts-packages/types/src/types/rust/Gateway.ts b/ts-packages/types/src/types/rust/Gateway.ts index 1dbba0e5ed..4c449b578d 100644 --- a/ts-packages/types/src/types/rust/Gateway.ts +++ b/ts-packages/types/src/types/rust/Gateway.ts @@ -1,3 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + export interface Gateway { host: string; mix_port: number; diff --git a/ts-packages/types/src/types/rust/GatewayBond.ts b/ts-packages/types/src/types/rust/GatewayBond.ts index 277994efac..405c1cab92 100644 --- a/ts-packages/types/src/types/rust/GatewayBond.ts +++ b/ts-packages/types/src/types/rust/GatewayBond.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; import type { Gateway } from './Gateway'; diff --git a/ts-packages/types/src/types/rust/InclusionProbabilityResponse.ts b/ts-packages/types/src/types/rust/InclusionProbabilityResponse.ts index 56d81bde41..3f80b794a0 100644 --- a/ts-packages/types/src/types/rust/InclusionProbabilityResponse.ts +++ b/ts-packages/types/src/types/rust/InclusionProbabilityResponse.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { SelectionChance } from './SelectionChance'; export interface InclusionProbabilityResponse { diff --git a/ts-packages/types/src/types/rust/Interval.ts b/ts-packages/types/src/types/rust/Interval.ts index b47687ae22..7a7fa7bb4d 100644 --- a/ts-packages/types/src/types/rust/Interval.ts +++ b/ts-packages/types/src/types/rust/Interval.ts @@ -3,6 +3,6 @@ export interface Interval { epochs_in_interval: number; current_epoch_start: string; current_epoch_id: number; - epoch_length: string; + epoch_length: { secs: number; nanos: number }; total_elapsed_epochs: number; } diff --git a/ts-packages/types/src/types/rust/MixNodeBond.ts b/ts-packages/types/src/types/rust/MixNodeBond.ts index 37059b9b61..173ce9599d 100644 --- a/ts-packages/types/src/types/rust/MixNodeBond.ts +++ b/ts-packages/types/src/types/rust/MixNodeBond.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; import type { MixNode } from './Mixnode'; diff --git a/ts-packages/types/src/types/rust/Mixnode.ts b/ts-packages/types/src/types/rust/Mixnode.ts index 0deaa5b919..8dddce4eb2 100644 --- a/ts-packages/types/src/types/rust/Mixnode.ts +++ b/ts-packages/types/src/types/rust/Mixnode.ts @@ -1,3 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + export interface MixNode { host: string; mix_port: number; diff --git a/ts-packages/types/src/types/rust/MixnodeStatus.ts b/ts-packages/types/src/types/rust/MixnodeStatus.ts index da89c7e8a7..6421988dce 100644 --- a/ts-packages/types/src/types/rust/MixnodeStatus.ts +++ b/ts-packages/types/src/types/rust/MixnodeStatus.ts @@ -1 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + export type MixnodeStatus = 'active' | 'standby' | 'inactive' | 'not_found'; diff --git a/ts-packages/types/src/types/rust/MixnodeStatusResponse.ts b/ts-packages/types/src/types/rust/MixnodeStatusResponse.ts index 2225b26df3..2dd6bb6f54 100644 --- a/ts-packages/types/src/types/rust/MixnodeStatusResponse.ts +++ b/ts-packages/types/src/types/rust/MixnodeStatusResponse.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { MixnodeStatus } from './MixnodeStatus'; export interface MixnodeStatusResponse { diff --git a/ts-packages/types/src/types/rust/OriginalVestingResponse.ts b/ts-packages/types/src/types/rust/OriginalVestingResponse.ts index 8d781d5ad0..ea10cd24af 100644 --- a/ts-packages/types/src/types/rust/OriginalVestingResponse.ts +++ b/ts-packages/types/src/types/rust/OriginalVestingResponse.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; export interface OriginalVestingResponse { diff --git a/ts-packages/types/src/types/rust/Period.ts b/ts-packages/types/src/types/rust/Period.ts index 05d9890d5f..76a8876b31 100644 --- a/ts-packages/types/src/types/rust/Period.ts +++ b/ts-packages/types/src/types/rust/Period.ts @@ -1 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + export type Period = 'Before' | { In: number } | 'After'; diff --git a/ts-packages/types/src/types/rust/PledgeData.ts b/ts-packages/types/src/types/rust/PledgeData.ts index 9fb19f9aaf..76adc23018 100644 --- a/ts-packages/types/src/types/rust/PledgeData.ts +++ b/ts-packages/types/src/types/rust/PledgeData.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; export interface PledgeData { diff --git a/ts-packages/types/src/types/rust/RewardedSetNodeStatus.ts b/ts-packages/types/src/types/rust/RewardedSetNodeStatus.ts index 8ddd13d047..5a8da8dbea 100644 --- a/ts-packages/types/src/types/rust/RewardedSetNodeStatus.ts +++ b/ts-packages/types/src/types/rust/RewardedSetNodeStatus.ts @@ -1 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + export type RewardedSetNodeStatus = 'Active' | 'Standby'; diff --git a/ts-packages/types/src/types/rust/RpcTransactionResponse.ts b/ts-packages/types/src/types/rust/RpcTransactionResponse.ts index 2463e3dd20..2f9c3bdc8a 100644 --- a/ts-packages/types/src/types/rust/RpcTransactionResponse.ts +++ b/ts-packages/types/src/types/rust/RpcTransactionResponse.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; import type { Gas } from './Gas'; diff --git a/ts-packages/types/src/types/rust/SendTxResult.ts b/ts-packages/types/src/types/rust/SendTxResult.ts index b44de3324d..02fb0b5b0c 100644 --- a/ts-packages/types/src/types/rust/SendTxResult.ts +++ b/ts-packages/types/src/types/rust/SendTxResult.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; import type { Gas } from './Gas'; import type { TransactionDetails } from './TransactionDetails'; diff --git a/ts-packages/types/src/types/rust/StakeSaturationResponse.ts b/ts-packages/types/src/types/rust/StakeSaturationResponse.ts index 038d261c46..6be2ae0e0e 100644 --- a/ts-packages/types/src/types/rust/StakeSaturationResponse.ts +++ b/ts-packages/types/src/types/rust/StakeSaturationResponse.ts @@ -1,3 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + export interface StakeSaturationResponse { saturation: string; uncapped_saturation: string; diff --git a/ts-packages/types/src/types/rust/TransactionDetails.ts b/ts-packages/types/src/types/rust/TransactionDetails.ts index 8de1cf9ec3..043db71473 100644 --- a/ts-packages/types/src/types/rust/TransactionDetails.ts +++ b/ts-packages/types/src/types/rust/TransactionDetails.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; export interface TransactionDetails { diff --git a/ts-packages/types/src/types/rust/TransactionExecuteResult.ts b/ts-packages/types/src/types/rust/TransactionExecuteResult.ts index e6d93e8448..ce06484dd1 100644 --- a/ts-packages/types/src/types/rust/TransactionExecuteResult.ts +++ b/ts-packages/types/src/types/rust/TransactionExecuteResult.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; import type { GasInfo } from './GasInfo'; diff --git a/ts-packages/types/src/types/rust/VestingAccountInfo.ts b/ts-packages/types/src/types/rust/VestingAccountInfo.ts index d317d045d1..538e941edb 100644 --- a/ts-packages/types/src/types/rust/VestingAccountInfo.ts +++ b/ts-packages/types/src/types/rust/VestingAccountInfo.ts @@ -1,3 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DecCoin } from './DecCoin'; import type { VestingPeriod } from './VestingPeriod'; diff --git a/ts-packages/types/src/types/rust/VestingPeriod.ts b/ts-packages/types/src/types/rust/VestingPeriod.ts index de1089005f..dae6901c10 100644 --- a/ts-packages/types/src/types/rust/VestingPeriod.ts +++ b/ts-packages/types/src/types/rust/VestingPeriod.ts @@ -1,3 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + export interface VestingPeriod { start_time: bigint; period_seconds: bigint; diff --git a/ts-packages/types/src/utils/decimal/index.ts b/ts-packages/types/src/utils/decimal/index.ts index 2f58196372..62807f25d6 100644 --- a/ts-packages/types/src/utils/decimal/index.ts +++ b/ts-packages/types/src/utils/decimal/index.ts @@ -10,5 +10,8 @@ export const stringToDecimal = (raw: string): Decimal => Decimal.fromUserInput(r export const decimalToPercentage = (raw: string) => Math.round(Decimal.fromUserInput(raw, 18).toFloatApproximation() * 100).toString(); +export const percentToDecimal = (raw: string) => + (Decimal.fromUserInput(raw, 18).toFloatApproximation() / 100).toString(); + export const decimalToFloatApproximation = (raw: string): number => Decimal.fromUserInput(raw, 18).toFloatApproximation(); diff --git a/validator-api/validator-api-requests/src/models.rs b/validator-api/validator-api-requests/src/models.rs index eee713a701..df5fe07768 100644 --- a/validator-api/validator-api-requests/src/models.rs +++ b/validator-api/validator-api-requests/src/models.rs @@ -114,7 +114,7 @@ impl MixNodeBondAnnotated { } } -#[derive(Deserialize, JsonSchema)] +#[derive(Debug, Serialize, Deserialize, JsonSchema)] pub struct ComputeRewardEstParam { pub performance: Option, pub active_in_rewarded_set: Option,