Compare commits
1 Commits
ls
...
release/v1.1.4
| Author | SHA1 | Date | |
|---|---|---|---|
| eff1f383c3 |
Generated
+9
-9
@@ -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",
|
||||
|
||||
@@ -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<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,
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Generated
+1
-1
@@ -2862,7 +2862,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym_wallet"
|
||||
version = "1.1.2"
|
||||
version = "1.1.4"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"argon2 0.3.4",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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<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)
|
||||
}
|
||||
|
||||
@@ -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<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,
|
||||
|
||||
@@ -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}>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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 (
|
||||
<Card variant="outlined" sx={{ p: 1 }}>
|
||||
<CardContent>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography fontWeight="medium">Stake saturation</Typography>
|
||||
<Typography>{saturation || '- '}%</Typography>
|
||||
</Stack>
|
||||
<Divider sx={{ my: 1 }} />
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography fontWeight="medium">Selection probability</Typography>
|
||||
<InclusionProbability probability={computeSelectionProbability(parseInt(saturation))} />
|
||||
</Stack>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -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 (
|
||||
<Card variant="outlined" sx={{ p: 1 }}>
|
||||
<CardContent>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{tableHeader.map((header) => (
|
||||
<TableCell>
|
||||
<Typography fontWeight={header.bold ? 'bold' : 'regular'}>{header.title}</Typography>
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{tableRows.map((row) => (
|
||||
<TableRow>
|
||||
<TableCell>{row.title}</TableCell>
|
||||
<TableCell>{row.daily}</TableCell>
|
||||
<TableCell>{row.monthly}</TableCell>
|
||||
<TableCell>{row.yearly}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -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' });
|
||||
}),
|
||||
});
|
||||
@@ -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),
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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 && (
|
||||
<NodeUnbondPage bondedNode={bondedNode} onConfirm={handleUnbond} onError={handleError} />
|
||||
)}
|
||||
{value === 'Playground' && bondedNode && <ApyPlayground bondedNode={bondedNode as TBondedMixnode} />}
|
||||
{confirmationDetails && confirmationDetails.status === 'success' && (
|
||||
<ConfirmationDetailsModal
|
||||
title={confirmationDetails.title}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
import React, { useState, useEffect, useContext } from 'react';
|
||||
import { Box, Card, CardContent, CardHeader, Grid, Typography } from '@mui/material';
|
||||
import { decimalToPercentage, percentToDecimal } from '@nymproject/types';
|
||||
import { ResultsTable } from 'src/components/RewardsPlayground/ResultsTable';
|
||||
import { getDelegationSummary } from 'src/requests';
|
||||
import { NodeDetails } from 'src/components/RewardsPlayground/NodeDetail';
|
||||
import { Inputs, CalculateArgs } from 'src/components/RewardsPlayground/Inputs';
|
||||
import { AppContext, TBondedMixnode } from 'src/context';
|
||||
import { computeEstimate, computeStakeSaturation, handleCalculatePeriodRewards } from './utils';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import { LoadingModal } from 'src/components/Modals/LoadingModal';
|
||||
|
||||
export type DefaultInputValues = {
|
||||
profitMargin: string;
|
||||
uptime: string;
|
||||
bond: string;
|
||||
delegations: string;
|
||||
operatorCost: string;
|
||||
};
|
||||
|
||||
export const ApyPlayground = ({ bondedNode }: { bondedNode: TBondedMixnode }) => {
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const [results, setResults] = useState({
|
||||
total: { daily: '-', monthly: '-', yearly: '-' },
|
||||
operator: { daily: '-', monthly: '-', yearly: '-' },
|
||||
delegator: { daily: '-', monthly: '-', yearly: '-' },
|
||||
});
|
||||
|
||||
const [defaultInputValues, setDefaultInputValues] = useState<DefaultInputValues>();
|
||||
const [stakeSaturation, setStakeSaturation] = useState<string>();
|
||||
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 <LoadingModal />;
|
||||
|
||||
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 (
|
||||
<Box sx={{ p: 3 }}>
|
||||
<Typography fontWeight="medium" sx={{ mb: 1 }}>
|
||||
Playground
|
||||
</Typography>
|
||||
<Typography variant="body2" sx={{ color: 'grey.600', mb: 2 }}>
|
||||
This is your parameters playground - change the parameters below to see the node specific estimations in the
|
||||
table
|
||||
</Typography>
|
||||
{defaultInputValues && (
|
||||
<Card variant="outlined" sx={{ p: 1, mb: 3 }}>
|
||||
<CardHeader
|
||||
title={
|
||||
<Typography variant="body2" fontWeight="medium">
|
||||
Estimation calculator
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
<CardContent>
|
||||
<Inputs onCalculate={handleCalculateEstimate} defaultValues={defaultInputValues} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={8}>
|
||||
<ResultsTable results={results} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<NodeDetails saturation={stakeSaturation} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -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(),
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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<TGatewayReport>('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<RewardEstimationResponse>('compute_mixnode_reward_estimation', args);
|
||||
};
|
||||
export const getMixnodeUptime = async (mixId: number) => invokeWrapper<number>('get_mixnode_uptime', { mixId });
|
||||
|
||||
@@ -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<RewardingParams>('get_current_rewarding_parameters', {});
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
|
||||
export interface AppEnv { ADMIN_ADDRESS: string | null, SHOW_TERMINAL: string | null, ENABLE_QA_MODE: string | null, }
|
||||
export interface AppEnv {
|
||||
ADMIN_ADDRESS: string | null;
|
||||
SHOW_TERMINAL: string | null;
|
||||
ENABLE_QA_MODE: string | null;
|
||||
}
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
export type Network = "QA" | "SANDBOX" | "MAINNET";
|
||||
export type Network = 'QA' | 'SANDBOX' | 'MAINNET';
|
||||
|
||||
@@ -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, }
|
||||
export interface TauriContractStateParams {
|
||||
minimum_mixnode_pledge: DecCoin;
|
||||
minimum_gateway_pledge: DecCoin;
|
||||
minimum_mixnode_delegation: DecCoin | null;
|
||||
}
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
|
||||
export interface ValidatorUrl { url: string, name: string | null, }
|
||||
export interface ValidatorUrl {
|
||||
url: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { ValidatorUrl } from "./ValidatorUrl";
|
||||
import type { ValidatorUrl } from './ValidatorUrl';
|
||||
|
||||
export interface ValidatorUrls { urls: Array<ValidatorUrl>, }
|
||||
export interface ValidatorUrls {
|
||||
urls: Array<ValidatorUrl>;
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ export const getDesignTokens = (mode: PaletteMode): ThemeOptions => {
|
||||
].join(','),
|
||||
fontSize: 14,
|
||||
fontWeightRegular: 500,
|
||||
fontWeightMedium: 600,
|
||||
button: {
|
||||
textTransform: 'none',
|
||||
fontWeight: '600',
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -114,7 +114,7 @@ impl MixNodeBondAnnotated {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct ComputeRewardEstParam {
|
||||
pub performance: Option<Performance>,
|
||||
pub active_in_rewarded_set: Option<bool>,
|
||||
|
||||
Reference in New Issue
Block a user