Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1047167f4 | ||
|
|
3b3430b489 | ||
|
|
28bcb4ada1 | ||
|
|
5812c8858d | ||
|
|
abf146895d | ||
|
|
4476e6c6d1 | ||
|
|
d967000e8f | ||
|
|
91d3d97399 | ||
|
|
ca700aa103 | ||
|
|
265bf7fb35 | ||
|
|
7a5c6f3a25 | ||
|
|
91e3460e9d | ||
|
|
cf0c45aaa5 | ||
|
|
bf63f9d46d |
@@ -10,6 +10,7 @@ NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
||||
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.xyz/rest
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
NX_VEGA_GOVERNANCE_URL=https://stagnet1.token.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.jsoo
|
||||
|
||||
|
||||
@@ -14,10 +14,72 @@ import {
|
||||
SettlementAssetInfoPanel,
|
||||
} from '@vegaprotocol/market-info';
|
||||
import { MarketInfoTable } from '@vegaprotocol/market-info';
|
||||
import type { DataSourceDefinition } from '@vegaprotocol/types';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
|
||||
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
||||
if (!market) return null;
|
||||
|
||||
const settlementData =
|
||||
market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData
|
||||
.data;
|
||||
const terminationData =
|
||||
market.tradableInstrument.instrument.product
|
||||
.dataSourceSpecForTradingTermination.data;
|
||||
|
||||
const getSigners = (data: DataSourceDefinition) => {
|
||||
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
||||
const signers = data.sourceType.sourceType.signers || [];
|
||||
|
||||
return signers.map(({ signer }, i) => {
|
||||
return (
|
||||
(signer.__typename === 'ETHAddress' && signer.address) ||
|
||||
(signer.__typename === 'PubKey' && signer.key)
|
||||
);
|
||||
});
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
const oraclePanels = isEqual(
|
||||
getSigners(settlementData),
|
||||
getSigners(terminationData)
|
||||
)
|
||||
? [
|
||||
{
|
||||
title: t('Settlement Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel
|
||||
noBorder={false}
|
||||
market={market}
|
||||
type="settlementData"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Termination Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel
|
||||
noBorder={false}
|
||||
market={market}
|
||||
type="termination"
|
||||
/>
|
||||
),
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
title: t('Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel
|
||||
noBorder={false}
|
||||
market={market}
|
||||
type="settlementData"
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const panels = [
|
||||
{
|
||||
title: t('Key details'),
|
||||
@@ -95,22 +157,7 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
||||
<LiquidityPriceRangeInfoPanel market={market} noBorder={false} />
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Settlement Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel
|
||||
noBorder={false}
|
||||
market={market}
|
||||
type="settlementData"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Termination Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel noBorder={false} market={market} type="termination" />
|
||||
),
|
||||
},
|
||||
...oraclePanels,
|
||||
];
|
||||
|
||||
return (
|
||||
|
||||
@@ -27,7 +27,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
cy.getByTestId('app-announcement').should('not.exist');
|
||||
});
|
||||
|
||||
it('should show open or enacted proposals with proposal summary', function () {
|
||||
it('should show open or enacted proposals without proposal summary', function () {
|
||||
cy.get('body').then(($body) => {
|
||||
if (!$body.find('[data-testid="proposals-list-item"]').length) {
|
||||
cy.createMarket();
|
||||
@@ -43,12 +43,6 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId('proposal-type').invoke('text').should('not.be.empty');
|
||||
cy.getByTestId('proposal-description')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId('proposal-details')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId('proposal-status')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
function ReactMarkdown({ children }) {
|
||||
return <div>{children}</div>;
|
||||
}
|
||||
|
||||
export default ReactMarkdown;
|
||||
@@ -20,12 +20,17 @@ import type { EthereumConfig } from '@vegaprotocol/web3';
|
||||
import {
|
||||
createConnectors,
|
||||
useEthTransactionManager,
|
||||
useEthTransactionUpdater,
|
||||
useEthWithdrawApprovalsManager,
|
||||
useWeb3ConnectStore,
|
||||
} from '@vegaprotocol/web3';
|
||||
import { Web3Provider } from '@vegaprotocol/web3';
|
||||
import { VegaWalletDialogs } from './components/vega-wallet-dialogs';
|
||||
import { VegaWalletProvider } from '@vegaprotocol/wallet';
|
||||
import {
|
||||
useVegaTransactionManager,
|
||||
useVegaTransactionUpdater,
|
||||
VegaWalletProvider,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||
import {
|
||||
@@ -37,6 +42,7 @@ import { ENV } from './config';
|
||||
import type { InMemoryCacheConfig } from '@apollo/client';
|
||||
import { WithdrawalDialog } from '@vegaprotocol/withdraws';
|
||||
import { SplashLoader } from './components/splash-loader';
|
||||
import { ToastsManager } from './toasts-manager';
|
||||
|
||||
const cache: InMemoryCacheConfig = {
|
||||
typePolicies: {
|
||||
@@ -81,7 +87,10 @@ const Web3Container = ({
|
||||
providerUrl: string;
|
||||
}) => {
|
||||
const InitializeHandlers = () => {
|
||||
useVegaTransactionManager();
|
||||
useVegaTransactionUpdater();
|
||||
useEthTransactionManager();
|
||||
useEthTransactionUpdater();
|
||||
useEthWithdrawApprovalsManager();
|
||||
return null;
|
||||
};
|
||||
@@ -135,6 +144,7 @@ const Web3Container = ({
|
||||
<NetworkInfo />
|
||||
</footer>
|
||||
</AppLayout>
|
||||
<ToastsManager />
|
||||
<InitializeHandlers />
|
||||
<VegaWalletDialogs />
|
||||
<TransactionModal />
|
||||
|
||||
+33
-15
@@ -3,9 +3,10 @@ import { generateProposal } from '../../test-helpers/generate-proposals';
|
||||
import { ProposalHeader } from './proposal-header';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
|
||||
const renderComponent = (proposal: ProposalQuery['proposal']) => (
|
||||
<ProposalHeader proposal={proposal} />
|
||||
);
|
||||
const renderComponent = (
|
||||
proposal: ProposalQuery['proposal'],
|
||||
isListItem = true
|
||||
) => <ProposalHeader proposal={proposal} isListItem={isListItem} />;
|
||||
|
||||
describe('Proposal header', () => {
|
||||
it('Renders New market proposal', () => {
|
||||
@@ -40,9 +41,6 @@ describe('Proposal header', () => {
|
||||
'New some market'
|
||||
);
|
||||
expect(screen.getByTestId('proposal-type')).toHaveTextContent('New market');
|
||||
expect(screen.getByTestId('proposal-description')).toHaveTextContent(
|
||||
'A new some market'
|
||||
);
|
||||
expect(screen.getByTestId('proposal-details')).toHaveTextContent(
|
||||
'tGBP settled future.'
|
||||
);
|
||||
@@ -191,7 +189,7 @@ describe('Proposal header', () => {
|
||||
expect(screen.getByTestId('proposal-details')).toHaveTextContent('short');
|
||||
});
|
||||
|
||||
it('Renders Freeform proposal - long rationale (105 chars)', () => {
|
||||
it('Renders Freeform proposal - long rationale (105 chars) - listing', () => {
|
||||
render(
|
||||
renderComponent(
|
||||
generateProposal({
|
||||
@@ -209,16 +207,39 @@ describe('Proposal header', () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
// For a rationale over 100 chars, we expect the header to be truncated at
|
||||
// 100 chars with ellipsis and the details-one element to contain the rest.
|
||||
expect(screen.getByTestId('proposal-title')).toHaveTextContent('0x0');
|
||||
expect(screen.getByTestId('proposal-type')).toHaveTextContent('Freeform');
|
||||
expect(screen.getByTestId('proposal-description')).toHaveTextContent(
|
||||
'Class aptent taciti sociosqu ad litora torquent per conubia'
|
||||
);
|
||||
// Rationale in list view is not rendered
|
||||
expect(
|
||||
screen.queryByTestId('proposal-description')
|
||||
).not.toBeInTheDocument();
|
||||
expect(screen.getByTestId('proposal-details')).toHaveTextContent('long');
|
||||
});
|
||||
|
||||
it('Renders Freeform proposal - long rationale (105 chars) - details', () => {
|
||||
render(
|
||||
renderComponent(
|
||||
generateProposal({
|
||||
id: 'long',
|
||||
rationale: {
|
||||
title: '0x0',
|
||||
description:
|
||||
'Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean dolor.',
|
||||
},
|
||||
terms: {
|
||||
change: {
|
||||
__typename: 'NewFreeform',
|
||||
},
|
||||
},
|
||||
}),
|
||||
false
|
||||
)
|
||||
);
|
||||
expect(screen.getByTestId('proposal-description')).toHaveTextContent(
|
||||
/Class aptent/
|
||||
);
|
||||
});
|
||||
|
||||
// Remove once proposals have rationale and re-enable above tests
|
||||
it('Renders Freeform proposal - id for title', () => {
|
||||
render(
|
||||
@@ -262,9 +283,6 @@ describe('Proposal header', () => {
|
||||
expect(screen.getByTestId('proposal-type')).toHaveTextContent(
|
||||
'Update asset'
|
||||
);
|
||||
expect(screen.getByTestId('proposal-details')).toHaveTextContent(
|
||||
'Update asset'
|
||||
);
|
||||
expect(screen.getByText('foo')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
||||
+22
-8
@@ -5,13 +5,15 @@ import { Heading, SubHeading } from '../../../../components/heading';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import { truncateMiddle } from '../../../../lib/truncate-middle';
|
||||
|
||||
export const ProposalHeader = ({
|
||||
proposal,
|
||||
useSubHeading = true,
|
||||
isListItem = true,
|
||||
}: {
|
||||
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
||||
useSubHeading?: boolean;
|
||||
isListItem?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const change = proposal?.terms.change;
|
||||
@@ -95,8 +97,8 @@ export const ProposalHeader = ({
|
||||
proposalType = t('UpdateAsset');
|
||||
details = (
|
||||
<>
|
||||
`${t('Update asset')}`;
|
||||
<Lozenge>{change.assetId}</Lozenge>
|
||||
<span>{t('Asset ID')}:</span>
|
||||
<Lozenge>{truncateMiddle(change.assetId)}</Lozenge>
|
||||
</>
|
||||
);
|
||||
break;
|
||||
@@ -106,7 +108,7 @@ export const ProposalHeader = ({
|
||||
return (
|
||||
<div className="text-sm mb-2">
|
||||
<div data-testid="proposal-title">
|
||||
{useSubHeading ? (
|
||||
{isListItem ? (
|
||||
<header>
|
||||
<SubHeading title={titleContent || t('Unknown proposal')} />
|
||||
</header>
|
||||
@@ -121,9 +123,21 @@ export const ProposalHeader = ({
|
||||
<Lozenge variant={Intent.None}>{proposalType}</Lozenge>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{description && (
|
||||
<div data-testid="proposal-description">{description}</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{description && !isListItem && (
|
||||
<div data-testid="proposal-description" className="mb-4">
|
||||
<ReactMarkdown
|
||||
className="react-markdown-container"
|
||||
/* Prevents HTML embedded in the description from rendering */
|
||||
skipHtml={true}
|
||||
/* Stops users embedding images which could be used for tracking */
|
||||
disallowedElements={['img']}
|
||||
linkTarget="_blank"
|
||||
>
|
||||
{description}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ export const Proposal = ({ proposal }: ProposalProps) => {
|
||||
return (
|
||||
<AsyncRenderer data={params} loading={loading} error={error}>
|
||||
<section data-testid="proposal">
|
||||
<ProposalHeader proposal={proposal} useSubHeading={false} />
|
||||
<ProposalHeader proposal={proposal} isListItem={false} />
|
||||
<div className="mb-10">
|
||||
<ProposalChangeTable proposal={proposal} />
|
||||
</div>
|
||||
|
||||
@@ -58,3 +58,39 @@
|
||||
.validators-table .ag-theme-balham-dark *:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Styles required to (effectively) un-override the
|
||||
* reset styles so that the Proposal description fields
|
||||
* render as you'd expect them to.
|
||||
*
|
||||
* Notes:
|
||||
* - image embeds are disabled, so no styles are required
|
||||
* - strong may not be required
|
||||
* - skipHTML is enabled, so no nested HTML will be rendered. Only
|
||||
* . valid markdown
|
||||
*/
|
||||
|
||||
.dark .react-markdown-container,
|
||||
.dark .react-markdown-container li,
|
||||
.dark .react-markdown-container p {
|
||||
color: #fff;
|
||||
}
|
||||
.react-markdown-container strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.react-markdown-container ol {
|
||||
margin-left: 1em;
|
||||
}
|
||||
.react-markdown-container li {
|
||||
margin-left: 1em;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.react-markdown-container ol li {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
.react-markdown-container ul li {
|
||||
list-style: circle;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { ToastsContainer, useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
useEthereumTransactionToasts,
|
||||
useEthereumWithdrawApprovalsToasts,
|
||||
useVegaTransactionToasts,
|
||||
} from '@vegaprotocol/web3';
|
||||
|
||||
export const ToastsManager = () => {
|
||||
useVegaTransactionToasts();
|
||||
useEthereumTransactionToasts();
|
||||
useEthereumWithdrawApprovalsToasts();
|
||||
|
||||
const toasts = useToasts((store) => store.toasts);
|
||||
return <ToastsContainer order="desc" toasts={toasts} />;
|
||||
};
|
||||
|
||||
export default ToastsManager;
|
||||
@@ -48,8 +48,8 @@
|
||||
"tranche_start": "2023-04-20T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-20T00:00:00.000Z",
|
||||
"total_added": "19242.125",
|
||||
"total_removed": "1214.9959502191275",
|
||||
"locked_amount": "9457.0664415991503175975",
|
||||
"total_removed": "1523.8177488329475",
|
||||
"locked_amount": "8012.91971990740883275",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "188",
|
||||
@@ -223,6 +223,11 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "308.82179861382",
|
||||
"user": "0xDd7a98557586ce21f770662319C2047C5a3bD605",
|
||||
"tx": "0x2b3571c143ecebddf91fb62f402d516d51110edfe37b13200a6e5cf682dc5bb0"
|
||||
},
|
||||
{
|
||||
"amount": "202.093666077975",
|
||||
"user": "0x1447Efc62d5077d7AbB20492dF831Dd6c9Eb1756",
|
||||
@@ -351,6 +356,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "308.82179861382",
|
||||
"user": "0xDd7a98557586ce21f770662319C2047C5a3bD605",
|
||||
"tranche_id": 56,
|
||||
"tx": "0x2b3571c143ecebddf91fb62f402d516d51110edfe37b13200a6e5cf682dc5bb0"
|
||||
},
|
||||
{
|
||||
"amount": "195.89040769089",
|
||||
"user": "0xDd7a98557586ce21f770662319C2047C5a3bD605",
|
||||
@@ -359,8 +370,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "914.25",
|
||||
"withdrawn_tokens": "195.89040769089",
|
||||
"remaining_tokens": "718.35959230911"
|
||||
"withdrawn_tokens": "504.71220630471",
|
||||
"remaining_tokens": "409.53779369529"
|
||||
},
|
||||
{
|
||||
"address": "0x9573BDF7FfC5519912d293e4D1f750eab2E471E7",
|
||||
@@ -866,8 +877,8 @@
|
||||
"tranche_start": "2023-04-06T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-06T00:00:00.000Z",
|
||||
"total_added": "14520",
|
||||
"total_removed": "5079.76864115505",
|
||||
"locked_amount": "360.24949074073997136",
|
||||
"total_removed": "5271.61936106733",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "111",
|
||||
@@ -1021,6 +1032,11 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "191.85071991228",
|
||||
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
|
||||
"tx": "0x1438ad7d4c51ec6cb9b8f9d67b05583915099427035179baf996fd208fd76603"
|
||||
},
|
||||
{
|
||||
"amount": "106.53500000286",
|
||||
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
|
||||
@@ -1326,6 +1342,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "191.85071991228",
|
||||
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
|
||||
"tranche_id": 54,
|
||||
"tx": "0x1438ad7d4c51ec6cb9b8f9d67b05583915099427035179baf996fd208fd76603"
|
||||
},
|
||||
{
|
||||
"amount": "106.53500000286",
|
||||
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
|
||||
@@ -1364,8 +1386,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "858",
|
||||
"withdrawn_tokens": "666.14928008772",
|
||||
"remaining_tokens": "191.85071991228"
|
||||
"withdrawn_tokens": "858",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x0bBf7580e036eA5D69ABe679CC90117EeC2e3dc1",
|
||||
@@ -4737,7 +4759,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "86666.297",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "50751.8588230648417449891",
|
||||
"locked_amount": "50217.2490198462727620419",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "86666.297",
|
||||
@@ -4803,7 +4825,7 @@
|
||||
"tranche_end": "2023-06-01T00:00:00.000Z",
|
||||
"total_added": "2500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "367.3669935388685",
|
||||
"locked_amount": "336.439255189255325",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
@@ -4836,7 +4858,7 @@
|
||||
"tranche_end": "2023-11-01T00:00:00.000Z",
|
||||
"total_added": "15000.000000000000015",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "14653.0693312198065146530693312198065",
|
||||
"locked_amount": "14469.519927536232014469519927536232",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1.5e-14",
|
||||
@@ -4924,7 +4946,7 @@
|
||||
"tranche_end": "2023-09-01T00:00:00.000Z",
|
||||
"total_added": "17500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "11293.61711830716525",
|
||||
"locked_amount": "11079.476147342995",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "12500",
|
||||
@@ -5190,8 +5212,8 @@
|
||||
"tranche_start": "2023-02-01T00:00:00.000Z",
|
||||
"tranche_end": "2023-08-01T00:00:00.000Z",
|
||||
"total_added": "37500",
|
||||
"total_removed": "17836.1796921",
|
||||
"locked_amount": "18179.07122851442625",
|
||||
"total_removed": "18077.0118744",
|
||||
"locked_amount": "17712.59208103130625",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -5220,6 +5242,11 @@
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x6bb6303a6a322698e6e295ad38b2a22bd20d8b44306d423a3e513bb0b858ad56"
|
||||
},
|
||||
{
|
||||
"amount": "240.8321823",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xe27cfead07bc34f4270f7f87b9146e9f6fa35d0cc5e20b2378a03265de432289"
|
||||
},
|
||||
{
|
||||
"amount": "126.30064455",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -5390,6 +5417,12 @@
|
||||
"tranche_id": 34,
|
||||
"tx": "0x6bb6303a6a322698e6e295ad38b2a22bd20d8b44306d423a3e513bb0b858ad56"
|
||||
},
|
||||
{
|
||||
"amount": "240.8321823",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 34,
|
||||
"tx": "0xe27cfead07bc34f4270f7f87b9146e9f6fa35d0cc5e20b2378a03265de432289"
|
||||
},
|
||||
{
|
||||
"amount": "126.30064455",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -5554,8 +5587,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "7500",
|
||||
"withdrawn_tokens": "3626.4210213",
|
||||
"remaining_tokens": "3873.5789787"
|
||||
"withdrawn_tokens": "3867.2532036",
|
||||
"remaining_tokens": "3632.7467964"
|
||||
},
|
||||
{
|
||||
"address": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
|
||||
@@ -5599,7 +5632,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "129999.45",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "50705.5541377325336221035",
|
||||
"locked_amount": "50171.43209869220647854",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129999.45",
|
||||
@@ -5632,7 +5665,7 @@
|
||||
"tranche_end": "2024-04-01T00:00:00.000Z",
|
||||
"total_added": "54144.7663",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "49077.09978780568889746099",
|
||||
"locked_amount": "48744.01489157271082711146",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "54144.7663",
|
||||
@@ -5665,7 +5698,7 @@
|
||||
"tranche_end": "2023-09-03T00:00:00.000Z",
|
||||
"total_added": "62600",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "20708.477403602233016",
|
||||
"locked_amount": "20322.3229832572315",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10000",
|
||||
@@ -5858,7 +5891,7 @@
|
||||
"tranche_end": "2023-09-17T00:00:00.000Z",
|
||||
"total_added": "5000",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "1845.81256341958375",
|
||||
"locked_amount": "1814.9695585996955",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "5000",
|
||||
@@ -6398,7 +6431,7 @@
|
||||
"tranche_start": "2022-11-01T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-01T00:00:00.000Z",
|
||||
"total_added": "22500",
|
||||
"total_removed": "7438.558452225",
|
||||
"total_removed": "7500",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
@@ -6423,6 +6456,11 @@
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xb76564ca91603758216069d7b139c683037029425e10b1694af25b478c19e26f"
|
||||
},
|
||||
{
|
||||
"amount": "61.441547775",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xbf247e382e7cbfd131b20942525b6a11a8d71b5dae727cf8ad0f0801a48572b7"
|
||||
},
|
||||
{
|
||||
"amount": "126.2948895",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -6648,6 +6686,12 @@
|
||||
"tranche_id": 33,
|
||||
"tx": "0xb76564ca91603758216069d7b139c683037029425e10b1694af25b478c19e26f"
|
||||
},
|
||||
{
|
||||
"amount": "61.441547775",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 33,
|
||||
"tx": "0xbf247e382e7cbfd131b20942525b6a11a8d71b5dae727cf8ad0f0801a48572b7"
|
||||
},
|
||||
{
|
||||
"amount": "126.2948895",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -6890,8 +6934,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "7500",
|
||||
"withdrawn_tokens": "7438.558452225",
|
||||
"remaining_tokens": "61.441547775"
|
||||
"withdrawn_tokens": "7500",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x2539b51EbDE65a75672aBcfE9439a706a99D18D1",
|
||||
@@ -6916,7 +6960,7 @@
|
||||
"tranche_end": "2023-06-02T00:00:00.000Z",
|
||||
"total_added": "1939928.38",
|
||||
"total_removed": "1709370.7872515768348",
|
||||
"locked_amount": "147457.5018725717723958",
|
||||
"locked_amount": "135490.8577976559580829712",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1852091.69",
|
||||
@@ -40788,7 +40832,7 @@
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "3732368.4671",
|
||||
"total_removed": "715655.108029600523393",
|
||||
"locked_amount": "251092.165858100635559352498",
|
||||
"locked_amount": "232703.600257911276488373015",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1998.95815",
|
||||
@@ -42180,8 +42224,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "15870102.715470999700000001",
|
||||
"total_removed": "869802.17678213314859352",
|
||||
"locked_amount": "6190044.28411574715560088425053188532414163",
|
||||
"total_removed": "871680.07831804700259352",
|
||||
"locked_amount": "6124839.6111562323029172253655785658718572",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "16249.93",
|
||||
@@ -42685,6 +42729,11 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "967.6813834225175",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x625e0c8fb8d5e2dd7fef0359bb396571f7d8aed05a601ddf0f6e6577edb26a13"
|
||||
},
|
||||
{
|
||||
"amount": "10150.87581603206683",
|
||||
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
|
||||
@@ -42740,6 +42789,11 @@
|
||||
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
|
||||
"tx": "0xa809dbfa0c31522127924306a6117331a578dfc402cf5fa464832baec46e4ac2"
|
||||
},
|
||||
{
|
||||
"amount": "910.2201524913365",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x24d004bb729a8d3e7df9be45895e411b7c3f8341a08737d41284acf79b3e9e53"
|
||||
},
|
||||
{
|
||||
"amount": "981.387731774910625",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -44848,6 +44902,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "967.6813834225175",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x625e0c8fb8d5e2dd7fef0359bb396571f7d8aed05a601ddf0f6e6577edb26a13"
|
||||
},
|
||||
{
|
||||
"amount": "913.910324501590625",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -44890,6 +44950,12 @@
|
||||
"tranche_id": 2,
|
||||
"tx": "0xc5cea08b124cdf6264d5b0c7494d63d9de264b429822d9a4e4cfadc43e611a1b"
|
||||
},
|
||||
{
|
||||
"amount": "910.2201524913365",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x24d004bb729a8d3e7df9be45895e411b7c3f8341a08737d41284acf79b3e9e53"
|
||||
},
|
||||
{
|
||||
"amount": "981.387731774910625",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -46398,8 +46464,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "259998.8875",
|
||||
"withdrawn_tokens": "157712.620568472569875",
|
||||
"remaining_tokens": "102286.266931527430125"
|
||||
"withdrawn_tokens": "159590.522104386423875",
|
||||
"remaining_tokens": "100408.365395613576125"
|
||||
},
|
||||
{
|
||||
"address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c",
|
||||
@@ -48780,7 +48846,7 @@
|
||||
"tranche_start": "2021-11-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-05T00:00:00.000Z",
|
||||
"total_added": "14597706.0446472999",
|
||||
"total_removed": "6169862.126766503085603932",
|
||||
"total_removed": "6170228.182342542771392682",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
@@ -49045,6 +49111,11 @@
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0x35f722557b9bc3a2dc314f9fac173013697c484059bd8d5c65497f8df72b9097"
|
||||
},
|
||||
{
|
||||
"amount": "366.05557603968578875",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0xf03a210cb8c386c7bae72a07c1d20e50eb9a9743c5cd5df4b5e016f1e103f73f"
|
||||
},
|
||||
{
|
||||
"amount": "1360.32447632896938825",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@@ -52393,6 +52464,12 @@
|
||||
"tranche_id": 3,
|
||||
"tx": "0x35f722557b9bc3a2dc314f9fac173013697c484059bd8d5c65497f8df72b9097"
|
||||
},
|
||||
{
|
||||
"amount": "366.05557603968578875",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0xf03a210cb8c386c7bae72a07c1d20e50eb9a9743c5cd5df4b5e016f1e103f73f"
|
||||
},
|
||||
{
|
||||
"amount": "1360.32447632896938825",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@@ -55215,8 +55292,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "359123.469575",
|
||||
"withdrawn_tokens": "358757.41399896031421125",
|
||||
"remaining_tokens": "366.05557603968578875"
|
||||
"withdrawn_tokens": "359123.469575",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
|
||||
@@ -58890,8 +58967,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "472355.6199999996",
|
||||
"total_removed": "44110.3307271943416",
|
||||
"locked_amount": "39786.9889842268933819326661593",
|
||||
"total_removed": "44479.0535455583416",
|
||||
"locked_amount": "36873.21565135463531748005175036",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "3000",
|
||||
@@ -65510,6 +65587,11 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "368.722818364",
|
||||
"user": "0x0436E2E4EA467f9958403dc56635404EE1bb1E94",
|
||||
"tx": "0x97f5b5ec5ac839a8d182b9267b5d052cb70f9a18b648874337e3d5360b21a5fb"
|
||||
},
|
||||
{
|
||||
"amount": "182.662252664",
|
||||
"user": "0xb1169C6daAc76bAcaf0D8f87641Fc38fbabe569F",
|
||||
@@ -81719,10 +81801,17 @@
|
||||
"tx": "0xb1425d9b0d5f10c5b06236d6f9d61ebddd21c4027e0f41deb5ec227a1753c715"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "368.722818364",
|
||||
"user": "0x0436E2E4EA467f9958403dc56635404EE1bb1E94",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x97f5b5ec5ac839a8d182b9267b5d052cb70f9a18b648874337e3d5360b21a5fb"
|
||||
}
|
||||
],
|
||||
"total_tokens": "400",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "400"
|
||||
"withdrawn_tokens": "368.722818364",
|
||||
"remaining_tokens": "31.277181636"
|
||||
},
|
||||
{
|
||||
"address": "0x6672F8789C54b49C596E6e7Ca3A72726Fc4C400E",
|
||||
|
||||
@@ -184,17 +184,9 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
.getByTestId('provider-name')
|
||||
.and('contain', 'Another oracle');
|
||||
|
||||
cy.getByTestId(accordionContent)
|
||||
.getByTestId('signed-proofs')
|
||||
.and('contain', '1');
|
||||
|
||||
cy.getByTestId(accordionContent)
|
||||
.getByTestId('verified-proofs')
|
||||
.and('contain', '1');
|
||||
|
||||
cy.getByTestId(accordionContent)
|
||||
.getByTestId('signed-proofs')
|
||||
.and('contain', '1');
|
||||
});
|
||||
|
||||
it('proposal displayed', () => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { ToastsContainer, useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import { useUpdateNetworkParametersToasts } from '@vegaprotocol/proposals';
|
||||
import { useVegaTransactionToasts } from '../lib/hooks/use-vega-transaction-toasts';
|
||||
import { useEthereumTransactionToasts } from '../lib/hooks/use-ethereum-transaction-toasts';
|
||||
import { useEthereumWithdrawApprovalsToasts } from '../lib/hooks/use-ethereum-withdraw-approval-toasts';
|
||||
import { useVegaTransactionToasts } from '@vegaprotocol/web3';
|
||||
import { useEthereumTransactionToasts } from '@vegaprotocol/web3';
|
||||
import { useEthereumWithdrawApprovalsToasts } from '@vegaprotocol/web3';
|
||||
|
||||
export const ToastsManager = () => {
|
||||
useUpdateNetworkParametersToasts();
|
||||
|
||||
@@ -260,7 +260,9 @@ export const DepositForm = ({
|
||||
<AssetOption
|
||||
asset={asset}
|
||||
key={asset.id}
|
||||
balance={<AssetBalance asset={asset} />}
|
||||
balance={
|
||||
isActive && account && <AssetBalance asset={asset} />
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</RichSelect>
|
||||
|
||||
@@ -198,4 +198,4 @@ export function useMarketInfoLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions
|
||||
}
|
||||
export type MarketInfoQueryHookResult = ReturnType<typeof useMarketInfoQuery>;
|
||||
export type MarketInfoLazyQueryHookResult = ReturnType<typeof useMarketInfoLazyQuery>;
|
||||
export type MarketInfoQueryResult = Apollo.QueryResult<MarketInfoQuery, MarketInfoQueryVariables>;
|
||||
export type MarketInfoQueryResult = Apollo.QueryResult<MarketInfoQuery, MarketInfoQueryVariables>;
|
||||
@@ -35,6 +35,8 @@ import {
|
||||
RiskParametersInfoPanel,
|
||||
SettlementAssetInfoPanel,
|
||||
} from './market-info-panels';
|
||||
import type { DataSourceDefinition } from '@vegaprotocol/types';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
|
||||
export interface MarketInfoAccordionProps {
|
||||
market: MarketInfo;
|
||||
@@ -70,7 +72,7 @@ export const MarketInfoAccordionContainer = ({
|
||||
);
|
||||
};
|
||||
|
||||
const MarketInfoAccordion = ({
|
||||
export const MarketInfoAccordion = ({
|
||||
market,
|
||||
onSelect,
|
||||
}: MarketInfoAccordionProps) => {
|
||||
@@ -103,8 +105,64 @@ const MarketInfoAccordion = ({
|
||||
content: <InsurancePoolInfoPanel market={market} account={a} />,
|
||||
})),
|
||||
];
|
||||
const product = market.tradableInstrument.instrument.product;
|
||||
const settlementData =
|
||||
market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData
|
||||
.data;
|
||||
const terminationData =
|
||||
market.tradableInstrument.instrument.product
|
||||
.dataSourceSpecForTradingTermination.data;
|
||||
|
||||
const getSigners = (data: DataSourceDefinition) => {
|
||||
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
||||
const signers = data.sourceType.sourceType.signers || [];
|
||||
|
||||
return signers.map(({ signer }, i) => {
|
||||
return (
|
||||
(signer.__typename === 'ETHAddress' && signer.address) ||
|
||||
(signer.__typename === 'PubKey' && signer.key)
|
||||
);
|
||||
});
|
||||
}
|
||||
return [];
|
||||
};
|
||||
const oraclePanels = isEqual(
|
||||
getSigners(settlementData),
|
||||
getSigners(terminationData)
|
||||
)
|
||||
? [
|
||||
{
|
||||
title: t('Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel
|
||||
noBorder={false}
|
||||
market={market}
|
||||
type="settlementData"
|
||||
/>
|
||||
),
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
title: t('Settlement Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel
|
||||
noBorder={false}
|
||||
market={market}
|
||||
type="settlementData"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Termination Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel
|
||||
noBorder={false}
|
||||
market={market}
|
||||
type="termination"
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
const marketSpecPanels = [
|
||||
{
|
||||
title: t('Key details'),
|
||||
@@ -114,14 +172,7 @@ const MarketInfoAccordion = ({
|
||||
title: t('Instrument'),
|
||||
content: <InstrumentInfoPanel market={market} />,
|
||||
},
|
||||
product.dataSourceSpecForSettlementData && {
|
||||
title: t('Settlement Oracle'),
|
||||
content: <OracleInfoPanel market={market} type="settlementData" />,
|
||||
},
|
||||
product.dataSourceSpecForTradingTermination && {
|
||||
title: t('Termination Oracle'),
|
||||
content: <OracleInfoPanel market={market} type="termination" />,
|
||||
},
|
||||
...oraclePanels,
|
||||
{
|
||||
title: t('Settlement asset'),
|
||||
content: <SettlementAssetInfoPanel market={market} />,
|
||||
@@ -182,33 +233,37 @@ const MarketInfoAccordion = ({
|
||||
title: t('Proposal'),
|
||||
content: (
|
||||
<div className="">
|
||||
<ExternalLink
|
||||
className="mb-2 w-full"
|
||||
href={generatePath(TokenLinks.PROPOSAL_PAGE, {
|
||||
tokenUrl: VEGA_TOKEN_URL,
|
||||
proposalId: market.proposal?.id || '',
|
||||
})}
|
||||
title={
|
||||
market.proposal?.rationale.title ||
|
||||
market.proposal?.rationale.description ||
|
||||
''
|
||||
}
|
||||
>
|
||||
{t('View governance proposal')}
|
||||
</ExternalLink>
|
||||
<ExternalLink
|
||||
className="w-full"
|
||||
href={generatePath(TokenLinks.UPDATE_PROPOSAL_PAGE, {
|
||||
tokenUrl: VEGA_TOKEN_URL,
|
||||
})}
|
||||
title={
|
||||
market.proposal?.rationale.title ||
|
||||
market.proposal?.rationale.description ||
|
||||
''
|
||||
}
|
||||
>
|
||||
{t('Propose a change to market')}
|
||||
</ExternalLink>
|
||||
{VEGA_TOKEN_URL && (
|
||||
<ExternalLink
|
||||
className="mb-2 w-full"
|
||||
href={generatePath(TokenLinks.PROPOSAL_PAGE, {
|
||||
tokenUrl: VEGA_TOKEN_URL,
|
||||
proposalId: market.proposal?.id || '',
|
||||
})}
|
||||
title={
|
||||
market.proposal?.rationale.title ||
|
||||
market.proposal?.rationale.description ||
|
||||
''
|
||||
}
|
||||
>
|
||||
{t('View governance proposal')}
|
||||
</ExternalLink>
|
||||
)}
|
||||
{VEGA_TOKEN_URL && (
|
||||
<ExternalLink
|
||||
className="w-full"
|
||||
href={generatePath(TokenLinks.UPDATE_PROPOSAL_PAGE, {
|
||||
tokenUrl: VEGA_TOKEN_URL,
|
||||
})}
|
||||
title={
|
||||
market.proposal?.rationale.title ||
|
||||
market.proposal?.rationale.description ||
|
||||
''
|
||||
}
|
||||
>
|
||||
{t('Propose a change to market')}
|
||||
</ExternalLink>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
@@ -225,7 +280,7 @@ const MarketInfoAccordion = ({
|
||||
<h3 className={headerClassName}>{t('Market specification')}</h3>
|
||||
<Accordion panels={marketSpecPanels} />
|
||||
</div>
|
||||
{VEGA_TOKEN_URL && market.proposal?.id && (
|
||||
{VEGA_TOKEN_URL && marketGovPanels && market.proposal?.id && (
|
||||
<div>
|
||||
<h3 className={headerClassName}>{t('Market governance')}</h3>
|
||||
<Accordion panels={marketGovPanels} />
|
||||
|
||||
@@ -5,62 +5,13 @@ import {
|
||||
} from '@vegaprotocol/types';
|
||||
import { DataSourceProof } from './market-info-panels';
|
||||
|
||||
jest.mock('@vegaprotocol/oracles', () => ({
|
||||
useOracleMarkets: () => [],
|
||||
}));
|
||||
|
||||
describe('DataSourceProof', () => {
|
||||
const ORACLE_PUBKEY =
|
||||
'69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f';
|
||||
it('renders correct proof for external data sources', () => {
|
||||
const props = {
|
||||
data: {
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionExternal' as const,
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfiguration' as const,
|
||||
signers: [
|
||||
{
|
||||
__typename: 'Signer' as const,
|
||||
signer: {
|
||||
__typename: 'PubKey' as const,
|
||||
key: ORACLE_PUBKEY,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
providers: [
|
||||
{
|
||||
name: 'Another oracle',
|
||||
url: 'https://zombo.com',
|
||||
description_markdown:
|
||||
'Some markdown describing the oracle provider.\n\nTwitter: @FacesPics2\n',
|
||||
oracle: {
|
||||
status: 'GOOD' as const,
|
||||
status_reason: '',
|
||||
first_verified: '2022-01-01T00:00:00.000Z',
|
||||
last_verified: '2022-12-31T00:00:00.000Z',
|
||||
type: 'public_key' as const,
|
||||
public_key: ORACLE_PUBKEY,
|
||||
},
|
||||
proofs: [
|
||||
{
|
||||
format: 'signed_message' as const,
|
||||
available: true,
|
||||
type: 'public_key' as const,
|
||||
public_key: ORACLE_PUBKEY,
|
||||
message: 'SOMEHEX',
|
||||
},
|
||||
],
|
||||
github_link: `https://github.com/vegaprotocol/well-known/blob/main/oracle-providers/PubKey-${ORACLE_PUBKEY}.toml`,
|
||||
},
|
||||
],
|
||||
type: 'termination' as const,
|
||||
};
|
||||
render(<DataSourceProof {...props} />);
|
||||
expect(screen.getByRole('link')).toHaveAttribute(
|
||||
'href',
|
||||
props.providers[0].github_link
|
||||
);
|
||||
});
|
||||
|
||||
it('renders message if there are no providers', () => {
|
||||
const props = {
|
||||
@@ -84,7 +35,7 @@ describe('DataSourceProof', () => {
|
||||
providers: [],
|
||||
type: 'termination' as const,
|
||||
};
|
||||
render(<DataSourceProof {...props} />);
|
||||
render(<DataSourceProof id={''} {...props} />);
|
||||
expect(
|
||||
screen.getByText('No oracle proof for termination')
|
||||
).toBeInTheDocument();
|
||||
@@ -137,7 +88,7 @@ describe('DataSourceProof', () => {
|
||||
],
|
||||
type: 'settlementData' as const,
|
||||
};
|
||||
render(<DataSourceProof {...props} />);
|
||||
render(<DataSourceProof id={''} {...props} />);
|
||||
expect(
|
||||
screen.getByText('No oracle proof for settlement data')
|
||||
).toBeInTheDocument();
|
||||
@@ -177,7 +128,7 @@ describe('DataSourceProof', () => {
|
||||
providers: [],
|
||||
type: 'termination' as const,
|
||||
};
|
||||
render(<DataSourceProof {...props} />);
|
||||
render(<DataSourceProof id={''} {...props} />);
|
||||
expect(screen.getByText('Internal conditions')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { ComponentProps } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
@@ -6,7 +7,7 @@ import {
|
||||
totalFeesPercentage,
|
||||
marketDataProvider,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import { ExternalLink, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { Dialog, ExternalLink, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumber,
|
||||
@@ -26,7 +27,12 @@ import { ConditionOperatorMapping } from '@vegaprotocol/types';
|
||||
import { MarketTradingModeMapping } from '@vegaprotocol/types';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import type { Provider } from '@vegaprotocol/oracles';
|
||||
import { OracleBasicProfile, useOracleProofs } from '@vegaprotocol/oracles';
|
||||
import { OracleProfileTitle, OracleFullProfile } from '@vegaprotocol/oracles';
|
||||
import {
|
||||
OracleBasicProfile,
|
||||
useOracleProofs,
|
||||
useOracleMarkets,
|
||||
} from '@vegaprotocol/oracles';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
|
||||
type PanelProps = Pick<
|
||||
@@ -456,6 +462,11 @@ export const OracleInfoPanel = ({
|
||||
const { VEGA_EXPLORER_URL, ORACLE_PROOFS_URL } = useEnvironment();
|
||||
const { data } = useOracleProofs(ORACLE_PROOFS_URL);
|
||||
|
||||
const dataSourceSpecId =
|
||||
type === 'settlementData'
|
||||
? product.dataSourceSpecForSettlementData.id
|
||||
: product.dataSourceSpecForTradingTermination.id;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<DataSourceProof
|
||||
@@ -467,6 +478,7 @@ export const OracleInfoPanel = ({
|
||||
}
|
||||
providers={data}
|
||||
type={type}
|
||||
id={dataSourceSpecId}
|
||||
/>
|
||||
<ExternalLink
|
||||
data-testid="oracle-spec-links"
|
||||
@@ -488,10 +500,12 @@ export const DataSourceProof = ({
|
||||
data,
|
||||
providers,
|
||||
type,
|
||||
id,
|
||||
}: {
|
||||
data: DataSourceDefinition;
|
||||
providers: Provider[] | undefined;
|
||||
type: 'settlementData' | 'termination';
|
||||
id: string;
|
||||
}) => {
|
||||
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
||||
const signers = data.sourceType.sourceType.signers || [];
|
||||
@@ -509,7 +523,7 @@ export const DataSourceProof = ({
|
||||
providers={providers}
|
||||
signer={signer}
|
||||
type={type}
|
||||
index={i}
|
||||
id={id}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@@ -540,11 +554,12 @@ const OracleLink = ({
|
||||
providers,
|
||||
signer,
|
||||
type,
|
||||
id,
|
||||
}: {
|
||||
providers: Provider[];
|
||||
signer: SignerKind;
|
||||
type: 'settlementData' | 'termination';
|
||||
index: number;
|
||||
id: string;
|
||||
}) => {
|
||||
const signerProviders = providers.filter((p) => {
|
||||
if (signer.__typename === 'PubKey') {
|
||||
@@ -575,10 +590,7 @@ const OracleLink = ({
|
||||
return (
|
||||
<div>
|
||||
{signerProviders.map((provider) => (
|
||||
<OracleBasicProfile
|
||||
key={provider.name}
|
||||
provider={provider}
|
||||
></OracleBasicProfile>
|
||||
<OracleProfile key={id} provider={provider} id={id} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
@@ -598,3 +610,36 @@ const NoOracleProof = ({
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
const OracleProfile = ({
|
||||
provider,
|
||||
id,
|
||||
}: {
|
||||
provider: Provider;
|
||||
id: string;
|
||||
}) => {
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const oracleMarkets = useOracleMarkets(provider);
|
||||
return (
|
||||
<div key={provider.name}>
|
||||
<OracleBasicProfile
|
||||
provider={provider}
|
||||
onClick={() => setDialogOpen(!dialogOpen)}
|
||||
markets={oracleMarkets}
|
||||
/>
|
||||
<Dialog
|
||||
title={<OracleProfileTitle provider={provider} />}
|
||||
open={dialogOpen}
|
||||
onChange={() => setDialogOpen(!dialogOpen)}
|
||||
aria-labelledby="oracle-proof-dialog"
|
||||
>
|
||||
<OracleFullProfile
|
||||
provider={provider}
|
||||
id={id}
|
||||
key={id}
|
||||
markets={oracleMarkets}
|
||||
/>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1 +1,7 @@
|
||||
import '@testing-library/jest-dom';
|
||||
import 'jest-canvas-mock';
|
||||
import ResizeObserver from 'resize-observer-polyfill';
|
||||
import { defaultFallbackInView } from 'react-intersection-observer';
|
||||
|
||||
defaultFallbackInView(true);
|
||||
global.ResizeObserver = ResizeObserver;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -0,0 +1,63 @@
|
||||
fragment OracleMarketSpecFields on Market {
|
||||
id
|
||||
state
|
||||
tradingMode
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
id
|
||||
name
|
||||
code
|
||||
product {
|
||||
... on Future {
|
||||
dataSourceSpecForSettlementData {
|
||||
id
|
||||
data {
|
||||
...DataSourceSpec
|
||||
}
|
||||
}
|
||||
dataSourceSpecForTradingTermination {
|
||||
id
|
||||
data {
|
||||
...DataSourceSpec
|
||||
}
|
||||
}
|
||||
dataSourceSpecBinding {
|
||||
settlementDataProperty
|
||||
tradingTerminationProperty
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment DataSourceSpec on DataSourceDefinition {
|
||||
sourceType {
|
||||
... on DataSourceDefinitionExternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfiguration {
|
||||
signers {
|
||||
signer {
|
||||
... on PubKey {
|
||||
key
|
||||
}
|
||||
... on ETHAddress {
|
||||
address
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query OracleMarketsSpec {
|
||||
marketsConnection {
|
||||
edges {
|
||||
node {
|
||||
...OracleMarketSpecFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
|
||||
export type OracleMarketSpecFieldsFragment = { __typename?: 'Market', id: string, state: Types.MarketState, tradingMode: Types.MarketTradingMode, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } } } };
|
||||
|
||||
export type DataSourceSpecFragment = { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } };
|
||||
|
||||
export type OracleMarketsSpecQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type OracleMarketsSpecQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, state: Types.MarketState, tradingMode: Types.MarketTradingMode, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } } } } }> } | null };
|
||||
|
||||
export const DataSourceSpecFragmentDoc = gql`
|
||||
fragment DataSourceSpec on DataSourceDefinition {
|
||||
sourceType {
|
||||
... on DataSourceDefinitionExternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfiguration {
|
||||
signers {
|
||||
signer {
|
||||
... on PubKey {
|
||||
key
|
||||
}
|
||||
... on ETHAddress {
|
||||
address
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const OracleMarketSpecFieldsFragmentDoc = gql`
|
||||
fragment OracleMarketSpecFields on Market {
|
||||
id
|
||||
state
|
||||
tradingMode
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
id
|
||||
name
|
||||
code
|
||||
product {
|
||||
... on Future {
|
||||
dataSourceSpecForSettlementData {
|
||||
id
|
||||
data {
|
||||
...DataSourceSpec
|
||||
}
|
||||
}
|
||||
dataSourceSpecForTradingTermination {
|
||||
id
|
||||
data {
|
||||
...DataSourceSpec
|
||||
}
|
||||
}
|
||||
dataSourceSpecBinding {
|
||||
settlementDataProperty
|
||||
tradingTerminationProperty
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${DataSourceSpecFragmentDoc}`;
|
||||
export const OracleMarketsSpecDocument = gql`
|
||||
query OracleMarketsSpec {
|
||||
marketsConnection {
|
||||
edges {
|
||||
node {
|
||||
...OracleMarketSpecFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${OracleMarketSpecFieldsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useOracleMarketsSpecQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useOracleMarketsSpecQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useOracleMarketsSpecQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useOracleMarketsSpecQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useOracleMarketsSpecQuery(baseOptions?: Apollo.QueryHookOptions<OracleMarketsSpecQuery, OracleMarketsSpecQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<OracleMarketsSpecQuery, OracleMarketsSpecQueryVariables>(OracleMarketsSpecDocument, options);
|
||||
}
|
||||
export function useOracleMarketsSpecLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<OracleMarketsSpecQuery, OracleMarketsSpecQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<OracleMarketsSpecQuery, OracleMarketsSpecQueryVariables>(OracleMarketsSpecDocument, options);
|
||||
}
|
||||
export type OracleMarketsSpecQueryHookResult = ReturnType<typeof useOracleMarketsSpecQuery>;
|
||||
export type OracleMarketsSpecLazyQueryHookResult = ReturnType<typeof useOracleMarketsSpecLazyQuery>;
|
||||
export type OracleMarketsSpecQueryResult = Apollo.QueryResult<OracleMarketsSpecQuery, OracleMarketsSpecQueryVariables>;
|
||||
@@ -1 +1,2 @@
|
||||
export * from './oracle-basic-profile';
|
||||
export * from './oracle-full-profile';
|
||||
|
||||
@@ -35,11 +35,10 @@ describe('OracleBasicProfile', () => {
|
||||
});
|
||||
|
||||
it('should render the name', () => {
|
||||
render(<OracleBasicProfile provider={testProvider} />);
|
||||
render(<OracleBasicProfile provider={testProvider} markets={undefined} />);
|
||||
expect(screen.getByTestId('provider-name')).toHaveTextContent(
|
||||
'Test oracle'
|
||||
);
|
||||
expect(screen.getByTestId('verified-proofs')).toHaveTextContent('1');
|
||||
expect(screen.getByTestId('signed-proofs')).toHaveTextContent('1');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { Provider } from '../../oracle-schema';
|
||||
import {
|
||||
ButtonLink,
|
||||
ExternalLink,
|
||||
Icon,
|
||||
Intent,
|
||||
Link,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { IconName } from '@blueprintjs/icons';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import classNames from 'classnames';
|
||||
import type { OracleMarketSpecFieldsFragment } from '../../__generated__/OracleMarketsSpec';
|
||||
|
||||
const getVerifiedStatusIcon = (provider: Provider) => {
|
||||
export const getVerifiedStatusIcon = (provider: Provider) => {
|
||||
const getIconIntent = () => {
|
||||
switch (provider.oracle.status) {
|
||||
case 'GOOD':
|
||||
@@ -54,17 +55,21 @@ const getVerifiedStatusIcon = (provider: Provider) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const OracleBasicProfile = ({ provider }: { provider: Provider }) => {
|
||||
export const OracleBasicProfile = ({
|
||||
provider,
|
||||
onClick,
|
||||
markets: oracleMarkets,
|
||||
}: {
|
||||
provider: Provider;
|
||||
markets?: OracleMarketSpecFieldsFragment[] | undefined;
|
||||
onClick?: (value?: boolean) => void;
|
||||
}) => {
|
||||
const { icon, message, intent } = getVerifiedStatusIcon(provider);
|
||||
|
||||
const verifiedProofs = provider.proofs.filter(
|
||||
(proof) => proof.available === true
|
||||
);
|
||||
|
||||
const signedProofs = provider.proofs.filter(
|
||||
(proof) => proof.format === 'signed_message' && proof.available === true
|
||||
);
|
||||
|
||||
const links = provider.proofs
|
||||
.filter((proof) => proof.format === 'url' && proof.available === true)
|
||||
.map((proof) => ({
|
||||
@@ -77,23 +82,20 @@ export const OracleBasicProfile = ({ provider }: { provider: Provider }) => {
|
||||
<>
|
||||
<span className="flex gap-1">
|
||||
{provider.url && (
|
||||
<Link
|
||||
href={provider.github_link}
|
||||
className="flex align-items-bottom text-md"
|
||||
target="_blank"
|
||||
>
|
||||
<span>
|
||||
<span data-testid="provider-name" className="underline pr-1">
|
||||
{provider.name}
|
||||
</span>
|
||||
<span
|
||||
data-testid="verified-proofs"
|
||||
className="dark:text-vega-light-300 text-vega-dark-300"
|
||||
>
|
||||
({verifiedProofs.length})
|
||||
</span>
|
||||
<span className="flex align-items-bottom text-md gap-1">
|
||||
<ButtonLink
|
||||
onClick={() => onClick && onClick(true)}
|
||||
data-testid="provider-name"
|
||||
>
|
||||
{provider.name}
|
||||
</ButtonLink>
|
||||
<span
|
||||
className="dark:text-vega-light-300 text-vega-dark-300"
|
||||
data-testid="verified-proofs"
|
||||
>
|
||||
({verifiedProofs.length})
|
||||
</span>
|
||||
</Link>
|
||||
</span>
|
||||
)}
|
||||
<span
|
||||
className={classNames(
|
||||
@@ -115,10 +117,11 @@ export const OracleBasicProfile = ({ provider }: { provider: Provider }) => {
|
||||
data-testid="signed-proofs"
|
||||
className="dark:text-vega-light-300 text-vega-dark-300"
|
||||
>
|
||||
{t('Involved in %s %s', [
|
||||
signedProofs.length.toString(),
|
||||
signedProofs.length !== 1 ? t('markets') : t('market'),
|
||||
])}
|
||||
{oracleMarkets &&
|
||||
t('Involved in %s %s', [
|
||||
oracleMarkets.length.toString(),
|
||||
oracleMarkets.length !== 1 ? t('markets') : t('market'),
|
||||
])}
|
||||
</p>
|
||||
{links.length > 0 && (
|
||||
<div className="flex flex-row gap-1">
|
||||
@@ -133,7 +136,7 @@ export const OracleBasicProfile = ({ provider }: { provider: Provider }) => {
|
||||
<VegaIcon name={getLinkIcon(link.type)} />
|
||||
</span>
|
||||
<span className="underline capitalize">
|
||||
{link.type}{' '}
|
||||
{link.type}
|
||||
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={13} />
|
||||
</span>
|
||||
</ExternalLink>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './oracle-full-profile.stories';
|
||||
export * from './oracle-full-profile';
|
||||
@@ -0,0 +1,54 @@
|
||||
import { OracleFullProfile } from './oracle-full-profile';
|
||||
import type { Provider } from '../../oracle-schema';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
describe('OracleFullProfile', () => {
|
||||
const testProvider = {
|
||||
name: 'Test oracle',
|
||||
url: 'https://zombo.com',
|
||||
description_markdown:
|
||||
'Some markdown describing the oracle provider.\n\nTwitter: @FacesPics2\n',
|
||||
oracle: {
|
||||
status: 'GOOD',
|
||||
status_reason: '',
|
||||
first_verified: '2023-02-28T00:00:00.000Z',
|
||||
last_verified: '2023-02-28T00:00:00.000Z',
|
||||
type: 'eth_address',
|
||||
eth_address: '0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC',
|
||||
},
|
||||
proofs: [
|
||||
{
|
||||
format: 'signed_message',
|
||||
available: true,
|
||||
type: 'eth_address',
|
||||
eth_address: '0x949AF81E51D57831AE52591d17fBcdd1014a5f52',
|
||||
message: 'SOMEHEX',
|
||||
},
|
||||
],
|
||||
github_link:
|
||||
'https://github.com/vegaprotocol/well-known/blob/main/oracle-providers/eth_address-0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC.toml',
|
||||
} as Provider;
|
||||
|
||||
it('should render successfully', () => {
|
||||
const component = (
|
||||
<OracleFullProfile provider={testProvider} id={''} markets={[]} />
|
||||
);
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render the name', () => {
|
||||
render(
|
||||
<OracleFullProfile
|
||||
provider={testProvider}
|
||||
id={'oracle-id'}
|
||||
markets={[]}
|
||||
/>
|
||||
);
|
||||
expect(screen.getByTestId('github-link')).toHaveTextContent(
|
||||
'Oracle repository'
|
||||
);
|
||||
expect(screen.getByTestId('block-explorer-link')).toHaveTextContent(
|
||||
'Block explorer'
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
import type { Story, Meta } from '@storybook/react';
|
||||
import { OracleFullProfile } from './oracle-full-profile';
|
||||
|
||||
export default {
|
||||
component: OracleFullProfile,
|
||||
title: 'OracleFullProfile',
|
||||
} as Meta;
|
||||
|
||||
const Template: Story = (args) => (
|
||||
<OracleFullProfile provider={args['provider']} id="4578" />
|
||||
);
|
||||
|
||||
export const OraclePrimary = Template.bind({});
|
||||
|
||||
OraclePrimary.args = {
|
||||
provider: {
|
||||
name: 'Test oracle',
|
||||
url: 'https://zombo.com',
|
||||
description_markdown:
|
||||
'Some markdown describing the oracle provider.\n\nTwitter: @FacesPics2\n',
|
||||
oracle: {
|
||||
status: 'GOOD',
|
||||
status_reason: '',
|
||||
first_verified: '2023-02-28T00:00:00.000Z',
|
||||
last_verified: '2023-02-28T00:00:00.000Z',
|
||||
type: 'eth_address',
|
||||
eth_address: '0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC',
|
||||
},
|
||||
proofs: [
|
||||
{
|
||||
format: 'signed_message',
|
||||
available: true,
|
||||
type: 'eth_address',
|
||||
eth_address: '0x949AF81E51D57831AE52591d17fBcdd1014a5f52',
|
||||
message: 'SOMEHEX',
|
||||
},
|
||||
],
|
||||
github_link:
|
||||
'https://github.com/vegaprotocol/well-known/blob/main/oracle-providers/eth_address-0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC.toml',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,216 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { Provider } from '../../oracle-schema';
|
||||
import { MarketState, MarketStateMapping } from '@vegaprotocol/types';
|
||||
import {
|
||||
ButtonLink,
|
||||
ExternalLink,
|
||||
Icon,
|
||||
Intent,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { IconName } from '@blueprintjs/icons';
|
||||
import classNames from 'classnames';
|
||||
import { getLinkIcon, getVerifiedStatusIcon } from '../oracle-basic-profile';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import type { OracleMarketSpecFieldsFragment } from '../../__generated__/OracleMarketsSpec';
|
||||
import { useState } from 'react';
|
||||
|
||||
export const OracleProfileTitle = ({ provider }: { provider: Provider }) => {
|
||||
const { icon, intent } = getVerifiedStatusIcon(provider);
|
||||
const verifiedProofs = provider.proofs.filter(
|
||||
(proof) => proof.available === true
|
||||
);
|
||||
return (
|
||||
<span className="flex gap-1">
|
||||
{provider.url && (
|
||||
<span>
|
||||
<span className="pr-1">{provider.name}</span>
|
||||
<span className="dark:text-vega-light-300 text-vega-dark-300">
|
||||
({verifiedProofs.length})
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
<span
|
||||
className={classNames(
|
||||
{
|
||||
'text-gray-700 dark:text-gray-300': intent === Intent.None,
|
||||
'text-vega-blue': intent === Intent.Primary,
|
||||
'text-vega-green dark:text-vega-green': intent === Intent.Success,
|
||||
'text-yellow-600 dark:text-yellow': intent === Intent.Warning,
|
||||
'text-vega-pink': intent === Intent.Danger,
|
||||
},
|
||||
'flex items-start align-text-bottom p-1'
|
||||
)}
|
||||
>
|
||||
<Icon size={6} name={icon as IconName} />
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export const OracleFullProfile = ({
|
||||
provider,
|
||||
id,
|
||||
markets: oracleMarkets,
|
||||
}: {
|
||||
provider: Provider;
|
||||
id: string;
|
||||
markets?: OracleMarketSpecFieldsFragment[] | undefined;
|
||||
}) => {
|
||||
const { message } = getVerifiedStatusIcon(provider);
|
||||
const { VEGA_EXPLORER_URL } = useEnvironment();
|
||||
const [showMore, setShowMore] = useState(false);
|
||||
|
||||
const links = provider.proofs
|
||||
.filter((proof) => proof.format === 'url' && proof.available === true)
|
||||
.map((proof) => ({
|
||||
...proof,
|
||||
url: 'url' in proof ? proof.url : '',
|
||||
icon: getLinkIcon(proof.type),
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="flex flex-col text-sm">
|
||||
<div className="dark:text-vega-light-300 text-vega-dark-300">
|
||||
<p className=" pb-2">{message}</p>
|
||||
{!showMore && (
|
||||
<p className="pb-2">
|
||||
{provider.description_markdown.slice(0, 100)}
|
||||
{'... '}
|
||||
<span className="ml-2">
|
||||
<ButtonLink onClick={() => setShowMore(!showMore)}>
|
||||
Read more
|
||||
</ButtonLink>
|
||||
</span>
|
||||
</p>
|
||||
)}
|
||||
{showMore && (
|
||||
<p className="pb-2">
|
||||
{provider.description_markdown}
|
||||
<span className="ml-2">
|
||||
<ButtonLink onClick={() => setShowMore(!showMore)}>
|
||||
Show less
|
||||
</ButtonLink>
|
||||
</span>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
<div className="col-span-1">
|
||||
<p
|
||||
className="dark:text-vega-light-300 text-vega-dark-300 uppercase"
|
||||
data-testid="verified-accounts"
|
||||
>
|
||||
{t('%s proofs of ownership', links.length.toString())}
|
||||
</p>
|
||||
{links.length > 0 ? (
|
||||
<div className="flex flex-col gap-1">
|
||||
{links.map((link) => (
|
||||
<ExternalLink
|
||||
key={link.url}
|
||||
href={link.url}
|
||||
className="flex align-items-bottom underline text-sm"
|
||||
>
|
||||
<span className="pt-1">
|
||||
<VegaIcon name={getLinkIcon(link.type)} />
|
||||
</span>
|
||||
<span className="underline capitalize">
|
||||
{link.type}{' '}
|
||||
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={13} />
|
||||
</span>
|
||||
</ExternalLink>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<p className="dark:text-vega-light-300 text-vega-dark-300">
|
||||
{t('This oracle has not proven ownership of any accounts.')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="col-span-1 gap-2 py-2 flex flex-col">
|
||||
<p className="dark:text-vega-light-300 text-vega-dark-300 uppercase">
|
||||
{t('Details')}
|
||||
</p>
|
||||
{id && (
|
||||
<ExternalLink
|
||||
href={`${VEGA_EXPLORER_URL}/oracles/${id}`}
|
||||
data-testid="block-explorer-link"
|
||||
>
|
||||
{t('Block explorer')}
|
||||
</ExternalLink>
|
||||
)}
|
||||
{provider.github_link && (
|
||||
<ExternalLink href={provider.github_link} data-testid="github-link">
|
||||
{t('Oracle repository')}
|
||||
</ExternalLink>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{oracleMarkets && (
|
||||
<p className="dark:text-vega-light-300 text-vega-dark-300 uppercase mt-4">
|
||||
{t('Oracle in %s %s', [
|
||||
oracleMarkets.length.toString(),
|
||||
oracleMarkets.length === 1 ? 'market' : 'markets',
|
||||
])}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{oracleMarkets && oracleMarkets.length > 0 && (
|
||||
<div
|
||||
data-testid="oracle-markets"
|
||||
className="border-vega-light-200 dark:border-vega-dark-200 border-solid border-2 py-4 px-2 rounded-lg my-2"
|
||||
>
|
||||
<div className="grid grid-cols-4 gap-1 uppercase mb-2 font-alpha calt dark:text-vega-light-300 text-vega-dark-300">
|
||||
<div className="col-span-1">{t('Market')}</div>
|
||||
<div className="col-span-1">{t('Status')}</div>
|
||||
<div className="col-span-1">{t('Specifications')}</div>
|
||||
</div>
|
||||
<div className="max-h-60 overflow-auto">
|
||||
{oracleMarkets?.map((market) => (
|
||||
<div
|
||||
className="grid grid-cols-4 gap-1 capitalize mb-2 last:mb-0"
|
||||
key={`oracle-market-${market.id}`}
|
||||
>
|
||||
<div className="col-span-1">
|
||||
{market.tradableInstrument.instrument.code}
|
||||
</div>
|
||||
<div
|
||||
className={classNames('col-span-1', {
|
||||
'dark:text-vega-light-300 text-vega-dark-300': ![
|
||||
MarketState.STATE_ACTIVE,
|
||||
MarketState.STATE_PROPOSED,
|
||||
].includes(market.state),
|
||||
})}
|
||||
>
|
||||
{MarketStateMapping[market.state]}
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
{
|
||||
<ExternalLink
|
||||
href={`${VEGA_EXPLORER_URL}/oracles/${market.tradableInstrument?.instrument.product?.dataSourceSpecForSettlementData.id}`}
|
||||
data-testid="block-explorer-link-settlement"
|
||||
>
|
||||
{t('Settlement')}
|
||||
</ExternalLink>
|
||||
}
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
{
|
||||
<ExternalLink
|
||||
href={`${VEGA_EXPLORER_URL}/oracles/${market.tradableInstrument?.instrument.product?.dataSourceSpecForTradingTermination.id}`}
|
||||
data-testid="block-explorer-link-termination"
|
||||
>
|
||||
{t('Termination')}
|
||||
</ExternalLink>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './use-oracle-markets';
|
||||
export * from './use-oracle-proofs';
|
||||
export * from './use-oracle-spec-binding-data';
|
||||
@@ -0,0 +1,50 @@
|
||||
import type { Provider } from '../oracle-schema';
|
||||
import type { OracleMarketSpecFieldsFragment } from '../__generated__/OracleMarketsSpec';
|
||||
import { useOracleMarketsSpecQuery } from '../__generated__/OracleMarketsSpec';
|
||||
|
||||
export const useOracleMarkets = (
|
||||
provider: Provider
|
||||
): OracleMarketSpecFieldsFragment[] | undefined => {
|
||||
const signedProofs = provider.proofs.filter(
|
||||
(proof) => proof.format === 'signed_message' && proof.available === true
|
||||
);
|
||||
|
||||
const { data: markets } = useOracleMarketsSpecQuery();
|
||||
|
||||
const oracleMarkets = markets?.marketsConnection?.edges
|
||||
?.map((edge) => edge.node)
|
||||
?.filter((node) => {
|
||||
const p = node.tradableInstrument.instrument.product;
|
||||
const sourceType = p.dataSourceSpecForSettlementData.data.sourceType;
|
||||
if (sourceType.__typename !== 'DataSourceDefinitionExternal') {
|
||||
return false;
|
||||
}
|
||||
const signers = sourceType?.sourceType.signers;
|
||||
|
||||
const signerKeys = signers?.filter(Boolean).map((signer) => {
|
||||
if (signer.signer.__typename === 'ETHAddress') {
|
||||
return signer.signer.address;
|
||||
}
|
||||
|
||||
if (signer.signer.__typename === 'PubKey') {
|
||||
return signer.signer.key;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const signedProofsKeys = signedProofs.map((proof) => {
|
||||
if ('public_key' in proof && proof.public_key) {
|
||||
return proof.public_key;
|
||||
}
|
||||
if ('eth_address' in proof && proof.eth_address) {
|
||||
return proof.eth_address;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const key = signedProofsKeys.find((key) => signerKeys?.includes(key));
|
||||
return !!key;
|
||||
});
|
||||
return oracleMarkets;
|
||||
};
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import type { Provider } from './oracle-schema';
|
||||
import type { Provider } from '../oracle-schema';
|
||||
import { useOracleProofs, cache, invalidateCache } from './use-oracle-proofs';
|
||||
|
||||
global.fetch = jest.fn();
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import type { Provider } from './oracle-schema';
|
||||
import { providersSchema } from './oracle-schema';
|
||||
import type { Provider } from '../oracle-schema';
|
||||
import { providersSchema } from '../oracle-schema';
|
||||
|
||||
export let cache: {
|
||||
[url: string]: Provider[];
|
||||
+2
-2
@@ -4,8 +4,8 @@ import { MockedProvider } from '@apollo/client/testing';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useOracleSpecBindingData } from './use-oracle-spec-binding-data';
|
||||
import type { Property } from '@vegaprotocol/types';
|
||||
import type { OracleSpecDataConnectionQuery } from './__generated__/OracleSpecDataConnection';
|
||||
import { OracleSpecDataConnectionDocument } from './__generated__/OracleSpecDataConnection';
|
||||
import type { OracleSpecDataConnectionQuery } from '../__generated__/OracleSpecDataConnection';
|
||||
import { OracleSpecDataConnectionDocument } from '../__generated__/OracleSpecDataConnection';
|
||||
|
||||
describe('useSettlementPrice', () => {
|
||||
const setup = (
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { useOracleSpecDataConnectionQuery } from './__generated__/OracleSpecDataConnection';
|
||||
import { useOracleSpecDataConnectionQuery } from '../__generated__/OracleSpecDataConnection';
|
||||
|
||||
export const useOracleSpecBindingData = (
|
||||
oracleSpecId: string | undefined,
|
||||
@@ -2,5 +2,4 @@ export * from './__generated__';
|
||||
export * from './components';
|
||||
export * from './oracle-schema';
|
||||
export * from './oracle-spec-data-connection.mock';
|
||||
export * from './use-oracle-proofs';
|
||||
export * from './use-oracle-spec-binding-data';
|
||||
export * from './hooks';
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
},
|
||||
"files": [
|
||||
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
|
||||
"../../node_modules/@nrwl/react/typings/image.d.ts"
|
||||
"../../node_modules/@nrwl/next/typings/image.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"**/*.spec.ts",
|
||||
|
||||
@@ -13,7 +13,7 @@ interface DialogProps {
|
||||
onChange?: (isOpen: boolean) => void;
|
||||
onCloseAutoFocus?: (e: Event) => void;
|
||||
onInteractOutside?: (e: Event) => void;
|
||||
title?: string;
|
||||
title?: string | ReactNode;
|
||||
icon?: ReactNode;
|
||||
intent?: Intent;
|
||||
size?: 'small' | 'medium';
|
||||
|
||||
@@ -40,7 +40,7 @@ describe('ExternalLink', () => {
|
||||
render(<ExternalLink href="https://vega.xyz/">Go to Vega</ExternalLink>);
|
||||
const link = screen.getByTestId('external-link');
|
||||
expect(link.children.length).toEqual(2);
|
||||
expect(link.children[1].tagName.toUpperCase()).toEqual('SVG');
|
||||
expect(link.children[1].tagName.toUpperCase()).toEqual('SPAN');
|
||||
});
|
||||
|
||||
it('should have an underlined text part', () => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import classNames from 'classnames';
|
||||
import type { ReactNode, AnchorHTMLAttributes } from 'react';
|
||||
import { Icon } from '../icon';
|
||||
import { VegaIcon, VegaIconNames } from '../icon';
|
||||
|
||||
type LinkProps = AnchorHTMLAttributes<HTMLAnchorElement> & {
|
||||
children?: ReactNode;
|
||||
@@ -24,7 +23,7 @@ export const Link = ({ className, children, ...props }: LinkProps) => {
|
||||
};
|
||||
|
||||
// if no href is passed just render a span, this is so that we can wrap an
|
||||
// element with our links styles with a react router link compoment
|
||||
// element with our links styles with a react router link component
|
||||
if (!props.href) {
|
||||
return (
|
||||
<span {...shared} {...props}>
|
||||
@@ -43,7 +42,10 @@ Link.displayName = 'Link';
|
||||
|
||||
export const ExternalLink = ({ children, className, ...props }: LinkProps) => (
|
||||
<Link
|
||||
className={classNames(className, 'inline-flex items-baseline')}
|
||||
className={classNames(
|
||||
className,
|
||||
'inline-flex items-baseline underline-offset-4'
|
||||
)}
|
||||
target="_blank"
|
||||
data-testid="external-link"
|
||||
rel="noreferrer nofollow noopener"
|
||||
@@ -56,7 +58,7 @@ export const ExternalLink = ({ children, className, ...props }: LinkProps) => (
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
<Icon size={3} name={IconNames.SHARE} className="ml-1" />
|
||||
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={13} />
|
||||
</>
|
||||
) : (
|
||||
children
|
||||
|
||||
@@ -22,3 +22,7 @@ export * from './lib/web3-connect-dialog';
|
||||
export * from './lib/web3-connect-store';
|
||||
export * from './lib/web3-connectors';
|
||||
export * from './lib/web3-provider';
|
||||
export * from './lib/use-vega-transaction-toasts';
|
||||
export * from './lib/use-ethereum-transaction-toasts';
|
||||
export * from './lib/use-ethereum-withdraw-approval-toasts';
|
||||
export * from './lib/withdrawal-approval-status';
|
||||
|
||||
+5
-7
@@ -11,13 +11,11 @@ import { useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import { Intent, ProgressBar } from '@vegaprotocol/ui-toolkit';
|
||||
import { useCallback } from 'react';
|
||||
import compact from 'lodash/compact';
|
||||
import type { EthStoredTxState } from '@vegaprotocol/web3';
|
||||
import {
|
||||
EthTxStatus,
|
||||
isEthereumError,
|
||||
TransactionContent,
|
||||
useEthTransactionStore,
|
||||
} from '@vegaprotocol/web3';
|
||||
import type { EthStoredTxState } from './use-ethereum-transaction-store';
|
||||
import { EthTxStatus } from './use-ethereum-transaction';
|
||||
import { isEthereumError } from './ethereum-error';
|
||||
import { TransactionContent } from './ethereum-transaction-dialog';
|
||||
import { useEthTransactionStore } from './use-ethereum-transaction-store';
|
||||
|
||||
const intentMap: { [s in EthTxStatus]: Intent } = {
|
||||
Default: Intent.Primary,
|
||||
+4
-3
@@ -6,11 +6,12 @@ import { Panel } from '@vegaprotocol/ui-toolkit';
|
||||
import { CLOSE_AFTER } from '@vegaprotocol/ui-toolkit';
|
||||
import { useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { ApprovalStatus, VerificationStatus } from '@vegaprotocol/withdraws';
|
||||
import { useCallback } from 'react';
|
||||
import compact from 'lodash/compact';
|
||||
import type { EthWithdrawalApprovalState } from '@vegaprotocol/web3';
|
||||
import { useEthWithdrawApprovalsStore } from '@vegaprotocol/web3';
|
||||
import type { EthWithdrawalApprovalState } from './use-ethereum-withdraw-approvals-store';
|
||||
import { useEthWithdrawApprovalsStore } from './use-ethereum-withdraw-approvals-store';
|
||||
import { ApprovalStatus } from './use-ethereum-withdraw-approvals-store';
|
||||
import { VerificationStatus } from './withdrawal-approval-status';
|
||||
|
||||
const intentMap: { [s in ApprovalStatus]: Intent } = {
|
||||
Pending: Intent.Warning,
|
||||
+1
-1
@@ -37,7 +37,7 @@ import {
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useAssetsDataProvider } from '@vegaprotocol/assets';
|
||||
import { useEthWithdrawApprovalsStore } from '@vegaprotocol/web3';
|
||||
import { useEthWithdrawApprovalsStore } from './use-ethereum-withdraw-approvals-store';
|
||||
import { DApp, EXPLORER_TX, useLinks } from '@vegaprotocol/environment';
|
||||
import {
|
||||
getOrderToastIntent,
|
||||
@@ -0,0 +1,36 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||
import type { EthWithdrawalApprovalState } from './use-ethereum-withdraw-approvals-store';
|
||||
import { ApprovalStatus } from './use-ethereum-withdraw-approvals-store';
|
||||
|
||||
export const VerificationStatus = ({
|
||||
state,
|
||||
}: {
|
||||
state: EthWithdrawalApprovalState;
|
||||
}) => {
|
||||
if (state.status === ApprovalStatus.Error) {
|
||||
return <p>{state.message || t('Something went wrong')}</p>;
|
||||
}
|
||||
|
||||
if (state.status === ApprovalStatus.Pending) {
|
||||
return <p>{t('Verifying...')}</p>;
|
||||
}
|
||||
|
||||
if (state.status === ApprovalStatus.Delayed && state.completeTimestamp) {
|
||||
const formattedTime = getDateTimeFormat().format(
|
||||
new Date(state.completeTimestamp)
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<p>{t("The amount you're withdrawing has triggered a time delay")}</p>
|
||||
<p>{t(`Cannot be completed until ${formattedTime}`)}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (state.status === ApprovalStatus.Ready) {
|
||||
return <p>{t('The withdrawal has been approved.')}</p>;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -4,25 +4,18 @@ import BigNumber from 'bignumber.js';
|
||||
import { addDecimal } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
useGetWithdrawThreshold,
|
||||
ApprovalStatus,
|
||||
useGetWithdrawDelay,
|
||||
useGetWithdrawThreshold,
|
||||
} from '@vegaprotocol/web3';
|
||||
import type { WithdrawalFieldsFragment } from './__generated__/Withdrawal';
|
||||
import { Erc20ApprovalDocument } from './__generated__/Erc20Approval';
|
||||
import type {
|
||||
Erc20ApprovalQuery,
|
||||
Erc20ApprovalQueryVariables,
|
||||
} from './__generated__/Erc20Approval';
|
||||
import { Erc20ApprovalDocument } from './__generated__/Erc20Approval';
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
|
||||
export enum ApprovalStatus {
|
||||
Idle = 'Idle',
|
||||
Pending = 'Pending',
|
||||
Delayed = 'Delayed',
|
||||
Error = 'Error',
|
||||
Ready = 'Ready',
|
||||
}
|
||||
|
||||
export interface VerifyState {
|
||||
status: ApprovalStatus;
|
||||
message?: string;
|
||||
|
||||
@@ -2,26 +2,24 @@ import { useRef } from 'react';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { AgGridColumn } from 'ag-grid-react';
|
||||
import {
|
||||
getDateTimeFormat,
|
||||
truncateByChars,
|
||||
addDecimalsFormatNumber,
|
||||
getDateTimeFormat,
|
||||
isNumeric,
|
||||
truncateByChars,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { useBottomPlaceholder } from '@vegaprotocol/react-helpers';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||
import type {
|
||||
TypedDataAgGrid,
|
||||
VegaICellRendererParams,
|
||||
VegaValueFormatterParams,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||
import { EtherscanLink } from '@vegaprotocol/environment';
|
||||
import type { WithdrawalFieldsFragment } from './__generated__/Withdrawal';
|
||||
import { useEthWithdrawApprovalsStore } from '@vegaprotocol/web3';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { VerifyState } from './use-verify-withdrawal';
|
||||
import { ApprovalStatus } from './use-verify-withdrawal';
|
||||
|
||||
export const WithdrawalsTable = (
|
||||
props: TypedDataAgGrid<WithdrawalFieldsFragment>
|
||||
@@ -195,31 +193,3 @@ const RecipientCell = ({
|
||||
</EtherscanLink>
|
||||
);
|
||||
};
|
||||
|
||||
export const VerificationStatus = ({ state }: { state: VerifyState }) => {
|
||||
if (state.status === ApprovalStatus.Error) {
|
||||
return <p>{state.message || t('Something went wrong')}</p>;
|
||||
}
|
||||
|
||||
if (state.status === ApprovalStatus.Pending) {
|
||||
return <p>{t('Verifying...')}</p>;
|
||||
}
|
||||
|
||||
if (state.status === ApprovalStatus.Delayed && state.completeTimestamp) {
|
||||
const formattedTime = getDateTimeFormat().format(
|
||||
new Date(state.completeTimestamp)
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<p>{t("The amount you're withdrawing has triggered a time delay")}</p>
|
||||
<p>{t(`Cannot be completed until ${formattedTime}`)}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (state.status === ApprovalStatus.Ready) {
|
||||
return <p>{t('The withdrawal has been approved.')}</p>;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user