Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add tabs for add liquidity #214

Merged
merged 35 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2c66299
add tabs
groninge01 Nov 29, 2024
8f97d5f
Merge branch 'main' into feat/add-liquidity-tabs
groninge01 Nov 29, 2024
c7ca500
set default tab
groninge01 Nov 29, 2024
b65e5fe
add tvl threshold
groninge01 Nov 29, 2024
dae10e7
set tab index
groninge01 Nov 29, 2024
0761db3
Merge branch 'main' into feat/add-liquidity-tabs
groninge01 Nov 29, 2024
8e96a7d
proportional check logic has moved
groninge01 Nov 29, 2024
b3d869c
Merge branch 'main' into feat/add-liquidity-tabs
agualis Nov 29, 2024
f68ad17
Merge branch 'main' into feat/add-liquidity-tabs
agualis Nov 29, 2024
8b203bc
reafactor: proportional tabs and handlers
agualis Nov 30, 2024
f6b7662
fix: do not show unbalanced error in nested adds
agualis Nov 30, 2024
a6d6743
fix: nested with top level with underlyings
agualis Nov 30, 2024
7d58595
chore: simplify AddLiquidityFormTabs
agualis Nov 30, 2024
98057ea
fix: disable wethIsEth for v3 boosted
agualis Nov 30, 2024
64ea9fd
fix: boostedPoolState when underlying token has undefined address
agualis Nov 30, 2024
b305468
fix: avoid using ETH instead of WETH when pool does not support wethI…
agualis Nov 30, 2024
8bfb117
fix: use token index instead of for index in boostedPoolState
agualis Nov 30, 2024
81fb155
fix: use explicit referenceAmount by address in Proportional adds
agualis Nov 30, 2024
9e0e9c7
debug: log silenced PI query error
agualis Dec 1, 2024
11f487d
debug: log nested PI inputs
agualis Dec 1, 2024
b4ef6c2
debug: avoid retry limit on PI error
agualis Dec 1, 2024
8067449
debug: alchemy route
agualis Dec 1, 2024
cd0ef87
debug: alchemy route 2
agualis Dec 1, 2024
720141b
chore: clean console logs
agualis Dec 2, 2024
a8dfe02
chore: improve ratio error messages
agualis Dec 2, 2024
365c5b5
Merge branch 'main' into feat/add-liquidity-tabs
agualis Dec 2, 2024
b4dea10
add optional prop for full width
groninge01 Dec 2, 2024
1ac39a6
set to full width
groninge01 Dec 2, 2024
afaecb1
add optional prop for larger text
groninge01 Dec 2, 2024
08d148b
set larger text for buttons
groninge01 Dec 2, 2024
9d2a39b
chore: refactor unbalanced error label logic
agualis Dec 2, 2024
8b9c851
chore: bump sdk to 0.33.2
agualis Dec 2, 2024
b48aa41
chore: add unit test for boosted state
agualis Dec 2, 2024
8b75d71
chore: change boosted message
agualis Dec 2, 2024
c918b95
chore: update MIN_LIQUIDITY_FOR_BALANCED_ADD
agualis Dec 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/frontend-v3/app/api/rpc/[chain]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const chainToRpcMap: Record<GqlChain, string | undefined> = {
[GqlChain.Avalanche]: dRpcUrl('avalanche'),
[GqlChain.Fantom]: dRpcUrl('fantom'),
[GqlChain.Sepolia]: dRpcUrl('sepolia'),
// DEBUG:
// [GqlChain.Sepolia]: 'https://eth-sepolia.g.alchemy.com/v2/<KEY>',
[GqlChain.Fraxtal]: dRpcUrl('fraxtal'),
[GqlChain.Gnosis]: dRpcUrl('gnosis'),
[GqlChain.Mode]: dRpcUrl('mode'),
Expand Down
2 changes: 1 addition & 1 deletion packages/lib/modules/pool/PoolDetail/PoolMyLiquidity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
Tooltip,
useDisclosure,
} from '@chakra-ui/react'
import React, { useMemo, useState, useLayoutEffect } from 'react'
import { useMemo, useState, useLayoutEffect } from 'react'
import { usePool } from '../PoolProvider'
import { Address } from 'viem'
import { usePathname, useRouter } from 'next/navigation'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { GqlChain, GqlPoolElement } from '@repo/lib/shared/services/api/generate
import { getPoolMock } from '../__mocks__/getPoolMock'
import { allPoolTokens } from '../pool.helpers'
import { LiquidityActionHelpers } from './LiquidityActionHelpers'
import { Pool } from '../PoolProvider'

