fix(explorer): refactor chain event view error handling (#2233)
* feat(explorer): change chain event tx error handling
This commit is contained in:
parent
af7a5630ac
commit
96843cd2be
@ -0,0 +1,453 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import type { BlockExplorerTransactionResult } from '../../../../routes/types/block-explorer-response';
|
||||
|
||||
import { ChainEvent } from '.';
|
||||
|
||||
const baseMock: Partial<BlockExplorerTransactionResult> = {
|
||||
block: '1',
|
||||
index: 1,
|
||||
hash: '123',
|
||||
submitter: '123',
|
||||
type: '1',
|
||||
code: 1,
|
||||
cursor: '1',
|
||||
};
|
||||
|
||||
jest.mock('./tx-builtin-deposit', () => ({
|
||||
TxDetailsChainEventBuiltinDeposit: () => (
|
||||
<span>TxDetailsChainEventBuiltinDeposit</span>
|
||||
),
|
||||
}));
|
||||
jest.mock('./tx-builtin-withdrawal', () => ({
|
||||
TxDetailsChainEventBuiltinWithdrawal: () => (
|
||||
<span>TxDetailsChainEventBuiltinWithdrawal</span>
|
||||
),
|
||||
}));
|
||||
jest.mock('./tx-erc20-deposit', () => ({
|
||||
TxDetailsChainEventDeposit: () => <span>TxDetailsChainEventDeposit</span>,
|
||||
}));
|
||||
jest.mock('./tx-erc20-withdrawal', () => ({
|
||||
TxDetailsChainEventWithdrawal: () => (
|
||||
<span>TxDetailsChainEventWithdrawal</span>
|
||||
),
|
||||
}));
|
||||
jest.mock('./tx-erc20-asset-list', () => ({
|
||||
TxDetailsChainEventErc20AssetList: () => (
|
||||
<span>TxDetailsChainEventErc20AssetList</span>
|
||||
),
|
||||
}));
|
||||
jest.mock('./tx-erc20-asset-delist', () => ({
|
||||
TxDetailsChainEventErc20AssetDelist: () => (
|
||||
<span>TxDetailsChainEventErc20AssetDelist</span>
|
||||
),
|
||||
}));
|
||||
jest.mock('./tx-erc20-asset-limits-updated', () => ({
|
||||
TxDetailsChainEventErc20AssetLimitsUpdated: () => (
|
||||
<span>TxDetailsChainEventErc20LimitsUpdated</span>
|
||||
),
|
||||
}));
|
||||
jest.mock('./tx-erc20-bridge-pause', () => ({
|
||||
TxDetailsChainEventErc20BridgePause: () => (
|
||||
<span>TxDetailsChainEventErc20BridgeEvent</span>
|
||||
),
|
||||
}));
|
||||
jest.mock('./tx-multisig-signer', () => ({
|
||||
TxDetailsChainMultisigSigner: () => <span>TxDetailsChainMultisigSigner</span>,
|
||||
}));
|
||||
jest.mock('./tx-multisig-threshold', () => ({
|
||||
TxDetailsChainMultisigThreshold: () => (
|
||||
<span>TxDetailsChainMultisigThreshold</span>
|
||||
),
|
||||
}));
|
||||
jest.mock('./tx-stake-deposit', () => ({
|
||||
TxDetailsChainEventStakeDeposit: () => (
|
||||
<span>TxDetailsChainStakeDeposit</span>
|
||||
),
|
||||
}));
|
||||
jest.mock('./tx-stake-remove', () => ({
|
||||
TxDetailsChainEventStakeRemove: () => <span>TxDetailsChainStakeRemove</span>,
|
||||
}));
|
||||
jest.mock('./tx-stake-totalsupply', () => ({
|
||||
TxDetailsChainEventStakeTotalSupply: () => (
|
||||
<span>TxDetailsChainStakeTotalSupply</span>
|
||||
),
|
||||
}));
|
||||
|
||||
describe('Chain Event: Chain Event selects the right component for the event', () => {
|
||||
it('Returns a Built In Deposit event for a built in deposit', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
builtin: {
|
||||
deposit: {
|
||||
amount: '',
|
||||
partyId: '',
|
||||
vegaAssetId: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(screen.getByText('TxDetailsChainEventBuiltinDeposit')).toBeVisible();
|
||||
});
|
||||
|
||||
it('Returns a Built In Deposit event for a built in withdrawal', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
builtin: {
|
||||
withdrawal: {
|
||||
amount: '',
|
||||
partyId: '',
|
||||
vegaAssetId: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(
|
||||
screen.getByText('TxDetailsChainEventBuiltinWithdrawal')
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
it('Returns a Built In Deposit event for an ERC20 deposit', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
erc20: {
|
||||
deposit: {
|
||||
amount: '',
|
||||
targetPartyId: '',
|
||||
sourceEthereumAddress: '',
|
||||
vegaAssetId: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(screen.getByText('TxDetailsChainEventDeposit')).toBeVisible();
|
||||
});
|
||||
|
||||
it('Returns a Built In Deposit event for an ERC20 withdrawal', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
erc20: {
|
||||
withdrawal: {
|
||||
referenceNonce: '',
|
||||
targetEthereumAddress: '',
|
||||
vegaAssetId: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(screen.getByText('TxDetailsChainEventWithdrawal')).toBeVisible();
|
||||
});
|
||||
|
||||
it('Returns a Asset List event view for a list', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
erc20: {
|
||||
assetList: {
|
||||
assetSource: '',
|
||||
vegaAssetId: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(screen.getByText('TxDetailsChainEventErc20AssetList')).toBeVisible();
|
||||
});
|
||||
|
||||
it('Returns a Asset Delist event view for a delist', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
erc20: {
|
||||
assetDelist: {
|
||||
vegaAssetId: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(
|
||||
screen.getByText('TxDetailsChainEventErc20AssetDelist')
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
it('Returns a Asset Limits Update event view for a update', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
erc20: {
|
||||
assetLimitsUpdated: {
|
||||
lifetimeLimits: '100',
|
||||
withdrawThreshold: '100',
|
||||
vegaAssetId: '',
|
||||
sourceEthereumAddress: '0x000',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(
|
||||
screen.getByText('TxDetailsChainEventErc20LimitsUpdated')
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
it('Returns a Bridge Pause event view when a pause event happens', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
erc20: {
|
||||
bridgeStopped: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(
|
||||
screen.getByText('TxDetailsChainEventErc20BridgeEvent')
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
it('Returns a Bridge Pause event view when a resume event happens', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
erc20: {
|
||||
bridgeResumed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(
|
||||
screen.getByText('TxDetailsChainEventErc20BridgeEvent')
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
it('Returns a multsig signer view when a multisig signer is added', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
erc20Multisig: {
|
||||
signerAdded: {
|
||||
blockTime: '100',
|
||||
newSigner: '0x000',
|
||||
nonce: '123',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(screen.getByText('TxDetailsChainMultisigSigner')).toBeVisible();
|
||||
});
|
||||
|
||||
it('Returns a multsig signer view when a multisig signer is removed', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
erc20Multisig: {
|
||||
signerRemoved: {
|
||||
blockTime: '100',
|
||||
oldSigner: '0x000',
|
||||
nonce: '123',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(screen.getByText('TxDetailsChainMultisigSigner')).toBeVisible();
|
||||
});
|
||||
|
||||
it('Returns a multsig signer view when a multisig threshold change event occurs', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
erc20Multisig: {
|
||||
thresholdSet: {
|
||||
blockTime: '100',
|
||||
newThreshold: 100,
|
||||
nonce: '123',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(screen.getByText('TxDetailsChainMultisigThreshold')).toBeVisible();
|
||||
});
|
||||
|
||||
it('Returns a stake deposit view when a stake arrives', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
stakingEvent: {
|
||||
stakeDeposited: {
|
||||
blockTime: '100',
|
||||
amount: '100',
|
||||
vegaPublicKey: '12345',
|
||||
ethereumAddress: '0x123',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(screen.getByText('TxDetailsChainStakeDeposit')).toBeVisible();
|
||||
});
|
||||
|
||||
it('Returns a stake removed view when a stake goes', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
stakingEvent: {
|
||||
stakeRemoved: {
|
||||
blockTime: '100',
|
||||
amount: '100',
|
||||
vegaPublicKey: '12345',
|
||||
ethereumAddress: '0x123',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(screen.getByText('TxDetailsChainStakeRemove')).toBeVisible();
|
||||
});
|
||||
|
||||
it('Returns a stake total supply view when the supply of the staking asset changes', () => {
|
||||
const commandMock: Partial<BlockExplorerTransactionResult> = {
|
||||
command: {
|
||||
chainEvent: {
|
||||
stakingEvent: {
|
||||
totalSupply: {
|
||||
totalSupply: '12345',
|
||||
tokenAddress: '0x123',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = Object.assign(
|
||||
{},
|
||||
baseMock,
|
||||
commandMock
|
||||
) as BlockExplorerTransactionResult;
|
||||
|
||||
const screen = render(<ChainEvent txData={mock} />);
|
||||
expect(screen.getByText('TxDetailsChainStakeTotalSupply')).toBeVisible();
|
||||
});
|
||||
});
|
@ -1,10 +1,10 @@
|
||||
import { TxDetailsChainMultisigThreshold } from './tx-multisig-threshold';
|
||||
import { TxDetailsChainMultisigSigner } from './tx-multisig-signer';
|
||||
import { TxDetailsChainEventBuiltinDeposit } from './tx-builtin-deposit';
|
||||
import { TxDetailsChainEventBuiltinWithdrawal } from './tx-builtin-withdrawal';
|
||||
import { TxDetailsChainEventStakeDeposit } from './tx-stake-deposit';
|
||||
import { TxDetailsChainEventStakeRemove } from './tx-stake-remove';
|
||||
import { TxDetailsChainEventStakeTotalSupply } from './tx-stake-totalsupply';
|
||||
import { TxDetailsChainEventBuiltinWithdrawal } from './tx-builtin-withdrawal';
|
||||
import { TxDetailsChainMultisigThreshold } from './tx-multisig-threshold';
|
||||
import { TxDetailsChainMultisigSigner } from './tx-multisig-signer';
|
||||
import { TxDetailsChainEventErc20AssetList } from './tx-erc20-asset-list';
|
||||
import { TxDetailsChainEventErc20AssetLimitsUpdated } from './tx-erc20-asset-limits-updated';
|
||||
import { TxDetailsChainEventErc20BridgePause } from './tx-erc20-bridge-pause';
|
||||
@ -13,6 +13,8 @@ import { TxDetailsChainEventDeposit } from './tx-erc20-deposit';
|
||||
import isUndefined from 'lodash/isUndefined';
|
||||
|
||||
import type { BlockExplorerTransactionResult } from '../../../../routes/types/block-explorer-response';
|
||||
import { TxDetailsChainEventWithdrawal } from './tx-erc20-withdrawal';
|
||||
import { TxDetailsChainEventErc20AssetDelist } from './tx-erc20-asset-delist';
|
||||
|
||||
interface ChainEventProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
@ -32,54 +34,58 @@ interface ChainEventProps {
|
||||
* @returns React.JSXElement
|
||||
*/
|
||||
export const ChainEvent = ({ txData }: ChainEventProps) => {
|
||||
const e = txData?.command.chainEvent;
|
||||
if (!e) {
|
||||
if (!txData?.command.chainEvent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { builtin, erc20, erc20Multisig, stakingEvent } =
|
||||
txData.command.chainEvent;
|
||||
|
||||
// Builtin Asset events
|
||||
if (e.builtin) {
|
||||
if (e.builtin.deposit) {
|
||||
return <TxDetailsChainEventBuiltinDeposit deposit={e.builtin.deposit} />;
|
||||
if (builtin) {
|
||||
if (builtin.deposit) {
|
||||
return <TxDetailsChainEventBuiltinDeposit deposit={builtin.deposit} />;
|
||||
}
|
||||
|
||||
if (e.builtin?.withdrawal) {
|
||||
if (builtin?.withdrawal) {
|
||||
return (
|
||||
<TxDetailsChainEventBuiltinWithdrawal
|
||||
withdrawal={e.builtin?.withdrawal}
|
||||
withdrawal={builtin?.withdrawal}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ERC20 asset events
|
||||
if (e.erc20) {
|
||||
if (e.erc20.deposit) {
|
||||
return <TxDetailsChainEventDeposit deposit={e.erc20.deposit} />;
|
||||
if (erc20) {
|
||||
if (erc20.deposit) {
|
||||
return <TxDetailsChainEventDeposit deposit={erc20.deposit} />;
|
||||
}
|
||||
|
||||
if (e.erc20.withdrawal) {
|
||||
if (erc20.withdrawal) {
|
||||
return <TxDetailsChainEventWithdrawal withdrawal={erc20.withdrawal} />;
|
||||
}
|
||||
|
||||
if (erc20.assetList) {
|
||||
return <TxDetailsChainEventErc20AssetList assetList={erc20.assetList} />;
|
||||
}
|
||||
|
||||
if (erc20.assetDelist) {
|
||||
return (
|
||||
<TxDetailsChainEventBuiltinWithdrawal withdrawal={e.erc20.withdrawal} />
|
||||
<TxDetailsChainEventErc20AssetDelist assetDelist={erc20.assetDelist} />
|
||||
);
|
||||
}
|
||||
|
||||
if (e.erc20.assetList) {
|
||||
return (
|
||||
<TxDetailsChainEventErc20AssetList assetList={e.erc20.assetList} />
|
||||
);
|
||||
}
|
||||
|
||||
if (e.erc20.assetLimitsUpdated) {
|
||||
if (erc20.assetLimitsUpdated) {
|
||||
return (
|
||||
<TxDetailsChainEventErc20AssetLimitsUpdated
|
||||
assetLimitsUpdated={e.erc20.assetLimitsUpdated}
|
||||
assetLimitsUpdated={erc20.assetLimitsUpdated}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const bridgeStopped = e.erc20.bridgeStopped;
|
||||
const bridgeResumed = e.erc20.bridgeResumed;
|
||||
const bridgeStopped = erc20.bridgeStopped;
|
||||
const bridgeResumed = erc20.bridgeResumed;
|
||||
if (!isUndefined(bridgeStopped) || !isUndefined(bridgeResumed)) {
|
||||
const isPaused = bridgeStopped === false || bridgeResumed === true;
|
||||
return <TxDetailsChainEventErc20BridgePause isPaused={isPaused} />;
|
||||
@ -87,48 +93,48 @@ export const ChainEvent = ({ txData }: ChainEventProps) => {
|
||||
}
|
||||
|
||||
// ERC20 multisig events
|
||||
if (e.erc20Multisig) {
|
||||
if (e.erc20Multisig.thresholdSet) {
|
||||
if (erc20Multisig) {
|
||||
if (erc20Multisig.thresholdSet) {
|
||||
return (
|
||||
<TxDetailsChainMultisigThreshold
|
||||
thresholdSet={e.erc20Multisig.thresholdSet}
|
||||
thresholdSet={erc20Multisig.thresholdSet}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (e.erc20Multisig.signerAdded) {
|
||||
if (erc20Multisig.signerAdded) {
|
||||
return (
|
||||
<TxDetailsChainMultisigSigner signer={e.erc20Multisig.signerAdded} />
|
||||
<TxDetailsChainMultisigSigner signer={erc20Multisig.signerAdded} />
|
||||
);
|
||||
}
|
||||
|
||||
if (e.erc20Multisig.signerRemoved) {
|
||||
if (erc20Multisig.signerRemoved) {
|
||||
return (
|
||||
<TxDetailsChainMultisigSigner signer={e.erc20Multisig.signerRemoved} />
|
||||
<TxDetailsChainMultisigSigner signer={erc20Multisig.signerRemoved} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Staking events
|
||||
if (e.stakingEvent) {
|
||||
if (e.stakingEvent.stakeDeposited) {
|
||||
if (stakingEvent) {
|
||||
if (stakingEvent.stakeDeposited) {
|
||||
return (
|
||||
<TxDetailsChainEventStakeDeposit
|
||||
deposit={e.stakingEvent.stakeDeposited}
|
||||
deposit={stakingEvent.stakeDeposited}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (e.stakingEvent.stakeRemoved) {
|
||||
if (stakingEvent.stakeRemoved) {
|
||||
return (
|
||||
<TxDetailsChainEventStakeRemove remove={e.stakingEvent.stakeRemoved} />
|
||||
<TxDetailsChainEventStakeRemove remove={stakingEvent.stakeRemoved} />
|
||||
);
|
||||
}
|
||||
|
||||
if (e.stakingEvent.totalSupply) {
|
||||
if (stakingEvent.totalSupply) {
|
||||
return (
|
||||
<TxDetailsChainEventStakeTotalSupply
|
||||
update={e.stakingEvent.totalSupply}
|
||||
update={stakingEvent.totalSupply}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
import { getBlockTime } from './get-block-time';
|
||||
|
||||
describe('Lib: getBlockTime', () => {
|
||||
it('- gets returned if nothing is provided', () => {
|
||||
const res = getBlockTime();
|
||||
expect(res).toEqual('-');
|
||||
});
|
||||
|
||||
it('Returns a known date string', () => {
|
||||
const mockBlockTime = '1669223762';
|
||||
const usRes = getBlockTime(mockBlockTime, 'en-US');
|
||||
expect(usRes).toEqual('11/23/2022, 5:16:02 PM');
|
||||
});
|
||||
});
|
@ -4,13 +4,22 @@
|
||||
* @param date String or null date
|
||||
* @returns String date in locale time
|
||||
*/
|
||||
export function getBlockTime(date?: string) {
|
||||
if (!date) {
|
||||
export function getBlockTime(date?: string, locale?: Intl.LocalesArgument) {
|
||||
try {
|
||||
if (!date) {
|
||||
throw new Error('No date provided');
|
||||
}
|
||||
|
||||
const timeInSeconds = parseInt(date, 10);
|
||||
|
||||
if (isNaN(timeInSeconds)) {
|
||||
throw new Error('Invalid date');
|
||||
}
|
||||
|
||||
const timeInMs = timeInSeconds * 1000;
|
||||
|
||||
return new Date(timeInMs).toLocaleString(locale);
|
||||
} catch (e) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
const timeInSeconds = parseInt(date, 10);
|
||||
const timeInMs = timeInSeconds * 1000;
|
||||
|
||||
return new Date(timeInMs).toLocaleString();
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { TxDetailsChainEventBuiltinDeposit } from './tx-builtin-deposit';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import omit from 'lodash/omit';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
type Deposit = components['schemas']['vegaBuiltinAssetDeposit'];
|
||||
|
||||
const fullMock: Deposit = {
|
||||
partyId: 'party123',
|
||||
vegaAssetId: 'asset123',
|
||||
amount: 'amount123',
|
||||
};
|
||||
|
||||
describe('Chain Event: Builtin asset deposit', () => {
|
||||
it('Renders nothing if no good data is provided', () => {
|
||||
const mock = undefined as unknown as Deposit;
|
||||
const screen = render(<TxDetailsChainEventBuiltinDeposit deposit={mock} />);
|
||||
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('Renders nothing if correct type with no data is provided', () => {
|
||||
const mock: Deposit = {};
|
||||
|
||||
const screen = render(<TxDetailsChainEventBuiltinDeposit deposit={mock} />);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it(`Renders nothing if correct type with partial data is provided`, () => {
|
||||
for (const key in fullMock) {
|
||||
const mock = omit(fullMock, key);
|
||||
const screen = render(
|
||||
<TxDetailsChainEventBuiltinDeposit deposit={mock} />
|
||||
);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
}
|
||||
});
|
||||
|
||||
it('Renders TableRows if all data is provided', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainEventBuiltinDeposit deposit={fullMock} />
|
||||
</tbody>
|
||||
</table>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(screen.getByText(t('Built-in asset deposit'))).toBeInTheDocument();
|
||||
expect(screen.getByText(t('Asset'))).toBeInTheDocument();
|
||||
expect(screen.getByText(`${fullMock.vegaAssetId}`)).toBeInTheDocument();
|
||||
expect(screen.getByText(t('Amount'))).toBeInTheDocument();
|
||||
expect(screen.getByText(`${fullMock.amount}`)).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Recipient'))).toBeInTheDocument();
|
||||
const partyLink = screen.getByText(`${fullMock.partyId}`);
|
||||
expect(partyLink).toBeInTheDocument();
|
||||
expect(partyLink.tagName).toEqual('A');
|
||||
expect(partyLink.getAttribute('href')).toEqual(
|
||||
`/parties/${fullMock.partyId}`
|
||||
);
|
||||
|
||||
const assetLink = screen.getByText(`${fullMock.vegaAssetId}`);
|
||||
expect(assetLink).toBeInTheDocument();
|
||||
expect(assetLink.tagName).toEqual('A');
|
||||
expect(assetLink.getAttribute('href')).toEqual(
|
||||
`/assets#${fullMock.vegaAssetId}`
|
||||
);
|
||||
});
|
||||
});
|
@ -15,26 +15,26 @@ interface TxDetailsChainEventBuiltinDepositProps {
|
||||
export const TxDetailsChainEventBuiltinDeposit = ({
|
||||
deposit,
|
||||
}: TxDetailsChainEventBuiltinDepositProps) => {
|
||||
if (!deposit) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
if (!deposit || !deposit.partyId || !deposit.vegaAssetId || !deposit.amount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Chain Event type')}</TableCell>
|
||||
<TableCell>{t('Chain event type')}</TableCell>
|
||||
<TableCell>{t('Built-in asset deposit')}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Recipient')}</TableCell>
|
||||
<TableCell>
|
||||
<PartyLink id={deposit.partyId || ''} />
|
||||
<PartyLink id={deposit.partyId} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Asset')}</TableCell>
|
||||
<TableCell>
|
||||
<AssetLink id={deposit.vegaAssetId || ''} /> ({t('built in asset')})
|
||||
<AssetLink id={deposit.vegaAssetId} /> ({t('built in asset')})
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
|
@ -0,0 +1,84 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { TxDetailsChainEventBuiltinWithdrawal } from './tx-builtin-withdrawal';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import omit from 'lodash/omit';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
type Withdrawal = components['schemas']['vegaBuiltinAssetWithdrawal'];
|
||||
|
||||
const fullMock: Withdrawal = {
|
||||
partyId: 'party123',
|
||||
vegaAssetId: 'asset123',
|
||||
amount: 'amount123',
|
||||
};
|
||||
|
||||
describe('Chain Event: Builtin asset withdrawal', () => {
|
||||
it('Renders nothing if no good data is provided', () => {
|
||||
const mock = undefined as unknown as Withdrawal;
|
||||
const screen = render(
|
||||
<TxDetailsChainEventBuiltinWithdrawal withdrawal={mock} />
|
||||
);
|
||||
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('Renders nothing if correct type with no data is provided', () => {
|
||||
const mock: Withdrawal = {};
|
||||
|
||||
const screen = render(
|
||||
<TxDetailsChainEventBuiltinWithdrawal withdrawal={mock} />
|
||||
);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it(`Renders nothing if correct type with partial data is provided`, () => {
|
||||
for (const key in fullMock) {
|
||||
const mock = omit(fullMock, key);
|
||||
const screen = render(
|
||||
<TxDetailsChainEventBuiltinWithdrawal withdrawal={mock} />
|
||||
);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
}
|
||||
});
|
||||
|
||||
it('Renders TableRows if all data is provided', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainEventBuiltinWithdrawal withdrawal={fullMock} />
|
||||
</tbody>
|
||||
</table>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(t('Built-in asset withdrawal'))
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText(t('Asset'))).toBeInTheDocument();
|
||||
expect(screen.getByText(`${fullMock.vegaAssetId}`)).toBeInTheDocument();
|
||||
expect(screen.getByText(t('Amount'))).toBeInTheDocument();
|
||||
expect(screen.getByText(`${fullMock.amount}`)).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Recipient'))).toBeInTheDocument();
|
||||
const partyLink = screen.getByText(`${fullMock.partyId}`);
|
||||
expect(partyLink).toBeInTheDocument();
|
||||
expect(partyLink.tagName).toEqual('A');
|
||||
expect(partyLink.getAttribute('href')).toEqual(
|
||||
`/parties/${fullMock.partyId}`
|
||||
);
|
||||
|
||||
const assetLink = screen.getByText(`${fullMock.vegaAssetId}`);
|
||||
expect(assetLink).toBeInTheDocument();
|
||||
expect(assetLink.tagName).toEqual('A');
|
||||
expect(assetLink.getAttribute('href')).toEqual(
|
||||
`/assets#${fullMock.vegaAssetId}`
|
||||
);
|
||||
});
|
||||
});
|
@ -15,14 +15,19 @@ interface TxDetailsChainEventBuiltinDepositProps {
|
||||
export const TxDetailsChainEventBuiltinWithdrawal = ({
|
||||
withdrawal,
|
||||
}: TxDetailsChainEventBuiltinDepositProps) => {
|
||||
if (!withdrawal) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
if (
|
||||
!withdrawal ||
|
||||
!withdrawal.partyId ||
|
||||
!withdrawal.vegaAssetId ||
|
||||
!withdrawal.amount
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Chain Event type')}</TableCell>
|
||||
<TableCell>{t('Chain event type')}</TableCell>
|
||||
<TableCell>{t('Built-in asset withdrawal')}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
|
@ -0,0 +1,68 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import omit from 'lodash/omit';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { TxDetailsChainEventErc20AssetDelist } from './tx-erc20-asset-delist';
|
||||
|
||||
type Delist = components['schemas']['vegaERC20AssetDelist'];
|
||||
|
||||
const fullMock: Delist = {
|
||||
vegaAssetId: 'asset123',
|
||||
};
|
||||
|
||||
describe('Chain Event: ERC20 Asset Delist', () => {
|
||||
it('Renders nothing if no good data is provided', () => {
|
||||
const mock = undefined as unknown as Delist;
|
||||
const screen = render(
|
||||
<TxDetailsChainEventErc20AssetDelist assetDelist={mock} />
|
||||
);
|
||||
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('Renders nothing if correct type with no data is provided', () => {
|
||||
const mock: Delist = {};
|
||||
|
||||
const screen = render(
|
||||
<TxDetailsChainEventErc20AssetDelist assetDelist={mock} />
|
||||
);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it(`Renders nothing if correct type with partial data is provided`, () => {
|
||||
for (const key in fullMock) {
|
||||
const mock = omit(fullMock, key);
|
||||
const screen = render(
|
||||
<TxDetailsChainEventErc20AssetDelist assetDelist={mock} />
|
||||
);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
}
|
||||
});
|
||||
|
||||
it('Renders TableRows if all data is provided', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainEventErc20AssetDelist assetDelist={fullMock} />
|
||||
</tbody>
|
||||
</table>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(screen.getByText(t('ERC20 asset removed'))).toBeInTheDocument();
|
||||
|
||||
const assetLink = screen.getByText(`${fullMock.vegaAssetId}`);
|
||||
expect(assetLink).toBeInTheDocument();
|
||||
expect(assetLink.tagName).toEqual('A');
|
||||
expect(assetLink.getAttribute('href')).toEqual(
|
||||
`/assets#${fullMock.vegaAssetId}`
|
||||
);
|
||||
});
|
||||
});
|
@ -16,8 +16,8 @@ interface TxDetailsChainEventErc20AssetDelistProps {
|
||||
export const TxDetailsChainEventErc20AssetDelist = ({
|
||||
assetDelist,
|
||||
}: TxDetailsChainEventErc20AssetDelistProps) => {
|
||||
if (!assetDelist) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
if (!assetDelist || !assetDelist.vegaAssetId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -0,0 +1,90 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import omit from 'lodash/omit';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { TxDetailsChainEventErc20AssetLimitsUpdated } from './tx-erc20-asset-limits-updated';
|
||||
|
||||
type AssetLimitsUpdated = components['schemas']['vegaERC20AssetLimitsUpdated'];
|
||||
|
||||
const fullMock: AssetLimitsUpdated = {
|
||||
sourceEthereumAddress: 'eth123',
|
||||
vegaAssetId: 'asset123',
|
||||
lifetimeLimits: '100',
|
||||
withdrawThreshold: '60',
|
||||
};
|
||||
|
||||
describe('Chain Event: ERC20 Asset limits updated', () => {
|
||||
it('Renders nothing if no good data is provided', () => {
|
||||
const mock = undefined as unknown as AssetLimitsUpdated;
|
||||
const screen = render(
|
||||
<TxDetailsChainEventErc20AssetLimitsUpdated assetLimitsUpdated={mock} />
|
||||
);
|
||||
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('Renders nothing if correct type with no data is provided', () => {
|
||||
const mock: AssetLimitsUpdated = {};
|
||||
|
||||
const screen = render(
|
||||
<TxDetailsChainEventErc20AssetLimitsUpdated assetLimitsUpdated={mock} />
|
||||
);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it(`Renders nothing if correct type with partial data is provided`, () => {
|
||||
for (const key in fullMock) {
|
||||
const mock = omit(fullMock, key);
|
||||
const screen = render(
|
||||
<TxDetailsChainEventErc20AssetLimitsUpdated assetLimitsUpdated={mock} />
|
||||
);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
}
|
||||
});
|
||||
|
||||
it('Renders TableRows if all data is provided', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainEventErc20AssetLimitsUpdated
|
||||
assetLimitsUpdated={fullMock}
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(t('ERC20 asset limits update'))
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText(t('Total lifetime limit'))).toBeInTheDocument();
|
||||
expect(screen.getByText(`${fullMock.lifetimeLimits}`)).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(t('Asset withdrawal threshold'))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(`${fullMock.withdrawThreshold}`)
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Vega asset'))).toBeInTheDocument();
|
||||
const assetLink = screen.getByText(`${fullMock.vegaAssetId}`);
|
||||
expect(assetLink).toBeInTheDocument();
|
||||
expect(assetLink.tagName).toEqual('A');
|
||||
expect(assetLink.getAttribute('href')).toEqual(
|
||||
`/assets#${fullMock.vegaAssetId}`
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('ERC20 asset'))).toBeInTheDocument();
|
||||
const ethLink = screen.getByText(`${fullMock.sourceEthereumAddress}`);
|
||||
expect(ethLink.getAttribute('href')).toContain(
|
||||
`/address/${fullMock.sourceEthereumAddress}`
|
||||
);
|
||||
});
|
||||
});
|
@ -23,33 +23,35 @@ interface TxDetailsChainEventErc20AssetLimitsUpdatedProps {
|
||||
export const TxDetailsChainEventErc20AssetLimitsUpdated = ({
|
||||
assetLimitsUpdated,
|
||||
}: TxDetailsChainEventErc20AssetLimitsUpdatedProps) => {
|
||||
if (!assetLimitsUpdated) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
if (
|
||||
!assetLimitsUpdated ||
|
||||
!assetLimitsUpdated.sourceEthereumAddress ||
|
||||
!assetLimitsUpdated.vegaAssetId ||
|
||||
!assetLimitsUpdated.lifetimeLimits ||
|
||||
!assetLimitsUpdated.withdrawThreshold
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Chain event type')}</TableCell>
|
||||
<TableCell>{t('ERC20 asset limits updated')}</TableCell>
|
||||
<TableCell>{t('ERC20 asset limits update')}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('ERC20 asset')}</TableCell>
|
||||
<TableCell>
|
||||
<EthExplorerLink
|
||||
id={assetLimitsUpdated.sourceEthereumAddress}
|
||||
type={EthExplorerLinkTypes.address}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
{assetLimitsUpdated.sourceEthereumAddress ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('ERC20 asset')}</TableCell>
|
||||
<TableCell>
|
||||
<EthExplorerLink
|
||||
id={assetLimitsUpdated.sourceEthereumAddress}
|
||||
type={EthExplorerLinkTypes.address}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Vega asset')}</TableCell>
|
||||
<TableCell>
|
||||
<AssetLink id={assetLimitsUpdated.vegaAssetId || ''} />
|
||||
<AssetLink id={assetLimitsUpdated.vegaAssetId} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
|
@ -0,0 +1,76 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import omit from 'lodash/omit';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { TxDetailsChainEventErc20AssetList } from './tx-erc20-asset-list';
|
||||
|
||||
type List = components['schemas']['vegaERC20AssetList'];
|
||||
|
||||
const fullMock: List = {
|
||||
vegaAssetId: 'asset123',
|
||||
assetSource: 'eth123',
|
||||
};
|
||||
|
||||
describe('Chain Event: ERC20 Asset List', () => {
|
||||
it('Renders nothing if no good data is provided', () => {
|
||||
const mock = undefined as unknown as List;
|
||||
const screen = render(
|
||||
<TxDetailsChainEventErc20AssetList assetList={mock} />
|
||||
);
|
||||
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('Renders nothing if correct type with no data is provided', () => {
|
||||
const mock: List = {};
|
||||
|
||||
const screen = render(
|
||||
<TxDetailsChainEventErc20AssetList assetList={mock} />
|
||||
);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it(`Renders nothing if correct type with partial data is provided`, () => {
|
||||
for (const key in fullMock) {
|
||||
const mock = omit(fullMock, key);
|
||||
const screen = render(
|
||||
<TxDetailsChainEventErc20AssetList assetList={mock} />
|
||||
);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
}
|
||||
});
|
||||
|
||||
it('Renders TableRows if all data is provided', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainEventErc20AssetList assetList={fullMock} />
|
||||
</tbody>
|
||||
</table>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(screen.getByText(t('ERC20 asset added'))).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Added Vega asset'))).toBeInTheDocument();
|
||||
const assetLink = screen.getByText(`${fullMock.vegaAssetId}`);
|
||||
expect(assetLink).toBeInTheDocument();
|
||||
expect(assetLink.tagName).toEqual('A');
|
||||
expect(assetLink.getAttribute('href')).toEqual(
|
||||
`/assets#${fullMock.vegaAssetId}`
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Source'))).toBeInTheDocument();
|
||||
const ethLink = screen.getByText(`${fullMock.assetSource}`);
|
||||
expect(ethLink.getAttribute('href')).toContain(
|
||||
`/address/${fullMock.assetSource}`
|
||||
);
|
||||
});
|
||||
});
|
@ -19,8 +19,8 @@ interface TxDetailsChainEventErc20AssetListProps {
|
||||
export const TxDetailsChainEventErc20AssetList = ({
|
||||
assetList,
|
||||
}: TxDetailsChainEventErc20AssetListProps) => {
|
||||
if (!assetList) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
if (!assetList || !assetList.assetSource || !assetList.vegaAssetId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
@ -29,21 +29,19 @@ export const TxDetailsChainEventErc20AssetList = ({
|
||||
<TableCell>{t('Chain event type')}</TableCell>
|
||||
<TableCell>{t('ERC20 asset added')}</TableCell>
|
||||
</TableRow>
|
||||
{assetList.assetSource ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Source')}</TableCell>
|
||||
<TableCell>
|
||||
<EthExplorerLink
|
||||
id={assetList.assetSource}
|
||||
type={EthExplorerLinkTypes.address}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Source')}</TableCell>
|
||||
<TableCell>
|
||||
<EthExplorerLink
|
||||
id={assetList.assetSource}
|
||||
type={EthExplorerLinkTypes.address}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Added Vega asset')}</TableCell>
|
||||
<TableCell>
|
||||
<AssetLink id={assetList.vegaAssetId || ''} />
|
||||
<AssetLink id={assetList.vegaAssetId} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</>
|
||||
|
@ -0,0 +1,31 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { TxDetailsChainEventErc20BridgePause } from './tx-erc20-bridge-pause';
|
||||
|
||||
describe('Chain Event: ERC20 bridge pause', () => {
|
||||
it('Renders pause if paused', () => {
|
||||
const screen = render(
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainEventErc20BridgePause isPaused={true} />
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(screen.getByText(t('ERC20 bridge pause'))).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Renders unpause if resumed', () => {
|
||||
const screen = render(
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainEventErc20BridgePause isPaused={false} />
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(screen.getByText(t('ERC20 bridge unpause'))).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { TableRow, TableCell } from '../../../table';
|
||||
|
||||
interface TxDetailsChainEventErc20BridgePauseProps {
|
||||
export interface TxDetailsChainEventErc20BridgePauseProps {
|
||||
isPaused: boolean;
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ interface TxDetailsChainEventErc20BridgePauseProps {
|
||||
export const TxDetailsChainEventErc20BridgePause = ({
|
||||
isPaused,
|
||||
}: TxDetailsChainEventErc20BridgePauseProps) => {
|
||||
const event = isPaused ? 'pause' : 'unpaused';
|
||||
const event = isPaused ? 'pause' : 'unpause';
|
||||
|
||||
return (
|
||||
<TableRow modifier="bordered">
|
||||
|
@ -0,0 +1,83 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import omit from 'lodash/omit';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { TxDetailsChainEventDeposit } from './tx-erc20-deposit';
|
||||
|
||||
type Deposit = components['schemas']['vegaERC20Deposit'];
|
||||
|
||||
const fullMock: Deposit = {
|
||||
vegaAssetId: 'asset123',
|
||||
amount: 'amount123',
|
||||
sourceEthereumAddress: 'eth123',
|
||||
targetPartyId: 'vega123',
|
||||
};
|
||||
|
||||
describe('Chain Event: ERC20 asset deposit', () => {
|
||||
it('Renders nothing if no good data is provided', () => {
|
||||
const mock = undefined as unknown as Deposit;
|
||||
const screen = render(<TxDetailsChainEventDeposit deposit={mock} />);
|
||||
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('Renders nothing if correct type with no data is provided', () => {
|
||||
const mock: Deposit = {};
|
||||
|
||||
const screen = render(<TxDetailsChainEventDeposit deposit={mock} />);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it(`Renders nothing if correct type with partial data is provided`, () => {
|
||||
for (const key in fullMock) {
|
||||
const mock = omit(fullMock, key);
|
||||
const screen = render(<TxDetailsChainEventDeposit deposit={mock} />);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
}
|
||||
});
|
||||
|
||||
it('Renders TableRows if all data is provided', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainEventDeposit deposit={fullMock} />
|
||||
</tbody>
|
||||
</table>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(screen.getByText(t('ERC20 deposit'))).toBeInTheDocument();
|
||||
expect(screen.getByText(t('Asset'))).toBeInTheDocument();
|
||||
expect(screen.getByText(`${fullMock.vegaAssetId}`)).toBeInTheDocument();
|
||||
expect(screen.getByText(t('Amount'))).toBeInTheDocument();
|
||||
expect(screen.getByText(`${fullMock.amount}`)).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Recipient'))).toBeInTheDocument();
|
||||
const partyLink = screen.getByText(`${fullMock.targetPartyId}`);
|
||||
expect(partyLink).toBeInTheDocument();
|
||||
expect(partyLink.tagName).toEqual('A');
|
||||
expect(partyLink.getAttribute('href')).toEqual(
|
||||
`/parties/${fullMock.targetPartyId}`
|
||||
);
|
||||
|
||||
const assetLink = screen.getByText(`${fullMock.vegaAssetId}`);
|
||||
expect(assetLink).toBeInTheDocument();
|
||||
expect(assetLink.tagName).toEqual('A');
|
||||
expect(assetLink.getAttribute('href')).toEqual(
|
||||
`/assets#${fullMock.vegaAssetId}`
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Source'))).toBeInTheDocument();
|
||||
const ethLink = screen.getByText(`${fullMock.sourceEthereumAddress}`);
|
||||
expect(ethLink.getAttribute('href')).toContain(
|
||||
`/address/${fullMock.sourceEthereumAddress}`
|
||||
);
|
||||
});
|
||||
});
|
@ -17,8 +17,14 @@ interface TxDetailsChainEventProps {
|
||||
export const TxDetailsChainEventDeposit = ({
|
||||
deposit,
|
||||
}: TxDetailsChainEventProps) => {
|
||||
if (!deposit) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
if (
|
||||
!deposit ||
|
||||
!deposit.sourceEthereumAddress ||
|
||||
!deposit.targetPartyId ||
|
||||
!deposit.vegaAssetId ||
|
||||
!deposit.amount
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
@ -27,27 +33,25 @@ export const TxDetailsChainEventDeposit = ({
|
||||
<TableCell>{t('Chain event type')}</TableCell>
|
||||
<TableCell>{t('ERC20 deposit')}</TableCell>
|
||||
</TableRow>
|
||||
{deposit.sourceEthereumAddress ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Source')}</TableCell>
|
||||
<TableCell>
|
||||
<EthExplorerLink
|
||||
id={deposit.sourceEthereumAddress}
|
||||
type={EthExplorerLinkTypes.address}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Source')}</TableCell>
|
||||
<TableCell>
|
||||
<EthExplorerLink
|
||||
id={deposit.sourceEthereumAddress}
|
||||
type={EthExplorerLinkTypes.address}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Recipient')}</TableCell>
|
||||
<TableCell>
|
||||
<PartyLink id={deposit.targetPartyId || ''} />
|
||||
<PartyLink id={deposit.targetPartyId} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Asset')}</TableCell>
|
||||
<TableCell>
|
||||
<AssetLink id={deposit.vegaAssetId || ''} />
|
||||
<AssetLink id={deposit.vegaAssetId} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
|
@ -0,0 +1,71 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import omit from 'lodash/omit';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { TxDetailsChainEventWithdrawal } from './tx-erc20-withdrawal';
|
||||
type Withdrawal = components['schemas']['vegaERC20Withdrawal'];
|
||||
|
||||
const fullMock: Partial<Withdrawal> = {
|
||||
vegaAssetId: 'asset123',
|
||||
targetEthereumAddress: 'eth123',
|
||||
};
|
||||
|
||||
describe('Chain Event: ERC20 asset deposit', () => {
|
||||
it('Renders nothing if no good data is provided', () => {
|
||||
const mock = undefined as unknown as Withdrawal;
|
||||
const screen = render(<TxDetailsChainEventWithdrawal withdrawal={mock} />);
|
||||
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('Renders nothing if correct type with no data is provided', () => {
|
||||
const mock: Withdrawal = {};
|
||||
|
||||
const screen = render(<TxDetailsChainEventWithdrawal withdrawal={mock} />);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it(`Renders nothing if correct type with partial data is provided`, () => {
|
||||
for (const key in fullMock) {
|
||||
const mock = omit(fullMock, key);
|
||||
const screen = render(
|
||||
<TxDetailsChainEventWithdrawal withdrawal={mock} />
|
||||
);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
}
|
||||
});
|
||||
|
||||
it('Renders TableRows if all data is provided', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainEventWithdrawal withdrawal={fullMock} />
|
||||
</tbody>
|
||||
</table>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(screen.getByText(t('ERC20 withdrawal'))).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Asset'))).toBeInTheDocument();
|
||||
const assetLink = screen.getByText(`${fullMock.vegaAssetId}`);
|
||||
expect(assetLink).toBeInTheDocument();
|
||||
expect(assetLink.tagName).toEqual('A');
|
||||
expect(assetLink.getAttribute('href')).toEqual(
|
||||
`/assets#${fullMock.vegaAssetId}`
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Recipient'))).toBeInTheDocument();
|
||||
const ethLink = screen.getByText(`${fullMock.targetEthereumAddress}`);
|
||||
expect(ethLink.getAttribute('href')).toContain(
|
||||
`/address/${fullMock.targetEthereumAddress}`
|
||||
);
|
||||
});
|
||||
});
|
@ -17,8 +17,12 @@ interface TxDetailsChainEventWithdrawalProps {
|
||||
export const TxDetailsChainEventWithdrawal = ({
|
||||
withdrawal,
|
||||
}: TxDetailsChainEventWithdrawalProps) => {
|
||||
if (!withdrawal) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
if (
|
||||
!withdrawal ||
|
||||
!withdrawal.targetEthereumAddress ||
|
||||
!withdrawal.vegaAssetId
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
@ -28,22 +32,20 @@ export const TxDetailsChainEventWithdrawal = ({
|
||||
<TableCell>{t('ERC20 withdrawal')}</TableCell>
|
||||
</TableRow>
|
||||
|
||||
{withdrawal.targetEthereumAddress ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Recipient')}</TableCell>
|
||||
<TableCell>
|
||||
<EthExplorerLink
|
||||
id={withdrawal.targetEthereumAddress}
|
||||
type={EthExplorerLinkTypes.address}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Recipient')}</TableCell>
|
||||
<TableCell>
|
||||
<EthExplorerLink
|
||||
id={withdrawal.targetEthereumAddress}
|
||||
type={EthExplorerLinkTypes.address}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Asset')}</TableCell>
|
||||
<TableCell>
|
||||
<AssetLink id={withdrawal.vegaAssetId || ''} />
|
||||
<AssetLink id={withdrawal.vegaAssetId} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</>
|
||||
|
@ -0,0 +1,101 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { TxDetailsChainMultisigSigner } from './tx-multisig-signer';
|
||||
import { getBlockTime } from './lib/get-block-time';
|
||||
|
||||
type Added = components['schemas']['vegaERC20SignerAdded'];
|
||||
type Removed = components['schemas']['vegaERC20SignerRemoved'];
|
||||
|
||||
const mockBlockTime = '1669631323';
|
||||
|
||||
describe('Chain Event: multisig signer change', () => {
|
||||
it('Copes with a poorly formatted time prop', () => {
|
||||
const addedMock: Added = {
|
||||
newSigner: 'eth123',
|
||||
nonce: 'nonce123',
|
||||
blockTime: 'you shall not parse',
|
||||
};
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainMultisigSigner signer={addedMock} />
|
||||
</tbody>
|
||||
</table>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Signer change at'))).toBeInTheDocument();
|
||||
expect(screen.getByText('-')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Renders addedSigner correctly', () => {
|
||||
const addedMock: Added = {
|
||||
newSigner: 'eth123',
|
||||
nonce: 'nonce123',
|
||||
blockTime: mockBlockTime,
|
||||
};
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainMultisigSigner signer={addedMock} />
|
||||
</tbody>
|
||||
</table>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(t('Add ERC20 bridge multisig signer'))
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Add signer'))).toBeInTheDocument();
|
||||
expect(screen.getByText(`${addedMock.newSigner}`)).toBeInTheDocument();
|
||||
|
||||
const expectedDate = getBlockTime(mockBlockTime);
|
||||
|
||||
expect(screen.getByText(t('Signer change at'))).toBeInTheDocument();
|
||||
expect(screen.getByText(expectedDate)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Renders TableRows if all data is provided', () => {
|
||||
const removedMock: Removed = {
|
||||
oldSigner: 'eth123',
|
||||
nonce: 'nonce123',
|
||||
blockTime: mockBlockTime,
|
||||
};
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainMultisigSigner signer={removedMock} />
|
||||
</tbody>
|
||||
</table>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(t('Remove ERC20 bridge multisig signer'))
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Remove signer'))).toBeInTheDocument();
|
||||
expect(screen.getByText(`${removedMock.oldSigner}`)).toBeInTheDocument();
|
||||
|
||||
const expectedDate = getBlockTime(mockBlockTime);
|
||||
|
||||
expect(screen.getByText(t('Signer change at'))).toBeInTheDocument();
|
||||
expect(screen.getByText(expectedDate)).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -15,8 +15,8 @@ interface TxDetailsChainMultisigSignerProps {
|
||||
export const TxDetailsChainMultisigSigner = ({
|
||||
signer,
|
||||
}: TxDetailsChainMultisigSignerProps) => {
|
||||
if (!signer) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
if (!signer || !signer.blockTime) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const blockTime = getBlockTime(signer.blockTime);
|
||||
@ -30,10 +30,12 @@ export const TxDetailsChainMultisigSigner = ({
|
||||
return (
|
||||
<>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Chain Event type')}</TableCell>
|
||||
{'newSigner' in signer
|
||||
? t('Add ERC20 bridge multisig signer')
|
||||
: t('Remove ERC20 bridge multsig signer')}
|
||||
<TableCell>{t('Chain event type')}</TableCell>
|
||||
<TableCell>
|
||||
{'newSigner' in signer
|
||||
? t('Add ERC20 bridge multisig signer')
|
||||
: t('Remove ERC20 bridge multisig signer')}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>
|
||||
|
@ -0,0 +1,82 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { TxDetailsChainMultisigThreshold } from './tx-multisig-threshold';
|
||||
import omit from 'lodash/omit';
|
||||
import { getBlockTime } from './lib/get-block-time';
|
||||
|
||||
type Threshold =
|
||||
components['schemas']['vegaERC20MultiSigEvent']['thresholdSet'];
|
||||
|
||||
const mockBlockTime = '1669631323';
|
||||
// Note: nonce is missing from this partial because the component does not render
|
||||
// the nonce currently. It could render the nonce, at which point it can be added
|
||||
// here.
|
||||
const fullMock: Partial<Threshold> = {
|
||||
blockTime: mockBlockTime,
|
||||
newThreshold: 667,
|
||||
};
|
||||
|
||||
describe('Chain Event: multisig threshold change', () => {
|
||||
it('Copes with a poorly formatted time prop', () => {
|
||||
const mockWithBadTime: Threshold = {
|
||||
blockTime: '-',
|
||||
newThreshold: 1000,
|
||||
nonce: 'nonce123',
|
||||
};
|
||||
const screen = render(
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainMultisigThreshold thresholdSet={mockWithBadTime} />
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Threshold change date'))).toBeInTheDocument();
|
||||
expect(screen.getByText('-')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it(`Renders nothing if correct type with partial data is provided`, () => {
|
||||
for (const key in fullMock) {
|
||||
const mock = omit(fullMock, key);
|
||||
const screen = render(
|
||||
<TxDetailsChainMultisigThreshold thresholdSet={mock} />
|
||||
);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
}
|
||||
});
|
||||
|
||||
it('Renders TableRows if all data is provided', () => {
|
||||
const mock: Threshold = Object.assign({}, fullMock, {
|
||||
nonce: 'nonce123',
|
||||
});
|
||||
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainMultisigThreshold thresholdSet={mock} />
|
||||
</tbody>
|
||||
</table>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(t('ERC20 multisig threshold set'))
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Threshold'))).toBeInTheDocument();
|
||||
expect(screen.getByText(`66.7%`)).toBeInTheDocument();
|
||||
|
||||
const expectedDate = getBlockTime(mockBlockTime);
|
||||
|
||||
expect(screen.getByText(t('Threshold change date'))).toBeInTheDocument();
|
||||
expect(screen.getByText(expectedDate)).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -2,23 +2,7 @@ import { t } from '@vegaprotocol/react-helpers';
|
||||
import { TableRow, TableCell } from '../../../table';
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import isNumber from 'lodash/isNumber';
|
||||
|
||||
/**
|
||||
* Returns a reasonably formatted time from unix timestamp of block height
|
||||
*
|
||||
* @param date String or null date
|
||||
* @returns String date in locale time
|
||||
*/
|
||||
function getBlockTime(date?: string) {
|
||||
if (!date) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
const timeInSeconds = parseInt(date, 10);
|
||||
const timeInMs = timeInSeconds * 1000;
|
||||
|
||||
return new Date(timeInMs).toLocaleString();
|
||||
}
|
||||
import { getBlockTime } from './lib/get-block-time';
|
||||
|
||||
interface TxDetailsChainMultisigThresholdProps {
|
||||
thresholdSet: components['schemas']['vegaERC20MultiSigEvent']['thresholdSet'];
|
||||
@ -27,12 +11,15 @@ interface TxDetailsChainMultisigThresholdProps {
|
||||
/**
|
||||
* Someone updated multsig threshold value on the smart contract.
|
||||
* It's a percentage, with 1000 being 100% and 0 being 0%.
|
||||
*
|
||||
* - Nonce is not rendered. It's in the full transaction details thing
|
||||
* in case anyone really wants it, but for now it feels like detail we don't need
|
||||
*/
|
||||
export const TxDetailsChainMultisigThreshold = ({
|
||||
thresholdSet,
|
||||
}: TxDetailsChainMultisigThresholdProps) => {
|
||||
if (!thresholdSet) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
if (!thresholdSet || !thresholdSet.blockTime || !thresholdSet.newThreshold) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const blockTime = getBlockTime(thresholdSet.blockTime);
|
||||
@ -43,7 +30,7 @@ export const TxDetailsChainMultisigThreshold = ({
|
||||
return (
|
||||
<>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Chain Event type')}</TableCell>
|
||||
<TableCell>{t('Chain event type')}</TableCell>
|
||||
<TableCell>{t('ERC20 multisig threshold set')}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
@ -51,7 +38,7 @@ export const TxDetailsChainMultisigThreshold = ({
|
||||
<TableCell>{threshold}%</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Threshold set from')}</TableCell>
|
||||
<TableCell>{t('Threshold change date')}</TableCell>
|
||||
<TableCell>{blockTime}</TableCell>
|
||||
</TableRow>
|
||||
</>
|
||||
|
@ -0,0 +1,78 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import omit from 'lodash/omit';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { TxDetailsChainEventStakeDeposit } from './tx-stake-deposit';
|
||||
|
||||
type Deposit = components['schemas']['vegaStakeDeposited'];
|
||||
|
||||
const fullMock: Deposit = {
|
||||
amount: 'amount123',
|
||||
blockTime: 'block123',
|
||||
ethereumAddress: 'eth123',
|
||||
vegaPublicKey: 'vega123',
|
||||
};
|
||||
|
||||
describe('Chain Event: Stake deposit', () => {
|
||||
it('Renders nothing if no good data is provided', () => {
|
||||
const mock = undefined as unknown as Deposit;
|
||||
const screen = render(<TxDetailsChainEventStakeDeposit deposit={mock} />);
|
||||
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('Renders nothing if correct type with no data is provided', () => {
|
||||
const mock: Deposit = {};
|
||||
|
||||
const screen = render(<TxDetailsChainEventStakeDeposit deposit={mock} />);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it(`Renders nothing if correct type with partial data is provided`, () => {
|
||||
for (const key in fullMock) {
|
||||
const mock = omit(fullMock, key);
|
||||
const screen = render(<TxDetailsChainEventStakeDeposit deposit={mock} />);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
}
|
||||
});
|
||||
|
||||
it('Renders TableRows if all data is provided', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainEventStakeDeposit deposit={fullMock} />
|
||||
</tbody>
|
||||
</table>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(screen.getByText(t('Stake deposit'))).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Amount'))).toBeInTheDocument();
|
||||
expect(screen.getByText(`${fullMock.amount}`)).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Deposited at'))).toBeInTheDocument();
|
||||
expect(screen.getByText(`${fullMock.blockTime}`)).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Recipient'))).toBeInTheDocument();
|
||||
const partyLink = screen.getByText(`${fullMock.vegaPublicKey}`);
|
||||
expect(partyLink).toBeInTheDocument();
|
||||
expect(partyLink.tagName).toEqual('A');
|
||||
expect(partyLink.getAttribute('href')).toEqual(
|
||||
`/parties/${fullMock.vegaPublicKey}`
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Source'))).toBeInTheDocument();
|
||||
const ethLink = screen.getByText(`${fullMock.ethereumAddress}`);
|
||||
expect(ethLink.getAttribute('href')).toContain(
|
||||
`/address/${fullMock.ethereumAddress}`
|
||||
);
|
||||
});
|
||||
});
|
@ -2,33 +2,48 @@ import { t } from '@vegaprotocol/react-helpers';
|
||||
import { TableRow, TableCell } from '../../../table';
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import { PartyLink } from '../../../links';
|
||||
import {
|
||||
EthExplorerLink,
|
||||
EthExplorerLinkTypes,
|
||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
||||
|
||||
interface TxDetailsChainEventStakeDepositProps {
|
||||
deposit: components['schemas']['vegaStakeDeposited'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Someone addedd some stake for a particular party
|
||||
* Someone added some stake for a particular party
|
||||
* This should link to the Governance asset, but doesn't
|
||||
* as that would require checking the Network Paramters
|
||||
* as that would require checking the Network Parameters
|
||||
* Ethereum address should also be a link to an ETH block explorer
|
||||
*/
|
||||
export const TxDetailsChainEventStakeDeposit = ({
|
||||
deposit,
|
||||
}: TxDetailsChainEventStakeDepositProps) => {
|
||||
if (!deposit) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
if (
|
||||
!deposit ||
|
||||
!deposit.ethereumAddress ||
|
||||
!deposit.vegaPublicKey ||
|
||||
!deposit.amount ||
|
||||
!deposit.blockTime
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Chain Event type')}</TableCell>
|
||||
<TableCell>{t('Stake deposited')}</TableCell>
|
||||
<TableCell>{t('Chain event type')}</TableCell>
|
||||
<TableCell>{t('Stake deposit')}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Source')}</TableCell>
|
||||
<TableCell>{deposit.ethereumAddress || ''}</TableCell>
|
||||
<TableCell>
|
||||
<EthExplorerLink
|
||||
id={deposit.ethereumAddress}
|
||||
type={EthExplorerLinkTypes.address}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Recipient')}</TableCell>
|
||||
@ -42,7 +57,7 @@ export const TxDetailsChainEventStakeDeposit = ({
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Deposited at')}</TableCell>
|
||||
<TableCell>{deposit.amount}</TableCell>
|
||||
<TableCell>{deposit.blockTime}</TableCell>
|
||||
</TableRow>
|
||||
</>
|
||||
);
|
||||
|
@ -0,0 +1,78 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import omit from 'lodash/omit';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { TxDetailsChainEventStakeRemove } from './tx-stake-remove';
|
||||
|
||||
type Remove = components['schemas']['vegaStakeRemoved'];
|
||||
|
||||
const fullMock: Remove = {
|
||||
amount: 'amount123',
|
||||
blockTime: 'block123',
|
||||
ethereumAddress: 'eth123',
|
||||
vegaPublicKey: 'vega123',
|
||||
};
|
||||
|
||||
describe('Chain Event: Stake remove', () => {
|
||||
it('Renders nothing if no good data is provided', () => {
|
||||
const mock = undefined as unknown as Remove;
|
||||
const screen = render(<TxDetailsChainEventStakeRemove remove={mock} />);
|
||||
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('Renders nothing if correct type with no data is provided', () => {
|
||||
const mock: Remove = {};
|
||||
|
||||
const screen = render(<TxDetailsChainEventStakeRemove remove={mock} />);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it(`Renders nothing if correct type with partial data is provided`, () => {
|
||||
for (const key in fullMock) {
|
||||
const mock = omit(fullMock, key);
|
||||
const screen = render(<TxDetailsChainEventStakeRemove remove={mock} />);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
}
|
||||
});
|
||||
|
||||
it('Renders TableRows if all data is provided', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainEventStakeRemove remove={fullMock} />
|
||||
</tbody>
|
||||
</table>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(screen.getByText(t('Stake remove'))).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Amount'))).toBeInTheDocument();
|
||||
expect(screen.getByText(`${fullMock.amount}`)).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Removed at'))).toBeInTheDocument();
|
||||
expect(screen.getByText(`${fullMock.blockTime}`)).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Recipient'))).toBeInTheDocument();
|
||||
const partyLink = screen.getByText(`${fullMock.vegaPublicKey}`);
|
||||
expect(partyLink).toBeInTheDocument();
|
||||
expect(partyLink.tagName).toEqual('A');
|
||||
expect(partyLink.getAttribute('href')).toEqual(
|
||||
`/parties/${fullMock.vegaPublicKey}`
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Source'))).toBeInTheDocument();
|
||||
const ethLink = screen.getByText(`${fullMock.ethereumAddress}`);
|
||||
expect(ethLink.getAttribute('href')).toContain(
|
||||
`/address/${fullMock.ethereumAddress}`
|
||||
);
|
||||
});
|
||||
});
|
@ -2,6 +2,10 @@ import { t } from '@vegaprotocol/react-helpers';
|
||||
import { TableRow, TableCell } from '../../../table';
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import { PartyLink } from '../../../links';
|
||||
import {
|
||||
EthExplorerLink,
|
||||
EthExplorerLinkTypes,
|
||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
||||
|
||||
interface TxDetailsChainEventStakeRemoveProps {
|
||||
remove: components['schemas']['vegaStakeRemoved'];
|
||||
@ -16,24 +20,35 @@ interface TxDetailsChainEventStakeRemoveProps {
|
||||
export const TxDetailsChainEventStakeRemove = ({
|
||||
remove,
|
||||
}: TxDetailsChainEventStakeRemoveProps) => {
|
||||
if (!remove) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
if (
|
||||
!remove ||
|
||||
!remove.ethereumAddress ||
|
||||
!remove.vegaPublicKey ||
|
||||
!remove.amount ||
|
||||
!remove.blockTime
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Chain Event type')}</TableCell>
|
||||
<TableCell>{t('Stake removed')}</TableCell>
|
||||
<TableCell>{t('Chain event type')}</TableCell>
|
||||
<TableCell>{t('Stake remove')}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Source')}</TableCell>
|
||||
<TableCell>{remove.ethereumAddress || ''}</TableCell>
|
||||
<TableCell>
|
||||
<EthExplorerLink
|
||||
id={remove.ethereumAddress}
|
||||
type={EthExplorerLinkTypes.address}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Recipient')}</TableCell>
|
||||
<TableCell>
|
||||
<PartyLink id={remove.vegaPublicKey || ''} />
|
||||
<PartyLink id={remove.vegaPublicKey} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
@ -41,7 +56,7 @@ export const TxDetailsChainEventStakeRemove = ({
|
||||
<TableCell>{remove.amount}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Deposited at')}</TableCell>
|
||||
<TableCell>{t('Removed at')}</TableCell>
|
||||
<TableCell>{remove.blockTime}</TableCell>
|
||||
</TableRow>
|
||||
</>
|
||||
|
@ -0,0 +1,73 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import omit from 'lodash/omit';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { TxDetailsChainEventStakeTotalSupply } from './tx-stake-totalsupply';
|
||||
|
||||
type TotalSupply = components['schemas']['vegaStakeTotalSupply'];
|
||||
|
||||
const fullMock: TotalSupply = {
|
||||
totalSupply: '123000000000000000000000',
|
||||
tokenAddress: 'eth123',
|
||||
};
|
||||
|
||||
describe('Chain Event: Stake total supply change', () => {
|
||||
it('Renders nothing if no good data is provided', () => {
|
||||
const mock = undefined as unknown as TotalSupply;
|
||||
const screen = render(
|
||||
<TxDetailsChainEventStakeTotalSupply update={mock} />
|
||||
);
|
||||
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('Renders nothing if correct type with no data is provided', () => {
|
||||
const mock: TotalSupply = {};
|
||||
|
||||
const screen = render(
|
||||
<TxDetailsChainEventStakeTotalSupply update={mock} />
|
||||
);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it(`Renders nothing if correct type with partial data is provided`, () => {
|
||||
for (const key in fullMock) {
|
||||
const mock = omit(fullMock, key);
|
||||
const screen = render(
|
||||
<TxDetailsChainEventStakeTotalSupply update={mock} />
|
||||
);
|
||||
expect(screen.container).toBeEmptyDOMElement();
|
||||
}
|
||||
});
|
||||
|
||||
it('Renders TableRows if all data is provided', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<table>
|
||||
<tbody>
|
||||
<TxDetailsChainEventStakeTotalSupply update={fullMock} />
|
||||
</tbody>
|
||||
</table>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(t('Chain event type'))).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(t('Stake total supply update'))
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Total supply'))).toBeInTheDocument();
|
||||
expect(screen.getByText('123,000')).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText(t('Source'))).toBeInTheDocument();
|
||||
const ethLink = screen.getByText(`${fullMock.tokenAddress}`);
|
||||
expect(ethLink.getAttribute('href')).toContain(
|
||||
`/address/${fullMock.tokenAddress}`
|
||||
);
|
||||
});
|
||||
});
|
@ -18,33 +18,32 @@ interface TxDetailsChainEventStakeTotalSupplyProps {
|
||||
export const TxDetailsChainEventStakeTotalSupply = ({
|
||||
update,
|
||||
}: TxDetailsChainEventStakeTotalSupplyProps) => {
|
||||
if (!update) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
if (!update || !update.tokenAddress || !update.totalSupply) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let totalSupply = update.totalSupply || '';
|
||||
if (totalSupply.length > 0) {
|
||||
totalSupply = formatNumber(toBigNum(totalSupply, 18));
|
||||
}
|
||||
const totalSupply =
|
||||
update.totalSupply.length > 0
|
||||
? formatNumber(toBigNum(update.totalSupply, 18))
|
||||
: update.totalSupply;
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Chain Event type')}</TableCell>
|
||||
<TableCell>{t('Chain event type')}</TableCell>
|
||||
<TableCell>{t('Stake total supply update')}</TableCell>
|
||||
</TableRow>
|
||||
|
||||
{update.tokenAddress ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Source')}</TableCell>
|
||||
<TableCell>
|
||||
<EthExplorerLink
|
||||
id={update.tokenAddress}
|
||||
type={EthExplorerLinkTypes.address}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Source')}</TableCell>
|
||||
<TableCell>
|
||||
<EthExplorerLink
|
||||
id={update.tokenAddress}
|
||||
type={EthExplorerLinkTypes.address}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Total supply')}</TableCell>
|
||||
<TableCell>{totalSupply}</TableCell>
|
||||
|
@ -75,7 +75,7 @@ export function getLabelForChainEvent(
|
||||
return t('Staking event');
|
||||
} else if (chainEvent.erc20Multisig) {
|
||||
if (chainEvent.erc20Multisig.signerAdded) {
|
||||
return t('Signer adde');
|
||||
return t('Signer added');
|
||||
} else if (chainEvent.erc20Multisig.signerRemoved) {
|
||||
return t('Signer remove');
|
||||
} else if (chainEvent.erc20Multisig.thresholdSet) {
|
||||
|
Loading…
Reference in New Issue
Block a user