Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e71f6f0f15 | |||
| b706815802 | |||
| 5336b2aa02 | |||
| 2d2ed2740c | |||
| 6b914692d6 | |||
| 85852086ea |
@@ -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>(
|
||||||
() => ({
|
() => ({
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ export const PageMixnodeDetail: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MixnodeContextProvider mixNodeIdentityKey={id}>
|
<MixnodeContextProvider mixId={id}>
|
||||||
<PageMixnodeDetailGuard />
|
<PageMixnodeDetailGuard />
|
||||||
</MixnodeContextProvider>
|
</MixnodeContextProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
Generated
+1
-1
@@ -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,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,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,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
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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' },
|
||||||
|
|||||||
@@ -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,18 +178,29 @@ export const MockDelegationContextProvider: FC<{}> = ({ children }) => {
|
|||||||
triggerStateUpdate();
|
triggerStateUpdate();
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
|
||||||
return [
|
return {
|
||||||
{
|
logs_json: '',
|
||||||
logs_json: '',
|
data_json: '',
|
||||||
data_json: '',
|
transaction_hash: '',
|
||||||
transaction_hash: '',
|
gas_info: {
|
||||||
gas_info: {
|
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],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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}`,
|
{
|
||||||
hash: tx.transaction_hash,
|
url: `${urls(network).blockExplorer}/transaction/${tx.transaction_hash}`,
|
||||||
})),
|
hash: tx.transaction_hash,
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Console.error('Failed to undelegate', e);
|
Console.error('Failed to undelegate', e);
|
||||||
|
|||||||
Reference in New Issue
Block a user