describe('Calculates toInputAmounts from allPoolTokens', () => {
it('for v2 weighted pool with no nested tokens', async () => {
Expand Down Expand Up @@ -293,3 +294,163 @@ describe.skip('Liquidity helpers for V3 NESTED pool', async () => {
])
})
})

// Unskip when sepolia V3 pools are available in production api
test.skip('Nested pool state for V3 BOOSTED POOL', async () => {
// const poolId = '0xbb83ba331c3254c8c44645430126797dceda89c0' // Sepolia Balancer 50 WETH 50 stataUSDC

// const v3Pool = await getPoolMock(poolId, GqlChain.Sepolia)
const v3Pool = {} as Pool

const helpers = new LiquidityActionHelpers(v3Pool)

const state = helpers.boostedPoolState

expect(state).toMatchInlineSnapshot(`
{
"address": "0xbb83ba331c3254c8c44645430126797dceda89c0",
"id": "0xbb83ba331c3254c8c44645430126797dceda89c0",
"protocolVersion": 3,
"tokens": [
{
"address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9",
"balance": "10.030375954528889",
"balanceUSD": "35947.96468719563",
"decimals": 18,
"erc4626ReviewData": null,
"hasNestedPool": false,
"id": "0xbb83ba331c3254c8c44645430126797dceda89c0-0x7b79995e5f793a07bc00c21412e50ecae098e7f9",
"index": 0,
"isAllowed": true,
"isErc4626": false,
"name": "Wrapped Ether",
"nestedPool": null,
"priceRate": "1",
"priceRateProvider": "0x0000000000000000000000000000000000000000",
"priceRateProviderData": null,
"symbol": "WETH",
"underlyingToken": null,
"weight": "0.5",
},
{
"address": "0x8a88124522dbbf1e56352ba3de1d9f78c143751e",
"balance": "25922.046716",
"balanceUSD": "30847.23559204",
"decimals": 6,
"erc4626ReviewData": null,
"hasNestedPool": false,
"id": "0xbb83ba331c3254c8c44645430126797dceda89c0-0x8a88124522dbbf1e56352ba3de1d9f78c143751e",
"index": 1,
"isAllowed": true,
"isErc4626": true,
"name": "Static Aave Ethereum USDC",
"nestedPool": null,
"priceRate": "1.188770181245210492",
"priceRateProvider": "0x34101091673238545de8a846621823d9993c3085",
"priceRateProviderData": {
"address": "0x34101091673238545de8a846621823d9993c3085",
"factory": null,
"name": "waUSDC Rate Provider",
"reviewFile": "./StatATokenTestnetRateProvider.md",
"reviewed": true,
"summary": "safe",
"upgradeableComponents": [],
"warnings": [
"",
],
},
"symbol": "stataEthUSDC",
"underlyingToken": {
"address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8",
"chainId": 11155111,
"decimals": 6,
"index": 1,
"name": "USDC (AAVE Faucet)",
"symbol": "usdc-aave",
},
"weight": "0.5",
},
],
"totalShares": "555.900851855167757901",
"type": "Weighted",
}
`)
})

