├── public ├── robots.txt ├── _headers ├── img │ └── assets │ │ ├── nyx.png │ │ ├── syn.png │ │ ├── amber.jpg │ │ ├── andr.png │ │ ├── binj.png │ │ ├── bkuji.png │ │ ├── bluna.png │ │ ├── butt.png │ │ ├── fina.png │ │ ├── fina.webp │ │ ├── luna.png │ │ ├── page.png │ │ ├── robots.txt │ │ ├── akt.svg │ │ ├── archway.svg │ │ ├── alink.svg │ │ ├── nolus.svg │ │ ├── stride.svg │ │ ├── kava.svg │ │ ├── adm.svg │ │ ├── xrp.svg │ │ ├── abusd.svg │ │ ├── usdt.svg │ │ ├── bld.svg │ │ ├── dvpn.svg │ │ ├── xprt.svg │ │ ├── saga.svg │ │ ├── wsteth.svg │ │ ├── scrt-white.svg │ │ ├── ksm.svg │ │ ├── stars.svg │ │ ├── orai.svg │ │ ├── deposit.svg │ │ ├── dydx.svg │ │ ├── eclip.svg │ │ ├── dot.svg │ │ ├── ntrn.svg │ │ ├── cre.svg │ │ ├── ampluna.svg │ │ ├── cmdx.svg │ │ ├── nstk.svg │ │ ├── silk.svg │ │ ├── stjuno.svg │ │ ├── luna2.svg │ │ ├── wbnb.svg │ │ ├── juno.svg │ │ ├── harbor.svg │ │ ├── coreum.svg │ │ ├── evmos.svg │ │ ├── pstake.svg │ │ ├── usk.svg │ │ ├── pica.svg │ │ ├── mnta.svg │ │ ├── rowan.svg │ │ ├── stinj.svg │ │ ├── inj.svg │ │ ├── cmst.svg │ │ ├── axl.svg │ │ ├── usdc.svg │ │ ├── adai.svg │ │ ├── ibc-black.svg │ │ ├── leap.svg │ │ ├── afrax.svg │ │ ├── scrt.svg │ │ ├── shd.svg │ │ ├── migaloo.svg │ │ ├── stkdydx.svg │ │ ├── statom.svg │ │ ├── keplr.svg │ │ ├── dshd.svg │ │ └── stluna.svg ├── fonts │ └── runddisplay │ │ ├── runddisplay-black.woff │ │ ├── runddisplay-bold.woff │ │ ├── runddisplay-light.woff │ │ ├── runddisplay-medium.woff │ │ ├── runddisplay-thin.woff │ │ ├── runddisplay-regular.woff │ │ ├── runddisplay-semibold.woff │ │ └── runddisplay-extrabold.woff ├── sitemap.xml ├── PriceIdsString.txt └── favicon.svg ├── src ├── types │ ├── Nullable.ts │ ├── Theme.ts │ ├── ValidatorRestakeStatus.ts │ ├── IbcMode.ts │ ├── WalletAPIType.ts │ ├── WrappingMode.ts │ ├── Validator.ts │ ├── FeeGrantStatus.ts │ ├── NotificationType.ts │ ├── StakingView.ts │ ├── ApiStatus.ts │ ├── GetBalanceError.ts │ ├── TokenBalances.ts │ ├── Currency.ts │ └── MessageType.ts ├── utils │ ├── vite-env.d.ts │ ├── env.d.ts │ ├── tokens.ts │ └── useHoverOutside.ts ├── assets │ └── scss │ │ └── components │ │ ├── _fonts.scss │ │ └── fonts │ │ └── _runddisplay.scss ├── custom.d.ts ├── components │ ├── Wallet │ │ ├── ManageBalances │ │ │ ├── Balances.scss │ │ │ └── ManageBalances.tsx │ │ └── StatusDot.tsx │ ├── Header.tsx │ ├── FeedbackButton.tsx │ ├── FloatingCTAButton.tsx │ ├── FeeGrant │ │ ├── FeeGrant.tsx │ │ └── components │ │ │ └── ActionableStatus.tsx │ ├── Title.tsx │ ├── PercentagePicker.tsx │ ├── FloatingCTAButton.scss │ └── UI │ │ ├── Badge │ │ └── Badge.tsx │ │ └── Button │ │ └── Button.tsx ├── pages │ ├── wrap │ │ ├── components │ │ │ ├── wrap.scss │ │ │ ├── SCRTUnwrapWarning.tsx │ │ │ └── FeeGrantInfoModal.tsx │ │ └── Wrap.tsx │ ├── apps │ │ └── components │ │ │ ├── tile │ │ │ ├── Tag.tsx │ │ │ └── AppTile.tsx │ │ │ ├── SkeletonLoaders │ │ │ ├── SkeletonLoader.tsx │ │ │ └── SkeletonLoaders.tsx │ │ │ └── FilterTag.tsx │ ├── ibc │ │ └── components │ │ │ ├── IbcSelect.tsx │ │ │ └── ibcSchema.ts │ ├── dashboard │ │ └── components │ │ │ ├── MiniTile.tsx │ │ │ ├── CurrentPrice.tsx │ │ │ ├── PriceVolTVLChart │ │ │ └── components │ │ │ │ ├── TypeSwitch.tsx │ │ │ │ └── RangeSwitch.tsx │ │ │ ├── SocialMedia.tsx │ │ │ └── QuadTile.tsx │ ├── send │ │ ├── sendSchema.ts │ │ └── Send.tsx │ ├── staking │ │ └── components │ │ │ ├── StakingStats │ │ │ ├── StakingStats.tsx │ │ │ ├── StakingAmount.tsx │ │ │ ├── AvailableBalance.tsx │ │ │ └── ClaimableRewards.tsx │ │ │ ├── NoScrtWarning.tsx │ │ │ └── ClaimRewardsModal.tsx │ ├── powertools │ │ └── components │ │ │ └── ApiStatusIcon.tsx │ └── bridge │ │ └── SwingModal.tsx ├── hooks │ └── useClickOutside.tsx ├── context │ └── ThemeContext.tsx ├── services │ ├── notification.service.ts │ ├── staking.service.ts │ └── send.service.ts └── store │ ├── UserPreferences.ts │ └── TokenPrices.ts ├── .dockerignore ├── banner.png ├── .husky └── pre-commit ├── postcss.config.js ├── Dockerfile ├── example.env ├── .prettierrc ├── docker-compose.yml ├── .gitignore ├── .github └── workflows │ └── docker-image.yml ├── tsconfig.json ├── vite.config.ts ├── index.html ├── LICENSE ├── README.md ├── package.json └── vite-plugin-whip-003.ts /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / -------------------------------------------------------------------------------- /src/types/Nullable.ts: -------------------------------------------------------------------------------- 1 | export type Nullable = X | null 2 | -------------------------------------------------------------------------------- /src/utils/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/assets/scss/components/_fonts.scss: -------------------------------------------------------------------------------- 1 | @use './fonts/runddisplay'; 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | build 4 | .vscode/launch.json 5 | .DS_Store -------------------------------------------------------------------------------- /banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/banner.png -------------------------------------------------------------------------------- /src/utils/env.d.ts: -------------------------------------------------------------------------------- 1 | interface ImportMeta { 2 | readonly env: ImportMetaEnv 3 | } 4 | -------------------------------------------------------------------------------- /src/custom.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | leap?: any 3 | keplr?: any 4 | wallet?: any 5 | } 6 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /public/_headers: -------------------------------------------------------------------------------- 1 | /* 2 | X-Frame-Options: SAMEORIGIN 3 | Content-Security-Policy: frame-ancestors 'self' -------------------------------------------------------------------------------- /public/img/assets/nyx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/img/assets/nyx.png -------------------------------------------------------------------------------- /public/img/assets/syn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/img/assets/syn.png -------------------------------------------------------------------------------- /public/img/assets/amber.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/img/assets/amber.jpg -------------------------------------------------------------------------------- /public/img/assets/andr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/img/assets/andr.png -------------------------------------------------------------------------------- /public/img/assets/binj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/img/assets/binj.png -------------------------------------------------------------------------------- /public/img/assets/bkuji.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/img/assets/bkuji.png -------------------------------------------------------------------------------- /public/img/assets/bluna.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/img/assets/bluna.png -------------------------------------------------------------------------------- /public/img/assets/butt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/img/assets/butt.png -------------------------------------------------------------------------------- /public/img/assets/fina.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/img/assets/fina.png -------------------------------------------------------------------------------- /public/img/assets/fina.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/img/assets/fina.webp -------------------------------------------------------------------------------- /public/img/assets/luna.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/img/assets/luna.png -------------------------------------------------------------------------------- /public/img/assets/page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/img/assets/page.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /public/img/assets/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | 3 | User-agent: facebookexternalhit 4 | Disallow: 5 | 6 | User-agent: Twitterbot 7 | Disallow: -------------------------------------------------------------------------------- /src/utils/tokens.ts: -------------------------------------------------------------------------------- 1 | import { Token, tokens } from './config' 2 | 3 | export const scrtToken: Token = tokens.find((token) => token.name === 'SCRT') 4 | -------------------------------------------------------------------------------- /public/fonts/runddisplay/runddisplay-black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/fonts/runddisplay/runddisplay-black.woff -------------------------------------------------------------------------------- /public/fonts/runddisplay/runddisplay-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/fonts/runddisplay/runddisplay-bold.woff -------------------------------------------------------------------------------- /public/fonts/runddisplay/runddisplay-light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/fonts/runddisplay/runddisplay-light.woff -------------------------------------------------------------------------------- /public/fonts/runddisplay/runddisplay-medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/fonts/runddisplay/runddisplay-medium.woff -------------------------------------------------------------------------------- /public/fonts/runddisplay/runddisplay-thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/fonts/runddisplay/runddisplay-thin.woff -------------------------------------------------------------------------------- /public/fonts/runddisplay/runddisplay-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/fonts/runddisplay/runddisplay-regular.woff -------------------------------------------------------------------------------- /public/fonts/runddisplay/runddisplay-semibold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/fonts/runddisplay/runddisplay-semibold.woff -------------------------------------------------------------------------------- /src/types/Theme.ts: -------------------------------------------------------------------------------- 1 | export type Theme = 'light' | 'dark' 2 | 3 | export function isTheme(x: String): boolean { 4 | return x === 'light' || x === 'dark' 5 | } 6 | -------------------------------------------------------------------------------- /public/fonts/runddisplay/runddisplay-extrabold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/dash.scrt.network/HEAD/public/fonts/runddisplay/runddisplay-extrabold.woff -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine 2 | WORKDIR /app 3 | COPY package.json . 4 | COPY package-lock.json . 5 | RUN npm install 6 | COPY . . 7 | EXPOSE 3000 8 | CMD ["npm", "start"] -------------------------------------------------------------------------------- /src/types/ValidatorRestakeStatus.ts: -------------------------------------------------------------------------------- 1 | export type ValidatorRestakeStatus = { 2 | validatorAddress: string 3 | autoRestake: boolean 4 | stakedAmount: string 5 | } 6 | -------------------------------------------------------------------------------- /src/types/IbcMode.ts: -------------------------------------------------------------------------------- 1 | export type IbcMode = 'deposit' | 'withdrawal' 2 | 3 | export function isIbcMode(x: String): boolean { 4 | return x === 'deposit' || x === 'withdrawal' 5 | } 6 | -------------------------------------------------------------------------------- /src/types/WalletAPIType.ts: -------------------------------------------------------------------------------- 1 | export type WalletAPIType = 'keplr' | 'leap' 2 | 3 | export function isWalletAPIType(x: String): boolean { 4 | return x === 'keplr' || x === 'leap' 5 | } 6 | -------------------------------------------------------------------------------- /src/types/WrappingMode.ts: -------------------------------------------------------------------------------- 1 | export type WrappingMode = 'wrap' | 'unwrap' 2 | 3 | export function isWrappingMode(x: String): boolean { 4 | return x === 'wrap' || x === 'unwrap' 5 | } 6 | -------------------------------------------------------------------------------- /src/components/Wallet/ManageBalances/Balances.scss: -------------------------------------------------------------------------------- 1 | .balance-item div { 2 | &:first-of-type { 3 | @apply rounded-t-lg; 4 | } 5 | &:last-of-type { 6 | @apply rounded-b-lg; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /example.env: -------------------------------------------------------------------------------- 1 | # Mixpanel 2 | VITE_MIXPANEL_ENABLED=false 3 | VITE_MIXPANEL_PROJECT_TOKEN= 4 | 5 | # Overrides debug mode in user settings 6 | VITE_DEBUG_MODE=false 7 | 8 | 9 | # Transak 10 | TRANSAK_API_KEY= -------------------------------------------------------------------------------- /src/types/Validator.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents a dummy type for better code readability. 3 | * @typedef {Object.} Validator 4 | */ 5 | 6 | export type Validator = { 7 | [prop: string]: any 8 | } 9 | -------------------------------------------------------------------------------- /src/types/FeeGrantStatus.ts: -------------------------------------------------------------------------------- 1 | export type FeeGrantStatus = 'success' | 'fail' | 'untouched' 2 | 3 | export function isFeeGrantStatus(x: any): boolean { 4 | return x === 'success' || x === 'fail' || x === 'untouched' 5 | } 6 | -------------------------------------------------------------------------------- /src/types/NotificationType.ts: -------------------------------------------------------------------------------- 1 | export type NotificationType = 'success' | 'error' | 'loading' 2 | 3 | export function isNotificationType(x: String): boolean { 4 | return x === 'success' || x === 'error' || x === 'loading' 5 | } 6 | -------------------------------------------------------------------------------- /src/types/StakingView.ts: -------------------------------------------------------------------------------- 1 | export type StakingView = 'delegate' | 'redelegate' | 'undelegate' 2 | 3 | export const isStakingView = (x: string) => { 4 | return x === 'delegate' || x === 'redelegate' || x === 'undelegate' 5 | } 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "arrowParens": "always", 4 | "singleQuote": true, 5 | "trailingComma": "none", 6 | "endOfLine": "auto", 7 | "printWidth": 120, 8 | "useTabs": false, 9 | "tabWidth": 2 10 | } 11 | -------------------------------------------------------------------------------- /src/types/ApiStatus.ts: -------------------------------------------------------------------------------- 1 | export type ApiStatus = 'online' | 'offline' | 'loading' | 'unknown' 2 | 3 | export function isApiStatus(x: any): boolean { 4 | return x === 'online' || x === 'offline' || x === 'loading' || x === 'unknown' 5 | } 6 | -------------------------------------------------------------------------------- /src/types/GetBalanceError.ts: -------------------------------------------------------------------------------- 1 | export type GetBalanceError = 'viewingKeyError' | 'GenericFetchError' 2 | 3 | export function isGetBalanceError(x: String): boolean { 4 | return x === 'viewingKeyError' || x === 'GenericFetchError' 5 | } 6 | -------------------------------------------------------------------------------- /src/pages/wrap/components/wrap.scss: -------------------------------------------------------------------------------- 1 | .no-spinner::-webkit-inner-spin-button, 2 | .no-spinner::-webkit-outer-spin-button { 3 | -webkit-appearance: none; 4 | margin: 0; 5 | } 6 | 7 | .no-spinner { 8 | -moz-appearance: textfield; 9 | } 10 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | services: 3 | dashboard_react_app: 4 | container_name: dashboard_frontend2 5 | build: ./ 6 | ports: 7 | - "3000:3000" 8 | stdin_open: true 9 | tty: true 10 | environment: 11 | - CHOKIDAR_USEPOLLING=true 12 | -------------------------------------------------------------------------------- /src/types/TokenBalances.ts: -------------------------------------------------------------------------------- 1 | import BigNumber from 'bignumber.js' 2 | import { Nullable } from './Nullable' 3 | import { GetBalanceError } from './GetBalanceError' 4 | 5 | export type TokenBalances = { 6 | balance: Nullable 7 | secretBalance?: Nullable 8 | } 9 | -------------------------------------------------------------------------------- /src/pages/apps/components/tile/Tag.tsx: -------------------------------------------------------------------------------- 1 | import Badge from 'components/UI/Badge/Badge' 2 | 3 | interface Props { 4 | name: string 5 | } 6 | const Tag = (props: Props) => { 7 | return ( 8 | <> 9 | {props.name} 10 | 11 | ) 12 | } 13 | 14 | export default Tag 15 | -------------------------------------------------------------------------------- /src/types/Currency.ts: -------------------------------------------------------------------------------- 1 | import { Nullable } from './Nullable' 2 | 3 | export type Currency = 'USD' | 'EUR' | 'JPY' | 'GBP' | 'AUD' | 'CAD' | 'CHF' 4 | 5 | export function isCurrency(x: any): boolean { 6 | return x === 'USD' || x === 'EUR' || x === 'JPY' || x === 'GBP' || x === 'AUD' || x === 'CAD' || x === 'CHF' 7 | } 8 | -------------------------------------------------------------------------------- /src/pages/apps/components/SkeletonLoaders/SkeletonLoader.tsx: -------------------------------------------------------------------------------- 1 | export default function SkeletonLoader() { 2 | return ( 3 |
4 |
5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # General 2 | dist 3 | build 4 | .vscode/launch.json 5 | 6 | # Dependency directories 7 | node_modules/ 8 | jspm_packages/ 9 | 10 | # Optional npm cache directory 11 | .npm 12 | 13 | # dotenv environment variable files 14 | .env 15 | .env.test 16 | 17 | # OS generated files 18 | .DS_Store* 19 | ehthumbs.db 20 | Icon? 21 | Thumbs.db -------------------------------------------------------------------------------- /public/img/assets/akt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /public/img/assets/archway.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/img/assets/alink.svg: -------------------------------------------------------------------------------- 1 | Asset 1 -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | push: 8 | branches: ["master"] 9 | pull_request: 10 | branches: ["master"] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v3 18 | - name: Build the Docker image 19 | run: docker build . --file Dockerfile --tag my-image-name:$(date +%s) 20 | -------------------------------------------------------------------------------- /src/pages/ibc/components/IbcSelect.tsx: -------------------------------------------------------------------------------- 1 | interface IProps { 2 | imgSrc: string 3 | altText: string 4 | optionName: string 5 | } 6 | 7 | export default function IbcSelect(props: IProps) { 8 | return ( 9 |
10 | {props.altText} 11 | {props.optionName} 12 |
13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | import Title from './Title' 2 | 3 | interface Props { 4 | title: string 5 | description?: string 6 | } 7 | 8 | const Header = (props: Props) => { 9 | return ( 10 | <> 11 | {/* Title */} 12 | 13 | {/* Description */} 14 | {props.description && ( 15 | <p className="mt-4 sm:max-w-lg mx-auto mb-6 text-center text-neutral-500 dark:text-neutral-500"> 16 | {props.description} 17 | </p> 18 | )} 19 | </> 20 | ) 21 | } 22 | 23 | export default Header 24 | -------------------------------------------------------------------------------- /public/img/assets/nolus.svg: -------------------------------------------------------------------------------- 1 | <svg width="83" height="83" viewBox="0 0 83 83" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path d="M41.3266 0.541992C18.6758 0.541992 0.316895 18.8077 0.316895 41.3436C0.316895 63.8794 18.6758 82.1451 41.3266 82.1451C63.9774 82.1451 82.3364 63.8794 82.3364 41.3436C82.3364 18.8077 63.9712 0.541992 41.3266 0.541992ZM55.6619 61.7443H26.9851C23.579 61.7443 20.8155 58.9949 20.8155 55.6061V27.081C20.8155 23.6923 23.579 20.9428 26.9851 20.9428H55.6619C59.068 20.9428 61.8315 23.6923 61.8315 27.081V55.6123C61.8315 59.0011 59.068 61.7505 55.6619 61.7505V61.7443Z" fill="#FF562E"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 5 | "allowJs": false, 6 | "skipLibCheck": true, 7 | "esModuleInterop": false, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "strictNullChecks": false, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx", 18 | "baseUrl": "src" 19 | }, 20 | "include": ["src"] 21 | } 22 | -------------------------------------------------------------------------------- /src/components/FeedbackButton.tsx: -------------------------------------------------------------------------------- 1 | import './FloatingCTAButton.scss' 2 | 3 | interface Props { 4 | url: string 5 | } 6 | 7 | function FeedbackButton(props: Props) { 8 | return ( 9 | <div className="z-10 fixed rotate-90 top-3/4 left-0 -translate-x-[30px] translate-y-[29px]"> 10 | <a 11 | href={props.url} 12 | target="_blank" 13 | className="bg-purple-100 text-purple-800 text-sm font-medium me-2 dark:bg-purple-900 dark:text-purple-300 transition-colors px-1.5 py-1.5 rounded-t" 14 | > 15 | Feedback 16 | </a> 17 | </div> 18 | ) 19 | } 20 | 21 | export default FeedbackButton 22 | -------------------------------------------------------------------------------- /src/utils/useHoverOutside.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | 3 | export function useHoverOutside(ref: any, handler: any) { 4 | useEffect(() => { 5 | const listener = (event: any) => { 6 | if (!ref.current || ref.current.contains(event.target)) { 7 | return 8 | } 9 | handler(event) 10 | } 11 | document.addEventListener('mouseover', listener) 12 | document.addEventListener('touchstart', listener) 13 | return () => { 14 | document.removeEventListener('mouseover', listener) 15 | document.removeEventListener('touchstart', listener) 16 | } 17 | }, [ref, handler]) 18 | } 19 | -------------------------------------------------------------------------------- /public/img/assets/stride.svg: -------------------------------------------------------------------------------- 1 | <svg width="240" height="240" viewBox="0 0 240 240" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <rect width="240" height="240" rx="120" fill="#E6007A"/> 3 | <path d="M173.186 156.694C160.463 156.694 150.168 146.38 150.168 133.676V99.2072H179.856V79.1581H150.168V46L127.42 58.1451V79.1581H84.276C54.2023 79.1581 46.2983 115.401 69.4319 128.895L92.9511 144.703C98.1561 148.559 96.0355 156.656 88.7099 156.656H56.7084V176.897H88.7099C118.976 176.897 126.688 140.655 103.554 127.16L80.2276 111.352C75.0225 107.497 76.9503 99.2072 84.276 99.2072H127.42V133.946C127.42 160.164 145.541 176.917 172.916 176.917H179.856V156.694H173.186Z" fill="white"/> 4 | </svg> 5 | -------------------------------------------------------------------------------- /src/hooks/useClickOutside.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | 3 | const useClickOutside = (ref: any, handler: any) => { 4 | useEffect(() => { 5 | const listener = (event: any) => { 6 | if (!ref.current || ref.current.contains(event.target)) { 7 | return 8 | } 9 | handler(event) 10 | } 11 | document.addEventListener('mousedown', listener) 12 | document.addEventListener('touchstart', listener) 13 | return () => { 14 | document.removeEventListener('mousedown', listener) 15 | document.removeEventListener('touchstart', listener) 16 | } 17 | }, [ref, handler]) 18 | } 19 | 20 | export default useClickOutside 21 | -------------------------------------------------------------------------------- /src/components/Wallet/StatusDot.tsx: -------------------------------------------------------------------------------- 1 | type Status = 'connected' | 'disconnected' 2 | 3 | type Props = { 4 | status: Status 5 | } 6 | 7 | function StatusDot(props: Props) { 8 | if (props.status === 'connected') { 9 | return ( 10 | <span className="flex relative h-2 w-2"> 11 | <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-1/2"></span> 12 | <span className="relative inline-flex rounded-full size-2 h-2 w-2 bg-emerald-500"></span> 13 | </span> 14 | ) 15 | } 16 | 17 | return <span className="relative inline-flex rounded-full h-2 w-2 bg-red-500"></span> 18 | } 19 | 20 | export default StatusDot 21 | -------------------------------------------------------------------------------- /public/img/assets/kava.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> 3 | <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" 4 | viewBox="0 0 256 256" style="enable-background:new 0 0 256 256;" xml:space="preserve"> 5 | <style type="text/css"> 6 | .st0{fill:#FF433E;} 7 | .st1{fill:#FFFFFF;} 8 | </style> 9 | <g> 10 | <circle class="st0" cx="128" cy="128" r="128"/> 11 | <g> 12 | <rect x="68.3" y="54.1" class="st1" width="25.8" height="147.9"/> 13 | <polygon class="st1" points="164.7,201.9 108.1,128 164.7,54.1 197,54.1 141.3,128 197,201.9 "/> 14 | </g> 15 | </g> 16 | </svg> 17 | -------------------------------------------------------------------------------- /src/pages/apps/components/SkeletonLoaders/SkeletonLoaders.tsx: -------------------------------------------------------------------------------- 1 | import SkeletonLoader from './SkeletonLoader' 2 | 3 | interface Props { 4 | amount?: number 5 | } 6 | 7 | /** 8 | * Render multiple SkeletonLoader components based on the specified amount. 9 | * 10 | * @param {number} [amount=20] - The number of SkeletonLoaders to render. Default is 20. 11 | * 12 | * @remarks 13 | * This function is intended for use in the /apps context. 14 | * 15 | * @example 16 | * ```tsx 17 | * <SkeletonLoaders amount={10} /> 18 | * ``` 19 | */ 20 | export default function SkeletonLoaders({ amount = 20 }: Props) { 21 | return ( 22 | <> 23 | {Array.from({ length: amount }).map((_, index) => ( 24 | <SkeletonLoader key={index} /> 25 | ))} 26 | </> 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /public/img/assets/adm.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <!-- Generator: Adobe Illustrator 26.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> 3 | <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" 4 | viewBox="0 0 1728 1728" style="enable-background:new 0 0 1728 1728;" xml:space="preserve"> 5 | <style type="text/css"> 6 | .st0{fill:#ED1C24;} 7 | </style> 8 | <g> 9 | <polygon class="st0" points="278.32,1410.46 865.97,392.62 1453.63,1410.46 1149.11,1410.46 1230.4,1551.27 1704.87,1551.27 10 | 865.97,98.27 27.08,1551.27 496.27,1551.27 577.57,1410.46 "/> 11 | <polygon class="st0" points="1079.84,1290.5 1247.36,1290.5 865.97,629.92 484.59,1290.5 646.83,1290.5 863.34,915.49 "/> 12 | </g> 13 | </svg> 14 | -------------------------------------------------------------------------------- /src/components/FloatingCTAButton.tsx: -------------------------------------------------------------------------------- 1 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 2 | import { faComment } from '@fortawesome/free-solid-svg-icons' 3 | import './FloatingCTAButton.scss' 4 | import { Link } from 'react-router-dom' 5 | 6 | interface Props { 7 | url: string 8 | text: string 9 | } 10 | 11 | function FloatingCTAButton(props: Props) { 12 | return ( 13 | <Link to={props.url} target="_blank" className="hidden md:block"> 14 | <div className="floatingCTAButton bg-violet-600 select-none text-white"> 15 | <FontAwesomeIcon icon={faComment} className="icon-circle bg-violet-600" /> 16 | <span className="cta-text text-xs font-light">{props.text}</span> 17 | </div> 18 | </Link> 19 | ) 20 | } 21 | 22 | export default FloatingCTAButton 23 | -------------------------------------------------------------------------------- /public/img/assets/xrp.svg: -------------------------------------------------------------------------------- 1 | <svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <g clip-path="url(#clip0_1148_7)"> 3 | <path d="M100 200C155.228 200 200 155.228 200 100C200 44.7715 155.228 0 100 0C44.7715 0 0 44.7715 0 100C0 155.228 44.7715 200 100 200Z" fill="black"/> 4 | <path d="M145.632 43.9883H164.292L125.449 84.2623C111.385 98.8437 88.5846 98.8437 74.5511 84.2623L35.7079 43.9883H54.3685L83.8662 74.5819C92.7855 83.8056 107.215 83.8056 116.104 74.5819L145.632 43.9883ZM54.1249 156.013H35.4644L74.5511 115.465C88.615 100.883 111.416 100.883 125.48 115.465L164.566 156.013H145.906L116.165 125.145C107.245 115.921 92.816 115.921 83.9271 125.145L54.1249 156.013Z" fill="white"/> 5 | </g> 6 | <defs> 7 | <clipPath id="clip0_1148_7"> 8 | <rect width="200" height="200" fill="white"/> 9 | </clipPath> 10 | </defs> 11 | </svg> 12 | -------------------------------------------------------------------------------- /public/img/assets/abusd.svg: -------------------------------------------------------------------------------- 1 | <svg width="25" height="25" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <g clip-path="url(#clip0_2518_19897)"> 3 | <path d="M12.4996 0.0526123L15.5836 3.20151L7.8178 10.9441L4.73376 7.86928L12.4996 0.0526123Z" fill="#F0B90B" stroke="#F0B90B" /> 4 | <path d="M17.1814 4.72034L20.2654 7.86923L7.8178 20.2796L4.73376 17.2048L17.1814 4.72034Z" fill="#F0B90B" stroke="#F0B90B" /> 5 | <path d="M3.13604 9.38818L6.22007 12.5371L3.13604 15.6119L0.052002 12.5371L3.13604 9.38818Z" fill="#F0B90B" stroke="#F0B90B" /> 6 | <path d="M21.8631 9.38818L24.9472 12.5371L12.4996 24.9474L9.41553 21.8726L21.8631 9.38818Z" fill="#F0B90B" stroke="#F0B90B" /> 7 | </g> 8 | <defs> 9 | <clipPath id="clip0_2518_19897"> 10 | <rect width="25" height="25" fill="white" /> 11 | </clipPath> 12 | </defs> 13 | </svg> 14 | -------------------------------------------------------------------------------- /public/sitemap.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"> 3 | <url> 4 | <loc>https://dash.scrt.network/</loc> 5 | </url> 6 | <url> 7 | <loc>https://dash.scrt.network/ibc</loc> 8 | </url> 9 | <url> 10 | <loc>https://dash.scrt.network/wrap</loc> 11 | </url> 12 | <url> 13 | <loc>https://dash.scrt.network/bridge</loc> 14 | </url> 15 | <url> 16 | <loc>https://dash.scrt.network/restake</loc> 17 | </url> 18 | <url> 19 | <loc>https://dash.scrt.network/apps</loc> 20 | </url> 21 | </urlset> -------------------------------------------------------------------------------- /public/img/assets/usdt.svg: -------------------------------------------------------------------------------- 1 | <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 339.43 295.27"><title>tether-usdt-logo -------------------------------------------------------------------------------- /src/pages/dashboard/components/MiniTile.tsx: -------------------------------------------------------------------------------- 1 | interface Props { 2 | name: string 3 | value?: string 4 | } 5 | 6 | export default function MiniTile(props: Props) { 7 | return ( 8 | <> 9 |
10 |
11 |
{props.name}
12 |
13 | {props.value ? ( 14 | <>{props.value} 15 | ) : ( 16 |
17 | )} 18 |
19 |
20 |
21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /public/img/assets/bld.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/pages/apps/components/FilterTag.tsx: -------------------------------------------------------------------------------- 1 | interface Props { 2 | name: string 3 | toggleTagFilter: any 4 | isTagInFilterList: (name: string) => string 5 | } 6 | 7 | const FilterTag = (props: Props) => { 8 | return ( 9 | 20 | ) 21 | } 22 | 23 | export default FilterTag 24 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | import tsconfigPaths from 'vite-tsconfig-paths' 4 | import { whip003 } from './vite-plugin-whip-003' 5 | 6 | export default defineConfig({ 7 | plugins: [ 8 | { ...react() }, 9 | { ...tsconfigPaths() }, 10 | { 11 | ...whip003(), 12 | apply: 'build' 13 | } 14 | ], 15 | server: { 16 | host: true, 17 | port: 3000 18 | }, 19 | resolve: { 20 | alias: [ 21 | { 22 | find: '@buf/evmos_evmos.bufbuild_es/evmos/vesting/v1/tx_pb.js', 23 | replacement: '@buf/evmos_evmos.bufbuild_es/evmos/vesting/v2/tx_pb.js' 24 | }, 25 | { 26 | find: '@buf/evmos_evmos.bufbuild_es/evmos/revenue/v1/tx_pb.js', 27 | replacement: '@evmos/proto/dist/proto/evmos/revenue/v1/tx.js' 28 | } 29 | ] 30 | }, 31 | build: { 32 | minify: 'esbuild' 33 | } 34 | }) 35 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Secret Dashboard 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 18 | 19 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /public/PriceIdsString.txt: -------------------------------------------------------------------------------- 1 | secret,akash-network,,eris-staked-kuji,eris-amplified-luna,eris-amplified-whale,andromeda-2,archway,cosmos,,,agoric,,cheqd-network,comdex,composite,cosmos,polkadot,sentinel,dydx,dymension,eclipse-fi,omniflix-network,graviton,harbor-2,chihuahua-token,injective-protocol,inter-stable-token,jackal-protocol,juno-network,kava,kujira,kusama,nolus,unstake-fi,neutron-3,nym,terra-luna-2,levana-protocol,milkyway-staked-tia,mantadao,oraichain-token,osmosis,page,picasso,pstake-finance,qatom,quicksilver,kujira,usd-coin,saga-2,stargaze,stride-staked-atom,stride-staked-injective,stride-staked-juno,stkatom,,stride-staked-luna,stride-staked-osmo,stride,stride-staked-tia,switcheo,,celestia,umee,tether,bitcoin,white-whale,wrapped-steth,persistence,alter,,,amberdao,shade-protocol,fina,shade-protocol,,sienna,silk-bcec1136-561c-4706-a42c-8b67d0d7f7d2,stkd-scrt,usd-coin,axelar,ethereum,bridged-wrapped-steth-axelar,bitcoin,binancecoin,busd,dai,chainlink,uniswap,tether,frax -------------------------------------------------------------------------------- /public/img/assets/dvpn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/context/ThemeContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useEffect, useState } from 'react' 2 | import { useUserPreferencesStore } from 'store/UserPreferences' 3 | import { Theme } from 'types/Theme' 4 | 5 | const ThemeContext = createContext(null) 6 | 7 | const ThemeContextProvider = ({ children }: any) => { 8 | // the value that will be given to the context 9 | const { theme } = useUserPreferencesStore() 10 | 11 | function setThemeClassToBody(theme: Theme) { 12 | if (theme === 'light') { 13 | document.body.classList.remove('dark') 14 | } else if (theme === 'dark') { 15 | document.body.classList.add('dark') 16 | } 17 | } 18 | 19 | // always save option to localStorage 20 | useEffect(() => { 21 | if (theme !== null) { 22 | setThemeClassToBody(theme) 23 | } 24 | }, [theme]) 25 | 26 | return {children} 27 | } 28 | 29 | export { ThemeContext, ThemeContextProvider } 30 | -------------------------------------------------------------------------------- /public/img/assets/xprt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /public/img/assets/saga.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/services/notification.service.ts: -------------------------------------------------------------------------------- 1 | import toast from 'react-hot-toast' 2 | import { NotificationType } from 'types/NotificationType' 3 | 4 | function notify(notification: string, type: NotificationType, toastId: string = null) { 5 | // Define an options object for toast, if toastId is provided 6 | const options = { 7 | id: toastId || undefined, 8 | duration: type === 'success' ? 10000 : Infinity, 9 | onClick: () => { 10 | toast.dismiss() 11 | }, 12 | style: { 13 | maxWidth: '35vw', 14 | whiteSpace: 'pre-wrap' as any, 15 | wordBreak: 'break-word' as any 16 | }, 17 | position: 'bottom-right' as any 18 | } 19 | 20 | switch (type) { 21 | case 'error': 22 | return toast.error(notification, options) 23 | 24 | case 'loading': 25 | return toast.loading(notification, options) 26 | 27 | case 'success': 28 | return toast.success(notification, options) 29 | 30 | default: 31 | return null 32 | } 33 | } 34 | 35 | export const NotificationService = { 36 | notify 37 | } 38 | -------------------------------------------------------------------------------- /public/img/assets/wsteth.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /public/img/assets/scrt-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /public/img/assets/ksm.svg: -------------------------------------------------------------------------------- 1 | kusama-ksm-logo -------------------------------------------------------------------------------- /src/pages/send/sendSchema.ts: -------------------------------------------------------------------------------- 1 | import * as yup from 'yup' 2 | import { validateAddress } from 'secretjs' 3 | 4 | export const sendSchema = yup.object().shape({ 5 | amount: yup 6 | .number() 7 | .typeError('Please enter a valid amount') 8 | .required('Please enter a valid amount') 9 | .test('min-amount', 'Please enter a valid amount', function (value) { 10 | const { token } = this.parent 11 | if (token && typeof token.decimals === 'number') { 12 | const minAmount = Math.pow(10, -token.decimals) 13 | if (value < minAmount) { 14 | return this.createError({ 15 | message: `Please enter an amount of at least ${minAmount}` 16 | }) 17 | } 18 | } 19 | return true 20 | }), 21 | token: yup.mixed().required('Token is required'), 22 | recipient: yup 23 | .string() 24 | .required('Add a recipient') 25 | .test('isValidAddress', 'Please enter a valid recipient', (value) => { 26 | if (!value) return false 27 | return validateAddress(value).isValid 28 | }), 29 | memo: yup.string().max(255, 'Memo too long') 30 | }) 31 | -------------------------------------------------------------------------------- /src/pages/wrap/components/SCRTUnwrapWarning.tsx: -------------------------------------------------------------------------------- 1 | import { faTriangleExclamation } from '@fortawesome/free-solid-svg-icons' 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 3 | 4 | function SCRTUnwrapWarning() { 5 | return ( 6 |
7 |
8 |
9 | 10 |
    11 |
    You do not have any SCRT to pay for gas
    12 |
  • Please unwrap some sSCRT into SCRT using a fee grant.
  • 13 |
  • 14 | Do NOT try to create a viewing key first, instead unwrap 0.1 sSCRT directly. 15 |
  • 16 |
17 |
18 |
19 |
20 | ) 21 | } 22 | 23 | export default SCRTUnwrapWarning 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 SCRT Labs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /public/img/assets/stars.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/pages/staking/components/StakingStats/StakingStats.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import StakingAmount from './StakingAmount' 3 | import AvailableBalance from './AvailableBalance' 4 | import ClaimableRewards from './ClaimableRewards' 5 | import { StakingContext } from 'pages/staking/Staking' 6 | 7 | function StakingStats() { 8 | const { getTotalAmountStaked } = useContext(StakingContext) 9 | 10 | const stakedAmount = getTotalAmountStaked() || null 11 | 12 | return ( 13 |
14 |
15 | {/* Total Staked */} 16 |
17 | 18 |
19 | 20 | {/* Available Balance */} 21 |
22 | 23 |
24 | 25 | {/* Claimable Rewards */} 26 |
27 | 28 |
29 |
30 |
31 | ) 32 | } 33 | 34 | export default StakingStats 35 | -------------------------------------------------------------------------------- /public/img/assets/orai.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/store/UserPreferences.ts: -------------------------------------------------------------------------------- 1 | import { Currency } from 'types/Currency' 2 | import { Theme } from 'types/Theme' 3 | import { create } from 'zustand' 4 | import { persist } from 'zustand/middleware' 5 | 6 | interface UserPreferencesState { 7 | theme: Theme 8 | debugMode: boolean 9 | currency: Currency 10 | } 11 | 12 | interface UserPreferencesActions { 13 | setTheme: (theme: UserPreferencesState['theme']) => void 14 | setDebugMode: (debugMode: boolean) => void 15 | setCurrency: (currency: UserPreferencesState['currency']) => void 16 | } 17 | 18 | type UserPreferencesStore = UserPreferencesState & UserPreferencesActions 19 | 20 | export const useUserPreferencesStore = create()( 21 | persist( 22 | (set, get) => ({ 23 | // Default preferences 24 | theme: 'dark', 25 | debugMode: false, 26 | currency: 'USD', 27 | 28 | // Actions to update preferences 29 | setTheme: (theme: Theme) => set(() => ({ theme })), 30 | setDebugMode: (debugMode: boolean) => set(() => ({ debugMode })), 31 | setCurrency: (currency: Currency) => set(() => ({ currency })) 32 | }), 33 | { 34 | name: 'user-preferences', 35 | getStorage: () => localStorage 36 | } 37 | ) 38 | ) 39 | -------------------------------------------------------------------------------- /src/components/FeeGrant/FeeGrant.tsx: -------------------------------------------------------------------------------- 1 | import { faInfoCircle } from '@fortawesome/free-solid-svg-icons' 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 3 | import Tooltip from '@mui/material/Tooltip' 4 | import ActionableStatus from './components/ActionableStatus' 5 | 6 | export default function FeeGrant() { 7 | return ( 8 |
9 |
10 | 15 | 16 | Fee Grant 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 | 25 |
26 |
27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /src/components/Title.tsx: -------------------------------------------------------------------------------- 1 | import Tooltip from '@mui/material/Tooltip' 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 3 | import { faInfoCircle } from '@fortawesome/free-solid-svg-icons' 4 | 5 | interface IProps { 6 | title: string 7 | tooltip?: string 8 | className?: string 9 | } 10 | 11 | export default function Title(props: IProps) { 12 | function TitleContent() { 13 | return ( 14 |
15 |

{props.title}

16 | {props.tooltip ? ( 17 | 18 | 19 | 20 | ) : null} 21 |
22 | ) 23 | } 24 | 25 | if (props.tooltip) { 26 | return ( 27 | 28 | 29 | 30 | 31 | 32 | ) 33 | } else { 34 | return 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/pages/ibc/components/ibcSchema.ts: -------------------------------------------------------------------------------- 1 | import * as yup from 'yup' 2 | import { isIbcMode } from 'types/IbcMode' 3 | import { chains } from 'utils/config' 4 | 5 | export const ibcSchema = yup.object().shape({ 6 | amount: yup 7 | .number() 8 | .typeError('Please enter a valid amount') 9 | .required('Please enter a valid amount') 10 | .test('min-amount', 'Please enter a valid amount', function (value) { 11 | const { token } = this.parent 12 | if (token && typeof token.decimals === 'number') { 13 | const minAmount = Math.pow(10, -token.decimals) 14 | if (value < minAmount) { 15 | return this.createError({ 16 | message: `Please enter an amount of at least ${minAmount}` 17 | }) 18 | } 19 | } 20 | return true 21 | }), 22 | token: yup.mixed().required('Token is required'), 23 | chain: yup 24 | .mixed() 25 | .required('Please select a chain') 26 | .test('isValidChain', 'Please select a valid chain', (chainValue: any) => 27 | Object.values(chains).some((chain) => chain.chain_name === chainValue.chain_name) 28 | ), 29 | ibcMode: yup 30 | .string() 31 | .required('Please pick an IBC Mode') 32 | .test('isIbcMode', 'Invalid IBC Mode', (value) => isIbcMode(value)) 33 | }) 34 | -------------------------------------------------------------------------------- /src/types/MessageType.ts: -------------------------------------------------------------------------------- 1 | export type MessageType = 2 | | 'MultiSend' 3 | | 'Send' 4 | | 'ExecuteContract' 5 | | 'InstantiateContract' 6 | | 'FundCommunityPool' 7 | | 'SetAutoRestake' 8 | | 'SetWithdrawAddress' 9 | | 'WithdrawDelegatorReward' 10 | | 'WithdrawValidatorCommission' 11 | | 'Deposit' 12 | | 'Vote' 13 | | 'VoteWeighted' 14 | | 'Transfer' 15 | | 'Unjail' 16 | | 'BeginRedelegate' 17 | | 'CreateValidator' 18 | | 'Delegate' 19 | | 'EditValidator' 20 | | 'Undelegate' 21 | | 'CreateVestingAccount' 22 | 23 | export function isMessageType(x: String): boolean { 24 | return ( 25 | x === 'MultiSend' || 26 | x === 'Send' || 27 | x === 'ExecuteContract' || 28 | x === 'InstantiateContract' || 29 | x === 'FundCommunityPool' || 30 | x === 'SetAutoRestake' || 31 | x === 'SetWithdrawAddress' || 32 | x === 'WithdrawDelegatorReward' || 33 | x === 'WithdrawValidatorCommission' || 34 | x === 'Deposit' || 35 | x === 'Vote' || 36 | x === 'VoteWeighted' || 37 | x === 'Transfer' || 38 | x === 'Unjail' || 39 | x === 'BeginRedelegate' || 40 | x === 'CreateValidator' || 41 | x === 'Delegate' || 42 | x === 'EditValidator' || 43 | x === 'Undelegate' || 44 | x === 'CreateVestingAccount' 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /public/img/assets/deposit.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 10 | 15 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /public/img/assets/dydx.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /public/img/assets/eclip.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/img/assets/dot.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /public/img/assets/ntrn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Secret Network Banner](banner.png) 2 | 3 | # Secret Dashboard 4 | 5 | Secret Dashboard is an entry point for new users into Secret Network. Features include a Dashboard UI for Secret Network data, IBC Transfer to and from Secret, a Wrap/Unwrap interface, a list of all active Secret dApps, a link collection to useful secret tools and more. 6 | 7 | ## System Requirements 8 | 9 | - [Node.js 20 LTS](https://nodejs.org/) 10 | 11 | ## Setup 12 | 13 | After verifying the system requirements you should be able to run a few commands to get everything set up: 14 | 15 | ``` 16 | git clone https://github.com/scrtlabs/dash.scrt.network.git 17 | cd dash.scrt.network 18 | npm install 19 | ``` 20 | 21 | ## Running the app 22 | 23 | ### The good ol' classic way 24 | 25 | To get the app up and running, run: 26 | 27 | ``` 28 | npm run start 29 | ``` 30 | 31 | The App runs on port 3000. 32 | 33 | ### Docker 34 | 35 | To get the app up and running inside Docker, run: 36 | 37 | ``` 38 | docker compose up 39 | ``` 40 | 41 | The App runs on port 3000. For further information check the `Dockerfile` and the `docker-compose.yml`. 42 | 43 | ## License 44 | 45 | Developed by [Secret Saturn](https://x.com/Secret_Saturn_) and [Secret Jupiter](https://x.com/secretjupiter_) 46 | 47 | Licensed under the [MIT license](https://github.com/scrtlabs/dash.scrt.network/blob/master/LICENSE.md) 48 | -------------------------------------------------------------------------------- /public/img/assets/cre.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /public/img/assets/ampluna.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 19 | 20 | -------------------------------------------------------------------------------- /public/img/assets/cmdx.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/img/assets/nstk.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/img/assets/silk.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | 16 | 24 | 25 | 29 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /public/img/assets/stjuno.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/scss/components/fonts/_runddisplay.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'RundDisplay'; 3 | font-style: normal; 4 | font-weight: 400; 5 | src: url('/fonts/runddisplay/runddisplay-regular.woff') format('woff'); 6 | } 7 | 8 | @font-face { 9 | font-family: 'RundDisplay'; 10 | font-style: normal; 11 | font-weight: 100; 12 | src: url('/fonts/runddisplay/runddisplay-thin.woff') format('woff'); 13 | } 14 | 15 | @font-face { 16 | font-family: 'RundDisplay'; 17 | font-style: normal; 18 | font-weight: 300; 19 | src: url('/fonts/runddisplay/runddisplay-light.woff') format('woff'); 20 | } 21 | 22 | @font-face { 23 | font-family: 'RundDisplay'; 24 | font-style: normal; 25 | font-weight: 500; 26 | src: url('/fonts/runddisplay/runddisplay-medium.woff') format('woff'); 27 | } 28 | 29 | @font-face { 30 | font-family: 'RundDisplay'; 31 | font-style: normal; 32 | font-weight: 600; 33 | src: url('/fonts/runddisplay/runddisplay-semibold.woff') format('woff'); 34 | } 35 | 36 | @font-face { 37 | font-family: 'RundDisplay'; 38 | font-style: normal; 39 | font-weight: 700; 40 | src: url('/fonts/runddisplay/runddisplay-bold.woff') format('woff'); 41 | } 42 | 43 | @font-face { 44 | font-family: 'RundDisplay'; 45 | font-style: normal; 46 | font-weight: 800; 47 | src: url('/fonts/runddisplay/runddisplay-extrabold.woff') format('woff'); 48 | } 49 | 50 | @font-face { 51 | font-family: 'RundDisplay'; 52 | font-style: normal; 53 | font-weight: 900; 54 | src: url('/fonts/runddisplay/runddisplay-black.woff') format('woff'); 55 | } 56 | -------------------------------------------------------------------------------- /public/img/assets/luna2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/PercentagePicker.tsx: -------------------------------------------------------------------------------- 1 | interface Props { 2 | setAmountByPercentage: (percentage: number) => void 3 | disabled?: boolean 4 | } 5 | 6 | export default function PercentagePicker(props: Props) { 7 | return ( 8 |
9 | 17 | 25 | 33 | 41 |
42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /public/img/assets/wbnb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 8 | 11 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /public/img/assets/juno.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /public/img/assets/harbor.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/components/FloatingCTAButton.scss: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes textFadeIn { 2 | from { 3 | opacity: 0; 4 | -webkit-transform: translate3d(-100%, 0, 0); 5 | transform: translate3d(-100%, 0, 0); 6 | } 7 | 8 | to { 9 | opacity: 1; 10 | -webkit-transform: translate3d(0, 0, 0); 11 | transform: translate3d(0, 0, 0); 12 | } 13 | } 14 | @keyframes textFadeIn { 15 | from { 16 | opacity: 0; 17 | -webkit-transform: translate3d(-100%, 0, 0); 18 | transform: translate3d(-100%, 0, 0); 19 | } 20 | 21 | to { 22 | opacity: 1; 23 | -webkit-transform: translate3d(0, 0, 0); 24 | transform: translate3d(0, 0, 0); 25 | } 26 | } 27 | 28 | .floatingCTAButton { 29 | position: fixed; 30 | bottom: 20px; 31 | right: 20px; 32 | z-index: 40; 33 | overflow: hidden; 34 | color: #fff; 35 | border-radius: 9999px; 36 | display: flex; 37 | flex-direction: row; 38 | align-items: center; 39 | padding: 0.5rem; 40 | 41 | .icon-circle { 42 | width: 1.75rem; 43 | height: 1.75rem; 44 | font-size: 1.5rem; 45 | margin: 0.5rem; 46 | display: inline-block; 47 | z-index: 5000 !important; 48 | transition: padding-right 350ms ease; 49 | flex: 0 1 auto; 50 | } 51 | 52 | .cta-text { 53 | flex: 0 1 auto; 54 | visibility: hidden; 55 | padding: 0; 56 | width: 0; 57 | height: 0; 58 | z-index: 1; 59 | transition: padding 350ms ease-in-out; 60 | } 61 | 62 | &:hover { 63 | .icon-circle { 64 | } 65 | .cta-text { 66 | visibility: visible; 67 | padding: 0 1.25rem 0 0.25rem; 68 | width: inherit; 69 | height: inherit; 70 | 71 | animation: textFadeIn; 72 | animation-duration: 350ms; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /public/img/assets/coreum.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/img/assets/evmos.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/pages/powertools/components/ApiStatusIcon.tsx: -------------------------------------------------------------------------------- 1 | import Tooltip from '@mui/material/Tooltip' 2 | import React from 'react' 3 | import { ApiStatus } from 'types/ApiStatus' 4 | 5 | type Props = { 6 | apiStatus?: ApiStatus 7 | } 8 | 9 | function ApiStatusIcon({ apiStatus = 'loading', ...props }: Props) { 10 | const colorClass: Record = { 11 | online: 'bg-emerald-500', 12 | offline: 'bg-rose-500', 13 | loading: '', 14 | unknown: 'bg-neutral-500' 15 | } 16 | 17 | const tooltipText: Record = { 18 | online: 'Online', 19 | offline: 'Offline', 20 | loading: 'Loading', 21 | unknown: 'Unknown' 22 | } 23 | 24 | return ( 25 | <> 26 | 27 | 28 | {apiStatus === 'loading' ? ( 29 | 30 | 36 | 37 | 42 | 43 | 44 | ) : ( 45 | 46 | )} 47 | 48 | 49 | 50 | ) 51 | } 52 | 53 | export default ApiStatusIcon 54 | -------------------------------------------------------------------------------- /public/img/assets/pstake.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/pages/staking/components/NoScrtWarning.tsx: -------------------------------------------------------------------------------- 1 | import { faArrowUpRightFromSquare, faInfoCircle } from '@fortawesome/free-solid-svg-icons' 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 3 | 4 | function NoScrtWarning() { 5 | return ( 6 | <> 7 |
8 |
9 |
10 | 11 |
12 |
13 | {`You do not have any SCRT for Staking`} 14 |
15 | 34 |
35 |
36 |
37 |
38 | 39 | ) 40 | } 41 | 42 | export default NoScrtWarning 43 | -------------------------------------------------------------------------------- /public/img/assets/usk.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/img/assets/pica.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/pages/dashboard/components/CurrentPrice.tsx: -------------------------------------------------------------------------------- 1 | import { faArrowUpRightFromSquare } from '@fortawesome/free-solid-svg-icons' 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 3 | import { toCurrencyString, trackMixPanelEvent } from 'utils/commons' 4 | import { Link } from 'react-router-dom' 5 | import { useUserPreferencesStore } from 'store/UserPreferences' 6 | 7 | interface Props { 8 | price?: number 9 | } 10 | 11 | export default function CurrentPrice(props: Props) { 12 | const { currency } = useUserPreferencesStore() 13 | return ( 14 |
15 |
16 |
17 |
Current Price
18 |
19 | {props.price ? ( 20 | <>{toCurrencyString(props.price, currency)} 21 | ) : ( 22 |
23 | )} 24 |
25 |
26 |
27 |
28 | { 32 | trackMixPanelEvent('Clicked buy SCRT on current price') 33 | }} 34 | > 35 | Get SCRT 36 | 37 | 38 |
39 |
40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /src/pages/bridge/SwingModal.tsx: -------------------------------------------------------------------------------- 1 | import { faXmark } from '@fortawesome/free-solid-svg-icons' 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 3 | import { Theme } from 'types/Theme' 4 | import { Swap } from '@swing.xyz/ui' 5 | import { useEffect } from 'react' 6 | 7 | interface Props { 8 | open: boolean 9 | onClose: any 10 | theme: Theme 11 | secretAddress: string 12 | } 13 | 14 | const SwingModal = (props: Props) => { 15 | if (!props.open) return null 16 | 17 | useEffect(() => { 18 | if (props.theme === 'light') { 19 | import('./SwingModal_Light.scss') 20 | } else { 21 | import('./SwingModal_Dark.scss') 22 | } 23 | }, [props.theme]) 24 | return ( 25 | <> 26 | {/* Outer */} 27 |
31 | {/* Inner */} 32 |
33 |
34 |
{ 37 | e.stopPropagation() 38 | }} 39 | > 40 | {/* Close Button */} 41 | 47 | 48 |
49 |
50 |
51 |
52 | 53 | ) 54 | } 55 | 56 | export default SwingModal 57 | -------------------------------------------------------------------------------- /public/img/assets/mnta.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /public/img/assets/rowan.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/pages/apps/components/tile/AppTile.tsx: -------------------------------------------------------------------------------- 1 | import Tag from './Tag' 2 | import mixpanel from 'mixpanel-browser' 3 | 4 | interface Props { 5 | name: string 6 | description: string 7 | image?: string 8 | tags?: string[] 9 | url?: string 10 | } 11 | 12 | const AppTile = (props: Props) => { 13 | const handleClick = () => { 14 | if (import.meta.env.VITE_MIXPANEL_ENABLED === 'true') { 15 | mixpanel.init(import.meta.env.VITE_MIXPANEL_PROJECT_TOKEN, { 16 | debug: false 17 | }) 18 | mixpanel.identify('Dashboard-App') 19 | mixpanel.track('dApp opened', { 20 | 'dApp name': props.name 21 | }) 22 | } 23 | } 24 | 25 | return ( 26 | 32 |
33 | {/* Image */} 34 | {props.image && ( 35 |
36 | {`${props.name} 41 |
42 | )} 43 | {/* Name */} 44 |
{props.name}
45 | 46 | {/* Description */} 47 |
{props.description}
48 | 49 | {/* Tags */} 50 | {props.tags?.length! > 0 && ( 51 |
52 | {props.tags?.map((tag) => )} 53 |
54 | )} 55 |
56 |
57 | ) 58 | } 59 | 60 | export default AppTile 61 | -------------------------------------------------------------------------------- /public/img/assets/stinj.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /public/img/assets/inj.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/pages/staking/components/ClaimRewardsModal.tsx: -------------------------------------------------------------------------------- 1 | import { useContext, useState } from 'react' 2 | import { StakingContext } from 'pages/staking/Staking' 3 | import FeeGrant from '../../../components/FeeGrant/FeeGrant' 4 | import { useSecretNetworkClientStore } from 'store/secretNetworkClient' 5 | import Modal from 'components/UI/Modal/Modal' 6 | import { StakingService } from 'services/staking.service' 7 | import Button from 'components/UI/Button/Button' 8 | import { tokens } from 'utils/config' 9 | 10 | interface Props { 11 | open: boolean 12 | onClose: any 13 | } 14 | 15 | export default function ClaimRewardsModal(props: Props) { 16 | const { secretNetworkClient, feeGrantStatus } = useSecretNetworkClientStore() 17 | 18 | const { delegatorDelegations, totalPendingRewards } = useContext(StakingContext) 19 | 20 | if (!props.open) return null 21 | 22 | async function handleClaimRewards() { 23 | await StakingService.performClaimStakingRewards({ 24 | delegatorDelegations: delegatorDelegations, 25 | secretNetworkClient: secretNetworkClient, 26 | feeGrantStatus: feeGrantStatus 27 | }) 28 | } 29 | 30 | return ( 31 | <> 32 | 38 | {/* Body */} 39 |
40 |
41 |
Claimable Amount
42 |
43 | {totalPendingRewards} 44 | {` SCRT`} 45 |
46 |
47 |
48 | 49 |
50 | 53 |
54 |
55 | 56 | ) 57 | } 58 | function getBalance(arg0: any, arg1: boolean) { 59 | throw new Error('Function not implemented.') 60 | } 61 | -------------------------------------------------------------------------------- /src/pages/dashboard/components/PriceVolTVLChart/components/TypeSwitch.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import { PriceVolumeHistoryContext } from '../PriceVolumeTVL' 3 | 4 | function TypeSwitch() { 5 | const { chartType, setChartType } = useContext(PriceVolumeHistoryContext) 6 | 7 | return ( 8 | <> 9 |
10 | 22 | 34 | 46 |
47 | 48 | ) 49 | } 50 | 51 | export default TypeSwitch 52 | -------------------------------------------------------------------------------- /src/components/Wallet/ManageBalances/ManageBalances.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import { Token } from 'utils/config' 3 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 4 | import { faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons' 5 | import './Balances.scss' 6 | import { SendService } from 'services/send.service' 7 | import BalanceItem from 'pages/portfolio/components/BalanceItem' 8 | 9 | export const ManageBalances = () => { 10 | const [searchQuery, setSearchQuery] = useState('') 11 | 12 | const tokens = SendService.getSupportedTokens() 13 | 14 | const displayedAssets = tokens.filter( 15 | (token: Token) => 16 | token.name?.toLowerCase().includes(searchQuery?.toLowerCase()) || 17 | ('s' + token.name)?.toLowerCase().includes(searchQuery?.toLowerCase()) || 18 | token.description?.toLowerCase().includes(searchQuery?.toLowerCase()) 19 | ) 20 | 21 | return ( 22 | <> 23 | {/* All Balances */} 24 |
25 | {/* Search */} 26 |
27 |
28 |
29 | 30 |
31 | setSearchQuery(e.target.value)} 34 | type="text" 35 | id="search" 36 | className="block w-full sm:w-72 p-2.5 pl-10 text-sm rounded-lg text-neutral-800 dark:text-white bg-white dark:bg-neutral-800 placeholder-neutral-600 dark:placeholder-neutral-400 border border-neutral-300 dark:border-neutral-700 focus:outline-none focus:ring-2 focus:ring-cyan-500 dark:focus:ring-cyan-500" 37 | placeholder="Search Asset" 38 | /> 39 |
40 |
41 |
42 | 43 |
44 | {tokens 45 | ? displayedAssets.map((token: Token, i: number) => ) 46 | : [...Array(10)].map((_, index) => )} 47 |
48 | 49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /public/img/assets/cmst.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/components/UI/Badge/Badge.tsx: -------------------------------------------------------------------------------- 1 | type Color = 'primary' | 'dark' | 'red' | 'green' | 'yellow' | 'indigo' | 'purple' | 'pink' 2 | 3 | type Size = 'default' | 'large' 4 | 5 | type Props = { 6 | color?: Color 7 | size?: Size 8 | bordered?: boolean 9 | pill?: boolean 10 | children: React.ReactNode 11 | } 12 | 13 | const colorClasses: Record = { 14 | primary: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300', 15 | dark: 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300', 16 | red: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300', 17 | green: 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300', 18 | yellow: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300', 19 | indigo: 'bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-300"', 20 | purple: 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300', 21 | pink: 'bg-pink-100 text-pink-800 dark:bg-pink-900 dark:text-pink-300' 22 | } 23 | 24 | const borderClasses: Record = { 25 | primary: 'border border-blue-400 dark:bg-gray-700 dark:text-blue-400', 26 | dark: 'border border-dark-500 dark:bg-gray-700 dark:text-gray-400', 27 | red: 'border border-red-400 dark:bg-gray-700 dark:text-red-400', 28 | green: 'border border-green-400 dark:bg-gray-700 dark:text-green-400', 29 | yellow: 'border border-yellow-300 dark:bg-gray-700 dark:text-yellow-300', 30 | indigo: 'border border-indigo-400 dark:bg-gray-700 dark:text-indigo-400', 31 | purple: 'border border-purple-400 dark:bg-gray-700 dark:text-purple-400', 32 | pink: 'border border-pink-400 dark:bg-gray-700 dark:text-pink-400' 33 | } 34 | 35 | const sizeClasses: Record = { 36 | default: 'text-xs', 37 | large: 'text-sm' 38 | } 39 | 40 | function Badge(props: Props) { 41 | return ( 42 | 51 | {props.children} 52 | 53 | ) 54 | } 55 | 56 | export default Badge 57 | -------------------------------------------------------------------------------- /src/pages/send/Send.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { sendPageTitle, sendPageDescription, sendJsonLdSchema } from 'utils/commons' 3 | import Title from 'components/Title' 4 | import { Helmet } from 'react-helmet-async' 5 | import mixpanel from 'mixpanel-browser' 6 | import { useSecretNetworkClientStore } from 'store/secretNetworkClient' 7 | import SendForm from './components/SendForm' 8 | 9 | export function Send() { 10 | const { isConnected, setIsConnectWalletModalOpen, setIsGetWalletModalOpen } = useSecretNetworkClientStore() 11 | 12 | useEffect(() => { 13 | if (import.meta.env.VITE_MIXPANEL_ENABLED === 'true') { 14 | mixpanel.init(import.meta.env.VITE_MIXPANEL_PROJECT_TOKEN, { 15 | debug: false 16 | }) 17 | mixpanel.identify('Dashboard-App') 18 | mixpanel.track('Open Wrap Tab') 19 | } 20 | }, []) 21 | 22 | return ( 23 | <> 24 | 25 | {sendPageTitle} 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | {/* */} 38 | 39 | 40 | 41 | {/* */} 42 | 43 | 44 | 45 | 46 |
47 | {/* Title*/} 48 | 49 | {/* Content */} 50 | <div className="rounded-3xl px-6 py-6 bg-white border border-neutral-200 dark:border-neutral-700 dark:bg-neutral-800"> 51 | <SendForm /> 52 | </div> 53 | </div> 54 | </> 55 | ) 56 | } 57 | -------------------------------------------------------------------------------- /public/img/assets/axl.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <svg id="b" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" width="38" height="38" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 38 38"> 3 | <defs> 4 | <filter id="d" data-name="drop-shadow-1" filterUnits="userSpaceOnUse"> 5 | <feOffset dx="0" dy="0"/> 6 | <feGaussianBlur result="e" stdDeviation=".256"/> 7 | <feFlood flood-color="#000" flood-opacity=".13"/> 8 | <feComposite in2="e" operator="in"/> 9 | <feComposite in="SourceGraphic"/> 10 | </filter> 11 | <filter id="f" data-name="drop-shadow-2" filterUnits="userSpaceOnUse"> 12 | <feOffset dx="0" dy="0"/> 13 | <feGaussianBlur result="g" stdDeviation=".256"/> 14 | <feFlood flood-color="#000" flood-opacity=".13"/> 15 | <feComposite in2="g" operator="in"/> 16 | <feComposite in="SourceGraphic"/> 17 | </filter> 18 | <filter id="h" data-name="drop-shadow-3" filterUnits="userSpaceOnUse"> 19 | <feOffset dx="0" dy="0"/> 20 | <feGaussianBlur result="i" stdDeviation=".256"/> 21 | <feFlood flood-color="#000" flood-opacity=".13"/> 22 | <feComposite in2="i" operator="in"/> 23 | <feComposite in="SourceGraphic"/> 24 | </filter> 25 | <filter id="j" data-name="drop-shadow-4" filterUnits="userSpaceOnUse"> 26 | <feOffset dx="0" dy="0"/> 27 | <feGaussianBlur result="k" stdDeviation=".256"/> 28 | <feFlood flood-color="#000" flood-opacity=".13"/> 29 | <feComposite in2="k" operator="in"/> 30 | <feComposite in="SourceGraphic"/> 31 | </filter> 32 | </defs> 33 | <g id="c" data-name="Layer 1"> 34 | <g> 35 | <circle cx="19" cy="19" r="19"/> 36 | <g> 37 | <path d="M20.412,17.093l7.415-7.374-2.813-2.798-6.009,5.976-6.009-5.976-2.813,2.798,7.415,7.374c.388,.386,.898,.579,1.406,.579s1.018-.193,1.406-.579Z" fill="#fff" filter="url(#d)"/> 38 | <path d="M31.146,24.97l-6.009-5.976,6.009-5.976-2.813-2.798-7.415,7.374c-.777,.773-.777,2.025,0,2.798l7.415,7.374,2.813-2.798h0Z" fill="#fff" filter="url(#f)"/> 39 | <path d="M18.995,25.104l6.009,5.976,2.813-2.798-7.415-7.374c-.777-.772-2.036-.772-2.813,0l-7.415,7.374,2.813,2.798,6.009-5.976h0Z" fill="#fff" filter="url(#h)"/> 40 | <path d="M17.082,20.404c.373-.371,.583-.874,.583-1.399s-.209-1.028-.583-1.399l-7.415-7.374-2.813,2.798,6.009,5.976-6.009,5.976,2.813,2.798,7.415-7.374h0Z" fill="#fff" filter="url(#j)"/> 41 | </g> 42 | </g> 43 | </g> 44 | </svg> -------------------------------------------------------------------------------- /public/img/assets/usdc.svg: -------------------------------------------------------------------------------- 1 | <svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <g clip-path="url(#clip0_438_1084)"> 3 | <path d="M14.8247 30C23.04 30 29.6493 23.3125 29.6493 15C29.6493 6.68745 23.04 0 14.8247 0C6.60928 0 0 6.68745 0 15C0 23.3125 6.60928 30 14.8247 30Z" fill="#2775CA"/> 4 | <path d="M18.9016 17.3749C18.9016 15.1875 17.6044 14.4375 15.0101 14.125C13.157 13.875 12.7864 13.375 12.7864 12.4999C12.7864 11.6248 13.4041 11.0625 14.6395 11.0625C15.7513 11.0625 16.3691 11.4375 16.6779 12.375C16.7397 12.5625 16.925 12.6874 17.1103 12.6874H18.0985C18.3456 12.6874 18.531 12.4999 18.531 12.25V12.1875C18.2838 10.8124 17.172 9.74999 15.7513 9.62504V8.12504C15.7513 7.87499 15.566 7.68749 15.2572 7.62494H14.3307C14.0836 7.62494 13.8982 7.81244 13.8364 8.12504V9.56249C11.9833 9.81254 10.8098 11.0625 10.8098 12.625C10.8098 14.6875 12.0452 15.4999 14.6395 15.8125C16.3691 16.125 16.925 16.5 16.925 17.5C16.925 18.5001 16.0601 19.1875 14.8866 19.1875C13.2805 19.1875 12.7246 18.4999 12.5393 17.5624C12.4776 17.3125 12.2923 17.1874 12.107 17.1874H11.0568C10.8098 17.1874 10.6245 17.3749 10.6245 17.625V17.6875C10.8715 19.2499 11.8599 20.3749 13.8982 20.6875V22.1875C13.8982 22.4374 14.0836 22.6249 14.3923 22.6875H15.3189C15.566 22.6875 15.7513 22.5 15.8131 22.1875V20.6875C17.6662 20.3749 18.9016 19.0624 18.9016 17.3749Z" fill="white"/> 5 | <path d="M11.6744 23.9375C6.85643 22.1876 4.3856 16.7501 6.17701 11.9375C7.10355 9.31246 9.14194 7.31251 11.6744 6.37501C11.9216 6.25006 12.0451 6.06256 12.0451 5.74996V4.87501C12.0451 4.62496 11.9216 4.43746 11.6744 4.37506C11.6126 4.37506 11.4891 4.37506 11.4273 4.43746C5.55927 6.31246 2.34721 12.6251 4.20029 18.5625C5.31214 22.0625 7.96828 24.75 11.4273 25.875C11.6744 26 11.9216 25.875 11.9832 25.625C12.0451 25.5626 12.0451 25.5 12.0451 25.3751V24.5C12.0451 24.3125 11.8597 24.0626 11.6744 23.9375ZM18.2221 4.43746C17.9749 4.31251 17.7278 4.43746 17.6661 4.68751C17.6043 4.75006 17.6043 4.81246 17.6043 4.93756V5.81251C17.6043 6.06256 17.7896 6.31246 17.9749 6.43756C22.7929 8.18746 25.2638 13.625 23.4724 18.4376C22.5458 21.0626 20.5074 23.0625 17.9749 24C17.7278 24.125 17.6043 24.3125 17.6043 24.6251V25.5C17.6043 25.7501 17.7278 25.9376 17.9749 26C18.0367 26 18.1602 26 18.2221 25.9376C24.0901 24.0626 27.3022 17.75 25.4491 11.8125C24.3372 8.25001 21.6193 5.56246 18.2221 4.43746Z" fill="white"/> 6 | </g> 7 | <defs> 8 | <clipPath id="clip0_438_1084"> 9 | <rect width="29.6493" height="30" fill="white"/> 10 | </clipPath> 11 | </defs> 12 | </svg> 13 | -------------------------------------------------------------------------------- /src/pages/staking/components/StakingStats/StakingAmount.tsx: -------------------------------------------------------------------------------- 1 | import BigNumber from 'bignumber.js' 2 | import { APIContext } from 'context/APIContext' 3 | import { StakingContext } from 'pages/staking/Staking' 4 | import { useContext, useEffect, useState } from 'react' 5 | import { useTokenPricesStore } from 'store/TokenPrices' 6 | import { useUserPreferencesStore } from 'store/UserPreferences' 7 | import { Nullable } from 'types/Nullable' 8 | import { toCurrencyString } from 'utils/commons' 9 | import { scrtToken } from 'utils/tokens' 10 | 11 | type Props = { 12 | stakedAmount?: Nullable<number> 13 | } 14 | 15 | function StakingAmount(props: Props) { 16 | const { convertCurrency } = useContext(APIContext) 17 | const { getValuePrice, priceMapping } = useTokenPricesStore() 18 | const { currency } = useUserPreferencesStore() 19 | const [stakedAmountInCurrency, setStakedAmountInCurrency] = useState<string>('') 20 | 21 | useEffect(() => { 22 | if (priceMapping !== null && props.stakedAmount !== null) { 23 | const valuePrice = getValuePrice(scrtToken, BigNumber(props.stakedAmount).multipliedBy(`1e${scrtToken.decimals}`)) 24 | if (valuePrice) { 25 | const priceInCurrency = convertCurrency('USD', valuePrice, currency) 26 | if (priceInCurrency !== null) { 27 | setStakedAmountInCurrency(toCurrencyString(priceInCurrency, currency)) 28 | } 29 | } 30 | } 31 | }, [priceMapping, props.stakedAmount]) 32 | 33 | return ( 34 | <div className="flex-1"> 35 | <div className="font-bold mb-2">Total Staked</div> 36 | <div className="mb-1"> 37 | {props.stakedAmount !== null ? ( 38 | <> 39 | <span className="font-medium font-mono">{props.stakedAmount}</span> 40 | <span className="text-xs font-semibold text-neutral-400"> SCRT</span> 41 | </> 42 | ) : ( 43 | <div className="animate-pulse inline-block"> 44 | <div className="h-5 w-12 bg-white dark:bg-neutral-700 rounded-xl"></div> 45 | </div> 46 | )} 47 | </div> 48 | <div className="text-xs text-neutral-400 font-medium font-mono"> 49 | {stakedAmountInCurrency ? ( 50 | <>{stakedAmountInCurrency}</> 51 | ) : ( 52 | <div className="animate-pulse inline-block"> 53 | <div className="h-5 w-12 bg-white dark:bg-neutral-700 rounded-xl"></div> 54 | </div> 55 | )} 56 | </div> 57 | </div> 58 | ) 59 | } 60 | 61 | export default StakingAmount 62 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "secret_dashboard", 3 | "description": "An entry point for new users into Secret Network", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "start": "vite --host", 7 | "dev": "vite --host", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview", 10 | "prepare": "husky install" 11 | }, 12 | "dependencies": { 13 | "@axelar-network/axelarjs-sdk": "^0.17.2", 14 | "@buf/evmos_evmos.bufbuild_es": "^2.2.3-20240408103001-f65bdd0ffeff.1", 15 | "@cosmjs/stargate": "^0.33.0", 16 | "@emotion/styled": "^11.14.0", 17 | "@evmos/proto": "^0.2.1", 18 | "@evmos/transactions": "^0.3.2", 19 | "@floating-ui/react": "^0.27.5", 20 | "@fortawesome/free-brands-svg-icons": "^6.7.2", 21 | "@fortawesome/free-solid-svg-icons": "^6.7.2", 22 | "@fortawesome/react-fontawesome": "^0.2.2", 23 | "@mui/material": "5.16.7", 24 | "@shadeprotocol/shadejs": "^1.7.0", 25 | "@skip-go/client": "^0.16.17", 26 | "@swing.xyz/ui": "^0.67.5", 27 | "@vitejs/plugin-react": "^4.3.4", 28 | "autoprefixer": "^10.4.21", 29 | "bignumber.js": "^9.1.2", 30 | "chart.js": "^4.4.8", 31 | "formik": "^2.4.6", 32 | "long": "^5.3.1", 33 | "mixpanel-browser": "^2.61.1", 34 | "query-string": "^9.1.1", 35 | "react": "18.3.1", 36 | "react-chartjs-2": "^5.3.0", 37 | "react-copy-to-clipboard": "5.1.0", 38 | "react-dom": "18.3.1", 39 | "react-helmet-async": "^1.3.0", 40 | "react-hot-toast": "^2.5.1", 41 | "react-qrcode-logo": "^3.0.0", 42 | "react-router-dom": "^6.28.1", 43 | "react-select": "^5.9.0", 44 | "secretjs": "1.21.2", 45 | "tailwindcss": "^3.4.17", 46 | "vite": "5.4.19", 47 | "vite-tsconfig-paths": "^4.3.2", 48 | "yup": "^1.4.0", 49 | "zustand": "^4.4.6" 50 | }, 51 | "devDependencies": { 52 | "@keplr-wallet/types": "^0.12.196", 53 | "@types/mixpanel-browser": "^2.51.0", 54 | "@types/react": "^18.3.18", 55 | "@types/react-copy-to-clipboard": "5.0.7", 56 | "@types/react-dom": "^18.3.5", 57 | "husky": "^9.1.7", 58 | "lint-staged": "^15.4.3", 59 | "prettier": "3.5.3", 60 | "typescript": "^5.6.3" 61 | }, 62 | "overrides": { 63 | "protobufjs": "^7.4.0", 64 | "elliptic": "6.6.1", 65 | "axios": "1.8.2", 66 | "esbuild": "0.25.1", 67 | "ws": "8.18.1", 68 | "secretjs": "1.21.2", 69 | "@babel/runtime": "7.26.10", 70 | "vite": "5.4.19" 71 | }, 72 | "private": true, 73 | "lint-staged": { 74 | "**/*": "prettier --write --ignore-unknown" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | <svg width="310" height="310" viewBox="0 0 310 310" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path 3 | d="M308.156 94.509C308.156 89.712 305.689 85.382 301.568 82.926L169.465 4.246C164.719 1.415 159.399 0 154.078 0C148.757 0 143.436 1.415 138.69 4.246L6.58798 82.927C2.51398 85.355 0.0669823 89.613 0.000982336 94.345C0.00298234 100.13 0.00598234 109.594 0.00698234 115.38C-0.158018 120.362 2.33298 124.894 6.58698 127.429L53.027 155.098C53.405 155.323 53.595 155.709 53.597 156.096C53.599 156.486 53.409 156.877 53.027 157.104L6.58698 184.763C2.47398 187.216 0.00798234 191.535 -1.76638e-05 196.323C-1.76638e-05 202.195 -1.76638e-05 211.802 -1.76638e-05 217.674C-1.76638e-05 222.482 2.46698 226.811 6.58798 229.257L138.69 307.948C143.436 310.779 148.754 312.194 154.083 312.194C159.412 312.194 164.719 310.779 169.465 307.948L301.567 229.257C305.688 226.811 308.155 222.482 308.155 217.674C308.155 211.802 308.155 202.195 308.155 196.323C308.147 191.535 305.681 187.216 301.567 184.764L255.127 157.105C254.747 156.879 254.557 156.49 254.557 156.102C254.557 155.714 254.747 155.325 255.127 155.099L301.567 127.43C305.688 124.974 308.155 120.645 308.155 115.847V94.51L308.156 94.509ZM144.935 137.889C147.755 136.214 150.919 135.37 154.083 135.37C157.247 135.37 160.4 136.213 163.221 137.889L193.788 156.102L163.221 174.305C157.58 177.667 150.576 177.667 144.935 174.305L114.368 156.102L144.935 137.889ZM277.58 206.012C278.34 206.465 278.34 207.566 277.58 208.019L163.221 276.132C160.401 277.813 157.239 278.653 154.078 278.653C150.917 278.653 147.755 277.813 144.935 276.132L30.575 208.018C29.815 207.565 29.815 206.464 30.575 206.012L52.006 193.243C56.194 190.747 58.76 186.232 58.76 181.356V161.278C58.76 160.096 60.047 159.364 61.063 159.968L138.69 206.119C143.436 208.939 148.754 210.355 154.083 210.355C159.412 210.355 164.719 208.939 169.465 206.119L192.116 192.624C196.33 190.113 198.9 185.559 198.871 180.654L198.758 161.756C198.751 160.57 200.042 159.83 201.062 160.438L277.58 206.012ZM249.145 150.749C249.145 151.931 247.858 152.663 246.842 152.059L169.465 106.073C159.973 100.422 148.182 100.422 138.69 106.073L115.894 119.651C111.679 122.162 109.109 126.716 109.138 131.622L109.255 150.963C109.26 151.872 108.271 152.438 107.49 151.973L30.576 106.181C29.816 105.728 29.815 104.627 30.576 104.174L144.935 36.061C147.755 34.375 150.919 33.532 154.083 33.532C157.247 33.532 160.4 34.375 163.221 36.061L277.58 104.174C278.34 104.627 278.34 105.728 277.58 106.181L255.9 119.096C251.711 121.591 249.145 126.107 249.145 130.983V150.749Z" 4 | fill="#FF3912" 5 | /> 6 | </svg> 7 | -------------------------------------------------------------------------------- /src/pages/staking/components/StakingStats/AvailableBalance.tsx: -------------------------------------------------------------------------------- 1 | import BigNumber from 'bignumber.js' 2 | import { APIContext } from 'context/APIContext' 3 | import { useContext, useEffect, useState } from 'react' 4 | import { useTokenPricesStore } from 'store/TokenPrices' 5 | import { useUserPreferencesStore } from 'store/UserPreferences' 6 | import { useSecretNetworkClientStore } from 'store/secretNetworkClient' 7 | import { toCurrencyString } from 'utils/commons' 8 | import { tokens } from 'utils/config' 9 | import { scrtToken } from 'utils/tokens' 10 | 11 | function AvailableBalance() { 12 | const { getBalance } = useSecretNetworkClientStore() 13 | 14 | const scrtBalance = getBalance( 15 | tokens.find((token) => token.name === 'SCRT'), 16 | false 17 | ) 18 | 19 | const { currency } = useUserPreferencesStore() 20 | const { convertCurrency } = useContext(APIContext) 21 | 22 | const { getValuePrice, priceMapping } = useTokenPricesStore() 23 | 24 | const [availableBalanceInCurrency, setAvailableBalanceInCurrency] = useState<string>('') 25 | 26 | useEffect(() => { 27 | if (priceMapping !== null && scrtBalance !== null) { 28 | const valuePrice = getValuePrice(scrtToken, BigNumber(scrtBalance)) 29 | if (valuePrice) { 30 | const priceInCurrency = convertCurrency('USD', valuePrice, currency) 31 | if (priceInCurrency !== null) { 32 | setAvailableBalanceInCurrency(toCurrencyString(priceInCurrency, currency)) 33 | } 34 | } 35 | } 36 | }, [priceMapping, scrtBalance]) 37 | 38 | return ( 39 | <div className="flex-1"> 40 | <div className="font-bold mb-2">Available Balance</div> 41 | <div className="mb-1"> 42 | <span className="font-medium font-mono"> 43 | {scrtBalance !== null ? ( 44 | <>{new BigNumber(scrtBalance).dividedBy(`1e${scrtToken.decimals}`).toNumber()}</> 45 | ) : ( 46 | <div className="animate-pulse inline-block"> 47 | <div className="h-5 w-24 bg-white dark:bg-neutral-700 rounded-xl"></div> 48 | </div> 49 | )} 50 | </span> 51 | <span className="text-xs font-semibold text-neutral-400"> SCRT</span> 52 | </div> 53 | <div className="text-xs text-neutral-400 font-medium font-mono"> 54 | {availableBalanceInCurrency ? ( 55 | <>{availableBalanceInCurrency}</> 56 | ) : ( 57 | <div className="animate-pulse inline-block"> 58 | <div className="h-5 w-12 bg-white dark:bg-neutral-700 rounded-xl"></div> 59 | </div> 60 | )} 61 | </div> 62 | </div> 63 | ) 64 | } 65 | 66 | export default AvailableBalance 67 | -------------------------------------------------------------------------------- /src/components/UI/Button/Button.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | type Type = 'button' | 'submit' | 'reset' 4 | type Size = 'default' | 'large' | 'small' 5 | type Color = 'primary' | 'secondary' | 'red' | 'blue' | 'emerald' | 'yellow' 6 | 7 | const colorClasses: Record<Color, string> = { 8 | primary: 9 | 'enabled:bg-sky-500 dark:enabled:bg-sky-600 enabled:hover:bg-sky-600 dark:enabled:hover:bg-sky-700 enabled:text-white disabled:bg-neutral-600 disabled:text-neutral-400 enabled:ring-sky-500/40 dark:enabled:ring-sky-600/40', 10 | secondary: 11 | 'enabled:bg-gray-500 dark:enabled:bg-gray-600 enabled:hover:bg-gray-600 dark:enabled:hover:bg-gray-700 enabled:text-white disabled:bg-neutral-600 disabled:text-neutral-400 enabled:ring-gray-500/40 dark:enabled:ring-gray-600/40', 12 | red: 'enabled:bg-red-500 dark:enabled:bg-red-600 enabled:hover:bg-red-600 dark:enabled:hover:bg-red-700 enabled:text-white disabled:bg-neutral-600 disabled:text-neutral-400 enabled:ring-red-500/40 dark:enabled:ring-red-600/40', 13 | blue: 'enabled:bg-blue-500 dark:enabled:bg-blue-600 enabled:hover:bg-blue-600 dark:enabled:hover:bg-blue-700 enabled:text-white disabled:bg-neutral-600 disabled:text-neutral-400 enabled:ring-blue-500/40 dark:enabled:ring-blue-600/40', 14 | emerald: 15 | 'enabled:bg-emerald-500 dark:enabled:bg-emerald-600 enabled:hover:bg-emerald-600 dark:enabled:hover:bg-emerald-700 enabled:text-white disabled:bg-neutral-600 disabled:text-neutral-400 enabled:ring-emerald-500/40 dark:enabled:ring-emerald-600/40', 16 | yellow: 17 | 'enabled:bg-yellow-500 dark:enabled:bg-yellow-600 enabled:hover:bg-yellow-600 dark:enabled:hover:bg-yellow-700 enabled:text-black disabled:bg-neutral-600 disabled:text-neutral-400 enabled:ring-yellow-500/40 dark:enabled:ring-yellow-600/40' 18 | } 19 | 20 | const sizeClasses: Record<Size, string> = { 21 | default: 'py-2 px-4 text-sm', 22 | large: 'py-3 px-4 text-sm', 23 | small: 'py-1.5 px-2 text-xs' 24 | } 25 | 26 | interface Props { 27 | children?: React.ReactNode 28 | type?: Type 29 | onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void 30 | color?: Color 31 | size?: Size 32 | disabled?: boolean 33 | className?: string 34 | } 35 | 36 | export default function Button(props: Props) { 37 | return ( 38 | <button 39 | disabled={props.disabled || false} 40 | className={`focus:outline-none focus-visible:ring-4 text-center font-bold rounded transition-colors 41 | ${colorClasses[props.color || 'primary']} 42 | ${sizeClasses[props.size || 'default']} 43 | ${props.className || ''} 44 | `} 45 | type={props.type || 'button'} 46 | onClick={props.onClick} 47 | > 48 | <>{props.children}</> 49 | </button> 50 | ) 51 | } 52 | -------------------------------------------------------------------------------- /public/img/assets/adai.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 3 | <!-- Creator: CorelDRAW 2019 (64-Bit) --> 4 | <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="100%" height="100%" version="1.1" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd" 5 | viewBox="0 0 444.44 444.44" 6 | xmlns:xlink="http://www.w3.org/1999/xlink" 7 | xmlns:xodm="http://www.corel.com/coreldraw/odm/2003"> 8 | <g id="Layer_x0020_1"> 9 | <metadata id="CorelCorpID_0Corel-Layer"/> 10 | <path fill="#F5AC37" fill-rule="nonzero" d="M222.22 0c122.74,0 222.22,99.5 222.22,222.22 0,122.74 -99.48,222.22 -222.22,222.22 -122.72,0 -222.22,-99.49 -222.22,-222.22 0,-122.72 99.5,-222.22 222.22,-222.22z"/> 11 | <path fill="#FEFEFD" fill-rule="nonzero" d="M230.41 237.91l84.44 0c1.8,0 2.65,0 2.78,-2.36 0.69,-8.59 0.69,-17.23 0,-25.83 0,-1.67 -0.83,-2.36 -2.64,-2.36l-168.05 0c-2.08,0 -2.64,0.69 -2.64,2.64l0 24.72c0,3.19 0,3.19 3.33,3.19l82.78 0zm77.79 -59.44c0.24,-0.63 0.24,-1.32 0,-1.94 -1.41,-3.07 -3.08,-6 -5.02,-8.75 -2.92,-4.7 -6.36,-9.03 -10.28,-12.92 -1.85,-2.35 -3.99,-4.46 -6.39,-6.25 -12.02,-10.23 -26.31,-17.47 -41.67,-21.11 -7.75,-1.74 -15.67,-2.57 -23.61,-2.5l-74.58 0c-2.08,0 -2.36,0.83 -2.36,2.64l0 49.3c0,2.08 0,2.64 2.64,2.64l160.27 0c0,0 1.39,-0.28 1.67,-1.11l-0.68 0zm0 88.33c-2.36,-0.26 -4.74,-0.26 -7.1,0l-154.02 0c-2.08,0 -2.78,0 -2.78,2.78l0 48.2c0,2.22 0,2.78 2.78,2.78l71.11 0c3.4,0.26 6.8,0.02 10.13,-0.69 10.32,-0.74 20.47,-2.98 30.15,-6.67 3.52,-1.22 6.92,-2.81 10.13,-4.72l0.97 0c16.67,-8.67 30.21,-22.29 38.75,-39.01 0,0 0.97,-2.1 -0.12,-2.65zm-191.81 78.75l0 -0.83 0 -32.36 0 -10.97 0 -32.64c0,-1.81 0,-2.08 -2.22,-2.08l-30.14 0c-1.67,0 -2.36,0 -2.36,-2.22l0 -26.39 32.22 0c1.8,0 2.5,0 2.5,-2.36l0 -26.11c0,-1.67 0,-2.08 -2.22,-2.08l-30.14 0c-1.67,0 -2.36,0 -2.36,-2.22l0 -24.44c0,-1.53 0,-1.94 2.22,-1.94l29.86 0c2.08,0 2.64,0 2.64,-2.64l0 -74.86c0,-2.22 0,-2.78 2.78,-2.78l104.16 0c7.56,0.3 15.07,1.13 22.5,2.5 15.31,2.83 30.02,8.3 43.47,16.11 8.92,5.25 17.13,11.59 24.44,18.89 5.5,5.71 10.46,11.89 14.86,18.47 4.37,6.67 8,13.8 10.85,21.25 0.35,1.94 2.21,3.25 4.15,2.92l24.86 0c3.19,0 3.19,0 3.33,3.06l0 22.78c0,2.22 -0.83,2.78 -3.06,2.78l-19.17 0c-1.94,0 -2.5,0 -2.36,2.5 0.76,8.46 0.76,16.95 0,25.41 0,2.36 0,2.64 2.65,2.64l21.93 0c0.97,1.25 0,2.5 0,3.76 0.14,1.61 0.14,3.24 0,4.85l0 16.81c0,2.36 -0.69,3.06 -2.78,3.06l-26.25 0c-1.83,-0.35 -3.61,0.82 -4.03,2.64 -6.25,16.25 -16.25,30.82 -29.17,42.5 -4.72,4.25 -9.68,8.25 -14.86,11.94 -5.56,3.2 -10.97,6.53 -16.67,9.17 -10.49,4.72 -21.49,8.2 -32.78,10.41 -10.72,1.92 -21.59,2.79 -32.5,2.64l-96.39 0 0 -0.14z"/> 12 | </g> 13 | </svg> 14 | -------------------------------------------------------------------------------- /src/pages/wrap/components/FeeGrantInfoModal.tsx: -------------------------------------------------------------------------------- 1 | import { faInfoCircle, faXmark } from '@fortawesome/free-solid-svg-icons' 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 3 | import { useEffect } from 'react' 4 | 5 | interface Props { 6 | open?: boolean 7 | onClose?: any 8 | } 9 | 10 | const FeeGrantInfoModal = (props: Props) => { 11 | // disable body scroll on open 12 | useEffect(() => { 13 | if (props.open) { 14 | document.body.classList.add('overflow-hidden') 15 | } else { 16 | document.body.classList.remove('overflow-hidden') 17 | } 18 | }, [props.open]) 19 | 20 | if (!props.open) return null 21 | 22 | return ( 23 | <div className="fixed top-0 left-0 right-0 bottom-0 bg-black/80 z-50" onClick={props.onClose}> 24 | <div className="absolute top-[15%] w-full onEnter_fadeInDown"> 25 | <div className="mx-auto max-w-xl px-4"> 26 | <div 27 | className="bg-neutral-900 p-8 rounded-2xl" 28 | onClick={(e) => { 29 | e.stopPropagation() 30 | }} 31 | > 32 | {/* Header */} 33 | <div className="mb-0 text-right"> 34 | <button 35 | onClick={props.onClose} 36 | className="text-neutral-500 hover:bg-neutral-800 transition-colors px-1.5 py-1 rounded-lg text-xl" 37 | > 38 | <FontAwesomeIcon icon={faXmark} className="fa-fw" /> 39 | </button> 40 | </div> 41 | 42 | {/* Header */} 43 | <div className="mb-4 text-center"> 44 | <h2 className="text-2xl font-medium mb-4"> 45 | <FontAwesomeIcon icon={faInfoCircle} className="mr-2 text-neutral-500" /> 46 | Fee Grant Feature 47 | </h2> 48 | <p className="text-neutral-400 max-w-sm mx-auto mb-6"> 49 | Lorem, ipsum dolor sit amet consectetur adipisicing elit. Corrupti, ducimus? Modi inventore, deleniti 50 | culpa quasi quis reiciendis sint, consectetur voluptate eaque ea aliquam rerum natus vel nostrum, quod 51 | praesentium quidem! 52 | </p> 53 | <button 54 | onClick={props.onClose} 55 | className="sm:max-w-[225px] w-full md:px-4 bg-cyan-600 text-cyan-00 hover:text-cyan-100 hover:bg-cyan-500 text-center transition-colors py-2.5 rounded-xl font-semibold text-sm" 56 | > 57 | Close 58 | </button> 59 | </div> 60 | 61 | {/* Body */} 62 | <div className="text-center"></div> 63 | </div> 64 | </div> 65 | </div> 66 | </div> 67 | ) 68 | } 69 | 70 | export default FeeGrantInfoModal 71 | -------------------------------------------------------------------------------- /public/img/assets/ibc-black.svg: -------------------------------------------------------------------------------- 1 | <svg width="2049" height="2050" viewBox="0 0 2049 2050" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <g clip-path="url(#clip0_3858_67292)"> 3 | <g clip-path="url(#clip1_3858_67292)"> 4 | <path fill-rule="evenodd" clip-rule="evenodd" d="M1024.5 71.4794L198.727 548.24V1501.76L1024.5 1978.52L1850.27 1501.76V548.24L1024.5 71.4794ZM1911.74 512.75L1024.5 0.5L137.257 512.75V1537.25L1024.5 2049.5L1911.74 1537.25V512.75Z" fill="black"/> 5 | </g> 6 | <path d="M988.035 692.22C967.763 686.6 949.371 676.411 934.041 662.838L663.346 1154.49C683.332 1160.93 701.321 1171.86 716.122 1186.08L988.035 692.22Z" fill="black"/> 7 | <path d="M755.385 1257.22C757.185 1266.05 758.13 1275.19 758.13 1284.54C758.13 1296.33 756.629 1307.77 753.809 1318.69H1298.61C1295.79 1307.77 1294.28 1296.33 1294.28 1284.54C1294.28 1275.19 1295.23 1266.05 1297.03 1257.22L755.385 1257.22Z" fill="black"/> 8 | <path d="M1115.32 662.512L1388.59 1154.64C1368.64 1161.15 1350.69 1172.14 1335.93 1186.42L1061.43 692.088C1081.68 686.395 1100.04 676.142 1115.32 662.512Z" fill="black"/> 9 | <path fill-rule="evenodd" clip-rule="evenodd" d="M1429.78 1231.14C1400.92 1231.14 1377.44 1254.64 1377.44 1283.52C1377.44 1312.41 1400.92 1335.91 1429.78 1335.91C1458.65 1335.91 1482.13 1312.41 1482.13 1283.52C1482.13 1254.64 1458.65 1231.14 1429.78 1231.14ZM1429.78 1398.62C1366.36 1398.62 1314.77 1346.99 1314.77 1283.52C1314.77 1220.06 1366.36 1168.43 1429.78 1168.43C1493.2 1168.43 1544.8 1220.06 1544.8 1283.52C1544.8 1346.99 1493.2 1398.62 1429.78 1398.62Z" fill="black"/> 10 | <path fill-rule="evenodd" clip-rule="evenodd" d="M1023.4 507.161C994.534 507.161 971.054 530.66 971.054 559.544C971.054 588.428 994.534 611.927 1023.4 611.927C1052.26 611.927 1075.75 588.428 1075.75 559.544C1075.75 530.66 1052.26 507.161 1023.4 507.161ZM1023.4 674.637C959.98 674.637 908.39 623.009 908.39 559.544C908.39 496.081 959.98 444.45 1023.4 444.45C1086.82 444.45 1138.41 496.081 1138.41 559.544C1138.41 623.009 1086.82 674.637 1023.4 674.637Z" fill="black"/> 11 | <path fill-rule="evenodd" clip-rule="evenodd" d="M620.429 1231.14C591.564 1231.14 568.084 1254.64 568.084 1283.52C568.084 1312.41 591.564 1335.91 620.429 1335.91C649.295 1335.91 672.78 1312.41 672.78 1283.52C672.78 1254.64 649.295 1231.14 620.429 1231.14ZM620.429 1398.62C557.01 1398.62 505.42 1346.99 505.42 1283.52C505.42 1220.06 557.01 1168.43 620.429 1168.43C683.849 1168.43 735.444 1220.06 735.444 1283.52C735.444 1346.99 683.849 1398.62 620.429 1398.62Z" fill="black"/> 12 | </g> 13 | <defs> 14 | <clipPath id="clip0_3858_67292"> 15 | <rect width="2049" height="2049" fill="white" transform="translate(0 0.5)"/> 16 | </clipPath> 17 | <clipPath id="clip1_3858_67292"> 18 | <rect width="2049" height="2049" fill="white" transform="translate(0 0.5)"/> 19 | </clipPath> 20 | </defs> 21 | </svg> 22 | -------------------------------------------------------------------------------- /src/services/staking.service.ts: -------------------------------------------------------------------------------- 1 | import { BroadcastMode, MsgWithdrawDelegatorReward, SecretNetworkClient } from 'secretjs' 2 | import { FeeGrantStatus } from 'types/FeeGrantStatus' 3 | import { faucetAddress, queryTxResult } from 'utils/commons' 4 | import { NotificationService } from './notification.service' 5 | 6 | interface Props { 7 | delegatorDelegations: any 8 | secretNetworkClient: SecretNetworkClient 9 | feeGrantStatus: FeeGrantStatus 10 | } 11 | 12 | /** 13 | * Attempts to perform staking via secret.js API 14 | * 15 | * @param {TProps} props 16 | * @returns {Promise<{success: boolean, errorMsg: Nullable<string>}>} A promise that resolves to an object containing: 17 | * - `success`: A boolean indicating whether the wrapping operation was successful. 18 | * - `errorMsg`: A string containing an error message if something went wrong, or null if there were no errors. 19 | * @async 20 | */ 21 | 22 | const performClaimStakingRewards = async (props: Props) => { 23 | const toastId = NotificationService.notify(`Claiming Staking Rewards`, 'loading') 24 | 25 | try { 26 | const txs = props.delegatorDelegations.map((delegation: any) => { 27 | return new MsgWithdrawDelegatorReward({ 28 | delegator_address: props.secretNetworkClient.address, 29 | validator_address: delegation?.delegation?.validator_address 30 | }) 31 | }) 32 | 33 | const broadcastResult = await props.secretNetworkClient.tx.broadcast(txs, { 34 | gasLimit: 100_000 * txs.length, 35 | gasPriceInFeeDenom: 0.25, 36 | feeDenom: 'uscrt', 37 | feeGranter: props.feeGrantStatus === 'success' ? faucetAddress : '', 38 | broadcastMode: BroadcastMode.Sync, 39 | waitForCommit: false 40 | }) 41 | 42 | // Poll the LCD for the transaction result every 10 seconds, 10 retries 43 | await queryTxResult(props.secretNetworkClient, broadcastResult.transactionHash, 6000, 10) 44 | .catch((error: any) => { 45 | console.error(error) 46 | if (error?.tx?.rawLog) { 47 | NotificationService.notify(`Claiming staking rewards failed: ${error.tx.rawLog}`, 'error', toastId) 48 | } else { 49 | NotificationService.notify(`Claiming staking rewards failed: ${error.message}`, 'error', toastId) 50 | } 51 | }) 52 | .then((tx: any) => { 53 | if (tx) { 54 | if (tx.code === 0) { 55 | NotificationService.notify(`Claimed staking rewards successfully`, 'success', toastId) 56 | } else { 57 | NotificationService.notify(`Claiming staking rewards failed: ${tx.rawLog}`, 'error', toastId) 58 | } 59 | } 60 | }) 61 | } catch (e: any) { 62 | console.error(e) 63 | } 64 | } 65 | 66 | export const StakingService = { 67 | performClaimStakingRewards 68 | } 69 | -------------------------------------------------------------------------------- /public/img/assets/leap.svg: -------------------------------------------------------------------------------- 1 | <svg width="805" height="805" viewBox="0 0 805 805" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <g clip-path="url(#clip0_2364_33755)"> 3 | <g clip-path="url(#clip1_2364_33755)"> 4 | <path d="M712.31 373.575C712.31 487.039 577.355 533.147 409.791 533.147C242.226 533.147 105.307 487.039 105.307 373.575C105.307 260.111 241.244 168.297 408.808 168.297C576.373 168.297 712.31 260.311 712.31 373.575Z" fill="#4BAF74"/> 5 | <path d="M681.513 126.544C681.513 66.8049 633.975 18.2919 575.435 18.2919C542.433 18.2919 512.967 33.7279 493.519 57.7839C467 51.7699 438.712 48.3619 409.442 48.3619C380.173 48.3619 351.885 51.5694 325.365 57.7839C305.721 33.7279 276.255 18.2919 243.449 18.2919C184.91 18.2919 137.371 66.8049 137.371 126.544C137.371 146.19 142.479 164.432 151.318 180.269C142.871 198.712 138.353 218.358 138.353 238.805C138.353 344.051 259.754 429.249 409.442 429.249C559.131 429.249 680.531 344.051 680.531 238.805C680.531 218.358 676.013 198.712 667.566 180.269C676.406 164.432 681.513 146.19 681.513 126.544Z" fill="#32DA6D"/> 6 | <path d="M234.9 186.766C270.702 186.766 299.725 157.148 299.725 120.612C299.725 84.0763 270.702 54.4581 234.9 54.4581C199.098 54.4581 170.074 84.0763 170.074 120.612C170.074 157.148 199.098 186.766 234.9 186.766Z" fill="white"/> 7 | <path d="M580.798 186.766C616.6 186.766 645.624 157.148 645.624 120.612C645.624 84.0763 616.6 54.4581 580.798 54.4581C544.996 54.4581 515.973 84.0763 515.973 120.612C515.973 157.148 544.996 186.766 580.798 186.766Z" fill="white"/> 8 | <path d="M200.288 525.351C214.235 525.351 225.236 512.922 223.664 498.89C217.967 449.174 193.805 341.523 87.5303 276.772C-53.9074 190.571 58.0641 487.262 58.0641 487.262L28.7943 504.503C18.9723 510.316 23.0975 525.351 34.2947 525.351H200.288Z" fill="#32DA6D"/> 9 | <path d="M622.343 525.351C609.771 525.351 599.949 512.922 601.324 498.89C606.235 449.374 628.236 341.523 724.1 276.772C851.983 190.571 750.816 487.262 750.816 487.262L777.335 504.503C786.175 510.316 782.443 525.351 772.424 525.351H622.343Z" fill="#32DA6D"/> 10 | <path d="M235.017 132.288C241.526 132.288 246.803 126.903 246.803 120.26C246.803 113.617 241.526 108.232 235.017 108.232C228.507 108.232 223.23 113.617 223.23 120.26C223.23 126.903 228.507 132.288 235.017 132.288Z" fill="#0D0D0D"/> 11 | <path d="M580.589 132.288C587.099 132.288 592.376 126.903 592.376 120.26C592.376 113.617 587.099 108.232 580.589 108.232C574.08 108.232 568.803 113.617 568.803 120.26C568.803 126.903 574.08 132.288 580.589 132.288Z" fill="#0D0D0D"/> 12 | </g> 13 | <rect y="586" width="805" height="310" fill="#AC4BFF"/> 14 | </g> 15 | <defs> 16 | <clipPath id="clip0_2364_33755"> 17 | <rect width="805" height="805" rx="144.9" fill="white"/> 18 | </clipPath> 19 | <clipPath id="clip1_2364_33755"> 20 | <rect width="772.8" height="515.2" fill="white" transform="translate(16 18)"/> 21 | </clipPath> 22 | </defs> 23 | </svg> 24 | -------------------------------------------------------------------------------- /public/img/assets/afrax.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <!-- Generator: Adobe Illustrator 24.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> 3 | <svg version="1.1" 4 | id="svg8" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg" 5 | xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 570.4 570.4" 6 | style="enable-background:new 0 0 570.4 570.4;" xml:space="preserve"> 7 | <style type="text/css"> 8 | .st0{fill-rule:evenodd;clip-rule:evenodd;stroke:#000000;stroke-width:1.2373;stroke-miterlimit:11.3386;} 9 | .st1{fill:#FFFFFF;} 10 | </style> 11 | <sodipodi:namedview bordercolor="#666666" borderopacity="1.0" id="base" inkscape:current-layer="layer1" inkscape:cx="184.71274" inkscape:cy="416.19233" inkscape:document-rotation="0" inkscape:document-units="mm" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:snap-bbox="true" inkscape:window-height="1051" inkscape:window-maximized="1" inkscape:window-width="1842" inkscape:window-x="69" inkscape:window-y="-9" inkscape:zoom="0.39629945" pagecolor="#ffffff" showgrid="false"> 12 | </sodipodi:namedview> 13 | <g id="layer1" transform="translate(295.65791,-75.71863)" inkscape:groupmode="layer" inkscape:label="Layer 1"> 14 | <circle id="path854" class="st0" cx="-10.5" cy="360.9" r="284.6"/> 15 | <path id="path862" class="st1" d="M-167.5,202.6c-12,12.6-21.9,23.2-22,23.4c-0.1,0.3,10.7,10.9,24,23.5 16 | c13.3,12.7,24.9,23.8,25.7,24.5l1.5,1.4l-2.7,4.5c-23.7,39.2-28.6,86.4-13.7,129.8c2.8,8.2,7.6,18.7,11.7,25.6c2,3.4,2.9,5.6,2.7,6 17 | c-0.2,0.4-12.3,13.2-26.9,28.5c-14.6,15.2-26.5,27.9-26.7,28.1c-0.1,0.3,40.8,39.8,44.7,43l1.5,1.3l23.1-24.1 18 | c12.7-13.3,24.6-25.8,26.4-27.7l3.4-3.4l3.2,2c16.3,10.4,35.4,17.6,56.5,21.4c10.6,1.9,30.8,2.4,42.1,1 19 | c21.8-2.5,43.4-9.8,61.1-20.5l4.6-2.8l4.9,4.8c10.7,10.4,50.7,48.4,51.1,48.6c0.4,0.2,44.3-45.7,44.2-46.3 20 | c-0.1-0.3-30.2-29.2-48.6-46.5l-6.1-5.8l2.8-4.6c23.5-39.1,28.4-86.5,13.2-130.2c-2.2-6.4-8.9-20.8-12.8-27.4l-1.9-3.3l25.7-26.9 21 | c14.1-14.7,25.6-27,25.5-27.3c-0.4-1-45.4-43.5-46-43.5c-0.4,0-11.7,11.5-25.2,25.7c-13.5,14.1-24.7,25.7-25,25.8 22 | c-0.2,0.1-1.5-0.5-2.7-1.4c-3.4-2.3-12-7-16.8-9.2c-14.6-6.7-28.2-10.8-44-13.1c-8.2-1.2-32.8-1.4-40.4-0.3 23 | c-18.2,2.6-33.1,7.1-48.3,14.7c-4.4,2.1-9.5,4.9-11.5,6.1l-3.6,2.2l-4.1-4c-2.2-2.2-12.2-11.6-22.1-21.1c-9.9-9.4-20-19-22.4-21.4 24 | l-4.4-4.3L-167.5,202.6z M0.4,267.8c15.9,1.9,30.1,7.3,43.2,16.5c6.7,4.7,16.7,14.7,21.4,21.4c26.7,37.8,21.6,89.2-12,120.7 25 | c-28.7,26.8-70.2,32.8-105.1,15c-25.2-12.9-43-36.5-48.7-64.8c-1.8-9-1.8-25.8,0-34.7c1.7-8.8,4-15.1,8.3-23.9 26 | C-75.3,283.4-38,263.2,0.4,267.8L0.4,267.8z"/> 27 | </g> 28 | </svg> 29 | -------------------------------------------------------------------------------- /vite-plugin-whip-003.ts: -------------------------------------------------------------------------------- 1 | import { Plugin } from 'vite' 2 | 3 | export function whip003(): Plugin { 4 | return { 5 | name: 'build-tokens', 6 | async buildStart(options) { 7 | const { chains, tokens, snips } = await import('./src/utils/config') 8 | 9 | const whip003 = { 10 | chains: {}, 11 | contracts: {} 12 | } 13 | 14 | // add chain definitions 15 | for (const chain of Object.values(chains)) { 16 | whip003.chains[chain.chain_id] = { 17 | namespace: 'cosmos', 18 | reference: chain.chain_id, 19 | label: chain.chain_name, 20 | bech32s: chain.bech32_prefix 21 | } 22 | } 23 | 24 | // add IBC tokens 25 | for (const token of Object.values(tokens)) { 26 | whip003.contracts[token.name] = { 27 | chain: 'cosmos:secret-4', 28 | address: token.address, 29 | label: 30 | 1 === token.withdrawals.length 31 | ? token.deposits[0].chain_name 32 | : 'SCRT' === token.name 33 | ? 'Secret Network' 34 | : token.name, 35 | interfaces: { 36 | snip20: { 37 | symbol: token.name, 38 | decimals: token.decimals, 39 | coingeckoId: token.coingecko_id 40 | } 41 | } 42 | } 43 | } 44 | 45 | // add IBC tokens 46 | for (const token of Object.values(tokens)) { 47 | whip003.contracts[token.name] = { 48 | chain: 'cosmos:secret-4', 49 | address: token.address, 50 | label: 51 | 1 === token.withdrawals.length 52 | ? token.deposits[0].chain_name 53 | : 'SCRT' === token.name 54 | ? 'Secret Network' 55 | : token.name, 56 | interfaces: { 57 | snip20: { 58 | symbol: token.name, 59 | decimals: token.decimals, 60 | coingeckoId: token.coingecko_id 61 | } 62 | } 63 | } 64 | } 65 | 66 | // add SNIPs 67 | for (const snip of Object.values(snips)) { 68 | whip003.contracts[snip.name] = { 69 | chain: 'cosmos:secret-4', 70 | address: snip.address, 71 | label: snip.coingecko_id 72 | ? snip.coingecko_id.replace(/-/g, ' ').replace(/\b[a-z]/g, (s) => s.toUpperCase()) 73 | : snip.name, 74 | interfaces: { 75 | snip20: { 76 | symbol: snip.name, 77 | decimals: snip.decimals, 78 | coingeckoId: snip.coingecko_id 79 | } 80 | } 81 | } 82 | } 83 | 84 | // emit the whip-003 JSON definition 85 | this.emitFile({ 86 | type: 'asset', 87 | fileName: 'whip-003.json', 88 | source: JSON.stringify(whip003, null, '\t') 89 | }) 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/store/TokenPrices.ts: -------------------------------------------------------------------------------- 1 | import BigNumber from 'bignumber.js' 2 | import { Nullable } from 'types/Nullable' 3 | import { allTokens, toCurrencyString } from 'utils/commons' 4 | import { Token, tokens } from 'utils/config' 5 | import { create } from 'zustand' 6 | 7 | export interface CoinPrice { 8 | coingecko_id: string 9 | priceUsd: number 10 | } 11 | 12 | interface TokenPricesState { 13 | priceMapping: Map<Token, number> 14 | init: () => void 15 | isInitialized: boolean 16 | getPrice: (token: Token) => Nullable<string> 17 | getValuePrice: (token: Token, amount: BigNumber) => Nullable<number> 18 | } 19 | 20 | export const useTokenPricesStore = create<TokenPricesState>()((set, get) => ({ 21 | priceMapping: null, 22 | isInitialized: false, 23 | init: () => { 24 | let prices: CoinPrice[] 25 | 26 | /*let coinGeckoIdsString: string = allTokens.map((token) => token.coingecko_id).join(',') 27 | console.log(coinGeckoIdsString)*/ 28 | 29 | // fetch(`https://api.coingecko.com/api/v3/simple/price?ids=${coinGeckoIdsString}&vs_currencies=USD`) 30 | fetch(`https://priceapibuffer.secretsaturn.net/getPrices`) 31 | .then((resp) => resp.json()) 32 | .then((result: { [coingecko_id: string]: { usd: number } }) => { 33 | const formattedPrices = Object.entries(result).map(([coingecko_id, { usd }]) => ({ 34 | coingecko_id, 35 | priceUsd: usd 36 | })) 37 | prices = formattedPrices 38 | const priceMapping = new Map<Token, number>() 39 | allTokens.forEach((token: Token) => { 40 | priceMapping.set(token, prices.find((price: any) => price.coingecko_id === token.coingecko_id)?.priceUsd) 41 | }) 42 | 43 | set({ 44 | priceMapping: priceMapping 45 | }) 46 | }) 47 | .catch((error) => { 48 | console.error(error) 49 | const priceMapping = new Map<Token, number>() 50 | tokens.forEach((token: Token) => { 51 | priceMapping.set(token, undefined) 52 | }) 53 | set({ 54 | priceMapping: priceMapping 55 | }) 56 | }) 57 | set({ 58 | priceMapping: new Map<Token, number>(), 59 | isInitialized: true 60 | }) 61 | }, 62 | getPrice: (token: Token) => { 63 | if (!get().isInitialized) { 64 | get().init() 65 | } 66 | const tokenPrice = get().priceMapping.get(token) 67 | if (tokenPrice !== undefined) { 68 | return toCurrencyString(tokenPrice) 69 | } 70 | return null 71 | }, 72 | getValuePrice: (token: Token, amount: BigNumber = new BigNumber(1)): Nullable<number> => { 73 | if (!get().isInitialized) { 74 | get().init() 75 | } 76 | const tokenPrice = get().priceMapping.get(token) 77 | if (tokenPrice !== undefined) { 78 | const result = new BigNumber(tokenPrice).multipliedBy(amount).dividedBy(`1e${token.decimals}`) 79 | return Number(result) 80 | } 81 | return null 82 | } 83 | })) 84 | -------------------------------------------------------------------------------- /public/img/assets/scrt.svg: -------------------------------------------------------------------------------- 1 | <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path d="M34.1427 5.86C30.3634 2.08 25.3429 0 20.0021 0C8.97208 0 0 8.972 0 20C0 31.028 8.97208 40 20.0021 40C25.3429 40 30.3674 37.92 34.1427 34.14C37.9221 30.36 40 25.34 40 20C40 14.66 37.9221 9.636 34.1427 5.86ZM20.0021 38.616C9.73677 38.616 1.38525 30.264 1.38525 20C1.38525 9.736 9.73677 1.384 20.0021 1.384C30.2672 1.384 38.6187 9.736 38.6187 20C38.6187 30.264 30.2672 38.616 20.0021 38.616Z" fill="#040506"/> 3 | <path d="M20.002 38.1654C9.89834 38.1654 1.67834 29.9449 1.67834 19.8425C1.67834 9.74016 9.89834 1.51968 20.002 1.51968C30.1055 1.51968 38.3255 9.74016 38.3255 19.8425C38.3255 29.9449 30.1055 38.1654 20.002 38.1654Z" fill="#040506"/> 4 | <path d="M30.7155 15.66C30.7155 15.3219 30.5416 15.0168 30.2512 14.8437L20.9421 9.29925C20.2732 8.90025 19.4423 8.90025 18.7734 9.29925L9.4643 14.8438C9.17721 15.0149 9.00477 15.315 9.00012 15.6484C9.00026 16.0561 9.00047 16.723 9.00054 17.1307C8.98892 17.4818 9.16445 17.8012 9.46423 17.9798L12.7368 19.9296C12.7904 19.9615 12.7904 20.0391 12.7368 20.071L9.46423 22.0201C9.17439 22.1929 9.00061 22.4973 9.00005 22.8347C9.00005 23.2485 9.00005 23.9255 9.00005 24.3393C9.00005 24.6781 9.1739 24.9832 9.4643 25.1555L18.7734 30.7008C19.1078 30.9003 19.4826 31 19.8581 31C20.2336 31 20.6076 30.9003 20.9421 30.7008L30.2511 25.1555C30.5415 24.9832 30.7154 24.6781 30.7154 24.3393C30.7154 23.9255 30.7154 23.2485 30.7154 22.8347C30.7148 22.4973 30.541 22.1929 30.2511 22.0202L26.9786 20.0711C26.925 20.0391 26.925 19.9615 26.9786 19.9297L30.2511 17.9799C30.5415 17.8068 30.7154 17.5018 30.7154 17.1636V15.6601L30.7155 15.66ZM19.2135 18.7169C19.4122 18.5989 19.6351 18.5394 19.8581 18.5394C20.0811 18.5394 20.3033 18.5988 20.5021 18.7169L22.6561 20.0004L20.5021 21.2831C20.1045 21.52 19.611 21.52 19.2135 21.2831L17.0594 20.0004L19.2135 18.7169ZM28.5608 23.5175C28.6144 23.5494 28.6144 23.627 28.5608 23.6589L20.5021 28.4587C20.1045 28.6957 19.611 28.6957 19.2135 28.4587L11.1546 23.6588C11.1011 23.6269 11.1011 23.5493 11.1546 23.5175L12.6649 22.6177C12.96 22.4418 13.1408 22.1236 13.1408 21.78V20.3651C13.1408 20.2818 13.2315 20.2302 13.3031 20.2728L18.7734 23.525C19.1078 23.7237 19.4826 23.8235 19.8581 23.8235C20.2336 23.8235 20.6076 23.7237 20.9421 23.525L22.5383 22.574C22.8352 22.3971 23.0163 22.0762 23.0143 21.7305L23.0063 20.3988C23.0058 20.3152 23.0968 20.2631 23.1687 20.3059L28.5608 23.5175ZM26.557 19.6232C26.557 19.7064 26.4663 19.758 26.3947 19.7155L20.9421 16.4749C20.2732 16.0767 19.4423 16.0767 18.7734 16.4749L17.167 17.4317C16.8699 17.6087 16.6888 17.9296 16.6909 18.2753L16.6991 19.6382C16.6995 19.7023 16.6298 19.7422 16.5748 19.7094L11.1547 16.4825C11.1012 16.4506 11.1011 16.373 11.1547 16.3411L19.2135 11.5412C19.4122 11.4224 19.6351 11.363 19.8581 11.363C20.0811 11.363 20.3033 11.4224 20.5021 11.5412L28.5608 16.3411C28.6144 16.373 28.6144 16.4506 28.5608 16.4825L27.033 17.3926C26.7378 17.5684 26.557 17.8867 26.557 18.2303V19.6232Z" fill="#FF3912"/> 5 | </svg> 6 | -------------------------------------------------------------------------------- /public/img/assets/shd.svg: -------------------------------------------------------------------------------- 1 | <svg 2 | width="40" 3 | height="40" 4 | viewBox="0 0 36 33" 5 | fill="none" 6 | xmlns="http://www.w3.org/2000/svg" 7 | > 8 | <path 9 | d="M14.9681 0.751949C21.1905 0.44129 25.3433 3.29338 29.2393 9.83998C34.0335 17.8956 31.5382 26.0359 26.4043 30.8452C29.6505 24.0412 28.9705 21.3013 21.8092 15.4524C14.6478 9.60341 14.1687 4.69824 14.9681 0.751949Z" 10 | fill="url(#paint0_linear_4159_2622)" 11 | /> 12 | <path 13 | d="M36 16.1128C36 22.6871 32.0546 28.3419 26.398 30.8474C30.0228 27.4974 34.409 18.7763 29.4135 10.5476C24.9961 3.27135 18.4678 1.44061 14.9656 0.752001C16.5078 0.263534 18.1504 0 19.8547 0C28.7715 0 36 7.21394 36 16.1128Z" 14 | fill="url(#paint1_linear_4159_2622)" 15 | /> 16 | <path 17 | d="M25.0319 31.2449C20.7797 31.9864 15.6627 29.311 10.7606 22.1568C5.46125 14.4228 8.46176 5.96094 13.5957 1.15155C10.3495 7.95552 11.0295 10.6955 18.1908 16.5445C25.3522 22.3935 25.8313 27.2986 25.0319 31.2449Z" 18 | fill="url(#paint2_linear_4159_2622)" 19 | /> 20 | <path 21 | d="M4 15.884C4 9.30966 7.94534 3.65496 13.602 1.14935C9.97724 4.49932 5.59092 13.2204 10.5865 21.4491C15.0039 28.7254 21.5322 30.5562 25.0344 31.2448C23.4922 31.7333 21.8496 31.9968 20.1453 31.9968C11.2285 31.9968 4 24.7828 4 15.884Z" 22 | fill="url(#paint3_linear_4159_2622)" 23 | /> 24 | <linearGradient 25 | id="paint0_linear_4159_2622" 26 | x1="14.9788" 27 | y1="0.75195" 28 | x2="26.5622" 29 | y2="30.8558" 30 | gradientUnits="userSpaceOnUse" 31 | > 32 | <stop stop-color="#3A447C" /> 33 | <stop 34 | offset="0.523958" 35 | stop-color="#252945" 36 | /> 37 | <stop 38 | offset="1" 39 | stop-color="#121114" 40 | /> 41 | </linearGradient> 42 | <linearGradient 43 | id="paint1_linear_4159_2622" 44 | x1="14.9681" 45 | y1="0.827123" 46 | x2="26.6915" 47 | y2="30.8667" 48 | gradientUnits="userSpaceOnUse" 49 | > 50 | <stop stop-color="#7387F6" /> 51 | <stop 52 | offset="0.473958" 53 | stop-color="#4B548D" 54 | /> 55 | <stop 56 | offset="1" 57 | stop-color="#1F1D23" 58 | /> 59 | </linearGradient> 60 | <linearGradient 61 | id="paint2_linear_4159_2622" 62 | x1="25.0212" 63 | y1="31.2449" 64 | x2="13.4378" 65 | y2="1.14102" 66 | gradientUnits="userSpaceOnUse" 67 | > 68 | <stop stop-color="#53347A" /> 69 | <stop 70 | offset="0.523958" 71 | stop-color="#37244D" 72 | /> 73 | <stop 74 | offset="1" 75 | stop-color="#16141B" 76 | /> 77 | </linearGradient> 78 | <linearGradient 79 | id="paint3_linear_4159_2622" 80 | x1="25.032" 81 | y1="31.1696" 82 | x2="13.3085" 83 | y2="1.13013" 84 | gradientUnits="userSpaceOnUse" 85 | > 86 | <stop stop-color="#A868F5" /> 87 | <stop 88 | offset="0.473958" 89 | stop-color="#684692" 90 | /> 91 | <stop 92 | offset="1" 93 | stop-color="#25222A" 94 | /> 95 | </linearGradient> 96 | </svg> 97 | -------------------------------------------------------------------------------- /src/pages/dashboard/components/SocialMedia.tsx: -------------------------------------------------------------------------------- 1 | import { faDiscord, faTelegram, faTwitter } from '@fortawesome/free-brands-svg-icons' 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 3 | import { trackMixPanelEvent } from 'utils/commons' 4 | 5 | export default function SocialMedia() { 6 | return ( 7 | <> 8 | <div className="rounded-xl bg-white border border-neutral-200 dark:border-neutral-700 dark:bg-neutral-800 h-full flex items-center px-4 py-4"> 9 | <div className="flex-1 text-center border-r border-neutral-300 dark:border-neutral-700"> 10 | <a 11 | href="https://twitter.com/SecretNetwork" 12 | target="_blank" 13 | className="group text-neutral-700 dark:text-neutral-300 hover:text-black dark:hover:text-white transition-colors" 14 | onClick={() => { 15 | trackMixPanelEvent('Clicked Twitter on dashboard') 16 | }} 17 | > 18 | <FontAwesomeIcon icon={faTwitter} size="xl" className="fa-fw sm:mb-1" /> 19 | <br /> 20 | <span className="group-hover:text-black dark:group-hover:text-white transition-colors text-sm font-semibold text-neutral-500 dark:text-neutral-500 hidden sm:inline-block"> 21 | Twitter 22 | </span> 23 | </a> 24 | </div> 25 | 26 | <div className="flex-1 text-center border-r border-neutral-300 dark:border-neutral-700"> 27 | <a 28 | href="https://discord.com/invite/SJK32GY" 29 | target="_blank" 30 | className="group text-neutral-700 dark:text-neutral-300 hover:text-black dark:hover:text-white transition-colors" 31 | onClick={() => { 32 | trackMixPanelEvent('Clicked Discord on dashboard') 33 | }} 34 | > 35 | <FontAwesomeIcon icon={faDiscord} size="xl" className="fa-fw sm:mb-1" /> 36 | <br /> 37 | <span className="group-hover:text-black dark:group-hover:text-white transition-colors text-sm font-semibold text-neutral-500 dark:text-neutral-500 hidden sm:inline-block"> 38 | Discord 39 | </span> 40 | </a> 41 | </div> 42 | 43 | <div className="flex-1 text-center"> 44 | <a 45 | href="https://t.me/SCRTCommunity" 46 | target="_blank" 47 | className="group text-center text-neutral-700 dark:text-neutral-300 hover:text-black dark:hover:text-white transition-colors" 48 | onClick={() => { 49 | trackMixPanelEvent('Clicked Telegram on dashboard') 50 | }} 51 | > 52 | <FontAwesomeIcon icon={faTelegram} size="xl" className="fa-fw sm:mb-1" /> 53 | <br /> 54 | <span className="group-hover:text-black dark:group-hover:text-white transition-colors text-sm font-semibold text-neutral-500 dark:text-neutral-500 hidden sm:inline-block"> 55 | Telegram 56 | </span> 57 | </a> 58 | </div> 59 | </div> 60 | </> 61 | ) 62 | } 63 | -------------------------------------------------------------------------------- /src/pages/dashboard/components/PriceVolTVLChart/components/RangeSwitch.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import { PriceVolumeHistoryContext } from '../PriceVolumeTVL' 3 | 4 | function RangeSwitch() { 5 | const { chartType, chartRange, setChartRange } = useContext(PriceVolumeHistoryContext) 6 | 7 | return ( 8 | <> 9 | {chartType !== 'TVL' && ( 10 | <> 11 | <button 12 | onClick={() => setChartRange('Day')} 13 | type="button" 14 | className={ 15 | 'py-1.5 px-3 text-xs font-semibold rounded-l-lg bg-neutral-100 dark:bg-neutral-700 ' + 16 | (chartRange === 'Day' 17 | ? ' cursor-default bg-neutral-300 dark:bg-cyan-500/20 text-black dark:text-cyan-200 font-semibold' 18 | : ' text-neutral-800 dark:text-neutral-200 hover:bg-neutral-300 dark:hover:bg-neutral-700 focus:bg-neutral-500 dark:focus:bg-neutral-500') 19 | } 20 | > 21 | Day 22 | </button> 23 | <button 24 | onClick={() => setChartRange('Month')} 25 | type="button" 26 | className={ 27 | 'py-1.5 px-3 text-xs font-semibold bg-neutral-100 dark:bg-neutral-700' + 28 | (chartRange === 'Month' 29 | ? ' cursor-default bg-neutral-300 dark:bg-cyan-500/20 text-black dark:text-cyan-200 font-semibold' 30 | : ' text-neutral-800 dark:text-neutral-200 hover:bg-neutral-300 dark:hover:bg-neutral-700 focus:bg-neutral-500 dark:focus:bg-neutral-500') 31 | } 32 | > 33 | Month 34 | </button> 35 | <button 36 | onClick={() => setChartRange('Year')} 37 | type="button" 38 | className={ 39 | 'py-1.5 px-3 text-xs font-semibold rounded-r-lg bg-neutral-100 dark:bg-neutral-700' + 40 | (chartRange === 'Year' 41 | ? ' cursor-default bg-neutral-300 dark:bg-cyan-500/20 text-black dark:text-cyan-200 font-semibold' 42 | : ' text-neutral-800 dark:text-neutral-200 hover:bg-neutral-300 dark:hover:bg-neutral-700 focus:bg-neutral-500 dark:focus:bg-neutral-500') 43 | } 44 | > 45 | Year 46 | </button> 47 | </> 48 | )} 49 | 50 | {chartType === 'TVL' && ( 51 | <> 52 | <button 53 | onClick={() => setChartRange('Year')} 54 | type="button" 55 | className={ 56 | 'py-1.5 px-3 text-xs font-semibold rounded-lg bg-neutral-100 dark:bg-neutral-900' + 57 | (chartRange === 'Year' 58 | ? ' cursor-default bg-neutral-300 dark:bg-cyan-500/20 text-black dark:text-cyan-200 font-semibold' 59 | : ' text-neutral-800 dark:text-neutral-200 hover:bg-neutral-300 dark:hover:bg-neutral-700 focus:bg-neutral-500 dark:focus:bg-neutral-500') 60 | } 61 | > 62 | Year 63 | </button> 64 | </> 65 | )} 66 | </> 67 | ) 68 | } 69 | 70 | export default RangeSwitch 71 | -------------------------------------------------------------------------------- /src/pages/staking/components/StakingStats/ClaimableRewards.tsx: -------------------------------------------------------------------------------- 1 | import BigNumber from 'bignumber.js' 2 | import Button from 'components/UI/Button/Button' 3 | import { APIContext } from 'context/APIContext' 4 | import { StakingContext } from 'pages/staking/Staking' 5 | import { useContext, useEffect, useState } from 'react' 6 | import { useTokenPricesStore } from 'store/TokenPrices' 7 | import { useUserPreferencesStore } from 'store/UserPreferences' 8 | import { toCurrencyString } from 'utils/commons' 9 | import { scrtToken } from 'utils/tokens' 10 | 11 | function ClaimableRewards() { 12 | const { setIsClaimRewardsModalOpen, totalPendingRewards } = useContext(StakingContext) 13 | const { convertCurrency } = useContext(APIContext) 14 | const { getValuePrice, priceMapping } = useTokenPricesStore() 15 | const { currency } = useUserPreferencesStore() 16 | 17 | const [claimableRewardsInCurrency, setClaimableRewardsInCurrency] = useState<string>('') 18 | 19 | useEffect(() => { 20 | if (priceMapping !== null && totalPendingRewards !== null) { 21 | const valuePrice = getValuePrice( 22 | scrtToken, 23 | BigNumber(totalPendingRewards).multipliedBy(`1e${scrtToken.decimals}`) 24 | ) 25 | if (valuePrice) { 26 | const priceInCurrency = convertCurrency('USD', valuePrice, currency) 27 | if (priceInCurrency !== null) { 28 | setClaimableRewardsInCurrency(toCurrencyString(priceInCurrency, currency)) 29 | } 30 | setClaimableRewardsInCurrency(toCurrencyString(valuePrice, currency)) 31 | } 32 | } 33 | }, [priceMapping, totalPendingRewards]) 34 | 35 | function openClaimRewardsModal() { 36 | setIsClaimRewardsModalOpen(true) 37 | } 38 | 39 | return ( 40 | <div className="flex items-center gap-4 p-4 rounded-xl dark:bg-neutral-800 bg-white"> 41 | <div className="flex-1"> 42 | <div className="font-bold mb-2">Claimable Rewards</div> 43 | <div className="mb-1"> 44 | {totalPendingRewards !== null ? ( 45 | <> 46 | <span className="font-medium font-mono">{totalPendingRewards}</span> 47 | <span className="text-xs font-semibold text-neutral-400"> SCRT</span> 48 | </> 49 | ) : ( 50 | <div className="animate-pulse inline-block"> 51 | <div className="h-5 w-12 bg-white dark:bg-neutral-700 rounded-xl"></div> 52 | </div> 53 | )} 54 | </div> 55 | <div className="text-xs text-neutral-400 font-medium font-mono"> 56 | {claimableRewardsInCurrency ? ( 57 | <>{claimableRewardsInCurrency}</> 58 | ) : ( 59 | <div className="animate-pulse inline-block"> 60 | <div className="h-5 w-12 bg-white dark:bg-neutral-700 rounded-xl"></div> 61 | </div> 62 | )} 63 | </div> 64 | </div> 65 | <div> 66 | <Button type="button" onClick={openClaimRewardsModal} color="emerald"> 67 | Claim 68 | </Button> 69 | </div> 70 | </div> 71 | ) 72 | } 73 | 74 | export default ClaimableRewards 75 | -------------------------------------------------------------------------------- /public/img/assets/migaloo.svg: -------------------------------------------------------------------------------- 1 | <svg width="559" height="559" viewBox="0 0 559 559" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path d="M279.5 559C433.864 559 559 433.864 559 279.5C559 125.136 433.864 0 279.5 0C125.136 0 0 125.136 0 279.5C0 433.864 125.136 559 279.5 559Z" fill="#3CCD64"/> 3 | <path d="M541 279.477C541 404.772 452.852 509.489 335.177 535L333.47 527.149C315.741 530.974 297.656 532.902 279.519 532.902C152.682 532.902 44.6478 438.228 28.2269 312.681C26.8003 301.671 26.0868 290.58 26.0907 279.477H18C18 135.085 135.07 18 279.5 18V26.027C419.286 26.027 532.947 139.716 532.947 279.452L541 279.477Z" fill="#191919"/> 4 | <path d="M413.956 479L405 465.614C505.772 397.65 534.105 261.426 468.83 158.69L482.372 150C552.352 260.129 521.995 406.15 413.956 479Z" fill="#3CCD64"/> 5 | <path d="M80.4196 414C61.8446 386.718 49.1294 355.927 43.0673 323.547C37.0052 291.167 37.7263 257.894 45.1856 225.803C52.645 193.713 66.6825 163.494 86.4223 137.031C106.162 110.569 131.18 88.4313 159.916 72L168 85.9396C98.4285 125.797 55.2098 200.055 55.2098 279.738C55.1279 324.396 68.5834 368.044 93.8247 404.999L80.4196 414Z" fill="#3CCD64"/> 6 | <path d="M187.856 468C83.3655 416.975 40.3032 291.414 91.6783 187.584C95.5324 179.796 99.8697 172.254 104.665 165L118.185 173.834C97.2812 205.361 86.1704 242.301 86.2359 280.055C86.2359 354.302 127.914 420.774 195 453.587L187.856 468Z" fill="#3CCD64"/> 7 | <path d="M482.172 333L466.639 328.911C470.828 312.836 472.944 296.288 472.938 279.672C472.938 172.94 386.386 86.1077 280 86.1077V70C395.419 70.0063 489 163.878 489 279.672C489.004 297.668 486.71 315.59 482.172 333Z" fill="#3CCD64"/> 8 | <path d="M437.369 202.856C399.252 260.987 365.311 243.372 324.771 235.498C284.231 227.625 261.835 270.596 261.835 270.596C261.835 270.596 261.88 270.451 261.905 270.382C261.135 271.79 260.384 273.21 259.665 274.65C258.366 277.175 257.192 279.821 256.069 282.529C256.195 279.585 256.644 276.663 257.407 273.816C258.144 270.949 259.104 268.143 260.277 265.425C261.737 262.039 263.507 258.794 265.564 255.734C271.873 215.086 238.317 199.447 195.941 174.975C148.746 147.725 169.867 118 169.867 118C169.867 118 90.0685 200.962 143.314 279.404C196.559 357.846 263.911 380.026 193.702 498.105C193.702 498.105 241.402 525.822 318.147 512.266C298.085 426.514 303.151 394.2 334.922 365.081L331.458 366.344C330.197 366.767 328.935 367.076 327.673 367.417L325.781 367.916C325.15 368.067 324.519 368.156 323.85 368.276C322.588 368.503 321.276 368.718 319.989 368.907C318.702 369.097 317.377 369.097 316.084 369.172C315.453 369.172 314.784 369.235 314.135 369.248C313.485 369.261 312.829 369.198 312.179 369.147C310.879 369.065 309.586 368.97 308.305 368.812C309.567 368.421 310.829 368.099 312.04 367.783C312.671 367.619 313.27 367.48 313.882 367.335L315.705 366.773C316.91 366.413 318.115 366.072 319.32 365.738C320.525 365.403 321.686 364.911 322.866 364.525C323.459 364.33 324.052 364.159 324.632 363.938L326.38 363.269C327.528 362.802 328.714 362.442 329.85 361.943L333.282 360.51C334.436 360.055 335.54 359.487 336.676 358.982C341.18 356.911 345.626 354.663 350.012 352.239L353.167 350.484C368.244 342.907 381.556 334.302 393.801 323.335C469.083 256.037 437.369 202.856 437.369 202.856Z" fill="white"/> 9 | </svg> 10 | -------------------------------------------------------------------------------- /public/img/assets/stkdydx.svg: -------------------------------------------------------------------------------- 1 | <svg width="122" height="122" viewBox="0 0 122 122" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <g filter="url(#filter0_d_1471_1791)"> 3 | <path d="M61 102C85.8528 102 106 81.8528 106 57C106 32.1472 85.8528 12 61 12C36.1472 12 16 32.1472 16 57C16 81.8528 36.1472 102 61 102Z" fill="url(#paint0_linear_1471_1791)"/> 4 | <path d="M118 57C118 64.4853 116.526 71.8974 113.661 78.813C110.797 85.7285 106.598 92.0121 101.305 97.3051C96.0121 102.598 89.7285 106.797 82.813 109.661C75.8974 112.526 68.4853 114 61 114C53.5147 114 46.1026 112.526 39.187 109.661C32.2715 106.797 25.9879 102.598 20.6949 97.3051C15.402 92.0121 11.2034 85.7285 8.33886 78.813C5.47435 71.8974 4 64.4853 4 57H17.6615C17.6615 62.6913 18.7824 68.3269 20.9604 73.5849C23.1384 78.843 26.3307 83.6206 30.355 87.645C34.3794 91.6693 39.157 94.8616 44.4151 97.0396C49.6731 99.2176 55.3087 100.339 61 100.339C66.6913 100.339 72.3269 99.2176 77.5849 97.0396C82.843 94.8616 87.6206 91.6693 91.645 87.645C95.6693 83.6206 98.8616 78.843 101.04 73.5849C103.218 68.3269 104.339 62.6913 104.339 57H118Z" fill="#C73238"/> 5 | <path d="M106 57C106 62.9095 104.836 68.7611 102.575 74.2208C100.313 79.6804 96.9984 84.6412 92.8198 88.8198C88.6412 92.9984 83.6804 96.3131 78.2208 98.5746C72.7611 100.836 66.9095 102 61 102C55.0905 102 49.2389 100.836 43.7792 98.5746C38.3196 96.3131 33.3588 92.9984 29.1802 88.8198C25.0016 84.6412 21.6869 79.6804 19.4254 74.2208C17.164 68.7611 16 62.9095 16 57L61 57H106Z" fill="#070B09"/> 6 | <path d="M72.5131 32L37 81.996H47.9033L83.6005 32H72.5131Z" fill="white"/> 7 | <path d="M49.0391 32L59.4881 46.7321L54.0365 54.7679L37.9087 32H49.0391Z" fill="url(#paint1_linear_1471_1791)"/> 8 | <path d="M73.5713 81.9999L61.9868 65.7055L67.4385 57.8928L84.4748 81.9999H73.5713Z" fill="url(#paint2_linear_1471_1791)"/> 9 | </g> 10 | <defs> 11 | <filter id="filter0_d_1471_1791" x="0" y="0" width="122" height="122" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> 12 | <feFlood flood-opacity="0" result="BackgroundImageFix"/> 13 | <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> 14 | <feOffset dy="4"/> 15 | <feGaussianBlur stdDeviation="2"/> 16 | <feComposite in2="hardAlpha" operator="out"/> 17 | <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/> 18 | <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1471_1791"/> 19 | <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1471_1791" result="shape"/> 20 | </filter> 21 | <linearGradient id="paint0_linear_1471_1791" x1="88.8453" y1="-0.679559" x2="66.7182" y2="91.3094" gradientUnits="userSpaceOnUse"> 22 | <stop stop-color="#2C2C3D"/> 23 | <stop offset="1" stop-color="#1A1A27"/> 24 | </linearGradient> 25 | <linearGradient id="paint1_linear_1471_1791" x1="46.5405" y1="35.125" x2="61.1895" y2="53.1215" gradientUnits="userSpaceOnUse"> 26 | <stop stop-color="white"/> 27 | <stop offset="1" stop-color="white" stop-opacity="0.55"/> 28 | </linearGradient> 29 | <linearGradient id="paint2_linear_1471_1791" x1="76.0703" y1="78.2055" x2="58.1048" y2="53.5587" gradientUnits="userSpaceOnUse"> 30 | <stop stop-color="#6966FF"/> 31 | <stop offset="1" stop-color="#6966FF" stop-opacity="0.36"/> 32 | </linearGradient> 33 | </defs> 34 | </svg> 35 | -------------------------------------------------------------------------------- /src/pages/wrap/Wrap.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState, useContext, createContext } from 'react' 2 | import { Token, tokens } from 'utils/config' 3 | import { wrapPageTitle, wrapPageDescription, wrapJsonLdSchema } from 'utils/commons' 4 | import { Helmet } from 'react-helmet-async' 5 | import FeeGrantInfoModal from './components/FeeGrantInfoModal' 6 | import mixpanel from 'mixpanel-browser' 7 | import { WrappingMode, isWrappingMode } from 'types/WrappingMode' 8 | import { useSecretNetworkClientStore } from 'store/secretNetworkClient' 9 | import Title from 'components/Title' 10 | import WrapForm from './components/WrapForm' 11 | import SCRTUnwrapWarning from './components/SCRTUnwrapWarning' 12 | 13 | export function Wrap() { 14 | const { getBalance } = useSecretNetworkClientStore() 15 | const scrtBalance = getBalance( 16 | tokens.find((token) => token.name === 'SCRT'), 17 | false 18 | ) 19 | 20 | useEffect(() => { 21 | if (import.meta.env.VITE_MIXPANEL_ENABLED === 'true') { 22 | mixpanel.init(import.meta.env.VITE_MIXPANEL_PROJECT_TOKEN, { 23 | debug: false 24 | }) 25 | mixpanel.identify('Dashboard-App') 26 | mixpanel.track('Open Wrap Tab') 27 | } 28 | }, []) 29 | 30 | const infoMsg = `Converting publicly visible tokens into its privacy-preserving equivalent Secret Token and vice versa. These tokens are not publicly visible and require a viewing key.` 31 | 32 | const [isFeeGrantInfoModalOpen, setIsFeeGrantInfoModalOpen] = useState(false) 33 | 34 | return ( 35 | <> 36 | <Helmet> 37 | <title>{wrapPageTitle} 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | {/* */} 50 | 51 | 52 | 53 | {/* */} 54 | 55 | 56 | 57 | 58 | { 61 | setIsFeeGrantInfoModalOpen(false) 62 | document.body.classList.remove('overflow-hidden') 63 | }} 64 | /> 65 | 66 | {/* Content */} 67 |
68 | {/* Title: Secret Wrap / Secret Unwrap */} 69 | 70 | {Number(scrtBalance) === 0 && scrtBalance !== null ? <SCRTUnwrapWarning /> : null} 71 | {/* Content */} 72 | <div className="rounded-3xl px-6 py-6 bg-white border border-neutral-200 dark:border-neutral-700 dark:bg-neutral-800"> 73 | <WrapForm /> 74 | </div> 75 | </div> 76 | </> 77 | ) 78 | } 79 | -------------------------------------------------------------------------------- /public/img/assets/statom.svg: -------------------------------------------------------------------------------- 1 | <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path d="M20 40C31.0457 40 40 31.0457 40 20C40 8.9543 31.0457 0 20 0C8.9543 0 0 8.9543 0 20C0 31.0457 8.9543 40 20 40Z" fill="#E50571"/> 3 | <path d="M20.0411 2.5515C17.8822 2.5515 16.1317 10.3819 16.1317 20.0413C16.1317 29.7006 17.8822 37.531 20.0411 37.531C22.2 37.531 23.9505 29.7006 23.9505 20.0413C23.9505 10.3819 22.2 2.5515 20.0411 2.5515ZM20.311 36.544C20.0641 36.8733 19.8173 36.6262 19.8173 36.6262C18.823 35.4742 18.3259 33.3341 18.3259 33.3341C16.5869 27.7374 17.0008 15.7209 17.0008 15.7209C17.8181 6.1811 19.3048 3.9275 19.8107 3.42718C19.8624 3.37612 19.9304 3.34491 20.0028 3.33906C20.0752 3.33321 20.1473 3.35308 20.2065 3.39518C20.9406 3.91534 21.5563 6.0907 21.5563 6.0907C23.3744 12.8397 23.2097 19.1771 23.2097 19.1771C23.3744 24.6915 22.2987 30.8643 22.2987 30.8643C21.4707 35.5555 20.311 36.544 20.311 36.544Z" fill="white"/> 4 | <path d="M35.2115 11.3375C34.1366 9.4642 26.4741 11.8428 18.0915 16.6495C9.70896 21.4562 3.796 26.8717 4.87008 28.7442C5.94416 30.6167 13.6075 28.2389 21.9901 23.4322C30.3726 18.6255 36.2856 13.21 35.2115 11.3375ZM5.86176 28.4872C5.45024 28.4354 5.5432 28.0972 5.5432 28.0972C6.048 26.6618 7.6544 25.1655 7.6544 25.1655C11.6453 20.8717 22.275 15.2511 22.275 15.2511C30.9557 11.2124 33.652 11.3828 34.336 11.5711C34.4062 11.5907 34.4672 11.6345 34.5082 11.6948C34.5492 11.755 34.5676 11.8279 34.56 11.9004C34.4778 12.7964 32.8933 14.4124 32.8933 14.4124C27.9474 19.3498 22.368 22.3613 22.368 22.3613C17.6667 25.2493 11.7771 27.3868 11.7771 27.3868C7.29568 29.0016 5.86192 28.4872 5.86192 28.4872H5.86176Z" fill="white"/> 5 | <path d="M35.1736 28.8066C36.2568 26.9382 30.3587 21.4979 22.0056 16.655C13.6525 11.8121 5.9909 9.40415 4.90866 11.2757C3.82642 13.1472 9.72354 18.5843 18.0815 23.4272C26.4394 28.2701 34.0914 30.6782 35.1736 28.8066ZM5.62642 11.9976C5.46642 11.6182 5.80418 11.5269 5.80418 11.5269C7.29954 11.2445 9.40002 11.888 9.40002 11.888C15.1144 13.1893 25.304 19.572 25.304 19.572C33.1493 25.0618 34.3525 27.4798 34.5328 28.1662C34.5512 28.2366 34.544 28.3113 34.5127 28.3769C34.4814 28.4426 34.4279 28.4951 34.3616 28.5251C33.5435 28.8997 31.3525 28.3416 31.3525 28.3416C24.5994 26.5309 19.1986 23.2133 19.1986 23.2133C14.3459 20.596 9.54754 16.5688 9.54754 16.5688C5.90146 13.4989 5.62754 12.0017 5.62754 12.0017L5.62642 11.9976Z" fill="white"/> 6 | <path d="M20 22.0576C21.1364 22.0576 22.0576 21.1364 22.0576 20C22.0576 18.8636 21.1364 17.9424 20 17.9424C18.8636 17.9424 17.9424 18.8636 17.9424 20C17.9424 21.1364 18.8636 22.0576 20 22.0576Z" fill="white"/> 7 | <path d="M28.4361 13.3333C29.0953 13.3333 29.6296 12.7805 29.6296 12.0987C29.6296 11.4169 29.0953 10.8642 28.4361 10.8642C27.777 10.8642 27.2427 11.4169 27.2427 12.0987C27.2427 12.7805 27.777 13.3333 28.4361 13.3333Z" fill="white"/> 8 | <path d="M8.84771 17.5309C9.50683 17.5309 10.0411 16.9782 10.0411 16.2963C10.0411 15.6145 9.50683 15.0618 8.84771 15.0618C8.18859 15.0618 7.65427 15.6145 7.65427 16.2963C7.65427 16.9782 8.18859 17.5309 8.84771 17.5309Z" fill="white"/> 9 | <path d="M17.572 32.6749C18.2311 32.6749 18.7655 32.1221 18.7655 31.4403C18.7655 30.7585 18.2311 30.2058 17.572 30.2058C16.9129 30.2058 16.3786 30.7585 16.3786 31.4403C16.3786 32.1221 16.9129 32.6749 17.572 32.6749Z" fill="white"/> 10 | <defs> 11 | <rect width="40" height="40" fill="white"/> 12 | </defs> 13 | </svg> 14 | -------------------------------------------------------------------------------- /public/img/assets/keplr.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <svg width="200px" height="200px" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 3 | <!-- Generator: Sketch 62 (91390) - https://sketch.com --> 4 | <title>Artboard Copy 6@960w 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/services/send.service.ts: -------------------------------------------------------------------------------- 1 | import BigNumber from 'bignumber.js' 2 | import { BroadcastMode, MsgExecuteContract, MsgSend, SecretNetworkClient } from 'secretjs' 3 | import { FeeGrantStatus } from 'types/FeeGrantStatus' 4 | import { Nullable } from 'types/Nullable' 5 | import { allTokens, faucetAddress, queryTxResult, randomPadding } from 'utils/commons' 6 | import { Token, tokens } from 'utils/config' 7 | 8 | function getSupportedTokens() { 9 | return [allTokens[0]].concat( 10 | allTokens.map((token: Token) => (token.name === 'SCRT' ? { ...token, address: 'native' } : token)) 11 | ) 12 | } 13 | 14 | interface IBaseProps { 15 | amount: string 16 | recipient: string 17 | memo?: string 18 | secretNetworkClient: SecretNetworkClient 19 | feeGrantStatus: FeeGrantStatus 20 | } 21 | 22 | interface IPropsToken extends IBaseProps { 23 | token: Token 24 | } 25 | 26 | // Main function to perform the sending 27 | async function performSending(props: IPropsToken): Promise { 28 | let token = props.token 29 | 30 | if (!token) { 31 | console.error('token', token) 32 | throw new Error('Token not found') 33 | } 34 | 35 | const baseAmount = props.amount 36 | const amount = new BigNumber(Number(baseAmount)).multipliedBy(`1e${token.decimals}`).toFixed(0, BigNumber.ROUND_DOWN) 37 | 38 | if (amount === 'NaN') { 39 | console.error('NaN amount', baseAmount) 40 | throw new Error('Amount is not a valid number') 41 | } 42 | 43 | // Broadcast the transaction 44 | const broadcastResult = await props.secretNetworkClient.tx.broadcast( 45 | [ 46 | token.address === 'native' 47 | ? new MsgSend({ 48 | from_address: props.secretNetworkClient?.address, 49 | to_address: props.recipient, 50 | amount: [ 51 | { 52 | amount: amount, 53 | denom: 'uscrt' 54 | } 55 | ] 56 | }) 57 | : new MsgExecuteContract({ 58 | sender: props.secretNetworkClient?.address, 59 | contract_address: token.address, 60 | code_hash: token.code_hash, 61 | sent_funds: [], 62 | msg: { 63 | transfer: { 64 | recipient: props.recipient, 65 | amount: amount, 66 | padding: randomPadding() 67 | } 68 | } 69 | }) 70 | ], 71 | { 72 | gasLimit: 150_000, 73 | gasPriceInFeeDenom: 0.25, 74 | feeDenom: 'uscrt', 75 | feeGranter: props.feeGrantStatus === 'success' ? faucetAddress : '', 76 | broadcastMode: BroadcastMode.Sync, 77 | memo: props.memo, 78 | waitForCommit: false 79 | } 80 | ) 81 | 82 | // Poll the LCD for the transaction result every 10 seconds, 10 retries 83 | await queryTxResult(props.secretNetworkClient, broadcastResult.transactionHash, 6000, 10) 84 | .catch((error: any) => { 85 | console.error(error) 86 | throw error 87 | }) 88 | .then((tx: any) => { 89 | if (tx) { 90 | if (tx.code === 0) { 91 | return 'success' 92 | } else { 93 | console.error(tx.rawLog) 94 | throw new Error(tx.rawLog) 95 | } 96 | } 97 | }) 98 | return 99 | } 100 | 101 | export const SendService = { 102 | performSending, 103 | getSupportedTokens 104 | } 105 | -------------------------------------------------------------------------------- /public/img/assets/dshd.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | 13 | 17 | 23 | 27 | 33 | 34 | 35 | 43 | 44 | 48 | 49 | 57 | 58 | 62 | 66 | 67 | 75 | 76 | 80 | 84 | 85 | 86 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /src/components/FeeGrant/components/ActionableStatus.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import { faCheckCircle, faXmarkCircle } from '@fortawesome/free-solid-svg-icons' 3 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 4 | import Button from 'components/UI/Button/Button' 5 | import { useSecretNetworkClientStore } from 'store/secretNetworkClient' 6 | import toast from 'react-hot-toast' 7 | import { NotificationService } from 'services/notification.service' 8 | 9 | export default function ActionableStatus() { 10 | const { feeGrantStatus, requestFeeGrant, isConnected } = useSecretNetworkClientStore() 11 | 12 | const [isLoading, setIsLoading] = useState(false) 13 | 14 | async function handleRequestFeeGrant() { 15 | setIsLoading(true) 16 | const toastId = NotificationService.notify(`Requesting Fee Grant...`, 'loading') 17 | 18 | try { 19 | const res = requestFeeGrant() 20 | 21 | res 22 | .then(() => { 23 | NotificationService.notify(`Request for Fee Grant successful`, 'success', toastId) 24 | }) 25 | .catch((error) => { 26 | NotificationService.notify(`Request for Fee Grant failed: ${error}`, 'error', toastId) 27 | }) 28 | } catch (error: any) { 29 | console.error(error) 30 | NotificationService.notify(`Request for Fee Grant failed: ${error}`, 'error', toastId) 31 | } 32 | setIsLoading(false) 33 | } 34 | 35 | if (isLoading) { 36 | return ( 37 |
38 | 44 | 45 | 50 | 51 | Requesting... 52 |
53 | ) 54 | } 55 | 56 | // Untouched 57 | if (feeGrantStatus === 'untouched') { 58 | return ( 59 | 68 | ) 69 | } 70 | 71 | // Success 72 | if (feeGrantStatus === 'success') { 73 | return ( 74 |
75 | 76 | Fee Granted 77 |
78 | ) 79 | } 80 | 81 | // Fail 82 | if (feeGrantStatus === 'fail') { 83 | return ( 84 |
85 | 86 | Request failed 87 |
88 | ) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /public/img/assets/stluna.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/pages/dashboard/components/QuadTile.tsx: -------------------------------------------------------------------------------- 1 | interface Item { 2 | key: string 3 | value: string 4 | } 5 | 6 | interface Props { 7 | item1?: Item 8 | item2?: Item 9 | item3?: Item 10 | item4?: Item 11 | } 12 | 13 | export default function QuadTile(props: Props) { 14 | return ( 15 | <> 16 |
17 |
18 |
19 | {/* First Item */} 20 |
21 |
22 |
23 | {props.item1?.key} 24 |
25 |
26 | {props.item1?.value ? ( 27 | <>{props.item1.value} 28 | ) : ( 29 |
30 | )} 31 |
32 |
33 |
34 | {/* Second Item */} 35 |
36 |
37 |
38 | {props.item2?.key} 39 |
40 |
41 | {props.item2?.value ? ( 42 | <>{props.item2?.value} 43 | ) : ( 44 |
45 | )} 46 |
47 |
48 |
49 |
50 |
51 | {/* Third Item */} 52 |
53 |
54 |
55 | {props.item3?.key} 56 |
57 |
58 | {props.item3?.value ? ( 59 | <>{props.item3.value} 60 | ) : ( 61 |
62 | )} 63 |
64 |
65 |
66 | {/* Fourth Item */} 67 |
68 |
69 |
70 | {props.item4?.key} 71 |
72 |
73 | {props.item4?.value ? ( 74 | <>{props.item4.value} 75 | ) : ( 76 |
77 | )} 78 |
79 |
80 |
81 |
82 |
83 |
84 | 85 | ) 86 | } 87 | --------------------------------------------------------------------------------