diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..2e98b3f
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,54 @@
+# LOCAL
+VITE_APP_LOCAL_CAPTCHA_SITE_KEY=''
+VITE_APP_LOCAL_FAUCET_ADDRESS=''
+VITE_APP_LOCAL_BRIDGE_URL=''
+VITE_APP_LOCAL_GRAPHQL_URL=''
+VITE_APP_LOCAL_GRAPHQL_WS=''
+VITE_APP_LOCAL_RPC=''
+VITE_APP_LOCAL_API=''
+VITE_APP_LOCAL_EXPLORER_URL=''
+VITE_APP_LOCAL_STAKING_URL=''
+VITE_APP_LOCAL_CHAIN_NAME=''
+VITE_APP_LOCAL_CHAIN_ID=''
+
+# PRIVATE
+VITE_APP_PRIVATE_CAPTCHA_SITE_KEY=''
+VITE_APP_PRIVATE_FAUCET_ADDRESS=''
+VITE_APP_PRIVATE_BRIDGE_URL=''
+VITE_APP_PRIVATE_GRAPHQL_URL=''
+VITE_APP_PRIVATE_GRAPHQL_WS=''
+VITE_APP_PRIVATE_RPC=''
+VITE_APP_PRIVATE_API=''
+VITE_APP_PRIVATE_EXPLORER_URL=''
+VITE_APP_PRIVATE_STAKING_URL=''
+VITE_APP_PRIVATE_CHAIN_NAME=''
+VITE_APP_PRIVATE_CHAIN_ID=''
+
+# PUBLIC
+VITE_APP_PUBLIC_CAPTCHA_SITE_KEY=''
+VITE_APP_PUBLIC_FAUCET_ADDRESS=''
+VITE_APP_PUBLIC_BRIDGE_URL=''
+VITE_APP_PUBLIC_GRAPHQL_UR=''
+VITE_APP_PUBLIC_GRAPHQL_WS=''
+VITE_APP_PUBLIC_RPC=''
+VITE_APP_PUBLIC_API=''
+VITE_APP_PUBLIC_EXPLORER_URL=''
+VITE_APP_PUBLIC_STAKING_URL=''
+VITE_APP_PUBLIC_CHAIN_NAME=''
+VITE_APP_PUBLIC_CHAIN_ID=''
+
+# MAINNET
+VITE_APP_MAINNET_BRIDGE_URL=''
+VITE_APP_MAINNET_GRAPHQL_URL=''
+VITE_APP_MAINNET_GRAPHQL_WS=''
+VITE_APP_MAINNET_RPC=''
+VITE_APP_MAINNET_API=''
+VITE_APP_MAINNET_EXPLORER_URL=''
+VITE_APP_MAINNET_STAKING_URL=''
+VITE_APP_MAINNET_CHAIN_NAME=''
+VITE_APP_MAINNET_CHAIN_ID=''
+
+# GENERAL SETTINGS
+VITE_NODE_ENV='' #Production or empty
+VITE_APP_DEFAULT_NETWORK='' # LOCAL | PRIVATE | PUBLIC | MAINNET
+VITE_APP_GAS_PRICE=5000000000000
diff --git a/codegen.yaml b/codegen.yaml
index 663c3fa..8b441b6 100644
--- a/codegen.yaml
+++ b/codegen.yaml
@@ -11,10 +11,6 @@ generates:
- 'typescript'
- 'typescript-operations'
- 'typescript-react-apollo' # To generate custom hooks per query
- ./src/graphql/desmos_profile.ts:
- schema: https://gql.mainnet.desmos.network/v1/graphql
- documents:
- - 'src/graphql/desmos_profile_graphql.ts'
plugins:
- 'typescript'
- 'typescript-operations'
diff --git a/index.html b/index.html
index 71e197b..6c4f905 100644
--- a/index.html
+++ b/index.html
@@ -4,7 +4,8 @@
-
CUDOS Dashboard
+ CUDOS Dashboard | Stake your CUDOS & vote on proposals
+
diff --git a/package.json b/package.json
index 8a20c43..627948d 100644
--- a/package.json
+++ b/package.json
@@ -10,8 +10,8 @@
},
"dependencies": {
"@apollo/client": "^3.5.10",
- "@cosmostation/cosmos-client": "^0.0.1",
- "@cosmostation/extension-client": "0.1.7",
+ "@cosmostation/cosmos-client": "^0.0.4",
+ "@cosmostation/extension-client": "0.1.11",
"@emotion/react": "^11.8.2",
"@emotion/styled": "^11.8.1",
"@fontsource/poppins": "^4.5.5",
@@ -25,8 +25,10 @@
"copy-to-clipboard": "^3.3.1",
"cosmjs-types": "^0.4.1",
"cudosjs": "^1.1.1",
+ "detect-browser": "^5.3.0",
"dompurify": "^2.3.8",
"graphql": "^16.3.0",
+ "graphql-tag": "^2.0.0",
"graphql-ws": "^5.6.4",
"jdenticon": "^3.1.1",
"lodash": "^4.17.21",
@@ -37,31 +39,35 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-google-recaptcha": "^2.1.0",
+ "react-markdown": "^8.0.3",
"react-redux": "^7.2.6",
+ "react-responsive": "^9.0.0",
"react-router-dom": "^6.2.2",
"redux": "^4.1.2",
"redux-persist": "^6.0.0",
+ "remark-gfm": "^3.0.1",
"uint8-to-base64": "^0.2.0",
"vite": "^2.9.8"
},
"devDependencies": {
+ "@babel/core": "^7.0.0",
"@graphql-codegen/cli": "^2.6.2",
- "@graphql-codegen/typescript": "^2.4.8",
- "@graphql-codegen/typescript-operations": "^2.3.5",
- "@graphql-codegen/typescript-react-apollo": "^3.2.11",
+ "@graphql-codegen/typescript": "^2.8.1",
+ "@graphql-codegen/typescript-operations": "^2.5.6",
+ "@graphql-codegen/typescript-react-apollo": "^3.3.6",
"@honkhonk/vite-plugin-svgr": "^1.1.0",
- "@rollup/plugin-alias": "^3.1.9",
+ "@rollup/plugin-alias": "^4.0.2",
"@types/big.js": "^6.1.3",
"@types/dompurify": "^2.3.3",
"@types/lodash": "^4.14.182",
"@types/long": "^4.0.2",
- "@types/node": "^17.0.23",
+ "@types/node": "^18.11.9",
"@types/numeral": "^2.0.2",
"@types/ramda": "^0.28.7",
"@types/react": "^17.0.33",
"@types/react-dom": "^17.0.10",
- "@typescript-eslint/eslint-plugin": "^5.17.0",
- "@typescript-eslint/parser": "^5.17.0",
+ "@typescript-eslint/eslint-plugin": "^4.0.1",
+ "@typescript-eslint/parser": "^4.0.0",
"@vitejs/plugin-react": "^1.0.7",
"eslint": "^7.32.0",
"eslint-config-airbnb": "^19.0.2",
@@ -72,6 +78,7 @@
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-jest": "^25.3.0",
"eslint-plugin-jsx-a11y": "^6.5.1",
+ "eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-react": "^7.27.1",
diff --git a/src/App.tsx b/src/App.tsx
index 1fafdfc..43bad6a 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,24 +1,16 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
-import { useCallback, useEffect } from 'react'
+import { useCallback, useEffect, useState } from 'react'
import { ThemeProvider } from '@mui/material/styles'
import { useDispatch, useSelector } from 'react-redux'
-import { CssBaseline } from '@mui/material'
-import { ApolloProvider } from '@apollo/client'
+import { Box, CssBaseline } from '@mui/material'
+import { ApolloClient, ApolloProvider, NormalizedCacheObject } from '@apollo/client'
import { Routes, Route, useLocation, Navigate } from 'react-router-dom'
-import { fetchRedelegations } from 'api/getAccountRedelegations'
-import { fetchUndedelegations } from 'api/getAccountUndelegations'
-import BigNumber from 'bignumber.js'
import { updateUser } from 'store/profile'
import { updateUserTransactions } from 'store/userTransactions'
-import { fetchRewards } from 'api/getRewards'
import NotificationPopup from 'components/NotificationPopup'
-import { fetchDelegations } from 'api/getAccountDelegations'
import CosmosNetworkConfig from 'ledgers/CosmosNetworkConfig'
-import { connectKeplrLedger } from 'ledgers/KeplrLedger'
-import { connectCosmostationLedger } from 'ledgers/CosmoStationLedger'
import { switchLedgerType } from 'ledgers/utils'
-import { getUnbondingBalance } from 'api/getUnbondingBalance'
-import { getStakedBalance, getWalletBalance } from './utils/projectUtils'
+import { connectUser } from './utils/projectUtils'
import { useApollo } from './graphql/client'
import Layout from './components/Layout'
import RequireLedger from './components/RequireLedger/RequireLedger'
@@ -33,19 +25,31 @@ import theme from './theme'
import { RootState } from './store'
import '@fontsource/poppins'
+import { ApolloLinks, defaultApolloLinks } from 'graphql/helpers'
+import { CHAIN_DETAILS } from 'utils/constants'
+import NetworkChangingLoading from 'components/NetworkChangeLoading'
+import { networkLoadingStyles } from 'components/NetworkChangeLoading/styles'
const App = () => {
const location = useLocation()
-
const themeColor = useSelector((state: RootState) => state.settings.theme)
- const apolloClient = useApollo(null)
- const { lastLoggedAddress } = useSelector((state: RootState) => state.profile)
+ const newApolloClient = useApollo(null)
+ const [currentApolloClient, setCurrentApolloClient] = useState>(
+ newApolloClient(defaultApolloLinks)
+ )
+ const {
+ lastLoggedAddress,
+ chosenNetwork: currentNetwork,
+ connectedLedger,
+ loadingState
+ } = useSelector((state: RootState) => state.profile)
const dispatch = useDispatch()
- const connectAccount = useCallback(async (ledgerType: string) => {
+ const connectAccount = useCallback(async (chosenNetwork: string, ledgerType: string) => {
try {
- const { address, accountName } = await switchLedgerType(ledgerType)
+
+ const { address } = await switchLedgerType(chosenNetwork!, ledgerType)
if (address !== lastLoggedAddress || lastLoggedAddress === '') {
dispatch(
updateUserTransactions({
@@ -56,36 +60,10 @@ const App = () => {
})
)
}
- const balance = await getWalletBalance(address!)
-
- const stakedAmountBalance = await getStakedBalance(address!)
-
- const { totalRewards, validatorArray } = await fetchRewards(address!)
-
- const { delegationsArray } = await fetchDelegations(address)
-
- const { redelegationsArray } = await fetchRedelegations(address)
- const { undelegationsArray } = await fetchUndedelegations(address)
+ const connectedUser = await connectUser(chosenNetwork, ledgerType)
+ dispatch(updateUser(connectedUser))
- const { unbondingBalance } = await getUnbondingBalance(address)
-
- dispatch(
- updateUser({
- address,
- lastLoggedAddress: address,
- connectedLedger: ledgerType,
- accountName,
- balance: new BigNumber(balance),
- availableRewards: new BigNumber(totalRewards),
- stakedValidators: validatorArray,
- stakedBalance: new BigNumber(stakedAmountBalance),
- unbondingBalance: new BigNumber(unbondingBalance),
- delegations: delegationsArray,
- redelegations: redelegationsArray,
- undelegations: undelegationsArray
- })
- )
} catch (e) {
throw new Error('Failed to connect!')
}
@@ -103,28 +81,47 @@ const App = () => {
})
)
- await connectAccount(CosmosNetworkConfig.KEPLR_LEDGER)
+ await connectAccount(currentNetwork, CosmosNetworkConfig.KEPLR_LEDGER)
})
if (window.cosmostation) {
window.cosmostation.cosmos.on('accountChanged', async () => {
- await connectAccount(CosmosNetworkConfig.COSMOSTATION_LEDGER)
+ await connectAccount(currentNetwork, CosmosNetworkConfig.COSMOSTATION_LEDGER)
})
}
return () => {
window.removeEventListener('keplr_keystorechange', async () => {
- await connectAccount(CosmosNetworkConfig.KEPLR_LEDGER)
+ await connectAccount(currentNetwork, CosmosNetworkConfig.KEPLR_LEDGER)
})
window.removeEventListener('accountChanged', async () => {
- await connectAccount(CosmosNetworkConfig.COSMOSTATION_LEDGER)
+ await connectAccount(currentNetwork, CosmosNetworkConfig.COSMOSTATION_LEDGER)
})
}
}, [])
+
+ useEffect(() => {
+ dispatch(updateUser({ loadingState: true })
+ )
+ const newApolloLinks: ApolloLinks = {
+ uri: CHAIN_DETAILS.GRAPHQL_URL[currentNetwork! as keyof typeof CHAIN_DETAILS.GRAPHQL_URL],
+ url: CHAIN_DETAILS.GRAPHQL_WS[currentNetwork! as keyof typeof CHAIN_DETAILS.GRAPHQL_WS]
+ }
+
+ setCurrentApolloClient(newApolloClient(newApolloLinks))
+
+ if (connectedLedger) {
+ connectAccount(currentNetwork, connectedLedger)
+ }
+
+ setTimeout(() => { dispatch(updateUser({ loadingState: false })) }, 4000)
+
+ }, [currentNetwork])
+
return (
-
-
+
+
{location.pathname !== '/' ? null : (
<>
@@ -136,31 +133,38 @@ const App = () => {
)}
{location.pathname === '/' ? null : (
-
- }>
-
- } />
+ {loadingState ? : null}
+
+
+ }>
+
+ } />
+
+
+ } />
+ } />
+
+
+ } />
+ } />
+
-
- } />
- } />
-
-
- } />
- } />
-
-
- {import.meta.env.VITE_CHAIN_STATUS !== 'mainnet' && (
-
- } />
-
- )}
- } />
-
-
-
-
+ {
+ CHAIN_DETAILS.CHAIN_ID[currentNetwork! as keyof typeof CHAIN_DETAILS.CHAIN_ID]
+ === CHAIN_DETAILS.CHAIN_ID.MAINNET ? null : (
+
+ } />
+
+ )}
+ } />
+
+
+
+
+
+
+
)}
diff --git a/src/api/config.ts b/src/api/config.ts
index fd81436..292b46b 100644
--- a/src/api/config.ts
+++ b/src/api/config.ts
@@ -1,5 +1,3 @@
/* eslint-disable import/prefer-default-export */
export const GET_CURRENCY_RATE_URL = (currency: string) =>
`https://api.coingecko.com/api/v3/simple/price?ids=CUDOS&vs_currencies=${currency}`
-
-export const GET_FAUCET_TOKENS = import.meta.env.VITE_FAUCET_URL
diff --git a/src/api/getAccountDelegations.ts b/src/api/getAccountDelegations.ts
index 250e1ab..abba20c 100644
--- a/src/api/getAccountDelegations.ts
+++ b/src/api/getAccountDelegations.ts
@@ -1,7 +1,9 @@
import axios from 'axios'
+import { CHAIN_DETAILS } from 'utils/constants'
import { AccountDelegationsDocument } from '../graphql/account_actions'
export const fetchDelegations = async (
+ chosenNetwork: string,
address: string,
signal?: AbortSignal
) => {
@@ -9,7 +11,7 @@ export const fetchDelegations = async (
try {
const { data } = await axios.post(
- import.meta.env.VITE_GRAPHQL_URL?.toString(),
+ CHAIN_DETAILS.GRAPHQL_URL[chosenNetwork! as keyof typeof CHAIN_DETAILS.GRAPHQL_URL].toString(),
{
variables: { address },
query: AccountDelegationsDocument
diff --git a/src/api/getAccountRedelegations.ts b/src/api/getAccountRedelegations.ts
index a9da0fc..ec0915c 100644
--- a/src/api/getAccountRedelegations.ts
+++ b/src/api/getAccountRedelegations.ts
@@ -1,8 +1,10 @@
import axios from 'axios'
import BigNumber from 'bignumber.js'
+import { CHAIN_DETAILS } from 'utils/constants'
import { AccountRedelegationsDocument } from '../graphql/account_actions'
export const fetchRedelegations = async (
+ chosenNetwork: string,
address: string,
signal?: AbortSignal
) => {
@@ -14,7 +16,7 @@ export const fetchRedelegations = async (
try {
const { data } = await axios.post(
- import.meta.env.VITE_GRAPHQL_URL?.toString(),
+ CHAIN_DETAILS.GRAPHQL_URL[chosenNetwork! as keyof typeof CHAIN_DETAILS.GRAPHQL_URL].toString(),
{
variables: { address },
query: AccountRedelegationsDocument
diff --git a/src/api/getAccountUndelegations.ts b/src/api/getAccountUndelegations.ts
index 1c6f9b4..55739f2 100644
--- a/src/api/getAccountUndelegations.ts
+++ b/src/api/getAccountUndelegations.ts
@@ -1,7 +1,9 @@
import axios from 'axios'
+import { CHAIN_DETAILS } from 'utils/constants'
import { AccountUndelegationsDocument } from '../graphql/account_actions'
export const fetchUndedelegations = async (
+ chosenNetwork: string,
address: string,
signal?: AbortSignal
) => {
@@ -13,7 +15,7 @@ export const fetchUndedelegations = async (
try {
const { data } = await axios.post(
- import.meta.env.VITE_GRAPHQL_URL?.toString(),
+ CHAIN_DETAILS.GRAPHQL_URL[chosenNetwork! as keyof typeof CHAIN_DETAILS.GRAPHQL_URL].toString(),
{
variables: { address },
query: AccountUndelegationsDocument
diff --git a/src/api/getFaucetTokens.ts b/src/api/getFaucetTokens.ts
index e7d247a..8913d55 100644
--- a/src/api/getFaucetTokens.ts
+++ b/src/api/getFaucetTokens.ts
@@ -1,12 +1,11 @@
import axios from 'axios'
-import { GET_FAUCET_TOKENS } from './config'
-const getFaucetTokens = async (data: {
+const getFaucetTokens = async (faucetAddress: string, data: {
address: string
coins: Array
captchaResponse: string
}) => {
- return axios.post(GET_FAUCET_TOKENS, data)
+ return axios.post(faucetAddress, data)
}
export default getFaucetTokens
diff --git a/src/api/getRewards.ts b/src/api/getRewards.ts
index cabee6e..8d92dc8 100644
--- a/src/api/getRewards.ts
+++ b/src/api/getRewards.ts
@@ -3,14 +3,15 @@ import axios from 'axios'
import BigNumber from 'bignumber.js'
import { formatBigNum } from '../utils/projectUtils'
import { AccountDelegationRewardsDocument } from '../graphql/account_actions'
+import { CHAIN_DETAILS } from 'utils/constants'
-export const fetchRewards = async (address: string, signal?: AbortSignal) => {
+export const fetchRewards = async (chosenNetwork: string, address: string, signal?: AbortSignal) => {
const defaultReturnValue = new BigNumber(0)
const rewardArray: Array = []
const validatorArray: { address: string; amount: string }[] = []
try {
const { data } = await axios.post(
- import.meta.env.VITE_GRAPHQL_URL?.toString(),
+ CHAIN_DETAILS.GRAPHQL_URL[chosenNetwork! as keyof typeof CHAIN_DETAILS.GRAPHQL_URL].toString(),
{
variables: { address },
query: AccountDelegationRewardsDocument
diff --git a/src/api/getUnbondingBalance.ts b/src/api/getUnbondingBalance.ts
index afa4c31..64d458f 100644
--- a/src/api/getUnbondingBalance.ts
+++ b/src/api/getUnbondingBalance.ts
@@ -1,9 +1,11 @@
import axios from 'axios'
import BigNumber from 'bignumber.js'
+import { CHAIN_DETAILS } from 'utils/constants'
import { formatBigNum } from 'utils/projectUtils'
import { AccountUnbondingBalanceDocument } from '../graphql/account_actions'
export const getUnbondingBalance = async (
+ chosenNetwork: string,
address: string,
signal?: AbortSignal
) => {
@@ -12,7 +14,7 @@ export const getUnbondingBalance = async (
try {
const { data } = await axios.post(
- import.meta.env.VITE_GRAPHQL_URL?.toString(),
+ CHAIN_DETAILS.GRAPHQL_URL[chosenNetwork! as keyof typeof CHAIN_DETAILS.GRAPHQL_URL]?.toString(),
{
variables: { address },
query: AccountUnbondingBalanceDocument
diff --git a/src/assets/vectors/arrow-down.svg b/src/assets/vectors/arrow-down.svg
index 95daeb2..937bc8d 100644
--- a/src/assets/vectors/arrow-down.svg
+++ b/src/assets/vectors/arrow-down.svg
@@ -1,3 +1,3 @@
-