// Unskip when sepolia V3 pools are available in production api
test.skip('Nested pool state for V3 NESTED POOL', async () => {
// const poolId = '0xc9233cc69435591b193b50f702ac31e404a08b10' // Sepolia Balancer 50 WETH 50 USD

const usdcSepoliaAddress = '0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8'
const daiSepoliaAddress = '0xff34b3d4aee8ddcd6f9afffb6fe49bd371b8a357'
const wethSepoliaAddress = '0x7b79995e5f793a07bc00c21412e50ecae098e7f9'
// const v3Pool = await getPoolMock(poolId, GqlChain.Sepolia)
const v3Pool = {} as Pool

const helpers = new LiquidityActionHelpers(v3Pool)

const state = helpers.nestedPoolStateV3

expect(state).toEqual({
mainTokens: [
{
address: wethSepoliaAddress,
decimals: 18,
index: 0,
},
{
address: usdcSepoliaAddress,
decimals: 6,
index: 0,
},
{
address: daiSepoliaAddress,
decimals: 18,
index: 1,
},
],
pools: [
{
address: '0xc9233cc69435591b193b50f702ac31e404a08b10',
id: '0xc9233cc69435591b193b50f702ac31e404a08b10',
level: 1,
tokens: [
{
address: wethSepoliaAddress,
decimals: 18,
index: 0,
underlyingToken: null,
},
{
address: '0x946e59e9637f44eb122fe64b372aaf6ed0441da1',
decimals: 18,
index: 1,
underlyingToken: null,
},
],
type: 'Weighted',
},
{
address: '0x946e59e9637f44eb122fe64b372aaf6ed0441da1',
id: '0x946e59e9637f44eb122fe64b372aaf6ed0441da1',
level: 0,
tokens: [
{
address: usdcSepoliaAddress,
decimals: 6,
index: 0,
underlyingToken: null,
},
{
address: daiSepoliaAddress,
decimals: 18,
index: 1,
underlyingToken: null,
},
],
type: 'Weighted',
},
],
protocolVersion: 3,
})
})
20 changes: 11 additions & 9 deletions packages/lib/modules/pool/actions/LiquidityActionHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import {
isUnbalancedLiquidityDisabled,
isV2Pool,
isV3Pool,
isV3WithNestedActionsPool,
isV3NotSupportingWethIsEth,
} from '../pool.helpers'
import { TokenAmountIn } from '../../tokens/approvals/permit2/useSignPermit2'

