diff --git a/apps/portal/package.json b/apps/portal/package.json index a702f8b77..ee9a0cf43 100644 --- a/apps/portal/package.json +++ b/apps/portal/package.json @@ -49,6 +49,7 @@ "@talismn/web-icons": "workspace:^", "@tanstack/react-query": "^5.32.0", "@visx/visx": "^3.1.2", + "avail-js-sdk": "^0.2.13", "bignumber.js": "^9.1.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", diff --git a/apps/portal/src/components/widgets/staking/substrate/NominationPoolsStakeSideSheet.tsx b/apps/portal/src/components/widgets/staking/substrate/NominationPoolsStakeSideSheet.tsx index e8cbec3bd..8c2d56307 100644 --- a/apps/portal/src/components/widgets/staking/substrate/NominationPoolsStakeSideSheet.tsx +++ b/apps/portal/src/components/widgets/staking/substrate/NominationPoolsStakeSideSheet.tsx @@ -1,4 +1,4 @@ -import { ChainProvider } from '../../../../domains/chains' +import { ChainProvider, useChainState } from '../../../../domains/chains' import { nominationPoolsEnabledChainsState, type ChainInfo } from '../../../../domains/chains/recoils' import { useEraEtaFormatter } from '../../../../domains/common/hooks' import { useApr } from '../../../../domains/staking/substrate/nominationPools' @@ -7,13 +7,18 @@ import StakeForm from '../../../recipes/StakeForm/StakeForm' import ErrorBoundary from '../../ErrorBoundary' import { AssetSelect, ControlledStakeForm } from './StakeForm' import { CircularProgressIndicator } from '@talismn/ui' +import { Text } from '@talismn/ui' import BN from 'bn.js' import { Suspense, useState, useTransition } from 'react' import { useSearchParams } from 'react-router-dom' import { useRecoilValue } from 'recoil' const Rewards = () => { - return <>{useApr().toLocaleString(undefined, { style: 'percent', maximumFractionDigits: 2 })} + const chain = useRecoilValue(useChainState()) + const apr = useApr() + + if (chain.id === 'avail') return Coming Soon + return <>{apr.toLocaleString(undefined, { style: 'percent', maximumFractionDigits: 2 })} } const EraEta = () => { diff --git a/apps/portal/src/components/widgets/staking/substrate/NominationPoolsStatisticsSideSheet.tsx b/apps/portal/src/components/widgets/staking/substrate/NominationPoolsStatisticsSideSheet.tsx index bc81f5c9a..ec0857a0b 100644 --- a/apps/portal/src/components/widgets/staking/substrate/NominationPoolsStatisticsSideSheet.tsx +++ b/apps/portal/src/components/widgets/staking/substrate/NominationPoolsStatisticsSideSheet.tsx @@ -305,7 +305,13 @@ const ExistingPool = (props: NominationPoolsStatisticsSideSheetProps & { pool: D poolStatus={props.pool.status} balance={{balance.decimalAmount.toLocaleString()}} rewards={{last15DaysTotalPayouts.toLocaleString()}} - apr={stakedReturn.toLocaleString(undefined, { style: 'percent' })} + apr={ + chain.id === 'avail' ? ( + Coming Soon + ) : ( + stakedReturn.toLocaleString(undefined, { style: 'percent' }) + ) + } nextEraEta={useEraEtaFormatter()(1)} unbondings={useMemo( () => diff --git a/apps/portal/src/components/widgets/staking/substrate/StakeCalculatorDialog.tsx b/apps/portal/src/components/widgets/staking/substrate/StakeCalculatorDialog.tsx index 20b7f8f52..9a5bbc21d 100644 --- a/apps/portal/src/components/widgets/staking/substrate/StakeCalculatorDialog.tsx +++ b/apps/portal/src/components/widgets/staking/substrate/StakeCalculatorDialog.tsx @@ -4,6 +4,7 @@ import { useApr } from '../../../../domains/staking/substrate/nominationPools' import StakeCalculatorDialogComponent from '../../../recipes/StakeCalculatorDialog' import ErrorBoundary from '../../ErrorBoundary' import { AssetSelect } from './StakeForm' +import { Text } from '@talismn/ui' import BN from 'bn.js' import { Suspense, useDeferredValue, useMemo, useState, useTransition } from 'react' import { useRecoilValue } from 'recoil' @@ -11,6 +12,7 @@ import { useRecoilValue } from 'recoil' type StakeCalculatorDialogProps = { open?: boolean; onRequestDismiss: () => unknown } const EstimatedYield = (props: { amount: string }) => { + const chain = useRecoilValue(useChainState()) const stakedReturn = useApr() const amount = useTokenAmount(props.amount) @@ -28,6 +30,16 @@ const EstimatedYield = (props: { amount: string }) => { const dailyYield = useTokenAmountFromPlanck(useMemo(() => bnPlanck?.divn(365), [bnPlanck])) + if (chain.id === 'avail') + return ( + Coming Soon} + monthlyYield={monthlyYield.decimalAmount?.toLocaleString()} + weeklyYield={weeklyYield.decimalAmount?.toLocaleString()} + dailyYield={dailyYield.decimalAmount?.toLocaleString()} + /> + ) + return ( (props: { const EstimatedYield = memo( (props: { amount: Decimal }) => { + const chain = useRecoilValue(Chains_useChainState()) const stakedReturn = useApr() const annualReturn = useMemo( () => new BN(props.amount.planck.toString()).muln(stakedReturn), @@ -255,6 +255,9 @@ const EstimatedYield = memo( ) const parsedAnnualReturn = useTokenAmountFromPlanck(annualReturn) + if (chain.id === 'avail') + return Coming Soon} fiatAmount={null} /> + return ( { - return <>{useApr().toLocaleString(undefined, { style: 'percent', maximumFractionDigits: 2 })} + const chain = useRecoilValue(useChainState()) + const apr = useApr() + + if (chain.id === 'avail') return Coming Soon + return <>{apr.toLocaleString(undefined, { style: 'percent', maximumFractionDigits: 2 })} } const useAvailableBalance = () => { diff --git a/apps/portal/src/domains/chains/config.ts b/apps/portal/src/domains/chains/config.ts index afdf12cd0..f290cac69 100644 --- a/apps/portal/src/domains/chains/config.ts +++ b/apps/portal/src/domains/chains/config.ts @@ -57,6 +57,13 @@ export const chainConfigs: ChainConfig[] = [ talismanPools: [8], novaIndexerUrl: 'https://api.subquery.network/sq/nova-wallet/nova-wallet---vara', }, + // Avail + { + genesisHash: '0xb91746b45e0346cc2f815a520b9c6cb4d5c0902af848db0a80f85932d2e8276a', + hasNominationPools: true, + priorityPool: 2, + talismanPools: [2], + }, // Westend { genesisHash: '0xe143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e', diff --git a/apps/portal/src/domains/common/recoils/api.ts b/apps/portal/src/domains/common/recoils/api.ts index a8800dd3e..2c926b537 100644 --- a/apps/portal/src/domains/common/recoils/api.ts +++ b/apps/portal/src/domains/common/recoils/api.ts @@ -1,10 +1,26 @@ import { useSubstrateApiEndpoint } from '..' +import { chainsState } from '@/domains/chains' import { ApiPromise, WsProvider } from '@polkadot/api' +import * as AvailJsSdk from 'avail-js-sdk' import { selectorFamily } from 'recoil' export const substrateApiState = selectorFamily({ key: 'SubstrateApiState', - get: endpoint => async () => await ApiPromise.create({ provider: new WsProvider(endpoint) }), + get: + endpoint => + async ({ get }) => { + const availEndpoints = (get(chainsState).find(chain => chain.id === 'avail')?.rpcs ?? []).map(({ url }) => url) + const isAvail = endpoint && availEndpoints.includes(endpoint) + if (isAvail) + return await ApiPromise.create({ + provider: new WsProvider(endpoint), + types: AvailJsSdk.spec.types, + rpc: AvailJsSdk.spec.rpc, + signedExtensions: AvailJsSdk.spec.signedExtensions, + }) + + return await ApiPromise.create({ provider: new WsProvider(endpoint) }) + }, dangerouslyAllowMutability: true, cachePolicy_UNSTABLE: { eviction: 'most-recent' }, }) diff --git a/apps/portal/src/routes/portfolio/assets/main.tsx b/apps/portal/src/routes/portfolio/assets/main.tsx index 2a3c6a75f..c575b8cec 100644 --- a/apps/portal/src/routes/portfolio/assets/main.tsx +++ b/apps/portal/src/routes/portfolio/assets/main.tsx @@ -39,7 +39,7 @@ const Assets = () => { onChangeText={setSearch} placeholder="Search for an Asset" containerClassName={css({ flex: 1, maxWidth: '37rem' })} - css={{ width: 0 }} + css={{ width: '100%' }} /> )} diff --git a/apps/portal/src/routes/portfolio/overview.tsx b/apps/portal/src/routes/portfolio/overview.tsx index bd7c81de3..5c16105a0 100644 --- a/apps/portal/src/routes/portfolio/overview.tsx +++ b/apps/portal/src/routes/portfolio/overview.tsx @@ -85,7 +85,7 @@ const SuspendableAssetsOverview = () => { onChangeText={setSearch} css={{ '@media (min-width: 1024px)': { - width: 0, + width: 'auto', }, }} /> diff --git a/packages/ui/src/theme.tsx b/packages/ui/src/theme.tsx index 864879db0..c3fecd578 100644 --- a/packages/ui/src/theme.tsx +++ b/packages/ui/src/theme.tsx @@ -143,7 +143,7 @@ export const ThemeProvider = ({ theme: propsTheme = greenDark, merge = false, ch styles={css` :root { color: ${theme.color.onBackground}; - font-family: ${theme.typography.body.fontFamily}; + font-family: ${theme.typography.body.fontFamily}, sans-serif; font-size: 10px; font-weight: ${theme.typography.body.fontWeight ?? 'revert'}; background-color: ${theme.color.background}; diff --git a/yarn.lock b/yarn.lock index aa007aa1d..fd702ec82 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5328,7 +5328,7 @@ __metadata: languageName: node linkType: hard -"@polkadot/api@npm:^10.11.1, @polkadot/api@npm:^10.7.3, @polkadot/api@npm:^10.9.1": +"@polkadot/api@npm:^10.11.1, @polkadot/api@npm:^10.11.3, @polkadot/api@npm:^10.7.3, @polkadot/api@npm:^10.9.1": version: 10.13.1 resolution: "@polkadot/api@npm:10.13.1" dependencies: @@ -9861,6 +9861,7 @@ __metadata: "@types/react-router-dom": "npm:^5.3.3" "@visx/visx": "npm:^3.1.2" "@vitejs/plugin-react": "npm:^4.2.1" + avail-js-sdk: "npm:^0.2.13" bignumber.js: "npm:^9.1.1" class-variance-authority: "npm:^0.7.0" clsx: "npm:^2.1.1" @@ -12962,6 +12963,15 @@ __metadata: languageName: node linkType: hard +"avail-js-sdk@npm:^0.2.13": + version: 0.2.13 + resolution: "avail-js-sdk@npm:0.2.13" + dependencies: + "@polkadot/api": "npm:^10.11.3" + checksum: 10c0/0f85b816f4858e0e132aab786280ce9500d5d69382f939203088c39e815f0aab27f6f6863535221119d9a2f19fb837b1aa304f80adf63925650f8d10788282fe + languageName: node + linkType: hard + "available-typed-arrays@npm:^1.0.7": version: 1.0.7 resolution: "available-typed-arrays@npm:1.0.7"