fix(#441): withdraw fixes
* chore: make sure etherscan links open in new tab * fix: format withdrawal amount correctly in table * fix: switch to use next Link element so page state not lost * fix: calc deposit max validation using ethereum storage at * fix: remaining amount in deposits and refetch allowance * fix: page background in dark mode * chore: disable autocomplete for ethaddress * fix: bump ag grid row size so underline is shown on FF * fix: expect correctly formatted withdrawal amount * fix: missing react keys in maps * fix: complete button text in test * fix: use sentry/react, fix webpack config path
This commit is contained in:
parent
fff924e4ca
commit
7c2a84805e
@ -18,7 +18,7 @@
|
|||||||
"assets": ["apps/token/src/favicon.ico", "apps/token/src/assets"],
|
"assets": ["apps/token/src/favicon.ico", "apps/token/src/assets"],
|
||||||
"styles": ["apps/token/src/styles.css"],
|
"styles": ["apps/token/src/styles.css"],
|
||||||
"scripts": [],
|
"scripts": [],
|
||||||
"webpackConfig": "apps/explorer/webpack.config.js"
|
"webpackConfig": "apps/token/webpack.config.js"
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
|
@ -81,9 +81,9 @@ const AssociatedAmounts = ({
|
|||||||
bold={true}
|
bold={true}
|
||||||
dark={true}
|
dark={true}
|
||||||
/>
|
/>
|
||||||
{vestingAssociationByVegaKey.map(([key, amount]) => {
|
{vestingAssociationByVegaKey.map(([key, amount], i) => {
|
||||||
return (
|
return (
|
||||||
<div data-testid="eth-wallet-associated-balances">
|
<div data-testid="eth-wallet-associated-balances" key={i}>
|
||||||
<WalletCardRow
|
<WalletCardRow
|
||||||
key={key}
|
key={key}
|
||||||
label={removeLeadingAddressSymbol(key)}
|
label={removeLeadingAddressSymbol(key)}
|
||||||
|
@ -38,7 +38,7 @@ describe('withdrawals', () => {
|
|||||||
cy.get(row)
|
cy.get(row)
|
||||||
.eq(0)
|
.eq(0)
|
||||||
.find('[col-id="amount"]')
|
.find('[col-id="amount"]')
|
||||||
.should('contain.text', '100.00000');
|
.should('contain.text', '0.00100');
|
||||||
cy.get(row)
|
cy.get(row)
|
||||||
.eq(0)
|
.eq(0)
|
||||||
.find('[col-id="details.receiverAddress"]')
|
.find('[col-id="details.receiverAddress"]')
|
||||||
@ -55,7 +55,7 @@ describe('withdrawals', () => {
|
|||||||
.find('[col-id="status"]')
|
.find('[col-id="status"]')
|
||||||
.should('contain.text', 'Open')
|
.should('contain.text', 'Open')
|
||||||
.find('button')
|
.find('button')
|
||||||
.contains('Complete');
|
.contains('Click to complete');
|
||||||
|
|
||||||
// Second row is complete so last cell should have a link to the tx
|
// Second row is complete so last cell should have a link to the tx
|
||||||
cy.get(row)
|
cy.get(row)
|
||||||
|
@ -44,7 +44,7 @@ function AppBody({ Component, pageProps }: AppProps) {
|
|||||||
<ThemeSwitcher onToggle={toggleTheme} className="-my-4" />
|
<ThemeSwitcher onToggle={toggleTheme} className="-my-4" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<main data-testid={pageProps.page}>
|
<main data-testid={pageProps.page} className="dark:bg-black">
|
||||||
{/* @ts-ignore conflict between @types/react and nextjs internal types */}
|
{/* @ts-ignore conflict between @types/react and nextjs internal types */}
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
</main>
|
</main>
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
import { t } from '@vegaprotocol/react-helpers';
|
import { t } from '@vegaprotocol/react-helpers';
|
||||||
import { AnchorButton } from '@vegaprotocol/ui-toolkit';
|
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
export const DepositsContainer = () => {
|
export const DepositsContainer = () => {
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-[1fr_min-content] gap-12 h-full">
|
<div className="grid grid-cols-[1fr_min-content] gap-12 h-full">
|
||||||
<div />
|
<div />
|
||||||
<div className="p-12">
|
<div className="p-12">
|
||||||
<AnchorButton data-testid="deposit" href="/portfolio/deposit">
|
<Link href="/portfolio/deposit" passHref={true}>
|
||||||
{t('Deposit')}
|
<Button data-testid="deposit">{t('Deposit')}</Button>
|
||||||
</AnchorButton>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -38,6 +38,7 @@ beforeEach(() => {
|
|||||||
requestFaucet: jest.fn(),
|
requestFaucet: jest.fn(),
|
||||||
limits: {
|
limits: {
|
||||||
max: new BigNumber(20),
|
max: new BigNumber(20),
|
||||||
|
deposited: new BigNumber(10),
|
||||||
},
|
},
|
||||||
allowance: new BigNumber(30),
|
allowance: new BigNumber(30),
|
||||||
isFaucetable: true,
|
isFaucetable: true,
|
||||||
@ -88,7 +89,7 @@ it('Form validation', async () => {
|
|||||||
expect(await screen.findByText('Invalid Vega key')).toBeInTheDocument();
|
expect(await screen.findByText('Invalid Vega key')).toBeInTheDocument();
|
||||||
|
|
||||||
// Max amount validation
|
// Max amount validation
|
||||||
const amountMoreThanAvailable = '11';
|
const amountMoreThanAvailable = '7'; // but also less than lifetime limit available
|
||||||
fireEvent.change(screen.getByLabelText('Amount'), {
|
fireEvent.change(screen.getByLabelText('Amount'), {
|
||||||
target: { value: amountMoreThanAvailable },
|
target: { value: amountMoreThanAvailable },
|
||||||
});
|
});
|
||||||
@ -96,7 +97,7 @@ it('Form validation', async () => {
|
|||||||
await screen.findByText('Insufficient amount in Ethereum wallet')
|
await screen.findByText('Insufficient amount in Ethereum wallet')
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
|
|
||||||
const amountMoreThanLimit = '21';
|
const amountMoreThanLimit = '11';
|
||||||
fireEvent.change(screen.getByLabelText('Amount'), {
|
fireEvent.change(screen.getByLabelText('Amount'), {
|
||||||
target: { value: amountMoreThanLimit },
|
target: { value: amountMoreThanLimit },
|
||||||
});
|
});
|
||||||
@ -104,7 +105,12 @@ it('Form validation', async () => {
|
|||||||
await screen.findByText('Amount is above permitted maximum')
|
await screen.findByText('Amount is above permitted maximum')
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
|
|
||||||
rerender(<DepositForm {...props} limits={{ max: new BigNumber(100) }} />);
|
rerender(
|
||||||
|
<DepositForm
|
||||||
|
{...props}
|
||||||
|
limits={{ max: new BigNumber(100), deposited: new BigNumber(10) }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
const amountMoreThanAllowance = '31';
|
const amountMoreThanAllowance = '31';
|
||||||
fireEvent.change(screen.getByLabelText('Amount'), {
|
fireEvent.change(screen.getByLabelText('Amount'), {
|
||||||
@ -165,8 +171,8 @@ it('Deposit', async () => {
|
|||||||
mockUseWeb3React.mockReturnValue({ account });
|
mockUseWeb3React.mockReturnValue({ account });
|
||||||
|
|
||||||
const limits = {
|
const limits = {
|
||||||
min: new BigNumber(10),
|
|
||||||
max: new BigNumber(20),
|
max: new BigNumber(20),
|
||||||
|
deposited: new BigNumber(10),
|
||||||
};
|
};
|
||||||
|
|
||||||
render(
|
render(
|
||||||
@ -181,11 +187,15 @@ it('Deposit', async () => {
|
|||||||
|
|
||||||
// Check deposit limit is displayed
|
// Check deposit limit is displayed
|
||||||
expect(
|
expect(
|
||||||
screen.getByText('Maximum', { selector: 'th' }).nextElementSibling
|
screen.getByText('Max deposit total', { selector: 'th' }).nextElementSibling
|
||||||
).toHaveTextContent(limits.max.toString());
|
).toHaveTextContent(limits.max.toString());
|
||||||
|
expect(
|
||||||
|
screen.getByText('Remaining available', { selector: 'th' })
|
||||||
|
.nextElementSibling
|
||||||
|
).toHaveTextContent(limits.max.minus(limits.deposited).toString());
|
||||||
|
|
||||||
fireEvent.change(screen.getByLabelText('Amount'), {
|
fireEvent.change(screen.getByLabelText('Amount'), {
|
||||||
target: { value: '15' },
|
target: { value: '8' },
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@ -197,7 +207,7 @@ it('Deposit', async () => {
|
|||||||
expect(props.submitDeposit).toHaveBeenCalledWith({
|
expect(props.submitDeposit).toHaveBeenCalledWith({
|
||||||
// @ts-ignore contract address definitely defined
|
// @ts-ignore contract address definitely defined
|
||||||
assetSource: asset.source.contractAddress,
|
assetSource: asset.source.contractAddress,
|
||||||
amount: '1500',
|
amount: '800',
|
||||||
vegaPublicKey: vegaKey,
|
vegaPublicKey: vegaKey,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -47,6 +47,7 @@ export interface DepositFormProps {
|
|||||||
requestFaucet: () => Promise<void>;
|
requestFaucet: () => Promise<void>;
|
||||||
limits: {
|
limits: {
|
||||||
max: BigNumber;
|
max: BigNumber;
|
||||||
|
deposited: BigNumber;
|
||||||
} | null;
|
} | null;
|
||||||
allowance: BigNumber | undefined;
|
allowance: BigNumber | undefined;
|
||||||
isFaucetable?: boolean;
|
isFaucetable?: boolean;
|
||||||
@ -97,12 +98,16 @@ export const DepositForm = ({
|
|||||||
const amount = useWatch({ name: 'amount', control });
|
const amount = useWatch({ name: 'amount', control });
|
||||||
|
|
||||||
const max = useMemo(() => {
|
const max = useMemo(() => {
|
||||||
const maxApproved = allowance ? allowance : new BigNumber(Infinity);
|
const maxApproved = allowance ? allowance : new BigNumber(0);
|
||||||
const maxAvailable = available ? available : new BigNumber(Infinity);
|
const maxAvailable = available ? available : new BigNumber(0);
|
||||||
// A max limit of zero indicates that there is no limit
|
|
||||||
|
// limits.max is a lifetime deposit limit, so the actual max value for form
|
||||||
|
// input is the max minus whats already been deposited
|
||||||
let maxLimit = new BigNumber(Infinity);
|
let maxLimit = new BigNumber(Infinity);
|
||||||
|
|
||||||
|
// A max limit of zero indicates that there is no limit
|
||||||
if (limits && limits.max.isGreaterThan(0)) {
|
if (limits && limits.max.isGreaterThan(0)) {
|
||||||
maxLimit = limits.max;
|
maxLimit = limits.max.minus(limits.deposited);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -4,6 +4,7 @@ import type BigNumber from 'bignumber.js';
|
|||||||
interface DepositLimitsProps {
|
interface DepositLimitsProps {
|
||||||
limits: {
|
limits: {
|
||||||
max: BigNumber;
|
max: BigNumber;
|
||||||
|
deposited: BigNumber;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,9 +25,21 @@ export const DepositLimits = ({ limits }: DepositLimitsProps) => {
|
|||||||
<table className="w-full text-ui">
|
<table className="w-full text-ui">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th className="text-left font-normal">{t('Maximum')}</th>
|
<th className="text-left font-normal">{t('Max deposit total')}</th>
|
||||||
<td className="text-right">{maxLimit}</td>
|
<td className="text-right">{maxLimit}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th className="text-left font-normal">{t('Deposited')}</th>
|
||||||
|
<td className="text-right">{limits.deposited.toString()}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th className="text-left font-normal">
|
||||||
|
{t('Remaining available')}
|
||||||
|
</th>
|
||||||
|
<td className="text-right">
|
||||||
|
{limits.max.minus(limits.deposited).toString()}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</>
|
</>
|
||||||
|
@ -11,7 +11,6 @@ import {
|
|||||||
EthTxStatus,
|
EthTxStatus,
|
||||||
TransactionDialog,
|
TransactionDialog,
|
||||||
useEthereumConfig,
|
useEthereumConfig,
|
||||||
useTokenDecimals,
|
|
||||||
} from '@vegaprotocol/web3';
|
} from '@vegaprotocol/web3';
|
||||||
import { useTokenContract } from '@vegaprotocol/web3';
|
import { useTokenContract } from '@vegaprotocol/web3';
|
||||||
|
|
||||||
@ -62,22 +61,23 @@ export const DepositManager = ({
|
|||||||
isFaucetable
|
isFaucetable
|
||||||
);
|
);
|
||||||
|
|
||||||
const decimals = useTokenDecimals(tokenContract);
|
|
||||||
|
|
||||||
// Get users balance of the erc20 token selected
|
// Get users balance of the erc20 token selected
|
||||||
const { balance, refetch } = useGetBalanceOfERC20Token(
|
const { balance, refetch: refetchBalance } = useGetBalanceOfERC20Token(
|
||||||
tokenContract,
|
tokenContract,
|
||||||
decimals
|
asset?.decimals
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get temporary deposit limits
|
// Get temporary deposit limits
|
||||||
const limits = useGetDepositLimits(asset, decimals);
|
const limits = useGetDepositLimits(asset);
|
||||||
|
|
||||||
// Get allowance (approved spending limit of brdige contract) for the selected asset
|
// Get allowance (approved spending limit of brdige contract) for the selected asset
|
||||||
const allowance = useGetAllowance(tokenContract, decimals);
|
const { allowance, refetch: refetchAllowance } = useGetAllowance(
|
||||||
|
tokenContract,
|
||||||
|
asset?.decimals
|
||||||
|
);
|
||||||
|
|
||||||
// Set up approve transaction
|
// Set up approve transaction
|
||||||
const approve = useSubmitApproval(tokenContract, decimals);
|
const approve = useSubmitApproval(tokenContract, asset?.decimals);
|
||||||
|
|
||||||
// Set up deposit transaction
|
// Set up deposit transaction
|
||||||
const { confirmationEvent, ...deposit } = useSubmitDeposit();
|
const { confirmationEvent, ...deposit } = useSubmitDeposit();
|
||||||
@ -91,9 +91,16 @@ export const DepositManager = ({
|
|||||||
faucet.transaction.status === EthTxStatus.Complete ||
|
faucet.transaction.status === EthTxStatus.Complete ||
|
||||||
confirmationEvent !== null
|
confirmationEvent !== null
|
||||||
) {
|
) {
|
||||||
refetch();
|
refetchBalance();
|
||||||
}
|
}
|
||||||
}, [confirmationEvent, refetch, faucet.transaction.status]);
|
}, [confirmationEvent, refetchBalance, faucet.transaction.status]);
|
||||||
|
|
||||||
|
// After an approval transaction refetch allowance
|
||||||
|
useEffect(() => {
|
||||||
|
if (approve.transaction.status === EthTxStatus.Complete) {
|
||||||
|
refetchAllowance();
|
||||||
|
}
|
||||||
|
}, [approve.transaction.status, refetchAllowance]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -19,13 +19,12 @@ export const useGetAllowance = (contract: Token | null, decimals?: number) => {
|
|||||||
);
|
);
|
||||||
}, [contract, account, config]);
|
}, [contract, account, config]);
|
||||||
|
|
||||||
const {
|
const { state, refetch } = useEthereumReadContract(getAllowance);
|
||||||
state: { data },
|
|
||||||
} = useEthereumReadContract(getAllowance);
|
|
||||||
|
|
||||||
if (!data || !decimals) return;
|
const allowance =
|
||||||
|
state.data && decimals
|
||||||
|
? new BigNumber(addDecimal(state.data.toString(), decimals))
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const allowance = new BigNumber(addDecimal(data.toString(), decimals));
|
return { allowance, refetch };
|
||||||
|
|
||||||
return allowance;
|
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,20 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { ethers } from 'ethers';
|
||||||
import type { Asset } from './deposit-manager';
|
import type { Asset } from './deposit-manager';
|
||||||
import { useBridgeContract, useEthereumReadContract } from '@vegaprotocol/web3';
|
import {
|
||||||
|
useBridgeContract,
|
||||||
|
useEthereumConfig,
|
||||||
|
useEthereumReadContract,
|
||||||
|
} from '@vegaprotocol/web3';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import { addDecimal } from '@vegaprotocol/react-helpers';
|
import { addDecimal } from '@vegaprotocol/react-helpers';
|
||||||
|
import { useWeb3React } from '@web3-react/core';
|
||||||
|
|
||||||
export const useGetDepositLimits = (asset?: Asset, decimals?: number) => {
|
export const useGetDepositLimits = (asset?: Asset) => {
|
||||||
|
const { account, provider } = useWeb3React();
|
||||||
|
const { config } = useEthereumConfig();
|
||||||
const contract = useBridgeContract(true);
|
const contract = useBridgeContract(true);
|
||||||
|
const [userTotal, setUserTotal] = useState<BigNumber | null>(null);
|
||||||
const getLimits = useCallback(async () => {
|
const getLimits = useCallback(async () => {
|
||||||
if (!contract || !asset || asset.source.__typename !== 'ERC20') {
|
if (!contract || !asset || asset.source.__typename !== 'ERC20') {
|
||||||
return;
|
return;
|
||||||
@ -14,15 +23,47 @@ export const useGetDepositLimits = (asset?: Asset, decimals?: number) => {
|
|||||||
return contract.getDepositMaximum(asset.source.contractAddress);
|
return contract.getDepositMaximum(asset.source.contractAddress);
|
||||||
}, [asset, contract]);
|
}, [asset, contract]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
!provider ||
|
||||||
|
!config ||
|
||||||
|
!account ||
|
||||||
|
!asset ||
|
||||||
|
asset.source.__typename !== 'ERC20'
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const abicoder = new ethers.utils.AbiCoder();
|
||||||
|
const innerHash = ethers.utils.keccak256(
|
||||||
|
abicoder.encode(['address', 'uint256'], [account, 4])
|
||||||
|
);
|
||||||
|
const storageLocation = ethers.utils.keccak256(
|
||||||
|
abicoder.encode(
|
||||||
|
['address', 'bytes32'],
|
||||||
|
[asset.source.contractAddress, innerHash]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
(async () => {
|
||||||
|
const res = await provider.getStorageAt(
|
||||||
|
config.collateral_bridge_contract.address,
|
||||||
|
storageLocation
|
||||||
|
);
|
||||||
|
const value = new BigNumber(res, 16).toString();
|
||||||
|
setUserTotal(new BigNumber(addDecimal(value, asset.decimals)));
|
||||||
|
})();
|
||||||
|
}, [provider, config, account, asset]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
state: { data },
|
state: { data },
|
||||||
} = useEthereumReadContract(getLimits);
|
} = useEthereumReadContract(getLimits);
|
||||||
|
|
||||||
if (!data || !decimals) return null;
|
if (!data || !userTotal || !asset) return null;
|
||||||
|
|
||||||
const max = new BigNumber(addDecimal(data.toString(), decimals));
|
const max = new BigNumber(addDecimal(data.toString(), asset.decimals));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
max: max.isEqualTo(0) ? new BigNumber(Infinity) : max,
|
max: max.isEqualTo(0) ? new BigNumber(Infinity) : max,
|
||||||
|
deposited: userTotal,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -34,7 +34,7 @@ export const AgGridThemed = ({
|
|||||||
customThemeParams?: string;
|
customThemeParams?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useContext(ThemeContext);
|
const theme = useContext(ThemeContext);
|
||||||
const defaultProps = { rowHeight: 20, headerHeight: 22 };
|
const defaultProps = { rowHeight: 22, headerHeight: 22 };
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`${className ?? ''} ${
|
className={`${className ?? ''} ${
|
||||||
|
@ -7,7 +7,7 @@ import { useCompleteWithdraw } from './use-complete-withdraw';
|
|||||||
import type { Erc20Approval } from './__generated__/Erc20Approval';
|
import type { Erc20Approval } from './__generated__/Erc20Approval';
|
||||||
import { ERC20_APPROVAL_QUERY_NEW } from './queries';
|
import { ERC20_APPROVAL_QUERY_NEW } from './queries';
|
||||||
import * as web3 from '@vegaprotocol/web3';
|
import * as web3 from '@vegaprotocol/web3';
|
||||||
import * as sentry from '@sentry/nextjs';
|
import * as sentry from '@sentry/react';
|
||||||
import type { Erc20ApprovalNew_erc20WithdrawalApproval } from './__generated__/Erc20ApprovalNew';
|
import type { Erc20ApprovalNew_erc20WithdrawalApproval } from './__generated__/Erc20ApprovalNew';
|
||||||
|
|
||||||
jest.mock('@vegaprotocol/web3', () => ({
|
jest.mock('@vegaprotocol/web3', () => ({
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { gql, useApolloClient } from '@apollo/client';
|
import { gql, useApolloClient } from '@apollo/client';
|
||||||
import { captureException } from '@sentry/nextjs';
|
import { captureException } from '@sentry/react';
|
||||||
import type {
|
import type {
|
||||||
CollateralBridge,
|
CollateralBridge,
|
||||||
CollateralBridgeNew,
|
CollateralBridgeNew,
|
||||||
|
@ -157,6 +157,7 @@ const getProps = (
|
|||||||
href={`${ethUrl}/tx/${ethTx.txHash}`}
|
href={`${ethUrl}/tx/${ethTx.txHash}`}
|
||||||
title={t('View transaction on Etherscan')}
|
title={t('View transaction on Etherscan')}
|
||||||
className="text-vega-pink dark:text-vega-yellow"
|
className="text-vega-pink dark:text-vega-yellow"
|
||||||
|
target="_blank"
|
||||||
>
|
>
|
||||||
{t('View on Etherscan')}
|
{t('View on Etherscan')}
|
||||||
</Link>
|
</Link>
|
||||||
@ -174,6 +175,7 @@ const getProps = (
|
|||||||
href={`${ethUrl}/tx/${ethTx.txHash}`}
|
href={`${ethUrl}/tx/${ethTx.txHash}`}
|
||||||
title={t('View transaction on Etherscan')}
|
title={t('View transaction on Etherscan')}
|
||||||
className="text-vega-pink dark:text-vega-yellow"
|
className="text-vega-pink dark:text-vega-yellow"
|
||||||
|
target="_blank"
|
||||||
>
|
>
|
||||||
{t('View on Etherscan')}
|
{t('View on Etherscan')}
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -112,7 +112,6 @@ export const WithdrawForm = ({
|
|||||||
</InputError>
|
</InputError>
|
||||||
)}
|
)}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={t('To (Ethereum address)')}
|
label={t('To (Ethereum address)')}
|
||||||
labelFor="ethereum-address"
|
labelFor="ethereum-address"
|
||||||
@ -121,6 +120,7 @@ export const WithdrawForm = ({
|
|||||||
<Input
|
<Input
|
||||||
{...register('to', { validate: { required, ethereumAddress } })}
|
{...register('to', { validate: { required, ethereumAddress } })}
|
||||||
id="ethereum-address"
|
id="ethereum-address"
|
||||||
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
{errors.to?.message && (
|
{errors.to?.message && (
|
||||||
<InputError intent="danger" className="mt-4">
|
<InputError intent="danger" className="mt-4">
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import { MockedProvider } from '@apollo/client/testing';
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
import { act, fireEvent, render, screen } from '@testing-library/react';
|
import { act, fireEvent, render, screen } from '@testing-library/react';
|
||||||
import { formatNumber, getDateTimeFormat } from '@vegaprotocol/react-helpers';
|
import {
|
||||||
|
addDecimalsFormatNumber,
|
||||||
|
getDateTimeFormat,
|
||||||
|
} from '@vegaprotocol/react-helpers';
|
||||||
import { WithdrawalStatus } from '@vegaprotocol/types';
|
import { WithdrawalStatus } from '@vegaprotocol/types';
|
||||||
import { generateWithdrawal } from './test-helpers';
|
import { generateWithdrawal } from './test-helpers';
|
||||||
import type {
|
import type {
|
||||||
@ -40,7 +43,7 @@ it('Renders the correct columns', async () => {
|
|||||||
const cells = screen.getAllByRole('gridcell');
|
const cells = screen.getAllByRole('gridcell');
|
||||||
const expectedValues = [
|
const expectedValues = [
|
||||||
'asset-symbol',
|
'asset-symbol',
|
||||||
formatNumber(withdrawal.amount, withdrawal.asset.decimals),
|
addDecimalsFormatNumber(withdrawal.amount, withdrawal.asset.decimals),
|
||||||
'123456\u2026123456',
|
'123456\u2026123456',
|
||||||
getDateTimeFormat().format(new Date(withdrawal.createdTimestamp)),
|
getDateTimeFormat().format(new Date(withdrawal.createdTimestamp)),
|
||||||
withdrawal.status,
|
withdrawal.status,
|
||||||
@ -73,7 +76,9 @@ describe('StatusCell', () => {
|
|||||||
render(<StatusCell {...props} />);
|
render(<StatusCell {...props} />);
|
||||||
|
|
||||||
expect(screen.getByText('Open')).toBeInTheDocument();
|
expect(screen.getByText('Open')).toBeInTheDocument();
|
||||||
fireEvent.click(screen.getByText('Complete', { selector: 'button' }));
|
fireEvent.click(
|
||||||
|
screen.getByText('Click to complete', { selector: 'button' })
|
||||||
|
);
|
||||||
expect(mockComplete).toHaveBeenCalled();
|
expect(mockComplete).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
getDateTimeFormat,
|
getDateTimeFormat,
|
||||||
t,
|
t,
|
||||||
truncateByChars,
|
truncateByChars,
|
||||||
formatNumber,
|
addDecimalsFormatNumber,
|
||||||
} from '@vegaprotocol/react-helpers';
|
} from '@vegaprotocol/react-helpers';
|
||||||
import { WithdrawalStatus } from '@vegaprotocol/types';
|
import { WithdrawalStatus } from '@vegaprotocol/types';
|
||||||
import { Link, AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
import { Link, AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
||||||
@ -39,7 +39,7 @@ export const WithdrawalsTable = ({ withdrawals }: WithdrawalsTableProps) => {
|
|||||||
headerName="Amount"
|
headerName="Amount"
|
||||||
field="amount"
|
field="amount"
|
||||||
valueFormatter={({ value, data }: ValueFormatterParams) => {
|
valueFormatter={({ value, data }: ValueFormatterParams) => {
|
||||||
return formatNumber(value, data.asset.decimals);
|
return addDecimalsFormatNumber(value, data.asset.decimals);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
@ -90,6 +90,7 @@ export const StatusCell = ({
|
|||||||
title={t('View transaction on Etherscan')}
|
title={t('View transaction on Etherscan')}
|
||||||
href={`${ethUrl}/tx/${data.txHash}`}
|
href={`${ethUrl}/tx/${data.txHash}`}
|
||||||
data-testid="etherscan-link"
|
data-testid="etherscan-link"
|
||||||
|
target="_blank"
|
||||||
>
|
>
|
||||||
{t('View on Etherscan')}
|
{t('View on Etherscan')}
|
||||||
</Link>
|
</Link>
|
||||||
@ -108,6 +109,7 @@ export const StatusCell = ({
|
|||||||
title={t('View transaction on Etherscan')}
|
title={t('View transaction on Etherscan')}
|
||||||
href={`${ethUrl}/tx/${data.txHash}`}
|
href={`${ethUrl}/tx/${data.txHash}`}
|
||||||
data-testid="etherscan-link"
|
data-testid="etherscan-link"
|
||||||
|
target="_blank"
|
||||||
>
|
>
|
||||||
{t('View on Etherscan')}
|
{t('View on Etherscan')}
|
||||||
</Link>
|
</Link>
|
||||||
@ -116,7 +118,7 @@ export const StatusCell = ({
|
|||||||
<>
|
<>
|
||||||
{t('Open')}
|
{t('Open')}
|
||||||
<button className="underline" onClick={() => complete(data.id)}>
|
<button className="underline" onClick={() => complete(data.id)}>
|
||||||
{t('Complete')}
|
{t('Click to complete')}
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -141,6 +143,7 @@ const RecipientCell = ({
|
|||||||
title={t('View on Etherscan (opens in a new tab)')}
|
title={t('View on Etherscan (opens in a new tab)')}
|
||||||
href={`${ethUrl}/address/${value}`}
|
href={`${ethUrl}/address/${value}`}
|
||||||
data-testid="etherscan-link"
|
data-testid="etherscan-link"
|
||||||
|
target="_blank"
|
||||||
>
|
>
|
||||||
{valueFormatted}
|
{valueFormatted}
|
||||||
</Link>
|
</Link>
|
||||||
|
Loading…
Reference in New Issue
Block a user