Expand Down Expand Up @@ -84,16 +84,18 @@ export class LiquidityActionHelpers {
/* Used by V3 boosted SDK handlers */
public get boostedPoolState(): PoolStateWithUnderlyings & { totalShares: HumanAmount } {
const poolTokensWithUnderlyings: PoolTokenWithUnderlying[] = this.pool.poolTokens.map(
(token, index) => ({
token => ({
...token,
address: token.address as Address,
balance: token.balance as HumanAmount,
underlyingToken: {
...token.underlyingToken,
address: token.underlyingToken?.address as Address,
decimals: token.underlyingToken?.decimals as number,
index, //TODO: review that this index is always the expected one
},
underlyingToken: token.underlyingToken?.address
? {
...token.underlyingToken,
address: token.underlyingToken?.address as Address,
decimals: token.underlyingToken?.decimals as number,
index: token.index, //TODO: review that this index is always the expected one
}
: null,
})
)
const state: PoolStateWithUnderlyings & { totalShares: HumanAmount } = {
Expand Down Expand Up @@ -359,7 +361,7 @@ export function emptyTokenAmounts(pool: Pool): TokenAmount[] {

export function shouldShowNativeWrappedSelector(token: GqlToken, pool: Pool) {
return (
!isV3WithNestedActionsPool(pool) && // V3 nested actions don't support wethIsEth currently
!isV3NotSupportingWethIsEth(pool) && // V3 boosted/nested actions don't support wethIsEth currently
!isCowAmmPool(pool.type) && // Cow AMM pools don't support wethIsEth
isNativeOrWrappedNative(token.address as Address, token.chain)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import { useTokens } from '@repo/lib/modules/tokens/TokensProvider'
import { useMandatoryContext } from '@repo/lib/shared/utils/contexts'
import { HumanAmount } from '@balancer/sdk'
import { HumanAmount, isSameAddress } from '@balancer/sdk'
import { PropsWithChildren, createContext, useEffect, useMemo, useState } from 'react'
import { Address, Hash } from 'viem'
import { usePool } from '../../PoolProvider'
Expand All @@ -28,7 +28,7 @@ import { useTotalUsdValue } from '@repo/lib/modules/tokens/useTotalUsdValue'
import { HumanTokenAmountWithAddress } from '@repo/lib/modules/tokens/token.types'
import { isUnhandledAddPriceImpactError } from '@repo/lib/modules/price-impact/price-impact.utils'
import { useModalWithPoolRedirect } from '../../useModalWithPoolRedirect'
import { getPoolActionableTokens, isV3WithNestedActionsPool } from '../../pool.helpers'
import { getPoolActionableTokens, isV3NotSupportingWethIsEth } from '../../pool.helpers'
import { useUserSettings } from '@repo/lib/modules/user/settings/UserSettingsProvider'
import { isUnbalancedAddErrorMessage } from '@repo/lib/shared/utils/error-filters'

Expand All @@ -37,6 +37,8 @@ export const AddLiquidityContext = createContext<UseAddLiquidityResponse | null>

export function _useAddLiquidity(urlTxHash?: Hash) {
const [humanAmountsIn, setHumanAmountsIn] = useState<HumanTokenAmountWithAddress[]>([])
// only used by Proportional handlers that require a referenceAmount
const [referenceAmountAddress, setReferenceAmountAddress] = useState<Address | undefined>()
const [needsToAcceptHighPI, setNeedsToAcceptHighPI] = useState(false)
const [acceptPoolRisks, setAcceptPoolRisks] = useState(false)
const [wethIsEth, setWethIsEth] = useState(false)
Expand Down Expand Up @@ -91,6 +93,19 @@ export function _useAddLiquidity(urlTxHash?: Hash) {
])
}

function clearAmountsIn(changedAmount?: HumanTokenAmountWithAddress) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i moved this function from useProportionalInputs to here

setHumanAmountsIn(
humanAmountsIn.map(({ tokenAddress }) => {
// Keeps user inputs like '0' or '0.' instead of replacing them with ''
if (changedAmount && isSameAddress(changedAmount.tokenAddress, tokenAddress)) {
return changedAmount
}

return { tokenAddress, humanAmount: '' }
})
)
}

const tokensWithNativeAsset = replaceWrappedWithNativeAsset(tokens, nativeAsset)

const validTokens = injectNativeAsset(tokens, nativeAsset, pool)
Expand All @@ -110,6 +125,7 @@ export function _useAddLiquidity(urlTxHash?: Hash) {
handler,
humanAmountsIn,
enabled: !urlTxHash,
referenceAmountAddress,
})
const priceImpactQuery = useAddLiquidityPriceImpactQuery({
handler,
Expand Down Expand Up @@ -179,7 +195,7 @@ export function _useAddLiquidity(urlTxHash?: Hash) {
return {
transactionSteps,
humanAmountsIn,
tokens: wethIsEth && !isV3WithNestedActionsPool(pool) ? tokensWithNativeAsset : tokens,
tokens: wethIsEth && !isV3NotSupportingWethIsEth(pool) ? tokensWithNativeAsset : tokens,
validTokens,
totalUSDValue,
simulationQuery,
Expand All @@ -202,11 +218,14 @@ export function _useAddLiquidity(urlTxHash?: Hash) {
proportionalSlippage,
isForcedProportionalAdd,
wantsProportional,
referenceAmountAddress,
setWantsProportional,
setProportionalSlippage,
refetchQuote,
setHumanAmountIn,
setHumanAmountsIn,
clearAmountsIn,
setReferenceAmountAddress,
setNeedsToAcceptHighPI,
setAcceptPoolRisks,
setWethIsEth,
Expand Down
Loading
Loading