Skip to content

Commit

Permalink
fix: add nonces query
Browse files Browse the repository at this point in the history
  • Loading branch information
agualis committed Sep 25, 2024
1 parent 8c58184 commit d4f70d1
Show file tree
Hide file tree
Showing 16 changed files with 355 additions and 43 deletions.
3 changes: 3 additions & 0 deletions app/(app)/debug/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ export default function Debug() {
<Link as={NextLink} href="/debug/remove-allowance">
Remove allowance
</Link>
<Link as={NextLink} href="/debug/permit2-allowance">
Permit2 allowance
</Link>
</VStack>
</FadeInOnView>
)
Expand Down
63 changes: 63 additions & 0 deletions app/(app)/debug/permit2-allowance/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use client'

import { useUserAccount } from '@/lib/modules/web3/UserAccountProvider'
import { Center, Input, Text, VStack } from '@chakra-ui/react'
import { useState } from 'react'
import { Address } from 'viem'
import { sepolia } from 'viem/chains'
import { useReadContract } from 'wagmi'
import { fNum } from '@/lib/shared/utils/numbers'
import { getGqlChain, getNetworkConfig } from '@/lib/config/app.config'
import { permit2Abi } from '@balancer/sdk'

export default function Page() {
const [tokenAddress, setTokenAddress] = useState<Address>('' as Address)

const { chain, userAddress } = useUserAccount()

const chainId = chain?.id || sepolia.id

const { data } = usePermit2Allowance({ chainId, tokenAddress, owner: userAddress })

return (
<Center>
<VStack w="50%">
<Text>
Enter address of token to check permit2 allowance in the current chain:{' '}
{chain ? chain.name : 'None'}
</Text>
<Input type="text" onChange={e => setTokenAddress(e.target.value as Address)} />

{data && (
<div>
<div>Amount: {fNum('integer', data[0])}</div>
<div>Expires: {data[1]}</div>
<div>Nonce: {data[2]}</div>
</div>
)}
</VStack>
</Center>
)
}

