Merge branch 'master' of github.com:vegaprotocol/frontend-monorepo

This commit is contained in:
madalinaraicu 2022-06-27 15:38:20 +01:00
commit e6eda21a33
167 changed files with 3228 additions and 1550 deletions

View File

@ -5,12 +5,14 @@ Feature: Transactions Page
When I navigate to the transactions page
Then transactions page is correctly displayed
@ignore
Scenario: Navigate to transaction details page
Given I am on the homepage
When I navigate to the transactions page
And I click on the top transaction
Then transaction details are displayed
@ignore
Scenario: Navigate to transactions page using mobile
Given I am on mobile and open the toggle menu
When I navigate to the transactions page

View File

@ -36,7 +36,12 @@ export const JumpTo = ({
placeholder={placeholder}
className="max-w-[200px]"
/>
<Button data-testid="go-submit" variant="secondary" type="submit">
<Button
data-testid="go-submit"
variant="secondary"
boxShadow={false}
type="submit"
>
{t('Go')}
</Button>
</div>

View File

@ -75,7 +75,12 @@ export const Search = () => {
</InputError>
)}
</FormGroup>
<Button type="submit" variant="secondary" data-testid="search-button">
<Button
type="submit"
boxShadow={false}
variant="secondary"
data-testid="search-button"
>
{t('Search')}
</Button>
</form>

View File

@ -7,7 +7,6 @@ import { DealTicketSteps } from './deal-ticket-steps';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { gql, useQuery } from '@apollo/client';
import { DealTicketBalance } from './deal-ticket-balance';
import * as React from 'react';
import type { PartyBalanceQuery } from './__generated__/PartyBalanceQuery';
const tempEmptyText = <p>Please select a market from the markets page</p>;

View File

@ -35,7 +35,7 @@ export const DrawerToggle = ({
}, [variant]);
return (
<Button variant="inline" className={classes} onClick={onToggle}>
<Button variant="inline-link" className={classes} onClick={onToggle}>
<Icon name={iconName as IconName} />
</Button>
);

View File

@ -1,3 +1,4 @@
import produce from 'immer';
import { gql } from '@apollo/client';
import { makeDataProvider } from '@vegaprotocol/react-helpers';
import type {
@ -87,15 +88,16 @@ export const FILTERS_QUERY = gql`
`;
const update = (
draft: SimpleMarkets_markets[],
data: SimpleMarkets_markets[],
delta: SimpleMarketDataSub_marketData
) => {
const index = draft.findIndex((m) => m.id === delta.market.id);
if (index !== -1) {
draft[index].data = delta;
}
// @TODO - else push new market to draft
};
) =>
produce(data, (draft) => {
const index = draft.findIndex((m) => m.id === delta.market.id);
if (index !== -1) {
draft[index].data = delta;
}
// @TODO - else push new market to draft
});
const getData = (responseData: SimpleMarkets) => responseData.markets;
const getDelta = (

View File

@ -101,7 +101,7 @@ const SimpleMarketList = () => {
<div className="absolute right-16 top-1/2 -translate-y-1/2">
<Button
onClick={() => onClick(market.id)}
variant="inline"
variant="inline-link"
prependIconName="chevron-right"
/>
</div>

View File

@ -70,7 +70,7 @@ export default ({ steps }: StepperProps) => {
{index === steps.length - 1 ? 'Finish' : 'Continue'}
</Button>
<Button
variant="inline"
variant="inline-link"
disabled={index === 0}
onClick={handleBack}
>

View File

@ -38,7 +38,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "129999.45",
"total_removed": "0",
"locked_amount": "125847.249906896297139465",
"locked_amount": "124661.013711767544930765",
"deposits": [
{
"amount": "129999.45",
@ -488,7 +488,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "97499.58",
"total_removed": "0",
"locked_amount": "66666.63057997215661197",
"locked_amount": "65503.04337545080622283",
"deposits": [
{
"amount": "97499.58",
@ -521,7 +521,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "135173.4239508",
"total_removed": "0",
"locked_amount": "91121.77448920241599915064844",
"locked_amount": "89531.35166557213976323285608",
"deposits": [
{
"amount": "135173.4239508",
@ -554,7 +554,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "32499.86",
"total_removed": "0",
"locked_amount": "28045.500213863789588014",
"locked_amount": "27555.99917099787937361",
"deposits": [
{
"amount": "32499.86",
@ -587,7 +587,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "10833.29",
"total_removed": "0",
"locked_amount": "9128.538172520424723312",
"locked_amount": "8969.210333073256934278",
"deposits": [
{
"amount": "10833.29",
@ -675,7 +675,7 @@
"tranche_end": "2022-11-01T00:00:00.000Z",
"total_added": "22500",
"total_removed": "0",
"locked_amount": "16079.77241847825975",
"locked_amount": "15468.3027626811615",
"deposits": [
{
"amount": "15000",
@ -761,7 +761,7 @@
"tranche_end": "2023-06-02T00:00:00.000Z",
"total_added": "1939928.38",
"total_removed": "0",
"locked_amount": "1830956.520319353226245706",
"locked_amount": "1804379.69836047439128314",
"deposits": [
{
"amount": "1852091.69",
@ -1776,8 +1776,8 @@
"tranche_start": "2021-09-05T00:00:00.000Z",
"tranche_end": "2022-09-30T00:00:00.000Z",
"total_added": "60916.66666633337",
"total_removed": "18323.723696937179372649",
"locked_amount": "15541.060867673757124652184217191",
"total_removed": "18705.279504739679372649",
"locked_amount": "14760.0056484630890178248654459722",
"deposits": [
{
"amount": "2833.333333",
@ -1876,6 +1876,11 @@
}
],
"withdrawals": [
{
"amount": "381.5558078025",
"user": "0x9fd50776F133751E8Ae6abE1Be124638Bb917E05",
"tx": "0xdf5387ab07596bf2a4a608ea38d3f98f8020941f4fa7ad88f1ccd223669ac2c7"
},
{
"amount": "327.532400005",
"user": "0x1887D97F9C875108Aa6bE109B282f87A666472f2",
@ -2591,6 +2596,12 @@
}
],
"withdrawals": [
{
"amount": "381.5558078025",
"user": "0x9fd50776F133751E8Ae6abE1Be124638Bb917E05",
"tranche_id": 13,
"tx": "0xdf5387ab07596bf2a4a608ea38d3f98f8020941f4fa7ad88f1ccd223669ac2c7"
},
{
"amount": "490.9767850775",
"user": "0x9fd50776F133751E8Ae6abE1Be124638Bb917E05",
@ -2635,8 +2646,8 @@
}
],
"total_tokens": "4250",
"withdrawn_tokens": "2838.102475055",
"remaining_tokens": "1411.897524945"
"withdrawn_tokens": "3219.6582828575",
"remaining_tokens": "1030.3417171425"
},
{
"address": "0xDFaF6D0a0102ea5e4688F95Eb22Dc353751a7563",
@ -3228,8 +3239,8 @@
"tranche_id": 10,
"tranche_start": "2021-07-15T23:37:11.000Z",
"tranche_end": "2021-07-15T23:37:11.000Z",
"total_added": "3653968.150000000000000001",
"total_removed": "3645778.640000000000000001",
"total_added": "3710968.150000000000000001",
"total_removed": "3702778.640000000000000001",
"locked_amount": "0",
"deposits": [
{
@ -3242,6 +3253,11 @@
"user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f",
"tx": "0x7b0e95e1914579c79eff111dd0df59e767321858e552cbd2a65e5f0ea8c60868"
},
{
"amount": "57000",
"user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f",
"tx": "0x66d007fc762ef9b7d2c0b57434295d06dfbafb9aeb5884cedc650f5f0c98d68f"
},
{
"amount": "40000",
"user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f",
@ -3669,6 +3685,11 @@
"user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f",
"tx": "0xc5ad7140387b5c2eeeae5c158d97a8df0d4c0bbae4a61b3c03c784f11272c89a"
},
{
"amount": "57000",
"user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f",
"tx": "0x25c796bbfae4d91dca908b1ea7c50f6ea26b38d5350862b154a7963802bc3497"
},
{
"amount": "40000",
"user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f",
@ -4041,6 +4062,12 @@
"tranche_id": 10,
"tx": "0x7b0e95e1914579c79eff111dd0df59e767321858e552cbd2a65e5f0ea8c60868"
},
{
"amount": "57000",
"user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f",
"tranche_id": 10,
"tx": "0x66d007fc762ef9b7d2c0b57434295d06dfbafb9aeb5884cedc650f5f0c98d68f"
},
{
"amount": "40000",
"user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f",
@ -4127,6 +4154,12 @@
"tranche_id": 10,
"tx": "0xc5ad7140387b5c2eeeae5c158d97a8df0d4c0bbae4a61b3c03c784f11272c89a"
},
{
"amount": "57000",
"user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f",
"tranche_id": 10,
"tx": "0x25c796bbfae4d91dca908b1ea7c50f6ea26b38d5350862b154a7963802bc3497"
},
{
"amount": "40000",
"user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f",
@ -4194,8 +4227,8 @@
"tx": "0xac16a4ce688d40a482a59914d68c3a676592f8804ee8f0781b66a4ba5ccfbdfc"
}
],
"total_tokens": "507651",
"withdrawn_tokens": "507651",
"total_tokens": "564651",
"withdrawn_tokens": "564651",
"remaining_tokens": "0"
},
{
@ -5194,8 +5227,8 @@
"tranche_start": "2021-09-03T00:00:00.000Z",
"tranche_end": "2022-09-03T00:00:00.000Z",
"total_added": "19455.000000000000000003",
"total_removed": "5052.45813105178",
"locked_amount": "3864.17904680365295175059586415525114155",
"total_removed": "5056.88782409978",
"locked_amount": "3597.64752092846370375055476445966514475",
"deposits": [
{
"amount": "75",
@ -8249,6 +8282,11 @@
}
],
"withdrawals": [
{
"amount": "4.429693048",
"user": "0xc5467213593778E528f0eB8117cc7AFBC5b7491b",
"tx": "0xfbca378f6263977884e6eebc653c8d68f39b6c8eb6ce2f6668767ed63bfcc55b"
},
{
"amount": "8.25227042",
"user": "0xc5467213593778E528f0eB8117cc7AFBC5b7491b",
@ -13997,6 +14035,12 @@
}
],
"withdrawals": [
{
"amount": "4.429693048",
"user": "0xc5467213593778E528f0eB8117cc7AFBC5b7491b",
"tranche_id": 11,
"tx": "0xfbca378f6263977884e6eebc653c8d68f39b6c8eb6ce2f6668767ed63bfcc55b"
},
{
"amount": "8.25227042",
"user": "0xc5467213593778E528f0eB8117cc7AFBC5b7491b",
@ -14053,8 +14097,8 @@
}
],
"total_tokens": "200",
"withdrawn_tokens": "157.871905124",
"remaining_tokens": "42.128094876"
"withdrawn_tokens": "162.301598172",
"remaining_tokens": "37.698401828"
},
{
"address": "0x1775cc97E5c05Fde8b571ef75CA52d0A9ff19025",
@ -14079,7 +14123,7 @@
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "3732368.4671",
"total_removed": "74162.9780761646031",
"locked_amount": "2838044.0251062046717742172",
"locked_amount": "2797204.7028220379638062054",
"deposits": [
{
"amount": "1998.95815",
@ -14791,8 +14835,8 @@
"tranche_start": "2022-06-05T00:00:00.000Z",
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "15788853.065470999700000001",
"total_removed": "5923.782558947259825",
"locked_amount": "15284554.9536832239111747473350177541524737",
"total_removed": "7926.7627792759659",
"locked_amount": "15140482.7365636033722263648641426217383077",
"deposits": [
{
"amount": "16249.93",
@ -15291,6 +15335,31 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xb11f9f763196e40be412b1c6992f64d3a73b094833f57eb7783a050c64ec159d"
},
{
"amount": "605.52572395991115",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x7bf7930893a08f0c18416bb3c9470c5671a1a10a9251d4ab5eb392ed90124a60"
},
{
"amount": "460.287027070071975",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xf2208f6e0a6d6b7f5e52e128632ac52b8473b408421318b9a28460aa19feca9c"
},
{
"amount": "358.037173900154925",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x2a92ef6c2eb5779e6219058a74210fcd461484d42d623dd06dcb9886683d7b50"
},
{
"amount": "226.8137106757935",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xcb5d0a1e6fdae5bed77fe2f8a29df14985d9f21d0e681416c618104b530fab36"
},
{
"amount": "352.316584722774525",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xa79f7f3e6436a1f473f3beab9e0a5c8bc4f52b38ac7aedb8610a1a9a9c4a786c"
},
{
"amount": "2446.31552516990115",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@ -15383,6 +15452,36 @@
"tranche_id": 2,
"tx": "0xb11f9f763196e40be412b1c6992f64d3a73b094833f57eb7783a050c64ec159d"
},
{
"amount": "605.52572395991115",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0x7bf7930893a08f0c18416bb3c9470c5671a1a10a9251d4ab5eb392ed90124a60"
},
{
"amount": "460.287027070071975",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0xf2208f6e0a6d6b7f5e52e128632ac52b8473b408421318b9a28460aa19feca9c"
},
{
"amount": "358.037173900154925",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0x2a92ef6c2eb5779e6219058a74210fcd461484d42d623dd06dcb9886683d7b50"
},
{
"amount": "226.8137106757935",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0xcb5d0a1e6fdae5bed77fe2f8a29df14985d9f21d0e681416c618104b530fab36"
},
{
"amount": "352.316584722774525",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0xa79f7f3e6436a1f473f3beab9e0a5c8bc4f52b38ac7aedb8610a1a9a9c4a786c"
},
{
"amount": "2446.31552516990115",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@ -15427,8 +15526,8 @@
}
],
"total_tokens": "194999.1675",
"withdrawn_tokens": "5923.782558947259825",
"remaining_tokens": "189075.384941052740175"
"withdrawn_tokens": "7926.7627792759659",
"remaining_tokens": "187072.4047207240341"
},
{
"address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c",
@ -16832,8 +16931,8 @@
"tranche_start": "2021-11-05T00:00:00.000Z",
"tranche_end": "2023-05-05T00:00:00.000Z",
"total_added": "14597706.0446472999",
"total_removed": "2068423.077146290360122272",
"locked_amount": "8461771.6695419306722268828527521",
"total_removed": "2113641.840890679071831632",
"locked_amount": "8328080.66510881884167481291924447",
"deposits": [
{
"amount": "129284.449",
@ -17047,6 +17146,41 @@
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0xa7bccea82ef34f1943bc5243ef75909d8ae81c45e67862b9c68b0a7532edc833"
},
{
"amount": "582.7808762737973505",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0xcdbefdbd89a68d401dd21553cded39ee57bb5a7c6f3203ed6971e625f90c8b9d"
},
{
"amount": "539.09172135635481275",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0x091d995cd60f0a5a93eccb13e0ca0e39fc513c28c860bd5bc6369da3994a09d0"
},
{
"amount": "845.684674761873869",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0xcb8ecc71a9024bab7454a33f6adf7bfcd0f25b3dc1919f92ca362a25b71f2a4d"
},
{
"amount": "41515.95004024647383586",
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
"tx": "0xd950c34bf5f503998bddc8f9fdeb7cdc4ae1e76c5e9b1564795c306c2e8cad63"
},
{
"amount": "657.674387973356598",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0xd0f13de38f21ba54433885d7e3e3db7438b9bcc92dbd52a75e0b7f772018ab1c"
},
{
"amount": "424.7645385693677305",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0x77d249279d8ea7554d19c557311687d57884b5e08537ac9574897ca58a13d880"
},
{
"amount": "652.81750520748751275",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0xc62ffa6bf5029422f44d9406972fc074b498e02f667a86ae9faba138b6cfd758"
},
{
"amount": "652.48254356494551875",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@ -18629,6 +18763,42 @@
"tranche_id": 3,
"tx": "0xa7bccea82ef34f1943bc5243ef75909d8ae81c45e67862b9c68b0a7532edc833"
},
{
"amount": "582.7808762737973505",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0xcdbefdbd89a68d401dd21553cded39ee57bb5a7c6f3203ed6971e625f90c8b9d"
},
{
"amount": "539.09172135635481275",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0x091d995cd60f0a5a93eccb13e0ca0e39fc513c28c860bd5bc6369da3994a09d0"
},
{
"amount": "845.684674761873869",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0xcb8ecc71a9024bab7454a33f6adf7bfcd0f25b3dc1919f92ca362a25b71f2a4d"
},
{
"amount": "657.674387973356598",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0xd0f13de38f21ba54433885d7e3e3db7438b9bcc92dbd52a75e0b7f772018ab1c"
},
{
"amount": "424.7645385693677305",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0x77d249279d8ea7554d19c557311687d57884b5e08537ac9574897ca58a13d880"
},
{
"amount": "652.81750520748751275",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0xc62ffa6bf5029422f44d9406972fc074b498e02f667a86ae9faba138b6cfd758"
},
{
"amount": "652.48254356494551875",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@ -19867,8 +20037,8 @@
}
],
"total_tokens": "359123.469575",
"withdrawn_tokens": "150390.162087073825163",
"remaining_tokens": "208733.307487926174837"
"withdrawn_tokens": "154092.9757912160630365",
"remaining_tokens": "205030.4937837839369635"
},
{
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
@ -20055,6 +20225,12 @@
}
],
"withdrawals": [
{
"amount": "41515.95004024647383586",
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
"tranche_id": 3,
"tx": "0xd950c34bf5f503998bddc8f9fdeb7cdc4ae1e76c5e9b1564795c306c2e8cad63"
},
{
"amount": "17786.1881146007542887",
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
@ -20261,8 +20437,8 @@
}
],
"total_tokens": "1266324.603486",
"withdrawn_tokens": "497356.38070819243695426",
"remaining_tokens": "768968.22277780756304574"
"withdrawn_tokens": "538872.33074843891079012",
"remaining_tokens": "727452.27273756108920988"
},
{
"address": "0xC5d9221EB9c28A69859264c0A2Fe0d3272228296",
@ -20859,7 +21035,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "5778205.3912159303",
"total_removed": "1390546.591547348229906227",
"locked_amount": "3026393.75946481397995019109643517",
"locked_amount": "2973571.63505682836710488797665665",
"deposits": [
{
"amount": "552496.6455",
@ -21981,8 +22157,8 @@
"tranche_start": "2022-06-05T00:00:00.000Z",
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "472355.6199999996",
"total_removed": "0",
"locked_amount": "449704.29872935272705903095281584",
"total_removed": "34.173053016",
"locked_amount": "443233.07466590775804275636428212",
"deposits": [
{
"amount": "3000",
@ -28600,7 +28776,18 @@
"tx": "0xe32a466fc780a0fb3fd84a804f622931ebfaf3f428bff0dc6d141270410e75f8"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "11.163032724",
"user": "0xF5037DDA4A660d67560200f45380FF8364e35540",
"tx": "0x0db96c68606a35c59786e3b1ff4f8e939a56af133709dd154718eb03138fe227"
},
{
"amount": "23.010020292",
"user": "0xD27929d68ac0E5fd5C919A5eb5968C1D06D3Fb83",
"tx": "0x8daf320262d0384cf5f9c290cc33721587beabd5e93026b3e9b76dc3fcd6659c"
}
],
"users": [
{
"address": "0xD18ffAa4a1d16f9eD9d3BE4078738Eeda3f160FD",
@ -47113,10 +47300,17 @@
"tx": "0xe32a466fc780a0fb3fd84a804f622931ebfaf3f428bff0dc6d141270410e75f8"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "23.010020292",
"user": "0xD27929d68ac0E5fd5C919A5eb5968C1D06D3Fb83",
"tranche_id": 5,
"tx": "0x8daf320262d0384cf5f9c290cc33721587beabd5e93026b3e9b76dc3fcd6659c"
}
],
"total_tokens": "400",
"withdrawn_tokens": "0",
"remaining_tokens": "400"
"withdrawn_tokens": "23.010020292",
"remaining_tokens": "376.989979708"
},
{
"address": "0xF5037DDA4A660d67560200f45380FF8364e35540",
@ -47128,10 +47322,17 @@
"tx": "0xe32a466fc780a0fb3fd84a804f622931ebfaf3f428bff0dc6d141270410e75f8"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "11.163032724",
"user": "0xF5037DDA4A660d67560200f45380FF8364e35540",
"tranche_id": 5,
"tx": "0x0db96c68606a35c59786e3b1ff4f8e939a56af133709dd154718eb03138fe227"
}
],
"total_tokens": "200",
"withdrawn_tokens": "0",
"remaining_tokens": "200"
"withdrawn_tokens": "11.163032724",
"remaining_tokens": "188.836967276"
},
{
"address": "0x2843a3A61C7a129e432455c02101Cec3fA428E60",
@ -47635,7 +47836,7 @@
"tranche_start": "2021-12-05T00:00:00.000Z",
"tranche_end": "2022-06-05T00:00:00.000Z",
"total_added": "171288.42",
"total_removed": "29185.5825162206377",
"total_removed": "32094.1716569431377",
"locked_amount": "0",
"deposits": [
{
@ -51870,6 +52071,71 @@
"user": "0x7fAA8d1Cb6Ab8A9fC039b66fe844575557389CD4",
"tx": "0xb45e62f845fe45f11bb86fdffbc1af3e737573726b3c2c8cc6ba39ab8127369d"
},
{
"amount": "250",
"user": "0xEF5D4Be15019F9b972E54b6B904076617aDAfb1C",
"tx": "0x44d207a93bdb1ef457d5a31207d3ccbda3e9fce6528f3a6c0d04f9153e064a2a"
},
{
"amount": "249.9",
"user": "0xcad0D46627628A8bAF524BF202669e8B9f04250f",
"tx": "0xa403d8af5a940c4abd4aadcc579e279218ae73b9c7fc3d7e4216d6aab5ba70eb"
},
{
"amount": "250",
"user": "0xEc925Fd72B46E2101D20686800343220c12Dedde",
"tx": "0xeaf8173b80d3ea3eb5c440a6edcc4fbf6d8624fa437203b66f6acb72d7462b5e"
},
{
"amount": "250",
"user": "0xbC10086CB362caE3071f2e09DF2aEE5265FdA238",
"tx": "0x1ea368a1c1f000d36d93627ccda127da12e4beade77d869aab7cadb7edfa354f"
},
{
"amount": "250",
"user": "0xDA83Ff6862ed0579248CEd14422C8B782732233b",
"tx": "0x7eb0ec3a5e3d8792b341881083f9046d550fdf0e92429b53bbdddfe439e83983"
},
{
"amount": "250",
"user": "0x2b28Fd98804e19cFe8d46f2d729C2A5195339fA4",
"tx": "0xd8c87e89222f0fea8933a403cd39756c6721d1e3d86a0bb7747b428f50c7f790"
},
{
"amount": "250",
"user": "0x0941FC05E3DA8d9dD29bCBB15F9FF3A16F342612",
"tx": "0xb3cffc52e62679835e65be5472f80bcfa949f7eb0c4c9948efc3271cca02fdae"
},
{
"amount": "100",
"user": "0x4796314cC5bDa80Ee2E8b119004b1fc72Cfb1783",
"tx": "0xbfdbd5e3712968f2726e8dba1f226944cfa637f8738f25c3a5b12a1c6a8e7197"
},
{
"amount": "250",
"user": "0xC26B3b40DC383d97B69Eedcd4E78a9e4eEb73499",
"tx": "0x2c9f57d5e697c29b67034cea8738939ec13b20b5a7d7fcb995fe83f16b4abf75"
},
{
"amount": "250",
"user": "0x9f6b5A46593b991dC78a0e1907a07517A1F80CC2",
"tx": "0x55b21517cf5fd148e596d9e4b63964ab1df82534fd76b6d9dc9d7cfd00971da0"
},
{
"amount": "250",
"user": "0x696971413b8Ae5342277AfeC16591271648B4FfF",
"tx": "0xa55b22bf465927c195b424ad7ea893c1c497da34290d5261be205c760fc11cf5"
},
{
"amount": "250",
"user": "0x8FC36B7695965Bc39BCB8a3679529f1825e472aE",
"tx": "0x7072667bf81811acda07177c1ace2edcfe19ce68711fa349ad94c1f8aa3d0b25"
},
{
"amount": "58.6891407225",
"user": "0xDD5730a33719083470e641cF0e4154Dd04D5738d",
"tx": "0x49bd6332008e65069aad8012f76f15f3dae19f664237b02f9152946297db812d"
},
{
"amount": "183.6335597275",
"user": "0x690Fc36d52eD3f198F0eBDea1557333a1766f786",
@ -57843,10 +58109,17 @@
"tx": "0x75de6ca47e0da361181d14aceb5d08e572754861465caa67a12b528886d55307"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "249.9",
"user": "0xcad0D46627628A8bAF524BF202669e8B9f04250f",
"tranche_id": 6,
"tx": "0xa403d8af5a940c4abd4aadcc579e279218ae73b9c7fc3d7e4216d6aab5ba70eb"
}
],
"total_tokens": "249.9",
"withdrawn_tokens": "0",
"remaining_tokens": "249.9"
"withdrawn_tokens": "249.9",
"remaining_tokens": "0"
},
{
"address": "0x783C204FfCC479cec7807C37480A4D4C77FB1F22",
@ -58384,6 +58657,12 @@
}
],
"withdrawals": [
{
"amount": "58.6891407225",
"user": "0xDD5730a33719083470e641cF0e4154Dd04D5738d",
"tranche_id": 6,
"tx": "0x49bd6332008e65069aad8012f76f15f3dae19f664237b02f9152946297db812d"
},
{
"amount": "65.928596865",
"user": "0xDD5730a33719083470e641cF0e4154Dd04D5738d",
@ -58398,8 +58677,8 @@
}
],
"total_tokens": "250",
"withdrawn_tokens": "191.3108592775",
"remaining_tokens": "58.6891407225"
"withdrawn_tokens": "250",
"remaining_tokens": "0"
},
{
"address": "0x243e23c83135cA0fed2F9f5dF9068dE644929433",
@ -59330,10 +59609,17 @@
"tx": "0x96a22c369645e8945b4047374a05332f4054b50a492c43092e8bb8e974a006b9"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "250",
"user": "0xEc925Fd72B46E2101D20686800343220c12Dedde",
"tranche_id": 6,
"tx": "0xeaf8173b80d3ea3eb5c440a6edcc4fbf6d8624fa437203b66f6acb72d7462b5e"
}
],
"total_tokens": "250",
"withdrawn_tokens": "0",
"remaining_tokens": "250"
"withdrawn_tokens": "250",
"remaining_tokens": "0"
},
{
"address": "0x08e9b80fCa090CB3E50d77964dc8777cD828253D",
@ -59570,10 +59856,17 @@
"tx": "0x96a22c369645e8945b4047374a05332f4054b50a492c43092e8bb8e974a006b9"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "250",
"user": "0x2b28Fd98804e19cFe8d46f2d729C2A5195339fA4",
"tranche_id": 6,
"tx": "0xd8c87e89222f0fea8933a403cd39756c6721d1e3d86a0bb7747b428f50c7f790"
}
],
"total_tokens": "250",
"withdrawn_tokens": "0",
"remaining_tokens": "250"
"withdrawn_tokens": "250",
"remaining_tokens": "0"
},
{
"address": "0x61f908D9ee13a68983e5FECc8D9467232F5E9cB4",
@ -59630,10 +59923,17 @@
"tx": "0x96a22c369645e8945b4047374a05332f4054b50a492c43092e8bb8e974a006b9"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "250",
"user": "0xDA83Ff6862ed0579248CEd14422C8B782732233b",
"tranche_id": 6,
"tx": "0x7eb0ec3a5e3d8792b341881083f9046d550fdf0e92429b53bbdddfe439e83983"
}
],
"total_tokens": "250",
"withdrawn_tokens": "0",
"remaining_tokens": "250"
"withdrawn_tokens": "250",
"remaining_tokens": "0"
},
{
"address": "0xbC10086CB362caE3071f2e09DF2aEE5265FdA238",
@ -59645,10 +59945,17 @@
"tx": "0x96a22c369645e8945b4047374a05332f4054b50a492c43092e8bb8e974a006b9"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "250",
"user": "0xbC10086CB362caE3071f2e09DF2aEE5265FdA238",
"tranche_id": 6,
"tx": "0x1ea368a1c1f000d36d93627ccda127da12e4beade77d869aab7cadb7edfa354f"
}
],
"total_tokens": "250",
"withdrawn_tokens": "0",
"remaining_tokens": "250"
"withdrawn_tokens": "250",
"remaining_tokens": "0"
},
{
"address": "0xEe3183EcE9ee7d73Fb7bA7F4eB262A2dE68C42B0",
@ -61749,10 +62056,17 @@
"tx": "0x716a7be06da5a7a3d8038907974887a31805ea8eeab5d130cba528e4d2094d9f"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "250",
"user": "0x9f6b5A46593b991dC78a0e1907a07517A1F80CC2",
"tranche_id": 6,
"tx": "0x55b21517cf5fd148e596d9e4b63964ab1df82534fd76b6d9dc9d7cfd00971da0"
}
],
"total_tokens": "250",
"withdrawn_tokens": "0",
"remaining_tokens": "250"
"withdrawn_tokens": "250",
"remaining_tokens": "0"
},
{
"address": "0x758E9AA35F2feA08aEc1613A0F0d9Ebe4d374152",
@ -61804,10 +62118,17 @@
"tx": "0x716a7be06da5a7a3d8038907974887a31805ea8eeab5d130cba528e4d2094d9f"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "250",
"user": "0x8FC36B7695965Bc39BCB8a3679529f1825e472aE",
"tranche_id": 6,
"tx": "0x7072667bf81811acda07177c1ace2edcfe19ce68711fa349ad94c1f8aa3d0b25"
}
],
"total_tokens": "250",
"withdrawn_tokens": "0",
"remaining_tokens": "250"
"withdrawn_tokens": "250",
"remaining_tokens": "0"
},
{
"address": "0x8186CDe8f7A2f95b50f847e2a3301c28bB61Fa8A",
@ -62231,10 +62552,17 @@
"tx": "0x9f916cf09e8a3c4ade0ffce5190db464d0a2b1dadba78e1ee7ba5d6e751d6148"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "250",
"user": "0x0941FC05E3DA8d9dD29bCBB15F9FF3A16F342612",
"tranche_id": 6,
"tx": "0xb3cffc52e62679835e65be5472f80bcfa949f7eb0c4c9948efc3271cca02fdae"
}
],
"total_tokens": "250",
"withdrawn_tokens": "0",
"remaining_tokens": "250"
"withdrawn_tokens": "250",
"remaining_tokens": "0"
},
{
"address": "0x0a5688ed5b0b804db2ee18767476bb60598EC398",
@ -63811,10 +64139,17 @@
"tx": "0xd23813c30e93f3867eaa257b7aef7052a050b1ee1c1a90102a3f40c5d989fe82"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "250",
"user": "0x696971413b8Ae5342277AfeC16591271648B4FfF",
"tranche_id": 6,
"tx": "0xa55b22bf465927c195b424ad7ea893c1c497da34290d5261be205c760fc11cf5"
}
],
"total_tokens": "250",
"withdrawn_tokens": "0",
"remaining_tokens": "250"
"withdrawn_tokens": "250",
"remaining_tokens": "0"
},
{
"address": "0xcbEca0abcc675A0F977c4Eb9a45bB4153C0246C3",
@ -63848,10 +64183,17 @@
"tx": "0xd23813c30e93f3867eaa257b7aef7052a050b1ee1c1a90102a3f40c5d989fe82"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "250",
"user": "0xC26B3b40DC383d97B69Eedcd4E78a9e4eEb73499",
"tranche_id": 6,
"tx": "0x2c9f57d5e697c29b67034cea8738939ec13b20b5a7d7fcb995fe83f16b4abf75"
}
],
"total_tokens": "250",
"withdrawn_tokens": "0",
"remaining_tokens": "250"
"withdrawn_tokens": "250",
"remaining_tokens": "0"
},
{
"address": "0xd866082E19c9E36bcA4fA649d530166303B656f2",
@ -64126,10 +64468,17 @@
"tx": "0xd23813c30e93f3867eaa257b7aef7052a050b1ee1c1a90102a3f40c5d989fe82"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "250",
"user": "0xEF5D4Be15019F9b972E54b6B904076617aDAfb1C",
"tranche_id": 6,
"tx": "0x44d207a93bdb1ef457d5a31207d3ccbda3e9fce6528f3a6c0d04f9153e064a2a"
}
],
"total_tokens": "250",
"withdrawn_tokens": "0",
"remaining_tokens": "250"
"withdrawn_tokens": "250",
"remaining_tokens": "0"
},
{
"address": "0x660Bc2766867E1E19252ad30A413fe20d08A85c4",
@ -64156,10 +64505,17 @@
"tx": "0xd23813c30e93f3867eaa257b7aef7052a050b1ee1c1a90102a3f40c5d989fe82"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "100",
"user": "0x4796314cC5bDa80Ee2E8b119004b1fc72Cfb1783",
"tranche_id": 6,
"tx": "0xbfdbd5e3712968f2726e8dba1f226944cfa637f8738f25c3a5b12a1c6a8e7197"
}
],
"total_tokens": "100",
"withdrawn_tokens": "0",
"remaining_tokens": "100"
"withdrawn_tokens": "100",
"remaining_tokens": "0"
},
{
"address": "0x351cc2560C870f01B099B106Be22C0073Fce10B2",

View File

@ -38,7 +38,7 @@
"tranche_end": "2022-11-26T13:48:10.000Z",
"total_added": "100",
"total_removed": "0",
"locked_amount": "43.033418949771685",
"locked_amount": "41.663429096905125",
"deposits": [
{
"amount": "100",
@ -242,7 +242,7 @@
"tranche_end": "2022-10-12T00:53:20.000Z",
"total_added": "1100",
"total_removed": "673.04388635",
"locked_amount": "336.1295630390665",
"locked_amount": "321.05967465753423",
"deposits": [
{
"amount": "1000",

View File

@ -69,7 +69,7 @@
"tranche_end": "2022-10-12T00:53:20.000Z",
"total_added": "1010.000000000000000001",
"total_removed": "668.4622323651",
"locked_amount": "308.628053335870150000305572330035515",
"locked_amount": "294.7911558219177930002918724315068493",
"deposits": [
{
"amount": "1000",

View File

@ -1,29 +1,17 @@
# React Environment Variables
# https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#expanding-environment-variables-in-env
# Netlify Environment Variables
# https://www.netlify.com/docs/continuous-deployment/#environment-variables
REACT_APP_VERSION=$npm_package_version
REACT_APP_REPOSITORY_URL=$REPOSITORY_URL
REACT_APP_BRANCH=$BRANCH
REACT_APP_PULL_REQUEST=$PULL_REQUEST
REACT_APP_HEAD=$HEAD
REACT_APP_COMMIT_REF=$COMMIT_REF
REACT_APP_CONTEXT=$CONTEXT
REACT_APP_REVIEW_ID=$REVIEW_ID
REACT_APP_INCOMING_HOOK_TITLE=$INCOMING_HOOK_TITLE
REACT_APP_INCOMING_HOOK_URL=$INCOMING_HOOK_URL
REACT_APP_INCOMING_HOOK_BODY=$INCOMING_HOOK_BODY
REACT_APP_URL=$URL
REACT_APP_DEPLOY_URL=$DEPLOY_URL
REACT_APP_DEPLOY_PRIME_URL=$DEPLOY_PRIME_URL
# App configuration variables
NX_VEGA_ENV=TESTNET
NX_VEGA_URL=https://lb.testnet.vega.xyz/query
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHEREUM_PROVIDER_URL=http://localhost:8545
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
NX_FAIRGROUND=false
NX_IS_NEW_BRIDGE_CONTRACT=true
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET":"https://dev.token.vega.xyz","STAGNET2":"staging2.token.vega.xyz","TESTNET":"token.fairground.wtf","MAINNET":"token.vega.xyz"}'
NX_VEGA_URL=http://localhost:3028/query
NX_VEGA_REST=http://localhost:3029
NX_ETHEREUM_CHAIN_ID=1440
NX_ETH_URL_CONNECT=1
NX_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
NX_LOCAL_PROVIDER_URL=http://localhost:8545/
#Test configuration variables
CYPRESS_FAIRGROUND=false

View File

@ -0,0 +1,4 @@
{
"tokenAddress": "0x67175Da1D5e966e40D11c4B2519392B2058373de",
"vestingContract": "0xF41bD86d462D36b997C0bbb4D97a0a3382f205B7"
}

View File

@ -1,4 +0,0 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io"
}

View File

@ -0,0 +1,124 @@
import navigation from '../../locators/navigation.locators';
import home from '../../locators/home.locators';
import vegaToken from '../../data/vegaToken.json';
context('Home Page - verify elements on page', function () {
before('visit token home page', function () {
cy.visit('/');
});
describe('with wallets disconnected', function () {
before('wait for page to load', function () {
cy.get(navigation.section, { timeout: 10000 }).should('be.visible');
});
describe('Navigation tabs', function () {
it('should have HOME tab', function () {
cy.get(navigation.section).within(() => {
cy.get(navigation.home).should('be.visible');
});
});
it('should have VESTING tab', function () {
cy.get(navigation.section).within(() => {
cy.get(navigation.vesting).should('be.visible');
});
});
it('should have STAKING tab', function () {
cy.get(navigation.section).within(() => {
cy.get(navigation.staking).should('be.visible');
});
});
it('should have REWARDS tab', function () {
cy.get(navigation.section).within(() => {
cy.get(navigation.rewards).should('be.visible');
});
});
it('should have WITHDRAW tab', function () {
cy.get(navigation.section).within(() => {
cy.get(navigation.withdraw).should('be.visible');
});
});
it('should have GOVERNANCE tab', function () {
cy.get(navigation.section).within(() => {
cy.get(navigation.governance).should('be.visible');
});
});
});
describe('THE $VEGA TOKEN table', function () {
it('should have TOKEN ADDRESS', function () {
cy.get(home.tokenDetailsTable).within(() => {
cy.get(home.address)
.should('be.visible')
.invoke('text')
.should('be.equal', vegaToken.tokenAddress);
});
});
it('should have VESTING CONTRACT', function () {
cy.get(home.tokenDetailsTable).within(() => {
cy.get(home.contract)
.should('be.visible')
.invoke('text')
.should('be.equal', vegaToken.vestingContract);
});
});
it('should have TOTAL SUPPLY', function () {
cy.get(home.tokenDetailsTable).within(() => {
cy.get(home.totalSupply).should('be.visible');
});
});
it('should have CIRCULATING SUPPLY', function () {
cy.get(home.tokenDetailsTable).within(() => {
cy.get(home.circulatingSupply).should('be.visible');
});
});
it('should have STAKED $VEGA', function () {
cy.get(home.tokenDetailsTable).within(() => {
cy.get(home.staked).should('be.visible');
});
});
});
describe('links and buttons', function () {
it('should have TRANCHES link', function () {
cy.get(home.tranchesLink)
.should('be.visible')
.and('have.attr', 'href')
.and('equal', '/tranches');
});
it('should have REDEEM button', function () {
cy.get(home.redeemBtn)
.should('be.visible')
.parent()
.should('have.attr', 'href')
.and('equal', '/vesting');
});
it('should have GET VEGA WALLET link', function () {
cy.get(home.getVegaWalletLink)
.should('be.visible')
.and('have.attr', 'href')
.and('equal', 'https://vega.xyz/wallet');
});
it('should have ASSOCIATE VEGA TOKENS link', function () {
cy.get(home.associateVegaLink)
.should('be.visible')
.and('have.attr', 'href')
.and('equal', '/staking/associate');
});
it('should have STAKING button', function () {
cy.get(home.stakingBtn)
.should('be.visible')
.parent()
.should('have.attr', 'href')
.and('equal', '/staking');
});
it('should have GOVERNANCE button', function () {
cy.get(home.governanceBtn)
.should('be.visible')
.parent()
.should('have.attr', 'href')
.and('equal', '/governance');
});
});
});
});

View File

@ -0,0 +1,15 @@
export default {
tokenDetailsTable: '.token-details',
address: '[data-testid="token-address"]',
contract: '[data-testid="token-contract"]',
totalSupply: '[data-testid="total-supply"]',
circulatingSupply: '[data-testid="circulating-supply"]',
staked: '[data-testid="staked"]',
tranchesLink: '[data-testid="tranches-link"]',
redeemBtn: '[data-testid="check-vesting-page-btn"]',
getVegaWalletLink: '[data-testid="get-vega-wallet-link"]',
associateVegaLink: '[data-testid="associate-vega-tokens-link-on-homepage"]',
stakingBtn: '[data-testid="staking-button-on-homepage"]',
governanceBtn: '[data-testid="governance-button-on-homepage"]',
};

View File

@ -0,0 +1,9 @@
export default {
section: 'nav',
home: '[href="/"]',
vesting: '[href="/vesting"]',
staking: '[href="/staking"]',
rewards: '[href="/rewards"]',
withdraw: '[href="/withdraw"]',
governance: '[href="/governance"]',
};

View File

@ -1,23 +1,3 @@
# React Environment Variables
# https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#expanding-environment-variables-in-env
# Netlify Environment Variables
# https://www.netlify.com/docs/continuous-deployment/#environment-variables
REACT_APP_VERSION=$npm_package_version
REACT_APP_REPOSITORY_URL=$REPOSITORY_URL
REACT_APP_BRANCH=$BRANCH
REACT_APP_PULL_REQUEST=$PULL_REQUEST
REACT_APP_HEAD=$HEAD
REACT_APP_COMMIT_REF=$COMMIT_REF
REACT_APP_CONTEXT=$CONTEXT
REACT_APP_REVIEW_ID=$REVIEW_ID
REACT_APP_INCOMING_HOOK_TITLE=$INCOMING_HOOK_TITLE
REACT_APP_INCOMING_HOOK_URL=$INCOMING_HOOK_URL
REACT_APP_INCOMING_HOOK_BODY=$INCOMING_HOOK_BODY
REACT_APP_URL=$URL
REACT_APP_DEPLOY_URL=$DEPLOY_URL
REACT_APP_DEPLOY_PRIME_URL=$DEPLOY_PRIME_URL
# App configuration variables
NX_VEGA_ENV=TESTNET
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json

17
apps/token/.env.capsule Normal file
View File

@ -0,0 +1,17 @@
# App configuration variables
NX_VEGA_ENV=TESTNET
NX_ETHEREUM_PROVIDER_URL=http://localhost:8545
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
NX_FAIRGROUND=false
NX_IS_NEW_BRIDGE_CONTRACT=true
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET":"https://dev.token.vega.xyz","STAGNET2":"staging2.token.vega.xyz","TESTNET":"token.fairground.wtf","MAINNET":"token.vega.xyz"}'
NX_VEGA_URL=http://localhost:3028/query
NX_VEGA_REST=http://localhost:3029
NX_ETHEREUM_CHAIN_ID=1440
NX_ETH_URL_CONNECT=1
NX_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
NX_LOCAL_PROVIDER_URL=http://localhost:8545/
#Test configuration variables
CYPRESS_FAIRGROUND=false

View File

@ -38,23 +38,19 @@ yarn nx run token:serve --env={env} # e.g. stagnet1
There are a few different configuration options offered for this app:
| **Flag** | **Purpose** |
| ------------------------------ | ---------------------------------------------------------------------------------------------------- |
| `NX_APP_SENTRY_DSN` | The sentry endpoint to report to. Should be off in dev but set in live. |
| `NX_APP_CHAIN` | The ETH chain for the app to work on. Should be mainnet for live, but ropsten for preview deploys. |
| `NX_APP_VEGA_URL` | The GraphQL query endpoint of a [Vega data node](https://github.com/vegaprotocol/networks#data-node) |
| `NX_APP_DEX_STAKING_DISABLED` | Disable the dex liquidity page an show a coming soon message |
| `NX_APP_FAIRGROUND` | Change styling to be themed as the fairground version of the website |
| `NX_APP_INFURA_ID` | Infura fallback for if the user does not have a web3 compatible browser |
| `NX_APP_HOSTED_WALLET_ENABLED` | If the hosted wallet is enabled or not. If so then allow users to login using the hosted wallet |
| `NX_APP_ENV` | Change network to connect to. When set to CUSTOM use CUSTOM\_\* vars for network parameters |
| `NX_CUSTOM_URLS` | When NX_APP_ENV=CUSTOM use these Data Node REST URLs, optional if CUSTOM_URLS_WITH_GRAPHQL is used. |
| `NX_CUSTOM_URLS_WITH_GRAPHQL` | When NX_APP_ENV=CUSTOM use these Data Node GraphQL URLs, optional if CUSTOM_URLS is used. |
| `NX_CUSTOM_TOKEN_ADDRESS` | When NX_APP_ENV=CUSTOM specify Vega token address. |
| `NX_CUSTOM_CLAIM_ADDRESS` | When NX_APP_ENV=CUSTOM specify Vega claim address. |
| `NX_CUSTOM_LOCKED_ADDRESS` | When NX_APP_ENV=CUSTOM specify Vega locked address. |
| `NX_CUSTOM_VESTING_ADDRESS` | When NX_APP_ENV=CUSTOM specify Vega vesting address. |
| `NX_CUSTOM_STAKING_BRIDGE` | When NX_APP_ENV=CUSTOM specify Vega staking bridge address. |
| **Flag** | **Purpose** |
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NX_APP_SENTRY_DSN` | The sentry endpoint to report to. Should be off in dev but set in live. |
| `NX_APP_CHAIN` | The ETH chain for the app to work on. Should be mainnet for live, but ropsten for preview deploys. |
| `NX_APP_VEGA_URL` | The GraphQL query endpoint of a [Vega data node](https://github.com/vegaprotocol/networks#data-node) |
| `NX_APP_DEX_STAKING_DISABLED` | Disable the dex liquidity page an show a coming soon message |
| `NX_APP_FAIRGROUND` | Change styling to be themed as the fairground version of the website |
| `NX_APP_INFURA_ID` | Infura fallback for if the user does not have a web3 compatible browser |
| `NX_APP_HOSTED_WALLET_ENABLED` | If the hosted wallet is enabled or not. If so then allow users to login using the hosted wallet |
| `NX_APP_ENV` | Change network to connect to. When set to CUSTOM use CUSTOM\_\* vars for network parameters |
| `NX_ETH_URL_CONNECT` (optional) | If set to true the below two must also be set. This allows siging transactions in brower to allow to connect to a local ganache node through cypress |
| `NX_ETH_WALLET_MNEMONIC` (optional) | The mnemonic to be used to sign transactions with in browser |
| `NX_LOCAL_PROVIDER_URL` (optional) | The local node to use to send transaction to when signing in browser |
## Example configs:

View File

@ -2,6 +2,7 @@ import { useWeb3React } from '@web3-react/core';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import { getButtonClasses, Button } from '@vegaprotocol/ui-toolkit';
import {
AppStateActionType,
@ -70,7 +71,7 @@ const AssociatedAmounts = ({
rightLabel={t('notAssociated')}
leftColor={Colors.white.DEFAULT}
rightColor={Colors.black.DEFAULT}
light={true}
light={false}
/>
{vestingAssociationByVegaKey.length ? (
<>
@ -129,6 +130,7 @@ const ConnectedKey = () => {
name="VEGA"
symbol="In vesting contract"
balance={totalInVestingContract}
dark={true}
/>
<LockedProgress
locked={totalLockedBalance}
@ -136,7 +138,7 @@ const ConnectedKey = () => {
total={totalVestedBalance.plus(totalLockedBalance)}
leftLabel={t('Locked')}
rightLabel={t('Unlocked')}
light={true}
light={false}
/>
</>
)}
@ -153,6 +155,7 @@ const ConnectedKey = () => {
name="VEGA"
symbol="In Wallet"
balance={walletWithAssociations}
dark={true}
/>
{!Object.keys(
appState.associationBreakdown.stakingAssociations
@ -163,15 +166,17 @@ const ConnectedKey = () => {
/>
)}
<WalletCardActions>
<Link className="flex-1" to={`${Routes.STAKING}/associate`}>
<span className="flex items-center justify-center w-full text-center px-28 border h-28">
{t('associate')}
</span>
<Link
className={getButtonClasses('flex-1 mr-4', 'secondary')}
to={`${Routes.STAKING}/associate`}
>
{t('associate')}
</Link>
<Link className="flex-1" to={`${Routes.STAKING}/disassociate`}>
<span className="flex items-center justify-center w-full px-28 border h-28">
{t('disassociate')}
</span>
<Link
className={getButtonClasses('flex-1 ml-4', 'secondary')}
to={`${Routes.STAKING}/disassociate`}
>
{t('disassociate')}
</Link>
</WalletCardActions>
</>
@ -185,7 +190,7 @@ export const EthWallet = () => {
const pendingTxs = usePendingTransactions();
return (
<WalletCard>
<WalletCard dark={true}>
<WalletCardHeader>
<h1 className="text-h3 uppercase">{t('ethereumKey')}</h1>
{account && (
@ -203,7 +208,7 @@ export const EthWallet = () => {
})
}
>
<Loader size="small" forceTheme="light" />
<Loader size="small" forceTheme="dark" />
{t('pendingTransactions')}
</button>
</div>
@ -215,7 +220,8 @@ export const EthWallet = () => {
{account ? (
<ConnectedKey />
) : (
<button
<Button
variant={'secondary'}
className="w-full px-28 border h-28"
onClick={() =>
appDispatch({
@ -226,7 +232,7 @@ export const EthWallet = () => {
data-test-id="connect-to-eth-wallet-button"
>
{t('connectEthWalletToAssociate')}
</button>
</Button>
)}
{account && (
<WalletCardActions>

View File

@ -1,8 +1,8 @@
import React from 'react';
import { formatNumber } from '../../lib/format-number';
import type { BigNumber } from '../../lib/bignumber';
import { theme } from '@vegaprotocol/tailwindcss-config';
import classnames from 'classnames';
const Colors = theme.colors;
@ -14,9 +14,10 @@ const ProgressContents = ({
children: React.ReactNode;
}) => (
<div
className={`flex justify-between py-2 font-mono ${
light ? 'gap-0 px-0 text-black' : 'gap-y-0 gap-x-4 px-4'
}`}
className={classnames('flex justify-between py-2 font-mono', {
'gap-0 px-0 text-black': light,
'gap-y-0 gap-x-4': !light,
})}
>
{children}
</div>
@ -25,17 +26,22 @@ const ProgressContents = ({
const ProgressIndicator = ({
bgColor,
side,
light,
}: {
bgColor: string;
side: 'left' | 'right';
light: boolean;
}) => (
<span
style={{
backgroundColor: bgColor,
}}
className={`inline-block w-12 h-12 border border-black ${
side === 'left' ? 'mr-8' : 'ml-8'
}`}
className={classnames('inline-block w-12 h-12 border', {
'mr-8': side === 'left',
'ml-8': side === 'right',
'border-black': light,
'border-white': !light,
})}
/>
);
@ -64,6 +70,7 @@ export interface LockedProgressProps {
leftColor?: string;
rightColor?: string;
light?: boolean;
decimals?: number;
}
export const LockedProgress = ({
@ -73,8 +80,9 @@ export const LockedProgress = ({
leftLabel,
rightLabel,
leftColor = Colors.vega.pink,
rightColor = Colors.green.DEFAULT,
rightColor = Colors.vega.green,
light = false,
decimals = 2,
}: LockedProgressProps) => {
const lockedPercentage = React.useMemo(() => {
return locked.div(total).times(100);
@ -85,26 +93,35 @@ export const LockedProgress = ({
}, [total, unlocked]);
return (
<div className="border-x border-x-white">
<div className={`flex ${light && 'border border-black'}`}>
<>
<div
className={classnames('flex border', {
'border-black': light,
'border-white': !light,
})}
>
<ProgressBar percentage={lockedPercentage} bgColor={leftColor} />
<ProgressBar percentage={unlockedPercentage} bgColor={rightColor} />
</div>
<ProgressContents light={light}>
<span>
<ProgressIndicator bgColor={leftColor} side={'left'} />
<ProgressIndicator bgColor={leftColor} side={'left'} light={false} />
{leftLabel}
</span>
<span>
{rightLabel}
<ProgressIndicator bgColor={rightColor} side={'right'} />
<ProgressIndicator
bgColor={rightColor}
side={'right'}
light={false}
/>
</span>
</ProgressContents>
<ProgressContents light={light}>
<span>{formatNumber(locked, 2)}</span>
<span>{formatNumber(unlocked, 2)}</span>
<span>{formatNumber(locked, decimals)}</span>
<span>{formatNumber(unlocked, decimals)}</span>
</ProgressContents>
</div>
</>
);
};

View File

@ -12,7 +12,7 @@ export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
<div className="border-b border-white lg:grid lg:grid-rows-[auto_minmax(600px,_1fr)] lg:grid-cols-[1fr_450px]">
<Nav />
<main className="p-20">{children}</main>
<aside className="hidden lg:block lg:col-start-2 lg:col-end-3 lg:row-start-1 lg: row-end-3 p-20 bg-banner bg-contain border-l border-white">
<aside className="hidden lg:block lg:col-start-2 lg:col-end-4 lg:row-start-1 lg: row-end-4 p-20 bg-banner bg-contain border-l border-white">
{sidebar.map((Component, i) => (
<section className="mb-20 last:mb-0" key={i}>
{Component}

View File

@ -180,15 +180,15 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
</div>
))}
<WalletCardActions>
<Link style={{ flex: 1 }} to={Routes.GOVERNANCE}>
<span className="flex items-center justify-center w-full px-28 border h-28 bg-white text-black">
<Link className="flex-1 pr-8" to={Routes.GOVERNANCE}>
<Button variant={'secondary'} className="w-full">
{t('governance')}
</span>
</Button>
</Link>
<Link style={{ flex: 1 }} to={Routes.STAKING}>
<span className="flex items-center justify-center w-full px-28 border h-28 bg-white text-black">
<Link className="flex-1 pl-8" to={Routes.STAKING}>
<Button variant={'secondary'} className="w-full">
{t('staking')}
</span>
</Button>
</Link>
</WalletCardActions>
<VegaWalletAssetList accounts={accounts} />

View File

@ -55,6 +55,9 @@ export const ENV = {
commit: windowOrDefault('NX_COMMIT_REF'),
branch: windowOrDefault('NX_BRANCH'),
vegaUrl: windowOrDefault('NX_VEGA_URL'),
urlConnect: TRUTHY.includes(windowOrDefault('NX_ETH_URL_CONNECT')),
ethWalletMnemonic: windowOrDefault('NX_ETH_WALLET_MNEMONIC'),
localProviderUrl: windowOrDefault('NX_LOCAL_PROVIDER_URL'),
flags: {
NETWORK_DOWN: TRUTHY.includes(windowOrDefault('NX_NETWORK_DOWN')),
HOSTED_WALLET_ENABLED: TRUTHY.includes(

View File

@ -1,10 +1,8 @@
import React from 'react';
import { useContracts } from '../../contexts/contracts/contracts-context';
import mock from './tranches-mock';
import type { Tranche } from '@vegaprotocol/smart-contracts';
export function useTranches() {
const { vesting } = useContracts();
const [tranches, setTranches] = React.useState<Tranche[] | null>(null);
const [error, setError] = React.useState<string | null>(null);
@ -17,7 +15,7 @@ export function useTranches() {
}
};
run();
}, [vesting]);
}, []);
return { tranches, error };
}

View File

@ -1,3 +1,4 @@
import { toBigNum } from '@vegaprotocol/react-helpers';
import React from 'react';
import {
@ -7,23 +8,26 @@ import {
import { useContracts } from '../contexts/contracts/contracts-context';
export function useRefreshAssociatedBalances() {
const { appDispatch } = useAppState();
const {
appDispatch,
appState: { decimals },
} = useAppState();
const { staking, vesting } = useContracts();
return React.useCallback(
async (ethAddress: string, vegaKey: string) => {
const [walletAssociatedBalance, vestingAssociatedBalance] =
await Promise.all([
staking.stakeBalance(ethAddress, `0x${vegaKey}`),
vesting.stakeBalance(ethAddress, `0x${vegaKey}`),
staking.stakeBalance(ethAddress, vegaKey),
vesting.stakeBalance(ethAddress, vegaKey),
]);
appDispatch({
type: AppStateActionType.REFRESH_ASSOCIATED_BALANCES,
walletAssociatedBalance,
vestingAssociatedBalance,
walletAssociatedBalance: toBigNum(walletAssociatedBalance, decimals),
vestingAssociatedBalance: toBigNum(vestingAssociatedBalance, decimals),
});
},
[staking, vesting, appDispatch]
[staking, vesting, appDispatch, decimals]
);
}

View File

@ -193,6 +193,7 @@
"noGovernanceTokens": "You need some VEGA tokens to participate in governance",
"youVoted": "You voted",
"changeVote": "Change vote",
"voteRequested": "Please confirm transaction in wallet",
"votePending": "Casting vote",
"voteError": "Something went wrong, and your vote was not seen by the network",
"back": "back",
@ -280,6 +281,7 @@
"stakingHasAssociated": "You have {{tokens}} $VEGA tokens associated.",
"stakingAssociateMoreButton": "Associate more $VEGA tokens with wallet",
"stakingDisassociateButton": "Disassociate $VEGA tokens from wallet",
"stakingConfirm": "Open you wallet app to confirm",
"associateButton": "Associate $VEGA tokens with wallet",
"nodeQueryFailed": "Could not get data for validator {{node}}",
"stakeAddPendingTitle": "Adding {{amount}} $VEGA to validator {{node}}",
@ -540,5 +542,8 @@
"numberOfAgainstVotes": "Number of votes against",
"yesPercentage": "Yes percentage",
"noPercentage": "No percentage",
"proposalTerms": "Proposal terms"
"proposalTerms": "Proposal terms",
"currentlySetTo": "Currently set to ",
"pass": "Pass",
"fail": "Fail"
}

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" class="bg-black w-full h-full">
<html lang="en" class="dark bg-black w-full h-full">
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="//static.vega.xyz/fonts.css" />

View File

@ -0,0 +1,150 @@
import { ethers, Wallet } from 'ethers';
import { Connector } from '@web3-react/types';
import { Eip1193Bridge } from '@ethersproject/experimental';
import type { ConnectionInfo } from '@ethersproject/web';
import type { Actions } from '@web3-react/types';
import { ENV } from '../config/env';
export class CustomizedBridge extends Eip1193Bridge {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async sendAsync(...args: any) {
console.debug('sendAsync called', ...args);
return this.send(...args);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
override async send(...args: any) {
console.debug('send called', ...args);
const isCallbackForm =
typeof args[0] === 'object' && typeof args[1] === 'function';
let callback;
let method;
let params;
if (isCallbackForm) {
callback = args[1];
method = args[0].method;
params = args[0].params;
} else {
method = args[0];
params = args[1];
}
try {
// Hacky, https://github.com/ethers-io/ethers.js/issues/1683#issuecomment-1016227588
// If from is present on eth_call it errors, removing it makes the library set
// from as the connected wallet which works fine
if (params && params.length && params[0].from && method === 'eth_call')
delete params[0].from;
let result;
// For sending a transaction if we call send it will error
// as it wants gasLimit in sendTransaction but hexlify sets the property gas
// to gasLimit which makes sensd transaction error.
// This has taken the code from the super method for sendTransaction and altered
// it slightly to make it work with the gas limit issues.
if (
params &&
params.length &&
params[0].from &&
method === 'eth_sendTransaction'
) {
// Hexlify will not take gas, must be gasLimit, set this property to be gasLimit
params[0].gasLimit = params[0].gas;
delete params[0].gas;
// If from is present on eth_sendTransaction it errors, removing it makes the library set
// from as the connected wallet which works fine
delete params[0].from;
const req = ethers.providers.JsonRpcProvider.hexlifyTransaction(
params[0]
);
// Hexlify sets the gasLimit property to be gas again and send transaction requires gasLimit
req['gasLimit'] = req['gas'];
delete req['gas'];
if (!this.signer) {
throw new Error('No signer');
}
// Send the transaction
const tx = await this.signer.sendTransaction(req);
result = tx.hash;
} else {
// All other transactions the base class works for
result = await super.send(method, params);
}
console.debug('result received', method, params, result);
if (isCallbackForm) {
callback(null, { result });
} else {
return result;
}
} catch (error) {
console.error(error);
if (isCallbackForm) {
callback(error, null);
} else {
throw error;
}
}
}
}
type url = string | ConnectionInfo;
export class Url extends Connector {
/** {@inheritdoc Connector.provider} */
public override provider: Eip1193Bridge | undefined;
private eagerConnection?: Promise<void>;
private url: url;
/**
* @param url - An RPC url.
* @param connectEagerly - A flag indicating whether connection should be initiated when the class is constructed.
*/
constructor(actions: Actions, url: url, connectEagerly = false) {
super(actions);
if (connectEagerly && typeof window === 'undefined') {
throw new Error(
'connectEagerly = true is invalid for SSR, instead use the activate method in a useEffect'
);
}
this.url = url;
if (connectEagerly) void this.activate();
}
private async isomorphicInitialize() {
if (this.eagerConnection) return this.eagerConnection;
await (this.eagerConnection = import('@ethersproject/providers')
.then(({ JsonRpcProvider }) => JsonRpcProvider)
.then((JsonRpcProvider) => {
const provider = new JsonRpcProvider(this.url);
const privateKey = Wallet.fromMnemonic(
ENV.ethWalletMnemonic,
`m/44'/60'/0'/0/0`
).privateKey;
const signer = new Wallet(privateKey, provider);
this.provider = new CustomizedBridge(signer, provider);
this.actions.update({ accounts: [signer.address], chainId: 1440 });
}));
}
/** {@inheritdoc Connector.activate} */
public async activate(): Promise<void> {
this.actions.startActivation();
await this.isomorphicInitialize();
try {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const chainId = await this.provider!.request({ method: 'eth_chainId' });
this.actions.update({ chainId: Number(chainId) });
} catch (error) {
this.actions.reportError(error as Error);
}
}
}

View File

@ -3,11 +3,18 @@ import type { Web3ReactHooks } from '@web3-react/core';
import { initializeConnector } from '@web3-react/core';
import { MetaMask } from '@web3-react/metamask';
import { WalletConnect } from '@web3-react/walletconnect';
import { Url } from './url-connector';
import type { Connector } from '@web3-react/types';
import { ENV } from '../config/env';
const [metamask, metamaskHooks] = initializeConnector<MetaMask>(
(actions) => new MetaMask(actions)
);
const [urlConnector, urlHooks] = initializeConnector<Url>(
(actions) => new Url(actions, ENV.localProviderUrl)
);
export const createDefaultProvider = (providerUrl: string, chainId: number) => {
return new ethers.providers.JsonRpcProvider(providerUrl, chainId);
};
@ -27,7 +34,8 @@ export const createConnectors = (providerUrl: string, chainId: number) => {
[chainId]
);
return [
ENV.urlConnect ? [urlConnector, urlHooks] : null,
[metamask, metamaskHooks],
[walletconnect, walletconnectHooks],
] as [MetaMask | WalletConnect, Web3ReactHooks][];
].filter(Boolean) as [Connector, Web3ReactHooks][];
};

