Compare commits

..
67 changed files with 1053 additions and 1022 deletions
-1
View File
@@ -4,7 +4,6 @@ on:
push:
branches:
- release/*
- develop
pull_request:
types:
- opened
+18 -30
View File
@@ -37,25 +37,18 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
# https://docs.github.com/en/actions/learn-github-actions/contexts
- name: Define variables
- name: Check node version
id: tags
run: |
nodeVersion=$(cat .nvmrc | head -n 1)
echo ::set-output name=nodeVersion::${nodeVersion}
if [[ "${{ github.event_name }}" = "push" ]]; then
domain="vega.rocks"
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
if [[ "${{ github.ref }}" =~ .*mainnet.* ]]; then
domain="vega.community"
fi
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
envName="stagnet3"
fi
bucketName="${{ matrix.app }}.${envName}.${domain}"
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
bucketName="${{ github.event.repository.name }}-$envName"
echo ::set-output name=bucketName::${bucketName}
echo ::set-output name=envName::${envName}
fi
nodeVersion=$(cat .nvmrc | head -n 1)
echo ::set-output name=nodeVersion::${nodeVersion}
- name: Build and export to local Docker
id: docker_build
@@ -75,15 +68,14 @@ jobs:
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat ipfs-hash
echo "List html directory"
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local sh -c 'apk add --update tree; tree .'
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local ls -lah
- name: Copy dist to local filesystem
run: |
echo "Copy dist to local filesystem"
docker create --name=dist ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
docker cp dist:/usr/share/nginx/html dist
echo "check local dist files"
tree dist
echo "Check local dist"
ls -al dist
- name: Publish dist as docker image
uses: docker/build-push-action@v3
@@ -96,18 +88,14 @@ jobs:
tags: |
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ github.event.pull_request.head.sha || github.sha }}
# bucket creation in github.com/vegaprotocol/terraform//frontend
- name: Publish dist to s3
uses: jakejarvis/s3-sync-action@master
if: ${{ github.event_name == 'push' }}
with:
args: --acl private --follow-symlinks --delete
env:
AWS_S3_BUCKET: ${{ steps.tags.outputs.bucketName }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: 'eu-west-1'
SOURCE_DIR: 'dist/${{ matrix.app }}'
# - uses: shallwefootball/s3-upload-action@master
# if: ${{ github.event_name == 'push' }}
# name: Upload dist S3
# with:
# aws_key_id: ${{ secrets.AWS_KEY_ID }}
# aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY}}
# aws_bucket: ${{ steps.tags.outputs.bucketName }}
# source_dir: 'dist'
- name: Add preview label
uses: actions-ecosystem/action-add-labels@v1
-1
View File
@@ -24,6 +24,5 @@ EXPOSE 80
# Copy dist
WORKDIR /usr/share/nginx/html
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
RUN rm -rf /usr/share/nginx/html/*
COPY --from=build /app/dist/apps/${APP} /usr/share/nginx/html
RUN apk add --no-cache go-ipfs; ipfs init && echo "$(ipfs add -rQ .)" > ipfs-hash; apk del go-ipfs
@@ -10,7 +10,7 @@ export const Footer = () => {
const [nodeSwitcherOpen, setNodeSwitcherOpen] = useState(false);
const { screenSize } = useScreenDimensions();
const showFullFeedbackLabel = useMemo(
() => ['md', 'lg', 'xl', 'xxl', 'xxxl'].includes(screenSize),
() => ['lg', 'xl', 'xxl', 'xxxl'].includes(screenSize),
[screenSize]
);
@@ -44,8 +44,7 @@ describe(
function () {
before('connect wallets and set approval limit', function () {
cy.visit('/');
ethereumWalletConnect();
cy.associateTokensToVegaWallet('1');
vegaWalletSetSpecifiedApprovalAmount('1000');
});
beforeEach('visit proposals tab', function () {
@@ -214,7 +213,6 @@ describe(
// 3001-VOTE-042, 3001-VOTE-057, 3001-VOTE-058, 3001-VOTE-059, 3001-VOTE-060
it('Newly created proposal details - ability to increase associated tokens - by voting again after association', function () {
vegaWalletSetSpecifiedApprovalAmount('1000');
createRawProposal();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getSubmittedProposalFromProposalList(rawProposal.rationale.title)
@@ -13,6 +13,7 @@ import {
createUpdateNetworkProposalTxBody,
createFreeFormProposalTxBody,
} from '../../support/proposal.functions';
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions';
@@ -32,6 +33,10 @@ context(
before('Connect wallets and set approval', function () {
cy.visit('/');
vegaWalletSetSpecifiedApprovalAmount('1000');
cy.connectVegaWallet();
ethereumWalletConnect();
ensureSpecifiedUnstakedTokensAreAssociated('1');
cy.clearLocalStorage();
});
beforeEach('visit proposals', function () {
@@ -109,7 +114,7 @@ context(
navigateTo(navigation.proposals);
cy.reload();
waitForSpinner();
cy.get(openProposals, { timeout: 6000 }).within(() => {
cy.get(openProposals).within(() => {
cy.contains(proposalTitle)
.parentsUntil('[data-testid="proposals-list-item"]')
.within(() => cy.get(viewProposalButton).click());
@@ -232,7 +232,7 @@ context(
it('Unable to create a freeform proposal - when json parent section contains unexpected field', function () {
const errorMsg =
'Invalid params: the transaction does not use a valid Vega command: unknown field "unexpected" in vega.commands.v1.ProposalSubmission';
'Invalid params: the transaction does not use a valid Vega command: unknown field unexpected" in vega.commands.v1.ProposalSubmission';
// 3001-VOTE-038 3002-PROP-013 3002-PROP-014
goToMakeNewProposal(governanceProposalType.RAW);
@@ -313,7 +313,7 @@ context(
it('Unable to vote on a proposal - when vega wallet disconnected - option to connect from within', function () {
createRawProposal();
cy.get('[data-testid="manage-vega-wallet"]:visible').click();
cy.get('[data-testid="manage-vega-wallet"]').click();
cy.get('[data-testid="disconnect"]').click();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getSubmittedProposalFromProposalList(
@@ -218,7 +218,7 @@ context(
it('Unable to submit new market proposal with missing/invalid fields', function () {
const errorMsg =
'Invalid params: the transaction does not use a valid Vega command: unknown field "invalid" in vega.NewMarket';
'Invalid params: the transaction is not a valid Vega command: unknown field "filters" in vega.DataSourceDefinition';
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
cy.get(newProposalSubmitButton).should('be.visible').click();
@@ -436,7 +436,7 @@ context(
});
});
it('Able to submit update asset proposal using max deadline', function () {
it.only('Able to submit update asset proposal using max deadline', function () {
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
enterUpdateAssetProposalDetails();
cy.get(maxVoteDeadline).click();
@@ -25,11 +25,11 @@ const vegaWalletUnstakedBalance =
'[data-testid="vega-wallet-balance-unstaked"]';
const txTimeout = Cypress.env('txTimeout');
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
const ethWalletAssociateButton = '[data-testid="associate-btn"]:visible';
const ethWalletAssociateButton = '[data-testid="associate-btn"]';
const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]';
const tokenAmountInputBox = '[data-testid="token-amount-input"]';
const tokenSubmitButton = '[data-testid="token-input-submit-button"]';
const ethWalletDissociateButton = '[href="/token/disassociate"]:visible';
const ethWalletDissociateButton = '[href="/token/disassociate"]';
const vestingContractSection = '[data-testid="vega-in-vesting-contract"]';
const vegaInWalletSection = '[data-testid="vega-in-wallet"]';
const connectedVegaKey = '[data-testid="connected-vega-key"]';
@@ -78,12 +78,12 @@ context(
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
6
3
);
validateWalletCurrency('Associated', '0.00');
validateWalletCurrency('Pending association', '2.00');
validateWalletCurrency('Total associated after pending', '2.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
// 0005-ETXN-002
verifyEthWalletAssociatedBalance('2.0');
@@ -111,12 +111,12 @@ context(
stakingPageDisassociateTokens('2');
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
6
3
);
validateWalletCurrency('Associated', '2.00');
validateWalletCurrency('Pending association', '2.00');
validateWalletCurrency('Total associated after pending', '0.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
cy.getByTestId('eth-wallet-associated-balances', txTimeout).should(
'not.exist'
);
@@ -192,12 +192,12 @@ context(
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
6
3
);
validateWalletCurrency('Associated', '0.00');
validateWalletCurrency('Pending association', '2.00');
validateWalletCurrency('Total associated after pending', '2.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
verifyEthWalletAssociatedBalance('2.0');
verifyEthWalletTotalAssociatedBalance('2.0');
cy.get(vegaWallet).within(() => {
@@ -210,12 +210,12 @@ context(
});
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
6
3
);
validateWalletCurrency('Associated', '2.00');
validateWalletCurrency('Pending association', '1.00');
validateWalletCurrency('Total associated after pending', '1.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
verifyEthWalletAssociatedBalance('1.0');
verifyEthWalletTotalAssociatedBalance('1.0');
});
@@ -266,7 +266,7 @@ context(
// 1004-ASSO-008
// 1004-ASSO-010
// No warning visible as described in AC, but the button is disabled
cy.get(ethWalletAssociateButton).click();
cy.get(ethWalletAssociateButton).first().click();
cy.get(associateWalletRadioButton, { timeout: 30000 }).click();
cy.get(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input
cy.get(tokenAmountInputBox, { timeout: 10000 }).type('6500000');
@@ -278,12 +278,12 @@ context(
vegaWalletAssociate('2');
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
6
3
);
validateWalletCurrency('Associated', '0.00');
validateWalletCurrency('Pending association', '2.00');
validateWalletCurrency('Total associated after pending', '2.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
validateWalletCurrency('Associated', '2.00');
});
@@ -294,24 +294,24 @@ context(
});
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
6
3
);
validateWalletCurrency('Associated', '2.00');
validateWalletCurrency('Pending association', '2.00');
validateWalletCurrency('Total associated after pending', '0.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
validateWalletCurrency('Associated', '0.00');
});
it('Able to associate tokens to different public key of connected vega wallet', function () {
cy.get(ethWalletAssociateButton).click();
cy.get(ethWalletAssociateButton).first().click();
cy.get(associateWalletRadioButton).click();
cy.get(connectedVegaKey).should(
'have.text',
Cypress.env('vegaWalletPublicKey')
);
cy.get('[data-testid="manage-vega-wallet"]:visible').click();
cy.get('[data-testid="manage-vega-wallet"]').click();
cy.get('[data-testid="select-keypair-button"]').eq(0).click();
cy.get(connectedVegaKey).should(
'have.text',
@@ -166,7 +166,6 @@ export function goToMakeNewProposal(proposalType: string) {
navigateTo(navigation.proposals);
cy.get(newProposalButton).should('be.visible').click();
cy.url().should('include', '/proposals/propose');
cy.get(navigation.pageSpinner, { timeout: 20000 }).should('not.exist');
cy.get('li').should('contain.text', proposalType).and('be.visible');
cy.get('li').contains(proposalType).click();
}
@@ -8,7 +8,6 @@ import {
} from '@vegaprotocol/smart-contracts';
import { ethers, Wallet } from 'ethers';
const associatedAmountInWallet = '[data-testid="associated-amount"]:visible';
const vegaWalletContainer = 'aside [data-testid="vega-wallet"]';
const vegaWalletMnemonic = Cypress.env('vegaWalletMnemonic');
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey');
@@ -60,7 +59,7 @@ export async function faucetAsset(assetEthAddress: string) {
}
export async function vegaWalletTeardown() {
cy.get(associatedAmountInWallet)
cy.get('[data-testid="associated-amount"]')
.should('be.visible')
.invoke('text')
.then((associatedAmount) => {
@@ -69,12 +68,12 @@ export async function vegaWalletTeardown() {
$body.find('[data-testid="eth-wallet-associated-balances"]').length ||
associatedAmount != '0.00'
) {
vegaWalletTeardownStaking(stakingBridgeContract);
vegaWalletTeardownVesting(vestingContract);
vegaWalletTeardownStaking(stakingBridgeContract);
}
});
cy.get(vegaWalletContainer).within(() => {
cy.get(associatedAmountInWallet, {
cy.getByTestId('associated-amount', {
timeout: transactionTimeout,
}).contains('0.00', {
timeout: transactionTimeout,
@@ -91,7 +90,7 @@ export async function vegaWalletSetSpecifiedApprovalAmount(
await promiseWithTimeout(
token.approve(
ethStakingBridgeContractAddress,
resetAmount + '0'.repeat(18)
resetAmount.concat('000000000000000000')
),
10 * 60 * 1000,
'set approval amount'
@@ -105,23 +104,12 @@ async function vegaWalletTeardownStaking(stakingBridgeContract: StakingBridge) {
{ timeout: transactionTimeout, log: false }
).then((stakeBalance) => {
if (Number(stakeBalance) != 0) {
cy.get('[data-testid="vega-wallet-balance-unstaked"]:visible').within(
() => {
cy.get(associatedAmountInWallet)
.invoke('text')
.then(($walletAmount) => {
cy.wrap(
stakingBridgeContract.remove_stake(
String(stakeBalance),
vegaWalletPubKey
),
{ timeout: transactionTimeout, log: false }
);
cy.get(associatedAmountInWallet, {
timeout: transactionTimeout,
}).should('not.have.text', $walletAmount);
});
}
cy.wrap(
stakingBridgeContract.remove_stake(
String(stakeBalance),
vegaWalletPubKey
),
{ timeout: transactionTimeout, log: false }
);
}
});
@@ -136,6 +124,7 @@ async function vegaWalletTeardownVesting(vestingContract: TokenVesting) {
if (Number(vestingAmount) != 0) {
// Wait needed to allow time for ganache to process tx for stakingBridgeContract.remove_stake
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000);
cy.wrap(
vestingContract.remove_stake(String(vestingAmount), vegaWalletPubKey),
{ timeout: transactionTimeout, log: false }
+59 -410
View File
@@ -3,9 +3,9 @@
"tranche_id": 56,
"tranche_start": "2023-04-20T00:00:00.000Z",
"tranche_end": "2023-05-20T00:00:00.000Z",
"total_added": "15711.125",
"total_added": "13748.125",
"total_removed": "0",
"locked_amount": "15711.125",
"locked_amount": "13748.125",
"deposits": [
{
"amount": "241.5",
@@ -62,31 +62,6 @@
"user": "0x4F37Fe90617Cc3eCB6DF715a8ceDcFb70417534d",
"tx": "0x5f2027e0aa478414b7a685465f465cc2e39a156ec6a35806367cbdf6092801ce"
},
{
"amount": "94.875",
"user": "0xdC483901425B2EA6494EaE01ADB6565936E25124",
"tx": "0x14ca69443a14b0f35538856a4fdda6a2b287d7ac6e7c4e600fb797c4c6d44098"
},
{
"amount": "1542.125",
"user": "0xE9F41a0090fcc7eaf626037003AAD44B17098E7C",
"tx": "0x34cc25a41e2bf106663fa4cf9880227b0823cf53e1e6069d4b7c526a1b6c6d21"
},
{
"amount": "84.5",
"user": "0x6A228Fffda4D1B3C773b9ce38DA43592581b36FC",
"tx": "0x687fa99f98028fc31d979c3cc72dec17f95d1e6afa305dec9d89632699a24e77"
},
{
"amount": "138",
"user": "0x268070d5EEd5b24E34a5F4C17B5482178b18089D",
"tx": "0x7543f201673298844d68e4dd15222ab85bdd2796b5b95c739d1a1d5c198806e8"
},
{
"amount": "103.5",
"user": "0x697cEF6741F519621fE14c72041e4B8B1f7e2c8A",
"tx": "0xc7483de16af39896b3ae052dd8a6e01fb3dc3794ceb9d2a76d81436992af320e"
},
{
"amount": "50",
"user": "0x15024E62134A8BFFCce11f5ce58CeCDe853038D7",
@@ -301,81 +276,6 @@
"withdrawn_tokens": "0",
"remaining_tokens": "136.25"
},
{
"address": "0xdC483901425B2EA6494EaE01ADB6565936E25124",
"deposits": [
{
"amount": "94.875",
"user": "0xdC483901425B2EA6494EaE01ADB6565936E25124",
"tranche_id": 56,
"tx": "0x14ca69443a14b0f35538856a4fdda6a2b287d7ac6e7c4e600fb797c4c6d44098"
}
],
"withdrawals": [],
"total_tokens": "94.875",
"withdrawn_tokens": "0",
"remaining_tokens": "94.875"
},
{
"address": "0xE9F41a0090fcc7eaf626037003AAD44B17098E7C",
"deposits": [
{
"amount": "1542.125",
"user": "0xE9F41a0090fcc7eaf626037003AAD44B17098E7C",
"tranche_id": 56,
"tx": "0x34cc25a41e2bf106663fa4cf9880227b0823cf53e1e6069d4b7c526a1b6c6d21"
}
],
"withdrawals": [],
"total_tokens": "1542.125",
"withdrawn_tokens": "0",
"remaining_tokens": "1542.125"
},
{
"address": "0x6A228Fffda4D1B3C773b9ce38DA43592581b36FC",
"deposits": [
{
"amount": "84.5",
"user": "0x6A228Fffda4D1B3C773b9ce38DA43592581b36FC",
"tranche_id": 56,
"tx": "0x687fa99f98028fc31d979c3cc72dec17f95d1e6afa305dec9d89632699a24e77"
}
],
"withdrawals": [],
"total_tokens": "84.5",
"withdrawn_tokens": "0",
"remaining_tokens": "84.5"
},
{
"address": "0x268070d5EEd5b24E34a5F4C17B5482178b18089D",
"deposits": [
{
"amount": "138",
"user": "0x268070d5EEd5b24E34a5F4C17B5482178b18089D",
"tranche_id": 56,
"tx": "0x7543f201673298844d68e4dd15222ab85bdd2796b5b95c739d1a1d5c198806e8"
}
],
"withdrawals": [],
"total_tokens": "138",
"withdrawn_tokens": "0",
"remaining_tokens": "138"
},
{
"address": "0x697cEF6741F519621fE14c72041e4B8B1f7e2c8A",
"deposits": [
{
"amount": "103.5",
"user": "0x697cEF6741F519621fE14c72041e4B8B1f7e2c8A",
"tranche_id": 56,
"tx": "0xc7483de16af39896b3ae052dd8a6e01fb3dc3794ceb9d2a76d81436992af320e"
}
],
"withdrawals": [],
"total_tokens": "103.5",
"withdrawn_tokens": "0",
"remaining_tokens": "103.5"
},
{
"address": "0x15024E62134A8BFFCce11f5ce58CeCDe853038D7",
"deposits": [
@@ -600,30 +500,15 @@
"tranche_id": 54,
"tranche_start": "2023-04-06T00:00:00.000Z",
"tranche_end": "2023-05-06T00:00:00.000Z",
"total_added": "8865",
"total_removed": "212.71903124703",
"locked_amount": "6720.641319444444729",
"total_added": "8694",
"total_removed": "52.2185023074",
"locked_amount": "7387.7868749999996136",
"deposits": [
{
"amount": "33",
"user": "0xBf1AaB792D729fA125e6D7122D4b916a1E1C44B1",
"tx": "0xc7736d362d5ffdd16dc26f25047f52fa6238f60837e831b149b6ebb25a0d9281"
},
{
"amount": "33",
"user": "0xB0Dbf35C0918536B62a2FbcCC852bCffDB41d6aF",
"tx": "0x60989e406ce3e35e39f93176a45ff46f7c0a293d538a27a685efa7bd350ad92e"
},
{
"amount": "24",
"user": "0xa8bdC133265C7Aab74eA1D00527925e47275D9Ad",
"tx": "0x8e2990dd83380f38f32cd3964e720e86b53a7a5d5f45adc4e0c012f5c0022101"
},
{
"amount": "114",
"user": "0xfD181C18D0442cBbad1207110D09b5fCa8CC8218",
"tx": "0xaa9cfb8f54f0d9066fe0ffaa6742acfb9626485a0497750e61e3d5dc925dfb37"
},
{
"amount": "33",
"user": "0xb5e340788922791727C240c33D27060157845291",
@@ -741,16 +626,6 @@
}
],
"withdrawals": [
{
"amount": "5.46866782407",
"user": "0x92A1e98C6f09970e45645Cbe57c6DcaF4547c8FE",
"tx": "0xb9b9b6b0882ad6e197e540e034c39e785f8b77372ac03f93d2f8960e8cde658b"
},
{
"amount": "155.03186111556",
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
"tx": "0x7da34162df1b167ed5a3de6d98759af7100bcd51ec4e4c55abce2d145c98ba15"
},
{
"amount": "52.2185023074",
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
@@ -773,51 +648,6 @@
"withdrawn_tokens": "0",
"remaining_tokens": "33"
},
{
"address": "0xB0Dbf35C0918536B62a2FbcCC852bCffDB41d6aF",
"deposits": [
{
"amount": "33",
"user": "0xB0Dbf35C0918536B62a2FbcCC852bCffDB41d6aF",
"tranche_id": 54,
"tx": "0x60989e406ce3e35e39f93176a45ff46f7c0a293d538a27a685efa7bd350ad92e"
}
],
"withdrawals": [],
"total_tokens": "33",
"withdrawn_tokens": "0",
"remaining_tokens": "33"
},
{
"address": "0xa8bdC133265C7Aab74eA1D00527925e47275D9Ad",
"deposits": [
{
"amount": "24",
"user": "0xa8bdC133265C7Aab74eA1D00527925e47275D9Ad",
"tranche_id": 54,
"tx": "0x8e2990dd83380f38f32cd3964e720e86b53a7a5d5f45adc4e0c012f5c0022101"
}
],
"withdrawals": [],
"total_tokens": "24",
"withdrawn_tokens": "0",
"remaining_tokens": "24"
},
{
"address": "0xfD181C18D0442cBbad1207110D09b5fCa8CC8218",
"deposits": [
{
"amount": "114",
"user": "0xfD181C18D0442cBbad1207110D09b5fCa8CC8218",
"tranche_id": 54,
"tx": "0xaa9cfb8f54f0d9066fe0ffaa6742acfb9626485a0497750e61e3d5dc925dfb37"
}
],
"withdrawals": [],
"total_tokens": "114",
"withdrawn_tokens": "0",
"remaining_tokens": "114"
},
{
"address": "0xb5e340788922791727C240c33D27060157845291",
"deposits": [
@@ -964,12 +794,6 @@
}
],
"withdrawals": [
{
"amount": "155.03186111556",
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
"tranche_id": 54,
"tx": "0x7da34162df1b167ed5a3de6d98759af7100bcd51ec4e4c55abce2d145c98ba15"
},
{
"amount": "52.2185023074",
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
@@ -978,8 +802,8 @@
}
],
"total_tokens": "858",
"withdrawn_tokens": "207.25036342296",
"remaining_tokens": "650.74963657704"
"withdrawn_tokens": "52.2185023074",
"remaining_tokens": "805.7814976926"
},
{
"address": "0x0bBf7580e036eA5D69ABe679CC90117EeC2e3dc1",
@@ -1141,17 +965,10 @@
"tx": "0x27cf29a5e602dfa51987ac99aa3bc05fbf042095f32d249b65429311405c10f5"
}
],
"withdrawals": [
{
"amount": "5.46866782407",
"user": "0x92A1e98C6f09970e45645Cbe57c6DcaF4547c8FE",
"tranche_id": 54,
"tx": "0xb9b9b6b0882ad6e197e540e034c39e785f8b77372ac03f93d2f8960e8cde658b"
}
],
"withdrawals": [],
"total_tokens": "33",
"withdrawn_tokens": "5.46866782407",
"remaining_tokens": "27.53133217593"
"withdrawn_tokens": "0",
"remaining_tokens": "33"
},
{
"address": "0xf9c6C5F942B94Db9dedC550956865cf99D743959",
@@ -1289,7 +1106,7 @@
"tranche_start": "2023-03-06T00:00:00.000Z",
"tranche_end": "2023-04-06T00:00:00.000Z",
"total_added": "14099",
"total_removed": "2337.49002352036",
"total_removed": "2255.42804995396",
"locked_amount": "0",
"deposits": [
{
@@ -2074,21 +1891,6 @@
"user": "0x031a9377440458daDEF934cA9007168190Ec7965",
"tx": "0xff1f72636535e61a142980a3cade2f274471572cbac5b18d5199778c2b779cdf"
},
{
"amount": "22.0619735664",
"user": "0xC6D7208DaDEe4F431bd0f3f11E7d4c91fF51bfb2",
"tx": "0xe7ed2d866425fe4d564dce3e14c17cb3965ead15c7a3ba98edf3dbf2058924c8"
},
{
"amount": "30",
"user": "0xFD357d3eD3134a00ed23761af6082ef36346130f",
"tx": "0x9177e9b46c56e8143455137ce053b73df8a89573e7e956992aa94eca77f6e514"
},
{
"amount": "30",
"user": "0x4081455DB9Ec3B9b66f370Fa12161E6763c40779",
"tx": "0xaf39ced29169a9e88e845cb6c069496920a0ad473b5bc4a0896df4154f51de10"
},
{
"amount": "19.9634296593",
"user": "0x47e6217C1667e2B1fD177Ab8fD89037bCEC7dc6C",
@@ -3140,12 +2942,6 @@
}
],
"withdrawals": [
{
"amount": "22.0619735664",
"user": "0xC6D7208DaDEe4F431bd0f3f11E7d4c91fF51bfb2",
"tranche_id": 53,
"tx": "0xe7ed2d866425fe4d564dce3e14c17cb3965ead15c7a3ba98edf3dbf2058924c8"
},
{
"amount": "7.937219982",
"user": "0xC6D7208DaDEe4F431bd0f3f11E7d4c91fF51bfb2",
@@ -3160,8 +2956,8 @@
}
],
"total_tokens": "30",
"withdrawn_tokens": "30",
"remaining_tokens": "0"
"withdrawn_tokens": "7.9380264336",
"remaining_tokens": "22.0619735664"
},
{
"address": "0xAA4110D07E062bAA025BECb15B795447F58B8d2E",
@@ -3297,17 +3093,10 @@
"tx": "0xecbb3424e425019a8ebdb9326f662c3520f220fbecdfdaa4770c282001a0f5eb"
}
],
"withdrawals": [
{
"amount": "30",
"user": "0x4081455DB9Ec3B9b66f370Fa12161E6763c40779",
"tranche_id": 53,
"tx": "0xaf39ced29169a9e88e845cb6c069496920a0ad473b5bc4a0896df4154f51de10"
}
],
"withdrawals": [],
"total_tokens": "30",
"withdrawn_tokens": "30",
"remaining_tokens": "0"
"withdrawn_tokens": "0",
"remaining_tokens": "30"
},
{
"address": "0xDF4717EDe8db8e2D66373b3ECFa40D1Fa9cBfb73",
@@ -3889,17 +3678,10 @@
"tx": "0x819f57b15fef080ab898405133d798a683e5fd805682901e160f5c0187c5fb16"
}
],
"withdrawals": [
{
"amount": "30",
"user": "0xFD357d3eD3134a00ed23761af6082ef36346130f",
"tranche_id": 53,
"tx": "0x9177e9b46c56e8143455137ce053b73df8a89573e7e956992aa94eca77f6e514"
}
],
"withdrawals": [],
"total_tokens": "30",
"withdrawn_tokens": "30",
"remaining_tokens": "0"
"withdrawn_tokens": "0",
"remaining_tokens": "30"
},
{
"address": "0x5EFee0C80F931CFD9dd54150f7fB81Ab8A7D25c7",
@@ -4276,7 +4058,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "86666.297",
"total_removed": "0",
"locked_amount": "55975.3362468715096583895",
"locked_amount": "56628.1640897288896285793",
"deposits": [
{
"amount": "86666.297",
@@ -4342,7 +4124,7 @@
"tranche_end": "2023-06-01T00:00:00.000Z",
"total_added": "2500",
"total_removed": "0",
"locked_amount": "669.55064611314625",
"locked_amount": "707.31742216117225",
"deposits": [
{
"amount": "2500",
@@ -4463,7 +4245,7 @@
"tranche_end": "2023-09-01T00:00:00.000Z",
"total_added": "17500",
"total_removed": "0",
"locked_amount": "13385.91045189210925",
"locked_amount": "13647.404325181158",
"deposits": [
{
"amount": "12500",
@@ -4729,8 +4511,8 @@
"tranche_start": "2023-02-01T00:00:00.000Z",
"tranche_end": "2023-08-01T00:00:00.000Z",
"total_added": "37500",
"total_removed": "12151.298246325",
"locked_amount": "22736.8688612645775",
"total_removed": "12043.9778043",
"locked_amount": "23306.5003453038675",
"deposits": [
{
"amount": "7500",
@@ -4749,11 +4531,6 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xe12a6d600113d4db203454713340e902cb62aa16534dec0b8d42772868e9cfe7"
},
{
"amount": "107.320442025",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x07414226f479239baa4081a211d749f54d8fe507067b1d3b122eb47bc69ff569"
},
{
"amount": "158.943370125",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -4898,12 +4675,6 @@
"tranche_id": 34,
"tx": "0xe12a6d600113d4db203454713340e902cb62aa16534dec0b8d42772868e9cfe7"
},
{
"amount": "107.320442025",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 34,
"tx": "0x07414226f479239baa4081a211d749f54d8fe507067b1d3b122eb47bc69ff569"
},
{
"amount": "158.943370125",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -5044,8 +4815,8 @@
}
],
"total_tokens": "7500",
"withdrawn_tokens": "2915.848967925",
"remaining_tokens": "4584.151032075"
"withdrawn_tokens": "2808.5285259",
"remaining_tokens": "4691.4714741"
},
{
"address": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
@@ -5083,7 +4854,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "129999.45",
"total_removed": "0",
"locked_amount": "55924.265795633105973795",
"locked_amount": "56576.4980152258274844015",
"deposits": [
{
"amount": "129999.45",
@@ -5116,7 +4887,7 @@
"tranche_end": "2024-04-01T00:00:00.000Z",
"total_added": "54144.7663",
"total_removed": "0",
"locked_amount": "52331.55083829013672190566",
"locked_amount": "52738.29065672785809931968",
"deposits": [
{
"amount": "54144.7663",
@@ -5149,7 +4920,7 @@
"tranche_end": "2023-09-03T00:00:00.000Z",
"total_added": "62600",
"total_removed": "0",
"locked_amount": "24481.45142059868271",
"locked_amount": "24952.99600456621016",
"deposits": [
{
"amount": "10000",
@@ -5342,7 +5113,7 @@
"tranche_end": "2023-09-17T00:00:00.000Z",
"total_added": "5000",
"total_removed": "0",
"locked_amount": "2147.16831557584975",
"locked_amount": "2184.831621004566",
"deposits": [
{
"amount": "5000",
@@ -5882,8 +5653,8 @@
"tranche_start": "2022-11-01T00:00:00.000Z",
"tranche_end": "2023-05-01T00:00:00.000Z",
"total_added": "22500",
"total_removed": "6727.9921539",
"locked_amount": "2205.657228360958425",
"total_removed": "6620.677467",
"locked_amount": "2547.436118784530175",
"deposits": [
{
"amount": "7500",
@@ -5902,11 +5673,6 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x86d038a897c455e098af47a53ffd861a150c68058e75d84b9224d08061075cb2"
},
{
"amount": "107.3146869",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xea8772c7ce65ecfdf87e34cf61b2614212c07d195a9e4d6962fcf758ba08c442"
},
{
"amount": "158.9433702",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -6106,12 +5872,6 @@
"tranche_id": 33,
"tx": "0x86d038a897c455e098af47a53ffd861a150c68058e75d84b9224d08061075cb2"
},
{
"amount": "107.3146869",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 33,
"tx": "0xea8772c7ce65ecfdf87e34cf61b2614212c07d195a9e4d6962fcf758ba08c442"
},
{
"amount": "158.9433702",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -6330,8 +6090,8 @@
}
],
"total_tokens": "7500",
"withdrawn_tokens": "6727.9921539",
"remaining_tokens": "772.0078461"
"withdrawn_tokens": "6620.677467",
"remaining_tokens": "879.322533"
},
{
"address": "0x2539b51EbDE65a75672aBcfE9439a706a99D18D1",
@@ -6356,7 +6116,7 @@
"tranche_end": "2023-06-02T00:00:00.000Z",
"total_added": "1939928.38",
"total_removed": "928642.9598472029154",
"locked_amount": "264379.2170894088612502104",
"locked_amount": "278992.0401065640187107672",
"deposits": [
{
"amount": "1852091.69",
@@ -40171,8 +39931,8 @@
"tranche_start": "2022-03-05T00:00:00.000Z",
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "3732368.4671",
"total_removed": "715655.108029600523393",
"locked_amount": "430760.134328755393533225946",
"total_removed": "700133.348465855088393",
"locked_amount": "453214.9556615113089817251",
"deposits": [
{
"amount": "1998.95815",
@@ -40341,11 +40101,6 @@
}
],
"withdrawals": [
{
"amount": "15521.759563745435",
"user": "0xf110D577F07ED846D2308050cc0D6CCC2bf9fb2C",
"tx": "0x1048d5b3f41b93036b8739fb877f9aad23bd81ecb6e4c8ae8a417fdf7f0b9750"
},
{
"amount": "2434.8339258401255",
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
@@ -41100,12 +40855,6 @@
}
],
"withdrawals": [
{
"amount": "15521.759563745435",
"user": "0xf110D577F07ED846D2308050cc0D6CCC2bf9fb2C",
"tranche_id": 1,
"tx": "0x1048d5b3f41b93036b8739fb877f9aad23bd81ecb6e4c8ae8a417fdf7f0b9750"
},
{
"amount": "10764.1909763241854",
"user": "0xf110D577F07ED846D2308050cc0D6CCC2bf9fb2C",
@@ -41114,8 +40863,8 @@
}
],
"total_tokens": "29899.87",
"withdrawn_tokens": "26285.9505400696204",
"remaining_tokens": "3613.9194599303796"
"withdrawn_tokens": "10764.1909763241854",
"remaining_tokens": "19135.6790236758146"
},
{
"address": "0x59Be5FCeF25aa8965D17cB17364F446f48c30425",
@@ -41564,8 +41313,8 @@
"tranche_start": "2022-06-05T00:00:00.000Z",
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "15870102.715470999700000001",
"total_removed": "832085.86755480045340352",
"locked_amount": "6827135.3645265337866511762819105499945931",
"total_removed": "817956.28073763226110452",
"locked_amount": "6906758.71923515853098258401903989114111927",
"deposits": [
{
"amount": "16249.93",
@@ -42079,21 +41828,6 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xc3ffcafbb7c8a077bbcab85c028fd0422a2781742ac5a330788a59bfd157cf4f"
},
{
"amount": "12900.825853069814424",
"user": "0xf5cEaa0Ad684Ed4286C2df1eC011Db721Df44312",
"tx": "0xcb7137aa3f3e1fd4887e3074de09eb7b274fd89ffb7f1a9e2eb44e3dd7d5c448"
},
{
"amount": "555.436593162100375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x7ca532bd40420cc601c90df506cc041676efc231f9e5822594d611c53de115d1"
},
{
"amount": "673.3243709362775",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x6c9a470f50be5317670260a9d3842614e4dc7f32e9c483582f3d1a8d992864d4"
},
{
"amount": "998.454771147362375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -44144,18 +43878,6 @@
"tranche_id": 2,
"tx": "0xc3ffcafbb7c8a077bbcab85c028fd0422a2781742ac5a330788a59bfd157cf4f"
},
{
"amount": "555.436593162100375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0x7ca532bd40420cc601c90df506cc041676efc231f9e5822594d611c53de115d1"
},
{
"amount": "673.3243709362775",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0x6c9a470f50be5317670260a9d3842614e4dc7f32e9c483582f3d1a8d992864d4"
},
{
"amount": "998.454771147362375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -45592,8 +45314,8 @@
}
],
"total_tokens": "259998.8875",
"withdrawn_tokens": "147729.061299969532625",
"remaining_tokens": "112269.826200030467375"
"withdrawn_tokens": "146500.30033587115475",
"remaining_tokens": "113498.58716412884525"
},
{
"address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c",
@@ -46240,12 +45962,6 @@
}
],
"withdrawals": [
{
"amount": "12900.825853069814424",
"user": "0xf5cEaa0Ad684Ed4286C2df1eC011Db721Df44312",
"tranche_id": 2,
"tx": "0xcb7137aa3f3e1fd4887e3074de09eb7b274fd89ffb7f1a9e2eb44e3dd7d5c448"
},
{
"amount": "3943.9749230905699244",
"user": "0xf5cEaa0Ad684Ed4286C2df1eC011Db721Df44312",
@@ -46254,8 +45970,8 @@
}
],
"total_tokens": "29799.74516",
"withdrawn_tokens": "16844.8007761603843484",
"remaining_tokens": "12954.9443838396156516"
"withdrawn_tokens": "3943.9749230905699244",
"remaining_tokens": "25855.7702369094300756"
},
{
"address": "0xa53B55F9B39FE7DbBb5b80A79565480117F899E0",
@@ -47944,8 +47660,8 @@
"tranche_start": "2021-11-05T00:00:00.000Z",
"tranche_end": "2023-05-05T00:00:00.000Z",
"total_added": "14597706.0446472999",
"total_removed": "5825428.980241267385732886",
"locked_amount": "581322.550569700658722837432388667",
"total_removed": "5823725.263131533067291136",
"locked_amount": "654830.3232367831021256106422497794",
"deposits": [
{
"amount": "129284.449",
@@ -48169,16 +47885,6 @@
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0x8f3733aa98609b6b0f1c09393d91f50b2a70151c56b8ba680483845c7146e168"
},
{
"amount": "769.641644748552004",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0xeb3074f26ba5b01f54b2e34889b4832542b0269fa47fd5874d7f266a435da128"
},
{
"amount": "934.07546498576643775",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0x98bfad2d34e3a47b0487e1219456287f109dfb14658df5848c2f801247039314"
},
{
"amount": "37462.74710421168752574",
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
@@ -51406,18 +51112,6 @@
"tranche_id": 3,
"tx": "0x8f3733aa98609b6b0f1c09393d91f50b2a70151c56b8ba680483845c7146e168"
},
{
"amount": "769.641644748552004",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0xeb3074f26ba5b01f54b2e34889b4832542b0269fa47fd5874d7f266a435da128"
},
{
"amount": "934.07546498576643775",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0x98bfad2d34e3a47b0487e1219456287f109dfb14658df5848c2f801247039314"
},
{
"amount": "1383.345213676043696",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@@ -54156,8 +53850,8 @@
}
],
"total_tokens": "359123.469575",
"withdrawn_tokens": "344238.6382386840534815",
"remaining_tokens": "14884.8313363159465185"
"withdrawn_tokens": "342534.92112894973503975",
"remaining_tokens": "16588.54844605026496025"
},
{
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
@@ -57768,8 +57462,8 @@
"tranche_start": "2022-06-05T00:00:00.000Z",
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "472355.6199999996",
"total_removed": "42408.3252372941949",
"locked_amount": "68256.405614294737212900293658024",
"total_removed": "42016.0689524121949",
"locked_amount": "71814.500411700855490844659360728",
"deposits": [
{
"amount": "3000",
@@ -64393,16 +64087,6 @@
"user": "0x38A292CB98Dc602ECAFF94E8E5fADD9800e4bA13",
"tx": "0x6542b368628d18394bfaa86589e1aea0160270c06cef24f171680879dc39b77c"
},
{
"amount": "346.75301243",
"user": "0xa9a677b0a3Be231C0654CabB0Eaa0A72E91B3E8d",
"tx": "0xc0db5f216679203b937bf90415f24231997ea35bc1d418af30913aa313be498d"
},
{
"amount": "45.503272452",
"user": "0x9347177014d3fEA775b5B29fFC96bF6B911686F9",
"tx": "0xd1d4724eae5566e3162c1b210a19d73f5a2e4b9b3d52d9d1e77c4b9cb9bdc2e1"
},
{
"amount": "19.918569252",
"user": "0xcB555C5602cC0b2434A27d277e14Cb5C7bF4Ead1",
@@ -81519,12 +81203,6 @@
}
],
"withdrawals": [
{
"amount": "45.503272452",
"user": "0x9347177014d3fEA775b5B29fFC96bF6B911686F9",
"tranche_id": 5,
"tx": "0xd1d4724eae5566e3162c1b210a19d73f5a2e4b9b3d52d9d1e77c4b9cb9bdc2e1"
},
{
"amount": "47.970776254",
"user": "0x9347177014d3fEA775b5B29fFC96bF6B911686F9",
@@ -81539,8 +81217,8 @@
}
],
"total_tokens": "200",
"withdrawn_tokens": "171.036523338",
"remaining_tokens": "28.963476662"
"withdrawn_tokens": "125.533250886",
"remaining_tokens": "74.466749114"
},
{
"address": "0x1a268a88b586B475FF4bD86882bF2f9D79875964",
@@ -85768,12 +85446,6 @@
}
],
"withdrawals": [
{
"amount": "346.75301243",
"user": "0xa9a677b0a3Be231C0654CabB0Eaa0A72E91B3E8d",
"tranche_id": 5,
"tx": "0xc0db5f216679203b937bf90415f24231997ea35bc1d418af30913aa313be498d"
},
{
"amount": "78.285023465",
"user": "0xa9a677b0a3Be231C0654CabB0Eaa0A72E91B3E8d",
@@ -85782,8 +85454,8 @@
}
],
"total_tokens": "500",
"withdrawn_tokens": "425.038035895",
"remaining_tokens": "74.961964105"
"withdrawn_tokens": "78.285023465",
"remaining_tokens": "421.714976535"
},
{
"address": "0x3aDDC4bF402118c9453a51B23fD3Ea3707028273",
@@ -87409,7 +87081,7 @@
"tranche_start": "2021-12-05T00:00:00.000Z",
"tranche_end": "2022-06-05T00:00:00.000Z",
"total_added": "171288.42",
"total_removed": "69390.5995794947989",
"total_removed": "69140.5995794947989",
"locked_amount": "0",
"deposits": [
{
@@ -91644,11 +91316,6 @@
"user": "0xC1991C8BDA29507991EEB230FF2063C2eA74a34C",
"tx": "0x71a163020ce928ca230a50c099b8baaf60af6191d6cbc46edc004239d3ff9901"
},
{
"amount": "250",
"user": "0x0715B8bA27dB75F7601A9D8E22c15dcA1487FB70",
"tx": "0x11c685c41ff0c2d5f1d7fe3b08dc84a7ddb9160764a45bc61b8f39df94729634"
},
{
"amount": "1250",
"user": "0x9405F540EcC1204801De5C4444D06386BD6693F0",
@@ -100470,17 +100137,10 @@
"tx": "0x057f65938b1360b6d2c4ebf5e789c67897cf60cb6a13f947004def03891afbd8"
}
],
"withdrawals": [
{
"amount": "250",
"user": "0x0715B8bA27dB75F7601A9D8E22c15dcA1487FB70",
"tranche_id": 6,
"tx": "0x11c685c41ff0c2d5f1d7fe3b08dc84a7ddb9160764a45bc61b8f39df94729634"
}
],
"withdrawals": [],
"total_tokens": "250",
"withdrawn_tokens": "250",
"remaining_tokens": "0"
"withdrawn_tokens": "0",
"remaining_tokens": "250"
},
{
"address": "0x027306C886Da27fa29Ce9B4DB489C6E44d2ECc55",
@@ -142915,11 +142575,6 @@
}
],
"withdrawals": [
{
"amount": "0",
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
"tx": "0x882126a437003e60226611d623415bf2e00befa69d76aba57fd4cf1c5b403d1f"
},
{
"amount": "0",
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
@@ -143190,12 +142845,6 @@
}
],
"withdrawals": [
{
"amount": "0",
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
"tranche_id": 9,
"tx": "0x882126a437003e60226611d623415bf2e00befa69d76aba57fd4cf1c5b403d1f"
},
{
"amount": "0",
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
@@ -411,7 +411,6 @@ describe('capsule', { tags: '@slow' }, () => {
it('approved amount is less than deposit', function () {
// 1001-DEPO-006
// 1001-DEPO-007
cy.getByTestId(depositsTab).click();
cy.getByTestId('deposit-button').click();
cy.get(assetSelectField, txTimeout).select(btcName, { force: true });
@@ -431,8 +430,8 @@ describe('capsule', { tags: '@slow' }, () => {
});
it('withdraw - delay verification', function () {
// 1001-DEPO-007
// 1001-DEPO-024
// 1002-WITH-007
cy.visit('/#/portfolio');
cy.get('main[data-testid="/portfolio"]').should('exist');
@@ -76,7 +76,6 @@ describe('deposit form validation', { tags: '@smoke' }, () => {
});
it('insufficient funds', () => {
// 1001-DEPO-004
mockWeb3DepositCalls({
allowance: '1000',
depositLifetimeLimit: '1000',
@@ -41,12 +41,6 @@ describe('accounts', { tags: '@smoke' }, () => {
.should('have.text', '100,001.01');
});
it('asset detail should be properly rendered', () => {
cy.getByTestId('Collateral').click();
cy.getByTestId('asset').contains('tEURO').click();
cy.get('[data-testid$="_label"]').should('have.length', 16);
});
describe('sorting by ag-grid columns should work well', () => {
it('sorting by asset', () => {
cy.getByTestId('Collateral').click();
@@ -514,8 +514,6 @@ describe('account validation', { tags: '@regression' }, () => {
it('must show error returned by wallet ', () => {
// 0003-WTXN-009
// 0003-WTXN-011
// 0002-WCON-016
// 0003-WTXN-008
//trigger error from the wallet
cy.intercept('POST', 'http://localhost:1789/api/v2/requests', (req) => {
@@ -539,8 +537,6 @@ describe('account validation', { tags: '@regression' }, () => {
'contain.text',
'The connection to your Vega Wallet has been lost.'
);
cy.getByTestId('connect-vega-wallet').click();
cy.getByTestId('dialog-content').should('be.visible');
});
it('must see that the order was rejected by the connected wallet', () => {
@@ -28,7 +28,7 @@ describe('time in force default values', () => {
});
it('must have market order set up to IOC by default', function () {
// 7002-SORD-030
// 7002-SORD-031
cy.getByTestId(toggleMarket).click();
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
@@ -117,7 +117,6 @@ describe('connect vega wallet', { tags: '@smoke' }, () => {
// 0002-WCON-002
// 0002-WCON-005
// 0002-WCON-007
// 0002-WCON-009
mockConnectWallet();
cy.getByTestId(connectVegaBtn).click();
@@ -125,10 +124,6 @@ describe('connect vega wallet', { tags: '@smoke' }, () => {
.find('[data-testid="connector-jsonRpc"]')
.click();
cy.wait('@walletReq');
cy.getByTestId(dialogContent).should(
'contain.text',
'Approve the connection from your Vega wallet app.'
);
cy.getByTestId(dialogContent).should('not.exist');
cy.getByTestId(manageVegaBtn).should('exist');
});
@@ -137,7 +132,6 @@ describe('connect vega wallet', { tags: '@smoke' }, () => {
// 0002-WCON-002
// 0002-WCON-005
// 0002-WCON-007
// 0002-WCON-015
mockConnectWalletWithUserError();
cy.getByTestId(connectVegaBtn).click();
@@ -185,7 +185,7 @@ export const columns = (
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onSelect(market.id, e.metaKey || e.ctrlKey);
onSelect(market.id, e.metaKey);
}}
>
<UILink>{market.tradableInstrument.instrument.code}</UILink>
@@ -366,7 +366,7 @@ export const columnsPositionMarkets = (
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onSelect(market.id, e.metaKey || e.ctrlKey);
onSelect(market.id, e.metaKey);
}}
>
<UILink>{market.tradableInstrument.instrument.code}</UILink>
@@ -44,7 +44,7 @@ export const SelectMarketTableRow = ({
<tr
className={`hover:bg-neutral-200 dark:hover:bg-neutral-700 cursor-pointer relative h-[34px]`}
onClick={(ev) => {
onSelect(marketId, ev.metaKey || ev.ctrlKey);
onSelect(marketId, ev.metaKey);
}}
data-testid={`market-link-${marketId}`}
>
@@ -8,10 +8,6 @@ import type {
MarketData,
} from '@vegaprotocol/market-list';
import { SelectMarketLandingTable } from './welcome-landing-dialog';
const mockMarketClickHandler = jest.fn();
jest.mock('../../lib/hooks/use-market-click-handler', () => ({
useMarketClickHandler: () => mockMarketClickHandler,
}));
type Market = MarketMaybeWithCandles & MarketMaybeWithData;
type PartialMarket = Partial<
@@ -178,25 +174,4 @@ describe('WelcomeLandingDialog', () => {
fireEvent.click(screen.getAllByTestId(`market-link-2`)[0]);
expect(onClose).toHaveBeenCalled();
});
it('should not call onClose when metaKey is held', () => {
const onClose = jest.fn();
render(
<MemoryRouter>
<SelectMarketLandingTable
markets={[MARKET_A as Market, MARKET_B as Market]}
onClose={onClose}
/>
</MemoryRouter>,
{ wrapper: MockedProvider }
);
fireEvent.click(screen.getAllByTestId(`market-link-1`)[0], {
metaKey: true,
});
expect(mockMarketClickHandler).toHaveBeenCalled();
expect(onClose).not.toHaveBeenCalled();
fireEvent.click(screen.getAllByTestId(`market-link-1`)[0]);
expect(onClose).toHaveBeenCalled();
});
});
@@ -12,10 +12,9 @@ import {
SelectMarketTableRow,
} from '../select-market';
import { WelcomeDialogHeader } from './welcome-dialog-header';
import { Link } from 'react-router-dom';
import { Link, useNavigate, useParams } from 'react-router-dom';
import { ProposedMarkets } from './proposed-markets';
import { Links, Routes } from '../../pages/client-router';
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
export const SelectMarketLandingTable = ({
markets,
@@ -24,14 +23,24 @@ export const SelectMarketLandingTable = ({
markets: MarketMaybeWithDataAndCandles[] | null;
onClose: () => void;
}) => {
const onSelect = useMarketClickHandler();
const onSelectMarket = useCallback(
(id: string, metaKey?: boolean) => {
onSelect(id, metaKey);
if (!metaKey) {
onClose();
const params = useParams();
const navigate = useNavigate();
const marketId = params.marketId;
const onSelect = useCallback(
(id: string) => {
if (id && id !== marketId) {
navigate(Links[Routes.MARKET](id));
}
},
[marketId, navigate]
);
const onSelectMarket = useCallback(
(id: string) => {
onSelect(id);
onClose();
},
[onSelect, onClose]
);
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
@@ -64,7 +73,7 @@ export const SelectMarketLandingTable = ({
key={i}
detailed={false}
onSelect={onSelectMarket}
columns={columns(market, onSelectMarket, onCellClick)}
columns={columns(market, onSelect, onCellClick)}
/>
))}
</tbody>
@@ -7,11 +7,7 @@ import {
} from '@vegaprotocol/types';
import type { VegaStoredTxState } from '@vegaprotocol/wallet';
import { VegaTxStatus } from '@vegaprotocol/wallet';
import {
VegaTransactionDetails,
getVegaTransactionContentIntent,
} from './use-vega-transaction-toasts';
import { Intent } from '@vegaprotocol/ui-toolkit';
import { VegaTransactionDetails } from './use-vega-transaction-toasts';
jest.mock('@vegaprotocol/assets', () => {
const A1 = {
@@ -282,27 +278,3 @@ describe('VegaTransactionDetails', () => {
expect(queryByTestId('toast-panel')?.textContent).toEqual(details);
});
});
describe('getVegaTransactionContentIntent', () => {
it('returns the correct intent for a transaction', () => {
expect(getVegaTransactionContentIntent(withdraw).intent).toBe(
Intent.Primary
);
expect(getVegaTransactionContentIntent(submitOrder).intent).toBe(
Intent.Success
);
expect(getVegaTransactionContentIntent(editOrder).intent).toBe(
Intent.Primary
);
expect(getVegaTransactionContentIntent(cancelOrder).intent).toBe(
Intent.Primary
);
expect(getVegaTransactionContentIntent(cancelAll).intent).toBe(
Intent.Primary
);
expect(getVegaTransactionContentIntent(closePosition).intent).toBe(
Intent.Primary
);
expect(getVegaTransactionContentIntent(batch).intent).toBe(Intent.Primary);
});
});
@@ -547,11 +547,7 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
return (
<>
<ToastHeading>
{tx.order?.status
? getOrderToastTitle(tx.order.status)
: t('Confirmed')}
</ToastHeading>
<ToastHeading>{t('Confirmed')}</ToastHeading>
<p>{t('Your transaction has been confirmed ')}</p>
{tx.txHash && (
<p className="break-all">
@@ -638,8 +634,25 @@ export const useVegaTransactionToasts = () => {
);
const fromVegaTransaction = (tx: VegaStoredTxState): Toast => {
let content: ToastContent;
const closeAfter = isFinal(tx) ? CLOSE_AFTER : undefined;
const { intent, content } = getVegaTransactionContentIntent(tx);
if (tx.status === VegaTxStatus.Requested) {
content = <VegaTxRequestedToastContent tx={tx} />;
}
if (tx.status === VegaTxStatus.Pending) {
content = <VegaTxPendingToastContentProps tx={tx} />;
}
if (tx.status === VegaTxStatus.Complete) {
content = <VegaTxCompleteToastsContent tx={tx} />;
}
if (tx.status === VegaTxStatus.Error) {
content = <VegaTxErrorToastContent tx={tx} />;
}
// Transaction can be successful but the order can be rejected by the network
const intent =
(tx.order && getOrderToastIntent(tx.order.status)) ||
intentMap[tx.status];
return {
id: `vega-${tx.id}`,
@@ -663,27 +676,3 @@ export const useVegaTransactionToasts = () => {
}
);
};
export const getVegaTransactionContentIntent = (tx: VegaStoredTxState) => {
let content: ToastContent;
if (tx.status === VegaTxStatus.Requested) {
content = <VegaTxRequestedToastContent tx={tx} />;
}
if (tx.status === VegaTxStatus.Pending) {
content = <VegaTxPendingToastContentProps tx={tx} />;
}
if (tx.status === VegaTxStatus.Complete) {
content = <VegaTxCompleteToastsContent tx={tx} />;
}
if (tx.status === VegaTxStatus.Error) {
content = <VegaTxErrorToastContent tx={tx} />;
}
// Transaction can be successful but the order can be rejected by the network
const intent =
(tx.order &&
!isOrderAmendmentTransaction(tx.body) &&
getOrderToastIntent(tx.order.status)) ||
intentMap[tx.status];
return { intent, content };
};
+1 -1
View File
@@ -63,7 +63,7 @@ html [data-theme='light'] {
--pennant-color-sell-stroke: theme('colors.vega.pink.400');
--pennant-color-volume-buy: theme('colors.vega.green.400');
--pennant-color-volume-sell: theme('colors.vega.pink.400');
--pennant-color-volume-sell: theme('colors.vega.pink.500');
/* depth chart */
--pennant-color-depth-buy-fill: theme('colors.vega.green.400');
+5 -3
View File
@@ -5,9 +5,7 @@ export PATH="/app/node_modules/.bin:$PATH"
flags="--network-timeout 100000 --pure-lockfile"
if [[ ! -z "${ENV_NAME}" ]]; then
if [[ "${ENV_NAME}" != "ops-vega" ]]; then
flags="--env=${ENV_NAME} $flags"
fi
flags="--env=${ENV_NAME} $flags"
fi
if [ "${APP}" = "trading" ]; then
@@ -18,3 +16,7 @@ if [ "${APP}" = "trading" ]; then
else
yarn nx build ${APP} $flags
fi
env_vars_file="/app/dist/apps/${APP}/.env"
# make sure there are no exposed .env files
rm $env_vars_file || echo "No env vars file"
+1 -18
View File
@@ -1,25 +1,8 @@
fragment AssetListFields on Asset {
id
name
symbol
decimals
quantum
source {
__typename
... on ERC20 {
contractAddress
lifetimeLimit
withdrawThreshold
}
}
status
}
query Assets {
assetsConnection {
edges {
node {
...AssetListFields
...AssetFields
}
}
}
+5 -23
View File
@@ -1,44 +1,26 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import { AssetFieldsFragmentDoc } from './Asset';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type AssetListFieldsFragment = { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: string } };
export type AssetsQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type AssetsQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: string } } } | null> | null } | null };
export type AssetsQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus, source: { __typename: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: string }, infrastructureFeeAccount?: { __typename?: 'AccountBalance', balance: string } | null, globalRewardPoolAccount?: { __typename?: 'AccountBalance', balance: string } | null, takerFeeRewardAccount?: { __typename?: 'AccountBalance', balance: string } | null, makerFeeRewardAccount?: { __typename?: 'AccountBalance', balance: string } | null, lpFeeRewardAccount?: { __typename?: 'AccountBalance', balance: string } | null, marketProposerRewardAccount?: { __typename?: 'AccountBalance', balance: string } | null } } | null> | null } | null };
export const AssetListFieldsFragmentDoc = gql`
fragment AssetListFields on Asset {
id
name
symbol
decimals
quantum
source {
__typename
... on ERC20 {
contractAddress
lifetimeLimit
withdrawThreshold
}
}
status
}
`;
export const AssetsDocument = gql`
query Assets {
assetsConnection {
edges {
node {
...AssetListFields
...AssetFields
}
}
}
}
${AssetListFieldsFragmentDoc}`;
${AssetFieldsFragmentDoc}`;
/**
* __useAssetsQuery__
@@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react';
import * as Schema from '@vegaprotocol/types';
import { AssetDetailsDialog } from './asset-details-dialog';
import { AssetDetail, testId } from './asset-details-table';
import { AssetDocument } from './__generated__/Asset';
import { AssetsDocument } from './__generated__/Assets';
import { generateBuiltinAsset, generateERC20Asset } from './test-helpers';
const mockedData = {
@@ -39,17 +39,15 @@ const mockedData = {
},
};
const mocks = mockedData.data.assetsConnection.edges.map((mock) => ({
request: {
query: AssetDocument,
variables: { assetId: mock.node.id },
},
result: {
data: {
assetsConnection: { edges: [mock] },
const mocks = [
{
request: {
query: AssetsDocument,
variables: {},
},
result: mockedData,
},
}));
];
const WrappedAssetDetailsDialog = ({ assetId }: { assetId: string }) => (
<MockedProvider mocks={mocks}>
+3 -2
View File
@@ -1,4 +1,5 @@
import { t } from '@vegaprotocol/i18n';
import { useAssetsDataProvider } from './assets-data-provider';
import {
Button,
Dialog,
@@ -9,7 +10,6 @@ import {
import { create } from 'zustand';
import { AssetDetailsTable } from './asset-details-table';
import { AssetProposalNotification } from '@vegaprotocol/proposals';
import { useAssetDataProvider } from './asset-data-provider';
export type AssetDetailsDialogStore = {
isOpen: boolean;
@@ -55,8 +55,9 @@ export const AssetDetailsDialog = ({
onChange,
asJson = false,
}: AssetDetailsDialogProps) => {
const { data: asset } = useAssetDataProvider(assetId);
const { data } = useAssetsDataProvider();
const asset = data?.find((a) => a.id === assetId);
const assetSymbol = asset?.symbol || '';
const content = asset ? (
+3 -2
View File
@@ -11,7 +11,6 @@ import {
} from '@vegaprotocol/ui-toolkit';
import type { ReactNode } from 'react';
import type { Asset } from './asset-data-provider';
import { WITHDRAW_THRESHOLD_TOOLTIP_TEXT } from './constants';
type Rows = {
key: AssetDetail;
@@ -122,7 +121,9 @@ export const rows: Rows = [
{
key: AssetDetail.WITHDRAWAL_THRESHOLD,
label: t('Withdrawal threshold'),
tooltip: WITHDRAW_THRESHOLD_TOOLTIP_TEXT,
tooltip: t(
'The maximum you can withdraw instantly. Theres no limit on the size of a withdrawal, but all withdrawals over the threshold will have a delay time added to them'
),
value: (asset) =>
num(asset, (asset.source as Schema.ERC20).withdrawThreshold),
},
+119 -5
View File
@@ -1,10 +1,8 @@
import merge from 'lodash/merge';
import type {
AssetsQuery,
AssetListFieldsFragment,
} from './__generated__/Assets';
import type { AssetsQuery } from './__generated__/Assets';
import * as Types from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest';
import type { AssetFieldsFragment } from './__generated__/Asset';
export const assetsQuery = (
override?: PartialDeep<AssetsQuery>
@@ -20,7 +18,7 @@ export const assetsQuery = (
return merge(defaultAssets, override);
};
const assetFields: AssetListFieldsFragment[] = [
const assetFields: AssetFieldsFragment[] = [
{
__typename: 'Asset',
id: 'asset-id',
@@ -35,6 +33,30 @@ const assetFields: AssetListFieldsFragment[] = [
},
quantum: '1',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '1',
__typename: 'AccountBalance',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'AccountBalance',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'AccountBalance',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'AccountBalance',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'AccountBalance',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'AccountBalance',
},
},
{
__typename: 'Asset',
@@ -50,6 +72,30 @@ const assetFields: AssetListFieldsFragment[] = [
},
quantum: '1',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '1',
__typename: 'AccountBalance',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'AccountBalance',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'AccountBalance',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'AccountBalance',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'AccountBalance',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'AccountBalance',
},
},
{
__typename: 'Asset',
@@ -58,10 +104,20 @@ const assetFields: AssetListFieldsFragment[] = [
decimals: 5,
name: 'Asto',
source: {
maxFaucetAmountMint: '5000000000',
__typename: 'BuiltinAsset',
},
quantum: '1',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '0',
__typename: 'AccountBalance',
},
globalRewardPoolAccount: null,
takerFeeRewardAccount: null,
makerFeeRewardAccount: null,
lpFeeRewardAccount: null,
marketProposerRewardAccount: null,
},
{
__typename: 'Asset',
@@ -70,10 +126,20 @@ const assetFields: AssetListFieldsFragment[] = [
decimals: 5,
name: 'tBTC TEST',
source: {
maxFaucetAmountMint: '5000000000',
__typename: 'BuiltinAsset',
},
quantum: '1',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '0',
__typename: 'AccountBalance',
},
globalRewardPoolAccount: null,
takerFeeRewardAccount: null,
makerFeeRewardAccount: null,
lpFeeRewardAccount: null,
marketProposerRewardAccount: null,
},
// NOTE: These assets ids and contract addresses are real assets on Sepolia, this is needed
// because we don't currently mock our seplia infura provider. If we change network these will
@@ -92,6 +158,30 @@ const assetFields: AssetListFieldsFragment[] = [
__typename: 'ERC20',
},
quantum: '1',
infrastructureFeeAccount: {
balance: '1',
__typename: 'AccountBalance',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'AccountBalance',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'AccountBalance',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'AccountBalance',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'AccountBalance',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'AccountBalance',
},
},
{
__typename: 'Asset',
@@ -107,5 +197,29 @@ const assetFields: AssetListFieldsFragment[] = [
__typename: 'ERC20',
},
quantum: '1',
infrastructureFeeAccount: {
balance: '1',
__typename: 'AccountBalance',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'AccountBalance',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'AccountBalance',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'AccountBalance',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'AccountBalance',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'AccountBalance',
},
},
];
-4
View File
@@ -1,4 +0,0 @@
import { t } from '@vegaprotocol/i18n';
export const WITHDRAW_THRESHOLD_TOOLTIP_TEXT = t(
"The maximum you can withdraw instantly. There's no limit on the size of a withdrawal, but all withdrawals over the threshold will have a delay time added to them"
);
-1
View File
@@ -5,4 +5,3 @@ export * from './assets-data-provider';
export * from './asset-details-dialog';
export * from './asset-details-table';
export * from './asset-option';
export * from './constants';
@@ -21,7 +21,7 @@ export const MarketNameCell = ({
ev.preventDefault();
ev.stopPropagation();
if (onMarketClick) {
onMarketClick(id, ev.metaKey || ev.ctrlKey);
onMarketClick(id, ev.metaKey);
}
},
[id, onMarketClick]
@@ -78,9 +78,7 @@ export const compileGridData = (
label: (
<Link
to={`/liquidity/${market.id}`}
onClick={(ev) =>
onSelect && onSelect(market.id, ev.metaKey || ev.ctrlKey)
}
onClick={(ev) => onSelect && onSelect(market.id, ev.metaKey)}
>
<UILink>{t('Current liquidity')}</UILink>
</Link>
+4
View File
@@ -1,2 +1,6 @@
export * from './__generated__/EstimateOrder';
export * from './use-calculate-slippage';
export * from './use-fee-deal-ticket-details';
export * from './use-market-positions';
export * from './use-maximum-position-size';
export * from './use-order-closeout';
@@ -0,0 +1,144 @@
import { MockedProvider } from '@apollo/client/testing';
import { renderHook } from '@testing-library/react';
import * as Schema from '@vegaprotocol/types';
import type { Market } from '@vegaprotocol/market-list';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { useCalculateSlippage } from './use-calculate-slippage';
const mockData = {
decimalPlaces: 0,
positionDecimalPlaces: 0,
depth: {
buy: [
{
price: '5',
volume: '2',
},
{
price: '4',
volume: '3',
},
{
price: '3',
volume: '2',
},
{
price: '2',
volume: '1',
},
{
price: '1',
volume: '1',
},
],
sell: [
{
price: '6',
volume: '1',
},
{
price: '7',
volume: '3',
},
{
price: '8',
volume: '2',
},
{
price: '9',
volume: '1',
},
{
price: '10',
volume: '2',
},
],
},
};
let mockOrderBookData = {
data: mockData,
};
jest.mock('@vegaprotocol/react-helpers', () => ({
...jest.requireActual('@vegaprotocol/react-helpers'),
useDataProvider: jest.fn(() => ({
data: {
marketsConnection: [],
},
})),
useThrottledDataProvider: jest.fn(() => mockOrderBookData),
}));
describe('useCalculateSlippage Hook', () => {
describe('calculate proper result', () => {
afterEach(() => {
jest.clearAllMocks();
});
const market = {
id: 'marketId',
decimalPlaces: 0,
positionDecimalPlaces: 0,
} as Market;
it('long order', () => {
const { result } = renderHook(
() =>
useCalculateSlippage({
market,
order: {
size: '10',
side: Schema.Side.SIDE_BUY,
} as OrderSubmissionBody['orderSubmission'],
}),
{
wrapper: MockedProvider,
}
);
expect(result.current).toEqual('33.33');
});
it('short order', () => {
const { result } = renderHook(
() =>
useCalculateSlippage({
market,
order: {
size: '10',
side: Schema.Side.SIDE_SELL,
} as OrderSubmissionBody['orderSubmission'],
}),
{
wrapper: MockedProvider,
}
);
expect(result.current).toEqual('31.11');
});
it('when no order book result should be null', () => {
mockOrderBookData = {
data: {
...mockData,
depth: {
...mockData.depth,
buy: [],
},
},
};
const { result } = renderHook(
() =>
useCalculateSlippage({
market,
order: {
size: '10',
side: Schema.Side.SIDE_SELL,
} as OrderSubmissionBody['orderSubmission'],
}),
{
wrapper: MockedProvider,
}
);
expect(result.current).toBeNull();
});
});
});
@@ -0,0 +1,63 @@
import { marketDepthProvider } from '@vegaprotocol/market-depth';
import * as Schema from '@vegaprotocol/types';
import type { Market } from '@vegaprotocol/market-list';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { BigNumber } from 'bignumber.js';
import { formatNumber, toBigNum } from '@vegaprotocol/utils';
import { useThrottledDataProvider } from '@vegaprotocol/react-helpers';
interface Props {
market: Market;
order: OrderSubmissionBody['orderSubmission'];
}
export const useCalculateSlippage = ({ market, order }: Props) => {
const { data } = useThrottledDataProvider(
{
dataProvider: marketDepthProvider,
variables: { marketId: market.id },
},
1000
);
const volPriceArr =
data?.depth[order.side === Schema.Side.SIDE_BUY ? 'sell' : 'buy'] || [];
if (volPriceArr.length && market) {
const decimals = market.decimalPlaces ?? 0;
const positionDecimals = market.positionDecimalPlaces ?? 0;
const bestPrice = toBigNum(volPriceArr[0].price, decimals);
const { size } = order;
let descSize = new BigNumber(size);
let i = 0;
const volPricePairs: Array<[BigNumber, BigNumber]> = [];
while (!descSize.isZero() && i < volPriceArr.length) {
const price = toBigNum(volPriceArr[i].price, decimals);
const amount = BigNumber.min(
descSize,
toBigNum(volPriceArr[i].volume, positionDecimals)
);
volPricePairs.push([price, amount]);
descSize = BigNumber.max(0, descSize.minus(amount));
i++;
}
if (volPricePairs.length) {
const volWeightAvPricePair = volPricePairs.reduce(
(agg, item) => {
agg[0] = agg[0].plus(item[0].multipliedBy(item[1]));
agg[1] = agg[1].plus(item[1]);
return agg;
},
[new BigNumber(0), new BigNumber(0)]
);
const volWeightAvPrice = volWeightAvPricePair[0].dividedBy(
volWeightAvPricePair[1]
);
const slippage = volWeightAvPrice
.minus(bestPrice)
.absoluteValue()
.dividedBy(bestPrice)
.multipliedBy(100);
return formatNumber(slippage, 2);
}
}
return null;
};
@@ -18,6 +18,7 @@ import {
DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT,
TOTAL_MARGIN_AVAILABLE,
} from '../constants';
import { useOrderCloseOut } from './use-order-closeout';
import { useMarketAccountBalance } from '@vegaprotocol/accounts';
import { getDerivedPrice } from '../utils/get-price';
import { useEstimateOrderQuery } from './__generated__/EstimateOrder';
@@ -48,6 +49,12 @@ export const useFeeDealTicketDetails = (
skip: !pubKey || !market || !order.size || !price,
});
const estCloseOut = useOrderCloseOut({
order,
market,
marketData,
});
const notionalSize = useMemo(() => {
if (price && order.size) {
return toBigNum(order.size, market.positionDecimalPlaces)
@@ -67,8 +74,16 @@ export const useFeeDealTicketDetails = (
notionalSize,
accountBalance,
estimateOrder: estMargin?.estimateOrder,
estCloseOut,
};
}, [market, assetSymbol, notionalSize, accountBalance, estMargin]);
}, [
market,
assetSymbol,
notionalSize,
accountBalance,
estMargin,
estCloseOut,
]);
};
export interface FeeDetails {
@@ -77,6 +92,7 @@ export interface FeeDetails {
market: Market;
assetSymbol: string;
notionalSize: string | null;
estCloseOut: string | null;
estimateOrder: EstimateOrderQuery['estimateOrder'] | undefined;
estimatedInitialMargin: string;
estimatedTotalInitialMargin: string;
@@ -0,0 +1,53 @@
import { renderHook } from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing';
import { useMarketPositions } from './use-market-positions';
jest.mock('@vegaprotocol/wallet', () => ({
...jest.requireActual('@vegaprotocol/wallet'),
useVegaWallet: jest.fn().mockReturnValue('wallet-pub-key'),
}));
let mockMarketAccountBalance: {
accountBalance: string;
accountDecimals: number | null;
} = { accountBalance: '50001000000', accountDecimals: 5 };
jest.mock('@vegaprotocol/accounts', () => ({
...jest.requireActual('@vegaprotocol/accounts'),
useMarketAccountBalance: jest.fn(() => mockMarketAccountBalance),
}));
jest.mock('@vegaprotocol/positions', () => ({
...jest.requireActual('@vegaprotocol/positions'),
useMarketPositionOpenVolume: jest.fn(() => '100002'),
}));
describe('useOrderPosition Hook', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('should return proper positive value', () => {
const { result } = renderHook(
() => useMarketPositions({ marketId: 'marketId' }),
{ wrapper: MockedProvider }
);
expect(result.current?.openVolume).toEqual('100002');
expect(result.current?.balance).toEqual('50001000000');
});
it('if balance equal 0 return null', () => {
mockMarketAccountBalance = { accountBalance: '0', accountDecimals: 5 };
const { result } = renderHook(
() => useMarketPositions({ marketId: 'marketId' }),
{ wrapper: MockedProvider }
);
expect(result.current).toBeNull();
});
it('if no markets return null', () => {
mockMarketAccountBalance = { accountBalance: '', accountDecimals: null };
const { result } = renderHook(
() => useMarketPositions({ marketId: 'marketId' }),
{ wrapper: MockedProvider }
);
expect(result.current).toBeNull();
});
});
@@ -0,0 +1,34 @@
import { useMemo } from 'react';
import { BigNumber } from 'bignumber.js';
import { useMarketAccountBalance } from '@vegaprotocol/accounts';
import { useMarketPositionOpenVolume } from '@vegaprotocol/positions';
interface Props {
marketId: string;
}
export type PositionMargin = {
openVolume: string;
balance: string;
balanceDecimals?: number;
} | null;
export const useMarketPositions = ({ marketId }: Props): PositionMargin => {
const { accountBalance, accountDecimals } = useMarketAccountBalance(marketId);
const openVolume = useMarketPositionOpenVolume(marketId);
return useMemo(() => {
if (accountBalance && accountDecimals) {
const balance = new BigNumber(accountBalance);
const volume = new BigNumber(openVolume);
if (!balance.isZero() && !volume.isZero()) {
return {
balance: accountBalance,
balanceDecimals: accountDecimals,
openVolume,
};
}
}
return null;
}, [accountBalance, accountDecimals, openVolume]);
};
@@ -0,0 +1,120 @@
import { renderHook } from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing';
import * as Schema from '@vegaprotocol/types';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { PositionMargin } from './use-market-positions';
import { useMaximumPositionSize } from './use-maximum-position-size';
jest.mock('@vegaprotocol/wallet', () => ({
...jest.requireActual('@vegaprotocol/wallet'),
useVegaWallet: jest.fn().mockReturnValue('wallet-pub-key'),
}));
let mockAccountBalance: {
accountBalance: string;
accountDecimals: number | null;
} = { accountBalance: '200000', accountDecimals: 5 };
jest.mock('@vegaprotocol/accounts', () => ({
...jest.requireActual('@vegaprotocol/accounts'),
useAccountBalance: jest.fn(() => mockAccountBalance),
}));
const defaultMockMarketPositions = {
openVolume: '1',
balance: '100000',
};
let mockMarketPositions: PositionMargin | null = defaultMockMarketPositions;
const mockOrder: OrderSubmissionBody['orderSubmission'] = {
type: Schema.OrderType.TYPE_MARKET,
size: '1',
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC,
marketId: 'market-id',
};
jest.mock('./use-market-positions', () => ({
useMarketPositions: ({
marketId,
partyId,
}: {
marketId: string;
partyId: string;
}) => mockMarketPositions,
}));
describe('useMaximumPositionSize', () => {
it('should return correct size when no open positions', () => {
mockMarketPositions = null;
const price = '50';
const expected = 4000;
const { result } = renderHook(
() =>
useMaximumPositionSize({
marketId: '',
price,
settlementAssetId: '',
order: mockOrder,
}),
{ wrapper: MockedProvider }
);
expect(result.current).toBe(expected);
});
it('should return correct size when open positions and same side', () => {
const price = '50';
mockMarketPositions = defaultMockMarketPositions;
const expected = 3999;
const { result } = renderHook(
() =>
useMaximumPositionSize({
marketId: '',
price,
settlementAssetId: '',
order: mockOrder,
}),
{ wrapper: MockedProvider }
);
expect(result.current).toBe(expected);
});
it('should return correct size when open positions and opposite side', () => {
const price = '50';
mockOrder.side = Schema.Side.SIDE_SELL;
mockMarketPositions = defaultMockMarketPositions;
const expected = 4001;
const { result } = renderHook(
() =>
useMaximumPositionSize({
marketId: '',
price,
settlementAssetId: '',
order: mockOrder,
}),
{ wrapper: MockedProvider }
);
expect(result.current).toBe(expected);
});
it('should return zero if no account balance', () => {
mockAccountBalance = {
accountBalance: '0',
accountDecimals: 5,
};
const price = '50';
mockMarketPositions = defaultMockMarketPositions;
const expected = 0;
const { result } = renderHook(
() =>
useMaximumPositionSize({
marketId: '',
price,
settlementAssetId: '',
order: mockOrder,
}),
{ wrapper: MockedProvider }
);
expect(result.current).toBe(expected);
});
});
@@ -0,0 +1,46 @@
import * as Schema from '@vegaprotocol/types';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { useAccountBalance } from '@vegaprotocol/accounts';
import { BigNumber } from 'bignumber.js';
import { useMarketPositions } from './use-market-positions';
interface Props {
marketId: string;
price?: string;
settlementAssetId: string;
order: OrderSubmissionBody['orderSubmission'];
}
const getSize = (balance: string, price: string) =>
new BigNumber(balance).dividedBy(new BigNumber(price));
export const useMaximumPositionSize = ({
marketId,
price,
settlementAssetId,
order,
}: Props): number => {
const { accountBalance } = useAccountBalance(settlementAssetId) || {};
const marketPositions = useMarketPositions({ marketId: marketId });
if (!accountBalance || new BigNumber(accountBalance || 0).isZero()) {
return 0;
}
const size = getSize(accountBalance, price || '');
if (!marketPositions) {
return size.toNumber() || 0;
}
const isSameSide =
(new BigNumber(marketPositions.openVolume).isPositive() &&
order.side === Schema.Side.SIDE_BUY) ||
(new BigNumber(marketPositions.openVolume).isNegative() &&
order.side === Schema.Side.SIDE_SELL);
const adjustedForVolume = new BigNumber(size)[isSameSide ? 'minus' : 'plus'](
marketPositions.openVolume
);
return adjustedForVolume.isNegative() ? 0 : adjustedForVolume.toNumber();
};
@@ -0,0 +1,117 @@
import { renderHook } from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { Market, MarketData } from '@vegaprotocol/market-list';
import { useOrderCloseOut } from './use-order-closeout';
jest.mock('@vegaprotocol/wallet', () => ({
...jest.requireActual('@vegaprotocol/wallet'),
useVegaWallet: jest.fn().mockReturnValue('wallet-pub-key'),
}));
let mockMarketMargin: string | undefined = undefined;
jest.mock('@vegaprotocol/positions', () => ({
...jest.requireActual('@vegaprotocol/positions'),
useMarketMargin: () => mockMarketMargin,
}));
describe('useOrderCloseOut', () => {
const order = { size: '2', side: 'SIDE_BUY' };
const market = {
decimalPlaces: 5,
tradableInstrument: {
instrument: {
product: {
settlementAsset: {
id: 'assetId',
},
},
},
},
} as unknown as Market;
const marketData = {
markPrice: 100000,
} as unknown as MarketData;
beforeEach(() => {
jest.clearAllMocks();
});
it('should return proper null value', () => {
mockMarketMargin = '-1';
const { result } = renderHook(
() =>
useOrderCloseOut({
order: order as OrderSubmissionBody['orderSubmission'],
market,
marketData: {
markPrice: '0',
} as MarketData,
}),
{
wrapper: MockedProvider,
}
);
expect(result.current).toEqual(null);
});
it('should return proper sell value', () => {
mockMarketMargin = '0';
const { result } = renderHook(
() =>
useOrderCloseOut({
order: {
...order,
side: 'SIDE_SELL',
} as OrderSubmissionBody['orderSubmission'],
market,
marketData,
}),
{
wrapper: MockedProvider,
}
);
expect(result.current).toEqual('1');
});
it('should return proper sell value on limit order', () => {
mockMarketMargin = '0';
const { result } = renderHook(
() =>
useOrderCloseOut({
order: {
...order,
price: '1000000',
type: 'TYPE_LIMIT',
side: 'SIDE_SELL',
} as OrderSubmissionBody['orderSubmission'],
market,
marketData,
}),
{
wrapper: MockedProvider,
}
);
expect(result.current).toEqual('1000000');
});
it('should return proper empty value', () => {
const { result } = renderHook(
() =>
useOrderCloseOut({
order: {
...order,
side: 'SIDE_SELL',
} as OrderSubmissionBody['orderSubmission'],
market,
marketData: {
markPrice: '0',
} as MarketData,
}),
{
wrapper: MockedProvider,
}
);
expect(result.current).toEqual('0');
});
});
@@ -0,0 +1,61 @@
import { BigNumber } from 'bignumber.js';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { addDecimal } from '@vegaprotocol/utils';
import * as Schema from '@vegaprotocol/types';
import type { Market, MarketData } from '@vegaprotocol/market-list';
import {
useAccountBalance,
useMarketAccountBalance,
} from '@vegaprotocol/accounts';
import { useMarketMargin } from '@vegaprotocol/positions';
import { useMarketPositions } from './use-market-positions';
interface Props {
order: OrderSubmissionBody['orderSubmission'];
market: Market;
marketData: MarketData;
}
export const useOrderCloseOut = ({
order,
market,
marketData,
}: Props): string | null => {
const { accountBalance, accountDecimals } = useAccountBalance(
market.tradableInstrument.instrument.product.settlementAsset.id
);
const { accountBalance: positionBalance, accountDecimals: positionDecimals } =
useMarketAccountBalance(market.id);
const maintenanceLevel = useMarketMargin(market.id);
const marginMaintenanceLevel = new BigNumber(
addDecimal(maintenanceLevel || 0, market.decimalPlaces)
);
const positionAccountBalance = new BigNumber(
addDecimal(positionBalance || 0, positionDecimals || 0)
);
const generalAccountBalance = new BigNumber(
addDecimal(accountBalance || 0, accountDecimals || 0)
);
const { openVolume } =
useMarketPositions({
marketId: market.id,
}) || {};
const volume = new BigNumber(
addDecimal(openVolume || '0', market.positionDecimalPlaces)
)[order.side === Schema.Side.SIDE_BUY ? 'plus' : 'minus'](order.size);
const price =
order.type === Schema.OrderType.TYPE_LIMIT && order.price
? new BigNumber(order.price)
: new BigNumber(addDecimal(marketData.markPrice, market.decimalPlaces));
// regarding formula (marginMaintenanceLevel - positionAccountBalance - generalAccountBalance) / volume + markPrice
const marginDifference = marginMaintenanceLevel
.minus(positionAccountBalance)
.minus(generalAccountBalance);
const closeOut = marginDifference.div(volume).plus(price);
if (closeOut.isPositive()) {
return closeOut.toString();
}
return null;
};
+1 -1
View File
@@ -100,7 +100,7 @@ export const DepositForm = ({
defaultValues: {
to: pubKey ? pubKey : undefined,
asset: selectedAsset?.id,
amount: persistedDeposit?.amount,
amount: persistedDeposit.amount,
},
});
+1 -2
View File
@@ -70,8 +70,7 @@ export const DepositManager = ({
const onAmountChange = useCallback(
(amount: string) => {
persistentDeposit &&
savePersistentDeposit({ ...persistentDeposit, amount });
savePersistentDeposit({ ...persistentDeposit, amount });
},
[savePersistentDeposit, persistentDeposit]
);
@@ -4,7 +4,7 @@ import { usePersistentDeposit } from './use-persistent-deposit';
describe('usePersistenDeposit', () => {
it('should return empty data', () => {
const { result } = renderHook(() => usePersistentDeposit());
expect(result.current).toEqual([undefined, expect.any(Function)]);
expect(result.current).toEqual([{ assetId: '' }, expect.any(Function)]);
});
it('should return empty and properly saved data', async () => {
const aId = 'test';
@@ -32,14 +32,10 @@ const usePersistentDepositStore = create<{
export const usePersistentDeposit = (
assetId?: string
): [PersistedDeposit | undefined, (entry: PersistedDeposit) => void] => {
): [PersistedDeposit, (entry: PersistedDeposit) => void] => {
const { deposits, lastVisited, saveValue } = usePersistentDepositStore();
const discoveredData = useMemo(() => {
return assetId
? deposits[assetId]
? deposits[assetId]
: { assetId }
: lastVisited;
return deposits[assetId || ''] || lastVisited || { assetId: assetId || '' };
}, [deposits, lastVisited, assetId]);
return [discoveredData, saveValue];
@@ -1,6 +1,8 @@
import React from 'react';
import throttle from 'lodash/throttle';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { Orderbook } from './orderbook';
import { addDecimal } from '@vegaprotocol/utils';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { marketDepthProvider } from './market-depth-provider';
import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list';
@@ -193,9 +195,10 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
positionDecimalPlaces={market?.positionDecimalPlaces ?? 0}
resolution={resolution}
onResolutionChange={(resolution: number) => setResolution(resolution)}
onClick={(price: string) => {
onClick={(price?: string | number) => {
if (price) {
updateOrder(marketId, { price });
const priceValue = addDecimal(price, market?.decimalPlaces ?? 0);
updateOrder(marketId, { price: priceValue });
}
}}
/>
+3 -3
View File
@@ -1,5 +1,5 @@
import React from 'react';
import { addDecimal, addDecimalsFixedFormatNumber } from '@vegaprotocol/utils';
import { addDecimalsFixedFormatNumber } from '@vegaprotocol/utils';
import { PriceCell, VolCell, CumulativeVol } from '@vegaprotocol/datagrid';
interface OrderbookRowProps {
@@ -15,7 +15,7 @@ interface OrderbookRowProps {
price: string;
relativeAsk?: number;
relativeBid?: number;
onClick?: (price: string) => void;
onClick?: (price?: string | number) => void;
}
export const OrderbookRow = React.memo(
@@ -59,7 +59,7 @@ export const OrderbookRow = React.memo(
<PriceCell
testId={`price-${price}`}
value={BigInt(price)}
onClick={() => onClick && onClick(addDecimal(price, decimalPlaces))}
onClick={() => onClick && onClick(price)}
valueFormatted={addDecimalsFixedFormatNumber(price, decimalPlaces)}
/>
<CumulativeVol
+9 -50
View File
@@ -20,7 +20,7 @@ describe('Orderbook', () => {
const decimalPlaces = 3;
it('should scroll to mid price on init', async () => {
window.innerHeight = 11 * rowHeight;
render(
const result = render(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
@@ -30,7 +30,7 @@ describe('Orderbook', () => {
/>
);
await waitFor(() => screen.getByTestId(`bid-vol-${params.midPrice}`));
expect(screen.getByTestId('scroll').scrollTop).toBe(91 * rowHeight);
expect(result.getByTestId('scroll').scrollTop).toBe(91 * rowHeight);
});
it('should keep mid price row in the middle', async () => {
@@ -45,7 +45,7 @@ describe('Orderbook', () => {
/>
);
await waitFor(() => screen.getByTestId(`bid-vol-${params.midPrice}`));
expect(screen.getByTestId('scroll').scrollTop).toBe(91 * rowHeight);
expect(result.getByTestId('scroll').scrollTop).toBe(91 * rowHeight);
result.rerender(
<Orderbook
decimalPlaces={decimalPlaces}
@@ -121,7 +121,7 @@ describe('Orderbook', () => {
/>
);
await waitFor(() => screen.getByTestId(`bid-vol-${params.midPrice}`));
expect(screen.getByTestId('scroll').scrollTop).toBe(91 * rowHeight + 0.01);
expect(result.getByTestId('scroll').scrollTop).toBe(91 * rowHeight + 0.01);
});
it('should get back to mid price on click', async () => {
@@ -143,7 +143,7 @@ describe('Orderbook', () => {
expect(result.getByTestId('scroll').scrollTop).toBe(1);
const scrollToMidPriceButton = result.getByTestId('scroll-to-midprice');
fireEvent.click(scrollToMidPriceButton);
expect(screen.getByTestId('scroll').scrollTop).toBe(91 * rowHeight + 1);
expect(result.getByTestId('scroll').scrollTop).toBe(91 * rowHeight + 1);
});
it('should get back to mid price on resolution change', async () => {
@@ -158,12 +158,12 @@ describe('Orderbook', () => {
/>
);
await waitFor(() => screen.getByTestId(`bid-vol-${params.midPrice}`));
const scrollElement = screen.getByTestId('scroll');
const scrollElement = result.getByTestId('scroll');
expect(scrollElement.scrollTop).toBe(91 * rowHeight);
scrollElement.scrollTop = 1;
fireEvent.scroll(scrollElement);
expect(screen.getByTestId('scroll').scrollTop).toBe(1);
const resolutionSelect = screen.getByTestId(
expect(result.getByTestId('scroll').scrollTop).toBe(1);
const resolutionSelect = result.getByTestId(
'resolution'
) as HTMLSelectElement;
fireEvent.change(resolutionSelect, { target: { value: '10' } });
@@ -181,47 +181,6 @@ describe('Orderbook', () => {
onResolutionChange={onResolutionChange}
/>
);
expect(screen.getByTestId('scroll').scrollTop).toBe(6 * rowHeight);
});
it('should format correctly the numbers on resolution change', async () => {
const onClickSpy = jest.fn();
const result = render(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
onClick={onClickSpy}
fillGaps
{...generateMockData(params)}
onResolutionChange={onResolutionChange}
/>
);
expect(
await screen.findByTestId(`bid-vol-${params.midPrice}`)
).toBeInTheDocument();
// Before resolution change the price is 122.934
await fireEvent.click(await screen.getByTestId('price-122934'));
expect(onClickSpy).toBeCalledWith('122.934');
const resolutionSelect = screen.getByTestId(
'resolution'
) as HTMLSelectElement;
await fireEvent.change(resolutionSelect, { target: { value: '10' } });
await result.rerender(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
onClick={onClickSpy}
fillGaps
{...generateMockData({
...params,
resolution: 10,
})}
onResolutionChange={onResolutionChange}
/>
);
await fireEvent.click(await screen.getByTestId('price-12299'));
// After resolution change the price is 122.99
expect(onResolutionChange.mock.calls[0][0]).toBe(10);
expect(onClickSpy).toBeCalledWith('122.99');
expect(result.getByTestId('scroll').scrollTop).toBe(6 * rowHeight);
});
});
+1 -1
View File
@@ -21,7 +21,7 @@ interface OrderbookProps extends OrderbookData {
positionDecimalPlaces: number;
resolution: number;
onResolutionChange: (resolution: number) => void;
onClick?: (price: string) => void;
onClick?: (price?: string | number) => void;
fillGaps?: boolean;
}
@@ -169,7 +169,7 @@ export const Info = ({ market, onSelect }: InfoProps) => {
<LiquidityInfoPanel market={market}>
<Link
to={`/liquidity/${market.id}`}
onClick={(ev) => onSelect?.(market.id, ev.metaKey || ev.ctrlKey)}
onClick={(ev) => onSelect?.(market.id, ev.metaKey)}
data-testid="view-liquidity-link"
>
<UILink>{t('View liquidity provision table')}</UILink>
@@ -47,8 +47,7 @@ export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => {
}
onSelect(
(data as MarketMaybeWithData).id,
(event as unknown as MouseEvent)?.metaKey ||
(event as unknown as MouseEvent)?.ctrlKey
(event as unknown as MouseEvent)?.metaKey
);
}}
onMarketClick={onSelect}
-129
View File
@@ -1,129 +0,0 @@
import { Intent } from '@vegaprotocol/ui-toolkit';
import {
getOrderToastIntent,
getOrderToastTitle,
getRejectionReason,
timeInForceLabel,
} from './utils';
import * as Types from '@vegaprotocol/types';
describe('getOrderToastTitle', () => {
it('should return the correct title', () => {
expect(getOrderToastTitle(Types.OrderStatus.STATUS_ACTIVE)).toBe(
'Order submitted'
);
expect(getOrderToastTitle(Types.OrderStatus.STATUS_FILLED)).toBe(
'Order filled'
);
expect(getOrderToastTitle(Types.OrderStatus.STATUS_PARTIALLY_FILLED)).toBe(
'Order partially filled'
);
expect(getOrderToastTitle(Types.OrderStatus.STATUS_PARKED)).toBe(
'Order parked'
);
expect(getOrderToastTitle(Types.OrderStatus.STATUS_STOPPED)).toBe(
'Order stopped'
);
expect(getOrderToastTitle(Types.OrderStatus.STATUS_CANCELLED)).toBe(
'Order cancelled'
);
expect(getOrderToastTitle(Types.OrderStatus.STATUS_EXPIRED)).toBe(
'Order expired'
);
expect(getOrderToastTitle(Types.OrderStatus.STATUS_REJECTED)).toBe(
'Order rejected'
);
expect(getOrderToastTitle(undefined)).toBe(undefined);
});
});
describe('getOrderToastIntent', () => {
it('should return the correct intent', () => {
expect(getOrderToastIntent(Types.OrderStatus.STATUS_PARKED)).toBe(
Intent.Warning
);
expect(getOrderToastIntent(Types.OrderStatus.STATUS_EXPIRED)).toBe(
Intent.Warning
);
expect(getOrderToastIntent(Types.OrderStatus.STATUS_PARTIALLY_FILLED)).toBe(
Intent.Warning
);
expect(getOrderToastIntent(Types.OrderStatus.STATUS_REJECTED)).toBe(
Intent.Danger
);
expect(getOrderToastIntent(Types.OrderStatus.STATUS_STOPPED)).toBe(
Intent.Danger
);
expect(getOrderToastIntent(Types.OrderStatus.STATUS_FILLED)).toBe(
Intent.Success
);
expect(getOrderToastIntent(Types.OrderStatus.STATUS_ACTIVE)).toBe(
Intent.Success
);
expect(getOrderToastIntent(Types.OrderStatus.STATUS_CANCELLED)).toBe(
Intent.Success
);
expect(getOrderToastIntent(undefined)).toBe(undefined);
});
});
describe('getRejectionReason', () => {
it('should return the correct rejection reason for insufficient asset balance', () => {
expect(
getRejectionReason({
rejectionReason:
Types.OrderRejectionReason.ORDER_ERROR_INSUFFICIENT_ASSET_BALANCE,
status: Types.OrderStatus.STATUS_REJECTED,
id: '',
createdAt: undefined,
size: '',
price: '',
timeInForce: Types.OrderTimeInForce.TIME_IN_FORCE_FOK,
side: Types.Side.SIDE_BUY,
marketId: '',
})
).toBe('Insufficient asset balance');
});
it('should return the correct rejection reason when order is stopped', () => {
expect(
getRejectionReason({
rejectionReason: null,
status: Types.OrderStatus.STATUS_STOPPED,
id: '',
createdAt: undefined,
size: '',
price: '',
timeInForce: Types.OrderTimeInForce.TIME_IN_FORCE_FOK,
side: Types.Side.SIDE_BUY,
marketId: '',
})
).toBe(
'Your Fill or Kill (FOK) order was not filled and it has been stopped'
);
});
});
describe('timeInForceLabel', () => {
it('should return the correct label for time in force', () => {
expect(timeInForceLabel(Types.OrderTimeInForce.TIME_IN_FORCE_FOK)).toBe(
`Fill or Kill (FOK)`
);
expect(timeInForceLabel(Types.OrderTimeInForce.TIME_IN_FORCE_GTC)).toBe(
`Good 'til Cancelled (GTC)`
);
expect(timeInForceLabel(Types.OrderTimeInForce.TIME_IN_FORCE_IOC)).toBe(
`Immediate or Cancel (IOC)`
);
expect(timeInForceLabel(Types.OrderTimeInForce.TIME_IN_FORCE_GTT)).toBe(
`Good 'til Time (GTT)`
);
expect(timeInForceLabel(Types.OrderTimeInForce.TIME_IN_FORCE_GFA)).toBe(
`Good for Auction (GFA)`
);
expect(timeInForceLabel(Types.OrderTimeInForce.TIME_IN_FORCE_GFN)).toBe(
`Good for Normal (GFN)`
);
expect(timeInForceLabel('')).toBe('');
});
});
+1 -1
View File
@@ -82,10 +82,10 @@ export const getOrderToastIntent = (
return Intent.Warning;
case Schema.OrderStatus.STATUS_REJECTED:
case Schema.OrderStatus.STATUS_STOPPED:
case Schema.OrderStatus.STATUS_CANCELLED:
return Intent.Danger;
case Schema.OrderStatus.STATUS_FILLED:
case Schema.OrderStatus.STATUS_ACTIVE:
case Schema.OrderStatus.STATUS_CANCELLED:
return Intent.Success;
default:
return;
+1
View File
@@ -5,5 +5,6 @@ export * from './lib/margin-data-provider';
export * from './lib/margin-calculator';
export * from './lib/positions-table';
export * from './lib/use-market-margin';
export * from './lib/use-market-position-open-volume';
export * from './lib/use-open-volume';
export * from './lib/use-positions-data';
@@ -354,7 +354,10 @@ export const volumeAndMarginProvider = makeDerivedDataProvider<
partyId,
marketIds: [marketId],
filter: {
status: [OrderStatus.STATUS_ACTIVE, OrderStatus.STATUS_PARKED],
status: [
OrderStatus.STATUS_ACTIVE,
OrderStatus.STATUS_PARTIALLY_FILLED,
],
},
}),
(callback, client, variables) =>
@@ -0,0 +1,29 @@
import { useCallback, useState } from 'react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { positionsDataProvider } from './positions-data-providers';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import type { PositionFieldsFragment } from './__generated__/Positions';
export const useMarketPositionOpenVolume = (marketId: string) => {
const { pubKey } = useVegaWallet();
const [openVolume, setOpenVolume] = useState<string>('');
const update = useCallback(
({ data }: { data: PositionFieldsFragment[] | null }) => {
const position = data?.find((node) => node.market.id === marketId);
if (position?.openVolume) {
setOpenVolume(position?.openVolume || '');
}
return true;
},
[setOpenVolume, marketId]
);
useDataProvider({
dataProvider: positionsDataProvider,
variables: { partyId: pubKey || '' },
skip: !pubKey || !marketId,
update,
});
return openVolume;
};
@@ -70,8 +70,6 @@ export const Notification = ({
'text-vega-green dark:text-vega-green': intent === Intent.Success,
'text-yellow-600 dark:text-yellow': intent === Intent.Warning,
'text-vega-pink': intent === Intent.Danger,
'mt-1': !!title,
'mt-[0.125rem]': !title,
},
'flex items-start mt-1'
)}
@@ -80,16 +78,11 @@ export const Notification = ({
</div>
<div className="flex flex-col flex-grow items-start gap-1.5">
{title && (
<div
key="title"
className="whitespace-nowrap overflow-hidden text-ellipsis uppercase leading-6"
>
<div className="whitespace-nowrap overflow-hidden text-ellipsis uppercase leading-6">
{title}
</div>
)}
<div key="message" className="text-sm [word-break:break-word]">
{message}
</div>
<div className="text-sm [word-break:break-word]">{message}</div>
{buttonProps && (
<Button
size={buttonProps.size || 'sm'}
-62
View File
@@ -6,7 +6,6 @@ import {
removeDecimal,
required,
isAssetTypeERC20,
formatNumber,
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { useLocalStorage } from '@vegaprotocol/react-helpers';
@@ -15,16 +14,12 @@ import {
FormGroup,
Input,
InputError,
Notification,
RichSelect,
ExternalLink,
Intent,
} from '@vegaprotocol/ui-toolkit';
import { useWeb3React } from '@web3-react/core';
import BigNumber from 'bignumber.js';
import type { ButtonHTMLAttributes } from 'react';
import type { ControllerRenderProps } from 'react-hook-form';
import { formatDistanceToNow } from 'date-fns';
import { useForm, Controller, useWatch } from 'react-hook-form';
import type { WithdrawalArgs } from './use-create-withdraw';
import { WithdrawLimits } from './withdraw-limits';
@@ -50,47 +45,6 @@ export interface WithdrawFormProps {
submitWithdraw: (withdrawal: WithdrawalArgs) => void;
}
const WithdrawDelayNotification = ({
threshold,
delay,
symbol,
decimals,
}: {
threshold: BigNumber;
delay: number | undefined;
symbol: string;
decimals: number;
}) => {
const replacements = [
symbol,
delay ? formatDistanceToNow(Date.now() + delay * 1000) : ' ',
];
return (
<Notification
intent={Intent.Warning}
testId={
threshold.isFinite()
? 'amount-withdrawal-delay-notification'
: 'withdrawals-delay-notification'
}
message={[
!threshold.isFinite()
? t('All %s withdrawals are subject to a %s delay.', replacements)
: t('Withdrawals of %s %s or more will be delayed for %s.', [
formatNumber(threshold, decimals),
...replacements,
]),
<ExternalLink
className="ml-1"
href="https://docs.vega.xyz/testnet/concepts/deposits-withdrawals#withdrawal-limits"
>
{t('Read more')}
</ExternalLink>,
]}
/>
);
};
export const WithdrawForm = ({
assets,
balance,
@@ -159,12 +113,6 @@ export const WithdrawForm = ({
);
};
const showWithdrawDelayNotification =
delay &&
selectedAsset &&
(!threshold.isFinite() ||
new BigNumber(amount).isGreaterThanOrEqualTo(threshold));
return (
<>
<div className="mb-4 text-sm">
@@ -258,16 +206,6 @@ export const WithdrawForm = ({
{t('Use maximum')}
</UseButton>
)}
{showWithdrawDelayNotification && (
<div className="mt-2">
<WithdrawDelayNotification
threshold={threshold}
symbol={selectedAsset.symbol}
decimals={selectedAsset.decimals}
delay={delay}
/>
</div>
)}
</FormGroup>
<Button
data-testid="submit-withdrawal"
+12 -34
View File
@@ -1,12 +1,7 @@
import type { Asset } from '@vegaprotocol/assets';
import { t } from '@vegaprotocol/i18n';
import { CompactNumber } from '@vegaprotocol/react-helpers';
import { WITHDRAW_THRESHOLD_TOOLTIP_TEXT } from '@vegaprotocol/assets';
import {
KeyValueTable,
KeyValueTableRow,
Tooltip,
} from '@vegaprotocol/ui-toolkit';
import { KeyValueTable, KeyValueTableRow } from '@vegaprotocol/ui-toolkit';
import BigNumber from 'bignumber.js';
import { formatDistanceToNow } from 'date-fns';
@@ -30,13 +25,7 @@ export const WithdrawLimits = ({
? formatDistanceToNow(Date.now() + delay * 1000)
: t('None');
const limits: {
key: string;
label: string;
value: string | JSX.Element;
rawValue?: BigNumber;
tooltip?: string;
}[] = [
const limits = [
{
key: 'BALANCE_AVAILABLE',
label: t('Balance available'),
@@ -47,35 +36,24 @@ export const WithdrawLimits = ({
'-'
),
},
];
if (threshold.isFinite()) {
limits.push({
{
key: 'WITHDRAWAL_THRESHOLD',
label: t('Delayed withdrawal threshold'),
tooltip: WITHDRAW_THRESHOLD_TOOLTIP_TEXT,
rawValue: threshold,
value: <CompactNumber number={threshold} decimals={asset.decimals} />,
});
}
limits.push({
key: 'DELAY_TIME',
label: t('Delay time'),
value: delayTime,
});
},
{
key: 'DELAY_TIME',
label: t('Delay time'),
value: delayTime,
},
];
return (
<KeyValueTable>
{limits.map(({ key, label, rawValue, value, tooltip }) => (
{limits.map(({ key, label, rawValue, value }) => (
<KeyValueTableRow key={key}>
<div data-testid={`${key}_label`}>
{tooltip ? (
<Tooltip description={tooltip}>
<span>{label}</span>
</Tooltip>
) : (
label
)}
</div>
<div data-testid={`${key}_label`}>{label}</div>
<div
data-testid={`${key}_value`}
className="truncate"
@@ -12,17 +12,15 @@ jest.mock('@web3-react/core', () => ({
useWeb3React: () => ({ account: ethereumAddress }),
}));
const withdrawAsset = {
asset,
balance: new BigNumber(1),
min: new BigNumber(0.0000001),
threshold: new BigNumber(1000),
delay: 10,
handleSelectAsset: jest.fn(),
};
jest.mock('./use-withdraw-asset', () => ({
useWithdrawAsset: () => withdrawAsset,
useWithdrawAsset: () => ({
asset,
balance: new BigNumber(1),
min: new BigNumber(0.0000001),
threshold: new BigNumber(1000),
delay: 10,
handleSelectAsset: jest.fn(),
}),
}));
jest.mock('@vegaprotocol/web3', () => ({
@@ -111,25 +109,4 @@ describe('WithdrawManager', () => {
});
fireEvent.submit(screen.getByTestId('withdraw-form'));
};
it('shows withdraw delay notification if amount greater than threshold', async () => {
render(generateJsx(props));
fireEvent.change(screen.getByLabelText('Amount'), {
target: { value: '1000' },
});
expect(
await screen.findByTestId('amount-withdrawal-delay-notification')
).toBeInTheDocument();
});
it('shows withdraw delay notification if threshold is 0', async () => {
withdrawAsset.threshold = new BigNumber(Infinity);
render(generateJsx(props));
fireEvent.change(screen.getByLabelText('Amount'), {
target: { value: '0.01' },
});
expect(
await screen.findByTestId('withdrawals-delay-notification')
).toBeInTheDocument();
});
});
+1 -1
View File
@@ -70,7 +70,7 @@
"react-hook-form": "^7.27.0",
"react-i18next": "^11.11.4",
"react-intersection-observer": "^9.2.2",
"react-markdown": "^8.0.6",
"react-markdown": "^8.0.5",
"react-router-dom": "^6.9.0",
"react-syntax-highlighter": "^15.4.5",
"react-use-websocket": "^3.0.0",
+4 -4
View File
@@ -19541,10 +19541,10 @@ react-lifecycles-compat@^3.0.4:
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-markdown@^8.0.6:
version "8.0.6"
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.6.tgz#3e939018f8bfce800ffdf22cf50aba3cdded7ad1"
integrity sha512-KgPWsYgHuftdx510wwIzpwf+5js/iHqBR+fzxefv8Khk3mFbnioF1bmL2idHN3ler0LMQmICKeDrWnZrX9mtbQ==
react-markdown@^8.0.5:
version "8.0.5"
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.5.tgz#c9a70a33ca9aeeafb769c6582e7e38843b9d70ad"
integrity sha512-jGJolWWmOWAvzf+xMdB9zwStViODyyFQhNB/bwCerbBKmrTmgmA599CGiOlP58OId1IMoIRsA8UdI1Lod4zb5A==
dependencies:
"@types/hast" "^2.0.0"
"@types/prop-types" "^15.0.0"