Compare commits

..
Author SHA1 Message Date
Bill He 54a520fbf2 bump v4-client and abacus 2023-09-15 10:43:56 -07:00
aleka 1462e37c43 temporarily shut down prod FE (#37)
* shut down fe for testnet3 prod
2023-09-13 17:01:42 -04:00
aleka d99b0356e9 bump v4-localization to use testnet3 (#36) 2023-09-13 09:36:23 -07:00
aleka 5cd9bb0fc5 bump abacus for transfers ws fix (#35) 2023-09-13 12:19:34 -04:00
Jared Vu 986a134d07 handle composite client error (#33) 2023-09-13 09:15:22 -07:00
Jared Vu ab454d5928 eslint (#26)
* eslint - hooks

* eslint - icons

* eslint - styles

* eslint - state
2023-09-12 09:42:38 -07:00
aleka 0f1491ac33 show exchange offline dialog for testnet2 (#32) 2023-09-12 11:29:38 -04:00
Jared Vu 1f73f3a884 v4-abacus (#31) 2023-09-11 16:56:13 -07:00
Jared Vu 419d05a0e1 Satoshi font 2 (#30)
* Use Satoshi in TvChart

* update tradingview.tgz
2023-09-11 15:59:43 -07:00
Jared Vu 0c4b605666 Add base position notional (#29) 2023-09-11 15:15:03 -07:00
James Jia 710e5ac113 Update README (#27) 2023-09-08 16:32:24 -07:00
Bill 8fdac4dc09 bump v4-client (#28) 2023-09-08 16:31:34 -07:00
James Jia - Test 4b86068d8f Initial commit 2023-09-08 13:52:13 -07:00
70 changed files with 312 additions and 530 deletions
-12
View File
@@ -2,17 +2,5 @@ VITE_BASE_URL=https://v4.testnet.dydx.exchange
VITE_ALCHEMY_API_KEY=FP275q327Yh7qswtZWenbPXdZZdnAFmC
VITE_FAUCET_URL_DEV=https://faucet.v4dev.dydx.exchange/
VITE_FAUCET_URL_STAGE=https://faucet.v4staging.dydx.exchange/
VITE_FAUCET_URL_TESTNET2=https://faucet.v4testnet2.dydx.exchange/
VITE_VALIDATOR_URL_DEV=http://52.192.187.113:26657/
VITE_VALIDATOR_URL_STAGE=https://validator.v4staging.dydx.exchange/
VITE_VALIDATOR_URL_TESTNET2=https://validator.v4testnet2.dydx.exchange/
VITE_INDEXER_URL_DEV=http://dev-indexer-apne1-lb-public-890774175.ap-northeast-1.elb.amazonaws.com
VITE_INDEXER_URL_STAGE=https://indexer.v4staging.dydx.exchange
VITE_INDEXER_URL_TESTNET2=https://indexer.v4testnet2.dydx.exchange
VITE_WALLETCONNECT1_BRIDGE=wss://api.dydx.exchange/wc/
VITE_WALLETCONNECT2_PROJECT_ID=fbe94eaa691fa8d929561f8567062b32
+3 -12
View File
@@ -1,17 +1,8 @@
VITE_BASE_URL=
VITE_ALCHEMY_API_KEY=
VITE_PK_ENCRYPTION_KEY=
VITE_WALLETCONNECT1_BRIDGE=
VITE_WALLETCONNECT2_PROJECT_ID=
VITE_FAUCET_URL_DEV=
VITE_FAUCET_URL_STAGE=
VITE_FAUCET_URL_TESTNET2=
VITE_VALIDATOR_URL_DEV=
VITE_VALIDATOR_URL_STAGE=
VITE_VALIDATOR_URL_TESTNET2=
VITE_INDEXER_URL_DEV=
VITE_INDEXER_URL_STAGE=
VITE_INDEXER_URL_TESTNET2=
-5
View File
@@ -5,15 +5,10 @@ vite.config.ts
# Temporarily ignore, we will slowly remove each directory as we fix files to follow ESLint rules
/src/components
/src/dialogs
/src/forms
/src/hooks
/src/history.ts
/src/icons
/src/lib
/src/main.tsx
/src/menus
/src/pages
/src/state
/src/styles
/src/views
+4 -6
View File
@@ -33,14 +33,11 @@
"jsx-a11y/anchor-is-valid": "off",
"jsx-a11y/click-events-have-key-events": "off",
"no-continue": "off",
"no-console": [
"error",
{
"devDependencies": ["./scripts/*.js"]
}
],
"no-console": ["error"],
"no-lonely-if": "off",
"no-multi-assign": "off",
"no-nested-ternary": "off",
"no-param-reassign": ["error", { "props": false }],
"no-return-assign": "off",
"no-return-await": "off",
"no-underscore-dangle": "off",
@@ -65,6 +62,7 @@
"react/sort-comp": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/comma-dangle": "off",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/member-delimiter-style": [
"error",
{
+4 -4
View File
@@ -1,4 +1,4 @@
# Contributing to Trader-Fe
# Contributing to V4-web
We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's:
- Reporting a bug
@@ -18,10 +18,10 @@ Pull requests are the best way to propose changes to the codebase (we use [Githu
4. Issue that pull request!
## Any contributions you make will be under the same License
When you submit code changes, your submissions are understood to be under the same [License](https://github.com/dydxprotocol/trader-fe/blob/master/LICENSE) that covers the project.
When you submit code changes, your submissions are understood to be under the same [License](https://github.com/dydxprotocol/v4-web/blob/master/LICENSE) that covers the project.
## Report bugs using Github's [issues](https://github.com/dydxprotocol/trader-fe/issues)
Report a bug by [opening a new issue](https://github.com/dydxprotocol/trader-fe/issues/new).
## Report bugs using Github's [issues](https://github.com/dydxprotocol/v4-web/issues)
Report a bug by [opening a new issue](https://github.com/dydxprotocol/v4-web/issues/new).
**Great Bug Reports** tend to have:
+9 -6
View File
@@ -1,16 +1,19 @@
Business Source License 1.1
License text copyright © 2023 MariaDB plc, All Rights Reserved. “Business Source License” is a trademark of MariaDB plc.
Copyright (C) 2023 dYdX Trading Inc.
Subject to your compliance with applicable law, you are granted the right to use the Licensed Work (defined below) under the terms of the below licenses; provided, however, that if you violate any such applicable law in your use of the Licensed Work, all of your rights and licenses to use (including any rights to reproduce, distribute, install or modify) the Licensed Work will automatically and immediately terminate.
Use of this software before the Change Date specified in the LICENSE file is governed by the Business Source License included in the LICENSE file and at https://spdx.org/licenses/BUSL-1.1.html.
On and after the Change Date specified in the LICENSE file, use of this software will be governed by the Change License (GNU Affero GPL v3) as specified in the LICENSE file.
Business Source License 1.1
Business Source License text copyright © 2023 MariaDB plc, All Rights Reserved. “Business Source License” is a trademark of MariaDB plc.
Copyright (C) 2023 dYdX Trading Inc.
Parameters
Licensor: dYdX Trading Inc.
Licensed Work: dydxprotocol/cosmos-sdk, dydxprotocol/cometbft, dydxprotocol/v4-chain, dydxprotocol/v4-clients, dydxprotocol/v4-web, dydxprotocol/v4-abacus, dydxprotocol/v4-localization, dydxprotocol/v4-documentation, and any dYdX or dYdX Trading Inc. github repository reflecting a copy of this license, or link to this license.
Additional Use Grant: None
Change Date: On the later to occur of (i) the release of the Licensed Work labeled “dYdX Version 1.0 GPL”, and which includes a document uploaded to the relevant github repository stating “The software in this repository is Version 1.0, subject to GPL license”, and (ii) September 30, 2023 (approximate projected release of “Version 1.0” of this software).
Change Date: On the later to occur of (i) the release of the Licensed Work labeled “dYdX Version 1.0 Affero GPL”, and which includes a document uploaded to the relevant github repository stating “The software in this repository is Version 1.0, subject to Affero GPL license”, and (ii) September 30, 2023 (approximate projected release of “Version 1.0” of this software).
Change License: GNU Affero GPL License v3
License text copyright © 2023 MariaDB plc, All Rights Reserved. “Business Source License” is a trademark of MariaDB plc.
@@ -39,7 +42,7 @@ OPEN SOURCE LICENSE BELOW - TO BE APPLIED AFTER THE CHANGE DATE.
Copyright (C) 2023 dYdX Trading Inc.
Use of this software is governed by the The GNU Affero General Public License as set forth below.
Subject to your compliance with applicable law, you are granted the right to use the Licensed Work (defined below) under the terms of the GNU Affero General Public License as set forth below; provided, however, that if you violate any such applicable law in your use of the Licensed Work, all of your rights and licenses to use (including any rights to reproduce, distribute, install or modify) the Licensed Work will automatically and immediately terminate.
The GNU Affero General Public License
@@ -835,4 +838,4 @@ copy of the Program in return for a fee.
For more information about this software, see https://dydx.exchange.
Copyright (C) 2023 dYdX Trading Inc.
Copyright (C) 2023 dYdX Trading Inc.
+11 -3
View File
@@ -1,4 +1,12 @@
# v4 Web App
<p align="center"><img src="https://dydx.exchange/icon.svg?" width="256" /></p>
<h1 align="center">v4 Web</h1>
<div align="center">
<a href='https://github.com/dydxprotocol/v4-web/blob/main/LICENSE'>
<img src='https://img.shields.io/badge/License-BSL_1.1-blue' alt='License' />
</a>
</div>
## Prerequisites
@@ -22,8 +30,8 @@ Alternatively, follow the [IPFS Kubo installation guide](https://docs.ipfs.tech
Clone the repository and navigate to its directory:
```bash
git clone https://github.com/dydxprotocol/trader-fe.git
cd trader-fe
git clone https://github.com/dydxprotocol/v4-web.git
cd v4-web
```
### Step 2: Install pnpm and dependencies
+3 -3
View File
@@ -37,9 +37,9 @@
"@cosmjs/proto-signing": "^0.31.0",
"@cosmjs/stargate": "^0.31.0",
"@cosmjs/tendermint-rpc": "^0.31.0",
"@dydxprotocol/abacus": "^0.4.7",
"@dydxprotocol/v4-client-js": "^0.32.0",
"@dydxprotocol/v4-localization": "^0.0.25",
"@dydxprotocol/v4-abacus": "^0.4.28",
"@dydxprotocol/v4-client-js": "^0.35.0",
"@dydxprotocol/v4-localization": "^0.1.5",
"@ethersproject/providers": "^5.7.2",
"@js-joda/core": "^5.5.3",
"@radix-ui/react-collapsible": "^1.0.3",
+36 -242
View File
@@ -26,15 +26,15 @@ dependencies:
'@cosmjs/tendermint-rpc':
specifier: ^0.31.0
version: 0.31.0
'@dydxprotocol/abacus':
specifier: ^0.4.7
version: 0.4.7
'@dydxprotocol/v4-abacus':
specifier: ^0.4.28
version: 0.4.28
'@dydxprotocol/v4-client-js':
specifier: ^0.32.0
version: 0.32.0
specifier: ^0.35.0
version: 0.35.0
'@dydxprotocol/v4-localization':
specifier: ^0.0.25
version: 0.0.25
specifier: ^0.1.5
version: 0.1.5
'@ethersproject/providers':
specifier: ^5.7.2
version: 5.7.2
@@ -614,74 +614,6 @@ packages:
'@babel/helper-validator-identifier': 7.22.5
to-fast-properties: 2.0.0
/@bufbuild/buf-darwin-arm64@1.19.0-1:
resolution: {integrity: sha512-HsWPii21wm3QSyuxrNq9+Yf8iAgpnC4rNCy4x3d6P1fd/LmgE1NPzQW0ghEZvl9dgAQKkL/4S5bKhlm7kbUdmQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@bufbuild/buf-darwin-x64@1.19.0-1:
resolution: {integrity: sha512-2+Ig7ylYpVh4kms/OeJJVY+X0KX4awPA6hYr7L7aZOIcHwZEM8lWtSTO/se5pQc7dc8FXNiC4YUqHC8yfxxX6Q==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@bufbuild/buf-linux-aarch64@1.19.0-1:
resolution: {integrity: sha512-g/Vxg3WiBr3nhsxsRr2Q81xXJD+0ktHIO3ZJggTG2Sbbl3dh8kyg1iKM6MjJiMP7su5RKCylLigzoEJzVTShyA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@bufbuild/buf-linux-x64@1.19.0-1:
resolution: {integrity: sha512-anYuGx8k/2kp8GPX3eHNUf3IY/01Zpnyw0HaLPXK1Btqyy6XkapVywrDqg7YUzMd1ySFEp1wD9UqRNdEFNCQ4A==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@bufbuild/buf-win32-arm64@1.19.0-1:
resolution: {integrity: sha512-xXgF1qYnCfRKbGx1FqvPbpZ6ajh4ddxpXhSxI3VCeb3MsMBuIbiLqX4fQAL3ls/Zwz8tVIITuSwOhYmSEGcpBA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@bufbuild/buf-win32-x64@1.19.0-1:
resolution: {integrity: sha512-futmqgpMQCR1lcAzZJEGjPr7ECw1gYTPIV8crm5SY+iCJ7sOeStOBNt7q5hV4LKmmeWmvm03XIMZPjhQzjH5NQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@bufbuild/buf@1.19.0-1:
resolution: {integrity: sha512-TIsLTTQUntr/Xq/IMSULv3dlC3/ZsVwQtWgxmJ++IzSuOW79TFQfq59vFeTWrPa6+QXFMz5t6jkMyD4ghzO5nw==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
'@bufbuild/buf-darwin-arm64': 1.19.0-1
'@bufbuild/buf-darwin-x64': 1.19.0-1
'@bufbuild/buf-linux-aarch64': 1.19.0-1
'@bufbuild/buf-linux-x64': 1.19.0-1
'@bufbuild/buf-win32-arm64': 1.19.0-1
'@bufbuild/buf-win32-x64': 1.19.0-1
dev: false
/@coinbase/wallet-sdk@3.7.1:
resolution: {integrity: sha512-LjyoDCB+7p0waQXfK+fUgcAs3Ezk6S6e+LYaoFjpJ6c9VTop3NyZF40Pi7df4z7QJohCwzuIDjz0Rhtig6Y7Pg==}
engines: {node: '>= 10.0.0'}
@@ -726,15 +658,6 @@ packages:
'@cosmjs/utils': 0.27.1
dev: false
/@cosmjs/amino@0.29.3:
resolution: {integrity: sha512-BFz1++ERerIggiFc7iGHhGe1CeV3rCv8BvkoBQTBN/ZwzHOaKvqQj8smDlRGlQxX3HWlTwgiLN2A+OB5yX4ZRw==}
dependencies:
'@cosmjs/crypto': 0.29.5
'@cosmjs/encoding': 0.29.5
'@cosmjs/math': 0.29.5
'@cosmjs/utils': 0.29.5
dev: false
/@cosmjs/amino@0.30.1:
resolution: {integrity: sha512-yNHnzmvAlkETDYIpeCTdVqgvrdt1qgkOXwuRVi8s27UKI5hfqyE9fJ/fuunXE6ZZPnKkjIecDznmuUOMrMvw4w==}
dependencies:
@@ -788,18 +711,6 @@ packages:
sha.js: 2.4.11
dev: false
/@cosmjs/crypto@0.29.5:
resolution: {integrity: sha512-2bKkaLGictaNL0UipQCL6C1afaisv6k8Wr/GCLx9FqiyFkh9ZgRHDyetD64ZsjnWV/N/D44s/esI+k6oPREaiQ==}
dependencies:
'@cosmjs/encoding': 0.29.5
'@cosmjs/math': 0.29.5
'@cosmjs/utils': 0.29.5
'@noble/hashes': 1.3.1
bn.js: 5.2.1
elliptic: 6.5.4
libsodium-wrappers: 0.7.11
dev: false
/@cosmjs/crypto@0.30.1:
resolution: {integrity: sha512-rAljUlake3MSXs9xAm87mu34GfBLN0h/1uPPV6jEwClWjNkAMotzjC0ab9MARy5FFAvYHL3lWb57bhkbt2GtzQ==}
dependencies:
@@ -832,14 +743,6 @@ packages:
readonly-date: 1.0.0
dev: false
/@cosmjs/encoding@0.29.5:
resolution: {integrity: sha512-G4rGl/Jg4dMCw5u6PEZHZcoHnUBlukZODHbm/wcL4Uu91fkn5jVo5cXXZcvs4VCkArVGrEj/52eUgTZCmOBGWQ==}
dependencies:
base64-js: 1.5.1
bech32: 1.1.4
readonly-date: 1.0.0
dev: false
/@cosmjs/encoding@0.30.1:
resolution: {integrity: sha512-rXmrTbgqwihORwJ3xYhIgQFfMSrwLu1s43RIK9I8EBudPx3KmnmyAKzMOVsRDo9edLFNuZ9GIvysUCwQfq3WlQ==}
dependencies:
@@ -856,11 +759,12 @@ packages:
readonly-date: 1.0.0
dev: false
/@cosmjs/json-rpc@0.29.5:
resolution: {integrity: sha512-C78+X06l+r9xwdM1yFWIpGl03LhB9NdM1xvZpQHwgCOl0Ir/WV8pw48y3Ez2awAoUBRfTeejPe4KvrE6NoIi/w==}
/@cosmjs/encoding@0.31.1:
resolution: {integrity: sha512-IuxP6ewwX6vg9sUJ8ocJD92pkerI4lyG8J5ynAM3NaX3q+n+uMoPRSQXNeL9bnlrv01FF1kIm8if/f5F7ZPtkA==}
dependencies:
'@cosmjs/stream': 0.29.5
xstream: 11.14.0
base64-js: 1.5.1
bech32: 1.1.4
readonly-date: 1.0.0
dev: false
/@cosmjs/json-rpc@0.30.1:
@@ -897,12 +801,6 @@ packages:
bn.js: 5.2.1
dev: false
/@cosmjs/math@0.29.5:
resolution: {integrity: sha512-2GjKcv+A9f86MAWYLUkjhw1/WpRl2R1BTb3m9qPG7lzMA7ioYff9jY5SPCfafKdxM4TIQGxXQlYGewQL16O68Q==}
dependencies:
bn.js: 5.2.1
dev: false
/@cosmjs/math@0.30.1:
resolution: {integrity: sha512-yaoeI23pin9ZiPHIisa6qqLngfnBR/25tSaWpkTm8Cy10MX70UF5oN4+/t1heLaM6SSmRrhk3psRkV4+7mH51Q==}
dependencies:
@@ -915,16 +813,10 @@ packages:
bn.js: 5.2.1
dev: false
/@cosmjs/proto-signing@0.29.3:
resolution: {integrity: sha512-Ai3l9THjMOrLJ4Ebn1Dgptwg6W5ZIRJqtnJjijHhGwTVC1WT0WdYU3aMZ7+PwubcA/cA1rH4ZTK7jrfYbra63g==}
/@cosmjs/math@0.31.1:
resolution: {integrity: sha512-kiuHV6m6DSB8/4UV1qpFhlc4ul8SgLXTGRlYkYiIIP4l0YNeJ+OpPYaOlEgx4Unk2mW3/O2FWYj7Jc93+BWXng==}
dependencies:
'@cosmjs/amino': 0.29.3
'@cosmjs/crypto': 0.29.5
'@cosmjs/encoding': 0.29.5
'@cosmjs/math': 0.29.5
'@cosmjs/utils': 0.29.5
cosmjs-types: 0.5.2
long: 4.0.0
bn.js: 5.2.1
dev: false
/@cosmjs/proto-signing@0.30.1:
@@ -951,18 +843,6 @@ packages:
long: 4.0.0
dev: false
/@cosmjs/socket@0.29.5:
resolution: {integrity: sha512-5VYDupIWbIXq3ftPV1LkS5Ya/T7Ol/AzWVhNxZ79hPe/mBfv1bGau/LqIYOm2zxGlgm9hBHOTmWGqNYDwr9LNQ==}
dependencies:
'@cosmjs/stream': 0.29.5
isomorphic-ws: 4.0.1(ws@7.5.9)
ws: 7.5.9
xstream: 11.14.0
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: false
/@cosmjs/socket@0.30.1:
resolution: {integrity: sha512-r6MpDL+9N+qOS/D5VaxnPaMJ3flwQ36G+vPvYJsXArj93BjgyFB7BwWwXCQDzZ+23cfChPUfhbINOenr8N2Kow==}
dependencies:
@@ -987,27 +867,6 @@ packages:
- utf-8-validate
dev: false
/@cosmjs/stargate@0.29.3:
resolution: {integrity: sha512-455TgXStCi6E8KDjnhDAM8wt6aLSjobH4Dixvd7Up1DfCH6UB9NkC/G0fMJANNcNXMaM4wSX14niTXwD1d31BA==}
dependencies:
'@confio/ics23': 0.6.8
'@cosmjs/amino': 0.29.3
'@cosmjs/encoding': 0.29.5
'@cosmjs/math': 0.29.5
'@cosmjs/proto-signing': 0.29.3
'@cosmjs/stream': 0.29.5
'@cosmjs/tendermint-rpc': 0.29.5
'@cosmjs/utils': 0.29.5
cosmjs-types: 0.5.2
long: 4.0.0
protobufjs: 6.11.4
xstream: 11.14.0
transitivePeerDependencies:
- bufferutil
- debug
- utf-8-validate
dev: false
/@cosmjs/stargate@0.30.1:
resolution: {integrity: sha512-RdbYKZCGOH8gWebO7r6WvNnQMxHrNXInY/gPHPzMjbQF6UatA6fNM2G2tdgS5j5u7FTqlCI10stNXrknaNdzog==}
dependencies:
@@ -1050,12 +909,6 @@ packages:
- utf-8-validate
dev: false
/@cosmjs/stream@0.29.5:
resolution: {integrity: sha512-TToTDWyH1p05GBtF0Y8jFw2C+4783ueDCmDyxOMM6EU82IqpmIbfwcdMOCAm0JhnyMh+ocdebbFvnX/sGKzRAA==}
dependencies:
xstream: 11.14.0
dev: false
/@cosmjs/stream@0.30.1:
resolution: {integrity: sha512-Fg0pWz1zXQdoxQZpdHRMGvUH5RqS6tPv+j9Eh7Q953UjMlrwZVo0YFLC8OTf/HKVf10E4i0u6aM8D69Q6cNkgQ==}
dependencies:
@@ -1068,25 +921,6 @@ packages:
xstream: 11.14.0
dev: false
/@cosmjs/tendermint-rpc@0.29.5:
resolution: {integrity: sha512-ar80twieuAxsy0x2za/aO3kBr2DFPAXDmk2ikDbmkda+qqfXgl35l9CVAAjKRqd9d+cRvbQyb5M4wy6XQpEV6w==}
dependencies:
'@cosmjs/crypto': 0.29.5
'@cosmjs/encoding': 0.29.5
'@cosmjs/json-rpc': 0.29.5
'@cosmjs/math': 0.29.5
'@cosmjs/socket': 0.29.5
'@cosmjs/stream': 0.29.5
'@cosmjs/utils': 0.29.5
axios: 0.21.4
readonly-date: 1.0.0
xstream: 11.14.0
transitivePeerDependencies:
- bufferutil
- debug
- utf-8-validate
dev: false
/@cosmjs/tendermint-rpc@0.30.1:
resolution: {integrity: sha512-Z3nCwhXSbPZJ++v85zHObeUggrEHVfm1u18ZRwXxFE9ZMl5mXTybnwYhczuYOl7KRskgwlB+rID0WYACxj4wdQ==}
dependencies:
@@ -1129,10 +963,6 @@ packages:
resolution: {integrity: sha512-VG7QPDiMUzVPxRdJahDV8PXxVdnuAHiIuG56hldV4yPnOz/si/DLNd7VAUUA5923b6jS1Hhev0Hr6AhEkcxBMg==}
dev: false
/@cosmjs/utils@0.29.5:
resolution: {integrity: sha512-m7h+RXDUxOzEOGt4P+3OVPX7PuakZT3GBmaM/Y2u+abN3xZkziykD/NvedYFvvCCdQo714XcGl33bwifS9FZPQ==}
dev: false
/@cosmjs/utils@0.30.1:
resolution: {integrity: sha512-KvvX58MGMWh7xA+N+deCfunkA/ZNDvFLw4YbOmX3f/XBIkqrVY7qlotfy2aNb1kgp6h4B6Yc8YawJPDTfvWX7g==}
dev: false
@@ -1141,39 +971,29 @@ packages:
resolution: {integrity: sha512-nNcycZWUYLNJlrIXgpcgVRqdl6BXjF4YlXdxobQWpW9Tikk61bEGeAFhDYtC0PwHlokCNw0KxWiHGJL4nL7Q5A==}
dev: false
/@cosmjs/utils@0.31.1:
resolution: {integrity: sha512-n4Se1wu4GnKwztQHNFfJvUeWcpvx3o8cWhSbNs9JQShEuB3nv3R5lqFBtDCgHZF/emFQAP+ZjF8bTfCs9UBGhA==}
dev: false
/@cush/relative@1.0.0:
resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==}
dev: true
/@dydxprotocol/abacus@0.4.7:
resolution: {integrity: sha512-3c7Dx5H+KeXZYDpAOJs6fqxSNerKqNSD4tuMNn5F7RXAPWUOU8ADQHAFPnrP1PgTxPjfZBZQzLIziKpyXww4NQ==}
/@dydxprotocol/v4-abacus@0.4.28:
resolution: {integrity: sha512-RQGTXI7q4HAXDmlUpDhpJDLN8C0dFMgKHzFITK1Sz3KnLb3mkkpqEU1D8VIn/hB7ngt+equMsLFSkUwzXCzgdA==}
dev: false
/@dydxprotocol/dydxjs@0.3.0:
resolution: {integrity: sha512-ygNeBs0f3H7sJk1qLUjfNwaXgc5TmjD+qZf7BFDbi7+boHJI9xuOWrGpjfBo7OTUZxS6O5jZG323CgU5XqMSPw==}
/@dydxprotocol/v4-client-js@0.35.0:
resolution: {integrity: sha512-H+0/tOBVqyWx2JQ4jUFdJOlFof0NqN1u9vzKJ2h3Nv5KNteSPd59eiywoz+3J0jlmkREw0Jzg9CS0bLwzYVLvA==}
dependencies:
'@babel/runtime': 7.22.10
'@bufbuild/buf': 1.19.0-1
'@cosmjs/amino': 0.30.1
'@cosmjs/encoding': 0.31.1
'@cosmjs/math': 0.31.1
'@cosmjs/proto-signing': 0.30.1
'@cosmjs/stargate': 0.30.1
'@cosmjs/tendermint-rpc': 0.30.1
osmojs: 15.5.0
protobufjs: 6.11.4
transitivePeerDependencies:
- bufferutil
- debug
- utf-8-validate
dev: false
/@dydxprotocol/v4-client-js@0.32.0:
resolution: {integrity: sha512-KvKActMgWLcsRQ7RQhpi/F8xeQ7MWUp3G5+4IPNZ4wyRwAxDSbcrfYbTetI/IesHyelRPSeYxam9eYq3wXwZ1A==}
dependencies:
'@cosmjs/amino': 0.30.1
'@cosmjs/proto-signing': 0.30.1
'@cosmjs/stargate': 0.30.1
'@cosmjs/tendermint-rpc': 0.30.1
'@dydxprotocol/dydxjs': 0.3.0
'@cosmjs/utils': 0.31.1
'@dydxprotocol/v4-proto': 0.2.1
'@osmonauts/lcd': 0.6.0
'@scure/bip32': 1.3.1
'@scure/bip39': 1.2.1
@@ -1182,6 +1002,7 @@ packages:
bignumber.js: 9.1.1
ethereum-cryptography: 2.1.2
long: 4.0.0
protobufjs: 6.11.4
ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)
transitivePeerDependencies:
- bufferutil
@@ -1189,8 +1010,14 @@ packages:
- utf-8-validate
dev: false
/@dydxprotocol/v4-localization@0.0.25:
resolution: {integrity: sha512-Rp6VHA8z+nwgvTjjB3fvL8gY7bd4DYDHV+NPoL0MFuRm39vhFxGlBVAGDkXPkQTh6YU5BlZV2yXLkDeSfFqEBQ==}
/@dydxprotocol/v4-localization@0.1.5:
resolution: {integrity: sha512-fiSHWrG8E2HuXkCzWsqyekntlI13hBRACrP0vaYudeSulw+ScGeAqZ5xp9/cANF6PP+H3z1yciNCZOH3OwSDwA==}
dev: false
/@dydxprotocol/v4-proto@0.2.1:
resolution: {integrity: sha512-Q5b/g331DoyMjBpO2/jtrxUX3WF5UaIKZp/unK332xuefHNFnkMYtZ05p0V71iSdO35tBdz8yt0VYP2WtUsp+w==}
dependencies:
protobufjs: 6.11.4
dev: false
/@emotion/is-prop-valid@1.2.1:
@@ -2246,15 +2073,6 @@ packages:
fastq: 1.15.0
dev: true
/@osmonauts/lcd@0.10.0:
resolution: {integrity: sha512-PzmXk9x9MHyLn2fUztpAqWqvDmMiEJaQv/JcAoAOE8VdHrD9Hf/KWnE1RZtamuS2ngQRqvQPD0xotCGXW7eTxA==}
dependencies:
'@babel/runtime': 7.22.10
axios: 0.27.2
transitivePeerDependencies:
- debug
dev: false
/@osmonauts/lcd@0.6.0:
resolution: {integrity: sha512-vz9VavXrEfxZoXbSAfNfk90MLpn34XtBYPV3L9YilE+s56AhqYxUh83nne9J5somnTRfGnyR3oeV8C+lHkqiuA==}
dependencies:
@@ -7787,13 +7605,6 @@ packages:
path-type: 4.0.0
dev: true
/cosmjs-types@0.5.2:
resolution: {integrity: sha512-zxCtIJj8v3Di7s39uN4LNcN3HIE1z0B9Z0SPE8ZNQR0oSzsuSe1ACgxoFkvhkS7WBasCAFcglS11G2hyfd5tPg==}
dependencies:
long: 4.0.0
protobufjs: 6.11.4
dev: false
/cosmjs-types@0.7.2:
resolution: {integrity: sha512-vf2uLyktjr/XVAgEq0DjMxeAWh1yYREe7AMHDKd7EiHVqxBPCaBS+qEEQUkXbR9ndnckqr1sUG8BQhazh4X5lA==}
dependencies:
@@ -11641,23 +11452,6 @@ packages:
type-check: 0.4.0
dev: true
/osmojs@15.5.0:
resolution: {integrity: sha512-7wy3QEYu+R+c8imfLEPS1PliYA8uw0qdFYjc2PToHteYG4hzYt4Noa7X0lM9O59s7nxo9ozT1N9z7uwB/1qHkA==}
dependencies:
'@babel/runtime': 7.22.10
'@cosmjs/amino': 0.29.3
'@cosmjs/proto-signing': 0.29.3
'@cosmjs/stargate': 0.29.3
'@cosmjs/tendermint-rpc': 0.29.5
'@osmonauts/lcd': 0.10.0
long: 5.2.3
protobufjs: 6.11.4
transitivePeerDependencies:
- bufferutil
- debug
- utf-8-validate
dev: false
/p-defer@3.0.0:
resolution: {integrity: sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==}
engines: {node: '>=8'}
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

+6 -5
View File
@@ -10,11 +10,11 @@ import { AppRoute, DEFAULT_TRADE_ROUTE } from '@/constants/routes';
import { useBreakpoints, useInitializePage, useShouldShowFooter, useAnalytics } from '@/hooks';
import { DydxProvider } from '@/hooks/useDydxClient';
import { AccountsProvider } from '@/hooks/useAccounts';
import { DialogAreaProvider, useDialogArea } from './hooks/useDialogArea';
import { LocaleProvider } from './hooks/useLocaleSeparators';
import { NotificationsProvider } from './hooks/useNotifications';
import { LocalNotificationsProvider } from './hooks/useLocalNotifications';
import { SubaccountProvider } from './hooks/useSubaccount';
import { DialogAreaProvider, useDialogArea } from '@/hooks/useDialogArea';
import { LocaleProvider } from '@/hooks/useLocaleSeparators';
import { NotificationsProvider } from '@/hooks/useNotifications';
import { LocalNotificationsProvider } from '@/hooks/useLocalNotifications';
import { SubaccountProvider } from '@/hooks/useSubaccount';
import { SquidProvider } from '@/hooks/useSquid';
import { GuardedMobileRoute } from '@/components/GuardedMobileRoute';
@@ -100,6 +100,7 @@ const Content = () => {
};
const wrapProvider = (Component: React.ComponentType<any>, props?: any) => {
// eslint-disable-next-line react/display-name
return ({ children }: { children: React.ReactNode }) => (
<Component {...props}>{children}</Component>
);
+1 -1
View File
@@ -1,4 +1,4 @@
import Abacus, { kollections } from '@dydxprotocol/abacus';
import Abacus, { kollections } from '@dydxprotocol/v4-abacus';
import { OrderSide } from '@dydxprotocol/v4-client-js';
import { PositionSide, TradeTypes } from './trade';
import { STRING_KEYS } from './localization';
+4 -19
View File
@@ -1,18 +1,5 @@
/**
* OnboardingSteps
* 1. Choose between 3 options
* a. Ethereum EOA (current)
* b. Keplr or Other Cosmos (future)
* c. Social (future)
* 2. Key derivation
* a. If wallet has no dYdX Chain transactions and not on whitelist, sign twice (future)
* i. Success
* ii. Signatures don't match error (Wallet is non-deterministic)
* b. Success
* 3. Post Registration items (Only on first onboarding)
* a. Acknowledge Terms
* b. DepositFunds
*/
import type { DydxAddress, EvmAddress } from './wallets';
export enum OnboardingSteps {
ChooseWallet = 'ChooseWallet',
KeyDerivation = 'KeyDerivation',
@@ -49,14 +36,12 @@ export enum EvmDerivedAccountStatus {
Derived,
}
import type { DydxAddress, EvmAddress } from './wallets';
export type EvmDerivedAddresses = {
version?: string;
[EvmAddress: EvmAddress]: {
encryptedSignature?: string;
dydxAddress?: DydxAddress;
};
}
};
export const AMOUNT_RESERVED_FOR_GAS_USDC = 100_000;
export const AMOUNT_RESERVED_FOR_GAS_USDC = 100_000;
+2
View File
@@ -34,6 +34,8 @@ export const STRING_KEYS = {
...WARNINGS_STRING_KEYS,
};
export type StringKey = keyof typeof STRING_KEYS;
export type LocaleData = typeof EN_LOCALE_DATA;
export type StringGetterFunction = (a: {
-30
View File
@@ -1,36 +1,6 @@
import { Asset, PerpetualMarket } from '@/constants/abacus';
import { STRING_KEYS } from '@/constants/localization';
export interface Market {
market: string;
status: string;
baseAsset: string;
quoteAsset: string;
stepSize: string;
tickSize: string;
oraclePrice: string;
priceChange24H: string;
nextFundingRate: string;
nextFundingAt: string;
minOrderSize: string;
type: string;
initialMarginFraction: string;
maintenanceMarginFraction: string;
volume24H: string;
trades24H: string;
openInterest: string;
incrementalInitialMarginFraction: string;
incrementalPositionSize: string;
maxPositionSize: string;
baselinePositionSize: string;
assetResolution: string;
syntheticAssetId: string;
}
export type AllMarkets = {
[market: string]: Market;
};
export type MarketData = {
asset: Asset;
tickSizeDecimals: number;
+6 -6
View File
@@ -1,4 +1,4 @@
import { StatusResponse } from "@0xsquid/sdk";
import { StatusResponse } from '@0xsquid/sdk';
/** implemented in useNotificationTypes */
export enum NotificationType {
@@ -11,7 +11,7 @@ export enum NotificationComponentType {}
export type NotificationId = string | number;
export type NotificationTypeConfig<
_NotificationId extends NotificationId = string,
NotificationIdType extends NotificationId = string,
NotificationUpdateKey = any
> = {
type: NotificationType;
@@ -20,7 +20,7 @@ export type NotificationTypeConfig<
useTrigger: (_: {
trigger: (
/** Unique ID for the triggered notification */
id: _NotificationId,
id: NotificationIdType,
/** Display data for the triggered notification */
displayData: NotificationDisplayData,
@@ -43,7 +43,7 @@ export type NotificationTypeConfig<
}) => void;
/** Callback for notification action (Toast action button click, NotificationsMenu item click, or native push notification interaction) */
useNotificationAction?: () => (id: _NotificationId) => any;
useNotificationAction?: () => (id: NotificationIdType) => any;
};
export enum NotificationStatus {
@@ -65,10 +65,10 @@ export enum NotificationStatus {
/** Notification state. Serialized and cached into localStorage. */
export type Notification<
_NotificationId extends NotificationId = string,
NotificationIdType extends NotificationId = string,
NotificationUpdateKey = any
> = {
id: _NotificationId;
id: NotificationIdType;
type: NotificationType;
status: NotificationStatus;
timestamps: Partial<Record<NotificationStatus, number>>;
-2
View File
@@ -1,5 +1,3 @@
import { getSeparator } from '@/lib/numbers';
export const USD_DECIMALS = 2;
export const SMALL_USD_DECIMALS = 4;
+4
View File
@@ -5,6 +5,10 @@ export const tradeTooltips: TooltipStrings = {
title: stringGetter({ key: TOOLTIP_STRING_KEYS.ACCOUNT_LEVERAGE_TITLE }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.ACCOUNT_LEVERAGE_BODY }),
}),
'base-position-notional': ({ stringGetter }) => ({
title: stringGetter({ key: TOOLTIP_STRING_KEYS.BASE_POSITION_NOTIONAL_TITLE }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.BASE_POSITION_NOTIONAL_BODY }),
}),
'bracket-sl': ({ stringGetter }) => ({
title: stringGetter({ key: TOOLTIP_STRING_KEYS.BRACKET_ORDER_SL_TITLE }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.BRACKET_ORDER_SL_BODY }),
+2 -4
View File
@@ -1,4 +1,6 @@
import type { ExternalProvider } from '@ethersproject/providers';
import { USDC_DENOM, type onboarding, DYDX_DENOM } from '@dydxprotocol/v4-client-js';
import type { suggestChain } from 'graz';
import { STRING_KEYS } from '@/constants/localization';
@@ -313,10 +315,6 @@ export type WalletConnection = {
};
// dYdX Chain wallets
import { USDC_DENOM, type onboarding, DYDX_DENOM } from '@dydxprotocol/v4-client-js';
import type { suggestChain } from 'graz';
export const COSMOS_DERIVATION_PATH = "m/44'/118'/0'/0/0";
/**
+1 -1
View File
@@ -4,7 +4,7 @@ import { useMatch, useNavigate } from 'react-router-dom';
import { LocalStorageKey } from '@/constants/localStorage';
import { DEFAULT_MARKETID } from '@/constants/markets';
import { AppRoute, DEFAULT_TRADE_ROUTE } from '@/constants/routes';
import { AppRoute } from '@/constants/routes';
import { getSelectedNetwork } from '@/state/appSelectors';
import { closeDialogInTradeBox } from '@/state/dialogs';
+1 -1
View File
@@ -114,7 +114,7 @@ const useDydxClientContext = () => {
}): Promise<Candle[]> => {
try {
const { candles } =
(await compositeClient!.indexerClient.markets.getPerpetualMarketCandles(
(await compositeClient?.indexerClient.markets.getPerpetualMarketCandles(
marketId,
RESOLUTION_MAP[resolution],
fromIso,
+15 -2
View File
@@ -1,13 +1,15 @@
import { useCallback } from 'react';
import { useCallback, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { DialogTypes } from '@/constants/dialogs';
import { LocalStorageKey } from '@/constants/localStorage';
import { DEFAULT_APP_ENVIRONMENT, DydxNetwork } from '@/constants/networks';
import { CLIENT_NETWORK_CONFIGS, DEFAULT_APP_ENVIRONMENT, DydxNetwork } from '@/constants/networks';
import { useAccounts, useLocalStorage } from '@/hooks';
import { setSelectedNetwork } from '@/state/app';
import { getSelectedNetwork } from '@/state/appSelectors';
import { openDialog } from '@/state/dialogs';
export const useSelectedNetwork = (): {
switchNetwork: (network: DydxNetwork) => void;
@@ -22,6 +24,17 @@ export const useSelectedNetwork = (): {
defaultValue: DEFAULT_APP_ENVIRONMENT,
});
useEffect(() => {
if (
import.meta.env.MODE === 'production' &&
CLIENT_NETWORK_CONFIGS[selectedNetwork].dydxChainId === 'dydx-testnet-3'
) {
dispatch(
openDialog({ type: DialogTypes.ExchangeOffline, dialogProps: { preventClose: true } })
);
}
}, [selectedNetwork]);
const switchNetwork = useCallback(
(network: DydxNetwork) => {
disconnect();
+1 -1
View File
@@ -1,6 +1,6 @@
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { useDispatch } from 'react-redux';
import type { Nullable } from '@dydxprotocol/abacus';
import type { Nullable } from '@dydxprotocol/v4-abacus';
import Long from 'long';
import type { IndexedTx } from '@cosmjs/stargate';
import type { EncodeObject, Coin } from '@cosmjs/proto-signing';
+1 -1
View File
@@ -1,4 +1,4 @@
const LogoShortIcon: React.FC<{ id?: string }> = ({ id }) => (
const LogoShortIcon: React.FC<{ id?: string }> = ({ id }: { id?: string }) => (
<svg
width="135"
height="145"
+1 -2
View File
@@ -7,10 +7,9 @@ import { DialogTypes } from '@/constants/dialogs';
import { STRING_KEYS } from '@/constants/localization';
import { AppRoute } from '@/constants/routes';
import { useStringGetter } from '@/hooks';
import { LogoShortIcon } from '@/icons';
import { LogoShortIcon, BellIcon } from '@/icons';
import { Icon, IconName } from '@/components/Icon';
import { BellIcon } from '@/icons';
import { IconButton } from '@/components/IconButton';
import { NavigationMenu } from '@/components/NavigationMenu';
import { VerticalSeparator } from '@/components/Separator';
+15 -6
View File
@@ -15,12 +15,20 @@ type StyleProps = {
};
export const NotificationsToastArea = ({ className }: StyleProps) => {
const { notifications, getKey, getDisplayData, markUnseen, markSeen, isMenuOpen, onNotificationAction } = useNotifications();
const {
notifications,
getKey,
getDisplayData,
markUnseen,
markSeen,
isMenuOpen,
onNotificationAction,
} = useNotifications();
const { isMobile } = useBreakpoints();
return (
<$ToastArea swipeDirection={isMobile ? 'up' : 'right'} className={className}>
<StyledToastArea swipeDirection={isMobile ? 'up' : 'right'} className={className}>
{Object.values(notifications)
// Sort by time of first trigger
.sort(
@@ -53,19 +61,20 @@ export const NotificationsToastArea = ({ className }: StyleProps) => {
sensitivity={displayData.toastSensitivity}
setIsOpen={(isOpen, isClosedFromTimeout) => {
if (!isOpen)
// Toast timer expired without user interaction
if (isClosedFromTimeout) markUnseen(notification);
if (isClosedFromTimeout)
// Toast timer expired without user interaction
markUnseen(notification);
// Toast interacted with or dismissed
else markSeen(notification);
}}
lastUpdated={notification.timestamps[notification.status]}
/>
))}
</$ToastArea>
</StyledToastArea>
);
};
const $ToastArea = styled(ToastArea)`
const StyledToastArea = styled(ToastArea)`
position: absolute;
width: min(16rem, 100%);
inset: 0 0 0 auto;
+44 -24
View File
@@ -1,4 +1,4 @@
import Abacus, { Nullable } from '@dydxprotocol/abacus';
import Abacus, { Nullable } from '@dydxprotocol/v4-abacus';
import Long from 'long';
import {
@@ -15,14 +15,24 @@ import {
type QueryTypes,
type TransactionTypes,
} from '@/constants/abacus';
import { DialogTypes } from '@/constants/dialogs';
import { RootStore } from '@/state/_store';
import { openDialog } from '@/state/dialogs';
import { log } from '../telemetry';
class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
private compositeClient: CompositeClient | undefined;
private store: RootStore | undefined;
constructor() {
this.compositeClient = undefined;
this.store = undefined;
}
setStore(store: RootStore): void {
this.store = store;
}
async connectNetwork(
@@ -33,30 +43,41 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
faucetUrl: Nullable<string> | undefined,
callback: (p0: Nullable<string>) => void
): Promise<void> {
this.compositeClient = await CompositeClient.connect(
new Network(
chainId,
new IndexerConfig(indexerUrl, indexerSocketUrl),
new ValidatorConfig(validatorUrl, chainId, {
broadcastPollIntervalMs: 3_000,
broadcastTimeoutMs: 60_000,
})
)
);
try {
const compositeClient = await CompositeClient.connect(
new Network(
chainId,
new IndexerConfig(indexerUrl, indexerSocketUrl),
new ValidatorConfig(validatorUrl, chainId, {
broadcastPollIntervalMs: 3_000,
broadcastTimeoutMs: 60_000,
})
)
);
// Dispatch custom event to notify other parts of the app that the network has been connected
const customEvent = new CustomEvent('abacus:connectNetwork', {
detail: {
indexerUrl,
indexerSocketUrl,
validatorUrl,
chainId,
faucetUrl,
},
});
this.compositeClient = compositeClient;
globalThis.dispatchEvent(customEvent);
callback(JSON.stringify({ success: true }));
// Dispatch custom event to notify other parts of the app that the network has been connected
const customEvent = new CustomEvent('abacus:connectNetwork', {
detail: {
indexerUrl,
indexerSocketUrl,
validatorUrl,
chainId,
faucetUrl,
},
});
globalThis.dispatchEvent(customEvent);
callback(JSON.stringify({ success: true }));
} catch (error) {
this.store?.dispatch(
openDialog({ type: DialogTypes.ExchangeOffline, dialogProps: { preventClose: true } })
);
log('DydxChainTransactions/connectNetwork', error);
return;
}
}
parseToPrimitives<T>(x: T): T {
@@ -85,7 +106,6 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
throw new Error(`Unsupported data type: ${typeof x}`);
}
async transaction(
type: TransactionTypes,
paramsInJson: Abacus.Nullable<string>,
+4 -1
View File
@@ -46,6 +46,7 @@ class AbacusStateManager {
websocket: AbacusWebsocket;
stateNotifier: AbacusStateNotifier;
abacusFormatter: AbacusFormatter;
chainTransactionClient: AbacusChainTransaction;
constructor() {
this.store = undefined;
@@ -53,12 +54,13 @@ class AbacusStateManager {
this.stateNotifier = new AbacusStateNotifier();
this.websocket = new AbacusWebsocket();
this.abacusFormatter = new AbacusFormatter();
this.chainTransactionClient = new AbacusChainTransaction();
const ioImplementations = new IOImplementations(
// @ts-ignore
new AbacusRest(),
this.websocket,
new AbacusChainTransaction(),
this.chainTransactionClient,
null,
new AbacusThreading(),
new CoroutineTimer(),
@@ -155,6 +157,7 @@ class AbacusStateManager {
setStore = (store: RootStore) => {
this.store = store;
this.stateNotifier.setStore(store);
this.chainTransactionClient.setStore(store);
};
setAccount = (walletAddress: string) => {
+1 -1
View File
@@ -1,4 +1,4 @@
import type { Nullable, kollections } from '@dydxprotocol/abacus';
import type { Nullable, kollections } from '@dydxprotocol/v4-abacus';
import type { AbacusRestProtocol } from '@/constants/abacus';
+1 -1
View File
@@ -1,4 +1,4 @@
import { kollections } from '@dydxprotocol/abacus';
import { kollections } from '@dydxprotocol/v4-abacus';
import type {
AbacusApiState,
+1 -1
View File
@@ -48,7 +48,7 @@ export const isNumber = (value: any): value is number =>
/**
* @description Returns null if input is 0 or null, '99+' if input is greater than 99, otherwise original input number
*/
export const shorternNumberForDisplay = (num?: number) =>
export const shortenNumberForDisplay = (num?: number) =>
MustBigNumber(num).eq(0) ? null : MustBigNumber(num).gt(99) ? '99+' : num;
/**
+11 -3
View File
@@ -1,5 +1,7 @@
export const log = (location: string, error: Error, metadata?: any) => {
// console.warn(error);
if (import.meta.env.MODE !== 'production') {
console.warn('telemetry/log:', { location, error, metadata });
}
const customEvent = new CustomEvent('dydx:log', {
detail: {
@@ -16,7 +18,10 @@ export const log = (location: string, error: Error, metadata?: any) => {
globalThis.addEventListener('unhandledrejection', (event) => {
event.preventDefault();
log('window/onunhandledrejection', new Error(`Promise rejected and uncaught; reason: ${event.reason}`));
log(
'window/onunhandledrejection',
new Error(`Promise rejected and uncaught; reason: ${event.reason}`)
);
});
// Log rejected Promises that are caught late (handler attached at a later time)
@@ -25,7 +30,10 @@ globalThis.addEventListener(
(event) => {
event.preventDefault();
log('window/onrejectionhandled', new Error(`Promise rejected and caught late; reason: ${event.reason}`));
log(
'window/onrejectionhandled',
new Error(`Promise rejected and caught late; reason: ${event.reason}`)
);
},
false
);
+3 -3
View File
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { Nullable } from '@dydxprotocol/abacus';
import { Nullable } from '@dydxprotocol/v4-abacus';
import styled, { AnyStyledComponent } from 'styled-components';
import { shallowEqual, useSelector } from 'react-redux';
@@ -270,11 +270,11 @@ Styled.FeeTable = styled(Table)`
--table-cell-align: end;
font: var(--font-base-book);
tbody tr {
&[data-yours='true'] {
background-color: var(--color-layer-3);
td:first-child {
border-left: 0.125rem solid var(--color-accent);
}
+5 -5
View File
@@ -31,7 +31,7 @@ import {
import { getCurrentMarketAssetId, getCurrentMarketId } from '@/state/perpetualsSelectors';
import { isTruthy } from '@/lib/isTruthy';
import { shorternNumberForDisplay } from '@/lib/numbers';
import { shortenNumberForDisplay } from '@/lib/numbers';
import { PositionInfo } from '@/views/PositionInfo';
@@ -73,9 +73,9 @@ export const HorizontalPanel = ({ isOpen = true, setIsOpen }: ElementProps) => {
const showCurrentMarket = isTablet || view === PanelView.CurrentMarket;
const fillsTagNumber = shorternNumberForDisplay(showCurrentMarket ? numFills : numTotalFills);
const fillsTagNumber = shortenNumberForDisplay(showCurrentMarket ? numFills : numTotalFills);
const ordersTagNumber = shorternNumberForDisplay(
const ordersTagNumber = shortenNumberForDisplay(
showCurrentMarket ? numOpenOrders : numTotalOpenOrders
);
@@ -86,7 +86,7 @@ export const HorizontalPanel = ({ isOpen = true, setIsOpen }: ElementProps) => {
key: showCurrentMarket ? STRING_KEYS.POSITION : STRING_KEYS.POSITIONS,
}),
tag: showCurrentMarket ? null : shorternNumberForDisplay(numTotalPositions),
tag: showCurrentMarket ? null : shortenNumberForDisplay(numTotalPositions),
content: showCurrentMarket ? (
<PositionInfo showNarrowVariation={isTablet} />
@@ -190,7 +190,7 @@ export const HorizontalPanel = ({ isOpen = true, setIsOpen }: ElementProps) => {
// value: InfoSection.Payments,
// label: stringGetter({ key: STRING_KEYS.PAYMENTS }),
// tag: shorternNumberForDisplay(
// tag: shortenNumberForDisplay(
// showCurrentMarket ? numFundingPayments : numTotalFundingPayments
// ),
// content: (
+1 -2
View File
@@ -1,5 +1,6 @@
import { configureStore } from '@reduxjs/toolkit';
import abacusStateManager from '@/lib/abacus';
import appMiddleware from './appMiddleware';
import localizationMiddleware from './localizationMiddleware';
import routerMiddleware from './routerMiddleware';
@@ -16,8 +17,6 @@ import { localizationSlice } from './localization';
import { navigationSlice } from './navigation';
import { perpetualsSlice } from './perpetuals';
import abacusStateManager from '@/lib/abacus';
export const commandMenuSlices = [layoutSlice, localizationSlice];
export const store = configureStore({
-1
View File
@@ -1,5 +1,4 @@
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
import _ from 'lodash';
import type {
SubaccountFill,
+11 -8
View File
@@ -12,9 +12,8 @@ import {
import { OnboardingState } from '@/constants/account';
import type { RootState } from './_store';
import { getHydratedTradingData } from '@/lib/orders';
import type { RootState } from './_store';
import { getCurrentMarketId, getPerpetualMarkets } from './perpetualsSelectors';
import { getAssets } from './assetsSelectors';
@@ -106,11 +105,11 @@ export const getSubaccountOpenOrdersBySideAndPrice = createSelector(
[getSubaccountOpenOrders],
(openOrders = []) => {
const ordersBySide: Partial<Record<OrderSide, Record<number, SubaccountOrder>>> = {};
for (const order of openOrders) {
openOrders.forEach((order) => {
const side = ORDER_SIDES[order.side.name];
const byPrice = (ordersBySide[side] ??= {});
byPrice[order.price] = order;
}
});
return ordersBySide;
}
);
@@ -123,8 +122,10 @@ export const getOrderDetails = (orderId: string) =>
createSelector(
[getSubaccountOrders, getAssets, getPerpetualMarkets],
(orders, assets, perpetualMarkets) => {
const order = orders?.find((order) => order.id === orderId);
return order ? getHydratedTradingData({ data: order, assets, perpetualMarkets }) : undefined;
const matchingOrder = orders?.find((order) => order.id === orderId);
return matchingOrder
? getHydratedTradingData({ data: matchingOrder, assets, perpetualMarkets })
: undefined;
}
);
@@ -178,8 +179,10 @@ export const getFillDetails = (fillId: string) =>
createSelector(
[getSubaccountFills, getAssets, getPerpetualMarkets],
(fills, assets, perpetualMarkets) => {
const fill = fills?.find((fill) => fill.id === fillId);
return fill ? getHydratedTradingData({ data: fill, assets, perpetualMarkets }) : undefined;
const matchingFill = fills?.find((fill) => fill.id === fillId);
return matchingFill
? getHydratedTradingData({ data: matchingFill, assets, perpetualMarkets })
: undefined;
}
);
+2 -6
View File
@@ -47,9 +47,5 @@ export const appSlice = createSlice({
},
});
export const {
initializeLocalization,
initializeWebsocket,
setApiState,
setSelectedNetwork,
} = appSlice.actions;
export const { initializeLocalization, initializeWebsocket, setApiState, setSelectedNetwork } =
appSlice.actions;
+1 -1
View File
@@ -1,5 +1,5 @@
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
import type { kollections } from '@dydxprotocol/abacus';
import type { kollections } from '@dydxprotocol/v4-abacus';
import type { Configs, FeeDiscount, FeeTier, NetworkConfigs, Nullable } from '@/constants/abacus';
import { LocalStorageKey } from '@/constants/localStorage';
+1 -1
View File
@@ -2,4 +2,4 @@ import { type RootState } from './_store';
export const getActiveDialog = (state: RootState) => state.dialogs.activeDialog;
export const getActiveTradeBoxDialog = (state: RootState) => state.dialogs.activeTradeBoxDialog;
export const getActiveTradeBoxDialog = (state: RootState) => state.dialogs.activeTradeBoxDialog;
+1 -1
View File
@@ -40,7 +40,7 @@ export const getStringGetterForLocaleData = (localeData: LocaleData) => {
params?: { [key: string]: string | React.ReactNode };
}): string | Array<string | React.ReactNode> => {
// Fallback to english whenever a key doesn't exist for other languages
let formattedString: string = _.get(localeData, key) || _.get(EN_LOCALE_DATA, key) || '';
const formattedString: string = _.get(localeData, key) || _.get(EN_LOCALE_DATA, key) || '';
return formatString(formattedString, params);
};
+2 -3
View File
@@ -1,11 +1,10 @@
import { matchPath } from 'react-router-dom';
import { createSelector } from 'reselect';
import { Candle, TradingViewBar } from '@/constants/candles';
import { TRADE_ROUTE } from '@/constants/routes';
import { mapCandle } from '@/lib/tradingView/utils';
import type { RootState } from './_store';
import { mapCandle } from '@/lib/tradingView/utils';
/**
* @param state
+1 -1
View File
@@ -1,4 +1,4 @@
import styled, { css, type FlattenSimpleInterpolation } from 'styled-components';
import { css } from 'styled-components';
import breakpoints from './breakpoints';
+36 -32
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-2
View File
@@ -6,8 +6,6 @@ import {
type ThemeProps,
} from 'styled-components';
import breakpoints from './breakpoints';
export const layoutMixins: Record<
string,
FlattenSimpleInterpolation | FlattenInterpolation<ThemeProps<any>>
-1
View File
@@ -5,7 +5,6 @@ import {
type ThemeProps,
} from 'styled-components';
import breakpoints from './breakpoints';
import { layoutMixins } from './layoutMixins';
export const tableMixins: Record<
+2 -8
View File
@@ -1,22 +1,16 @@
/* Constants */
:root {
--fontFamily-base: "Circular", system-ui, -apple-system, Helvetica, Arial, sans-serif;
--fontFamily-monospace: "CircularMono", Courier, monospace, var(--fontFamily-base);
--fontFamily-base: "Satoshi", system-ui, -apple-system, Helvetica, Arial, sans-serif;
--fontFamily-monospace: Courier, monospace, var(--fontFamily-base);
--fontWeight-base-0: 450;
--fontWeight-base-1: 500;
--fontWeight-base-2: 700;
--fontWeight-monospace: 400;
--letter-spacing-base: -0.02em;
/* New Typography system */
/**
* @size 10px/11px
* @weight 400
*/
--fontSize-tiny: 0.625rem; /* 10px/11px */
--fontSize-mini: 0.75rem; /* 12px/13px */
--fontSize-small: 0.8438rem; /* 13.5px/14.5px */
+29 -39
View File
@@ -2,7 +2,7 @@ import { shallowEqual, useSelector } from 'react-redux';
import styled, { type AnyStyledComponent } from 'styled-components';
import { ButtonShape, ButtonSize, ButtonType } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { STRING_KEYS, type StringKey } from '@/constants/localization';
import { useBreakpoints, useStringGetter } from '@/hooks';
import { breakpoints } from '@/styles';
import { layoutMixins } from '@/styles/layoutMixins';
@@ -29,15 +29,13 @@ export const MarketDetails: React.FC = () => {
if (!configs) return null;
const {
basePositionNotional,
tickSize,
stepSize,
initialMarginFraction,
maintenanceMarginFraction,
minOrderSize,
maxPositionSize,
baselinePositionSize,
incrementalInitialMarginFraction,
incrementalPositionSize,
stepSizeDecimals,
tickSizeDecimals,
} = configs;
@@ -72,12 +70,28 @@ export const MarketDetails: React.FC = () => {
key: 'step-size',
label: stringGetter({ key: STRING_KEYS.STEP_SIZE }),
tooltip: 'step-size',
value: <Output useGrouping value={stepSize} type={OutputType.Asset} tag={symbol} />,
value: (
<Output
useGrouping
value={stepSize}
type={OutputType.Asset}
tag={symbol}
fractionDigits={stepSizeDecimals}
/>
),
},
{
key: 'min-order-size',
label: stringGetter({ key: STRING_KEYS.MINIMUM_ORDER_SIZE }),
value: <Output useGrouping value={minOrderSize} type={OutputType.Asset} tag={symbol} />,
value: (
<Output
useGrouping
value={minOrderSize}
type={OutputType.Asset}
tag={symbol}
fractionDigits={stepSizeDecimals}
/>
),
},
{
key: 'max-leverage',
@@ -100,40 +114,16 @@ export const MarketDetails: React.FC = () => {
),
},
{
key: 'initial-margin-fraction',
label: stringGetter({ key: STRING_KEYS.INITIAL_MARGIN_FRACTION }),
key: 'base-initial-margin-fraction',
label: stringGetter({ key: STRING_KEYS.BASE_INITIAL_MARGIN_FRACTION }),
tooltip: 'initial-margin-fraction',
value: <Output useGrouping value={initialMarginFraction} type={OutputType.SmallPercent} />,
},
{
key: 'incremental-initial-margin-fraction',
label: stringGetter({ key: STRING_KEYS.INCREMENTAL_INITIAL_MARGIN_FRACTION }),
value: (
<Output
useGrouping
value={incrementalInitialMarginFraction}
type={OutputType.SmallPercent}
/>
),
},
{
key: 'incremental-position-size',
label: stringGetter({ key: STRING_KEYS.INCREMENTAL_POSITION_SIZE }),
value: (
<Output useGrouping value={incrementalPositionSize} type={OutputType.Asset} tag={symbol} />
),
},
{
key: 'baseline-position-size',
label: stringGetter({ key: STRING_KEYS.BASELINE_POSITION_SIZE }),
value: (
<Output useGrouping value={baselinePositionSize} type={OutputType.Asset} tag={symbol} />
),
},
{
key: 'max-position-size',
label: stringGetter({ key: STRING_KEYS.MAXIMUM_POSITION_SIZE }),
value: <Output useGrouping value={maxPositionSize} type={OutputType.Asset} tag={symbol} />,
key: 'base-position-notional',
label: stringGetter({ key: STRING_KEYS.BASE_POSITION_NOTIONAL }),
tooltip: 'base-position-notional',
value: <Output useGrouping value={basePositionNotional} type={OutputType.Number} />,
},
];
@@ -150,10 +140,10 @@ export const MarketDetails: React.FC = () => {
<Styled.MarketDescription>
{primaryDescriptionKey && (
<p>{stringGetter({ key: STRING_KEYS[primaryDescriptionKey] })}</p>
<p>{stringGetter({ key: STRING_KEYS[primaryDescriptionKey as StringKey] })}</p>
)}
{secondaryDescriptionKey && (
<p>{stringGetter({ key: STRING_KEYS[secondaryDescriptionKey] })}</p>
<p>{stringGetter({ key: STRING_KEYS[secondaryDescriptionKey as StringKey] })}</p>
)}
</Styled.MarketDescription>
+23 -9
View File
@@ -1,12 +1,12 @@
import { useEffect } from 'react';
import styled, { AnyStyledComponent } from 'styled-components';
import { useDispatch, useSelector } from 'react-redux';
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import { AbacusApiStatus } from '@/constants/abacus';
import { DialogTypes } from '@/constants/dialogs';
import { STRING_KEYS } from '@/constants/localization';
import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks';
import { UNICODE } from '@/constants/unicode';
import { STRING_KEYS } from '@/constants/localization';
import { useApiState, useStringGetter } from '@/hooks';
import { layoutMixins } from '@/styles/layoutMixins';
@@ -17,6 +17,7 @@ import { NetworkSelectMenu } from '@/views/menus/NetworkSelectMenu';
import { closeDialog } from '@/state/dialogs';
import { getSelectedNetwork } from '@/state/appSelectors';
import { getActiveDialog } from '@/state/dialogsSelectors';
type ElementProps = {
preventClose?: boolean;
@@ -28,9 +29,18 @@ export const ExchangeOfflineDialog = ({ preventClose, setIsOpen }: ElementProps)
const stringGetter = useStringGetter();
const { status, statusErrorMessage } = useApiState();
const selectedNetwork = useSelector(getSelectedNetwork);
const activeDialog = useSelector(getActiveDialog, shallowEqual);
const showOfflineMessage =
import.meta.env.MODE === 'production' &&
CLIENT_NETWORK_CONFIGS[selectedNetwork].dydxChainId === 'dydx-testnet-3';
useEffect(() => {
if (status === AbacusApiStatus.NORMAL) {
if (
activeDialog?.type === DialogTypes.ExchangeOffline &&
status === AbacusApiStatus.NORMAL &&
!showOfflineMessage
) {
dispatch(closeDialog());
}
}, [status, selectedNetwork]);
@@ -43,11 +53,15 @@ export const ExchangeOfflineDialog = ({ preventClose, setIsOpen }: ElementProps)
title={stringGetter({ key: STRING_KEYS.UNAVAILABLE })}
>
<Styled.Content>
<p>{statusErrorMessage}</p>
{CLIENT_NETWORK_CONFIGS[selectedNetwork].dydxChainId === 'dydx-testnet-2' && (
<Styled.Link href="https://status.v4testnet.dydx.exchange">
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} {UNICODE.ARROW_RIGHT}
</Styled.Link>
{showOfflineMessage ? (
<>
<p>Testnet is currently offline. Please check back!</p>
<Styled.Link href="https://v4-teacher.vercel.app/testnets/schedule">
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} {UNICODE.ARROW_RIGHT}
</Styled.Link>
</>
) : (
<p>{statusErrorMessage}</p>
)}
{import.meta.env.MODE !== 'production' && <NetworkSelectMenu />}
</Styled.Content>
+1 -1
View File
@@ -13,7 +13,7 @@ import { ButtonShape, ButtonSize } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks';
import { NumberSign, QUANTUM_MULTIPLIER } from '@/constants/numbers';
import { DYDX_CHAIN_ASSET_COIN_DENOM, DYDX_CHAIN_INFO, DydxChainAsset } from '@/constants/wallets';
import { DYDX_CHAIN_ASSET_COIN_DENOM, DydxChainAsset } from '@/constants/wallets';
import {
useAccountBalance,
+1 -1
View File
@@ -3,12 +3,12 @@ import styled, { type AnyStyledComponent, css } from 'styled-components';
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import { OrderSide } from '@dydxprotocol/v4-client-js';
import type { ColumnSize } from '@react-types/table';
import { Nullable } from '@dydxprotocol/v4-abacus';
import { type Asset, type SubaccountFill } from '@/constants/abacus';
import { DialogTypes } from '@/constants/dialogs';
import { STRING_KEYS, StringGetterFunction } from '@/constants/localization';
import { Nullable } from '@dydxprotocol/abacus';
import { useBreakpoints, useStringGetter } from '@/hooks';
import { layoutMixins } from '@/styles/layoutMixins';
Binary file not shown.