Compare commits

..
10 Commits
Author SHA1 Message Date
zramsay 2212e607cf critical typo
Publish ApplicationRecord to Registry / cns_publish (push) Successful in 1m27s
2024-02-27 18:26:06 -05:00
zramsay a50ff841a0 use npm not pnpm for install reg-cli
Publish ApplicationRecord to Registry / cns_publish (push) Successful in 1m14s
2024-02-27 18:23:54 -05:00
zramsay d2020664d5 https://github.com/nodejs/corepack/issues/157
Publish ApplicationRecord to Registry / cns_publish (push) Successful in 1m14s
2024-02-27 18:20:06 -05:00
zramsay e2b2af6680 hrm
Publish ApplicationRecord to Registry / cns_publish (push) Failing after 36s
2024-02-27 18:14:18 -05:00
zramsay 3b4af29bd5 install corepack
Publish ApplicationRecord to Registry / cns_publish (push) Failing after 36s
2024-02-27 18:11:37 -05:00
zramsay 37ca83b29f ok
Publish ApplicationRecord to Registry / cns_publish (push) Failing after 36s
2024-02-27 17:55:34 -05:00
zramsay 8959364dee publish to registry 2024-02-27 17:50:12 -05:00
Jared Vu d24a02f7b9 Add BrowserRouter support (#258)
* Add BrowserRouter support

* Handle base route for hashrouter/browserrouter

* Add hashstring fallback

* parseHash -> parseLocationHash
2024-02-23 09:44:01 -08:00
mike-dydx caaea7e475 remove trailing slash (#325) 2024-02-23 08:49:10 -08:00
Bill 9d3a124485 Add support for OKX wallet (#312)
* Add support for OKX wallet

* strings
2024-02-22 13:54:58 -08:00
16 changed files with 249 additions and 21 deletions
+1
View File
@@ -3,6 +3,7 @@ VITE_BASE_URL=
VITE_ALCHEMY_API_KEY=
VITE_PK_ENCRYPTION_KEY=
VITE_ROUTER_TYPE=
VITE_V3_TOKEN_ADDRESS=
VITE_TOKEN_MIGRATION_URI=
+41
View File
@@ -0,0 +1,41 @@
name: Publish ApplicationRecord to Registry
on:
release:
types: [published]
push:
branches:
- registry
- test
env:
CERC_REGISTRY_USER_KEY: ${{ secrets.CICD_LACONIC_USER_KEY }}
CERC_REGISTRY_BOND_ID: ${{ secrets.CICD_LACONIC_BOND_ID }}
COREPACK_ENABLE_STRICT: 0
jobs:
cns_publish:
runs-on: ubuntu-latest
steps:
- name: "Clone project repository"
uses: actions/checkout@v3
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: "Install Yarn"
run: npm install -g yarn
- name: "Install Corepack"
run: npm install -g corepack
- name: "Enable Corepack"
run: corepack enable
- name: "Install registry CLI"
run: |
npm config set @cerc-io:registry https://git.vdb.to/api/packages/cerc-io/npm/
yarn global add @cerc-io/laconic-registry-cli
- name: "Install jq"
run: apt -y update && apt -y install jq
- name: "Publish Application Record"
run: scripts/publish-app-record.sh
- name: "Request Deployment"
run: scripts/request-app-deployment.sh
+20 -6
View File
@@ -66,10 +66,12 @@ This will automatically open your default browser at `http://localhost:61000`.
Add or modify the relevant endpoints, links and options in `/public/configs/env.json`.
You'll need to provide a Wallet Connect project id to enable onboarding and wallet connection:
- Create a project on https://cloud.walletconnect.com/app
- Copy over the project ID into this [field](https://github.com/dydxprotocol/v4-web/blob/67ecbd75b43e0c264b7b4d2d9b3d969830b0621c/public/configs/env.json#L822C33-L822C46)
## Part 4: Set Enviornment variables
Set environment variables via `.env`.
- `VITE_BASE_URL` (required): The base URL of the deployment (e.g., `https://www.example.com`).
@@ -96,10 +98,12 @@ Select "Import Git Repository" from your dashboard, and provide the URL of this
### Step 2: Configure your project
For the "Build & Development Settings", we recommend the following:
- Framework Preset: `Vite`
- Build Command (override): `pnpm run build`
By default, the dev server runs in development mode and the build command runs in production mode. To override the default mode, you can pass in the `--mode` option flag. For example, if you want to build your app for testnet:
```
pnpm run build --mode testnet
```
@@ -114,6 +118,14 @@ For more details, check out Vercel's [official documentation](https://vercel.com
## Deploying to IPFS
### Must Enable HashRouting
Add the following to `.env` file
```
VITE_ROUTER_TYPE=hash
```
### web3.storage: deploy to IPFS via web3.storage using the provided script
Export the API token as an environment variable (replace `your_token` with the generated token), and run the script to build and deploy to IPFS:
@@ -150,12 +162,14 @@ Replace `your_cid` with the actual CID.
We recommend that you add your website to Cloudflare for additional security settings.
To block OFAC Sanctioned countries:
1. Navigate Websites > Domain > Security > WAF
2. Create Rule with the following settings:
* If incoming requests match
`(ip.geoip.country eq "CU") or (ip.geoip.country eq "IR") or (ip.geoip.country eq "KP") or (ip.geoip.country eq "SY") or (ip.geoip.country eq "MM") or (ip.geoip.subdivision_1_iso_code eq "UA-09") or (ip.geoip.subdivision_1_iso_code eq "UA-14") or (ip.geoip.subdivision_1_iso_code eq "UA-43")`
* This rule will bring up a Cloudflare page when a restricted geography tries to access your site. You will have the option to display:
1. Custom Text
- (e.g. `Because you appear to be a resident of, or trading from, a jurisdiction that violates our terms of use, or have engaged in activity that violates our terms of use, you have been blocked. You may withdraw your funds from the protocol at any time.`)
2. Default Cloudflare WAF block page
- If incoming requests match
`(ip.geoip.country eq "CU") or (ip.geoip.country eq "IR") or (ip.geoip.country eq "KP") or (ip.geoip.country eq "SY") or (ip.geoip.country eq "MM") or (ip.geoip.subdivision_1_iso_code eq "UA-09") or (ip.geoip.subdivision_1_iso_code eq "UA-14") or (ip.geoip.subdivision_1_iso_code eq "UA-43")`
- This rule will bring up a Cloudflare page when a restricted geography tries to access your site. You will have the option to display:
1. Custom Text
- (e.g. `Because you appear to be a resident of, or trading from, a jurisdiction that violates our terms of use, or have engaged in activity that violates our terms of use, you have been blocked. You may withdraw your funds from the protocol at any time.`)
2. Default Cloudflare WAF block page
+2 -1
View File
@@ -1,5 +1,6 @@
{
"name": "dydx-chain-web",
"name": "@lx-mars/dydx-chain-web",
"repository": "https://git.vdb.to/LaconicNetwork/dydx-v4-web",
"private": true,
"version": "1.0.0",
"type": "module",
+2 -2
View File
@@ -72,7 +72,7 @@
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"launchIncentive": "https://cloud.chaoslabs.co/"
"launchIncentive": "https://cloud.chaoslabs.co"
},
"dydx-testnet-4": {
"tos": "https://dydx.exchange/v4-terms",
@@ -94,7 +94,7 @@
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"launchIncentive": "https://cloud.chaoslabs.co/"
"launchIncentive": "https://cloud.chaoslabs.co"
},
"[mainnet chain id]": {
"tos": "[HTTP link to TOS]",
+70
View File
@@ -0,0 +1,70 @@
#!/bin/bash
set -e
RECORD_FILE=tmp.rf.$$
CONFIG_FILE=`mktemp`
CERC_APP_TYPE=${CERC_APP_TYPE:-"webapp"}
CERC_REPO_REF=${CERC_REPO_REF:-${GITHUB_SHA:-`git log -1 --format="%H"`}}
CERC_IS_LATEST_RELEASE=${CERC_IS_LATEST_RELEASE:-"true"}
rcd_name=$(jq -r '.name' package.json | sed 's/null//')
rcd_desc=$(jq -r '.description' package.json | sed 's/null//')
rcd_repository=$(jq -r '.repository' package.json | sed 's/null//')
rcd_homepage=$(jq -r '.homepage' package.json | sed 's/null//')
rcd_license=$(jq -r '.license' package.json | sed 's/null//')
rcd_author=$(jq -r '.author' package.json | sed 's/null//')
rcd_app_version=$(jq -r '.version' package.json | sed 's/null//')
cat <<EOF > "$CONFIG_FILE"
services:
cns:
restEndpoint: '${CERC_REGISTRY_REST_ENDPOINT:-http://console.laconic.com:1317}'
gqlEndpoint: '${CERC_REGISTRY_GQL_ENDPOINT:-http://console.laconic.com:9473/api}'
chainId: ${CERC_REGISTRY_CHAIN_ID:-laconic_9000-1}
gas: 1750000
fees: 20000aphoton
EOF
next_ver=$(laconic -c $CONFIG_FILE cns record list --type ApplicationRecord --all --name "$rcd_name" 2>/dev/null | jq -r -s ".[] | sort_by(.createTime) | reverse | [ .[] | select(.bondId == \"$CERC_REGISTRY_BOND_ID\") ] | .[0].attributes.version" | awk -F. -v OFS=. '{$NF += 1 ; print}')
if [ -z "$next_ver" ] || [ "1" == "$next_ver" ]; then
next_ver=0.0.1
fi
cat <<EOF | sed '/.*: ""$/d' > "$RECORD_FILE"
record:
type: ApplicationRecord
version: ${next_ver}
name: "$rcd_name"
description: "$rcd_desc"
homepage: "$rcd_homepage"
license: "$rcd_license"
author: "$rcd_author"
repository:
- "$rcd_repository"
repository_ref: "$CERC_REPO_REF"
app_version: "$rcd_app_version"
app_type: "$CERC_APP_TYPE"
EOF
cat $RECORD_FILE
RECORD_ID=$(laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} | jq -r '.id')
echo $RECORD_ID
if [ -z "$CERC_REGISTRY_APP_CRN" ]; then
authority=$(echo "$rcd_name" | cut -d'/' -f1 | sed 's/@//')
app=$(echo "$rcd_name" | cut -d'/' -f2-)
CERC_REGISTRY_APP_CRN="crn://$authority/applications/$app"
fi
laconic -c $CONFIG_FILE cns name set --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} "$CERC_REGISTRY_APP_CRN@${rcd_app_version}" "$RECORD_ID"
laconic -c $CONFIG_FILE cns name set --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} "$CERC_REGISTRY_APP_CRN@${CERC_REPO_REF}" "$RECORD_ID"
if [ "true" == "$CERC_IS_LATEST_RELEASE" ]; then
laconic -c $CONFIG_FILE cns name set --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} "$CERC_REGISTRY_APP_CRN" "$RECORD_ID"
fi
rm -f $RECORD_FILE $CONFIG_FILE
+57
View File
@@ -0,0 +1,57 @@
#!/bin/bash
set -e
RECORD_FILE=tmp.rf.$$
CONFIG_FILE=`mktemp`
rcd_name=$(jq -r '.name' package.json | sed 's/null//' | sed 's/^@//')
rcd_app_version=$(jq -r '.version' package.json | sed 's/null//')
cat <<EOF > "$CONFIG_FILE"
services:
cns:
restEndpoint: '${CERC_REGISTRY_REST_ENDPOINT:-http://console.laconic.com:1317}'
gqlEndpoint: '${CERC_REGISTRY_GQL_ENDPOINT:-http://console.laconic.com:9473/api}'
chainId: ${CERC_REGISTRY_CHAIN_ID:-laconic_9000-1}
gas: 1550000
fees: 20000aphoton
EOF
if [ -z "$CERC_REGISTRY_APP_CRN" ]; then
authority=$(echo "$rcd_name" | cut -d'/' -f1 | sed 's/@//')
app=$(echo "$rcd_name" | cut -d'/' -f2-)
CERC_REGISTRY_APP_CRN="crn://$authority/applications/$app"
fi
APP_RECORD=$(laconic -c $CONFIG_FILE cns name resolve "$CERC_REGISTRY_APP_CRN" | jq '.[0]')
if [ -z "$APP_RECORD" ] || [ "null" == "$APP_RECORD" ]; then
echo "No record found for $CERC_REGISTRY_APP_CRN."
exit 1
fi
cat <<EOF | sed '/.*: ""$/d' > "$RECORD_FILE"
record:
type: ApplicationDeploymentRequest
version: 1.0.0
name: "$rcd_name@$rcd_app_version"
application: "$CERC_REGISTRY_APP_CRN@$rcd_app_version"
dns: "$CERC_REGISTRY_DEPLOYMENT_SHORT_HOSTNAME"
deployment: "$CERC_REGISTRY_DEPLOYMENT_CRN"
config:
env:
CERC_WEBAPP_DEBUG: "$rcd_app_version"
CERC_MAX_GENERATE_TIME: 180
CERC_NEXT_VERSION: 13.4.2
meta:
note: "Added by CI @ `date`"
repository: "`git remote get-url origin`"
repository_ref: "${GITHUB_SHA:-`git log -1 --format="%H"`}"
EOF
cat $RECORD_FILE
RECORD_ID=$(laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} | jq -r '.id')
echo $RECORD_ID
rm -f $RECORD_FILE $CONFIG_FILE
+16 -5
View File
@@ -1,5 +1,5 @@
import { lazy, Suspense } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import { lazy, Suspense, useMemo } from 'react';
import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
import styled, { AnyStyledComponent, css } from 'styled-components';
import { WagmiConfig } from 'wagmi';
import { QueryClient, QueryClientProvider } from 'react-query';
@@ -26,6 +26,7 @@ import { RestrictionProvider } from '@/hooks/useRestrictions';
import { SubaccountProvider } from '@/hooks/useSubaccount';
import { GuardedMobileRoute } from '@/components/GuardedMobileRoute';
import { LoadingSpace } from '@/components/Loading/LoadingSpinner';
import { HeaderDesktop } from '@/layout/Header/HeaderDesktop';
import { FooterDesktop } from '@/layout/Footer/FooterDesktop';
@@ -34,12 +35,12 @@ import { NotificationsToastArea } from '@/layout/NotificationsToastArea';
import { DialogManager } from '@/layout/DialogManager';
import { GlobalCommandDialog } from '@/views/dialogs/GlobalCommandDialog';
import { parseLocationHash } from '@/lib/urlUtils';
import { config } from '@/lib/wagmi';
import { breakpoints } from '@/styles';
import { GlobalStyle } from '@/styles/globalStyle';
import { layoutMixins } from '@/styles/layoutMixins';
import { LoadingSpace } from './components/Loading/LoadingSpinner';
import '@/styles/constants.css';
import '@/styles/fonts.css';
@@ -68,6 +69,14 @@ const Content = () => {
const isShowingHeader = isNotTablet;
const isShowingFooter = useShouldShowFooter();
const { chainTokenLabel } = useTokenConfigs();
const location = useLocation();
const pathFromHash = useMemo(() => {
if (location.hash === '') {
return '';
}
return parseLocationHash(location.hash);
}, [location.hash]);
return (
<>
@@ -102,8 +111,10 @@ const Content = () => {
<Route path={AppRoute.Terms} element={<TermsOfUsePage />} />
<Route path={AppRoute.Privacy} element={<PrivacyPolicyPage />} />
<Route path="*" element={<Navigate to={DEFAULT_TRADE_ROUTE} replace />} />
<Route
path="*"
element={<Navigate to={pathFromHash || DEFAULT_TRADE_ROUTE} replace />}
/>
</Routes>
</Suspense>
</Styled.Main>
+1
View File
@@ -41,6 +41,7 @@ export enum MobileSettingsRoute {
Network = 'network',
}
export const BASE_ROUTE = import.meta.env.VITE_ROUTER_TYPE === 'hash' ? '/#' : '';
export const TRADE_ROUTE = `${AppRoute.Trade}/:market`;
export const PORTFOLIO_ROUTE = `${AppRoute.Portfolio}/:subroute`;
export const HISTORY_ROUTE = `${AppRoute.Portfolio}/${PortfolioRoute.History}/:subroute`;
+14
View File
@@ -0,0 +1,14 @@
import { describe, expect, it } from 'vitest';
import { parseLocationHash } from '@/lib/urlUtils';
describe('parseLocationHash', () => {
it('returns the path separated from hash', () => {
const hash = '#/markets';
expect(parseLocationHash(hash)).toEqual('/markets');
});
it('returns the path and query string separated from hash', () => {
const hash = '#/markets?displayinitializingmarkets=true';
expect(parseLocationHash(hash)).toEqual('/markets?displayinitializingmarkets=true');
});
});
+13
View File
@@ -0,0 +1,13 @@
/**
* @param hash location.hash
* @returns path and query string if hash parameter is not empty
*/
export const parseLocationHash = (hash: string) => {
if (!hash || hash.length === 0) return '';
// Remove '#' and split by '?'
const [path, queryString] = hash.substring(1).split('?');
// Reconstruct path and query string
return `${path}${queryString ? `?${queryString}` : ''}`;
};
+4 -2
View File
@@ -1,7 +1,7 @@
import './polyfills';
import { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
import { HashRouter } from 'react-router-dom';
import { BrowserRouter, HashRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { store } from '@/state/_store';
@@ -12,11 +12,13 @@ import './index.css';
import App from './App';
const Router = import.meta.env.VITE_ROUTER_TYPE === 'hash' ? HashRouter : BrowserRouter;
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<ErrorBoundary>
<StrictMode>
<Provider store={store}>
<HashRouter children={<App />} />
<Router children={<App />} />
</Provider>
</StrictMode>
</ErrorBoundary>
@@ -2,7 +2,7 @@ import { useState } from 'react';
import styled, { AnyStyledComponent } from 'styled-components';
import { ButtonAction } from '@/constants/buttons';
import { AppRoute } from '@/constants/routes';
import { AppRoute, BASE_ROUTE } from '@/constants/routes';
import { STRING_KEYS } from '@/constants/localization';
import { useStringGetter } from '@/hooks';
import breakpoints from '@/styles/breakpoints';
@@ -40,7 +40,7 @@ export const NewMarketAgreementDialog = ({ acceptTerms, setIsOpen }: ElementProp
</Styled.Link>
),
TERMS_OF_USE: (
<Styled.Link href={`/#${AppRoute.Terms}`}>
<Styled.Link href={`${BASE_ROUTE}${AppRoute.Terms}`}>
{stringGetter({ key: STRING_KEYS.TERMS_OF_USE })}
</Styled.Link>
),
@@ -2,7 +2,7 @@ import styled, { type AnyStyledComponent } from 'styled-components';
import { useAccounts, useStringGetter } from '@/hooks';
import { AppRoute } from '@/constants/routes';
import { AppRoute, BASE_ROUTE } from '@/constants/routes';
import { STRING_KEYS } from '@/constants/localization';
import { ButtonAction } from '@/constants/buttons';
@@ -34,12 +34,12 @@ export const AcknowledgeTerms = ({ onClose, onContinue }: ElementProps) => {
key: STRING_KEYS.TOS_TITLE,
params: {
TERMS_LINK: (
<Styled.Link href={`/#${AppRoute.Terms}`}>
<Styled.Link href={`${BASE_ROUTE}${AppRoute.Terms}`}>
{stringGetter({ key: STRING_KEYS.TERMS_OF_USE })}
</Styled.Link>
),
PRIVACY_POLICY_LINK: (
<Styled.Link href={`/#${AppRoute.Privacy}`}>
<Styled.Link href={`${BASE_ROUTE}${AppRoute.Privacy}`}>
{stringGetter({ key: STRING_KEYS.PRIVACY_POLICY })}
</Styled.Link>
),
+3
View File
@@ -0,0 +1,3 @@
{
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}