From b8c2b01b54103b983565e1d70800281d64fe2416 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Mon, 7 Feb 2022 14:58:47 +0000 Subject: [PATCH] Pool stats updates and pool context provider (#1057) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * remove datatokens from liquidity stats, multiply base token * naming: Pool Creator Statistics → Owner Liquidity * remove all the noise * more pool stats data * simplify user liquidity data structure, remove datatoken calculations * chart tweaks, new calculation for liquidity * tweaks * todo * frontpage error fixes * account switch fixes * comment out fees * pool context provider * double pool share * move subgraph-related methods into context provider * typing fix --- content/price.json | 5 +- src/@context/Asset.tsx | 4 - src/@context/Pool/_queries.ts | 46 +++ src/@context/Pool/_types.ts | 36 ++ src/@context/Pool/_utils.ts | 38 ++ src/@context/Pool/index.tsx | 280 ++++++++++++++ src/@context/Prices.tsx | 10 +- src/@utils/subgraph.ts | 173 +-------- src/components/@shared/Price/Conversion.tsx | 8 +- .../@shared/atoms/Tooltip.module.css | 4 +- .../Asset/AssetActions/Pool/Add/FormAdd.tsx | 2 +- .../AssetActions/Pool/Add/Output.module.css | 11 - .../Asset/AssetActions/Pool/Add/Output.tsx | 13 +- .../Asset/AssetActions/Pool/Graph/_utils.ts | 8 +- .../Asset/AssetActions/Pool/Graph/index.tsx | 35 +- .../index.module.css} | 6 +- .../Pool/{Remove.tsx => Remove/index.tsx} | 22 +- .../AssetActions/Pool/TokenList.module.css | 2 +- .../Asset/AssetActions/Pool/TokenList.tsx | 37 +- .../Asset/AssetActions/Pool/index.tsx | 364 ++---------------- src/components/Asset/AssetActions/index.tsx | 13 +- 21 files changed, 528 insertions(+), 589 deletions(-) create mode 100644 src/@context/Pool/_queries.ts create mode 100644 src/@context/Pool/_types.ts create mode 100644 src/@context/Pool/_utils.ts create mode 100644 src/@context/Pool/index.tsx rename src/components/Asset/AssetActions/Pool/{Remove.module.css => Remove/index.module.css} (85%) rename src/components/Asset/AssetActions/Pool/{Remove.tsx => Remove/index.tsx} (95%) diff --git a/content/price.json b/content/price.json index d10b34934..9f27ea668 100644 --- a/content/price.json +++ b/content/price.json @@ -41,7 +41,7 @@ "add": { "title": "Add Liquidity", "output": { - "help": "Providing liquidity will earn you SWAPFEE% on every transaction in this pool, proportionally to your share of the pool. Your token input will be converted based on the weight of the pool.", + "help": "Providing liquidity will earn you SWAPFEE% on every transaction in this pool, proportionally to your share of the pool.", "titleIn": "You will receive", "titleOut": "Pool conversion" }, @@ -50,8 +50,7 @@ }, "remove": { "title": "Remove Liquidity", - "simple": "Set the amount of your pool shares to spend. You will get the equivalent value in OCEAN, limited to maximum amount for pool protection. If you have Datatokens left in your wallet, you can add them to the pool to increase the maximum amount.", - "advanced": "Set the amount of your pool shares to spend. You will get OCEAN and Datatokens equivalent to your pool share, without any limit. You can use these Datatokens in other DeFi tools.", + "simple": "Set the amount of your pool shares to spend. You will get the equivalent value in OCEAN, limited to maximum amount for pool protection.", "output": { "titleIn": "You will spend", "titleOut": "You will receive" diff --git a/src/@context/Asset.tsx b/src/@context/Asset.tsx index 689d6ef22..fd0b83f66 100644 --- a/src/@context/Asset.tsx +++ b/src/@context/Asset.tsx @@ -25,7 +25,6 @@ interface AssetProviderValue { title: string owner: string error?: string - refreshInterval: number isAssetNetwork: boolean oceanConfig: Config loading: boolean @@ -34,8 +33,6 @@ interface AssetProviderValue { const AssetContext = createContext({} as AssetProviderValue) -const refreshInterval = 10000 // 10 sec. - function AssetProvider({ did, children @@ -168,7 +165,6 @@ function AssetProvider({ error, isInPurgatory, purgatoryData, - refreshInterval, loading, fetchAsset, isAssetNetwork, diff --git a/src/@context/Pool/_queries.ts b/src/@context/Pool/_queries.ts new file mode 100644 index 000000000..8f89c8730 --- /dev/null +++ b/src/@context/Pool/_queries.ts @@ -0,0 +1,46 @@ +import { gql } from 'urql' + +export const poolDataQuery = gql` + query PoolData( + $pool: ID! + $poolAsString: String! + $owner: String! + $user: String + ) { + poolData: pool(id: $pool) { + id + totalShares + poolFee + opfFee + marketFee + spotPrice + baseToken { + address + symbol + } + baseTokenWeight + baseTokenLiquidity + datatoken { + address + symbol + } + datatokenWeight + datatokenLiquidity + shares(where: { user: $owner }) { + shares + } + } + poolDataUser: pool(id: $pool) { + shares(where: { user: $user }) { + shares + } + } + poolSnapshots(first: 1000, where: { pool: $poolAsString }, orderBy: date) { + date + spotPrice + baseTokenLiquidity + datatokenLiquidity + swapVolume + } + } +` diff --git a/src/@context/Pool/_types.ts b/src/@context/Pool/_types.ts new file mode 100644 index 000000000..967680573 --- /dev/null +++ b/src/@context/Pool/_types.ts @@ -0,0 +1,36 @@ +import Decimal from 'decimal.js' +import { + PoolData_poolSnapshots as PoolDataPoolSnapshots, + PoolData_poolData as PoolDataPoolData +} from 'src/@types/subgraph/PoolData' + +export interface PoolInfo { + poolFee: string + marketFee: string + opfFee: string + weightBaseToken: string + weightDt: string + datatokenSymbol: string + baseTokenSymbol: string + baseTokenAddress: string + totalPoolTokens: string + totalLiquidityInOcean: Decimal +} + +export interface PoolInfoUser { + liquidity: Decimal // liquidity in base token + poolShares: string // pool share tokens + poolShare: string // in % +} + +export interface PoolProviderValue { + poolData: PoolDataPoolData + poolInfo: PoolInfo + poolInfoOwner: PoolInfoUser + poolInfoUser: PoolInfoUser + poolSnapshots: PoolDataPoolSnapshots[] + hasUserAddedLiquidity: boolean + isRemoveDisabled: boolean + refreshInterval: number + fetchAllData: () => void +} diff --git a/src/@context/Pool/_utils.ts b/src/@context/Pool/_utils.ts new file mode 100644 index 000000000..09559febb --- /dev/null +++ b/src/@context/Pool/_utils.ts @@ -0,0 +1,38 @@ +import { isValidNumber } from '@utils/numbers' +import { getQueryContext, fetchData } from '@utils/subgraph' +import Decimal from 'decimal.js' +import { PoolData } from 'src/@types/subgraph/PoolData' +import { OperationResult } from 'urql' +import { poolDataQuery } from './_queries' + +export async function getPoolData( + chainId: number, + pool: string, + owner: string, + user: string +) { + const queryVariables = { + // Using `pool` & `poolAsString` is a workaround to make the mega query work. + // See https://github.com/oceanprotocol/ocean-subgraph/issues/301 + pool: pool.toLowerCase(), + poolAsString: pool.toLowerCase(), + owner: owner.toLowerCase(), + user: user.toLowerCase() + } + + const response: OperationResult = await fetchData( + poolDataQuery, + queryVariables, + getQueryContext(chainId) + ) + return response?.data +} + +export function getWeight(weight: string) { + return isValidNumber(weight) ? new Decimal(weight).mul(10).toString() : '0' +} + +export function getFee(fee: string) { + // fees are tricky: to get 0.1% you need to convert from 0.001 + return isValidNumber(fee) ? new Decimal(fee).mul(100).toString() : '0' +} diff --git a/src/@context/Pool/index.tsx b/src/@context/Pool/index.tsx new file mode 100644 index 000000000..4557730f2 --- /dev/null +++ b/src/@context/Pool/index.tsx @@ -0,0 +1,280 @@ +import { LoggerInstance } from '@oceanprotocol/lib' +import { isValidNumber } from '@utils/numbers' +import Decimal from 'decimal.js' +import React, { + useContext, + useState, + useEffect, + createContext, + ReactElement, + useCallback, + ReactNode +} from 'react' +import { + PoolData_poolSnapshots as PoolDataPoolSnapshots, + PoolData_poolData as PoolDataPoolData +} from 'src/@types/subgraph/PoolData' +import { useAsset } from '../Asset' +import { useWeb3 } from '../Web3' +import { PoolProviderValue, PoolInfo, PoolInfoUser } from './_types' +import { getFee, getPoolData, getWeight } from './_utils' + +Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 }) + +const PoolContext = createContext({} as PoolProviderValue) + +const refreshInterval = 10000 // 10 sec. + +const initialPoolInfo: Partial = { + totalLiquidityInOcean: new Decimal(0) +} + +const initialPoolInfoUser: Partial = { + liquidity: new Decimal(0) +} + +const initialPoolInfoCreator: Partial = initialPoolInfoUser + +function PoolProvider({ children }: { children: ReactNode }): ReactElement { + const { accountId } = useWeb3() + const { isInPurgatory, asset, owner } = useAsset() + + const [poolData, setPoolData] = useState() + const [poolInfo, setPoolInfo] = useState( + initialPoolInfo as PoolInfo + ) + const [poolInfoOwner, setPoolInfoOwner] = useState( + initialPoolInfoCreator as PoolInfoUser + ) + const [poolInfoUser, setPoolInfoUser] = useState( + initialPoolInfoUser as PoolInfoUser + ) + const [poolSnapshots, setPoolSnapshots] = useState() + const [hasUserAddedLiquidity, setUserHasAddedLiquidity] = useState(false) + const [isRemoveDisabled, setIsRemoveDisabled] = useState(false) + const [fetchInterval, setFetchInterval] = useState() + + const fetchAllData = useCallback(async () => { + if (!asset?.chainId || !asset?.accessDetails?.addressOrId || !owner) return + + const response = await getPoolData( + asset.chainId, + asset.accessDetails.addressOrId, + owner, + accountId || '' + ) + if (!response) return + + setPoolData(response.poolData) + setPoolInfoUser((prevState) => ({ + ...prevState, + poolShares: response.poolDataUser?.shares[0]?.shares + })) + setPoolSnapshots(response.poolSnapshots) + LoggerInstance.log('[pool] Fetched pool data:', response.poolData) + LoggerInstance.log('[pool] Fetched user data:', response.poolDataUser) + LoggerInstance.log('[pool] Fetched pool snapshots:', response.poolSnapshots) + }, [asset?.chainId, asset?.accessDetails?.addressOrId, owner, accountId]) + + // Helper: start interval fetching + // Having `accountId` as dependency is important for interval to + // change after user account switch. + const initFetchInterval = useCallback(() => { + if (fetchInterval) return + + const newInterval = setInterval(() => { + fetchAllData() + LoggerInstance.log( + `[pool] Refetch interval fired after ${refreshInterval / 1000}s` + ) + }, refreshInterval) + setFetchInterval(newInterval) + }, [fetchInterval, fetchAllData, accountId]) + + useEffect(() => { + return () => { + clearInterval(fetchInterval) + } + }, [fetchInterval]) + + // + // 0 Fetch all the data on mount if we are on a pool. + // All further effects depend on the fetched data + // and only do further data checking and manipulation. + // + useEffect(() => { + if (asset?.accessDetails?.type !== 'dynamic') return + + fetchAllData() + initFetchInterval() + }, [fetchAllData, initFetchInterval, asset?.accessDetails?.type]) + + // + // 1 General Pool Info + // + useEffect(() => { + if (!poolData) return + + // Fees + const poolFee = getFee(poolData.poolFee) + const marketFee = getFee(poolData.marketFee) + const opfFee = getFee(poolData.opfFee) + + // Total Liquidity + const totalLiquidityInOcean = isValidNumber(poolData.spotPrice) + ? new Decimal(poolData.baseTokenLiquidity).add( + new Decimal(poolData.datatokenLiquidity).mul(poolData.spotPrice) + ) + : new Decimal(0) + + const newPoolInfo = { + poolFee, + marketFee, + opfFee, + weightBaseToken: getWeight(poolData.baseTokenWeight), + weightDt: getWeight(poolData.datatokenWeight), + datatokenSymbol: poolData.datatoken.symbol, + baseTokenSymbol: poolData.baseToken.symbol, + baseTokenAddress: poolData.baseToken.address, + totalPoolTokens: poolData.totalShares, + totalLiquidityInOcean + } + setPoolInfo(newPoolInfo) + LoggerInstance.log('[pool] Created new pool info:', newPoolInfo) + }, [poolData]) + + // + // 2 Pool Creator Info + // + useEffect(() => { + if (!poolData || !poolInfo?.totalPoolTokens) return + + // Staking bot receives half the pool shares so for display purposes + // we can multiply by 2 as we have a hardcoded 50/50 pool weight. + const ownerPoolShares = new Decimal(poolData.shares[0]?.shares) + .mul(2) + .toString() + + // Liquidity in base token, calculated from pool share tokens. + const liquidity = + isValidNumber(ownerPoolShares) && + isValidNumber(poolInfo.totalPoolTokens) && + isValidNumber(poolData.baseTokenLiquidity) + ? new Decimal(ownerPoolShares) + .dividedBy(new Decimal(poolInfo.totalPoolTokens)) + .mul(poolData.baseTokenLiquidity) + : new Decimal(0) + + // Pool share tokens. + const poolShare = + isValidNumber(ownerPoolShares) && isValidNumber(poolInfo.totalPoolTokens) + ? new Decimal(ownerPoolShares) + .dividedBy(new Decimal(poolInfo.totalPoolTokens)) + .mul(100) + .toFixed(2) + : '0' + + const newPoolOwnerInfo = { + liquidity, + poolShares: ownerPoolShares, + poolShare + } + setPoolInfoOwner(newPoolOwnerInfo) + LoggerInstance.log('[pool] Created new owner pool info:', newPoolOwnerInfo) + }, [poolData, poolInfo?.totalPoolTokens]) + + // + // 3 User Pool Info + // + useEffect(() => { + if ( + !poolData || + !poolInfo?.totalPoolTokens || + !asset?.chainId || + !accountId + ) + return + + // Staking bot receives half the pool shares so for display purposes + // we can multiply by 2 as we have a hardcoded 50/50 pool weight. + const userPoolShares = new Decimal(poolInfoUser.poolShares) + .mul(2) + .toString() + + // Pool share in %. + const poolShare = + isValidNumber(userPoolShares) && + isValidNumber(poolInfo.totalPoolTokens) && + new Decimal(userPoolShares) + .dividedBy(new Decimal(poolInfo.totalPoolTokens)) + .mul(100) + .toFixed(2) + + setUserHasAddedLiquidity(Number(poolShare) > 0) + + // Liquidity in base token, calculated from pool share tokens. + const liquidity = + isValidNumber(userPoolShares) && + isValidNumber(poolInfo.totalPoolTokens) && + isValidNumber(poolData.baseTokenLiquidity) + ? new Decimal(userPoolShares) + .dividedBy(new Decimal(poolInfo.totalPoolTokens)) + .mul(poolData.baseTokenLiquidity) + : new Decimal(0) + + const newPoolInfoUser = { + liquidity, + poolShare + } + setPoolInfoUser((prevState: PoolInfoUser) => ({ + ...prevState, + ...newPoolInfoUser + })) + + LoggerInstance.log('[pool] Created new user pool info:', { + poolShares: userPoolShares, + ...newPoolInfoUser + }) + }, [ + poolData, + poolInfoUser?.poolShares, + accountId, + asset?.chainId, + owner, + poolInfo?.totalPoolTokens + ]) + + // + // Check if removing liquidity should be disabled. + // + useEffect(() => { + if (!owner || !accountId) return + setIsRemoveDisabled(isInPurgatory && owner === accountId) + }, [isInPurgatory, owner, accountId]) + + return ( + + {children} + + ) +} + +// Helper hook to access the provider values +const usePool = (): PoolProviderValue => useContext(PoolContext) + +export { PoolProvider, usePool, PoolContext } +export default PoolProvider diff --git a/src/@context/Prices.tsx b/src/@context/Prices.tsx index c5b7d37e8..b2ce1f8e4 100644 --- a/src/@context/Prices.tsx +++ b/src/@context/Prices.tsx @@ -10,11 +10,15 @@ import useSWR from 'swr' import { useSiteMetadata } from '@hooks/useSiteMetadata' import { LoggerInstance } from '@oceanprotocol/lib' -interface PricesValue { +interface Prices { [key: string]: number } -const initialData: PricesValue = { +interface PricesValue { + prices: Prices +} + +const initialData: Prices = { eur: 0.0, usd: 0.0, eth: 0.0, @@ -37,7 +41,7 @@ export default function PricesProvider({ const [prices, setPrices] = useState(initialData) - const onSuccess = async (data: { [tokenId]: { [key: string]: number } }) => { + const onSuccess = async (data: { [tokenId]: Prices }) => { if (!data) return LoggerInstance.log('[prices] Got new OCEAN spot prices.', data[tokenId]) setPrices(data[tokenId]) diff --git a/src/@utils/subgraph.ts b/src/@utils/subgraph.ts index 444232fe0..7f6778113 100644 --- a/src/@utils/subgraph.ts +++ b/src/@utils/subgraph.ts @@ -2,18 +2,7 @@ import { gql, OperationResult, TypedDocumentNode, OperationContext } from 'urql' import { Asset, LoggerInstance } from '@oceanprotocol/lib' import { getUrqlClientInstance } from '@context/UrqlProvider' import { getOceanConfig } from './ocean' -import { - AssetsPoolPrice, - AssetsPoolPrice_pools as AssetsPoolPricePool -} from '../@types/subgraph/AssetsPoolPrice' -import { - AssetsFrePrice, - AssetsFrePrice_fixedRateExchanges as AssetsFrePriceFixedRateExchange -} from '../@types/subgraph/AssetsFrePrice' -import { - AssetsFreePrice, - AssetsFreePrice_dispensers as AssetFreePriceDispenser -} from '../@types/subgraph/AssetsFreePrice' +import { AssetPoolPrice } from '../@types/subgraph/AssetPoolPrice' import { AssetPreviousOrder } from '../@types/subgraph/AssetPreviousOrder' import { HighestLiquidityAssets_pools as HighestLiquidityAssetsPool, @@ -25,7 +14,6 @@ import { } from '../@types/subgraph/PoolShares' import { OrdersData_orders as OrdersData } from '../@types/subgraph/OrdersData' import { UserSalesQuery as UsersSalesList } from '../@types/subgraph/UserSalesQuery' -import { PoolData } from 'src/@types/subgraph/PoolData' export interface UserLiquidity { price: string @@ -36,91 +24,6 @@ export interface PriceList { [key: string]: string } -interface DidAndDatatokenMap { - [name: string]: string -} - -const FreeQuery = gql` - query AssetsFreePrice($datatoken_in: [String!]) { - dispensers(orderBy: id, where: { token_in: $datatoken_in }) { - token { - id - address - } - } - } -` - -const AssetFreeQuery = gql` - query AssetFreePrice($datatoken: String) { - dispensers(orderBy: id, where: { token: $datatoken }) { - active - owner - isMinter - maxTokens - maxBalance - balance - token { - id - isDatatoken - } - } - } -` - -const FreQuery = gql` - query AssetsFrePrice($datatoken_in: [String!]) { - fixedRateExchanges(orderBy: id, where: { datatoken_in: $datatoken_in }) { - id - price - baseToken { - symbol - } - datatoken { - id - address - symbol - } - } - } -` - -const AssetFreQuery = gql` - query AssetFrePrice($datatoken: String) { - fixedRateExchanges(orderBy: id, where: { datatoken: $datatoken }) { - id - price - baseToken { - symbol - } - datatoken { - id - address - symbol - } - } - } -` - -const PoolQuery = gql` - query AssetsPoolPrice($datatokenAddress_in: [String!]) { - pools(where: { datatoken_in: $datatokenAddress_in }) { - id - spotPrice - datatoken { - address - symbol - } - baseToken { - address - symbol - } - datatokenLiquidity - baseTokenLiquidity - } - } -` - const AssetPoolPriceQuery = gql` query AssetPoolPrice($datatokenAddress: String) { pools(where: { datatoken: $datatokenAddress }) { @@ -280,51 +183,6 @@ const TopSalesQuery = gql` } ` -const poolDataQuery = gql` - query PoolData( - $pool: ID! - $poolAsString: String! - $owner: String! - $user: String - ) { - poolData: pool(id: $pool) { - id - totalShares - poolFee - opfFee - marketFee - spotPrice - baseToken { - address - symbol - } - baseTokenWeight - baseTokenLiquidity - datatoken { - address - symbol - } - datatokenWeight - datatokenLiquidity - shares(where: { user: $owner }) { - shares - } - } - poolDataUser: pool(id: $pool) { - shares(where: { user: $user }) { - shares - } - } - poolSnapshots(first: 1000, where: { pool: $poolAsString }, orderBy: date) { - date - spotPrice - baseTokenLiquidity - datatokenLiquidity - swapVolume - } - } -` - export function getSubgraphUri(chainId: number): string { const config = getOceanConfig(chainId) return config.subgraphUri @@ -411,7 +269,7 @@ export async function getSpotPrice(asset: Asset): Promise { } const queryContext = getQueryContext(Number(asset.chainId)) - const poolPriceResponse: OperationResult = await fetchData( + const poolPriceResponse: OperationResult = await fetchData( AssetPoolPriceQuery, poolVariables, queryContext @@ -430,14 +288,14 @@ export async function getHighestLiquidityDatatokens( const fetchedPools: OperationResult = await fetchData(HighestLiquidityAssets, null, queryContext) highestLiquidityAssets = highestLiquidityAssets.concat( - fetchedPools.data.pools + fetchedPools?.data?.pools ) } highestLiquidityAssets.sort( (a, b) => b.baseTokenLiquidity - a.baseTokenLiquidity ) for (let i = 0; i < highestLiquidityAssets.length; i++) { - if (!highestLiquidityAssets[i].datatoken.address) continue + if (!highestLiquidityAssets[i]?.datatoken?.address) continue dtList.push(highestLiquidityAssets[i].datatoken.address) } return dtList @@ -588,26 +446,3 @@ export async function getTopAssetsPublishers( return publisherSales.slice(0, nrItems) } - -export async function getPoolData( - chainId: number, - pool: string, - owner: string, - user: string -) { - const queryVariables = { - // Using `pool` & `poolAsString` is a workaround to make the mega query work. - // See https://github.com/oceanprotocol/ocean-subgraph/issues/301 - pool: pool.toLowerCase(), - poolAsString: pool.toLowerCase(), - owner: owner.toLowerCase(), - user: user.toLowerCase() - } - - const response: OperationResult = await fetchData( - poolDataQuery, - queryVariables, - getQueryContext(chainId) - ) - return response?.data -} diff --git a/src/components/@shared/Price/Conversion.tsx b/src/components/@shared/Price/Conversion.tsx index 0d47f7dd6..e672d87af 100644 --- a/src/components/@shared/Price/Conversion.tsx +++ b/src/components/@shared/Price/Conversion.tsx @@ -10,13 +10,11 @@ const cx = classNames.bind(styles) export default function Conversion({ price, className, - hideApproximateSymbol, - showTVLLabel + hideApproximateSymbol }: { price: string // expects price in OCEAN, not wei className?: string hideApproximateSymbol?: boolean - showTVLLabel?: boolean }): ReactElement { const { prices } = usePrices() const { currency, locale } = useUserPreferences() @@ -29,7 +27,6 @@ export default function Conversion({ const styleClasses = cx({ conversion: true, - removeTvlPadding: showTVLLabel, [className]: className }) @@ -39,7 +36,7 @@ export default function Conversion({ return } - const conversionValue = (prices as any)[currency.toLowerCase()] + const conversionValue = prices[currency.toLowerCase()] const converted = conversionValue * Number(price) const convertedFormatted = formatCurrency( converted, @@ -64,7 +61,6 @@ export default function Conversion({ className={styleClasses} title="Approximation based on current OCEAN spot price on Coingecko" > - {showTVLLabel && 'TVL'} {!hideApproximateSymbol && '≈ '} {' '} {!isFiat && currency} diff --git a/src/components/@shared/atoms/Tooltip.module.css b/src/components/@shared/atoms/Tooltip.module.css index 131a7cea5..06af42728 100644 --- a/src/components/@shared/atoms/Tooltip.module.css +++ b/src/components/@shared/atoms/Tooltip.module.css @@ -14,8 +14,8 @@ } .icon { - width: 1em; - height: 1em; + width: 0.85em; + height: 0.85em; cursor: help; display: inline-block; margin-bottom: -0.1em; diff --git a/src/components/Asset/AssetActions/Pool/Add/FormAdd.tsx b/src/components/Asset/AssetActions/Pool/Add/FormAdd.tsx index 1791e3e03..45379e0aa 100644 --- a/src/components/Asset/AssetActions/Pool/Add/FormAdd.tsx +++ b/src/components/Asset/AssetActions/Pool/Add/FormAdd.tsx @@ -120,7 +120,7 @@ export default function FormAdd({ )} - {Number(balance.ocean) && ( + {Number(balance.ocean) > 0 && (