Skip to content
This repository was archived by the owner on Oct 15, 2024. It is now read-only.

Commit cbec43a

Browse files
committed
refactor: extract base abstract class
1 parent 49fd31a commit cbec43a

13 files changed

+245
-189
lines changed

lib/modules/pool/actions/LiquidityActionHelpers.ts

+1-10
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,6 @@ export class LiquidityActionHelpers {
137137
return humanAmountsIn.some(amountIn => isSameAddress(amountIn.tokenAddress, nativeAssetAddress))
138138
}
139139

140-
public includesNativeAsset(amountsIn: TokenAmount[]): boolean {
141-
const nativeAssetAddress = this.networkConfig.tokens.nativeAsset.address
142-
143-
return amountsIn.some(amountIn => isSameAddress(amountIn.token.address, nativeAssetAddress))
144-
}
145-
146140
public isNativeAsset(tokenAddress: Address): boolean {
147141
const nativeAssetAddress = this.networkConfig.tokens.nativeAsset.address
148142

@@ -319,10 +313,7 @@ export function hasNoLiquidity(pool: Pool): boolean {
319313
}
320314

321315
// When the pool has version < v3, it adds extra buildCall params (sender and recipient) that must be present only in V1/V2
322-
export function formatBuildCallParams<T>(buildCallParams: T, isV3Pool: boolean, account: Address) {
323-
// sender must be undefined for v3 pools
324-
if (isV3Pool) return buildCallParams
325-
316+
export function formatBuildCallParams<T>(buildCallParams: T, account: Address) {
326317
// sender and recipient must be defined only for v1 and v2 pools
327318
return { ...buildCallParams, sender: account, recipient: account }
328319
}

lib/modules/pool/actions/add-liquidity/handlers/AddLiquidity.handler.ts

+1-11
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { HumanTokenAmountWithAddress } from '@/lib/modules/tokens/token.types'
22
import { TransactionConfig } from '@/lib/modules/web3/contracts/contract.types'
3-
import { AddLiquidityQueryOutput, Permit2, PublicWalletClient } from '@balancer/sdk'
3+
import { AddLiquidityQueryOutput } from '@balancer/sdk'
44
import { Address } from 'viem'
55
import { BuildAddLiquidityInput, QueryAddLiquidityOutput } from '../add-liquidity.types'
6-
import { NoncesByTokenAddress } from '@/lib/modules/tokens/approvals/permit2/usePermit2Nonces'
76

87
export interface Permit2AddLiquidityInput {
98
account: Address
@@ -36,13 +35,4 @@ export interface AddLiquidityHandler {
3635
It is responsibility of the UI to avoid calling buildAddLiquidityCallData before the last queryAddLiquidity was finished
3736
*/
3837
buildCallData(inputs: BuildAddLiquidityInput): Promise<TransactionConfig>
39-
40-
/* Sign permit2 for adding liquidity (for now only used by v3 pools)
41-
TODO: generalize for other handlers using permit2
42-
*/
43-
signPermit2?(
44-
input: Permit2AddLiquidityInput,
45-
walletClient: PublicWalletClient,
46-
nonces?: NoncesByTokenAddress
47-
): Promise<Permit2>
4838
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
2+
import { HumanTokenAmountWithAddress } from '@/lib/modules/tokens/token.types'
3+
import { TransactionConfig } from '@/lib/modules/web3/contracts/contract.types'
4+
import { getRpcUrl } from '@/lib/modules/web3/transports'
5+
import {
6+
AddLiquidity,
7+
AddLiquidityKind,
8+
AddLiquidityUnbalancedInput,
9+
PriceImpact,
10+
PriceImpactAmount,
11+
} from '@balancer/sdk'
12+
import { Pool } from '../../../PoolProvider'
13+
import { LiquidityActionHelpers, areEmptyAmounts } from '../../LiquidityActionHelpers'
14+
import { SdkBuildAddLiquidityInput, SdkQueryAddLiquidityOutput } from '../add-liquidity.types'
15+
import { AddLiquidityHandler } from './AddLiquidity.handler'
16+
17+
/**
18+
* UnbalancedAddLiquidityHandler is a handler that implements the
19+
* AddLiquidityHandler interface for unbalanced adds, e.g. where the user
20+
* specifies the token amounts in. It uses the Balancer SDK to implement it's
21+
* methods. It also handles the case where one of the input tokens is the native
22+
* asset instead of the wrapped native asset.
23+
*/
24+
export abstract class BaseUnbalancedAddLiquidityHandler implements AddLiquidityHandler {
25+
protected helpers: LiquidityActionHelpers
26+
27+
constructor(pool: Pool) {
28+
this.helpers = new LiquidityActionHelpers(pool)
29+
}
30+
31+
public async simulate(
32+
humanAmountsIn: HumanTokenAmountWithAddress[]
33+
): Promise<SdkQueryAddLiquidityOutput> {
34+
const addLiquidity = new AddLiquidity()
35+
const addLiquidityInput = this.constructSdkInput(humanAmountsIn)
36+
37+
const sdkQueryOutput = await addLiquidity.query(addLiquidityInput, this.helpers.poolState)
38+
39+
return { bptOut: sdkQueryOutput.bptOut, sdkQueryOutput }
40+
}
41+
42+
public async getPriceImpact(humanAmountsIn: HumanTokenAmountWithAddress[]): Promise<number> {
43+
if (areEmptyAmounts(humanAmountsIn)) {
44+
// Avoid price impact calculation when there are no amounts in
45+
return 0
46+
}
47+
48+
const addLiquidityInput = this.constructSdkInput(humanAmountsIn)
49+
50+
const priceImpactABA: PriceImpactAmount = await PriceImpact.addLiquidityUnbalanced(
51+
addLiquidityInput,
52+
this.helpers.poolState
53+
)
54+
55+
return priceImpactABA.decimal
56+
}
57+
58+
public abstract buildCallData(input: SdkBuildAddLiquidityInput): Promise<TransactionConfig>
59+
60+
/**
61+
* PRIVATE METHODS
62+
*/
63+
protected constructSdkInput(
64+
humanAmountsIn: HumanTokenAmountWithAddress[]
65+
): AddLiquidityUnbalancedInput {
66+
const amountsIn = this.helpers.toSdkInputAmounts(humanAmountsIn)
67+
68+
return {
69+
chainId: this.helpers.chainId,
70+
rpcUrl: getRpcUrl(this.helpers.chainId),
71+
amountsIn,
72+
kind: AddLiquidityKind.Unbalanced,
73+
}
74+
}
75+
}
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,40 @@
11
/* eslint-disable @typescript-eslint/no-non-null-assertion */
2-
import { HumanTokenAmountWithAddress } from '@/lib/modules/tokens/token.types'
32
import { TransactionConfig } from '@/lib/modules/web3/contracts/contract.types'
4-
import { getRpcUrl } from '@/lib/modules/web3/transports'
5-
import {
6-
AddLiquidity,
7-
AddLiquidityBaseBuildCallInput,
8-
AddLiquidityBaseQueryOutput,
9-
AddLiquidityKind,
10-
AddLiquidityUnbalancedInput,
11-
Permit2,
12-
Permit2Helper,
13-
PriceImpact,
14-
PriceImpactAmount,
15-
PublicWalletClient,
16-
Slippage,
17-
} from '@balancer/sdk'
18-
import { Pool } from '../../../PoolProvider'
19-
import {
20-
LiquidityActionHelpers,
21-
areEmptyAmounts,
22-
formatBuildCallParams,
23-
} from '../../LiquidityActionHelpers'
24-
import { SdkBuildAddLiquidityInput, SdkQueryAddLiquidityOutput } from '../add-liquidity.types'
25-
import { AddLiquidityHandler, Permit2AddLiquidityInput } from './AddLiquidity.handler'
26-
import { NoncesByTokenAddress } from '@/lib/modules/tokens/approvals/permit2/usePermit2Nonces'
3+
import { AddLiquidity } from '@balancer/sdk'
4+
import { formatBuildCallParams } from '../../LiquidityActionHelpers'
5+
import { SdkBuildAddLiquidityInput } from '../add-liquidity.types'
6+
import { BaseUnbalancedAddLiquidityHandler } from './BaseUnbalancedAddLiquidity.handler'
7+
import { constructBaseBuildCallInput } from './v3Helpers'
278

289
/**
2910
* UnbalancedAddLiquidityHandler is a handler that implements the
30-
* AddLiquidityHandler interface for unbalanced adds, e.g. where the user
11+
* AddLiquidityHandler interface for unbalanced adds in v1(cowAMM) and v2 pools, e.g. where the user
3112
* specifies the token amounts in. It uses the Balancer SDK to implement it's
3213
* methods. It also handles the case where one of the input tokens is the native
3314
* asset instead of the wrapped native asset.
3415
*/
35-
export class UnbalancedAddLiquidityHandler implements AddLiquidityHandler {
36-
helpers: LiquidityActionHelpers
37-
38-
constructor(pool: Pool) {
39-
this.helpers = new LiquidityActionHelpers(pool)
40-
}
41-
42-
public async simulate(
43-
humanAmountsIn: HumanTokenAmountWithAddress[]
44-
): Promise<SdkQueryAddLiquidityOutput> {
45-
const addLiquidity = new AddLiquidity()
46-
const addLiquidityInput = this.constructSdkInput(humanAmountsIn)
47-
48-
const sdkQueryOutput = await addLiquidity.query(addLiquidityInput, this.helpers.poolState)
49-
50-
return { bptOut: sdkQueryOutput.bptOut, sdkQueryOutput }
51-
}
52-
53-
public async getPriceImpact(humanAmountsIn: HumanTokenAmountWithAddress[]): Promise<number> {
54-
if (areEmptyAmounts(humanAmountsIn)) {
55-
// Avoid price impact calculation when there are no amounts in
56-
return 0
57-
}
58-
59-
const addLiquidityInput = this.constructSdkInput(humanAmountsIn)
60-
61-
const priceImpactABA: PriceImpactAmount = await PriceImpact.addLiquidityUnbalanced(
62-
addLiquidityInput,
63-
this.helpers.poolState
64-
)
65-
66-
return priceImpactABA.decimal
67-
}
68-
16+
export class UnbalancedAddLiquidityHandler extends BaseUnbalancedAddLiquidityHandler {
6917
public async buildCallData({
18+
humanAmountsIn,
7019
slippagePercent,
7120
queryOutput,
7221
account,
73-
permit2,
7422
}: SdkBuildAddLiquidityInput): Promise<TransactionConfig> {
7523
const addLiquidity = new AddLiquidity()
7624

7725
const buildCallParams = formatBuildCallParams(
78-
this.constructBaseBuildCallInput({
26+
constructBaseBuildCallInput({
27+
humanAmountsIn,
7928
sdkQueryOutput: queryOutput.sdkQueryOutput,
8029
slippagePercent: slippagePercent,
30+
pool: this.helpers.pool,
8131
}),
82-
this.helpers.isV3Pool(),
8332
account
8433
)
8534

86-
if (this.helpers.isV3Pool() && !permit2) {
87-
throw new Error('Permit2 signature is required for V3 pools')
88-
}
35+
console.log({ buildCallParams })
8936

90-
const { callData, to, value } =
91-
this.helpers.isV3Pool() && permit2
92-
? addLiquidity.buildCallWithPermit2(buildCallParams, permit2)
93-
: addLiquidity.buildCall(buildCallParams)
37+
const { callData, to, value } = addLiquidity.buildCall(buildCallParams)
9438

9539
return {
9640
account,
@@ -100,56 +44,4 @@ export class UnbalancedAddLiquidityHandler implements AddLiquidityHandler {
10044
value,
10145
}
10246
}
103-
104-
public async signPermit2(
105-
input: Permit2AddLiquidityInput,
106-
sdkClient: PublicWalletClient,
107-
nonces: NoncesByTokenAddress
108-
): Promise<Permit2> {
109-
const baseInput = this.constructBaseBuildCallInput({
110-
slippagePercent: input.slippagePercent,
111-
sdkQueryOutput: input.sdkQueryOutput as AddLiquidityBaseQueryOutput,
112-
})
113-
const signature = await Permit2Helper.signAddLiquidityApproval({
114-
...baseInput,
115-
client: sdkClient,
116-
owner: input.account,
117-
nonces: baseInput.amountsIn.map(a => nonces[a.token.address]),
118-
})
119-
return signature
120-
}
121-
122-
/**
123-
* PRIVATE METHODS
124-
*/
125-
private constructSdkInput(
126-
humanAmountsIn: HumanTokenAmountWithAddress[]
127-
): AddLiquidityUnbalancedInput {
128-
const amountsIn = this.helpers.toSdkInputAmounts(humanAmountsIn)
129-
130-
return {
131-
chainId: this.helpers.chainId,
132-
rpcUrl: getRpcUrl(this.helpers.chainId),
133-
amountsIn,
134-
kind: AddLiquidityKind.Unbalanced,
135-
}
136-
}
137-
138-
public constructBaseBuildCallInput({
139-
slippagePercent,
140-
sdkQueryOutput,
141-
}: {
142-
slippagePercent: string
143-
sdkQueryOutput: AddLiquidityBaseQueryOutput
144-
}): AddLiquidityBaseBuildCallInput {
145-
const baseBuildCallParams = {
146-
...(sdkQueryOutput as AddLiquidityBaseQueryOutput),
147-
slippage: Slippage.fromPercentage(`${Number(slippagePercent)}`),
148-
wethIsEth: this.helpers.includesNativeAsset(sdkQueryOutput.amountsIn),
149-
}
150-
// baseBuildCallParams.amountsIn = baseBuildCallParams.amountsIn.filter(
151-
// amountIn => amountIn.amount > 0n
152-
// )
153-
return baseBuildCallParams
154-
}
15547
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
2+
import { TransactionConfig } from '@/lib/modules/web3/contracts/contract.types'
3+
import { AddLiquidity } from '@balancer/sdk'
4+
import { SdkBuildAddLiquidityInput } from '../add-liquidity.types'
5+
import { BaseUnbalancedAddLiquidityHandler } from './BaseUnbalancedAddLiquidity.handler'
6+
import { constructBaseBuildCallInput } from './v3Helpers'
7+
8+
/**
9+
* UnbalancedAddLiquidityHandlerV3 is a handler that implements the
10+
* AddLiquidityHandler interface for unbalanced V3 adds, e.g. where the user
11+
* specifies the token amounts in. It uses the Balancer SDK to implement it's
12+
* methods. It also handles the case where one of the input tokens is the native
13+
* asset instead of the wrapped native asset.
14+
*/
15+
export class UnbalancedAddLiquidityHandlerV3 extends BaseUnbalancedAddLiquidityHandler {
16+
public async buildCallData({
17+
humanAmountsIn,
18+
slippagePercent,
19+
queryOutput,
20+
account,
21+
permit2,
22+
}: SdkBuildAddLiquidityInput): Promise<TransactionConfig> {
23+
const addLiquidity = new AddLiquidity()
24+
25+
const buildCallParams = constructBaseBuildCallInput({
26+
humanAmountsIn,
27+
sdkQueryOutput: queryOutput.sdkQueryOutput,
28+
slippagePercent: slippagePercent,
29+
pool: this.helpers.pool,
30+
})
31+
32+
if (!permit2) {
33+
throw new Error('Permit2 signature is required for V3 pools')
34+
}
35+
36+
const { callData, to, value } = addLiquidity.buildCallWithPermit2(buildCallParams, permit2)
37+
38+
return {
39+
account,
40+
chainId: this.helpers.chainId,
41+
data: callData,
42+
to,
43+
value,
44+
}
45+
}
46+
}

lib/modules/pool/actions/add-liquidity/handlers/selectAddLiquidityHandler.ts

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { AddLiquidityHandler } from './AddLiquidity.handler'
66
import { NestedAddLiquidityHandler } from './NestedAddLiquidity.handler'
77
import { requiresProportionalInput, supportsNestedActions } from '../../LiquidityActionHelpers'
88
import { ProportionalAddLiquidityHandler } from './ProportionalAddLiquidity.handler'
9+
import { isV3Pool } from '../../../pool.helpers'
10+
import { UnbalancedAddLiquidityHandlerV3 } from './UnbalancedAddLiquidityV3.handler'
911

1012
export function selectAddLiquidityHandler(pool: Pool): AddLiquidityHandler {
1113
// This is just an example to illustrate how edge-case handlers would receive different inputs but return a common contract
@@ -22,5 +24,6 @@ export function selectAddLiquidityHandler(pool: Pool): AddLiquidityHandler {
2224
return new NestedAddLiquidityHandler(pool)
2325
}
2426

27+
if (isV3Pool(pool)) return new UnbalancedAddLiquidityHandlerV3(pool)
2528
return new UnbalancedAddLiquidityHandler(pool)
2629
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//TODO: move all this file logic to a better place
2+
3+
import {
4+
AddLiquidityBaseBuildCallInput,
5+
AddLiquidityBaseQueryOutput,
6+
Slippage,
7+
} from '@balancer/sdk'
8+
import { Pool } from '../../../PoolProvider'
9+
import { LiquidityActionHelpers } from '../../LiquidityActionHelpers'
10+
import { HumanTokenAmountWithAddress } from '@/lib/modules/tokens/token.types'
11+
12+
// For now only valid for unbalanced adds
13+
export function constructBaseBuildCallInput({
14+
humanAmountsIn,
15+
slippagePercent,
16+
sdkQueryOutput,
17+
pool,
18+
}: {
19+
humanAmountsIn: HumanTokenAmountWithAddress[]
20+
slippagePercent: string
21+
sdkQueryOutput: AddLiquidityBaseQueryOutput
22+
pool: Pool
23+
}): AddLiquidityBaseBuildCallInput {
24+
const helpers = new LiquidityActionHelpers(pool)
25+
26+
console.log({ includesNativeAsset: helpers.isNativeAssetIn(humanAmountsIn) })
27+
28+
const baseBuildCallParams = {
29+
...(sdkQueryOutput as AddLiquidityBaseQueryOutput),
30+
slippage: Slippage.fromPercentage(`${Number(slippagePercent)}`),
31+
wethIsEth: helpers.isNativeAssetIn(humanAmountsIn),
32+
}
33+
// baseBuildCallParams.amountsIn = baseBuildCallParams.amountsIn.filter(
34+
// amountIn => amountIn.amount > 0n
35+
// )
36+
return baseBuildCallParams
37+
}

0 commit comments

Comments
 (0)