From 6b0561315f126b208a1104ab6ff2bd1f7e58f1f2 Mon Sep 17 00:00:00 2001 From: Alberto Gualis Date: Mon, 21 Oct 2024 14:26:59 +0200 Subject: [PATCH 01/27] feat: permit2 swaps --- .../app/(app)/debug/page.tsx | 5 +- apps/frontend-v3/app/(app)/debug/page.tsx | 5 +- .../pool/actions/LiquidityActionHelpers.ts | 12 +++ .../add-liquidity/useAddLiquiditySteps.tsx | 15 ++- .../add-liquidity/useSignPermit2AddStep.tsx | 52 ++++++++++ packages/lib/modules/swap/SwapLayout.tsx | 21 +++-- .../swap/handlers/DefaultSwap.handler.ts | 18 +++- .../modules/swap/queries/useBuildSwapQuery.ts | 4 + packages/lib/modules/swap/swap.helpers.ts | 13 ++- packages/lib/modules/swap/swap.types.ts | 3 + .../lib/modules/swap/usePermit2SwapStep.tsx | 62 ++++++++++++ packages/lib/modules/swap/useSwapSteps.tsx | 40 +++++--- .../approvals/permit2/permit2.helpers.ts | 94 +++++++++++++------ .../approvals/permit2/signPermit2Add.tsx | 58 ++++++++---- .../approvals/permit2/signPermit2Swap.tsx | 76 +++++++++++++++ .../approvals/permit2/usePermit2Allowance.tsx | 18 ++-- .../approvals/permit2/useSignPermit2.tsx | 71 +++++++------- packages/lib/modules/tokens/token.helpers.ts | 18 +--- .../transaction-steps/useSignPermit2Step.tsx | 81 ++++++++-------- 19 files changed, 470 insertions(+), 196 deletions(-) create mode 100644 packages/lib/modules/pool/actions/add-liquidity/useSignPermit2AddStep.tsx create mode 100644 packages/lib/modules/swap/usePermit2SwapStep.tsx create mode 100644 packages/lib/modules/tokens/approvals/permit2/signPermit2Swap.tsx diff --git a/apps/beets-frontend-v3/app/(app)/debug/page.tsx b/apps/beets-frontend-v3/app/(app)/debug/page.tsx index b00f8c69a..e9cf6cf23 100644 --- a/apps/beets-frontend-v3/app/(app)/debug/page.tsx +++ b/apps/beets-frontend-v3/app/(app)/debug/page.tsx @@ -7,7 +7,7 @@ import FadeInOnView from '@repo/lib/shared/components/containers/FadeInOnView' export default function Debug() { return ( - + Demos Pools @@ -39,9 +39,6 @@ export default function Debug() { Permit2 allowance - - Permit2 allowance - ) diff --git a/apps/frontend-v3/app/(app)/debug/page.tsx b/apps/frontend-v3/app/(app)/debug/page.tsx index b00f8c69a..e9cf6cf23 100644 --- a/apps/frontend-v3/app/(app)/debug/page.tsx +++ b/apps/frontend-v3/app/(app)/debug/page.tsx @@ -7,7 +7,7 @@ import FadeInOnView from '@repo/lib/shared/components/containers/FadeInOnView' export default function Debug() { return ( - + Demos Pools @@ -39,9 +39,6 @@ export default function Debug() { Permit2 allowance - - Permit2 allowance - ) diff --git a/packages/lib/modules/pool/actions/LiquidityActionHelpers.ts b/packages/lib/modules/pool/actions/LiquidityActionHelpers.ts index d48b38a61..f5c679ff0 100644 --- a/packages/lib/modules/pool/actions/LiquidityActionHelpers.ts +++ b/packages/lib/modules/pool/actions/LiquidityActionHelpers.ts @@ -6,6 +6,7 @@ import { isSameAddress } from '@repo/lib/shared/utils/addresses' import { SentryError } from '@repo/lib/shared/utils/errors' import { bn, isZero } from '@repo/lib/shared/utils/numbers' import { + AddLiquidityQueryOutput, HumanAmount, InputAmount, MinimalToken, @@ -35,6 +36,7 @@ import { isUnbalancedLiquidityDisabled, isV3Pool, } from '../pool.helpers' +import { TokenAmountIn } from '../../tokens/approvals/permit2/useSignPermit2' // Null object used to avoid conditional checks during hook loading state const NullPool: Pool = { @@ -319,3 +321,13 @@ export function formatBuildCallParams(buildCallParams: T, account: Address) { // sender and recipient must be defined only for v1 and v2 pools return { ...buildCallParams, sender: account, recipient: account } } + +export function toTokenAmountsIn(sdkQueryOutput: AddLiquidityQueryOutput): TokenAmountIn[] | undefined { + if (!sdkQueryOutput) return + return sdkQueryOutput.amountsIn.map(amountIn => ( + { + address: amountIn.token.address, + amount: amountIn.amount + } + )) +} diff --git a/packages/lib/modules/pool/actions/add-liquidity/useAddLiquiditySteps.tsx b/packages/lib/modules/pool/actions/add-liquidity/useAddLiquiditySteps.tsx index 09d749716..9da1a6336 100644 --- a/packages/lib/modules/pool/actions/add-liquidity/useAddLiquiditySteps.tsx +++ b/packages/lib/modules/pool/actions/add-liquidity/useAddLiquiditySteps.tsx @@ -4,15 +4,14 @@ import { useApproveRelayerStep } from '@repo/lib/modules/relayer/useApproveRelay import { useRelayerMode } from '@repo/lib/modules/relayer/useRelayerMode' import { useTokenApprovalSteps } from '@repo/lib/modules/tokens/approvals/useTokenApprovalSteps' import { getSpenderForAddLiquidity } from '@repo/lib/modules/tokens/token.helpers' -import { useSignPermit2Step } from '@repo/lib/modules/transactions/transaction-steps/useSignPermit2Step' import { useSignRelayerStep } from '@repo/lib/modules/transactions/transaction-steps/useSignRelayerStep' import { useUserSettings } from '@repo/lib/modules/user/settings/UserSettingsProvider' import { useMemo } from 'react' import { usePool } from '../../PoolProvider' import { requiresPermit2Approval } from '../../pool.helpers' import { LiquidityActionHelpers } from '../LiquidityActionHelpers' -import { SdkQueryAddLiquidityOutput } from './add-liquidity.types' import { AddLiquidityStepParams, useAddLiquidityStep } from './useAddLiquidityStep' +import { useSignPermit2AddStep } from './useSignPermit2AddStep' type AddLiquidityStepsParams = AddLiquidityStepParams & { helpers: LiquidityActionHelpers @@ -48,13 +47,13 @@ export function useAddLiquiditySteps({ isPermit2, }) - const signPermit2Step = useSignPermit2Step({ - pool, + + const wethIsEth = helpers.isNativeAssetIn(humanAmountsIn) + + const signPermit2Step = useSignPermit2AddStep({ + wethIsEth, humanAmountsIn, - slippagePercent: slippage, - queryOutput: simulationQuery.data as SdkQueryAddLiquidityOutput, - isPermit2, - wethIsEth: helpers.isNativeAssetIn(humanAmountsIn), + simulationQuery, }) const isSignPermit2Loading = isPermit2 && !signPermit2Step diff --git a/packages/lib/modules/pool/actions/add-liquidity/useSignPermit2AddStep.tsx b/packages/lib/modules/pool/actions/add-liquidity/useSignPermit2AddStep.tsx new file mode 100644 index 000000000..acd7e8949 --- /dev/null +++ b/packages/lib/modules/pool/actions/add-liquidity/useSignPermit2AddStep.tsx @@ -0,0 +1,52 @@ +import { PublicWalletClient } from '@balancer/sdk' +import { signPermit2Add } from '@repo/lib/modules/tokens/approvals/permit2/signPermit2Add' +import { NoncesByTokenAddress } from '@repo/lib/modules/tokens/approvals/permit2/usePermit2Allowance' +import { SignPermit2Callback } from '@repo/lib/modules/tokens/approvals/permit2/useSignPermit2' +import { useSignPermit2Step } from '@repo/lib/modules/transactions/transaction-steps/useSignPermit2Step' +import { useUserAccount } from '@repo/lib/modules/web3/UserAccountProvider' +import { SdkQueryAddLiquidityOutput } from './add-liquidity.types' +import { AddLiquiditySimulationQueryResult } from './queries/useAddLiquiditySimulationQuery' +import { requiresPermit2Approval } from '../../pool.helpers' +import { usePool } from '../../PoolProvider' +import { HumanTokenAmountWithAddress } from '@repo/lib/modules/tokens/token.types' +import { useUserSettings } from '@repo/lib/modules/user/settings/UserSettingsProvider' +import { toTokenAmountsIn } from '../LiquidityActionHelpers' + +type Props = { + wethIsEth: boolean, + simulationQuery: AddLiquiditySimulationQueryResult + humanAmountsIn: HumanTokenAmountWithAddress[] +} + +export function useSignPermit2AddStep({ wethIsEth, humanAmountsIn, simulationQuery }: Props) { + const { userAddress } = useUserAccount() + const { pool, chainId } = usePool() + const { slippage } = useUserSettings() + + const isPermit2 = requiresPermit2Approval(pool) + const queryOutput = simulationQuery.data as SdkQueryAddLiquidityOutput + + const signPermit2Callback: SignPermit2Callback = (sdkClient: PublicWalletClient, nonces: NoncesByTokenAddress) => { + return signPermit2Add({ + sdkClient, + pool, + humanAmountsIn, + wethIsEth, + account: userAddress, + sdkQueryOutput: queryOutput?.sdkQueryOutput, + slippagePercent: slippage, + nonces + }) + } + + const signPermit2Step = useSignPermit2Step({ + chainId, + signPermit2Callback, + wethIsEth, + tokenAmountsIn: toTokenAmountsIn(queryOutput?.sdkQueryOutput), + isPermit2, + isSimulationReady: !!queryOutput?.sdkQueryOutput.bptOut.amount, + }) + + return signPermit2Step +} \ No newline at end of file diff --git a/packages/lib/modules/swap/SwapLayout.tsx b/packages/lib/modules/swap/SwapLayout.tsx index 530d16a62..a4544a79d 100644 --- a/packages/lib/modules/swap/SwapLayout.tsx +++ b/packages/lib/modules/swap/SwapLayout.tsx @@ -10,6 +10,7 @@ import { useTokens } from '@repo/lib/modules/tokens/TokensProvider' import { TransactionStateProvider } from '@repo/lib/modules/transactions/transaction-steps/TransactionStateProvider' import { GqlChain } from '@repo/lib/shared/services/api/generated/graphql' import { PropsWithChildren } from 'react' +import { Permit2SignatureProvider } from '../tokens/approvals/permit2/Permit2SignatureProvider' type Props = PropsWithChildren<{ props: SwapProviderProps @@ -24,15 +25,17 @@ export default function SwapLayout({ props, children }: Props) { return ( - - - - - {children} - - - - + + + + + + {children} + + + + + ) } diff --git a/packages/lib/modules/swap/handlers/DefaultSwap.handler.ts b/packages/lib/modules/swap/handlers/DefaultSwap.handler.ts index b565616f9..479999c02 100644 --- a/packages/lib/modules/swap/handlers/DefaultSwap.handler.ts +++ b/packages/lib/modules/swap/handlers/DefaultSwap.handler.ts @@ -66,20 +66,28 @@ export class DefaultSwapHandler implements SwapHandler { } build({ - simulateResponse: { swap, queryOutput }, + simulateResponse: { swap, queryOutput, protocolVersion }, slippagePercent, account, selectedChain, wethIsEth, + permit2, }: SdkBuildSwapInputs): TransactionConfig { - const tx = swap.buildCall({ + const baseBuildCallParams = { slippage: Slippage.fromPercentage(slippagePercent as `${number}`), deadline: BigInt(Number.MAX_SAFE_INTEGER), - sender: account, - recipient: account, wethIsEth, queryOutput, - }) + } + const isV3SwapRoute = protocolVersion === 3 + + const buildCallParams = isV3SwapRoute + ? baseBuildCallParams + : {...baseBuildCallParams, sender: account, recipient: account} + + const tx = isV3SwapRoute && permit2 + ? swap.buildCallWithPermit2(buildCallParams, permit2) + : swap.buildCall(buildCallParams) return { account, diff --git a/packages/lib/modules/swap/queries/useBuildSwapQuery.ts b/packages/lib/modules/swap/queries/useBuildSwapQuery.ts index 1253e3123..e883bba9b 100644 --- a/packages/lib/modules/swap/queries/useBuildSwapQuery.ts +++ b/packages/lib/modules/swap/queries/useBuildSwapQuery.ts @@ -11,6 +11,7 @@ import { useRelayerSignature } from '../../relayer/RelayerSignatureProvider' import { SwapMetaParams, sentryMetaForSwapHandler } from '@repo/lib/shared/utils/query-errors' import { getChainId } from '@repo/lib/config/app.config' import { useBlockNumber } from 'wagmi' +import { usePermit2Signature } from '../../tokens/approvals/permit2/Permit2SignatureProvider' export type BuildSwapQueryResponse = ReturnType @@ -34,6 +35,7 @@ export function useBuildSwapQuery({ const { userAddress, isConnected } = useUserAccount() const { slippage } = useUserSettings() const { relayerApprovalSignature } = useRelayerSignature() + const { permit2Signature: permit2 } = usePermit2Signature() const { selectedChain, tokenIn, tokenOut, swapType } = swapState const chainId = getChainId(selectedChain) @@ -59,8 +61,10 @@ export function useBuildSwapQuery({ simulateResponse, wethIsEth, relayerApprovalSignature, + permit2, }) console.log('Swap callData built:', response) + if (permit2) console.log('Swap permit2:', permit2) return response } diff --git a/packages/lib/modules/swap/swap.helpers.ts b/packages/lib/modules/swap/swap.helpers.ts index dd6367137..53cd0bae8 100644 --- a/packages/lib/modules/swap/swap.helpers.ts +++ b/packages/lib/modules/swap/swap.helpers.ts @@ -1,5 +1,5 @@ import { Address } from 'viem' -import { OSwapAction, SwapAction } from './swap.types' +import { OSwapAction, SdkSimulateSwapResponse, SwapAction } from './swap.types' import { GqlChain, GqlSorSwapType } from '@repo/lib/shared/services/api/generated/graphql' import { getNativeAssetAddress, @@ -8,6 +8,7 @@ import { } from '@repo/lib/config/app.config' import { isSameAddress } from '@repo/lib/shared/utils/addresses' import { isMainnet } from '../chains/chain.utils' +import { SwapSimulationQueryResult } from './queries/useSimulateSwapQuery' export function swapActionPastTense(action: SwapAction): string { switch (action) { @@ -66,3 +67,13 @@ export function isAuraBalSwap( return tokenInOrOutIsAuraBal && tokenInOrOutIsRelevantToken && isExactInSwap && isMainnet(chain) } + +export function isV3SwapRoute(simulationQuery: SwapSimulationQueryResult): boolean { + return orderRouteVersion(simulationQuery) === 3 +} + +export function orderRouteVersion(simulationQuery: SwapSimulationQueryResult): number { + const queryData = simulationQuery.data as SdkSimulateSwapResponse + const orderRouteVersion = queryData ? queryData.protocolVersion : 2 + return orderRouteVersion +} diff --git a/packages/lib/modules/swap/swap.types.ts b/packages/lib/modules/swap/swap.types.ts index 52182019b..2e7258ebc 100644 --- a/packages/lib/modules/swap/swap.types.ts +++ b/packages/lib/modules/swap/swap.types.ts @@ -7,6 +7,7 @@ import { AuraBalSwapQueryOutput, ExactInQueryOutput, ExactOutQueryOutput, + Permit2, Swap, } from '@balancer/sdk' import { Address, Hex } from 'viem' @@ -30,6 +31,7 @@ export type SimulateSwapInputs = { tokenOut: Address swapType: GqlSorSwapType swapAmount: string + permit2?: Permit2 } type ApiSwapQuery = GetSorSwapsQuery['swaps'] @@ -54,6 +56,7 @@ export interface BuildSwapInputs extends SwapState { simulateResponse: SimulateSwapResponse wethIsEth: boolean relayerApprovalSignature?: Hex + permit2?: Permit2 // only used by v3 swaps } export interface SdkBuildSwapInputs extends BuildSwapInputs { diff --git a/packages/lib/modules/swap/usePermit2SwapStep.tsx b/packages/lib/modules/swap/usePermit2SwapStep.tsx new file mode 100644 index 000000000..894b87352 --- /dev/null +++ b/packages/lib/modules/swap/usePermit2SwapStep.tsx @@ -0,0 +1,62 @@ +import { PublicWalletClient, SwapKind } from '@balancer/sdk' +import { useUserSettings } from '@repo/lib/modules/user/settings/UserSettingsProvider' +import { useUserAccount } from '@repo/lib/modules/web3/UserAccountProvider' +import { GqlToken } from '@repo/lib/shared/services/api/generated/graphql' +import { Address } from 'viem' +import { signPermit2Swap } from '../tokens/approvals/permit2/signPermit2Swap' +import { NoncesByTokenAddress } from '../tokens/approvals/permit2/usePermit2Allowance' +import { SignPermit2Callback, TokenAmountIn } from '../tokens/approvals/permit2/useSignPermit2' +import { useSignPermit2Step } from '../transactions/transaction-steps/useSignPermit2Step' +import { SwapSimulationQueryResult } from './queries/useSimulateSwapQuery' +import { SdkSimulateSwapResponse } from './swap.types' + +type Props = { + wethIsEth: boolean, + simulationQuery: SwapSimulationQueryResult + tokenInInfo?: GqlToken + chainId: number + isPermit2: boolean +} + +export function useSignPermit2SwapStep({ chainId, wethIsEth, tokenInInfo, simulationQuery, isPermit2 }: Props) { + const { userAddress } = useUserAccount() + const { slippage } = useUserSettings() + + const tokenInAddress = tokenInInfo?.address as Address + + const queryData = simulationQuery.data as SdkSimulateSwapResponse + + function getTokenInAmount(simulationQuery: SwapSimulationQueryResult): bigint { + if (!simulationQuery.data) return 0n + const queryData = simulationQuery.data as SdkSimulateSwapResponse + if (queryData.queryOutput.swapKind === SwapKind.GivenIn) return queryData.queryOutput.amountIn.amount + if (queryData.queryOutput.swapKind === SwapKind.GivenOut) return queryData.queryOutput.expectedAmountIn.amount + return 0n + } + + const tokenIn: TokenAmountIn = { + address: tokenInAddress, + amount: getTokenInAmount(simulationQuery), + } + + const signPermit2Callback: SignPermit2Callback = (sdkClient: PublicWalletClient, nonces: NoncesByTokenAddress) => { + return signPermit2Swap({ + sdkClient, + wethIsEth, + account: userAddress, + queryOutput: queryData.queryOutput, + slippagePercent: slippage, + nonces, + tokenIn + }) + } + + return useSignPermit2Step({ + chainId, + signPermit2Callback, + wethIsEth, + tokenAmountsIn: [tokenIn], + isPermit2, + isSimulationReady: !!simulationQuery.data, + }) +} \ No newline at end of file diff --git a/packages/lib/modules/swap/useSwapSteps.tsx b/packages/lib/modules/swap/useSwapSteps.tsx index 73ac7f6bc..b8117f62a 100644 --- a/packages/lib/modules/swap/useSwapSteps.tsx +++ b/packages/lib/modules/swap/useSwapSteps.tsx @@ -1,15 +1,18 @@ +import { getChainId, getNetworkConfig } from '@repo/lib/config/app.config' import { useMemo } from 'react' import { Address, parseUnits } from 'viem' +import { useShouldSignRelayerApproval } from '../relayer/signRelayerApproval.hooks' +import { useApproveRelayerStep } from '../relayer/useApproveRelayerStep' +import { useRelayerMode } from '../relayer/useRelayerMode' import { ApprovalAction } from '../tokens/approvals/approval-labels' import { RawAmount } from '../tokens/approvals/approval-rules' import { useTokenApprovalSteps } from '../tokens/approvals/useTokenApprovalSteps' +import { useSignRelayerStep } from '../transactions/transaction-steps/useSignRelayerStep' +import { orderRouteVersion } from './swap.helpers' import { OSwapAction } from './swap.types' +import { useSignPermit2SwapStep } from './usePermit2SwapStep' import { SwapStepParams, useSwapStep } from './useSwapStep' -import { useRelayerMode } from '../relayer/useRelayerMode' -import { useShouldSignRelayerApproval } from '../relayer/signRelayerApproval.hooks' -import { getChainId } from '@repo/lib/config/app.config' -import { useApproveRelayerStep } from '../relayer/useApproveRelayerStep' -import { useSignRelayerStep } from '../transactions/transaction-steps/useSignRelayerStep' +import { permit2Address } from '../tokens/approvals/permit2/permit2.helpers' type Params = SwapStepParams & { vaultAddress: Address @@ -25,7 +28,10 @@ export function useSwapSteps({ tokenInInfo, tokenOutInfo, }: Params) { - const chainId = getChainId(swapState.selectedChain) + const chain = swapState.selectedChain + const chainId = getChainId(chain) + + const isPermit2 = orderRouteVersion(simulationQuery) === 3 const relayerMode = useRelayerMode() const shouldSignRelayerApproval = useShouldSignRelayerApproval(chainId, relayerMode) @@ -51,12 +57,15 @@ export function useSwapSteps({ const { isLoading: isLoadingTokenApprovalSteps, steps: tokenApprovalSteps } = useTokenApprovalSteps({ - spenderAddress: vaultAddress, - chain: swapState.selectedChain, + spenderAddress: isPermit2 ? permit2Address(chain) : vaultAddress, + chain, approvalAmounts: tokenInAmounts, actionType: approvalActionType, + isPermit2, }) + const signPermit2Step = useSignPermit2SwapStep({ chainId, wethIsEth, tokenInInfo, simulationQuery, isPermit2 }) + const swapStep = useSwapStep({ handler, wethIsEth, @@ -67,19 +76,26 @@ export function useSwapSteps({ tokenOutInfo, }) + const isSignPermit2Loading = isPermit2 && !signPermit2Step + const steps = useMemo(() => { + const swapSteps = + isPermit2 && signPermit2Step ? [signPermit2Step, swapStep] : [swapStep] + if (swapRequiresRelayer) { if (relayerMode === 'approveRelayer') { - return [approveRelayerStep, ...tokenApprovalSteps, swapStep] + return [approveRelayerStep, ...tokenApprovalSteps, ...swapSteps] } else if (shouldSignRelayerApproval) { - return [signRelayerStep, ...tokenApprovalSteps, swapStep] + return [signRelayerStep, ...tokenApprovalSteps, ...swapSteps] } } - return [...tokenApprovalSteps, swapStep] + return [...tokenApprovalSteps, ...swapSteps] }, [ swapRequiresRelayer, tokenApprovalSteps, + isPermit2, swapStep, + signPermit2Step, relayerMode, shouldSignRelayerApproval, approveRelayerStep, @@ -87,7 +103,7 @@ export function useSwapSteps({ ]) return { - isLoadingSteps: isLoadingTokenApprovalSteps || isLoadingRelayerApproval, + isLoadingSteps: isLoadingTokenApprovalSteps || isLoadingRelayerApproval || isSignPermit2Loading, steps, } } diff --git a/packages/lib/modules/tokens/approvals/permit2/permit2.helpers.ts b/packages/lib/modules/tokens/approvals/permit2/permit2.helpers.ts index 519288675..91a1d8342 100644 --- a/packages/lib/modules/tokens/approvals/permit2/permit2.helpers.ts +++ b/packages/lib/modules/tokens/approvals/permit2/permit2.helpers.ts @@ -1,64 +1,96 @@ -import { SdkQueryAddLiquidityOutput } from '@repo/lib/modules/pool/actions/add-liquidity/add-liquidity.types' +import { getGqlChain, getNetworkConfig } from '@repo/lib/config/app.config' import { getNowTimestampInSecs } from '@repo/lib/shared/utils/time' -import { AllowedAmountsByTokenAddress, ExpirationByTokenAddress } from './usePermit2Allowance' import { Address } from 'viem' -import { TokenAmount } from '@balancer/sdk' -import { getGqlChain } from '@repo/lib/config/app.config' -import { filterWrappedNativeAsset } from '../../token.helpers' 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' export function hasValidPermit2( - queryOutput?: SdkQueryAddLiquidityOutput, + tokenAmountsIn?: TokenAmountIn[], expirations?: ExpirationByTokenAddress, - allowedAmounts?: AllowedAmountsByTokenAddress + allowedAmounts?: AllowedAmountsByTokenAddress, ): boolean { - if (!expirations || !allowedAmounts) return false + if (!expirations || !allowedAmounts || !tokenAmountsIn) return false const approvalExpired = (tokenAddress: Address) => - expirations[tokenAddress] >= getNowTimestampInSecs() - const alreadyAllowed = (amountIn: TokenAmount) => - !approvalExpired(amountIn.token.address) && - allowedAmounts[amountIn.token.address] >= amountIn.amount - const amountInValid = (amountIn: TokenAmount) => + expirations[tokenAddress] < getNowTimestampInSecs() + const alreadyAllowed = (amountIn: TokenAmountIn) => + !approvalExpired(amountIn.address) && + allowedAmounts[amountIn.address] >= amountIn.amount + const amountInValid = (amountIn: TokenAmountIn) => amountIn.amount === 0n || alreadyAllowed(amountIn) - const isValid = !!queryOutput?.sdkQueryOutput.amountsIn.every(amountInValid) + const isValid = tokenAmountsIn.every(amountInValid) + /* + // Delete after debug: + if (tokenAmountsIn) { + const tokenAddress = tokenAmountsIn[0].address + const amountIn = tokenAmountsIn[0] + console.log({tokenAddress, + approvalExpired: approvalExpired(tokenAddress), + alreadyAllowed: alreadyAllowed(amountIn), + }) + } + */ return isValid } type BasePermit2Params = { - queryOutput?: SdkQueryAddLiquidityOutput + tokenAmountsIn?: TokenAmountIn[] + chainId: number wethIsEth: boolean } // Returns the symbols of the tokens that need to be approved for permit2 -export function getTokenSymbolsForPermit2({ +export function getTokenSymbolsForPermit({ getToken, - queryOutput, + tokenAmountsIn, wethIsEth, -}: BasePermit2Params & { getToken: GetTokenFn }) { - if (!queryOutput) return [] - const chain = getGqlChain(queryOutput.sdkQueryOutput.chainId) + chainId, +}: BasePermit2Params & { getToken: GetTokenFn }): string[] { + if (!tokenAmountsIn) return [] + const chain = getGqlChain(chainId) const tokenSymbols = filterWrappedNativeAsset({ wethIsEth, - amountsIn: queryOutput.sdkQueryOutput.amountsIn, + tokenAmountsIn, chain, }) - .filter(a => a.amount > 0n) - .map(a => getToken(a.token.address, chain)?.symbol ?? 'Unknown') + .filter(t => t.amount > 0n) // This must be filtered in a different place (caller??) + .map(t => getToken(t.address, chain)?.symbol ?? 'Unknown') return tokenSymbols } // Returns the token addresses that need to be approved for permit2 -export function getTokenAddressesForPermit2({ +export function getTokenAddressesForPermit({ wethIsEth, - queryOutput, + tokenAmountsIn, + chainId, }: BasePermit2Params): Address[] | undefined { - if (!queryOutput?.sdkQueryOutput) return undefined - const chain = getGqlChain(queryOutput.sdkQueryOutput.chainId) - const result = filterWrappedNativeAsset({ + if (!tokenAmountsIn) return undefined + const chain = getGqlChain(chainId) + return filterWrappedNativeAsset({ wethIsEth, chain, - amountsIn: queryOutput.sdkQueryOutput.amountsIn, - }).map(a => a.token.address) - return result + tokenAmountsIn, + }).map(t => t.address) } + +export function permit2Address(chain: GqlChain): Address { + return getNetworkConfig(chain).contracts.permit2 || ('' as Address) +} + +function filterWrappedNativeAsset({ + tokenAmountsIn, + wethIsEth, + chain, +}: { + tokenAmountsIn?: TokenAmountIn[], + wethIsEth: boolean + chain: GqlChain +}): TokenAmountIn[] { + if (!tokenAmountsIn) return [] + if (!wethIsEth) return tokenAmountsIn + return tokenAmountsIn.filter(t => !isWrappedNativeAsset(t.address, chain)) +} + diff --git a/packages/lib/modules/tokens/approvals/permit2/signPermit2Add.tsx b/packages/lib/modules/tokens/approvals/permit2/signPermit2Add.tsx index e5ca6ae6f..86fd8b205 100644 --- a/packages/lib/modules/tokens/approvals/permit2/signPermit2Add.tsx +++ b/packages/lib/modules/tokens/approvals/permit2/signPermit2Add.tsx @@ -2,7 +2,6 @@ import { Pool } from '@repo/lib/modules/pool/PoolProvider' import { ensureError } from '@repo/lib/shared/utils/errors' import { get24HoursFromNowInSecs } from '@repo/lib/shared/utils/time' import { - AddLiquidityBaseQueryOutput, AddLiquidityQueryOutput, Address, Permit2, @@ -13,23 +12,21 @@ import { import { HumanTokenAmountWithAddress } from '../../token.types' import { NoncesByTokenAddress } from './usePermit2Allowance' import { constructBaseBuildCallInput } from '@repo/lib/modules/pool/actions/add-liquidity/handlers/add-liquidity.utils' -import { filterWrappedNativeAsset } from '../../token.helpers' +import { GqlChain } from '@repo/lib/shared/services/api/generated/graphql' +import { isWrappedNativeAsset } from '../../token.helpers' -export interface Permit2AddLiquidityInput { - account: Address - slippagePercent: string - sdkQueryOutput: AddLiquidityQueryOutput -} - -type SignPermit2Params = { +type SignPermit2AddParams = { sdkClient?: PublicWalletClient pool: Pool humanAmountsIn: HumanTokenAmountWithAddress[] - permit2Input: Permit2AddLiquidityInput - nonces: NoncesByTokenAddress + nonces?: NoncesByTokenAddress wethIsEth: boolean + account: Address + slippagePercent: string + sdkQueryOutput?: AddLiquidityQueryOutput } -export async function signPermit2Add(params: SignPermit2Params): Promise { +export async function signPermit2Add(params: SignPermit2AddParams): Promise { + if (!params.nonces) throw new Error('Missing nonces in signPermitAdd') try { const signature = await sign(params) return signature @@ -47,27 +44,33 @@ async function sign({ pool, humanAmountsIn, wethIsEth, - permit2Input, + account, + sdkQueryOutput, + slippagePercent, nonces, -}: SignPermit2Params): Promise { +}: SignPermit2AddParams): Promise { if (!sdkClient) throw new Error('Missing sdkClient') + if (!nonces) throw new Error('Missing nonces') + if (!sdkQueryOutput) throw new Error('Missing sdkQueryOutput') + const baseInput = constructBaseBuildCallInput({ humanAmountsIn, - slippagePercent: permit2Input.slippagePercent, - sdkQueryOutput: permit2Input.sdkQueryOutput as AddLiquidityBaseQueryOutput, + slippagePercent: slippagePercent, + sdkQueryOutput, pool, }) + const filteredAmountsIn = filterWrappedNativeAsset({ wethIsEth, chain: pool.chain, - amountsIn: baseInput.amountsIn, + amountsIn: sdkQueryOutput.amountsIn, }) const signature = await Permit2Helper.signAddLiquidityApproval({ ...baseInput, client: sdkClient, - owner: permit2Input.account, + owner: account, nonces: filteredAmountsIn.map(a => nonces[a.token.address]), amountsIn: maximizePositiveAmounts(filteredAmountsIn), // Permit2 allowance expires in 24H @@ -88,6 +91,23 @@ function maximizePositiveAmounts(amountsIn: TokenAmount[]): TokenAmount[] { ({ ...item, amount: item.amount > 0n ? MaxAllowance : item.amount, - }) as TokenAmount + }) as TokenAmount, ) } + +function filterWrappedNativeAsset({ + amountsIn, + wethIsEth, + chain, +}: { + amountsIn: TokenAmount[] + wethIsEth: boolean + chain: GqlChain +}): TokenAmount[] { + if (!wethIsEth) return amountsIn + return amountsIn.filter(a => { + return !isWrappedNativeAsset(a.token.address, chain) + }) +} + + diff --git a/packages/lib/modules/tokens/approvals/permit2/signPermit2Swap.tsx b/packages/lib/modules/tokens/approvals/permit2/signPermit2Swap.tsx new file mode 100644 index 000000000..b04da524b --- /dev/null +++ b/packages/lib/modules/tokens/approvals/permit2/signPermit2Swap.tsx @@ -0,0 +1,76 @@ +import { + Address, + ExactInQueryOutput, + ExactOutQueryOutput, + Permit2, + Permit2Helper, + PublicWalletClient, + Slippage, + SwapKind, +} from '@balancer/sdk' +import { ensureError } from '@repo/lib/shared/utils/errors' +import { get24HoursFromNowInSecs } from '@repo/lib/shared/utils/time' +import { NoncesByTokenAddress } from './usePermit2Allowance' +import { TokenAmountIn } from './useSignPermit2' + +type SignPermit2SwapParams = { + sdkClient?: PublicWalletClient + nonces?: NoncesByTokenAddress + wethIsEth: boolean + account: Address + slippagePercent: string + queryOutput: ExactInQueryOutput | ExactOutQueryOutput + tokenIn?: TokenAmountIn +} +export async function signPermit2Swap(params: SignPermit2SwapParams): Promise { + if (!params.nonces) throw new Error('Missing nonces in signPermitSwap') + try { + const signature = await sign(params) + return signature + } catch (e: unknown) { + const error = ensureError(e) + console.log(error) + // When the user explicitly rejects in the wallet we return undefined to ignore the error and do nothing + if (error.name === 'UserRejectedRequestError') return + throw error + } +} + +async function sign({ + sdkClient, + account, + queryOutput, + slippagePercent, + nonces, + tokenIn, + wethIsEth +}: SignPermit2SwapParams): Promise { + if (!sdkClient) throw new Error('Missing sdkClient') + if (!nonces) throw new Error('Missing nonces') + if (!tokenIn) throw new Error('Missing token in') + + + // Instead of MaxAllowanceTransferAmount(MaxUint160) we use MaxUint159 to avoid overflow issues + const MaxUint159 = BigInt('0x7fffffffffffffffffffffffffffffffffffffff') + const MaxAllowance = MaxUint159 + + const maximizedQueryOutput = { ...queryOutput } + if (maximizedQueryOutput.swapKind === SwapKind.GivenIn) maximizedQueryOutput.amountIn.amount = MaxAllowance + if (maximizedQueryOutput.swapKind === SwapKind.GivenOut) maximizedQueryOutput.amountOut.amount = MaxAllowance + + const signature = await Permit2Helper.signSwapApproval({ + client: sdkClient, + owner: account, + nonce: nonces[tokenIn.address], + // Permit2 allowance expires in 24H + expiration: get24HoursFromNowInSecs(), + queryOutput: maximizedQueryOutput, + wethIsEth, + slippage: Slippage.fromPercentage(`${Number(slippagePercent)}`), + }) + + return signature +} + + + diff --git a/packages/lib/modules/tokens/approvals/permit2/usePermit2Allowance.tsx b/packages/lib/modules/tokens/approvals/permit2/usePermit2Allowance.tsx index 63f9cc0e5..793462f16 100644 --- a/packages/lib/modules/tokens/approvals/permit2/usePermit2Allowance.tsx +++ b/packages/lib/modules/tokens/approvals/permit2/usePermit2Allowance.tsx @@ -45,25 +45,25 @@ export function usePermit2Allowance({ chainId, tokenAddresses, owner, enabled }: const nonces: NoncesByTokenAddress | undefined = tokenAddresses && data ? zipObject( - tokenAddresses, - data.map(result => result[2]) - ) + tokenAddresses, + data.map(result => result[2]) + ) : undefined const expirations: ExpirationByTokenAddress | undefined = tokenAddresses && data ? zipObject( - tokenAddresses, - data.map(result => result[1]) - ) + tokenAddresses, + data.map(result => result[1]) + ) : undefined const allowedAmounts: AllowedAmountsByTokenAddress | undefined = tokenAddresses && data ? zipObject( - tokenAddresses, - data.map(result => result[0]) - ) + tokenAddresses, + data.map(result => result[0]) + ) : undefined return { diff --git a/packages/lib/modules/tokens/approvals/permit2/useSignPermit2.tsx b/packages/lib/modules/tokens/approvals/permit2/useSignPermit2.tsx index d50db942c..9ccf4c382 100644 --- a/packages/lib/modules/tokens/approvals/permit2/useSignPermit2.tsx +++ b/packages/lib/modules/tokens/approvals/permit2/useSignPermit2.tsx @@ -1,7 +1,6 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import { Pool } from '@repo/lib/modules/pool/PoolProvider' -import { SdkQueryAddLiquidityOutput } from '@repo/lib/modules/pool/actions/add-liquidity/add-liquidity.types' -import { useUserAccount } from '@repo/lib/modules/web3/UserAccountProvider' +import { Permit2, PublicWalletClient } from '@balancer/sdk' +import { useToast } from '@chakra-ui/react' import { SignatureState, isSignatureDisabled, @@ -9,73 +8,69 @@ import { } from '@repo/lib/modules/web3/signatures/signature.helpers' import { useSdkWalletClient } from '@repo/lib/modules/web3/useSdkViemClient' import { Toast } from '@repo/lib/shared/components/toasts/Toast' -import { useToast } from '@chakra-ui/react' import { useEffect, useState } from 'react' import { useTokens } from '../../TokensProvider' -import { HumanTokenAmountWithAddress } from '../../token.types' import { usePermit2Signature } from './Permit2SignatureProvider' -import { signPermit2Add } from './signPermit2Add' +import { getTokenSymbolsForPermit } from './permit2.helpers' import { NoncesByTokenAddress } from './usePermit2Allowance' -import { getTokenSymbolsForPermit2 } from './permit2.helpers' +import { Address } from 'viem' + +// eslint-disable-next-line no-unused-vars +export type SignPermit2Callback = (sdkClient: PublicWalletClient, nonces: NoncesByTokenAddress) => + Promise + +export type TokenAmountIn = { + amount: bigint, + address: Address +} -export type AddLiquidityPermit2Params = { - humanAmountsIn: HumanTokenAmountWithAddress[] - pool: Pool - queryOutput?: SdkQueryAddLiquidityOutput - slippagePercent: string +export type BasePermit2Params = { + tokenAmountsIn?: TokenAmountIn[] nonces?: NoncesByTokenAddress isPermit2: boolean wethIsEth: boolean + isSimulationReady: boolean + chainId: number + signPermit2Callback: SignPermit2Callback } export function useSignPermit2({ - humanAmountsIn, - queryOutput, - slippagePercent, + tokenAmountsIn, nonces, wethIsEth, -}: AddLiquidityPermit2Params) { + chainId, + signPermit2Callback, + isSimulationReady +}: BasePermit2Params) { + const sdkClient = useSdkWalletClient() + const toast = useToast() - const { userAddress } = useUserAccount() const { getToken } = useTokens() const { signPermit2State, setSignPermit2State, setPermit2Signature } = usePermit2Signature() const [error, setError] = useState() - const sdkClient = useSdkWalletClient() useEffect(() => { if (sdkClient === undefined) setSignPermit2State(SignatureState.Preparing) }, [sdkClient]) - //TODO: Generalize for Swaps and other potential signatures - const hasBptOut = queryOutput?.sdkQueryOutput.bptOut.amount useEffect(() => { - if (hasBptOut) { + if (isSimulationReady) { setPermit2Signature(undefined) setSignPermit2State(SignatureState.Ready) } - }, [hasBptOut]) + }, [isSimulationReady]) - async function signPermit2(pool: Pool) { - if (!queryOutput) throw new Error('No input provided for permit2 signature') + async function signPermit2() { + if (!tokenAmountsIn) throw new Error('No tokenAmountsIn provided for permit2 signature') if (!nonces) throw new Error('No nonces provided for permit2 signature') + if (!sdkClient) throw new Error('No sdkClient provided for permit2 signature') setSignPermit2State(SignatureState.Confirming) setError(undefined) try { - const signature = await signPermit2Add({ - pool, - humanAmountsIn, - wethIsEth, - sdkClient, - permit2Input: { - account: userAddress, - slippagePercent, - sdkQueryOutput: queryOutput.sdkQueryOutput, - }, - nonces, - }) + const signature = await signPermit2Callback(sdkClient, nonces) if (signature) { setSignPermit2State(SignatureState.Completed) @@ -104,9 +99,9 @@ export function useSignPermit2({ signPermit2State, buttonLabel: getButtonLabel( signPermit2State, - getTokenSymbolsForPermit2({ getToken, queryOutput, wethIsEth }) + getTokenSymbolsForPermit({ getToken, chainId, tokenAmountsIn, wethIsEth }), ), - isLoading: isSignatureLoading(signPermit2State) || !queryOutput, + isLoading: isSignatureLoading(signPermit2State) || !tokenAmountsIn, isDisabled: isSignatureDisabled(signPermit2State), error, } diff --git a/packages/lib/modules/tokens/token.helpers.ts b/packages/lib/modules/tokens/token.helpers.ts index d355a2c67..0a3fdc5e8 100644 --- a/packages/lib/modules/tokens/token.helpers.ts +++ b/packages/lib/modules/tokens/token.helpers.ts @@ -8,7 +8,7 @@ import { GqlChain } from '@repo/lib/shared/services/api/generated/graphql' import { includesAddress, isSameAddress } from '@repo/lib/shared/utils/addresses' import { Address } from 'viem' import { HumanTokenAmountWithAddress, TokenBase } from './token.types' -import { InputAmount, TokenAmount } from '@balancer/sdk' +import { InputAmount } from '@balancer/sdk' import { Pool } from '../pool/PoolProvider' import { getVaultConfig, isCowAmmPool, isV3Pool } from '../pool/pool.helpers' @@ -144,19 +144,3 @@ export function getSpenderForAddLiquidity(pool: Pool): Address { const { vaultAddress } = getVaultConfig(pool) return vaultAddress } - -// Excludes wrapped native asset from amountsIn when wethIsEth -export function filterWrappedNativeAsset({ - amountsIn, - wethIsEth, - chain, -}: { - amountsIn: TokenAmount[] - wethIsEth: boolean - chain: GqlChain -}): TokenAmount[] { - if (!wethIsEth) return amountsIn - return amountsIn.filter(a => { - return !isWrappedNativeAsset(a.token.address, chain) - }) -} diff --git a/packages/lib/modules/transactions/transaction-steps/useSignPermit2Step.tsx b/packages/lib/modules/transactions/transaction-steps/useSignPermit2Step.tsx index b095ff838..8607041c7 100644 --- a/packages/lib/modules/transactions/transaction-steps/useSignPermit2Step.tsx +++ b/packages/lib/modules/transactions/transaction-steps/useSignPermit2Step.tsx @@ -1,46 +1,48 @@ 'use client' -import { getChainId } from '@repo/lib/config/app.config' +import { Button, VStack } from '@chakra-ui/react' import { ConnectWallet } from '@repo/lib/modules/web3/ConnectWallet' import { useUserAccount } from '@repo/lib/modules/web3/UserAccountProvider' import { BalAlert } from '@repo/lib/shared/components/alerts/BalAlert' -import { Button, VStack } from '@chakra-ui/react' import { useMemo } from 'react' import { useTokens } from '../../tokens/TokensProvider' import { - getTokenAddressesForPermit2, - getTokenSymbolsForPermit2, + getTokenAddressesForPermit, + getTokenSymbolsForPermit, hasValidPermit2, } from '../../tokens/approvals/permit2/permit2.helpers' import { usePermit2Allowance } from '../../tokens/approvals/permit2/usePermit2Allowance' import { - AddLiquidityPermit2Params, + BasePermit2Params, useSignPermit2, } from '../../tokens/approvals/permit2/useSignPermit2' import { SignatureState } from '../../web3/signatures/signature.helpers' import { useChainSwitch } from '../../web3/useChainSwitch' -import { StepDetails as StepDetails, TransactionStep } from './lib' +import { StepDetails, TransactionStep } from './lib' /* - Returns a transaction step to sign a permit2 for the given pool and token amounts + Returns a transaction step to sign a permit2 for the token amounts in If the permit2 allowance is expired for one of the positive token amounts in: returns undefined */ -export function useSignPermit2Step(params: AddLiquidityPermit2Params): TransactionStep | undefined { +export function useSignPermit2Step(params: BasePermit2Params): TransactionStep | undefined { const { isConnected, userAddress } = useUserAccount() const { getToken } = useTokens() + const { chainId, tokenAmountsIn } = params + const { isLoadingPermit2Allowances, nonces, expirations, allowedAmounts } = usePermit2Allowance({ - chainId: getChainId(params.pool.chain), - tokenAddresses: getTokenAddressesForPermit2({ - queryOutput: params.queryOutput, + chainId, + tokenAddresses: getTokenAddressesForPermit({ + chainId, + tokenAmountsIn: params.tokenAmountsIn, wethIsEth: params.wethIsEth, }), owner: userAddress, enabled: params.isPermit2, }) - const isValidPermit2 = hasValidPermit2(params.queryOutput, expirations, allowedAmounts) + const isValidPermit2 = hasValidPermit2(tokenAmountsIn, expirations, allowedAmounts) const { signPermit2, @@ -49,45 +51,46 @@ export function useSignPermit2Step(params: AddLiquidityPermit2Params): Transacti isDisabled, buttonLabel, error, - } = useSignPermit2({ ...params, nonces }) - const { shouldChangeNetwork, NetworkSwitchButton, networkSwitchButtonProps } = useChainSwitch( - getChainId(params.pool.chain) - ) + } = useSignPermit2({ + ...params, + nonces + }) + + const { shouldChangeNetwork, NetworkSwitchButton, networkSwitchButtonProps } = useChainSwitch(chainId) const isLoading = isLoadingSignature || isLoadingPermit2Allowances || signPermit2State === SignatureState.Confirming - const SignPermitButton = () => ( - - {error && } - {!isConnected && } - {shouldChangeNetwork && isConnected && } - {!shouldChangeNetwork && isConnected && ( - - )} + function SignPermitButton() { + return + {error ? : null} + {!isConnected && } + {shouldChangeNetwork && isConnected ? : null} + {!shouldChangeNetwork && isConnected ? : null} - ) + } const isComplete = () => signPermit2State === SignatureState.Completed || isValidPermit2 const details: StepDetails = { gasless: true, - batchApprovalTokens: getTokenSymbolsForPermit2({ + batchApprovalTokens: getTokenSymbolsForPermit({ + chainId, getToken, - queryOutput: params.queryOutput, + tokenAmountsIn, wethIsEth: params.wethIsEth, }), } @@ -106,7 +109,7 @@ export function useSignPermit2Step(params: AddLiquidityPermit2Params): Transacti renderAction: () => , }), // eslint-disable-next-line react-hooks/exhaustive-deps - [signPermit2State, isLoading, isConnected, isValidPermit2] + [signPermit2State, isLoading, isConnected, isValidPermit2], ) } From 107ca374446591dc4bdfb1e3e49216a73d1a37d8 Mon Sep 17 00:00:00 2001 From: Alberto Gualis Date: Mon, 28 Oct 2024 17:52:35 +0100 Subject: [PATCH 02/27] fix: delete old function --- .../swap/handlers/BaseDefaultSwap.handler.ts | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/packages/lib/modules/swap/handlers/BaseDefaultSwap.handler.ts b/packages/lib/modules/swap/handlers/BaseDefaultSwap.handler.ts index 5fecc5854..9326f1967 100644 --- a/packages/lib/modules/swap/handlers/BaseDefaultSwap.handler.ts +++ b/packages/lib/modules/swap/handlers/BaseDefaultSwap.handler.ts @@ -16,31 +16,6 @@ export abstract class BaseDefaultSwapHandler implements SwapHandler { public abstract name: string public abstract simulate({ ...variables }: SimulateSwapInputs): Promise - buildOld({ - simulateResponse: { swap, queryOutput }, - slippagePercent, - account, - selectedChain, - wethIsEth, - }: SdkBuildSwapInputs): TransactionConfig { - const tx = swap.buildCall({ - slippage: Slippage.fromPercentage(slippagePercent as `${number}`), - deadline: BigInt(Number.MAX_SAFE_INTEGER), - sender: account, - recipient: account, - wethIsEth, - queryOutput, - }) - - return { - account, - chainId: getChainId(selectedChain), - data: tx.callData, - value: tx.value, - to: tx.to, - } - } - build({ simulateResponse: { swap, queryOutput, protocolVersion }, slippagePercent, From 89c7204082102eb5406c541e5125d94e7e699937 Mon Sep 17 00:00:00 2001 From: Alberto Gualis Date: Mon, 28 Oct 2024 17:58:06 +0100 Subject: [PATCH 03/27] refactor: permit2 callback --- .../add-liquidity/useSignPermit2AddStep.tsx | 15 +++++---- .../lib/modules/swap/usePermit2SwapStep.tsx | 31 +++++++++++++------ .../approvals/permit2/useSignPermit2.tsx | 17 +++++----- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/packages/lib/modules/pool/actions/add-liquidity/useSignPermit2AddStep.tsx b/packages/lib/modules/pool/actions/add-liquidity/useSignPermit2AddStep.tsx index acd7e8949..f3f4e82c5 100644 --- a/packages/lib/modules/pool/actions/add-liquidity/useSignPermit2AddStep.tsx +++ b/packages/lib/modules/pool/actions/add-liquidity/useSignPermit2AddStep.tsx @@ -1,7 +1,7 @@ import { PublicWalletClient } from '@balancer/sdk' import { signPermit2Add } from '@repo/lib/modules/tokens/approvals/permit2/signPermit2Add' import { NoncesByTokenAddress } from '@repo/lib/modules/tokens/approvals/permit2/usePermit2Allowance' -import { SignPermit2Callback } from '@repo/lib/modules/tokens/approvals/permit2/useSignPermit2' +import { SignPermit2Fn as SignPermit2Fn } from '@repo/lib/modules/tokens/approvals/permit2/useSignPermit2' import { useSignPermit2Step } from '@repo/lib/modules/transactions/transaction-steps/useSignPermit2Step' import { useUserAccount } from '@repo/lib/modules/web3/UserAccountProvider' import { SdkQueryAddLiquidityOutput } from './add-liquidity.types' @@ -13,7 +13,7 @@ import { useUserSettings } from '@repo/lib/modules/user/settings/UserSettingsPro import { toTokenAmountsIn } from '../LiquidityActionHelpers' type Props = { - wethIsEth: boolean, + wethIsEth: boolean simulationQuery: AddLiquiditySimulationQueryResult humanAmountsIn: HumanTokenAmountWithAddress[] } @@ -26,7 +26,10 @@ export function useSignPermit2AddStep({ wethIsEth, humanAmountsIn, simulationQue const isPermit2 = requiresPermit2Approval(pool) const queryOutput = simulationQuery.data as SdkQueryAddLiquidityOutput - const signPermit2Callback: SignPermit2Callback = (sdkClient: PublicWalletClient, nonces: NoncesByTokenAddress) => { + const signPermit2Fn: SignPermit2Fn = ( + sdkClient: PublicWalletClient, + nonces: NoncesByTokenAddress, + ) => { return signPermit2Add({ sdkClient, pool, @@ -35,13 +38,13 @@ export function useSignPermit2AddStep({ wethIsEth, humanAmountsIn, simulationQue account: userAddress, sdkQueryOutput: queryOutput?.sdkQueryOutput, slippagePercent: slippage, - nonces + nonces, }) } const signPermit2Step = useSignPermit2Step({ chainId, - signPermit2Callback, + signPermit2Fn, wethIsEth, tokenAmountsIn: toTokenAmountsIn(queryOutput?.sdkQueryOutput), isPermit2, @@ -49,4 +52,4 @@ export function useSignPermit2AddStep({ wethIsEth, humanAmountsIn, simulationQue }) return signPermit2Step -} \ No newline at end of file +} diff --git a/packages/lib/modules/swap/usePermit2SwapStep.tsx b/packages/lib/modules/swap/usePermit2SwapStep.tsx index 894b87352..6edec968d 100644 --- a/packages/lib/modules/swap/usePermit2SwapStep.tsx +++ b/packages/lib/modules/swap/usePermit2SwapStep.tsx @@ -5,20 +5,26 @@ import { GqlToken } from '@repo/lib/shared/services/api/generated/graphql' import { Address } from 'viem' import { signPermit2Swap } from '../tokens/approvals/permit2/signPermit2Swap' import { NoncesByTokenAddress } from '../tokens/approvals/permit2/usePermit2Allowance' -import { SignPermit2Callback, TokenAmountIn } from '../tokens/approvals/permit2/useSignPermit2' +import { SignPermit2Fn, TokenAmountIn } from '../tokens/approvals/permit2/useSignPermit2' import { useSignPermit2Step } from '../transactions/transaction-steps/useSignPermit2Step' import { SwapSimulationQueryResult } from './queries/useSimulateSwapQuery' import { SdkSimulateSwapResponse } from './swap.types' type Props = { - wethIsEth: boolean, + wethIsEth: boolean simulationQuery: SwapSimulationQueryResult tokenInInfo?: GqlToken chainId: number isPermit2: boolean } -export function useSignPermit2SwapStep({ chainId, wethIsEth, tokenInInfo, simulationQuery, isPermit2 }: Props) { +export function useSignPermit2SwapStep({ + chainId, + wethIsEth, + tokenInInfo, + simulationQuery, + isPermit2, +}: Props) { const { userAddress } = useUserAccount() const { slippage } = useUserSettings() @@ -29,8 +35,12 @@ export function useSignPermit2SwapStep({ chainId, wethIsEth, tokenInInfo, simula function getTokenInAmount(simulationQuery: SwapSimulationQueryResult): bigint { if (!simulationQuery.data) return 0n const queryData = simulationQuery.data as SdkSimulateSwapResponse - if (queryData.queryOutput.swapKind === SwapKind.GivenIn) return queryData.queryOutput.amountIn.amount - if (queryData.queryOutput.swapKind === SwapKind.GivenOut) return queryData.queryOutput.expectedAmountIn.amount + if (queryData.queryOutput.swapKind === SwapKind.GivenIn) { + return queryData.queryOutput.amountIn.amount + } + if (queryData.queryOutput.swapKind === SwapKind.GivenOut) { + return queryData.queryOutput.expectedAmountIn.amount + } return 0n } @@ -39,7 +49,10 @@ export function useSignPermit2SwapStep({ chainId, wethIsEth, tokenInInfo, simula amount: getTokenInAmount(simulationQuery), } - const signPermit2Callback: SignPermit2Callback = (sdkClient: PublicWalletClient, nonces: NoncesByTokenAddress) => { + const signPermit2Fn: SignPermit2Fn = ( + sdkClient: PublicWalletClient, + nonces: NoncesByTokenAddress, + ) => { return signPermit2Swap({ sdkClient, wethIsEth, @@ -47,16 +60,16 @@ export function useSignPermit2SwapStep({ chainId, wethIsEth, tokenInInfo, simula queryOutput: queryData.queryOutput, slippagePercent: slippage, nonces, - tokenIn + tokenIn, }) } return useSignPermit2Step({ chainId, - signPermit2Callback, + signPermit2Fn, wethIsEth, tokenAmountsIn: [tokenIn], isPermit2, isSimulationReady: !!simulationQuery.data, }) -} \ No newline at end of file +} diff --git a/packages/lib/modules/tokens/approvals/permit2/useSignPermit2.tsx b/packages/lib/modules/tokens/approvals/permit2/useSignPermit2.tsx index 9ccf4c382..e455125e7 100644 --- a/packages/lib/modules/tokens/approvals/permit2/useSignPermit2.tsx +++ b/packages/lib/modules/tokens/approvals/permit2/useSignPermit2.tsx @@ -16,11 +16,13 @@ import { NoncesByTokenAddress } from './usePermit2Allowance' import { Address } from 'viem' // eslint-disable-next-line no-unused-vars -export type SignPermit2Callback = (sdkClient: PublicWalletClient, nonces: NoncesByTokenAddress) => - Promise +export type SignPermit2Fn = ( + sdkClient: PublicWalletClient, + nonces: NoncesByTokenAddress, +) => Promise export type TokenAmountIn = { - amount: bigint, + amount: bigint address: Address } @@ -31,15 +33,15 @@ export type BasePermit2Params = { wethIsEth: boolean isSimulationReady: boolean chainId: number - signPermit2Callback: SignPermit2Callback + signPermit2Fn: SignPermit2Fn } export function useSignPermit2({ tokenAmountsIn, nonces, wethIsEth, chainId, - signPermit2Callback, - isSimulationReady + signPermit2Fn, + isSimulationReady, }: BasePermit2Params) { const sdkClient = useSdkWalletClient() @@ -50,7 +52,6 @@ export function useSignPermit2({ const [error, setError] = useState() - useEffect(() => { if (sdkClient === undefined) setSignPermit2State(SignatureState.Preparing) }, [sdkClient]) @@ -70,7 +71,7 @@ export function useSignPermit2({ setError(undefined) try { - const signature = await signPermit2Callback(sdkClient, nonces) + const signature = await signPermit2Fn(sdkClient, nonces) if (signature) { setSignPermit2State(SignatureState.Completed) From f2c878952eb6e2467212db5047b3278ca3e00f41 Mon Sep 17 00:00:00 2001 From: Alberto Gualis Date: Mon, 28 Oct 2024 17:59:40 +0100 Subject: [PATCH 04/27] chore: fix tsx format --- .../transactions/transaction-steps/useSignPermit2Step.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/lib/modules/transactions/transaction-steps/useSignPermit2Step.tsx b/packages/lib/modules/transactions/transaction-steps/useSignPermit2Step.tsx index 90f549120..c83e1a3b6 100644 --- a/packages/lib/modules/transactions/transaction-steps/useSignPermit2Step.tsx +++ b/packages/lib/modules/transactions/transaction-steps/useSignPermit2Step.tsx @@ -64,11 +64,11 @@ export function useSignPermit2Step(params: BasePermit2Params): TransactionStep | function SignPermitButton() { return ( - {error ? : null} + {error && } {!isConnected && } - {shouldChangeNetwork && isConnected ? ( + {shouldChangeNetwork && isConnected && ( - ) : null} + )} {!shouldChangeNetwork && isConnected ? (