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

chore: permit2 initial changes #1104

Merged
merged 12 commits into from
Sep 19, 2024
1 change: 1 addition & 0 deletions lib/config/config.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export interface ContractsConfig {
feeDistributor?: Address
veDelegationProxy?: Address
veBAL?: Address
permit2?: Address
}
export interface PoolsConfig {
issues: Partial<Record<PoolIssue, string[]>>
Expand Down
1 change: 1 addition & 0 deletions lib/config/networks/sepolia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const networkConfig: NetworkConfig = {
minter: '0x1783Cd84b3d01854A96B4eD5843753C2CcbD574A',
},
veBAL: '0x150A72e4D4d81BbF045565E232c50Ed0931ad795',
permit2: '0x000000000022D473030F116dDEE9F6B43aC78BA3',
},
pools: convertHexToLowerCase({
issues: {},
Expand Down
4 changes: 3 additions & 1 deletion lib/modules/pool/actions/LiquidityActionHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,12 @@ export class LiquidityActionHelpers {
}

public getAmountsToApprove(
humanAmountsIn: HumanTokenAmountWithAddress[]
humanAmountsIn: HumanTokenAmountWithAddress[],
isPermit2 = false
): TokenAmountToApprove[] {
return this.toInputAmounts(humanAmountsIn).map(({ address, rawAmount }) => {
return {
isPermit2,
tokenAddress: address,
requiredRawAmount: rawAmount,
requestedRawAmount: rawAmount, //This amount will be probably replaced by MAX_BIGINT depending on the approval rules
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import { useMemo } from 'react'
import { usePool } from '../../PoolProvider'
import { LiquidityActionHelpers } from '../LiquidityActionHelpers'
import { AddLiquidityStepParams, useAddLiquidityStep } from './useAddLiquidityStep'
import { getVaultConfig } from '../../pool.helpers'
import { requiresPermit2Approval } from '../../pool.helpers'
import { useSignRelayerStep } from '@/lib/modules/transactions/transaction-steps/useSignRelayerStep'
import { Address } from 'viem'
import { isCowAmmPool } from '../../pool.helpers'
import { getSpenderForAddLiquidity } from '@/lib/modules/tokens/token.helpers'

type AddLiquidityStepsParams = AddLiquidityStepParams & {
helpers: LiquidityActionHelpers
Expand All @@ -22,7 +21,6 @@ export function useAddLiquiditySteps({
simulationQuery,
}: AddLiquidityStepsParams) {
const { pool, chainId, chain } = usePool()
const { vaultAddress } = getVaultConfig(pool)
const relayerMode = useRelayerMode(pool)
const shouldSignRelayerApproval = useShouldSignRelayerApproval(chainId, relayerMode)

Expand All @@ -37,10 +35,11 @@ export function useAddLiquiditySteps({

const { isLoading: isLoadingTokenApprovalSteps, steps: tokenApprovalSteps } =
useTokenApprovalSteps({
spenderAddress: isCowAmmPool(pool.type) ? (pool.address as Address) : vaultAddress,
spenderAddress: getSpenderForAddLiquidity(pool),
chain: pool.chain,
approvalAmounts: inputAmounts,
actionType: 'AddLiquidity',
isPermit2: requiresPermit2Approval(pool),
})

const addLiquidityStep = useAddLiquidityStep({
Expand Down
4 changes: 4 additions & 0 deletions lib/modules/pool/pool.helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,10 @@ export function isV3Pool(pool: Pool): boolean {
return pool.protocolVersion === 3
}

export function requiresPermit2Approval(pool: Pool): boolean {
return isV3Pool(pool)
}

export function getRateProviderWarnings(warnings: string[]) {
return warnings.filter(warning => !isEmpty(warning))
}
5 changes: 5 additions & 0 deletions lib/modules/tokens/approvals/approval-rules.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@ describe('getRequiredTokenApprovals', () => {
})
).toEqual([
{
isPermit2: false,
tokenAddress: wETHAddress,
requiredRawAmount: 10000000000000000000n,
requestedRawAmount: MAX_BIGINT,
},
{
isPermit2: false,
tokenAddress: wjAuraAddress,
requiredRawAmount: 20000000000000000000n,
requestedRawAmount: MAX_BIGINT,
Expand Down Expand Up @@ -87,11 +89,13 @@ describe('getRequiredTokenApprovals', () => {
requiredRawAmount: 0n,
requestedRawAmount: 0n,
tokenAddress: usdtAddress,
isPermit2: false,
},
{
tokenAddress: usdtAddress,
requiredRawAmount: 10000000000000000000n,
requestedRawAmount: MAX_BIGINT,
isPermit2: false,
},
])
})
Expand All @@ -116,6 +120,7 @@ describe('getRequiredTokenApprovals', () => {
})
).toEqual([
{
isPermit2: false,
requiredRawAmount: 10000000000000000000n,
requestedRawAmount: MAX_BIGINT,
tokenAddress: usdtAddress,
Expand Down
5 changes: 5 additions & 0 deletions lib/modules/tokens/approvals/approval-rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type TokenAmountToApprove = {
tokenAddress: Address
requiredRawAmount: bigint // actual amount that the transaction requires
requestedRawAmount: bigint // amount that we are going to request (normally MAX_BIGINT)
isPermit2: boolean // whether the approval is for Permit2 or standard token approval
}

// This is a subtype of InputAmount as we only need rawAmount and address
Expand All @@ -19,6 +20,7 @@ type TokenApprovalParams = {
chainId: GqlChain | SupportedChainId | null
rawAmounts: RawAmount[]
allowanceFor: (tokenAddress: Address) => bigint
isPermit2?: boolean
approveMaxBigInt?: boolean
skipAllowanceCheck?: boolean
}
Expand All @@ -30,6 +32,7 @@ export function getRequiredTokenApprovals({
chainId,
rawAmounts,
allowanceFor,
isPermit2 = false,
approveMaxBigInt = true,
skipAllowanceCheck = false,
}: TokenApprovalParams): TokenAmountToApprove[] {
Expand All @@ -42,6 +45,7 @@ export function getRequiredTokenApprovals({
requiredRawAmount: rawAmount,
// The transaction only requires requiredRawAmount but we will normally request MAX_BIGINT
requestedRawAmount: approveMaxBigInt ? MAX_BIGINT : rawAmount,
isPermit2,
}
})

Expand All @@ -59,6 +63,7 @@ export function getRequiredTokenApprovals({
requiredRawAmount: 0n,
requestedRawAmount: 0n,
tokenAddress: t.tokenAddress,
isPermit2,
}
// Prepend approval for ZERO amount
return [zeroTokenAmountToApprove, t]
Expand Down
5 changes: 4 additions & 1 deletion lib/modules/tokens/approvals/useTokenApprovalSteps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,20 @@ export type Params = {
chain: GqlChain
approvalAmounts: RawAmount[]
actionType: ApprovalAction
isPermit2?: boolean
bptSymbol?: string //Edge-case for approving
}

/*
Generic hook to creates a Token Approval Step Config for different flows defined by the actionType property
Generic hook to create a Token Approval Step Config for different flows defined by the actionType property
*/
export function useTokenApprovalSteps({
spenderAddress,
chain,
approvalAmounts,
actionType,
bptSymbol,
isPermit2 = false,
}: Params): { isLoading: boolean; steps: TransactionStep[] } {
const { userAddress } = useUserAccount()
const { getToken } = useTokens()
Expand All @@ -58,6 +60,7 @@ export function useTokenApprovalSteps({
chainId: chain,
rawAmounts: _approvalAmounts,
allowanceFor: tokenAllowances.allowanceFor,
isPermit2,
})

const steps = useMemo(() => {
Expand Down
14 changes: 14 additions & 0 deletions lib/modules/tokens/token.helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Address } from 'viem'
import { HumanTokenAmountWithAddress, TokenBase } from './token.types'
import { InputAmount } from '@balancer/sdk'
import { Pool } from '../pool/PoolProvider'
import { getVaultConfig, isCowAmmPool, isV3Pool } from '../pool/pool.helpers'

export function isNativeAsset(token: TokenBase | string, chain: GqlChain | SupportedChainId) {
return nativeAssetFilter(chain)(token)
Expand Down Expand Up @@ -130,3 +131,16 @@ export function getLeafTokens(poolTokens: PoolToken[]) {

return leafTokens
}

export function getSpenderForAddLiquidity(pool: Pool): Address {
if (isCowAmmPool(pool.type)) return pool.address as Address
if (isV3Pool(pool)) {
const permit2Address = getNetworkConfig(pool.chain).contracts.permit2
if (!permit2Address) {
throw new Error(`Permit2 feature is not yet available for this chain (${pool.chain}) `)
}
return permit2Address
}
const { vaultAddress } = getVaultConfig(pool)
return vaultAddress
}
Loading