Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9908003ba | ||
|
|
1f9af79215 | ||
|
|
e31e40a7ef | ||
|
|
81f6b3cc15 | ||
|
|
8adb208a91 | ||
|
|
545c3a17d2 | ||
|
|
ad76988f63 | ||
|
|
d2bbd7e1fc | ||
|
|
fb1ebb3bdf | ||
|
|
b2489537ef | ||
|
|
382a7ea411 | ||
|
|
1ae2b4c153 | ||
|
|
e8875e817e | ||
|
|
4a01c880f3 | ||
|
|
f7f00dc7bb | ||
|
|
d151b6e923 | ||
|
|
8f8e9c1061 | ||
|
|
b40358a723 | ||
|
|
01f0934da3 | ||
|
|
df7755dbc4 | ||
|
|
9073234040 | ||
|
|
053cd0fa27 | ||
|
|
961dc88dc7 | ||
|
|
b16607a844 | ||
|
|
d0d804631c | ||
|
|
3e778a88dc | ||
|
|
dbb09c9c79 | ||
|
|
06f44b67de | ||
|
|
1861852852 | ||
|
|
3ee0eee80d | ||
|
|
69ce870a81 | ||
|
|
d8467c3206 | ||
|
|
de87f40a01 |
@@ -64,12 +64,11 @@ jobs:
|
||||
######
|
||||
|
||||
- name: Run Cypress tests
|
||||
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
|
||||
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome --env.grepTags="${{ inputs.tags }}"
|
||||
working-directory: frontend-monorepo
|
||||
env:
|
||||
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
||||
CYPRESS_VEGA_WALLET_API_TOKEN: ${{ steps.setup-vega.outputs.token }}
|
||||
CYPRESS_grepTags: ${{ inputs.tags }}
|
||||
|
||||
######
|
||||
## Upload logs
|
||||
|
||||
@@ -8,14 +8,16 @@ jobs:
|
||||
lint_pr:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Use Node.js 16
|
||||
id: Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16.14.0
|
||||
- name: Install commitlint cli and config
|
||||
run: npm install @commitlint/cli @commitlint/config-conventional
|
||||
- name: Create config
|
||||
run: echo "module.exports = {extends:['@commitlint/config-conventional']};" > commitlint.config.js
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
- name: Check PR title
|
||||
run: echo "${{ github.event.pull_request.title }}" | npx commitlint
|
||||
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Main } from './components/main';
|
||||
import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-websocket-provider';
|
||||
import type { InMemoryCacheConfig } from '@apollo/client';
|
||||
import { Footer } from './components/footer/footer';
|
||||
import { AnnouncementBanner, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
function App() {
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
@@ -40,6 +41,15 @@ function App() {
|
||||
return (
|
||||
<TendermintWebsocketProvider>
|
||||
<NetworkLoader cache={cacheConfig}>
|
||||
<AnnouncementBanner>
|
||||
<div className="font-alpha calt uppercase text-center text-lg text-white">
|
||||
<span className="pr-4">The Mainnet sims are live!</span>
|
||||
<ExternalLink href="https://fairground.wtf/">
|
||||
Come help stress test the network
|
||||
</ExternalLink>
|
||||
</div>
|
||||
</AnnouncementBanner>
|
||||
|
||||
<div className={layoutClasses}>
|
||||
<Header menuOpen={menuOpen} setMenuOpen={setMenuOpen} />
|
||||
<Nav menuOpen={menuOpen} />
|
||||
|
||||
@@ -63,7 +63,7 @@ export const TxDataView = ({ txData, blockData }: TxDataViewProps) => {
|
||||
<Select
|
||||
placeholder="View as..."
|
||||
onChange={(v) => setShowTxData(v.target.value as ShowTxDataType)}
|
||||
value={'JSON'}
|
||||
value={showTxData}
|
||||
>
|
||||
<option value={'JSON'}>JSON</option>
|
||||
<option value={'base64'}>Base64</option>
|
||||
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
BlockExplorerTransactions,
|
||||
} from '../routes/types/block-explorer-response';
|
||||
import { DATA_SOURCES } from '../config';
|
||||
import isNumber from 'lodash/isNumber';
|
||||
|
||||
export interface TxsStateProps {
|
||||
txsData: BlockExplorerTransactionResult[];
|
||||
@@ -54,15 +55,15 @@ export const useTxsData = ({ limit, filters }: IUseTxsData) => {
|
||||
} = useFetch<BlockExplorerTransactions>(url, {}, false);
|
||||
|
||||
useEffect(() => {
|
||||
if (data?.transactions?.length) {
|
||||
if (data && isNumber(data?.transactions?.length)) {
|
||||
setTxsState((prev) => ({
|
||||
txsData: [...prev.txsData, ...data.transactions],
|
||||
hasMoreTxs: true,
|
||||
hasMoreTxs: data.transactions.length > 0,
|
||||
lastCursor:
|
||||
data.transactions[data.transactions.length - 1].cursor || '',
|
||||
data.transactions[data.transactions.length - 1]?.cursor || '',
|
||||
}));
|
||||
}
|
||||
}, [setTxsState, data?.transactions]);
|
||||
}, [setTxsState, data]);
|
||||
|
||||
const loadTxs = useCallback(() => {
|
||||
return refetch({
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
@@ -1,11 +1,77 @@
|
||||
[
|
||||
{
|
||||
"tranche_id": 50,
|
||||
"tranche_start": "2023-10-01T00:00:00.000Z",
|
||||
"tranche_end": "2024-04-01T00:00:00.000Z",
|
||||
"total_added": "2500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "2500",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
"user": "0x6ad69157EfB1E17EBf6614D352D098589EaE3060",
|
||||
"tx": "0x0e229459260c2e74579e12e05ffd21cb4e470e3a4eacf85b7f924778b4f1c8a6"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"users": [
|
||||
{
|
||||
"address": "0x6ad69157EfB1E17EBf6614D352D098589EaE3060",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
"user": "0x6ad69157EfB1E17EBf6614D352D098589EaE3060",
|
||||
"tranche_id": 50,
|
||||
"tx": "0x0e229459260c2e74579e12e05ffd21cb4e470e3a4eacf85b7f924778b4f1c8a6"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "2500",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "2500"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tranche_id": 51,
|
||||
"tranche_start": "2024-01-01T00:00:00.000Z",
|
||||
"tranche_end": "2024-07-01T00:00:00.000Z",
|
||||
"total_added": "2500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "2500",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
"user": "0x6ad69157EfB1E17EBf6614D352D098589EaE3060",
|
||||
"tx": "0x0e229459260c2e74579e12e05ffd21cb4e470e3a4eacf85b7f924778b4f1c8a6"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"users": [
|
||||
{
|
||||
"address": "0x6ad69157EfB1E17EBf6614D352D098589EaE3060",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
"user": "0x6ad69157EfB1E17EBf6614D352D098589EaE3060",
|
||||
"tranche_id": 51,
|
||||
"tx": "0x0e229459260c2e74579e12e05ffd21cb4e470e3a4eacf85b7f924778b4f1c8a6"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "2500",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "2500"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tranche_id": 49,
|
||||
"tranche_start": "2022-12-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "86666.297",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "73487.251446645509463922",
|
||||
"locked_amount": "72537.154027859368347703",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "86666.297",
|
||||
@@ -71,7 +137,7 @@
|
||||
"tranche_end": "2023-06-01T00:00:00.000Z",
|
||||
"total_added": "2500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "1682.6333244301995",
|
||||
"locked_amount": "1627.66919134106625",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
@@ -265,12 +331,34 @@
|
||||
"tranche_id": 42,
|
||||
"tranche_start": "2023-07-01T00:00:00.000Z",
|
||||
"tranche_end": "2024-01-01T00:00:00.000Z",
|
||||
"total_added": "0",
|
||||
"total_added": "2500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "0",
|
||||
"deposits": [],
|
||||
"locked_amount": "2500",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
"user": "0x6ad69157EfB1E17EBf6614D352D098589EaE3060",
|
||||
"tx": "0x0e229459260c2e74579e12e05ffd21cb4e470e3a4eacf85b7f924778b4f1c8a6"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"users": []
|
||||
"users": [
|
||||
{
|
||||
"address": "0x6ad69157EfB1E17EBf6614D352D098589EaE3060",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
"user": "0x6ad69157EfB1E17EBf6614D352D098589EaE3060",
|
||||
"tranche_id": 42,
|
||||
"tx": "0x0e229459260c2e74579e12e05ffd21cb4e470e3a4eacf85b7f924778b4f1c8a6"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "2500",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "2500"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tranche_id": 43,
|
||||
@@ -397,7 +485,7 @@
|
||||
"tranche_end": "2023-08-01T00:00:00.000Z",
|
||||
"total_added": "37500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "37500",
|
||||
"locked_amount": "37188.0491290669125",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -450,7 +538,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "129999.45",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "73420.20357622098315111",
|
||||
"locked_amount": "72470.97300178364112351",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129999.45",
|
||||
@@ -516,7 +604,7 @@
|
||||
"tranche_end": "2023-09-03T00:00:00.000Z",
|
||||
"total_added": "62600",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "37130.49642947742434",
|
||||
"locked_amount": "36444.23082825976788",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10000",
|
||||
@@ -709,7 +797,7 @@
|
||||
"tranche_end": "2023-09-17T00:00:00.000Z",
|
||||
"total_added": "5000",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "3157.4754249112125",
|
||||
"locked_amount": "3102.661878488077",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "5000",
|
||||
@@ -920,7 +1008,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "97499.58",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "15240.5819298544871083824",
|
||||
"locked_amount": "14309.4751611591714224046",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "97499.58",
|
||||
@@ -953,7 +1041,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "135173.4239508",
|
||||
"total_removed": "98230.390980249184455396",
|
||||
"locked_amount": "20831.244321407448710024671284",
|
||||
"locked_amount": "19558.58211747851579304108696",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "135173.4239508",
|
||||
@@ -999,7 +1087,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "32499.86",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "6411.4496271174975967098",
|
||||
"locked_amount": "6019.749088881220610994",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "32499.86",
|
||||
@@ -1032,7 +1120,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "10833.29",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "2086.8646383922243299952",
|
||||
"locked_amount": "1959.369914168368365833",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10833.29",
|
||||
@@ -1065,7 +1153,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "22749.93",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "7801.1661111092940288519",
|
||||
"locked_amount": "7324.562356528141179063",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "6500",
|
||||
@@ -1203,8 +1291,8 @@
|
||||
"tranche_start": "2022-11-01T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-01T00:00:00.000Z",
|
||||
"total_added": "22500",
|
||||
"total_removed": "3707.308452225",
|
||||
"locked_amount": "11373.775610036832",
|
||||
"total_removed": "3853.26264195",
|
||||
"locked_amount": "10876.365389042358075",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -1223,6 +1311,11 @@
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x3bd3579f34ddc1eee597ba9b3fbbf18b6c268d085cd299e964b7239b2434fcf3"
|
||||
},
|
||||
{
|
||||
"amount": "145.954189725",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x702e76a6868be327dcce3416fa163759a406b68600063473106afdb555f03db4"
|
||||
},
|
||||
{
|
||||
"amount": "305.3119245",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -1292,6 +1385,12 @@
|
||||
"tranche_id": 33,
|
||||
"tx": "0x3bd3579f34ddc1eee597ba9b3fbbf18b6c268d085cd299e964b7239b2434fcf3"
|
||||
},
|
||||
{
|
||||
"amount": "145.954189725",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 33,
|
||||
"tx": "0x702e76a6868be327dcce3416fa163759a406b68600063473106afdb555f03db4"
|
||||
},
|
||||
{
|
||||
"amount": "305.3119245",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -1354,8 +1453,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "7500",
|
||||
"withdrawn_tokens": "3707.308452225",
|
||||
"remaining_tokens": "3792.691547775"
|
||||
"withdrawn_tokens": "3853.26264195",
|
||||
"remaining_tokens": "3646.73735805"
|
||||
},
|
||||
{
|
||||
"address": "0x2539b51EbDE65a75672aBcfE9439a706a99D18D1",
|
||||
@@ -1380,7 +1479,7 @@
|
||||
"tranche_end": "2023-06-02T00:00:00.000Z",
|
||||
"total_added": "1939928.38",
|
||||
"total_removed": "928642.9598472029154",
|
||||
"locked_amount": "656363.903872495430316328",
|
||||
"locked_amount": "635097.0330095579571042166",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1852091.69",
|
||||
@@ -1732,7 +1831,7 @@
|
||||
"tranche_end": "2023-02-01T00:00:00.000Z",
|
||||
"total_added": "42500",
|
||||
"total_removed": "24434.0787288",
|
||||
"locked_amount": "576.45383579911392",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "12500",
|
||||
@@ -1830,7 +1929,7 @@
|
||||
"tranche_start": "2021-09-03T00:00:00.000Z",
|
||||
"tranche_end": "2022-03-03T00:00:00.000Z",
|
||||
"total_added": "3145.41",
|
||||
"total_removed": "1726.74",
|
||||
"total_removed": "1736.74",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
@@ -1995,6 +2094,11 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "10",
|
||||
"user": "0x4cBC0C88d8FE503f62823B42f30a4900292C13bE",
|
||||
"tx": "0xa0ad93f116b5a6098ceda7e07141f806a90d5fb94f0c0555ac7049709a7fb3b7"
|
||||
},
|
||||
{
|
||||
"amount": "20",
|
||||
"user": "0xE9F41a0090fcc7eaf626037003AAD44B17098E7C",
|
||||
@@ -2241,10 +2345,17 @@
|
||||
"tx": "0xf6ffe87368413b25eb480d979745c5f7c32444318abb1c75e0c3bf3dba3410cd"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "10",
|
||||
"user": "0x4cBC0C88d8FE503f62823B42f30a4900292C13bE",
|
||||
"tranche_id": 12,
|
||||
"tx": "0xa0ad93f116b5a6098ceda7e07141f806a90d5fb94f0c0555ac7049709a7fb3b7"
|
||||
}
|
||||
],
|
||||
"total_tokens": "10",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "10"
|
||||
"withdrawn_tokens": "10",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0xF3638a47940B4d8c4b7F0AabB44Dc6DB8313a03A",
|
||||
@@ -6722,8 +6833,8 @@
|
||||
"tranche_id": 11,
|
||||
"tranche_start": "2021-09-03T00:00:00.000Z",
|
||||
"tranche_end": "2022-09-03T00:00:00.000Z",
|
||||
"total_added": "53995.000000000000000003",
|
||||
"total_removed": "42939.21518131551",
|
||||
"total_added": "54025.000000000000000003",
|
||||
"total_removed": "43035.21518131551",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
@@ -6781,6 +6892,16 @@
|
||||
"user": "0xa7d3D2CC58e1E82e3ff2C2Cd3B750442522aBbfb",
|
||||
"tx": "0x6957b2bd0f9f04f7cc124c11638be50ff5e2a26412e0be0c16f7aac1f1b73bc6"
|
||||
},
|
||||
{
|
||||
"amount": "15",
|
||||
"user": "0xB12Cdb63E38f9a6ff2C0F68aBC3CA9beFCb7148c",
|
||||
"tx": "0x7a0b7cc2723724de05fc2185b23021413450f47d40e27bcfa6b26f0872e94c9f"
|
||||
},
|
||||
{
|
||||
"amount": "15",
|
||||
"user": "0xB12Cdb63E38f9a6ff2C0F68aBC3CA9beFCb7148c",
|
||||
"tx": "0xcbf45579767dff34e84484629ee3fb3355232245f30ad259443e3864db80a707"
|
||||
},
|
||||
{
|
||||
"amount": "20",
|
||||
"user": "0xB12Cdb63E38f9a6ff2C0F68aBC3CA9beFCb7148c",
|
||||
@@ -16728,6 +16849,11 @@
|
||||
"user": "0xa10aD7E7712617fc4ABe0811D8a30fD96cE48F9f",
|
||||
"tx": "0x7ffe3e795b50a8449052143a739d53aec81c2f53c7981f31496b8c121bd4ec81"
|
||||
},
|
||||
{
|
||||
"amount": "96",
|
||||
"user": "0x4cBC0C88d8FE503f62823B42f30a4900292C13bE",
|
||||
"tx": "0x51d8ec749dbb4148d170869bca8a6b8ce679bfea0686f9582c3a58f3f31fd77a"
|
||||
},
|
||||
{
|
||||
"amount": "200",
|
||||
"user": "0xa7d3D2CC58e1E82e3ff2C2Cd3B750442522aBbfb",
|
||||
@@ -17799,6 +17925,18 @@
|
||||
{
|
||||
"address": "0xB12Cdb63E38f9a6ff2C0F68aBC3CA9beFCb7148c",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "15",
|
||||
"user": "0xB12Cdb63E38f9a6ff2C0F68aBC3CA9beFCb7148c",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x7a0b7cc2723724de05fc2185b23021413450f47d40e27bcfa6b26f0872e94c9f"
|
||||
},
|
||||
{
|
||||
"amount": "15",
|
||||
"user": "0xB12Cdb63E38f9a6ff2C0F68aBC3CA9beFCb7148c",
|
||||
"tranche_id": 11,
|
||||
"tx": "0xcbf45579767dff34e84484629ee3fb3355232245f30ad259443e3864db80a707"
|
||||
},
|
||||
{
|
||||
"amount": "20",
|
||||
"user": "0xB12Cdb63E38f9a6ff2C0F68aBC3CA9beFCb7148c",
|
||||
@@ -18570,9 +18708,9 @@
|
||||
"tx": "0x6940787f6ceaac0846e69f1bc93ad9efee8c39774b91ea29f84328ae64fc9969"
|
||||
}
|
||||
],
|
||||
"total_tokens": "2600",
|
||||
"total_tokens": "2630",
|
||||
"withdrawn_tokens": "2585",
|
||||
"remaining_tokens": "15"
|
||||
"remaining_tokens": "45"
|
||||
},
|
||||
{
|
||||
"address": "0xE9F41a0090fcc7eaf626037003AAD44B17098E7C",
|
||||
@@ -30450,10 +30588,17 @@
|
||||
"tx": "0xe7518eaa0fe2385aec5ab0f8617ba0b62d71d82e8be39586763020ec04c98422"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "96",
|
||||
"user": "0x4cBC0C88d8FE503f62823B42f30a4900292C13bE",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x51d8ec749dbb4148d170869bca8a6b8ce679bfea0686f9582c3a58f3f31fd77a"
|
||||
}
|
||||
],
|
||||
"total_tokens": "96",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "96"
|
||||
"withdrawn_tokens": "96",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0xaf487ccD027742705EC1B2DD1adCFAb0eBccDeAb",
|
||||
@@ -33294,8 +33439,8 @@
|
||||
"tranche_start": "2022-03-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "3732368.4671",
|
||||
"total_removed": "442882.3484327902809",
|
||||
"locked_amount": "1033104.123341510407167357286",
|
||||
"total_removed": "589730.8667090699299",
|
||||
"locked_amount": "1000424.34716318809300120353",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1998.95815",
|
||||
@@ -33464,6 +33609,16 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "144779.049152",
|
||||
"user": "0x1da69E9C22d77Ef8Ccbf5a1F2d83eDBc5Dcc20fA",
|
||||
"tx": "0x0b7e2937cd20679a8b18424808e50d0bfa356895b08fcac7afeb5166214a6134"
|
||||
},
|
||||
{
|
||||
"amount": "2069.469124279649",
|
||||
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
|
||||
"tx": "0x8a19d30e4686bca650aa1c4e84a82d8a16d607e07828706cb758a6e17cab0190"
|
||||
},
|
||||
{
|
||||
"amount": "2536.282963529438",
|
||||
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
|
||||
@@ -33813,6 +33968,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "2069.469124279649",
|
||||
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
|
||||
"tranche_id": 1,
|
||||
"tx": "0x8a19d30e4686bca650aa1c4e84a82d8a16d607e07828706cb758a6e17cab0190"
|
||||
},
|
||||
{
|
||||
"amount": "2536.282963529438",
|
||||
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
|
||||
@@ -34079,8 +34240,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "187637.95",
|
||||
"withdrawn_tokens": "134424.6460800270605",
|
||||
"remaining_tokens": "53213.3039199729395"
|
||||
"withdrawn_tokens": "136494.1152043067095",
|
||||
"remaining_tokens": "51143.8347956932905"
|
||||
},
|
||||
{
|
||||
"address": "0x1A71e3ED1996CAbB91bB043f880CE963D601707e",
|
||||
@@ -34184,10 +34345,17 @@
|
||||
"tx": "0xeb14f907c987ad54eed8697ec95c8a674c9034a4cbee43b013f947bb0e398ce5"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "144779.049152",
|
||||
"user": "0x1da69E9C22d77Ef8Ccbf5a1F2d83eDBc5Dcc20fA",
|
||||
"tranche_id": 1,
|
||||
"tx": "0x0b7e2937cd20679a8b18424808e50d0bfa356895b08fcac7afeb5166214a6134"
|
||||
}
|
||||
],
|
||||
"total_tokens": "200000",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "200000"
|
||||
"withdrawn_tokens": "144779.049152",
|
||||
"remaining_tokens": "55220.950848"
|
||||
},
|
||||
{
|
||||
"address": "0x4d50f66eF38892248Bb4Badbbf993dE965BDb029",
|
||||
@@ -34586,8 +34754,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "15870102.715470999700000001",
|
||||
"total_removed": "549182.48543502092691952",
|
||||
"locked_amount": "8963008.4753852283836950014010192461651798",
|
||||
"total_removed": "553068.12935216697830452",
|
||||
"locked_amount": "8847128.0872990775682462500282478416234118",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "16249.93",
|
||||
@@ -35101,6 +35269,31 @@
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x6c49f9f742a84f7889b90e6f978f3fb1f642ea447f737f348b3fac91716b9717"
|
||||
},
|
||||
{
|
||||
"amount": "687.93046004616176",
|
||||
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
|
||||
"tx": "0x137cf963adc7f889f2b24bb3d55716cb6b8581bf13040f13e65f1d16c52e2f9f"
|
||||
},
|
||||
{
|
||||
"amount": "1412.763584",
|
||||
"user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37",
|
||||
"tx": "0x606ddaa3882cccb0062bc2827cfcfceb64cef8a6c4df41d06747ae651e5dd52e"
|
||||
},
|
||||
{
|
||||
"amount": "113.697899560567",
|
||||
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
|
||||
"tx": "0xeb5f2401c9402d58fa4a7549ce2045a48a2c3b90ec6e812ca2f0059f1275e213"
|
||||
},
|
||||
{
|
||||
"amount": "1102.899782241316125",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x6a0a62bebbd8dbc54bb67ab842f6fc121d8ca4fab087e2779a089007ce6b0b20"
|
||||
},
|
||||
{
|
||||
"amount": "568.3521912980065",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x374feedb0a834a85c280bc2d0d021b727c4d7b303ac035bca381e1f1e7cd662e"
|
||||
},
|
||||
{
|
||||
"amount": "858.360074993579125",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -36690,6 +36883,18 @@
|
||||
"tranche_id": 2,
|
||||
"tx": "0x6c49f9f742a84f7889b90e6f978f3fb1f642ea447f737f348b3fac91716b9717"
|
||||
},
|
||||
{
|
||||
"amount": "1102.899782241316125",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x6a0a62bebbd8dbc54bb67ab842f6fc121d8ca4fab087e2779a089007ce6b0b20"
|
||||
},
|
||||
{
|
||||
"amount": "568.3521912980065",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x374feedb0a834a85c280bc2d0d021b727c4d7b303ac035bca381e1f1e7cd662e"
|
||||
},
|
||||
{
|
||||
"amount": "858.360074993579125",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -37778,8 +37983,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "259998.8875",
|
||||
"withdrawn_tokens": "113142.013429259527625",
|
||||
"remaining_tokens": "146856.874070740472375"
|
||||
"withdrawn_tokens": "114813.26540279885025",
|
||||
"remaining_tokens": "145185.62209720114975"
|
||||
},
|
||||
{
|
||||
"address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c",
|
||||
@@ -38006,6 +38211,12 @@
|
||||
"tranche_id": 2,
|
||||
"tx": "0x7882fc86536accee89368b825b374eb365ee5f051cb89fb3710c7e2d24b0d29d"
|
||||
},
|
||||
{
|
||||
"amount": "687.93046004616176",
|
||||
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x137cf963adc7f889f2b24bb3d55716cb6b8581bf13040f13e65f1d16c52e2f9f"
|
||||
},
|
||||
{
|
||||
"amount": "1293.67099136315494",
|
||||
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
|
||||
@@ -38206,8 +38417,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "150551.801",
|
||||
"withdrawn_tokens": "65072.74657224015982",
|
||||
"remaining_tokens": "85479.05442775984018"
|
||||
"withdrawn_tokens": "65760.67703228632158",
|
||||
"remaining_tokens": "84791.12396771367842"
|
||||
},
|
||||
{
|
||||
"address": "0x4d982Ab0823fD2f48e934a7be2bb0a5374a26148",
|
||||
@@ -38409,6 +38620,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "1412.763584",
|
||||
"user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x606ddaa3882cccb0062bc2827cfcfceb64cef8a6c4df41d06747ae651e5dd52e"
|
||||
},
|
||||
{
|
||||
"amount": "1099.300488",
|
||||
"user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37",
|
||||
@@ -38591,8 +38808,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "200000",
|
||||
"withdrawn_tokens": "86015.962928",
|
||||
"remaining_tokens": "113984.037072"
|
||||
"withdrawn_tokens": "87428.726512",
|
||||
"remaining_tokens": "112571.273488"
|
||||
},
|
||||
{
|
||||
"address": "0x1b956E6c00E238194B331eddEFF72Cb5f28A8d01",
|
||||
@@ -39052,6 +39269,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "113.697899560567",
|
||||
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
|
||||
"tranche_id": 2,
|
||||
"tx": "0xeb5f2401c9402d58fa4a7549ce2045a48a2c3b90ec6e812ca2f0059f1275e213"
|
||||
},
|
||||
{
|
||||
"amount": "139.3487773806265",
|
||||
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
|
||||
@@ -39300,8 +39523,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "12362.05",
|
||||
"withdrawn_tokens": "5310.2045398579465",
|
||||
"remaining_tokens": "7051.8454601420535"
|
||||
"withdrawn_tokens": "5423.9024394185135",
|
||||
"remaining_tokens": "6938.1475605814865"
|
||||
},
|
||||
{
|
||||
"address": "0xb091D456d0dFCB94dcba6f355379056C5bb995fC",
|
||||
@@ -39932,8 +40155,8 @@
|
||||
"tranche_start": "2021-11-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-05T00:00:00.000Z",
|
||||
"total_added": "14597706.0446472999",
|
||||
"total_removed": "3709441.39326687814680893",
|
||||
"locked_amount": "2553146.968835877717601199418901287",
|
||||
"total_removed": "3711762.46803043411726343",
|
||||
"locked_amount": "2446166.93445800685782748312503739",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129284.449",
|
||||
@@ -40147,6 +40370,16 @@
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0xc8aae35d9d474b83dd5524de9db59f994fd77040397c00a1a4cf30a5c9315826"
|
||||
},
|
||||
{
|
||||
"amount": "1535.17244264446063625",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0x7d23b7beca87dac22f754a5d6b367079b813549a87bb547a4c3e08046fc23846"
|
||||
},
|
||||
{
|
||||
"amount": "785.90232091150981825",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0x0552a16f5a65f3ea47db290b80f164d6553717dd735e73bb0429b81e17bbbb3e"
|
||||
},
|
||||
{
|
||||
"amount": "8950.14985089483210984",
|
||||
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
|
||||
@@ -42954,6 +43187,18 @@
|
||||
"tranche_id": 3,
|
||||
"tx": "0xc8aae35d9d474b83dd5524de9db59f994fd77040397c00a1a4cf30a5c9315826"
|
||||
},
|
||||
{
|
||||
"amount": "1535.17244264446063625",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0x7d23b7beca87dac22f754a5d6b367079b813549a87bb547a4c3e08046fc23846"
|
||||
},
|
||||
{
|
||||
"amount": "785.90232091150981825",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0x0552a16f5a65f3ea47db290b80f164d6553717dd735e73bb0429b81e17bbbb3e"
|
||||
},
|
||||
{
|
||||
"amount": "1192.05386354121365675",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@@ -45344,8 +45589,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "359123.469575",
|
||||
"withdrawn_tokens": "296283.340785656990038",
|
||||
"remaining_tokens": "62840.128789343009962"
|
||||
"withdrawn_tokens": "298604.4155492129604925",
|
||||
"remaining_tokens": "60519.0540257870395075"
|
||||
},
|
||||
{
|
||||
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
|
||||
@@ -46655,8 +46900,8 @@
|
||||
"tranche_start": "2021-10-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "5778205.3912159303",
|
||||
"total_removed": "2622261.560853924298939789",
|
||||
"locked_amount": "691860.405151183386025619771012724",
|
||||
"total_removed": "2720584.477569657792162642",
|
||||
"locked_amount": "649591.946558625470488911658628152",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "552496.6455",
|
||||
@@ -46800,6 +47045,36 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "19117.297184565582142",
|
||||
"user": "0x1dD2718fd01d05C9F50Fce8Bb723A4C7483A1E15",
|
||||
"tx": "0xf86662bab80d05690accd866da9bbe8e7a82e1b62133350789d7a863f1019211"
|
||||
},
|
||||
{
|
||||
"amount": "4217.129347329502683",
|
||||
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
|
||||
"tx": "0x687f74292db1a9d0c79bedca56eb5dd57d5d338a2d536b355cd2d1022dc4889b"
|
||||
},
|
||||
{
|
||||
"amount": "52477.45638404822374",
|
||||
"user": "0x83b1a48376E045D26420200345414e6b93066396",
|
||||
"tx": "0x8ef3d71e781d7e16dc337620776e044a6e914dc3074109837336941b634ffd61"
|
||||
},
|
||||
{
|
||||
"amount": "18757.845956872719119701",
|
||||
"user": "0xC24da173A250e9Ca5c54870639EbE5f88be5102d",
|
||||
"tx": "0xcdaa0ab119158f2731c0cb7a799ccf34558ac31b643729af102801152247b2d2"
|
||||
},
|
||||
{
|
||||
"amount": "1.402852498117196502",
|
||||
"user": "0xC24da173A250e9Ca5c54870639EbE5f88be5102d",
|
||||
"tx": "0xfae37b3119bf4c1718b13a78a1a3d7fd25c760691f6cc9d52eba3b2ac3d04ec5"
|
||||
},
|
||||
{
|
||||
"amount": "3751.78499041934834165",
|
||||
"user": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D",
|
||||
"tx": "0x47eb4c897187630f558845180b019d4c5c1816efd91abf3db4964ed14eea5efd"
|
||||
},
|
||||
{
|
||||
"amount": "3634.58269967002683",
|
||||
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
|
||||
@@ -47602,6 +47877,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "19117.297184565582142",
|
||||
"user": "0x1dD2718fd01d05C9F50Fce8Bb723A4C7483A1E15",
|
||||
"tranche_id": 4,
|
||||
"tx": "0xf86662bab80d05690accd866da9bbe8e7a82e1b62133350789d7a863f1019211"
|
||||
},
|
||||
{
|
||||
"amount": "376.2625308599198808",
|
||||
"user": "0x1dD2718fd01d05C9F50Fce8Bb723A4C7483A1E15",
|
||||
@@ -47610,8 +47891,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "22099.90582",
|
||||
"withdrawn_tokens": "376.2625308599198808",
|
||||
"remaining_tokens": "21723.6432891400801192"
|
||||
"withdrawn_tokens": "19493.5597154255020228",
|
||||
"remaining_tokens": "2606.3461045744979772"
|
||||
},
|
||||
{
|
||||
"address": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
|
||||
@@ -47813,6 +48094,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "3751.78499041934834165",
|
||||
"user": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D",
|
||||
"tranche_id": 4,
|
||||
"tx": "0x47eb4c897187630f558845180b019d4c5c1816efd91abf3db4964ed14eea5efd"
|
||||
},
|
||||
{
|
||||
"amount": "3672.33735125894336105",
|
||||
"user": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D",
|
||||
@@ -47893,8 +48180,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "92082.572555",
|
||||
"withdrawn_tokens": "77880.2646886437186477",
|
||||
"remaining_tokens": "14202.3078663562813523"
|
||||
"withdrawn_tokens": "81632.04967906306698935",
|
||||
"remaining_tokens": "10450.52287593693301065"
|
||||
},
|
||||
{
|
||||
"address": "0x1dC9B91DE003fd503F25cB5d114cf0fc68F7aFe6",
|
||||
@@ -47922,6 +48209,18 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "18757.845956872719119701",
|
||||
"user": "0xC24da173A250e9Ca5c54870639EbE5f88be5102d",
|
||||
"tranche_id": 4,
|
||||
"tx": "0xcdaa0ab119158f2731c0cb7a799ccf34558ac31b643729af102801152247b2d2"
|
||||
},
|
||||
{
|
||||
"amount": "1.402852498117196502",
|
||||
"user": "0xC24da173A250e9Ca5c54870639EbE5f88be5102d",
|
||||
"tranche_id": 4,
|
||||
"tx": "0xfae37b3119bf4c1718b13a78a1a3d7fd25c760691f6cc9d52eba3b2ac3d04ec5"
|
||||
},
|
||||
{
|
||||
"amount": "18362.008706688844354071",
|
||||
"user": "0xC24da173A250e9Ca5c54870639EbE5f88be5102d",
|
||||
@@ -48020,8 +48319,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "460415.072915097",
|
||||
"withdrawn_tokens": "389402.491279555911199683",
|
||||
"remaining_tokens": "71012.581635541088800317"
|
||||
"withdrawn_tokens": "408161.740088926747515886",
|
||||
"remaining_tokens": "52253.332826170252484114"
|
||||
},
|
||||
{
|
||||
"address": "0xd66e4853c0880df150e7329974715BFC8d2da47D",
|
||||
@@ -48090,6 +48389,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "52477.45638404822374",
|
||||
"user": "0x83b1a48376E045D26420200345414e6b93066396",
|
||||
"tranche_id": 4,
|
||||
"tx": "0x8ef3d71e781d7e16dc337620776e044a6e914dc3074109837336941b634ffd61"
|
||||
},
|
||||
{
|
||||
"amount": "78729.23106762397314",
|
||||
"user": "0x83b1a48376E045D26420200345414e6b93066396",
|
||||
@@ -48146,8 +48451,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "1104995.291",
|
||||
"withdrawn_tokens": "926865.56004188459769",
|
||||
"remaining_tokens": "178129.73095811540231"
|
||||
"withdrawn_tokens": "979343.01642593282143",
|
||||
"remaining_tokens": "125652.27457406717857"
|
||||
},
|
||||
{
|
||||
"address": "0x5565d64f29Ea17355106DF3bA5903Eb793B3e139",
|
||||
@@ -48224,6 +48529,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "4217.129347329502683",
|
||||
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
|
||||
"tranche_id": 4,
|
||||
"tx": "0x687f74292db1a9d0c79bedca56eb5dd57d5d338a2d536b355cd2d1022dc4889b"
|
||||
},
|
||||
{
|
||||
"amount": "3634.58269967002683",
|
||||
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
|
||||
@@ -48454,8 +48765,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "331498.5873",
|
||||
"withdrawn_tokens": "288277.339276030741737",
|
||||
"remaining_tokens": "43221.248023969258263"
|
||||
"withdrawn_tokens": "292494.46862336024442",
|
||||
"remaining_tokens": "39004.11867663975558"
|
||||
},
|
||||
{
|
||||
"address": "0x16da609341ed67750A8BCC5AAa2005471006Cd77",
|
||||
@@ -48550,8 +48861,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "472355.6199999996",
|
||||
"total_removed": "31616.1712341930685",
|
||||
"locked_amount": "163701.253818397273052118746829",
|
||||
"total_removed": "31923.1301021472685",
|
||||
"locked_amount": "158522.95647737743991233846067988",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "3000",
|
||||
@@ -55170,6 +55481,26 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "13.1116203702",
|
||||
"user": "0x4cBC0C88d8FE503f62823B42f30a4900292C13bE",
|
||||
"tx": "0xf712a2417c5e58f65ac39422766fd902301f905f41e9eed0dc097e1dfa641b1c"
|
||||
},
|
||||
{
|
||||
"amount": "262.76406646",
|
||||
"user": "0xD3ec605d078326B0a636ca90d496Ebb5Eb457a27",
|
||||
"tx": "0xc3734fbb0982f35d4add052e69d6b997f92364ac75654253f4abdc62a4245d1e"
|
||||
},
|
||||
{
|
||||
"amount": "9.342237444",
|
||||
"user": "0x479F059c46c6873C6B970A92911084b3eA036d56",
|
||||
"tx": "0x36fe6a597bd0be532236bf13e1e2575fbb56536666438d07a006a9df0c9b0a13"
|
||||
},
|
||||
{
|
||||
"amount": "21.74094368",
|
||||
"user": "0x7C8D2D8BcFffcD48dBcb65C5Bb7588B66dcD22bb",
|
||||
"tx": "0x2883648c0fa0f5a27defb406ab22bc0120d43e3a98b16fd7a97d99f9e79dc24c"
|
||||
},
|
||||
{
|
||||
"amount": "78.261187214",
|
||||
"user": "0x479F059c46c6873C6B970A92911084b3eA036d56",
|
||||
@@ -63244,10 +63575,17 @@
|
||||
"tx": "0xc7dd4c2b995cc486fcd8b7892cd79f8fb393ada004dc68cf66ec82d99b35763c"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "262.76406646",
|
||||
"user": "0xD3ec605d078326B0a636ca90d496Ebb5Eb457a27",
|
||||
"tranche_id": 5,
|
||||
"tx": "0xc3734fbb0982f35d4add052e69d6b997f92364ac75654253f4abdc62a4245d1e"
|
||||
}
|
||||
],
|
||||
"total_tokens": "400",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "400"
|
||||
"withdrawn_tokens": "262.76406646",
|
||||
"remaining_tokens": "137.23593354"
|
||||
},
|
||||
{
|
||||
"address": "0x7f6aba7563Cb5d31980D440337D3d1A6e3dB58F3",
|
||||
@@ -63409,10 +63747,17 @@
|
||||
"tx": "0x057f65938b1360b6d2c4ebf5e789c67897cf60cb6a13f947004def03891afbd8"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "13.1116203702",
|
||||
"user": "0x4cBC0C88d8FE503f62823B42f30a4900292C13bE",
|
||||
"tranche_id": 5,
|
||||
"tx": "0xf712a2417c5e58f65ac39422766fd902301f905f41e9eed0dc097e1dfa641b1c"
|
||||
}
|
||||
],
|
||||
"total_tokens": "20",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "20"
|
||||
"withdrawn_tokens": "13.1116203702",
|
||||
"remaining_tokens": "6.8883796298"
|
||||
},
|
||||
{
|
||||
"address": "0x9999099991E044E3538379C80F00308E430881AA",
|
||||
@@ -68997,6 +69342,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "21.74094368",
|
||||
"user": "0x7C8D2D8BcFffcD48dBcb65C5Bb7588B66dcD22bb",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x2883648c0fa0f5a27defb406ab22bc0120d43e3a98b16fd7a97d99f9e79dc24c"
|
||||
},
|
||||
{
|
||||
"amount": "15.426179608",
|
||||
"user": "0x7C8D2D8BcFffcD48dBcb65C5Bb7588B66dcD22bb",
|
||||
@@ -69029,8 +69380,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "400",
|
||||
"withdrawn_tokens": "243.804249112",
|
||||
"remaining_tokens": "156.195750888"
|
||||
"withdrawn_tokens": "265.545192792",
|
||||
"remaining_tokens": "134.454807208"
|
||||
},
|
||||
{
|
||||
"address": "0xc56F9f1d5f124655FA9CB8f85C7701E13a2fBF4D",
|
||||
@@ -73105,6 +73456,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "9.342237444",
|
||||
"user": "0x479F059c46c6873C6B970A92911084b3eA036d56",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x36fe6a597bd0be532236bf13e1e2575fbb56536666438d07a006a9df0c9b0a13"
|
||||
},
|
||||
{
|
||||
"amount": "78.261187214",
|
||||
"user": "0x479F059c46c6873C6B970A92911084b3eA036d56",
|
||||
@@ -73119,8 +73476,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "122.354712074",
|
||||
"remaining_tokens": "77.645287926"
|
||||
"withdrawn_tokens": "131.696949518",
|
||||
"remaining_tokens": "68.303050482"
|
||||
},
|
||||
{
|
||||
"address": "0x311944e80915b08248111173671093623Fd74851",
|
||||
@@ -77036,7 +77393,7 @@
|
||||
"tranche_start": "2021-12-05T00:00:00.000Z",
|
||||
"tranche_end": "2022-06-05T00:00:00.000Z",
|
||||
"total_added": "171288.42",
|
||||
"total_removed": "64226.1049690697989",
|
||||
"total_removed": "64726.1049690697989",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
@@ -81266,6 +81623,16 @@
|
||||
"user": "0x4A13d4dC5e06ACdA81C011D55a7DaAc332bC5Dbf",
|
||||
"tx": "0x72e95b2e51cae897d2c09ca7294c630fb3b969aea950a53e10158570faee89c7"
|
||||
},
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0x0428D82D3C4d8C616Dac3862E9Fc88af9A294b83",
|
||||
"tx": "0x01dfb567e73d420d9370ba42ec1399e159e56fb50457cbe1b2d28e20da2f1dc9"
|
||||
},
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0x68091918EaDB98f54E8fC179870aB6F755736174",
|
||||
"tx": "0x6957558e2c90b17cd1ef8673ca4a6c949dfcdf0772e3b580e7dda2655b647c64"
|
||||
},
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0xbd09687340A09BeB0B5EE0D3C2bCa8d78eBF6E63",
|
||||
@@ -93866,10 +94233,17 @@
|
||||
"tx": "0x9f916cf09e8a3c4ade0ffce5190db464d0a2b1dadba78e1ee7ba5d6e751d6148"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0x0428D82D3C4d8C616Dac3862E9Fc88af9A294b83",
|
||||
"tranche_id": 6,
|
||||
"tx": "0x01dfb567e73d420d9370ba42ec1399e159e56fb50457cbe1b2d28e20da2f1dc9"
|
||||
}
|
||||
],
|
||||
"total_tokens": "250",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "250"
|
||||
"withdrawn_tokens": "250",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0xA715676aBD2aebb2aa6392D3Dc4e9e0521b823Ef",
|
||||
@@ -97753,10 +98127,17 @@
|
||||
"tx": "0xe32a466fc780a0fb3fd84a804f622931ebfaf3f428bff0dc6d141270410e75f8"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0x68091918EaDB98f54E8fC179870aB6F755736174",
|
||||
"tranche_id": 6,
|
||||
"tx": "0x6957558e2c90b17cd1ef8673ca4a6c949dfcdf0772e3b580e7dda2655b647c64"
|
||||
}
|
||||
],
|
||||
"total_tokens": "250",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "250"
|
||||
"withdrawn_tokens": "250",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x0E39d235cf6874F22a13c55C19500343B371000f",
|
||||
|
||||
+13
-1
@@ -16,4 +16,16 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||
#Test configuration variables
|
||||
CYPRESS_FAIRGROUND=false
|
||||
CYPRESS_VEGA_URL=http://localhost:3028/query
|
||||
CYPRESS_VEGA_WALLET_API_TOKEN=
|
||||
CYPRESS_VEGA_WALLET_API_TOKEN=jpeAkxcffzTLCzBX2m5TZIp3hF500YZhHwESwNKOGksdGPXeeIznXypaDfpNe2M9
|
||||
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
|
||||
CYPRESS_ETHEREUM_PROVIDER_URL=http://localhost:8545
|
||||
CYPRESS_EXPLORER_URL=https://explorer.fairground.wtf
|
||||
CYPRESS_FAUCET_URL=http://localhost:1790/api/v1/mint
|
||||
CYPRESS_TRUNCATED_VEGA_PUBLIC_KEY=02ecea…342f65
|
||||
CYPRESS_TRUNCATED_VEGA_PUBLIC_KEY2=7f9cf0…c25535
|
||||
CYPRESS_VEGA_ENV=CUSTOM
|
||||
CYPRESS_VEGA_PUBLIC_KEY=02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65
|
||||
CYPRESS_VEGA_PUBLIC_KEY2=7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535
|
||||
CYPRESS_VEGA_TOKEN_URL=https://token.fairground.wtf
|
||||
CYPRESS_VEGA_URL=http://localhost:3028/query
|
||||
CYPRESS_VEGA_WALLET_URL=http://localhost:1789
|
||||
|
||||
@@ -2,56 +2,59 @@
|
||||
"changes": {
|
||||
"decimalPlaces": "5",
|
||||
"positionDecimalPlaces": "5",
|
||||
"lpPriceRange": "10",
|
||||
"instrument": {
|
||||
"name": "Oranges Daily",
|
||||
"code": "ORANGES.24h",
|
||||
"name": "Token test market",
|
||||
"code": "Token.24h",
|
||||
"future": {
|
||||
"settlementAsset": "8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4",
|
||||
"quoteName": "tEuro",
|
||||
"settlementDataDecimals": 5,
|
||||
"settlementAsset": "fBTC",
|
||||
"quoteName": "fBTC",
|
||||
"dataSourceSpecForSettlementData": {
|
||||
"signers": [
|
||||
{
|
||||
"signer": {
|
||||
"__typename": "ETHAddress",
|
||||
"address": "0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"
|
||||
}
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "prices.BTC.value",
|
||||
"type": "TYPE_INTEGER"
|
||||
},
|
||||
"conditions": [
|
||||
"external": {
|
||||
"oracle": {
|
||||
"signers": [
|
||||
{
|
||||
"operator": "OPERATOR_GREATER_THAN",
|
||||
"value": "0"
|
||||
"pubKey": {
|
||||
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
|
||||
}
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "prices.ETH.value",
|
||||
"type": "TYPE_INTEGER",
|
||||
"numberDecimalPlaces": "0"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_GREATER_THAN",
|
||||
"value": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dataSourceSpecForTradingTermination": {
|
||||
"signers": [
|
||||
{
|
||||
"signer": {
|
||||
"__typename": "ETHAddress",
|
||||
"address": "0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"
|
||||
"pubKey": {
|
||||
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
|
||||
}
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "vegaprotocol.builtin.timestamp",
|
||||
"type": "TYPE_TIMESTAMP"
|
||||
"name": "trading.terminated.ETH5",
|
||||
"type": "TYPE_BOOLEAN"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_GREATER_THAN_OR_EQUAL",
|
||||
"value": "1648684800000000000"
|
||||
"operator": "OPERATOR_EQUALS",
|
||||
"value": "true"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -59,7 +62,7 @@
|
||||
},
|
||||
"dataSourceSpecBinding": {
|
||||
"settlementPriceProperty": "prices.BTC.value",
|
||||
"tradingTerminationProperty": "vegaprotocol.builtin.timestamp"
|
||||
"tradingTerminationProperty": "trading.terminated.ETH5"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,83 +1,78 @@
|
||||
{
|
||||
"marketId": "315a8e48db0a292c92b617264728048c82c20efc922c75fd292fc54e5c727c81",
|
||||
"changes": {
|
||||
"instrument": {
|
||||
"code": "ORANGES.24h",
|
||||
"future": {
|
||||
"quoteName": "tEuro",
|
||||
"settlementDataDecimals": 5,
|
||||
"dataSourceSpecForSettlementData": {
|
||||
"signers": [
|
||||
{
|
||||
"signer": {
|
||||
"__typename": "ETHAddress",
|
||||
"address": "0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"
|
||||
"instrument": {
|
||||
"code": "TEST.24h",
|
||||
"future": {
|
||||
"quoteName": "fUSDC",
|
||||
"settlementDataDecimals": 5,
|
||||
"dataSourceSpecForSettlementData": {
|
||||
"signers": [
|
||||
{
|
||||
"pubKey": {
|
||||
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
|
||||
}
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "prices.ETH.value",
|
||||
"type": "TYPE_INTEGER"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_GREATER_THAN",
|
||||
"value": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"dataSourceSpecForTradingTermination": {
|
||||
"signers": [
|
||||
{
|
||||
"pubKey": {
|
||||
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "prices.BTC.value",
|
||||
"type": "TYPE_INTEGER"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_GREATER_THAN",
|
||||
"value": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"dataSourceSpecForTradingTermination": {
|
||||
"signers": [
|
||||
{
|
||||
"signer": {
|
||||
"__typename": "ETHAddress",
|
||||
"address": "0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "trading.terminated.ETH5",
|
||||
"type": "TYPE_BOOLEAN"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_GREATER_THAN_OR_EQUAL",
|
||||
"value": "1648684800000000000"
|
||||
}
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "vegaprotocol.builtin.timestamp",
|
||||
"type": "TYPE_TIMESTAMP"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_GREATER_THAN_OR_EQUAL",
|
||||
"value": "1648684800000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"dataSourceSpecBinding": {
|
||||
"settlementPriceProperty": "prices.BTC.value",
|
||||
"tradingTerminationProperty": "vegaprotocol.builtin.timestamp"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"dataSourceSpecBinding": {
|
||||
"settlementPriceProperty": "prices.ETH.value",
|
||||
"tradingTerminationProperty": "trading.terminated.ETH5"
|
||||
}
|
||||
},
|
||||
"metadata": ["sector:energy", "sector:food", "source:docs.vega.xyz"],
|
||||
"priceMonitoringParameters": {
|
||||
"triggers": [
|
||||
{
|
||||
"horizon": "43200",
|
||||
"probability": "0.9999999",
|
||||
"auctionExtension": "600"
|
||||
}
|
||||
]
|
||||
},
|
||||
"logNormal": {
|
||||
"tau": 0.0001140771161,
|
||||
"riskAversionParameter": 0.001,
|
||||
"params": {
|
||||
"mu": 0,
|
||||
"r": 0.016,
|
||||
"sigma": 0.3
|
||||
}
|
||||
},
|
||||
"metadata": ["sector:energy", "sector:food", "source:docs.vega.xyz"],
|
||||
"priceMonitoringParameters": {
|
||||
"triggers": [
|
||||
{
|
||||
"horizon": "43200",
|
||||
"probability": "0.9999999",
|
||||
"auctionExtension": "600"
|
||||
}
|
||||
]
|
||||
},
|
||||
"logNormal": {
|
||||
"tau": 0.0001140771161,
|
||||
"riskAversionParameter": 0.001,
|
||||
"params": {
|
||||
"mu": 0,
|
||||
"r": 0.016,
|
||||
"sigma": 0.3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
123
|
||||
0123245
|
||||
|
||||
@@ -11,6 +11,7 @@ const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
||||
const dialogCloseButton = '[data-testid="dialog-close"]';
|
||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const closedProposals = '[data-testid="closed-proposals"]';
|
||||
const proposalVoteProgressForPercentage =
|
||||
'[data-testid="vote-progress-indicator-percentage-for"]';
|
||||
const proposalVoteProgressAgainstPercentage =
|
||||
@@ -22,7 +23,9 @@ const proposalVoteProgressAgainstTokens =
|
||||
const changeVoteButton = '[data-testid="change-vote-button"]';
|
||||
const proposalDetailsTitle = '[data-testid="proposal-title"]';
|
||||
const proposalDetailsDescription = '[data-testid="proposal-description"]';
|
||||
const proposalStatus = '[data-testid="proposal-status"]';
|
||||
const rawProposalData = '[data-testid="proposal-data"]';
|
||||
const votesTable = '[data-testid="votes-table"]';
|
||||
const minVoteButton = '[data-testid="min-vote"]';
|
||||
const maxVoteButton = '[data-testid="max-vote"]';
|
||||
const voteButtons = '[data-testid="vote-buttons"]';
|
||||
@@ -37,6 +40,10 @@ const txTimeout = Cypress.env('txTimeout');
|
||||
const epochTimeout = Cypress.env('epochTimeout');
|
||||
const proposalTimeout = { timeout: 14000 };
|
||||
|
||||
const minCloseDays = 2;
|
||||
const maxCloseDays = 3;
|
||||
const requiredParticipation = 0.001;
|
||||
|
||||
const governanceProposalType = {
|
||||
NETWORK_PARAMETER: 'Network parameter',
|
||||
NEW_MARKET: 'New market',
|
||||
@@ -65,21 +72,6 @@ context(
|
||||
network_parameters['governance.proposal.freeform.requiredMajority'] *
|
||||
100
|
||||
).as('requiredMajority');
|
||||
cy.wrap(
|
||||
network_parameters[
|
||||
'governance.proposal.freeform.requiredParticipation'
|
||||
] * 100
|
||||
).as('requiredParticipation');
|
||||
cy.wrap(
|
||||
network_parameters['governance.proposal.freeform.minClose'].split(
|
||||
'h'
|
||||
)[0] / 24
|
||||
).as('minCloseDays');
|
||||
cy.wrap(
|
||||
network_parameters['governance.proposal.freeform.maxClose'].split(
|
||||
'h'
|
||||
)[0] / 24
|
||||
).as('maxCloseDays');
|
||||
cy.wrap(
|
||||
network_parameters['governance.proposal.freeform.minClose'].split(
|
||||
'h'
|
||||
@@ -108,21 +100,6 @@ context(
|
||||
0.00001,
|
||||
'Asserting that value is at least 0.00001 for network parameter minVoterBalance'
|
||||
);
|
||||
assert.isAtLeast(
|
||||
parseFloat(this.requiredParticipation),
|
||||
0.00001,
|
||||
'Asserting that value is at least 0.00001 for network parameter requiredParticipation'
|
||||
);
|
||||
assert.isAtLeast(
|
||||
parseInt(this.minCloseDays),
|
||||
1,
|
||||
'Asserting that value is at least 1 for network parameter minCloseDays'
|
||||
);
|
||||
assert.isAtLeast(
|
||||
parseInt(this.maxCloseDays),
|
||||
parseInt(this.minCloseDays + 1),
|
||||
'Asserting that network parameter maxCloseDays is at least 1 day higher than minCloseDays'
|
||||
);
|
||||
// workaround for first eth tx hanging
|
||||
associateTokenStartOfTests();
|
||||
}
|
||||
@@ -182,10 +159,10 @@ context(
|
||||
this.minProposerBalance
|
||||
);
|
||||
let proposalDays = [
|
||||
this.minCloseDays + 1,
|
||||
this.maxCloseDays,
|
||||
this.minCloseDays + 3,
|
||||
this.minCloseDays + 2,
|
||||
minCloseDays + 1,
|
||||
maxCloseDays,
|
||||
minCloseDays + 3,
|
||||
minCloseDays + 2,
|
||||
];
|
||||
for (var index = 0; index < proposalDays.length; index++) {
|
||||
cy.go_to_make_new_proposal(governanceProposalType.RAW);
|
||||
@@ -227,6 +204,7 @@ context(
|
||||
cy.navigate_to('validators');
|
||||
cy.click_on_validator_from_list(0);
|
||||
cy.staking_validator_page_add_stake('2');
|
||||
cy.close_staking_dialog();
|
||||
|
||||
cy.get(vegaWalletStakedBalances, txTimeout).should('contain', '2');
|
||||
|
||||
@@ -297,10 +275,12 @@ context(
|
||||
});
|
||||
});
|
||||
|
||||
// Skipping test due to bug: #1320
|
||||
it.skip('Newly created freeform proposals list - shows proposal participation - both met and not', function () {
|
||||
createFreeformProposal(this.minProposerBalance);
|
||||
cy.get_submitted_proposal_from_proposal_list()
|
||||
// 3001-VOTE-071
|
||||
it('Newly created freeform proposals list - shows proposal participation - both met and not', function () {
|
||||
const proposalTitle = generateProposalTitle();
|
||||
createFreeformProposal(this.minProposerBalance, proposalTitle);
|
||||
|
||||
cy.get_submitted_proposal_from_proposal_list(proposalTitle)
|
||||
.as('submittedProposal')
|
||||
.within(() => {
|
||||
// 3001-VOTE-039
|
||||
@@ -312,7 +292,7 @@ context(
|
||||
.invoke('text')
|
||||
.then((totalSupply) => {
|
||||
let tokensRequiredToAchieveResult = parseFloat(
|
||||
(totalSupply.replace(/,/g, '') * this.requiredParticipation) / 100
|
||||
(totalSupply.replace(/,/g, '') * requiredParticipation) / 100
|
||||
).toFixed(2);
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
tokensRequiredToAchieveResult
|
||||
@@ -321,16 +301,17 @@ context(
|
||||
cy.get('@submittedProposal').within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
cy.get_proposal_information_from_table('Participation met')
|
||||
cy.get_proposal_information_from_table('Token participation met')
|
||||
.contains('👍')
|
||||
.should('be.visible');
|
||||
cy.navigate_to('proposals');
|
||||
cy.get('@submittedProposal').within(() =>
|
||||
cy.get(voteStatus).should('have.text', 'Participation met')
|
||||
cy.get(voteStatus).should('have.text', 'Set to pass')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// 3001-VOTE-055
|
||||
it('Newly created raw proposal details - shows proposal title and full description', function () {
|
||||
createRawProposal(this.minProposerBalance);
|
||||
cy.get('@rawProposal').then((rawProposal) => {
|
||||
@@ -357,6 +338,7 @@ context(
|
||||
});
|
||||
});
|
||||
|
||||
// 3001-VOTE-043
|
||||
it('Newly created freeform proposal details - shows proposed and closing dates', function () {
|
||||
const closingVoteHrs = '72';
|
||||
const proposalTitle = generateProposalTitle();
|
||||
@@ -399,6 +381,7 @@ context(
|
||||
it('Newly created proposal details - shows default status set to fail', function () {
|
||||
// 3001-VOTE-037
|
||||
// 3001-VOTE-040
|
||||
// 3001-VOTE-067
|
||||
createRawProposal(this.minProposerBalance);
|
||||
cy.get('@rawProposal').then((rawProposal) => {
|
||||
cy.get_submitted_proposal_from_proposal_list(
|
||||
@@ -413,15 +396,17 @@ context(
|
||||
.should('be.visible');
|
||||
// 3001-VOTE-062
|
||||
// 3001-VOTE-040
|
||||
// 3001-VOTE-070
|
||||
cy.get_proposal_information_from_table('Token majority met')
|
||||
.contains('👎')
|
||||
.should('be.visible');
|
||||
// 3001-VOTE-068
|
||||
cy.get_proposal_information_from_table('Token participation met')
|
||||
.contains('👎')
|
||||
.should('be.visible');
|
||||
});
|
||||
|
||||
// 3001-VOTE-080 3001-VOTE-090
|
||||
// 3001-VOTE-080 3001-VOTE-090 3001-VOTE-069 3001-VOTE-072 3001-VOTE-073
|
||||
it('Newly created proposal details - ability to vote for and against proposal - with minimum required tokens associated', function () {
|
||||
createRawProposal(this.minProposerBalance);
|
||||
cy.get('@rawProposal').then((rawProposal) => {
|
||||
@@ -446,7 +431,7 @@ context(
|
||||
.contains(votedDate)
|
||||
.should('be.visible');
|
||||
});
|
||||
cy.get(proposalVoteProgressForPercentage)
|
||||
cy.get(proposalVoteProgressForPercentage) // 3001-VOTE-072
|
||||
.contains('100.00%')
|
||||
.and('be.visible');
|
||||
cy.get(proposalVoteProgressAgainstPercentage)
|
||||
@@ -466,10 +451,10 @@ context(
|
||||
.and('be.visible');
|
||||
// 3001-VOTE-061
|
||||
cy.get_proposal_information_from_table('Participation required')
|
||||
.contains(`${this.requiredParticipation}%`)
|
||||
.contains(`${requiredParticipation}%`)
|
||||
.should('be.visible');
|
||||
// 3001-VOTE-066
|
||||
cy.get_proposal_information_from_table('Majority Required')
|
||||
cy.get_proposal_information_from_table('Majority Required') // 3001-VOTE-073
|
||||
.contains(`${parseFloat(this.requiredMajority).toFixed(2)}%`)
|
||||
.should('be.visible');
|
||||
cy.get_proposal_information_from_table('Number of voting parties')
|
||||
@@ -512,7 +497,7 @@ context(
|
||||
.invoke('text')
|
||||
.then((totalSupply) => {
|
||||
let tokensRequiredToAchieveResult = parseFloat(
|
||||
(totalSupply.replace(/,/g, '') * this.requiredParticipation) / 100
|
||||
(totalSupply.replace(/,/g, '') * requiredParticipation) / 100
|
||||
).toFixed(2);
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
tokensRequiredToAchieveResult
|
||||
@@ -536,6 +521,11 @@ context(
|
||||
cy.get(proposalVoteProgressAgainstTokens)
|
||||
.contains('0.00')
|
||||
.and('be.visible');
|
||||
cy.get_proposal_information_from_table(
|
||||
'Total tokens voted percentage'
|
||||
)
|
||||
.should('have.text', '0.00%')
|
||||
.and('be.visible');
|
||||
cy.get_proposal_information_from_table('Tokens for proposal')
|
||||
.should('have.text', tokensRequiredToAchieveResult)
|
||||
.and('be.visible');
|
||||
@@ -588,6 +578,7 @@ context(
|
||||
);
|
||||
});
|
||||
|
||||
// 3001-VOTE-006
|
||||
it('Creating a proposal - proposal rejected - able to access rejected proposals', function () {
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
this.minProposerBalance
|
||||
@@ -649,6 +640,7 @@ context(
|
||||
cy.get(dialogCloseButton).click();
|
||||
});
|
||||
|
||||
// 3002-PROP-009
|
||||
it('Unable to create a proposal - when some but not enough tokens are associated', function () {
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
this.minProposerBalance - 0.000001
|
||||
@@ -669,7 +661,7 @@ context(
|
||||
});
|
||||
|
||||
it('Unable to create a freeform proposal - when json parent section contains unexpected field', function () {
|
||||
// 3001-VOTE-038
|
||||
// 3001-VOTE-038 3002-PROP-013 3002-PROP-014
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
this.minProposerBalance
|
||||
);
|
||||
@@ -695,6 +687,9 @@ context(
|
||||
'Invalid params: the transaction is malformed'
|
||||
);
|
||||
cy.get(dialogCloseButton).click();
|
||||
cy.get(rawProposalData)
|
||||
.invoke('val')
|
||||
.should('contain', "i shouldn't be here");
|
||||
});
|
||||
|
||||
it('Unable to create a freeform proposal - when json terms section contains unexpected field', function () {
|
||||
@@ -792,6 +787,107 @@ context(
|
||||
cy.contains('You voted: Against').should('be.visible');
|
||||
});
|
||||
|
||||
// 3001-VOTE-006
|
||||
it('Able to view enacted proposal', function () {
|
||||
cy.createMarket();
|
||||
cy.reload();
|
||||
cy.wait_for_spinner();
|
||||
cy.get(closedProposals).within(() => {
|
||||
cy.get(proposalDetailsTitle).should(
|
||||
'have.text',
|
||||
'Add Lorem Ipsum market'
|
||||
);
|
||||
cy.get(proposalStatus).should('have.text', 'Enacted ');
|
||||
cy.get(viewProposalButton).click();
|
||||
});
|
||||
cy.getByTestId('proposal-type').should('have.text', 'New market');
|
||||
cy.get_proposal_information_from_table('State')
|
||||
.contains('Enacted')
|
||||
.and('be.visible');
|
||||
cy.get(votesTable).within(() => {
|
||||
cy.contains('Vote passed.').should('be.visible');
|
||||
cy.contains('Voting has ended.').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
// 3001-VOTE-047
|
||||
it('Able to enact freeform proposal', function () {
|
||||
const proposalTitle = 'Add New free form proposal with short enactment';
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
this.minProposerBalance
|
||||
);
|
||||
cy.sendWalletTxFreeFormProposal();
|
||||
cy.navigate_to('proposals');
|
||||
cy.reload();
|
||||
cy.wait_for_spinner();
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil('[data-testid="proposals-list-item"]')
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
cy.get_proposal_information_from_table('State')
|
||||
.contains('Open')
|
||||
.and('be.visible');
|
||||
cy.vote_for_proposal('for');
|
||||
cy.get_proposal_information_from_table('State')
|
||||
.contains('Enacted', epochTimeout)
|
||||
.and('be.visible');
|
||||
});
|
||||
|
||||
// 3001-VOTE-046 3001-VOTE-044 3001-VOTE-074 3001-VOTE-074
|
||||
it('Able to enact proposal by voting', function () {
|
||||
const proposalTitle = 'Add New proposal with short enactment';
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
this.minProposerBalance
|
||||
);
|
||||
cy.sendWalletTxUpdateNetworkProposal();
|
||||
cy.navigate_to('proposals');
|
||||
cy.reload();
|
||||
cy.wait_for_spinner();
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil('[data-testid="proposals-list-item"]')
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
cy.get_proposal_information_from_table('State')
|
||||
.contains('Open')
|
||||
.and('be.visible');
|
||||
cy.vote_for_proposal('for');
|
||||
cy.get_proposal_information_from_table('State') // 3001-VOTE-047
|
||||
.contains('Passed', txTimeout)
|
||||
.and('be.visible');
|
||||
cy.get_proposal_information_from_table('State')
|
||||
.contains('Enacted', epochTimeout)
|
||||
.and('be.visible');
|
||||
cy.get(votesTable).within(() => {
|
||||
cy.contains('Vote passed.').should('be.visible');
|
||||
cy.contains('Voting has ended.').should('be.visible');
|
||||
});
|
||||
cy.get(proposalVoteProgressForPercentage)
|
||||
.contains('100.00%')
|
||||
.and('be.visible');
|
||||
});
|
||||
|
||||
// 3001-VOTE-048 3001-VOTE-049
|
||||
it('Able to fail proposal due to lack of participation', function () {
|
||||
const proposalTitle = 'Add New free form proposal with short enactment';
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
this.minProposerBalance
|
||||
);
|
||||
cy.sendWalletTxFreeFormProposal();
|
||||
cy.navigate_to('proposals');
|
||||
cy.reload();
|
||||
cy.wait_for_spinner();
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil('[data-testid="proposals-list-item"]')
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
cy.get_proposal_information_from_table('State')
|
||||
.contains('Open')
|
||||
.and('be.visible');
|
||||
cy.get_proposal_information_from_table('State') // 3001-VOTE-047
|
||||
.contains('Declined', txTimeout)
|
||||
.and('be.visible');
|
||||
cy.get_proposal_information_from_table('Rejection reason')
|
||||
.contains('PROPOSAL_ERROR_PARTICIPATION_THRESHOLD_NOT_REACHED')
|
||||
.and('be.visible');
|
||||
});
|
||||
|
||||
function createRawProposal(proposerBalance) {
|
||||
if (proposerBalance)
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(proposerBalance);
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
const proposalListItem = '[data-testid="proposals-list-item"]';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const proposalType = '[data-testid="proposal-type"]';
|
||||
const proposalDetails = '[data-testid="proposal-details"]';
|
||||
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
||||
const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]';
|
||||
const proposalValidationDeadline =
|
||||
@@ -209,18 +213,15 @@ context(
|
||||
);
|
||||
});
|
||||
|
||||
// skipped because no markets available to select in capsule
|
||||
it.skip('Able to submit update market proposal', function () {
|
||||
const marketId =
|
||||
'315a8e48db0a292c92b617264728048c82c20efc922c75fd292fc54e5c727c81';
|
||||
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_MARKET);
|
||||
cy.get(newProposalTitle).type('Test update asset proposal');
|
||||
cy.get(newProposalTitle).type('Test update market proposal');
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.get(proposalMarketSelect).select(marketId);
|
||||
cy.get(proposalMarketSelect).select('Test market 1');
|
||||
cy.get('[data-testid="update-market-details"]').within(() => {
|
||||
cy.get('dd').eq(0).should('have.text', 'Oranges Daily');
|
||||
cy.get('dd').eq(1).should('have.text', 'ORANGES.24h');
|
||||
cy.get('dd').eq(2).should('have.text', marketId);
|
||||
cy.get('dd').eq(0).should('have.text', 'Test market 1');
|
||||
cy.get('dd').eq(1).should('have.text', 'TEST.24h');
|
||||
cy.get('dd').eq(2).should('not.be.empty');
|
||||
});
|
||||
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
|
||||
let newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
|
||||
@@ -281,12 +282,28 @@ context(
|
||||
});
|
||||
|
||||
it('Able to submit update asset proposal using min deadline', function () {
|
||||
const assetId =
|
||||
'ebcd94151ae1f0d39a4bde3b21a9c7ae81a80ea4352fb075a92e07608d9c953d';
|
||||
|
||||
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_ASSET);
|
||||
enterUpdateAssetProposalDetails();
|
||||
cy.get(minVoteDeadline).click();
|
||||
cy.get(minEnactDeadline).click();
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.wait_for_proposal_submitted();
|
||||
cy.navigate_to('proposals');
|
||||
cy.get(openProposals).within(() => {
|
||||
cy.get(proposalType)
|
||||
.contains('Update asset')
|
||||
.parentsUntil(proposalListItem)
|
||||
.within(() => {
|
||||
cy.get(proposalDetails).should('contain.text', assetId); // 3001-VOTE-029
|
||||
cy.getByTestId('view-proposal-btn').click();
|
||||
});
|
||||
});
|
||||
cy.get_proposal_information_from_table('Proposed enactment') // 3001-VOTE-044
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
});
|
||||
|
||||
it('Able to submit update asset proposal using max deadline', function () {
|
||||
|
||||
@@ -20,7 +20,10 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
|
||||
|
||||
it('Able to connect public key via wallet', function () {
|
||||
verifyConnectedToPubKey();
|
||||
cy.getByTestId('currency-title').should('contain.text', 'USDC (fake)');
|
||||
cy.getByTestId('currency-title', Cypress.env('epochTimeout')).should(
|
||||
'contain.text',
|
||||
'USDC (fake)'
|
||||
);
|
||||
});
|
||||
|
||||
it('Able to connect public key using url', function () {
|
||||
|
||||
@@ -46,6 +46,6 @@ Cypress.Commands.add('verify_page_header', (text) => {
|
||||
});
|
||||
|
||||
Cypress.Commands.add('wait_for_spinner', () => {
|
||||
cy.get(navigation.pageSpinner).should('exist');
|
||||
cy.get(navigation.pageSpinner, Cypress.env('epochTimeout')).should('exist');
|
||||
cy.get(navigation.pageSpinner, { timeout: 20000 }).should('not.exist');
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import './governance.functions.js';
|
||||
import './wallet-eth.functions.js';
|
||||
import './wallet-teardown.functions.js';
|
||||
import './wallet-vega.functions.js';
|
||||
import './proposal.functions.js';
|
||||
import registerCypressGrep from '@cypress/grep';
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import { chainIdQuery, statisticsQuery } from '@vegaprotocol/mock';
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
import { addSeconds, millisecondsToSeconds } from 'date-fns';
|
||||
|
||||
const walletName = Cypress.env('vegaWalletName');
|
||||
const walletPubKey = Cypress.env('vegaWalletPublicKey');
|
||||
const walletLocation = Cypress.env('vegaWalletLocation');
|
||||
const walletPassphraseFile = './src/fixtures/wallet/passphrase';
|
||||
|
||||
Cypress.Commands.add('sendWalletTxUpdateNetworkProposal', () => {
|
||||
const MIN_CLOSE_SEC = 8;
|
||||
const MIN_ENACT_SEC = 5;
|
||||
|
||||
const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC);
|
||||
const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC);
|
||||
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
|
||||
const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime());
|
||||
|
||||
cy.exec(
|
||||
`vegawallet transaction send --wallet ${walletName} --pubkey ${walletPubKey} -p ${walletPassphraseFile} --network DV '{
|
||||
"proposalSubmission": {
|
||||
"rationale": {
|
||||
"title": "Add New proposal with short enactment",
|
||||
"description": "E2E enactment test"
|
||||
},
|
||||
"terms": {
|
||||
"updateNetworkParameter": {
|
||||
"changes": {
|
||||
"key": "governance.proposal.updateNetParam.minProposerBalance",
|
||||
"value": "2"
|
||||
}
|
||||
},
|
||||
"closingTimestamp": ${closingTimestamp},
|
||||
"enactmentTimestamp": ${enactmentTimestamp}
|
||||
}
|
||||
}
|
||||
}' --home ${walletLocation}`,
|
||||
{ failOnNonZeroExit: false }
|
||||
)
|
||||
.its('stderr')
|
||||
.should('contain', '');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('sendWalletTxUpdateAssetProposal', () => {
|
||||
const MIN_CLOSE_SEC = 8;
|
||||
const MIN_ENACT_SEC = 5;
|
||||
|
||||
const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC);
|
||||
const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC);
|
||||
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
|
||||
const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime());
|
||||
|
||||
cy.exec(
|
||||
`vegawallet transaction send --wallet ${walletName} --pubkey ${walletPubKey} -p ${walletPassphraseFile} --network DV '{
|
||||
"proposalSubmission": {
|
||||
"rationale": {
|
||||
"title": "Update Asset set to fail",
|
||||
"description": "E2E fail test"
|
||||
},
|
||||
"terms": {
|
||||
"updateAsset": {
|
||||
"assetId": "ebcd94151ae1f0d39a4bde3b21a9c7ae81a80ea4352fb075a92e07608d9c953d",
|
||||
"changes": {
|
||||
"quantum": "1",
|
||||
"erc20": {
|
||||
"withdrawThreshold": "10",
|
||||
"lifetimeLimit": "10"
|
||||
}
|
||||
}
|
||||
},
|
||||
"closingTimestamp": ${closingTimestamp},
|
||||
"enactmentTimestamp": ${enactmentTimestamp}
|
||||
}
|
||||
}
|
||||
}' --home ${walletLocation}`,
|
||||
{ failOnNonZeroExit: false }
|
||||
)
|
||||
.its('stderr')
|
||||
.should('contain', '');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('sendWalletTxFreeFormProposal', () => {
|
||||
const MIN_CLOSE_SEC = 5;
|
||||
|
||||
const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC);
|
||||
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
|
||||
|
||||
cy.exec(
|
||||
`vegawallet transaction send --wallet ${walletName} --pubkey ${walletPubKey} -p ${walletPassphraseFile} --network DV '{
|
||||
"proposalSubmission": {
|
||||
"rationale": {
|
||||
"title": "Add New free form proposal with short enactment",
|
||||
"description": "E2E enactment test"
|
||||
},
|
||||
"terms": {
|
||||
"newFreeform": {},
|
||||
"closingTimestamp": ${closingTimestamp}
|
||||
}
|
||||
}
|
||||
}' --home ${walletLocation}`,
|
||||
{ failOnNonZeroExit: false }
|
||||
)
|
||||
.its('stderr')
|
||||
.should('contain', '');
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_ENV=TESTNET
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json
|
||||
NX_VEGA_URL=https://api.n10.testnet.vega.xyz/graphql
|
||||
NX_VEGA_URL=https://api.n08.testnet.vega.xyz/graphql
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
|
||||
@@ -12,5 +12,10 @@ export default {
|
||||
moduleNameMapper: {
|
||||
'^d3-(.*)$': `d3-$1/dist/d3-$1`,
|
||||
},
|
||||
collectCoverageFrom: ['**/*.{ts,tsx}', '!**/node_modules/**'],
|
||||
collectCoverageFrom: [
|
||||
'**/*.{ts,tsx}',
|
||||
'!**/node_modules/**',
|
||||
'!**/__generated__/**',
|
||||
'!**/__generated___/**',
|
||||
],
|
||||
};
|
||||
|
||||
@@ -2,20 +2,24 @@ import * as Sentry from '@sentry/react';
|
||||
import { toBigNum } from '@vegaprotocol/react-helpers';
|
||||
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import React from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useAppState } from '../../contexts/app-state/app-state-context';
|
||||
import { useContracts } from '../../contexts/contracts/contracts-context';
|
||||
import { useGetAssociationBreakdown } from '../../hooks/use-get-association-breakdown';
|
||||
import { useGetUserTrancheBalances } from '../../hooks/use-get-user-tranche-balances';
|
||||
import { useBalances } from '../../lib/balances/balances-store';
|
||||
import type { ReactElement } from 'react';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useListenForStakingEvents as useListenForAssociationEvents } from '../../hooks/use-listen-for-staking-events';
|
||||
|
||||
interface BalanceManagerProps {
|
||||
children: React.ReactElement;
|
||||
children: ReactElement;
|
||||
}
|
||||
|
||||
export const BalanceManager = ({ children }: BalanceManagerProps) => {
|
||||
const contracts = useContracts();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { account } = useWeb3React();
|
||||
const {
|
||||
appState: { decimals },
|
||||
@@ -23,6 +27,20 @@ export const BalanceManager = ({ children }: BalanceManagerProps) => {
|
||||
const { updateBalances: updateStoreBalances } = useBalances();
|
||||
const { config } = useEthereumConfig();
|
||||
|
||||
const numberOfConfirmations = config?.confirmations || 0;
|
||||
|
||||
useListenForAssociationEvents(
|
||||
contracts?.staking.contract,
|
||||
pubKey,
|
||||
numberOfConfirmations
|
||||
);
|
||||
|
||||
useListenForAssociationEvents(
|
||||
contracts?.vesting.contract,
|
||||
pubKey,
|
||||
numberOfConfirmations
|
||||
);
|
||||
|
||||
const getUserTrancheBalances = useGetUserTrancheBalances(
|
||||
account || '',
|
||||
contracts?.vesting
|
||||
@@ -34,7 +52,7 @@ export const BalanceManager = ({ children }: BalanceManagerProps) => {
|
||||
);
|
||||
|
||||
// update balances on connect to Ethereum
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
const updateBalances = async () => {
|
||||
if (!account || !config) return;
|
||||
try {
|
||||
@@ -75,13 +93,13 @@ export const BalanceManager = ({ children }: BalanceManagerProps) => {
|
||||
]);
|
||||
|
||||
// This use effect hook is very expensive and is kept separate to prevent expensive reloading of data.
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
if (account) {
|
||||
getUserTrancheBalances();
|
||||
}
|
||||
}, [account, getUserTrancheBalances]);
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
if (account) {
|
||||
getAssociationBreakdown();
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ export const LockedProgress = ({
|
||||
unlocked,
|
||||
leftLabel,
|
||||
rightLabel,
|
||||
leftColor = Colors.vega.pink,
|
||||
rightColor = Colors.vega.green,
|
||||
leftColor = Colors.vega.pink.DEFAULT,
|
||||
rightColor = Colors.vega.green.DEFAULT,
|
||||
decimals = 2,
|
||||
}: LockedProgressProps) => {
|
||||
const lockedPercentage = React.useMemo(() => {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import { ViewingAsBanner } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
ViewingAsBanner,
|
||||
AnnouncementBanner,
|
||||
ExternalLink,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import React from 'react';
|
||||
|
||||
@@ -15,6 +19,14 @@ export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
|
||||
const { isReadOnly, pubKey, disconnect } = useVegaWallet();
|
||||
return (
|
||||
<>
|
||||
<AnnouncementBanner>
|
||||
<div className="font-alpha calt uppercase text-center text-lg text-white">
|
||||
<span className="pr-4">The Mainnet sims are live!</span>
|
||||
<ExternalLink href="https://fairground.wtf/">
|
||||
Come help stress test the network
|
||||
</ExternalLink>
|
||||
</div>
|
||||
</AnnouncementBanner>
|
||||
<Nav navbarTheme={VEGA_ENV === Networks.TESTNET ? 'yellow' : 'dark'} />
|
||||
{isReadOnly ? (
|
||||
<ViewingAsBanner pubKey={pubKey} disconnect={disconnect} />
|
||||
|
||||
@@ -25,6 +25,8 @@ import { usePollForDelegations } from './hooks';
|
||||
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||
import { Button, ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { toBigNum } from '@vegaprotocol/react-helpers';
|
||||
import { usePendingBalancesStore } from '../../hooks/use-pending-balances-manager';
|
||||
import { StakingEventType } from '../../hooks/use-get-association-breakdown';
|
||||
|
||||
export const VegaWallet = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -119,6 +121,10 @@ interface VegaWalletConnectedProps {
|
||||
}
|
||||
|
||||
const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
|
||||
const pendingBalances = usePendingBalancesStore(
|
||||
(state) => state.pendingBalances
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
appDispatch,
|
||||
@@ -126,6 +132,27 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
|
||||
} = useAppState();
|
||||
const { delegations, currentStakeAvailable, delegatedNodes, accounts } =
|
||||
usePollForDelegations();
|
||||
const amountRemoved = BigNumber.sum.apply(null, [
|
||||
new BigNumber(0),
|
||||
...pendingBalances
|
||||
.filter(({ event }) => event === StakingEventType.Stake_Removed)
|
||||
.map(({ args }) => toBigNum(args?.[1].toString(), decimals)),
|
||||
]);
|
||||
|
||||
const amountAdded = BigNumber.sum.apply(null, [
|
||||
new BigNumber(0),
|
||||
...pendingBalances
|
||||
.filter(({ event }) => event === StakingEventType.Stake_Deposited)
|
||||
.map(({ args }) => toBigNum(args?.[1].toString(), decimals)),
|
||||
]);
|
||||
const totalPending = React.useMemo(
|
||||
() => amountRemoved.plus(amountAdded),
|
||||
[amountAdded, amountRemoved]
|
||||
);
|
||||
const pendingStakeAmount = React.useMemo(
|
||||
() => currentStakeAvailable.plus(amountAdded).minus(amountRemoved),
|
||||
[amountAdded, amountRemoved, currentStakeAvailable]
|
||||
);
|
||||
|
||||
const unstaked = React.useMemo(() => {
|
||||
const totalDelegated = delegations.reduce<BigNumber>(
|
||||
@@ -161,6 +188,26 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
|
||||
symbol="VEGA"
|
||||
balance={currentStakeAvailable}
|
||||
/>
|
||||
{totalPending.eq(0) ? null : (
|
||||
<>
|
||||
<WalletCardAsset
|
||||
image={vegaWhite}
|
||||
decimals={decimals}
|
||||
name="VEGA"
|
||||
subheading={t('Pending association')}
|
||||
symbol="VEGA"
|
||||
balance={totalPending}
|
||||
/>
|
||||
<WalletCardAsset
|
||||
image={vegaWhite}
|
||||
decimals={decimals}
|
||||
name="VEGA"
|
||||
subheading={t('Total associated after pending')}
|
||||
symbol="VEGA"
|
||||
balance={pendingStakeAmount}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div data-testid="vega-wallet-balance-unstaked">
|
||||
<WalletCardRow label={t('unstaked')} value={unstaked} />
|
||||
</div>
|
||||
|
||||
@@ -30,9 +30,12 @@ export function useAnimateValue(
|
||||
) {
|
||||
elRef.current?.animate(
|
||||
[
|
||||
{ backgroundColor: customColors.vega.pink, color: colors.white },
|
||||
{
|
||||
backgroundColor: customColors.vega.pink,
|
||||
backgroundColor: customColors.vega.pink.DEFAULT,
|
||||
color: colors.white,
|
||||
},
|
||||
{
|
||||
backgroundColor: customColors.vega.pink.DEFAULT,
|
||||
color: colors.white,
|
||||
offset: 0.8,
|
||||
},
|
||||
@@ -53,11 +56,11 @@ export function useAnimateValue(
|
||||
elRef.current?.animate(
|
||||
[
|
||||
{
|
||||
backgroundColor: customColors.vega.green,
|
||||
backgroundColor: customColors.vega.green.DEFAULT,
|
||||
color: colors.white,
|
||||
},
|
||||
{
|
||||
backgroundColor: customColors.vega.green,
|
||||
backgroundColor: customColors.vega.green.DEFAULT,
|
||||
color: colors.white,
|
||||
offset: 0.8,
|
||||
},
|
||||
|
||||
@@ -11,6 +11,11 @@ import { useAppState } from '../contexts/app-state/app-state-context';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { useBalances } from '../lib/balances/balances-store';
|
||||
|
||||
export enum StakingEventType {
|
||||
Stake_Removed = 'Stake_Removed',
|
||||
Stake_Deposited = 'Stake_Deposited',
|
||||
}
|
||||
|
||||
export function useGetAssociationBreakdown(
|
||||
ethAddress: string,
|
||||
staking: StakingBridge,
|
||||
@@ -63,8 +68,8 @@ function combineStakeEventsByVegaKey(
|
||||
const res = events.reduce((obj, e) => {
|
||||
const vegaKey = e.args?.vega_public_key;
|
||||
const amount = parseEventAmount(e, decimals);
|
||||
const isDeposit = e.event === 'Stake_Deposited';
|
||||
const isRemove = e.event === 'Stake_Removed';
|
||||
const isDeposit = e.event === StakingEventType.Stake_Deposited;
|
||||
const isRemove = e.event === StakingEventType.Stake_Removed;
|
||||
|
||||
if (!isDeposit && !isRemove) return obj;
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import { useListenForPendingEthEvents } from './use-listen-for-pending-eth-events';
|
||||
import { renderHook, cleanup, waitFor } from '@testing-library/react';
|
||||
import type { Contract, EventFilter, Event } from 'ethers';
|
||||
|
||||
let contract: Contract;
|
||||
let filter: EventFilter;
|
||||
let addPendingTxs: (event: Event[]) => void;
|
||||
let removePendingTx: (event: Event) => void;
|
||||
let resetPendingTxs: () => void;
|
||||
|
||||
beforeEach(() => {
|
||||
contract = {
|
||||
on: jest.fn(),
|
||||
off: jest.fn(),
|
||||
queryFilter: jest.fn().mockResolvedValue([]),
|
||||
} as unknown as Contract;
|
||||
filter = {} as EventFilter;
|
||||
addPendingTxs = jest.fn();
|
||||
removePendingTx = jest.fn();
|
||||
resetPendingTxs = jest.fn();
|
||||
});
|
||||
|
||||
jest.mock('@web3-react/core', () => ({
|
||||
useWeb3React: () => ({
|
||||
provider: {
|
||||
getBlockNumber: jest.fn().mockResolvedValue(1),
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('useListenForPendingEthEvents', () => {
|
||||
it('listens for events on contract', async () => {
|
||||
renderHook(() =>
|
||||
useListenForPendingEthEvents(
|
||||
1,
|
||||
contract,
|
||||
filter,
|
||||
addPendingTxs,
|
||||
removePendingTx,
|
||||
resetPendingTxs
|
||||
)
|
||||
);
|
||||
|
||||
expect(contract.on).toHaveBeenCalledWith(filter, expect.any(Function));
|
||||
cleanup();
|
||||
expect(contract.off).toHaveBeenCalledWith(filter, expect.any(Function));
|
||||
});
|
||||
|
||||
it('waits for correct number of confirmations before removing tx from pending txs', async () => {
|
||||
renderHook(() => {
|
||||
useListenForPendingEthEvents(
|
||||
2,
|
||||
contract,
|
||||
filter,
|
||||
addPendingTxs,
|
||||
removePendingTx,
|
||||
resetPendingTxs
|
||||
);
|
||||
});
|
||||
|
||||
const listener = (contract.on as jest.Mock).mock.calls[0][1];
|
||||
const event = {
|
||||
getTransaction: jest.fn().mockResolvedValue({
|
||||
wait: jest.fn().mockResolvedValue({}),
|
||||
}),
|
||||
} as unknown as Event;
|
||||
listener(null, null, null, event);
|
||||
|
||||
expect(addPendingTxs).toHaveBeenCalledWith([event]);
|
||||
expect(removePendingTx).not.toHaveBeenCalled();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(removePendingTx).toHaveBeenCalledWith(event);
|
||||
});
|
||||
});
|
||||
|
||||
it('gets existing transactions', async () => {
|
||||
const event = {
|
||||
getTransaction: jest.fn().mockResolvedValue({
|
||||
wait: jest.fn().mockResolvedValue(null),
|
||||
}),
|
||||
} as unknown as Event;
|
||||
|
||||
contract.queryFilter = jest.fn().mockResolvedValue([event]);
|
||||
|
||||
renderHook(() => {
|
||||
useListenForPendingEthEvents(
|
||||
2,
|
||||
contract,
|
||||
filter,
|
||||
addPendingTxs,
|
||||
removePendingTx,
|
||||
resetPendingTxs
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(contract.queryFilter).toHaveBeenCalledWith(filter, -1);
|
||||
expect(addPendingTxs).toHaveBeenCalledWith([event]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,103 @@
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import type { Contract, Event, EventFilter } from 'ethers';
|
||||
|
||||
export const useListenForPendingEthEvents = (
|
||||
numberOfConfirmations: number,
|
||||
contract: Contract | undefined,
|
||||
filter: EventFilter | null,
|
||||
addPendingTxs: (event: Event[]) => void,
|
||||
removePendingTx: (event: Event) => void,
|
||||
resetPendingTxs: () => void
|
||||
) => {
|
||||
const { provider } = useWeb3React();
|
||||
|
||||
/**
|
||||
* Add listener for the ethereum events on the contract passed in for the filter passed in.
|
||||
* Push the event into the store and wait for the correct number of confirmations before removing it.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (!contract || !filter) {
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const listener = async (...args: any[]) => {
|
||||
try {
|
||||
const event = args[3] as Event;
|
||||
addPendingTxs([event]);
|
||||
const tx = await event.getTransaction();
|
||||
await tx.wait(numberOfConfirmations);
|
||||
removePendingTx(event);
|
||||
} catch (e) {
|
||||
Sentry.captureException(`Error listening for pending eth events ${e}`);
|
||||
}
|
||||
};
|
||||
|
||||
contract.on(filter, listener);
|
||||
|
||||
return () => {
|
||||
contract.off(filter, listener);
|
||||
};
|
||||
}, [addPendingTxs, contract, filter, numberOfConfirmations, removePendingTx]);
|
||||
|
||||
/**
|
||||
* Get all transactions that exist on the blockchain but have yet to reach the number of confirmations
|
||||
*/
|
||||
const getExistingTransactions = useCallback(async () => {
|
||||
const blockNumber = (await provider?.getBlockNumber()) || 0;
|
||||
if (!filter || !contract) {
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
return await contract.queryFilter(
|
||||
filter,
|
||||
blockNumber - numberOfConfirmations
|
||||
);
|
||||
} catch (e) {
|
||||
Sentry.captureException(`Error getting existing transactions ${e}`);
|
||||
return [];
|
||||
}
|
||||
}, [contract, filter, numberOfConfirmations, provider]);
|
||||
|
||||
const waitForExistingTransactions = useCallback(
|
||||
(events: Event[], numberOfConfirmations: number) => {
|
||||
events.map(async (event) => {
|
||||
try {
|
||||
const tx = await event.getTransaction();
|
||||
|
||||
await tx.wait(Math.max(numberOfConfirmations, 0));
|
||||
|
||||
removePendingTx(event);
|
||||
} catch (e) {
|
||||
Sentry.captureException(
|
||||
`Error waiting for existing transactions ${e}`
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
[removePendingTx]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
resetPendingTxs();
|
||||
getExistingTransactions().then((events) => {
|
||||
if (!cancelled) {
|
||||
addPendingTxs([...events]);
|
||||
waitForExistingTransactions([...events], numberOfConfirmations);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [
|
||||
addPendingTxs,
|
||||
getExistingTransactions,
|
||||
numberOfConfirmations,
|
||||
resetPendingTxs,
|
||||
waitForExistingTransactions,
|
||||
]);
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
import { useMemo } from 'react';
|
||||
import { usePendingBalancesStore } from './use-pending-balances-manager';
|
||||
import type { Contract } from 'ethers';
|
||||
import { useListenForPendingEthEvents } from './use-listen-for-pending-eth-events';
|
||||
import { prepend0x } from '@vegaprotocol/smart-contracts';
|
||||
|
||||
export const useListenForStakingEvents = (
|
||||
contract: Contract | undefined,
|
||||
vegaPublicKey: string | null,
|
||||
numberOfConfirmations: number
|
||||
) => {
|
||||
const { addPendingTxs, removePendingTx, resetPendingTxs } =
|
||||
usePendingBalancesStore((state) => ({
|
||||
addPendingTxs: state.addPendingTxs,
|
||||
removePendingTx: state.removePendingTx,
|
||||
resetPendingTxs: state.resetPendingTxs,
|
||||
}));
|
||||
const addFilter = useMemo(
|
||||
() =>
|
||||
vegaPublicKey && contract
|
||||
? contract.filters.Stake_Deposited(null, null, prepend0x(vegaPublicKey))
|
||||
: null,
|
||||
[contract, vegaPublicKey]
|
||||
);
|
||||
const removeFilter = useMemo(
|
||||
() =>
|
||||
vegaPublicKey && contract
|
||||
? contract.filters.Stake_Removed(null, null, prepend0x(vegaPublicKey))
|
||||
: null,
|
||||
[contract, vegaPublicKey]
|
||||
);
|
||||
|
||||
/**
|
||||
* Listen for all add stake events
|
||||
*/
|
||||
useListenForPendingEthEvents(
|
||||
numberOfConfirmations,
|
||||
contract,
|
||||
addFilter,
|
||||
addPendingTxs,
|
||||
removePendingTx,
|
||||
resetPendingTxs
|
||||
);
|
||||
|
||||
/**
|
||||
* Listen for all remove stake events
|
||||
*/
|
||||
useListenForPendingEthEvents(
|
||||
numberOfConfirmations,
|
||||
contract,
|
||||
removeFilter,
|
||||
addPendingTxs,
|
||||
removePendingTx,
|
||||
resetPendingTxs
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
import { act } from '@testing-library/react-hooks';
|
||||
import { usePendingBalancesStore } from './use-pending-balances-manager';
|
||||
import type { Event } from 'ethers';
|
||||
|
||||
afterEach(() => {
|
||||
usePendingBalancesStore.setState((state) => ({
|
||||
...state,
|
||||
pendingBalances: [],
|
||||
}));
|
||||
});
|
||||
|
||||
const event1 = { transactionHash: 'tx1' } as Event;
|
||||
const event2 = { transactionHash: 'tx2' } as Event;
|
||||
|
||||
describe('usePendingBalancesStore', () => {
|
||||
it('should add new events to the pendingBalances state and remove duplicates', () => {
|
||||
const { addPendingTxs } = usePendingBalancesStore.getState();
|
||||
const duplicateEvent = { transactionHash: 'tx1' } as Event;
|
||||
|
||||
act(() => {
|
||||
addPendingTxs([event1, duplicateEvent]);
|
||||
});
|
||||
|
||||
expect(usePendingBalancesStore.getState().pendingBalances).toEqual([
|
||||
event1,
|
||||
]);
|
||||
|
||||
act(() => {
|
||||
addPendingTxs([event2]);
|
||||
});
|
||||
|
||||
expect(usePendingBalancesStore.getState().pendingBalances).toEqual([
|
||||
event1,
|
||||
event2,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should remove a specific event from the pendingBalances state', () => {
|
||||
const { addPendingTxs, removePendingTx } =
|
||||
usePendingBalancesStore.getState();
|
||||
const eventToRemove = { transactionHash: 'tx1' } as Event;
|
||||
|
||||
act(() => {
|
||||
addPendingTxs([eventToRemove, event2]);
|
||||
});
|
||||
expect(usePendingBalancesStore.getState().pendingBalances).toEqual([
|
||||
eventToRemove,
|
||||
event2,
|
||||
]);
|
||||
|
||||
act(() => {
|
||||
removePendingTx(eventToRemove);
|
||||
});
|
||||
expect(usePendingBalancesStore.getState().pendingBalances).toEqual([
|
||||
event2,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should reset the pendingBalances state', () => {
|
||||
const { addPendingTxs, resetPendingTxs } =
|
||||
usePendingBalancesStore.getState();
|
||||
|
||||
act(() => {
|
||||
addPendingTxs([event1, event2]);
|
||||
});
|
||||
expect(usePendingBalancesStore.getState().pendingBalances).toEqual([
|
||||
event1,
|
||||
event2,
|
||||
]);
|
||||
|
||||
act(() => {
|
||||
resetPendingTxs();
|
||||
});
|
||||
expect(usePendingBalancesStore.getState().pendingBalances).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { Event } from 'ethers';
|
||||
import uniqBy from 'lodash/uniqBy';
|
||||
|
||||
import create from 'zustand';
|
||||
|
||||
export type PendingTxsStore = {
|
||||
pendingBalances: Event[];
|
||||
addPendingTxs: (event: Event[]) => void;
|
||||
removePendingTx: (event: Event) => void;
|
||||
resetPendingTxs: () => void;
|
||||
};
|
||||
|
||||
export const usePendingBalancesStore = create<PendingTxsStore>((set, get) => ({
|
||||
pendingBalances: [],
|
||||
addPendingTxs: (event: Event[]) => {
|
||||
set({
|
||||
pendingBalances: uniqBy(
|
||||
[...get().pendingBalances, ...event],
|
||||
'transactionHash'
|
||||
),
|
||||
});
|
||||
},
|
||||
removePendingTx: (event: Event) => {
|
||||
set({
|
||||
pendingBalances: [
|
||||
...get().pendingBalances.filter(
|
||||
({ transactionHash }) => transactionHash !== event.transactionHash
|
||||
),
|
||||
],
|
||||
});
|
||||
},
|
||||
resetPendingTxs: () => {
|
||||
set({ pendingBalances: [] });
|
||||
},
|
||||
}));
|
||||
@@ -102,7 +102,7 @@ export const VoteDetails = ({
|
||||
</table>
|
||||
</section>
|
||||
)}
|
||||
<section>
|
||||
<section data-testid="votes-table">
|
||||
<SubHeading title={t('tokenVotes')} />
|
||||
<p>
|
||||
<span>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Dialog, Icon, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import Routes from '../../routes';
|
||||
import type { StakeAction } from './staking-form';
|
||||
import { Actions, RemoveType } from './staking-form';
|
||||
@@ -23,6 +23,7 @@ export const StakeSuccess = ({
|
||||
toggleDialog,
|
||||
}: StakeSuccessProps) => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const isAdd = action === Actions.Add;
|
||||
const title = isAdd
|
||||
? t('stakeAddSuccessTitle', { amount })
|
||||
@@ -44,7 +45,15 @@ export const StakeSuccess = ({
|
||||
<div>
|
||||
<p>{message}</p>
|
||||
<p>
|
||||
<Link className="underline" to={Routes.VALIDATORS}>
|
||||
<Link
|
||||
className="underline"
|
||||
to={Routes.VALIDATORS}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
toggleDialog();
|
||||
setTimeout(() => navigate(Routes.VALIDATORS), 0);
|
||||
}}
|
||||
>
|
||||
{t('backToStaking')}
|
||||
</Link>
|
||||
</p>
|
||||
|
||||
@@ -29,7 +29,7 @@ export const TrancheProgress = ({
|
||||
<span className="tranches__progress-title">{t('Locked')}</span>
|
||||
<ProgressBar
|
||||
width={220}
|
||||
color={Colors.vega.pink}
|
||||
color={Colors.vega.pink.DEFAULT}
|
||||
percentage={lockedPercentage}
|
||||
/>
|
||||
<span className="tranches__progress-numbers">
|
||||
@@ -40,7 +40,7 @@ export const TrancheProgress = ({
|
||||
<span className="tranches__progress-title">{t('Redeemed')}</span>
|
||||
<ProgressBar
|
||||
width={220}
|
||||
color={Colors.vega.green}
|
||||
color={Colors.vega.green.DEFAULT}
|
||||
percentage={removedPercentage}
|
||||
/>
|
||||
<span className="tranches__progress-numbers">
|
||||
|
||||
@@ -34,10 +34,10 @@ export const VestingChart = () => {
|
||||
<AreaChart data={data}>
|
||||
<defs>
|
||||
{[
|
||||
['pink', Colors.vega.pink],
|
||||
['green', Colors.vega.green],
|
||||
['pink', Colors.vega.pink.DEFAULT],
|
||||
['green', Colors.vega.green.DEFAULT],
|
||||
['orange', Colors.warning],
|
||||
['yellow', Colors.vega.yellow],
|
||||
['yellow', Colors.vega.yellow.DEFAULT],
|
||||
].map(([key, color]) => (
|
||||
<linearGradient key={key} id={key} x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stopColor={color} stopOpacity={0.85} />
|
||||
@@ -97,7 +97,7 @@ export const VestingChart = () => {
|
||||
dot={false}
|
||||
type="linear"
|
||||
dataKey="team"
|
||||
stroke={Colors.vega.pink}
|
||||
stroke={Colors.vega.pink.DEFAULT}
|
||||
fill="url(#pink)"
|
||||
yAxisId={0}
|
||||
strokeWidth={2}
|
||||
@@ -109,7 +109,7 @@ export const VestingChart = () => {
|
||||
dot={false}
|
||||
type="monotone"
|
||||
dataKey="earlyInvestors"
|
||||
stroke={Colors.vega.green}
|
||||
stroke={Colors.vega.green.DEFAULT}
|
||||
fill="url(#green)"
|
||||
yAxisId={0}
|
||||
strokeWidth={2}
|
||||
@@ -121,7 +121,7 @@ export const VestingChart = () => {
|
||||
dot={false}
|
||||
type="monotone"
|
||||
dataKey="publicSale"
|
||||
stroke={Colors.vega.yellow}
|
||||
stroke={Colors.vega.yellow.DEFAULT}
|
||||
fill="url(#yellow)"
|
||||
yAxisId={0}
|
||||
strokeWidth={2}
|
||||
|
||||
@@ -21,15 +21,21 @@ const orderUpdatedAt = 'updatedAt';
|
||||
const assetSelectField = 'select[name="asset"]';
|
||||
const amountField = 'input[name="amount"]';
|
||||
const txTimeout = Cypress.env('txTimeout');
|
||||
const btcName = 'BTC (local)';
|
||||
const sepoliaUrl = Cypress.env('ETHERSCAN_URL');
|
||||
const btcName =
|
||||
'BTC (local)5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c - tBTC';
|
||||
const btcSymbol = 'tBTC';
|
||||
const usdcSymbol = 'fUSDC';
|
||||
const toastContent = 'toast-content';
|
||||
const ordersTab = 'Orders';
|
||||
const depositsTab = 'Deposits';
|
||||
const toastCloseBtn = 'toast-close';
|
||||
const price = '390';
|
||||
const size = '0.0005';
|
||||
const newPrice = '200';
|
||||
|
||||
// TODO: ensure this test runs only if capsule is running via workflow
|
||||
// Because the tests are run on a live network to optimize time, the tests are interdependent and must be run in the given order.
|
||||
describe('capsule', { tags: '@slow' }, () => {
|
||||
before(() => {
|
||||
cy.createMarket();
|
||||
@@ -50,8 +56,8 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
marketId: market.id,
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
size: '0.0005',
|
||||
price: '390',
|
||||
size: size,
|
||||
price: price,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
};
|
||||
const rawPrice = removeDecimal(order.price, market.decimalPlaces);
|
||||
@@ -64,7 +70,8 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
|
||||
cy.getByTestId(toastContent).should(
|
||||
'contain.text',
|
||||
`ConfirmedYour transaction has been confirmed View in block explorerSubmit order - activeTEST.24h+0.0005 @ 390.00 ${usdcSymbol}`
|
||||
`ConfirmedYour transaction has been confirmed View in block explorerSubmit order - activeTEST.24h+${order.size} @ ${order.price}.00 ${usdcSymbol}`,
|
||||
{ matchCase: false }
|
||||
);
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
// orderbook cells are keyed by price level
|
||||
@@ -75,7 +82,7 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
.should('contain.text', rawSize);
|
||||
|
||||
cy.getByTestId(ordersTab).click();
|
||||
cy.getByTestId('edit').should('contain.text', 'Edit');
|
||||
cy.getByTestId('edit', txTimeout).should('contain.text', 'Edit');
|
||||
cy.getByTestId('tab-orders').within(() => {
|
||||
cy.get('.ag-center-cols-container')
|
||||
.children()
|
||||
@@ -113,35 +120,41 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
checkIfDataAndTimeOfCreationAndUpdateIsEqual(orderCreatedAt);
|
||||
});
|
||||
});
|
||||
//edit order
|
||||
});
|
||||
|
||||
it('can edit order', function () {
|
||||
cy.getByTestId(ordersTab).click();
|
||||
cy.getByTestId('edit').first().should('be.visible').click();
|
||||
cy.getByTestId('dialog-title').should('contain.text', 'Edit order');
|
||||
cy.get('#limitPrice').focus().clear().type('200');
|
||||
cy.get('#limitPrice').focus().clear().type(newPrice);
|
||||
cy.getByTestId('edit-order').find('[type="submit"]').click();
|
||||
cy.getByTestId(toastContent).should(
|
||||
'contain.text',
|
||||
`ConfirmedYour transaction has been confirmed View in block explorerEdit order - activeTEST.24h+0.0005 @ 200.00 ${usdcSymbol}+0.0005 @ 200.00 ${usdcSymbol}`
|
||||
`ConfirmedYour transaction has been confirmed View in block explorerEdit order - activeTEST.24h+${size} @ ${price}.00 ${usdcSymbol}+${size} @ ${newPrice}.00 ${usdcSymbol}`,
|
||||
{ matchCase: false }
|
||||
);
|
||||
cy.getByTestId(ordersTab).click();
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
cy.getByTestId(toastCloseBtn).click({ multiple: true });
|
||||
cy.get('.ag-center-cols-container')
|
||||
.children()
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get(`[col-id='${orderPrice}']`).then(($price) => {
|
||||
expect(parseFloat($price.text())).to.equal(parseFloat('200'));
|
||||
expect(parseFloat($price.text())).to.equal(parseFloat(newPrice));
|
||||
});
|
||||
checkIfDataAndTimeOfCreationAndUpdateIsEqual(orderUpdatedAt);
|
||||
});
|
||||
//cancel order
|
||||
});
|
||||
|
||||
it('can cancel order', function () {
|
||||
cy.getByTestId(ordersTab).click();
|
||||
cy.getByTestId('cancel').first().click();
|
||||
cy.getByTestId(toastContent).should(
|
||||
'contain.text',
|
||||
`ConfirmedYour transaction has been confirmed View in block explorerCancel order - cancelledTEST.24h+0.0005 @ 200.00 ${usdcSymbol}`
|
||||
`ConfirmedYour transaction has been confirmed View in block explorerCancel order - cancelledTEST.24h+${size} @ ${newPrice}.00 ${usdcSymbol}`,
|
||||
{ matchCase: false }
|
||||
);
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
cy.getByTestId(toastCloseBtn).click({ multiple: true });
|
||||
|
||||
cy.getByTestId('tab-orders')
|
||||
.get('.ag-center-cols-container')
|
||||
@@ -151,7 +164,10 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
.should('contain.text', OrderStatusMapping.STATUS_CANCELLED);
|
||||
});
|
||||
|
||||
it('can deposit and withdrawal', function () {
|
||||
it('can deposit', function () {
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
|
||||
// 1001-DEPO-001
|
||||
// 1001-DEPO-002
|
||||
// 1001-DEPO-003
|
||||
@@ -160,27 +176,12 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
// 1001-DEPO-007
|
||||
// 1001-DEPO-008
|
||||
// 1001-DEPO-009
|
||||
// 1002-WITH-001
|
||||
// 1002-WITH-006
|
||||
// 1002-WITH-009
|
||||
// 002-WITH-011
|
||||
// 1002-WITH-024
|
||||
// 1002-WITH-012
|
||||
// 1002-WITH-013
|
||||
// 1002-WITH-014
|
||||
// 1002-WITH-015
|
||||
// 1002-WITH-016
|
||||
// 1002-WITH-019
|
||||
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
|
||||
cy.highlight('creating deposit');
|
||||
// 1001-DEPO-010
|
||||
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
connectEthereumWallet('Unknown');
|
||||
cy.get(assetSelectField, txTimeout).select(btcName);
|
||||
cy.get(assetSelectField, txTimeout).select(btcName, { force: true });
|
||||
cy.getByTestId('deposit-approve-submit').click();
|
||||
cy.getByTestId('dialog-title').should('contain.text', 'Approve complete');
|
||||
cy.get('[data-testid="Return to deposit"]').click();
|
||||
@@ -188,7 +189,8 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
cy.getByTestId('deposit-submit').click();
|
||||
cy.getByTestId(toastContent, txTimeout).should(
|
||||
'contain.text',
|
||||
`Transaction completedYour transaction has been completedView on EtherscanDeposit 1.00 ${btcSymbol}`
|
||||
`Transaction confirmedYour transaction has been confirmed.View on EtherscanDeposit 1.00 ${btcSymbol}`,
|
||||
{ matchCase: false }
|
||||
);
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
cy.getByTestId('Collateral').click();
|
||||
@@ -196,8 +198,6 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
cy.highlight('deposit verification');
|
||||
|
||||
cy.getByTestId('asset', txTimeout).should('contain.text', btcSymbol);
|
||||
// need to reload page to see deposit history complete
|
||||
cy.reload();
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.get('.ag-cell-value', txTimeout).should('contain.text', btcSymbol);
|
||||
cy.get('[col-id="status"]').should('not.have.text', 'Open', txTimeout);
|
||||
@@ -214,15 +214,29 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
cy.get('[col-id="txHash"]')
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://sepolia.etherscan.io/tx');
|
||||
.and('contain', `${sepoliaUrl}/tx/0x`);
|
||||
});
|
||||
});
|
||||
|
||||
cy.highlight('creating withdrawals');
|
||||
it('can withdrawal', function () {
|
||||
// 1002-WITH-001
|
||||
// 1002-WITH-006
|
||||
// 1002-WITH-009
|
||||
// 1002-WITH-011
|
||||
// 1002-WITH-024
|
||||
// 1002-WITH-012
|
||||
// 1002-WITH-013
|
||||
// 1002-WITH-014
|
||||
// 1002-WITH-015
|
||||
// 1002-WITH-016
|
||||
// 1002-WITH-019
|
||||
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
cy.getByTestId('withdraw-dialog-button').click();
|
||||
connectEthereumWallet('Unknown');
|
||||
cy.get(assetSelectField).select(btcName);
|
||||
cy.get(assetSelectField, txTimeout).select(
|
||||
'BTC (local)5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c - tBTC',
|
||||
{ force: true }
|
||||
);
|
||||
cy.get(amountField).clear().type('1');
|
||||
cy.getByTestId('submit-withdrawal').click();
|
||||
cy.getByTestId(toastContent, txTimeout).should(
|
||||
@@ -243,7 +257,7 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
cy.getByTestId('toast-complete-withdrawal').click();
|
||||
cy.getByTestId(toastContent, txTimeout).should(
|
||||
'contain.text',
|
||||
'Transaction completed'
|
||||
'Transaction confirmed'
|
||||
);
|
||||
|
||||
cy.getByTestId('complete-withdrawal', txTimeout).should('not.exist');
|
||||
@@ -258,17 +272,28 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
cy.get('[col-id="details.receiverAddress"]')
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://sepolia.etherscan.io/address/');
|
||||
.and('contain', `${sepoliaUrl}/address/`);
|
||||
cy.get('[col-id="createdTimestamp"]').should('not.be.empty');
|
||||
cy.get('[col-id="withdrawnTimestamp"]').should('not.be.empty');
|
||||
cy.get('[col-id="status"]').should('have.text', 'Completed');
|
||||
cy.get('[col-id="txHash"]')
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://sepolia.etherscan.io/tx/0x');
|
||||
.and('contain', `${sepoliaUrl}/tx/0x`);
|
||||
});
|
||||
});
|
||||
|
||||
it('deposit - if approved amount is less than deposit: must see that an approval is needed and be prompted to approve more', function () {
|
||||
// 1001-DEPO-006
|
||||
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
cy.get(assetSelectField, txTimeout).select(btcName, { force: true });
|
||||
cy.get(amountField).clear().type('20000000');
|
||||
cy.getByTestId('deposit-approve-submit').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
function checkIfDataAndTimeOfCreationAndUpdateIsEqual(date: string) {
|
||||
cy.get(`[col-id='${date}'] .ag-cell-wrapper`)
|
||||
.children('span')
|
||||
|
||||
@@ -56,6 +56,7 @@ describe('deposit form validation', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
it('insufficient funds', () => {
|
||||
// 1001-DEPO-005
|
||||
// Deposit amount is valid, but less than approved. This will always be the case because our
|
||||
// CI wallet wont have approved any assets
|
||||
cy.get(amountField)
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import { marketQuery } from '@vegaprotocol/mock';
|
||||
import { getDateTimeFormat } from '@vegaprotocol/react-helpers';
|
||||
|
||||
describe('markets table', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
@@ -111,6 +114,53 @@ describe('markets table', { tags: '@smoke' }, () => {
|
||||
`${Cypress.env('VEGA_TOKEN_URL')}/proposals/propose/new-market`
|
||||
);
|
||||
});
|
||||
|
||||
it('opening auction subsets should be properly displayed', () => {
|
||||
cy.mockTradingPage(
|
||||
Schema.MarketState.STATE_ACTIVE,
|
||||
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION
|
||||
);
|
||||
cy.mockGQL((req) => {
|
||||
const override = {
|
||||
market: {
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
name: `opening auction MARKET`,
|
||||
},
|
||||
},
|
||||
state: Schema.MarketState.STATE_ACTIVE,
|
||||
tradingMode: Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
|
||||
},
|
||||
};
|
||||
const market = marketQuery(override);
|
||||
aliasGQLQuery(req, 'Market', market);
|
||||
aliasGQLQuery(req, 'ProposalOfMarket', {
|
||||
proposal: { terms: { enactmentDatetime: '2023-01-31 12:00:01' } },
|
||||
});
|
||||
});
|
||||
cy.visit('/');
|
||||
cy.visit('#/markets/market-0');
|
||||
cy.getByTestId('item-value').contains('Opening auction').realHover();
|
||||
cy.getByTestId('opening-auction-sub-status').should(
|
||||
'contain.text',
|
||||
'Opening auction: Not enough liquidity to open'
|
||||
);
|
||||
|
||||
const now = new Date(Date.parse('2023-01-30 12:00:01')).getTime();
|
||||
cy.clock(now, ['Date']); // Set "now" to BEFORE reservation
|
||||
cy.visit('/');
|
||||
cy.visit('#/markets/market-0');
|
||||
cy.getByTestId('item-value').contains('Opening auction').realHover();
|
||||
cy.getByTestId('opening-auction-sub-status').should(
|
||||
'contain.text',
|
||||
`Opening auction: Closing on ${getDateTimeFormat().format(
|
||||
new Date('2023-01-31 12:00:01')
|
||||
)}`
|
||||
);
|
||||
cy.clock().then((clock) => {
|
||||
clock.restore();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function openMarketDropDown() {
|
||||
|
||||
@@ -452,7 +452,7 @@ describe('limit order validations', { tags: '@smoke' }, () => {
|
||||
//7002-SORD-018
|
||||
cy.getByTestId(orderPriceField)
|
||||
.siblings('label')
|
||||
.should('have.text', 'Price (tBTC)');
|
||||
.should('have.text', 'Price (BTC)');
|
||||
});
|
||||
|
||||
it('must see warning when placing an order with expiry date in past', () => {
|
||||
|
||||
@@ -454,8 +454,4 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
it.skip('tbd for 7003-MORD', () => {
|
||||
// NOT COVERED: must see the reference, offset and direction for each part pegged order - waiting for clarification
|
||||
// NOT COVERED: must see the reference, offset and direction for each part liquidity order order - waiting for clarification
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import { t, useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
|
||||
export const DepositsContainer = () => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: depositsProvider,
|
||||
variables: { partyId: pubKey || '' },
|
||||
@@ -30,15 +30,17 @@ export const DepositsContainer = () => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full dark:bg-black bg-white absolute bottom-0 h-auto flex justify-end px-[11px] py-2">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => openDepositDialog()}
|
||||
data-testid="deposit-button"
|
||||
>
|
||||
{t('Deposit')}
|
||||
</Button>
|
||||
</div>
|
||||
{!isReadOnly && (
|
||||
<div className="w-full dark:bg-black bg-white absolute bottom-0 h-auto flex justify-end px-[11px] py-2">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => openDepositDialog()}
|
||||
data-testid="deposit-button"
|
||||
>
|
||||
{t('Deposit')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ import { t, useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { VegaWalletContainer } from '../../components/vega-wallet-container';
|
||||
|
||||
export const WithdrawalsContainer = () => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: withdrawalProvider,
|
||||
variables: { partyId: pubKey || '' },
|
||||
@@ -36,15 +36,17 @@ export const WithdrawalsContainer = () => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full dark:bg-black bg-white absolute bottom-0 h-auto flex justify-end px-[11px] py-2">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => openWithdrawDialog()}
|
||||
data-testid="withdraw-dialog-button"
|
||||
>
|
||||
{t('Make withdrawal')}
|
||||
</Button>
|
||||
</div>
|
||||
{!isReadOnly && (
|
||||
<div className="w-full dark:bg-black bg-white absolute bottom-0 h-auto flex justify-end px-[11px] py-2">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => openWithdrawDialog()}
|
||||
data-testid="withdraw-dialog-button"
|
||||
>
|
||||
{t('Make withdrawal')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</VegaWalletContainer>
|
||||
);
|
||||
|
||||
@@ -9,7 +9,7 @@ import { AccountManager } from '@vegaprotocol/accounts';
|
||||
import { useDepositDialog } from '@vegaprotocol/deposits';
|
||||
|
||||
export const AccountsContainer = () => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||
const openWithdrawalDialog = useWithdrawalDialog((store) => store.open);
|
||||
const openDepositDialog = useDepositDialog((store) => store.open);
|
||||
@@ -37,13 +37,16 @@ export const AccountsContainer = () => {
|
||||
onClickAsset={onClickAsset}
|
||||
onClickWithdraw={openWithdrawalDialog}
|
||||
onClickDeposit={openDepositDialog}
|
||||
isReadOnly={isReadOnly}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-end p-2 px-[11px]">
|
||||
<Button size="sm" onClick={() => openDepositDialog()}>
|
||||
{t('Deposit')}
|
||||
</Button>
|
||||
</div>
|
||||
{!isReadOnly && (
|
||||
<div className="flex justify-end p-2 px-[11px]">
|
||||
<Button size="sm" onClick={() => openDepositDialog()}>
|
||||
{t('Deposit')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -49,7 +49,6 @@ describe('NodeHealth', () => {
|
||||
it.each(cases)(
|
||||
'renders correct text and indicator color for $diff block difference',
|
||||
(elem) => {
|
||||
console.log(elem);
|
||||
render(<NodeHealth blockDiff={elem.diff} openNodeSwitcher={jest.fn()} />);
|
||||
expect(screen.getByTestId('indicator')).toHaveClass(elem.classname);
|
||||
expect(screen.getByText(elem.text)).toBeInTheDocument();
|
||||
|
||||
@@ -1,11 +1,25 @@
|
||||
import type { RefObject } from 'react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { useMemo } from 'react';
|
||||
import { t, useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { TradingModeTooltip } from '@vegaprotocol/deal-ticket';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { useStaticMarketData } from '@vegaprotocol/market-list';
|
||||
import { HeaderStat } from '../header';
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import { marketDataProvider } from '@vegaprotocol/market-list';
|
||||
|
||||
// This will cause often re-rendering
|
||||
// Here it may not be a problem because the component is not very complex
|
||||
// In general, we should avoid using this marketData hook without any throttling
|
||||
const useMarketData = (marketId?: string, skip?: boolean) => {
|
||||
const variables = useMemo(() => ({ marketId }), [marketId]);
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: marketDataProvider,
|
||||
variables,
|
||||
skip: skip || !marketId,
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
||||
const getTradingModeLabel = (
|
||||
tradingMode?: Schema.MarketTradingMode,
|
||||
@@ -35,7 +49,7 @@ export const HeaderStatMarketTradingMode = ({
|
||||
initialTradingMode,
|
||||
initialTrigger,
|
||||
}: HeaderStatMarketTradingModeProps) => {
|
||||
const data = useStaticMarketData(marketId);
|
||||
const data = useMarketData(marketId);
|
||||
const tradingMode = data?.marketTradingMode ?? initialTradingMode;
|
||||
const trigger = data?.trigger ?? initialTrigger;
|
||||
|
||||
@@ -61,7 +75,7 @@ export const MarketTradingMode = ({
|
||||
inViewRoot?: RefObject<Element>;
|
||||
}) => {
|
||||
const [ref, inView] = useInView({ root: inViewRoot?.current });
|
||||
const data = useStaticMarketData(marketId, !inView);
|
||||
const data = useMarketData(marketId, !inView);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
|
||||
@@ -151,6 +151,8 @@ const MARKET_B: PartialMarket = {
|
||||
};
|
||||
|
||||
describe('SelectMarket', () => {
|
||||
const table = document.createElement('table');
|
||||
|
||||
it('should render the SelectAllMarketsTableBody', () => {
|
||||
const onSelect = jest.fn();
|
||||
const onCellClick = jest.fn();
|
||||
@@ -162,7 +164,7 @@ describe('SelectMarket', () => {
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
</MemoryRouter>,
|
||||
{ wrapper: MockedProvider }
|
||||
{ wrapper: MockedProvider, container: document.body.appendChild(table) }
|
||||
);
|
||||
expect(screen.getByText('ABCDEF')).toBeTruthy(); // name
|
||||
expect(screen.getByText('25.00%')).toBeTruthy(); // price change
|
||||
|
||||
@@ -10,49 +10,49 @@ body,
|
||||
|
||||
/* Styles for allotment */
|
||||
html {
|
||||
--focus-border: theme('colors.vega.pink');
|
||||
--separator-border: theme('colors.neutral.300');
|
||||
--pennant-color-danger: theme('colors.vega.pink');
|
||||
--focus-border: theme('colors.vega.pink.500');
|
||||
--separator-border: theme('colors.vega.light.200');
|
||||
--pennant-color-danger: theme('colors.vega.pink.500');
|
||||
}
|
||||
|
||||
html.dark {
|
||||
--focus-border: theme('colors.vega.yellow');
|
||||
--separator-border: theme('colors.neutral.600');
|
||||
--focus-border: theme('colors.vega.yellow.500');
|
||||
--separator-border: theme('colors.vega.dark.200');
|
||||
}
|
||||
|
||||
.border-default {
|
||||
@apply border-neutral-300 dark:border-neutral-600;
|
||||
@apply border-vega-light-200 dark:border-vega-dark-200;
|
||||
}
|
||||
|
||||
/* Styles for charts */
|
||||
html [data-theme='dark'] {
|
||||
--pennant-color-danger: theme('colors.vega.pink');
|
||||
--pennant-color-danger: theme('colors.vega.pink.DEFAULT');
|
||||
|
||||
/* candles */
|
||||
--pennant-color-buy-fill: theme('colors.vega.green-data-dark');
|
||||
--pennant-color-buy-stroke: theme('colors.vega.green');
|
||||
--pennant-color-buy-fill: theme('colors.vega.green.650');
|
||||
--pennant-color-buy-stroke: theme('colors.vega.green.500');
|
||||
/* sell candles only use stroke as the candle is solid (without border) */
|
||||
--pennant-color-sell-stroke: theme('colors.vega.pink');
|
||||
--pennant-color-sell-stroke: theme('colors.vega.pink.500');
|
||||
|
||||
/* depth chart */
|
||||
--pennant-color-depth-buy-fill: theme('colors.vega.green-data-dark');
|
||||
--pennant-color-depth-buy-stroke: theme('colors.vega.green');
|
||||
--pennant-color-depth-sell-fill: theme('colors.vega.pink-data-dark');
|
||||
--pennant-color-depth-sell-stroke: theme('colors.vega.pink');
|
||||
--pennant-color-depth-buy-fill: theme('colors.vega.green.650');
|
||||
--pennant-color-depth-buy-stroke: theme('colors.vega.green.500');
|
||||
--pennant-color-depth-sell-fill: theme('colors.vega.pink.650');
|
||||
--pennant-color-depth-sell-stroke: theme('colors.vega.pink.500');
|
||||
}
|
||||
|
||||
html [data-theme='light'] {
|
||||
--pennant-color-danger: theme('colors.vega.pink');
|
||||
--pennant-color-danger: theme('colors.vega.pink.500');
|
||||
|
||||
/* candles */
|
||||
--pennant-color-buy-fill: theme('colors.vega.green-data-light');
|
||||
--pennant-color-buy-stroke: theme('colors.vega.green-dark');
|
||||
--pennant-color-buy-fill: theme('colors.vega.green.400');
|
||||
--pennant-color-buy-stroke: theme('colors.vega.green.550');
|
||||
/* sell candles only use stroke as the candle is solid (without border) */
|
||||
--pennant-color-sell-stroke: theme('colors.vega.pink-data-light');
|
||||
--pennant-color-sell-stroke: theme('colors.vega.pink.400');
|
||||
|
||||
/* depth chart */
|
||||
--pennant-color-depth-buy-fill: theme('colors.vega.green-data-light');
|
||||
--pennant-color-depth-buy-stroke: theme('colors.vega.green-dark');
|
||||
--pennant-color-depth-sell-fill: theme('colors.vega.pink-data-light');
|
||||
--pennant-color-depth-sell-stroke: theme('colors.vega.pink-dark');
|
||||
--pennant-color-depth-buy-fill: theme('colors.vega.green.400');
|
||||
--pennant-color-depth-buy-stroke: theme('colors.vega.green.550');
|
||||
--pennant-color-depth-sell-fill: theme('colors.vega.pink.400');
|
||||
--pennant-color-depth-sell-stroke: theme('colors.vega.pink.550');
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
const { utils } = require('@commitlint/config-nx-scopes');
|
||||
|
||||
module.exports = {
|
||||
extends: ['@commitlint/config-conventional', '@commitlint/config-nx-scopes'],
|
||||
rules: {
|
||||
'scope-empty': [2, 'never'],
|
||||
'scope-enum': async (ctx) => [
|
||||
2,
|
||||
'always',
|
||||
['ci', 'docs', ...(await utils.getProjects(ctx))],
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -23,13 +23,23 @@ jest.mock('@vegaprotocol/react-helpers', () => ({
|
||||
describe('AccountManager', () => {
|
||||
it('change partyId should reload data provider', async () => {
|
||||
const { rerender } = render(
|
||||
<AccountManager partyId="partyOne" onClickAsset={jest.fn} />
|
||||
<AccountManager
|
||||
partyId="partyOne"
|
||||
onClickAsset={jest.fn}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
(helpers.useDataProvider as jest.Mock).mock.calls[0][0].variables.partyId
|
||||
).toEqual('partyOne');
|
||||
await act(() => {
|
||||
rerender(<AccountManager partyId="partyTwo" onClickAsset={jest.fn} />);
|
||||
rerender(
|
||||
<AccountManager
|
||||
partyId="partyTwo"
|
||||
onClickAsset={jest.fn}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
expect(
|
||||
(helpers.useDataProvider as jest.Mock).mock.calls[1][0].variables.partyId
|
||||
@@ -38,19 +48,28 @@ describe('AccountManager', () => {
|
||||
|
||||
it('update method should return proper result', async () => {
|
||||
await act(() => {
|
||||
render(<AccountManager partyId="partyOne" onClickAsset={jest.fn} />);
|
||||
render(
|
||||
<AccountManager
|
||||
partyId="partyOne"
|
||||
onClickAsset={jest.fn}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('No accounts')).toBeInTheDocument();
|
||||
});
|
||||
expect(mockedUpdate({ data: [] })).toEqual(true);
|
||||
expect(
|
||||
mockedUpdate({ data: [{ party: { id: 't1' } }] as AccountFields[] })
|
||||
).toEqual(false);
|
||||
expect(
|
||||
mockedUpdate({ data: [{ party: { id: 't2' } }] as AccountFields[] })
|
||||
).toEqual(true);
|
||||
expect(mockedUpdate({ data: [] })).toEqual(false);
|
||||
expect(mockedUpdate({ data: [] })).toEqual(true);
|
||||
await act(() => {
|
||||
expect(mockedUpdate({ data: [] })).toEqual(true);
|
||||
|
||||
expect(
|
||||
mockedUpdate({ data: [{ party: { id: 't1' } }] as AccountFields[] })
|
||||
).toEqual(false);
|
||||
expect(
|
||||
mockedUpdate({ data: [{ party: { id: 't2' } }] as AccountFields[] })
|
||||
).toEqual(true);
|
||||
expect(mockedUpdate({ data: [] })).toEqual(false);
|
||||
expect(mockedUpdate({ data: [] })).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,6 +16,7 @@ interface AccountManagerProps {
|
||||
onClickAsset: (assetId: string) => void;
|
||||
onClickWithdraw?: (assetId?: string) => void;
|
||||
onClickDeposit?: (assetId?: string) => void;
|
||||
isReadOnly: boolean;
|
||||
}
|
||||
|
||||
export const AccountManager = ({
|
||||
@@ -23,6 +24,7 @@ export const AccountManager = ({
|
||||
onClickWithdraw,
|
||||
onClickDeposit,
|
||||
partyId,
|
||||
isReadOnly,
|
||||
}: AccountManagerProps) => {
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const dataRef = useRef<AccountFields[] | null>(null);
|
||||
@@ -58,6 +60,7 @@ export const AccountManager = ({
|
||||
onClickAsset={onClickAsset}
|
||||
onClickDeposit={onClickDeposit}
|
||||
onClickWithdraw={onClickWithdraw}
|
||||
isReadOnly={isReadOnly}
|
||||
/>
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
<AsyncRenderer
|
||||
|
||||
@@ -35,7 +35,11 @@ describe('AccountsTable', () => {
|
||||
it('should render correct columns', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<AccountTable rowData={singleRowData} onClickAsset={() => null} />
|
||||
<AccountTable
|
||||
rowData={singleRowData}
|
||||
onClickAsset={() => null}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const expectedHeaders = ['Asset', 'Total', 'Used', 'Available', ''];
|
||||
@@ -49,7 +53,11 @@ describe('AccountsTable', () => {
|
||||
it('should apply correct formatting', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<AccountTable rowData={singleRowData} onClickAsset={() => null} />
|
||||
<AccountTable
|
||||
rowData={singleRowData}
|
||||
onClickAsset={() => null}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const cells = await screen.findAllByRole('gridcell');
|
||||
|
||||
@@ -29,6 +29,7 @@ export interface AccountTableProps extends AgGridReactProps {
|
||||
onClickAsset: (assetId: string) => void;
|
||||
onClickWithdraw?: (assetId: string) => void;
|
||||
onClickDeposit?: (assetId: string) => void;
|
||||
isReadOnly: boolean;
|
||||
}
|
||||
|
||||
export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
|
||||
@@ -127,48 +128,50 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
|
||||
}
|
||||
maxWidth={300}
|
||||
/>
|
||||
<AgGridColumn
|
||||
colId="breakdown"
|
||||
headerName=""
|
||||
sortable={false}
|
||||
minWidth={200}
|
||||
type="rightAligned"
|
||||
cellRenderer={({
|
||||
data,
|
||||
}: VegaICellRendererParams<AccountFields>) => {
|
||||
return data ? (
|
||||
<>
|
||||
<ButtonLink
|
||||
data-testid="breakdown"
|
||||
onClick={() => {
|
||||
setOpenBreakdown(!openBreakdown);
|
||||
setBreakdown(data.breakdown || null);
|
||||
}}
|
||||
>
|
||||
{t('Breakdown')}
|
||||
</ButtonLink>
|
||||
<span className="mx-1" />
|
||||
<ButtonLink
|
||||
data-testid="deposit"
|
||||
onClick={() => {
|
||||
onClickDeposit && onClickDeposit(data.asset.id);
|
||||
}}
|
||||
>
|
||||
{t('Deposit')}
|
||||
</ButtonLink>
|
||||
<span className="mx-1" />
|
||||
<ButtonLink
|
||||
data-testid="withdraw"
|
||||
onClick={() =>
|
||||
onClickWithdraw && onClickWithdraw(data.asset.id)
|
||||
}
|
||||
>
|
||||
{t('Withdraw')}
|
||||
</ButtonLink>
|
||||
</>
|
||||
) : null;
|
||||
}}
|
||||
/>
|
||||
{!props.isReadOnly && (
|
||||
<AgGridColumn
|
||||
colId="breakdown"
|
||||
headerName=""
|
||||
sortable={false}
|
||||
minWidth={200}
|
||||
type="rightAligned"
|
||||
cellRenderer={({
|
||||
data,
|
||||
}: VegaICellRendererParams<AccountFields>) => {
|
||||
return data ? (
|
||||
<>
|
||||
<ButtonLink
|
||||
data-testid="breakdown"
|
||||
onClick={() => {
|
||||
setOpenBreakdown(!openBreakdown);
|
||||
setBreakdown(data.breakdown || null);
|
||||
}}
|
||||
>
|
||||
{t('Breakdown')}
|
||||
</ButtonLink>
|
||||
<span className="mx-1" />
|
||||
<ButtonLink
|
||||
data-testid="deposit"
|
||||
onClick={() => {
|
||||
onClickDeposit && onClickDeposit(data.asset.id);
|
||||
}}
|
||||
>
|
||||
{t('Deposit')}
|
||||
</ButtonLink>
|
||||
<span className="mx-1" />
|
||||
<ButtonLink
|
||||
data-testid="withdraw"
|
||||
onClick={() =>
|
||||
onClickWithdraw && onClickWithdraw(data.asset.id)
|
||||
}
|
||||
>
|
||||
{t('Withdraw')}
|
||||
</ButtonLink>
|
||||
</>
|
||||
) : null;
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</AgGrid>
|
||||
<Dialog size="medium" open={openBreakdown} onChange={setOpenBreakdown}>
|
||||
<div className="h-[35vh] w-full m-auto flex flex-col">
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Option } from '@vegaprotocol/ui-toolkit';
|
||||
import type { AssetFieldsFragment } from './__generated__/Asset';
|
||||
|
||||
export const AssetOption = ({ asset }: { asset: AssetFieldsFragment }) => {
|
||||
return (
|
||||
<Option key={asset.id} value={asset.id}>
|
||||
<div className="flex flex-col items-start">
|
||||
<span>{asset.name}</span>
|
||||
<div className="text-[10px] font-mono w-full text-left break-all">
|
||||
<span className="text-gray-500">{asset.id} -</span> {asset.symbol}
|
||||
</div>
|
||||
</div>
|
||||
</Option>
|
||||
);
|
||||
};
|
||||
@@ -4,3 +4,4 @@ export * from './asset-data-provider';
|
||||
export * from './assets-data-provider';
|
||||
export * from './asset-details-dialog';
|
||||
export * from './asset-details-table';
|
||||
export * from './asset-option';
|
||||
|
||||
@@ -48,7 +48,7 @@ function createNewMarketProposal(): ProposalSubmissionBody {
|
||||
signers: [
|
||||
{
|
||||
pubKey: {
|
||||
key: '0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC',
|
||||
key: '70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -16,7 +16,7 @@ export interface DealTicketFeeDetails {
|
||||
label: string;
|
||||
value?: string | number | null;
|
||||
labelDescription?: string | ReactNode;
|
||||
quoteName?: string;
|
||||
symbol?: string;
|
||||
}
|
||||
|
||||
export const DealTicketFeeDetails = ({
|
||||
@@ -27,7 +27,7 @@ export const DealTicketFeeDetails = ({
|
||||
const details = getFeeDetailsValues(feeDetails);
|
||||
return (
|
||||
<div>
|
||||
{details.map(({ label, value, labelDescription, quoteName }) => (
|
||||
{details.map(({ label, value, labelDescription, symbol }) => (
|
||||
<div
|
||||
key={label}
|
||||
className="text-xs mt-2 flex justify-between items-center gap-4 flex-wrap"
|
||||
@@ -39,7 +39,7 @@ export const DealTicketFeeDetails = ({
|
||||
</div>
|
||||
<div className="text-neutral-500 dark:text-neutral-300">{`${
|
||||
value ?? '-'
|
||||
} ${quoteName || ''}`}</div>
|
||||
} ${symbol || ''}`}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -15,8 +15,7 @@ export const DealTicketLimitAmount = ({
|
||||
}: DealTicketLimitAmountProps) => {
|
||||
const priceStep = toDecimal(market?.decimalPlaces);
|
||||
const sizeStep = toDecimal(market?.positionDecimalPlaces);
|
||||
const quoteName =
|
||||
market.tradableInstrument.instrument.product.settlementAsset.symbol;
|
||||
const quoteName = market.tradableInstrument.instrument.product.quoteName;
|
||||
|
||||
const renderError = () => {
|
||||
if (sizeError) {
|
||||
|
||||
@@ -19,8 +19,7 @@ export const DealTicketMarketAmount = ({
|
||||
market,
|
||||
sizeError,
|
||||
}: DealTicketMarketAmountProps) => {
|
||||
const quoteName =
|
||||
market.tradableInstrument.instrument.product.settlementAsset.symbol;
|
||||
const quoteName = market.tradableInstrument.instrument.product.quoteName;
|
||||
const sizeStep = toDecimal(market?.positionDecimalPlaces);
|
||||
const price = getMarketPrice(market);
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ describe('DealTicket', () => {
|
||||
expect(screen.getByTestId('last-price')).toHaveTextContent(
|
||||
// eslint-disable-next-line
|
||||
`~${addDecimal(market!.data.markPrice, market.decimalPlaces)} ${
|
||||
market.tradableInstrument.instrument.product.settlementAsset.symbol
|
||||
market.tradableInstrument.instrument.product.quoteName
|
||||
}`
|
||||
);
|
||||
});
|
||||
|
||||
@@ -45,7 +45,7 @@ export type DealTicketFormFields = OrderSubmissionBody['orderSubmission'] & {
|
||||
};
|
||||
|
||||
export const DealTicket = ({ market, submit }: DealTicketProps) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const { getPersistedOrder, setPersistedOrder } = usePersistedOrderStore(
|
||||
(store) => ({
|
||||
getPersistedOrder: store.getOrder,
|
||||
@@ -158,7 +158,11 @@ export const DealTicket = ({ market, submit }: DealTicketProps) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="p-4" noValidate>
|
||||
<form
|
||||
onSubmit={isReadOnly ? () => null : handleSubmit(onSubmit)}
|
||||
className="p-4"
|
||||
noValidate
|
||||
>
|
||||
<Controller
|
||||
name="type"
|
||||
control={control}
|
||||
@@ -220,13 +224,14 @@ export const DealTicket = ({ market, submit }: DealTicketProps) => {
|
||||
/>
|
||||
)}
|
||||
<DealTicketButton
|
||||
disabled={Object.keys(errors).length >= 1}
|
||||
disabled={Object.keys(errors).length >= 1 || isReadOnly}
|
||||
variant={order.side === Schema.Side.SIDE_BUY ? 'ternary' : 'secondary'}
|
||||
/>
|
||||
<SummaryMessage
|
||||
errorMessage={errors.summary?.message}
|
||||
market={market}
|
||||
order={order}
|
||||
isReadOnly={isReadOnly}
|
||||
/>
|
||||
<DealTicketFeeDetails order={order} market={market} />
|
||||
</form>
|
||||
@@ -241,9 +246,10 @@ interface SummaryMessageProps {
|
||||
errorMessage?: string;
|
||||
market: MarketDealTicket;
|
||||
order: OrderSubmissionBody['orderSubmission'];
|
||||
isReadOnly: boolean;
|
||||
}
|
||||
const SummaryMessage = memo(
|
||||
({ errorMessage, market, order }: SummaryMessageProps) => {
|
||||
({ errorMessage, market, order, isReadOnly }: SummaryMessageProps) => {
|
||||
// Specific error UI for if balance is so we can
|
||||
// render a deposit dialog
|
||||
const asset = market.tradableInstrument.instrument.product.settlementAsset;
|
||||
@@ -251,6 +257,17 @@ const SummaryMessage = memo(
|
||||
market,
|
||||
order,
|
||||
});
|
||||
if (isReadOnly) {
|
||||
return (
|
||||
<div className="mb-4">
|
||||
<InputError data-testid="dealticket-error-message-summary">
|
||||
{
|
||||
'You need to connect your own wallet to start trading on this market'
|
||||
}
|
||||
</InputError>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (errorMessage === SummaryValidationType.NoCollateral) {
|
||||
return (
|
||||
<ZeroBalanceError
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { useMemo } from 'react';
|
||||
import { parseISO, isValid, isAfter } from 'date-fns';
|
||||
import classNames from 'classnames';
|
||||
import { useProposalOfMarketQuery } from '@vegaprotocol/governance';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { DataGrid, t } from '@vegaprotocol/react-helpers';
|
||||
import { DataGrid, getDateTimeFormat, t } from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { createDocsLinks } from '@vegaprotocol/react-helpers';
|
||||
@@ -21,14 +24,24 @@ export const TradingModeTooltip = ({
|
||||
const { VEGA_DOCS_URL } = useEnvironment();
|
||||
const market = useMarket(marketId);
|
||||
const marketData = useStaticMarketData(marketId, skip);
|
||||
const { marketTradingMode: tradingMode, trigger } = marketData || {};
|
||||
const variables = useMemo(() => ({ marketId: marketId || '' }), [marketId]);
|
||||
const { data: proposalData } = useProposalOfMarketQuery({
|
||||
variables,
|
||||
skip:
|
||||
!tradingMode ||
|
||||
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION !== tradingMode,
|
||||
});
|
||||
|
||||
if (!market || !marketData) {
|
||||
return null;
|
||||
}
|
||||
const enactmentDate = parseISO(
|
||||
proposalData?.proposal?.terms.enactmentDatetime
|
||||
);
|
||||
|
||||
const compiledGrid =
|
||||
onSelect && compileGridData(market, marketData, onSelect);
|
||||
const { marketTradingMode: tradingMode, trigger } = marketData;
|
||||
|
||||
switch (tradingMode) {
|
||||
case Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS: {
|
||||
@@ -43,12 +56,47 @@ export const TradingModeTooltip = ({
|
||||
case Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION: {
|
||||
return (
|
||||
<section data-testid="trading-mode-tooltip">
|
||||
<p className={classNames({ 'mb-4': Boolean(compiledGrid) })}>
|
||||
<span>
|
||||
{t(
|
||||
'This new market is in an opening auction to determine a fair mid-price before starting continuous trading.'
|
||||
)}
|
||||
</span>{' '}
|
||||
<p
|
||||
className={classNames('flex flex-col', {
|
||||
'mb-4': Boolean(compiledGrid),
|
||||
})}
|
||||
>
|
||||
{isValid(enactmentDate) && isAfter(new Date(), enactmentDate) ? (
|
||||
<>
|
||||
<span
|
||||
className="justify-center font-bold my-2"
|
||||
data-testid="opening-auction-sub-status"
|
||||
>
|
||||
{`${Schema.MarketTradingModeMapping[tradingMode]}: ${t(
|
||||
'Not enough liquidity to open'
|
||||
)}`}
|
||||
</span>
|
||||
<span>
|
||||
{t(
|
||||
'This market is in opening auction until it has reached enough liquidity to move into continuous trading.'
|
||||
)}
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{isValid(enactmentDate) && (
|
||||
<span
|
||||
className="justify-center font-bold my-2"
|
||||
data-testid="opening-auction-sub-status"
|
||||
>
|
||||
{`${Schema.MarketTradingModeMapping[tradingMode]}: ${t(
|
||||
'Closing on %s',
|
||||
getDateTimeFormat().format(enactmentDate)
|
||||
)}`}
|
||||
</span>
|
||||
)}
|
||||
<span>
|
||||
{t(
|
||||
'This is a new market in an opening auction to determine a fair mid-price before starting continuous trading.'
|
||||
)}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
{VEGA_DOCS_URL && (
|
||||
<ExternalLink
|
||||
href={createDocsLinks(VEGA_DOCS_URL).AUCTION_TYPE_OPENING}
|
||||
|
||||
@@ -69,12 +69,13 @@ export const useFeeDealTicketDetails = (
|
||||
return null;
|
||||
}, [derivedPrice, order.size, market.decimalPlaces]);
|
||||
|
||||
const quoteName = market.tradableInstrument.instrument.product.quoteName;
|
||||
const symbol =
|
||||
market.tradableInstrument.instrument.product.settlementAsset.symbol;
|
||||
|
||||
return useMemo(() => {
|
||||
return {
|
||||
market,
|
||||
quoteName,
|
||||
symbol,
|
||||
notionalSize,
|
||||
estMargin,
|
||||
estCloseOut,
|
||||
@@ -83,7 +84,7 @@ export const useFeeDealTicketDetails = (
|
||||
};
|
||||
}, [
|
||||
market,
|
||||
quoteName,
|
||||
symbol,
|
||||
notionalSize,
|
||||
estMargin,
|
||||
estCloseOut,
|
||||
@@ -94,7 +95,7 @@ export const useFeeDealTicketDetails = (
|
||||
|
||||
export interface FeeDetails {
|
||||
market: MarketDealTicket;
|
||||
quoteName: string;
|
||||
symbol: string;
|
||||
notionalSize: string | null;
|
||||
estMargin: OrderMargin | null;
|
||||
estCloseOut: string | null;
|
||||
@@ -102,7 +103,7 @@ export interface FeeDetails {
|
||||
}
|
||||
|
||||
export const getFeeDetailsValues = ({
|
||||
quoteName,
|
||||
symbol,
|
||||
notionalSize,
|
||||
estMargin,
|
||||
estCloseOut,
|
||||
@@ -128,7 +129,7 @@ export const getFeeDetailsValues = ({
|
||||
{
|
||||
label: t('Notional'),
|
||||
value: formatValueWithMarketDp(notionalSize),
|
||||
quoteName,
|
||||
symbol,
|
||||
labelDescription: NOTIONAL_SIZE_TOOLTIP_TEXT,
|
||||
},
|
||||
{
|
||||
@@ -146,24 +147,24 @@ export const getFeeDetailsValues = ({
|
||||
<FeesBreakdown
|
||||
fees={estMargin?.fees}
|
||||
feeFactors={market.fees.factors}
|
||||
quoteName={quoteName}
|
||||
symbol={symbol}
|
||||
decimals={assetDecimals}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
quoteName,
|
||||
symbol,
|
||||
},
|
||||
{
|
||||
label: t('Margin'),
|
||||
value:
|
||||
estMargin?.margin && `~${formatValueWithAssetDp(estMargin?.margin)}`,
|
||||
quoteName,
|
||||
symbol,
|
||||
labelDescription: EST_MARGIN_TOOLTIP_TEXT,
|
||||
},
|
||||
{
|
||||
label: t('Liquidation'),
|
||||
value: estCloseOut && `~${formatValueWithMarketDp(estCloseOut)}`,
|
||||
quoteName,
|
||||
symbol: market.tradableInstrument.instrument.product.quoteName,
|
||||
labelDescription: EST_CLOSEOUT_TOOLTIP_TEXT,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Asset } from '@vegaprotocol/assets';
|
||||
import { AssetOption } from '@vegaprotocol/assets';
|
||||
import {
|
||||
ethereumAddress,
|
||||
t,
|
||||
@@ -17,7 +18,6 @@ import {
|
||||
Input,
|
||||
InputError,
|
||||
RichSelect,
|
||||
Option,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
@@ -185,14 +185,7 @@ export const DepositForm = ({
|
||||
hasError={Boolean(errors.asset?.message)}
|
||||
>
|
||||
{assets.filter(isAssetTypeERC20).map((a) => (
|
||||
<Option key={a.id} value={a.id}>
|
||||
<div className="flex flex-col items-start">
|
||||
<span>{a.name}</span>
|
||||
<span className="text-[10px] font-mono">
|
||||
<span className="text-gray-500">{a.id} -</span> {a.symbol}
|
||||
</span>
|
||||
</div>
|
||||
</Option>
|
||||
<AssetOption asset={a} key={a.id} />
|
||||
))}
|
||||
</RichSelect>
|
||||
)}
|
||||
|
||||
@@ -82,8 +82,9 @@ describe('FillsTable', () => {
|
||||
liquidityFee: '2',
|
||||
},
|
||||
});
|
||||
|
||||
render(<FillsTable partyId={partyId} rowData={[{ ...buyerFill }]} />);
|
||||
await act(async () => {
|
||||
render(<FillsTable partyId={partyId} rowData={[{ ...buyerFill }]} />);
|
||||
});
|
||||
await waitForGridToBeInTheDOM();
|
||||
await waitForDataToHaveLoaded();
|
||||
|
||||
@@ -119,8 +120,9 @@ describe('FillsTable', () => {
|
||||
liquidityFee: '1',
|
||||
},
|
||||
});
|
||||
|
||||
render(<FillsTable partyId={partyId} rowData={[buyerFill]} />);
|
||||
await act(async () => {
|
||||
render(<FillsTable partyId={partyId} rowData={[buyerFill]} />);
|
||||
});
|
||||
await waitForGridToBeInTheDOM();
|
||||
await waitForDataToHaveLoaded();
|
||||
|
||||
@@ -150,10 +152,13 @@ describe('FillsTable', () => {
|
||||
},
|
||||
aggressor: Schema.Side.SIDE_SELL,
|
||||
});
|
||||
|
||||
const { rerender } = render(
|
||||
<FillsTable partyId={partyId} rowData={[takerFill]} />
|
||||
);
|
||||
let rerenderer: (ui: React.ReactElement) => void;
|
||||
await act(async () => {
|
||||
const { rerender } = render(
|
||||
<FillsTable partyId={partyId} rowData={[takerFill]} />
|
||||
);
|
||||
rerenderer = rerender;
|
||||
});
|
||||
await waitForGridToBeInTheDOM();
|
||||
await waitForDataToHaveLoaded();
|
||||
|
||||
@@ -169,8 +174,9 @@ describe('FillsTable', () => {
|
||||
},
|
||||
aggressor: Schema.Side.SIDE_BUY,
|
||||
});
|
||||
|
||||
rerender(<FillsTable partyId={partyId} rowData={[makerFill]} />);
|
||||
await act(async () => {
|
||||
rerenderer(<FillsTable partyId={partyId} rowData={[makerFill]} />);
|
||||
});
|
||||
await waitForGridToBeInTheDOM();
|
||||
await waitForDataToHaveLoaded();
|
||||
|
||||
@@ -189,7 +195,7 @@ describe('FillsTable', () => {
|
||||
},
|
||||
aggressor: Schema.Side.SIDE_SELL,
|
||||
});
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
render(<FillsTable partyId={partyId} rowData={[takerFill]} />);
|
||||
});
|
||||
await waitForGridToBeInTheDOM();
|
||||
@@ -206,11 +212,12 @@ describe('FillsTable', () => {
|
||||
await waitFor(() => {
|
||||
expect(feeCell).toBeInTheDocument();
|
||||
});
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
userEvent.hover(feeCell as HTMLElement);
|
||||
await new Promise((res) => setTimeout(() => res(true), 1000));
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
await act(async () => {
|
||||
expect(screen.getByTestId('fee-breakdown-tooltip')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,3 +43,12 @@ subscription OnUpdateNetworkParameters {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query ProposalOfMarket($marketId: ID!) {
|
||||
proposal(id: $marketId) {
|
||||
id
|
||||
terms {
|
||||
enactmentDatetime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,13 @@ export type OnUpdateNetworkParametersSubscriptionVariables = Types.Exact<{ [key:
|
||||
|
||||
export type OnUpdateNetworkParametersSubscription = { __typename?: 'Subscription', busEvents?: Array<{ __typename?: 'BusEvent', event: { __typename?: 'AccountEvent' } | { __typename?: 'Asset' } | { __typename?: 'AuctionEvent' } | { __typename?: 'Deposit' } | { __typename?: 'LiquidityProvision' } | { __typename?: 'LossSocialization' } | { __typename?: 'MarginLevels' } | { __typename?: 'Market' } | { __typename?: 'MarketData' } | { __typename?: 'MarketEvent' } | { __typename?: 'MarketTick' } | { __typename?: 'NodeSignature' } | { __typename?: 'OracleSpec' } | { __typename?: 'Order' } | { __typename?: 'Party' } | { __typename?: 'PositionResolution' } | { __typename?: 'Proposal', id?: string | null, state: Types.ProposalState, datetime: any, terms: { __typename?: 'ProposalTerms', enactmentDatetime?: any | null, change: { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket' } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } } } | { __typename?: 'RiskFactor' } | { __typename?: 'SettleDistressed' } | { __typename?: 'SettlePosition' } | { __typename?: 'TimeUpdate' } | { __typename?: 'Trade' } | { __typename?: 'TransactionResult' } | { __typename?: 'TransferResponses' } | { __typename?: 'Vote' } | { __typename?: 'Withdrawal' } }> | null };
|
||||
|
||||
export type ProposalOfMarketQueryVariables = Types.Exact<{
|
||||
marketId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type ProposalOfMarketQuery = { __typename?: 'Query', proposal?: { __typename?: 'Proposal', id?: string | null, terms: { __typename?: 'ProposalTerms', enactmentDatetime?: any | null } } | null };
|
||||
|
||||
export const ProposalEventFieldsFragmentDoc = gql`
|
||||
fragment ProposalEventFields on Proposal {
|
||||
id
|
||||
@@ -113,4 +120,42 @@ export function useOnUpdateNetworkParametersSubscription(baseOptions?: Apollo.Su
|
||||
return Apollo.useSubscription<OnUpdateNetworkParametersSubscription, OnUpdateNetworkParametersSubscriptionVariables>(OnUpdateNetworkParametersDocument, options);
|
||||
}
|
||||
export type OnUpdateNetworkParametersSubscriptionHookResult = ReturnType<typeof useOnUpdateNetworkParametersSubscription>;
|
||||
export type OnUpdateNetworkParametersSubscriptionResult = Apollo.SubscriptionResult<OnUpdateNetworkParametersSubscription>;
|
||||
export type OnUpdateNetworkParametersSubscriptionResult = Apollo.SubscriptionResult<OnUpdateNetworkParametersSubscription>;
|
||||
export const ProposalOfMarketDocument = gql`
|
||||
query ProposalOfMarket($marketId: ID!) {
|
||||
proposal(id: $marketId) {
|
||||
id
|
||||
terms {
|
||||
enactmentDatetime
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useProposalOfMarketQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useProposalOfMarketQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useProposalOfMarketQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useProposalOfMarketQuery({
|
||||
* variables: {
|
||||
* marketId: // value for 'marketId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useProposalOfMarketQuery(baseOptions: Apollo.QueryHookOptions<ProposalOfMarketQuery, ProposalOfMarketQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<ProposalOfMarketQuery, ProposalOfMarketQueryVariables>(ProposalOfMarketDocument, options);
|
||||
}
|
||||
export function useProposalOfMarketLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ProposalOfMarketQuery, ProposalOfMarketQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<ProposalOfMarketQuery, ProposalOfMarketQueryVariables>(ProposalOfMarketDocument, options);
|
||||
}
|
||||
export type ProposalOfMarketQueryHookResult = ReturnType<typeof useProposalOfMarketQuery>;
|
||||
export type ProposalOfMarketLazyQueryHookResult = ReturnType<typeof useProposalOfMarketLazyQuery>;
|
||||
export type ProposalOfMarketQueryResult = Apollo.QueryResult<ProposalOfMarketQuery, ProposalOfMarketQueryVariables>;
|
||||
@@ -51,7 +51,7 @@ export const FeesBreakdownPercentage = ({
|
||||
export const FeesBreakdown = ({
|
||||
fees,
|
||||
feeFactors,
|
||||
quoteName,
|
||||
symbol,
|
||||
decimals,
|
||||
}: {
|
||||
fees?: {
|
||||
@@ -60,7 +60,7 @@ export const FeesBreakdown = ({
|
||||
makerFee: string;
|
||||
};
|
||||
feeFactors?: Market['fees']['factors'];
|
||||
quoteName?: string;
|
||||
symbol?: string;
|
||||
decimals: number;
|
||||
}) => {
|
||||
if (!fees) return null;
|
||||
@@ -84,7 +84,7 @@ export const FeesBreakdown = ({
|
||||
</dd>
|
||||
)}
|
||||
<dd className="text-right col-span-2">
|
||||
{formatValue(fees.infrastructureFee)} {quoteName || ''}
|
||||
{formatValue(fees.infrastructureFee)} {symbol || ''}
|
||||
</dd>
|
||||
<dt className="col-span-2">{t('Liquidity fee')}</dt>
|
||||
{feeFactors && (
|
||||
@@ -95,7 +95,7 @@ export const FeesBreakdown = ({
|
||||
</dd>
|
||||
)}
|
||||
<dd className="text-right col-span-2">
|
||||
{formatValue(fees.liquidityFee)} {quoteName || ''}
|
||||
{formatValue(fees.liquidityFee)} {symbol || ''}
|
||||
</dd>
|
||||
<dt className="col-span-2">{t('Maker fee')}</dt>
|
||||
{feeFactors && (
|
||||
@@ -106,7 +106,7 @@ export const FeesBreakdown = ({
|
||||
</dd>
|
||||
)}
|
||||
<dd className="text-right col-span-2">
|
||||
{formatValue(fees.makerFee)} {quoteName || ''}
|
||||
{formatValue(fees.makerFee)} {symbol || ''}
|
||||
</dd>
|
||||
<dt className="col-span-2">{t('Total fees')}</dt>
|
||||
{feeFactors && (
|
||||
@@ -115,7 +115,7 @@ export const FeesBreakdown = ({
|
||||
</dd>
|
||||
)}
|
||||
<dd className="text-right col-span-2">
|
||||
{formatValue(totalFees)} {quoteName || ''}
|
||||
{formatValue(totalFees)} {symbol || ''}
|
||||
</dd>
|
||||
</dl>
|
||||
);
|
||||
|
||||
@@ -10,7 +10,7 @@ export const OrderListContainer = ({
|
||||
marketId?: string;
|
||||
onMarketClick?: (marketId: string) => void;
|
||||
}) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
|
||||
if (!pubKey) {
|
||||
return <Splash>{t('Please connect Vega wallet')}</Splash>;
|
||||
@@ -21,6 +21,7 @@ export const OrderListContainer = ({
|
||||
partyId={pubKey}
|
||||
marketId={marketId}
|
||||
onMarketClick={onMarketClick}
|
||||
isReadOnly={isReadOnly}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render, screen, act } from '@testing-library/react';
|
||||
import { OrderListManager } from './order-list-manager';
|
||||
import * as useDataProviderHook from '@vegaprotocol/react-helpers';
|
||||
import type { OrderFieldsFragment } from '../';
|
||||
@@ -13,13 +13,13 @@ const generateJsx = () => {
|
||||
return (
|
||||
<MockedProvider>
|
||||
<VegaWalletContext.Provider value={{ pubKey } as VegaWalletContextShape}>
|
||||
<OrderListManager partyId={pubKey} />
|
||||
<OrderListManager partyId={pubKey} isReadOnly={false} />
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
);
|
||||
};
|
||||
|
||||
it('Renders a loading state while awaiting orders', () => {
|
||||
it('Renders a loading state while awaiting orders', async () => {
|
||||
jest.spyOn(useDataProviderHook, 'useDataProvider').mockReturnValue({
|
||||
data: [],
|
||||
loading: true,
|
||||
@@ -29,11 +29,13 @@ it('Renders a loading state while awaiting orders', () => {
|
||||
load: jest.fn(),
|
||||
totalCount: 0,
|
||||
});
|
||||
render(generateJsx());
|
||||
await act(async () => {
|
||||
render(generateJsx());
|
||||
});
|
||||
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Renders an error state', () => {
|
||||
it('Renders an error state', async () => {
|
||||
const errorMsg = 'Oops! An Error';
|
||||
jest.spyOn(useDataProviderHook, 'useDataProvider').mockReturnValue({
|
||||
data: [],
|
||||
@@ -44,7 +46,9 @@ it('Renders an error state', () => {
|
||||
load: jest.fn(),
|
||||
totalCount: undefined,
|
||||
});
|
||||
render(generateJsx());
|
||||
await act(async () => {
|
||||
render(generateJsx());
|
||||
});
|
||||
expect(
|
||||
screen.getByText(`Something went wrong: ${errorMsg}`)
|
||||
).toBeInTheDocument();
|
||||
@@ -63,6 +67,8 @@ it('Renders the order list if orders provided', async () => {
|
||||
load: jest.fn(),
|
||||
totalCount: undefined,
|
||||
});
|
||||
render(generateJsx());
|
||||
await act(async () => {
|
||||
render(generateJsx());
|
||||
});
|
||||
expect(await screen.findByText('OrderList')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -31,6 +31,7 @@ export interface OrderListManagerProps {
|
||||
partyId: string;
|
||||
marketId?: string;
|
||||
onMarketClick?: (marketId: string) => void;
|
||||
isReadOnly: boolean;
|
||||
}
|
||||
|
||||
export const TransactionComplete = ({
|
||||
@@ -72,6 +73,7 @@ export const OrderListManager = ({
|
||||
partyId,
|
||||
marketId,
|
||||
onMarketClick,
|
||||
isReadOnly,
|
||||
}: OrderListManagerProps) => {
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const scrolledToTop = useRef(true);
|
||||
@@ -146,6 +148,7 @@ export const OrderListManager = ({
|
||||
}}
|
||||
setEditOrder={setEditOrder}
|
||||
onMarketClick={onMarketClick}
|
||||
isReadOnly={isReadOnly}
|
||||
/>
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
<AsyncRenderer
|
||||
|
||||
@@ -19,6 +19,7 @@ const defaultProps: OrderListTableProps = {
|
||||
rowData: [],
|
||||
setEditOrder: jest.fn(),
|
||||
cancel: jest.fn(),
|
||||
isReadOnly: false,
|
||||
};
|
||||
|
||||
const generateJsx = (
|
||||
@@ -156,6 +157,29 @@ describe('OrderListTable', () => {
|
||||
expect(mockCancel).toHaveBeenCalledWith(order);
|
||||
});
|
||||
|
||||
it('does not allow cancelling and editing for permitted orders if read only', async () => {
|
||||
const mockEdit = jest.fn();
|
||||
const mockCancel = jest.fn();
|
||||
const order = generateOrder({
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
liquidityProvision: null,
|
||||
peggedOrder: null,
|
||||
});
|
||||
await act(async () => {
|
||||
render(
|
||||
generateJsx({
|
||||
rowData: [order],
|
||||
setEditOrder: mockEdit,
|
||||
cancel: mockCancel,
|
||||
isReadOnly: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
const amendCell = getAmendCell();
|
||||
expect(amendCell.queryAllByRole('button')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('shows if an order is a liquidity provision order and does not show order actions', async () => {
|
||||
const order = generateOrder({
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
|
||||
@@ -22,6 +22,7 @@ const Template: Story = (args) => {
|
||||
setEditOrder={() => {
|
||||
return;
|
||||
}}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -48,6 +49,7 @@ const Template2: Story = (args) => {
|
||||
rowData={args.data}
|
||||
cancel={cancel}
|
||||
setEditOrder={setEditOrder}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
</div>
|
||||
<VegaTransactionDialog
|
||||
|
||||
@@ -32,6 +32,7 @@ export type OrderListTableProps = OrderListProps & {
|
||||
cancel: (order: Order) => void;
|
||||
setEditOrder: (order: Order) => void;
|
||||
onMarketClick?: (marketId: string) => void;
|
||||
isReadOnly: boolean;
|
||||
};
|
||||
|
||||
export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
|
||||
@@ -248,7 +249,7 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
|
||||
minWidth={100}
|
||||
type="rightAligned"
|
||||
cellRenderer={({ data, node }: VegaICellRendererParams<Order>) => {
|
||||
return data && isOrderAmendable(data) ? (
|
||||
return data && isOrderAmendable(data) && !props.isReadOnly ? (
|
||||
<>
|
||||
<ButtonLink
|
||||
data-testid="edit"
|
||||
|
||||
@@ -8,7 +8,7 @@ export const PositionsContainer = ({
|
||||
}: {
|
||||
onMarketClick?: (marketId: string) => void;
|
||||
}) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
|
||||
if (!pubKey) {
|
||||
return (
|
||||
@@ -17,5 +17,11 @@ export const PositionsContainer = ({
|
||||
</Splash>
|
||||
);
|
||||
}
|
||||
return <PositionsManager partyId={pubKey} onMarketClick={onMarketClick} />;
|
||||
return (
|
||||
<PositionsManager
|
||||
partyId={pubKey}
|
||||
onMarketClick={onMarketClick}
|
||||
isReadOnly={isReadOnly}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,16 +9,45 @@ import { t } from '@vegaprotocol/react-helpers';
|
||||
interface PositionsManagerProps {
|
||||
partyId: string;
|
||||
onMarketClick?: (marketId: string) => void;
|
||||
isReadOnly: boolean;
|
||||
}
|
||||
|
||||
export const PositionsManager = ({
|
||||
partyId,
|
||||
onMarketClick,
|
||||
isReadOnly,
|
||||
}: PositionsManagerProps) => {
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const { data, error, loading, getRows } = usePositionsData(partyId, gridRef);
|
||||
const create = useVegaTransactionStore((store) => store.create);
|
||||
|
||||
const onClose = ({
|
||||
marketId,
|
||||
openVolume,
|
||||
}: {
|
||||
marketId: string;
|
||||
openVolume: string;
|
||||
}) =>
|
||||
create({
|
||||
batchMarketInstructions: {
|
||||
cancellations: [
|
||||
{
|
||||
marketId,
|
||||
orderId: '', // omit order id to cancel all active orders
|
||||
},
|
||||
],
|
||||
submissions: [
|
||||
{
|
||||
marketId: marketId,
|
||||
type: Schema.OrderType.TYPE_MARKET as const,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK as const,
|
||||
side: openVolume.startsWith('-')
|
||||
? Schema.Side.SIDE_BUY
|
||||
: Schema.Side.SIDE_SELL,
|
||||
size: openVolume.replace('-', ''),
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
return (
|
||||
<div className="h-full relative">
|
||||
<PositionsTable
|
||||
@@ -26,31 +55,9 @@ export const PositionsManager = ({
|
||||
ref={gridRef}
|
||||
datasource={{ getRows }}
|
||||
onMarketClick={onMarketClick}
|
||||
onClose={({ marketId, openVolume }) =>
|
||||
create({
|
||||
batchMarketInstructions: {
|
||||
cancellations: [
|
||||
{
|
||||
marketId,
|
||||
orderId: '', // omit order id to cancel all active orders
|
||||
},
|
||||
],
|
||||
submissions: [
|
||||
{
|
||||
marketId: marketId,
|
||||
type: Schema.OrderType.TYPE_MARKET as const,
|
||||
timeInForce: Schema.OrderTimeInForce
|
||||
.TIME_IN_FORCE_FOK as const,
|
||||
side: openVolume.startsWith('-')
|
||||
? Schema.Side.SIDE_BUY
|
||||
: Schema.Side.SIDE_SELL,
|
||||
size: openVolume.replace('-', ''),
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
}
|
||||
onClose={onClose}
|
||||
noRowsOverlayComponent={() => null}
|
||||
isReadOnly={isReadOnly}
|
||||
/>
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
<AsyncRenderer
|
||||
|
||||
@@ -32,14 +32,16 @@ const singleRowData = [singleRow];
|
||||
|
||||
it('should render successfully', async () => {
|
||||
await act(async () => {
|
||||
const { baseElement } = render(<PositionsTable rowData={[]} />);
|
||||
const { baseElement } = render(
|
||||
<PositionsTable rowData={[]} isReadOnly={false} />
|
||||
);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
it('Render correct columns', async () => {
|
||||
it('render correct columns', async () => {
|
||||
await act(async () => {
|
||||
render(<PositionsTable rowData={singleRowData} />);
|
||||
render(<PositionsTable rowData={singleRowData} isReadOnly={true} />);
|
||||
});
|
||||
|
||||
const headers = screen.getAllByRole('columnheader');
|
||||
@@ -64,7 +66,7 @@ it('Render correct columns', async () => {
|
||||
|
||||
it('renders market name', async () => {
|
||||
await act(async () => {
|
||||
render(<PositionsTable rowData={singleRowData} />);
|
||||
render(<PositionsTable rowData={singleRowData} isReadOnly={false} />);
|
||||
});
|
||||
expect(screen.getByText('ETH/BTC (31 july 2022)')).toBeTruthy();
|
||||
});
|
||||
@@ -75,7 +77,7 @@ it('Does not fail if the market name does not match the split pattern', async ()
|
||||
Object.assign({}, singleRow, { marketName: breakingMarketName }),
|
||||
];
|
||||
await act(async () => {
|
||||
render(<PositionsTable rowData={row} />);
|
||||
render(<PositionsTable rowData={row} isReadOnly={false} />);
|
||||
});
|
||||
|
||||
expect(screen.getByText(breakingMarketName)).toBeTruthy();
|
||||
@@ -84,7 +86,9 @@ it('Does not fail if the market name does not match the split pattern', async ()
|
||||
it('add color and sign to amount, displays positive notional value', async () => {
|
||||
let result: RenderResult;
|
||||
await act(async () => {
|
||||
result = render(<PositionsTable rowData={singleRowData} />);
|
||||
result = render(
|
||||
<PositionsTable rowData={singleRowData} isReadOnly={false} />
|
||||
);
|
||||
});
|
||||
let cells = screen.getAllByRole('gridcell');
|
||||
|
||||
@@ -94,7 +98,10 @@ it('add color and sign to amount, displays positive notional value', async () =>
|
||||
expect(cells[1].textContent).toEqual('1,230.0');
|
||||
await act(async () => {
|
||||
result.rerender(
|
||||
<PositionsTable rowData={[{ ...singleRow, openVolume: '-100' }]} />
|
||||
<PositionsTable
|
||||
rowData={[{ ...singleRow, openVolume: '-100' }]}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
cells = screen.getAllByRole('gridcell');
|
||||
@@ -107,7 +114,9 @@ it('add color and sign to amount, displays positive notional value', async () =>
|
||||
it('displays mark price', async () => {
|
||||
let result: RenderResult;
|
||||
await act(async () => {
|
||||
result = render(<PositionsTable rowData={singleRowData} />);
|
||||
result = render(
|
||||
<PositionsTable rowData={singleRowData} isReadOnly={false} />
|
||||
);
|
||||
});
|
||||
|
||||
let cells = screen.getAllByRole('gridcell');
|
||||
@@ -123,6 +132,7 @@ it('displays mark price', async () => {
|
||||
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
|
||||
},
|
||||
]}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@@ -134,14 +144,19 @@ it('displays mark price', async () => {
|
||||
it("displays properly entry, liquidation price and liquidation bar and it's intent", async () => {
|
||||
let result: RenderResult;
|
||||
await act(async () => {
|
||||
result = render(<PositionsTable rowData={singleRowData} />);
|
||||
result = render(
|
||||
<PositionsTable rowData={singleRowData} isReadOnly={false} />
|
||||
);
|
||||
});
|
||||
let cells = screen.getAllByRole('gridcell');
|
||||
const entryPrice = cells[5].firstElementChild?.firstElementChild?.textContent;
|
||||
expect(entryPrice).toEqual('13.3');
|
||||
await act(async () => {
|
||||
result.rerender(
|
||||
<PositionsTable rowData={[{ ...singleRow, lowMarginLevel: true }]} />
|
||||
<PositionsTable
|
||||
rowData={[{ ...singleRow, lowMarginLevel: true }]}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
cells = screen.getAllByRole('gridcell');
|
||||
@@ -149,7 +164,7 @@ it("displays properly entry, liquidation price and liquidation bar and it's inte
|
||||
|
||||
it('displays leverage', async () => {
|
||||
await act(async () => {
|
||||
render(<PositionsTable rowData={singleRowData} />);
|
||||
render(<PositionsTable rowData={singleRowData} isReadOnly={false} />);
|
||||
});
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
expect(cells[7].textContent).toEqual('1.1');
|
||||
@@ -157,7 +172,7 @@ it('displays leverage', async () => {
|
||||
|
||||
it('displays allocated margin', async () => {
|
||||
await act(async () => {
|
||||
render(<PositionsTable rowData={singleRowData} />);
|
||||
render(<PositionsTable rowData={singleRowData} isReadOnly={false} />);
|
||||
});
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const cell = cells[8];
|
||||
@@ -166,7 +181,7 @@ it('displays allocated margin', async () => {
|
||||
|
||||
it('displays realised and unrealised PNL', async () => {
|
||||
await act(async () => {
|
||||
render(<PositionsTable rowData={singleRowData} />);
|
||||
render(<PositionsTable rowData={singleRowData} isReadOnly={false} />);
|
||||
});
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
expect(cells[9].textContent).toEqual('1.23');
|
||||
@@ -181,6 +196,7 @@ it('displays close button', async () => {
|
||||
onClose={() => {
|
||||
return;
|
||||
}}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@@ -196,6 +212,7 @@ it('do not display close button if openVolume is zero', async () => {
|
||||
onClose={() => {
|
||||
return;
|
||||
}}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -33,6 +33,7 @@ interface Props extends TypedDataAgGrid<Position> {
|
||||
onClose?: (data: Position) => void;
|
||||
onMarketClick?: (id: string) => void;
|
||||
style?: CSSProperties;
|
||||
isReadOnly: boolean;
|
||||
}
|
||||
|
||||
export interface AmountCellProps {
|
||||
@@ -378,7 +379,7 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
|
||||
return getDateTimeFormat().format(new Date(value));
|
||||
}}
|
||||
/>
|
||||
{onClose ? (
|
||||
{onClose && !props.isReadOnly ? (
|
||||
<AgGridColumn
|
||||
type="rightAligned"
|
||||
cellRenderer={({ data }: VegaICellRendererParams<Position>) =>
|
||||
|
||||
@@ -71,8 +71,8 @@ export const FlashCell = memo(({ children, value }: FlashCellProps) => {
|
||||
if (value < previousValue) {
|
||||
ref.current?.animate(
|
||||
[
|
||||
{ color: theme.colors.vega.pink },
|
||||
{ color: theme.colors.vega.pink, offset: 0.8 },
|
||||
{ color: theme.colors.vega.pink.DEFAULT },
|
||||
{ color: theme.colors.vega.pink.DEFAULT, offset: 0.8 },
|
||||
{ color: 'inherit' },
|
||||
],
|
||||
FLASH_DURATION
|
||||
@@ -80,8 +80,8 @@ export const FlashCell = memo(({ children, value }: FlashCellProps) => {
|
||||
} else if (value > previousValue) {
|
||||
ref.current?.animate(
|
||||
[
|
||||
{ color: theme.colors.vega.green },
|
||||
{ color: theme.colors.vega.green, offset: 0.8 },
|
||||
{ color: theme.colors.vega.green.DEFAULT },
|
||||
{ color: theme.colors.vega.green.DEFAULT, offset: 0.8 },
|
||||
{ color: 'inherit' },
|
||||
],
|
||||
FLASH_DURATION
|
||||
|
||||
@@ -19,16 +19,16 @@ export const Size = ({
|
||||
data-testid="size"
|
||||
className={classNames('text-right', {
|
||||
// BUY
|
||||
'text-vega-green-dark dark:text-vega-green':
|
||||
'text-vega-green-550 dark:text-vega-green':
|
||||
side === Schema.Side.SIDE_BUY && !forceTheme,
|
||||
'text-vega-green-dark':
|
||||
'text-vega-green-550':
|
||||
side === Schema.Side.SIDE_BUY && forceTheme === 'light',
|
||||
'text-vega-green':
|
||||
side === Schema.Side.SIDE_BUY && forceTheme === 'dark',
|
||||
// SELL
|
||||
'text-vega-pink-dark dark:text-vega-pink':
|
||||
'text-vega-pink-550 dark:text-vega-pink':
|
||||
side === Schema.Side.SIDE_SELL && !forceTheme,
|
||||
'text-vega-pink-dark':
|
||||
'text-vega-pink-550':
|
||||
side === Schema.Side.SIDE_SELL && forceTheme === 'light',
|
||||
'text-vega-pink':
|
||||
side === Schema.Side.SIDE_SELL && forceTheme === 'dark',
|
||||
|
||||
@@ -20,8 +20,8 @@ export interface IVolCellProps extends ICellRendererParams {
|
||||
valueFormatted: Omit<VolProps, 'value'>;
|
||||
}
|
||||
|
||||
export const BID_COLOR = tailwind.theme.colors.vega['green'];
|
||||
export const ASK_COLOR = tailwind.theme.colors.vega['pink'];
|
||||
export const BID_COLOR = tailwind.theme.colors.vega.green.DEFAULT;
|
||||
export const ASK_COLOR = tailwind.theme.colors.vega.pink.DEFAULT;
|
||||
|
||||
export const Vol = React.memo(
|
||||
({ value, valueFormatted, relativeValue, type, testId }: VolProps) => {
|
||||
|
||||
@@ -10,22 +10,113 @@ module.exports = {
|
||||
colors: {
|
||||
transparent: 'transparent',
|
||||
current: 'currentColor',
|
||||
black: '#000000',
|
||||
white: '#FFFFFF',
|
||||
vega: {
|
||||
yellow: '#DFFF0B',
|
||||
'yellow-dark': '#B6DC26',
|
||||
pink: '#FF077F',
|
||||
'pink-data-light': '#FF6AB2',
|
||||
'pink-dark': '#CF0064',
|
||||
'pink-data-dark': '#7A033D',
|
||||
green: '#00F780',
|
||||
'green-data-light': '#85FBC2',
|
||||
'green-dark': '#00D46E',
|
||||
'green-data-dark': '#006333',
|
||||
orange: '#FF7A1A',
|
||||
blue: '#1DA2FB',
|
||||
// YELLOW
|
||||
yellow: {
|
||||
700: '#23290E',
|
||||
650: '#515E1E',
|
||||
600: '#7E932F',
|
||||
550: '#ABC840',
|
||||
DEFAULT: '#D7FB50',
|
||||
500: '#D7FB50',
|
||||
450: '#E0FC75',
|
||||
400: '#E8FD9A',
|
||||
350: '#F0FDBE',
|
||||
300: '#F9FEE3',
|
||||
},
|
||||
|
||||
// GREEN
|
||||
green: {
|
||||
700: '#012915',
|
||||
650: '#015D30',
|
||||
600: '#01914B',
|
||||
550: '#01C566',
|
||||
DEFAULT: '#00F780',
|
||||
500: '#00F780',
|
||||
450: '#37F99B',
|
||||
400: '#6CFAB6',
|
||||
350: '#A1FCD0',
|
||||
300: '#D6FEEB',
|
||||
},
|
||||
|
||||
// BLUE
|
||||
blue: {
|
||||
700: '#01142A',
|
||||
650: '#012C60',
|
||||
600: '#014595',
|
||||
550: '#015ECB',
|
||||
DEFAULT: '#0075FF',
|
||||
500: '#0075FF',
|
||||
450: '#3793FF',
|
||||
400: '#6CAFFF',
|
||||
350: '#A1CCFF',
|
||||
300: '#D6E9FF',
|
||||
},
|
||||
|
||||
// PURPLE
|
||||
purple: {
|
||||
700: '#15072A',
|
||||
650: '#301060',
|
||||
600: '#4B1895',
|
||||
550: '#6620CB',
|
||||
DEFAULT: '#8028FF',
|
||||
500: '#8028FF',
|
||||
450: '#9B56FF',
|
||||
400: '#B683FF',
|
||||
350: '#D0B0FF',
|
||||
300: '#EBDDFF',
|
||||
},
|
||||
|
||||
// PINK
|
||||
pink: {
|
||||
700: '#210215',
|
||||
650: '#600330',
|
||||
600: '#95054B',
|
||||
550: '#CB0666',
|
||||
DEFAULT: '#FF077F',
|
||||
500: '#FF077F',
|
||||
450: '#FF3C9A',
|
||||
400: '#FF70B5',
|
||||
350: '#FFA3D0',
|
||||
300: '#FFD7EA',
|
||||
},
|
||||
|
||||
// ORANGE
|
||||
orange: {
|
||||
700: '#2A1701',
|
||||
650: '#603301',
|
||||
600: '#954F01',
|
||||
550: '#CB6C01',
|
||||
DEFAULT: '#FF8700',
|
||||
500: '#FF8700',
|
||||
450: '#FFA137',
|
||||
400: '#FFBA6C',
|
||||
350: '#FFD3A1',
|
||||
300: '#FFECD6',
|
||||
},
|
||||
|
||||
// DARK
|
||||
dark: {
|
||||
400: '#161616',
|
||||
300: '#262626',
|
||||
200: '#404040',
|
||||
150: '#8B8B8B',
|
||||
100: '#C0C0C0',
|
||||
},
|
||||
|
||||
// LIGHT
|
||||
light: {
|
||||
400: '#F0F0F0',
|
||||
300: '#E9E9E9',
|
||||
200: '#D2D2D2',
|
||||
150: '#939393',
|
||||
100: '#626262',
|
||||
},
|
||||
},
|
||||
danger: '#FF077F',
|
||||
warning: '#FF7A1A',
|
||||
warning: '#FF8700',
|
||||
success: '#00F780',
|
||||
},
|
||||
fontFamily: {
|
||||
|
||||
@@ -22,17 +22,17 @@ const vegaCustomClasses = plugin(function ({ addUtilities }) {
|
||||
},
|
||||
'.dark .syntax-highlighter-wrapper .hljs': {
|
||||
background: colors.neutral[800],
|
||||
color: theme.colors.vega.green,
|
||||
color: theme.colors.vega.green.DEFAULT,
|
||||
border: 0,
|
||||
},
|
||||
'.syntax-highlighter-wrapper .hljs-literal': {
|
||||
color: theme.colors.vega.pink,
|
||||
color: theme.colors.vega.pink.DEFAULT,
|
||||
},
|
||||
'.syntax-highlighter-wrapper .hljs-number': {
|
||||
color: theme.colors.vega.orange,
|
||||
color: theme.colors.vega.orange.DEFAULT,
|
||||
},
|
||||
'.syntax-highlighter-wrapper .hljs-string': {
|
||||
color: theme.colors.vega.blue,
|
||||
color: theme.colors.vega.blue.DEFAULT,
|
||||
},
|
||||
'.clip-path-rounded': {
|
||||
clipPath: 'circle(50%)',
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { AnnouncementBanner } from './announcement-banner';
|
||||
|
||||
describe('Banner', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = render(<AnnouncementBanner>Hi</AnnouncementBanner>);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import type { Story, ComponentMeta } from '@storybook/react';
|
||||
import { AnnouncementBanner } from './announcement-banner';
|
||||
|
||||
export default {
|
||||
component: AnnouncementBanner,
|
||||
title: 'Announcement Banner',
|
||||
} as ComponentMeta<typeof AnnouncementBanner>;
|
||||
|
||||
const Template: Story = (args) => (
|
||||
<div className="mb-8">
|
||||
<AnnouncementBanner {...args} />
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
children: <div className="text-center">Banner text</div>,
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
import classnames from 'classnames';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
export interface BannerProps {
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export const AnnouncementBanner = ({ children }: BannerProps) => {
|
||||
const bannerClasses = classnames(
|
||||
"bg-[url('https://static.vega.xyz/assets/img/banner-bg.jpg')] bg-cover bg-center bg-no-repeat",
|
||||
'p-4'
|
||||
);
|
||||
|
||||
return <div className={bannerClasses}>{children}</div>;
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './announcement-banner';
|
||||
@@ -27,20 +27,20 @@ const primary = [
|
||||
'text-black',
|
||||
'border-vega-yellow',
|
||||
'bg-vega-yellow',
|
||||
'enabled:hover:bg-vega-yellow-dark enabled:hover:border-vega-yellow-dark',
|
||||
'enabled:active:bg-vega-yellow-dark enabled:active:border-vega-yellow-dark',
|
||||
'enabled:hover:bg-vega-yellow-550 enabled:hover:border-vega-yellow-550',
|
||||
'enabled:active:bg-vega-yellow-550 enabled:active:border-vega-yellow-550',
|
||||
];
|
||||
const secondary = [
|
||||
'text-white dark:text-black',
|
||||
'border-vega-pink',
|
||||
'dark:bg-vega-pink bg-vega-pink-dark',
|
||||
'dark:bg-vega-pink bg-vega-pink-550',
|
||||
'enabled:hover:bg-vega-pink enabled:hover:border-vega-pink',
|
||||
'enabled:active:bg-vega-pink enabled:active:border-vega-pink',
|
||||
];
|
||||
const ternary = [
|
||||
'text-white dark:text-black',
|
||||
'border-vega-green',
|
||||
'dark:bg-vega-green bg-vega-green-dark',
|
||||
'dark:bg-vega-green bg-vega-green-550',
|
||||
'enabled:hover:bg-vega-green enabled:hover:border-vega-green',
|
||||
'enabled:active:bg-vega-green enabled:active:border-vega-green',
|
||||
];
|
||||
|
||||
@@ -79,7 +79,7 @@ export function Dialog({
|
||||
)}
|
||||
<div className="flex gap-4 max-w-full">
|
||||
{icon && <div className="fill-current">{icon}</div>}
|
||||
<div data-testid="dialog-content" className="flex-1">
|
||||
<div data-testid="dialog-content" className="flex-1 max-w-full">
|
||||
{title && (
|
||||
<h1
|
||||
className="text-xl uppercase mb-4 pr-2"
|
||||
|
||||
@@ -3,6 +3,7 @@ export * from './ag-grid';
|
||||
export * from './arrows';
|
||||
export * from './async-renderer';
|
||||
export * from './background-video';
|
||||
export * from './announcement-banner';
|
||||
export * from './button';
|
||||
export * from './callout';
|
||||
export * from './checkbox';
|
||||
|
||||
@@ -69,7 +69,8 @@ export const RichSelect = forwardRef<
|
||||
data-testid={props['data-testid'] || 'rich-select-trigger'}
|
||||
className={classNames(
|
||||
defaultSelectElement(hasError),
|
||||
'rounded-md pl-2 pr-11'
|
||||
'rounded-md pl-2 pr-11',
|
||||
'max-w-full overflow-hidden break-all'
|
||||
)}
|
||||
id={id}
|
||||
ref={forwardedRef}
|
||||
|
||||
@@ -40,9 +40,9 @@ export const Toggle = ({
|
||||
{
|
||||
'peer-checked:bg-neutral-400 dark:peer-checked:bg-white dark:peer-checked:text-black':
|
||||
type === 'primary',
|
||||
'dark:peer-checked:bg-vega-green peer-checked:bg-vega-green-dark':
|
||||
'dark:peer-checked:bg-vega-green peer-checked:bg-vega-green-550':
|
||||
type === 'buy',
|
||||
'dark:peer-checked:bg-vega-pink peer-checked:bg-vega-pink-dark':
|
||||
'dark:peer-checked:bg-vega-pink peer-checked:bg-vega-pink-550':
|
||||
type === 'sell',
|
||||
},
|
||||
'peer-checked:text-white dark:peer-checked:text-black',
|
||||
|
||||
@@ -14,32 +14,29 @@ import colors from 'tailwindcss/colors';
|
||||
|
||||
This project uses Tailwindcss so a lot of colour props are passed in as CSS classes that
|
||||
Tailwind applies styling to i.e. `text-blue-500` to use the primary blue. You can find the
|
||||
full colour palette [here](https://tailwindcss.com/docs/customizing-colors/#default-color-palette).
|
||||
full tailiwnd's colour palette [here](https://tailwindcss.com/docs/customizing-colors/#default-color-palette).
|
||||
|
||||
The Vega's colour palette can be found [here](https://www.figma.com/file/8lCQ6iNK3dbw42bIKwGCRk/Foundations?node-id=3750%3A77046)
|
||||
|
||||
## Colours
|
||||
|
||||
### Shared
|
||||
|
||||
<ColorPalette>
|
||||
<ColorItem title="White" colors={colors.white} />
|
||||
<ColorItem title="Black" colors={colors.black} />
|
||||
</ColorPalette>
|
||||
|
||||
### Vega
|
||||
|
||||
<ColorPalette>
|
||||
<ColorItem
|
||||
title="theme.color.vega"
|
||||
subtitle="Vega colors"
|
||||
colors={theme.colors.vega}
|
||||
title="dark"
|
||||
colors={{ ...theme.colors.vega.dark, black: theme.colors.black }}
|
||||
/>
|
||||
</ColorPalette>
|
||||
|
||||
### Intent
|
||||
|
||||
<ColorPalette>
|
||||
<ColorItem
|
||||
title="theme.color[danger|warning|success]"
|
||||
title="light"
|
||||
colors={{ ...theme.colors.vega.light, white: theme.colors.white }}
|
||||
/>
|
||||
<ColorItem title="yellow" colors={theme.colors.vega.yellow} />
|
||||
<ColorItem title="green" colors={theme.colors.vega.green} />
|
||||
<ColorItem title="blue" colors={theme.colors.vega.blue} />
|
||||
<ColorItem title="purple" colors={theme.colors.vega.purple} />
|
||||
<ColorItem title="pink" colors={theme.colors.vega.pink} />
|
||||
<ColorItem title="orange" colors={theme.colors.vega.orange} />
|
||||
<ColorItem
|
||||
title="intent"
|
||||
colors={{
|
||||
danger: theme.colors.danger,
|
||||
warning: theme.colors.warning,
|
||||
@@ -47,3 +44,33 @@ full colour palette [here](https://tailwindcss.com/docs/customizing-colors/#defa
|
||||
}}
|
||||
/>
|
||||
</ColorPalette>
|
||||
|
||||
# Replacement for legacy shades
|
||||
|
||||
<ColorPalette>
|
||||
<ColorItem
|
||||
title="legacy shades"
|
||||
colors={{
|
||||
'vega-yellow-dark': '#B6DC26', // vega-yellow-dark -> vega-yellow-550
|
||||
'vega-pink-data-light': '#FF6AB2', // vega-pink-data-light -> vega-pink-400
|
||||
'vega-pink-dark': '#CF0064', // vega-pink-dark -> vega-pink-550
|
||||
'vega-pink-data-dark': '#7A033D', // vega-pink-data-dark -> vega-pink-650
|
||||
'vega-green-data-light': '#85FBC2', // vega-green-data-light -> vega-green-400
|
||||
'vega-green-dark': '#00D46E', // vega-green-dark -> vega-green-550
|
||||
'vega-green-data-dark': '#006333', // vega-green-data-dark -> vega-green-650
|
||||
}}
|
||||
/>
|
||||
|
||||
<ColorItem
|
||||
title="replacement"
|
||||
colors={{
|
||||
'vega-yellow-550': theme.colors.vega.yellow[550],
|
||||
'vega-pink-400': theme.colors.vega.pink[400],
|
||||
'vega-pink-550': theme.colors.vega.pink[550],
|
||||
'vega-pink-650': theme.colors.vega.pink[650],
|
||||
'vega-green-400': theme.colors.vega.green[400],
|
||||
'vega-green-550': theme.colors.vega.green[550],
|
||||
'vega-green-650': theme.colors.vega.green[650],
|
||||
}}
|
||||
/>
|
||||
</ColorPalette>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook, act } from '@testing-library/react-hooks';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import type { ReactNode } from 'react';
|
||||
@@ -33,6 +33,7 @@ const render = (mocks?: MockedResponse[]) => {
|
||||
const wrapper = ({ children }: { children: ReactNode }) => (
|
||||
<MockedProvider mocks={mocks}>{children}</MockedProvider>
|
||||
);
|
||||
|
||||
return renderHook(() => useVegaTransactionUpdater(), { wrapper });
|
||||
};
|
||||
|
||||
@@ -193,19 +194,23 @@ describe('useVegaTransactionManager', () => {
|
||||
it('updates order on OrderBusEvents', async () => {
|
||||
mockTransactionStoreState.mockReturnValue(defaultState);
|
||||
const { waitForNextUpdate } = render([mockedOrderBusEvent]);
|
||||
waitForNextUpdate();
|
||||
await waitForNextTick();
|
||||
expect(updateOrder).toHaveBeenCalledWith(orderBusEvent);
|
||||
await act(async () => {
|
||||
waitForNextUpdate();
|
||||
await waitForNextTick();
|
||||
expect(updateOrder).toHaveBeenCalledWith(orderBusEvent);
|
||||
});
|
||||
});
|
||||
|
||||
it('updates transaction on TransactionResultBusEvents', async () => {
|
||||
mockTransactionStoreState.mockReturnValue(defaultState);
|
||||
const { waitForNextUpdate } = render([mockedTransactionResultBusEvent]);
|
||||
waitForNextUpdate();
|
||||
await waitForNextTick();
|
||||
expect(updateTransactionResult).toHaveBeenCalledWith(
|
||||
transactionResultBusEvent
|
||||
);
|
||||
await act(async () => {
|
||||
waitForNextUpdate();
|
||||
await waitForNextTick();
|
||||
expect(updateTransactionResult).toHaveBeenCalledWith(
|
||||
transactionResultBusEvent
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('updates withdrawal on WithdrawalBusEvents', async () => {
|
||||
@@ -215,11 +220,13 @@ describe('useVegaTransactionManager', () => {
|
||||
erc20WithdrawalApproval
|
||||
);
|
||||
const { waitForNextUpdate } = render([mockedWithdrawalBusEvent]);
|
||||
waitForNextUpdate();
|
||||
await waitForNextTick();
|
||||
expect(updateWithdrawal).toHaveBeenCalledWith(
|
||||
withdrawalBusEvent,
|
||||
erc20WithdrawalApproval
|
||||
);
|
||||
await act(async () => {
|
||||
waitForNextUpdate();
|
||||
await waitForNextTick();
|
||||
expect(updateWithdrawal).toHaveBeenCalledWith(
|
||||
withdrawalBusEvent,
|
||||
erc20WithdrawalApproval
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { act } from '@testing-library/react';
|
||||
const zu = jest.requireActual('zustand'); // if using jest
|
||||
|
||||
// a variable to hold reset functions for all stores declared in the app
|
||||
@@ -6,7 +6,14 @@ const storeResetFns = new Set();
|
||||
|
||||
// when creating a store, we get its initial state, create a reset function and add it in the set
|
||||
export const create = (createState) => {
|
||||
const store = zu.create(createState);
|
||||
let store;
|
||||
if (typeof createState === 'function') {
|
||||
store = zu.create(createState);
|
||||
} else {
|
||||
store = (selector, equalityFn) =>
|
||||
zu.useStore(createState, selector, equalityFn);
|
||||
Object.assign(store, createState);
|
||||
}
|
||||
const initialState = store.getState();
|
||||
storeResetFns.add(() => store.setState(initialState, true));
|
||||
return store;
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import {
|
||||
fireEvent,
|
||||
render,
|
||||
screen,
|
||||
act,
|
||||
waitFor,
|
||||
} from '@testing-library/react';
|
||||
import type { RenderResult } from '@testing-library/react';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { Web3Container } from './web3-container';
|
||||
@@ -63,103 +70,111 @@ jest.mock('@web3-react/core', () => {
|
||||
};
|
||||
});
|
||||
|
||||
function setup(mock = networkParamsQueryMock) {
|
||||
return render(
|
||||
<EnvironmentProvider definitions={mockEnvironment}>
|
||||
<MockedProvider mocks={[mock]}>
|
||||
<Web3Container>
|
||||
<div>
|
||||
<div>Child</div>
|
||||
<div>{mockEthereumConfig.collateral_bridge_contract.address}</div>
|
||||
</div>
|
||||
</Web3Container>
|
||||
</MockedProvider>
|
||||
<Web3ConnectUncontrolledDialog />
|
||||
</EnvironmentProvider>
|
||||
);
|
||||
let renderResults: RenderResult;
|
||||
async function setup(mock = networkParamsQueryMock) {
|
||||
await act(async () => {
|
||||
renderResults = await render(
|
||||
<EnvironmentProvider definitions={mockEnvironment}>
|
||||
<MockedProvider mocks={[mock]}>
|
||||
<Web3Container>
|
||||
<div>
|
||||
<div>Child</div>
|
||||
<div>{mockEthereumConfig.collateral_bridge_contract.address}</div>
|
||||
</div>
|
||||
</Web3Container>
|
||||
</MockedProvider>
|
||||
<Web3ConnectUncontrolledDialog />
|
||||
</EnvironmentProvider>
|
||||
);
|
||||
});
|
||||
return renderResults;
|
||||
}
|
||||
|
||||
it('Prompt to connect opens dialog', async () => {
|
||||
mockHookValue = defaultHookValue;
|
||||
setup();
|
||||
describe('Web3Container', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('Prompt to connect opens dialog', async () => {
|
||||
mockHookValue = defaultHookValue;
|
||||
await setup();
|
||||
await waitFor(async () => {
|
||||
expect(
|
||||
await screen.findByText('Connect your Ethereum wallet')
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
||||
expect(
|
||||
await screen.findByText('Connect your Ethereum wallet')
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText('Child')).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByTestId('web3-connector-list')
|
||||
).not.toBeInTheDocument();
|
||||
await act(() => {
|
||||
fireEvent.click(screen.getByText('Connect'));
|
||||
});
|
||||
expect(screen.getByTestId('web3-connector-list')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
expect(screen.queryByText('Child')).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId('web3-connector-list')).not.toBeInTheDocument();
|
||||
it('Error message is shown', async () => {
|
||||
const message = 'Opps! An error';
|
||||
mockHookValue = { ...defaultHookValue, error: new Error(message) };
|
||||
await setup();
|
||||
|
||||
fireEvent.click(screen.getByText('Connect'));
|
||||
expect(screen.getByTestId('web3-connector-list')).toBeInTheDocument();
|
||||
});
|
||||
await waitFor(async () => {
|
||||
expect(
|
||||
await screen.findByText(`Something went wrong: ${message}`)
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText('Child')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('Error message is shown', async () => {
|
||||
const message = 'Opps! An error';
|
||||
mockHookValue = { ...defaultHookValue, error: new Error(message) };
|
||||
setup();
|
||||
it('Checks that chain ID matches app ID', async () => {
|
||||
const expectedChainId = 4;
|
||||
mockHookValue = {
|
||||
...defaultHookValue,
|
||||
isActive: true,
|
||||
chainId: expectedChainId,
|
||||
};
|
||||
await setup();
|
||||
expect(
|
||||
await screen.findByText(`This app only works on Sepolia`)
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText('Child')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
||||
expect(
|
||||
await screen.findByText(`Something went wrong: ${message}`)
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText('Child')).not.toBeInTheDocument();
|
||||
});
|
||||
it('Passes ethereum config to children', async () => {
|
||||
mockHookValue = {
|
||||
...defaultHookValue,
|
||||
isActive: true,
|
||||
};
|
||||
await setup();
|
||||
expect(
|
||||
await screen.findByText(
|
||||
mockEthereumConfig.collateral_bridge_contract.address
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Checks that chain ID matches app ID', async () => {
|
||||
const expectedChainId = 4;
|
||||
mockHookValue = {
|
||||
...defaultHookValue,
|
||||
isActive: true,
|
||||
chainId: expectedChainId,
|
||||
};
|
||||
setup();
|
||||
|
||||
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
||||
expect(
|
||||
await screen.findByText(`This app only works on Sepolia`)
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText('Child')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Passes ethereum config to children', async () => {
|
||||
mockHookValue = {
|
||||
...defaultHookValue,
|
||||
isActive: true,
|
||||
};
|
||||
setup();
|
||||
|
||||
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
||||
expect(
|
||||
await screen.findByText(
|
||||
mockEthereumConfig.collateral_bridge_contract.address
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Shows no config found message if the network parameter doesnt exist', async () => {
|
||||
const mock: MockedResponse<NetworkParamsQuery> = {
|
||||
request: {
|
||||
query: NetworkParamsDocument,
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
networkParametersConnection: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
__typename: 'NetworkParameter',
|
||||
key: 'nope',
|
||||
value: 'foo',
|
||||
it('Shows no config found message if the network parameter doesnt exist', async () => {
|
||||
const mock: MockedResponse<NetworkParamsQuery> = {
|
||||
request: {
|
||||
query: NetworkParamsDocument,
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
networkParametersConnection: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
__typename: 'NetworkParameter',
|
||||
key: 'nope',
|
||||
value: 'foo',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
setup(mock);
|
||||
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
||||
expect(await screen.findByText('No data')).toBeInTheDocument();
|
||||
};
|
||||
await setup(mock);
|
||||
expect(await screen.findByText('No data')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render, screen, act, waitFor } from '@testing-library/react';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import type { Account } from '@vegaprotocol/accounts';
|
||||
import { WithdrawFormContainer } from './withdraw-form-container';
|
||||
@@ -95,7 +95,7 @@ describe('WithdrawFormContainer', () => {
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
it('should be properly rendered', () => {
|
||||
it('should be properly rendered', async () => {
|
||||
mockData = [
|
||||
{ ...account1 },
|
||||
{ ...account2 },
|
||||
@@ -186,50 +186,68 @@ describe('WithdrawFormContainer', () => {
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
];
|
||||
const { container } = render(
|
||||
<MockedProvider>
|
||||
<WithdrawFormContainer {...props} />
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(screen.getByTestId('select-asset')).toBeInTheDocument();
|
||||
const options = container.querySelectorAll('select[name="asset"] option');
|
||||
expect(options).toHaveLength(3);
|
||||
let rendererContainer: Element;
|
||||
await act(() => {
|
||||
const { container } = render(<WithdrawFormContainer {...props} />, {
|
||||
wrapper: MockedProvider,
|
||||
});
|
||||
rendererContainer = container;
|
||||
});
|
||||
await expect(screen.getByTestId('select-asset')).toBeInTheDocument();
|
||||
await waitFor(() => {
|
||||
const options = rendererContainer.querySelectorAll(
|
||||
'select[name="asset"] option'
|
||||
);
|
||||
expect(options).toHaveLength(3);
|
||||
});
|
||||
});
|
||||
|
||||
it('should display no data message', () => {
|
||||
it('should display no data message', async () => {
|
||||
mockData = null;
|
||||
render(
|
||||
<MockedProvider>
|
||||
<WithdrawFormContainer {...props} />
|
||||
</MockedProvider>
|
||||
);
|
||||
await act(() => {
|
||||
render(
|
||||
<MockedProvider>
|
||||
<WithdrawFormContainer {...props} />
|
||||
</MockedProvider>
|
||||
);
|
||||
});
|
||||
expect(
|
||||
screen.getByText('You have no assets to withdraw')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should filter out zero balance account assets', () => {
|
||||
it('should filter out zero balance account assets', async () => {
|
||||
let rendererContainer: Element;
|
||||
mockData = [{ ...account1 }, { ...account2, balance: '0' }];
|
||||
const { container } = render(
|
||||
<MockedProvider>
|
||||
<WithdrawFormContainer {...props} />
|
||||
</MockedProvider>
|
||||
);
|
||||
await act(() => {
|
||||
const { container } = render(
|
||||
<MockedProvider>
|
||||
<WithdrawFormContainer {...props} />
|
||||
</MockedProvider>
|
||||
);
|
||||
rendererContainer = container;
|
||||
});
|
||||
expect(screen.getByTestId('select-asset')).toBeInTheDocument();
|
||||
const options = container.querySelectorAll('select[name="asset"] option');
|
||||
expect(options).toHaveLength(2);
|
||||
await waitFor(() => {
|
||||
const options = rendererContainer.querySelectorAll(
|
||||
'select[name="asset"] option'
|
||||
);
|
||||
expect(options).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('when no accounts have a balance should should display no data message', () => {
|
||||
it('when no accounts have a balance should should display no data message', async () => {
|
||||
mockData = [
|
||||
{ ...account1, balance: '0' },
|
||||
{ ...account2, balance: '0' },
|
||||
];
|
||||
render(
|
||||
<MockedProvider>
|
||||
<WithdrawFormContainer {...props} />
|
||||
</MockedProvider>
|
||||
);
|
||||
await act(() => {
|
||||
render(
|
||||
<MockedProvider>
|
||||
<WithdrawFormContainer {...props} />
|
||||
</MockedProvider>
|
||||
);
|
||||
});
|
||||
expect(
|
||||
screen.getByText('You have no assets to withdraw')
|
||||
).toBeInTheDocument();
|
||||
|
||||
@@ -23,13 +23,17 @@ export const WithdrawFormContainer = ({
|
||||
variables,
|
||||
});
|
||||
|
||||
const filteredAsset = data
|
||||
?.filter(
|
||||
(account) =>
|
||||
account.type === Types.AccountType.ACCOUNT_TYPE_GENERAL &&
|
||||
toBigNum(account.balance, account.asset.decimals).isGreaterThan(0)
|
||||
)
|
||||
.map((account) => account.asset);
|
||||
const filteredAsset = useMemo(
|
||||
() =>
|
||||
data
|
||||
?.filter(
|
||||
(account) =>
|
||||
account.type === Types.AccountType.ACCOUNT_TYPE_GENERAL &&
|
||||
toBigNum(account.balance, account.asset.decimals).isGreaterThan(0)
|
||||
)
|
||||
.map((account) => account.asset),
|
||||
[data]
|
||||
);
|
||||
const assets = filteredAsset?.length ? filteredAsset : null;
|
||||
return (
|
||||
<AsyncRenderer
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Asset } from '@vegaprotocol/assets';
|
||||
import { AssetOption } from '@vegaprotocol/assets';
|
||||
import {
|
||||
ethereumAddress,
|
||||
minSafe,
|
||||
@@ -14,7 +15,6 @@ import {
|
||||
Input,
|
||||
InputError,
|
||||
RichSelect,
|
||||
Option,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import BigNumber from 'bignumber.js';
|
||||
@@ -92,9 +92,6 @@ export const WithdrawForm = ({
|
||||
}: {
|
||||
field: ControllerRenderProps<FormFields, 'asset'>;
|
||||
}) => {
|
||||
console.log('assets', assets.filter(isAssetTypeERC20));
|
||||
console.log('selected asset', selectedAsset);
|
||||
|
||||
return (
|
||||
<RichSelect
|
||||
data-testid="select-asset"
|
||||
@@ -110,14 +107,7 @@ export const WithdrawForm = ({
|
||||
hasError={Boolean(errors.asset?.message)}
|
||||
>
|
||||
{assets.filter(isAssetTypeERC20).map((a) => (
|
||||
<Option key={a.id} value={a.id}>
|
||||
<div className="flex flex-col items-start">
|
||||
<span>{a.name}</span>
|
||||
<span className="text-[10px] font-mono">
|
||||
<span className="text-gray-500">{a.id} -</span> {a.symbol}
|
||||
</span>
|
||||
</div>
|
||||
</Option>
|
||||
<AssetOption key={a.id} asset={a} />
|
||||
))}
|
||||
</RichSelect>
|
||||
);
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
"@babel/preset-typescript": "7.12.13",
|
||||
"@commitlint/cli": "^16.2.4",
|
||||
"@commitlint/config-conventional": "^16.2.4",
|
||||
"@commitlint/config-nx-scopes": "^17.4.2",
|
||||
"@cypress/grep": "^3.1.0",
|
||||
"@ethersproject/experimental": "^5.6.0",
|
||||
"@graphql-codegen/cli": "^2.11.8",
|
||||
|
||||
@@ -188,6 +188,8 @@
|
||||
"governance.proposal.updateNetParam.minClose": "2s",
|
||||
"governance.proposal.updateNetParam.minEnact": "2s",
|
||||
"governance.proposal.updateNetParam.requiredParticipation": "0.00000000000000000000000015",
|
||||
"governance.proposal.freeform.minClose": "2s",
|
||||
"governance.proposal.freeform.requiredParticipation": "0.00000000000000000000000015",
|
||||
"market.auction.minimumDuration": "3s",
|
||||
"market.fee.factors.infrastructureFee": "0.001",
|
||||
"market.fee.factors.makerFee": "0.004",
|
||||
|
||||
@@ -1618,6 +1618,11 @@
|
||||
dependencies:
|
||||
conventional-changelog-conventionalcommits "^4.3.1"
|
||||
|
||||
"@commitlint/config-nx-scopes@^17.4.2":
|
||||
version "17.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@commitlint/config-nx-scopes/-/config-nx-scopes-17.4.2.tgz#365feba8d5f935517d4387381b8c90289a8596c7"
|
||||
integrity sha512-xNbbLfFxK+U0LJv99PNP+qe1c3J8Q76gdtz9JIcUJL8FsRV5dDdxvYplNAs88WqCFViP0ipNTYljyigftr3nqg==
|
||||
|
||||
"@commitlint/config-validator@^16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@commitlint/config-validator/-/config-validator-16.2.1.tgz#794e769afd4756e4cf1bfd823b6612932e39c56d"
|
||||
@@ -19190,9 +19195,9 @@ react-refresh@^0.11.0:
|
||||
integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==
|
||||
|
||||
react-remove-scroll-bar@^2.3.3:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.3.tgz#e291f71b1bb30f5f67f023765b7435f4b2b2cd94"
|
||||
integrity sha512-i9GMNWwpz8XpUpQ6QlevUtFjHGqnPG4Hxs+wlIJntu/xcsZVEpJcIV71K3ZkqNy2q3GfgvkD7y6t/Sv8ofYSbw==
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9"
|
||||
integrity sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==
|
||||
dependencies:
|
||||
react-style-singleton "^2.2.1"
|
||||
tslib "^2.0.0"
|
||||
|
||||
Reference in New Issue
Block a user