diff --git a/.env.development b/.env.development index cec98b4a0..a6a163d27 100644 --- a/.env.development +++ b/.env.development @@ -18,5 +18,4 @@ VITE_EVM_PROVIDER_URL=https://rpc.nice.hydration.cloud VITE_EVM_EXPLORER_URL=https://explorer.nice.hydration.cloud VITE_EVM_NATIVE_ASSET_ID=20 VITE_MIGRATION_TRIGGER_DOMAIN="deploy-preview-1334--testnet-hydra-app.netlify.app" -VITE_MIGRATION_TARGET_DOMAIN="testnet-app.hydradx.io" - +VITE_MIGRATION_TARGET_DOMAIN="deploy-preview-1374--testnet-hydra-app.netlify.app" \ No newline at end of file diff --git a/index.html b/index.html index 3d5ee98a9..0703ca49f 100644 --- a/index.html +++ b/index.html @@ -13,7 +13,7 @@ - + diff --git a/index.template.html b/index.template.html index 8bee4e838..22ac371f6 100644 --- a/index.template.html +++ b/index.template.html @@ -3,7 +3,7 @@ <%= title %> - + @@ -14,11 +14,11 @@ - + - + diff --git a/package.json b/package.json index 48952287e..e7bed63d4 100644 --- a/package.json +++ b/package.json @@ -31,15 +31,15 @@ "@emotion/styled": "^11.10.4", "@ethersproject/address": "^5.7.0", "@ethersproject/providers": "^5.7.2", - "@galacticcouncil/apps": "^3.9.0", + "@galacticcouncil/apps": "^3.9.1", "@galacticcouncil/math-lbp": "^1.0.0", "@galacticcouncil/math-liquidity-mining": "^1.0.0", "@galacticcouncil/math-omnipool": "^1.0.0", "@galacticcouncil/math-stableswap": "^1.0.0", "@galacticcouncil/math-staking": "^1.0.0", "@galacticcouncil/math-xyk": "^1.0.0", - "@galacticcouncil/sdk": "^3.0.0", - "@galacticcouncil/ui": "^3.2.2", + "@galacticcouncil/sdk": "^3.0.1", + "@galacticcouncil/ui": "^3.2.3", "@galacticcouncil/xcm-cfg": "^2.5.0", "@galacticcouncil/xcm-core": "^1.4.0", "@galacticcouncil/xcm-sdk": "^3.3.0", diff --git a/public/favicon.ico b/public/favicon.ico index 30e09660e..87a8a126f 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/images/meta-image.jpg b/public/images/meta-image.jpg deleted file mode 100644 index 3f0de37bc..000000000 Binary files a/public/images/meta-image.jpg and /dev/null differ diff --git a/src/api/accountBalances.ts b/src/api/accountBalances.ts index 4ee7791c3..a81f09725 100644 --- a/src/api/accountBalances.ts +++ b/src/api/accountBalances.ts @@ -10,10 +10,15 @@ import BN from "bn.js" import { useRpcProvider } from "providers/rpcProvider" import { calculateFreeBalance } from "./balances" -export const useAccountBalances = (id: Maybe) => { +export const useAccountBalances = ( + id: Maybe, + noRefresh?: boolean, +) => { const { api } = useRpcProvider() return useQuery( - QUERY_KEYS.accountBalances(id), + noRefresh + ? QUERY_KEYS.accountBalances(id) + : QUERY_KEYS.accountBalancesLive(id), !!id ? getAccountBalances(api, id) : undefinedNoop, { enabled: id != null }, ) diff --git a/src/api/assetDetails.ts b/src/api/assetDetails.ts index b32c5fcab..8ae82a6f2 100644 --- a/src/api/assetDetails.ts +++ b/src/api/assetDetails.ts @@ -222,7 +222,6 @@ export const getAssets = async (api: ApiPromise) => { if (id === NATIVE_ASSET_ID) { const asset: TToken = { ...assetCommon, - name: "HydraDX", symbol: system.tokenSymbol.unwrap()[0].toString(), decimals: system.tokenDecimals.unwrap()[0].toNumber(), isNative: true, diff --git a/src/api/democracy.ts b/src/api/democracy.ts index fb1dc0bb0..728a0f24f 100644 --- a/src/api/democracy.ts +++ b/src/api/democracy.ts @@ -3,15 +3,28 @@ import { useQuery } from "@tanstack/react-query" import { QUERY_KEYS } from "utils/queryKeys" import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { useRpcProvider } from "providers/rpcProvider" +import { undefinedNoop } from "utils/helpers" +import BN from "bignumber.js" +import { BN_0 } from "utils/constants" const REFERENDUM_DATA_URL = import.meta.env.VITE_REFERENDUM_DATA_URL as string +const CONVICTIONS_BLOCKS: { [key: string]: number } = { + none: 0, + locked1x: 50400, + locked2x: 100800, + locked3x: 201600, + locked4x: 403200, + locked5x: 806400, + locked6x: 1612800, +} + export const useReferendums = (type?: "ongoing" | "finished") => { const { api, isLoaded } = useRpcProvider() const { account } = useAccount() return useQuery( - QUERY_KEYS.referendums(account?.address), + QUERY_KEYS.referendums(account?.address, type), getReferendums(api, account?.address), { enabled: isLoaded, @@ -94,3 +107,97 @@ export type Referendum = { export const getReferendumInfoOf = async (api: ApiPromise, id: string) => await api.query.democracy.referendumInfoOf(id) + +export const useAccountVotes = () => { + const { api, isLoaded } = useRpcProvider() + const { account } = useAccount() + + return useQuery( + QUERY_KEYS.referendumVotes(account?.address), + account ? getAccountUnlockedVotes(api, account.address) : undefinedNoop, + { + enabled: isLoaded && !!account, + }, + ) +} + +export const getAccountUnlockedVotes = + (api: ApiPromise, accountId: string) => async () => { + const [votesRaw, currentBlock] = await Promise.all([ + api.query.democracy.votingOf(accountId), + api.derive.chain.bestNumber(), + ]) + + if (!votesRaw || votesRaw.isDelegating) return undefined + + const votes = votesRaw.asDirect.votes.map(([id, dataRaw]) => { + const test = dataRaw.asStandard + + return { + id: id.toString(), + balance: test.balance.toBigNumber(), + conviction: test.vote.conviction.toString(), + } + }) + + const votedAmounts = await Promise.all( + votes.map(async (vote) => { + const voteId = vote.id + const referendumRaw = await api.query.democracy.referendumInfoOf(voteId) + const referendum = referendumRaw.unwrap() + const isFinished = referendum.isFinished + + const endBlock = isFinished + ? referendum.asFinished.end.toBigNumber() + : referendum.asOngoing.end.toBigNumber() + const convictionBlock = + CONVICTIONS_BLOCKS[vote.conviction.toLocaleLowerCase()] + const unlockBlockNumber = endBlock.plus(convictionBlock) + const isUnlocked = isFinished + ? unlockBlockNumber.lte(currentBlock.toNumber()) + : false + + return { + isUnlocked, + amount: vote.balance, + id: voteId, + endDiff: unlockBlockNumber.minus(currentBlock.toNumber()), + } + }), + ) + + const unlockedVotes = votedAmounts.reduce<{ + maxUnlockedValue: BN + maxLockedValue: BN + maxLockedBlock: BN + ids: string[] + }>( + (acc, votedAmount) => { + if (votedAmount.isUnlocked) + return { + maxUnlockedValue: BN.maximum( + acc.maxUnlockedValue, + votedAmount.amount, + ), + maxLockedValue: acc.maxLockedValue, + maxLockedBlock: BN.maximum(votedAmount.endDiff, acc.maxLockedBlock), + ids: [...acc.ids, votedAmount.id], + } + + return { + maxLockedValue: BN.maximum(acc.maxLockedValue, votedAmount.amount), + maxUnlockedValue: acc.maxUnlockedValue, + maxLockedBlock: BN.maximum(votedAmount.endDiff, acc.maxLockedBlock), + ids: acc.ids, + } + }, + { + maxUnlockedValue: BN_0, + maxLockedValue: BN_0, + ids: [], + maxLockedBlock: BN_0, + }, + ) + + return unlockedVotes + } diff --git a/src/api/externalAssetRegistry.ts b/src/api/externalAssetRegistry.ts index 63ff2e9bc..834d63400 100644 --- a/src/api/externalAssetRegistry.ts +++ b/src/api/externalAssetRegistry.ts @@ -84,9 +84,12 @@ export const getPedulumAssets = async () => { const data = dataRaw.unwrap() const location = data.location.unwrap() - if (location.isV2 && location.asV2.interior.toString() !== "Here") { + if (location) { + const type = location.type.toString() + const interior = location[`as${type}`].interior.toString() + const id = getPendulumAssetId(idRaw) - if (id) + if (interior !== "Here" && id) acc.push({ id, // @ts-ignore @@ -95,7 +98,7 @@ export const getPedulumAssets = async () => { symbol: data.symbol.toHuman() as string, // @ts-ignore name: data.name.toHuman() as string, - location: location.asV2 as HydradxRuntimeXcmAssetLocation, + location: location[`as${type}`] as HydradxRuntimeXcmAssetLocation, origin: PENDULUM_ID, }) } @@ -111,11 +114,11 @@ export const getPedulumAssets = async () => { */ export const useExternalAssetRegistry = () => { const assetHub = useAssetHubAssetRegistry() - //const pendulum = usePendulumAssetRegistry() + const pendulum = usePendulumAssetRegistry() return { [ASSET_HUB_ID as number]: assetHub, - // [PENDULUM_ID as number]: pendulum, + [PENDULUM_ID as number]: pendulum, } } diff --git a/src/api/staking.ts b/src/api/staking.ts index 607c23605..466756655 100644 --- a/src/api/staking.ts +++ b/src/api/staking.ts @@ -59,7 +59,7 @@ export const useCirculatingSupply = () => { } const getCirculatingSupply = () => async () => { - const res = await fetch("https://hydradx.api.subscan.io/api/scan/token") + const res = await fetch("https://hydration.api.subscan.io/api/scan/token") const data: Promise = res.json() diff --git a/src/api/transaction.ts b/src/api/transaction.ts index 6295e373f..365106467 100644 --- a/src/api/transaction.ts +++ b/src/api/transaction.ts @@ -39,7 +39,7 @@ export function useNextNonce(account: Maybe) { } export function getSubscanLink(blockNumber: string, txIndex: string) { - return `https://hydradx.subscan.io/extrinsic/${[blockNumber, txIndex].join( + return `https://hydration.subscan.io/extrinsic/${[blockNumber, txIndex].join( "-", )}` } diff --git a/src/components/Charts/AreaChart/AreaChart.tsx b/src/components/Charts/AreaChart/AreaChart.tsx index 664f7de80..d707d7046 100644 --- a/src/components/Charts/AreaChart/AreaChart.tsx +++ b/src/components/Charts/AreaChart/AreaChart.tsx @@ -79,7 +79,7 @@ const Label = ({ value }: { value: number }) => { zIndex: 1, }} > - + diff --git a/src/components/Layout/Header/MobileNavBar/MoreButton.tsx b/src/components/Layout/Header/MobileNavBar/MoreButton.tsx index 78abaeeb9..c8666755d 100644 --- a/src/components/Layout/Header/MobileNavBar/MoreButton.tsx +++ b/src/components/Layout/Header/MobileNavBar/MoreButton.tsx @@ -9,6 +9,7 @@ import { SQuestionmark } from "components/Layout/Header/Header.styled" import { Separator } from "components/Separator/Separator" import { Text } from "components/Typography/Text/Text" import { theme } from "theme" +import { DOC_LINK } from "utils/constants" const settingsEanbled = import.meta.env.VITE_FF_SETTINGS_ENABLED === "true" @@ -43,7 +44,7 @@ export const MoreButton = ({ tabs }: MoreButtonProps) => { )} = () => { const { t } = useTranslation() return ( - + = ({ diff --git a/src/components/Table/Table.styled.ts b/src/components/Table/Table.styled.ts index c0d78a2a0..04b278b45 100644 --- a/src/components/Table/Table.styled.ts +++ b/src/components/Table/Table.styled.ts @@ -179,16 +179,17 @@ export const TableHeader = styled.th<{ canSort?: boolean }>` export const TableData = styled.td<{ isExpanded?: boolean isSkeleton?: boolean + sub?: boolean }>` height: 56px; - ${({ isExpanded }) => (isExpanded ? `padding: 16px` : "padding: 0 16px")}; + padding: 0 16px; ${({ isSkeleton }) => !isSkeleton && "padding-right: 0px;"} text-align: start; ${({ isExpanded }) => - isExpanded && `background: rgba(${theme.rgbColors.white}, 0.06);`} + isExpanded && `background: rgba(${theme.rgbColors.white}, 0.03);`} &:last-of-type { width: 1px; @@ -198,8 +199,7 @@ export const TableData = styled.td<{ @media ${theme.viewport.gte.sm} { height: 82px; - ${({ isExpanded }) => - isExpanded ? `padding: 24px 32px` : "padding: 0 32px"}; + ${({ sub }) => (sub ? `padding: 24px 32px` : "padding: 0 32px")}; &:last-of-type { padding-right: 10px; diff --git a/src/i18n/locales/en/translations.json b/src/i18n/locales/en/translations.json index adf0bb186..98689e901 100644 --- a/src/i18n/locales/en/translations.json +++ b/src/i18n/locales/en/translations.json @@ -487,8 +487,15 @@ "wallet.assets.table.details.locked": "Locked", "wallet.assets.table.details.lockedVesting": "Locked in Vesting", "wallet.assets.table.details.lockedDemocracy": "Locked in Democracy", + "wallet.assets.table.details.unlockable": "Unlockable", + "wallet.assets.table.details.btn": "Unlock Assets", "wallet.assets.table.details.lockedStaking": "Total Locked in Staking", "wallet.assets.table.details.noprice.tooltip": "Spot price currently not available", + "wallet.assets.table.details.expired_one": "{{count}} Expired lock", + "wallet.assets.table.details.expired_other": "{{count}} Expired locks", + "wallet.assets.table.details.expiring": "100% Expires in {{duration}}", + "wallet.assets.table.details.unlock.onLoading": "Unlocking {{value, bignumber(type: token)}} HDX", + "wallet.assets.table.details.unlock.onSuccess": "Uncloked {{value, bignumber(type: token)}} HDX", "wallet.assets.table.empty.desc": "Looks like you don’t have any assets on Hydration yet. Click below to add them through cross-chain transfers.", "wallet.assets.table.empty.btn": "Transfer to Hydration", "wallet.assets.hydraPositions.empty.desc": "You still don't have any liquidity positions. Add liquidity to the Omnipool and begin your hydrated journey.", @@ -901,8 +908,11 @@ "migration.export.description": "As part of the rebranding, this app has moved to app.hydration.net.", "migration.export.question": "Would you like to migrate all past app settings to the new app?", "migration.export.button": "Migrate Settings", - "migration.import.title": "Do you wish to overwrite your settings?", - "migration.import.description": "You already transferred your settings on {{ date, dd/MM/yyyy hh:mm:ss }}. Do you wish to overwrite your current settings?", - "migration.import.button": "Overwrite Settings", + "migration.import.overwrite.title": "Do you wish to overwrite your settings?", + "migration.import.overwrite.description": "You already transferred your settings on {{ date, dd/MM/yyyy hh:mm:ss }}. Do you wish to overwrite your current settings?", + "migration.import.overwrite.button": "Overwrite Settings", + "migration.import.confirm.title": "You have opened a migration link", + "migration.import.confirm.description": "Do you want to import new app settings?", + "migration.import.confirm.button": "Yes, import settings", "migration.warning.text": "You can transfer Your app settings from HydraDX to Hydration" } diff --git a/src/sections/migration/MigrationProvider.utils.ts b/src/sections/migration/MigrationProvider.utils.ts index a843508ca..8f0c72533 100644 --- a/src/sections/migration/MigrationProvider.utils.ts +++ b/src/sections/migration/MigrationProvider.utils.ts @@ -5,7 +5,6 @@ import { persist } from "zustand/middleware" export const MIGRATION_LS_KEYS = [ "external-tokens", "address-book", - "toasts", "rpcUrl", "hydradx-rpc-list", "referral-codes", diff --git a/src/sections/migration/components/MigrationImportModal.tsx b/src/sections/migration/components/MigrationImportModal.tsx index 211a04942..e5329be48 100644 --- a/src/sections/migration/components/MigrationImportModal.tsx +++ b/src/sections/migration/components/MigrationImportModal.tsx @@ -2,7 +2,7 @@ import { Button } from "components/Button/Button" import { Modal } from "components/Modal/Modal" import { Separator } from "components/Separator/Separator" import { Text } from "components/Typography/Text/Text" -import { FC, useCallback, useEffect, useState } from "react" +import { FC, useCallback, useRef } from "react" import { useTranslation } from "react-i18next" import { importToLocalStorage, @@ -12,51 +12,42 @@ import MigrationLogo from "assets/icons/migration/MigrationLogo.svg?react" export const MigrationImportModal: FC<{ data?: string }> = ({ data }) => { const { t } = useTranslation() - const [lastImportDate, setLastImportDate] = useState(null) - const [isAutoImporting, setIsAutoImporting] = useState(false) const { migrationCompleted, setMigrationCompleted } = useMigrationStore() + const lastImportDateRef = useRef( + migrationCompleted && migrationCompleted !== "0" + ? new Date(migrationCompleted) + : null, + ) + + const lastImportDate = lastImportDateRef.current + const reloadAppWithTimestamp = useCallback( - (date: string) => { - setMigrationCompleted(date) + (date?: string) => { + setMigrationCompleted(date ?? "0") window.location.href = window.location.origin }, [setMigrationCompleted], ) - useEffect(() => { - const migrationCompletedOn = - migrationCompleted && migrationCompleted !== "0" - ? new Date(migrationCompleted) - : null - - if (migrationCompletedOn && !!data) { - setLastImportDate(new Date(migrationCompletedOn)) - return - } else if (!!data) { - setIsAutoImporting(true) - importToLocalStorage(data) - } - - reloadAppWithTimestamp(data ? new Date().toISOString() : "0") - }, [data, migrationCompleted, reloadAppWithTimestamp]) - - if (!lastImportDate || isAutoImporting) { - return null - } - return ( - {t("migration.import.title")} + {lastImportDate + ? t("migration.import.overwrite.title") + : t("migration.import.confirm.title")} - {t("migration.import.description", { date: lastImportDate })} + {lastImportDate + ? t("migration.import.overwrite.description", { + date: lastImportDate, + }) + : t("migration.import.confirm.description")} = ({ data }) => {
{data && ( )}
diff --git a/src/sections/pools/modals/AddLiquidity/AddLiquidityInfoCard.tsx b/src/sections/pools/modals/AddLiquidity/AddLiquidityInfoCard.tsx index 41e28784b..0fe539580 100644 --- a/src/sections/pools/modals/AddLiquidity/AddLiquidityInfoCard.tsx +++ b/src/sections/pools/modals/AddLiquidity/AddLiquidityInfoCard.tsx @@ -3,6 +3,7 @@ import InfoIcon from "assets/icons/LPInfoIcon.svg?react" import { Icon } from "components/Icon/Icon" import { SCardContainer, SLink } from "./AddLiquidity.styled" import { useTranslation } from "react-i18next" +import { DOC_LINK } from "utils/constants" export const PoolAddLiquidityInformationCard = () => { const { t } = useTranslation() @@ -14,7 +15,7 @@ export const PoolAddLiquidityInformationCard = () => { {t("liquidity.add.modal.information.text")} - + {t("liquidity.add.modal.information.linkText")} diff --git a/src/sections/referrals/components/FaqAccordion/FaqAccordion.tsx b/src/sections/referrals/components/FaqAccordion/FaqAccordion.tsx index 6ad448411..69135afed 100644 --- a/src/sections/referrals/components/FaqAccordion/FaqAccordion.tsx +++ b/src/sections/referrals/components/FaqAccordion/FaqAccordion.tsx @@ -7,6 +7,7 @@ import { FeatureBox } from "components/FeatureBox/FeatureBox" import { Text } from "components/Typography/Text/Text" import { useTranslation } from "react-i18next" import { theme } from "theme" +import { DOC_LINK } from "utils/constants" const FAQ_STEPS = [ { @@ -49,11 +50,7 @@ export const FaqAccordion = () => { }, }} > -
+ {t("referrals.faq.docs.learnMore")} diff --git a/src/sections/staking/sections/dashboard/components/Stats/Values/StakingValues.tsx b/src/sections/staking/sections/dashboard/components/Stats/Values/StakingValues.tsx index f576e72d9..259c1e10b 100644 --- a/src/sections/staking/sections/dashboard/components/Stats/Values/StakingValues.tsx +++ b/src/sections/staking/sections/dashboard/components/Stats/Values/StakingValues.tsx @@ -52,7 +52,7 @@ export const StakingValue = ({ )} {typeof value === "string" ? ( - + {value} ) : ( @@ -94,7 +94,7 @@ export const StakingValues = ({ ) : (
- + {t("value.tokenWithSymbol", { value: data?.availableBalance, symbol: "HDX", @@ -183,7 +183,7 @@ export const StakingValues = ({
) : (
- + {t("value.tokenWithSymbol", { value: data?.stakePosition?.stake, symbol: "HDX", @@ -244,7 +244,7 @@ export const AprStatValue = ({ const stakeApr = useStakeARP(availableBalance) return ( - + {stakeApr.isLoading ? ( ) : ( diff --git a/src/sections/stats/components/RecentTradesTable/RecentTradesTable.tsx b/src/sections/stats/components/RecentTradesTable/RecentTradesTable.tsx index b55bf6916..88c9007c2 100644 --- a/src/sections/stats/components/RecentTradesTable/RecentTradesTable.tsx +++ b/src/sections/stats/components/RecentTradesTable/RecentTradesTable.tsx @@ -27,7 +27,7 @@ export const RecentTradesTable = ({ data }: Props) => { const table = useRecentTradesTable(data) const onRowSelect = (hash: string) => { - window.open(`https://hydradx.subscan.io/extrinsic/${hash}`, "_blank") + window.open(`https://hydration.subscan.io/extrinsic/${hash}`, "_blank") } return ( diff --git a/src/sections/stats/components/RecentTradesTable/RecentTradesTable.utils.tsx b/src/sections/stats/components/RecentTradesTable/RecentTradesTable.utils.tsx index 5321ce28c..521fe8aab 100644 --- a/src/sections/stats/components/RecentTradesTable/RecentTradesTable.utils.tsx +++ b/src/sections/stats/components/RecentTradesTable/RecentTradesTable.utils.tsx @@ -172,7 +172,7 @@ export const useRecentTradesTable = (data: TRecentTradesTableData) => { cell: ({ row }) => (
diff --git a/src/sections/stats/sections/omnipoolAsset/LiquidityProvidersTable/LiquidityProvidersTable.tsx b/src/sections/stats/sections/omnipoolAsset/LiquidityProvidersTable/LiquidityProvidersTable.tsx index 1579ef331..26a87cce0 100644 --- a/src/sections/stats/sections/omnipoolAsset/LiquidityProvidersTable/LiquidityProvidersTable.tsx +++ b/src/sections/stats/sections/omnipoolAsset/LiquidityProvidersTable/LiquidityProvidersTable.tsx @@ -27,7 +27,7 @@ export const LiquidityProvidersTable = ({ data }: Props) => { const isDesktop = useMedia(theme.viewport.gte.sm) const onRowSelect = (account: string) => { - window.open(`https://hydradx.subscan.io/account/${account}`, "_blank") + window.open(`https://hydration.subscan.io/account/${account}`, "_blank") } const table = useLiquidityProvidersTable(data) diff --git a/src/sections/stats/sections/omnipoolAsset/LiquidityProvidersTable/LiquidityProvidersTable.utils.tsx b/src/sections/stats/sections/omnipoolAsset/LiquidityProvidersTable/LiquidityProvidersTable.utils.tsx index f3d55c717..9953b0615 100644 --- a/src/sections/stats/sections/omnipoolAsset/LiquidityProvidersTable/LiquidityProvidersTable.utils.tsx +++ b/src/sections/stats/sections/omnipoolAsset/LiquidityProvidersTable/LiquidityProvidersTable.utils.tsx @@ -115,7 +115,7 @@ export const useLiquidityProvidersTable = ( cell: ({ row }) => (
diff --git a/src/sections/stats/sections/overview/components/PieTotalValue/PieTotalValue.tsx b/src/sections/stats/sections/overview/components/PieTotalValue/PieTotalValue.tsx index d5bf1ad38..520becc4a 100644 --- a/src/sections/stats/sections/overview/components/PieTotalValue/PieTotalValue.tsx +++ b/src/sections/stats/sections/overview/components/PieTotalValue/PieTotalValue.tsx @@ -27,7 +27,7 @@ export const PieTotalValue = ({
{title}
- + { const { t } = useTranslation() @@ -107,11 +108,7 @@ export const WhyBonds = () => { }, }} > - + {t("bonds.whyBonds.link")} diff --git a/src/sections/trade/sections/bonds/table/BondsTable.tsx b/src/sections/trade/sections/bonds/table/BondsTable.tsx index d16065cfd..1e4f7513f 100644 --- a/src/sections/trade/sections/bonds/table/BondsTable.tsx +++ b/src/sections/trade/sections/bonds/table/BondsTable.tsx @@ -74,7 +74,7 @@ export const BondsTable = ({ {table.getHeaderGroups().map((hg) => ( - + {hg.headers.map((header) => ( {flexRender( diff --git a/src/sections/wallet/addToken/AddToken.utils.tsx b/src/sections/wallet/addToken/AddToken.utils.tsx index d71e08e12..5064b0367 100644 --- a/src/sections/wallet/addToken/AddToken.utils.tsx +++ b/src/sections/wallet/addToken/AddToken.utils.tsx @@ -12,6 +12,7 @@ import { TOAST_MESSAGES } from "state/toasts" import { Trans, useTranslation } from "react-i18next" import { ASSET_HUB_ID, + PENDULUM_ID, useExternalAssetRegistry, } from "api/externalAssetRegistry" import { useProviderRpcUrlStore } from "api/provider" @@ -157,7 +158,7 @@ const internalIds = new Map([ ["2230", "1000073"], ]) -export const SELECTABLE_PARACHAINS_IDS = [ASSET_HUB_ID /*PENDULUM_ID*/] +export const SELECTABLE_PARACHAINS_IDS = [ASSET_HUB_ID, PENDULUM_ID] export const PARACHAIN_CONFIG: { [x: number]: { @@ -365,6 +366,7 @@ export const useExternalTokenMeta = (id: string | undefined) => { return { ...meta, ...externalMeta, + externalId: externalAsset.id, } } diff --git a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.tsx b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.tsx index 0c372a581..29f182567 100644 --- a/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.tsx +++ b/src/sections/wallet/assets/farmingPositions/WalletFarmingPositions.tsx @@ -51,7 +51,7 @@ export const WalletFarmingPositions = ({ data }: Props) => {
{table.getHeaderGroups().map((hg) => ( - + {hg.headers.map((header) => ( {
{table.getHeaderGroups().map((hg) => ( - + {hg.headers.map((header) => ( {
{table.getHeaderGroups().map((hg) => ( - + {hg.headers.map((header) => ( { if (!row.original.symbol && row.original.isExternal) return ( { !isDesktop && setRow(row.original) }} @@ -144,7 +145,10 @@ export const WalletAssetsTable = ({ data, setShowAll, showAll }: Props) => { }} > {row.getVisibleCells().map((cell) => ( - + {flexRender( cell.column.columnDef.cell, cell.getContext(), @@ -153,10 +157,11 @@ export const WalletAssetsTable = ({ data, setShowAll, showAll }: Props) => { ))} {row.getIsSelected() && ( - + diff --git a/src/sections/wallet/assets/table/actions/WalletAssetsTable.styled.ts b/src/sections/wallet/assets/table/actions/WalletAssetsTable.styled.ts index 5d03ddd73..04507dce3 100644 --- a/src/sections/wallet/assets/table/actions/WalletAssetsTable.styled.ts +++ b/src/sections/wallet/assets/table/actions/WalletAssetsTable.styled.ts @@ -3,7 +3,7 @@ import { theme } from "theme" export const SActionButtonsContainer = styled.div` margin: calc(var(--modal-content-padding) * -1); - padding: 0 20px 20px; + padding: 0 12px 20px; background: rgba(${theme.rgbColors.darkBlue900}, 0.6); ` diff --git a/src/sections/wallet/assets/table/actions/WalletAssetsTableActions.tsx b/src/sections/wallet/assets/table/actions/WalletAssetsTableActions.tsx index afa03b3f4..e19fa2ab4 100644 --- a/src/sections/wallet/assets/table/actions/WalletAssetsTableActions.tsx +++ b/src/sections/wallet/assets/table/actions/WalletAssetsTableActions.tsx @@ -26,6 +26,7 @@ import { } from "sections/wallet/addToken/AddToken.utils" import { useRefetchProviderData } from "api/provider" import { useToast } from "state/toasts" +import { useQueryClient } from "@tanstack/react-query" type Props = { toggleExpanded: () => void @@ -234,6 +235,7 @@ export const AddTokenAction = ({ const { t } = useTranslation() const { account } = useAccount() const { addToken } = useUserExternalTokenStore() + const queryClient = useQueryClient() const externalAsset = useExternalTokenMeta(id) @@ -243,7 +245,7 @@ export const AddTokenAction = ({ const addExternalAsset = externalAsset ? () => { addToken({ - id: externalAsset.id, + id: externalAsset.externalId, name: externalAsset.name, symbol: externalAsset.symbol, decimals: externalAsset.decimals, @@ -251,6 +253,17 @@ export const AddTokenAction = ({ internalId: id, }) refetchProvider() + setTimeout(() => { + queryClient.removeQueries({ + predicate: (query) => { + return ( + query.queryKey.includes("spotPrice") && + query.queryKey.includes(id.toString()) + ) + }, + }) + }, 1000) + add("success", { title: ( { const { t } = useTranslation() + const { + assets: { native }, + } = useRpcProvider() const { account } = useAccount() const setFeeAsPayment = useSetAsFeePayment() const { featureFlags } = useRpcProvider() - const lockedValues = useLockedValues(row?.id ?? "") - if (!row) return null - const canBuy = row.tradability.inTradeRouter && row.tradability.canBuy - - const isNativeAsset = row.id === NATIVE_ASSET_ID + const isNativeAsset = row.id === native.id const displayFeePaymentAssetButton = isEvmAccount(account?.address) ? featureFlags.dispatchPermit @@ -89,6 +95,7 @@ export const WalletAssetsTableActionsMob = ({ +
{t("wallet.assets.table.header.transferable")} @@ -96,14 +103,13 @@ export const WalletAssetsTableActionsMob = ({ {t("value", { value: row.transferable })} - +
)} - {isUnknownExternalAsset ? ( ) : ( <> -
- {isNativeAsset && ( -
- - {t("wallet.assets.table.details.lockedStaking")} - - {lockedValues.isLoading ? ( - - ) : ( - - {t("value", { - value: lockedValues.data?.lockedStaking, - })} - - )} - {lockedValues.isLoading ? ( - - ) : ( - - - - )} -
- )} - {isNativeAsset && ( -
- - {t("wallet.assets.table.details.lockedDemocracy")} - - {lockedValues.isLoading ? ( - - ) : ( - - {t("value", { - value: lockedValues.data?.lockedDemocracy, - })} - - )} - {lockedValues.isLoading ? ( - - ) : ( - - - - )} -
- )} -
- - {t("wallet.assets.table.details.reserved")} - - - {t("value", { value: row.reserved })} - - - - -
- {isNativeAsset && ( -
- - {t("wallet.assets.table.details.lockedVesting")} - - {lockedValues.isLoading ? ( - - ) : ( - - {t("value", { - value: lockedValues.data?.lockedVesting, - })} - - )} - {lockedValues.isLoading ? ( - - ) : ( - - - - )} -
- )} -
- -
+ {isNativeAsset ? ( + + ) : ( + + )} +
{t("wallet.assets.table.actions.transfer")} + ) } + +const NativeLocks = ({ + reserved, + reservedDisplay, +}: { + reserved: BN + reservedDisplay: BN +}) => { + const { account } = useAccount() + const { t } = useTranslation() + const lockedTokens = useLockedNativeTokens() + const unlocable = useUnlockableTokens() + + const toast = TOAST_MESSAGES.reduce((memo, type) => { + const msType = type === "onError" ? "onLoading" : type + memo[type] = ( + + + + ) + return memo + }, {} as ToastMessage) + + const unlock = useUnlockTokens({ ids: unlocable.ids, toast }) + + return ( +
+
+ + {t("wallet.assets.table.details.lockedStaking")} + + {lockedTokens.isLoading ? ( + + ) : ( + + {t("value", { value: lockedTokens.lockStaking })} + + )} + {lockedTokens.isLoading ? ( + + ) : ( + + + + )} +
+ +
+
+ + {t("wallet.assets.table.details.lockedDemocracy")} + + {lockedTokens.isLoading ? ( + + ) : ( + + {t("value", { value: lockedTokens.lockDemocracy })} + + )} + {lockedTokens.isLoading ? ( + + ) : ( + + + + )} + {unlocable.endDate ? ( + + + {t("wallet.assets.table.details.expiring", { + duration: unlocable.endDate, + })} + + + ) : null} +
+
+ + {enableUnlockTokens && ( + <> +
+ + {t("wallet.assets.table.details.unlockable")} + + + + {unlocable.isLoading ? ( + + ) : ( + t("value.token", { value: unlocable.value ?? BN_0 }) + )} + + + {unlocable.isLoading ? ( + + ) : ( + + )} + + {unlocable.votesUnlocked ? ( + + + {t("wallet.assets.table.details.expired", { + count: unlocable.votesUnlocked, + })} + + + ) : null} +
+ +
+ +
+ + )} + +
+ + {t("wallet.assets.table.details.reserved")} + + + {t("value", { value: reserved })} + + + + +
+ +
+
+ + {t("wallet.assets.table.details.lockedVesting")} + + {lockedTokens.isLoading ? ( + + ) : ( + + {t("value", { value: lockedTokens.lockVesting })} + + )} + {lockedTokens.isLoading ? ( + + ) : ( + + + + )} +
+
+
+ ) +} + +const Locks = ({ + reserved, + reservedDisplay, +}: { + reserved: BN + reservedDisplay: BN +}) => { + const { t } = useTranslation() + + return ( +
+
+ + {t("wallet.assets.table.details.reserved")} + + + {t("value", { value: reserved })} + + + + +
+
+ ) +} diff --git a/src/sections/wallet/assets/table/data/WalletAssetsTableData.utils.ts b/src/sections/wallet/assets/table/data/WalletAssetsTableData.utils.ts index f2d930ec5..f3972d547 100644 --- a/src/sections/wallet/assets/table/data/WalletAssetsTableData.utils.ts +++ b/src/sections/wallet/assets/table/data/WalletAssetsTableData.utils.ts @@ -2,12 +2,17 @@ import { useAccountBalances } from "api/accountBalances" import { useTokenLocks } from "api/balances" import { useMemo } from "react" import { NATIVE_ASSET_ID } from "utils/api" -import { BN_0, BN_1 } from "utils/constants" +import { BLOCK_TIME, BN_0, BN_NAN } from "utils/constants" import { arraySearch } from "utils/helpers" import { useDisplayPrice, useDisplayPrices } from "utils/displayAsset" import { useRpcProvider } from "providers/rpcProvider" import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { useAcceptedCurrencies, useAccountCurrency } from "api/payments" +import { useAccountVotes } from "api/democracy" +import { durationInDaysAndHoursFromNow } from "utils/formatting" +import { ToastMessage, useStore } from "state/store" +import { useMutation, useQueryClient } from "@tanstack/react-query" +import { QUERY_KEYS } from "utils/queryKeys" export const useAssetsData = ({ isAllAssets, @@ -22,7 +27,7 @@ export const useAssetsData = ({ const { account } = useAccount() const address = givenAddress ?? account?.address - const balances = useAccountBalances(address) + const balances = useAccountBalances(address, true) const nativeTokenWithBalance = balances.data?.native const tokensWithBalance = useMemo(() => { if (nativeTokenWithBalance && balances.data) { @@ -58,6 +63,7 @@ export const useAssetsData = ({ ) const data = useMemo(() => { + if (!tokensWithBalance.length || !spotPrices.data) return [] const rowsWithBalance = tokensWithBalance.map((balance) => { let { decimals, id, name, symbol, isExternal } = assets.getAsset( balance.id, @@ -68,7 +74,7 @@ export const useAssetsData = ({ ) const spotPrice = spotPrices.data?.find((spotPrice) => spotPrice?.tokenIn === id) - ?.spotPrice ?? BN_1 + ?.spotPrice ?? BN_NAN const reserved = balance.reservedBalance.shiftedBy(-decimals) const reservedDisplay = reserved.times(spotPrice) @@ -184,7 +190,7 @@ export const useAssetsData = ({ allAssets, ]) - return { data, isLoading: balances.isLoading } + return { data, isLoading: balances.isLoading || spotPrices.isInitialLoading } } export type AssetsTableData = ReturnType["data"][number] @@ -237,3 +243,112 @@ export const useLockedValues = (id: string) => { isLoading: locks.isInitialLoading || spotPrice.isInitialLoading, } } + +export const useLockedNativeTokens = () => { + const { + assets: { + native: { id, decimals }, + }, + } = useRpcProvider() + const locks = useTokenLocks(id) + const spotPrice = useDisplayPrice(id) + + const lockVesting = + locks.data + ?.find((lock) => lock.type === "ormlvest") + ?.amount.shiftedBy(-decimals) ?? BN_0 + const lockDemocracy = + locks.data + ?.find((lock) => lock.type === "democrac") + ?.amount.shiftedBy(-decimals) ?? BN_0 + const lockStaking = + locks.data + ?.find((lock) => lock.type === "stk_stks") + ?.amount.shiftedBy(-decimals) ?? BN_0 + + const lockVestingDisplay = lockVesting.times(spotPrice.data?.spotPrice ?? 1) + const lockDemocracyDisplay = lockDemocracy.times( + spotPrice.data?.spotPrice ?? 1, + ) + const lockStakingDisplay = lockStaking.times(spotPrice.data?.spotPrice ?? 1) + + return { + isLoading: locks.isLoading || spotPrice.isLoading, + lockVesting, + lockDemocracy, + lockStaking, + lockVestingDisplay, + lockDemocracyDisplay, + lockStakingDisplay, + } +} + +export const useUnlockableTokens = () => { + const { + assets: { native }, + } = useRpcProvider() + const locks = useTokenLocks(native.id) + const votes = useAccountVotes() + const spotPrice = useDisplayPrice(native.id) + + const lockDemocracy = + locks.data?.find((lock) => lock.type === "democrac")?.amount ?? BN_0 + + const value = lockDemocracy.isZero() + ? BN_0 + : lockDemocracy + .minus(votes.data?.maxLockedValue ?? 0) + .shiftedBy(-native.decimals) + const date = votes.data?.maxLockedBlock.times(BLOCK_TIME) + const endDate = + votes.data && !votes.data.maxLockedBlock.isZero() + ? durationInDaysAndHoursFromNow(date?.times(1000).toNumber() ?? 0) + : undefined + + return { + isLoading: votes.isInitialLoading || spotPrice.isLoading || locks.isLoading, + ids: votes.data?.ids ?? [], + value, + displayValue: value?.times(spotPrice.data?.spotPrice ?? 1), + votesUnlocked: votes.data?.ids.length, + endDate, + } +} + +export const useUnlockTokens = ({ + ids, + toast, +}: { + ids: string[] + toast: ToastMessage +}) => { + const { api, assets } = useRpcProvider() + const { account } = useAccount() + const { createTransaction } = useStore() + const queryClient = useQueryClient() + + return useMutation(async () => { + const txs = ids.map((id) => api.tx.democracy.removeVote(id)) + + if (!txs.length) return null + + return await createTransaction( + { + tx: api.tx.utility.batchAll([ + ...txs, + ...(account?.address + ? [api.tx.democracy.unlock(account.address)] + : []), + ]), + }, + { + toast, + onSuccess: () => { + queryClient.invalidateQueries( + QUERY_KEYS.lock(account?.address, assets.native.id), + ) + }, + }, + ) + }) +} diff --git a/src/sections/wallet/assets/table/details/WalletAssetsTableDetails.styled.ts b/src/sections/wallet/assets/table/details/WalletAssetsTableDetails.styled.ts index 5a17a5edd..f85d521ce 100644 --- a/src/sections/wallet/assets/table/details/WalletAssetsTableDetails.styled.ts +++ b/src/sections/wallet/assets/table/details/WalletAssetsTableDetails.styled.ts @@ -13,16 +13,15 @@ export const SContainer = styled.div<{ } ${({ hasChain, isNativeAsset }) => { - const cols = isNativeAsset ? 2 : hasChain ? 2 : 1 + const cols = isNativeAsset ? 3 : hasChain ? 2 : 1 return ` grid-template-columns: repeat(${cols}, 1fr); - justify-items: ${cols === 1 ? "center" : "normal"}; & > div { text-align: center; - &:not(:nth-of-type(${cols}n)) { - border-right: 1px solid rgba(255, 255, 255, 0.12); + &:not(:nth-of-type(${cols})):not(:nth-of-type(${cols * 2 + 1})) { + border-right: 1px solid rgba(158, 167, 186, 0.06); } &:not(:has(p)) { @@ -37,3 +36,19 @@ export const SContainer = styled.div<{ ` }} ` + +export const SLocksContainer = styled.div` + margin-top: 2px; + padding: 0 4px; + + width: fit-content; + + display: flex; + justify-content: center; + align-items: center; + gap: 4px; + + border-radius: 4px; + + background: rgba(${theme.rgbColors.white}, 0.06); +` diff --git a/src/sections/wallet/assets/table/details/WalletAssetsTableDetails.tsx b/src/sections/wallet/assets/table/details/WalletAssetsTableDetails.tsx index b8000763a..8fcad1fee 100644 --- a/src/sections/wallet/assets/table/details/WalletAssetsTableDetails.tsx +++ b/src/sections/wallet/assets/table/details/WalletAssetsTableDetails.tsx @@ -4,15 +4,23 @@ import { DisplayValue } from "components/DisplayValue/DisplayValue" import { Icon } from "components/Icon/Icon" import { Text } from "components/Typography/Text/Text" import { useMemo } from "react" -import Skeleton from "react-loading-skeleton" -import { useTranslation } from "react-i18next" +import { Trans, useTranslation } from "react-i18next" import { useRpcProvider } from "providers/rpcProvider" -import { SContainer } from "./WalletAssetsTableDetails.styled" -import { NATIVE_ASSET_ID } from "utils/api" +import { SContainer, SLocksContainer } from "./WalletAssetsTableDetails.styled" import { AssetsTableData, - useLockedValues, + useLockedNativeTokens, + useUnlockableTokens, + useUnlockTokens, } from "sections/wallet/assets/table/data/WalletAssetsTableData.utils" +import BN from "bignumber.js" +import { Button } from "components/Button/Button" +import { Separator } from "components/Separator/Separator" +import { BN_0 } from "utils/constants" +import { useAccount } from "sections/web3-connect/Web3Connect.utils" +import { TOAST_MESSAGES } from "state/toasts" +import { ToastMessage } from "state/store" +import Skeleton from "react-loading-skeleton" import { AnyParachain } from "@galacticcouncil/xcm-core" import { isAnyParachain } from "utils/helpers" import { AssetTableName } from "components/AssetTableName/AssetTableName" @@ -22,17 +30,219 @@ import { theme } from "theme" const chains = Array.from(chainsMap.values()) +export const enableUnlockTokens = false + export const WalletAssetsTableDetails = ({ reserved, reservedDisplay, id, }: AssetsTableData) => { + const { + assets: { native }, + } = useRpcProvider() + + const isNativeAsset = id === native.id + + if (isNativeAsset) + return ( + + ) + + return ( + + ) +} + +const NativeAssetDetails = ({ + reserved, + reservedDisplay, +}: { + reserved: BN + reservedDisplay: BN +}) => { + const { account } = useAccount() const { t } = useTranslation() - const { assets } = useRpcProvider() + const lockedTokens = useLockedNativeTokens() + const unlocable = useUnlockableTokens() + + const toast = TOAST_MESSAGES.reduce((memo, type) => { + const msType = type === "onError" ? "onLoading" : type + memo[type] = ( + + + + ) + return memo + }, {} as ToastMessage) + + const unlock = useUnlockTokens({ ids: unlocable.ids, toast }) + + return ( + +
+ + {t("wallet.assets.table.details.lockedStaking")} + + + {lockedTokens.isLoading ? ( + + ) : ( + t("value.token", { value: lockedTokens.lockStaking }) + )} + + + {lockedTokens.isLoading ? ( + + ) : ( + + )} + +
+
+ + {t("wallet.assets.table.details.lockedDemocracy")} + + + {lockedTokens.isLoading ? ( + + ) : ( + t("value.token", { value: lockedTokens.lockDemocracy }) + )} + + + {lockedTokens.isLoading ? ( + + ) : ( + + )} + + {unlocable.endDate ? ( + + + {t("wallet.assets.table.details.expiring", { + duration: unlocable.endDate, + })} + + + ) : null} +
+
+ {enableUnlockTokens && ( +
+ + {t("wallet.assets.table.details.unlockable")} + + + + {unlocable.isLoading ? ( + + ) : ( + t("value.token", { value: unlocable.value ?? BN_0 }) + )} + + + {unlocable.isLoading ? ( + + ) : ( + + )} + + {unlocable.votesUnlocked ? ( + + + {t("wallet.assets.table.details.expired", { + count: unlocable.votesUnlocked, + })} + + + ) : null} +
+ )} + {enableUnlockTokens && ( + + )} +
+
+ +

+ +

+
+

+

+
+ + {t("wallet.assets.table.details.reserved")} + + + {t("value.token", { value: reserved })} + + + + +
+
+ + {t("wallet.assets.table.details.lockedVesting")} + + + {lockedTokens.isLoading ? ( + + ) : ( + t("value.token", { value: lockedTokens.lockVesting }) + )} + + + {lockedTokens.isLoading ? ( + + ) : ( + + )} + +
+
+ ) +} - const lockedValues = useLockedValues(id) +const AssetDetails = ({ + reserved, + reservedDisplay, + id, +}: { + reserved: BN + reservedDisplay: BN + id: string +}) => { + const { t } = useTranslation() + const { assets } = useRpcProvider() - const asset = useMemo(() => { + const origin = useMemo(() => { const assetDetails = assets.getAsset(id) const chain = chains.find( @@ -41,105 +251,41 @@ export const WalletAssetsTableDetails = ({ chain.parachainId === Number(assetDetails.parachainId), ) as AnyParachain + if (!chain) return undefined + return { - chain: chain?.key, - name: chain?.name, + chain: chain.key, + name: chain.name, symbol: assetDetails.symbol, } }, [assets, id]) - const isNativeAsset = id === NATIVE_ASSET_ID - const hasChain = !!asset?.chain - return ( - - {hasChain && ( + + {origin && (
{t("wallet.assets.table.details.origin")} -
- } /> +
+ } /> - {asset?.name} + {origin.name}
)} - {isNativeAsset && ( -
- - {t("wallet.assets.table.details.lockedStaking")} - - {lockedValues.isLoading ? ( - - ) : ( - - {t("value.token", { value: lockedValues.data?.lockedStaking })} - - )} - {lockedValues.isLoading ? ( - - ) : ( - - - - )} -
- )} - {isNativeAsset && ( -
- - {t("wallet.assets.table.details.lockedDemocracy")} - - {lockedValues.isLoading ? ( - - ) : ( - - {t("value.token", { value: lockedValues.data?.lockedDemocracy })} - - )} - {lockedValues.isLoading ? ( - - ) : ( - - - - )} -
- )} -
- +
+ {t("wallet.assets.table.details.reserved")} - + {t("value.token", { value: reserved })} - +
- {isNativeAsset && ( -
- - {t("wallet.assets.table.details.lockedVesting")} - - {lockedValues.isLoading ? ( - - ) : ( - - {t("value.token", { value: lockedValues.data?.lockedVesting })} - - )} - {lockedValues.isLoading ? ( - - ) : ( - - - - )} -
- )} ) } diff --git a/src/seo.ts b/src/seo.ts index af5d6b4ef..e0daa3887 100644 --- a/src/seo.ts +++ b/src/seo.ts @@ -11,9 +11,9 @@ export const SEO_METADATA = { title: "Hydration - An Ocean of Liquidity", description: "Hydration is a next-gen DeFi protocol which is designed to bring an ocean of liquidity to Polkadot. Our tool for the job the Hydration - an innovative Automated Market Maker (AMM) which unlocks unparalleled efficiencies by combining all assets in a single trading pool.", - image: "https://app.hydradx.io/images/meta-image.jpg", + image: "https://hydration.net/opengraph-image.png", }, referrals: { - image: "https://hydradx.io/assets/meta-referrals-image.jpg", + image: "https://hydration.net/opengraph-image-ref.png", }, } satisfies MetadataMap diff --git a/src/utils/constants.ts b/src/utils/constants.ts index d5e60ef70..6ee7e4c68 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -45,3 +45,5 @@ export const SLIPPAGE_LIMIT = new BN(3) //decimals export const TRILL = 12 export const QUINTILL = 18 + +export const DOC_LINK = "https://docs.hydration.net" diff --git a/src/utils/evm.ts b/src/utils/evm.ts index 16dee28e0..b7bc6a258 100644 --- a/src/utils/evm.ts +++ b/src/utils/evm.ts @@ -78,7 +78,7 @@ export function getEvmTxLink( } else if (key === "moonbeam") { return `https://moonbeam.subscan.io/tx/${txHash}` } else { - return `https://hydradx.subscan.io/tx/${txHash}` + return `https://hydration.subscan.io/tx/${txHash}` } } diff --git a/src/utils/externalAssets.ts b/src/utils/externalAssets.ts index 4951380d3..b71628088 100644 --- a/src/utils/externalAssets.ts +++ b/src/utils/externalAssets.ts @@ -3,7 +3,6 @@ import { PENDULUM_ID } from "api/externalAssetRegistry" import { Buffer } from "buffer" import { InteriorProp, - isGeneralKey, TExternalAssetInput, } from "sections/wallet/addToken/AddToken.utils" import { Option } from "@polkadot/types" @@ -11,24 +10,6 @@ import { Option } from "@polkadot/types" export const getPendulumInputData = ( location: HydradxRuntimeXcmAssetLocation, ): TExternalAssetInput => { - const formatGeneralKey = (key: string) => { - const isHex = key.startsWith("0x") - const bytes = Buffer.from( - isHex ? key.slice(2) : key, - isHex ? "hex" : "ascii", - ) - - const length = bytes.buffer.byteLength - const data = Buffer.concat([bytes, Buffer.alloc(32 - length)]).toString( - "hex", - ) - - return { - length: length.toString(), - data: `0x${data}`, - } - } - const interiorType = location.interior.type if (interiorType !== "Here") { @@ -38,22 +19,10 @@ export const getPendulumInputData = ( const newInteriorType = `X${Number(interiorType.slice(1)) + 1}` - const props = (Array.isArray(interior) ? interior : [interior]).map( - (interiorProp) => { - const formatedProp = isGeneralKey(interiorProp) - ? { - GeneralKey: formatGeneralKey(interiorProp["GeneralKey"]), - } - : interiorProp - - return formatedProp - }, - ) - return { parents: "1", interior: { - [newInteriorType]: [{ Parachain: PENDULUM_ID.toString() }, ...props], + [newInteriorType]: [{ Parachain: PENDULUM_ID.toString() }, ...interior], }, } } else { diff --git a/src/utils/formatting.ts b/src/utils/formatting.ts index 04777c8b4..1f110685c 100644 --- a/src/utils/formatting.ts +++ b/src/utils/formatting.ts @@ -1,4 +1,11 @@ -import { format, Locale } from "date-fns" +import { + addMilliseconds, + differenceInDays, + format, + formatDistanceToNowStrict, + isBefore, + Locale, +} from "date-fns" import { enUS } from "date-fns/locale" import { z } from "zod" import { BigNumberLikeType, normalizeBigNumber } from "./balance" @@ -308,6 +315,21 @@ export const customFormatDuration = ({ } } +export const durationInDaysAndHoursFromNow = (milliseconds: number) => { + const now = new Date() + const end = addMilliseconds(now, milliseconds) + + if (isBefore(end, now)) return undefined + + if (differenceInDays(end, now)) + return formatDistanceToNowStrict(end, { + unit: "day", + roundingMethod: "floor", + }) + + return customFormatDuration({ end: milliseconds }).duration +} + export const qs = ( query: Record, { preppendPrefix = true, prefix = "?" } = {}, @@ -354,5 +376,5 @@ export const getSubscanLinkByType = ( ? `/${[params?.blockNumber, params?.txIndex].join("-")}` : "" - return `https://hydradx.subscan.io/${type}${extrinsicPath}` + return `https://hydration.subscan.io/${type}${extrinsicPath}` } diff --git a/src/utils/queryKeys.ts b/src/utils/queryKeys.ts index ffcebb110..ee2df8a13 100644 --- a/src/utils/queryKeys.ts +++ b/src/utils/queryKeys.ts @@ -29,11 +29,15 @@ export const QUERY_KEYS = { ], miningPosition: (id: string) => ["miningPosition", id], miningPositionXYK: (id: string) => ["miningPositionXYK", id], - accountBalances: (id: Maybe) => [ + accountBalancesLive: (id: Maybe) => [ QUERY_KEY_PREFIX, "accountBalances", id?.toString(), ], + accountBalances: (id: Maybe) => [ + "accountBalances", + id?.toString(), + ], accountOmnipoolPositions: (id: string | undefined) => [ "accountOmnipoolPositions", id, @@ -302,10 +306,16 @@ export const QUERY_KEYS = { insufficientFee: ["insufficientFee"], coingeckoUsd: ["coingeckoUsd"], polStats: ["polStats"], - referendums: (accountAddress?: string) => [ + referendums: (accountAddress?: string, type?: "ongoing" | "finished") => [ QUERY_KEY_PREFIX, - accountAddress, "referendums", + accountAddress, + type, + ], + referendumVotes: (accountAddress?: string) => [ + QUERY_KEY_PREFIX, + "referendumVotes", + accountAddress, ], referendumInfo: (id: string) => [QUERY_KEY_PREFIX, id, "referendumInfo"], stats: ( diff --git a/yarn.lock b/yarn.lock index 7e40a55fe..f92258fb2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2586,10 +2586,10 @@ resolved "https://registry.yarnpkg.com/@galacticcouncil/api-augment/-/api-augment-0.0.6.tgz#fc54c04c3bb953db3f739ea2c5820153088d564d" integrity sha512-5Qq+dzRoyuMS6uUXjl1asRrosIQ1n0vD0dzbxK8H8f3hmIzDdpiQVqlqWBLEc7D/PA7VM/7j1scICpdjtJJELw== -"@galacticcouncil/apps@^3.9.0": - version "3.9.0" - resolved "https://registry.yarnpkg.com/@galacticcouncil/apps/-/apps-3.9.0.tgz#87ec48a6dfc46a068e1d4eabf1e7cf0c4959d12b" - integrity sha512-KtdccozlLbtpQyMA7CwH3chFh5gK6/iR7rzCkUAALtfuhjJDSfZitWMiG++Kli5W+n7s0xxleqy3iDO+dhMgcg== +"@galacticcouncil/apps@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@galacticcouncil/apps/-/apps-3.9.1.tgz#3cafd864a8eddb8eac82bb52397d3789a1499f4e" + integrity sha512-t69sW8dWexThPkITIAzTJdvwGMO16UuIYCuWISFzieIUnCgBbD0Q8pnDyh2Av7ZNKK5d8NPDbjDiW29CTCpCVQ== dependencies: "@cfx-kit/wallet-avatar" "0.0.5" "@thi.ng/atom" "^5.1.3" @@ -2632,10 +2632,10 @@ resolved "https://registry.yarnpkg.com/@galacticcouncil/math-xyk/-/math-xyk-1.0.0.tgz#eeb6f3693587c96131647a24af31536cab423d96" integrity sha512-n44M7jKes5Rxr4RQZ5W7kscTfoO4xwhW3VL/VyaEP1KEHMavlICpDNOlCwO/k6RTr+UXU8cHLJZdBzGFa2soJA== -"@galacticcouncil/sdk@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@galacticcouncil/sdk/-/sdk-3.0.0.tgz#947001ad629414b40e031d8af0d146adb9227e06" - integrity sha512-vm6mqQ5u3HyX5+0oLP0an6BkmuKi06dNWOcHFKIgaBMXYwrwL5RbqiN5hG+baSefla0yWl1PB+o4VB5pfvhpFA== +"@galacticcouncil/sdk@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@galacticcouncil/sdk/-/sdk-3.0.1.tgz#d634f2804dd09c98b8ea3b7ef90691368e38c320" + integrity sha512-zw3p4XL2NcZ1RerSmzpMesrpHUY8oY7v/hm3YG9oXGnhEqsDOVoyUnyDJZB7S7Q0Hf29yjdepSv1qNrUDA3Zog== dependencies: "@galacticcouncil/math-lbp" "^1.0.0" "@galacticcouncil/math-liquidity-mining" "^1.0.0" @@ -2646,10 +2646,10 @@ bignumber.js "^9.1.0" lodash.clonedeep "^4.5.0" -"@galacticcouncil/ui@^3.2.2": - version "3.2.2" - resolved "https://registry.yarnpkg.com/@galacticcouncil/ui/-/ui-3.2.2.tgz#8fb87fd668c862e944baa72af6a9c1693c84b17f" - integrity sha512-H0dbDVxmklRYhERtVRU2AJxdUFcrzzS1d460RIeZQ6RAns1zHn7+h1Qk9xQUUb01U4fUlXYLrRgR+D4rRNpv4Q== +"@galacticcouncil/ui@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@galacticcouncil/ui/-/ui-3.2.3.tgz#847da6005d09d4a1910544f6b233157f30565382" + integrity sha512-SLCrwNwalVwV9PCmfXgFZ8wVTDEBRsZp40G1nLXzuDNwnkjx7UhXY1L6M9N7KLi92cnswoM4baRKXHgyNVzkAQ== dependencies: "@floating-ui/dom" "^1.5.1" "@lit/reactive-element" "^1.0.0" @@ -14301,9 +14301,9 @@ victory-vendor@^36.6.8: d3-timer "^3.0.1" viem@^2.12.0: - version "2.13.5" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.13.5.tgz#8bff8f982f40871867d4729794f503e4d4452bf9" - integrity sha512-jXkFh52GwBLJJE/OWkPZdXwiO3zpgTL7ebhpMcQkaa7F7xEhYeGBjqs26zn6rjlUYP43JjoAf/VnpmbYTQvR6Q== + version "2.13.6" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.13.6.tgz#32d1dc3215627044972bb905db4adfcf674655f1" + integrity sha512-BhvYhLrExC9P4AH9Gu/2A3VPUFkJT/ayH+A9anco2Ja/D0h3NStq+2uF4htcly1e68/U7IOrlCyX3Jz9zqeEJA== dependencies: "@adraffy/ens-normalize" "1.10.0" "@noble/curves" "1.2.0"