Skip to content

Commit

Permalink
feat: add wethIsEth option for V3 nested and boosted pools (#445)
Browse files Browse the repository at this point in the history
* feat: activates wethIsEth feature for boosted and nested v3 pools

* chore: rename function

* fix: permit 2 approvals for wethIsEth
  • Loading branch information
agualis authored Jan 15, 2025
1 parent d5e5de0 commit 1498e47
Show file tree
Hide file tree
Showing 10 changed files with 64 additions and 58 deletions.
8 changes: 2 additions & 6 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,
isV3NotSupportingWethIsEth,
supportsWethIsEth,
getActionableTokenSymbol,
hasNestedPools,
} from '../pool.helpers'
Expand Down Expand Up @@ -392,11 +392,7 @@ export function emptyTokenAmounts(pool: Pool): TokenAmount[] {
}

export function shouldShowNativeWrappedSelector(token: ApiToken, pool: Pool) {
return (
!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)
)
return supportsWethIsEth(pool) && isNativeOrWrappedNative(token.address as Address, token.chain)
}

export function replaceWrappedWithNativeAsset(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,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, isV3NotSupportingWethIsEth } from '../../pool.helpers'
import { getPoolActionableTokens, supportsWethIsEth } from '../../pool.helpers'
import { useUserSettings } from '@repo/lib/modules/user/settings/UserSettingsProvider'
import { isUnbalancedAddErrorMessage } from '@repo/lib/shared/utils/error-filters'
import { getDefaultProportionalSlippagePercentage } from '@repo/lib/shared/utils/slippage'
Expand Down Expand Up @@ -207,7 +207,7 @@ export function _useAddLiquidity(urlTxHash?: Hash) {
return {
transactionSteps,
humanAmountsIn,
tokens: wethIsEth && !isV3NotSupportingWethIsEth(pool) ? tokensWithNativeAsset : tokens,
tokens: wethIsEth && supportsWethIsEth(pool) ? tokensWithNativeAsset : tokens,
validTokens,
totalUSDValue,
simulationQuery,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import { useTokens } from '@repo/lib/modules/tokens/TokensProvider'
import { AddLiquidityFormTabs } from './AddLiquidityFormTabs'
import { UnbalancedAddError } from '@repo/lib/shared/components/errors/UnbalancedAddError'
import { isUnbalancedAddError } from '@repo/lib/shared/utils/error-filters'
import { isV3NotSupportingWethIsEth } from '../../../pool.helpers'
import { supportsWethIsEth } from '../../../pool.helpers'
import { UnbalancedNestedAddError } from '@repo/lib/shared/components/errors/UnbalancedNestedAddError'
import { ApiToken } from '@repo/lib/modules/tokens/token.types'

Expand Down Expand Up @@ -147,7 +147,7 @@ function AddLiquidityMainForm() {

// if native asset balance is higher set that asset as the 'default'
useEffect(() => {
if (!isBalancesLoading && nativeAsset && wNativeAsset && !isV3NotSupportingWethIsEth(pool)) {
if (!isBalancesLoading && nativeAsset && wNativeAsset && supportsWethIsEth(pool)) {
const nativeAssetBalance = balanceFor(nativeAsset.address)
const wNativeAssetBalance = balanceFor(wNativeAsset.address)
if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export class BoostedUnbalancedAddLiquidityV3Handler extends BaseUnbalancedAddLiq
}),
protocolVersion: 3,
userData: '0x' as Hex,
wethIsEth: this.helpers.isNativeAssetIn(humanAmountsIn),
}

const { callData, to, value } = permit2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,15 @@ export class NestedAddLiquidityV3Handler implements AddLiquidityHandler {
slippagePercent,
queryOutput,
permit2,
humanAmountsIn,
}: NestedBuildAddLiquidityInputV3): Promise<TransactionConfig> {
const addLiquidity = new AddLiquidityNested()

const buildCallParams: AddLiquidityNestedCallInputV3 = {
...queryOutput.sdkQueryOutput,
slippage: Slippage.fromPercentage(`${Number(slippagePercent)}`),
amountsIn: queryOutput.sdkQueryOutput.amountsIn,
wethIsEth: this.helpers.isNativeAssetIn(humanAmountsIn),
}

const { callData, to, value } = permit2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export class ProportionalBoostedAddLiquidityV3 implements AddLiquidityHandler {
}),
protocolVersion: 3,
userData: '0x' as Hex,
wethIsEth: this.helpers.isNativeAssetIn(humanAmountsIn),
}

const { callData, to, value } = permit2
Expand Down
8 changes: 6 additions & 2 deletions packages/lib/modules/pool/pool.helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,12 @@ export function isV3WithNestedActionsPool(pool: Pool): boolean {
return supportsNestedActions(pool) && isV3Pool(pool)
}

export function isV3NotSupportingWethIsEth(pool: Pool): boolean {
return (supportsNestedActions(pool) || isBoosted(pool)) && isV3Pool(pool)
export function supportsWethIsEth(pool: Pool): boolean {
/*
Currently all SDK handlers support wethIsEth
and Cow AMM pools is the only scenario that doesn't support wethIsEth
*/
return !isCowAmmPool(pool.type)
}

export function requiresPermit2Approval(pool: Pool): boolean {
Expand Down
35 changes: 18 additions & 17 deletions packages/lib/modules/tokens/approvals/permit2/permit2.helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { GetTokenFn } from '../../TokensProvider'
import { AllowedAmountsByTokenAddress, ExpirationByTokenAddress } from './usePermit2Allowance'
import { TokenAmountIn } from './useSignPermit2'
import { GqlChain } from '@repo/lib/shared/services/api/generated/graphql'
import { isWrappedNativeAsset } from '../../token.helpers'
import { isNativeAsset, isWrappedNativeAsset } from '../../token.helpers'

export function hasValidPermit2(
tokenAmountsIn?: TokenAmountIn[],
Expand Down Expand Up @@ -51,7 +51,7 @@ export function getTokenSymbolsForPermit2({
if (!tokenAmountsIn) return []

const chain = getGqlChain(chainId)
const tokenSymbols = filterWrappedNativeAsset({
const tokenSymbols = filterTokensForPermit2({
wethIsEth,
tokenAmountsIn,
chain,
Expand All @@ -65,26 +65,22 @@ export function getTokenSymbolsForPermit2({
}

// Returns the token addresses that need to be approved for permit2
export function getTokenAddressesForPermit2({
wethIsEth,
tokenAmountsIn,
chainId,
}: BasePermit2Params): Address[] | undefined {
if (!tokenAmountsIn) return undefined
const chain = getGqlChain(chainId)
return filterWrappedNativeAsset({
wethIsEth,
chain,
tokenAmountsIn,
}).map(t => t.address)
export function getTokenAddressesForPermit2(tokenAmountsIn?: TokenAmountIn[]): Address[] {
if (!tokenAmountsIn) return []
return tokenAmountsIn.map(t => t.address)
}

export function permit2Address(chain: GqlChain): Address {
// TODO: Remove ('' as Address) when all chains have permit2 defined to it's not optional anymore
return getNetworkConfig(chain).contracts.permit2 || ('' as Address)
}

function filterWrappedNativeAsset({
/*
Returns the token amounts that need to be approved for permit2
Excludes the native asset
If wethIsEth, it excludes the wrapped native asset (as the user will use the native asset instead, which does not require approval)
*/
export function filterTokensForPermit2({
tokenAmountsIn,
wethIsEth,
chain,
Expand All @@ -94,6 +90,11 @@ function filterWrappedNativeAsset({
chain: GqlChain
}): TokenAmountIn[] {
if (!tokenAmountsIn) return []
if (!wethIsEth) return tokenAmountsIn
return tokenAmountsIn.filter(t => !isWrappedNativeAsset(t.address, chain))
return (
tokenAmountsIn
// native asset does not require permit2 approval
.filter(t => !isNativeAsset(t.address, chain))
// if wethIsEth the wrapped native asset token will be replaced with the native asset token so no required permit2 approval neither
.filter(t => wethIsEth && !isWrappedNativeAsset(t.address, chain))
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type Permit2AllowanceResult = ReturnType<typeof usePermit2Allowance>

type Params = {
chainId: number
tokenAddresses?: Address[]
tokenAddresses: Address[]
owner?: Address
enabled: boolean
spender: Address
Expand All @@ -37,33 +37,30 @@ export function usePermit2Allowance({ chainId, tokenAddresses, owner, enabled, s
contracts,
allowFailure: false,
query: {
enabled: enabled && tokenAddresses && tokenAddresses.length > 0 && !!owner && !!spender,
enabled: enabled && tokenAddresses.length > 0 && !!owner && !!spender,
},
})

const nonces: NoncesByTokenAddress | undefined =
tokenAddresses && data
? zipObject(
tokenAddresses,
data.map(result => result[2])
)
: undefined
const nonces: NoncesByTokenAddress | undefined = data
? zipObject(
tokenAddresses,
data.map(result => result[2])
)
: undefined

const expirations: ExpirationByTokenAddress | undefined =
tokenAddresses && data
? zipObject(
tokenAddresses,
data.map(result => result[1])
)
: undefined
const expirations: ExpirationByTokenAddress | undefined = data
? zipObject(
tokenAddresses,
data.map(result => result[1])
)
: undefined

const allowedAmounts: AllowedAmountsByTokenAddress | undefined =
tokenAddresses && data
? zipObject(
tokenAddresses,
data.map(result => result[0])
)
: undefined
const allowedAmounts: AllowedAmountsByTokenAddress | undefined = data
? zipObject(
tokenAddresses,
data.map(result => result[0])
)
: undefined

return {
isLoadingPermit2Allowances: isLoading,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useMemo } from 'react'

import { useTokens } from '../../tokens/TokensProvider'
import {
filterTokensForPermit2,
getTokenAddressesForPermit2,
getTokenSymbolsForPermit2,
hasValidPermit2,
Expand All @@ -18,6 +19,7 @@ import { SignatureState } from '../../web3/signatures/signature.helpers'
import { NetworkSwitchButton, useChainSwitch } from '../../web3/useChainSwitch'
import { StepDetails, TransactionStep } from './lib'
import { LabelWithIcon } from '@repo/lib/shared/components/btns/button-group/LabelWithIcon'
import { getGqlChain } from '@repo/lib/config/app.config'

/*
Returns a transaction step to sign a permit2 for the token amounts in
Expand All @@ -31,17 +33,19 @@ export function useSignPermit2Step(params: BasePermit2Params): TransactionStep |

const { isLoadingPermit2Allowances, nonces, expirations, allowedAmounts } = usePermit2Allowance({
chainId,
tokenAddresses: getTokenAddressesForPermit2({
chainId,
tokenAmountsIn,
wethIsEth,
}),
tokenAddresses: getTokenAddressesForPermit2(tokenAmountsIn),
owner: userAddress,
enabled: isPermit2 && !!spender,
spender: spender,
})

const isValidPermit2 = hasValidPermit2(tokenAmountsIn, expirations, allowedAmounts)
const filteredTokenAmountsIn = filterTokensForPermit2({
chain: getGqlChain(chainId),
wethIsEth,
tokenAmountsIn,
})

const isValidPermit2 = hasValidPermit2(filteredTokenAmountsIn, expirations, allowedAmounts)

const {
signPermit2,
Expand Down

0 comments on commit 1498e47

Please sign in to comment.