View File

@ -25,7 +25,7 @@ export const TargetAddressMismatch = ({
}}
components={{
bold: <strong />,
red: <span className={'text-red'} />,
red: <span className={'text-vega-red'} />,
}}
/>
</p>

View File

@ -43,7 +43,7 @@ const Contracts = () => {
title={t('View address on Etherscan')}
href={`${ETHERSCAN_URL}/address/${contract.address}`}
>
{config.collateral_bridge_contract.address}
{contract.address}
</Link>
</div>
);
@ -58,7 +58,6 @@ const Contracts = () => {
title={t('View address on Etherscan')}
href={`${ETHERSCAN_URL}/address/${value}`}
>
asdfasd
{value}
</Link>
</div>

View File

@ -34,30 +34,22 @@ export const CurrentProposalStatus = ({
{ addSuffix: true }
);
if (proposal.state === ProposalState.Open && willPass) {
return <StatusPass>{t('shouldPass')}</StatusPass>;
}
if (!participationMet) {
return (
<>
<span>{t('voteFailedReason')}</span>
<span className="current-proposal-status__fail">
{t('participationNotMet')}
</span>
<span>&nbsp;{daysClosedAgo}.</span>
</>
);
}
if (!majorityMet) {
return (
<>
<span>{t('voteFailedReason')}</span>
<StatusFail>{t('majorityNotMet')}</StatusFail>
<span>&nbsp;{daysClosedAgo}.</span>
</>
);
if (proposal.state === ProposalState.Open) {
if (willPass) {
return (
<>
{t('currentlySetTo')}
<StatusPass>{t('pass')}</StatusPass>
</>
);
} else {
return (
<>
{t('currentlySetTo')}
<StatusFail>{t('fail')}</StatusFail>
</>
);
}
}
if (
@ -65,6 +57,26 @@ export const CurrentProposalStatus = ({
proposal.state === ProposalState.Declined ||
proposal.state === ProposalState.Rejected
) {
if (!participationMet) {
return (
<>
<span>{t('voteFailedReason')}</span>
<StatusFail>{t('participationNotMet')}</StatusFail>
<span>&nbsp;{daysClosedAgo}.</span>
</>
);
}
if (!majorityMet) {
return (
<>
<span>{t('voteFailedReason')}</span>
<StatusFail>{t('majorityNotMet')}</StatusFail>
<span>&nbsp;{daysClosedAgo}.</span>
</>
);
}
return (
<>
<span>{t('voteFailedReason')}</span>

View File

@ -17,6 +17,7 @@ export enum VoteState {
NotCast = 'NotCast',
Yes = 'Yes',
No = 'No',
Requested = 'Requested',
Pending = 'Pending',
Failed = 'Failed',
}
@ -69,7 +70,7 @@ export function useUserVote(
}
}, [userVote]);
// Start a starts a timeout of 30s to set a failed message if
// Starts a timeout of 30s to set a failed message if
// the vote is not seen by the time the callback is invoked
React.useEffect(() => {
// eslint-disable-next-line
@ -93,7 +94,7 @@ export function useUserVote(
async function castVote(value: VoteValue) {
if (!proposalId || !keypair) return;
setVoteState(VoteState.Pending);
setVoteState(VoteState.Requested);
try {
const variables = {
@ -105,6 +106,7 @@ export function useUserVote(
},
};
await sendTx(variables);
setVoteState(VoteState.Pending);
// Now await vote via poll in parent component
} catch (err) {

View File

@ -124,6 +124,10 @@ export const VoteButtons = ({
return <p>{cantVoteUI}</p>;
}
if (voteState === VoteState.Requested) {
return <p>{t('voteRequested')}...</p>;
}
if (voteState === VoteState.Pending) {
return <p>{t('votePending')}...</p>;
}

View File

@ -49,7 +49,7 @@ export const VoteDetails = ({ proposal }: VoteDetailsProps) => {
<span>
<CurrentProposalStatus proposal={proposal} />
</span>
.&nbsp;
{'. '}
{proposal.state === ProposalState.Open ? daysLeft : null}
</p>
<table className="w-full font-normal mb-12">

View File

@ -24,6 +24,7 @@ export const ProposalsContainer = () => {
const { t } = useTranslation();
const { data, loading, error } = useQuery<Proposals, never>(PROPOSALS_QUERY, {
pollInterval: 5000,
errorPolicy: 'ignore', // this is to get around some backend issues and should be removed in future
});
const proposals = React.useMemo(() => {

View File

@ -52,7 +52,13 @@ const Home = ({ name }: RouteChildProps) => {
<Trans
i18nKey="Tokens are held in different <trancheLink>Tranches</trancheLink>. Each tranche has its own schedule for how the tokens are unlocked."
components={{
trancheLink: <Link to={Routes.TRANCHES} />,
trancheLink: (
<Link
data-testid="tranches-link"
to={Routes.TRANCHES}
className="underline text-white"
/>
),
}}
/>
</p>
@ -62,7 +68,7 @@ const Home = ({ name }: RouteChildProps) => {
)}
</p>
<Link to={Routes.VESTING}>
<Button variant="secondary" data-test-id="check-vesting-page-btn">
<Button variant="secondary" data-testid="check-vesting-page-btn">
{t('Check to see if you can redeem unlocked VEGA tokens')}
</Button>
</Link>
@ -81,7 +87,7 @@ const Home = ({ name }: RouteChildProps) => {
</p>
<p>
<a
data-test-id="get-vega-wallet-link"
data-testid="get-vega-wallet-link"
href={Links.WALLET_GUIDE}
className="underline text-white"
target="_blank"
@ -90,8 +96,9 @@ const Home = ({ name }: RouteChildProps) => {
{t('Get a Vega wallet')}
</a>
</p>
<p data-test-id="associate-vega-tokens-link-on-homepage">
<p>
<Link
data-testid="associate-vega-tokens-link-on-homepage"
to={`${Routes.STAKING}/associate`}
className="underline text-white"
>
@ -110,7 +117,12 @@ const Home = ({ name }: RouteChildProps) => {
</p>
<p>
<Link to={Routes.STAKING}>
<Button variant="secondary">{t('Nominate a validator')}</Button>
<Button
variant="secondary"
data-testid="staking-button-on-homepage"
>
{t('Nominate a validator')}
</Button>
</Link>
</p>
</HomeSection>
@ -125,7 +137,10 @@ const Home = ({ name }: RouteChildProps) => {
</p>
<p>
<Link to={Routes.GOVERNANCE}>
<Button variant="secondary">
<Button
variant="secondary"
data-testid="governance-button-on-homepage"
>
{t('View Governance proposals')}
</Button>
</Link>

View File

@ -8,7 +8,6 @@ import { Link } from 'react-router-dom';
import { EthConnectPrompt } from '../../components/eth-connect-prompt';
import { SplashLoader } from '../../components/splash-loader';
import { useAppState } from '../../contexts/app-state/app-state-context';
import { useContracts } from '../../contexts/contracts/contracts-context';
import { useTranches } from '../../hooks/use-tranches';
import { Routes as RoutesConfig } from '../router-config';
import {
@ -19,7 +18,6 @@ import {
const RedemptionRouter = () => {
const { t } = useTranslation();
const { vesting } = useContracts();
const [state, dispatch] = React.useReducer(
redemptionReducer,
initialRedemptionState
@ -49,7 +47,7 @@ const RedemptionRouter = () => {
if (account) {
run(account);
}
}, [account, tranches, vesting]);
}, [account, tranches]);
if (error) {
return (

View File

@ -76,6 +76,7 @@ export const TrancheItem = ({
total={total}
leftLabel={t('Locked')}
rightLabel={t('Unlocked')}
decimals={18}
/>
<div className="text-right" data-testid="tranche-item-footer">

View File

@ -12,7 +12,7 @@ import { useTransaction } from '../../../hooks/use-transaction';
import { BigNumber } from '../../../lib/bignumber';
import { AssociateInfo } from './associate-info';
import type { VegaKeyExtended } from '@vegaprotocol/wallet';
import { toBigNum } from '@vegaprotocol/react-helpers';
import { removeDecimal, toBigNum } from '@vegaprotocol/react-helpers';
import type { EthereumConfig } from '@vegaprotocol/web3';
export const WalletAssociate = ({
@ -35,19 +35,18 @@ export const WalletAssociate = ({
appDispatch,
appState: { walletBalance, allowance, walletAssociatedBalance, decimals },
} = useAppState();
const { token } = useContracts();
const {
state: approveState,
perform: approve,
dispatch: approveDispatch,
} = useTransaction(() =>
token.approve(
} = useTransaction(() => {
return token.approve(
ethereumConfig.staking_bridge_contract.address,
Number.MAX_SAFE_INTEGER.toString()
)
);
removeDecimal('1000000', decimals).toString()
);
});
// Once they have approved deposits then we need to refresh their allowance
React.useEffect(() => {

View File

@ -8,6 +8,7 @@ import {
} from '../../../components/staking-method-radio';
import { TxState } from '../../../hooks/transaction-reducer';
import { useSearchParams } from '../../../hooks/use-search-params';
import { useRefreshAssociatedBalances } from '../../../hooks/use-refresh-associated-balances';
import { ContractDisassociate } from './contract-disassociate';
import { DisassociateTransaction } from './disassociate-transaction';
import { useRemoveStake } from './hooks';
@ -26,6 +27,7 @@ export const DisassociatePage = ({
const [amount, setAmount] = React.useState<string>('');
const [selectedStakingMethod, setSelectedStakingMethod] =
React.useState<StakingMethod | null>(params.method || null);
const refreshBalances = useRefreshAssociatedBalances();
// Clear the amount when the staking method changes
React.useEffect(() => {
@ -38,6 +40,12 @@ export const DisassociatePage = ({
perform: txPerform,
} = useRemoveStake(address, amount, vegaKey.pub, selectedStakingMethod);
React.useEffect(() => {
if (txState.txState === TxState.Complete) {
refreshBalances(address, vegaKey.pub);
}
}, [txState, refreshBalances, address, vegaKey.pub]);
if (txState.txState !== TxState.Default) {
return (
<DisassociateTransaction

View File

@ -18,7 +18,14 @@ import type {
import { StakeFailure } from './stake-failure';
import { StakePending } from './stake-pending';
import { StakeSuccess } from './stake-success';
import { Button, FormGroup, RadioGroup, Radio } from '@vegaprotocol/ui-toolkit';
import {
Button,
Callout,
FormGroup,
Intent,
Radio,
RadioGroup,
} from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import type {
DelegateSubmissionBody,
@ -46,6 +53,7 @@ export const PARTY_DELEGATIONS_QUERY = gql`
enum FormState {
Default,
Requested,
Pending,
Success,
Failure,
@ -115,7 +123,7 @@ export const StakingForm = ({
}, [action, availableStakeToAdd, availableStakeToRemove]);
async function onSubmit() {
setFormState(FormState.Pending);
setFormState(FormState.Requested);
const delegateInput: DelegateSubmissionBody = {
pubKey: pubkey,
propagate: true,
@ -139,6 +147,7 @@ export const StakingForm = ({
try {
const command = action === Actions.Add ? delegateInput : undelegateInput;
await sendTx(command);
setFormState(FormState.Pending);
// await success via poll
} catch (err) {
@ -184,6 +193,12 @@ export const StakingForm = ({
if (formState === FormState.Failure) {
return <StakeFailure nodeName={nodeName} />;
} else if (formState === FormState.Requested) {
return (
<Callout title="Confirm transaction in wallet" intent={Intent.Warning}>
<p>{t('stakingConfirm')}</p>
</Callout>
);
} else if (formState === FormState.Pending) {
return <StakePending action={action} amount={amount} nodeName={nodeName} />;
} else if (formState === FormState.Success) {

View File

@ -88,7 +88,9 @@ export const StakingNode = ({ vegaKey, data }: StakingNodeProps) => {
if (!nodeInfo) {
return (
<span className={'text-red'}>{t('stakingNodeNotFound', { node })}</span>
<span className={'text-vega-red'}>
{t('stakingNodeNotFound', { node })}
</span>
);
}

View File

@ -40,7 +40,7 @@ export const TrancheProgress = ({
<span className="tranches__progress-title">{t('Redeemed')}</span>
<ProgressBar
width={220}
color={Colors.green.DEFAULT}
color={Colors.vega.green}
percentage={removedPercentage}
/>
<span className="tranches__progress-numbers">

View File

@ -36,7 +36,7 @@ export const VestingChart = () => {
['pink', Colors.vega.pink],
['green', Colors.vega.green],
['orange', Colors.orange],
['yellow', Colors.yellow.DEFAULT],
['yellow', Colors.vega.yellow],
].map(([key, color]) => (
<linearGradient key={key} id={key} x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor={color} stopOpacity={0.85} />
@ -119,7 +119,7 @@ export const VestingChart = () => {
dot={false}
type="monotone"
dataKey="publicSale"
stroke={Colors.yellow.DEFAULT}
stroke={Colors.vega.yellow}
fill="url(#yellow)"
yAxisId={0}
strokeWidth={2}

View File

@ -19,12 +19,14 @@ describe('orders', () => {
const orderTimeInForce = 'timeInForce';
const orderCreatedAt = 'createdAt';
it('renders orders', () => {
beforeEach(() => {
cy.getByTestId('Orders').click();
cy.getByTestId('tab-orders').contains('Please connect Vega wallet');
connectVegaWallet();
});
it('renders orders', () => {
cy.getByTestId('tab-orders').should('be.visible');
cy.getByTestId('tab-orders')
@ -68,4 +70,17 @@ describe('orders', () => {
cy.wrap($dateTime).invoke('text').should('not.be.empty');
});
});
it('orders are sorted by most recent order', () => {
const expectedOrderList = ['TSLA.QM21', 'BTCUSD.MF21', 'AAVEDAI.MF21'];
cy.getByTestId('tab-orders')
.get(`[col-id='${orderSymbol}']`)
.should('have.length.at.least', 3)
.each(($symbol, index) => {
if (index != 0) {
cy.wrap($symbol).should('have.text', expectedOrderList[index - 1]);
}
});
});
});

View File

@ -15,50 +15,6 @@ export const generateDealTicketQuery = (
positionDecimalPlaces: 0,
state: MarketState.Active,
tradingMode: MarketTradingMode.Continuous,
fees: {
__typename: 'Fees',
factors: {
__typename: 'FeeFactors',
makerFee: '0.0002',
infrastructureFee: '0.0005',
liquidityFee: '0.01',
},
},
priceMonitoringSettings: {
__typename: 'PriceMonitoringSettings',
parameters: {
__typename: 'PriceMonitoringParameters',
triggers: [
{
__typename: 'PriceMonitoringTrigger',
horizonSecs: 43200,
probability: 0.9999999,
auctionExtensionSecs: 600,
},
],
},
updateFrequencySecs: 1,
},
riskFactors: {
__typename: 'RiskFactor',
market:
'54b78c1b877e106842ae156332ccec740ad98d6bad43143ac6a029501dd7c6e0',
short: '0.008571790367285281',
long: '0.008508132993273576',
},
data: {
__typename: 'MarketData',
market: {
__typename: 'Market',
id: '54b78c1b877e106842ae156332ccec740ad98d6bad43143ac6a029501dd7c6e0',
},
markPrice: '5749',
indicativeVolume: '0',
bestBidVolume: '5',
bestOfferVolume: '1',
bestStaticBidVolume: '5',
bestStaticOfferVolume: '1',
},
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
@ -74,17 +30,6 @@ export const generateDealTicketQuery = (
},
},
},
riskModel: {
__typename: 'LogNormalRiskModel',
tau: 0.0001140771161,
riskAversionParameter: 0.01,
params: {
__typename: 'LogNormalModelParams',
r: 0.016,
sigma: 0.3,
mu: 0,
},
},
},
depth: {
__typename: 'MarketDepth',

View File

@ -0,0 +1,100 @@
import type { MarketInfoQuery } from '@vegaprotocol/deal-ticket';
import { MarketState, MarketTradingMode } from '@vegaprotocol/types';
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
export const generateMarketInfoQuery = (
override?: PartialDeep<MarketInfoQuery>
): MarketInfoQuery => {
const defaultResult: MarketInfoQuery = {
market: {
__typename: 'Market',
id: 'market-0',
name: 'ETHBTC Quarterly (30 Jun 2022)',
decimalPlaces: 2,
positionDecimalPlaces: 0,
state: MarketState.Active,
tradingMode: MarketTradingMode.Continuous,
fees: {
__typename: 'Fees',
factors: {
__typename: 'FeeFactors',
makerFee: '0.0002',
infrastructureFee: '0.0005',
liquidityFee: '0.01',
},
},
priceMonitoringSettings: {
__typename: 'PriceMonitoringSettings',
parameters: {
__typename: 'PriceMonitoringParameters',
triggers: [
{
__typename: 'PriceMonitoringTrigger',
horizonSecs: 43200,
probability: 0.9999999,
auctionExtensionSecs: 600,
},
],
},
updateFrequencySecs: 1,
},
riskFactors: {
__typename: 'RiskFactor',
market:
'54b78c1b877e106842ae156332ccec740ad98d6bad43143ac6a029501dd7c6e0',
short: '0.008571790367285281',
long: '0.008508132993273576',
},
data: {
__typename: 'MarketData',
market: {
__typename: 'Market',
id: '54b78c1b877e106842ae156332ccec740ad98d6bad43143ac6a029501dd7c6e0',
},
markPrice: '5749',
indicativeVolume: '0',
bestBidVolume: '5',
bestOfferVolume: '1',
bestStaticBidVolume: '5',
bestStaticOfferVolume: '1',
},
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
product: {
__typename: 'Future',
quoteName: 'BTC',
settlementAsset: {
__typename: 'Asset',
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
symbol: 'tBTC',
name: 'tBTC TEST',
},
},
},
riskModel: {
__typename: 'LogNormalRiskModel',
tau: 0.0001140771161,
riskAversionParameter: 0.01,
params: {
__typename: 'LogNormalModelParams',
r: 0.016,
sigma: 0.3,
mu: 0,
},
},
},
depth: {
__typename: 'MarketDepth',
lastTrade: {
__typename: 'Trade',
price: '100',
},
},
},
};
return merge(defaultResult, override);
};

View File

@ -12,6 +12,7 @@ export const generateOrderBook = (
const marketDepth: MarketDepth_market = {
id: 'b2426f67b085ba8fb429f1b529d49372b2d096c6fb6f509f76c5863abb6d969e',
decimalPlaces: 5,
positionDecimalPlaces: 0,
data: {
staticMidPrice: '826337',
marketTradingMode: MarketTradingMode.Continuous,

View File

@ -18,6 +18,7 @@ export const generateOrders = (override?: PartialDeep<Orders>): Orders => {
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
name: 'AAVEDAI Monthly (30 Jun 2022)',
decimalPlaces: 5,
positionDecimalPlaces: 0,
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
@ -33,7 +34,7 @@ export const generateOrders = (override?: PartialDeep<Orders>): Orders => {
remaining: '0',
price: '20000000',
timeInForce: OrderTimeInForce.GTC,
createdAt: new Date().toISOString(),
createdAt: new Date(2020, 1, 1).toISOString(),
updatedAt: null,
expiresAt: null,
rejectionReason: null,
@ -46,6 +47,7 @@ export const generateOrders = (override?: PartialDeep<Orders>): Orders => {
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
name: 'Tesla Quarterly (30 Jun 2022)',
decimalPlaces: 5,
positionDecimalPlaces: 0,
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
@ -59,13 +61,42 @@ export const generateOrders = (override?: PartialDeep<Orders>): Orders => {
status: OrderStatus.Filled,
side: Side.Buy,
remaining: '0',
price: '0',
price: '100',
timeInForce: OrderTimeInForce.GTC,
createdAt: new Date().toISOString(),
updatedAt: null,
expiresAt: null,
rejectionReason: null,
},
{
__typename: 'Order',
id: '4e93702990712c41f6995fcbbd94f60bb372ad12d64dfa7d96d205c49f790336',
market: {
__typename: 'Market',
id: 'c6f4337b31ed57a961969c3ba10297b369d01b9e75a4cbb96db4fc62886444e6',
name: 'BTCUSD Monthly (30 Jun 2022)',
decimalPlaces: 5,
positionDecimalPlaces: 0,
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
code: 'BTCUSD.MF21',
},
},
},
size: '1',
type: OrderType.Limit,
status: OrderStatus.Filled,
side: Side.Buy,
remaining: '0',
price: '20000',
timeInForce: OrderTimeInForce.GTC,
createdAt: new Date(2022, 5, 10).toISOString(),
updatedAt: null,
expiresAt: null,
rejectionReason: null,
},
];
const defaultResult = {

View File

@ -25,6 +25,7 @@ export const generatePositions = (
market: { __typename: 'Market', id: '123' },
},
decimalPlaces: 5,
positionDecimalPlaces: 0,
tradableInstrument: {
instrument: {
id: '',
@ -78,6 +79,7 @@ export const generatePositions = (
},
},
decimalPlaces: 5,
positionDecimalPlaces: 0,
tradableInstrument: {
instrument: {
id: '',

View File

@ -12,6 +12,7 @@ export const generateTrades = (override?: PartialDeep<Trades>): Trades => {
market: {
id: '0c3c1490db767f926d24fb674b4235a9aa339614915a4ab96cbfc0e1ad83c0ff',
decimalPlaces: 5,
positionDecimalPlaces: 0,
__typename: 'Market',
},
__typename: 'Trade',
@ -24,6 +25,7 @@ export const generateTrades = (override?: PartialDeep<Trades>): Trades => {
market: {
id: '0c3c1490db767f926d24fb674b4235a9aa339614915a4ab96cbfc0e1ad83c0ff',
decimalPlaces: 5,
positionDecimalPlaces: 0,
__typename: 'Market',
},
__typename: 'Trade',
@ -36,6 +38,7 @@ export const generateTrades = (override?: PartialDeep<Trades>): Trades => {
market: {
id: '0c3c1490db767f926d24fb674b4235a9aa339614915a4ab96cbfc0e1ad83c0ff',
decimalPlaces: 5,
positionDecimalPlaces: 0,
__typename: 'Market',
},
__typename: 'Trade',

View File

@ -6,6 +6,7 @@ import { generateCandles } from './mocks/generate-candles';
import { generateChart } from './mocks/generate-chart';
import { generateDealTicketQuery } from './mocks/generate-deal-ticket-query';
import { generateMarket } from './mocks/generate-market';
import { generateMarketInfoQuery } from './mocks/generate-market-info-query';
import { generateOrders } from './mocks/generate-orders';
import { generatePositions } from './mocks/generate-positions';
import { generateTrades } from './mocks/generate-trades';
@ -31,6 +32,11 @@ export const mockTradingPage = (
'DealTicketQuery',
generateDealTicketQuery({ market: { state } })
);
aliasQuery(
req,
'MarketInfoQuery',
generateMarketInfoQuery({ market: { state } })
);
aliasQuery(req, 'Trades', generateTrades());
aliasQuery(req, 'Chart', generateChart());
aliasQuery(req, 'Candles', generateCandles());

View File

@ -1,8 +1,8 @@
import { useRouter } from 'next/router';
import { Vega } from '../icons/vega';
import Link from 'next/link';
import { AnchorButton } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/react-helpers';
import classNames from 'classnames';
export const Navbar = () => {
return (
@ -33,14 +33,17 @@ const NavLink = ({ name, path, exact, testId = name }: NavLinkProps) => {
const router = useRouter();
const isActive =
router.asPath === path || (!exact && router.asPath.startsWith(path));
const linkClasses = classNames(
'px-16 py-6 border-0 self-end',
'uppercase xs:text-ui sm:text-body-large md:text-h5 lg:text-h4',
{
'bg-vega-pink dark:bg-vega-yellow text-white dark:text-black': isActive,
'text-black dark:text-white': !isActive,
}
);
return (
<AnchorButton
variant={isActive ? 'accent' : 'inline'}
className="px-16 py-6 h-[38px] uppercase border-0 self-end xs:text-ui sm:text-body-large md:text-h5 lg:text-h4"
data-testid={testId}
href={path}
>
{name}
</AnchorButton>
<Link data-testid={testId} href={path} passHref={true}>
<a className={linkClasses}>{name}</a>
</Link>
);
};

View File

@ -24,84 +24,80 @@ function AppBody({ Component, pageProps }: AppProps) {
const { push } = useRouter();
const store = useGlobalStore();
const { VEGA_NETWORKS } = useEnvironment();
const [, toggleTheme] = useThemeSwitcher();
const [theme, toggleTheme] = useThemeSwitcher();
return (
<div className="h-full dark:bg-black dark:text-white-60 bg-white relative z-0 text-black-60 grid grid-rows-[min-content,1fr]">
<AppLoader>
<div className="flex items-stretch border-b-[7px] border-vega-yellow">
<Navbar />
<div className="flex items-center gap-4 ml-auto mr-8">
<VegaWalletConnectButton
setConnectDialog={(open) => {
store.setVegaWalletConnectDialog(open);
}}
setManageDialog={(open) => {
store.setVegaWalletManageDialog(open);
}}
/>
<ThemeSwitcher onToggle={toggleTheme} className="-my-4" />
<ThemeContext.Provider value={theme}>
<div className="h-full dark:bg-black dark:text-white-60 bg-white relative z-0 text-black-60 grid grid-rows-[min-content,1fr]">
<AppLoader>
<div className="flex items-stretch border-b-[7px] border-vega-pink dark:border-vega-yellow">
<Navbar />
<div className="flex items-center gap-4 ml-auto mr-8">
<VegaWalletConnectButton
setConnectDialog={(open) => {
store.setVegaWalletConnectDialog(open);
}}
setManageDialog={(open) => {
store.setVegaWalletManageDialog(open);
}}
/>
<ThemeSwitcher onToggle={toggleTheme} className="-my-4" />
</div>
</div>
</div>
<main data-testid={pageProps.page}>
{/* @ts-ignore conflict between @types/react and nextjs internal types */}
<Component {...pageProps} />
</main>
<VegaConnectDialog
connectors={Connectors}
dialogOpen={store.vegaWalletConnectDialog}
setDialogOpen={(open) => store.setVegaWalletConnectDialog(open)}
/>
<VegaManageDialog
dialogOpen={store.vegaWalletManageDialog}
setDialogOpen={(open) => store.setVegaWalletManageDialog(open)}
/>
<NetworkSwitcherDialog
dialogOpen={store.vegaNetworkSwitcherDialog}
setDialogOpen={(open) => store.setVegaNetworkSwitcherDialog(open)}
onConnect={({ network }) => {
if (VEGA_NETWORKS[network]) {
push(VEGA_NETWORKS[network] ?? '');
}
}}
/>
</AppLoader>
</div>
<main data-testid={pageProps.page}>
{/* @ts-ignore conflict between @types/react and nextjs internal types */}
<Component {...pageProps} />
</main>
<VegaConnectDialog
connectors={Connectors}
dialogOpen={store.vegaWalletConnectDialog}
setDialogOpen={(open) => store.setVegaWalletConnectDialog(open)}
/>
<VegaManageDialog
dialogOpen={store.vegaWalletManageDialog}
setDialogOpen={(open) => store.setVegaWalletManageDialog(open)}
/>
<NetworkSwitcherDialog
dialogOpen={store.vegaNetworkSwitcherDialog}
setDialogOpen={(open) => store.setVegaNetworkSwitcherDialog(open)}
onConnect={({ network }) => {
if (VEGA_NETWORKS[network]) {
push(VEGA_NETWORKS[network] ?? '');
}
}}
/>
</AppLoader>
</div>
</ThemeContext.Provider>
);
}
function VegaTradingApp(props: AppProps) {
const [theme] = useThemeSwitcher();
return (
<EnvironmentProvider>
<ThemeContext.Provider value={theme}>
<VegaWalletProvider>
<Head>
<link
rel="preload"
href="https://static.vega.xyz/AlphaLyrae-Medium.woff2"
as="font"
type="font/woff2"
crossOrigin="anonymous"
/>
<title>{t('Welcome to Vega trading!')}</title>
<link
rel="icon"
type="image/x-icon"
href="https://static.vega.xyz/favicon.ico"
/>
<link rel="stylesheet" href="https://static.vega.xyz/fonts.css" />
{['1', 'true'].includes(
process.env['NX_USE_ENV_OVERRIDES'] || ''
) ? (
/* eslint-disable-next-line @next/next/no-sync-scripts */
<script src="./env-config.js" type="text/javascript" />
) : null}
</Head>
<AppBody {...props} />
</VegaWalletProvider>
</ThemeContext.Provider>
<VegaWalletProvider>
<Head>
<link
rel="preload"
href="https://static.vega.xyz/AlphaLyrae-Medium.woff2"
as="font"
type="font/woff2"
crossOrigin="anonymous"
/>
<title>{t('Welcome to Vega trading!')}</title>
<link
rel="icon"
type="image/x-icon"
href="https://static.vega.xyz/favicon.ico"
/>
<link rel="stylesheet" href="https://static.vega.xyz/fonts.css" />
{['1', 'true'].includes(process.env['NX_USE_ENV_OVERRIDES'] || '') ? (
/* eslint-disable-next-line @next/next/no-sync-scripts */
<script src="./env-config.js" type="text/javascript" />
) : null}
</Head>
<AppBody {...props} />
</VegaWalletProvider>
</EnvironmentProvider>
);
}

View File

@ -2,7 +2,10 @@ import classNames from 'classnames';
import AutoSizer from 'react-virtualized-auto-sizer';
import type { ReactNode } from 'react';
import { useState } from 'react';
import { DealTicketContainer } from '@vegaprotocol/deal-ticket';
import {
DealTicketContainer,
MarketInfoContainer,
} from '@vegaprotocol/deal-ticket';
import { OrderListContainer } from '@vegaprotocol/order-list';
import { TradesContainer } from '@vegaprotocol/trades';
import { PositionsContainer } from '@vegaprotocol/positions';
@ -15,8 +18,8 @@ import { CandlesChartContainer } from '@vegaprotocol/candles-chart';
import { SelectMarketDialog } from '@vegaprotocol/market-list';
import {
ArrowDown,
GridTab,
GridTabs,
Tab,
Tabs,
PriceCellChange,
} from '@vegaprotocol/ui-toolkit';
import type { CandleClose } from '@vegaprotocol/types';
@ -30,6 +33,7 @@ const TradingViews = {
Positions: PositionsContainer,
Accounts: AccountsContainer,
Trades: TradesContainer,
Info: MarketInfoContainer,
};
type TradingView = keyof typeof TradingViews;
@ -52,17 +56,17 @@ export const TradeMarketHeader = ({
'font-sans font-normal mb-0 text-dark/80 dark:text-white/80 text-ui-small';
const itemValueClassName =
'capitalize font-sans tracking-tighter text-black dark:text-white text-ui';
const headerClassname = classNames(
const headerClassName = classNames(
'w-full p-8 bg-white dark:bg-black',
className
);
return (
<header className={headerClassname}>
<header className={headerClassName}>
<SelectMarketDialog dialogOpen={open} setDialogOpen={setOpen} />
<div className="flex flex-col md:flex-row gap-20 md:gap-64 ml-auto mr-8">
<button
onClick={() => setOpen(!open)}
className="shrink-0 dark:text-vega-yellow text-black text-h5 flex items-center gap-8 px-4 py-0 h-37 hover:bg-vega-yellow dark:hover:bg-white/20"
className="shrink-0 dark:text-vega-yellow text-black text-h5 flex items-center gap-8 px-4 py-0 h-37 hover:bg-black/20 dark:hover:bg-white/20"
>
<span className="break-words text-left">{market.name}</span>
<ArrowDown color="yellow" borderX={8} borderTop={12} />
@ -105,7 +109,7 @@ interface TradeGridProps {
export const TradeGrid = ({ market }: TradeGridProps) => {
const wrapperClasses = classNames(
'h-full max-h-full',
'grid gap-4 grid-cols-[1fr_375px_460px] grid-rows-[min-content_1fr_200px]',
'grid gap-4 grid-cols-[1fr_375px_460px] grid-rows-[min-content_1fr_300px]',
'bg-black-10 dark:bg-white-10',
'text-ui'
);
@ -115,43 +119,50 @@ export const TradeGrid = ({ market }: TradeGridProps) => {
<div className={wrapperClasses}>
<TradeMarketHeader
market={market}
className="row-start-1 row-end-2 col-start-1 col-end-2"
className="row-start-1 row-end-2 col-start-1 col-end-4"
/>
<TradeGridChild className="row-start-2 row-end-3 col-start-1 col-end-2">
<GridTabs>
<GridTab id="candles" name={t('Candles')}>
<Tabs>
<Tab id="candles" name={t('Candles')}>
<TradingViews.Candles marketId={market.id} />
</GridTab>
<GridTab id="depth" name={t('Depth')}>
</Tab>
<Tab id="depth" name={t('Depth')}>
<TradingViews.Depth marketId={market.id} />
</GridTab>
</GridTabs>
</Tab>
</Tabs>
</TradeGridChild>
<TradeGridChild className="row-start-1 row-end-3">
<TradingViews.Ticket marketId={market.id} />
<TradeGridChild className="row-start-2 row-end-3 col-start-2 col-end-3">
<Tabs>
<Tab id="ticket" name={t('Ticket')}>
<TradingViews.Ticket marketId={market.id} />
</Tab>
<Tab id="info" name={t('Info')}>
<TradingViews.Info marketId={market.id} />
</Tab>
</Tabs>
</TradeGridChild>
<TradeGridChild className="row-start-1 row-end-3">
<GridTabs>
<GridTab id="trades" name={t('Trades')}>
<TradeGridChild className="row-start-2 row-end-3 col-start-3 col-end-4">
<Tabs>
<Tab id="trades" name={t('Trades')}>
<TradingViews.Trades marketId={market.id} />
</GridTab>
<GridTab id="orderbook" name={t('Orderbook')}>
</Tab>
<Tab id="orderbook" name={t('Orderbook')}>
<TradingViews.Orderbook marketId={market.id} />
</GridTab>
</GridTabs>
</Tab>
</Tabs>
</TradeGridChild>
<TradeGridChild className="col-span-3">
<GridTabs>
<GridTab id="orders" name={t('Orders')}>
<Tabs>
<Tab id="orders" name={t('Orders')}>
<TradingViews.Orders />
</GridTab>
<GridTab id="positions" name={t('Positions')}>
</Tab>
<Tab id="positions" name={t('Positions')}>
<TradingViews.Positions />
</GridTab>
<GridTab id="accounts" name={t('Accounts')}>
</Tab>
<Tab id="accounts" name={t('Accounts')}>
<TradingViews.Accounts />
</GridTab>
</GridTabs>
</Tab>
</Tabs>
</TradeGridChild>
</div>
</>

View File

@ -3,8 +3,7 @@ import { t } from '@vegaprotocol/react-helpers';
import { PositionsContainer } from '@vegaprotocol/positions';
import { OrderListContainer } from '@vegaprotocol/order-list';
import { AccountsContainer } from '@vegaprotocol/accounts';
import { AnchorButton, GridTab, GridTabs } from '@vegaprotocol/ui-toolkit';
import { AnchorButton, Tab, Tabs } from '@vegaprotocol/ui-toolkit';
import { WithdrawalsContainer } from './withdrawals/withdrawals-container';
const Portfolio = () => {
@ -20,54 +19,54 @@ const Portfolio = () => {
</h2>
</aside>
<section data-testid="portfolio-grid">
<GridTabs>
<GridTab id="positions" name={t('Positions')}>
<Tabs>
<Tab id="positions" name={t('Positions')}>
<div className={tabClassName}>
<h4 className="text-h4 text-black dark:text-white">
{t('Positions')}
</h4>
<PositionsContainer />
</div>
</GridTab>
<GridTab id="orders" name={t('Orders')}>
</Tab>
<Tab id="orders" name={t('Orders')}>
<div className={tabClassName}>
<h4 className="text-h4 text-black dark:text-white">
{t('Orders')}
</h4>
<OrderListContainer />
</div>
</GridTab>
<GridTab id="fills" name={t('Fills')}>
</Tab>
<Tab id="fills" name={t('Fills')}>
<div className={tabClassName}>
<h4 className="text-h4 text-black dark:text-white">
{t('Fills')}
</h4>
</div>
</GridTab>
<GridTab id="history" name={t('History')}>
</Tab>
<Tab id="history" name={t('History')}>
<div className={tabClassName}>
<h4 className="text-h4 text-black dark:text-white">
{t('History')}
</h4>
</div>
</GridTab>
</GridTabs>
</Tab>
</Tabs>
</section>
</main>
<section className="fixed bottom-0 left-0 w-full h-[200px]">
<GridTabs>
<GridTab id="collateral" name={t('Collateral')}>
<Tabs>
<Tab id="collateral" name={t('Collateral')}>
<AccountsContainer />
</GridTab>
<GridTab id="deposits" name={t('Deposits')}>
</Tab>
<Tab id="deposits" name={t('Deposits')}>
<AnchorButton data-testid="deposit" href="/portfolio/deposit">
{t('Deposit')}
</AnchorButton>
</GridTab>
<GridTab id="withdrawals" name={t('Withdrawals')}>
</Tab>
<Tab id="withdrawals" name={t('Withdrawals')}>
<WithdrawalsContainer />
</GridTab>
</GridTabs>
</Tab>
</Tabs>
</section>
</div>
</Web3Container>

View File

@ -1,3 +1,4 @@
import produce from 'immer';
import { gql } from '@apollo/client';
import type {
Accounts,
@ -52,17 +53,18 @@ export const getId = (
) => `${data.type}-${data.asset.symbol}-${data.market?.id ?? 'null'}`;
const update = (
draft: Accounts_party_accounts[],
data: Accounts_party_accounts[],
delta: AccountSubscribe_accounts
) => {
const id = getId(delta);
const index = draft.findIndex((a) => getId(a) === id);
if (index !== -1) {
draft[index] = delta;
} else {
draft.push(delta);
}
};
) =>
produce(data, (draft) => {
const id = getId(delta);
const index = draft.findIndex((a) => getId(a) === id);
if (index !== -1) {
draft[index] = delta;
} else {
draft.push(delta);
}
});
const getData = (responseData: Accounts): Accounts_party_accounts[] | null =>
responseData.party ? responseData.party.accounts : null;
const getDelta = (

View File

@ -17,7 +17,6 @@ import { useContext, useMemo, useState } from 'react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { ThemeContext } from '@vegaprotocol/react-helpers';
import {
Button,
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
@ -58,14 +57,14 @@ export const CandlesChartContainer = ({
return new VegaDataSource(client, marketId, keypair?.pub);
}, [client, marketId, keypair]);
const dropdownTriggerStyles = 'border-black-60 dark:border-white-60 px-20';
return (
<div className="h-full flex flex-col">
<div className="p-8 flex flex-row flex-wrap gap-8">
<DropdownMenu>
<DropdownMenuTrigger asChild={true}>
<Button appendIconName="caret-down" variant="secondary">
{t('Interval')}
</Button>
<DropdownMenuTrigger className={dropdownTriggerStyles}>
{t('Interval')}
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuRadioGroup
@ -90,10 +89,8 @@ export const CandlesChartContainer = ({
</DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
<DropdownMenuTrigger asChild={true}>
<Button appendIconName="caret-down" variant="secondary">
<Icon name={chartTypeIcon.get(chartType) as IconName} />
</Button>
<DropdownMenuTrigger className={dropdownTriggerStyles}>
<Icon name={chartTypeIcon.get(chartType) as IconName} />
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuRadioGroup
@ -114,10 +111,8 @@ export const CandlesChartContainer = ({
</DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
<DropdownMenuTrigger asChild={true}>
<Button appendIconName="caret-down" variant="secondary">
{t('Overlays')}
</Button>
<DropdownMenuTrigger className={dropdownTriggerStyles}>
{t('Overlays')}
</DropdownMenuTrigger>
<DropdownMenuContent>
{Object.values(Overlay).map((overlay) => (
@ -145,10 +140,8 @@ export const CandlesChartContainer = ({
</DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
<DropdownMenuTrigger asChild={true}>
<Button appendIconName="caret-down" variant="secondary">
{t('Studies')}
</Button>
<DropdownMenuTrigger className={dropdownTriggerStyles}>
{t('Studies')}
</DropdownMenuTrigger>
<DropdownMenuContent>
{Object.values(Study).map((study) => (

View File

@ -9,124 +9,6 @@ import { MarketState, MarketTradingMode } from "@vegaprotocol/types";
// GraphQL query operation: DealTicketQuery
// ====================================================
export interface DealTicketQuery_market_fees_factors {
__typename: "FeeFactors";
/**
* The factor applied to calculate MakerFees, a non-negative float
*/
makerFee: string;
/**
* The factor applied to calculate InfrastructureFees, a non-negative float
*/
infrastructureFee: string;
/**
* The factor applied to calculate LiquidityFees, a non-negative float
*/
liquidityFee: string;
}
export interface DealTicketQuery_market_fees {
__typename: "Fees";
/**
* The factors used to calculate the different fees
*/
factors: DealTicketQuery_market_fees_factors;
}
export interface DealTicketQuery_market_priceMonitoringSettings_parameters_triggers {
__typename: "PriceMonitoringTrigger";
/**
* Price monitoring projection horizon τ in seconds (> 0).
*/
horizonSecs: number;
/**
* Price monitoring probability level p. (>0 and < 1)
*/
probability: number;
/**
* Price monitoring auction extension duration in seconds should the price
* breach it's theoretical level over the specified horizon at the specified
* probability level (> 0)
*/
auctionExtensionSecs: number;
}
export interface DealTicketQuery_market_priceMonitoringSettings_parameters {
__typename: "PriceMonitoringParameters";
/**
* The list of triggers for this price monitoring
*/
triggers: DealTicketQuery_market_priceMonitoringSettings_parameters_triggers[] | null;
}
export interface DealTicketQuery_market_priceMonitoringSettings {
__typename: "PriceMonitoringSettings";
/**
* Specified a set of PriceMonitoringParameters to be use for price monitoring purposes
*/
parameters: DealTicketQuery_market_priceMonitoringSettings_parameters | null;
/**
* How often (in seconds) the price monitoring bounds should be updated
*/
updateFrequencySecs: number;
}
export interface DealTicketQuery_market_riskFactors {
__typename: "RiskFactor";
/**
* market the risk factor was emitted for
*/
market: string;
/**
* short factor
*/
short: string;
/**
* long factor
*/
long: string;
}
export interface DealTicketQuery_market_data_market {
__typename: "Market";
/**
* Market ID
*/
id: string;
}
export interface DealTicketQuery_market_data {
__typename: "MarketData";
/**
* market id of the associated mark price
*/
market: DealTicketQuery_market_data_market;
/**
* the mark price (actually an unsigned int)
*/
markPrice: string;
/**
* indicative volume if the auction ended now, 0 if not in auction mode
*/
indicativeVolume: string;
/**
* the aggregated volume being bid at the best bid price.
*/
bestBidVolume: string;
/**
* the aggregated volume being offered at the best offer price.
*/
bestOfferVolume: string;
/**
* the aggregated volume being offered at the best static bid price, excluding pegged orders
*/
bestStaticBidVolume: string;
/**
* the aggregated volume being offered at the best static offer price, excluding pegged orders.
*/
bestStaticOfferVolume: string;
}
export interface DealTicketQuery_market_tradableInstrument_instrument_product_settlementAsset {
__typename: "Asset";
/**
@ -163,70 +45,12 @@ export interface DealTicketQuery_market_tradableInstrument_instrument {
product: DealTicketQuery_market_tradableInstrument_instrument_product;
}
export interface DealTicketQuery_market_tradableInstrument_riskModel_LogNormalRiskModel_params {
__typename: "LogNormalModelParams";
/**
* r parameter
*/
r: number;
/**
* sigma parameter
*/
sigma: number;
/**
* mu parameter
*/
mu: number;
}
export interface DealTicketQuery_market_tradableInstrument_riskModel_LogNormalRiskModel {
__typename: "LogNormalRiskModel";
/**
* Tau parameter of the risk model
*/
tau: number;
/**
* Lambda parameter of the risk model
*/
riskAversionParameter: number;
/**
* Params for the log normal risk model
*/
params: DealTicketQuery_market_tradableInstrument_riskModel_LogNormalRiskModel_params;
}
export interface DealTicketQuery_market_tradableInstrument_riskModel_SimpleRiskModel_params {
__typename: "SimpleRiskModelParams";
/**
* Risk factor for long
*/
factorLong: number;
/**
* Risk factor for short
*/
factorShort: number;
}
export interface DealTicketQuery_market_tradableInstrument_riskModel_SimpleRiskModel {
__typename: "SimpleRiskModel";
/**
* Params for the simple risk model
*/
params: DealTicketQuery_market_tradableInstrument_riskModel_SimpleRiskModel_params;
}
export type DealTicketQuery_market_tradableInstrument_riskModel = DealTicketQuery_market_tradableInstrument_riskModel_LogNormalRiskModel | DealTicketQuery_market_tradableInstrument_riskModel_SimpleRiskModel;
export interface DealTicketQuery_market_tradableInstrument {
__typename: "TradableInstrument";
/**
* An instance of or reference to a fully specified instrument.
*/
instrument: DealTicketQuery_market_tradableInstrument_instrument;
/**
* A reference to a risk model that is valid for the instrument
*/
riskModel: DealTicketQuery_market_tradableInstrument_riskModel;
}
export interface DealTicketQuery_market_depth_lastTrade {
@ -286,22 +110,6 @@ export interface DealTicketQuery_market {
* Current mode of execution of the market
*/
tradingMode: MarketTradingMode;
/**
* Fees related data
*/
fees: DealTicketQuery_market_fees;
/**
* Price monitoring settings for the market
*/
priceMonitoringSettings: DealTicketQuery_market_priceMonitoringSettings;
/**
* risk factors for the market
*/
riskFactors: DealTicketQuery_market_riskFactors | null;
/**
* marketData for the given market
*/
data: DealTicketQuery_market_data | null;
/**
* An instance of or reference to a tradable instrument.
*/

View File

@ -0,0 +1,324 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
import { MarketState, MarketTradingMode } from "@vegaprotocol/types";
// ====================================================
// GraphQL query operation: MarketInfoQuery
// ====================================================
export interface MarketInfoQuery_market_fees_factors {
__typename: "FeeFactors";
/**
* The factor applied to calculate MakerFees, a non-negative float
*/
makerFee: string;
/**
* The factor applied to calculate InfrastructureFees, a non-negative float
*/
infrastructureFee: string;
/**
* The factor applied to calculate LiquidityFees, a non-negative float
*/
liquidityFee: string;
}
export interface MarketInfoQuery_market_fees {
__typename: "Fees";
/**
* The factors used to calculate the different fees
*/
factors: MarketInfoQuery_market_fees_factors;
}
export interface MarketInfoQuery_market_priceMonitoringSettings_parameters_triggers {
__typename: "PriceMonitoringTrigger";
/**
* Price monitoring projection horizon τ in seconds (> 0).
*/
horizonSecs: number;
/**
* Price monitoring probability level p. (>0 and < 1)
*/
probability: number;
/**
* Price monitoring auction extension duration in seconds should the price
* breach it's theoretical level over the specified horizon at the specified
* probability level (> 0)
*/
auctionExtensionSecs: number;
}
export interface MarketInfoQuery_market_priceMonitoringSettings_parameters {
__typename: "PriceMonitoringParameters";
/**
* The list of triggers for this price monitoring
*/
triggers: MarketInfoQuery_market_priceMonitoringSettings_parameters_triggers[] | null;
}
export interface MarketInfoQuery_market_priceMonitoringSettings {
__typename: "PriceMonitoringSettings";
/**
* Specified a set of PriceMonitoringParameters to be use for price monitoring purposes
*/
parameters: MarketInfoQuery_market_priceMonitoringSettings_parameters | null;
/**
* How often (in seconds) the price monitoring bounds should be updated
*/
updateFrequencySecs: number;
}
export interface MarketInfoQuery_market_riskFactors {
__typename: "RiskFactor";
/**
* market the risk factor was emitted for
*/
market: string;
/**
* short factor
*/
short: string;
/**
* long factor
*/
long: string;
}
export interface MarketInfoQuery_market_data_market {
__typename: "Market";
/**
* Market ID
*/
id: string;
}
export interface MarketInfoQuery_market_data {
__typename: "MarketData";
/**
* market id of the associated mark price
*/
market: MarketInfoQuery_market_data_market;
/**
* the mark price (actually an unsigned int)
*/
markPrice: string;
/**
* indicative volume if the auction ended now, 0 if not in auction mode
*/
indicativeVolume: string;
/**
* the aggregated volume being bid at the best bid price.
*/
bestBidVolume: string;
/**
* the aggregated volume being offered at the best offer price.
*/
bestOfferVolume: string;
/**
* the aggregated volume being offered at the best static bid price, excluding pegged orders
*/
bestStaticBidVolume: string;
/**
* the aggregated volume being offered at the best static offer price, excluding pegged orders.
*/
bestStaticOfferVolume: string;
}
export interface MarketInfoQuery_market_tradableInstrument_instrument_product_settlementAsset {
__typename: "Asset";
/**
* The id of the asset
*/
id: string;
/**
* The symbol of the asset (e.g: GBP)
*/
symbol: string;
/**
* The full name of the asset (e.g: Great British Pound)
*/
name: string;
}
export interface MarketInfoQuery_market_tradableInstrument_instrument_product {
__typename: "Future";
/**
* String representing the quote (e.g. BTCUSD -> USD is quote)
*/
quoteName: string;
/**
* The name of the asset (string)
*/
settlementAsset: MarketInfoQuery_market_tradableInstrument_instrument_product_settlementAsset;
}
export interface MarketInfoQuery_market_tradableInstrument_instrument {
__typename: "Instrument";
/**
* A reference to or instance of a fully specified product, including all required product parameters for that product (Product union)
*/
product: MarketInfoQuery_market_tradableInstrument_instrument_product;
}
export interface MarketInfoQuery_market_tradableInstrument_riskModel_LogNormalRiskModel_params {
__typename: "LogNormalModelParams";
/**
* r parameter
*/
r: number;
/**
* sigma parameter
*/
sigma: number;
/**
* mu parameter
*/
mu: number;
}
export interface MarketInfoQuery_market_tradableInstrument_riskModel_LogNormalRiskModel {
__typename: "LogNormalRiskModel";
/**
* Tau parameter of the risk model
*/
tau: number;
/**
* Lambda parameter of the risk model
*/
riskAversionParameter: number;
/**
* Params for the log normal risk model
*/
params: MarketInfoQuery_market_tradableInstrument_riskModel_LogNormalRiskModel_params;
}
export interface MarketInfoQuery_market_tradableInstrument_riskModel_SimpleRiskModel_params {
__typename: "SimpleRiskModelParams";
/**
* Risk factor for long
*/
factorLong: number;
/**
* Risk factor for short
*/
factorShort: number;
}
export interface MarketInfoQuery_market_tradableInstrument_riskModel_SimpleRiskModel {
__typename: "SimpleRiskModel";
/**
* Params for the simple risk model
*/
params: MarketInfoQuery_market_tradableInstrument_riskModel_SimpleRiskModel_params;
}
export type MarketInfoQuery_market_tradableInstrument_riskModel = MarketInfoQuery_market_tradableInstrument_riskModel_LogNormalRiskModel | MarketInfoQuery_market_tradableInstrument_riskModel_SimpleRiskModel;
export interface MarketInfoQuery_market_tradableInstrument {
__typename: "TradableInstrument";
/**
* An instance of or reference to a fully specified instrument.
*/
instrument: MarketInfoQuery_market_tradableInstrument_instrument;
/**
* A reference to a risk model that is valid for the instrument
*/
riskModel: MarketInfoQuery_market_tradableInstrument_riskModel;
}
export interface MarketInfoQuery_market_depth_lastTrade {
__typename: "Trade";
/**
* The price of the trade (probably initially the passive order price, other determination algorithms are possible though) (uint64)
*/
price: string;
}
export interface MarketInfoQuery_market_depth {
__typename: "MarketDepth";
/**
* Last trade for the given market (if available)
*/
lastTrade: MarketInfoQuery_market_depth_lastTrade | null;
}
export interface MarketInfoQuery_market {
__typename: "Market";
/**
* Market ID
*/
id: string;
/**
* Market full name
*/
name: string;
/**
* decimalPlaces indicates the number of decimal places that an integer must be shifted by in order to get a correct
* number denominated in the currency of the Market. (uint64)
*
* Examples:
* Currency Balance decimalPlaces Real Balance
* GBP 100 0 GBP 100
* GBP 100 2 GBP 1.00
* GBP 100 4 GBP 0.01
* GBP 1 4 GBP 0.0001 ( 0.01p )
*
* GBX (pence) 100 0 GBP 1.00 (100p )
* GBX (pence) 100 2 GBP 0.01 ( 1p )
* GBX (pence) 100 4 GBP 0.0001 ( 0.01p )
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
*/
decimalPlaces: number;
/**
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
*/
positionDecimalPlaces: number;
/**
* Current state of the market
*/
state: MarketState;
/**
* Current mode of execution of the market
*/
tradingMode: MarketTradingMode;
/**
* Fees related data
*/
fees: MarketInfoQuery_market_fees;
/**
* Price monitoring settings for the market
*/
priceMonitoringSettings: MarketInfoQuery_market_priceMonitoringSettings;
/**
* risk factors for the market
*/
riskFactors: MarketInfoQuery_market_riskFactors | null;
/**
* marketData for the given market
*/
data: MarketInfoQuery_market_data | null;
/**
* An instance of or reference to a tradable instrument.
*/
tradableInstrument: MarketInfoQuery_market_tradableInstrument;
/**
* Current depth on the order book for this market
*/
depth: MarketInfoQuery_market_depth;
}
export interface MarketInfoQuery {
/**
* An instrument that is trading on the VEGA network
*/
market: MarketInfoQuery_market | null;
}
export interface MarketInfoQueryVariables {
marketId: string;
}

View File

@ -1,108 +0,0 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
import { BusEventType, OrderType, OrderStatus, OrderRejectionReason } from "@vegaprotocol/types";
// ====================================================
// GraphQL subscription operation: OrderEvent
// ====================================================
export interface OrderEvent_busEvents_event_TimeUpdate {
__typename: "TimeUpdate" | "MarketEvent" | "TransferResponses" | "PositionResolution" | "Trade" | "Account" | "Party" | "MarginLevels" | "Proposal" | "Vote" | "MarketData" | "NodeSignature" | "LossSocialization" | "SettlePosition" | "Market" | "Asset" | "MarketTick" | "SettleDistressed" | "AuctionEvent" | "RiskFactor" | "Deposit" | "Withdrawal" | "OracleSpec" | "LiquidityProvision";
}
export interface OrderEvent_busEvents_event_Order_market {
__typename: "Market";
/**
* Market full name
*/
name: string;
/**
* decimalPlaces indicates the number of decimal places that an integer must be shifted by in order to get a correct
* number denominated in the currency of the Market. (uint64)
*
* Examples:
* Currency Balance decimalPlaces Real Balance
* GBP 100 0 GBP 100
* GBP 100 2 GBP 1.00
* GBP 100 4 GBP 0.01
* GBP 1 4 GBP 0.0001 ( 0.01p )
*
* GBX (pence) 100 0 GBP 1.00 (100p )
* GBX (pence) 100 2 GBP 0.01 ( 1p )
* GBX (pence) 100 4 GBP 0.0001 ( 0.01p )
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
*/
decimalPlaces: number;
}
export interface OrderEvent_busEvents_event_Order {
__typename: "Order";
/**
* Type the order type (defaults to PARTY)
*/
type: OrderType | null;
/**
* Hash of the order data
*/
id: string;
/**
* The status of an order, for example 'Active'
*/
status: OrderStatus;
/**
* Reason for the order to be rejected
*/
rejectionReason: OrderRejectionReason | null;
/**
* RFC3339Nano formatted date and time for when the order was created (timestamp)
*/
createdAt: string;
/**
* Total number of contracts that may be bought or sold (immutable) (uint64)
*/
size: string;
/**
* The worst price the order will trade at (e.g. buy for price or less, sell for price or more) (uint64)
*/
price: string;
/**
* The market the order is trading on (probably stored internally as a hash of the market details)
*/
market: OrderEvent_busEvents_event_Order_market | null;
}
export type OrderEvent_busEvents_event = OrderEvent_busEvents_event_TimeUpdate | OrderEvent_busEvents_event_Order;
export interface OrderEvent_busEvents {
__typename: "BusEvent";
/**
* the id for this event
*/
eventId: string;
/**
* the block hash
*/
block: string;
/**
* the type of event we're dealing with
*/
type: BusEventType;
/**
* the payload - the wrapped event
*/
event: OrderEvent_busEvents_event;
}
export interface OrderEvent {
/**
* Subscribe to event data from the event bus
*/
busEvents: OrderEvent_busEvents[] | null;
}
export interface OrderEventVariables {
partyId: string;
}

View File

@ -1,2 +1,2 @@
export * from './DealTicketQuery';
export * from './OrderEvent';
export * from './MarketInfoQuery';

View File

@ -12,22 +12,17 @@ export interface DealTicketAmountProps {
price?: string;
}
const getAmountComponent = (type: OrderType) => {
switch (type) {
export const DealTicketAmount = ({
orderType,
...props
}: DealTicketAmountProps) => {
switch (orderType) {
case OrderType.Market:
return DealTicketMarketAmount;
return <DealTicketMarketAmount {...props} />;
case OrderType.Limit:
return DealTicketLimitAmount;
return <DealTicketLimitAmount {...props} />;
default: {
throw new Error('Invalid ticket type');
}
}
};
export const DealTicketAmount = ({
orderType,
...props
}: DealTicketAmountProps) => {
const AmountComponent = getAmountComponent(orderType);
return <AmountComponent {...props} />;
};

View File

@ -1,13 +1,7 @@
import { gql, useQuery } from '@apollo/client';
import {
AsyncRenderer,
GridTab,
GridTabs,
Splash,
} from '@vegaprotocol/ui-toolkit';
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
import { DealTicketManager } from './deal-ticket-manager';
import { t } from '@vegaprotocol/react-helpers';
import { Info } from './info-market';
import type { DealTicketQuery_market, DealTicketQuery } from './__generated__';
const DEAL_TICKET_QUERY = gql`
@ -19,40 +13,6 @@ const DEAL_TICKET_QUERY = gql`
positionDecimalPlaces
state
tradingMode
fees {
factors {
makerFee
infrastructureFee
liquidityFee
}
}
priceMonitoringSettings {
parameters {
triggers {
horizonSecs
probability
auctionExtensionSecs
}
}
updateFrequencySecs
}
riskFactors {
market
short
long
}
data {
market {
id
}
markPrice
indicativeVolume
bestBidVolume
bestOfferVolume
bestStaticBidVolume
bestStaticOfferVolume
indicativeVolume
}
tradableInstrument {
instrument {
product {
@ -66,23 +26,6 @@ const DEAL_TICKET_QUERY = gql`
}
}
}
riskModel {
... on LogNormalRiskModel {
tau
riskAversionParameter
params {
r
sigma
mu
}
}
... on SimpleRiskModel {
params {
factorLong
factorShort
}
}
}
}
depth {
lastTrade {
@ -111,45 +54,18 @@ export const DealTicketContainer = ({
});
return (
<GridTabs>
<GridTab id="ticket" name={t('Ticket')}>
<AsyncRenderer<DealTicketQuery>
data={data}
loading={loading}
error={error}
>
{data && data.market ? (
children ? (
children(data)
) : (
<DealTicketManager market={data.market} />
)
) : (
<Splash>
<p>{t('Could not load market')}</p>
</Splash>
)}
</AsyncRenderer>
</GridTab>
<GridTab id="info" name={t('Info')}>
<AsyncRenderer<DealTicketQuery>
data={data}
loading={loading}
error={error}
>
{data && data.market ? (
children ? (
children(data)
) : (
<Info market={data.market} />
)
) : (
<Splash>
<p>{t('Could not load market')}</p>
</Splash>
)}
</AsyncRenderer>
</GridTab>
</GridTabs>
<AsyncRenderer<DealTicketQuery> data={data} loading={loading} error={error}>
{data && data.market ? (
children ? (
children(data)
) : (
<DealTicketManager market={data.market} />
)
) : (
<Splash>
<p>{t('Could not load market')}</p>
</Splash>
)}
</AsyncRenderer>
);
};

View File

@ -37,6 +37,10 @@ export const DealTicketManager = ({
return Intent.Danger;
}
if (status === VegaTxStatus.Requested) {
return Intent.Warning;
}
if (status === VegaTxStatus.Error) {
return Intent.Danger;
}
@ -47,6 +51,8 @@ export const DealTicketManager = ({
useEffect(() => {
if (transaction.status !== VegaTxStatus.Default) {
setOrderDialogOpen(true);
} else {
setOrderDialogOpen(false);
}
}, [transaction.status]);

View File

@ -6,13 +6,14 @@ import {
import { addDecimal } from '@vegaprotocol/react-helpers';
import { fireEvent, render, screen, act } from '@testing-library/react';
import { DealTicket } from './deal-ticket';
import type { DealTicketQuery_market } from '../__generated__/DealTicketQuery';
import type { DealTicketQuery_market } from './__generated__/DealTicketQuery';
import type { Order } from '../utils/get-default-order';
import { MarketState, MarketTradingMode } from '@vegaprotocol/types';
const market: DealTicketQuery_market = {
__typename: 'Market',
id: 'market-id',
name: 'market-name',
decimalPlaces: 2,
positionDecimalPlaces: 1,
tradingMode: MarketTradingMode.Continuous,
@ -24,6 +25,12 @@ const market: DealTicketQuery_market = {
product: {
__typename: 'Future',
quoteName: 'quote-name',
settlementAsset: {
__typename: 'Asset',
id: 'asset-id',
name: 'asset-name',
symbol: 'asset-symbol',
},
},
},
},

View File

@ -77,7 +77,7 @@ export const DealTicket = ({
/>
<DealTicketAmount
orderType={orderType}
step={0.02}
step={step}
register={register}
price={
market.depth.lastTrade
@ -109,7 +109,7 @@ export const DealTicket = ({
)}
<Button
className="w-full mb-8"
variant="primary"
variant="trade"
type="submit"
disabled={isDisabled}
data-testid="place-order"

View File

@ -8,18 +8,130 @@ import {
import {
KeyValueTable,
KeyValueTableRow,
AsyncRenderer,
Splash,
Accordion,
} from '@vegaprotocol/ui-toolkit';
import startCase from 'lodash/startCase';
import pick from 'lodash/pick';
import omit from 'lodash/omit';
import type { DealTicketQuery_market } from './__generated__/DealTicketQuery';
import type {
MarketInfoQuery,
MarketInfoQuery_market,
} from './__generated__/MarketInfoQuery';
import BigNumber from 'bignumber.js';
import { gql, useQuery } from '@apollo/client';
const MARKET_INFO_QUERY = gql`
query MarketInfoQuery($marketId: ID!) {
market(id: $marketId) {
id
name
decimalPlaces
positionDecimalPlaces
state
tradingMode
fees {
factors {
makerFee
infrastructureFee
liquidityFee
}
}
priceMonitoringSettings {
parameters {
triggers {
horizonSecs
probability
auctionExtensionSecs
}
}
updateFrequencySecs
}
riskFactors {
market
short
long
}
data {
market {
id
}
markPrice
indicativeVolume
bestBidVolume
bestOfferVolume
bestStaticBidVolume
bestStaticOfferVolume
indicativeVolume
}
tradableInstrument {
instrument {
product {
... on Future {
quoteName
settlementAsset {
id
symbol
name
}
}
}
}
riskModel {
... on LogNormalRiskModel {
tau
riskAversionParameter
params {
r
sigma
mu
}
}
... on SimpleRiskModel {
params {
factorLong
factorShort
}
}
}
}
depth {
lastTrade {
price
}
}
}
}
`;
export interface InfoProps {
market: DealTicketQuery_market;
market: MarketInfoQuery_market;
}
export interface MarketInfoContainerProps {
marketId: string;
}
export const MarketInfoContainer = ({ marketId }: MarketInfoContainerProps) => {
const { data, loading, error } = useQuery(MARKET_INFO_QUERY, {
variables: { marketId },
});
return (
<AsyncRenderer<MarketInfoQuery> data={data} loading={loading} error={error}>
{data && data.market ? (
<div className={'overflow-auto h-full'}>
<Info market={data.market} />
</div>
) : (
<Splash>
<p>{t('Could not load market')}</p>
</Splash>
)}
</AsyncRenderer>
);
};
export const Info = ({ market }: InfoProps) => {
const headerClassName =
'text-h5 font-bold uppercase text-black dark:text-white';

View File

@ -1,9 +1,13 @@
import { Icon, Loader } from '@vegaprotocol/ui-toolkit';
import type { ReactNode } from 'react';
import type { OrderEvent_busEvents_event_Order } from './__generated__/OrderEvent';
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
import {
addDecimal,
addDecimalsFormatNumber,
t,
} from '@vegaprotocol/react-helpers';
import type { VegaTxState } from '@vegaprotocol/wallet';
import { VegaTxStatus } from '@vegaprotocol/wallet';
import type { OrderEvent_busEvents_event_Order } from '../hooks/__generated__/OrderEvent';
interface OrderDialogProps {
transaction: VegaTxState;
@ -14,9 +18,22 @@ export const OrderDialog = ({
transaction,
finalizedOrder,
}: OrderDialogProps) => {
// TODO: When wallets support confirming transactions return UI for 'awaiting confirmation' step
// Rejected by wallet
if (transaction.status === VegaTxStatus.Requested) {
return (
<OrderDialogWrapper
title="Confirm transaction in wallet"
icon={<Icon name="hand-up" size={20} />}
>
<p>
Please open your wallet application and confirm or reject the
transaction
</p>
</OrderDialogWrapper>
);
}
// Transaction error
if (transaction.status === VegaTxStatus.Error) {
return (
<OrderDialogWrapper
@ -72,7 +89,14 @@ export const OrderDialog = ({
<p>{t(`Market: ${finalizedOrder.market.name}`)}</p>
)}
<p>{t(`Type: ${finalizedOrder.type}`)}</p>
<p>{t(`Amount: ${finalizedOrder.size}`)}</p>
<p>
{t(
`Amount: ${addDecimal(
finalizedOrder.size,
finalizedOrder.market?.positionDecimalPlaces || 0
)}`
)}
</p>
{finalizedOrder.type === 'Limit' && finalizedOrder.market && (
<p>
{t(

View File

@ -36,6 +36,12 @@ export interface OrderEvent_busEvents_event_Order_market {
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
*/
decimalPlaces: number;
/**
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
*/
positionDecimalPlaces: number;
}
export interface OrderEvent_busEvents_event_Order {

View File

@ -4,12 +4,12 @@ import type { Order } from '../utils/get-default-order';
import { OrderType, useVegaWallet } from '@vegaprotocol/wallet';
import { determineId, removeDecimal } from '@vegaprotocol/react-helpers';
import { useVegaTransaction } from '@vegaprotocol/wallet';
import type { DealTicketQuery_market } from '../components/__generated__/DealTicketQuery';
import type {
OrderEvent,
OrderEventVariables,
OrderEvent_busEvents_event_Order,
} from '../components/__generated__/OrderEvent';
import type { DealTicketQuery_market } from '../components/__generated__/DealTicketQuery';
} from './__generated__/OrderEvent';
const ORDER_EVENT_SUB = gql`
subscription OrderEvent($partyId: ID!) {
@ -29,6 +29,7 @@ const ORDER_EVENT_SUB = gql`
market {
name
decimalPlaces
positionDecimalPlaces
}
}
}

View File

@ -37,7 +37,6 @@ beforeEach(() => {
submitDeposit: jest.fn(),
requestFaucet: jest.fn(),
limits: {
min: new BigNumber(0),
max: new BigNumber(20),
},
allowance: new BigNumber(30),
@ -199,6 +198,6 @@ it('Deposit', async () => {
// @ts-ignore contract address definitely defined
assetSource: asset.source.contractAddress,
amount: '1500',
vegaPublicKey: `0x${vegaKey}`,
vegaPublicKey: vegaKey,
});
});

View File

@ -89,7 +89,7 @@ export const DepositForm = ({
submitDeposit({
assetSource: selectedAsset.source.contractAddress,
amount: removeDecimal(fields.amount, selectedAsset.decimals),
vegaPublicKey: `0x${fields.to}`,
vegaPublicKey: fields.to,
});
};

View File

@ -132,6 +132,12 @@ export interface MarketDepth_market {
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
*/
decimalPlaces: number;
/**
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
*/
positionDecimalPlaces: number;
/**
* marketData for the given market
*/

View File

@ -55,6 +55,12 @@ export interface MarketDepthSubscription_marketDepthUpdate_market {
* Market ID
*/
id: string;
/**
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
*/
positionDecimalPlaces: number;
/**
* marketData for the given market
*/

View File

@ -1,5 +1,4 @@
import { DepthChart } from 'pennant';
import { produce } from 'immer';
import throttle from 'lodash/throttle';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import {
@ -92,28 +91,31 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
if (!dataRef.current) {
return false;
}
dataRef.current = produce(dataRef.current, (draft) => {
if (delta.buy) {
draft.data.buy = updateLevels(
draft.data.buy,
delta.buy,
decimalPlacesRef.current
);
}
if (delta.sell) {
draft.data.sell = updateLevels(
draft.data.sell,
delta.sell,
decimalPlacesRef.current
);
}
draft.midPrice = delta.market.data?.staticMidPrice
dataRef.current = {
...dataRef.current,
midPrice: delta.market.data?.staticMidPrice
? formatMidPrice(
delta.market.data?.staticMidPrice,
decimalPlacesRef.current
)
: undefined;
});
: undefined,
data: {
buy: delta.buy
? updateLevels(
dataRef.current.data.buy,
delta.buy,
decimalPlacesRef.current
)
: dataRef.current.data.buy,
sell: delta.sell
? updateLevels(
dataRef.current.data.sell,
delta.sell,
decimalPlacesRef.current
)
: dataRef.current.data.sell,
},
};
setDepthDataThrottledRef.current(dataRef.current);
return true;
},

View File

@ -16,6 +16,7 @@ const MARKET_DEPTH_QUERY = gql`
market(id: $marketId) {
id
decimalPlaces
positionDecimalPlaces
data {
staticMidPrice
marketTradingMode
@ -52,6 +53,7 @@ export const MARKET_DEPTH_SUBSCRIPTION_QUERY = gql`
marketDepthUpdate(marketId: $marketId) {
market {
id
positionDecimalPlaces
data {
staticMidPrice
marketTradingMode
@ -84,27 +86,31 @@ const sequenceNumbers: Record<string, number> = {};
const update: Update<
MarketDepth_market,
MarketDepthSubscription_marketDepthUpdate
> = (draft, delta, reload) => {
if (delta.market.id !== draft.id) {
return;
> = (data, delta, reload) => {
if (delta.market.id !== data.id) {
return data;
}
const sequenceNumber = Number(delta.sequenceNumber);
if (sequenceNumber <= sequenceNumbers[delta.market.id]) {
return;
return data;
}
/*
if (sequenceNumber - 1 !== sequenceNumbers[delta.market.id]) {
sequenceNumbers[delta.market.id] = 0;
reload();
return;
}
*/
sequenceNumbers[delta.market.id] = sequenceNumber;
Object.assign(draft.data, delta.market.data);
const updatedData = { ...data };
data.data = delta.market.data;
if (delta.buy) {
draft.depth.buy = updateLevels(draft.depth.buy ?? [], delta.buy);
updatedData.depth.buy = updateLevels(data.depth.buy ?? [], delta.buy);
}
if (delta.sell) {
draft.depth.sell = updateLevels(draft.depth.sell ?? [], delta.sell);
updatedData.depth.sell = updateLevels(data.depth.sell ?? [], delta.sell);
}
return updatedData;
};
const getData = (responseData: MarketDepth) => {

View File

@ -55,10 +55,8 @@ describe('compactRows', () => {
'1097': 3,
'1098': 2,
'1099': 1,
'1100': 0,
});
expect(orderbookRows[orderbookRows.length - 1].bidByLevel).toEqual({
'901': 0,
'902': 1,
'903': 2,
'904': 3,
@ -81,7 +79,7 @@ describe('compactRows', () => {
});
describe('updateLevels', () => {
const levels: MarketDepth_market_depth_sell[] = new Array(10)
let levels: MarketDepth_market_depth_sell[] = new Array(10)
.fill(null)
.map((n, i) => ({
__typename: 'PriceLevel',
@ -96,9 +94,9 @@ describe('updateLevels', () => {
volume: '0',
numberOfOrders: '0',
};
updateLevels(levels, [removeFirstRow]);
levels = updateLevels(levels, [removeFirstRow]);
expect(levels[0].price).toEqual('20');
updateLevels(levels, [removeFirstRow]);
levels = updateLevels(levels, [removeFirstRow]);
expect(levels[0].price).toEqual('20');
expect(updateLevels([], [removeFirstRow])).toEqual([]);
const addFirstRow: MarketDepthSubscription_marketDepthUpdate_sell = {
@ -107,7 +105,7 @@ describe('updateLevels', () => {
volume: '10',
numberOfOrders: '10',
};
updateLevels(levels, [addFirstRow]);
levels = updateLevels(levels, [addFirstRow]);
expect(levels[0].price).toEqual('10');
const addBeforeLastRow: MarketDepthSubscription_marketDepthUpdate_sell = {
__typename: 'PriceLevel',
@ -115,7 +113,7 @@ describe('updateLevels', () => {
volume: '95',
numberOfOrders: '95',
};
updateLevels(levels, [addBeforeLastRow]);
levels = updateLevels(levels, [addBeforeLastRow]);
expect(levels[levels.length - 2].price).toEqual('95');
const addAtTheEnd: MarketDepthSubscription_marketDepthUpdate_sell = {
__typename: 'PriceLevel',
@ -123,7 +121,7 @@ describe('updateLevels', () => {
volume: '115',
numberOfOrders: '115',
};
updateLevels(levels, [addAtTheEnd]);
levels = updateLevels(levels, [addAtTheEnd]);
expect(levels[levels.length - 1].price).toEqual('115');
const updateLastRow: MarketDepthSubscription_marketDepthUpdate_sell = {
__typename: 'PriceLevel',
@ -131,7 +129,7 @@ describe('updateLevels', () => {
volume: '116',
numberOfOrders: '115',
};
updateLevels(levels, [updateLastRow]);
levels = updateLevels(levels, [updateLastRow]);
expect(levels[levels.length - 1]).toEqual(updateLastRow);
expect(updateLevels([], [updateLastRow])).toEqual([updateLastRow]);
});

View File

@ -1,4 +1,3 @@
import produce from 'immer';
import groupBy from 'lodash/groupBy';
import { VolumeType } from '@vegaprotocol/react-helpers';
import { MarketTradingMode } from '@vegaprotocol/types';
@ -31,6 +30,8 @@ export interface OrderbookRowData {
cumulativeVol: CumulativeVol;
}
type PartialOrderbookRowData = Pick<OrderbookRowData, 'price' | 'ask' | 'bid'>;
export type OrderbookData = Partial<
Omit<MarketDepth_market_data, '__typename' | 'market'>
> & { rows: OrderbookRowData[] | null };
@ -75,21 +76,31 @@ const updateRelativeData = (data: OrderbookRowData[]) => {
});
};
export const createPartialRow = (
price: string,
volume = 0,
dataType?: VolumeType
): PartialOrderbookRowData => ({
price,
ask: dataType === VolumeType.ask ? volume : 0,
bid: dataType === VolumeType.bid ? volume : 0,
});
export const extendRow = (row: PartialOrderbookRowData): OrderbookRowData =>
Object.assign(row, {
cumulativeVol: {
ask: 0,
bid: 0,
},
askByLevel: row.ask ? { [row.price]: row.ask } : {},
bidByLevel: row.bid ? { [row.price]: row.bid } : {},
});
export const createRow = (
price: string,
volume = 0,
dataType?: VolumeType
): OrderbookRowData => ({
price,
ask: dataType === VolumeType.ask ? volume : 0,
bid: dataType === VolumeType.bid ? volume : 0,
cumulativeVol: {
ask: dataType === VolumeType.ask ? volume : 0,
bid: dataType === VolumeType.bid ? volume : 0,
},
askByLevel: dataType === VolumeType.ask ? { [price]: volume } : {},
bidByLevel: dataType === VolumeType.bid ? { [price]: volume } : {},
});
): OrderbookRowData => extendRow(createPartialRow(price, volume, dataType));
const mapRawData =
(dataType: VolumeType.ask | VolumeType.bid) =>
@ -99,8 +110,8 @@ const mapRawData =
| MarketDepthSubscription_marketDepthUpdate_sell
| MarketDepth_market_depth_buy
| MarketDepthSubscription_marketDepthUpdate_buy
): OrderbookRowData =>
createRow(data.price, Number(data.volume), dataType);
): PartialOrderbookRowData =>
createPartialRow(data.price, Number(data.volume), dataType);
/**
* @summary merges sell amd buy data, orders by price desc, group by price level, counts cumulative and relative values
@ -121,37 +132,38 @@ export const compactRows = (
resolution: number
) => {
// map raw sell data to OrderbookData
const askOrderbookData = [...(sell ?? [])].map<OrderbookRowData>(
const askOrderbookData = [...(sell ?? [])].map<PartialOrderbookRowData>(
mapRawData(VolumeType.ask)
);
// map raw buy data to OrderbookData
const bidOrderbookData = [...(buy ?? [])].map<OrderbookRowData>(
const bidOrderbookData = [...(buy ?? [])].map<PartialOrderbookRowData>(
mapRawData(VolumeType.bid)
);
// group by price level
const groupedByLevel = groupBy<OrderbookRowData>(
const groupedByLevel = groupBy<PartialOrderbookRowData>(
[...askOrderbookData, ...bidOrderbookData],
(row) => getPriceLevel(row.price, resolution)
);
// create single OrderbookData from grouped OrderbookData[], sum volumes and atore volume by level
const orderbookData = Object.keys(groupedByLevel).reduce<OrderbookRowData[]>(
(rows, price) =>
rows.concat(
groupedByLevel[price].reduce<OrderbookRowData>(
(a, c) => ({
...a,
ask: a.ask + c.ask,
askByLevel: Object.assign(a.askByLevel, c.askByLevel),
bid: (a.bid ?? 0) + (c.bid ?? 0),
bidByLevel: Object.assign(a.bidByLevel, c.bidByLevel),
}),
createRow(price)
)
),
[]
);
const orderbookData: OrderbookRowData[] = [];
Object.keys(groupedByLevel).forEach((price) => {
const row = extendRow(
groupedByLevel[price].pop() as PartialOrderbookRowData
);
row.price = price;
let subRow: PartialOrderbookRowData | undefined;
// eslint-disable-next-line no-cond-assign
while ((subRow = groupedByLevel[price].pop())) {
row.ask += subRow.ask;
row.bid += subRow.bid;
if (subRow.ask) {
row.askByLevel[subRow.price] = subRow.ask;
}
if (subRow.bid) {
row.bidByLevel[subRow.price] = subRow.bid;
}
}
orderbookData.push(row);
});
// order by price, it's safe to cast to number price diff should not exceed Number.MAX_SAFE_INTEGER
orderbookData.sort((a, b) => Number(BigInt(b.price) - BigInt(a.price)));
// count cumulative volumes
@ -163,11 +175,9 @@ export const compactRows = (
(i !== 0 ? orderbookData[i - 1].cumulativeVol.bid : 0);
}
for (let i = maxIndex; i >= 0; i--) {
if (!orderbookData[i].cumulativeVol.ask) {
orderbookData[i].cumulativeVol.ask =
orderbookData[i].ask +
(i !== maxIndex ? orderbookData[i + 1].cumulativeVol.ask : 0);
}
orderbookData[i].cumulativeVol.ask =
orderbookData[i].ask +
(i !== maxIndex ? orderbookData[i + 1].cumulativeVol.ask : 0);
}
}
// count relative volumes
@ -186,13 +196,13 @@ export const compactRows = (
*/
const partiallyUpdateCompactedRows = (
dataType: VolumeType,
draft: OrderbookRowData[],
data: OrderbookRowData[],
delta:
| MarketDepthSubscription_marketDepthUpdate_sell
| MarketDepthSubscription_marketDepthUpdate_buy,
resolution: number,
modifiedIndex: number
) => {
): [number, OrderbookRowData[]] => {
const { price } = delta;
const volume = Number(delta.volume);
const priceLevel = getPriceLevel(price, resolution);
@ -201,28 +211,36 @@ const partiallyUpdateCompactedRows = (
const oppositeVolKey = isAskDataType ? 'bid' : 'ask';
const volByLevelKey = isAskDataType ? 'askByLevel' : 'bidByLevel';
const resolveModifiedIndex = isAskDataType ? Math.max : Math.min;
let index = draft.findIndex((data) => data.price === priceLevel);
let index = data.findIndex((row) => row.price === priceLevel);
if (index !== -1) {
modifiedIndex = resolveModifiedIndex(modifiedIndex, index);
draft[index][volKey] =
draft[index][volKey] - (draft[index][volByLevelKey][price] || 0) + volume;
draft[index][volByLevelKey][price] = volume;
data[index] = {
...data[index],
[volKey]:
data[index][volKey] - (data[index][volByLevelKey][price] || 0) + volume,
[volByLevelKey]: {
...data[index][volByLevelKey],
[price]: volume,
},
};
return [modifiedIndex, [...data]];
} else {
const newData: OrderbookRowData = createRow(priceLevel, volume, dataType);
index = draft.findIndex((data) => BigInt(data.price) < BigInt(priceLevel));
index = data.findIndex((row) => BigInt(row.price) < BigInt(priceLevel));
if (index !== -1) {
draft.splice(index, 0, newData);
newData.cumulativeVol[oppositeVolKey] =
draft[index + (isAskDataType ? -1 : 1)]?.cumulativeVol[
oppositeVolKey
] ?? 0;
data[index + (isAskDataType ? 0 : 1)]?.cumulativeVol[oppositeVolKey] ??
0;
modifiedIndex = resolveModifiedIndex(modifiedIndex, index);
return [
modifiedIndex,
[...data.slice(0, index), newData, ...data.slice(index)],
];
} else {
draft.push(newData);
modifiedIndex = draft.length - 1;
modifiedIndex = data.length - 1;
return [modifiedIndex, [...data, newData]];
}
}
return modifiedIndex;
};
/**
@ -239,59 +257,66 @@ export const updateCompactedRows = (
sell: MarketDepthSubscription_marketDepthUpdate_sell[] | null,
buy: MarketDepthSubscription_marketDepthUpdate_buy[] | null,
resolution: number
) =>
produce(rows, (draft) => {
let sellModifiedIndex = -1;
sell?.forEach((delta) => {
sellModifiedIndex = partiallyUpdateCompactedRows(
VolumeType.ask,
draft,
delta,
resolution,
sellModifiedIndex
);
});
let buyModifiedIndex = draft.length;
buy?.forEach((delta) => {
buyModifiedIndex = partiallyUpdateCompactedRows(
VolumeType.bid,
draft,
delta,
resolution,
buyModifiedIndex
);
});
// update cummulative ask only below hihgest modified price level
if (sellModifiedIndex !== -1) {
for (let i = Math.min(sellModifiedIndex, draft.length - 2); i >= 0; i--) {
draft[i].cumulativeVol.ask =
draft[i + 1].cumulativeVol.ask + draft[i].ask;
}
}
// update cummulative bid only above lowest modified price level
if (buyModifiedIndex !== draft.length) {
for (
let i = Math.max(buyModifiedIndex, 1), l = draft.length;
i < l;
i++
) {
draft[i].cumulativeVol.bid =
draft[i - 1].cumulativeVol.bid + draft[i].bid;
}
}
let index = 0;
// remove levels that do not have any volume
while (index < draft.length) {
if (!draft[index].ask && !draft[index].bid) {
draft.splice(index, 1);
} else {
index += 1;
}
}
// count relative volumes
updateRelativeData(draft);
) => {
let sellModifiedIndex = -1;
let data = [...rows];
sell?.forEach((delta) => {
[sellModifiedIndex, data] = partiallyUpdateCompactedRows(
VolumeType.ask,
data,
delta,
resolution,
sellModifiedIndex
);
});
let buyModifiedIndex = data.length;
buy?.forEach((delta) => {
[buyModifiedIndex, data] = partiallyUpdateCompactedRows(
VolumeType.bid,
data,
delta,
resolution,
buyModifiedIndex
);
});
// update cummulative ask only below hihgest modified price level
if (sellModifiedIndex !== -1) {
for (let i = Math.min(sellModifiedIndex, data.length - 2); i >= 0; i--) {
data[i] = {
...data[i],
cumulativeVol: {
...data[i].cumulativeVol,
ask: data[i + 1].cumulativeVol.ask + data[i].ask,
},
};
}
}
// update cummulative bid only above lowest modified price level
if (buyModifiedIndex !== data.length) {
for (let i = Math.max(buyModifiedIndex, 1), l = data.length; i < l; i++) {
data[i] = {
...data[i],
cumulativeVol: {
...data[i].cumulativeVol,
bid: data[i - 1].cumulativeVol.bid + data[i].bid,
},
};
}
}
let index = 0;
// remove levels that do not have any volume
while (index < data.length) {
if (!data[index].ask && !data[index].bid) {
data.splice(index, 1);
} else {
index += 1;
}
}
// count relative volumes
updateRelativeData(data);
return data;
};
export const mapMarketData = (
data:
@ -319,23 +344,24 @@ export const mapMarketData = (
* @returns
*/
export const updateLevels = (
levels: (MarketDepth_market_depth_buy | MarketDepth_market_depth_sell)[],
draft: (MarketDepth_market_depth_buy | MarketDepth_market_depth_sell)[],
updates: (
| MarketDepthSubscription_marketDepthUpdate_buy
| MarketDepthSubscription_marketDepthUpdate_sell
)[]
) => {
const levels = [...draft];
updates.forEach((update) => {
let index = levels.findIndex((level) => level.price === update.price);
if (index !== -1) {
if (update.volume === '0') {
levels.splice(index, 1);
} else {
Object.assign(levels[index], update);
levels[index] = update;
}
} else if (update.volume !== '0') {
index = levels.findIndex(
(level) => Number(level.price) > Number(update.price)
(level) => BigInt(level.price) > BigInt(update.price)
);
if (index !== -1) {
levels.splice(index, 0, update);

View File

@ -1,5 +1,4 @@
import throttle from 'lodash/throttle';
import produce from 'immer';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { Orderbook } from './orderbook';
import { useDataProvider } from '@vegaprotocol/react-helpers';
@ -25,27 +24,52 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
rows: null,
});
const dataRef = useRef<OrderbookData>({ rows: null });
const setOrderbookDataThrottled = useRef(throttle(setOrderbookData, 1000));
const deltaRef = useRef<MarketDepthSubscription_marketDepthUpdate>();
const updateOrderbookData = useRef(
throttle(() => {
if (!deltaRef.current) {
return;
}
dataRef.current = {
...deltaRef.current.market.data,
...mapMarketData(deltaRef.current.market.data, resolutionRef.current),
rows: updateCompactedRows(
dataRef.current.rows ?? [],
deltaRef.current.sell,
deltaRef.current.buy,
resolutionRef.current
),
};
deltaRef.current = undefined;
setOrderbookData(dataRef.current);
}, 1000)
);
const update = useCallback(
(delta: MarketDepthSubscription_marketDepthUpdate) => {
if (!dataRef.current.rows) {
return false;
}
dataRef.current = produce(dataRef.current, (draft) => {
Object.assign(draft, delta.market.data);
draft.rows = updateCompactedRows(
draft.rows ?? [],
delta.sell,
delta.buy,
resolutionRef.current
);
Object.assign(
draft,
mapMarketData(delta.market.data, resolutionRef.current)
);
});
setOrderbookDataThrottled.current(dataRef.current);
if (deltaRef.current) {
deltaRef.current.market = delta.market;
if (delta.sell) {
if (deltaRef.current.sell) {
deltaRef.current.sell.push(...delta.sell);
} else {
deltaRef.current.sell = delta.sell;
}
}
if (delta.buy) {
if (deltaRef.current.buy) {
deltaRef.current.buy.push(...delta.buy);
} else {
deltaRef.current.buy = delta.buy;
}
}
} else {
deltaRef.current = delta;
}
updateOrderbookData.current();
return true;
},
// using resolutionRef.current to avoid using resolution as a dependency - it will cause data provider restart on resolution change
@ -82,6 +106,7 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
<Orderbook
{...orderbookData}
decimalPlaces={data?.decimalPlaces ?? 0}
positionDecimalPlaces={data?.positionDecimalPlaces ?? 0}
resolution={resolution}
onResolutionChange={(resolution: number) => setResolution(resolution)}
/>

View File

@ -5,6 +5,7 @@ import {
CumulativeVol,
addDecimalsFormatNumber,
VolumeType,
addDecimal,
} from '@vegaprotocol/react-helpers';
interface OrderbookRowProps {
@ -15,6 +16,7 @@ interface OrderbookRowProps {
cumulativeRelativeAsk?: number;
cumulativeRelativeBid?: number;
decimalPlaces: number;
positionDecimalPlaces: number;
indicativeVolume?: string;
price: string;
relativeAsk?: number;
@ -30,6 +32,7 @@ export const OrderbookRow = React.memo(
cumulativeRelativeAsk,
cumulativeRelativeBid,
decimalPlaces,
positionDecimalPlaces,
indicativeVolume,
price,
relativeAsk,
@ -40,6 +43,7 @@ export const OrderbookRow = React.memo(
<Vol
testId={`bid-vol-${price}`}
value={bid}
valueFormatted={addDecimal(bid, positionDecimalPlaces)}
relativeValue={relativeBid}
type={VolumeType.bid}
/>
@ -51,6 +55,7 @@ export const OrderbookRow = React.memo(
<Vol
testId={`ask-vol-${price}`}
value={ask}
valueFormatted={addDecimal(ask, positionDecimalPlaces)}
relativeValue={relativeAsk}
type={VolumeType.ask}
/>

View File

@ -22,6 +22,7 @@ describe('Orderbook', () => {
const result = render(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
{...generateMockData(params)}
onResolutionChange={onResolutionChange}
/>
@ -35,6 +36,7 @@ describe('Orderbook', () => {
const result = render(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
{...generateMockData(params)}
onResolutionChange={onResolutionChange}
/>
@ -44,6 +46,7 @@ describe('Orderbook', () => {
result.rerender(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
{...generateMockData({
...params,
numberOfSellRows: params.numberOfSellRows - 1,
@ -60,6 +63,7 @@ describe('Orderbook', () => {
const result = render(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
{...generateMockData(params)}
onResolutionChange={onResolutionChange}
/>
@ -69,6 +73,7 @@ describe('Orderbook', () => {
result.rerender(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
{...generateMockData({
...params,
bestStaticBidPrice: params.bestStaticBidPrice + 1,
@ -86,6 +91,7 @@ describe('Orderbook', () => {
const result = render(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
{...generateMockData(params)}
onResolutionChange={onResolutionChange}
/>
@ -98,6 +104,7 @@ describe('Orderbook', () => {
result.rerender(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
{...generateMockData({
...params,
numberOfSellRows: params.numberOfSellRows - 1,
@ -114,6 +121,7 @@ describe('Orderbook', () => {
const result = render(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
{...generateMockData(params)}
onResolutionChange={onResolutionChange}
/>
@ -134,6 +142,7 @@ describe('Orderbook', () => {
const result = render(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
{...generateMockData(params)}
onResolutionChange={onResolutionChange}
/>
@ -153,6 +162,7 @@ describe('Orderbook', () => {
result.rerender(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
{...generateMockData({
...params,
resolution: 10,

View File

@ -19,6 +19,7 @@ import { Icon, Splash } from '@vegaprotocol/ui-toolkit';
import type { OrderbookData, OrderbookRowData } from './orderbook-data';
interface OrderbookProps extends OrderbookData {
decimalPlaces: number;
positionDecimalPlaces: number;
resolution: number;
onResolutionChange: (resolution: number) => void;
}
@ -100,6 +101,7 @@ export const Orderbook = ({
indicativeVolume,
indicativePrice,
decimalPlaces,
positionDecimalPlaces,
resolution,
onResolutionChange,
}: OrderbookProps) => {
@ -174,7 +176,10 @@ export const Orderbook = ({
// adjust to current rows position
scrollTop +=
(scrollTopRef.current % rowHeight) - (scrollTop % rowHeight);
const priceCenterScrollOffset = Math.max(0, Math.min(scrollTop));
const priceCenterScrollOffset = Math.max(
0,
Math.min(scrollTop, numberOfRows * rowHeight - viewportHeight)
);
if (scrollTopRef.current !== priceCenterScrollOffset) {
updateScrollOffset(priceCenterScrollOffset);
scrollTopRef.current = priceCenterScrollOffset;
@ -182,7 +187,13 @@ export const Orderbook = ({
}
}
},
[maxPriceLevel, resolution, viewportHeight, updateScrollOffset]
[
maxPriceLevel,
resolution,
viewportHeight,
numberOfRows,
updateScrollOffset,
]
);
useEffect(() => {
@ -197,23 +208,36 @@ export const Orderbook = ({
return;
}
priceInCenter.current = undefined;
setLockOnMidPrice(true);
scrollToPrice(
getPriceLevel(
BigInt(bestStaticOfferPrice) +
(BigInt(bestStaticBidPrice) - BigInt(bestStaticOfferPrice)) /
BigInt(2),
resolution
)
let midPrice = getPriceLevel(
BigInt(bestStaticOfferPrice) +
(BigInt(bestStaticBidPrice) - BigInt(bestStaticOfferPrice)) / BigInt(2),
resolution
);
}, [bestStaticOfferPrice, bestStaticBidPrice, scrollToPrice, resolution]);
if (BigInt(midPrice) > BigInt(maxPriceLevel)) {
midPrice = maxPriceLevel;
} else {
const minPriceLevel =
BigInt(maxPriceLevel) - BigInt(Math.floor(numberOfRows * resolution));
if (BigInt(midPrice) < minPriceLevel) {
midPrice = minPriceLevel.toString();
}
}
scrollToPrice(midPrice);
setLockOnMidPrice(true);
}, [
bestStaticOfferPrice,
bestStaticBidPrice,
scrollToPrice,
resolution,
maxPriceLevel,
numberOfRows,
]);
// adjust scroll position to keep selected price in center
useLayoutEffect(() => {
if (resolutionRef.current !== resolution) {
priceInCenter.current = undefined;
resolutionRef.current = resolution;
setLockOnMidPrice(true);
}
if (priceInCenter.current) {
scrollToPrice(priceInCenter.current);
@ -236,21 +260,19 @@ export const Orderbook = ({
return () => window.removeEventListener('resize', handleResize);
}, []);
const renderedRows = useMemo(() => {
let offset = Math.max(0, Math.round(scrollOffset / rowHeight));
const prependingBufferSize = Math.min(bufferSize, offset);
offset -= prependingBufferSize;
const viewportSize = Math.round(viewportHeight / rowHeight);
const limit = Math.min(
prependingBufferSize + viewportSize + bufferSize,
numberOfRows - offset
);
return {
offset,
limit,
data: getRowsToRender(rows, resolution, offset, limit),
};
}, [rows, scrollOffset, resolution, viewportHeight, numberOfRows]);
let offset = Math.max(0, Math.round(scrollOffset / rowHeight));
const prependingBufferSize = Math.min(bufferSize, offset);
offset -= prependingBufferSize;
const viewportSize = Math.round(viewportHeight / rowHeight);
const limit = Math.min(
prependingBufferSize + viewportSize + bufferSize,
numberOfRows - offset
);
const renderedRows = {
offset,
limit,
data: getRowsToRender(rows, resolution, offset, limit),
};
const paddingTop = renderedRows.offset * rowHeight;
const paddingBottom =
@ -298,6 +320,7 @@ export const Orderbook = ({
<OrderbookRow
price={(BigInt(data.price) / BigInt(resolution)).toString()}
decimalPlaces={decimalPlaces - Math.log10(resolution)}
positionDecimalPlaces={positionDecimalPlaces}
bid={data.bid}
relativeBid={data.relativeBid}
cumulativeBid={data.cumulativeVol.bid}

View File

@ -1,3 +1,4 @@
import produce from 'immer';
import { gql } from '@apollo/client';
import type {
Markets,
@ -90,13 +91,14 @@ const MARKET_DATA_SUB = gql`
}
`;
const update = (draft: Markets_markets[], delta: MarketDataSub_marketData) => {
const index = draft.findIndex((m) => m.id === delta.market.id);
if (index !== -1) {
draft[index].data = delta;
}
// @TODO - else push new market to draft
};
const update = (data: Markets_markets[], delta: MarketDataSub_marketData) =>
produce(data, (draft) => {
const index = draft.findIndex((m) => m.id === delta.market.id);
if (index !== -1) {
draft[index].data = delta;
}
// @TODO - else push new market to draft
});
const getData = (responseData: Markets): Markets_markets[] | null =>
responseData.markets;
const getDelta = (subscriptionData: MarketDataSub): MarketDataSub_marketData =>

View File

@ -52,6 +52,12 @@ export interface OrderFields_market {
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
*/
decimalPlaces: number;
/**
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
*/
positionDecimalPlaces: number;
/**
* An instance of or reference to a tradable instrument.
*/

View File

@ -52,6 +52,12 @@ export interface OrderSub_orders_market {
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
*/
decimalPlaces: number;
/**
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
*/
positionDecimalPlaces: number;
/**
* An instance of or reference to a tradable instrument.
*/

View File

@ -52,6 +52,12 @@ export interface Orders_party_orders_market {
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
*/
decimalPlaces: number;
/**
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
*/
positionDecimalPlaces: number;
/**
* An instance of or reference to a tradable instrument.
*/

View File

@ -25,6 +25,7 @@ const marketOrder: Orders_party_orders = {
id: 'market-id',
name: 'market-name',
decimalPlaces: 2,
positionDecimalPlaces: 0,
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
@ -54,6 +55,7 @@ const limitOrder: Orders_party_orders = {
id: 'market-id',
name: 'market-name',
decimalPlaces: 2,
positionDecimalPlaces: 2,
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
@ -62,11 +64,11 @@ const limitOrder: Orders_party_orders = {
},
},
},
size: '10',
size: '1000',
type: OrderType.Limit,
status: OrderStatus.Active,
side: Side.Sell,
remaining: '5',
remaining: '500',
price: '12345',
timeInForce: OrderTimeInForce.GTT,
createdAt: new Date('2022-3-3').toISOString(),
@ -122,10 +124,10 @@ it('Correct formatting applied for GTT limit order', async () => {
const cells = screen.getAllByRole('gridcell');
const expectedValues = [
limitOrder.market?.tradableInstrument.instrument.code,
'-10',
'-10.00',
limitOrder.type,
limitOrder.status,
'5',
'5.00',
formatNumber(limitOrder.price, limitOrder.market?.decimalPlaces ?? 0),
`${limitOrder.timeInForce}: ${getDateTimeFormat().format(
new Date(limitOrder.expiresAt ?? '')

View File

@ -1,11 +1,17 @@
import { OrderTimeInForce, OrderStatus, Side } from '@vegaprotocol/types';
import type { Orders_party_orders } from './__generated__/Orders';
import { formatNumber, getDateTimeFormat } from '@vegaprotocol/react-helpers';
import {
addDecimal,
formatNumber,
getDateTimeFormat,
t,
} from '@vegaprotocol/react-helpers';
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
import type { ValueFormatterParams } from 'ag-grid-community';
import type { AgGridReact } from 'ag-grid-react';
import { AgGridColumn } from 'ag-grid-react';
import { forwardRef } from 'react';
import BigNumber from 'bignumber.js';
interface OrderListProps {
data: Orders_party_orders[] | null;
@ -23,16 +29,18 @@ export const OrderList = forwardRef<AgGridReact, OrderListProps>(
getRowId={({ data }) => data.id}
>
<AgGridColumn
headerName="Market"
headerName={t('Market')}
field="market.tradableInstrument.instrument.code"
/>
<AgGridColumn
headerName="Amount"
headerName={t('Amount')}
field="size"
cellClass="font-mono"
valueFormatter={({ value, data }: ValueFormatterParams) => {
const prefix = data.side === Side.Buy ? '+' : '-';
return prefix + value;
return (
prefix + addDecimal(value, data.market.positionDecimalPlaces)
);
}}
/>
<AgGridColumn field="type" />
@ -47,11 +55,18 @@ export const OrderList = forwardRef<AgGridReact, OrderListProps>(
}}
/>
<AgGridColumn
headerName="Filled"
headerName={t('Filled')}
field="remaining"
cellClass="font-mono"
valueFormatter={({ data }: ValueFormatterParams) => {
return `${Number(data.size) - Number(data.remaining)}/${data.size}`;
const dps = data.market.positionDecimalPlaces;
const size = new BigNumber(data.size);
const remaining = new BigNumber(data.remaining);
const fills = size.minus(remaining);
return `${addDecimal(fills.toString(), dps)}/${addDecimal(
size.toString(),
dps
)}`;
}}
/>
<AgGridColumn

View File

@ -1,3 +1,4 @@
import produce from 'immer';
import { gql } from '@apollo/client';
import { makeDataProvider } from '@vegaprotocol/react-helpers';
import type { OrderFields } from './__generated__/OrderFields';
@ -13,6 +14,7 @@ const ORDER_FRAGMENT = gql`
id
name
decimalPlaces
positionDecimalPlaces
tradableInstrument {
instrument {
code
@ -77,19 +79,20 @@ export const prepareIncomingOrders = (delta: OrderFields[]) => {
return incoming;
};
const update = (draft: OrderFields[], delta: OrderFields[]) => {
const incoming = prepareIncomingOrders(delta);
const update = (data: OrderFields[], delta: OrderFields[]) =>
produce(data, (draft) => {
const incoming = prepareIncomingOrders(delta);
// Add or update incoming orders
incoming.forEach((order) => {
const index = draft.findIndex((o) => o.id === order.id);
if (index === -1) {
draft.unshift(order);
} else {
draft[index] = order;
}
// Add or update incoming orders
incoming.forEach((order) => {
const index = draft.findIndex((o) => o.id === order.id);
if (index === -1) {
draft.unshift(order);
} else {
draft[index] = order;
}
});
});
};
const getData = (responseData: Orders): Orders_party_orders[] | null =>
responseData?.party?.orders || null;

View File

@ -136,6 +136,12 @@ export interface PositionDetails_market {
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
*/
decimalPlaces: number;
/**
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
*/
positionDecimalPlaces: number;
/**
* An instance of or reference to a tradable instrument.
*/

View File

@ -136,6 +136,12 @@ export interface PositionSubscribe_positions_market {
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
*/
decimalPlaces: number;
/**
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
*/
positionDecimalPlaces: number;
/**
* An instance of or reference to a tradable instrument.
*/

View File

@ -136,6 +136,12 @@ export interface Positions_party_positions_market {
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
*/
decimalPlaces: number;
/**
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
*/
positionDecimalPlaces: number;
/**
* An instance of or reference to a tradable instrument.
*/

View File

@ -1,3 +1,4 @@
import produce from 'immer';
import { gql } from '@apollo/client';
import type {
Positions,
@ -27,6 +28,7 @@ const POSITIONS_FRAGMENT = gql`
}
}
decimalPlaces
positionDecimalPlaces
tradableInstrument {
instrument {
id
@ -74,16 +76,17 @@ export const POSITIONS_SUB = gql`
`;
const update = (
draft: Positions_party_positions[],
data: Positions_party_positions[],
delta: PositionSubscribe_positions
) => {
const index = draft.findIndex((m) => m.market.id === delta.market.id);
if (index !== -1) {
draft[index] = delta;
} else {
draft.push(delta);
}
};
) =>
produce(data, (draft) => {
const index = draft.findIndex((m) => m.market.id === delta.market.id);
if (index !== -1) {
draft[index] = delta;
} else {
draft.push(delta);
}
});
const getData = (responseData: Positions): Positions_party_positions[] | null =>
responseData.party ? responseData.party.positions : null;
const getDelta = (

View File

@ -5,7 +5,7 @@ import { MarketTradingMode } from '@vegaprotocol/types';
const singleRow: Positions_party_positions = {
realisedPNL: '520000000',
openVolume: '100',
openVolume: '10000',
unrealisedPNL: '895000',
averageEntryPrice: '1129935',
market: {
@ -17,6 +17,7 @@ const singleRow: Positions_party_positions = {
__typename: 'MarketData',
market: { __typename: 'Market', id: '123' },
},
positionDecimalPlaces: 2,
decimalPlaces: 5,
tradableInstrument: {
instrument: {
@ -90,7 +91,7 @@ it('Correct formatting applied', async () => {
const cells = screen.getAllByRole('gridcell');
const expectedValues = [
singleRow.market.tradableInstrument.instrument.code,
'+100',
'+100.00',
'11.29935',
'11.38885',
'+5,200.000',

View File

@ -88,8 +88,11 @@ export const PositionsTable = forwardRef<AgGridReact, PositionsTableProps>(
<AgGridColumn
headerName={t('Amount')}
field="openVolume"
valueFormatter={({ value }: PositionsTableValueFormatterParams) =>
volumePrefix(value)
valueFormatter={({
value,
data,
}: PositionsTableValueFormatterParams) =>
volumePrefix(addDecimal(value, data.market.positionDecimalPlaces))
}
/>
<AgGridColumn

View File

@ -1,19 +1,6 @@
import once from 'lodash/once';
import { getUserLocale } from './utils';
/**
* Returns a number prefixed with either a '-' or a '+'. The open volume field
* already comes with a '-' if negative so we only need to actually prefix if
* its a positive value
*/
export function volumePrefix(value: string): string {
if (value === '0' || value.startsWith('-')) {
return value;
}
return '+' + value;
}
export const getTimeFormat = once(
() =>
new Intl.DateTimeFormat(getUserLocale(), {

Some files were not shown because too many files have changed in this diff Show More