Compare commits

...

6 Commits

Author SHA1 Message Date
pierre e71f6f0f15 fix(wallet): broken explorer links 2022-11-17 18:33:29 +01:00
pierre b706815802 refactor(explorer): rename mixnodeidentitykey to mixid 2022-11-17 18:33:25 +01:00
pierre 5336b2aa02 fix(wallet): explorer links 2022-11-17 18:33:17 +01:00
fmtabbara 2d2ed2740c update tauri conf version 2022-11-17 16:35:14 +00:00
fmtabbara 6b914692d6 update version number 2022-11-17 15:33:27 +00:00
fmtabbara 85852086ea fix undelegating with vesting tokens 2022-11-17 15:14:06 +00:00
15 changed files with 90 additions and 54 deletions
+12 -12
View File
@@ -36,16 +36,16 @@ export const useMixnodeContext = (): React.ContextType<typeof MixnodeContext> =>
React.useContext<MixnodeState>(MixnodeContext); React.useContext<MixnodeState>(MixnodeContext);
interface MixnodeContextProviderProps { interface MixnodeContextProviderProps {
mixNodeIdentityKey: string; mixId: string;
} }
/** /**
* Provides a state context for a mixnode by identity * Provides a state context for a mixnode by identity
* @param mixNodeIdentityKey The identity key of the mixnode * @param mixId The mixID of the mixnode
*/ */
export const MixnodeContextProvider: React.FC<MixnodeContextProviderProps> = ({ mixNodeIdentityKey, children }) => { export const MixnodeContextProvider: React.FC<MixnodeContextProviderProps> = ({ mixId, children }) => {
const [mixNode, fetchMixnodeById, clearMixnodeById] = useApiState<MixNodeResponseItem | undefined>( const [mixNode, fetchMixnodeById, clearMixnodeById] = useApiState<MixNodeResponseItem | undefined>(
mixNodeIdentityKey, mixId,
Api.fetchMixnodeByID, Api.fetchMixnodeByID,
'Failed to fetch mixnode by id', 'Failed to fetch mixnode by id',
); );
@@ -53,44 +53,44 @@ export const MixnodeContextProvider: React.FC<MixnodeContextProviderProps> = ({
const [mixNodeRow, setMixnodeRow] = React.useState<MixnodeRowType | undefined>(); const [mixNodeRow, setMixnodeRow] = React.useState<MixnodeRowType | undefined>();
const [delegations, fetchDelegations, clearDelegations] = useApiState<DelegationsResponse>( const [delegations, fetchDelegations, clearDelegations] = useApiState<DelegationsResponse>(
mixNodeIdentityKey, mixId,
Api.fetchDelegationsById, Api.fetchDelegationsById,
'Failed to fetch delegations for mixnode', 'Failed to fetch delegations for mixnode',
); );
const [uniqDelegations, fetchUniqDelegations, clearUniqDelegations] = useApiState<UniqDelegationsResponse>( const [uniqDelegations, fetchUniqDelegations, clearUniqDelegations] = useApiState<UniqDelegationsResponse>(
mixNodeIdentityKey, mixId,
Api.fetchUniqDelegationsById, Api.fetchUniqDelegationsById,
'Failed to fetch delegations for mixnode', 'Failed to fetch delegations for mixnode',
); );
const [status, fetchStatus, clearStatus] = useApiState<StatusResponse>( const [status, fetchStatus, clearStatus] = useApiState<StatusResponse>(
mixNodeIdentityKey, mixId,
Api.fetchStatusById, Api.fetchStatusById,
'Failed to fetch mixnode status', 'Failed to fetch mixnode status',
); );
const [stats, fetchStats, clearStats] = useApiState<StatsResponse>( const [stats, fetchStats, clearStats] = useApiState<StatsResponse>(
mixNodeIdentityKey, mixId,
Api.fetchStatsById, Api.fetchStatsById,
'Failed to fetch mixnode stats', 'Failed to fetch mixnode stats',
); );
const [description, fetchDescription, clearDescription] = useApiState<MixNodeDescriptionResponse>( const [description, fetchDescription, clearDescription] = useApiState<MixNodeDescriptionResponse>(
mixNodeIdentityKey, mixId,
Api.fetchMixnodeDescriptionById, Api.fetchMixnodeDescriptionById,
'Failed to fetch mixnode description', 'Failed to fetch mixnode description',
); );
const [economicDynamicsStats, fetchEconomicDynamicsStats, clearEconomicDynamicsStats] = const [economicDynamicsStats, fetchEconomicDynamicsStats, clearEconomicDynamicsStats] =
useApiState<MixNodeEconomicDynamicsStatsResponse>( useApiState<MixNodeEconomicDynamicsStatsResponse>(
mixNodeIdentityKey, mixId,
Api.fetchMixnodeEconomicDynamicsStatsById, Api.fetchMixnodeEconomicDynamicsStatsById,
'Failed to fetch mixnode dynamics stats by id', 'Failed to fetch mixnode dynamics stats by id',
); );
const [uptimeStory, fetchUptimeHistory, clearUptimeHistory] = useApiState<UptimeStoryResponse>( const [uptimeStory, fetchUptimeHistory, clearUptimeHistory] = useApiState<UptimeStoryResponse>(
mixNodeIdentityKey, mixId,
Api.fetchUptimeStoryById, Api.fetchUptimeStoryById,
'Failed to fetch mixnode uptime history', 'Failed to fetch mixnode uptime history',
); );
@@ -123,7 +123,7 @@ export const MixnodeContextProvider: React.FC<MixnodeContextProviderProps> = ({
fetchUptimeHistory(), fetchUptimeHistory(),
]); ]);
}); });
}, [mixNodeIdentityKey]); }, [mixId]);
const state = React.useMemo<MixnodeState>( const state = React.useMemo<MixnodeState>(
() => ({ () => ({
+1 -1
View File
@@ -223,7 +223,7 @@ export const PageMixnodeDetail: React.FC = () => {
} }
return ( return (
<MixnodeContextProvider mixNodeIdentityKey={id}> <MixnodeContextProvider mixId={id}>
<PageMixnodeDetailGuard /> <PageMixnodeDetailGuard />
</MixnodeContextProvider> </MixnodeContextProvider>
); );
+1 -1
View File
@@ -2877,7 +2877,7 @@ dependencies = [
[[package]] [[package]]
name = "nym_wallet" name = "nym_wallet"
version = "1.1.0" version = "1.1.1"
dependencies = [ dependencies = [
"aes-gcm", "aes-gcm",
"argon2 0.3.4", "argon2 0.3.4",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@nymproject/nym-wallet-app", "name": "@nymproject/nym-wallet-app",
"version": "1.0.0", "version": "1.1.1",
"main": "index.js", "main": "index.js",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym_wallet" name = "nym_wallet"
version = "1.1.0" version = "1.1.1"
description = "Nym Native Wallet" description = "Nym Native Wallet"
authors = ["Nym Technologies SA"] authors = ["Nym Technologies SA"]
license = "" license = ""
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"package": { "package": {
"productName": "nym-wallet", "productName": "nym-wallet",
"version": "1.1.0" "version": "1.1.1"
}, },
"build": { "build": {
"distDir": "../dist", "distDir": "../dist",
@@ -91,7 +91,7 @@ export const BondedGateway = ({
{network && ( {network && (
<Typography sx={{ mt: 2, fontSize: 'small' }}> <Typography sx={{ mt: 2, fontSize: 'small' }}>
Check more stats of your gateway on the{' '} Check more stats of your gateway on the{' '}
<Link href={`${urls(network).networkExplorer}/network-components/gateways`} target="_blank"> <Link href={`${urls(network).networkExplorer}/network-components/gateway/${identityKey}`} target="_blank">
explorer explorer
</Link> </Link>
</Typography> </Typography>
@@ -66,6 +66,7 @@ export const BondedMixnode = ({
const navigate = useNavigate(); const navigate = useNavigate();
const { const {
name, name,
mixId,
stake, stake,
bond, bond,
stakeSaturation, stakeSaturation,
@@ -165,7 +166,7 @@ export const BondedMixnode = ({
{network && ( {network && (
<Typography sx={{ mt: 2, fontSize: 'small' }}> <Typography sx={{ mt: 2, fontSize: 'small' }}>
Check more stats of your node on the{' '} Check more stats of your node on the{' '}
<Link href={`${urls(network).networkExplorer}/network-components/mixnodes`} target="_blank"> <Link href={`${urls(network).networkExplorer}/network-components/mixnode/${mixId}`} target="_blank">
explorer explorer
</Link> </Link>
</Typography> </Typography>
@@ -45,7 +45,7 @@ export const DelegationItem = ({
) : ( ) : (
<Link <Link
target="_blank" target="_blank"
href={`${explorerUrl}/network-components/mixnode/${item.node_identity}`} href={`${explorerUrl}/network-components/mixnode/${item.mix_id}`}
text={`${item.node_identity.slice(0, 6)}...${item.node_identity.slice(-6)}`} text={`${item.node_identity.slice(0, 6)}...${item.node_identity.slice(-6)}`}
color="text.primary" color="text.primary"
noIcon noIcon
@@ -8,7 +8,7 @@ export const PendingDelegationItem = ({ item, explorerUrl }: { item: WrappedDele
<TableCell> <TableCell>
<Link <Link
target="_blank" target="_blank"
href={`${explorerUrl}/network-components/mixnode/${item.node_identity}`} href={`${explorerUrl}/network-components/mixnode/${item.event.mix_id}`}
text={`${item.node_identity.slice(0, 6)}...${item.node_identity.slice(-6)}`} text={`${item.node_identity.slice(0, 6)}...${item.node_identity.slice(-6)}`}
color="text.primary" color="text.primary"
noIcon noIcon
+2
View File
@@ -48,6 +48,7 @@ import {
export type TBondedMixnode = { export type TBondedMixnode = {
name?: string; name?: string;
mixId: number;
identityKey: string; identityKey: string;
stake: DecCoin; stake: DecCoin;
bond: DecCoin; bond: DecCoin;
@@ -266,6 +267,7 @@ export const BondingContextProvider = ({ children }: { children?: React.ReactNod
const routingScore = await getAvgUptime(); const routingScore = await getAvgUptime();
setBondedNode({ setBondedNode({
name: nodeDescription?.name, name: nodeDescription?.name,
mixId: mix_id,
identityKey: bond_information.mix_node.identity_key, identityKey: bond_information.mix_node.identity_key,
stake: { stake: {
amount: calculateStake(rewarding_details.operator, rewarding_details.delegates), amount: calculateStake(rewarding_details.operator, rewarding_details.delegates),
+16 -9
View File
@@ -1,14 +1,20 @@
import React, { createContext, FC, useCallback, useContext, useEffect, useMemo, useState } from 'react'; import React, { createContext, FC, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { getDelegationSummary, undelegateAllFromMixnode } from 'src/requests/delegation'; import { getDelegationSummary, undelegateAllFromMixnode, undelegateFromMixnode } from 'src/requests/delegation';
import { import {
DelegationWithEverything, DelegationWithEverything,
FeeDetails, FeeDetails,
DecCoin, DecCoin,
TransactionExecuteResult, TransactionExecuteResult,
WrappedDelegationEvent, WrappedDelegationEvent,
Fee,
} from '@nymproject/types'; } from '@nymproject/types';
import type { Network } from 'src/types'; import type { Network } from 'src/types';
import { delegateToMixnode, getAllPendingDelegations, vestingDelegateToMixnode } from 'src/requests'; import {
delegateToMixnode,
getAllPendingDelegations,
vestingDelegateToMixnode,
vestingUndelegateFromMixnode,
} from 'src/requests';
import { TPoolOption } from 'src/components'; import { TPoolOption } from 'src/components';
import { decCoinToDisplay } from 'src/utils'; import { decCoinToDisplay } from 'src/utils';
@@ -25,11 +31,8 @@ export type TDelegationContext = {
tokenPool: TPoolOption, tokenPool: TPoolOption,
fee?: FeeDetails, fee?: FeeDetails,
) => Promise<TransactionExecuteResult>; ) => Promise<TransactionExecuteResult>;
undelegate: ( undelegate: (mix_id: number, fee?: Fee) => Promise<TransactionExecuteResult>;
mix_id: number, undelegateVesting: (mix_id: number) => Promise<TransactionExecuteResult>;
usesVestingContractTokens: boolean,
fee?: FeeDetails,
) => Promise<TransactionExecuteResult[]>;
}; };
export type TDelegationTransaction = { export type TDelegationTransaction = {
@@ -51,7 +54,10 @@ export const DelegationContext = createContext<TDelegationContext>({
addDelegation: async () => { addDelegation: async () => {
throw new Error('Not implemented'); throw new Error('Not implemented');
}, },
undelegate: async () => { undelegate: () => {
throw new Error('Not implemented');
},
undelegateVesting: () => {
throw new Error('Not implemented'); throw new Error('Not implemented');
}, },
}); });
@@ -135,7 +141,8 @@ export const DelegationContextProvider: FC<{
totalRewards, totalRewards,
refresh, refresh,
addDelegation, addDelegation,
undelegate: undelegateAllFromMixnode, undelegate: undelegateFromMixnode,
undelegateVesting: vestingUndelegateFromMixnode,
}), }),
[isLoading, error, delegations, pendingDelegations, totalDelegations], [isLoading, error, delegations, pendingDelegations, totalDelegations],
); );
+1
View File
@@ -8,6 +8,7 @@ const SLEEP_MS = 1000;
const bondedMixnodeMock: TBondedMixnode = { const bondedMixnodeMock: TBondedMixnode = {
name: 'Monster node', name: 'Monster node',
mixId: 1,
identityKey: '7mjM2fYbtN6kxMwp1TrmQ4VwPks3URR5pBgWPWhzT98F', identityKey: '7mjM2fYbtN6kxMwp1TrmQ4VwPks3URR5pBgWPWhzT98F',
stake: { denom: 'nym', amount: '1234' }, stake: { denom: 'nym', amount: '1234' },
bond: { denom: 'nym', amount: '1234' }, bond: { denom: 'nym', amount: '1234' },
+25 -10
View File
@@ -1,5 +1,12 @@
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { DelegationWithEverything, DecCoin, TransactionExecuteResult, FeeDetails } from '@nymproject/types'; import {
DelegationWithEverything,
DecCoin,
TransactionExecuteResult,
FeeDetails,
Fee,
CurrencyDenom,
} from '@nymproject/types';
import { DelegationContext, TDelegationTransaction } from '../delegations'; import { DelegationContext, TDelegationTransaction } from '../delegations';
import { mockSleep } from './utils'; import { mockSleep } from './utils';
@@ -154,11 +161,7 @@ export const MockDelegationContextProvider: FC<{}> = ({ children }) => {
}; };
}; };
const undelegate = async ( const undelegate = async (mix_id: number, _fee?: Fee): Promise<TransactionExecuteResult> => {
mix_id: number,
_usesVestingContractTokens: boolean,
_fee?: FeeDetails,
): Promise<TransactionExecuteResult[]> => {
await mockSleep(SLEEP_MS); await mockSleep(SLEEP_MS);
mockDelegations = mockDelegations.map((d) => { mockDelegations = mockDelegations.map((d) => {
if (d.mix_id === mix_id) { if (d.mix_id === mix_id) {
@@ -175,8 +178,7 @@ export const MockDelegationContextProvider: FC<{}> = ({ children }) => {
triggerStateUpdate(); triggerStateUpdate();
}, 3000); }, 3000);
return [ return {
{
logs_json: '', logs_json: '',
data_json: '', data_json: '',
transaction_hash: '', transaction_hash: '',
@@ -184,9 +186,21 @@ export const MockDelegationContextProvider: FC<{}> = ({ children }) => {
gas_wanted: { gas_units: BigInt(1) }, gas_wanted: { gas_units: BigInt(1) },
gas_used: { gas_units: BigInt(1) }, gas_used: { gas_units: BigInt(1) },
}, },
fee: { amount: '1', denom: 'nym' }, fee: { amount: '1', denom: 'nym' as CurrencyDenom },
};
};
const undelegateVesting = async (mix_id: number, _fee?: FeeDetails) => {
return {
logs_json: '',
data_json: '',
transaction_hash: '',
gas_info: {
gas_wanted: { gas_units: BigInt(1) },
gas_used: { gas_units: BigInt(1) },
}, },
]; fee: { amount: '1', denom: 'nym' as CurrencyDenom },
};
}; };
const resetState = () => { const resetState = () => {
@@ -226,6 +240,7 @@ export const MockDelegationContextProvider: FC<{}> = ({ children }) => {
addDelegation, addDelegation,
updateDelegation, updateDelegation,
undelegate, undelegate,
undelegateVesting,
}), }),
[isLoading, error, delegations, totalDelegations, trigger], [isLoading, error, delegations, totalDelegations, trigger],
); );
+15 -5
View File
@@ -52,6 +52,7 @@ export const Delegation: FC<{ isStorybook?: boolean }> = ({ isStorybook }) => {
isLoading, isLoading,
addDelegation, addDelegation,
undelegate, undelegate,
undelegateVesting,
refresh: refreshDelegations, refresh: refreshDelegations,
} = useDelegationContext(); } = useDelegationContext();
@@ -206,7 +207,8 @@ export const Delegation: FC<{ isStorybook?: boolean }> = ({ isStorybook }) => {
const handleUndelegate = async ( const handleUndelegate = async (
mixId: number, mixId: number,
identityKey: string, // identityKey is no longer used
_: string,
usesVestingContractTokens: boolean, usesVestingContractTokens: boolean,
fee?: FeeDetails, fee?: FeeDetails,
) => { ) => {
@@ -216,19 +218,27 @@ export const Delegation: FC<{ isStorybook?: boolean }> = ({ isStorybook }) => {
}); });
setShowUndelegateModal(false); setShowUndelegateModal(false);
setCurrentDelegationListActionItem(undefined); setCurrentDelegationListActionItem(undefined);
let tx;
try { try {
const txs = await undelegate(mixId, usesVestingContractTokens, fee); if (usesVestingContractTokens) {
tx = await undelegateVesting(mixId);
} else {
tx = await undelegate(mixId, fee?.fee);
}
// const txs = await undelegate(mixId, usesVestingContractTokens, fee);
const balances = await getAllBalances(); const balances = await getAllBalances();
setConfirmationModalProps({ setConfirmationModalProps({
status: 'success', status: 'success',
action: 'undelegate', action: 'undelegate',
...balances, ...balances,
transactions: txs.map((tx) => ({ transactions: [
{
url: `${urls(network).blockExplorer}/transaction/${tx.transaction_hash}`, url: `${urls(network).blockExplorer}/transaction/${tx.transaction_hash}`,
hash: tx.transaction_hash, hash: tx.transaction_hash,
})), },
],
}); });
} catch (e) { } catch (e) {
Console.error('Failed to undelegate', e); Console.error('Failed to undelegate', e);