type Params = {
chainId: number
tokenAddress: Address
owner: Address
}
function usePermit2Allowance({ chainId, tokenAddress, owner }: Params) {
const permit2Address = '0x000000000022D473030F116dDEE9F6B43aC78BA3'
const balancerRouter = getNetworkConfig(getGqlChain(chainId)).contracts.balancer.router!
const spender = balancerRouter

return useReadContract({
chainId,
address: permit2Address,
abi: permit2Abi,
functionName: 'allowance',
args: [owner, tokenAddress, spender],
query: {
enabled: !!tokenAddress && !!owner,
},
})
}
2 changes: 2 additions & 0 deletions lib/config/config.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export interface ContractsConfig {
vaultV2: Address
// TODO: make it required when v3 is deployed in all networks
vaultV3?: Address
// TODO: make it required when v3 is deployed in all networks
router?: Address
relayerV6: Address
minter: Address
}
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 @@ -32,6 +32,7 @@ const networkConfig: NetworkConfig = {
balancer: {
vaultV2: '0xBA12222222228d8Ba445958a75a0704d566BF2C8',
vaultV3: '0x0EF1c156a7986F394d90eD1bEeA6483Cc435F542',
router: '0xB12FcB422aAe6720f882E22C340964a7723f2387',
relayerV6: '0x7852fB9d0895e6e8b3EedA553c03F6e2F9124dF9',
minter: '0x1783Cd84b3d01854A96B4eD5843753C2CcbD574A',
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { HumanTokenAmountWithAddress } from '@/lib/modules/tokens/token.types'
import { TransactionConfig } from '@/lib/modules/web3/contracts/contract.types'
import { SdkClient } from '@/lib/modules/web3/useSdkViemClient'
import { AddLiquidityQueryOutput, Permit2 } from '@balancer/sdk'
import { AddLiquidityQueryOutput, Permit2, PublicWalletClient } from '@balancer/sdk'
import { Address } from 'viem'
import { BuildAddLiquidityInput, QueryAddLiquidityOutput } from '../add-liquidity.types'
import { NoncesByTokenAddress } from '@/lib/modules/tokens/approvals/permit2/usePermit2Nonces'

export interface Permit2AddLiquidityInput {
account: Address
Expand Down Expand Up @@ -40,5 +40,9 @@ export interface AddLiquidityHandler {
/* Sign permit2 for adding liquidity (for now only used by v3 pools)
TODO: generalize for other handlers using permit2
*/
signPermit2?(input: Permit2AddLiquidityInput, walletClient: SdkClient): Promise<Permit2>
signPermit2?(
input: Permit2AddLiquidityInput,
walletClient: PublicWalletClient,
nonces?: NoncesByTokenAddress
): Promise<Permit2>
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { UnbalancedAddLiquidityHandler } from './UnbalancedAddLiquidity.handler'
import { selectAddLiquidityHandler } from './selectAddLiquidityHandler'
import { HumanTokenAmountWithAddress } from '@/lib/modules/tokens/token.types'
import { Pool } from '../../../PoolProvider'
import { getNetworkConfig } from '@/lib/config/app.config'
import { GqlChain } from '@/lib/shared/services/api/generated/graphql'

function selectUnbalancedHandler() {
return selectAddLiquidityHandler(aWjAuraWethPoolElementMock()) as UnbalancedAddLiquidityHandler
Expand Down Expand Up @@ -110,7 +112,8 @@ describe.skip('When adding unbalanced liquidity for a V3 pool', async () => {
queryOutput,
})

const sepoliaRouter = '0xB12FcB422aAe6720f882E22C340964a7723f2387'
const sepoliaRouter = getNetworkConfig(GqlChain.Sepolia).contracts.balancer.router

expect(result.to).toBe(sepoliaRouter)
expect(result.data).toBeDefined()
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import { HumanTokenAmountWithAddress } from '@/lib/modules/tokens/token.types'
import { TransactionConfig } from '@/lib/modules/web3/contracts/contract.types'
import { getRpcUrl } from '@/lib/modules/web3/transports'
import { SdkClient } from '@/lib/modules/web3/useSdkViemClient'
import {
AddLiquidity,
AddLiquidityBaseBuildCallInput,
Expand All @@ -13,6 +12,7 @@ import {
Permit2Helper,
PriceImpact,
PriceImpactAmount,
PublicWalletClient,
Slippage,
} from '@balancer/sdk'
import { Pool } from '../../../PoolProvider'
Expand All @@ -23,6 +23,7 @@ import {
} from '../../LiquidityActionHelpers'
import { SdkBuildAddLiquidityInput, SdkQueryAddLiquidityOutput } from '../add-liquidity.types'
import { AddLiquidityHandler, Permit2AddLiquidityInput } from './AddLiquidity.handler'
import { NoncesByTokenAddress } from '@/lib/modules/tokens/approvals/permit2/usePermit2Nonces'

/**
* UnbalancedAddLiquidityHandler is a handler that implements the
Expand Down Expand Up @@ -102,18 +103,19 @@ export class UnbalancedAddLiquidityHandler implements AddLiquidityHandler {

public async signPermit2(
input: Permit2AddLiquidityInput,
sdkClient: SdkClient
sdkClient: PublicWalletClient,
nonces: NoncesByTokenAddress
): Promise<Permit2> {
const baseInput = this.constructBaseBuildCallInput({
slippagePercent: input.slippagePercent,
sdkQueryOutput: input.sdkQueryOutput as AddLiquidityBaseQueryOutput,
})
const signature = await Permit2Helper.signAddLiquidityApproval({
...this.constructBaseBuildCallInput({
slippagePercent: input.slippagePercent,
sdkQueryOutput: input.sdkQueryOutput as AddLiquidityBaseQueryOutput,
}),
...baseInput,
client: sdkClient,
owner: input.account,
// nonces: input.sdkQueryOutput.amountsIn.map(a => (a.amount === 0n ? 0 : 2)),
nonces: baseInput.amountsIn.map(a => nonces[a.token.address]),
})

return signature
}

Expand Down Expand Up @@ -145,6 +147,9 @@ export class UnbalancedAddLiquidityHandler implements AddLiquidityHandler {
slippage: Slippage.fromPercentage(`${Number(slippagePercent)}`),
wethIsEth: this.helpers.includesNativeAsset(sdkQueryOutput.amountsIn),
}
// baseBuildCallParams.amountsIn = baseBuildCallParams.amountsIn.filter(
// amountIn => amountIn.amount > 0n
// )
return baseBuildCallParams
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { HumanTokenAmountWithAddress } from '@/lib/modules/tokens/token.types'
import { TransactionConfig } from '@/lib/modules/web3/contracts/contract.types'
import { getRpcUrl } from '@/lib/modules/web3/transports'
import {
AddLiquidity,
AddLiquidityBaseBuildCallInput,
AddLiquidityBaseQueryOutput,
AddLiquidityKind,
AddLiquidityUnbalancedInput,
Permit2,
Permit2Helper,
PriceImpact,
PriceImpactAmount,
PublicWalletClient,
Slippage,
} from '@balancer/sdk'
import { Pool } from '../../../PoolProvider'
import {
LiquidityActionHelpers,
areEmptyAmounts,
formatBuildCallParams,
} from '../../LiquidityActionHelpers'
import { SdkBuildAddLiquidityInput, SdkQueryAddLiquidityOutput } from '../add-liquidity.types'
import { AddLiquidityHandler, Permit2AddLiquidityInput } from './AddLiquidity.handler'
import { NoncesByTokenAddress } from '@/lib/modules/tokens/approvals/permit2/usePermit2Nonces'

/**
* UnbalancedAddLiquidityHandler is a handler that implements the
* AddLiquidityHandler interface for unbalanced adds, e.g. where the user
* specifies the token amounts in. It uses the Balancer SDK to implement it's
* methods. It also handles the case where one of the input tokens is the native
* asset instead of the wrapped native asset.
*/
export class UnbalancedAddLiquidityHandler implements AddLiquidityHandler {
helpers: LiquidityActionHelpers

constructor(pool: Pool) {
this.helpers = new LiquidityActionHelpers(pool)
}

public async simulate(
humanAmountsIn: HumanTokenAmountWithAddress[]
): Promise<SdkQueryAddLiquidityOutput> {
const addLiquidity = new AddLiquidity()
const addLiquidityInput = this.constructSdkInput(humanAmountsIn)

const sdkQueryOutput = await addLiquidity.query(addLiquidityInput, this.helpers.poolState)

return { bptOut: sdkQueryOutput.bptOut, sdkQueryOutput }
}

public async getPriceImpact(humanAmountsIn: HumanTokenAmountWithAddress[]): Promise<number> {
if (areEmptyAmounts(humanAmountsIn)) {
// Avoid price impact calculation when there are no amounts in
return 0
}

const addLiquidityInput = this.constructSdkInput(humanAmountsIn)

const priceImpactABA: PriceImpactAmount = await PriceImpact.addLiquidityUnbalanced(
addLiquidityInput,
this.helpers.poolState
)

return priceImpactABA.decimal
}

public async buildCallData({
slippagePercent,
queryOutput,
account,
permit2,
}: SdkBuildAddLiquidityInput): Promise<TransactionConfig> {
const addLiquidity = new AddLiquidity()

const buildCallParams = formatBuildCallParams(
this.constructBaseBuildCallInput({
sdkQueryOutput: queryOutput.sdkQueryOutput,
slippagePercent: slippagePercent,
}),
this.helpers.isV3Pool(),
account
)

if (this.helpers.isV3Pool() && !permit2) {
throw new Error('Permit2 signature is required for V3 pools')
}

const { callData, to, value } =
this.helpers.isV3Pool() && permit2
? addLiquidity.buildCallWithPermit2(buildCallParams, permit2)
: addLiquidity.buildCall(buildCallParams)

return {
account,
chainId: this.helpers.chainId,
data: callData,
to,
value,
}
}

public async signPermit2(
input: Permit2AddLiquidityInput,
sdkClient: PublicWalletClient,
nonces?: NoncesByTokenAddress
): Promise<Permit2> {
// console.log('tengo los nonces super ricos')
const baseInput = this.constructBaseBuildCallInput({
slippagePercent: input.slippagePercent,
sdkQueryOutput: input.sdkQueryOutput as AddLiquidityBaseQueryOutput,
})
const signature = await Permit2Helper.signAddLiquidityApproval({
...baseInput,
client: sdkClient,
owner: input.account,
nonces: baseInput.amountsIn.map(a => (a.amount === 0n ? 3 : 1)),
})

return signature
}

/**
* PRIVATE METHODS
*/
private constructSdkInput(
humanAmountsIn: HumanTokenAmountWithAddress[]
): AddLiquidityUnbalancedInput {
const amountsIn = this.helpers.toSdkInputAmounts(humanAmountsIn)

return {
chainId: this.helpers.chainId,
rpcUrl: getRpcUrl(this.helpers.chainId),
amountsIn,
kind: AddLiquidityKind.Unbalanced,
}
}

public constructBaseBuildCallInput({
slippagePercent,
sdkQueryOutput,
}: {
slippagePercent: string
sdkQueryOutput: AddLiquidityBaseQueryOutput
}): AddLiquidityBaseBuildCallInput {
const baseBuildCallParams = {
...(sdkQueryOutput as AddLiquidityBaseQueryOutput),
slippage: Slippage.fromPercentage(`${Number(slippagePercent)}`),
wethIsEth: this.helpers.includesNativeAsset(sdkQueryOutput.amountsIn),
}
baseBuildCallParams.amountsIn = baseBuildCallParams.amountsIn.filter(
amountIn => amountIn.amount > 0n
)
return baseBuildCallParams
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ export function useAddLiquiditySteps({
slippagePercent: slippage,
queryOutput: simulationQuery.data as SdkQueryAddLiquidityOutput,
},
chainId
chainId,
requiresPermit2Approval(pool)
)

const addLiquidityStep = useAddLiquidityStep({
Expand Down
4 changes: 2 additions & 2 deletions lib/modules/relayer/signRelayerApproval.hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { RelayerMode } from './useRelayerMode'
import { SignRelayerState, useRelayerSignature } from './RelayerSignatureProvider'
import { SupportedChainId } from '@/lib/config/config.types'
import { Toast } from '@/lib/shared/components/toasts/Toast'
import { useSdkViemClient } from '../web3/useSdkViemClient'
import { useSdkWalletClient } from '../web3/useSdkViemClient'

export function useShouldSignRelayerApproval(chainId: SupportedChainId, relayerMode: RelayerMode) {
const { hasApprovedRelayer } = useHasApprovedRelayer(chainId)
Expand All @@ -23,7 +23,7 @@ export function useSignRelayerApproval(chainId: SupportedChainId) {

const [error, setError] = useState<string | undefined>()

const sdkClient = useSdkViemClient()
const sdkClient = useSdkWalletClient()

useEffect(() => {
if (sdkClient === undefined) {
Expand Down
5 changes: 2 additions & 3 deletions lib/modules/relayer/signRelayerApproval.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { getNetworkConfig } from '@/lib/config/app.config'
import { SupportedChainId } from '@/lib/config/config.types'
import { ensureError } from '@/lib/shared/utils/errors'
import { Relayer } from '@balancer/sdk'
import { PublicWalletClient, Relayer } from '@balancer/sdk'
import { Address } from 'viem'
import { SdkClient } from '../web3/useSdkViemClient'

export async function signRelayerApproval(
userAddress: Address,
chainId: SupportedChainId,
client?: SdkClient
client?: PublicWalletClient
): Promise<Address | undefined> {
if (!client) return undefined

Expand Down
Loading

0 comments on commit d4f70d1

Please sign in to comment.