Compare commits
30
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab0c3c4a15 | ||
|
|
d615587564 | ||
|
|
ba4ce1ce88 | ||
|
|
3bbacc1aa0 | ||
|
|
de5371435d | ||
|
|
12cb5e10b6 | ||
|
|
ee2909cc84 | ||
|
|
068d6abf1b | ||
|
|
e5d4d2b0b8 | ||
|
|
d4e801cfc6 | ||
|
|
964deb2f23 | ||
|
|
6669125dd3 | ||
|
|
129b6c4e89 | ||
|
|
ca418cabfe | ||
|
|
192af844c4 | ||
|
|
6a841f226a | ||
|
|
76426baa2a | ||
|
|
6fdac2419c | ||
|
|
87807d2088 | ||
|
|
a5f2533a66 | ||
|
|
1e9251c9c0 | ||
|
|
2a27e124d7 | ||
|
|
4ee85720ab | ||
|
|
a19da4c408 | ||
|
|
65ad4fffda | ||
|
|
11317cdb2e | ||
|
|
c98870f27d | ||
|
|
c0c56e4c48 | ||
|
|
d9dc43b359 | ||
|
|
06a6fe6d67 |
@@ -10,7 +10,7 @@ on:
|
||||
inputs:
|
||||
console-test-branch:
|
||||
type: choice
|
||||
description: 'main: v0.72.14, develop: v0.73.4'
|
||||
description: 'main: v0.73.5, develop: v0.73.5'
|
||||
options:
|
||||
- main
|
||||
- develop
|
||||
@@ -215,7 +215,7 @@ jobs:
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-trace
|
||||
path: ./traces/
|
||||
path: apps/trading/e2e/traces/
|
||||
retention-days: 15
|
||||
#----------------------------------------------
|
||||
# ----- upload logs -----
|
||||
|
||||
+1
-2
@@ -59,5 +59,4 @@ apps/trading/e2e/logs/
|
||||
apps/trading/e2e/.pytest_cache/
|
||||
apps/trading/e2e/traces/
|
||||
|
||||
.nx/cache
|
||||
|
||||
.nx/
|
||||
|
||||
+20
-1
@@ -8,7 +8,7 @@ import {
|
||||
networkParamsQueryMock,
|
||||
nextWeek,
|
||||
} from '../../test-helpers/mocks';
|
||||
import { VoteBreakdown } from './vote-breakdown';
|
||||
import { CompactVotes, VoteBreakdown } from './vote-breakdown';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import {
|
||||
@@ -346,3 +346,22 @@ describe('VoteBreakdown', () => {
|
||||
expect(style.width).toBe(`${expectedProgress}%`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('CompactVotes', () => {
|
||||
it.each([
|
||||
[0, '0'],
|
||||
[1, '1'],
|
||||
[12, '12'],
|
||||
[123, '123'],
|
||||
[1234, '1.2K'],
|
||||
[12345, '12.3K'],
|
||||
[123456, '123.5K'],
|
||||
[1234567, '1.2M'],
|
||||
[12345678, '12.3M'],
|
||||
[123456789, '123.5M'],
|
||||
[1234567890, '1.2B'],
|
||||
])('compacts %s to %s', (input, output) => {
|
||||
const { getByTestId } = render(<CompactVotes number={BigNumber(input)} />);
|
||||
expect(getByTestId('compact-number').textContent).toBe(output);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,11 +3,21 @@ import BigNumber from 'bignumber.js';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useVoteInformation } from '../../hooks';
|
||||
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import { formatNumber, toBigNum } from '@vegaprotocol/utils';
|
||||
import { formatNumber } from '@vegaprotocol/utils';
|
||||
import { ProposalState } from '@vegaprotocol/types';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import { CompactNumber } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const CompactVotes = ({ number }: { number: BigNumber }) => (
|
||||
<CompactNumber
|
||||
number={number}
|
||||
decimals={number.isGreaterThan(1000) ? 1 : 0}
|
||||
compactAbove={1000}
|
||||
compactDisplay="short"
|
||||
/>
|
||||
);
|
||||
|
||||
interface VoteBreakdownProps {
|
||||
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
||||
@@ -198,10 +208,7 @@ export const VoteBreakdown = ({ proposal }: VoteBreakdownProps) => {
|
||||
)}
|
||||
>
|
||||
<button>
|
||||
{yesEquityLikeShareWeight
|
||||
.dividedBy(toBigNum(10 ** 6, 0))
|
||||
.toFixed(1)}
|
||||
M
|
||||
<CompactVotes number={yesEquityLikeShareWeight} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<span>
|
||||
@@ -226,10 +233,7 @@ export const VoteBreakdown = ({ proposal }: VoteBreakdownProps) => {
|
||||
)}
|
||||
>
|
||||
<button>
|
||||
{noEquityLikeShareWeight
|
||||
.dividedBy(toBigNum(10 ** 6, 0))
|
||||
.toFixed(1)}
|
||||
M
|
||||
<CompactVotes number={noEquityLikeShareWeight} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<span>
|
||||
@@ -279,10 +283,7 @@ export const VoteBreakdown = ({ proposal }: VoteBreakdownProps) => {
|
||||
)}
|
||||
>
|
||||
<button>
|
||||
{totalEquityLikeShareWeight
|
||||
.dividedBy(toBigNum(10 ** 6, 0))
|
||||
.toFixed(1)}
|
||||
M
|
||||
<CompactVotes number={totalEquityLikeShareWeight} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<span>
|
||||
@@ -321,7 +322,7 @@ export const VoteBreakdown = ({ proposal }: VoteBreakdownProps) => {
|
||||
<span>{t('tokenVotesFor')}:</span>
|
||||
<Tooltip description={formatNumber(yesTokens, defaultDP)}>
|
||||
<button data-testid="num-votes-for">
|
||||
{yesTokens.dividedBy(toBigNum(10 ** 6, 0)).toFixed(1)}M
|
||||
<CompactVotes number={yesTokens} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<span>
|
||||
@@ -341,7 +342,7 @@ export const VoteBreakdown = ({ proposal }: VoteBreakdownProps) => {
|
||||
<span>{t('tokenVotesAgainst')}:</span>
|
||||
<Tooltip description={formatNumber(noTokens, defaultDP)}>
|
||||
<button data-testid="num-votes-against">
|
||||
{noTokens.dividedBy(toBigNum(10 ** 6, 0)).toFixed(1)}M
|
||||
<CompactVotes number={noTokens} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<span>
|
||||
@@ -384,7 +385,7 @@ export const VoteBreakdown = ({ proposal }: VoteBreakdownProps) => {
|
||||
<span>{t('totalTokensVoted')}:</span>
|
||||
<Tooltip description={formatNumber(totalTokensVoted, defaultDP)}>
|
||||
<button data-testid="total-voted">
|
||||
{totalTokensVoted.dividedBy(toBigNum(10 ** 6, 0)).toFixed(1)}M
|
||||
<CompactVotes number={totalTokensVoted} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<span data-testid="total-voted-percentage">
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
const marketInfoBtn = 'Info';
|
||||
const marketInfoSubtitle = 'accordion-title';
|
||||
const marketSummaryBlock = 'header-summary';
|
||||
const marketExpiry = 'market-expiry';
|
||||
const marketPrice = 'market-price';
|
||||
const marketChange = 'market-change';
|
||||
const marketVolume = 'market-volume';
|
||||
const marketMode = 'market-trading-mode';
|
||||
const marketSettlement = 'market-settlement-asset';
|
||||
const percentageValue = 'price-change-percentage';
|
||||
const priceChangeValue = 'price-change';
|
||||
const itemHeader = 'item-header';
|
||||
const itemValue = 'item-value';
|
||||
const marketListContent = 'popover-content';
|
||||
|
||||
describe(
|
||||
'Console - market info - live env',
|
||||
{ tags: '@live', testIsolation: true },
|
||||
() => {
|
||||
before(() => {
|
||||
cy.visit('/');
|
||||
cy.contains('Loading market data...').should('not.exist');
|
||||
cy.getByTestId('link').should('be.visible');
|
||||
cy.getByTestId('dialog-close').click();
|
||||
cy.getByTestId(marketInfoBtn).click();
|
||||
});
|
||||
const titles = ['Market data', 'Market specification', 'Market governance'];
|
||||
const subtitles = [
|
||||
'Current fees',
|
||||
'Market price',
|
||||
'Market volume',
|
||||
'Insurance pool',
|
||||
'Key details',
|
||||
'Instrument',
|
||||
'Settlement asset',
|
||||
'Metadata',
|
||||
'Risk model',
|
||||
'Risk parameters',
|
||||
'Risk factors',
|
||||
'Price monitoring bounds 1',
|
||||
'Liquidity monitoring parameters',
|
||||
'Liquidity',
|
||||
'Liquidity price range',
|
||||
'Oracle',
|
||||
'Proposal',
|
||||
];
|
||||
|
||||
it('market info titles are displayed', () => {
|
||||
cy.getByTestId('split-view-view')
|
||||
.find('.text-lg')
|
||||
.each((element, index) => {
|
||||
cy.wrap(element).should('have.text', titles[index]);
|
||||
});
|
||||
});
|
||||
|
||||
it('market info subtitles are displayed', () => {
|
||||
cy.getByTestId('popover-trigger').click();
|
||||
cy.contains('Loading market data...').should('not.exist');
|
||||
cy.contains('[data-testid="link"]', 'AAVEDAI.MF21').click();
|
||||
cy.getByTestId(marketInfoBtn).click();
|
||||
cy.getByTestId(marketInfoSubtitle).each((element, index) => {
|
||||
cy.wrap(element).should('have.text', subtitles[index]);
|
||||
});
|
||||
});
|
||||
|
||||
it('renders correctly liquidity in trading tab', () => {
|
||||
cy.getByTestId('Liquidity').click();
|
||||
cy.contains('Loading').should('not.exist');
|
||||
cy.contains('Something went wrong').should('not.exist');
|
||||
cy.contains('Application error').should('not.exist');
|
||||
cy.getByTestId('tab-liquidity').within(() => {
|
||||
cy.get('[col-id="partyId"]').eq(1).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
describe(
|
||||
'Console - market summary - live env',
|
||||
{ tags: '@live', testIsolation: true },
|
||||
() => {
|
||||
before(() => {
|
||||
cy.visit('/');
|
||||
cy.getByTestId('dialog-close').click();
|
||||
cy.getByTestId(marketSummaryBlock).should('be.visible');
|
||||
});
|
||||
|
||||
it('must display market name', () => {
|
||||
cy.getByTestId('popover-trigger').should('not.be.empty');
|
||||
});
|
||||
|
||||
it('must see market expiry', () => {
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketExpiry).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Expiry');
|
||||
cy.getByTestId(itemValue).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('must see market price', () => {
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketPrice).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Price');
|
||||
cy.getByTestId(itemValue).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('must see market change', () => {
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketChange).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Change (24h)');
|
||||
cy.getByTestId(percentageValue).should('not.be.empty');
|
||||
cy.getByTestId(priceChangeValue).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('must see market volume', () => {
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketVolume).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Volume (24h)');
|
||||
cy.getByTestId(itemValue).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('must see market mode', () => {
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketMode).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Trading mode');
|
||||
cy.getByTestId(itemValue).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('must see market settlement', () => {
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketSettlement).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Settlement asset');
|
||||
cy.getByTestId(itemValue).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
describe(
|
||||
'Console - markets table - live env',
|
||||
{ tags: '@live', testIsolation: true },
|
||||
() => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/');
|
||||
});
|
||||
|
||||
it('renders markets correctly', () => {
|
||||
cy.get('[data-testid^="market-link-"]').should('not.be.empty');
|
||||
cy.getByTestId('price').invoke('text').should('not.be.empty');
|
||||
cy.getByTestId('settlement-asset').should('not.be.empty');
|
||||
cy.getByTestId('price-change-percentage').should('not.be.empty');
|
||||
cy.getByTestId('price-change').should('not.be.empty');
|
||||
cy.getByTestId('sparkline-svg').should('be.visible');
|
||||
});
|
||||
|
||||
it('renders market list drop down', () => {
|
||||
openMarketDropDown();
|
||||
cy.getByTestId(marketListContent)
|
||||
.find('[data-testid="price"]')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId(marketListContent)
|
||||
.find('[data-testid="trading-mode-col"]')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId(marketListContent)
|
||||
.find('[data-testid="taker-fee"]')
|
||||
.should('contain.text', '%');
|
||||
cy.getByTestId(marketListContent)
|
||||
.find('[data-testid="market-volume"]')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId(marketListContent)
|
||||
.find('[data-testid="market-name"]')
|
||||
.should('not.be.empty');
|
||||
});
|
||||
|
||||
it('Able to select market from dropdown', () => {
|
||||
cy.getByTestId('popover-trigger')
|
||||
.invoke('text')
|
||||
.then((marketName) => {
|
||||
openMarketDropDown();
|
||||
cy.get('[data-testid^=market-link]').eq(1).click();
|
||||
cy.getByTestId('popover-trigger').should('not.be.equal', marketName);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
function openMarketDropDown() {
|
||||
cy.contains('Loading...').should('not.exist');
|
||||
cy.getByTestId('link').should('be.visible');
|
||||
cy.getByTestId('dialog-close').click();
|
||||
cy.getByTestId('popover-trigger').click();
|
||||
cy.contains('Loading market data...').should('not.exist');
|
||||
}
|
||||
@@ -1,311 +0,0 @@
|
||||
import { checkSorting } from '@vegaprotocol/cypress';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
const liquidityTab = 'Liquidity';
|
||||
const rowSelector =
|
||||
'[data-testid="tab-liquidity"] .ag-center-cols-container .ag-row';
|
||||
const rowSelectorLiquidityActive =
|
||||
'[data-testid="tab-active"] .ag-center-cols-container .ag-row';
|
||||
const rowSelectorLiquidityInactive =
|
||||
'[data-testid="tab-inactive"] .ag-center-cols-container .ag-row';
|
||||
const marketSummaryBlock = 'header-summary';
|
||||
const itemValue = 'item-value';
|
||||
const itemHeader = 'item-header';
|
||||
const colCommitmentAmount = '[col-id="commitmentAmount"]';
|
||||
const colEquityLikeShare = '[col-id="feeShare.equityLikeShare"]';
|
||||
const colFee = '[col-id="fee"]';
|
||||
const colCommitmentAmount_1 = '[col-id="commitmentAmount_1"]';
|
||||
const colBalance = '[col-id="balance"]';
|
||||
const colStatus = '[col-id="status"]';
|
||||
const colCreatedAt = '[col-id="createdAt"] button';
|
||||
const colUpdatedAt = '[col-id="updatedAt"] button';
|
||||
|
||||
const headers = [
|
||||
'Party',
|
||||
'Status',
|
||||
'Commitment (tDAI)',
|
||||
'Obligation',
|
||||
'Fee',
|
||||
'Adjusted stake share',
|
||||
'Share',
|
||||
'Live supplied liquidity',
|
||||
'Fees accrued this epoch',
|
||||
'Live time on book',
|
||||
'Live liquidity quality score (%)',
|
||||
'Last time on the book',
|
||||
'Last fee penalty',
|
||||
'Last bond penalty',
|
||||
'Created',
|
||||
'Updated',
|
||||
];
|
||||
|
||||
describe('liquidity table - trading', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.setOnBoardingViewed();
|
||||
cy.mockSubscription();
|
||||
cy.mockTradingPage(
|
||||
Schema.MarketState.STATE_ACTIVE,
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
|
||||
);
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@MarketData');
|
||||
cy.getByTestId(liquidityTab).click();
|
||||
cy.wait('@LiquidityProvisions');
|
||||
});
|
||||
|
||||
it('can see table headers', () => {
|
||||
// 5002-LIQP-001
|
||||
cy.getByTestId('tab-liquidity').within(($headers) => {
|
||||
cy.wrap($headers)
|
||||
.get('.ag-header-cell-text')
|
||||
.each(($header, i) => {
|
||||
cy.wrap($header).should('have.text', headers[i]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('renders liquidity table correctly', () => {
|
||||
// 5002-LIQP-002
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[col-id="partyId"]')
|
||||
.should('have.text', '69464e…dc6f');
|
||||
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find(colCommitmentAmount)
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find(colEquityLikeShare)
|
||||
.should('have.text', '100.00%');
|
||||
|
||||
cy.get(rowSelector).first().find(colFee).should('have.text', '0.09%');
|
||||
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find(colCommitmentAmount_1)
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find(colBalance)
|
||||
.scrollIntoView()
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelector).first().find(colStatus).should('have.text', 'Active');
|
||||
|
||||
cy.get(rowSelector).first().find(colCreatedAt).should('not.be.empty');
|
||||
cy.get(rowSelector).first().find(colUpdatedAt).should('not.be.empty');
|
||||
});
|
||||
|
||||
it('liquidity status column should be sorted properly', () => {
|
||||
// 5002-LIQP-003
|
||||
const liquidityColDefault = ['Active', 'Pending'];
|
||||
const liquidityColAsc = ['Active', 'Pending'];
|
||||
const liquidityColDesc = ['Pending', 'Active'];
|
||||
checkSorting(
|
||||
'status',
|
||||
liquidityColDefault,
|
||||
liquidityColAsc,
|
||||
liquidityColDesc
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('liquidity table view', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.setOnBoardingViewed();
|
||||
cy.mockSubscription();
|
||||
cy.mockTradingPage(
|
||||
Schema.MarketState.STATE_ACTIVE,
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
|
||||
);
|
||||
cy.visit('/#/liquidity/market-0');
|
||||
cy.wait('@LiquidityProvisions');
|
||||
});
|
||||
|
||||
it('can see header title', () => {
|
||||
// 5002-LIQP-004
|
||||
// 5002-LIQP-005
|
||||
cy.getByTestId('header-title').should(
|
||||
'contain.text',
|
||||
'BTCUSD.MF21 liquidity provision'
|
||||
);
|
||||
});
|
||||
|
||||
it('can see target stake', () => {
|
||||
// 5002-LIQP-006
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId('target-stake').within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Target stake');
|
||||
cy.getByTestId(itemValue).should('have.text', '10.00 tDAI').realHover();
|
||||
});
|
||||
});
|
||||
cy.getByTestId('tooltip-content').should(
|
||||
'contain.text',
|
||||
`The market's liquidity requirement which is derived from the maximum open interest observed over a rolling time window.The market's liquidity requirement which is derived from the maximum open interest observed over a rolling time window.`
|
||||
);
|
||||
});
|
||||
|
||||
it('can see supplied stake', () => {
|
||||
// 5002-LIQP-007
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId('supplied-stake').within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Supplied stake');
|
||||
cy.getByTestId(itemValue).should('have.text', '0.01 tDAI').realHover();
|
||||
});
|
||||
});
|
||||
cy.getByTestId('tooltip-content').should(
|
||||
'contain.text',
|
||||
'The current amount of liquidity supplied for this market.'
|
||||
);
|
||||
});
|
||||
|
||||
it('can see liquidity supplied', () => {
|
||||
// 5002-LIQP-008
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId('liquidity-supplied').within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Liquidity supplied');
|
||||
cy.getByTestId('indicator').should('be.visible');
|
||||
cy.getByTestId(itemValue).should('have.text', ' 0.10%').realHover();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can see market id', () => {
|
||||
// 5002-LIQP-009
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId('liquidity-market-id').within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Market ID');
|
||||
cy.getByTestId(itemValue).should('have.text', 'market-0');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can see market id', () => {
|
||||
// 5002-LIQP-010
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId('liquidity-learn-more').within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Learn more');
|
||||
cy.getByTestId(itemValue).should('have.text', 'Providing liquidity');
|
||||
cy.getByTestId('external-link')
|
||||
.should('have.attr', 'href')
|
||||
.and(
|
||||
'include',
|
||||
'https://docs.vega.xyz/testnet/concepts/liquidity/provision'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('liquidity table view', { tags: '@smoke' }, () => {
|
||||
it('can see table headers', () => {
|
||||
cy.getByTestId('tab-active').within(($headers) => {
|
||||
cy.wrap($headers)
|
||||
.get('.ag-header-cell-text')
|
||||
.each(($header, i) => {
|
||||
cy.wrap($header).should('have.text', headers[i]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('renders liquidity active table correctly', () => {
|
||||
// 5002-LIQP-011
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find('[col-id="partyId"]')
|
||||
.should('have.text', '69464e…dc6f');
|
||||
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colCommitmentAmount)
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colEquityLikeShare)
|
||||
.should('have.text', '100.00%');
|
||||
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colFee)
|
||||
.should('have.text', '0.09%');
|
||||
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colCommitmentAmount_1)
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colBalance)
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colStatus)
|
||||
.should('have.text', 'Active');
|
||||
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colCreatedAt)
|
||||
.should('not.be.empty');
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colUpdatedAt)
|
||||
.should('not.be.empty');
|
||||
});
|
||||
|
||||
it('renders liquidity inactive table correctly', () => {
|
||||
// 5002-LIQP-012
|
||||
cy.getByTestId('Inactive').click();
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find('[col-id="partyId"]')
|
||||
.should('have.text', 'cc464e…dc6f');
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colCommitmentAmount)
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colEquityLikeShare)
|
||||
.should('have.text', '100.00%');
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colFee)
|
||||
.should('have.text', '0.40%');
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colCommitmentAmount_1)
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colBalance)
|
||||
.should('have.text', '2,000.00');
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colStatus)
|
||||
.should('have.text', 'Pending');
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colCreatedAt)
|
||||
.should('not.be.empty');
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colUpdatedAt)
|
||||
.should('not.be.empty');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import { proposalListQuery, marketUpdateProposal } from '@vegaprotocol/mock';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
const marketSummaryBlock = 'header-summary';
|
||||
|
||||
describe('Market proposal notification', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage(
|
||||
Schema.MarketState.STATE_ACTIVE,
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
|
||||
);
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(
|
||||
req,
|
||||
'ProposalsList',
|
||||
proposalListQuery({
|
||||
proposalsConnection: {
|
||||
edges: [{ node: marketUpdateProposal }],
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@MarketData');
|
||||
cy.getByTestId(marketSummaryBlock).should('be.visible');
|
||||
});
|
||||
|
||||
it('should display market proposal notification if proposal found', () => {
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId('market-proposal-notification').should(
|
||||
'contain.text',
|
||||
'Changes have been proposed for this market'
|
||||
);
|
||||
cy.getByTestId('market-proposal-notification').within(() => {
|
||||
cy.getByTestId('external-link').should(
|
||||
'have.attr',
|
||||
'href',
|
||||
`${Cypress.env('VEGA_TOKEN_URL')}/proposals/123`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -14,7 +14,6 @@ const marketMode = 'market-trading-mode';
|
||||
const marketName = 'header-title';
|
||||
const marketPrice = 'market-price';
|
||||
const marketSettlement = 'market-settlement-asset';
|
||||
const marketState = 'market-state';
|
||||
const marketSummaryBlock = 'header-summary';
|
||||
const marketVolume = 'market-volume';
|
||||
const percentageValue = 'price-change-percentage';
|
||||
@@ -85,30 +84,6 @@ describe('Market trading page', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('must see market mode', () => {
|
||||
// 6002-MDET-006
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketMode).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Trading mode');
|
||||
cy.getByTestId(itemValue).should(
|
||||
'have.text',
|
||||
'Monitoring auction - liquidity (target not met)'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('must see market status', () => {
|
||||
// 6002-MDET-007
|
||||
// 7002-SORD-061
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketState).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Status');
|
||||
cy.getByTestId(itemValue).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('must see market settlement', () => {
|
||||
// 6002-MDET-008
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
@@ -118,15 +93,6 @@ describe('Market trading page', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
it('must see market liquidity supplied', () => {
|
||||
// 6002-MDET-009
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(liquiditySupplied).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Liquidity supplied');
|
||||
cy.getByTestId(itemValue).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Market tooltips', { tags: '@smoke' }, () => {
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
import { FeesContainer } from '../../components/fees-container';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { usePageTitleStore } from '../../stores';
|
||||
import { titlefy } from '@vegaprotocol/utils';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export const Fees = () => {
|
||||
const t = useT();
|
||||
const title = t('Fees');
|
||||
const { updateTitle } = usePageTitleStore((store) => ({
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
useEffect(() => {
|
||||
updateTitle(titlefy([title]));
|
||||
}, [updateTitle, title]);
|
||||
return (
|
||||
<div className="container p-4 mx-auto">
|
||||
<h1 className="px-4 pb-4 text-2xl">{t('Fees')}</h1>
|
||||
<h1 className="px-4 pb-4 text-2xl">{title}</h1>
|
||||
<FeesContainer />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useEffect, useMemo } from 'react';
|
||||
import { addDecimalsFormatNumber, titlefy } from '@vegaprotocol/utils';
|
||||
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||
import { useThrottledDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { ExternalLink, Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { Link, Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { getAsset, marketDataProvider, useMarket } from '@vegaprotocol/markets';
|
||||
import { useGlobalStore, usePageTitleStore } from '../../stores';
|
||||
import { TradeGrid } from './trade-grid';
|
||||
@@ -114,15 +114,16 @@ export const MarketPage = () => {
|
||||
</p>
|
||||
<p className="justify-center text-sm">
|
||||
<Trans
|
||||
defaults="Please choose another market from the <0>market list<0>"
|
||||
defaults="Please choose another market from the <0>market list</0>"
|
||||
ns={ns}
|
||||
components={[
|
||||
<ExternalLink
|
||||
<Link
|
||||
className="underline underline-offset-4 "
|
||||
onClick={() => navigate(Links.MARKETS())}
|
||||
key="link"
|
||||
>
|
||||
market list
|
||||
</ExternalLink>,
|
||||
</Link>,
|
||||
]}
|
||||
/>
|
||||
</p>
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import type { TypedDataAgGrid } from '@vegaprotocol/datagrid';
|
||||
import { AgGrid, PriceFlashCell } from '@vegaprotocol/datagrid';
|
||||
import {
|
||||
AgGrid,
|
||||
PriceFlashCell,
|
||||
useDataGridEvents,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import type { MarketMaybeWithData } from '@vegaprotocol/markets';
|
||||
import { useColumnDefs } from './use-column-defs';
|
||||
import type { DataGridStore } from '../../stores/datagrid-store-slice';
|
||||
import { type StateCreator, create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
export const getRowId = ({ data }: { data: { id: string } }) => data.id;
|
||||
|
||||
@@ -18,8 +25,37 @@ const components = {
|
||||
|
||||
type Props = TypedDataAgGrid<MarketMaybeWithData>;
|
||||
|
||||
export type DataGridSlice = {
|
||||
gridStore: DataGridStore;
|
||||
updateGridStore: (gridStore: DataGridStore) => void;
|
||||
};
|
||||
|
||||
export const createDataGridSlice: StateCreator<DataGridSlice> = (set) => ({
|
||||
gridStore: {},
|
||||
updateGridStore: (newStore) => {
|
||||
set((curr) => ({
|
||||
gridStore: {
|
||||
...curr.gridStore,
|
||||
...newStore,
|
||||
},
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
const useMarketsStore = create<DataGridSlice>()(
|
||||
persist(createDataGridSlice, {
|
||||
name: 'vega_market_list_store',
|
||||
})
|
||||
);
|
||||
|
||||
export const MarketListTable = (props: Props) => {
|
||||
const columnDefs = useColumnDefs();
|
||||
const gridStore = useMarketsStore((store) => store.gridStore);
|
||||
const updateGridStore = useMarketsStore((store) => store.updateGridStore);
|
||||
|
||||
const gridStoreCallbacks = useDataGridEvents(gridStore, (colState) => {
|
||||
updateGridStore(colState);
|
||||
});
|
||||
|
||||
return (
|
||||
<AgGrid
|
||||
@@ -28,6 +64,7 @@ export const MarketListTable = (props: Props) => {
|
||||
columnDefs={columnDefs}
|
||||
components={components}
|
||||
rowHeight={45}
|
||||
{...gridStoreCallbacks}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -43,7 +43,7 @@ export const OpenMarkets = () => {
|
||||
if (!data) return;
|
||||
|
||||
// prevent navigating to the market page if any of the below cells are clicked
|
||||
// event.preventDefault or event.stopPropagation dont seem to apply for aggird
|
||||
// event.preventDefault or event.stopPropagation do not seem to apply for ag-grid
|
||||
const colId = column.getColId();
|
||||
|
||||
if (
|
||||
|
||||
@@ -51,6 +51,29 @@ export const useColumnDefs = () => {
|
||||
headerName: t('Description'),
|
||||
field: 'tradableInstrument.instrument.name',
|
||||
},
|
||||
{
|
||||
headerName: t('Settlement asset'),
|
||||
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
|
||||
cellRenderer: ({
|
||||
data,
|
||||
}: VegaICellRendererParams<
|
||||
MarketMaybeWithData,
|
||||
'tradableInstrument.instrument.product.settlementAsset.symbol'
|
||||
>) => {
|
||||
const value = data && getAsset(data);
|
||||
return value ? (
|
||||
<ButtonLink
|
||||
onClick={(e) => {
|
||||
openAssetDetailsDialog(value.id, e.target as HTMLElement);
|
||||
}}
|
||||
>
|
||||
{value.symbol}
|
||||
</ButtonLink>
|
||||
) : (
|
||||
''
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
headerName: t('Trading mode'),
|
||||
field: 'tradingMode',
|
||||
@@ -142,27 +165,21 @@ export const useColumnDefs = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
headerName: t('Settlement asset'),
|
||||
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
|
||||
cellRenderer: ({
|
||||
headerName: t('Open Interest'),
|
||||
field: 'data.openInterest',
|
||||
type: 'rightAligned',
|
||||
valueFormatter: ({
|
||||
data,
|
||||
}: VegaICellRendererParams<
|
||||
}: VegaValueFormatterParams<
|
||||
MarketMaybeWithData,
|
||||
'tradableInstrument.instrument.product.settlementAsset.symbol'
|
||||
>) => {
|
||||
const value = data && getAsset(data);
|
||||
return value ? (
|
||||
<ButtonLink
|
||||
onClick={(e) => {
|
||||
openAssetDetailsDialog(value.id, e.target as HTMLElement);
|
||||
}}
|
||||
>
|
||||
{value.symbol}
|
||||
</ButtonLink>
|
||||
) : (
|
||||
''
|
||||
);
|
||||
},
|
||||
'data.openInterest'
|
||||
>) =>
|
||||
data?.data?.openInterest === undefined
|
||||
? '-'
|
||||
: addDecimalsFormatNumber(
|
||||
data?.data?.openInterest,
|
||||
data?.positionDecimalPlaces
|
||||
),
|
||||
},
|
||||
{
|
||||
headerName: t('Spread'),
|
||||
|
||||
@@ -152,8 +152,8 @@ export const ApplyCodeForm = () => {
|
||||
// show "code applied" message when successfully applied
|
||||
if (status === 'successful') {
|
||||
return (
|
||||
<div className="w-1/2 mx-auto">
|
||||
<h3 className="mb-5 text-xl text-center uppercase calt flex flex-row gap-2 justify-center items-center">
|
||||
<div className="mx-auto w-1/2">
|
||||
<h3 className="calt mb-5 flex flex-row items-center justify-center gap-2 text-center text-xl uppercase">
|
||||
<span className="text-vega-green-500">
|
||||
<VegaIcon name={VegaIconNames.TICK} size={20} />
|
||||
</span>{' '}
|
||||
@@ -205,15 +205,15 @@ export const ApplyCodeForm = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-2/3 max-w-md mx-auto bg-vega-clight-800 dark:bg-vega-cdark-800 p-8 rounded-lg">
|
||||
<h3 className="mb-4 text-2xl text-center calt">
|
||||
<div className="bg-vega-clight-800 dark:bg-vega-cdark-800 mx-auto w-2/3 max-w-md rounded-lg p-8">
|
||||
<h3 className="calt mb-4 text-center text-2xl">
|
||||
{t('Apply a referral code')}
|
||||
</h3>
|
||||
<p className="mb-4 text-center text-base">
|
||||
{t('Enter a referral code to get trading discounts.')}
|
||||
</p>
|
||||
<form
|
||||
className={classNames('w-full flex flex-col gap-4', {
|
||||
className={classNames('flex w-full flex-col gap-4', {
|
||||
'animate-shake': Boolean(errors.code),
|
||||
})}
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
@@ -227,13 +227,13 @@ export const ApplyCodeForm = () => {
|
||||
validate: (value) => validateCode(value, t),
|
||||
})}
|
||||
placeholder="Enter a code"
|
||||
className="mb-2 bg-vega-clight-900 dark:bg-vega-cdark-700"
|
||||
className="bg-vega-clight-900 dark:bg-vega-cdark-700 mb-2"
|
||||
/>
|
||||
</label>
|
||||
<RainbowButton variant="border" {...getButtonProps()} />
|
||||
</form>
|
||||
{errors.code && (
|
||||
<InputError className="break-words overflow-auto">
|
||||
<InputError className="overflow-auto break-words">
|
||||
{errors.code.message?.toString()}
|
||||
</InputError>
|
||||
)}
|
||||
@@ -245,10 +245,10 @@ export const ApplyCodeForm = () => {
|
||||
) : null}
|
||||
{previewData ? (
|
||||
<div className="mt-10">
|
||||
<h2 className="text-2xl mb-5">
|
||||
<h2 className="mb-5 text-2xl">
|
||||
{t(
|
||||
'You are joining the group shown, but will not have access to benefits until you have completed at least %s epochs.',
|
||||
[nextBenefitTierEpochsValue.toString()]
|
||||
'You are joining the group shown, but will not have access to benefits until you have completed at least {{count}} epochs.',
|
||||
{ count: nextBenefitTierEpochsValue }
|
||||
)}
|
||||
</h2>
|
||||
<Statistics data={previewData} program={program} as="referee" />
|
||||
|
||||
@@ -95,6 +95,11 @@ const CreateCodeDialog = ({
|
||||
const { stakeAvailable: currentStakeAvailable, requiredStake } =
|
||||
useStakeAvailable();
|
||||
|
||||
const { data: referralSets } = useReferral({
|
||||
pubKey,
|
||||
role: 'referrer',
|
||||
});
|
||||
|
||||
const onSubmit = () => {
|
||||
if (isReadOnly || !pubKey) {
|
||||
setErr('Not connected');
|
||||
@@ -193,6 +198,68 @@ const CreateCodeDialog = ({
|
||||
);
|
||||
}
|
||||
|
||||
if (!referralSets) {
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
{(status === 'idle' || status === 'loading' || status === 'error') && (
|
||||
<>
|
||||
{
|
||||
<p>
|
||||
{t(
|
||||
'There is currently no referral program active, are you sure you want to create a code?'
|
||||
)}
|
||||
</p>
|
||||
}
|
||||
</>
|
||||
)}
|
||||
{status === 'success' && code && (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex-1 min-w-0 p-2 text-sm rounded bg-vega-clight-700 dark:bg-vega-cdark-700">
|
||||
<p className="overflow-hidden whitespace-nowrap text-ellipsis">
|
||||
{code}
|
||||
</p>
|
||||
</div>
|
||||
<CopyWithTooltip text={code}>
|
||||
<TradingButton
|
||||
className="text-sm no-underline"
|
||||
icon={<VegaIcon name={VegaIconNames.COPY} />}
|
||||
>
|
||||
<span>{t('Copy')}</span>
|
||||
</TradingButton>
|
||||
</CopyWithTooltip>
|
||||
</div>
|
||||
)}
|
||||
<TradingButton
|
||||
fill={true}
|
||||
intent={Intent.Primary}
|
||||
onClick={() => onSubmit()}
|
||||
{...getButtonProps()}
|
||||
></TradingButton>
|
||||
{status === 'idle' && (
|
||||
<TradingButton
|
||||
fill={true}
|
||||
intent={Intent.Primary}
|
||||
onClick={() => {
|
||||
refetch();
|
||||
setDialogOpen(false);
|
||||
}}
|
||||
>
|
||||
{t('No')}
|
||||
</TradingButton>
|
||||
)}
|
||||
{err && <InputError>{err}</InputError>}
|
||||
<div className="flex justify-center pt-5 mt-2 text-sm border-t gap-4 text-default border-default">
|
||||
<ExternalLink href={ABOUT_REFERRAL_DOCS_LINK}>
|
||||
{t('About the referral program')}
|
||||
</ExternalLink>
|
||||
<ExternalLink href={DISCLAIMER_REFERRAL_DOCS_LINK}>
|
||||
{t('Disclaimer')}
|
||||
</ExternalLink>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
{(status === 'idle' || status === 'loading' || status === 'error') && (
|
||||
|
||||
@@ -6,7 +6,12 @@ import { BORDER_COLOR, GRADIENT } from './constants';
|
||||
import { Tag } from './tag';
|
||||
import type { ComponentProps, ReactNode } from 'react';
|
||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { DApp, TOKEN_PROPOSALS, useLinks } from '@vegaprotocol/environment';
|
||||
import {
|
||||
DApp,
|
||||
DocsLinks,
|
||||
TOKEN_PROPOSALS,
|
||||
useLinks,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { useT, ns } from '../../lib/use-t';
|
||||
import { Trans } from 'react-i18next';
|
||||
|
||||
@@ -88,10 +93,19 @@ export const TiersContainer = () => {
|
||||
return (
|
||||
<div className="text-base px-5 py-10 text-center">
|
||||
<Trans
|
||||
defaults="We're sorry but we don't have an active referral programme currently running. You can propose a new programme <0>here</0>."
|
||||
defaults="There are currently no active referral programs. Check the <0>Governance App</0> to see if there are any proposals in progress and vote."
|
||||
components={[
|
||||
<ExternalLink href={governanceLink(TOKEN_PROPOSALS)} key="link">
|
||||
{t('here')}
|
||||
{t('Governance App')}
|
||||
</ExternalLink>,
|
||||
]}
|
||||
ns={ns}
|
||||
/>
|
||||
<Trans
|
||||
defaults="You can propose a new program via the <0>Docs</0>."
|
||||
components={[
|
||||
<ExternalLink href={DocsLinks?.REFERRALS} key="link">
|
||||
{t('Docs')}
|
||||
</ExternalLink>,
|
||||
]}
|
||||
ns={ns}
|
||||
|
||||
@@ -8,6 +8,9 @@ import classNames from 'classnames';
|
||||
import type { HTMLAttributes, ReactNode } from 'react';
|
||||
import { Button } from './buttons';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { Routes } from '../../lib/links';
|
||||
import { DApp, useLinks } from '@vegaprotocol/environment';
|
||||
import truncate from 'lodash/truncate';
|
||||
|
||||
export const Tile = ({
|
||||
className,
|
||||
@@ -63,6 +66,10 @@ export const CodeTile = ({
|
||||
className?: string;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const consoleLink = useLinks(DApp.Console);
|
||||
const applyCodeLink = consoleLink(
|
||||
`#${Routes.REFERRALS_APPLY_CODE}?code=${code}`
|
||||
);
|
||||
return (
|
||||
<StatTile
|
||||
title={t('Your referral code')}
|
||||
@@ -89,10 +96,27 @@ export const CodeTile = ({
|
||||
{code}
|
||||
</div>
|
||||
</Tooltip>
|
||||
<CopyWithTooltip text={code}>
|
||||
<CopyWithTooltip text={code} description={t('Copy referral code')}>
|
||||
<Button className="text-sm no-underline !py-0 !px-0 h-fit !bg-transparent">
|
||||
<span className="sr-only">{t('Copy')}</span>
|
||||
<VegaIcon size={24} name={VegaIconNames.COPY} />
|
||||
<VegaIcon size={20} name={VegaIconNames.COPY} />
|
||||
</Button>
|
||||
</CopyWithTooltip>
|
||||
<CopyWithTooltip
|
||||
text={applyCodeLink}
|
||||
description={
|
||||
<>
|
||||
{t('Copy shareable apply code link')}
|
||||
{': '}
|
||||
<a className="text-vega-blue-500 underline" href={applyCodeLink}>
|
||||
{truncate(applyCodeLink, { length: 32 })}
|
||||
</a>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Button className="text-sm no-underline !py-0 !px-0 h-fit !bg-transparent">
|
||||
<span className="sr-only">{t('Copy')}</span>
|
||||
<VegaIcon size={20} name={VegaIconNames.OPEN_EXTERNAL} />
|
||||
</Button>
|
||||
</CopyWithTooltip>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { RewardsContainer } from '../../components/rewards-container';
|
||||
import { usePageTitleStore } from '../../stores';
|
||||
import { titlefy } from '@vegaprotocol/utils';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export const Rewards = () => {
|
||||
const t = useT();
|
||||
const title = t('Rewards');
|
||||
const { updateTitle } = usePageTitleStore((store) => ({
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
useEffect(() => {
|
||||
updateTitle(titlefy([title]));
|
||||
}, [updateTitle, title]);
|
||||
return (
|
||||
<div className="container mx-auto p-4">
|
||||
<h1 className="px-4 pb-4 text-2xl">{t('Rewards')}</h1>
|
||||
<h1 className="px-4 pb-4 text-2xl">{title}</h1>
|
||||
<RewardsContainer />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -65,7 +65,7 @@ export const FundingContainer = ({ marketId }: { marketId: string }) => {
|
||||
if (edge.node.endTime) {
|
||||
acc?.push({
|
||||
endTime: fromNanoSeconds(edge.node.endTime),
|
||||
fundingRate: Number(edge.node.fundingRate) * 100,
|
||||
fundingRate: Number(edge.node.fundingRate),
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
@@ -82,7 +82,8 @@ export const FundingContainer = ({ marketId }: { marketId: string }) => {
|
||||
<LineChart
|
||||
data={values}
|
||||
theme={theme}
|
||||
priceFormat={(fundingRate) => `${fundingRate.toFixed(4)}%`}
|
||||
priceFormat={(fundingRate) => `${(fundingRate * 100).toFixed(4)}%`}
|
||||
yAxisTickFormat="%"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import type { Account } from '@vegaprotocol/accounts';
|
||||
import { useAccounts } from '@vegaprotocol/accounts';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
NetworkParams,
|
||||
useNetworkParams,
|
||||
@@ -31,8 +30,10 @@ import { addDecimalsFormatNumberQuantum } from '@vegaprotocol/utils';
|
||||
import { ViewType, useSidebar } from '../sidebar';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
import { RewardsHistoryContainer } from './rewards-history';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const RewardsContainer = () => {
|
||||
const t = useT();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { params, loading: paramsLoading } = useNetworkParams([
|
||||
NetworkParams.reward_asset,
|
||||
@@ -121,7 +122,9 @@ export const RewardsContainer = () => {
|
||||
return (
|
||||
<Card
|
||||
key={assetId}
|
||||
title={t('%s Reward pot', asset.symbol)}
|
||||
title={t('{{assetSymbol}} Reward pot', {
|
||||
assetSymbol: asset.symbol,
|
||||
})}
|
||||
className="lg:col-span-3 xl:col-span-2"
|
||||
loading={loading}
|
||||
>
|
||||
@@ -167,6 +170,7 @@ export const RewardPot = ({
|
||||
assetId,
|
||||
vestingBalancesSummary,
|
||||
}: RewardPotProps) => {
|
||||
const t = useT();
|
||||
// TODO: Opening the sidebar for the first time works, but then clicking on redeem
|
||||
// for a different asset does not update the form
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
@@ -242,7 +246,9 @@ export const RewardPot = ({
|
||||
<CardTable>
|
||||
<tr>
|
||||
<CardTableTH className="flex items-center gap-1">
|
||||
{t(`Locked ${rewardAsset.symbol}`)}
|
||||
{t('Locked {{assetSymbol}}', {
|
||||
assetSymbol: rewardAsset.symbol,
|
||||
})}
|
||||
<VegaIcon name={VegaIconNames.LOCK} size={12} />
|
||||
</CardTableTH>
|
||||
<CardTableTD>
|
||||
@@ -254,7 +260,11 @@ export const RewardPot = ({
|
||||
</CardTableTD>
|
||||
</tr>
|
||||
<tr>
|
||||
<CardTableTH>{t(`Vesting ${rewardAsset.symbol}`)}</CardTableTH>
|
||||
<CardTableTH>
|
||||
{t('Vesting {{assetSymbol}}', {
|
||||
assetSymbol: rewardAsset.symbol,
|
||||
})}
|
||||
</CardTableTH>
|
||||
<CardTableTD>
|
||||
{addDecimalsFormatNumberQuantum(
|
||||
totalVesting.toString(),
|
||||
@@ -309,6 +319,7 @@ export const Vesting = ({
|
||||
baseRate: string;
|
||||
multiplier?: string;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const rate = new BigNumber(baseRate).times(multiplier);
|
||||
const rateFormatted = formatPercentage(Number(rate));
|
||||
const baseRateFormatted = formatPercentage(Number(baseRate));
|
||||
@@ -341,6 +352,7 @@ export const Multipliers = ({
|
||||
streakMultiplier?: string;
|
||||
hoarderMultiplier?: string;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const combinedMultiplier = new BigNumber(streakMultiplier).times(
|
||||
hoarderMultiplier
|
||||
);
|
||||
|
||||
@@ -16,12 +16,12 @@ import {
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
useRewardsHistoryQuery,
|
||||
type RewardsHistoryQuery,
|
||||
} from './__generated__/Rewards';
|
||||
import { useRewardsRowData } from './use-reward-row-data';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const RewardsHistoryContainer = ({
|
||||
epoch,
|
||||
@@ -140,6 +140,7 @@ export const RewardHistoryTable = ({
|
||||
onEpochChange: (epochVariables: { from: number; to: number }) => void;
|
||||
loading: boolean;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const [isParty, setIsParty] = useState(false);
|
||||
|
||||
const rowData = useRewardsRowData({
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Settings } from './settings';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
describe('Settings', () => {
|
||||
it('should the settings component with all the options', () => {
|
||||
render(<Settings />);
|
||||
expect(screen.getByText('Dark mode')).toBeInTheDocument();
|
||||
expect(screen.getByText('Share usage data')).toBeInTheDocument();
|
||||
expect(screen.getByText('Toast location')).toBeInTheDocument();
|
||||
expect(screen.getByText('Reset to default')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,13 @@
|
||||
import { Switch, ToastPositionSetter } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
Dialog,
|
||||
Intent,
|
||||
Switch,
|
||||
ToastPositionSetter,
|
||||
TradingButton,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
||||
import { useTelemetryApproval } from '../../lib/hooks/use-telemetry-approval';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useState, type ReactNode } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
@@ -9,6 +15,7 @@ export const Settings = () => {
|
||||
const t = useT();
|
||||
const { theme, setTheme } = useThemeSwitcher();
|
||||
const [isApproved, setIsApproved] = useTelemetryApproval();
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<div>
|
||||
<SettingsGroup label={t('Dark mode')}>
|
||||
@@ -33,6 +40,52 @@ export const Settings = () => {
|
||||
<SettingsGroup label={t('Toast location')}>
|
||||
<ToastPositionSetter />
|
||||
</SettingsGroup>
|
||||
<SettingsGroup label={t('Reset to default')}>
|
||||
<TradingButton
|
||||
name="reset-to-defaults"
|
||||
size="small"
|
||||
intent={Intent.None}
|
||||
onClick={() => {
|
||||
setOpen(true);
|
||||
}}
|
||||
>
|
||||
{t('Reset')}
|
||||
</TradingButton>
|
||||
<Dialog open={open} title={t('Reset')}>
|
||||
<div className="mb-4">
|
||||
<p>
|
||||
{t(
|
||||
'You will lose all persisted settings and you will be logged out.'
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{t('Are you sure you want to reset all settings to default?')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
<TradingButton
|
||||
name="reset-to-defaults-cancel"
|
||||
intent={Intent.Primary}
|
||||
onClick={() => {
|
||||
localStorage.clear();
|
||||
window.location.reload();
|
||||
}}
|
||||
>
|
||||
{t('Yes, clear cache and refresh')}
|
||||
</TradingButton>
|
||||
<TradingButton
|
||||
name="reset-to-defaults-cancel"
|
||||
intent={Intent.None}
|
||||
onClick={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
{t('No, keep settings')}
|
||||
</TradingButton>
|
||||
</div>
|
||||
</Dialog>
|
||||
</SettingsGroup>
|
||||
<SettingsGroup inline={false} label={t('App information')}>
|
||||
<dl className="text-sm grid grid-cols-2 gap-1">
|
||||
{process.env.GIT_TAG && (
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
CONSOLE_IMAGE_NAME=vegaprotocol/trading:latest
|
||||
VEGA_VERSION=v0.73.4
|
||||
VEGA_VERSION=v0.73.5
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
CONSOLE_IMAGE_NAME=vegaprotocol/trading:develop
|
||||
VEGA_VERSION=v0.73.4
|
||||
VEGA_VERSION=v0.73.5
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
CONSOLE_IMAGE_NAME=vegaprotocol/trading:main
|
||||
VEGA_VERSION=v0.73.4
|
||||
VEGA_VERSION=v0.73.5
|
||||
|
||||
@@ -34,4 +34,15 @@ def next_epoch(vega: VegaServiceNull):
|
||||
"Epoch not started after forwarding the duration of two epochs."
|
||||
)
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
def truncate_middle(market_id, start=6, end=4):
|
||||
if len(market_id) < 11:
|
||||
return market_id
|
||||
return market_id[:start] + '\u2026' + market_id[-end:]
|
||||
|
||||
def change_keys(page: Page, vega:VegaServiceNull, key_name):
|
||||
page.get_by_test_id("manage-vega-wallet").click()
|
||||
page.get_by_test_id("key-" + vega.wallet.public_key(key_name)).click()
|
||||
page.click(f'data-testid=key-{vega.wallet.public_key(key_name)} >> .inline-flex')
|
||||
page.reload()
|
||||
|
||||
@@ -136,8 +136,11 @@ def init_page(vega: VegaServiceNull, browser: Browser, request: pytest.FixtureRe
|
||||
page.add_init_script(script=window_env)
|
||||
yield page
|
||||
finally:
|
||||
if not os.path.exists("traces"):
|
||||
os.makedirs("traces")
|
||||
try:
|
||||
if not os.path.exists("apps/trading/e2e/traces"):
|
||||
os.makedirs("apps/trading/e2e/traces")
|
||||
except OSError as e:
|
||||
print(f"Failed to create directory '{'apps/trading/e2e/traces'}': {e}")
|
||||
|
||||
# Check whether this test failed or passed
|
||||
outcome = request.config.cache.get(request.node.nodeid, None)
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
from collections import namedtuple
|
||||
from vega_sim.service import VegaService
|
||||
from actions.vega import submit_multiple_orders, submit_order, submit_liquidity
|
||||
|
||||
|
||||
from wallet_config import MM_WALLET, MM_WALLET2, TERMINATE_WALLET, wallets
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
# Defined namedtuples
|
||||
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
|
||||
|
||||
# Wallet Configurations
|
||||
MM_WALLET = WalletConfig("mm", "pin")
|
||||
MM_WALLET2 = WalletConfig("mm2", "pin2")
|
||||
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
|
||||
|
||||
wallets = [MM_WALLET, MM_WALLET2, TERMINATE_WALLET]
|
||||
|
||||
mint_amount: float = 10e5
|
||||
market_name = "BTC:DAI_2023"
|
||||
|
||||
|
||||
def setup_simple_market(
|
||||
vega: VegaService,
|
||||
approve_proposal=True,
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import pytest
|
||||
from playwright.sync_api import expect, Page
|
||||
|
||||
@pytest.mark.usefixtures("page", "continuous_market", "risk_accepted")
|
||||
def test_see_market_depth_chart(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
# Click on the 'Depth' tab
|
||||
page.get_by_test_id("Depth").click()
|
||||
# Check if the 'Depth' tab and the depth chart are visible
|
||||
# 6006-DEPC-001
|
||||
expect(page.get_by_test_id("tab-depth")).to_be_visible()
|
||||
expect(page.locator('[class^="depth-chart-module_canvas__"]').first).to_be_visible()
|
||||
@@ -29,11 +29,12 @@ def continuous_market(vega):
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_limit_buy_order_GTT(continuous_market, vega: VegaService, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id(tif).select_option("Good 'til Time (GTT)")
|
||||
page.get_by_test_id(order_size).fill("10")
|
||||
page.get_by_test_id(order_price).fill("120")
|
||||
page.get_by_test_id(tif).select_option("Good 'til Time (GTT)")
|
||||
expires_at = datetime.now() + timedelta(days=1)
|
||||
expires_at_input_value = expires_at.strftime("%Y-%m-%dT%H:%M:%S")
|
||||
page.get_by_test_id("date-picker-field").clear()
|
||||
page.get_by_test_id("date-picker-field").fill(expires_at_input_value)
|
||||
# 7002-SORD-011
|
||||
expect(page.get_by_test_id("place-order").locator("span").first).to_have_text(
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
import pytest
|
||||
from collections import namedtuple
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService
|
||||
from actions.vega import submit_order
|
||||
from actions.utils import wait_for_toast_confirmation
|
||||
|
||||
# Defined namedtuples
|
||||
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
|
||||
|
||||
# Wallet Configurations
|
||||
MM_WALLET = WalletConfig("mm", "pin")
|
||||
|
||||
notional = "deal-ticket-fee-notional"
|
||||
fees = "deal-ticket-fee-fees"
|
||||
margin_required = "deal-ticket-fee-margin-required"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import pytest
|
||||
from collections import namedtuple
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService
|
||||
from actions.vega import submit_order
|
||||
@@ -7,14 +6,6 @@ from datetime import datetime, timedelta
|
||||
from conftest import init_vega
|
||||
from fixtures.market import setup_continuous_market
|
||||
|
||||
# Defined namedtuples
|
||||
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
|
||||
|
||||
# Wallet Configurations
|
||||
MM_WALLET = WalletConfig("mm", "pin")
|
||||
MM_WALLET2 = WalletConfig("mm2", "pin2")
|
||||
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
|
||||
|
||||
stop_order_btn = "order-type-Stop"
|
||||
stop_limit_order_btn = "order-type-StopLimit"
|
||||
stop_market_order_btn = "order-type-StopMarket"
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
import pytest
|
||||
from collections import namedtuple
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService
|
||||
from actions.vega import submit_order
|
||||
from conftest import init_vega
|
||||
from fixtures.market import setup_continuous_market
|
||||
from actions.utils import wait_for_toast_confirmation
|
||||
|
||||
# Defined namedtuples
|
||||
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
|
||||
|
||||
# Wallet Configurations
|
||||
MM_WALLET = WalletConfig("mm", "pin")
|
||||
MM_WALLET2 = WalletConfig("mm2", "pin2")
|
||||
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
|
||||
|
||||
stop_order_btn = "order-type-Stop"
|
||||
stop_limit_order_btn = "order-type-StopLimit"
|
||||
@@ -336,98 +326,4 @@ def test_submit_stop_oco_limit_order_cancel(
|
||||
page.locator(".ag-center-cols-container").locator('[col-id="status"]').last
|
||||
).to_have_text("CancelledOCO")
|
||||
|
||||
class TestStopOcoValidation:
|
||||
@pytest.fixture(scope="class")
|
||||
def vega(self, request):
|
||||
with init_vega(request) as vega:
|
||||
yield vega
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def continuous_market(self, vega):
|
||||
return setup_continuous_market(vega)
|
||||
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_stop_market_order_oco_form_validation(self, continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id(stop_order_btn).click()
|
||||
page.get_by_test_id(stop_market_order_btn).is_visible()
|
||||
page.get_by_test_id(stop_market_order_btn).click()
|
||||
page.get_by_test_id(oco).click()
|
||||
expect(
|
||||
page.get_by_test_id("sidebar-content").get_by_text("Trigger").last
|
||||
).to_be_visible()
|
||||
# 7002-SORD-084
|
||||
expect(page.locator('[for="triggerDirection-risesAbove-oco"]')).to_have_text(
|
||||
"Rises above"
|
||||
)
|
||||
# 7002-SORD-085
|
||||
expect(page.locator('[for="triggerDirection-fallsBelow-oco"]')).to_have_text(
|
||||
"Falls below"
|
||||
)
|
||||
# 7002-SORD-087
|
||||
expect(page.locator('[for="triggerType-price-oco"]')).to_have_text("Price")
|
||||
expect(page.locator('[for="triggerType-price"]')).to_be_checked
|
||||
# 7002-SORD-088
|
||||
expect(
|
||||
page.locator('[for="triggerType-trailingPercentOffset-oco"]')
|
||||
).to_have_text("Trailing Percent Offset")
|
||||
expect(page.locator('[for="order-size-oco"]')).to_have_text("Size")
|
||||
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_stop_limit_order_oco_form_validation(self, continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id(stop_order_btn).click()
|
||||
page.get_by_test_id(stop_market_order_btn).is_visible()
|
||||
page.get_by_test_id(stop_limit_order_btn).click()
|
||||
page.get_by_test_id(oco).click()
|
||||
expect(
|
||||
page.get_by_test_id("sidebar-content").get_by_text("Trigger").last
|
||||
).to_be_visible()
|
||||
# 7002-SORD-099
|
||||
expect(page.locator('[for="triggerDirection-risesAbove-oco"]')).to_have_text(
|
||||
"Rises above"
|
||||
)
|
||||
# 7002-SORD-091
|
||||
expect(page.locator('[for="triggerDirection-fallsBelow-oco"]')).to_have_text(
|
||||
"Falls below"
|
||||
)
|
||||
# 7002-SORD-095
|
||||
expect(page.locator('[for="triggerType-price-oco"]')).to_have_text("Price")
|
||||
expect(page.locator('[for="triggerType-price"]')).to_be_checked
|
||||
# 7002-SORD-095
|
||||
expect(
|
||||
page.locator('[for="triggerType-trailingPercentOffset-oco"]')
|
||||
).to_have_text("Trailing Percent Offset")
|
||||
|
||||
expect(page.locator('[for="order-size-oco"]')).to_have_text("Size")
|
||||
expect(page.locator('[for="order-price-oco"]')).to_have_text("Price")
|
||||
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_maximum_number_of_active_stop_orders_oco(
|
||||
self, continuous_market, vega: VegaService, page: Page
|
||||
):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id(stop_order_btn).click()
|
||||
page.get_by_test_id(stop_limit_order_btn).is_visible()
|
||||
page.get_by_test_id(stop_limit_order_btn).click()
|
||||
page.get_by_test_id(order_side_sell).click()
|
||||
page.locator("label").filter(has_text="Falls below").click()
|
||||
page.get_by_test_id(trigger_price).fill("102")
|
||||
page.get_by_test_id(order_size).fill("3")
|
||||
page.get_by_test_id(order_price).fill("103")
|
||||
page.get_by_test_id(oco).click()
|
||||
page.get_by_test_id(trigger_price_oco).fill("120")
|
||||
page.get_by_test_id(order_size_oco).fill("2")
|
||||
page.get_by_test_id(order_limit_price_oco).fill("99")
|
||||
for i in range(2):
|
||||
page.get_by_test_id(submit_stop_order).click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.wait_fn(1)
|
||||
vega.forward("20s")
|
||||
vega.wait_for_total_catchup()
|
||||
if page.get_by_test_id(close_toast).is_visible():
|
||||
page.get_by_test_id(close_toast).click()
|
||||
# 7002-SORD-011
|
||||
expect(page.get_by_test_id("stop-order-warning-limit")).to_have_text(
|
||||
"There is a limit of 4 active stop orders per market. Orders submitted above the limit will be immediately rejected."
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import pytest
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService
|
||||
from actions.utils import wait_for_toast_confirmation
|
||||
from actions.utils import change_keys
|
||||
from conftest import init_vega
|
||||
from fixtures.market import setup_continuous_market
|
||||
|
||||
@@ -39,9 +39,7 @@ def test_should_display_info_and_button_for_deposit(continuous_market, vega: Veg
|
||||
def test_should_show_an_error_if_your_balance_is_zero(continuous_market, vega: VegaService, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
vega.create_key("key_empty")
|
||||
page.get_by_test_id("manage-vega-wallet").click()
|
||||
page.locator('[role="menuitemradio"]').nth(4).click()
|
||||
page.reload()
|
||||
change_keys(page, vega, "key_empty")
|
||||
page.get_by_test_id(order_size).fill("200")
|
||||
page.get_by_test_id(order_price).fill("20")
|
||||
# 7002-SORD-060
|
||||
|
||||
@@ -4,8 +4,8 @@ import json
|
||||
from vega_sim.service import VegaService
|
||||
from fixtures.market import setup_simple_market
|
||||
from conftest import init_vega
|
||||
from collections import namedtuple
|
||||
from actions.vega import submit_order
|
||||
from wallet_config import MM_WALLET, TERMINATE_WALLET, wallets
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger()
|
||||
@@ -74,16 +74,6 @@ class TestGetStarted:
|
||||
|
||||
page.reload()
|
||||
|
||||
# Defined namedtuples
|
||||
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
|
||||
|
||||
# Wallet Configurations
|
||||
MM_WALLET = WalletConfig("mm", "pin")
|
||||
MM_WALLET2 = WalletConfig("mm2", "pin2")
|
||||
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
|
||||
|
||||
wallets = [MM_WALLET, MM_WALLET2, TERMINATE_WALLET]
|
||||
|
||||
mint_amount: float = 10e5
|
||||
|
||||
for wallet in wallets:
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
import pytest
|
||||
from collections import namedtuple
|
||||
from playwright.sync_api import expect, Page
|
||||
from vega_sim.service import VegaService
|
||||
from actions.vega import submit_order
|
||||
from conftest import init_vega
|
||||
from fixtures.market import setup_continuous_market
|
||||
|
||||
# Defined namedtuples
|
||||
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
|
||||
|
||||
# Wallet Configurations
|
||||
MM_WALLET = WalletConfig("mm", "pin")
|
||||
MM_WALLET2 = WalletConfig("mm2", "pin2")
|
||||
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
|
||||
|
||||
|
||||
wallets = [MM_WALLET, MM_WALLET2, TERMINATE_WALLET]
|
||||
|
||||
from wallet_config import MM_WALLET2
|
||||
|
||||
def hover_and_assert_tooltip(page: Page, element_text):
|
||||
element = page.get_by_text(element_text)
|
||||
@@ -52,55 +40,13 @@ class TestIcebergOrdersValidations:
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
expect(page.get_by_test_id("toast-content")).to_have_text(
|
||||
"Order filledYour transaction has been confirmed View in block explorerSubmit order - filledBTC:DAI_2023+3 @ 107.00 tDAI"
|
||||
"Order filledYour transaction has been confirmedView in block explorerSubmit order - filledBTC:DAI_2023+3 @ 107.00 tDAI"
|
||||
)
|
||||
page.get_by_test_id("All").click()
|
||||
expect(
|
||||
(page.get_by_role("row").locator('[col-id="type"]')).nth(1)
|
||||
).to_have_text("Limit (Iceberg)")
|
||||
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_iceberg_tooltips(self, continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id("iceberg").hover()
|
||||
expect(page.get_by_role("tooltip")).to_be_visible()
|
||||
page.get_by_test_id("iceberg").click()
|
||||
hover_and_assert_tooltip(page, "Peak size")
|
||||
hover_and_assert_tooltip(page, "Minimum size")
|
||||
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_iceberg_validations(self, continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id("iceberg").click()
|
||||
page.get_by_test_id("place-order").click()
|
||||
expect(page.get_by_test_id("deal-ticket-peak-error-message")).to_be_visible()
|
||||
expect(page.get_by_test_id("deal-ticket-peak-error-message")).to_have_text(
|
||||
"You need to provide a peak size"
|
||||
)
|
||||
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_be_visible()
|
||||
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_have_text(
|
||||
"You need to provide a minimum visible size"
|
||||
)
|
||||
page.get_by_test_id("order-peak-size").clear()
|
||||
page.get_by_test_id("order-peak-size").type("1")
|
||||
page.get_by_test_id("order-minimum-size").clear()
|
||||
page.get_by_test_id("order-minimum-size").type("2")
|
||||
expect(page.get_by_test_id("deal-ticket-peak-error-message")).to_be_visible()
|
||||
expect(page.get_by_test_id("deal-ticket-peak-error-message")).to_have_text(
|
||||
"Peak size cannot be greater than the size (0)"
|
||||
)
|
||||
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_be_visible()
|
||||
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_have_text(
|
||||
"Minimum visible size cannot be greater than the peak size (1)"
|
||||
)
|
||||
page.get_by_test_id("order-minimum-size").clear()
|
||||
page.get_by_test_id("order-minimum-size").type("0.1")
|
||||
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_be_visible()
|
||||
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_have_text(
|
||||
"Minimum visible size cannot be lower than 1"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted")
|
||||
def test_iceberg_open_order(continuous_market, vega: VegaService, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
|
||||
@@ -3,7 +3,8 @@ from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService
|
||||
from conftest import init_vega
|
||||
from fixtures.market import setup_continuous_market
|
||||
from actions.utils import next_epoch
|
||||
from actions.utils import next_epoch, truncate_middle, change_keys
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vega(request):
|
||||
@@ -20,19 +21,28 @@ def continuous_market(vega):
|
||||
def test_liquidity_provision_amendment(continuous_market, vega: VegaService, page: Page):
|
||||
# TODO Refactor asserting the grid
|
||||
page.goto(f"/#/liquidity/{continuous_market}")
|
||||
page.get_by_test_id("manage-vega-wallet").click()
|
||||
#TODO Rename "mm" to "marketMaker" so that we don't have to specify where to click when switching wallets
|
||||
# Currently the default click will click the middle of the element which will click the copy wallet key button
|
||||
page.locator('[role="menuitemradio"] >> .mr-2.uppercase').nth(1).click(position={ "x": 0, "y": 0}, force=True)
|
||||
page.reload()
|
||||
change_keys(page, vega, "market_maker")
|
||||
row = page.get_by_test_id("tab-myLP").locator(".ag-center-cols-container .ag-row").first
|
||||
expect(row).to_contain_text(
|
||||
"Active"
|
||||
)
|
||||
# 5002-LIQP-006
|
||||
expect(page.get_by_test_id("target-stake")).to_have_text("Target stake5.82757 tDAI")
|
||||
# 5002-LIQP-007
|
||||
expect(page.get_by_test_id("supplied-stake")).to_have_text("Supplied stake10,000.00 tDAI")
|
||||
# 5002-LIQP-008
|
||||
expect(page.get_by_test_id("liquidity-supplied")).to_have_text("Liquidity supplied 171,598.11%")
|
||||
expect(page.get_by_test_id("fees-paid")).to_have_text("Fees paid-")
|
||||
# 5002-LIQP-009
|
||||
expect(page.get_by_test_id("liquidity-market-id")).to_have_text("Market ID" + truncate_middle(continuous_market))
|
||||
expect(page.get_by_test_id("liquidity-learn-more")).to_have_text("Learn moreProviding liquidity")
|
||||
# 002-LIQP-010
|
||||
expect(page.get_by_test_id("liquidity-learn-more").get_by_test_id("external-link")).to_have_attribute("href", "https://docs.vega.xyz/testnet/concepts/liquidity/provision")
|
||||
|
||||
vega.submit_simple_liquidity(
|
||||
key_name="mm",
|
||||
key_name="market_maker",
|
||||
market_id=continuous_market,
|
||||
commitment_amount=100,
|
||||
commitment_amount=1,
|
||||
fee=0.001,
|
||||
is_amendment=True,
|
||||
)
|
||||
@@ -46,7 +56,30 @@ def test_liquidity_provision_amendment(continuous_market, vega: VegaService, pag
|
||||
)
|
||||
next_epoch(vega=vega)
|
||||
page.reload()
|
||||
expect(page.get_by_test_id("supplied-stake")).to_have_text("Supplied stake1.00001 tDAI")
|
||||
expect(page.get_by_test_id("liquidity-supplied")).to_have_text("Liquidity supplied 17.16%")
|
||||
row = page.get_by_test_id("tab-myLP").locator(".ag-center-cols-container .ag-row").first
|
||||
expect(row).to_contain_text(
|
||||
"Active"
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.skip("Waiting for the ability to cancel LP")
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_liquidity_provision_inactive(continuous_market, vega: VegaService, page: Page):
|
||||
# TODO Refactor asserting the grid
|
||||
page.goto(f"/#/liquidity/{continuous_market}")
|
||||
change_keys(page,vega, "market_maker")
|
||||
row = page.get_by_test_id("tab-myLP").locator(".ag-center-cols-container .ag-row").first
|
||||
expect(row).to_contain_text(
|
||||
"Active"
|
||||
)
|
||||
vega.submit_simple_liquidity(
|
||||
key_name="market_maker",
|
||||
market_id=continuous_market,
|
||||
commitment_amount=0,
|
||||
fee=0,
|
||||
is_amendment=False,
|
||||
)
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -1,23 +1,12 @@
|
||||
import pytest
|
||||
|
||||
from collections import namedtuple
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService, PeggedOrder
|
||||
from vega_sim.service import VegaService
|
||||
from actions.vega import submit_order
|
||||
|
||||
from wallet_config import MM_WALLET, MM_WALLET2
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
# Wallet Configurations
|
||||
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
|
||||
MM_WALLET = WalletConfig("mm", "pin")
|
||||
MM_WALLET2 = WalletConfig("mm2", "pin2")
|
||||
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
|
||||
|
||||
wallets = [MM_WALLET, MM_WALLET2, TERMINATE_WALLET]
|
||||
|
||||
table_row_selector = (
|
||||
'[data-testid="tab-open-markets"] .ag-center-cols-container .ag-row'
|
||||
)
|
||||
@@ -85,7 +74,7 @@ def test_price_monitoring(simple_market, vega: VegaService, page: Page):
|
||||
time_in_force="TIME_IN_FORCE_GTC",
|
||||
volume=99,
|
||||
)
|
||||
|
||||
#6002-MDET-009
|
||||
expect(
|
||||
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
|
||||
).to_have_text("0.00 (0.00%)")
|
||||
@@ -203,6 +192,7 @@ def test_price_monitoring(simple_market, vega: VegaService, page: Page):
|
||||
# commented out because we have an issue #4233
|
||||
# expect(page.get_by_text("Opening auction")).to_be_hidden()
|
||||
|
||||
#6002-MDET-009
|
||||
expect(
|
||||
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
|
||||
).to_have_text("50.00 (>100%)")
|
||||
|
||||
@@ -25,15 +25,15 @@ def test_table_headers(page: Page, create_markets):
|
||||
headers = [
|
||||
"Market",
|
||||
"Description",
|
||||
"Settlement asset",
|
||||
"Trading mode",
|
||||
"Status",
|
||||
"Mark price",
|
||||
"24h volume",
|
||||
"Settlement asset",
|
||||
"Open Interest",
|
||||
"Spread",
|
||||
"",
|
||||
]
|
||||
|
||||
page.wait_for_selector('[data-testid="tab-open-markets"]', state="visible")
|
||||
page_headers = (
|
||||
page.get_by_test_id("tab-open-markets").locator(".ag-header-cell-text").all()
|
||||
@@ -157,4 +157,4 @@ def test_drag_and_drop_column(page: Page, create_markets):
|
||||
page.locator(col_instrument_code).drag_to(
|
||||
page.locator('.ag-header-row [col-id="data.bestBidPrice"]')
|
||||
)
|
||||
expect(page.locator(col_instrument_code)).to_have_attribute("aria-colindex", "8")
|
||||
expect(page.locator(col_instrument_code)).to_have_attribute("aria-colindex", "9")
|
||||
|
||||
@@ -1,24 +1,11 @@
|
||||
from math import exp
|
||||
import pytest
|
||||
import vega_sim.api.governance as governance
|
||||
import re
|
||||
|
||||
from collections import namedtuple
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService
|
||||
|
||||
from conftest import init_vega
|
||||
from fixtures.market import setup_simple_market
|
||||
|
||||
# Defined namedtuples
|
||||
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
|
||||
|
||||
# Wallet Configurations
|
||||
MM_WALLET = WalletConfig("mm", "pin")
|
||||
MM_WALLET2 = WalletConfig("mm2", "pin2")
|
||||
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
|
||||
|
||||
wallets = [MM_WALLET, MM_WALLET2, TERMINATE_WALLET]
|
||||
from wallet_config import MM_WALLET, MM_WALLET2, TERMINATE_WALLET, wallets
|
||||
|
||||
row_selector = '[data-testid="tab-proposed-markets"] .ag-center-cols-container .ag-row'
|
||||
col_market_id = '[col-id="market"] [data-testid="stack-cell-primary"]'
|
||||
@@ -29,7 +16,6 @@ def vega(request):
|
||||
with init_vega(request) as vega:
|
||||
yield vega
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def proposed_market(vega: VegaService):
|
||||
# setup market without liquidity provided
|
||||
@@ -54,7 +40,6 @@ def test_can_see_table_headers(proposed_market, page: Page):
|
||||
"Settlement asset",
|
||||
"State",
|
||||
"Parent market",
|
||||
"Voting",
|
||||
"Closing date",
|
||||
"Enactment date",
|
||||
"",
|
||||
@@ -83,10 +68,6 @@ def test_renders_markets_correctly(proposed_market, page: Page):
|
||||
row.locator('[col-id="terms.change.successorConfiguration.parentMarketId"]')
|
||||
).to_have_text("-")
|
||||
|
||||
# 6001-MARK-054
|
||||
# 6001-MARK-055
|
||||
expect(row.get_by_test_id("vote-progress-bar-against")).to_be_visible()
|
||||
|
||||
# 6001-MARK-056
|
||||
expect(row.locator('[col-id="closing-date"]')).not_to_be_empty()
|
||||
|
||||
@@ -124,8 +105,8 @@ def test_can_drag_and_drop_columns(proposed_market, page: Page):
|
||||
page.goto("/#/markets/all")
|
||||
page.click('[data-testid="Proposed markets"]')
|
||||
col_market = page.locator('[col-id="market"]').first
|
||||
col_vote = page.locator('[col-id="voting"]').first
|
||||
col_market.drag_to(col_vote)
|
||||
col_state = page.locator('[col-id="state"]').first
|
||||
col_market.drag_to(col_state)
|
||||
|
||||
# Check the attribute of the dragged element
|
||||
attribute_value = col_market.get_attribute("aria-colindex")
|
||||
|
||||
@@ -1,23 +1,11 @@
|
||||
import pytest
|
||||
from collections import namedtuple
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService
|
||||
from actions.vega import submit_order
|
||||
from fixtures.market import setup_simple_market
|
||||
from conftest import init_vega
|
||||
|
||||
from actions.utils import wait_for_toast_confirmation
|
||||
|
||||
|
||||
# Defined namedtuples
|
||||
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
|
||||
|
||||
# Wallet Configurations
|
||||
MM_WALLET = WalletConfig("mm", "pin")
|
||||
MM_WALLET2 = WalletConfig("mm2", "pin2")
|
||||
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
|
||||
|
||||
wallets = [MM_WALLET, MM_WALLET2, TERMINATE_WALLET]
|
||||
from wallet_config import MM_WALLET, MM_WALLET2
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vega(request):
|
||||
|
||||
@@ -1,27 +1,11 @@
|
||||
import pytest
|
||||
import vega_sim.api.governance as governance
|
||||
import re
|
||||
|
||||
from collections import namedtuple
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService, PeggedOrder
|
||||
import vega_sim.proto.vega as vega_protos
|
||||
import vega_sim.api.governance as governance
|
||||
from actions.vega import submit_order
|
||||
from fixtures.market import setup_continuous_market
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
from vega_sim.service import MarketStateUpdateType
|
||||
from wallet_config import MM_WALLET, MM_WALLET2, GOVERNANCE_WALLET
|
||||
|
||||
# Defined namedtuples
|
||||
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
|
||||
|
||||
# Wallet Configurations
|
||||
MM_WALLET = WalletConfig("mm", "pin")
|
||||
MM_WALLET2 = WalletConfig("mm2", "pin2")
|
||||
GOVERNANCE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
|
||||
|
||||
wallets = [MM_WALLET, MM_WALLET2, GOVERNANCE_WALLET]
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vega", "page", "proposed_market", "risk_accepted")
|
||||
@@ -36,6 +20,9 @@ def test_market_lifecycle(proposed_market, vega: VegaService, page: Page):
|
||||
page.goto(f"/#/markets/{market_id}")
|
||||
|
||||
# check that market is in proposed state
|
||||
# 6002-MDET-006
|
||||
# 6002-MDET-007
|
||||
# 7002-SORD-061
|
||||
expect(trading_mode).to_have_text("No trading")
|
||||
expect(market_state).to_have_text("Proposed")
|
||||
|
||||
@@ -135,7 +122,7 @@ def test_market_closing_banners(page: Page, continuous_market, vega: VegaService
|
||||
page.goto(f"/#/markets/{market_id}")
|
||||
proposalID = vega.update_market_state(
|
||||
continuous_market,
|
||||
"mm",
|
||||
"market_maker",
|
||||
MarketStateUpdateType.Terminate,
|
||||
approve_proposal=False,
|
||||
vote_enactment_time = datetime.now() + timedelta(weeks=1),
|
||||
@@ -148,7 +135,7 @@ def test_market_closing_banners(page: Page, continuous_market, vega: VegaService
|
||||
|
||||
vega.update_market_state(
|
||||
continuous_market,
|
||||
"mm",
|
||||
"market_maker",
|
||||
MarketStateUpdateType.Terminate,
|
||||
approve_proposal=False,
|
||||
vote_enactment_time = datetime.now() + timedelta(weeks=1),
|
||||
@@ -161,7 +148,7 @@ def test_market_closing_banners(page: Page, continuous_market, vega: VegaService
|
||||
governance.approve_proposal(
|
||||
proposal_id=proposalID,
|
||||
wallet=vega.wallet,
|
||||
key_name="mm"
|
||||
key_name="market_maker"
|
||||
|
||||
)
|
||||
vega.forward("60s")
|
||||
|
||||
@@ -1,19 +1,10 @@
|
||||
import pytest
|
||||
from collections import namedtuple
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService
|
||||
from typing import List
|
||||
from actions.vega import submit_order, submit_liquidity, submit_multiple_orders
|
||||
from conftest import init_vega
|
||||
from fixtures.market import setup_simple_market
|
||||
|
||||
# Defined namedtuples
|
||||
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
|
||||
|
||||
# Wallet Configurations
|
||||
MM_WALLET = WalletConfig("mm", "pin")
|
||||
MM_WALLET2 = WalletConfig("mm2", "pin2")
|
||||
|
||||
from wallet_config import MM_WALLET, MM_WALLET2
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vega():
|
||||
|
||||
@@ -2,6 +2,7 @@ import pytest
|
||||
from playwright.sync_api import Page
|
||||
from vega_sim.service import VegaService
|
||||
from actions.vega import submit_order
|
||||
from actions.utils import change_keys
|
||||
|
||||
def check_pnl_color_value(element, expected_color, expected_value):
|
||||
color = element.evaluate("element => getComputedStyle(element).color")
|
||||
@@ -29,18 +30,16 @@ def test_pnl(continuous_market, vega: VegaService, page: Page):
|
||||
check_pnl_color_value(unrealised_pnl, "rgb(236, 0, 60)", "-4.00")
|
||||
|
||||
# profit Trading unrealised
|
||||
page.get_by_test_id("manage-vega-wallet").click()
|
||||
page.locator('[role="menuitemradio"] >> .mr-2.uppercase').nth(1).click(position={ "x": 0, "y": 0}, force=True)
|
||||
change_keys(page, vega, "market_maker")
|
||||
check_pnl_color_value(realised_pnl, "rgb(0, 0, 0)", "0.00")
|
||||
check_pnl_color_value(unrealised_pnl, "rgb(1, 145, 75)", "4.00")
|
||||
|
||||
# neutral Trading unrealised
|
||||
page.locator('[role="menuitemradio"] >> .mr-2.uppercase').nth(2).click(position={ "x": 0, "y": 0}, force=True)
|
||||
change_keys(page, vega, "market_maker_2")
|
||||
check_pnl_color_value(realised_pnl, "rgb(0, 0, 0)", "0.00")
|
||||
check_pnl_color_value(unrealised_pnl, "rgb(0, 0, 0)", "0.00")
|
||||
|
||||
# Portfolio Unrealised
|
||||
page.get_by_test_id("manage-vega-wallet").click(force=True)
|
||||
page.get_by_role("link", name="Portfolio").click()
|
||||
page.get_by_test_id("Positions").click()
|
||||
page.wait_for_selector(
|
||||
@@ -52,10 +51,10 @@ def test_pnl(continuous_market, vega: VegaService, page: Page):
|
||||
'//div[@role="row" and .//div[@col-id="partyId"]/div/span[text()="Key 1"]]'
|
||||
)
|
||||
key_mm = page.query_selector(
|
||||
'//div[@role="row" and .//div[@col-id="partyId"]/div/span[text()="mm"]]'
|
||||
'//div[@role="row" and .//div[@col-id="partyId"]/div/span[text()="market_maker"]]'
|
||||
)
|
||||
key_mm2 = page.query_selector(
|
||||
'//div[@role="row" and .//div[@col-id="partyId"]/div/span[text()="mm2"]]'
|
||||
'//div[@role="row" and .//div[@col-id="partyId"]/div/span[text()="market_maker_2"]]'
|
||||
)
|
||||
|
||||
key_1_unrealised_pnl = key_1.query_selector('xpath=./div[@col-id="unrealisedPNL"]')
|
||||
@@ -101,12 +100,11 @@ def test_pnl(continuous_market, vega: VegaService, page: Page):
|
||||
check_pnl_color_value(unrealised_pnl, "rgb(0, 0, 0)", "0.00")
|
||||
|
||||
# profit trading realised
|
||||
page.get_by_test_id("manage-vega-wallet").click()
|
||||
page.locator('[role="menuitemradio"] >> .mr-2.uppercase').nth(1).click(position={ "x": 0, "y": 0}, force=True)
|
||||
change_keys(page, vega, "market_maker")
|
||||
check_pnl_color_value(realised_pnl, "rgb(1, 145, 75)", "8.00")
|
||||
check_pnl_color_value(unrealised_pnl, "rgb(0, 0, 0)", "0.00")
|
||||
|
||||
# loss trading realised
|
||||
page.locator('[role="menuitemradio"] >> .mr-2.uppercase').nth(0).click(position={ "x": 0, "y": 0}, force=True)
|
||||
change_keys(page, vega, "Key 1")
|
||||
check_pnl_color_value(realised_pnl, "rgb(236, 0, 60)", "-8.00")
|
||||
check_pnl_color_value(unrealised_pnl, "rgb(0, 0, 0)", "0.00")
|
||||
|
||||
@@ -32,12 +32,12 @@ def test_share_usage_data(page: Page):
|
||||
|
||||
# Define a mapping of icon selectors to toast selectors
|
||||
ICON_TO_TOAST = {
|
||||
'aria-label="arrow-top-left icon"': 'class="group absolute z-20 top-0 left-0 max-w-full max-h-full overflow-x-hidden overflow-y-auto p-4"',
|
||||
'aria-label="arrow-up icon"': 'class="group absolute z-20 top-0 left-[50%] translate-x-[-50%] max-w-full max-h-full overflow-x-hidden overflow-y-auto p-4"',
|
||||
'aria-label="arrow-top-right icon"': 'class="group absolute z-20 top-0 right-0 max-w-full max-h-full overflow-x-hidden overflow-y-auto p-4"',
|
||||
'aria-label="arrow-bottom-left icon"': 'class="group absolute z-20 bottom-0 left-0 max-w-full max-h-full overflow-x-hidden overflow-y-auto p-4"',
|
||||
'aria-label="arrow-down icon"': 'class="group absolute z-20 bottom-0 left-[50%] translate-x-[-50%] max-w-full max-h-full overflow-x-hidden overflow-y-auto p-4"',
|
||||
'aria-label="arrow-bottom-right icon"': 'class="group absolute z-20 bottom-0 right-0 max-w-full max-h-full overflow-x-hidden overflow-y-auto p-4"',
|
||||
'aria-label="arrow-top-left icon"': 'class="relative flex-1 overflow-auto p-4 pr-[40px] [&>p]:mb-[2.5px]"',
|
||||
'aria-label="arrow-up icon"': 'class="relative flex-1 overflow-auto p-4 pr-[40px] [&>p]:mb-[2.5px]"',
|
||||
'aria-label="arrow-top-right icon"': 'class="relative flex-1 overflow-auto p-4 pr-[40px] [&>p]:mb-[2.5px]"',
|
||||
'aria-label="arrow-bottom-left icon"': 'class="relative flex-1 overflow-auto p-4 pr-[40px] [&>p]:mb-[2.5px]"',
|
||||
'aria-label="arrow-down icon"': 'class="relative flex-1 overflow-auto p-4 pr-[40px] [&>p]:mb-[2.5px]"',
|
||||
'aria-label="arrow-bottom-right icon"': 'class="relative flex-1 overflow-auto p-4 pr-[40px] [&>p]:mb-[2.5px]"',
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
# page.goto(f"/#/markets/{continuous_market}")
|
||||
# vega.forward("24h")
|
||||
# vega.wait_for_total_catchup()
|
||||
# submit_order(vega, "mm", continuous_market, "SIDE_SELL", 1, 101.50000)
|
||||
# submit_order(vega, "mm2", continuous_market, "SIDE_SELL", 1, 101.50000)
|
||||
# submit_order(vega, "market_maker", continuous_market, "SIDE_SELL", 1, 101.50000)
|
||||
# submit_order(vega, "market_maker_2", continuous_market, "SIDE_SELL", 1, 101.50000)
|
||||
# vega.forward("10s")
|
||||
# vega.wait_for_total_catchup()
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import pytest
|
||||
import pytest
|
||||
import re
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService
|
||||
from actions.utils import wait_for_toast_confirmation, create_and_faucet_wallet, WalletConfig, next_epoch
|
||||
from actions.utils import wait_for_toast_confirmation, create_and_faucet_wallet, WalletConfig, next_epoch, change_keys
|
||||
import vega_sim.proto.vega as vega_protos
|
||||
|
||||
LIQ = WalletConfig("liq", "liq")
|
||||
@@ -20,40 +20,40 @@ def test_transfer_submit(continuous_market, vega: VegaService, page: Page):
|
||||
# 1003-TRAN-010
|
||||
# 1003-TRAN-023
|
||||
page.goto('/#/portfolio')
|
||||
|
||||
|
||||
expect(page.get_by_test_id('transfer-form')).to_be_visible
|
||||
page.get_by_test_id('select-asset').click()
|
||||
expect(page.get_by_test_id('rich-select-option')).to_have_count(1)
|
||||
|
||||
|
||||
page.get_by_test_id('rich-select-option').click()
|
||||
page.select_option('[data-testid=transfer-form] [name="toVegaKey"]', index=2)
|
||||
page.select_option('[data-testid=transfer-form] [name="fromAccount"]', index=1)
|
||||
|
||||
expected_asset_text = re.compile(r"tDAI tDAI999,991.49731 tDAI.{6}….{4}")
|
||||
|
||||
expected_asset_text = re.compile(r"tDAI tDAI999991.49731 tDAI.{6}….{4}")
|
||||
actual_asset_text = page.get_by_test_id('select-asset').text_content().strip()
|
||||
|
||||
|
||||
assert expected_asset_text.search(actual_asset_text), f"Expected pattern not found in {actual_asset_text}"
|
||||
|
||||
|
||||
page.locator('[data-testid=transfer-form] input[name="amount"]').fill('1')
|
||||
expect(page.locator('[data-testid=transfer-form] input[name="amount"]')).not_to_be_empty()
|
||||
|
||||
|
||||
page.locator('[data-testid=transfer-form] [type="submit"]').click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
expected_confirmation_text = re.compile(r"Transfer completeYour transaction has been confirmed View in block explorerTransferTo .{6}….{6}1\.00 tDAI")
|
||||
expected_confirmation_text = re.compile(r"Transfer completeYour transaction has been confirmedView in block explorerTransferTo .{6}….{6}1\.00 tDAI")
|
||||
actual_confirmation_text = page.get_by_test_id('toast-content').text_content()
|
||||
assert expected_confirmation_text.search(actual_confirmation_text), f"Expected pattern not found in {actual_confirmation_text}"
|
||||
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_transfer_vesting_below_minimum(continuous_market, vega: VegaService, page: Page):
|
||||
vega.update_network_parameter(
|
||||
"mm", parameter="transfer.minTransferQuantumMultiple", new_value="100000"
|
||||
"market_maker", parameter="transfer.minTransferQuantumMultiple", new_value="100000"
|
||||
)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
|
||||
create_and_faucet_wallet(vega=vega, wallet=PARTY_A, amount=1e3)
|
||||
create_and_faucet_wallet(vega=vega, wallet=PARTY_B, amount=1e5)
|
||||
create_and_faucet_wallet(vega=vega, wallet=PARTY_C, amount=1e5)
|
||||
@@ -96,13 +96,11 @@ def test_transfer_vesting_below_minimum(continuous_market, vega: VegaService, pa
|
||||
next_epoch(vega=vega)
|
||||
page.goto('/#/portfolio')
|
||||
expect(page.get_by_test_id('transfer-form')).to_be_visible
|
||||
|
||||
page.get_by_test_id("manage-vega-wallet").click()
|
||||
page.locator('[role="menuitemradio"]').nth(5).click()
|
||||
page.reload()
|
||||
|
||||
change_keys(page, vega, "party_b")
|
||||
page.get_by_test_id('select-asset').click()
|
||||
page.get_by_test_id('rich-select-option').click()
|
||||
|
||||
|
||||
option_value = page.locator('[data-testid="transfer-form"] [name="fromAccount"] option[value^="ACCOUNT_TYPE_VESTED_REWARDS"]').first.get_attribute("value")
|
||||
|
||||
page.select_option('[data-testid="transfer-form"] [name="fromAccount"]', option_value)
|
||||
@@ -122,13 +120,13 @@ def test_transfer_vesting_below_minimum(continuous_market, vega: VegaService, pa
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(10)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
|
||||
page.get_by_text("Use max").first.click()
|
||||
page.locator('[data-testid=transfer-form] [type="submit"]').click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
expected_confirmation_text = re.compile(r"Transfer completeYour transaction has been confirmed View in block explorerTransferTo .{6}….{6}0\.00001 tDAI")
|
||||
expected_confirmation_text = re.compile(r"Transfer completeYour transaction has been confirmedView in block explorerTransferTo .{6}….{6}0\.00001 tDAI")
|
||||
actual_confirmation_text = page.get_by_test_id('toast-content').text_content()
|
||||
assert expected_confirmation_text.search(actual_confirmation_text), f"Expected pattern not found in {actual_confirmation_text}"
|
||||
assert expected_confirmation_text.search(actual_confirmation_text), f"Expected pattern not found in {actual_confirmation_text}"
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
from collections import namedtuple
|
||||
|
||||
# Defined namedtuples
|
||||
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
|
||||
|
||||
# Wallet Configurations
|
||||
MM_WALLET = WalletConfig("market_maker", "pin")
|
||||
MM_WALLET2 = WalletConfig("market_maker_2", "pin2")
|
||||
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
|
||||
GOVERNANCE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
|
||||
|
||||
wallets = [MM_WALLET, MM_WALLET2, TERMINATE_WALLET, GOVERNANCE_WALLET]
|
||||
@@ -66,7 +66,18 @@ i18n
|
||||
'environment',
|
||||
'fills',
|
||||
'funding-payments',
|
||||
'ledger',
|
||||
'liquidity',
|
||||
'market-depth',
|
||||
'markets',
|
||||
'orders',
|
||||
'positions',
|
||||
'trades',
|
||||
'trading',
|
||||
'ui-toolkit',
|
||||
'utils',
|
||||
'wallet',
|
||||
'web3',
|
||||
],
|
||||
defaultNS: 'trading',
|
||||
nsSeparator: false,
|
||||
|
||||
@@ -170,7 +170,7 @@ html [data-theme='dark'] {
|
||||
|
||||
.ag-theme-balham,
|
||||
.ag-theme-balham-dark {
|
||||
--ag-grid-size: 2px; /* Used for compactness */
|
||||
--ag-grid-size: 5px; /* Used for compactness */
|
||||
--ag-row-height: 36px;
|
||||
--ag-header-height: 28px;
|
||||
}
|
||||
@@ -184,7 +184,7 @@ html [data-theme='dark'] {
|
||||
|
||||
/* Light variables */
|
||||
.ag-theme-balham {
|
||||
--ag-background-color: transparent;
|
||||
--ag-background-color: theme(colors.vega.clight.900);
|
||||
--ag-border-color: theme(colors.vega.clight.600);
|
||||
--ag-header-background-color: theme(colors.vega.clight.700);
|
||||
--ag-odd-row-background-color: transparent;
|
||||
@@ -196,7 +196,7 @@ html [data-theme='dark'] {
|
||||
|
||||
/* Dark variables */
|
||||
.ag-theme-balham-dark {
|
||||
--ag-background-color: transparent;
|
||||
--ag-background-color: theme(colors.vega.cdark.900);
|
||||
--ag-border-color: theme(colors.vega.cdark.600);
|
||||
--ag-header-background-color: theme(colors.vega.cdark.700);
|
||||
--ag-odd-row-background-color: transparent;
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
import { act, render, screen } from '@testing-library/react';
|
||||
import { act, render, screen, within } from '@testing-library/react';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
import type { AccountFields } from './accounts-data-provider';
|
||||
import { getAccountData } from './accounts-data-provider';
|
||||
import { AccountTable } from './accounts-table';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
const asset1 = {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-1',
|
||||
symbol: 'tBTC',
|
||||
decimals: 5,
|
||||
name: 'T BTC',
|
||||
};
|
||||
const asset2 = {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-2',
|
||||
symbol: 'aBTC',
|
||||
decimals: 5,
|
||||
name: 'A BTC',
|
||||
};
|
||||
const singleRow = {
|
||||
__typename: 'AccountBalance',
|
||||
type: Types.AccountType.ACCOUNT_TYPE_MARGIN,
|
||||
@@ -13,12 +26,7 @@ const singleRow = {
|
||||
__typename: 'Market',
|
||||
id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35',
|
||||
},
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||
symbol: 'tBTC',
|
||||
decimals: 5,
|
||||
},
|
||||
asset: asset1,
|
||||
available: '125600000',
|
||||
used: '125600000',
|
||||
total: '251200000',
|
||||
@@ -33,12 +41,7 @@ const secondRow = {
|
||||
__typename: 'Market',
|
||||
id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35',
|
||||
},
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||
symbol: 'aBTC',
|
||||
decimals: 5,
|
||||
},
|
||||
asset: asset2,
|
||||
available: '125600001',
|
||||
used: '125600001',
|
||||
total: '251200002',
|
||||
@@ -134,7 +137,7 @@ describe('AccountsTable', () => {
|
||||
|
||||
it('should sort assets', async () => {
|
||||
// 7001-COLL-010
|
||||
const { container } = render(
|
||||
render(
|
||||
<AccountTable
|
||||
rowData={multiRowData}
|
||||
onClickAsset={() => null}
|
||||
@@ -142,13 +145,13 @@ describe('AccountsTable', () => {
|
||||
/>
|
||||
);
|
||||
|
||||
const headerCell = screen.getByText('Asset');
|
||||
await userEvent.click(headerCell);
|
||||
const rows = container.querySelectorAll(
|
||||
'.ag-center-cols-container .ag-row'
|
||||
);
|
||||
expect(rows[0].textContent).toContain('aBTC');
|
||||
expect(rows[1].textContent).toContain('tBTC');
|
||||
const headerCell = screen
|
||||
.getAllByRole('columnheader')
|
||||
.find((h) => h?.getAttribute('col-id') === 'asset.symbol') as HTMLElement;
|
||||
|
||||
await userEvent.click(within(headerCell).getByText(/asset/i));
|
||||
|
||||
expect(headerCell).toHaveAttribute('aria-sort', 'ascending');
|
||||
});
|
||||
|
||||
it('should apply correct formatting in view as user mode', async () => {
|
||||
@@ -176,12 +179,7 @@ describe('AccountsTable', () => {
|
||||
rowData={singleRowData}
|
||||
onClickAsset={() => null}
|
||||
isReadOnly={false}
|
||||
pinnedAsset={{
|
||||
decimals: 5,
|
||||
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||
symbol: 'tBTC',
|
||||
name: 'tBTC',
|
||||
}}
|
||||
pinnedAsset={asset1}
|
||||
/>
|
||||
);
|
||||
await screen.findAllByRole('rowgroup');
|
||||
@@ -213,23 +211,13 @@ describe('AccountsTable', () => {
|
||||
const result = getAccountData([singleRow]);
|
||||
const expected = [
|
||||
{
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
decimals: 5,
|
||||
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||
symbol: 'tBTC',
|
||||
},
|
||||
asset: asset1,
|
||||
available: '0',
|
||||
balance: '0',
|
||||
breakdown: [
|
||||
{
|
||||
__typename: 'AccountBalance',
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
decimals: 5,
|
||||
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||
symbol: 'tBTC',
|
||||
},
|
||||
asset: asset1,
|
||||
available: '0',
|
||||
balance: '125600000',
|
||||
total: '125600000',
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import {
|
||||
fireEvent,
|
||||
render,
|
||||
screen,
|
||||
waitFor,
|
||||
within,
|
||||
} from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import {
|
||||
@@ -7,7 +13,7 @@ import {
|
||||
TransferForm,
|
||||
type TransferFormProps,
|
||||
} from './transfer-form';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
import { AccountType, AccountTypeMapping } from '@vegaprotocol/types';
|
||||
import { removeDecimal } from '@vegaprotocol/utils';
|
||||
|
||||
describe('TransferForm', () => {
|
||||
@@ -39,8 +45,7 @@ describe('TransferForm', () => {
|
||||
};
|
||||
|
||||
const amount = '100';
|
||||
const pubKey =
|
||||
'70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680';
|
||||
const pubKey = '1'.repeat(64);
|
||||
const asset = {
|
||||
id: 'eur',
|
||||
symbol: '€',
|
||||
@@ -50,10 +55,7 @@ describe('TransferForm', () => {
|
||||
};
|
||||
const props = {
|
||||
pubKey,
|
||||
pubKeys: [
|
||||
pubKey,
|
||||
'a4b6e3de5d7ef4e31ae1b090be49d1a2ef7bcefff60cccf7658a0d4922651cce',
|
||||
],
|
||||
pubKeys: [pubKey, '2'.repeat(64)],
|
||||
feeFactor: '0.001',
|
||||
submitTransfer: jest.fn(),
|
||||
accounts: [
|
||||
@@ -177,7 +179,7 @@ describe('TransferForm', () => {
|
||||
|
||||
// Test use max button
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Use max' }));
|
||||
expect(amountInput).toHaveValue('1000');
|
||||
expect(amountInput).toHaveValue('1000.00');
|
||||
|
||||
// Test amount validation
|
||||
await userEvent.clear(amountInput);
|
||||
@@ -262,7 +264,7 @@ describe('TransferForm', () => {
|
||||
|
||||
// Test use max button
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Use max' }));
|
||||
expect(amountInput).toHaveValue('100');
|
||||
expect(amountInput).toHaveValue('100.00');
|
||||
|
||||
// If transfering from a vested account 'include fees' checkbox should
|
||||
// be disabled and fees should be 0
|
||||
@@ -291,6 +293,88 @@ describe('TransferForm', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('handles lots of decimal places', async () => {
|
||||
const balance = '904195168829277777';
|
||||
const expectedBalance = '0.904195168829277777';
|
||||
|
||||
const longDecimalAsset = {
|
||||
id: 'assetId',
|
||||
symbol: 'VEGA',
|
||||
name: 'VEGA',
|
||||
decimals: 18,
|
||||
quantum: '1',
|
||||
};
|
||||
|
||||
const account = {
|
||||
type: AccountType.ACCOUNT_TYPE_VESTED_REWARDS,
|
||||
asset: longDecimalAsset,
|
||||
balance,
|
||||
};
|
||||
|
||||
const mockSubmit = jest.fn();
|
||||
|
||||
renderComponent({
|
||||
...props,
|
||||
accounts: [account],
|
||||
submitTransfer: mockSubmit,
|
||||
minQuantumMultiple: '100000',
|
||||
});
|
||||
|
||||
// Select a pubkey
|
||||
await userEvent.selectOptions(
|
||||
screen.getByLabelText('To Vega key'),
|
||||
props.pubKeys[1] // Use not current pubkey so we can check it switches to current pubkey later
|
||||
);
|
||||
|
||||
// Select asset
|
||||
await selectAsset(longDecimalAsset);
|
||||
|
||||
const accountSelect = screen.getByLabelText('From account');
|
||||
const option = within(accountSelect)
|
||||
.getAllByRole('option')
|
||||
.find(
|
||||
(o) => o.getAttribute('value') === `${account.type}-${account.asset.id}`
|
||||
);
|
||||
// plus one for disabled 'please select' option
|
||||
|
||||
expect(option).toHaveTextContent(
|
||||
`${AccountTypeMapping[account.type]} (${expectedBalance} ${
|
||||
account.asset.symbol
|
||||
})`
|
||||
);
|
||||
|
||||
await userEvent.selectOptions(
|
||||
accountSelect,
|
||||
`${AccountType.ACCOUNT_TYPE_VESTED_REWARDS}-${longDecimalAsset.id}`
|
||||
);
|
||||
|
||||
expect(accountSelect).toHaveValue(
|
||||
`${AccountType.ACCOUNT_TYPE_VESTED_REWARDS}-${longDecimalAsset.id}`
|
||||
);
|
||||
|
||||
// Check switch back to connected key
|
||||
const amountInput = screen.getByLabelText('Amount');
|
||||
|
||||
// Test use max button
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Use max' }));
|
||||
expect(amountInput).toHaveValue(expectedBalance);
|
||||
|
||||
await submit();
|
||||
|
||||
await waitFor(() => {
|
||||
// 1003-TRAN-023
|
||||
expect(mockSubmit).toHaveBeenCalledTimes(1);
|
||||
expect(mockSubmit).toHaveBeenCalledWith({
|
||||
fromAccountType: AccountType.ACCOUNT_TYPE_VESTED_REWARDS,
|
||||
toAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
to: props.pubKey,
|
||||
asset: longDecimalAsset.id,
|
||||
amount: balance,
|
||||
oneOff: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('IncludeFeesCheckbox', () => {
|
||||
it('validates fields and submits when checkbox is checked', async () => {
|
||||
const mockSubmit = jest.fn();
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
useVegaPublicKey,
|
||||
addDecimal,
|
||||
formatNumber,
|
||||
addDecimalsFormatNumber,
|
||||
toBigNum,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { useT } from './use-t';
|
||||
@@ -218,12 +217,7 @@ export const TransferForm = ({
|
||||
<AssetOption
|
||||
key={a.key}
|
||||
asset={a}
|
||||
balance={
|
||||
<Balance
|
||||
balance={formatNumber(a.balance, a.decimals)}
|
||||
symbol={a.symbol}
|
||||
/>
|
||||
}
|
||||
balance={<Balance balance={a.balance} symbol={a.symbol} />}
|
||||
/>
|
||||
))}
|
||||
</TradingRichSelect>
|
||||
@@ -290,8 +284,8 @@ export const TransferForm = ({
|
||||
return (
|
||||
<option value={id} key={id}>
|
||||
{AccountTypeMapping[a.type]} (
|
||||
{addDecimalsFormatNumber(a.balance, a.asset.decimals)}{' '}
|
||||
{a.asset.symbol})
|
||||
{addDecimal(a.balance, a.asset.decimals)} {a.asset.symbol}
|
||||
)
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
@@ -420,7 +414,7 @@ export const TransferForm = ({
|
||||
type="button"
|
||||
className="absolute right-0 top-0 ml-auto text-xs underline"
|
||||
onClick={() =>
|
||||
setValue('amount', parseFloat(accountBalance).toString(), {
|
||||
setValue('amount', accountBalance, {
|
||||
shouldValidate: true,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ export const AgGridThemed = ({
|
||||
ref={gridRef}
|
||||
overlayLoadingTemplate={t('Loading...')}
|
||||
overlayNoRowsTemplate={t('No data')}
|
||||
suppressDragLeaveHidesColumns
|
||||
{...defaultProps}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { getAsset, getProductType, getQuoteName } from '@vegaprotocol/markets';
|
||||
import { getAsset, getQuoteName } from '@vegaprotocol/markets';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
|
||||
@@ -297,134 +297,120 @@ export const DealTicketMarginDetails = ({
|
||||
);
|
||||
|
||||
const quoteName = getQuoteName(market);
|
||||
const productType = getProductType(market);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full gap-2 pt-2">
|
||||
{/*
|
||||
TODO: remove this conditional check once the following PRs are deployed
|
||||
and the estimatePosition query is working for perps
|
||||
|
||||
- https://github.com/vegaprotocol/vega/pull/10119
|
||||
- https://github.com/vegaprotocol/vega/pull/10122
|
||||
*/}
|
||||
{productType === 'Future' && (
|
||||
<>
|
||||
<Accordion>
|
||||
<AccordionPanel
|
||||
itemId="margin"
|
||||
trigger={
|
||||
<AccordionPrimitive.Trigger
|
||||
data-testid="accordion-toggle"
|
||||
className={classNames(
|
||||
'w-full',
|
||||
'flex items-center gap-2 text-xs',
|
||||
'group'
|
||||
)}
|
||||
>
|
||||
<div
|
||||
data-testid={`deal-ticket-fee-margin-required`}
|
||||
key={'value-dropdown'}
|
||||
className="flex items-center justify-between w-full gap-2"
|
||||
>
|
||||
<div className="flex items-center text-left gap-1">
|
||||
<Tooltip
|
||||
description={t(
|
||||
'MARGIN_DIFF_TOOLTIP_TEXT',
|
||||
MARGIN_DIFF_TOOLTIP_TEXT,
|
||||
{ assetSymbol }
|
||||
)}
|
||||
>
|
||||
<span className="text-muted">
|
||||
{t('Margin required')}
|
||||
</span>
|
||||
</Tooltip>
|
||||
|
||||
<AccordionChevron size={10} />
|
||||
</div>
|
||||
<Tooltip
|
||||
description={
|
||||
formatRange(
|
||||
marginRequiredBestCase,
|
||||
marginRequiredWorstCase,
|
||||
assetDecimals
|
||||
) ?? '-'
|
||||
}
|
||||
>
|
||||
<div className="font-mono text-right">
|
||||
{formatValue(
|
||||
marginRequiredWorstCase,
|
||||
assetDecimals,
|
||||
quantum
|
||||
)}{' '}
|
||||
{assetSymbol || ''}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</AccordionPrimitive.Trigger>
|
||||
}
|
||||
<Accordion>
|
||||
<AccordionPanel
|
||||
itemId="margin"
|
||||
trigger={
|
||||
<AccordionPrimitive.Trigger
|
||||
data-testid="accordion-toggle"
|
||||
className={classNames(
|
||||
'w-full',
|
||||
'flex items-center gap-2 text-xs',
|
||||
'group'
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-col w-full gap-2">
|
||||
<KeyValue
|
||||
label={t('Total margin available')}
|
||||
indent
|
||||
value={formatValue(totalMarginAvailable, assetDecimals)}
|
||||
formattedValue={formatValue(
|
||||
totalMarginAvailable,
|
||||
<div
|
||||
data-testid={`deal-ticket-fee-margin-required`}
|
||||
key={'value-dropdown'}
|
||||
className="flex items-center justify-between w-full gap-2"
|
||||
>
|
||||
<div className="flex items-center text-left gap-1">
|
||||
<Tooltip
|
||||
description={t(
|
||||
'MARGIN_DIFF_TOOLTIP_TEXT',
|
||||
MARGIN_DIFF_TOOLTIP_TEXT,
|
||||
{ assetSymbol }
|
||||
)}
|
||||
>
|
||||
<span className="text-muted">{t('Margin required')}</span>
|
||||
</Tooltip>
|
||||
|
||||
<AccordionChevron size={10} />
|
||||
</div>
|
||||
<Tooltip
|
||||
description={
|
||||
formatRange(
|
||||
marginRequiredBestCase,
|
||||
marginRequiredWorstCase,
|
||||
assetDecimals
|
||||
) ?? '-'
|
||||
}
|
||||
>
|
||||
<div className="font-mono text-right">
|
||||
{formatValue(
|
||||
marginRequiredWorstCase,
|
||||
assetDecimals,
|
||||
quantum
|
||||
)}{' '}
|
||||
{assetSymbol || ''}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</AccordionPrimitive.Trigger>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-col w-full gap-2">
|
||||
<KeyValue
|
||||
label={t('Total margin available')}
|
||||
indent
|
||||
value={formatValue(totalMarginAvailable, assetDecimals)}
|
||||
formattedValue={formatValue(
|
||||
totalMarginAvailable,
|
||||
assetDecimals,
|
||||
quantum
|
||||
)}
|
||||
symbol={assetSymbol}
|
||||
labelDescription={t(
|
||||
'TOTAL_MARGIN_AVAILABLE',
|
||||
TOTAL_MARGIN_AVAILABLE,
|
||||
{
|
||||
generalAccountBalance: formatValue(
|
||||
generalAccountBalance,
|
||||
assetDecimals,
|
||||
quantum
|
||||
)}
|
||||
symbol={assetSymbol}
|
||||
labelDescription={t(
|
||||
'TOTAL_MARGIN_AVAILABLE',
|
||||
TOTAL_MARGIN_AVAILABLE,
|
||||
{
|
||||
generalAccountBalance: formatValue(
|
||||
generalAccountBalance,
|
||||
assetDecimals,
|
||||
quantum
|
||||
),
|
||||
marginAccountBalance: formatValue(
|
||||
marginAccountBalance,
|
||||
assetDecimals,
|
||||
quantum
|
||||
),
|
||||
marginMaintenance: formatValue(
|
||||
currentMargins?.maintenanceLevel,
|
||||
assetDecimals,
|
||||
quantum
|
||||
),
|
||||
assetSymbol,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
{deductionFromCollateral}
|
||||
<KeyValue
|
||||
label={t('Current margin allocation')}
|
||||
indent
|
||||
onClick={
|
||||
generalAccountBalance
|
||||
? () => setBreakdownDialog(true)
|
||||
: undefined
|
||||
}
|
||||
value={formatValue(marginAccountBalance, assetDecimals)}
|
||||
symbol={assetSymbol}
|
||||
labelDescription={t(
|
||||
'MARGIN_ACCOUNT_TOOLTIP_TEXT',
|
||||
MARGIN_ACCOUNT_TOOLTIP_TEXT
|
||||
)}
|
||||
formattedValue={formatValue(
|
||||
),
|
||||
marginAccountBalance: formatValue(
|
||||
marginAccountBalance,
|
||||
assetDecimals,
|
||||
quantum
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</AccordionPanel>
|
||||
</Accordion>
|
||||
{projectedMargin}
|
||||
</>
|
||||
)}
|
||||
),
|
||||
marginMaintenance: formatValue(
|
||||
currentMargins?.maintenanceLevel,
|
||||
assetDecimals,
|
||||
quantum
|
||||
),
|
||||
assetSymbol,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
{deductionFromCollateral}
|
||||
<KeyValue
|
||||
label={t('Current margin allocation')}
|
||||
indent
|
||||
onClick={
|
||||
generalAccountBalance
|
||||
? () => setBreakdownDialog(true)
|
||||
: undefined
|
||||
}
|
||||
value={formatValue(marginAccountBalance, assetDecimals)}
|
||||
symbol={assetSymbol}
|
||||
labelDescription={t(
|
||||
'MARGIN_ACCOUNT_TOOLTIP_TEXT',
|
||||
MARGIN_ACCOUNT_TOOLTIP_TEXT
|
||||
)}
|
||||
formattedValue={formatValue(
|
||||
marginAccountBalance,
|
||||
assetDecimals,
|
||||
quantum
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</AccordionPanel>
|
||||
</Accordion>
|
||||
{projectedMargin}
|
||||
<KeyValue
|
||||
label={t('Liquidation')}
|
||||
value={liquidationPriceEstimateRange}
|
||||
|
||||
@@ -101,7 +101,7 @@ describe('StopOrder', () => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should display ticket defaults', async () => {
|
||||
it('should display ticket defaults limit order', async () => {
|
||||
render(generateJsx());
|
||||
// place order button should always be enabled
|
||||
expect(screen.getByTestId(submitButton)).toBeEnabled();
|
||||
@@ -131,6 +131,47 @@ describe('StopOrder', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should display ticket defaults market order', async () => {
|
||||
render(generateJsx());
|
||||
// place order button should always be enabled
|
||||
expect(screen.getByTestId(submitButton)).toBeEnabled();
|
||||
// Assert defaults are used
|
||||
await userEvent.click(screen.getByTestId(orderTypeTrigger));
|
||||
await userEvent.click(screen.getByTestId(orderTypeMarket));
|
||||
await userEvent.click(screen.getByTestId(orderTypeTrigger));
|
||||
expect(screen.getByTestId(orderTypeLimit).dataset.state).toEqual(
|
||||
'unchecked'
|
||||
);
|
||||
expect(screen.getByTestId(orderTypeMarket).dataset.state).toEqual(
|
||||
'checked'
|
||||
);
|
||||
await userEvent.click(screen.getByTestId(orderTypeMarket));
|
||||
expect(screen.getByTestId(orderSideBuy).dataset.state).toEqual('checked');
|
||||
expect(screen.getByTestId(sizeInput)).toHaveDisplayValue('0');
|
||||
expect(screen.getByTestId(timeInForce)).toHaveValue(
|
||||
Schema.OrderTimeInForce.TIME_IN_FORCE_FOK
|
||||
);
|
||||
// 7002-SORD-084
|
||||
expect(
|
||||
screen.getByTestId(triggerDirectionRisesAbove).dataset.state
|
||||
).toEqual('checked');
|
||||
// 7002-SORD-085
|
||||
expect(
|
||||
screen.getByTestId(triggerDirectionFallsBelow).dataset.state
|
||||
).toEqual('unchecked');
|
||||
expect(screen.getByTestId(triggerTypePrice).dataset.state).toEqual(
|
||||
'checked'
|
||||
);
|
||||
expect(screen.getByTestId(expire).dataset.state).toEqual('unchecked');
|
||||
expect(screen.getByTestId(oco).dataset.state).toEqual('unchecked');
|
||||
await userEvent.click(screen.getByTestId(expire));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId(expiryStrategySubmit).dataset.state).toEqual(
|
||||
'checked'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('calculate notional for market limit', async () => {
|
||||
render(generateJsx());
|
||||
await userEvent.type(screen.getByTestId(sizeInput), '10');
|
||||
@@ -239,33 +280,43 @@ describe('StopOrder', () => {
|
||||
it.each([
|
||||
{ fieldName: 'size', ocoValue: false },
|
||||
{ fieldName: 'ocoSize', ocoValue: true },
|
||||
])('validates $fieldName field', async ({ ocoValue }) => {
|
||||
render(generateJsx());
|
||||
if (ocoValue) {
|
||||
await userEvent.click(screen.getByTestId(oco));
|
||||
}
|
||||
await userEvent.click(screen.getByTestId(submitButton));
|
||||
const getByTestId = (id: string) =>
|
||||
screen.getByTestId(ocoPostfix(id, ocoValue));
|
||||
const queryByTestId = (id: string) =>
|
||||
screen.queryByTestId(ocoPostfix(id, ocoValue));
|
||||
// default value should be invalid
|
||||
expect(getByTestId(sizeErrorMessage)).toBeInTheDocument();
|
||||
// to small value should be invalid
|
||||
await userEvent.type(getByTestId(sizeInput), '0.01');
|
||||
expect(getByTestId(sizeErrorMessage)).toBeInTheDocument();
|
||||
{ fieldName: 'size', ocoValue: false, orderTypeMarketValue: true },
|
||||
{ fieldName: 'ocoSize', ocoValue: true, orderTypeMarketValue: true },
|
||||
])(
|
||||
'validates $fieldName field',
|
||||
async ({ ocoValue, orderTypeMarketValue }) => {
|
||||
render(generateJsx());
|
||||
if (orderTypeMarketValue) {
|
||||
await userEvent.click(screen.getByTestId(orderTypeTrigger));
|
||||
await userEvent.click(screen.getByTestId(orderTypeMarket));
|
||||
}
|
||||
if (ocoValue) {
|
||||
await userEvent.click(screen.getByTestId(oco));
|
||||
}
|
||||
await userEvent.click(screen.getByTestId(submitButton));
|
||||
const getByTestId = (id: string) =>
|
||||
screen.getByTestId(ocoPostfix(id, ocoValue));
|
||||
const queryByTestId = (id: string) =>
|
||||
screen.queryByTestId(ocoPostfix(id, ocoValue));
|
||||
// default value should be invalid
|
||||
expect(getByTestId(sizeErrorMessage)).toBeInTheDocument();
|
||||
// to small value should be invalid
|
||||
await userEvent.type(getByTestId(sizeInput), '0.01');
|
||||
expect(getByTestId(sizeErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// clear and fill using valid value
|
||||
await userEvent.clear(getByTestId(sizeInput));
|
||||
await userEvent.type(getByTestId(sizeInput), '0.1');
|
||||
expect(queryByTestId(sizeErrorMessage)).toBeNull();
|
||||
});
|
||||
// clear and fill using valid value
|
||||
await userEvent.clear(getByTestId(sizeInput));
|
||||
await userEvent.type(getByTestId(sizeInput), '0.1');
|
||||
expect(queryByTestId(sizeErrorMessage)).toBeNull();
|
||||
}
|
||||
);
|
||||
|
||||
it.each([
|
||||
{ fieldName: 'price', ocoValue: false },
|
||||
{ fieldName: 'ocoPrice', ocoValue: true },
|
||||
])('validates $fieldName field', async ({ ocoValue }) => {
|
||||
render(generateJsx());
|
||||
|
||||
if (ocoValue) {
|
||||
await userEvent.click(screen.getByTestId(oco));
|
||||
}
|
||||
@@ -275,7 +326,7 @@ describe('StopOrder', () => {
|
||||
screen.getByTestId(ocoPostfix(id, ocoValue));
|
||||
const queryByTestId = (id: string) =>
|
||||
screen.queryByTestId(ocoPostfix(id, ocoValue));
|
||||
|
||||
// 7002-SORD-095
|
||||
expect(getByTestId(priceErrorMessage)).toBeInTheDocument();
|
||||
await userEvent.type(getByTestId(priceInput), '0.001');
|
||||
expect(getByTestId(priceErrorMessage)).toBeInTheDocument();
|
||||
@@ -305,48 +356,77 @@ describe('StopOrder', () => {
|
||||
it.each([
|
||||
{ fieldName: 'triggerPrice', ocoValue: false },
|
||||
{ fieldName: 'ocoTriggerPrice', ocoValue: true },
|
||||
])('validates $fieldName field', async ({ ocoValue }) => {
|
||||
render(generateJsx());
|
||||
{ fieldName: 'triggerPrice', ocoValue: false, orderTypeMarketValue: true },
|
||||
{
|
||||
fieldName: 'ocoTriggerPrice',
|
||||
ocoValue: true,
|
||||
orderTypeMarketValue: true,
|
||||
},
|
||||
])(
|
||||
'validates $fieldName field',
|
||||
async ({ ocoValue, orderTypeMarketValue }) => {
|
||||
render(generateJsx());
|
||||
if (orderTypeMarketValue) {
|
||||
await userEvent.click(screen.getByTestId(orderTypeTrigger));
|
||||
await userEvent.click(screen.getByTestId(orderTypeMarket));
|
||||
}
|
||||
if (ocoValue) {
|
||||
await userEvent.click(screen.getByTestId(oco));
|
||||
await userEvent.click(screen.getByTestId(triggerDirectionFallsBelow));
|
||||
}
|
||||
await userEvent.click(screen.getByTestId(submitButton));
|
||||
const getByTestId = (id: string) =>
|
||||
screen.getByTestId(ocoPostfix(id, ocoValue));
|
||||
const queryByTestId = (id: string) =>
|
||||
screen.queryByTestId(ocoPostfix(id, ocoValue));
|
||||
// 7002-SORD-095
|
||||
// 7002-SORD-087
|
||||
|
||||
if (ocoValue) {
|
||||
await userEvent.click(screen.getByTestId(oco));
|
||||
await userEvent.click(screen.getByTestId(triggerDirectionFallsBelow));
|
||||
expect(getByTestId(triggerPriceErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// switch to trailing percentage offset trigger type
|
||||
await userEvent.click(getByTestId(triggerTypeTrailingPercentOffset));
|
||||
expect(queryByTestId(triggerPriceErrorMessage)).toBeNull();
|
||||
|
||||
// switch back to price trigger type
|
||||
await userEvent.click(getByTestId(triggerTypePrice));
|
||||
expect(getByTestId(triggerPriceErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// to small value should be invalid
|
||||
await userEvent.type(getByTestId(triggerPriceInput), '0.001');
|
||||
expect(getByTestId(triggerPriceErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// clear and fill using value causing immediate trigger
|
||||
await userEvent.clear(getByTestId(triggerPriceInput));
|
||||
await userEvent.type(getByTestId(triggerPriceInput), '0.01');
|
||||
expect(queryByTestId(triggerPriceErrorMessage)).toBeNull();
|
||||
expect(queryByTestId(triggerPriceWarningMessage)).toBeInTheDocument();
|
||||
|
||||
// change to correct value
|
||||
await userEvent.type(getByTestId(triggerPriceInput), '2');
|
||||
expect(queryByTestId(triggerPriceWarningMessage)).toBeNull();
|
||||
}
|
||||
await userEvent.click(screen.getByTestId(submitButton));
|
||||
const getByTestId = (id: string) =>
|
||||
screen.getByTestId(ocoPostfix(id, ocoValue));
|
||||
const queryByTestId = (id: string) =>
|
||||
screen.queryByTestId(ocoPostfix(id, ocoValue));
|
||||
expect(getByTestId(triggerPriceErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// switch to trailing percentage offset trigger type
|
||||
await userEvent.click(getByTestId(triggerTypeTrailingPercentOffset));
|
||||
expect(queryByTestId(triggerPriceErrorMessage)).toBeNull();
|
||||
|
||||
// switch back to price trigger type
|
||||
await userEvent.click(getByTestId(triggerTypePrice));
|
||||
expect(getByTestId(triggerPriceErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// to small value should be invalid
|
||||
await userEvent.type(getByTestId(triggerPriceInput), '0.001');
|
||||
expect(getByTestId(triggerPriceErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// clear and fill using value causing immediate trigger
|
||||
await userEvent.clear(getByTestId(triggerPriceInput));
|
||||
await userEvent.type(getByTestId(triggerPriceInput), '0.01');
|
||||
expect(queryByTestId(triggerPriceErrorMessage)).toBeNull();
|
||||
expect(queryByTestId(triggerPriceWarningMessage)).toBeInTheDocument();
|
||||
|
||||
// change to correct value
|
||||
await userEvent.type(getByTestId(triggerPriceInput), '2');
|
||||
expect(queryByTestId(triggerPriceWarningMessage)).toBeNull();
|
||||
});
|
||||
);
|
||||
|
||||
it.each([
|
||||
{ fieldName: 'trailingPercentageOffset', ocoValue: false },
|
||||
{ fieldName: 'ocoTrailingPercentageOffset', ocoValue: true },
|
||||
{
|
||||
fieldName: 'trailingPercentageOffset',
|
||||
ocoValue: false,
|
||||
orderTypeMarket: true,
|
||||
},
|
||||
{
|
||||
fieldName: 'ocoTrailingPercentageOffset',
|
||||
ocoValue: true,
|
||||
orderTypeMarket: true,
|
||||
},
|
||||
])('validates $fieldName field', async ({ ocoValue }) => {
|
||||
render(generateJsx());
|
||||
if (orderTypeMarket) {
|
||||
await userEvent.click(screen.getByTestId(orderTypeTrigger));
|
||||
await userEvent.click(screen.getByTestId(orderTypeMarket));
|
||||
}
|
||||
if (ocoValue) {
|
||||
await userEvent.click(screen.getByTestId(oco));
|
||||
}
|
||||
@@ -401,9 +481,11 @@ describe('StopOrder', () => {
|
||||
it('sync oco trigger', async () => {
|
||||
render(generateJsx());
|
||||
await userEvent.click(screen.getByTestId(oco));
|
||||
// 7002-SORD-099
|
||||
expect(
|
||||
screen.getByTestId(triggerDirectionRisesAbove).dataset.state
|
||||
).toEqual('checked');
|
||||
// 7002-SORD-091
|
||||
expect(
|
||||
screen.getByTestId(ocoPostfix(triggerDirectionFallsBelow)).dataset.state
|
||||
).toEqual('checked');
|
||||
@@ -481,6 +563,7 @@ describe('StopOrder', () => {
|
||||
expect(mockDataProvider.mock.lastCall?.[0].skip).toBe(true);
|
||||
await userEvent.type(screen.getByTestId(sizeInput), '0.01');
|
||||
expect(mockDataProvider.mock.lastCall?.[0].skip).toBe(false);
|
||||
// 7002-SORD-011
|
||||
expect(screen.getByTestId(numberOfActiveOrdersLimit)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
||||
@@ -367,6 +367,29 @@ describe('DealTicket', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should see an explanation of peak size', async () => {
|
||||
render(generateJsx());
|
||||
await userEvent.click(screen.getByTestId('iceberg'));
|
||||
await userEvent.hover(screen.getByText('Peak size'));
|
||||
await waitFor(() => {
|
||||
const tooltips = screen.getAllByTestId('tooltip-content');
|
||||
expect(tooltips[0]).toHaveTextContent(
|
||||
`The maximum volume that can be traded at once. Must be less than the total size of the order.`
|
||||
);
|
||||
});
|
||||
});
|
||||
it('should see an explanation of minimum size', async () => {
|
||||
render(generateJsx());
|
||||
await userEvent.click(screen.getByTestId('iceberg'));
|
||||
await userEvent.hover(screen.getByText('Minimum size'));
|
||||
await waitFor(() => {
|
||||
const tooltips = screen.getAllByTestId('tooltip-content');
|
||||
expect(tooltips[0]).toHaveTextContent(
|
||||
`When the order trades and its size falls below this threshold, it will be reset to the peak size and moved to the back of the priority order. Must be less than or equal to peak size, and greater than 0.`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should see an explanation of reduce only', async () => {
|
||||
render(generateJsx());
|
||||
userEvent.hover(screen.getByText('Reduce only'));
|
||||
|
||||
@@ -85,6 +85,7 @@ export const DocsLinks = VEGA_DOCS_URL
|
||||
ICEBERG_ORDERS: `${VEGA_DOCS_URL}/concepts/trading-on-vega/orders#iceberg-order`,
|
||||
POST_REDUCE_ONLY: `${VEGA_DOCS_URL}/concepts/trading-on-vega/orders#conditional-order-parameters`,
|
||||
QUANTUM: `${VEGA_DOCS_URL}/concepts/assets/asset-framework#quantum`,
|
||||
REFERRALS: `${VEGA_DOCS_URL}/tutorials/proposals/referral-program-proposal`,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import en_proposals from './locales/en/proposals.json';
|
||||
import en_positions from './locales/en/positions.json';
|
||||
import en_trades from './locales/en/trading.json';
|
||||
import en_ui_toolkit from './locales/en/ui-toolkit.json';
|
||||
import en_wallet from './locales/en/wallet.json';
|
||||
|
||||
export const locales = {
|
||||
en: {
|
||||
@@ -37,5 +38,6 @@ export const locales = {
|
||||
proposals: en_proposals,
|
||||
trades: en_trades,
|
||||
'ui-toolkit': en_ui_toolkit,
|
||||
wallet: en_wallet,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -139,5 +139,5 @@
|
||||
"View settlement data specification": "View settlement data specification",
|
||||
"View settlement schedule specification": "View settlement schedule specification",
|
||||
"View termination specification": "View termination specification",
|
||||
"Within %s seconds": "Within %s seconds"
|
||||
"Within {{horizonSecs}} seconds": "Within {{horizonSecs}} seconds"
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"(Combined set volume {{runningVolume}} over last {{epochs}} epochs)": "(Combined set volume {{runningVolume}} over last {{epochs}} epochs)",
|
||||
"(Created at: {{createdAt}})": "(Created at: {{createdAt}})",
|
||||
"{{amount}} $VEGA staked": "{{amount}} $VEGA staked",
|
||||
"{{assetSymbol}} Reward pot": "{{assetSymbol}} Reward pot",
|
||||
"{{checkedAssets}} Assets": "{{checkedAssets}} Assets",
|
||||
"{{distance}} ago": "{{distance}} ago",
|
||||
"{{instrumentCode}} liquidity provision": "{{instrumentCode}} liquidity provision",
|
||||
@@ -17,7 +18,9 @@
|
||||
"Anyone with the referral link can apply it to their key(s) of choice via an on chain transaction": "Anyone with the referral link can apply it to their key(s) of choice via an on chain transaction",
|
||||
"Asset (1)": "Asset (1)",
|
||||
"Assets": "Assets",
|
||||
"Available to withdraw this epoch": "Available to withdraw this epoch",
|
||||
"Base commission rate": "Base commission rate",
|
||||
"Base rate": "Base rate",
|
||||
"Best bid": "Best bid",
|
||||
"Best offer": "Best offer",
|
||||
"Browse": "Browse",
|
||||
@@ -71,6 +74,7 @@
|
||||
"Discounts are applied automatically during trading based on the key(s) used": "Discounts are applied automatically during trading based on the key(s) used",
|
||||
"Docs": "Docs",
|
||||
"Earn commission & stake rewards": "Earn commission & stake rewards",
|
||||
"Earned by me": "Earned by me",
|
||||
"Enactment date reached and usual auction exit checks pass": "Enactment date reached and usual auction exit checks pass",
|
||||
"Environment not configured": "Environment not configured",
|
||||
"epochs in referral set": "epochs in referral set",
|
||||
@@ -96,6 +100,7 @@
|
||||
"Funding Rate": "Funding Rate",
|
||||
"Funding rate": "Funding rate",
|
||||
"Futures": "Futures",
|
||||
"From epoch": "From epoch",
|
||||
"Generate a referral code to share with your friends and start earning commission.": "Generate a referral code to share with your friends and start earning commission.",
|
||||
"Generate code": "Generate code",
|
||||
"Get started": "Get started",
|
||||
@@ -109,6 +114,7 @@
|
||||
"Help identify bugs and improve the service by sharing anonymous usage data.": "Help identify bugs and improve the service by sharing anonymous usage data.",
|
||||
"Help us identify bugs and improve Vega Governance by sharing anonymous usage data.": "Help us identify bugs and improve Vega Governance by sharing anonymous usage data.",
|
||||
"Hide closed markets": "Hide closed markets",
|
||||
"Hoarder reward multiplier": "Hoarder reward multiplier",
|
||||
"How it works": "How it works",
|
||||
"I want a code": "I want a code",
|
||||
"Improve vega console": "Improve vega console",
|
||||
@@ -122,6 +128,7 @@
|
||||
"Liquidity": "Liquidity",
|
||||
"Liquidity fees": "Liquidity fees",
|
||||
"Liquidity supplied": "Liquidity supplied",
|
||||
"Locked {{assetSymbol}}": "Locked {{assetSymbol}}",
|
||||
"Low fees and no cost to place orders": "Low fees and no cost to place orders",
|
||||
"Mainnet status & incidents": "Mainnet status & incidents",
|
||||
"Make withdrawal": "Make withdrawal",
|
||||
@@ -157,6 +164,7 @@
|
||||
"No perpetual markets.": "No perpetual markets.",
|
||||
"No referral program active": "No referral program active",
|
||||
"No rejected orders": "No rejected orders",
|
||||
"No rewards": "No rewards",
|
||||
"No thanks": "No thanks",
|
||||
"No third party has access to your funds.": "No third party has access to your funds.",
|
||||
"No volume discount program active": "No volume discount program active",
|
||||
@@ -165,6 +173,7 @@
|
||||
"Non-custodial and pseudonymous": "Non-custodial and pseudonymous",
|
||||
"None": "None",
|
||||
"Number of traders": "Number of traders",
|
||||
"Not connected": "Not connected",
|
||||
"Open": "Open",
|
||||
"Open a position": "Open a position",
|
||||
"Open markets": "Open markets",
|
||||
@@ -176,7 +185,7 @@
|
||||
"Parent of a market": "Parent of a market",
|
||||
"Past {{count}} epochs": "Past {{count}} epochs",
|
||||
"Perpetuals": "Perpetuals",
|
||||
"Please choose another market from the <0>market list<0>": "Please choose another market from the <0>market list<0>",
|
||||
"Please choose another market from the <0>market list</0>": "Please choose another market from the <0>market list</0>",
|
||||
"Please connect Vega wallet": "Please connect Vega wallet",
|
||||
"Portfolio": "Portfolio",
|
||||
"Positions": "Positions",
|
||||
@@ -193,6 +202,7 @@
|
||||
"Read the terms": "Read the terms",
|
||||
"Ready to trade": "Ready to trade",
|
||||
"Ready to trade with real funds? <0>Switch to Mainnet</0>": "Ready to trade with real funds? <0>Switch to Mainnet</0>",
|
||||
"Redeem rewards": "Redeem rewards",
|
||||
"Referral benefits": "Referral benefits",
|
||||
"Referral discount": "Referral discount",
|
||||
"referral-statistics-commission": "Commission earned in <0>qUSD</0> (last {{count}} epochs)",
|
||||
@@ -205,6 +215,9 @@
|
||||
"Required epochs": "Required epochs",
|
||||
"Required for next tier": "Required for next tier",
|
||||
"Resources": "Resources",
|
||||
"Rewards": "Rewards",
|
||||
"Rewards history": "Rewards history",
|
||||
"Rewards multipliers": "Rewards multipliers",
|
||||
"SCCR": "SCCR",
|
||||
"Search": "Search",
|
||||
"See all markets": "See all markets",
|
||||
@@ -229,10 +242,12 @@
|
||||
"Status": "Status",
|
||||
"Stop": "Stop",
|
||||
"Stop orders": "Stop orders",
|
||||
"Streak reward multiplier": "Streak reward multiplier",
|
||||
"Successor of a market": "Successor of a market",
|
||||
"Successors to this market have been proposed": "Successors to this market have been proposed",
|
||||
"Supplied stake": "Supplied stake",
|
||||
"Suspended due to price or liquidity monitoring trigger": "Suspended due to price or liquidity monitoring trigger",
|
||||
"to": "to",
|
||||
"Target stake": "Target stake",
|
||||
"The amount of fees paid to liquidity providers across the whole market during the last epoch {{epoch}}.": "The amount of fees paid to liquidity providers across the whole market during the last epoch {{epoch}}.",
|
||||
"The commission is taken from the infrastructure fee, maker fee, and liquidity provider fee, not from the referee": "The commission is taken from the infrastructure fee, maker fee, and liquidity provider fee, not from the referee",
|
||||
@@ -254,6 +269,7 @@
|
||||
"Toast location": "Toast location",
|
||||
"Total commission (last {{count}}} epochs)": "Total commission (last {{count}}} epochs)",
|
||||
"Total discount": "Total discount",
|
||||
"Total distributed": "Total distributed",
|
||||
"Total fee after discount": "Total fee after discount",
|
||||
"Total fee before discount": "Total fee before discount",
|
||||
"Trader": "Trader",
|
||||
@@ -267,6 +283,10 @@
|
||||
"Transfer": "Transfer",
|
||||
"Unknown": "Unknown",
|
||||
"Unknown settlement date": "Unknown settlement date",
|
||||
"Vega Reward pot": "Vega Reward pot",
|
||||
"Vesting": "Vesting",
|
||||
"Vesting {{assetSymbol}}": "Vesting {{assetSymbol}}",
|
||||
"Vesting multiplier": "Vesting multiplier",
|
||||
"View as party": "View as party",
|
||||
"View liquidity provision table": "View liquidity provision table",
|
||||
"View on Explorer": "View on Explorer",
|
||||
@@ -284,6 +304,7 @@
|
||||
"We're sorry but we don't have an active referral programme currently running. You can propose a new programme <0>here</0>.": "We're sorry but we don't have an active referral programme currently running. You can propose a new programme <0>here</0>.",
|
||||
"Welcome to Vega trading!": "Welcome to Vega trading!",
|
||||
"Withdraw": "Withdraw",
|
||||
"You are joining the group shown, but will not have access to benefits until you have completed at least {{count}} epochs.": "You are joining the group shown, but will not have access to benefits until you have completed at least {{count}} epochs.",
|
||||
"You can opt out any time via settings": "You can opt out any time via settings",
|
||||
"You may encounter bugs, loss of functionality or loss of assets.": "You may encounter bugs, loss of functionality or loss of assets.",
|
||||
"You must be connected to the Vega wallet.": "You must be connected to the Vega wallet.",
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"About the Vega wallet": "About the Vega wallet",
|
||||
"Supported browsers": "Supported browsers",
|
||||
"Connect Vega wallet": "Connect Vega wallet",
|
||||
"Get a Vega wallet": "Get a Vega wallet",
|
||||
"Connect securely, deposit funds and approve or reject transactions with the Vega wallet": "Connect securely, deposit funds and approve or reject transactions with the Vega wallet",
|
||||
"Connect": "Connect",
|
||||
"Vega Wallet <0>full featured<0>": "Vega Wallet <0>full featured<0>",
|
||||
"your browser": "your browser",
|
||||
"Connect with Vega Wallet extension for {{browserName}} to access all features including key management and detailed transaction views from your browser.": "Connect with Vega Wallet extension for {{browserName}} to access all features including key management and detailed transaction views from your browser.",
|
||||
"Install Vega Wallet extension for {{browserName}} to access all features including key management and detailed transaction views from your browser.": "Install Vega Wallet extension for {{browserName}} to access all features including key management and detailed transaction views from your browser.",
|
||||
"Metamask Snap <0>quick start</0>": "Metamask Snap <0>quick start</0>",
|
||||
"Connect directly via Metamask with the Vega Snap for single key support without advanced features.": "Connect directly via Metamask with the Vega Snap for single key support without advanced features.",
|
||||
"Connect via Vega MetaMask Snap": "Connect via Vega MetaMask Snap",
|
||||
"Install Metamask with the Vega Snap for single key support without advanced features.": "Install Metamask with the Vega Snap for single key support without advanced features.",
|
||||
"Install Vega MetaMask Snap": "Install Vega MetaMask Snap",
|
||||
"No MetaMask version that supports snaps detected. Learn more about <0>MetaMask Snaps</0>": "No MetaMask version that supports snaps detected. Learn more about <0>MetaMask Snaps</0>",
|
||||
"Advanced / Other options...": "Advanced / Other options...",
|
||||
"View as party": "View as party",
|
||||
"Get the Vega Wallet": "Get the Vega Wallet",
|
||||
"Custom wallet location": "Custom wallet location",
|
||||
"Go back": "Go back",
|
||||
"Connect the App/CLI": "Connect the App/CLI",
|
||||
"Use the Desktop App/CLI": "Use the Desktop App/CLI",
|
||||
"Enter a custom wallet location": "Enter a custom wallet location",
|
||||
"<0>No running Desktop App/CLI detected. Open your app now to connect or enter a</0> <1>custom wallet location</1>": "<0>No running Desktop App/CLI detected. Open your app now to connect or enter a</0> <1>custom wallet location</1>",
|
||||
"Verifying chain": "Verifying chain",
|
||||
"Successfully connected": "Successfully connected",
|
||||
"Connecting...": "Connecting...",
|
||||
"Approve the connection from your Vega wallet app. If you have multiple wallets you'll need to choose which to connect with.": "Approve the connection from your Vega wallet app. If you have multiple wallets you'll need to choose which to connect with.",
|
||||
"Understand the risk": "Understand the risk",
|
||||
"Cancel": "Cancel",
|
||||
"I agree": "I agree",
|
||||
"Something went wrong": "Something went wrong",
|
||||
"An unknown error occurred": "An unknown error occurred",
|
||||
"Try again": "Try again",
|
||||
"User rejected": "User rejected",
|
||||
"The user rejected the wallet connection": "The user rejected the wallet connection",
|
||||
"Wrong network": "Wrong network",
|
||||
"No wallet detected": "No wallet detected",
|
||||
"Vega browser extension not installed": "Vega browser extension not installed",
|
||||
"Snap failed": "Snap failed",
|
||||
"Could not connect to Vega MetaMask Snap": "Could not connect to Vega MetaMask Snap",
|
||||
"No wallet application running at {{connectorUrl}}": "No wallet application running at {{connectorUrl}}",
|
||||
"No Vega Wallet application running": "No Vega Wallet application running",
|
||||
"Read the docs to troubleshoot": "Read the docs to troubleshoot",
|
||||
"Connection in progress": "Connection in progress",
|
||||
"Approve the connection from your Vega wallet app.": "Approve the connection from your Vega wallet app.",
|
||||
"To complete your wallet connection, set your wallet network in your app to \"{{appChainId}}\".": "To complete your wallet connection, set your wallet network in your app to \"{{appChainId}}\".",
|
||||
"SELECT A VEGA KEY": "SELECT A VEGA KEY",
|
||||
"Select": "Select",
|
||||
"Copy": "Copy",
|
||||
"Disconnect all keys": "Disconnect all keys",
|
||||
"Pubkey must be 64 characters in length": "Pubkey must be 64 characters in length",
|
||||
"Pubkey must be be valid hex": "Pubkey must be be valid hex",
|
||||
"VIEW AS VEGA USER": "VIEW AS VEGA USER",
|
||||
"Browse from the perspective of another Vega user in read-only mode.": "Browse from the perspective of another Vega user in read-only mode.",
|
||||
"Required": "Required",
|
||||
"Browse network": "Browse network",
|
||||
"Checking wallet version": "Checking wallet version",
|
||||
"Checking your wallet is compatible with this app": "Checking your wallet is compatible with this app",
|
||||
"Wrong Network": "Wrong Network"
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"All {{symbol}} withdrawals are subject to a {{delay}} delay.": "All {{symbol}} withdrawals are subject to a {{delay}} delay.",
|
||||
"Amount": "Amount",
|
||||
"Asset": "Asset",
|
||||
"Available to withdraw in {{availableTimestamp}}": "Available to withdraw in {{availableTimestamp}}",
|
||||
"Balance available": "Balance available",
|
||||
"Complete the withdrawal to release your funds": "Complete the withdrawal to release your funds",
|
||||
"Complete these {{count}} withdrawals to release your funds": "Complete these {{count}} withdrawals to release your funds",
|
||||
"Complete withdrawal": "Complete withdrawal",
|
||||
"Completed": "Completed",
|
||||
"Connect Ethereum wallet to complete": "Connect Ethereum wallet to complete",
|
||||
"Connect": "Connect",
|
||||
"Created": "Created",
|
||||
"Delay time": "Delay time",
|
||||
"Delayed (ready in {{readyIn}})": "Delayed (ready in {{readyIn}})",
|
||||
"Delayed withdrawal threshold": "Delayed withdrawal threshold",
|
||||
"Disconnect": "Disconnect",
|
||||
"Failed": "Failed",
|
||||
"Insufficient amount in account": "Insufficient amount in account",
|
||||
"Invalid asset source: {{source}}": "Invalid asset source: {{source}}",
|
||||
"No withdrawals": "No withdrawals",
|
||||
"None": "None",
|
||||
"Pending": "Pending",
|
||||
"Please select an asset": "Please select an asset",
|
||||
"Read more": "Read more",
|
||||
"Ready to complete": "Ready to complete",
|
||||
"Recipient": "Recipient",
|
||||
"Rejected": "Rejected",
|
||||
"Release funds": "Release funds",
|
||||
"Status": "Status",
|
||||
"Step 1 - Release funds from Vega": "Step 1 - Release funds from Vega",
|
||||
"Step 2 - Transfer funds to your Ethereum wallet": "Step 2 - Transfer funds to your Ethereum wallet",
|
||||
"There are two steps required to make a withdrawal": "There are two steps required to make a withdrawal",
|
||||
"This app only works on {{chainName}}. Please change chain.": "This app only works on {{chainName}}. Please change chain.",
|
||||
"To (Ethereum address)": "To (Ethereum address)",
|
||||
"Transaction": "Transaction",
|
||||
"Use maximum": "Use maximum",
|
||||
"Verifying withdrawal approval": "Verifying withdrawal approval",
|
||||
"View withdrawal details": "View withdrawal details",
|
||||
"View withdrawals": "View withdrawals",
|
||||
"Withdraw {{amount}} {{symbol}}": "Withdraw {{amount}} {{symbol}}",
|
||||
"Withdraw funds": "Withdraw funds",
|
||||
"Withdraw": "Withdraw",
|
||||
"Withdrawal ready": "Withdrawal ready",
|
||||
"Withdrawals of {{threshold}} {{symbol}} or more will be delayed for {{delay}}.": "Withdrawals of {{threshold}} {{symbol}} or more will be delayed for {{delay}}.",
|
||||
"Withdrawals ready": "Withdrawals ready",
|
||||
"You have no assets to withdraw": "You have no assets to withdraw",
|
||||
"Your funds have been unlocked for withdrawal - <0>View in block explorer<0>": "Your funds have been unlocked for withdrawal - <0>View in block explorer<0>"
|
||||
}
|
||||
@@ -1,24 +1,60 @@
|
||||
import LiquidityTable from './liquidity-table';
|
||||
import { act, render, screen } from '@testing-library/react';
|
||||
import { act, render, screen, within } from '@testing-library/react';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { LiquidityProvisionData } from './liquidity-data-provider';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
const singleRow = {
|
||||
party: 'a3f762f0a6e998e1d0c6e73017a13ec8a22386c30f7f64a1bdca47330bc592dd',
|
||||
const partyId1 = 'party1';
|
||||
const partyId2 = 'party2';
|
||||
|
||||
const singleRow: LiquidityProvisionData = {
|
||||
id: 'lp-single',
|
||||
commitmentMinTimeFraction: '100',
|
||||
performanceHysteresisEpochs: 4,
|
||||
priceRange: '1',
|
||||
slaCompetitionFactor: '1',
|
||||
partyId: partyId1,
|
||||
party: {
|
||||
id: partyId1,
|
||||
},
|
||||
createdAt: '2022-08-19T17:18:36.257028Z',
|
||||
updatedAt: '2022-08-19T17:18:36.257028Z',
|
||||
commitmentAmount: '56298653179',
|
||||
commitmentAmount: '100',
|
||||
fee: '0.001',
|
||||
status: Schema.LiquidityProvisionStatus.STATUS_ACTIVE,
|
||||
feeShare: {
|
||||
equityLikeShare: '0.5',
|
||||
averageEntryValuation: '0.5',
|
||||
virtualStake: '0.5',
|
||||
averageScore: '0.5',
|
||||
},
|
||||
supplied: '67895',
|
||||
obligation: '56785',
|
||||
} as unknown as LiquidityProvisionData;
|
||||
};
|
||||
|
||||
const multiRow: LiquidityProvisionData = {
|
||||
id: 'lp-multi',
|
||||
commitmentMinTimeFraction: '100',
|
||||
performanceHysteresisEpochs: 4,
|
||||
priceRange: '1',
|
||||
slaCompetitionFactor: '1',
|
||||
partyId: partyId2,
|
||||
party: {
|
||||
id: partyId2,
|
||||
},
|
||||
createdAt: '2022-08-19T17:18:37.257028Z',
|
||||
updatedAt: '2022-08-19T17:18:37.257028Z',
|
||||
commitmentAmount: '200',
|
||||
fee: '0.002',
|
||||
status: Schema.LiquidityProvisionStatus.STATUS_ACTIVE,
|
||||
feeShare: {
|
||||
equityLikeShare: '0.5',
|
||||
averageEntryValuation: '0.5',
|
||||
virtualStake: '0.5',
|
||||
averageScore: '0.5',
|
||||
},
|
||||
};
|
||||
|
||||
const singleRowData = [singleRow];
|
||||
const multiRowData = [singleRow, multiRow];
|
||||
|
||||
describe('LiquidityTable', () => {
|
||||
it('should render successfully', async () => {
|
||||
@@ -26,6 +62,10 @@ describe('LiquidityTable', () => {
|
||||
const { baseElement } = render(
|
||||
<LiquidityTable rowData={[]} stakeToCcyVolume={'1'} />
|
||||
);
|
||||
// 5002-LIQP-002
|
||||
// 5002-LIQP-004
|
||||
// 5002-LIQP-005
|
||||
// 5002-LIQP-011
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -65,7 +105,30 @@ describe('LiquidityTable', () => {
|
||||
'Created',
|
||||
'Updated',
|
||||
];
|
||||
// 5002-LIQP-001
|
||||
expect(headers).toHaveLength(expectedHeaders.length);
|
||||
expect(headerTexts).toEqual(expectedHeaders);
|
||||
});
|
||||
|
||||
it('should be able to sort', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<LiquidityTable rowData={multiRowData} stakeToCcyVolume={'0.3'} />
|
||||
);
|
||||
});
|
||||
const headers = await screen.findAllByRole('columnheader');
|
||||
|
||||
const commitmentHeader = headers.find(
|
||||
(h) => h.getAttribute('col-id') === 'commitmentAmount'
|
||||
);
|
||||
|
||||
if (!commitmentHeader) {
|
||||
throw new Error('No commitment header found');
|
||||
}
|
||||
|
||||
// 5002-LIQP-003
|
||||
expect(commitmentHeader).toHaveAttribute('aria-sort', 'none');
|
||||
await userEvent.click(within(commitmentHeader).getByText(/commitment/i));
|
||||
expect(commitmentHeader).toHaveAttribute('aria-sort', 'ascending');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ describe('DepthChart', () => {
|
||||
<DepthChartContainer marketId={'market-id'} />
|
||||
</MockedProvider>
|
||||
);
|
||||
// 6006-DEPC-001
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
+3
-2
@@ -3,12 +3,12 @@ import * as Types from '@vegaprotocol/types';
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type MarketsDataFieldsFragment = { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, market: { __typename?: 'Market', id: string } };
|
||||
export type MarketsDataFieldsFragment = { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, openInterest: string, market: { __typename?: 'Market', id: string } };
|
||||
|
||||
export type MarketsDataQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type MarketsDataQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', data?: { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, market: { __typename?: 'Market', id: string } } | null } }> } | null };
|
||||
export type MarketsDataQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', data?: { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, openInterest: string, market: { __typename?: 'Market', id: string } } | null } }> } | null };
|
||||
|
||||
export const MarketsDataFieldsFragmentDoc = gql`
|
||||
fragment MarketsDataFields on MarketData {
|
||||
@@ -30,6 +30,7 @@ export const MarketsDataFieldsFragmentDoc = gql`
|
||||
suppliedStake
|
||||
auctionStart
|
||||
auctionEnd
|
||||
openInterest
|
||||
}
|
||||
`;
|
||||
export const MarketsDataDocument = gql`
|
||||
|
||||
@@ -723,7 +723,7 @@ export const PriceMonitoringBoundsInfoPanel = ({
|
||||
})}
|
||||
</p>
|
||||
<p className="col-span-1 text-right">
|
||||
{t('Within %s seconds', {
|
||||
{t('Within {{horizonSecs}} seconds', {
|
||||
horizonSecs: formatNumber(trigger.horizonSecs),
|
||||
})}
|
||||
</p>
|
||||
|
||||
@@ -189,7 +189,7 @@ export const OracleFullProfile = ({
|
||||
'verifyProofs',
|
||||
'Verify {{count}} proofs of ownership',
|
||||
{
|
||||
proofs: signedMessageProofs,
|
||||
count: signedMessageProofs.length,
|
||||
}
|
||||
)}{' '}
|
||||
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={13} />
|
||||
|
||||
@@ -17,6 +17,7 @@ fragment MarketsDataFields on MarketData {
|
||||
suppliedStake
|
||||
auctionStart
|
||||
auctionEnd
|
||||
openInterest
|
||||
}
|
||||
|
||||
query MarketsData {
|
||||
|
||||
@@ -40,6 +40,7 @@ export const createMarketsDataFragment = (
|
||||
bestStaticBidPrice: '0',
|
||||
bestStaticOfferPrice: '0',
|
||||
indicativeVolume: '0',
|
||||
openInterest: '0',
|
||||
bestBidPrice: '0',
|
||||
bestOfferPrice: '0',
|
||||
markPrice: '4612690058',
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const useT = () => useTranslation('funding-payments').t;
|
||||
export const useT = () => useTranslation('markets').t;
|
||||
|
||||
@@ -267,6 +267,7 @@ export const preparePositions = (metrics: Position[], showClosed: boolean) => {
|
||||
MarketState.STATE_ACTIVE,
|
||||
MarketState.STATE_PENDING,
|
||||
MarketState.STATE_SUSPENDED,
|
||||
MarketState.STATE_SUSPENDED_VIA_GOVERNANCE,
|
||||
].includes(p.marketState)
|
||||
) {
|
||||
return true;
|
||||
|
||||
@@ -6,14 +6,17 @@ import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MAXGOINT64 } from '@vegaprotocol/utils';
|
||||
|
||||
const mockCreate = jest.fn();
|
||||
|
||||
jest.mock('@vegaprotocol/wallet', () => ({
|
||||
...jest.requireActual('@vegaprotocol/wallet'),
|
||||
useVegaWallet: jest.fn(() => ({ pubKey: 'partyId' })),
|
||||
}));
|
||||
|
||||
jest.mock('@vegaprotocol/web3', () => ({
|
||||
...jest.requireActual('@vegaprotocol/web3'),
|
||||
useVegaTransactionStore: jest.fn(() => mockCreate),
|
||||
}));
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const mockUseDataProvider = (args: any) => {
|
||||
if (args.dataProvider === positionsMarketsProvider) {
|
||||
@@ -21,17 +24,20 @@ const mockUseDataProvider = (args: any) => {
|
||||
}
|
||||
return { data: [singleRow] };
|
||||
};
|
||||
|
||||
jest.mock('@vegaprotocol/data-provider', () => ({
|
||||
...jest.requireActual('@vegaprotocol/data-provider'),
|
||||
useDataProvider: jest.fn((args) => mockUseDataProvider(args)),
|
||||
}));
|
||||
|
||||
describe('PositionsManager', () => {
|
||||
it('should close position with max uint64', async () => {
|
||||
// TODO: Close position temporarily disabled in https://github.com/vegaprotocol/frontend-monorepo/pull/5350
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('should close position with max uint64', async () => {
|
||||
render(<PositionsManager partyIds={['partyId']} isReadOnly={false} />, {
|
||||
wrapper: MockedProvider,
|
||||
});
|
||||
expect(await screen.getByTestId('close-position')).toBeInTheDocument();
|
||||
expect(await screen.findByTestId('close-position')).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByTestId('close-position'));
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import { useCallback } from 'react';
|
||||
import { PositionsTable } from './positions-table';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { useVegaTransactionStore } from '@vegaprotocol/web3';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import {
|
||||
@@ -9,9 +6,15 @@ import {
|
||||
positionsMarketsProvider,
|
||||
} from './positions-data-providers';
|
||||
import type { useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||
import { MAXGOINT64 } from '@vegaprotocol/utils';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
// TODO: Close position temporarily disabled in https://github.com/vegaprotocol/frontend-monorepo/pull/5350
|
||||
//
|
||||
// import { useCallback } from 'react';
|
||||
// import * as Schema from '@vegaprotocol/types';
|
||||
// import { useVegaTransactionStore } from '@vegaprotocol/web3';
|
||||
// import { MAXGOINT64 } from '@vegaprotocol/utils';
|
||||
|
||||
interface PositionsManagerProps {
|
||||
partyIds: string[];
|
||||
onMarketClick?: (marketId: string) => void;
|
||||
@@ -29,33 +32,37 @@ export const PositionsManager = ({
|
||||
}: PositionsManagerProps) => {
|
||||
const t = useT();
|
||||
const { pubKeys, pubKey } = useVegaWallet();
|
||||
const create = useVegaTransactionStore((store) => store.create);
|
||||
const onClose = useCallback(
|
||||
({ marketId, openVolume }: { marketId: string; openVolume: string }) =>
|
||||
create({
|
||||
batchMarketInstructions: {
|
||||
cancellations: [
|
||||
{
|
||||
marketId,
|
||||
orderId: '', // omit order id to cancel all active orders
|
||||
},
|
||||
],
|
||||
submissions: [
|
||||
{
|
||||
marketId: marketId,
|
||||
type: Schema.OrderType.TYPE_MARKET as const,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC as const,
|
||||
side: openVolume.startsWith('-')
|
||||
? Schema.Side.SIDE_BUY
|
||||
: Schema.Side.SIDE_SELL,
|
||||
size: MAXGOINT64, // improvement for avoiding leftovers filled in the meantime when close request has been sent
|
||||
reduceOnly: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
[create]
|
||||
);
|
||||
|
||||
// TODO: Close position temporarily disabled in https://github.com/vegaprotocol/frontend-monorepo/pull/5350
|
||||
//
|
||||
// const create = useVegaTransactionStore((store) => store.create);
|
||||
//
|
||||
// const onClose = useCallback(
|
||||
// ({ marketId, openVolume }: { marketId: string; openVolume: string }) =>
|
||||
// create({
|
||||
// batchMarketInstructions: {
|
||||
// cancellations: [
|
||||
// {
|
||||
// marketId,
|
||||
// orderId: '', // omit order id to cancel all active orders
|
||||
// },
|
||||
// ],
|
||||
// submissions: [
|
||||
// {
|
||||
// marketId: marketId,
|
||||
// type: Schema.OrderType.TYPE_MARKET as const,
|
||||
// timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC as const,
|
||||
// side: openVolume.startsWith('-')
|
||||
// ? Schema.Side.SIDE_BUY
|
||||
// : Schema.Side.SIDE_SELL,
|
||||
// size: MAXGOINT64, // improvement for avoiding leftovers filled in the meantime when close request has been sent
|
||||
// reduceOnly: true,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// }),
|
||||
// [create]
|
||||
// );
|
||||
|
||||
const { data: marketIds } = useDataProvider({
|
||||
dataProvider: positionsMarketsProvider,
|
||||
@@ -74,7 +81,8 @@ export const PositionsManager = ({
|
||||
pubKeys={pubKeys}
|
||||
rowData={data}
|
||||
onMarketClick={onMarketClick}
|
||||
onClose={onClose}
|
||||
// TODO: temporarily disable close position
|
||||
// onClose={onClose}
|
||||
isReadOnly={isReadOnly}
|
||||
multipleKeys={partyIds.length > 1}
|
||||
overlayNoRowsTemplate={error ? error.message : t('No positions')}
|
||||
|
||||
@@ -22,11 +22,13 @@ export const CompactNumber = ({
|
||||
decimals = 'infer',
|
||||
compactDisplay = 'short',
|
||||
testId = 'compact-number',
|
||||
compactAbove = DEFAULT_COMPACT_ABOVE,
|
||||
}: {
|
||||
number: BigNumber;
|
||||
decimals?: number | 'infer';
|
||||
compactDisplay?: 'short' | 'long';
|
||||
testId?: string;
|
||||
compactAbove?: number;
|
||||
}) => {
|
||||
if (!number.isFinite()) {
|
||||
return (
|
||||
@@ -44,7 +46,7 @@ export const CompactNumber = ({
|
||||
return <span data-testid={testId}>{INFINITY}</span>;
|
||||
}
|
||||
|
||||
if (number.isLessThan(DEFAULT_COMPACT_ABOVE)) {
|
||||
if (number.isLessThan(compactAbove)) {
|
||||
return (
|
||||
<span data-testid={testId}>{formatNumber(number, decimalPlaces)}</span>
|
||||
);
|
||||
|
||||
Generated
+13
-1
@@ -4376,7 +4376,19 @@ export type Query = {
|
||||
/** The last block process by the blockchain */
|
||||
lastBlockHeight: Scalars['String'];
|
||||
/**
|
||||
* Get ledger entries by asset, market, party, account type, transfer type within the given date range.
|
||||
* Get a list of ledger entries within the given date range. The date range is restricted to a maximum of 5 days.
|
||||
* This query requests and sums the number of ledger entries from a given subset of accounts, specified via the 'filter' argument.
|
||||
* It returns a time series - implemented as a list of AggregateLedgerEntry structs - with a row for every time
|
||||
* the summed ledger entries of the set of specified accounts changes.
|
||||
* Each account filter must contain no more than one party ID.
|
||||
* At least one party ID must be specified in the from or to account filter.
|
||||
*
|
||||
* Entries can be filtered by:
|
||||
* - the sending account (market ID, asset ID, account type)
|
||||
* - receiving account (market ID, asset ID, account type)
|
||||
* - sending AND receiving account
|
||||
* - transfer type either in addition to the above filters or as a standalone option
|
||||
*
|
||||
* Note: The date range is restricted to any 5 days.
|
||||
* If no start or end date is provided, only ledger entries from the last 5 days will be returned.
|
||||
* If a start and end date are provided, but the end date is more than 5 days after the start date, only data up to 5 days after the start date will be returned.
|
||||
|
||||
@@ -1,24 +1,41 @@
|
||||
import type { ReactElement } from 'react';
|
||||
import type { ReactElement, ReactNode } from 'react';
|
||||
import { Tooltip } from '../tooltip';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import { useCopyTimeout } from '@vegaprotocol/react-helpers';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
export const TOOLTIP_TIMEOUT = 800;
|
||||
|
||||
export interface CopyWithTooltipProps {
|
||||
children: ReactElement;
|
||||
text: string;
|
||||
/**
|
||||
* The tooltip's description to be shown on mouse over
|
||||
* (replaced by "Copied" when clicked on)
|
||||
*/
|
||||
description?: ReactNode;
|
||||
}
|
||||
|
||||
export function CopyWithTooltip({ children, text }: CopyWithTooltipProps) {
|
||||
export function CopyWithTooltip({
|
||||
children,
|
||||
text,
|
||||
description,
|
||||
}: CopyWithTooltipProps) {
|
||||
const t = useT();
|
||||
const [copied, setCopied] = useCopyTimeout();
|
||||
|
||||
const copiedDescription = t('Copied');
|
||||
|
||||
return (
|
||||
<CopyToClipboard text={text} onCopy={() => setCopied(true)}>
|
||||
{/*
|
||||
// @ts-ignore not sure about this typescript error. Needs this wrapping span as tooltip component interferes with element used to capture click for copy */}
|
||||
<span>
|
||||
<Tooltip description="Copied" open={copied} align="center">
|
||||
<Tooltip
|
||||
description={copied ? copiedDescription : description}
|
||||
open={description ? copied || undefined : copied}
|
||||
align="center"
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
ExternalLink,
|
||||
VegaIcon,
|
||||
@@ -9,10 +8,11 @@ import type { ReactNode } from 'react';
|
||||
import { MozillaIcon } from './mozilla-icon';
|
||||
import { ChromeIcon } from './chrome-icon';
|
||||
import { useVegaWallet } from '../use-vega-wallet';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
export const ConnectDialogTitle = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
<h1 data-testid="wallet-dialog-title" className="mb-6 text-2xl font-alpha">
|
||||
<h1 data-testid="wallet-dialog-title" className="font-alpha mb-6 text-2xl">
|
||||
{children}
|
||||
</h1>
|
||||
);
|
||||
@@ -23,6 +23,7 @@ export const ConnectDialogContent = ({ children }: { children: ReactNode }) => {
|
||||
};
|
||||
|
||||
export const ConnectDialogFooter = () => {
|
||||
const t = useT();
|
||||
const { links } = useVegaWallet();
|
||||
const wrapperClasses = classNames(
|
||||
'flex justify-center gap-4 mt-4',
|
||||
@@ -56,7 +57,7 @@ export const BrowserIcon = ({
|
||||
const isItMozilla =
|
||||
window.navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||
return (
|
||||
<div className="absolute top-0 flex items-center h-8 right-1">
|
||||
<div className="absolute right-1 top-0 flex h-8 items-center">
|
||||
{!isItChrome && !isItMozilla ? (
|
||||
<>
|
||||
<a href={mozillaExtensionUrl} target="_blank" rel="noreferrer">
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useCallback, useState, type ReactNode } from 'react';
|
||||
import { type WalletClientError } from '@vegaprotocol/wallet-client';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { type Connectors, type VegaConnector } from '../connectors';
|
||||
import { DEFAULT_SNAP_VERSION } from '../connectors';
|
||||
import {
|
||||
@@ -46,6 +45,8 @@ import { useIsWalletServiceRunning } from '../use-is-wallet-service-running';
|
||||
import { SnapStatus, useSnapStatus } from '../use-snap-status';
|
||||
import { useVegaWalletDialogStore } from './vega-wallet-dialog-store';
|
||||
import { useChainId } from './use-chain-id';
|
||||
import { useT } from '../use-t';
|
||||
import { Trans } from 'react-i18next';
|
||||
|
||||
export const CLOSE_DELAY = 1700;
|
||||
|
||||
@@ -225,6 +226,7 @@ const ConnectorList = ({
|
||||
isDesktopWalletRunning: boolean | null;
|
||||
snapStatus: SnapStatus;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { pubKey, links } = useVegaWallet();
|
||||
const title = isBrowserWalletInstalled()
|
||||
? t('Connect Vega wallet')
|
||||
@@ -248,7 +250,7 @@ const ConnectorList = ({
|
||||
? 'Chrome'
|
||||
: isItMozilla
|
||||
? 'Firefox'
|
||||
: 'your browser';
|
||||
: t('your browser');
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -265,34 +267,28 @@ const ConnectorList = ({
|
||||
text={extendedText}
|
||||
onClick={() => onSelect('injected')}
|
||||
title={
|
||||
<>
|
||||
<span>{t('Vega Wallet')}</span>
|
||||
{' '}
|
||||
<span className="text-xs">{t('full featured')}</span>
|
||||
</>
|
||||
<Trans
|
||||
defaults="Vega Wallet <0>full featured<0>"
|
||||
components={[<span className="text-xs">full featured</span>]}
|
||||
/>
|
||||
}
|
||||
description={t(
|
||||
`Connect with Vega Wallet extension
|
||||
for %s to access all features including key
|
||||
management and detailed transaction views from your
|
||||
browser.`,
|
||||
[browserName]
|
||||
'Connect with Vega Wallet extension for {{browserName}} to access all features including key management and detailed transaction views from your browser.',
|
||||
{ browserName }
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<div>
|
||||
<h1 className="mb-1 text-lg">
|
||||
<span>{t('Vega Wallet')}</span>
|
||||
{' '}
|
||||
<span className="text-xs"> {t('full featured')}</span>
|
||||
<Trans
|
||||
defaults="Vega Wallet <0>full featured<0>"
|
||||
components={[<span className="text-xs">full featured</span>]}
|
||||
/>
|
||||
</h1>
|
||||
<p className="mb-2 text-sm">
|
||||
{t(
|
||||
`Install Vega Wallet extension
|
||||
for %s to access all features including key
|
||||
management and detailed transaction views from your
|
||||
browser.`,
|
||||
[browserName]
|
||||
'Install Vega Wallet extension for {{browserName}} to access all features including key management and detailed transaction views from your browser.',
|
||||
{ browserName }
|
||||
)}
|
||||
</p>
|
||||
<GetWalletButton
|
||||
@@ -307,11 +303,10 @@ const ConnectorList = ({
|
||||
<ConnectionOptionWithDescription
|
||||
type="snap"
|
||||
title={
|
||||
<>
|
||||
<span>{t('Metamask Snap')}</span>
|
||||
{' '}
|
||||
<span className="text-xs"> {t('quick start')}</span>
|
||||
</>
|
||||
<Trans
|
||||
defaults="Metamask Snap <0>quick start</0>"
|
||||
components={[<span className="text-xs">quick start</span>]}
|
||||
/>
|
||||
}
|
||||
description={t(
|
||||
`Connect directly via Metamask with the Vega Snap for single key support without advanced features.`
|
||||
@@ -336,11 +331,12 @@ const ConnectorList = ({
|
||||
type="snap"
|
||||
disabled={snapStatus === SnapStatus.NOT_SUPPORTED}
|
||||
title={
|
||||
<>
|
||||
<span>{t('Metamask Snap')}</span>
|
||||
{' '}
|
||||
<span className="text-xs"> {t('quick start')}</span>
|
||||
</>
|
||||
<Trans
|
||||
defaults="Metamask Snap <0>quick start</0>"
|
||||
components={[
|
||||
<span className="text-xs">quick start</span>,
|
||||
]}
|
||||
/>
|
||||
}
|
||||
description={t(
|
||||
`Install Metamask with the Vega Snap for single key support without advanced features.`
|
||||
@@ -363,11 +359,14 @@ const ConnectorList = ({
|
||||
/>
|
||||
{snapStatus === SnapStatus.NOT_SUPPORTED ? (
|
||||
<p className="text-muted pt-1 text-xs leading-tight">
|
||||
{t('No MetaMask version that supports snaps detected.')}{' '}
|
||||
{t('Learn more about')}{' '}
|
||||
<ExternalLink href="https://metamask.io/snaps/">
|
||||
MetaMask Snaps
|
||||
</ExternalLink>
|
||||
<Trans
|
||||
defaults="No MetaMask version that supports snaps detected. Learn more about <0>MetaMask Snaps</0>"
|
||||
components={[
|
||||
<ExternalLink href="https://metamask.io/snaps/">
|
||||
MetaMask Snaps
|
||||
</ExternalLink>,
|
||||
]}
|
||||
/>
|
||||
</p>
|
||||
) : null}
|
||||
</>
|
||||
@@ -469,6 +468,7 @@ export const GetWalletButton = ({
|
||||
mozillaExtensionUrl?: string;
|
||||
className?: string;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const isItChrome = window.navigator.userAgent.includes('Chrome');
|
||||
const isItMozilla =
|
||||
window.navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||
@@ -599,6 +599,7 @@ const CustomUrlInput = ({
|
||||
isDesktopWalletRunning: boolean | null;
|
||||
onSelect: (type: WalletType) => void;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const [urlInputExpanded, setUrlInputExpanded] = useState(false);
|
||||
return urlInputExpanded ? (
|
||||
@@ -654,18 +655,22 @@ const CustomUrlInput = ({
|
||||
</button>
|
||||
) : (
|
||||
<p className="text-muted leading-tight">
|
||||
<span className="text-xs">
|
||||
{t(
|
||||
'No running Desktop App/CLI detected. Open your app now to connect or enter a'
|
||||
)}
|
||||
</span>{' '}
|
||||
<button
|
||||
className="text-xs underline"
|
||||
onClick={() => setUrlInputExpanded(true)}
|
||||
disabled={Boolean(pubKey)}
|
||||
>
|
||||
{t('custom wallet location')}
|
||||
</button>
|
||||
<Trans
|
||||
defaults="<0>No running Desktop App/CLI detected. Open your app now to connect or enter a</0> <1>custom wallet location</1>"
|
||||
components={[
|
||||
<span className="text-xs">
|
||||
No running Desktop App/CLI detected. Open your app now to
|
||||
connect or enter a
|
||||
</span>,
|
||||
<button
|
||||
className="text-xs underline"
|
||||
onClick={() => setUrlInputExpanded(true)}
|
||||
disabled={Boolean(pubKey)}
|
||||
>
|
||||
custom wallet location
|
||||
</button>,
|
||||
]}
|
||||
/>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Status } from '../use-injected-connector';
|
||||
import { ConnectDialogTitle } from './connect-dialog-elements';
|
||||
import type { ReactNode } from 'react';
|
||||
@@ -12,6 +11,7 @@ import {
|
||||
import { setAcknowledged } from '../storage';
|
||||
import { useVegaWallet } from '../use-vega-wallet';
|
||||
import { InjectedConnectorErrors, SnapConnectorErrors } from '../connectors';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
export const InjectedConnectorForm = ({
|
||||
status,
|
||||
@@ -28,6 +28,7 @@ export const InjectedConnectorForm = ({
|
||||
reset: () => void;
|
||||
riskMessage?: React.ReactNode;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { disconnect } = useVegaWallet();
|
||||
|
||||
if (status === Status.Idle) {
|
||||
@@ -109,7 +110,7 @@ export const InjectedConnectorForm = ({
|
||||
|
||||
const Center = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
<div className="flex items-center justify-center my-6">{children}</div>
|
||||
<div className="my-6 flex items-center justify-center">{children}</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -122,6 +123,7 @@ const Error = ({
|
||||
appChainId: string;
|
||||
onTryAgain: () => void;
|
||||
}) => {
|
||||
const t = useT();
|
||||
let title = t('Something went wrong');
|
||||
let text: ReactNode | undefined = t('An unknown error occurred');
|
||||
const tryAgain: ReactNode | null = (
|
||||
@@ -139,8 +141,8 @@ const Error = ({
|
||||
) {
|
||||
title = t('Wrong network');
|
||||
text = t(
|
||||
'To complete your wallet connection, set your wallet network in your app to "%s".',
|
||||
appChainId
|
||||
'To complete your wallet connection, set your wallet network in your app to "{{appChainId}}".',
|
||||
{ appChainId }
|
||||
);
|
||||
} else if (
|
||||
error.message === InjectedConnectorErrors.VEGA_UNDEFINED.message
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import capitalize from 'lodash/capitalize';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
Button,
|
||||
ButtonLink,
|
||||
@@ -16,6 +15,7 @@ import { ConnectDialogTitle } from './connect-dialog-elements';
|
||||
import { Status } from '../use-json-rpc-connect';
|
||||
import { useVegaWallet } from '../use-vega-wallet';
|
||||
import { setAcknowledged } from '../storage';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
export const ServiceErrors = {
|
||||
NO_HEALTHY_NODE: 1000,
|
||||
@@ -39,6 +39,7 @@ export const JsonRpcConnectorForm = ({
|
||||
reset: () => void;
|
||||
riskMessage?: React.ReactNode;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { disconnect } = useVegaWallet();
|
||||
if (status === Status.Idle) {
|
||||
return null;
|
||||
@@ -140,7 +141,7 @@ export const JsonRpcConnectorForm = ({
|
||||
|
||||
const Center = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
<div className="flex justify-center items-center my-6">{children}</div>
|
||||
<div className="my-6 flex items-center justify-center">{children}</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -155,6 +156,7 @@ const Error = ({
|
||||
appChainId: string;
|
||||
onTryAgain: () => void;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { links } = useVegaWallet();
|
||||
let title = t('Something went wrong');
|
||||
let text: ReactNode | undefined = t('An unknown error occurred');
|
||||
@@ -168,13 +170,15 @@ const Error = ({
|
||||
if (error.code === ClientErrors.NO_SERVICE.code) {
|
||||
title = t('No wallet detected');
|
||||
text = connectorUrl
|
||||
? t('No wallet application running at %s', connectorUrl)
|
||||
? t('No wallet application running at {{connectorUrl}}', {
|
||||
connectorUrl,
|
||||
})
|
||||
: t('No Vega Wallet application running');
|
||||
} else if (error.code === ClientErrors.WRONG_NETWORK.code) {
|
||||
title = t('Wrong network');
|
||||
text = t(
|
||||
'To complete your wallet connection, set your wallet network in your app to "%s".',
|
||||
appChainId
|
||||
'To complete your wallet connection, set your wallet network in your app to "{{appChainId}}".',
|
||||
{ appChainId }
|
||||
);
|
||||
} else if (error.code === ServiceErrors.NO_HEALTHY_NODE) {
|
||||
title = error.title;
|
||||
@@ -196,9 +200,8 @@ const Error = ({
|
||||
text = (
|
||||
<>
|
||||
{t(
|
||||
`To complete your wallet connection, set your wallet network in your
|
||||
app to %s.`,
|
||||
appChainId
|
||||
'To complete your wallet connection, set your wallet network in your app to "{{appChainId}}".',
|
||||
{ appChainId }
|
||||
)}
|
||||
</>
|
||||
);
|
||||
@@ -213,15 +216,15 @@ const Error = ({
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
title = t(error.title);
|
||||
text = t(error.message);
|
||||
title = error.title;
|
||||
text = error.message;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ConnectDialogTitle>{title}</ConnectDialogTitle>
|
||||
<p className="text-center mb-2 first-letter:uppercase">{text}</p>
|
||||
<p className="mb-2 text-center first-letter:uppercase">{text}</p>
|
||||
{tryAgain}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import { useVegaWallet } from '../use-vega-wallet';
|
||||
import { useChainId } from './use-chain-id';
|
||||
|
||||
global.fetch = jest.fn();
|
||||
const mockFetch = global.fetch as jest.Mock;
|
||||
mockFetch.mockImplementation((url: string) => {
|
||||
return Promise.resolve({ ok: true });
|
||||
});
|
||||
|
||||
jest.mock('../use-vega-wallet', () => {
|
||||
const original = jest.requireActual('../use-vega-wallet');
|
||||
return {
|
||||
...original,
|
||||
useVegaWallet: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('useChainId', () => {
|
||||
it('does not call fetch when statistics url could not be determined', async () => {
|
||||
(useVegaWallet as jest.Mock).mockReturnValue({
|
||||
vegaUrl: '',
|
||||
});
|
||||
renderHook(() => useChainId());
|
||||
await waitFor(() => {
|
||||
expect(mockFetch).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('calls fetch with correct statistics url', async () => {
|
||||
(useVegaWallet as jest.Mock).mockReturnValue({
|
||||
vegaUrl: 'http://localhost:1234/graphql',
|
||||
});
|
||||
renderHook(() => useChainId());
|
||||
await waitFor(() => {
|
||||
expect(mockFetch).toHaveBeenCalledWith(
|
||||
'http://localhost:1234/statistics'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not return chain id when chain id is not present in response', async () => {
|
||||
(useVegaWallet as jest.Mock).mockReturnValue({
|
||||
vegaUrl: 'http://localhost:1234/graphql',
|
||||
});
|
||||
const { result } = renderHook(() => useChainId());
|
||||
await waitFor(() => {
|
||||
expect(result.current).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns chain id when chain id is present in response', async () => {
|
||||
(useVegaWallet as jest.Mock).mockReturnValue({
|
||||
vegaUrl: 'http://localhost:1234/graphql',
|
||||
});
|
||||
mockFetch.mockImplementation(() => {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: () => ({
|
||||
statistics: {
|
||||
chainId: '1234',
|
||||
},
|
||||
}),
|
||||
});
|
||||
});
|
||||
const { result } = renderHook(() => useChainId());
|
||||
await waitFor(() => {
|
||||
expect(result.current).not.toBeUndefined();
|
||||
expect(result.current).toEqual('1234');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,17 +3,37 @@ import { useVegaWallet } from '../use-vega-wallet';
|
||||
|
||||
const cache: Record<string, string> = {};
|
||||
|
||||
/**
|
||||
* Gets the statistics url for a given vega url.
|
||||
* Example:
|
||||
* https://graphql.example.com/graphql -> https://graphql.example.com/statistics
|
||||
*/
|
||||
const getNodeStatisticsUrl = (vegaUrl: string) => {
|
||||
try {
|
||||
const url = new URL(vegaUrl);
|
||||
url.pathname = 'statistics';
|
||||
return url.toString();
|
||||
} catch (err) {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export const useChainId = () => {
|
||||
const { vegaUrl } = useVegaWallet();
|
||||
const [chainId, setChainId] = useState<undefined | string>(cache[vegaUrl]);
|
||||
const [fetchAttempt, setFetchAttempt] = useState(1);
|
||||
|
||||
const statisticsUrl = getNodeStatisticsUrl(vegaUrl);
|
||||
|
||||
useEffect(() => {
|
||||
// abort when `/statistics` URL could not be determined
|
||||
if (!statisticsUrl) return;
|
||||
let isCancelled = false;
|
||||
if (cache[vegaUrl]) {
|
||||
setChainId(cache[vegaUrl]);
|
||||
return;
|
||||
}
|
||||
fetch(vegaUrl.replace('graphql', 'statistics'))
|
||||
fetch(statisticsUrl)
|
||||
.then((response) => response.json())
|
||||
.then((response) => {
|
||||
if (isCancelled) {
|
||||
@@ -32,6 +52,6 @@ export const useChainId = () => {
|
||||
return () => {
|
||||
isCancelled = true;
|
||||
};
|
||||
}, [fetchAttempt, vegaUrl]);
|
||||
}, [fetchAttempt, statisticsUrl, vegaUrl]);
|
||||
return chainId;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
TradingFormGroup,
|
||||
TradingInput,
|
||||
@@ -12,6 +11,7 @@ import { useForm } from 'react-hook-form';
|
||||
import type { ViewConnector } from '../connectors';
|
||||
import { useVegaWallet } from '../use-vega-wallet';
|
||||
import { ConnectDialogTitle } from './connect-dialog-elements';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
interface FormFields {
|
||||
address: string;
|
||||
@@ -28,6 +28,7 @@ export function ViewConnectorForm({
|
||||
onConnect,
|
||||
reset,
|
||||
}: ViewConnectorFormProps) {
|
||||
const t = useT();
|
||||
const { connect } = useVegaWallet();
|
||||
const {
|
||||
register,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { WalletClient, WalletClientError } from '@vegaprotocol/wallet-client';
|
||||
import { clearConfig, getConfig, setConfig } from '../storage';
|
||||
import type { Transaction, VegaConnector } from './vega-connector';
|
||||
@@ -7,19 +6,19 @@ import { WalletError } from './vega-connector';
|
||||
const VERSION = 'v2';
|
||||
|
||||
export const ClientErrors = {
|
||||
NO_SERVICE: new WalletError(t('No service'), 100),
|
||||
INVALID_WALLET: new WalletError(t('Wallet version invalid'), 103),
|
||||
NO_SERVICE: new WalletError('No service', 100),
|
||||
INVALID_WALLET: new WalletError('Wallet version invalid', 103),
|
||||
WRONG_NETWORK: new WalletError(
|
||||
t('Wrong network'),
|
||||
'Wrong network',
|
||||
104,
|
||||
t('App is configured to work with a different chain')
|
||||
'App is configured to work with a different chain'
|
||||
),
|
||||
UNKNOWN: new WalletError(
|
||||
t('Something went wrong'),
|
||||
'Something went wrong',
|
||||
105,
|
||||
t('Unknown error occurred')
|
||||
'Unknown error occurred'
|
||||
),
|
||||
NO_CLIENT: new WalletError(t('No client found.'), 106),
|
||||
NO_CLIENT: new WalletError('No client found.', 106),
|
||||
} as const;
|
||||
|
||||
export class JsonRpcConnector implements VegaConnector {
|
||||
@@ -156,16 +155,10 @@ export class JsonRpcConnector implements VegaConnector {
|
||||
try {
|
||||
const result = await fetch(`${this._url}/api/${this.version}/methods`);
|
||||
if (!result.ok) {
|
||||
const sent1 = t(
|
||||
'The version of the wallet service running at %s is not supported.',
|
||||
this._url as string
|
||||
);
|
||||
const sent2 = t(
|
||||
'Update the wallet software to a version that expose the API %s.',
|
||||
this.version
|
||||
);
|
||||
const sent1 = `The version of the wallet service running at ${this._url} is not supported.`;
|
||||
const sent2 = `Update the wallet software to a version that expose the API ${this.version}.`;
|
||||
const data = `${sent1}\n ${sent2}`;
|
||||
const title = t('Wallet version invalid');
|
||||
const title = 'Wallet version invalid';
|
||||
throw new WalletError(title, ClientErrors.INVALID_WALLET.code, data);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { truncateByChars } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
@@ -8,6 +7,7 @@ import {
|
||||
Icon,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '../use-vega-wallet';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
export interface VegaManageDialogProps {
|
||||
dialogOpen: boolean;
|
||||
@@ -18,6 +18,7 @@ export const VegaManageDialog = ({
|
||||
dialogOpen,
|
||||
setDialogOpen,
|
||||
}: VegaManageDialogProps) => {
|
||||
const t = useT();
|
||||
const { pubKey, pubKeys, selectPubKey, disconnect } = useVegaWallet();
|
||||
return (
|
||||
<Dialog
|
||||
@@ -38,13 +39,13 @@ export const VegaManageDialog = ({
|
||||
className="mb-2 last:mb-0"
|
||||
>
|
||||
<div
|
||||
className="flex justify-between text-sm gap-4"
|
||||
className="flex justify-between gap-4 text-sm"
|
||||
data-testid={isSelected ? 'selected-key' : ''}
|
||||
>
|
||||
<p data-testid="vega-public-key-full">
|
||||
{truncateByChars(pk.publicKey)}
|
||||
</p>
|
||||
<div className="flex ml-auto gap-4">
|
||||
<div className="ml-auto flex gap-4">
|
||||
{!isSelected && (
|
||||
<button
|
||||
onClick={() => {
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
import '@testing-library/jest-dom';
|
||||
import ResizeObserver from 'resize-observer-polyfill';
|
||||
import { locales } from '@vegaprotocol/i18n';
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
|
||||
// Set up i18n instance so that components have the correct default
|
||||
// en translations
|
||||
i18n.use(initReactI18next).init({
|
||||
// we init with resources
|
||||
resources: locales,
|
||||
fallbackLng: 'en',
|
||||
ns: ['wallet'],
|
||||
defaultNS: 'wallet',
|
||||
});
|
||||
|
||||
global.ResizeObserver = ResizeObserver;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
export const ns = 'wallet';
|
||||
export const useT = () => useTranslation(ns).t;
|
||||
@@ -677,10 +677,8 @@ const VegaTxRequestedToastContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
const VegaTxPendingToastContentProps = (
|
||||
{ tx }: VegaTxToastContentProps,
|
||||
t: ReturnType<typeof useT>
|
||||
) => {
|
||||
const VegaTxPendingToastContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
const t = useT();
|
||||
const explorerLink = useLinks(DApp.Explorer);
|
||||
return (
|
||||
<>
|
||||
@@ -750,7 +748,7 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
// eslint-disable-next-line jsx-a11y/anchor-is-valid
|
||||
<a
|
||||
href="#"
|
||||
className="inline underline underline-offset-4 cursor-pointer text-inherit break-words"
|
||||
className="inline cursor-pointer break-words text-inherit underline underline-offset-4"
|
||||
data-testid="toast-withdrawal-details"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
@@ -993,7 +991,7 @@ export const getVegaTransactionContentIntent = (tx: VegaStoredTxState) => {
|
||||
content = <VegaTxRequestedToastContent tx={tx} />;
|
||||
}
|
||||
if (tx.status === VegaTxStatus.Pending) {
|
||||
content = <VegaTxPendingToastContentProps tx={tx} />;
|
||||
content = <VegaTxPendingToastContent tx={tx} />;
|
||||
}
|
||||
if (tx.status === VegaTxStatus.Complete) {
|
||||
content = <VegaTxCompleteToastsContent tx={tx} />;
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
export const useTranslation = () => ({
|
||||
t: (label: string, replacements?: Record<string, string>) => {
|
||||
let translatedLabel = label;
|
||||
if (typeof replacements === 'object' && replacements !== null) {
|
||||
Object.keys(replacements).forEach((key) => {
|
||||
translatedLabel = translatedLabel.replace(
|
||||
`{{${key}}}`,
|
||||
replacements[key]
|
||||
);
|
||||
});
|
||||
}
|
||||
return translatedLabel;
|
||||
},
|
||||
});
|
||||
@@ -1,12 +1,13 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Dialog } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { WithdrawFormContainer } from './withdraw-form-container';
|
||||
import { useWeb3ConnectStore } from '@vegaprotocol/web3';
|
||||
import { useWithdrawalDialog } from './withdrawal-dialog';
|
||||
import { useVegaTransactionStore } from '@vegaprotocol/web3';
|
||||
import { useT } from './use-t';
|
||||
|
||||
export const CreateWithdrawalDialog = () => {
|
||||
const t = useT();
|
||||
const { assetId, isOpen, open, close } = useWithdrawalDialog();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const createTransaction = useVegaTransactionStore((state) => state.create);
|
||||
|
||||
@@ -5,7 +5,6 @@ import type { Toast } from '@vegaprotocol/ui-toolkit';
|
||||
import { Button, Intent, Panel, ToastHeading } from '@vegaprotocol/ui-toolkit';
|
||||
import { useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { formatNumber, toBigNum } from '@vegaprotocol/utils';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
@@ -17,6 +16,7 @@ import {
|
||||
import { withdrawalProvider } from './withdrawals-provider';
|
||||
import type { WithdrawalFieldsFragment } from './__generated__/Withdrawal';
|
||||
import uniqBy from 'lodash/uniqBy';
|
||||
import { useT } from './use-t';
|
||||
|
||||
const CHECK_INTERVAL = 1000;
|
||||
const ON_APP_START_TOAST_ID = `ready-to-withdraw`;
|
||||
@@ -199,15 +199,15 @@ const MultipleReadyToWithdrawToastContent = ({
|
||||
count: number;
|
||||
withdrawalsLink?: string;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<>
|
||||
<ToastHeading>{t('Withdrawals ready')}</ToastHeading>
|
||||
<p>
|
||||
{t(
|
||||
'Complete these %s withdrawals to release your funds',
|
||||
count.toString()
|
||||
)}
|
||||
{t('Complete these {{count}} withdrawals to release your funds', {
|
||||
count,
|
||||
})}
|
||||
</p>
|
||||
<p className="mt-2">
|
||||
<Button
|
||||
@@ -229,6 +229,7 @@ const SingleReadyToWithdrawToastContent = ({
|
||||
}: {
|
||||
withdrawal: WithdrawalFieldsFragment;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { createEthWithdrawalApproval } = useEthWithdrawApprovalsStore(
|
||||
(state) => ({
|
||||
createEthWithdrawalApproval: state.create,
|
||||
@@ -266,7 +267,10 @@ const SingleReadyToWithdrawToastContent = ({
|
||||
<p>{t('Complete the withdrawal to release your funds')}</p>
|
||||
<Panel>
|
||||
<strong>
|
||||
{t('Withdraw')} {amount} {withdrawal.asset.symbol}
|
||||
{t('Withdraw {{amount}} {{symbol}}', {
|
||||
amount,
|
||||
symbol: withdrawal.asset.symbol,
|
||||
})}
|
||||
</strong>
|
||||
</Panel>
|
||||
{completeButton}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
export const ns = 'withdraws';
|
||||
export const useT = () => useTranslation(ns).t;
|
||||
@@ -2,7 +2,6 @@ import { useCallback, useState } from 'react';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { addDecimal } from '@vegaprotocol/utils';
|
||||
import { localLoggerFactory } from '@vegaprotocol/logger';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
ApprovalStatus,
|
||||
useGetWithdrawDelay,
|
||||
@@ -15,6 +14,7 @@ import {
|
||||
type Erc20ApprovalQueryVariables,
|
||||
} from './__generated__/Erc20Approval';
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import { useT } from './use-t';
|
||||
|
||||
export interface VerifyState {
|
||||
status: ApprovalStatus;
|
||||
@@ -33,6 +33,7 @@ const initialState = {
|
||||
};
|
||||
|
||||
export const useVerifyWithdrawal = () => {
|
||||
const t = useT();
|
||||
const client = useApolloClient();
|
||||
const getThreshold = useGetWithdrawThreshold();
|
||||
const getDelay = useGetWithdrawDelay();
|
||||
@@ -62,9 +63,9 @@ export const useVerifyWithdrawal = () => {
|
||||
if (withdrawal.asset.source.__typename !== 'ERC20') {
|
||||
setState({
|
||||
status: ApprovalStatus.Error,
|
||||
message: t(
|
||||
`Invalid asset source: ${withdrawal.asset.source.__typename}`
|
||||
),
|
||||
message: t('Invalid asset source: {{source}}', {
|
||||
source: withdrawal.asset.source.__typename,
|
||||
}),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
@@ -132,7 +133,7 @@ export const useVerifyWithdrawal = () => {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
[getThreshold, getDelay, client, setState]
|
||||
[getThreshold, getDelay, client, setState, t]
|
||||
);
|
||||
|
||||
return { verify, state, reset };
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useMemo } from 'react';
|
||||
import { toBigNum } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { AsyncRendererInline } from '@vegaprotocol/ui-toolkit';
|
||||
import { accountsDataProvider } from '@vegaprotocol/accounts';
|
||||
@@ -8,6 +7,7 @@ import { accountsDataProvider } from '@vegaprotocol/accounts';
|
||||
import { WithdrawManager } from './withdraw-manager';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
import type { WithdrawalArgs } from './withdraw-form';
|
||||
import { useT } from './use-t';
|
||||
|
||||
interface WithdrawFormContainerProps {
|
||||
partyId?: string;
|
||||
@@ -20,6 +20,7 @@ export const WithdrawFormContainer = ({
|
||||
partyId,
|
||||
submit,
|
||||
}: WithdrawFormContainerProps) => {
|
||||
const t = useT();
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: accountsDataProvider,
|
||||
variables: { partyId: partyId || '' },
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
isAssetTypeERC20,
|
||||
formatNumber,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useLocalStorage } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
TradingFormGroup,
|
||||
@@ -33,6 +32,7 @@ import {
|
||||
} from '@vegaprotocol/web3';
|
||||
import { AssetBalance } from './asset-balance';
|
||||
import { DocsLinks } from '@vegaprotocol/environment';
|
||||
import { useT } from './use-t';
|
||||
|
||||
export interface WithdrawalArgs {
|
||||
amount: string;
|
||||
@@ -69,10 +69,11 @@ const WithdrawDelayNotification = ({
|
||||
symbol: string;
|
||||
decimals: number;
|
||||
}) => {
|
||||
const replacements = [
|
||||
const t = useT();
|
||||
const replacements = {
|
||||
symbol,
|
||||
delay ? formatDistanceToNow(Date.now() + delay * 1000) : ' ',
|
||||
];
|
||||
delay: delay ? formatDistanceToNow(Date.now() + delay * 1000) : ' ',
|
||||
};
|
||||
return (
|
||||
<Notification
|
||||
intent={Intent.Warning}
|
||||
@@ -84,11 +85,17 @@ const WithdrawDelayNotification = ({
|
||||
}
|
||||
message={[
|
||||
threshold.isEqualTo(0)
|
||||
? t('All %s withdrawals are subject to a %s delay.', replacements)
|
||||
: t('Withdrawals of %s %s or more will be delayed for %s.', [
|
||||
formatNumber(threshold, decimals),
|
||||
...replacements,
|
||||
]),
|
||||
? t(
|
||||
'All {{symbol}} withdrawals are subject to a {{delay}} delay.',
|
||||
replacements
|
||||
)
|
||||
: t(
|
||||
'Withdrawals of {{threshold}} {{symbol}} or more will be delayed for {{delay}}.',
|
||||
{
|
||||
threshold: formatNumber(threshold, decimals),
|
||||
...replacements,
|
||||
}
|
||||
),
|
||||
DocsLinks?.WITHDRAWAL_LIMITS ? (
|
||||
<ExternalLink className="ml-1" href={DocsLinks.WITHDRAWAL_LIMITS}>
|
||||
{t('Read more')}
|
||||
@@ -111,10 +118,10 @@ export const WithdrawForm = ({
|
||||
onSelectAsset,
|
||||
submitWithdraw,
|
||||
}: WithdrawFormProps) => {
|
||||
const t = useT();
|
||||
const ethereumAddress = useEthereumAddress();
|
||||
const required = useRequired();
|
||||
const minSafe = useMinSafe();
|
||||
|
||||
const { account: address } = useWeb3React();
|
||||
const {
|
||||
register,
|
||||
@@ -315,6 +322,7 @@ const UseButton = (props: UseButtonProps) => {
|
||||
};
|
||||
|
||||
const EthereumButton = ({ clearAddress }: { clearAddress: () => void }) => {
|
||||
const t = useT();
|
||||
const openDialog = useWeb3ConnectStore((state) => state.open);
|
||||
const { isActive, connector } = useWeb3React();
|
||||
const [, , removeEagerConnector] = useLocalStorage(ETHEREUM_EAGER_CONNECT);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { Asset } from '@vegaprotocol/assets';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { CompactNumber } from '@vegaprotocol/react-helpers';
|
||||
import { WITHDRAW_THRESHOLD_TOOLTIP_TEXT } from '@vegaprotocol/assets';
|
||||
import {
|
||||
@@ -9,6 +8,7 @@ import {
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import { useT } from './use-t';
|
||||
|
||||
interface WithdrawLimitsProps {
|
||||
amount: string;
|
||||
@@ -25,6 +25,7 @@ export const WithdrawLimits = ({
|
||||
delay,
|
||||
asset,
|
||||
}: WithdrawLimitsProps) => {
|
||||
const t = useT();
|
||||
const delayTime =
|
||||
new BigNumber(amount).isGreaterThan(threshold) && delay
|
||||
? formatDistanceToNow(Date.now() + delay * 1000)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { addDecimalsFormatNumber, truncateByChars } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
Button,
|
||||
KeyValueTable,
|
||||
@@ -11,6 +10,8 @@ import { getChainName, useWeb3ConnectStore } from '@vegaprotocol/web3';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import type { WithdrawalFieldsFragment } from './__generated__/Withdrawal';
|
||||
import { useT } from './use-t';
|
||||
import { Trans } from 'react-i18next';
|
||||
|
||||
export const WithdrawalFeedback = ({
|
||||
transaction,
|
||||
@@ -23,6 +24,7 @@ export const WithdrawalFeedback = ({
|
||||
submitWithdraw: (withdrawalId: string) => void;
|
||||
availableTimestamp: number | null;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { VEGA_EXPLORER_URL } = useEnvironment();
|
||||
const isAvailable =
|
||||
availableTimestamp === null || Date.now() > availableTimestamp;
|
||||
@@ -30,16 +32,20 @@ export const WithdrawalFeedback = ({
|
||||
return (
|
||||
<div>
|
||||
<p className="mb-2">
|
||||
{t('Your funds have been unlocked for withdrawal')} -{' '}
|
||||
<a
|
||||
className="underline"
|
||||
data-testid="tx-block-explorer"
|
||||
href={`${VEGA_EXPLORER_URL}/txs/0x${transaction.txHash}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{t('View in block explorer')}
|
||||
</a>
|
||||
<Trans
|
||||
defaults="Your funds have been unlocked for withdrawal - <0>View in block explorer<0>"
|
||||
components={[
|
||||
<a
|
||||
className="underline"
|
||||
data-testid="tx-block-explorer"
|
||||
href={`${VEGA_EXPLORER_URL}/txs/0x${transaction.txHash}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
View in block explorer
|
||||
</a>,
|
||||
]}
|
||||
/>
|
||||
</p>
|
||||
{withdrawal && (
|
||||
<KeyValueTable>
|
||||
@@ -78,11 +84,9 @@ export const WithdrawalFeedback = ({
|
||||
<ActionButton withdrawal={withdrawal} submitWithdraw={submitWithdraw} />
|
||||
) : (
|
||||
<p className="text-danger">
|
||||
{t(
|
||||
`Available to withdraw in ${formatDistanceToNow(
|
||||
availableTimestamp
|
||||
)}`
|
||||
)}
|
||||
{t('Available to withdraw in {{availableTimestamp}}', {
|
||||
availableTimestamp: formatDistanceToNow(availableTimestamp),
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -96,6 +100,7 @@ const ActionButton = ({
|
||||
withdrawal: WithdrawalFieldsFragment | null;
|
||||
submitWithdraw: (withdrawalId: string) => void;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { isActive, chainId } = useWeb3React();
|
||||
const { open, desiredChainId } = useWeb3ConnectStore((store) => ({
|
||||
open: store.open,
|
||||
@@ -115,7 +120,9 @@ const ActionButton = ({
|
||||
return (
|
||||
<>
|
||||
<p className="text-danger mb-2">
|
||||
{t(`This app only works on ${chainName}. Please change chain.`)}
|
||||
{t('This app only works on {{chainName}}. Please change chain.', {
|
||||
chainName,
|
||||
})}
|
||||
</p>
|
||||
<Button disabled={true}>{t('Withdraw funds')}</Button>
|
||||
</>
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
isNumeric,
|
||||
truncateByChars,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
ActionsDropdown,
|
||||
ButtonLink,
|
||||
@@ -30,6 +29,7 @@ import {
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { type TimestampedWithdrawals } from './use-ready-to-complete-withdrawals-toast';
|
||||
import classNames from 'classnames';
|
||||
import { useT } from './use-t';
|
||||
|
||||
export const WithdrawalsTable = ({
|
||||
delayed,
|
||||
@@ -39,13 +39,14 @@ export const WithdrawalsTable = ({
|
||||
ready?: TimestampedWithdrawals;
|
||||
delayed?: TimestampedWithdrawals;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const createWithdrawApproval = useEthWithdrawApprovalsStore(
|
||||
(store) => store.create
|
||||
);
|
||||
|
||||
const columnDefs = useMemo<ColDef[]>(
|
||||
() => [
|
||||
{ headerName: 'Asset', field: 'asset.symbol' },
|
||||
{ headerName: t('Asset'), field: 'asset.symbol' },
|
||||
{
|
||||
headerName: t('Amount'),
|
||||
field: 'amount',
|
||||
@@ -128,7 +129,7 @@ export const WithdrawalsTable = ({
|
||||
}),
|
||||
},
|
||||
],
|
||||
[createWithdrawApproval, delayed, ready]
|
||||
[createWithdrawApproval, delayed, ready, t]
|
||||
);
|
||||
return (
|
||||
<AgGrid
|
||||
@@ -151,6 +152,7 @@ export type CompleteCellProps = {
|
||||
complete: (withdrawal: WithdrawalFieldsFragment) => void;
|
||||
};
|
||||
export const CompleteCell = ({ data, complete }: CompleteCellProps) => {
|
||||
const t = useT();
|
||||
const open = useWithdrawalApprovalDialog((state) => state.open);
|
||||
const ref = useRef<HTMLButtonElement>(null);
|
||||
|
||||
@@ -206,8 +208,8 @@ export const StatusCell = ({
|
||||
ready?: TimestampedWithdrawals;
|
||||
delayed?: TimestampedWithdrawals;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const READY_TO_COMPLETE = t('Ready to complete');
|
||||
const DELAYED = (readyIn: string) => t('Delayed (ready in %s)', readyIn);
|
||||
const PENDING = t('Pending');
|
||||
const COMPLETED = t('Completed');
|
||||
const REJECTED = t('Rejected');
|
||||
@@ -246,7 +248,11 @@ export const StatusCell = ({
|
||||
if (isDelayed.timestamp == null) return;
|
||||
const remaining = Date.now() - isDelayed.timestamp;
|
||||
if (remaining < 0) {
|
||||
setLabel(DELAYED(convertToCountdownString(remaining, '0:00:00:00')));
|
||||
setLabel(
|
||||
t('Delayed (ready in {{readyIn}})', {
|
||||
readyIn: convertToCountdownString(remaining, '0:00:00:00'),
|
||||
})
|
||||
);
|
||||
} else {
|
||||
setLabel(READY_TO_COMPLETE);
|
||||
}
|
||||
@@ -254,7 +260,7 @@ export const StatusCell = ({
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, [READY_TO_COMPLETE, data, delayed, isDelayed, isPending]);
|
||||
}, [READY_TO_COMPLETE, data, delayed, isDelayed, isPending, t]);
|
||||
|
||||
return data ? (
|
||||
<span
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user