-
Notifications
You must be signed in to change notification settings - Fork 13
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 liquidity unbalanced permit2 #1117
base: main
Are you sure you want to change the base?
Changes from 9 commits
7fa63fe
7175c7c
7aa9c95
a720db9
f2c0788
863ea60
c8aa8a6
8c58184
d4f70d1
8666be6
0125d2d
61b1563
aaafbbd
0cfdcf9
49fd31a
cbec43a
bb2285b
272f36b
8db0520
90ec059
46a2f82
ae4198c
5e1e154
b927f2f
bb9ff72
ca06eb0
89b708e
b20ee98
3cb8df6
be9d4b0
bebdb88
04bba89
3b0b1c6
1fd092c
eade12c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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, | ||
}, | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,20 +4,26 @@ 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, | ||
formatBuildCallParams, | ||
areEmptyAmounts, | ||
formatBuildCallParams, | ||
} from '../../LiquidityActionHelpers' | ||
import { AddLiquidityHandler } from './AddLiquidity.handler' | ||
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 | ||
|
@@ -61,26 +67,30 @@ export class UnbalancedAddLiquidityHandler implements AddLiquidityHandler { | |
} | ||
|
||
public async buildCallData({ | ||
humanAmountsIn, | ||
account, | ||
slippagePercent, | ||
queryOutput, | ||
account, | ||
permit2, | ||
}: SdkBuildAddLiquidityInput): Promise<TransactionConfig> { | ||
const addLiquidity = new AddLiquidity() | ||
|
||
const baseBuildCallParams = { | ||
...queryOutput.sdkQueryOutput, | ||
slippage: Slippage.fromPercentage(`${Number(slippagePercent)}`), | ||
wethIsEth: this.helpers.isNativeAssetIn(humanAmountsIn), | ||
} | ||
|
||
const buildCallParams = formatBuildCallParams( | ||
baseBuildCallParams, | ||
this.constructBaseBuildCallInput({ | ||
sdkQueryOutput: queryOutput.sdkQueryOutput, | ||
slippagePercent: slippagePercent, | ||
}), | ||
this.helpers.isV3Pool(), | ||
account | ||
) | ||
|
||
const { callData, to, value } = addLiquidity.buildCall(buildCallParams) | ||
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, | ||
|
@@ -91,6 +101,24 @@ export class UnbalancedAddLiquidityHandler implements AddLiquidityHandler { | |
} | ||
} | ||
|
||
public async signPermit2( | ||
input: Permit2AddLiquidityInput, | ||
sdkClient: PublicWalletClient, | ||
nonces: NoncesByTokenAddress | ||
): Promise<Permit2> { | ||
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 => nonces[a.token.address]), | ||
}) | ||
return signature | ||
} | ||
|
||
/** | ||
* PRIVATE METHODS | ||
*/ | ||
|
@@ -106,4 +134,22 @@ export class UnbalancedAddLiquidityHandler implements AddLiquidityHandler { | |
kind: AddLiquidityKind.Unbalanced, | ||
} | ||
} | ||
|
||
public constructBaseBuildCallInput({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will probably try to extract this method to be shared by all the handlers but for now I will keep it here until I implement the rest of the v3 handlers |
||
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( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will delete this later. It is a reminder to try something... |
||
// amountIn => amountIn.amount > 0n | ||
// ) | ||
return baseBuildCallParams | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we rename this file/class to UnbalancedAddLiquidityV2.handler.ts to make it more explicit? Note that it also used for V1 CowAMM pools to that would not be precise.