Compare commits
1 Commits
develop
...
fix/5899-g
Author | SHA1 | Date | |
---|---|---|---|
|
18e032817b |
@ -4,5 +4,6 @@ tmp/*
|
|||||||
.dockerignore
|
.dockerignore
|
||||||
dockerfiles
|
dockerfiles
|
||||||
node_modules
|
node_modules
|
||||||
|
.git
|
||||||
.github
|
.github
|
||||||
.vscode
|
.vscode
|
||||||
|
3
.github/workflows/ci-cd-trigger.yml
vendored
3
.github/workflows/ci-cd-trigger.yml
vendored
@ -196,9 +196,9 @@ jobs:
|
|||||||
cypress:
|
cypress:
|
||||||
needs: [build-sources, check-e2e-needed]
|
needs: [build-sources, check-e2e-needed]
|
||||||
name: '(CI) cypress'
|
name: '(CI) cypress'
|
||||||
|
if: ${{ needs.check-e2e-needed.outputs.run-tests == 'true' }}
|
||||||
uses: ./.github/workflows/cypress-run.yml
|
uses: ./.github/workflows/cypress-run.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
if: needs.check-e2e-needed.outputs.run-tests == 'true' && (contains(needs.build-sources.outputs.projects, 'governance') || contains(needs.build-sources.outputs.projects, 'explorer'))
|
|
||||||
with:
|
with:
|
||||||
projects: ${{ needs.build-sources.outputs.projects-e2e }}
|
projects: ${{ needs.build-sources.outputs.projects-e2e }}
|
||||||
tags: '@smoke'
|
tags: '@smoke'
|
||||||
@ -287,7 +287,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- run: |
|
- run: |
|
||||||
result="${{ needs.cypress.result }}"
|
result="${{ needs.cypress.result }}"
|
||||||
echo "Result: $result"
|
|
||||||
if [[ $result == "success" || $result == "skipped" ]]; then
|
if [[ $result == "success" || $result == "skipped" ]]; then
|
||||||
exit 0
|
exit 0
|
||||||
else
|
else
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
# path to a directory with all packages
|
|
||||||
storage: ../tmp/local-registry/storage
|
|
||||||
|
|
||||||
# a list of other known repositories we can talk to
|
|
||||||
uplinks:
|
|
||||||
npmjs:
|
|
||||||
url: https://registry.yarnpkg.com
|
|
||||||
maxage: 60m
|
|
||||||
|
|
||||||
packages:
|
|
||||||
'**':
|
|
||||||
# give all users (including non-authenticated users) full access
|
|
||||||
# because it is a local registry
|
|
||||||
access: $all
|
|
||||||
publish: $all
|
|
||||||
unpublish: $all
|
|
||||||
|
|
||||||
# if package is not available locally, proxy requests to npm registry
|
|
||||||
proxy: npmjs
|
|
||||||
|
|
||||||
# log settings
|
|
||||||
logs:
|
|
||||||
type: stdout
|
|
||||||
format: pretty
|
|
||||||
level: warn
|
|
||||||
|
|
||||||
publish:
|
|
||||||
allow_offline: true # set offline to true to allow publish offline
|
|
@ -1,9 +1,7 @@
|
|||||||
const { join } = require('path');
|
const { join } = require('path');
|
||||||
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
|
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
|
||||||
const { theme } = require('../../libs/tailwindcss-config/src/theme');
|
const theme = require('../../libs/tailwindcss-config/src/theme');
|
||||||
const {
|
const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes');
|
||||||
vegaCustomClasses,
|
|
||||||
} = require('../../libs/tailwindcss-config/src/vega-custom-classes');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: [
|
content: [
|
||||||
|
@ -79,21 +79,21 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should have information on active nodes', function () {
|
it('should have information on active nodes', function () {
|
||||||
cy.getByTestId('node-information')
|
cy.getByTestId('node-information')
|
||||||
.first()
|
.first()
|
||||||
.should('contain.text', '2')
|
.should('contain.text', '2')
|
||||||
.and('contain.text', 'active nodes');
|
.and('contain.text', 'active nodes');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should have information on consensus nodes', function () {
|
it('should have information on consensus nodes', function () {
|
||||||
cy.getByTestId('node-information')
|
cy.getByTestId('node-information')
|
||||||
.last()
|
.last()
|
||||||
.should('contain.text', '2')
|
.should('contain.text', '2')
|
||||||
.and('contain.text', 'consensus nodes');
|
.and('contain.text', 'consensus nodes');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should contain link to specific validators', function () {
|
it('should contain link to specific validators', function () {
|
||||||
cy.getByTestId('validators')
|
cy.getByTestId('validators')
|
||||||
.should('have.length', '2')
|
.should('have.length', '2')
|
||||||
.each(($validator) => {
|
.each(($validator) => {
|
||||||
@ -153,7 +153,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
|||||||
.invoke('text')
|
.invoke('text')
|
||||||
.should('not.eq', currentBlockHeight);
|
.should('not.eq', currentBlockHeight);
|
||||||
});
|
});
|
||||||
cy.getByTestId('subscription-cell').should('be.be.visible');
|
cy.getByTestId('subscription-cell').should('have.text', 'Yes');
|
||||||
});
|
});
|
||||||
cy.getByTestId('connect').should('be.disabled');
|
cy.getByTestId('connect').should('be.disabled');
|
||||||
cy.getByTestId('node-url-custom').click({ force: true });
|
cy.getByTestId('node-url-custom').click({ force: true });
|
||||||
|
@ -26,9 +26,9 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
|
|||||||
const { token, staking, vesting } = useContracts();
|
const { token, staking, vesting } = useContracts();
|
||||||
const setAssociatedBalances = useRefreshAssociatedBalances();
|
const setAssociatedBalances = useRefreshAssociatedBalances();
|
||||||
const [balancesLoaded, setBalancesLoaded] = React.useState(false);
|
const [balancesLoaded, setBalancesLoaded] = React.useState(false);
|
||||||
const vegaWalletStatus = useEagerConnect();
|
const vegaConnecting = useEagerConnect();
|
||||||
|
|
||||||
const loaded = balancesLoaded && vegaWalletStatus !== 'connecting';
|
const loaded = balancesLoaded && !vegaConnecting;
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
@ -169,5 +169,3 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
|
|||||||
}
|
}
|
||||||
return <Suspense fallback={loading}>{children}</Suspense>;
|
return <Suspense fallback={loading}>{children}</Suspense>;
|
||||||
};
|
};
|
||||||
|
|
||||||
AppLoader.displayName = 'AppLoader';
|
|
||||||
|
@ -111,4 +111,3 @@ export const ContractsProvider = ({ children }: { children: JSX.Element }) => {
|
|||||||
</ContractsContext.Provider>
|
</ContractsContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
ContractsProvider.displayName = 'ContractsProvider';
|
|
||||||
|
@ -38,7 +38,6 @@ import { differenceInHours, format, formatDistanceToNowStrict } from 'date-fns';
|
|||||||
import { DATE_FORMAT_DETAILED } from '../../../../lib/date-formats';
|
import { DATE_FORMAT_DETAILED } from '../../../../lib/date-formats';
|
||||||
import { MarketName } from '../proposal/market-name';
|
import { MarketName } from '../proposal/market-name';
|
||||||
import { Indicator } from '../proposal/indicator';
|
import { Indicator } from '../proposal/indicator';
|
||||||
import { type ProposalNode } from '../proposal/proposal-utils';
|
|
||||||
|
|
||||||
const ProposalTypeTags = ({
|
const ProposalTypeTags = ({
|
||||||
proposal,
|
proposal,
|
||||||
@ -541,12 +540,10 @@ const BatchProposalStateText = ({
|
|||||||
|
|
||||||
export const ProposalHeader = ({
|
export const ProposalHeader = ({
|
||||||
proposal,
|
proposal,
|
||||||
restData,
|
|
||||||
isListItem = true,
|
isListItem = true,
|
||||||
voteState,
|
voteState,
|
||||||
}: {
|
}: {
|
||||||
proposal: Proposal | BatchProposal;
|
proposal: Proposal | BatchProposal;
|
||||||
restData?: ProposalNode | null;
|
|
||||||
isListItem?: boolean;
|
isListItem?: boolean;
|
||||||
voteState?: VoteState | null;
|
voteState?: VoteState | null;
|
||||||
}) => {
|
}) => {
|
||||||
@ -598,7 +595,7 @@ export const ProposalHeader = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<ProposalDetails proposal={proposal} />
|
<ProposalDetails proposal={proposal} />
|
||||||
<VoteBreakdown proposal={proposal} restData={restData} />
|
<VoteBreakdown proposal={proposal} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -91,28 +91,6 @@ export type ProposalNode = {
|
|||||||
proposal: ProposalData;
|
proposal: ProposalData;
|
||||||
proposalType: ProposalNodeType;
|
proposalType: ProposalNodeType;
|
||||||
proposals: SubProposalData[];
|
proposals: SubProposalData[];
|
||||||
yes?: [
|
|
||||||
{
|
|
||||||
partyId: string;
|
|
||||||
elsPerMarket?: [
|
|
||||||
{
|
|
||||||
marketId: string;
|
|
||||||
els: string;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
no?: [
|
|
||||||
{
|
|
||||||
partyId: string;
|
|
||||||
elsPerMarket?: [
|
|
||||||
{
|
|
||||||
marketId: string;
|
|
||||||
els: string;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type SingleProposalNode = ProposalNode & {
|
type SingleProposalNode = ProposalNode & {
|
||||||
|
@ -48,7 +48,6 @@ export const Proposal = ({ proposal, restData }: ProposalProps) => {
|
|||||||
|
|
||||||
<ProposalHeader
|
<ProposalHeader
|
||||||
proposal={proposal}
|
proposal={proposal}
|
||||||
restData={restData}
|
|
||||||
isListItem={false}
|
isListItem={false}
|
||||||
voteState={voteState}
|
voteState={voteState}
|
||||||
/>
|
/>
|
||||||
|
@ -17,7 +17,6 @@ import {
|
|||||||
import { useBatchVoteInformation } from '../../hooks/use-vote-information';
|
import { useBatchVoteInformation } from '../../hooks/use-vote-information';
|
||||||
import { MarketName } from '../proposal/market-name';
|
import { MarketName } from '../proposal/market-name';
|
||||||
import { Indicator } from '../proposal/indicator';
|
import { Indicator } from '../proposal/indicator';
|
||||||
import { type ProposalNode } from '../proposal/proposal-utils';
|
|
||||||
|
|
||||||
export const CompactVotes = ({ number }: { number: BigNumber }) => (
|
export const CompactVotes = ({ number }: { number: BigNumber }) => (
|
||||||
<CompactNumber
|
<CompactNumber
|
||||||
@ -111,64 +110,24 @@ const Status = ({ reached, threshold, text, testId }: StatusProps) => {
|
|||||||
|
|
||||||
export const VoteBreakdown = ({
|
export const VoteBreakdown = ({
|
||||||
proposal,
|
proposal,
|
||||||
restData,
|
|
||||||
}: {
|
}: {
|
||||||
proposal: Proposal | BatchProposal;
|
proposal: Proposal | BatchProposal;
|
||||||
restData?: ProposalNode | null;
|
|
||||||
}) => {
|
}) => {
|
||||||
if (proposal.__typename === 'Proposal') {
|
if (proposal.__typename === 'Proposal') {
|
||||||
return <VoteBreakdownNormal proposal={proposal} />;
|
return <VoteBreakdownNormal proposal={proposal} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proposal.__typename === 'BatchProposal') {
|
if (proposal.__typename === 'BatchProposal') {
|
||||||
return <VoteBreakdownBatch proposal={proposal} restData={restData} />;
|
return <VoteBreakdownBatch proposal={proposal} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const VoteBreakdownBatch = ({
|
const VoteBreakdownBatch = ({ proposal }: { proposal: BatchProposal }) => {
|
||||||
proposal,
|
|
||||||
restData,
|
|
||||||
}: {
|
|
||||||
proposal: BatchProposal;
|
|
||||||
restData?: ProposalNode | null;
|
|
||||||
}) => {
|
|
||||||
const [fullBreakdown, setFullBreakdown] = useState(false);
|
const [fullBreakdown, setFullBreakdown] = useState(false);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const yesELS =
|
|
||||||
restData?.yes?.reduce((all, y) => {
|
|
||||||
if (y.elsPerMarket) {
|
|
||||||
y.elsPerMarket.forEach((item) => {
|
|
||||||
const share = Number(item.els);
|
|
||||||
if (all[item.marketId]) {
|
|
||||||
all[item.marketId].push(share);
|
|
||||||
} else {
|
|
||||||
all[item.marketId] = [share];
|
|
||||||
}
|
|
||||||
return all;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return all;
|
|
||||||
}, {} as Record<string, number[]>) || {};
|
|
||||||
|
|
||||||
const noELS =
|
|
||||||
restData?.no?.reduce((all, y) => {
|
|
||||||
if (y.elsPerMarket) {
|
|
||||||
y.elsPerMarket.forEach((item) => {
|
|
||||||
const share = Number(item.els);
|
|
||||||
if (all[item.marketId]) {
|
|
||||||
all[item.marketId].push(share);
|
|
||||||
} else {
|
|
||||||
all[item.marketId] = [share];
|
|
||||||
}
|
|
||||||
return all;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return all;
|
|
||||||
}, {} as Record<string, number[]>) || {};
|
|
||||||
|
|
||||||
const voteInfo = useBatchVoteInformation({
|
const voteInfo = useBatchVoteInformation({
|
||||||
terms: compact(
|
terms: compact(
|
||||||
proposal.subProposals ? proposal.subProposals.map((p) => p?.terms) : []
|
proposal.subProposals ? proposal.subProposals.map((p) => p?.terms) : []
|
||||||
@ -235,8 +194,6 @@ const VoteBreakdownBatch = ({
|
|||||||
proposal={proposal}
|
proposal={proposal}
|
||||||
votes={proposal.votes}
|
votes={proposal.votes}
|
||||||
terms={p.terms}
|
terms={p.terms}
|
||||||
yesELS={yesELS}
|
|
||||||
noELS={noELS}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@ -297,8 +254,6 @@ const VoteBreakdownBatch = ({
|
|||||||
proposal={proposal}
|
proposal={proposal}
|
||||||
votes={proposal.votes}
|
votes={proposal.votes}
|
||||||
terms={p.terms}
|
terms={p.terms}
|
||||||
yesELS={yesELS}
|
|
||||||
noELS={noELS}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@ -316,17 +271,17 @@ const VoteBreakdownBatchSubProposal = ({
|
|||||||
votes,
|
votes,
|
||||||
terms,
|
terms,
|
||||||
indicator,
|
indicator,
|
||||||
yesELS,
|
|
||||||
noELS,
|
|
||||||
}: {
|
}: {
|
||||||
proposal: BatchProposal;
|
proposal: BatchProposal;
|
||||||
votes: VoteFieldsFragment;
|
votes: VoteFieldsFragment;
|
||||||
terms: ProposalTermsFieldsFragment;
|
terms: ProposalTermsFieldsFragment;
|
||||||
indicator?: number;
|
indicator?: number;
|
||||||
yesELS: Record<string, number[]>;
|
|
||||||
noELS: Record<string, number[]>;
|
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const voteInfo = useVoteInformation({
|
||||||
|
votes,
|
||||||
|
terms,
|
||||||
|
});
|
||||||
|
|
||||||
const isProposalOpen = proposal?.state === ProposalState.STATE_OPEN;
|
const isProposalOpen = proposal?.state === ProposalState.STATE_OPEN;
|
||||||
const isUpdateMarket = terms?.change?.__typename === 'UpdateMarket';
|
const isUpdateMarket = terms?.change?.__typename === 'UpdateMarket';
|
||||||
@ -339,15 +294,6 @@ const VoteBreakdownBatchSubProposal = ({
|
|||||||
marketId = terms.change.market.id;
|
marketId = terms.change.market.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const voteInfo = useVoteInformation({
|
|
||||||
votes,
|
|
||||||
terms,
|
|
||||||
// yes votes ELS for this specific proposal (market)
|
|
||||||
yesELS: marketId ? yesELS[marketId] : undefined,
|
|
||||||
// no votes ELS for this specific proposal (market)
|
|
||||||
noELS: marketId ? noELS[marketId] : undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const marketName = marketId ? (
|
const marketName = marketId ? (
|
||||||
<>
|
<>
|
||||||
: <MarketName marketId={marketId} />
|
: <MarketName marketId={marketId} />
|
||||||
|
@ -8,18 +8,13 @@ import {
|
|||||||
type VoteFieldsFragment,
|
type VoteFieldsFragment,
|
||||||
} from '../__generated__/Proposals';
|
} from '../__generated__/Proposals';
|
||||||
import { type ProposalChangeType } from '../types';
|
import { type ProposalChangeType } from '../types';
|
||||||
import sum from 'lodash/sum';
|
|
||||||
|
|
||||||
export const useVoteInformation = ({
|
export const useVoteInformation = ({
|
||||||
votes,
|
votes,
|
||||||
terms,
|
terms,
|
||||||
yesELS,
|
|
||||||
noELS,
|
|
||||||
}: {
|
}: {
|
||||||
votes: VoteFieldsFragment;
|
votes: VoteFieldsFragment;
|
||||||
terms: ProposalTermsFieldsFragment;
|
terms: ProposalTermsFieldsFragment;
|
||||||
yesELS?: number[];
|
|
||||||
noELS?: number[];
|
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
appState: { totalSupply, decimals },
|
appState: { totalSupply, decimals },
|
||||||
@ -36,9 +31,7 @@ export const useVoteInformation = ({
|
|||||||
paramsForChange,
|
paramsForChange,
|
||||||
votes,
|
votes,
|
||||||
totalSupply,
|
totalSupply,
|
||||||
decimals,
|
decimals
|
||||||
yesELS,
|
|
||||||
noELS
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -79,11 +72,7 @@ const getVoteData = (
|
|||||||
},
|
},
|
||||||
votes: ProposalFieldsFragment['votes'],
|
votes: ProposalFieldsFragment['votes'],
|
||||||
totalSupply: BigNumber,
|
totalSupply: BigNumber,
|
||||||
decimals: number,
|
decimals: number
|
||||||
/** A list of ELS yes votes */
|
|
||||||
yesELS?: number[],
|
|
||||||
/** A list if ELS no votes */
|
|
||||||
noELS?: number[]
|
|
||||||
) => {
|
) => {
|
||||||
const requiredMajorityPercentage = params.requiredMajority
|
const requiredMajorityPercentage = params.requiredMajority
|
||||||
? new BigNumber(params.requiredMajority).times(100)
|
? new BigNumber(params.requiredMajority).times(100)
|
||||||
@ -97,31 +86,17 @@ const getVoteData = (
|
|||||||
addDecimal(votes.no.totalTokens ?? 0, decimals)
|
addDecimal(votes.no.totalTokens ?? 0, decimals)
|
||||||
);
|
);
|
||||||
|
|
||||||
let noEquityLikeShareWeight = !votes.no.totalEquityLikeShareWeight
|
const noEquityLikeShareWeight = !votes.no.totalEquityLikeShareWeight
|
||||||
? new BigNumber(0)
|
? new BigNumber(0)
|
||||||
: new BigNumber(votes.no.totalEquityLikeShareWeight).times(100);
|
: new BigNumber(votes.no.totalEquityLikeShareWeight).times(100);
|
||||||
// there's no meaningful `totalEquityLikeShareWeight` in batch proposals,
|
|
||||||
// it has to be deduced from `elsPerMarket` of `no` votes of given proposal
|
|
||||||
// data. (by REST DATA)
|
|
||||||
if (noELS != null) {
|
|
||||||
const noTotalELS = sum(noELS);
|
|
||||||
noEquityLikeShareWeight = new BigNumber(noTotalELS).times(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
const yesTokens = new BigNumber(
|
const yesTokens = new BigNumber(
|
||||||
addDecimal(votes.yes.totalTokens ?? 0, decimals)
|
addDecimal(votes.yes.totalTokens ?? 0, decimals)
|
||||||
);
|
);
|
||||||
|
|
||||||
let yesEquityLikeShareWeight = !votes.yes.totalEquityLikeShareWeight
|
const yesEquityLikeShareWeight = !votes.yes.totalEquityLikeShareWeight
|
||||||
? new BigNumber(0)
|
? new BigNumber(0)
|
||||||
: new BigNumber(votes.yes.totalEquityLikeShareWeight).times(100);
|
: new BigNumber(votes.yes.totalEquityLikeShareWeight).times(100);
|
||||||
// there's no meaningful `totalEquityLikeShareWeight` in batch proposals,
|
|
||||||
// it has to be deduced from `elsPerMarket` of `yes` votes of given proposal
|
|
||||||
// data. (by REST DATA)
|
|
||||||
if (noELS != null) {
|
|
||||||
const yesTotalELS = sum(yesELS);
|
|
||||||
yesEquityLikeShareWeight = new BigNumber(yesTotalELS).times(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
const totalTokensVoted = yesTokens.plus(noTokens);
|
const totalTokensVoted = yesTokens.plus(noTokens);
|
||||||
|
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
const { join } = require('path');
|
const { join } = require('path');
|
||||||
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
|
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
|
||||||
const { theme } = require('../../libs/tailwindcss-config/src/theme');
|
const theme = require('../../libs/tailwindcss-config/src/theme');
|
||||||
const {
|
const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes');
|
||||||
vegaCustomClasses,
|
|
||||||
} = require('../../libs/tailwindcss-config/src/vega-custom-classes');
|
|
||||||
|
|
||||||
export default {
|
module.exports = {
|
||||||
content: [
|
content: [
|
||||||
join(__dirname, 'src/**/*.{js,ts,jsx,tsx}'),
|
join(__dirname, 'src/**/*.{js,ts,jsx,tsx}'),
|
||||||
'libs/ui-toolkit/src/utils/shared.ts',
|
'libs/ui-toolkit/src/utils/shared.ts',
|
||||||
|
11
apps/liquidity-provision-dashboard/.babelrc
Normal file
11
apps/liquidity-provision-dashboard/.babelrc
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
[
|
||||||
|
"@nx/react/babel",
|
||||||
|
{
|
||||||
|
"runtime": "automatic"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"plugins": []
|
||||||
|
}
|
16
apps/liquidity-provision-dashboard/.browserslistrc
Normal file
16
apps/liquidity-provision-dashboard/.browserslistrc
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# This file is used by:
|
||||||
|
# 1. autoprefixer to adjust CSS to support the below specified browsers
|
||||||
|
# 2. babel preset-env to adjust included polyfills
|
||||||
|
#
|
||||||
|
# For additional information regarding the format and rule options, please see:
|
||||||
|
# https://github.com/browserslist/browserslist#queries
|
||||||
|
#
|
||||||
|
# If you need to support different browsers in production, you may tweak the list below.
|
||||||
|
|
||||||
|
last 1 Chrome version
|
||||||
|
last 1 Firefox version
|
||||||
|
last 2 Edge major versions
|
||||||
|
last 2 Safari major version
|
||||||
|
last 2 iOS major versions
|
||||||
|
Firefox ESR
|
||||||
|
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
28
apps/liquidity-provision-dashboard/.env
Normal file
28
apps/liquidity-provision-dashboard/.env
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# React Environment Variables
|
||||||
|
# https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#expanding-environment-variables-in-env
|
||||||
|
|
||||||
|
# Netlify Environment Variables
|
||||||
|
# https://www.netlify.com/docs/continuous-deployment/#environment-variables
|
||||||
|
NX_VERSION=\$npm_package_version
|
||||||
|
NX_REPOSITORY_URL=\$REPOSITORY_URL
|
||||||
|
NX_BRANCH=\$BRANCH
|
||||||
|
NX_PULL_REQUEST=\$PULL_REQUEST
|
||||||
|
NX_HEAD=\$HEAD
|
||||||
|
NX_COMMIT_REF=\$COMMIT_REF
|
||||||
|
NX_CONTEXT=\$CONTEXT
|
||||||
|
NX_REVIEW_ID=\$REVIEW_ID
|
||||||
|
NX_INCOMING_HOOK_TITLE=\$INCOMING_HOOK_TITLE
|
||||||
|
NX_INCOMING_HOOK_URL=\$INCOMING_HOOK_URL
|
||||||
|
NX_INCOMING_HOOK_BODY=\$INCOMING_HOOK_BODY
|
||||||
|
NX_URL=\$URL
|
||||||
|
NX_DEPLOY_URL=\$DEPLOY_URL
|
||||||
|
NX_DEPLOY_PRIME_URL=\$DEPLOY_PRIME_URL
|
||||||
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/fairground/vegawallet-fairground.toml
|
||||||
|
NX_VEGA_ENV = 'TESTNET'
|
||||||
|
NX_VEGA_URL="https://api.n07.testnet.vega.xyz/graphql"
|
||||||
|
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||||
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://trading.stagnet1.vega.rocks\"}
|
||||||
|
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||||
|
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
3
apps/liquidity-provision-dashboard/.env.capsule
Normal file
3
apps/liquidity-provision-dashboard/.env.capsule
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# App configuration variables
|
||||||
|
NX_VEGA_URL=http://localhost:3008/graphql
|
||||||
|
NX_VEGA_ENV=LOCAL
|
8
apps/liquidity-provision-dashboard/.env.devnet
Normal file
8
apps/liquidity-provision-dashboard/.env.devnet
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# App configuration variables
|
||||||
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||||
|
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
||||||
|
NX_VEGA_ENV=DEVNET
|
||||||
|
NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://trading.stagnet1.vega.rocks\"}
|
||||||
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_VEGA_EXPLORER_URL=#
|
9
apps/liquidity-provision-dashboard/.env.mainnet
Normal file
9
apps/liquidity-provision-dashboard/.env.mainnet
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# App configuration variables
|
||||||
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml
|
||||||
|
NX_VEGA_URL=https://api.vega.community/graphql
|
||||||
|
NX_VEGA_ENV=MAINNET
|
||||||
|
NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\"}
|
||||||
|
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
|
NX_ETHERSCAN_URL=https://etherscan.io
|
||||||
|
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz
|
||||||
|
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
9
apps/liquidity-provision-dashboard/.env.stagnet1
Normal file
9
apps/liquidity-provision-dashboard/.env.stagnet1
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# App configuration variables
|
||||||
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
|
||||||
|
NX_VEGA_URL=https://api.n00.stagnet1.vega.xyz/graphql
|
||||||
|
NX_VEGA_ENV=STAGNET1
|
||||||
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks
|
||||||
|
NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://trading.stagnet1.vega.rocks\"}
|
||||||
|
|
9
apps/liquidity-provision-dashboard/.env.testnet
Normal file
9
apps/liquidity-provision-dashboard/.env.testnet
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# App configuration variables
|
||||||
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/fairground/vegawallet-fairground.toml
|
||||||
|
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||||
|
NX_VEGA_ENV=TESTNET
|
||||||
|
NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\"}
|
||||||
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||||
|
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
18
apps/liquidity-provision-dashboard/.eslintrc.json
Normal file
18
apps/liquidity-provision-dashboard/.eslintrc.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
|
||||||
|
"ignorePatterns": ["!**/*", "__generated__"],
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||||
|
"rules": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": ["*.ts", "*.tsx"],
|
||||||
|
"rules": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": ["*.js", "*.jsx"],
|
||||||
|
"rules": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
11
apps/liquidity-provision-dashboard/jest.config.ts
Normal file
11
apps/liquidity-provision-dashboard/jest.config.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
export default {
|
||||||
|
displayName: 'liquidity-provision-dashboard',
|
||||||
|
preset: '../../jest.preset.js',
|
||||||
|
transform: {
|
||||||
|
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
|
||||||
|
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/next/babel'] }],
|
||||||
|
},
|
||||||
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||||
|
coverageDirectory: '../../coverage/apps/liquidity-provision-dashboard',
|
||||||
|
};
|
10
apps/liquidity-provision-dashboard/postcss.config.js
Normal file
10
apps/liquidity-provision-dashboard/postcss.config.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const { join } = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {
|
||||||
|
config: join(__dirname, 'tailwind.config.js'),
|
||||||
|
},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
};
|
94
apps/liquidity-provision-dashboard/project.json
Normal file
94
apps/liquidity-provision-dashboard/project.json
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
{
|
||||||
|
"name": "liquidity-provision-dashboard",
|
||||||
|
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||||
|
"sourceRoot": "apps/liquidity-provision-dashboard/src",
|
||||||
|
"projectType": "application",
|
||||||
|
"targets": {
|
||||||
|
"build": {
|
||||||
|
"executor": "@nx/webpack:webpack",
|
||||||
|
"outputs": ["{options.outputPath}"],
|
||||||
|
"defaultConfiguration": "production",
|
||||||
|
"options": {
|
||||||
|
"compiler": "babel",
|
||||||
|
"outputPath": "dist/apps/liquidity-provision-dashboard",
|
||||||
|
"index": "apps/liquidity-provision-dashboard/src/index.html",
|
||||||
|
"baseHref": "/",
|
||||||
|
"main": "apps/liquidity-provision-dashboard/src/main.tsx",
|
||||||
|
"polyfills": "apps/liquidity-provision-dashboard/src/polyfills.ts",
|
||||||
|
"tsConfig": "apps/liquidity-provision-dashboard/tsconfig.app.json",
|
||||||
|
"assets": [
|
||||||
|
"apps/liquidity-provision-dashboard/src/favicon.ico",
|
||||||
|
"apps/liquidity-provision-dashboard/src/assets"
|
||||||
|
],
|
||||||
|
"styles": ["apps/liquidity-provision-dashboard/src/styles.scss"],
|
||||||
|
"scripts": [],
|
||||||
|
"webpackConfig": "@nx/react/plugins/webpack"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"development": {
|
||||||
|
"extractLicenses": false,
|
||||||
|
"optimization": false,
|
||||||
|
"sourceMap": true,
|
||||||
|
"vendorChunk": true
|
||||||
|
},
|
||||||
|
"production": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "apps/liquidity-provision-dashboard/src/environments/environment.ts",
|
||||||
|
"with": "apps/liquidity-provision-dashboard/src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"optimization": true,
|
||||||
|
"outputHashing": "all",
|
||||||
|
"sourceMap": false,
|
||||||
|
"namedChunks": false,
|
||||||
|
"extractLicenses": true,
|
||||||
|
"vendorChunk": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"executor": "@nx/webpack:dev-server",
|
||||||
|
"options": {
|
||||||
|
"buildTarget": "liquidity-provision-dashboard:build",
|
||||||
|
"hmr": true,
|
||||||
|
"port": 4201
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"development": {
|
||||||
|
"buildTarget": "liquidity-provision-dashboard:build:development"
|
||||||
|
},
|
||||||
|
"production": {
|
||||||
|
"buildTarget": "liquidity-provision-dashboard:build:production",
|
||||||
|
"hmr": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"executor": "@nx/eslint:lint",
|
||||||
|
"outputs": ["{options.outputFile}"],
|
||||||
|
"options": {
|
||||||
|
"lintFilePatterns": [
|
||||||
|
"apps/liquidity-provision-dashboard/**/*.{ts,tsx,js,jsx}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"executor": "@nx/jest:jest",
|
||||||
|
"outputs": [
|
||||||
|
"{workspaceRoot}/coverage/apps/liquidity-provision-dashboard"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"jestConfig": "apps/liquidity-provision-dashboard/jest.config.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"build-spec": {
|
||||||
|
"executor": "nx:run-commands",
|
||||||
|
"outputs": [],
|
||||||
|
"options": {
|
||||||
|
"command": "yarn tsc --project ./apps/liquidity-provision-dashboard/tsconfig.spec.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": []
|
||||||
|
}
|
47
apps/liquidity-provision-dashboard/src/app/app.tsx
Normal file
47
apps/liquidity-provision-dashboard/src/app/app.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import type { InMemoryCacheConfig } from '@apollo/client';
|
||||||
|
import { NetworkLoader, useInitializeEnv } from '@vegaprotocol/environment';
|
||||||
|
import { useRoutes } from 'react-router-dom';
|
||||||
|
|
||||||
|
import '../styles.scss';
|
||||||
|
import { Navbar } from './components/navbar';
|
||||||
|
|
||||||
|
import { routerConfig } from './routes/router-config';
|
||||||
|
|
||||||
|
const cache: InMemoryCacheConfig = {
|
||||||
|
typePolicies: {
|
||||||
|
Market: {
|
||||||
|
merge: true,
|
||||||
|
},
|
||||||
|
Party: {
|
||||||
|
merge: true,
|
||||||
|
},
|
||||||
|
Query: {},
|
||||||
|
Account: {
|
||||||
|
keyFields: false,
|
||||||
|
fields: {
|
||||||
|
balanceFormatted: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Node: {
|
||||||
|
keyFields: false,
|
||||||
|
},
|
||||||
|
Instrument: {
|
||||||
|
keyFields: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const AppRouter = () => useRoutes(routerConfig);
|
||||||
|
|
||||||
|
export function App() {
|
||||||
|
useInitializeEnv();
|
||||||
|
return (
|
||||||
|
<NetworkLoader cache={cache}>
|
||||||
|
<div className="max-h-full min-h-full bg-white">
|
||||||
|
<Navbar />
|
||||||
|
<AppRouter />
|
||||||
|
</div>
|
||||||
|
</NetworkLoader>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
@ -0,0 +1,25 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
import { Intro } from './intro';
|
||||||
|
import { MarketList } from './market-list';
|
||||||
|
|
||||||
|
export function Dashboard() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="px-16 pt-20 pb-12 bg-greys-light-100">
|
||||||
|
<div className="max-w-screen-xl mx-auto">
|
||||||
|
<h1 className="font-alpha calt uppercase text-5xl mb-8">
|
||||||
|
{t('Top liquidity opportunities')}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<Intro />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="px-16 py-6">
|
||||||
|
<div className="max-w-screen-xl mx-auto">
|
||||||
|
<MarketList />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
export * from './dashboard';
|
@ -0,0 +1 @@
|
|||||||
|
export * from './intro';
|
@ -0,0 +1,53 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
|
// TODO: add mainnet links once docs have been updated
|
||||||
|
const LINKS = {
|
||||||
|
testnet: [
|
||||||
|
{
|
||||||
|
label: 'Learn about liquidity fees',
|
||||||
|
url: 'https://docs.vega.xyz/testnet/tutorials/providing-liquidity#resources',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Provide liquidity',
|
||||||
|
url: 'https://docs.vega.xyz/testnet/tutorials/providing-liquidity#overview',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'View your liquidity provisions',
|
||||||
|
url: 'https://docs.vega.xyz/testnet/tutorials/providing-liquidity#viewing-existing-liquidity-provisions',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Amend or remove liquidity',
|
||||||
|
url: 'https://docs.vega.xyz/testnet/tutorials/providing-liquidity#amending-a-liquidity-commitment',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mainnet: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: update this when network switcher is added
|
||||||
|
type Network = 'testnet' | 'mainnet';
|
||||||
|
|
||||||
|
export const Intro = ({ network = 'testnet' }: { network?: Network }) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p className="font-alpha calt text-2xl font-medium mb-2">
|
||||||
|
{t(
|
||||||
|
'Become a liquidity provider and earn a cut of the fees paid during trading.'
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
<ul className="flex flex-wrap">
|
||||||
|
{LINKS[network].map(
|
||||||
|
({ label, url }: { label: string; url: string }) => (
|
||||||
|
<li key={url} className="mr-6">
|
||||||
|
<ExternalLink href={url} rel="noreferrer">
|
||||||
|
{t(label)}
|
||||||
|
</ExternalLink>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './market-list';
|
@ -0,0 +1,296 @@
|
|||||||
|
import { DApp, useLinks } from '@vegaprotocol/environment';
|
||||||
|
import { type Market } from '@vegaprotocol/liquidity';
|
||||||
|
import {
|
||||||
|
displayChange,
|
||||||
|
formatWithAsset,
|
||||||
|
useMarketsLiquidity,
|
||||||
|
} from '@vegaprotocol/liquidity';
|
||||||
|
import {
|
||||||
|
addDecimalsFormatNumber,
|
||||||
|
formatNumberPercentage,
|
||||||
|
getExpiryDate,
|
||||||
|
toBigNum,
|
||||||
|
} from '@vegaprotocol/utils';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { type VegaValueFormatterParams } from '@vegaprotocol/datagrid';
|
||||||
|
import { PriceChangeCell } from '@vegaprotocol/datagrid';
|
||||||
|
import type * as Schema from '@vegaprotocol/types';
|
||||||
|
import {
|
||||||
|
AsyncRenderer,
|
||||||
|
Icon,
|
||||||
|
HealthBar,
|
||||||
|
TooltipCellComponent,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import {
|
||||||
|
type GetRowIdParams,
|
||||||
|
type RowClickedEvent,
|
||||||
|
type ColDef,
|
||||||
|
} from 'ag-grid-community';
|
||||||
|
import 'ag-grid-community/styles/ag-grid.css';
|
||||||
|
import 'ag-grid-community/styles/ag-theme-alpine.css';
|
||||||
|
import { useCallback, useState, useMemo } from 'react';
|
||||||
|
|
||||||
|
import { Grid } from '../../grid';
|
||||||
|
import { HealthDialog } from '../../health-dialog';
|
||||||
|
import { Status } from '../../status';
|
||||||
|
import { intentForStatus } from '../../../lib/utils';
|
||||||
|
import { formatDistanceToNow } from 'date-fns';
|
||||||
|
import { getAsset } from '@vegaprotocol/markets';
|
||||||
|
|
||||||
|
export const MarketList = () => {
|
||||||
|
const { data, error, loading } = useMarketsLiquidity();
|
||||||
|
const [isHealthDialogOpen, setIsHealthDialogOpen] = useState(false);
|
||||||
|
const consoleLink = useLinks(DApp.Console);
|
||||||
|
|
||||||
|
const getRowId = useCallback(({ data }: GetRowIdParams) => data.id, []);
|
||||||
|
const columnDefs = useMemo<ColDef[]>(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
headerName: t('Market (futures)'),
|
||||||
|
field: 'tradableInstrument.instrument.name',
|
||||||
|
cellRenderer: ({ value, data }: { value: string; data: Market }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span className="leading-3">{value}</span>
|
||||||
|
<span className="leading-3">{getAsset(data).symbol}</span>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
minWidth: 100,
|
||||||
|
flex: 1,
|
||||||
|
headerTooltip: t('The market name and settlement asset'),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
headerName: t('Market Code'),
|
||||||
|
headerTooltip: t(
|
||||||
|
'The market code is a unique identifier for this market'
|
||||||
|
),
|
||||||
|
field: 'tradableInstrument.instrument.code',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
headerName: t('Type'),
|
||||||
|
headerTooltip: t('Type'),
|
||||||
|
field: 'tradableInstrument.instrument.product.__typename',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
headerName: t('Last Price'),
|
||||||
|
headerTooltip: t('Latest price for this market'),
|
||||||
|
field: 'data.markPrice',
|
||||||
|
valueFormatter: ({
|
||||||
|
value,
|
||||||
|
data,
|
||||||
|
}: VegaValueFormatterParams<Market, 'data.markPrice'>) =>
|
||||||
|
value && data ? formatWithAsset(value, getAsset(data)) : '-',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
headerName: t('Change (24h)'),
|
||||||
|
headerTooltip: t('Change in price over the last 24h'),
|
||||||
|
cellRenderer: ({
|
||||||
|
data,
|
||||||
|
}: VegaValueFormatterParams<Market, 'data.candles'>) => {
|
||||||
|
if (data && data.candles) {
|
||||||
|
const prices = data.candles.map((candle) => candle.close);
|
||||||
|
return (
|
||||||
|
<PriceChangeCell
|
||||||
|
candles={prices}
|
||||||
|
decimalPlaces={data?.decimalPlaces}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else return <div>{t('-')}</div>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
headerName: t('Volume (24h)'),
|
||||||
|
field: 'dayVolume',
|
||||||
|
valueFormatter: ({
|
||||||
|
value,
|
||||||
|
data,
|
||||||
|
}: VegaValueFormatterParams<Market, 'dayVolume'>) =>
|
||||||
|
value && data
|
||||||
|
? `${addDecimalsFormatNumber(
|
||||||
|
value,
|
||||||
|
getAsset(data).decimals || 0
|
||||||
|
)} (${displayChange(data.volumeChange)})`
|
||||||
|
: '-',
|
||||||
|
headerTooltip: t('The trade volume over the last 24h'),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
headerName: t('Total staked by LPs'),
|
||||||
|
field: 'liquidityCommitted',
|
||||||
|
valueFormatter: ({
|
||||||
|
value,
|
||||||
|
data,
|
||||||
|
}: VegaValueFormatterParams<Market, 'liquidityCommitted'>) =>
|
||||||
|
data && value
|
||||||
|
? formatWithAsset(value.toString(), getAsset(data))
|
||||||
|
: '-',
|
||||||
|
headerTooltip: t('The amount of funds allocated to provide liquidity'),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
headerName: t('Target stake'),
|
||||||
|
field: 'target',
|
||||||
|
valueFormatter: ({
|
||||||
|
value,
|
||||||
|
data,
|
||||||
|
}: VegaValueFormatterParams<Market, 'target'>) =>
|
||||||
|
data && value ? formatWithAsset(value, getAsset(data)) : '-',
|
||||||
|
headerTooltip: t(
|
||||||
|
'The ideal committed liquidity to operate the market. If total commitment currently below this level then LPs can set the fee level with new commitment.'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
headerName: t('% Target stake met'),
|
||||||
|
valueFormatter: ({ data }: VegaValueFormatterParams<Market, ''>) => {
|
||||||
|
if (data) {
|
||||||
|
const roundedPercentage =
|
||||||
|
parseInt(
|
||||||
|
(data.liquidityCommitted / parseFloat(data.target)).toFixed(0)
|
||||||
|
) * 100;
|
||||||
|
const display = Number.isNaN(roundedPercentage)
|
||||||
|
? 'N/A'
|
||||||
|
: formatNumberPercentage(toBigNum(roundedPercentage, 0), 0);
|
||||||
|
return display;
|
||||||
|
} else return '-';
|
||||||
|
},
|
||||||
|
headerTooltip: t('% Target stake met'),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
headerName: t('Fee levels'),
|
||||||
|
field: 'fees',
|
||||||
|
valueFormatter: ({ value }: VegaValueFormatterParams<Market, 'fees'>) =>
|
||||||
|
value ? `${value.factors.liquidityFee}%` : '-',
|
||||||
|
headerTooltip: t('Fee level for this market'),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
headerName: t('Status'),
|
||||||
|
field: 'tradingMode',
|
||||||
|
cellRenderer: ({
|
||||||
|
value,
|
||||||
|
data,
|
||||||
|
}: {
|
||||||
|
value: Schema.MarketTradingMode;
|
||||||
|
data: Market;
|
||||||
|
}) => {
|
||||||
|
return <Status trigger={data.data?.trigger} tradingMode={value} />;
|
||||||
|
},
|
||||||
|
headerTooltip: t(
|
||||||
|
'The current market status - those below the target stake mark are most in need of liquidity'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
headerComponent: () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<span>{t('Health')}</span>{' '}
|
||||||
|
<button
|
||||||
|
onClick={() => setIsHealthDialogOpen(true)}
|
||||||
|
aria-label={t('open tooltip')}
|
||||||
|
>
|
||||||
|
<Icon name="info-sign" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
field: 'tradingMode',
|
||||||
|
cellRenderer: ({
|
||||||
|
value,
|
||||||
|
data,
|
||||||
|
}: {
|
||||||
|
value: Schema.MarketTradingMode;
|
||||||
|
data: Market;
|
||||||
|
}) => (
|
||||||
|
<HealthBar
|
||||||
|
target={data.target}
|
||||||
|
decimals={getAsset(data).decimals || 0}
|
||||||
|
levels={data.feeLevels}
|
||||||
|
intent={intentForStatus(value)}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
sortable: false,
|
||||||
|
cellStyle: { overflow: 'unset' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('Age'),
|
||||||
|
field: 'marketTimestamps.open',
|
||||||
|
headerTooltip: t('Age of the market'),
|
||||||
|
valueFormatter: ({
|
||||||
|
value,
|
||||||
|
}: VegaValueFormatterParams<Market, 'marketTimestamps.open'>) => {
|
||||||
|
return value ? formatDistanceToNow(new Date(value)) : '-';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('Closing Time'),
|
||||||
|
field: 'tradableInstrument.instrument.metadata.tags',
|
||||||
|
headerTooltip: t('Closing time of the market'),
|
||||||
|
valueFormatter: ({ data }: VegaValueFormatterParams<Market, ''>) => {
|
||||||
|
let expiry;
|
||||||
|
if (data?.tradableInstrument.instrument.metadata.tags) {
|
||||||
|
expiry = getExpiryDate(
|
||||||
|
data?.tradableInstrument.instrument.metadata.tags,
|
||||||
|
data?.marketTimestamps.close,
|
||||||
|
data?.state
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return expiry ? expiry : '-';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||||
|
<div
|
||||||
|
className="w-full grow"
|
||||||
|
style={{ minHeight: 500, overflow: 'hidden' }}
|
||||||
|
>
|
||||||
|
<Grid
|
||||||
|
gridOptions={{
|
||||||
|
onRowClicked: ({ data }: RowClickedEvent) => {
|
||||||
|
window.open(
|
||||||
|
liquidityDetailsConsoleLink(data.id, consoleLink),
|
||||||
|
'_blank',
|
||||||
|
'noopener,noreferrer'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
rowData={data}
|
||||||
|
defaultColDef={{
|
||||||
|
resizable: true,
|
||||||
|
sortable: true,
|
||||||
|
unSortIcon: true,
|
||||||
|
cellClass: ['flex', 'flex-col', 'justify-center'],
|
||||||
|
tooltipComponent: TooltipCellComponent,
|
||||||
|
}}
|
||||||
|
columnDefs={columnDefs}
|
||||||
|
getRowId={getRowId}
|
||||||
|
isRowClickable
|
||||||
|
tooltipShowDelay={500}
|
||||||
|
/>
|
||||||
|
<HealthDialog
|
||||||
|
isOpen={isHealthDialogOpen}
|
||||||
|
onChange={() => {
|
||||||
|
setIsHealthDialogOpen(!isHealthDialogOpen);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</AsyncRenderer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const liquidityDetailsConsoleLink = (
|
||||||
|
marketId: string,
|
||||||
|
consoleLink: (url: string | undefined) => string
|
||||||
|
) => consoleLink(`/#/liquidity/${marketId}`);
|
@ -0,0 +1,103 @@
|
|||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { makeDerivedDataProvider } from '@vegaprotocol/data-provider';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||||
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
|
import {
|
||||||
|
getFeeLevels,
|
||||||
|
sumLiquidityCommitted,
|
||||||
|
lpAggregatedDataProvider,
|
||||||
|
} from '@vegaprotocol/liquidity';
|
||||||
|
import { getAsset, marketWithDataProvider } from '@vegaprotocol/markets';
|
||||||
|
import type { MarketWithData } from '@vegaprotocol/markets';
|
||||||
|
|
||||||
|
import { Market } from './market';
|
||||||
|
import { Header } from './header';
|
||||||
|
import { LPProvidersGrid } from './providers';
|
||||||
|
|
||||||
|
const formatMarket = (market: MarketWithData) => {
|
||||||
|
return {
|
||||||
|
name: market?.tradableInstrument.instrument.name,
|
||||||
|
symbol: getAsset(market).symbol,
|
||||||
|
settlementAsset: getAsset(market),
|
||||||
|
targetStake: market?.data?.targetStake,
|
||||||
|
tradingMode: market?.data?.marketTradingMode,
|
||||||
|
trigger: market?.data?.trigger,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const lpDataProvider = makeDerivedDataProvider(
|
||||||
|
[marketWithDataProvider, lpAggregatedDataProvider],
|
||||||
|
([market, lpAggregatedData]) => ({
|
||||||
|
market: { ...formatMarket(market) },
|
||||||
|
liquidityProviders: lpAggregatedData || [],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const useMarketDetails = (marketId: string | undefined) => {
|
||||||
|
const { data, loading, error } = useDataProvider({
|
||||||
|
dataProvider: lpDataProvider,
|
||||||
|
skipUpdates: true,
|
||||||
|
variables: { marketId: marketId || '' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const liquidityProviders = data?.liquidityProviders || [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
name: data?.market?.name,
|
||||||
|
symbol: data?.market?.symbol,
|
||||||
|
liquidityProviders: liquidityProviders,
|
||||||
|
feeLevels: getFeeLevels(liquidityProviders),
|
||||||
|
comittedLiquidity: sumLiquidityCommitted(liquidityProviders) || 0,
|
||||||
|
settlementAsset: data?.market?.settlementAsset || {},
|
||||||
|
targetStake: data?.market?.targetStake || '0',
|
||||||
|
tradingMode: data?.market.tradingMode,
|
||||||
|
},
|
||||||
|
error,
|
||||||
|
loading: loading,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type Params = { marketId: string };
|
||||||
|
|
||||||
|
export const Detail = () => {
|
||||||
|
const { marketId } = useParams<Params>();
|
||||||
|
const { data, loading, error } = useMarketDetails(marketId);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||||
|
<div className="bg-greys-light-100 px-16 pb-12 pt-14">
|
||||||
|
<div className="mx-auto max-w-screen-xl">
|
||||||
|
<Header name={data.name} symbol={data.symbol} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="px-16">
|
||||||
|
<div className="mx-auto max-w-screen-xl">
|
||||||
|
<div className="py-12">
|
||||||
|
{marketId && (
|
||||||
|
<Market
|
||||||
|
marketId={marketId}
|
||||||
|
feeLevels={data.feeLevels}
|
||||||
|
comittedLiquidity={data.comittedLiquidity}
|
||||||
|
settlementAsset={data.settlementAsset}
|
||||||
|
targetStake={data.targetStake}
|
||||||
|
tradingMode={data.tradingMode}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2 className="font-alpha calt mb-4 text-2xl">
|
||||||
|
{t('Current Liquidity Provision')}
|
||||||
|
</h2>
|
||||||
|
<LPProvidersGrid
|
||||||
|
liquidityProviders={data.liquidityProviders}
|
||||||
|
settlementAsset={data.settlementAsset}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AsyncRenderer>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,26 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { Icon } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
|
export const Header = ({
|
||||||
|
name,
|
||||||
|
symbol,
|
||||||
|
}: {
|
||||||
|
name?: string;
|
||||||
|
symbol?: string;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="mb-6">
|
||||||
|
<Link to="/">
|
||||||
|
<Icon name="chevron-left" className="mr-2" />
|
||||||
|
<span className="underline font-alpha calt text-lg font-medium">
|
||||||
|
{t('Liquidity opportunities')}
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<h1 className="font-alpha calt text-5xl mb-6">{name}</h1>
|
||||||
|
<p className="font-alpha calt text-4xl">{symbol}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './header';
|
@ -0,0 +1 @@
|
|||||||
|
export * from './detail';
|
@ -0,0 +1 @@
|
|||||||
|
export * from './last-24h-volume';
|
@ -0,0 +1,108 @@
|
|||||||
|
import { useState, useMemo, useRef, useCallback } from 'react';
|
||||||
|
import throttle from 'lodash/throttle';
|
||||||
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
|
import { useYesterday } from '@vegaprotocol/react-helpers';
|
||||||
|
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||||
|
import * as Schema from '@vegaprotocol/types';
|
||||||
|
import {
|
||||||
|
calcDayVolume,
|
||||||
|
getChange,
|
||||||
|
displayChange,
|
||||||
|
} from '@vegaprotocol/liquidity';
|
||||||
|
|
||||||
|
import type { Candle } from '@vegaprotocol/markets';
|
||||||
|
import { marketCandlesProvider } from '@vegaprotocol/markets';
|
||||||
|
|
||||||
|
const THROTTLE_UPDATE_TIME = 500;
|
||||||
|
|
||||||
|
export const Last24hVolume = ({
|
||||||
|
marketId,
|
||||||
|
decimals,
|
||||||
|
}: {
|
||||||
|
marketId: string;
|
||||||
|
decimals: number;
|
||||||
|
}) => {
|
||||||
|
const [candleVolume, setCandleVolume] = useState<string>();
|
||||||
|
const [volumeChange, setVolumeChange] = useState<string>(' - ');
|
||||||
|
|
||||||
|
const yesterday = useYesterday();
|
||||||
|
|
||||||
|
const yTimestamp = useMemo(() => {
|
||||||
|
return new Date(yesterday).toISOString();
|
||||||
|
}, [yesterday]);
|
||||||
|
|
||||||
|
const variables = useMemo(
|
||||||
|
() => ({
|
||||||
|
marketId: marketId,
|
||||||
|
interval: Schema.Interval.INTERVAL_I1H,
|
||||||
|
since: yTimestamp,
|
||||||
|
}),
|
||||||
|
[marketId, yTimestamp]
|
||||||
|
);
|
||||||
|
|
||||||
|
const variables24hAgo = {
|
||||||
|
marketId: marketId,
|
||||||
|
interval: Schema.Interval.INTERVAL_I1D,
|
||||||
|
since: yTimestamp,
|
||||||
|
};
|
||||||
|
|
||||||
|
const throttledSetCandles = useRef(
|
||||||
|
throttle((data: Candle[]) => {
|
||||||
|
setCandleVolume(calcDayVolume(data));
|
||||||
|
}, THROTTLE_UPDATE_TIME)
|
||||||
|
).current;
|
||||||
|
|
||||||
|
const update = useCallback(
|
||||||
|
({ data }: { data: Candle[] | null }) => {
|
||||||
|
if (data) {
|
||||||
|
throttledSetCandles(data);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[throttledSetCandles]
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data, error } = useDataProvider({
|
||||||
|
dataProvider: marketCandlesProvider,
|
||||||
|
variables: variables,
|
||||||
|
update,
|
||||||
|
skip: !marketId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const throttledSetVolumeChange = useRef(
|
||||||
|
throttle((candles: Candle[]) => {
|
||||||
|
const candle24hAgo = candles?.[0];
|
||||||
|
setVolumeChange(getChange(data || [], candle24hAgo?.close));
|
||||||
|
}, THROTTLE_UPDATE_TIME)
|
||||||
|
).current;
|
||||||
|
|
||||||
|
const updateCandle24hAgo = useCallback(
|
||||||
|
({ data }: { data: Candle[] | null }) => {
|
||||||
|
if (data) {
|
||||||
|
throttledSetVolumeChange(data);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[throttledSetVolumeChange]
|
||||||
|
);
|
||||||
|
|
||||||
|
useDataProvider({
|
||||||
|
dataProvider: marketCandlesProvider,
|
||||||
|
update: updateCandle24hAgo,
|
||||||
|
variables: variables24hAgo,
|
||||||
|
skip: !marketId || !data,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<span className="text-3xl">
|
||||||
|
{!error && candleVolume
|
||||||
|
? addDecimalsFormatNumber(candleVolume, decimals)
|
||||||
|
: '0'}{' '}
|
||||||
|
</span>
|
||||||
|
<span className="text-lg text-greys-light-400">
|
||||||
|
({displayChange(volumeChange)})
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './market';
|
@ -0,0 +1,118 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { Icon, HealthBar } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { formatWithAsset } from '@vegaprotocol/liquidity';
|
||||||
|
|
||||||
|
import type * as Schema from '@vegaprotocol/types';
|
||||||
|
import { HealthDialog } from '../../health-dialog';
|
||||||
|
import { Last24hVolume } from '../last-24h-volume';
|
||||||
|
import { Status } from '../../status';
|
||||||
|
import { intentForStatus } from '../../../lib/utils';
|
||||||
|
|
||||||
|
interface Levels {
|
||||||
|
fee: string;
|
||||||
|
commitmentAmount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface settlementAsset {
|
||||||
|
symbol?: string;
|
||||||
|
decimals?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Market = ({
|
||||||
|
marketId,
|
||||||
|
feeLevels,
|
||||||
|
comittedLiquidity,
|
||||||
|
settlementAsset,
|
||||||
|
targetStake,
|
||||||
|
tradingMode,
|
||||||
|
trigger,
|
||||||
|
}: {
|
||||||
|
marketId: string;
|
||||||
|
feeLevels: Levels[];
|
||||||
|
comittedLiquidity: number;
|
||||||
|
targetStake: string;
|
||||||
|
settlementAsset?: settlementAsset;
|
||||||
|
tradingMode?: Schema.MarketTradingMode;
|
||||||
|
trigger?: Schema.AuctionTrigger;
|
||||||
|
}) => {
|
||||||
|
const [isHealthDialogOpen, setIsHealthDialogOpen] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="border border-greys-light-200 rounded-2xl px-2 py-6">
|
||||||
|
<table className="w-full">
|
||||||
|
<thead>
|
||||||
|
<tr
|
||||||
|
className="text-sm text-greys-light-400 text-left font-alpha calt"
|
||||||
|
style={{ fontFeatureSettings: "'liga' off, 'calt' off" }}
|
||||||
|
>
|
||||||
|
<th className="font-medium px-4">{t('Volume (24h)')}</th>
|
||||||
|
<th className="font-medium px-4">{t('Commited Liquidity')}</th>
|
||||||
|
<th className="font-medium px-4">{t('Status')}</th>
|
||||||
|
<th className="font-medium flex items-center px-4">
|
||||||
|
<span>{t('Health')}</span>{' '}
|
||||||
|
<button
|
||||||
|
onClick={() => setIsHealthDialogOpen(true)}
|
||||||
|
aria-label={t('open tooltip')}
|
||||||
|
className="flex ml-1"
|
||||||
|
>
|
||||||
|
<Icon name="info-sign" />
|
||||||
|
</button>
|
||||||
|
</th>
|
||||||
|
<th className="font-medium">{t('Est. APY')}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td className="px-4">
|
||||||
|
<div>
|
||||||
|
{marketId && settlementAsset?.decimals && (
|
||||||
|
<Last24hVolume
|
||||||
|
marketId={marketId}
|
||||||
|
decimals={settlementAsset.decimals}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="px-4">
|
||||||
|
<span className="text-3xl">
|
||||||
|
{comittedLiquidity && settlementAsset
|
||||||
|
? formatWithAsset(`${comittedLiquidity}`, settlementAsset)
|
||||||
|
: '0'}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td className="px-4">
|
||||||
|
<Status
|
||||||
|
trigger={trigger}
|
||||||
|
tradingMode={tradingMode}
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td className="px-4">
|
||||||
|
{tradingMode && settlementAsset?.decimals && feeLevels && (
|
||||||
|
<HealthBar
|
||||||
|
target={targetStake}
|
||||||
|
decimals={settlementAsset.decimals}
|
||||||
|
levels={feeLevels}
|
||||||
|
intent={intentForStatus(tradingMode)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="px-4">
|
||||||
|
<span className="text-3xl"></span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<HealthDialog
|
||||||
|
isOpen={isHealthDialogOpen}
|
||||||
|
onChange={() => {
|
||||||
|
setIsHealthDialogOpen(!isHealthDialogOpen);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './providers';
|
@ -0,0 +1,125 @@
|
|||||||
|
import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
|
import { type GetRowIdParams, type ColDef } from 'ag-grid-community';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
import {
|
||||||
|
type LiquidityProviderFeeShareFieldsFragment,
|
||||||
|
type LiquidityProvisionFieldsFragment,
|
||||||
|
} from '@vegaprotocol/liquidity';
|
||||||
|
import { formatWithAsset } from '@vegaprotocol/liquidity';
|
||||||
|
|
||||||
|
import { Grid } from '../../grid';
|
||||||
|
import { TooltipCellComponent } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
|
const formatToHours = ({ value }: { value?: string | null }) => {
|
||||||
|
if (!value) {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
const MS_IN_HOUR = 1000 * 60 * 60;
|
||||||
|
const created = new Date(value).getTime();
|
||||||
|
const now = new Date().getTime();
|
||||||
|
return `${Math.round(Math.abs(now - created) / MS_IN_HOUR)}h`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const LPProvidersGrid = ({
|
||||||
|
liquidityProviders,
|
||||||
|
settlementAsset,
|
||||||
|
}: {
|
||||||
|
liquidityProviders: LiquidityProvisionFieldsFragment &
|
||||||
|
LiquidityProviderFeeShareFieldsFragment[];
|
||||||
|
settlementAsset: {
|
||||||
|
decimals?: number;
|
||||||
|
symbol?: string;
|
||||||
|
};
|
||||||
|
}) => {
|
||||||
|
const getRowId = useCallback(({ data }: GetRowIdParams) => data.party.id, []);
|
||||||
|
const columnDefs = useMemo<ColDef[]>(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
headerName: t('LPs'),
|
||||||
|
field: 'party.id',
|
||||||
|
flex: 1,
|
||||||
|
minWidth: 100,
|
||||||
|
headerTooltip: t('Liquidity providers'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('Duration'),
|
||||||
|
valueFormatter: formatToHours,
|
||||||
|
field: 'createdAt',
|
||||||
|
headerTooltip: t('Time in market'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('Equity-like share'),
|
||||||
|
field: 'equityLikeShare',
|
||||||
|
valueFormatter: ({ value }: { value?: string | null }) => {
|
||||||
|
return value
|
||||||
|
? `${parseFloat(parseFloat(value).toFixed(2)) * 100}%`
|
||||||
|
: '';
|
||||||
|
},
|
||||||
|
headerTooltip: t(
|
||||||
|
'The share of the markets liquidity held - the earlier you commit liquidity the greater % fees you earn'
|
||||||
|
),
|
||||||
|
minWidth: 140,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('committed bond'),
|
||||||
|
field: 'commitmentAmount',
|
||||||
|
valueFormatter: ({ value }: { value?: string | null }) =>
|
||||||
|
value ? formatWithAsset(value, settlementAsset) : '0',
|
||||||
|
headerTooltip: t('The amount of funds allocated to provide liquidity'),
|
||||||
|
minWidth: 140,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('Margin Req.'),
|
||||||
|
field: 'margin',
|
||||||
|
headerTooltip: t(
|
||||||
|
'Margin required for arising positions based on liquidity commitment'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('24h Fees'),
|
||||||
|
field: 'fees',
|
||||||
|
headerTooltip: t(
|
||||||
|
'Total fees earned by the liquidity provider in the last 24 hours'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('Fee level'),
|
||||||
|
valueFormatter: ({ value }: { value?: string | null }) => `${value}%`,
|
||||||
|
field: 'fee',
|
||||||
|
headerTooltip: t(
|
||||||
|
"The market's liquidity fee, or the percentage of a trade's value which is collected from the price taker for every trade"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
headerName: t('APY'),
|
||||||
|
field: 'apy',
|
||||||
|
headerTooltip: t(
|
||||||
|
'An annualised estimate based on the total liquidity provision fees and maker fees collected by liquidity providers, the maximum margin needed and maximum commitment (bond) over the course of 7 epochs'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[settlementAsset]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid
|
||||||
|
rowData={liquidityProviders}
|
||||||
|
tooltipShowDelay={500}
|
||||||
|
defaultColDef={{
|
||||||
|
resizable: true,
|
||||||
|
sortable: true,
|
||||||
|
unSortIcon: true,
|
||||||
|
cellClass: ['flex', 'flex-col', 'justify-center'],
|
||||||
|
tooltipComponent: TooltipCellComponent,
|
||||||
|
minWidth: 100,
|
||||||
|
}}
|
||||||
|
columnDefs={columnDefs}
|
||||||
|
getRowId={getRowId}
|
||||||
|
rowHeight={92}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,50 @@
|
|||||||
|
.ag-theme-alpine {
|
||||||
|
--ag-line-height: 24px;
|
||||||
|
--ag-row-hover-color: transparent;
|
||||||
|
--ag-header-background-color: transparent;
|
||||||
|
--ag-odd-row-background-color: transparent;
|
||||||
|
--ag-header-foreground-color: #626262;
|
||||||
|
--ag-secondary-foreground-color: #626262;
|
||||||
|
--ag-font-size: 16px;
|
||||||
|
--ag-background-color: transparent;
|
||||||
|
--ag-range-selection-border-color: transparent;
|
||||||
|
|
||||||
|
font-family: AlphaLyrae, Helvetica Neue, -apple-system, BlinkMacSystemFont,
|
||||||
|
Segoe UI, Roboto, Arial, Noto Sans, sans-serif, Apple Color Emoji,
|
||||||
|
Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
|
||||||
|
font-feature-settings: 'liga' off, 'calt' off;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-theme-alpine .ag-cell {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-theme-alpine .ag-header {
|
||||||
|
border-bottom: 1px solid #a7a7a7;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-theme-alpine .ag-root-wrapper {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-theme-alpine .ag-header-row {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-theme-alpine .ag-row {
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid #bfccd6;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-theme-alpine .ag-root-wrapper-body.ag-layout-normal {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-theme-alpine.row-hover .ag-row:hover {
|
||||||
|
background: #f0f0f0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
import { useRef, useCallback, useEffect } from 'react';
|
||||||
|
import { AgGridReact } from 'ag-grid-react';
|
||||||
|
import {
|
||||||
|
type AgGridReactProps,
|
||||||
|
type AgReactUiProps,
|
||||||
|
type AgGridReact as AgGridReactType,
|
||||||
|
} from 'ag-grid-react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import 'ag-grid-community/styles/ag-grid.css';
|
||||||
|
import 'ag-grid-community/styles/ag-theme-alpine.css';
|
||||||
|
|
||||||
|
import './grid.scss';
|
||||||
|
|
||||||
|
type Props = (AgGridReactProps | AgReactUiProps) & {
|
||||||
|
isRowClickable?: boolean;
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Grid = ({ isRowClickable, ...props }: Props) => {
|
||||||
|
const gridRef = useRef<AgGridReactType | null>(null);
|
||||||
|
|
||||||
|
const resizeGrid = useCallback(() => {
|
||||||
|
gridRef.current?.api?.sizeColumnsToFit();
|
||||||
|
}, [gridRef]);
|
||||||
|
|
||||||
|
const handleOnGridReady = useCallback(() => {
|
||||||
|
resizeGrid();
|
||||||
|
}, [resizeGrid]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.addEventListener('resize', resizeGrid);
|
||||||
|
return () => window.removeEventListener('resize', resizeGrid);
|
||||||
|
}, [resizeGrid]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AgGridReact
|
||||||
|
className={classNames('ag-theme-alpine font-alpha calt h-full', {
|
||||||
|
'row-hover': isRowClickable,
|
||||||
|
})}
|
||||||
|
rowHeight={92}
|
||||||
|
ref={gridRef}
|
||||||
|
onGridReady={handleOnGridReady}
|
||||||
|
suppressRowClickSelection
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './grid';
|
@ -0,0 +1,110 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { Dialog, HealthBar } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import * as Schema from '@vegaprotocol/types';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { intentForStatus } from '../../lib/utils';
|
||||||
|
|
||||||
|
interface HealthDialogProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
onChange: (isOpen: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ROWS = [
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
title: 'Continuous',
|
||||||
|
copy: 'Markets that have committed liquidity equal or greater than the target stake are trading continuously.',
|
||||||
|
data: {
|
||||||
|
status: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||||
|
target: '171320',
|
||||||
|
decimals: 5,
|
||||||
|
levels: [
|
||||||
|
{ fee: '0.6', commitmentAmount: 150000 },
|
||||||
|
{ fee: '1', commitmentAmount: 150000 },
|
||||||
|
{ fee: '2', commitmentAmount: 30000 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2',
|
||||||
|
title: 'Monitoring auction (liquidity)',
|
||||||
|
copy: 'Markets below the target stake will see trading suspended and go into liquidity auction.',
|
||||||
|
data: {
|
||||||
|
status: Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||||
|
target: '171320',
|
||||||
|
decimals: 5,
|
||||||
|
levels: [
|
||||||
|
{ fee: '0.6', commitmentAmount: 110000 },
|
||||||
|
{ fee: '1', commitmentAmount: 50000 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '3',
|
||||||
|
title: 'Opening auction',
|
||||||
|
copy: 'A newly created market looking for a target liquidity amount to start trading.',
|
||||||
|
data: {
|
||||||
|
status: Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
|
||||||
|
target: '171320',
|
||||||
|
decimals: 3,
|
||||||
|
levels: [
|
||||||
|
{ fee: '0.6', commitmentAmount: 110000 },
|
||||||
|
{ fee: '1', commitmentAmount: 50000 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const HealthDialog = ({ onChange, isOpen }: HealthDialogProps) => {
|
||||||
|
return (
|
||||||
|
<Dialog size="large" open={isOpen} onChange={onChange}>
|
||||||
|
<h1 className="text-2xl mb-5 pr-2 font-medium font-alpha uppercase">
|
||||||
|
{t('Health')}
|
||||||
|
</h1>
|
||||||
|
<p className="text-lg font-medium font-alpha mb-8">
|
||||||
|
{t(
|
||||||
|
'Market health is a representation of market and liquidity status and how close that market is to moving from one fee level to another.'
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table className="table-fixed">
|
||||||
|
<thead className="border-b border-greys-light-300">
|
||||||
|
<th className="w-1/2 text-left font-medium font-alpha text-base pb-4 uppercase">
|
||||||
|
{t('Market status')}
|
||||||
|
</th>
|
||||||
|
<th className="w-1/2 text-lef font-medium font-alpha text-base pb-4 uppercase">
|
||||||
|
{t('Liquidity status')}
|
||||||
|
</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{ROWS.map((r, index) => {
|
||||||
|
const isFirstRow = index === 0;
|
||||||
|
return (
|
||||||
|
<tr key={r.key}>
|
||||||
|
<td
|
||||||
|
className={classNames('pr-4 pb-10', { 'pt-8': isFirstRow })}
|
||||||
|
>
|
||||||
|
<h2 className="font-medium font-alpha uppercase text-base">
|
||||||
|
{t(r.title)}
|
||||||
|
</h2>
|
||||||
|
<p className="font-medium font-alpha text-lg">{t(r.copy)}</p>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
className={classNames('pl-4 pb-10', { 'pt-8': isFirstRow })}
|
||||||
|
>
|
||||||
|
<HealthBar
|
||||||
|
size="large"
|
||||||
|
levels={r.data.levels}
|
||||||
|
target={r.data.target}
|
||||||
|
decimals={r.data.decimals}
|
||||||
|
intent={intentForStatus(r.data.status)}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './health-dialog';
|
@ -0,0 +1 @@
|
|||||||
|
export * from './indicator';
|
@ -0,0 +1,24 @@
|
|||||||
|
import type * as Schema from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
import { getColorForStatus } from '../../lib/utils';
|
||||||
|
|
||||||
|
export const Indicator = ({
|
||||||
|
status,
|
||||||
|
opacity,
|
||||||
|
}: {
|
||||||
|
status?: Schema.MarketTradingMode;
|
||||||
|
opacity?: number;
|
||||||
|
}) => {
|
||||||
|
const backgroundColor = status ? getColorForStatus(status) : undefined;
|
||||||
|
return (
|
||||||
|
<div className="inline-block w-2 h-2 mr-1 rounded-full bg-white overflow-hidden shrink-0">
|
||||||
|
<div
|
||||||
|
className="h-full bg-black"
|
||||||
|
style={{
|
||||||
|
opacity,
|
||||||
|
backgroundColor,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,35 @@
|
|||||||
|
.ag-theme-alpine {
|
||||||
|
--ag-line-height: 24px;
|
||||||
|
--ag-row-hover-color: transparent;
|
||||||
|
--ag-header-background-color: #f5f5f5;
|
||||||
|
--ag-odd-row-background-color: transparent;
|
||||||
|
--ag-header-foreground-color: #000;
|
||||||
|
--ag-secondary-foreground-color: #fff;
|
||||||
|
--ag-font-family: 'Helvetica Neue';
|
||||||
|
--ag-font-size: 12px;
|
||||||
|
|
||||||
|
font-family: 'Helvetica Neue', -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
||||||
|
Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-theme-alpine .ag-cell {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-theme-alpine .ag-header {
|
||||||
|
border: 1px solid #bfccd6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-theme-alpine .ag-root-wrapper {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-theme-alpine .ag-row {
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid #bfccd6;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-theme-alpine .ag-root-wrapper-body.ag-layout-normal {
|
||||||
|
height: auto;
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
export * from './navbar';
|
@ -0,0 +1,15 @@
|
|||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { VegaLogo } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
|
export const Navbar = () => {
|
||||||
|
return (
|
||||||
|
<div className="px-8 py-4 flex items-stretch border-b border-greys-light-200">
|
||||||
|
<div className="flex gap-4 mr-4 items-center h-full">
|
||||||
|
<Link to="/">
|
||||||
|
<VegaLogo />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2 ml-auto"></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './status';
|
@ -0,0 +1,96 @@
|
|||||||
|
import { Lozenge, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import * as Schema from '@vegaprotocol/types';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
import { Indicator } from '../indicator';
|
||||||
|
import type { AuctionTrigger } from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
export const Status = ({
|
||||||
|
tradingMode,
|
||||||
|
trigger,
|
||||||
|
size = 'small',
|
||||||
|
}: {
|
||||||
|
tradingMode?: Schema.MarketTradingMode;
|
||||||
|
trigger?: Schema.AuctionTrigger;
|
||||||
|
size?: 'small' | 'large';
|
||||||
|
}) => {
|
||||||
|
const getStatus = () => {
|
||||||
|
if (!tradingMode) return '';
|
||||||
|
if (
|
||||||
|
tradingMode === Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
trigger &&
|
||||||
|
trigger !== Schema.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED
|
||||||
|
) {
|
||||||
|
return `${Schema.MarketTradingModeMapping[tradingMode]} - ${Schema.AuctionTriggerMapping[trigger]}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Schema.MarketTradingModeMapping[tradingMode];
|
||||||
|
};
|
||||||
|
|
||||||
|
const status = getStatus();
|
||||||
|
const tooltipDescription =
|
||||||
|
tradingMode && getTooltipDescription(tradingMode, trigger);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Tooltip description={tooltipDescription}>
|
||||||
|
<div
|
||||||
|
className={classNames('inline-flex whitespace-normal', {
|
||||||
|
'text-base': size === 'large',
|
||||||
|
'text-sm': size === 'small',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Lozenge className="border border-greys-light-300 bg-greys-light-100 flex items-center">
|
||||||
|
<Indicator status={tradingMode} />
|
||||||
|
{status}
|
||||||
|
</Lozenge>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTooltipDescription = (
|
||||||
|
status: Schema.MarketTradingMode,
|
||||||
|
trigger?: Schema.AuctionTrigger
|
||||||
|
) => {
|
||||||
|
switch (status) {
|
||||||
|
case Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS:
|
||||||
|
return t(
|
||||||
|
'This is the standard trading mode where trades are executed whenever orders are received'
|
||||||
|
);
|
||||||
|
case Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION:
|
||||||
|
return getMonitoringDescriptionTooltip(trigger);
|
||||||
|
case Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION:
|
||||||
|
return t(
|
||||||
|
'This is a new market in an opening auction to determine a fair mid-price before starting continuous trading.'
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMonitoringDescriptionTooltip = (trigger?: AuctionTrigger) => {
|
||||||
|
switch (trigger) {
|
||||||
|
case Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET:
|
||||||
|
return t(
|
||||||
|
`This market is in auction until it reaches sufficient liquidity.`
|
||||||
|
);
|
||||||
|
case Schema.AuctionTrigger.AUCTION_TRIGGER_UNABLE_TO_DEPLOY_LP_ORDERS:
|
||||||
|
return t(
|
||||||
|
`This market may have sufficient liquidity but there are not enough priced limit orders in the order book, which are required to deploy liquidity commitment pegged orders.`
|
||||||
|
);
|
||||||
|
case Schema.AuctionTrigger.AUCTION_TRIGGER_PRICE:
|
||||||
|
return t(`This market is in auction due to high price volatility.`);
|
||||||
|
case Schema.AuctionTrigger.AUCTION_TRIGGER_OPENING:
|
||||||
|
return t(
|
||||||
|
`This is a new market in an opening auction to determine a fair mid-price before starting continuous trading`
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
28
apps/liquidity-provision-dashboard/src/app/lib/utils.tsx
Normal file
28
apps/liquidity-provision-dashboard/src/app/lib/utils.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import * as Schema from '@vegaprotocol/types';
|
||||||
|
import { Intent } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
|
const marketTradingModeStyle = {
|
||||||
|
[Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS]: '#00D46E',
|
||||||
|
[Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION]: '#CF0064',
|
||||||
|
[Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION]: '#0046CD',
|
||||||
|
[Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION]: '#CF0064',
|
||||||
|
[Schema.MarketTradingMode.TRADING_MODE_NO_TRADING]: '#CF0064',
|
||||||
|
[Schema.MarketTradingMode.TRADING_MODE_SUSPENDED_VIA_GOVERNANCE]: '#CF0064',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getColorForStatus = (status: Schema.MarketTradingMode) =>
|
||||||
|
marketTradingModeStyle[status];
|
||||||
|
|
||||||
|
const marketTradingModeIntent = {
|
||||||
|
[Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS]: Intent.Success,
|
||||||
|
[Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION]: Intent.Danger,
|
||||||
|
[Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION]: Intent.Primary,
|
||||||
|
[Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION]: Intent.Danger,
|
||||||
|
[Schema.MarketTradingMode.TRADING_MODE_NO_TRADING]: Intent.Danger,
|
||||||
|
[Schema.MarketTradingMode.TRADING_MODE_SUSPENDED_VIA_GOVERNANCE]:
|
||||||
|
Intent.Danger,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const intentForStatus = (status: Schema.MarketTradingMode) => {
|
||||||
|
return marketTradingModeIntent[status];
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './router-config';
|
@ -0,0 +1,25 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
import { Dashboard } from '../components/dashboard';
|
||||||
|
import { Detail } from '../components/detail';
|
||||||
|
|
||||||
|
export const ROUTES = {
|
||||||
|
MARKETS: 'markets',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const routerConfig = [
|
||||||
|
{ path: '/', element: <Dashboard />, icon: '' },
|
||||||
|
{
|
||||||
|
path: ROUTES.MARKETS,
|
||||||
|
name: 'Markets',
|
||||||
|
text: t('Markets'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: ':marketId',
|
||||||
|
element: <Detail />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
icon: 'trade',
|
||||||
|
isNavItem: true,
|
||||||
|
},
|
||||||
|
];
|
@ -0,0 +1,3 @@
|
|||||||
|
export const environment = {
|
||||||
|
production: true,
|
||||||
|
};
|
@ -0,0 +1,6 @@
|
|||||||
|
// This file can be replaced during build by using the `fileReplacements` array.
|
||||||
|
// When building for production, this file is replaced with `environment.prod.ts`.
|
||||||
|
|
||||||
|
export const environment = {
|
||||||
|
production: false,
|
||||||
|
};
|
BIN
apps/liquidity-provision-dashboard/src/favicon.ico
Normal file
BIN
apps/liquidity-provision-dashboard/src/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
23
apps/liquidity-provision-dashboard/src/index.html
Normal file
23
apps/liquidity-provision-dashboard/src/index.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Liquidity Provision Dashboard</title>
|
||||||
|
<base href="/" />
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="https://static.vega.xyz/AlphaLyrae-Medium.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://static.vega.xyz/fonts.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root" class="h-full max-h-full min-h-full"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
15
apps/liquidity-provision-dashboard/src/main.tsx
Normal file
15
apps/liquidity-provision-dashboard/src/main.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { StrictMode } from 'react';
|
||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
import App from './app/app';
|
||||||
|
|
||||||
|
const rootElement = document.getElementById('root');
|
||||||
|
const root = rootElement && createRoot(rootElement);
|
||||||
|
root?.render(
|
||||||
|
<StrictMode>
|
||||||
|
<BrowserRouter>
|
||||||
|
<App />
|
||||||
|
</BrowserRouter>
|
||||||
|
</StrictMode>
|
||||||
|
);
|
7
apps/liquidity-provision-dashboard/src/polyfills.ts
Normal file
7
apps/liquidity-provision-dashboard/src/polyfills.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* Polyfill stable language features. These imports will be optimized by `@babel/preset-env`.
|
||||||
|
*
|
||||||
|
* See: https://github.com/zloirock/core-js#babel
|
||||||
|
*/
|
||||||
|
import 'core-js/stable';
|
||||||
|
import 'regenerator-runtime/runtime';
|
10
apps/liquidity-provision-dashboard/src/styles.scss
Normal file
10
apps/liquidity-provision-dashboard/src/styles.scss
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
@apply h-full;
|
||||||
|
|
||||||
|
font-family: 'Helvetica Neue', Helvetica, sans-serif;
|
||||||
|
}
|
29
apps/liquidity-provision-dashboard/tailwind.config.js
Normal file
29
apps/liquidity-provision-dashboard/tailwind.config.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
const { join } = require('path');
|
||||||
|
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
|
||||||
|
const theme = require('../../libs/tailwindcss-config/src/theme-lite');
|
||||||
|
const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes');
|
||||||
|
const vegaCustomClassesLite = require('../../libs/tailwindcss-config/src/vega-custom-classes-lite');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
content: [
|
||||||
|
join(__dirname, 'src/**/*.{js,ts,jsx,tsx}'),
|
||||||
|
'libs/ui-toolkit/src/utils/shared.ts',
|
||||||
|
...createGlobPatternsForDependencies(__dirname),
|
||||||
|
],
|
||||||
|
darkMode: 'class',
|
||||||
|
theme: {
|
||||||
|
...theme,
|
||||||
|
colors: {
|
||||||
|
...theme.colors,
|
||||||
|
greys: {
|
||||||
|
light: {
|
||||||
|
100: '#F0F0F0',
|
||||||
|
200: '#D2D2D2',
|
||||||
|
300: '#A7A7A7',
|
||||||
|
400: '#626262',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [vegaCustomClasses, vegaCustomClassesLite],
|
||||||
|
};
|
27
apps/liquidity-provision-dashboard/tsconfig.app.json
Normal file
27
apps/liquidity-provision-dashboard/tsconfig.app.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../dist/out-tsc",
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
"@nx/react/typings/cssmodule.d.ts",
|
||||||
|
"@nx/react/typings/image.d.ts"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
|
||||||
|
"../../node_modules/@nx/react/typings/image.d.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.test.ts",
|
||||||
|
"**/*.spec.tsx",
|
||||||
|
"**/*.test.tsx",
|
||||||
|
"**/*.spec.js",
|
||||||
|
"**/*.test.js",
|
||||||
|
"**/*.spec.jsx",
|
||||||
|
"**/*.test.jsx"
|
||||||
|
],
|
||||||
|
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
|
||||||
|
}
|
24
apps/liquidity-provision-dashboard/tsconfig.json
Normal file
24
apps/liquidity-provision-dashboard/tsconfig.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"allowJs": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": false,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
33
apps/liquidity-provision-dashboard/tsconfig.spec.json
Normal file
33
apps/liquidity-provision-dashboard/tsconfig.spec.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../dist/out-tsc",
|
||||||
|
"module": "commonjs",
|
||||||
|
"types": [
|
||||||
|
"jest",
|
||||||
|
"node",
|
||||||
|
"@testing-library/jest-dom",
|
||||||
|
"@nx/react/typings/cssmodule.d.ts",
|
||||||
|
"@nx/react/typings/image.d.ts"
|
||||||
|
],
|
||||||
|
"jsx": "react",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"**/*.test.ts",
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.test.tsx",
|
||||||
|
"**/*.spec.tsx",
|
||||||
|
"**/*.test.js",
|
||||||
|
"**/*.spec.js",
|
||||||
|
"**/*.test.jsx",
|
||||||
|
"**/*.spec.jsx",
|
||||||
|
"**/*.d.ts"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
|
||||||
|
"../../node_modules/@nx/react/typings/image.d.ts"
|
||||||
|
]
|
||||||
|
}
|
@ -1,9 +1,7 @@
|
|||||||
const { join } = require('path');
|
const { join } = require('path');
|
||||||
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
|
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
|
||||||
const { theme } = require('../../libs/tailwindcss-config/src/theme');
|
const theme = require('../../libs/tailwindcss-config/src/theme');
|
||||||
const {
|
const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes');
|
||||||
vegaCustomClasses,
|
|
||||||
} = require('../../libs/tailwindcss-config/src/vega-custom-classes');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: [
|
content: [
|
||||||
|
BIN
apps/trading/assets/apple-touch-icon.png
Normal file
BIN
apps/trading/assets/apple-touch-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
apps/trading/assets/logo.png
Normal file
BIN
apps/trading/assets/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 547 B |
BIN
apps/trading/assets/logo192.png
Normal file
BIN
apps/trading/assets/logo192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
22
apps/trading/assets/manifest.json
Normal file
22
apps/trading/assets/manifest.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "Vega Protocol - Trading",
|
||||||
|
"short_name": "Console",
|
||||||
|
"description": "Vega Protocol - Trading dApp",
|
||||||
|
"start_url": "/",
|
||||||
|
"display": "standalone",
|
||||||
|
"orientation": "portrait",
|
||||||
|
"theme_color": "#000000",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "favicon.ico",
|
||||||
|
"sizes": "64x64 32x32 24x24 16x16",
|
||||||
|
"type": "image/x-icon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "logo192.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "192x192"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,126 +1,63 @@
|
|||||||
import type { InMemoryCacheConfig } from '@apollo/client';
|
import type { InMemoryCacheConfig } from '@apollo/client';
|
||||||
import {
|
import {
|
||||||
|
AppFailure,
|
||||||
AppLoader,
|
AppLoader,
|
||||||
NetworkLoader,
|
NetworkLoader,
|
||||||
|
NodeFailure,
|
||||||
|
NodeGuard,
|
||||||
useEnvironment,
|
useEnvironment,
|
||||||
useNodeSwitcherStore,
|
|
||||||
} from '@vegaprotocol/environment';
|
} from '@vegaprotocol/environment';
|
||||||
import { useEffect, type ReactNode, useState } from 'react';
|
import { type ReactNode } from 'react';
|
||||||
import { Web3Provider } from './web3-provider';
|
import { Web3Provider } from './web3-provider';
|
||||||
import { useT } from '../../lib/use-t';
|
import { useT } from '../../lib/use-t';
|
||||||
import { DataLoader } from './data-loader';
|
import { DataLoader } from './data-loader';
|
||||||
import { WalletProvider } from '@vegaprotocol/wallet-react';
|
import { WalletProvider } from '@vegaprotocol/wallet-react';
|
||||||
import { useVegaWalletConfig } from '../../lib/hooks/use-vega-wallet-config';
|
import { useVegaWalletConfig } from '../../lib/hooks/use-vega-wallet-config';
|
||||||
import { Trans } from 'react-i18next';
|
|
||||||
import { Button, Loader, Splash, VLogo } from '@vegaprotocol/ui-toolkit';
|
|
||||||
|
|
||||||
const Failure = ({ reason }: { reason?: ReactNode }) => {
|
|
||||||
const t = useT();
|
|
||||||
const setNodeSwitcher = useNodeSwitcherStore((store) => store.setDialogOpen);
|
|
||||||
return (
|
|
||||||
<Splash>
|
|
||||||
<div className="border border-vega-red m-10 mx-auto w-4/5 max-w-3xl rounded-lg overflow-hidden animate-shake">
|
|
||||||
<div className="bg-vega-red text-white px-2 py-2 flex gap-1 items-center font-alpha calt uppercase">
|
|
||||||
<VLogo className="h-4" />
|
|
||||||
<span className="text-lg">{t('Failed to initialize the app')}</span>
|
|
||||||
</div>
|
|
||||||
<div className="p-4 text-left text-sm">
|
|
||||||
<p className="mb-4">{reason}</p>
|
|
||||||
<div className="text-center">
|
|
||||||
<Button className="border-2" onClick={() => setNodeSwitcher(true)}>
|
|
||||||
{t('Change node')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Splash>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Loading = () => {
|
|
||||||
const [showSlowNotification, setShowSlowNotification] = useState(false);
|
|
||||||
const t = useT();
|
|
||||||
const setNodeSwitcher = useNodeSwitcherStore((store) => store.setDialogOpen);
|
|
||||||
useEffect(() => {
|
|
||||||
const to = setTimeout(() => {
|
|
||||||
if (!showSlowNotification) setShowSlowNotification(true);
|
|
||||||
}, 5000);
|
|
||||||
return () => {
|
|
||||||
clearTimeout(to);
|
|
||||||
};
|
|
||||||
}, [showSlowNotification]);
|
|
||||||
return (
|
|
||||||
<Splash>
|
|
||||||
<div className="border border-transparent m-10 mx-auto w-4/5 max-w-3xl rounded-lg overflow-hidden">
|
|
||||||
<div className="mt-11 p-4 text-left text-sm">
|
|
||||||
<Loader />
|
|
||||||
{showSlowNotification && (
|
|
||||||
<>
|
|
||||||
<p className="mt-4 text-center">
|
|
||||||
{t(
|
|
||||||
"It looks like you're connection is slow, try switching to another node."
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
<div className="mt-4 text-center">
|
|
||||||
<Button
|
|
||||||
className="border-2"
|
|
||||||
onClick={() => setNodeSwitcher(true)}
|
|
||||||
>
|
|
||||||
{t('Change node')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Splash>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Bootstrapper = ({ children }: { children: ReactNode }) => {
|
export const Bootstrapper = ({ children }: { children: ReactNode }) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
const { error, VEGA_URL } = useEnvironment();
|
||||||
const { error, VEGA_URL } = useEnvironment((state) => ({
|
|
||||||
error: state.error,
|
|
||||||
VEGA_URL: state.VEGA_URL,
|
|
||||||
}));
|
|
||||||
const config = useVegaWalletConfig();
|
const config = useVegaWalletConfig();
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
return <AppLoader />;
|
return <AppLoader />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ERR_DATA_LOADER = (
|
|
||||||
<Trans
|
|
||||||
i18nKey="It appears that the connection to the node <0>{{VEGA_URL}}</0> does not return necessary data, try switching to another node."
|
|
||||||
components={[
|
|
||||||
<span key="vega" className="text-muted">
|
|
||||||
{VEGA_URL}
|
|
||||||
</span>,
|
|
||||||
]}
|
|
||||||
values={{
|
|
||||||
VEGA_URL,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NetworkLoader
|
<NetworkLoader
|
||||||
cache={cacheConfig}
|
cache={cacheConfig}
|
||||||
skeleton={<Loading />}
|
skeleton={<AppLoader />}
|
||||||
failure={<Failure reason={error} />}
|
failure={
|
||||||
|
<AppFailure title={t('Could not initialize app')} error={error} />
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<DataLoader
|
<NodeGuard
|
||||||
skeleton={<Loading />}
|
skeleton={<AppLoader />}
|
||||||
failure={<Failure reason={ERR_DATA_LOADER} />}
|
failure={
|
||||||
|
<NodeFailure
|
||||||
|
title={t('Node: {{VEGA_URL}} is unsuitable', { VEGA_URL })}
|
||||||
|
/>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Web3Provider
|
<DataLoader
|
||||||
skeleton={<Loading />}
|
skeleton={<AppLoader />}
|
||||||
failure={<Failure reason={t('Could not configure web3 provider')} />}
|
failure={
|
||||||
|
<AppFailure
|
||||||
|
title={t('Could not load market data or asset data')}
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<WalletProvider config={config}>{children}</WalletProvider>
|
<Web3Provider
|
||||||
</Web3Provider>
|
skeleton={<AppLoader />}
|
||||||
</DataLoader>
|
failure={
|
||||||
|
<AppFailure title={t('Could not configure web3 provider')} />
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<WalletProvider config={config}>{children}</WalletProvider>
|
||||||
|
</Web3Provider>
|
||||||
|
</DataLoader>
|
||||||
|
</NodeGuard>
|
||||||
</NetworkLoader>
|
</NetworkLoader>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -170,9 +107,6 @@ const cacheConfig: InMemoryCacheConfig = {
|
|||||||
Fees: {
|
Fees: {
|
||||||
keyFields: false,
|
keyFields: false,
|
||||||
},
|
},
|
||||||
PartyProfile: {
|
|
||||||
keyFields: ['partyId'],
|
|
||||||
},
|
|
||||||
// The folling types are cached by the data provider and not by apollo
|
// The folling types are cached by the data provider and not by apollo
|
||||||
PositionUpdate: {
|
PositionUpdate: {
|
||||||
keyFields: false,
|
keyFields: false,
|
||||||
|
@ -30,6 +30,8 @@ export const ChartContainer = ({ marketId }: { marketId: string }) => {
|
|||||||
setStudies,
|
setStudies,
|
||||||
setStudySizes,
|
setStudySizes,
|
||||||
setOverlays,
|
setOverlays,
|
||||||
|
state,
|
||||||
|
setState,
|
||||||
} = useChartSettings();
|
} = useChartSettings();
|
||||||
|
|
||||||
const pennantChart = (
|
const pennantChart = (
|
||||||
@ -66,6 +68,10 @@ export const ChartContainer = ({ marketId }: { marketId: string }) => {
|
|||||||
onIntervalChange={(newInterval) => {
|
onIntervalChange={(newInterval) => {
|
||||||
setInterval(fromTradingViewResolution(newInterval));
|
setInterval(fromTradingViewResolution(newInterval));
|
||||||
}}
|
}}
|
||||||
|
onAutoSaveNeeded={(data) => {
|
||||||
|
setState(data);
|
||||||
|
}}
|
||||||
|
state={state}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,7 @@ export const SUPPORTED_INTERVALS = [
|
|||||||
Interval.INTERVAL_I1M,
|
Interval.INTERVAL_I1M,
|
||||||
Interval.INTERVAL_I5M,
|
Interval.INTERVAL_I5M,
|
||||||
Interval.INTERVAL_I15M,
|
Interval.INTERVAL_I15M,
|
||||||
Interval.INTERVAL_I30M,
|
|
||||||
Interval.INTERVAL_I1H,
|
Interval.INTERVAL_I1H,
|
||||||
Interval.INTERVAL_I4H,
|
|
||||||
Interval.INTERVAL_I6H,
|
Interval.INTERVAL_I6H,
|
||||||
Interval.INTERVAL_I8H,
|
|
||||||
Interval.INTERVAL_I12H,
|
|
||||||
Interval.INTERVAL_I1D,
|
Interval.INTERVAL_I1D,
|
||||||
Interval.INTERVAL_I7D,
|
|
||||||
] as const;
|
] as const;
|
||||||
|
@ -9,6 +9,7 @@ type StudySizes = { [S in Study]?: number };
|
|||||||
export type Chartlib = 'pennant' | 'tradingview';
|
export type Chartlib = 'pennant' | 'tradingview';
|
||||||
|
|
||||||
interface StoredSettings {
|
interface StoredSettings {
|
||||||
|
state: object | undefined; // Don't see a better type provided from TradingView type definitions
|
||||||
chartlib: Chartlib;
|
chartlib: Chartlib;
|
||||||
// For interval we use the enum from @vegaprotocol/types, this is to make mapping between different
|
// For interval we use the enum from @vegaprotocol/types, this is to make mapping between different
|
||||||
// chart types easier and more consistent
|
// chart types easier and more consistent
|
||||||
@ -29,6 +30,7 @@ const STUDY_ORDER: Study[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const DEFAULT_CHART_SETTINGS = {
|
export const DEFAULT_CHART_SETTINGS = {
|
||||||
|
state: undefined,
|
||||||
chartlib: 'pennant' as const,
|
chartlib: 'pennant' as const,
|
||||||
interval: Interval.INTERVAL_I15M,
|
interval: Interval.INTERVAL_I15M,
|
||||||
type: ChartType.CANDLE,
|
type: ChartType.CANDLE,
|
||||||
@ -45,6 +47,7 @@ export const useChartSettingsStore = create<
|
|||||||
setStudies: (studies?: Study[]) => void;
|
setStudies: (studies?: Study[]) => void;
|
||||||
setStudySizes: (sizes: number[]) => void;
|
setStudySizes: (sizes: number[]) => void;
|
||||||
setChartlib: (lib: Chartlib) => void;
|
setChartlib: (lib: Chartlib) => void;
|
||||||
|
setState: (state: object) => void;
|
||||||
}
|
}
|
||||||
>()(
|
>()(
|
||||||
persist(
|
persist(
|
||||||
@ -92,6 +95,9 @@ export const useChartSettingsStore = create<
|
|||||||
state.chartlib = lib;
|
state.chartlib = lib;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
setState: (state) => {
|
||||||
|
set({ state });
|
||||||
|
},
|
||||||
})),
|
})),
|
||||||
{
|
{
|
||||||
name: 'vega_candles_chart_store',
|
name: 'vega_candles_chart_store',
|
||||||
@ -145,5 +151,7 @@ export const useChartSettings = () => {
|
|||||||
setOverlays: settings.setOverlays,
|
setOverlays: settings.setOverlays,
|
||||||
setStudySizes: settings.setStudySizes,
|
setStudySizes: settings.setStudySizes,
|
||||||
setChartlib: settings.setChartlib,
|
setChartlib: settings.setChartlib,
|
||||||
|
state: settings.state,
|
||||||
|
setState: settings.setState,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -8,12 +8,6 @@ import {
|
|||||||
mockConfig,
|
mockConfig,
|
||||||
MockedWalletProvider,
|
MockedWalletProvider,
|
||||||
} from '@vegaprotocol/wallet-react/testing';
|
} from '@vegaprotocol/wallet-react/testing';
|
||||||
import { MockedProvider, type MockedResponse } from '@apollo/react-testing';
|
|
||||||
import {
|
|
||||||
PartyProfilesDocument,
|
|
||||||
type PartyProfilesQuery,
|
|
||||||
type PartyProfilesQueryVariables,
|
|
||||||
} from '../vega-wallet-connect-button/__generated__/PartyProfiles';
|
|
||||||
|
|
||||||
jest.mock('@vegaprotocol/proposals', () => ({
|
jest.mock('@vegaprotocol/proposals', () => ({
|
||||||
ProtocolUpgradeCountdown: () => null,
|
ProtocolUpgradeCountdown: () => null,
|
||||||
@ -30,45 +24,15 @@ describe('Navbar', () => {
|
|||||||
publicKey: '2'.repeat(64),
|
publicKey: '2'.repeat(64),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const key1Alias = 'key 1 alias';
|
|
||||||
const marketId = 'abc';
|
const marketId = 'abc';
|
||||||
const navbarContent = 'navbar-menu-content';
|
const navbarContent = 'navbar-menu-content';
|
||||||
|
|
||||||
const partyProfilesMock: MockedResponse<
|
|
||||||
PartyProfilesQuery,
|
|
||||||
PartyProfilesQueryVariables
|
|
||||||
> = {
|
|
||||||
request: {
|
|
||||||
query: PartyProfilesDocument,
|
|
||||||
variables: {
|
|
||||||
partyIds: mockKeys.map((k) => k.publicKey),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
partiesProfilesConnection: {
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
node: {
|
|
||||||
partyId: mockKeys[0].publicKey,
|
|
||||||
alias: key1Alias,
|
|
||||||
metadata: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderComponent = (initialEntries?: string[]) => {
|
const renderComponent = (initialEntries?: string[]) => {
|
||||||
return render(
|
return render(
|
||||||
<MemoryRouter initialEntries={initialEntries}>
|
<MemoryRouter initialEntries={initialEntries}>
|
||||||
<MockedProvider mocks={[partyProfilesMock]}>
|
<MockedWalletProvider>
|
||||||
<MockedWalletProvider>
|
<Navbar />
|
||||||
<Navbar />
|
</MockedWalletProvider>
|
||||||
</MockedWalletProvider>
|
|
||||||
</MockedProvider>
|
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -176,7 +140,6 @@ describe('Navbar', () => {
|
|||||||
const activeKey = within(menu.getByTestId(/key-1+-mobile/));
|
const activeKey = within(menu.getByTestId(/key-1+-mobile/));
|
||||||
expect(activeKey.getByText(mockKeys[0].name)).toBeInTheDocument();
|
expect(activeKey.getByText(mockKeys[0].name)).toBeInTheDocument();
|
||||||
expect(activeKey.getByTestId('icon-tick')).toBeInTheDocument();
|
expect(activeKey.getByTestId('icon-tick')).toBeInTheDocument();
|
||||||
expect(screen.getByText(key1Alias)).toBeInTheDocument();
|
|
||||||
|
|
||||||
const inactiveKey = within(menu.getByTestId(/key-2+-mobile/));
|
const inactiveKey = within(menu.getByTestId(/key-2+-mobile/));
|
||||||
await userEvent.click(inactiveKey.getByText(mockKeys[1].name));
|
await userEvent.click(inactiveKey.getByText(mockKeys[1].name));
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export { ProfileDialog } from './profile-dialog';
|
|
@ -1,166 +0,0 @@
|
|||||||
import {
|
|
||||||
Dialog,
|
|
||||||
FormGroup,
|
|
||||||
Input,
|
|
||||||
InputError,
|
|
||||||
Intent,
|
|
||||||
TradingButton,
|
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { useProfileDialogStore } from '../../stores/profile-dialog-store';
|
|
||||||
import { useForm } from 'react-hook-form';
|
|
||||||
import { useT } from '../../lib/use-t';
|
|
||||||
import { useRequired } from '@vegaprotocol/utils';
|
|
||||||
import {
|
|
||||||
useSimpleTransaction,
|
|
||||||
type Status,
|
|
||||||
useVegaWallet,
|
|
||||||
} from '@vegaprotocol/wallet-react';
|
|
||||||
import {
|
|
||||||
usePartyProfilesQuery,
|
|
||||||
type PartyProfilesQuery,
|
|
||||||
} from '../vega-wallet-connect-button/__generated__/PartyProfiles';
|
|
||||||
|
|
||||||
export const ProfileDialog = () => {
|
|
||||||
const t = useT();
|
|
||||||
const { pubKeys } = useVegaWallet();
|
|
||||||
const { data, refetch } = usePartyProfilesQuery({
|
|
||||||
variables: { partyIds: pubKeys.map((pk) => pk.publicKey) },
|
|
||||||
skip: pubKeys.length <= 0,
|
|
||||||
});
|
|
||||||
const open = useProfileDialogStore((store) => store.open);
|
|
||||||
const pubKey = useProfileDialogStore((store) => store.pubKey);
|
|
||||||
const setOpen = useProfileDialogStore((store) => store.setOpen);
|
|
||||||
|
|
||||||
const profileEdge = data?.partiesProfilesConnection?.edges.find(
|
|
||||||
(e) => e.node.partyId === pubKey
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dialog
|
|
||||||
open={open}
|
|
||||||
onChange={() => {
|
|
||||||
setOpen(undefined);
|
|
||||||
}}
|
|
||||||
title={t('Edit profile')}
|
|
||||||
>
|
|
||||||
<ProfileFormContainer
|
|
||||||
profile={profileEdge?.node}
|
|
||||||
onSuccess={() => {
|
|
||||||
refetch();
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
setOpen(undefined);
|
|
||||||
}, 1000);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface FormFields {
|
|
||||||
alias: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type Profile = NonNullable<
|
|
||||||
PartyProfilesQuery['partiesProfilesConnection']
|
|
||||||
>['edges'][number]['node'];
|
|
||||||
|
|
||||||
const ProfileFormContainer = ({
|
|
||||||
profile,
|
|
||||||
onSuccess,
|
|
||||||
}: {
|
|
||||||
profile: Profile | undefined;
|
|
||||||
onSuccess: () => void;
|
|
||||||
}) => {
|
|
||||||
const { send, status, error } = useSimpleTransaction({ onSuccess });
|
|
||||||
const sendTx = (field: FormFields) => {
|
|
||||||
send({
|
|
||||||
updatePartyProfile: {
|
|
||||||
alias: field.alias,
|
|
||||||
metadata: [],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<ProfileForm
|
|
||||||
profile={profile}
|
|
||||||
status={status}
|
|
||||||
error={error}
|
|
||||||
onSubmit={sendTx}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ProfileForm = ({
|
|
||||||
profile,
|
|
||||||
onSubmit,
|
|
||||||
status,
|
|
||||||
error,
|
|
||||||
}: {
|
|
||||||
profile: Profile | undefined;
|
|
||||||
onSubmit: (fields: FormFields) => void;
|
|
||||||
status: Status;
|
|
||||||
error: string | undefined;
|
|
||||||
}) => {
|
|
||||||
const t = useT();
|
|
||||||
const required = useRequired();
|
|
||||||
const {
|
|
||||||
register,
|
|
||||||
handleSubmit,
|
|
||||||
formState: { errors },
|
|
||||||
} = useForm<FormFields>({
|
|
||||||
defaultValues: {
|
|
||||||
alias: profile?.alias,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const renderButtonText = () => {
|
|
||||||
if (status === 'requested') {
|
|
||||||
return t('Confirm in wallet...');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status === 'pending') {
|
|
||||||
return t('Confirming transaction...');
|
|
||||||
}
|
|
||||||
|
|
||||||
return t('Submit');
|
|
||||||
};
|
|
||||||
|
|
||||||
const errorMessage = errors.alias?.message || error;
|
|
||||||
|
|
||||||
if (status === 'confirmed') {
|
|
||||||
return (
|
|
||||||
<p className="mt-2 mb-4 text-sm text-vega-green-600 dark:text-vega-green">
|
|
||||||
{t('Profile updated')}
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className="mt-3">
|
|
||||||
<FormGroup label="Alias" labelFor="alias">
|
|
||||||
<Input
|
|
||||||
{...register('alias', {
|
|
||||||
validate: {
|
|
||||||
required,
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
{errorMessage && (
|
|
||||||
<InputError>
|
|
||||||
<p className="break-words max-w-full first-letter:uppercase">
|
|
||||||
{errorMessage}
|
|
||||||
</p>
|
|
||||||
</InputError>
|
|
||||||
)}
|
|
||||||
</FormGroup>
|
|
||||||
<TradingButton
|
|
||||||
type="submit"
|
|
||||||
intent={Intent.Info}
|
|
||||||
disabled={status === 'requested' || status === 'pending'}
|
|
||||||
>
|
|
||||||
{renderButtonText()}
|
|
||||||
</TradingButton>
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,14 +0,0 @@
|
|||||||
query PartyProfiles($partyIds: [ID!]) {
|
|
||||||
partiesProfilesConnection(ids: $partyIds) {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
partyId
|
|
||||||
alias
|
|
||||||
metadata {
|
|
||||||
key
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
import * as Types from '@vegaprotocol/types';
|
|
||||||
|
|
||||||
import { gql } from '@apollo/client';
|
|
||||||
import * as Apollo from '@apollo/client';
|
|
||||||
const defaultOptions = {} as const;
|
|
||||||
export type PartyProfilesQueryVariables = Types.Exact<{
|
|
||||||
partyIds?: Types.InputMaybe<Array<Types.Scalars['ID']> | Types.Scalars['ID']>;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
|
|
||||||
export type PartyProfilesQuery = { __typename?: 'Query', partiesProfilesConnection?: { __typename?: 'PartiesProfilesConnection', edges: Array<{ __typename?: 'PartyProfileEdge', node: { __typename?: 'PartyProfile', partyId: string, alias: string, metadata: Array<{ __typename?: 'Metadata', key: string, value: string }> } }> } | null };
|
|
||||||
|
|
||||||
|
|
||||||
export const PartyProfilesDocument = gql`
|
|
||||||
query PartyProfiles($partyIds: [ID!]) {
|
|
||||||
partiesProfilesConnection(ids: $partyIds) {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
partyId
|
|
||||||
alias
|
|
||||||
metadata {
|
|
||||||
key
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __usePartyProfilesQuery__
|
|
||||||
*
|
|
||||||
* To run a query within a React component, call `usePartyProfilesQuery` and pass it any options that fit your needs.
|
|
||||||
* When your component renders, `usePartyProfilesQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
|
||||||
* you can use to render your UI.
|
|
||||||
*
|
|
||||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const { data, loading, error } = usePartyProfilesQuery({
|
|
||||||
* variables: {
|
|
||||||
* partyIds: // value for 'partyIds'
|
|
||||||
* },
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
export function usePartyProfilesQuery(baseOptions?: Apollo.QueryHookOptions<PartyProfilesQuery, PartyProfilesQueryVariables>) {
|
|
||||||
const options = {...defaultOptions, ...baseOptions}
|
|
||||||
return Apollo.useQuery<PartyProfilesQuery, PartyProfilesQueryVariables>(PartyProfilesDocument, options);
|
|
||||||
}
|
|
||||||
export function usePartyProfilesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<PartyProfilesQuery, PartyProfilesQueryVariables>) {
|
|
||||||
const options = {...defaultOptions, ...baseOptions}
|
|
||||||
return Apollo.useLazyQuery<PartyProfilesQuery, PartyProfilesQueryVariables>(PartyProfilesDocument, options);
|
|
||||||
}
|
|
||||||
export type PartyProfilesQueryHookResult = ReturnType<typeof usePartyProfilesQuery>;
|
|
||||||
export type PartyProfilesLazyQueryHookResult = ReturnType<typeof usePartyProfilesLazyQuery>;
|
|
||||||
export type PartyProfilesQueryResult = Apollo.QueryResult<PartyProfilesQuery, PartyProfilesQueryVariables>;
|
|
@ -1,57 +1,21 @@
|
|||||||
import { act, fireEvent, render, screen, within } from '@testing-library/react';
|
import { act, fireEvent, render, screen } from '@testing-library/react';
|
||||||
import { VegaWalletConnectButton } from './vega-wallet-connect-button';
|
import { VegaWalletConnectButton } from './vega-wallet-connect-button';
|
||||||
|
import { truncateByChars } from '@vegaprotocol/utils';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import {
|
import {
|
||||||
mockConfig,
|
mockConfig,
|
||||||
MockedWalletProvider,
|
MockedWalletProvider,
|
||||||
} from '@vegaprotocol/wallet-react/testing';
|
} from '@vegaprotocol/wallet-react/testing';
|
||||||
import { MockedProvider, type MockedResponse } from '@apollo/react-testing';
|
|
||||||
import {
|
|
||||||
PartyProfilesDocument,
|
|
||||||
type PartyProfilesQuery,
|
|
||||||
} from './__generated__/PartyProfiles';
|
|
||||||
|
|
||||||
jest.mock('../../lib/hooks/use-get-current-route-id', () => ({
|
jest.mock('../../lib/hooks/use-get-current-route-id', () => ({
|
||||||
useGetCurrentRouteId: jest.fn().mockReturnValue('current-route-id'),
|
useGetCurrentRouteId: jest.fn().mockReturnValue('current-route-id'),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const key = { publicKey: '123456__123456', name: 'test' };
|
|
||||||
const key2 = { publicKey: 'abcdef__abcdef', name: 'test2' };
|
|
||||||
const keys = [key, key2];
|
|
||||||
const keyProfile = {
|
|
||||||
__typename: 'PartyProfile' as const,
|
|
||||||
partyId: key.publicKey,
|
|
||||||
alias: `${key.name} alias`,
|
|
||||||
metadata: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderComponent = (mockOnClick = jest.fn()) => {
|
const renderComponent = (mockOnClick = jest.fn()) => {
|
||||||
const partyProfilesMock: MockedResponse<PartyProfilesQuery> = {
|
|
||||||
request: {
|
|
||||||
query: PartyProfilesDocument,
|
|
||||||
variables: { partyIds: keys.map((k) => k.publicKey) },
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
partiesProfilesConnection: {
|
|
||||||
__typename: 'PartiesProfilesConnection',
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
__typename: 'PartyProfileEdge',
|
|
||||||
node: keyProfile,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MockedProvider mocks={[partyProfilesMock]}>
|
<MockedWalletProvider>
|
||||||
<MockedWalletProvider>
|
<VegaWalletConnectButton onClick={mockOnClick} />
|
||||||
<VegaWalletConnectButton onClick={mockOnClick} />
|
</MockedWalletProvider>
|
||||||
</MockedWalletProvider>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -79,6 +43,10 @@ describe('VegaWalletConnectButton', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should open dropdown and refresh keys when connected', async () => {
|
it('should open dropdown and refresh keys when connected', async () => {
|
||||||
|
const key = { publicKey: '123456__123456', name: 'test' };
|
||||||
|
const key2 = { publicKey: 'abcdef__abcdef', name: 'test2' };
|
||||||
|
const keys = [key, key2];
|
||||||
|
|
||||||
mockConfig.store.setState({
|
mockConfig.store.setState({
|
||||||
status: 'connected',
|
status: 'connected',
|
||||||
keys,
|
keys,
|
||||||
@ -93,22 +61,14 @@ describe('VegaWalletConnectButton', () => {
|
|||||||
|
|
||||||
expect(screen.queryByTestId('connect-vega-wallet')).not.toBeInTheDocument();
|
expect(screen.queryByTestId('connect-vega-wallet')).not.toBeInTheDocument();
|
||||||
const button = screen.getByTestId('manage-vega-wallet');
|
const button = screen.getByTestId('manage-vega-wallet');
|
||||||
expect(button).toHaveTextContent(key.name);
|
expect(button).toHaveTextContent(truncateByChars(key.publicKey));
|
||||||
|
|
||||||
fireEvent.click(button);
|
fireEvent.click(button);
|
||||||
|
|
||||||
expect(await screen.findByRole('menu')).toBeInTheDocument();
|
expect(await screen.findByRole('menu')).toBeInTheDocument();
|
||||||
const menuItems = await screen.findAllByRole('menuitemradio');
|
expect(await screen.findAllByRole('menuitemradio')).toHaveLength(
|
||||||
expect(menuItems).toHaveLength(keys.length);
|
keys.length
|
||||||
|
|
||||||
expect(within(menuItems[0]).getByTestId('alias')).toHaveTextContent(
|
|
||||||
keyProfile.alias
|
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(within(menuItems[1]).getByTestId('alias')).toHaveTextContent(
|
|
||||||
'No alias'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(refreshKeys).toHaveBeenCalled();
|
expect(refreshKeys).toHaveBeenCalled();
|
||||||
|
|
||||||
fireEvent.click(screen.getByTestId(`key-${key2.publicKey}`));
|
fireEvent.click(screen.getByTestId(`key-${key2.publicKey}`));
|
||||||
|
@ -14,7 +14,6 @@ import {
|
|||||||
TradingDropdownItem,
|
TradingDropdownItem,
|
||||||
TradingDropdownRadioItem,
|
TradingDropdownRadioItem,
|
||||||
TradingDropdownItemIndicator,
|
TradingDropdownItemIndicator,
|
||||||
Tooltip,
|
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { isBrowserWalletInstalled, type Key } from '@vegaprotocol/wallet';
|
import { isBrowserWalletInstalled, type Key } from '@vegaprotocol/wallet';
|
||||||
import { useDialogStore, useVegaWallet } from '@vegaprotocol/wallet-react';
|
import { useDialogStore, useVegaWallet } from '@vegaprotocol/wallet-react';
|
||||||
@ -23,8 +22,6 @@ import classNames from 'classnames';
|
|||||||
import { ViewType, useSidebar } from '../sidebar';
|
import { ViewType, useSidebar } from '../sidebar';
|
||||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||||
import { useT } from '../../lib/use-t';
|
import { useT } from '../../lib/use-t';
|
||||||
import { usePartyProfilesQuery } from './__generated__/PartyProfiles';
|
|
||||||
import { useProfileDialogStore } from '../../stores/profile-dialog-store';
|
|
||||||
|
|
||||||
export const VegaWalletConnectButton = ({
|
export const VegaWalletConnectButton = ({
|
||||||
intent = Intent.None,
|
intent = Intent.None,
|
||||||
@ -71,10 +68,10 @@ export const VegaWalletConnectButton = ({
|
|||||||
{activeKey ? (
|
{activeKey ? (
|
||||||
<>
|
<>
|
||||||
{activeKey && (
|
{activeKey && (
|
||||||
<span className="uppercase">
|
<span className="uppercase">{activeKey.name}</span>
|
||||||
{activeKey.name ? activeKey.name : t('Unnamed key')}
|
|
||||||
</span>
|
|
||||||
)}
|
)}
|
||||||
|
{' | '}
|
||||||
|
{truncateByChars(activeKey.publicKey)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>{'Select key'}</>
|
<>{'Select key'}</>
|
||||||
@ -91,12 +88,20 @@ export const VegaWalletConnectButton = ({
|
|||||||
onEscapeKeyDown={() => setDropdownOpen(false)}
|
onEscapeKeyDown={() => setDropdownOpen(false)}
|
||||||
>
|
>
|
||||||
<div className="min-w-[340px]" data-testid="keypair-list">
|
<div className="min-w-[340px]" data-testid="keypair-list">
|
||||||
<KeypairRadioGroup
|
<TradingDropdownRadioGroup
|
||||||
pubKey={pubKey}
|
value={pubKey || undefined}
|
||||||
pubKeys={pubKeys}
|
onValueChange={(value) => {
|
||||||
activeKey={activeKey?.publicKey}
|
selectPubKey(value);
|
||||||
onSelect={selectPubKey}
|
}}
|
||||||
/>
|
>
|
||||||
|
{pubKeys.map((pk) => (
|
||||||
|
<KeypairItem
|
||||||
|
key={pk.publicKey}
|
||||||
|
pk={pk}
|
||||||
|
active={pk.publicKey === pubKey}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</TradingDropdownRadioGroup>
|
||||||
<TradingDropdownSeparator />
|
<TradingDropdownSeparator />
|
||||||
{!isReadOnly && (
|
{!isReadOnly && (
|
||||||
<TradingDropdownItem
|
<TradingDropdownItem
|
||||||
@ -136,68 +141,28 @@ export const VegaWalletConnectButton = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const KeypairRadioGroup = ({
|
const KeypairItem = ({ pk, active }: { pk: Key; active: boolean }) => {
|
||||||
pubKey,
|
|
||||||
pubKeys,
|
|
||||||
activeKey,
|
|
||||||
onSelect,
|
|
||||||
}: {
|
|
||||||
pubKey: string | undefined;
|
|
||||||
pubKeys: Key[];
|
|
||||||
activeKey: string | undefined;
|
|
||||||
onSelect: (pubKey: string) => void;
|
|
||||||
}) => {
|
|
||||||
const { data } = usePartyProfilesQuery({
|
|
||||||
variables: { partyIds: pubKeys.map((pk) => pk.publicKey) },
|
|
||||||
skip: pubKeys.length <= 0,
|
|
||||||
fetchPolicy: 'cache-and-network',
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TradingDropdownRadioGroup value={pubKey} onValueChange={onSelect}>
|
|
||||||
{pubKeys.map((pk) => {
|
|
||||||
const profile = data?.partiesProfilesConnection?.edges.find(
|
|
||||||
(e) => e.node.partyId === pk.publicKey
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<KeypairItem
|
|
||||||
key={pk.publicKey}
|
|
||||||
pk={pk}
|
|
||||||
isActive={activeKey === pk.publicKey}
|
|
||||||
alias={profile?.node.alias}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TradingDropdownRadioGroup>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const KeypairItem = ({
|
|
||||||
pk,
|
|
||||||
isActive,
|
|
||||||
alias,
|
|
||||||
}: {
|
|
||||||
pk: Key;
|
|
||||||
alias: string | undefined;
|
|
||||||
isActive: boolean;
|
|
||||||
}) => {
|
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const [copied, setCopied] = useCopyTimeout();
|
const [copied, setCopied] = useCopyTimeout();
|
||||||
const setOpen = useProfileDialogStore((store) => store.setOpen);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TradingDropdownRadioItem value={pk.publicKey}>
|
<TradingDropdownRadioItem value={pk.publicKey}>
|
||||||
<div>
|
<div
|
||||||
<div className="flex items-center gap-2">
|
className={classNames('flex-1 mr-2', {
|
||||||
<span>{pk.name ? pk.name : t('Unnamed key')}</span>
|
'text-default': active,
|
||||||
|
'text-muted': !active,
|
||||||
|
})}
|
||||||
|
data-testid={`key-${pk.publicKey}`}
|
||||||
|
>
|
||||||
|
<span className={classNames('mr-2 uppercase')}>
|
||||||
|
{pk.name}
|
||||||
{' | '}
|
{' | '}
|
||||||
<span className="font-mono">
|
{truncateByChars(pk.publicKey)}
|
||||||
{truncateByChars(pk.publicKey, 3, 3)}
|
</span>
|
||||||
</span>
|
<span className="inline-flex items-center gap-1">
|
||||||
<CopyToClipboard text={pk.publicKey} onCopy={() => setCopied(true)}>
|
<CopyToClipboard text={pk.publicKey} onCopy={() => setCopied(true)}>
|
||||||
<button
|
<button
|
||||||
data-testid="copy-vega-public-key"
|
data-testid="copy-vega-public-key"
|
||||||
className="relative -top-px"
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
<span className="sr-only">{t('Copy')}</span>
|
<span className="sr-only">{t('Copy')}</span>
|
||||||
@ -205,22 +170,7 @@ const KeypairItem = ({
|
|||||||
</button>
|
</button>
|
||||||
</CopyToClipboard>
|
</CopyToClipboard>
|
||||||
{copied && <span className="text-xs">{t('Copied')}</span>}
|
{copied && <span className="text-xs">{t('Copied')}</span>}
|
||||||
</div>
|
</span>
|
||||||
<div
|
|
||||||
className={classNames('flex-1 mr-2 text-secondary text-sm')}
|
|
||||||
data-testid={`key-${pk.publicKey}`}
|
|
||||||
>
|
|
||||||
<Tooltip description={t('Public facing key alias. Click to edit')}>
|
|
||||||
<button
|
|
||||||
data-testid="alias"
|
|
||||||
onClick={() => setOpen(pk.publicKey)}
|
|
||||||
className="flex items-center gap-1"
|
|
||||||
>
|
|
||||||
{alias ? alias : t('No alias')}
|
|
||||||
{isActive && <VegaIcon name={VegaIconNames.EDIT} />}
|
|
||||||
</button>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<TradingDropdownItemIndicator />
|
<TradingDropdownItemIndicator />
|
||||||
</TradingDropdownRadioItem>
|
</TradingDropdownRadioItem>
|
||||||
|
@ -12,8 +12,6 @@ import CopyToClipboard from 'react-copy-to-clipboard';
|
|||||||
import { ViewType, useSidebar } from '../sidebar';
|
import { ViewType, useSidebar } from '../sidebar';
|
||||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||||
import { useT } from '../../lib/use-t';
|
import { useT } from '../../lib/use-t';
|
||||||
import { usePartyProfilesQuery } from '../vega-wallet-connect-button/__generated__/PartyProfiles';
|
|
||||||
import { useProfileDialogStore } from '../../stores/profile-dialog-store';
|
|
||||||
|
|
||||||
export const VegaWalletMenu = ({
|
export const VegaWalletMenu = ({
|
||||||
setMenu,
|
setMenu,
|
||||||
@ -25,12 +23,6 @@ export const VegaWalletMenu = ({
|
|||||||
const currentRouteId = useGetCurrentRouteId();
|
const currentRouteId = useGetCurrentRouteId();
|
||||||
const setViews = useSidebar((store) => store.setViews);
|
const setViews = useSidebar((store) => store.setViews);
|
||||||
|
|
||||||
const { data } = usePartyProfilesQuery({
|
|
||||||
variables: { partyIds: pubKeys.map((pk) => pk.publicKey) },
|
|
||||||
skip: pubKeys.length <= 0,
|
|
||||||
fetchPolicy: 'cache-and-network',
|
|
||||||
});
|
|
||||||
|
|
||||||
const activeKey = useMemo(() => {
|
const activeKey = useMemo(() => {
|
||||||
return pubKeys?.find((pk) => pk.publicKey === pubKey);
|
return pubKeys?.find((pk) => pk.publicKey === pubKey);
|
||||||
}, [pubKey, pubKeys]);
|
}, [pubKey, pubKeys]);
|
||||||
@ -45,21 +37,14 @@ export const VegaWalletMenu = ({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="grow my-4" role="list">
|
<div className="grow my-4" role="list">
|
||||||
{(pubKeys || []).map((pk) => {
|
{(pubKeys || []).map((pk) => (
|
||||||
const profile = data?.partiesProfilesConnection?.edges.find(
|
<KeypairListItem
|
||||||
(e) => e.node.partyId === pk.publicKey
|
key={pk.publicKey}
|
||||||
);
|
pk={pk}
|
||||||
return (
|
isActive={activeKey?.publicKey === pk.publicKey}
|
||||||
<KeypairListItem
|
onSelectItem={onSelectItem}
|
||||||
key={pk.publicKey}
|
/>
|
||||||
pk={pk}
|
))}
|
||||||
isActive={activeKey?.publicKey === pk.publicKey}
|
|
||||||
onSelectItem={onSelectItem}
|
|
||||||
alias={profile?.node.alias}
|
|
||||||
setMenu={setMenu}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col gap-2 m-4">
|
<div className="flex flex-col gap-2 m-4">
|
||||||
@ -87,23 +72,18 @@ export const VegaWalletMenu = ({
|
|||||||
const KeypairListItem = ({
|
const KeypairListItem = ({
|
||||||
pk,
|
pk,
|
||||||
isActive,
|
isActive,
|
||||||
alias,
|
|
||||||
onSelectItem,
|
onSelectItem,
|
||||||
setMenu,
|
|
||||||
}: {
|
}: {
|
||||||
pk: Key;
|
pk: Key;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
alias: string | undefined;
|
|
||||||
onSelectItem: (pk: string) => void;
|
onSelectItem: (pk: string) => void;
|
||||||
setMenu: (open: 'nav' | 'wallet' | null) => void;
|
|
||||||
}) => {
|
}) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const [copied, setCopied] = useCopyTimeout();
|
const [copied, setCopied] = useCopyTimeout();
|
||||||
const setOpen = useProfileDialogStore((store) => store.setOpen);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="flex flex-col w-full px-4 mb-4"
|
className="flex flex-col w-full ml-4 mr-2 mb-4"
|
||||||
data-testid={`key-${pk.publicKey}-mobile`}
|
data-testid={`key-${pk.publicKey}-mobile`}
|
||||||
>
|
>
|
||||||
<span className="flex gap-2 items-center mr-2">
|
<span className="flex gap-2 items-center mr-2">
|
||||||
@ -126,24 +106,6 @@ const KeypairListItem = ({
|
|||||||
</CopyToClipboard>
|
</CopyToClipboard>
|
||||||
{copied && <span className="text-xs">{t('Copied')}</span>}
|
{copied && <span className="text-xs">{t('Copied')}</span>}
|
||||||
</span>
|
</span>
|
||||||
<span
|
|
||||||
className="flex gap-2 items-center"
|
|
||||||
data-testid={`key-${pk.publicKey}`}
|
|
||||||
>
|
|
||||||
<span className="truncate">{alias ? alias : t('No alias')}</span>
|
|
||||||
{isActive && (
|
|
||||||
<button
|
|
||||||
data-testid="alias"
|
|
||||||
onClick={() => {
|
|
||||||
setOpen(pk.publicKey);
|
|
||||||
setMenu(null);
|
|
||||||
}}
|
|
||||||
className="flex items-center gap-1"
|
|
||||||
>
|
|
||||||
<VegaIcon name={VegaIconNames.EDIT} />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
CONSOLE_IMAGE_NAME=vegaprotocol/trading:latest
|
CONSOLE_IMAGE_NAME=vegaprotocol/trading:latest
|
||||||
VEGA_VERSION=v0.75.0-preview.2
|
VEGA_VERSION=v0.74.6
|
||||||
LOCAL_SERVER=false
|
LOCAL_SERVER=false
|
||||||
|
@ -50,6 +50,8 @@ def truncate_middle(market_id, start=6, end=4):
|
|||||||
def change_keys(page: Page, vega: VegaServiceNull, key_name):
|
def change_keys(page: Page, vega: VegaServiceNull, key_name):
|
||||||
page.get_by_test_id("manage-vega-wallet").click()
|
page.get_by_test_id("manage-vega-wallet").click()
|
||||||
page.get_by_test_id("key-" + vega.wallet.public_key(key_name)).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()
|
page.reload()
|
||||||
|
|
||||||
|
|
||||||
|
@ -339,3 +339,4 @@ def retry_on_http_error(request):
|
|||||||
print(f"Retrying due to HTTPError (attempt {i+1}/{retry_count})")
|
print(f"Retrying due to HTTPError (attempt {i+1}/{retry_count})")
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
8
apps/trading/e2e/poetry.lock
generated
8
apps/trading/e2e/poetry.lock
generated
@ -877,13 +877,13 @@ testing = ["filelock"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-dateutil"
|
name = "python-dateutil"
|
||||||
version = "2.9.0.post0"
|
version = "2.8.2"
|
||||||
description = "Extensions to the standard Python datetime module"
|
description = "Extensions to the standard Python datetime module"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
|
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
|
||||||
{file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
|
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -1166,7 +1166,7 @@ profile = ["pytest-profiling", "snakeviz"]
|
|||||||
type = "git"
|
type = "git"
|
||||||
url = "https://github.com/vegaprotocol/vega-market-sim.git/"
|
url = "https://github.com/vegaprotocol/vega-market-sim.git/"
|
||||||
reference = "HEAD"
|
reference = "HEAD"
|
||||||
resolved_reference = "53eed8942acb670783105cb1115bab76710a46dc"
|
resolved_reference = "33fec45ce8044ef7f53b625584ce590d174f9057"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "websocket-client"
|
name = "websocket-client"
|
||||||
|
@ -18,7 +18,7 @@ expire = "expire"
|
|||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def vega(request):
|
def vega(request):
|
||||||
with init_vega(request) as vega_instance:
|
with init_vega(request) as vega_instance:
|
||||||
request.addfinalizer(lambda: cleanup_container(vega_instance))
|
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
|
||||||
yield vega_instance
|
yield vega_instance
|
||||||
|
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ class TestStopOcoValidation:
|
|||||||
@pytest.fixture(scope="class")
|
@pytest.fixture(scope="class")
|
||||||
def vega(request):
|
def vega(request):
|
||||||
with init_vega(request) as vega_instance:
|
with init_vega(request) as vega_instance:
|
||||||
request.addfinalizer(lambda: cleanup_container(vega_instance))
|
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
|
||||||
yield vega_instance
|
yield vega_instance
|
||||||
|
|
||||||
@pytest.fixture(scope="class")
|
@pytest.fixture(scope="class")
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from typing import Tuple, Generator
|
|
||||||
from fees_test_ids import *
|
from fees_test_ids import *
|
||||||
from playwright.sync_api import expect, Page
|
from playwright.sync_api import Page, expect
|
||||||
from vega_sim.null_service import VegaServiceNull
|
from vega_sim.null_service import VegaServiceNull
|
||||||
from actions.vega import submit_order
|
from actions.vega import submit_order
|
||||||
from wallet_config import MM_WALLET
|
from wallet_config import MM_WALLET
|
||||||
@ -17,70 +16,77 @@ from fixtures.market import setup_continuous_market
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def setup_environment(
|
def vega(request):
|
||||||
request, browser
|
|
||||||
) -> Generator[Tuple[VegaServiceNull, str, Page], None, None]:
|
|
||||||
with init_vega(request) as vega_instance:
|
with init_vega(request) as vega_instance:
|
||||||
request.addfinalizer(lambda: cleanup_container(vega_instance))
|
request.addfinalizer(
|
||||||
market = setup_continuous_market(vega_instance, custom_quantum=100000)
|
lambda: cleanup_container(vega_instance)
|
||||||
vega_instance.update_volume_discount_program(
|
|
||||||
proposal_key=MM_WALLET.name,
|
|
||||||
benefit_tiers=[
|
|
||||||
{
|
|
||||||
"minimum_running_notional_taker_volume": 100,
|
|
||||||
"volume_discount_factor": 0.1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"minimum_running_notional_taker_volume": 200,
|
|
||||||
"volume_discount_factor": 0.2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
window_length=7,
|
|
||||||
)
|
)
|
||||||
next_epoch(vega_instance)
|
yield vega_instance
|
||||||
|
|
||||||
vega_instance.update_referral_program(
|
|
||||||
proposal_key=MM_WALLET.name,
|
|
||||||
benefit_tiers=[
|
|
||||||
{
|
|
||||||
"minimum_running_notional_taker_volume": 100,
|
|
||||||
"minimum_epochs": 1,
|
|
||||||
"referral_reward_factor": 0.1,
|
|
||||||
"referral_discount_factor": 0.1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"minimum_running_notional_taker_volume": 200,
|
|
||||||
"minimum_epochs": 2,
|
|
||||||
"referral_reward_factor": 0.2,
|
|
||||||
"referral_discount_factor": 0.2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
staking_tiers=[
|
|
||||||
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
|
|
||||||
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
|
|
||||||
],
|
|
||||||
window_length=1,
|
|
||||||
)
|
|
||||||
vega_instance.create_referral_set(key_name=MM_WALLET.name)
|
|
||||||
next_epoch(vega_instance)
|
|
||||||
referral_set_id = list(vega_instance.list_referral_sets().keys())[0]
|
|
||||||
vega_instance.apply_referral_code(key_name="Key 1", id=referral_set_id)
|
|
||||||
next_epoch(vega_instance)
|
|
||||||
|
|
||||||
for _ in range(2):
|
|
||||||
submit_order(vega_instance, "Key 1", market, "SIDE_BUY", 2, 110)
|
|
||||||
forward_time(vega_instance, True if _ < 2 - 1 else False)
|
|
||||||
|
|
||||||
with init_page(vega_instance, browser, request) as page_instance:
|
|
||||||
risk_accepted_setup(page_instance)
|
|
||||||
auth_setup(vega_instance, page_instance)
|
|
||||||
yield vega_instance, market, page_instance
|
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_my_trading_fees(
|
@pytest.fixture(scope="module")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def page(vega, browser, request):
|
||||||
) -> None:
|
with init_page(vega, browser, request) as page:
|
||||||
vega, market, page = setup_environment
|
risk_accepted_setup(page)
|
||||||
|
auth_setup(vega, page)
|
||||||
|
yield page
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module", autouse=True)
|
||||||
|
def setup_combined_market(vega: VegaServiceNull):
|
||||||
|
market = setup_continuous_market(vega, custom_quantum=100000)
|
||||||
|
vega.update_volume_discount_program(
|
||||||
|
proposal_key=MM_WALLET.name,
|
||||||
|
benefit_tiers=[
|
||||||
|
{
|
||||||
|
"minimum_running_notional_taker_volume": 100,
|
||||||
|
"volume_discount_factor": 0.1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minimum_running_notional_taker_volume": 200,
|
||||||
|
"volume_discount_factor": 0.2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
window_length=7,
|
||||||
|
)
|
||||||
|
next_epoch(vega=vega)
|
||||||
|
|
||||||
|
vega.update_referral_program(
|
||||||
|
proposal_key=MM_WALLET.name,
|
||||||
|
benefit_tiers=[
|
||||||
|
{
|
||||||
|
"minimum_running_notional_taker_volume": 100,
|
||||||
|
"minimum_epochs": 1,
|
||||||
|
"referral_reward_factor": 0.1,
|
||||||
|
"referral_discount_factor": 0.1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minimum_running_notional_taker_volume": 200,
|
||||||
|
"minimum_epochs": 2,
|
||||||
|
"referral_reward_factor": 0.2,
|
||||||
|
"referral_discount_factor": 0.2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
staking_tiers=[
|
||||||
|
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
|
||||||
|
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
|
||||||
|
],
|
||||||
|
window_length=1,
|
||||||
|
)
|
||||||
|
vega.create_referral_set(key_name=MM_WALLET.name)
|
||||||
|
next_epoch(vega=vega)
|
||||||
|
referral_set_id = list(vega.list_referral_sets().keys())[0]
|
||||||
|
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
|
||||||
|
next_epoch(vega=vega)
|
||||||
|
|
||||||
|
for _ in range(2):
|
||||||
|
submit_order(vega, "Key 1", market, "SIDE_BUY", 2, 110)
|
||||||
|
forward_time(vega, True if _ < 2 - 1 else False)
|
||||||
|
return market
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
|
||||||
|
def test_fees_page_discount_program_my_trading_fees(page: Page):
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("6.432%-6.432%")
|
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("6.432%-6.432%")
|
||||||
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
|
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
|
||||||
@ -91,10 +97,10 @@ def test_fees_page_discount_program_my_trading_fees(
|
|||||||
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
|
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
|
||||||
def test_fees_page_discount_program_total_discount(
|
def test_fees_page_discount_program_total_discount(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page,
|
||||||
) -> None:
|
):
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("36%")
|
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("36%")
|
||||||
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount20%")
|
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount20%")
|
||||||
@ -107,10 +113,8 @@ def test_fees_page_discount_program_total_discount(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_fees_by_market(
|
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def test_fees_page_discount_program_fees_by_market(page: Page):
|
||||||
) -> None:
|
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
pinned = page.locator(PINNED_ROW_LOCATOR)
|
pinned = page.locator(PINNED_ROW_LOCATOR)
|
||||||
row = page.locator(ROW_LOCATOR)
|
row = page.locator(ROW_LOCATOR)
|
||||||
@ -122,11 +126,12 @@ def test_fees_page_discount_program_fees_by_market(
|
|||||||
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
|
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
|
||||||
def test_deal_ticket_discount_program(
|
def test_deal_ticket_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page,
|
||||||
) -> None:
|
setup_combined_market,
|
||||||
vega, market, page = setup_environment
|
):
|
||||||
page.goto(f"/#/markets/{market}")
|
page.goto(f"/#/markets/{setup_combined_market}")
|
||||||
page.get_by_test_id(ORDER_SIZE).fill("1")
|
page.get_by_test_id(ORDER_SIZE).fill("1")
|
||||||
page.get_by_test_id(ORDER_PRICE).fill("1")
|
page.get_by_test_id(ORDER_PRICE).fill("1")
|
||||||
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-36%")
|
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-36%")
|
||||||
@ -145,9 +150,12 @@ def test_deal_ticket_discount_program(
|
|||||||
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.06432 tDAI")
|
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.06432 tDAI")
|
||||||
|
|
||||||
|
|
||||||
def test_fills_taker_discount_program(setup_environment):
|
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
|
||||||
vega, market, page = setup_environment
|
def test_fills_taker_discount_program(
|
||||||
page.goto(f"/#/markets/{market}")
|
page: Page,
|
||||||
|
setup_combined_market,
|
||||||
|
):
|
||||||
|
page.goto(f"/#/markets/{setup_combined_market}")
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
expect(row.locator(COL_SIZE)).to_have_text("+2")
|
expect(row.locator(COL_SIZE)).to_have_text("+2")
|
||||||
@ -158,11 +166,13 @@ def test_fills_taker_discount_program(setup_environment):
|
|||||||
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("7.48926 tDAI")
|
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("7.48926 tDAI")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
|
||||||
def test_fills_maker_discount_program(
|
def test_fills_maker_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
vega: VegaServiceNull,
|
||||||
) -> None:
|
page: Page,
|
||||||
vega, market, page = setup_environment
|
setup_combined_market,
|
||||||
page.goto(f"/#/markets/{market}")
|
):
|
||||||
|
page.goto(f"/#/markets/{setup_combined_market}")
|
||||||
change_keys(page, vega, MM_WALLET.name)
|
change_keys(page, vega, MM_WALLET.name)
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
@ -174,11 +184,11 @@ def test_fills_maker_discount_program(
|
|||||||
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("7.452 tDAI")
|
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("7.452 tDAI")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
|
||||||
def test_fills_maker_fee_tooltip_discount_program(
|
def test_fills_maker_fee_tooltip_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
vega: VegaServiceNull, page: Page, setup_combined_market
|
||||||
) -> None:
|
):
|
||||||
vega, market, page = setup_environment
|
page.goto(f"/#/markets/{setup_combined_market}")
|
||||||
page.goto(f"/#/markets/{market}")
|
|
||||||
change_keys(page, vega, MM_WALLET.name)
|
change_keys(page, vega, MM_WALLET.name)
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
@ -190,11 +200,12 @@ def test_fills_maker_fee_tooltip_discount_program(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
|
||||||
def test_fills_taker_fee_tooltip_discount_program(
|
def test_fills_taker_fee_tooltip_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page,
|
||||||
) -> None:
|
setup_combined_market,
|
||||||
vega, market, page = setup_environment
|
):
|
||||||
page.goto(f"/#/markets/{market}")
|
page.goto(f"/#/markets/{setup_combined_market}")
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
# tbd - tooltip is not visible without this wait
|
# tbd - tooltip is not visible without this wait
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from typing import Tuple, Generator
|
|
||||||
from fees_test_ids import *
|
from fees_test_ids import *
|
||||||
from playwright.sync_api import Page, expect
|
from playwright.sync_api import Page, expect
|
||||||
from vega_sim.null_service import VegaServiceNull
|
from vega_sim.null_service import VegaServiceNull
|
||||||
@ -15,58 +14,63 @@ from conftest import (
|
|||||||
from actions.utils import next_epoch, change_keys, forward_time
|
from actions.utils import next_epoch, change_keys, forward_time
|
||||||
from fixtures.market import setup_continuous_market
|
from fixtures.market import setup_continuous_market
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def vega(request):
|
||||||
|
with init_vega(request) as vega_instance:
|
||||||
|
request.addfinalizer(
|
||||||
|
lambda: cleanup_container(vega_instance)
|
||||||
|
)
|
||||||
|
yield vega_instance
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def setup_environment(
|
def page(vega, browser, request):
|
||||||
request, browser
|
with init_page(vega, browser, request) as page:
|
||||||
) -> Generator[Tuple[VegaServiceNull, str, Page], None, None]:
|
risk_accepted_setup(page)
|
||||||
with init_vega(request) as vega_instance:
|
auth_setup(vega, page)
|
||||||
request.addfinalizer(lambda: cleanup_container(vega_instance))
|
yield page
|
||||||
|
|
||||||
# Setup the market with the referral discount program
|
|
||||||
market = setup_continuous_market(vega_instance, custom_quantum=100000)
|
|
||||||
vega_instance.update_referral_program(
|
|
||||||
proposal_key=MM_WALLET.name,
|
|
||||||
benefit_tiers=[
|
|
||||||
{
|
|
||||||
"minimum_running_notional_taker_volume": 100,
|
|
||||||
"minimum_epochs": 1,
|
|
||||||
"referral_reward_factor": 0.1,
|
|
||||||
"referral_discount_factor": 0.1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"minimum_running_notional_taker_volume": 200,
|
|
||||||
"minimum_epochs": 2,
|
|
||||||
"referral_reward_factor": 0.2,
|
|
||||||
"referral_discount_factor": 0.2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
staking_tiers=[
|
|
||||||
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
|
|
||||||
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
|
|
||||||
],
|
|
||||||
window_length=1,
|
|
||||||
)
|
|
||||||
vega_instance.create_referral_set(key_name=MM_WALLET.name)
|
|
||||||
next_epoch(vega_instance)
|
|
||||||
referral_set_id = list(vega_instance.list_referral_sets().keys())[0]
|
|
||||||
vega_instance.apply_referral_code(key_name="Key 1", id=referral_set_id)
|
|
||||||
next_epoch(vega_instance)
|
|
||||||
|
|
||||||
for _ in range(2):
|
|
||||||
submit_order(vega_instance, "Key 1", market, "SIDE_BUY", 1, 110)
|
|
||||||
forward_time(vega_instance, True if _ < 2 - 1 else False)
|
|
||||||
|
|
||||||
with init_page(vega_instance, browser, request) as page_instance:
|
|
||||||
risk_accepted_setup(page_instance)
|
|
||||||
auth_setup(vega_instance, page_instance)
|
|
||||||
yield vega_instance, market, page_instance
|
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_my_trading_fees(
|
@pytest.fixture(scope="module", autouse=True)
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def setup_market_with_referral_discount_program(vega: VegaServiceNull):
|
||||||
) -> None:
|
market = setup_continuous_market(vega, custom_quantum=100000)
|
||||||
vega, market, page = setup_environment
|
vega.update_referral_program(
|
||||||
|
proposal_key=MM_WALLET.name,
|
||||||
|
benefit_tiers=[
|
||||||
|
{
|
||||||
|
"minimum_running_notional_taker_volume": 100,
|
||||||
|
"minimum_epochs": 1,
|
||||||
|
"referral_reward_factor": 0.1,
|
||||||
|
"referral_discount_factor": 0.1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minimum_running_notional_taker_volume": 200,
|
||||||
|
"minimum_epochs": 2,
|
||||||
|
"referral_reward_factor": 0.2,
|
||||||
|
"referral_discount_factor": 0.2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
staking_tiers=[
|
||||||
|
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
|
||||||
|
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
|
||||||
|
],
|
||||||
|
window_length=1,
|
||||||
|
)
|
||||||
|
vega.create_referral_set(key_name=MM_WALLET.name)
|
||||||
|
next_epoch(vega=vega)
|
||||||
|
referral_set_id = list(vega.list_referral_sets().keys())[0]
|
||||||
|
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
|
||||||
|
next_epoch(vega=vega)
|
||||||
|
|
||||||
|
for _ in range(2):
|
||||||
|
submit_order(vega, "Key 1", market, "SIDE_BUY", 1, 110)
|
||||||
|
forward_time(vega, True if _ < 2 - 1 else False)
|
||||||
|
|
||||||
|
return market
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
|
||||||
|
def test_fees_page_discount_program_my_trading_fees(page: Page):
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("9.045%-9.045%")
|
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("9.045%-9.045%")
|
||||||
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
|
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
|
||||||
@ -77,10 +81,8 @@ def test_fees_page_discount_program_my_trading_fees(
|
|||||||
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
|
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_total_discount(
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def test_fees_page_discount_program_total_discount(page: Page):
|
||||||
) -> None:
|
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("10%")
|
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("10%")
|
||||||
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount0%")
|
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount0%")
|
||||||
@ -93,19 +95,15 @@ def test_fees_page_discount_program_total_discount(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_referral_discount_program_referral_benefits(
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def test_fees_page_referral_discount_program_referral_benefits(page: Page):
|
||||||
) -> None:
|
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(RUNNING_NOTIONAL_TAKER_VOLUME)).to_have_text("103")
|
expect(page.get_by_test_id(RUNNING_NOTIONAL_TAKER_VOLUME)).to_have_text("103")
|
||||||
expect(page.get_by_test_id(EPOCHS_IN_REFERRAL_SET)).to_have_text("1")
|
expect(page.get_by_test_id(EPOCHS_IN_REFERRAL_SET)).to_have_text("1")
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_discount(
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def test_fees_page_discount_program_discount(page: Page):
|
||||||
) -> None:
|
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
|
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
|
||||||
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
|
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
|
||||||
@ -121,10 +119,8 @@ def test_fees_page_discount_program_discount(
|
|||||||
expect(page.get_by_test_id("your-referral-tier-0").nth(1)).to_have_text("Your tier")
|
expect(page.get_by_test_id("your-referral-tier-0").nth(1)).to_have_text("Your tier")
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_fees_by_market(
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def test_fees_page_discount_program_fees_by_market(page: Page):
|
||||||
) -> None:
|
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
pinned = page.locator(PINNED_ROW_LOCATOR)
|
pinned = page.locator(PINNED_ROW_LOCATOR)
|
||||||
row = page.locator(ROW_LOCATOR)
|
row = page.locator(ROW_LOCATOR)
|
||||||
@ -136,11 +132,11 @@ def test_fees_page_discount_program_fees_by_market(
|
|||||||
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
|
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
|
||||||
def test_deal_ticket_discount_program(
|
def test_deal_ticket_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page, setup_market_with_referral_discount_program
|
||||||
) -> None:
|
):
|
||||||
vega, market, page = setup_environment
|
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
|
||||||
page.goto(f"/#/markets/{market}")
|
|
||||||
page.get_by_test_id(ORDER_SIZE).fill("1")
|
page.get_by_test_id(ORDER_SIZE).fill("1")
|
||||||
page.get_by_test_id(ORDER_PRICE).fill("1")
|
page.get_by_test_id(ORDER_PRICE).fill("1")
|
||||||
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-10%")
|
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-10%")
|
||||||
@ -159,11 +155,12 @@ def test_deal_ticket_discount_program(
|
|||||||
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.09045 tDAI")
|
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.09045 tDAI")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
|
||||||
def test_fills_taker_discount_program(
|
def test_fills_taker_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page,
|
||||||
) -> None:
|
setup_market_with_referral_discount_program,
|
||||||
vega, market, page = setup_environment
|
):
|
||||||
page.goto(f"/#/markets/{market}")
|
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
expect(row.locator(COL_SIZE)).to_have_text("+1")
|
expect(row.locator(COL_SIZE)).to_have_text("+1")
|
||||||
@ -174,11 +171,13 @@ def test_fills_taker_discount_program(
|
|||||||
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("1.04017 tDAI")
|
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("1.04017 tDAI")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
|
||||||
def test_fills_maker_discount_program(
|
def test_fills_maker_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
vega: VegaServiceNull,
|
||||||
) -> None:
|
page: Page,
|
||||||
vega, market, page = setup_environment
|
setup_market_with_referral_discount_program,
|
||||||
page.goto(f"/#/markets/{market}")
|
):
|
||||||
|
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
|
||||||
change_keys(page, vega, MM_WALLET.name)
|
change_keys(page, vega, MM_WALLET.name)
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
@ -190,11 +189,11 @@ def test_fills_maker_discount_program(
|
|||||||
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("1.035 tDAI")
|
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("1.035 tDAI")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
|
||||||
def test_fills_maker_fee_tooltip_discount_program(
|
def test_fills_maker_fee_tooltip_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
vega: VegaServiceNull, page: Page, setup_market_with_referral_discount_program
|
||||||
) -> None:
|
):
|
||||||
vega, market, page = setup_environment
|
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
|
||||||
page.goto(f"/#/markets/{market}")
|
|
||||||
change_keys(page, vega, MM_WALLET.name)
|
change_keys(page, vega, MM_WALLET.name)
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
@ -206,11 +205,12 @@ def test_fills_maker_fee_tooltip_discount_program(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
|
||||||
def test_fills_taker_fee_tooltip_discount_program(
|
def test_fills_taker_fee_tooltip_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page,
|
||||||
) -> None:
|
setup_market_with_referral_discount_program,
|
||||||
vega, market, page = setup_environment
|
):
|
||||||
page.goto(f"/#/markets/{market}")
|
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
# tbd - tooltip is not visible without this wait
|
# tbd - tooltip is not visible without this wait
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from fees_test_ids import *
|
from fees_test_ids import *
|
||||||
from typing import Tuple, Generator
|
|
||||||
from playwright.sync_api import Page, expect
|
from playwright.sync_api import Page, expect
|
||||||
from vega_sim.null_service import VegaServiceNull
|
from vega_sim.null_service import VegaServiceNull
|
||||||
from actions.vega import submit_order
|
from actions.vega import submit_order
|
||||||
@ -17,56 +16,62 @@ from fixtures.market import setup_continuous_market
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def setup_environment(
|
def vega(request):
|
||||||
request, browser
|
|
||||||
) -> Generator[Tuple[VegaServiceNull, str, Page], None, None]:
|
|
||||||
with init_vega(request) as vega_instance:
|
with init_vega(request) as vega_instance:
|
||||||
request.addfinalizer(lambda: cleanup_container(vega_instance))
|
request.addfinalizer(
|
||||||
|
lambda: cleanup_container(vega_instance)
|
||||||
# Setup market with referral discount program
|
|
||||||
market = setup_continuous_market(vega_instance, custom_quantum=100000)
|
|
||||||
vega_instance.update_referral_program(
|
|
||||||
proposal_key=MM_WALLET.name,
|
|
||||||
benefit_tiers=[
|
|
||||||
{
|
|
||||||
"minimum_running_notional_taker_volume": 100,
|
|
||||||
"minimum_epochs": 1,
|
|
||||||
"referral_reward_factor": 0.1,
|
|
||||||
"referral_discount_factor": 0.1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"minimum_running_notional_taker_volume": 200,
|
|
||||||
"minimum_epochs": 2,
|
|
||||||
"referral_reward_factor": 0.2,
|
|
||||||
"referral_discount_factor": 0.2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
staking_tiers=[
|
|
||||||
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
|
|
||||||
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
|
|
||||||
],
|
|
||||||
window_length=1,
|
|
||||||
)
|
)
|
||||||
vega_instance.create_referral_set(key_name=MM_WALLET.name)
|
yield vega_instance
|
||||||
next_epoch(vega_instance)
|
|
||||||
referral_set_id = list(vega_instance.list_referral_sets().keys())[0]
|
|
||||||
vega_instance.apply_referral_code(key_name="Key 1", id=referral_set_id)
|
|
||||||
next_epoch(vega_instance)
|
|
||||||
|
|
||||||
for _ in range(2):
|
|
||||||
submit_order(vega_instance, "Key 1", market, "SIDE_BUY", 2, 110)
|
|
||||||
forward_time(vega_instance, True if _ < 2 - 1 else False)
|
|
||||||
|
|
||||||
with init_page(vega_instance, browser, request) as page_instance:
|
|
||||||
risk_accepted_setup(page_instance)
|
|
||||||
auth_setup(vega_instance, page_instance)
|
|
||||||
yield vega_instance, market, page_instance
|
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_my_trading_fees(
|
@pytest.fixture(scope="module")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def page(vega, browser, request):
|
||||||
) -> None:
|
with init_page(vega, browser, request) as page:
|
||||||
vega, market, page = setup_environment
|
risk_accepted_setup(page)
|
||||||
|
auth_setup(vega, page)
|
||||||
|
yield page
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module", autouse=True)
|
||||||
|
def setup_market_with_referral_discount_program(vega: VegaServiceNull):
|
||||||
|
market = setup_continuous_market(vega, custom_quantum=100000)
|
||||||
|
vega.update_referral_program(
|
||||||
|
proposal_key=MM_WALLET.name,
|
||||||
|
benefit_tiers=[
|
||||||
|
{
|
||||||
|
"minimum_running_notional_taker_volume": 100,
|
||||||
|
"minimum_epochs": 1,
|
||||||
|
"referral_reward_factor": 0.1,
|
||||||
|
"referral_discount_factor": 0.1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minimum_running_notional_taker_volume": 200,
|
||||||
|
"minimum_epochs": 2,
|
||||||
|
"referral_reward_factor": 0.2,
|
||||||
|
"referral_discount_factor": 0.2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
staking_tiers=[
|
||||||
|
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
|
||||||
|
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
|
||||||
|
],
|
||||||
|
window_length=1,
|
||||||
|
)
|
||||||
|
vega.create_referral_set(key_name=MM_WALLET.name)
|
||||||
|
next_epoch(vega=vega)
|
||||||
|
referral_set_id = list(vega.list_referral_sets().keys())[0]
|
||||||
|
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
|
||||||
|
next_epoch(vega=vega)
|
||||||
|
|
||||||
|
for _ in range(2):
|
||||||
|
submit_order(vega, "Key 1", market, "SIDE_BUY", 2, 110)
|
||||||
|
forward_time(vega, True if _ < 2 - 1 else False)
|
||||||
|
|
||||||
|
return market
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
|
||||||
|
def test_fees_page_discount_program_my_trading_fees(page: Page):
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("8.04%-8.04%")
|
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("8.04%-8.04%")
|
||||||
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
|
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
|
||||||
@ -77,10 +82,8 @@ def test_fees_page_discount_program_my_trading_fees(
|
|||||||
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
|
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_total_discount(
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def test_fees_page_discount_program_total_discount(page: Page):
|
||||||
) -> None:
|
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("20%")
|
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("20%")
|
||||||
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount0%")
|
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount0%")
|
||||||
@ -93,19 +96,15 @@ def test_fees_page_discount_program_total_discount(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_referral_discount_program_referral_benefits(
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def test_fees_page_referral_discount_program_referral_benefits(page: Page):
|
||||||
) -> None:
|
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(RUNNING_NOTIONAL_TAKER_VOLUME)).to_have_text("207")
|
expect(page.get_by_test_id(RUNNING_NOTIONAL_TAKER_VOLUME)).to_have_text("207")
|
||||||
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).not_to_be_visible()
|
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).not_to_be_visible()
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_discount(
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def test_fees_page_discount_program_discount(page: Page):
|
||||||
) -> None:
|
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
|
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
|
||||||
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
|
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
|
||||||
@ -121,10 +120,8 @@ def test_fees_page_discount_program_discount(
|
|||||||
expect(page.get_by_test_id("your-referral-tier-1").nth(1)).to_have_text("Your tier")
|
expect(page.get_by_test_id("your-referral-tier-1").nth(1)).to_have_text("Your tier")
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_fees_by_market(
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def test_fees_page_discount_program_fees_by_market(page: Page):
|
||||||
) -> None:
|
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
pinned = page.locator(PINNED_ROW_LOCATOR)
|
pinned = page.locator(PINNED_ROW_LOCATOR)
|
||||||
row = page.locator(ROW_LOCATOR)
|
row = page.locator(ROW_LOCATOR)
|
||||||
@ -136,11 +133,11 @@ def test_fees_page_discount_program_fees_by_market(
|
|||||||
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
|
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
|
||||||
def test_deal_ticket_discount_program(
|
def test_deal_ticket_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page, setup_market_with_referral_discount_program
|
||||||
) -> None:
|
):
|
||||||
vega, market, page = setup_environment
|
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
|
||||||
page.goto(f"/#/markets/{market}")
|
|
||||||
page.get_by_test_id(ORDER_SIZE).fill("1")
|
page.get_by_test_id(ORDER_SIZE).fill("1")
|
||||||
page.get_by_test_id(ORDER_PRICE).fill("1")
|
page.get_by_test_id(ORDER_PRICE).fill("1")
|
||||||
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-20%")
|
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-20%")
|
||||||
@ -159,11 +156,12 @@ def test_deal_ticket_discount_program(
|
|||||||
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.0804 tDAI")
|
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.0804 tDAI")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
|
||||||
def test_fills_taker_discount_program(
|
def test_fills_taker_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page,
|
||||||
) -> None:
|
setup_market_with_referral_discount_program,
|
||||||
vega, market, page = setup_environment
|
):
|
||||||
page.goto(f"/#/markets/{market}")
|
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
expect(row.locator(COL_SIZE)).to_have_text("+2")
|
expect(row.locator(COL_SIZE)).to_have_text("+2")
|
||||||
@ -174,11 +172,13 @@ def test_fills_taker_discount_program(
|
|||||||
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("4.1607 tDAI")
|
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("4.1607 tDAI")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
|
||||||
def test_fills_maker_discount_program(
|
def test_fills_maker_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
vega: VegaServiceNull,
|
||||||
) -> None:
|
page: Page,
|
||||||
vega, market, page = setup_environment
|
setup_market_with_referral_discount_program,
|
||||||
page.goto(f"/#/markets/{market}")
|
):
|
||||||
|
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
|
||||||
change_keys(page, vega, MM_WALLET.name)
|
change_keys(page, vega, MM_WALLET.name)
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
@ -190,11 +190,11 @@ def test_fills_maker_discount_program(
|
|||||||
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("4.14 tDAI")
|
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("4.14 tDAI")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
|
||||||
def test_fills_maker_fee_tooltip_discount_program(
|
def test_fills_maker_fee_tooltip_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
vega: VegaServiceNull, page: Page, setup_market_with_referral_discount_program
|
||||||
) -> None:
|
):
|
||||||
vega, market, page = setup_environment
|
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
|
||||||
page.goto(f"/#/markets/{market}")
|
|
||||||
change_keys(page, vega, MM_WALLET.name)
|
change_keys(page, vega, MM_WALLET.name)
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
@ -206,11 +206,12 @@ def test_fills_maker_fee_tooltip_discount_program(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
|
||||||
def test_fills_taker_fee_tooltip_discount_program(
|
def test_fills_taker_fee_tooltip_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page,
|
||||||
) -> None:
|
setup_market_with_referral_discount_program,
|
||||||
vega, market, page = setup_environment
|
):
|
||||||
page.goto(f"/#/markets/{market}")
|
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
# tbd - tooltip is not visible without this wait
|
# tbd - tooltip is not visible without this wait
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from fees_test_ids import *
|
from fees_test_ids import *
|
||||||
from typing import Tuple, Generator
|
|
||||||
from playwright.sync_api import Page, expect
|
from playwright.sync_api import Page, expect
|
||||||
from vega_sim.null_service import VegaServiceNull
|
from vega_sim.null_service import VegaServiceNull
|
||||||
from actions.vega import submit_order
|
from actions.vega import submit_order
|
||||||
@ -17,45 +16,49 @@ from fixtures.market import setup_continuous_market
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def setup_environment(
|
def vega(request):
|
||||||
request, browser
|
|
||||||
) -> Generator[Tuple[VegaServiceNull, str, Page], None, None]:
|
|
||||||
with init_vega(request) as vega_instance:
|
with init_vega(request) as vega_instance:
|
||||||
request.addfinalizer(lambda: cleanup_container(vega_instance))
|
request.addfinalizer(
|
||||||
|
lambda: cleanup_container(vega_instance)
|
||||||
# Setup the market with volume discount program
|
|
||||||
market = setup_continuous_market(vega_instance, custom_quantum=100000)
|
|
||||||
vega_instance.update_volume_discount_program(
|
|
||||||
proposal_key=MM_WALLET.name,
|
|
||||||
benefit_tiers=[
|
|
||||||
{
|
|
||||||
"minimum_running_notional_taker_volume": 100,
|
|
||||||
"volume_discount_factor": 0.1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"minimum_running_notional_taker_volume": 200,
|
|
||||||
"volume_discount_factor": 0.2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
window_length=7,
|
|
||||||
)
|
)
|
||||||
next_epoch(vega=vega_instance)
|
yield vega_instance
|
||||||
|
|
||||||
for _ in range(2):
|
|
||||||
submit_order(vega_instance, "Key 1", market, "SIDE_BUY", 1, 110)
|
|
||||||
forward_time(vega_instance, True if _ < 2 - 1 else False)
|
|
||||||
|
|
||||||
# Initialize and setup page
|
|
||||||
with init_page(vega_instance, browser, request) as page:
|
|
||||||
risk_accepted_setup(page)
|
|
||||||
auth_setup(vega_instance, page)
|
|
||||||
yield vega_instance, market, page
|
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_my_trading_fees(
|
@pytest.fixture(scope="module")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def page(vega, browser, request):
|
||||||
) -> None:
|
with init_page(vega, browser, request) as page:
|
||||||
vega, market, page = setup_environment
|
risk_accepted_setup(page)
|
||||||
|
auth_setup(vega, page)
|
||||||
|
yield page
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module", autouse=True)
|
||||||
|
def setup_market_with_volume_discount_program(vega: VegaServiceNull):
|
||||||
|
market = setup_continuous_market(vega, custom_quantum=100000)
|
||||||
|
vega.update_volume_discount_program(
|
||||||
|
proposal_key=MM_WALLET.name,
|
||||||
|
benefit_tiers=[
|
||||||
|
{
|
||||||
|
"minimum_running_notional_taker_volume": 100,
|
||||||
|
"volume_discount_factor": 0.1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minimum_running_notional_taker_volume": 200,
|
||||||
|
"volume_discount_factor": 0.2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
window_length=7,
|
||||||
|
)
|
||||||
|
next_epoch(vega=vega)
|
||||||
|
|
||||||
|
for _ in range(2):
|
||||||
|
submit_order(vega, "Key 1", market, "SIDE_BUY", 1, 110)
|
||||||
|
forward_time(vega, True if _ < 2 - 1 else False)
|
||||||
|
return market
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
|
||||||
|
def test_fees_page_discount_program_my_trading_fees(page: Page):
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("9.045%-9.045%")
|
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("9.045%-9.045%")
|
||||||
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
|
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
|
||||||
@ -66,10 +69,10 @@ def test_fees_page_discount_program_my_trading_fees(
|
|||||||
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
|
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
|
||||||
def test_fees_page_discount_program_total_discount(
|
def test_fees_page_discount_program_total_discount(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page,
|
||||||
) -> None:
|
):
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("10%")
|
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("10%")
|
||||||
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount10%")
|
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount10%")
|
||||||
@ -82,20 +85,20 @@ def test_fees_page_discount_program_total_discount(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
|
||||||
def test_fees_page_volume_discount_program_my_current_volume(
|
def test_fees_page_volume_discount_program_my_current_volume(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page,
|
||||||
) -> None:
|
):
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(PAST_EPOCHS_VOLUME)).to_have_text("103")
|
expect(page.get_by_test_id(PAST_EPOCHS_VOLUME)).to_have_text("103")
|
||||||
|
|
||||||
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).to_have_text("97")
|
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).to_have_text("97")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
|
||||||
def test_fees_page_discount_program_discount(
|
def test_fees_page_discount_program_discount(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page,
|
||||||
) -> None:
|
):
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
|
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
|
||||||
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
|
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
|
||||||
@ -108,10 +111,8 @@ def test_fees_page_discount_program_discount(
|
|||||||
expect(page.get_by_test_id("your-volume-tier-0").nth(1)).to_have_text("Your tier")
|
expect(page.get_by_test_id("your-volume-tier-0").nth(1)).to_have_text("Your tier")
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_fees_by_market(
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def test_fees_page_discount_program_fees_by_market(page: Page):
|
||||||
) -> None:
|
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
pinned = page.locator(PINNED_ROW_LOCATOR)
|
pinned = page.locator(PINNED_ROW_LOCATOR)
|
||||||
row = page.locator(ROW_LOCATOR)
|
row = page.locator(ROW_LOCATOR)
|
||||||
@ -123,11 +124,11 @@ def test_fees_page_discount_program_fees_by_market(
|
|||||||
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
|
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
|
||||||
def test_deal_ticket_discount_program_testing(
|
def test_deal_ticket_discount_program_testing(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page, setup_market_with_volume_discount_program
|
||||||
) -> None:
|
):
|
||||||
vega, market, page = setup_environment
|
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
|
||||||
page.goto(f"/#/markets/{market}")
|
|
||||||
page.get_by_test_id(ORDER_SIZE).fill("1")
|
page.get_by_test_id(ORDER_SIZE).fill("1")
|
||||||
page.get_by_test_id(ORDER_PRICE).fill("1")
|
page.get_by_test_id(ORDER_PRICE).fill("1")
|
||||||
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-10%")
|
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-10%")
|
||||||
@ -148,10 +149,9 @@ def test_deal_ticket_discount_program_testing(
|
|||||||
|
|
||||||
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
|
||||||
def test_fills_taker_discount_program(
|
def test_fills_taker_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page, setup_market_with_volume_discount_program
|
||||||
) -> None:
|
):
|
||||||
vega, market, page = setup_environment
|
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
|
||||||
page.goto(f"/#/markets/{market}")
|
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
expect(row.locator(COL_SIZE)).to_have_text("+1")
|
expect(row.locator(COL_SIZE)).to_have_text("+1")
|
||||||
@ -164,10 +164,9 @@ def test_fills_taker_discount_program(
|
|||||||
|
|
||||||
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
|
||||||
def test_fills_maker_discount_program(
|
def test_fills_maker_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page, setup_market_with_volume_discount_program, vega: VegaServiceNull
|
||||||
) -> None:
|
):
|
||||||
vega, market, page = setup_environment
|
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
|
||||||
page.goto(f"/#/markets/{market}")
|
|
||||||
change_keys(page, vega, MM_WALLET.name)
|
change_keys(page, vega, MM_WALLET.name)
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
@ -179,11 +178,11 @@ def test_fills_maker_discount_program(
|
|||||||
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("1.035 tDAI")
|
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("1.035 tDAI")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
|
||||||
def test_fills_maker_fee_tooltip_discount_program(
|
def test_fills_maker_fee_tooltip_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
vega: VegaServiceNull, page: Page, setup_market_with_volume_discount_program
|
||||||
) -> None:
|
):
|
||||||
vega, market, page = setup_environment
|
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
|
||||||
page.goto(f"/#/markets/{market}")
|
|
||||||
change_keys(page, vega, MM_WALLET.name)
|
change_keys(page, vega, MM_WALLET.name)
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
@ -195,11 +194,12 @@ def test_fills_maker_fee_tooltip_discount_program(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
|
||||||
def test_fills_taker_fee_tooltip_discount_program(
|
def test_fills_taker_fee_tooltip_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page,
|
||||||
) -> None:
|
setup_market_with_volume_discount_program,
|
||||||
vega, market, page = setup_environment
|
):
|
||||||
page.goto(f"/#/markets/{market}")
|
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
# tbd - tooltip is not visible without this wait
|
# tbd - tooltip is not visible without this wait
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from fees_test_ids import *
|
from fees_test_ids import *
|
||||||
from typing import Tuple, Generator
|
|
||||||
from playwright.sync_api import Page, expect
|
from playwright.sync_api import Page, expect
|
||||||
from vega_sim.null_service import VegaServiceNull
|
from vega_sim.null_service import VegaServiceNull
|
||||||
from actions.vega import submit_order
|
from actions.vega import submit_order
|
||||||
@ -15,47 +14,51 @@ from conftest import (
|
|||||||
from actions.utils import next_epoch, change_keys, forward_time
|
from actions.utils import next_epoch, change_keys, forward_time
|
||||||
from fixtures.market import setup_continuous_market
|
from fixtures.market import setup_continuous_market
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def vega(request):
|
||||||
|
with init_vega(request) as vega_instance:
|
||||||
|
request.addfinalizer(
|
||||||
|
lambda: cleanup_container(vega_instance)
|
||||||
|
)
|
||||||
|
yield vega_instance
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def setup_environment(
|
def page(vega, browser, request):
|
||||||
request, browser
|
with init_page(vega, browser, request) as page:
|
||||||
) -> Generator[Tuple[VegaServiceNull, str, Page], None, None]:
|
risk_accepted_setup(page)
|
||||||
with init_vega(request) as vega_instance:
|
auth_setup(vega, page)
|
||||||
request.addfinalizer(lambda: cleanup_container(vega_instance))
|
yield page
|
||||||
|
|
||||||
# Setup the market with volume discount program
|
|
||||||
market = setup_continuous_market(vega_instance, custom_quantum=100000)
|
|
||||||
vega_instance.update_volume_discount_program(
|
|
||||||
proposal_key=MM_WALLET.name,
|
|
||||||
benefit_tiers=[
|
|
||||||
{
|
|
||||||
"minimum_running_notional_taker_volume": 100,
|
|
||||||
"volume_discount_factor": 0.1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"minimum_running_notional_taker_volume": 200,
|
|
||||||
"volume_discount_factor": 0.2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
window_length=7,
|
|
||||||
)
|
|
||||||
next_epoch(vega=vega_instance)
|
|
||||||
|
|
||||||
for _ in range(3):
|
|
||||||
submit_order(vega_instance, "Key 1", market, "SIDE_BUY", 1, 110)
|
|
||||||
forward_time(vega_instance, True if _ < 3 - 1 else False)
|
|
||||||
|
|
||||||
# Initialize page and apply setups
|
|
||||||
with init_page(vega_instance, browser, request) as page_instance:
|
|
||||||
risk_accepted_setup(page_instance)
|
|
||||||
auth_setup(vega_instance, page_instance)
|
|
||||||
yield vega_instance, market, page_instance
|
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_my_trading_fees(
|
@pytest.fixture(scope="module", autouse=True)
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def setup_market_with_volume_discount_program(vega: VegaServiceNull):
|
||||||
) -> None:
|
market = setup_continuous_market(vega, custom_quantum=100000)
|
||||||
vega, market, page = setup_environment
|
vega.update_volume_discount_program(
|
||||||
|
proposal_key=MM_WALLET.name,
|
||||||
|
benefit_tiers=[
|
||||||
|
{
|
||||||
|
"minimum_running_notional_taker_volume": 100,
|
||||||
|
"volume_discount_factor": 0.1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minimum_running_notional_taker_volume": 200,
|
||||||
|
"volume_discount_factor": 0.2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
window_length=7,
|
||||||
|
)
|
||||||
|
next_epoch(vega=vega)
|
||||||
|
|
||||||
|
for _ in range(3):
|
||||||
|
submit_order(vega, "Key 1", market, "SIDE_BUY", 1, 110)
|
||||||
|
forward_time(vega, True if _ < 3 - 1 else False)
|
||||||
|
|
||||||
|
return market
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
|
||||||
|
def test_fees_page_discount_program_my_trading_fees(page: Page):
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("8.04%-8.04%")
|
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("8.04%-8.04%")
|
||||||
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
|
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
|
||||||
@ -66,10 +69,8 @@ def test_fees_page_discount_program_my_trading_fees(
|
|||||||
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
|
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_total_discount(
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def test_fees_page_discount_program_total_discount(page: Page):
|
||||||
) -> None:
|
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("20%")
|
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("20%")
|
||||||
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount20%")
|
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount20%")
|
||||||
@ -82,19 +83,15 @@ def test_fees_page_discount_program_total_discount(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_volume_discount_program_my_current_volume(
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def test_fees_page_volume_discount_program_my_current_volume(page: Page):
|
||||||
) -> None:
|
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(PAST_EPOCHS_VOLUME)).to_have_text("206")
|
expect(page.get_by_test_id(PAST_EPOCHS_VOLUME)).to_have_text("206")
|
||||||
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).not_to_be_visible()
|
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).not_to_be_visible()
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_discount(
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
def test_fees_page_discount_program_discount(page: Page):
|
||||||
) -> None:
|
|
||||||
vega, market, page = setup_environment
|
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
|
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
|
||||||
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
|
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
|
||||||
@ -107,8 +104,8 @@ def test_fees_page_discount_program_discount(
|
|||||||
expect(page.get_by_test_id("your-volume-tier-1").nth(1)).to_have_text("Your tier")
|
expect(page.get_by_test_id("your-volume-tier-1").nth(1)).to_have_text("Your tier")
|
||||||
|
|
||||||
|
|
||||||
def test_fees_page_discount_program_fees_by_market(setup_environment):
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
|
||||||
vega, market, page = setup_environment
|
def test_fees_page_discount_program_fees_by_market(page: Page):
|
||||||
page.goto("/#/fees")
|
page.goto("/#/fees")
|
||||||
pinned = page.locator(PINNED_ROW_LOCATOR)
|
pinned = page.locator(PINNED_ROW_LOCATOR)
|
||||||
row = page.locator(ROW_LOCATOR)
|
row = page.locator(ROW_LOCATOR)
|
||||||
@ -120,11 +117,12 @@ def test_fees_page_discount_program_fees_by_market(setup_environment):
|
|||||||
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
|
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
|
||||||
def test_deal_ticket_discount_program(
|
def test_deal_ticket_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page,
|
||||||
) -> None:
|
setup_market_with_volume_discount_program,
|
||||||
vega, market, page = setup_environment
|
):
|
||||||
page.goto(f"/#/markets/{market}")
|
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
|
||||||
page.get_by_test_id(ORDER_SIZE).fill("1")
|
page.get_by_test_id(ORDER_SIZE).fill("1")
|
||||||
page.get_by_test_id(ORDER_PRICE).fill("1")
|
page.get_by_test_id(ORDER_PRICE).fill("1")
|
||||||
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-20%")
|
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-20%")
|
||||||
@ -143,11 +141,12 @@ def test_deal_ticket_discount_program(
|
|||||||
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.0804 tDAI")
|
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.0804 tDAI")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
|
||||||
def test_fills_taker_discount_program(
|
def test_fills_taker_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page,
|
||||||
) -> None:
|
setup_market_with_volume_discount_program,
|
||||||
vega, market, page = setup_environment
|
):
|
||||||
page.goto(f"/#/markets/{market}")
|
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
expect(row.locator(COL_SIZE)).to_have_text("+1")
|
expect(row.locator(COL_SIZE)).to_have_text("+1")
|
||||||
@ -160,11 +159,13 @@ def test_fills_taker_discount_program(
|
|||||||
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("2.08035 tDAI")
|
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("2.08035 tDAI")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
|
||||||
def test_fills_maker_discount_program(
|
def test_fills_maker_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
vega: VegaServiceNull,
|
||||||
) -> None:
|
page: Page,
|
||||||
vega, market, page = setup_environment
|
setup_market_with_volume_discount_program,
|
||||||
page.goto(f"/#/markets/{market}")
|
):
|
||||||
|
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
|
||||||
change_keys(page, vega, MM_WALLET.name)
|
change_keys(page, vega, MM_WALLET.name)
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
@ -176,11 +177,11 @@ def test_fills_maker_discount_program(
|
|||||||
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("2.07 tDAI")
|
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("2.07 tDAI")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
|
||||||
def test_fills_maker_fee_tooltip_discount_program(
|
def test_fills_maker_fee_tooltip_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
vega, page: Page, setup_market_with_volume_discount_program
|
||||||
) -> None:
|
):
|
||||||
vega, market, page = setup_environment
|
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
|
||||||
page.goto(f"/#/markets/{market}")
|
|
||||||
change_keys(page, vega, MM_WALLET.name)
|
change_keys(page, vega, MM_WALLET.name)
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
@ -192,11 +193,12 @@ def test_fills_maker_fee_tooltip_discount_program(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
|
||||||
def test_fills_taker_fee_tooltip_discount_program(
|
def test_fills_taker_fee_tooltip_discount_program(
|
||||||
setup_environment: Tuple[VegaServiceNull, str, Page],
|
page: Page,
|
||||||
) -> None:
|
setup_market_with_volume_discount_program,
|
||||||
vega, market, page = setup_environment
|
):
|
||||||
page.goto(f"/#/markets/{market}")
|
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
|
||||||
page.get_by_test_id(FILLS).click()
|
page.get_by_test_id(FILLS).click()
|
||||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||||
# tbd - tooltip is not visible without this wait
|
# tbd - tooltip is not visible without this wait
|
||||||
|
@ -37,16 +37,19 @@ def validate_info_section(page: Page, fields: [[str, str]]):
|
|||||||
for rowNumber, field in enumerate(fields):
|
for rowNumber, field in enumerate(fields):
|
||||||
name, value = field
|
name, value = field
|
||||||
expect(
|
expect(
|
||||||
page.get_by_test_id("key-value-table-row").nth(rowNumber).locator("dt")
|
page.get_by_test_id(
|
||||||
|
"key-value-table-row").nth(rowNumber).locator("dt")
|
||||||
).to_contain_text(name)
|
).to_contain_text(name)
|
||||||
expect(
|
expect(
|
||||||
page.get_by_test_id("key-value-table-row").nth(rowNumber).locator("dd")
|
page.get_by_test_id(
|
||||||
|
"key-value-table-row").nth(rowNumber).locator("dd")
|
||||||
).to_contain_text(value)
|
).to_contain_text(value)
|
||||||
|
|
||||||
|
|
||||||
def test_market_info_current_fees(page: Page):
|
def test_market_info_current_fees(page: Page):
|
||||||
# 6002-MDET-101
|
# 6002-MDET-101
|
||||||
page.get_by_test_id(market_title_test_id).get_by_text("Current fees").click()
|
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||||
|
"Current fees").click()
|
||||||
fields = [
|
fields = [
|
||||||
["Maker Fee", "10%"],
|
["Maker Fee", "10%"],
|
||||||
["Infrastructure Fee", "0.05%"],
|
["Infrastructure Fee", "0.05%"],
|
||||||
@ -58,7 +61,8 @@ def test_market_info_current_fees(page: Page):
|
|||||||
|
|
||||||
def test_market_info_market_price(page: Page):
|
def test_market_info_market_price(page: Page):
|
||||||
# 6002-MDET-102
|
# 6002-MDET-102
|
||||||
page.get_by_test_id(market_title_test_id).get_by_text("Market price").click()
|
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||||
|
"Market price").click()
|
||||||
fields = [
|
fields = [
|
||||||
["Mark Price", "107.50"],
|
["Mark Price", "107.50"],
|
||||||
["Best Bid Price", "101.50"],
|
["Best Bid Price", "101.50"],
|
||||||
@ -67,10 +71,11 @@ def test_market_info_market_price(page: Page):
|
|||||||
]
|
]
|
||||||
validate_info_section(page, fields)
|
validate_info_section(page, fields)
|
||||||
|
|
||||||
#TODO: remove skip once volume is fixed
|
|
||||||
""" def test_market_info_market_volume(page: Page):
|
def test_market_info_market_volume(page: Page):
|
||||||
# 6002-MDET-103
|
# 6002-MDET-103
|
||||||
page.get_by_test_id(market_title_test_id).get_by_text("Market volume").click()
|
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||||
|
"Market volume").click()
|
||||||
fields = [
|
fields = [
|
||||||
["24 Hour Volume", "0 (0 )"],
|
["24 Hour Volume", "0 (0 )"],
|
||||||
["Open Interest", "1"],
|
["Open Interest", "1"],
|
||||||
@ -79,13 +84,12 @@ def test_market_info_market_price(page: Page):
|
|||||||
["Best Static Bid Volume", "1"],
|
["Best Static Bid Volume", "1"],
|
||||||
["Best Static Offer Volume", "1"],
|
["Best Static Offer Volume", "1"],
|
||||||
]
|
]
|
||||||
validate_info_section(page, fields) """
|
validate_info_section(page, fields)
|
||||||
|
|
||||||
|
|
||||||
def test_market_info_liquidation_strategy(page: Page):
|
def test_market_info_liquidation_strategy(page: Page):
|
||||||
page.get_by_test_id(market_title_test_id).get_by_text(
|
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||||
"Liquidation strategy"
|
"Liquidation strategy").click()
|
||||||
).click()
|
|
||||||
fields = [
|
fields = [
|
||||||
["Disposal Fraction", "1"],
|
["Disposal Fraction", "1"],
|
||||||
["Disposal Time Step", "1"],
|
["Disposal Time Step", "1"],
|
||||||
@ -97,14 +101,16 @@ def test_market_info_liquidation_strategy(page: Page):
|
|||||||
|
|
||||||
def test_market_info_liquidation(page: Page):
|
def test_market_info_liquidation(page: Page):
|
||||||
# 6002-MDET-104
|
# 6002-MDET-104
|
||||||
page.get_by_test_id(market_title_test_id).get_by_text("Liquidations").click()
|
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||||
|
"Liquidations").click()
|
||||||
fields = [["Insurance Pool Balance", "0.00 tDAI"]]
|
fields = [["Insurance Pool Balance", "0.00 tDAI"]]
|
||||||
validate_info_section(page, fields)
|
validate_info_section(page, fields)
|
||||||
|
|
||||||
|
|
||||||
def test_market_info_key_details(page: Page, vega: VegaServiceNull):
|
def test_market_info_key_details(page: Page, vega: VegaServiceNull):
|
||||||
# 6002-MDET-201
|
# 6002-MDET-201
|
||||||
page.get_by_test_id(market_title_test_id).get_by_text("Key details").click()
|
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||||
|
"Key details").click()
|
||||||
market_id = vega.find_market_id("BTC:DAI_2023")
|
market_id = vega.find_market_id("BTC:DAI_2023")
|
||||||
short_market_id = market_id[:6] + "…" + market_id[-4:]
|
short_market_id = market_id[:6] + "…" + market_id[-4:]
|
||||||
fields = [
|
fields = [
|
||||||
@ -150,7 +156,8 @@ def test_market_info_oracle(page: Page):
|
|||||||
|
|
||||||
def test_market_info_settlement_asset(page: Page, vega: VegaServiceNull):
|
def test_market_info_settlement_asset(page: Page, vega: VegaServiceNull):
|
||||||
# 6002-MDET-206
|
# 6002-MDET-206
|
||||||
page.get_by_test_id(market_title_test_id).get_by_text("Settlement asset").click()
|
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||||
|
"Settlement asset").click()
|
||||||
tdai_id = vega.find_asset_id("tDAI")
|
tdai_id = vega.find_asset_id("tDAI")
|
||||||
tdai_id_short = tdai_id[:6] + "…" + tdai_id[-4:]
|
tdai_id_short = tdai_id[:6] + "…" + tdai_id[-4:]
|
||||||
fields = [
|
fields = [
|
||||||
@ -204,7 +211,8 @@ def test_market_info_margin_scaling_factors(page: Page):
|
|||||||
|
|
||||||
def test_market_info_risk_factors(page: Page):
|
def test_market_info_risk_factors(page: Page):
|
||||||
# 6002-MDET-210
|
# 6002-MDET-210
|
||||||
page.get_by_test_id(market_title_test_id).get_by_text("Risk factors").click()
|
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||||
|
"Risk factors").click()
|
||||||
fields = [
|
fields = [
|
||||||
["Long", "0.05153"],
|
["Long", "0.05153"],
|
||||||
["Short", "0.05422"],
|
["Short", "0.05422"],
|
||||||
@ -224,7 +232,8 @@ def test_market_info_price_monitoring_bounds(page: Page):
|
|||||||
expect(page.locator("p.col-span-1").nth(0)).to_contain_text(
|
expect(page.locator("p.col-span-1").nth(0)).to_contain_text(
|
||||||
"99.9999% probability price bounds"
|
"99.9999% probability price bounds"
|
||||||
)
|
)
|
||||||
expect(page.locator("p.col-span-1").nth(1)).to_contain_text("Within 86,400 seconds")
|
expect(page.locator("p.col-span-1").nth(1)
|
||||||
|
).to_contain_text("Within 86,400 seconds")
|
||||||
fields = [
|
fields = [
|
||||||
["Highest Price", "138.66685 BTC"],
|
["Highest Price", "138.66685 BTC"],
|
||||||
["Lowest Price", "83.11038 BTC"],
|
["Lowest Price", "83.11038 BTC"],
|
||||||
@ -245,7 +254,7 @@ def test_market_info_liquidity_monitoring_parameters(page: Page):
|
|||||||
|
|
||||||
|
|
||||||
# Liquidity resolves to 3 results
|
# Liquidity resolves to 3 results
|
||||||
def test_market_info_liquidity(page: Page):
|
def test_market_info_liquidit(page: Page):
|
||||||
# 6002-MDET-213
|
# 6002-MDET-213
|
||||||
page.get_by_test_id(market_title_test_id).get_by_text(
|
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||||
"Liquidity", exact=True
|
"Liquidity", exact=True
|
||||||
@ -274,14 +283,17 @@ def test_market_info_proposal(page: Page, vega: VegaServiceNull):
|
|||||||
# 6002-MDET-301
|
# 6002-MDET-301
|
||||||
page.get_by_test_id(market_title_test_id).get_by_text("Proposal").click()
|
page.get_by_test_id(market_title_test_id).get_by_text("Proposal").click()
|
||||||
first_link = (
|
first_link = (
|
||||||
page.get_by_test_id("accordion-content").get_by_test_id("external-link").first
|
page.get_by_test_id(
|
||||||
|
"accordion-content").get_by_test_id("external-link").first
|
||||||
)
|
)
|
||||||
second_link = (
|
second_link = (
|
||||||
page.get_by_test_id("accordion-content").get_by_test_id("external-link").nth(1)
|
page.get_by_test_id(
|
||||||
|
"accordion-content").get_by_test_id("external-link").nth(1)
|
||||||
)
|
)
|
||||||
expect(first_link).to_have_text("View governance proposal")
|
expect(first_link).to_have_text("View governance proposal")
|
||||||
expect(first_link).to_have_attribute(
|
expect(first_link).to_have_attribute(
|
||||||
"href", re.compile(rf'(\/proposals\/{vega.find_market_id("BTC:DAI_2023")})')
|
"href", re.compile(
|
||||||
|
rf'(\/proposals\/{vega.find_market_id("BTC:DAI_2023")})')
|
||||||
)
|
)
|
||||||
expect(second_link).to_have_text("Propose a change to market")
|
expect(second_link).to_have_text("Propose a change to market")
|
||||||
|
|
||||||
@ -292,10 +304,12 @@ def test_market_info_proposal(page: Page, vega: VegaServiceNull):
|
|||||||
|
|
||||||
|
|
||||||
def test_market_info_succession_line(page: Page, vega: VegaServiceNull):
|
def test_market_info_succession_line(page: Page, vega: VegaServiceNull):
|
||||||
page.get_by_test_id(market_title_test_id).get_by_text("Succession line").click()
|
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||||
|
"Succession line").click()
|
||||||
market_id = vega.find_market_id("BTC:DAI_2023")
|
market_id = vega.find_market_id("BTC:DAI_2023")
|
||||||
succession_line = page.get_by_test_id("succession-line-item")
|
succession_line = page.get_by_test_id("succession-line-item")
|
||||||
expect(succession_line.get_by_test_id("external-link")).to_have_text("BTC:DAI_2023")
|
expect(succession_line.get_by_test_id(
|
||||||
|
"external-link")).to_have_text("BTC:DAI_2023")
|
||||||
expect(succession_line.get_by_test_id("external-link")).to_have_attribute(
|
expect(succession_line.get_by_test_id("external-link")).to_have_attribute(
|
||||||
"href", re.compile(rf"(\/proposals\/{market_id})")
|
"href", re.compile(rf"(\/proposals\/{market_id})")
|
||||||
)
|
)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user