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

Migrate to latest b-sdk public API #105

Merged
merged 4 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MockApi } from '@/lib/shared/hooks/balancer-api/MockApi'
import { JoinConfigBuilder } from './JoinConfigBuilder'
import { AddLiquidityConfigBuilder } from './AddLiquidityConfigBuilder'
import { ChainId } from '@balancer/sdk'
import { defaultTestUserAccount } from '@/test/utils/wagmi'

Expand All @@ -12,37 +12,41 @@ const wethAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'

test('build Unbalanced Join Config', async () => {
const poolStateInput = await getPoolState()
const builder = new JoinConfigBuilder(ChainId.MAINNET, poolStateInput, 'unbalanced')
const builder = new AddLiquidityConfigBuilder(ChainId.MAINNET, poolStateInput, 'unbalanced')

builder.setAmountIn('0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f', '1')
builder.setAmountIn('0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '1')

builder.setSlippage('2')
const result = await builder.buildSdkJoinTxConfig(defaultTestUserAccount)
const result = await builder.buildSdkAddLiquidityTxConfig(defaultTestUserAccount)

expect(result.minBptOut).toBeGreaterThan(400000000000000000000n)
expect(result.minBptOut.amount).toBeGreaterThan(400000000000000000000n)
})

test('build Unbalanced Join Config with ETH (mainnet native asset)', async () => {
const poolStateInput = await getPoolState()
const builder = new JoinConfigBuilder(ChainId.MAINNET, poolStateInput, 'unbalancedNativeAsset')
const builder = new AddLiquidityConfigBuilder(
ChainId.MAINNET,
poolStateInput,
'unbalancedNativeAsset'
)

// The user chose ETH in the UI but we need to pass WETH in amountsIn
builder.setAmountIn(wethAddress, '1')

const result = await builder.buildSdkJoinTxConfig(defaultTestUserAccount)
const result = await builder.buildSdkAddLiquidityTxConfig(defaultTestUserAccount)

expect(result.minBptOut).toBeGreaterThan(400000000000000000000n)
expect(result.minBptOut.amount).toBeGreaterThan(400000000000000000000n)
})

test('build Single Asset Join Config', async () => {
const poolStateInput = await getPoolState()
const builder = new JoinConfigBuilder(ChainId.MAINNET, poolStateInput, 'singleAsset')
const builder = new AddLiquidityConfigBuilder(ChainId.MAINNET, poolStateInput, 'singleAsset')

// We need to rethink this use case when the SDK is ready
builder.setAmountIn(wethAddress, '1')

const result = await builder.buildSdkJoinTxConfig(defaultTestUserAccount)
const result = await builder.buildSdkAddLiquidityTxConfig(defaultTestUserAccount)

expect(result.minBptOut).toBeGreaterThanOrEqual(1000000000000000000n)
expect(result.minBptOut.amount).toBeGreaterThanOrEqual(1000000000000000000n)
})
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,48 @@ import { chains } from '@/lib/modules/web3/Web3Provider'
import { isSameAddress } from '@/lib/shared/utils/addresses'
import {
HumanAmount,
JoinKind,
PoolJoin,
PoolStateInput,
SingleAssetJoinInput,
AddLiquidityKind,
AddLiquidityUnbalancedInput,
AddLiquiditySingleTokenInput,
Slippage,
Token,
TokenAmount,
UnbalancedJoinInput,
PoolStateInput,
InputAmount,
AddLiquidity,
} from '@balancer/sdk'
import { Dictionary, keyBy } from 'lodash'
import { parseUnits } from 'viem'
import { Address } from 'wagmi'

type JoinType = 'unbalanced' | 'unbalancedNativeAsset' | 'singleAsset'
type AddLiquidityType = 'unbalanced' | 'unbalancedNativeAsset' | 'singleAsset'

/*
Class to build Join configs with balancer SDK
Those configs are passed to useManagedSendTransaction hook to send the a Join transaction
Class to build AddLiquidity configs with balancer SDK
Those configs are passed to useManagedSendTransaction hook to send the an AddLiquidity transaction

Usage:
- Create an instance of JoinConfigBuilder
- Setup the Join state with methods like this.setAmountsIn()
- Generate the final join config with this.buildSdkJoinTxConfig()
- Create an instance of AddLiquidityConfigBuilder
- Setup the AddLiquidity state with methods like this.setAmountsIn()
- Generate the final AddLiquidity config with this.buildSdkAddLiquidityTxConfig()
*/
export class JoinConfigBuilder {
export class AddLiquidityConfigBuilder {
inputAmount: InputAmount[] = []
slippage: Slippage = Slippage.fromPercentage('1')
checkNativeBalance = false
amountsInByTokenAddress: Dictionary<TokenAmount> = {}
amountsInByTokenAddress: Dictionary<InputAmount> = {}

constructor(
private chainId: SupportedChainId,
private poolStateInput: PoolStateInput = NullPoolState,
public joinType: JoinType = 'unbalanced'
public addLiquidityType: AddLiquidityType = 'unbalanced'
) {
const amountsInList = poolStateInput?.tokens
.map(t => new Token(chainId, t.address, t.decimals))
.map(t => TokenAmount.fromHumanAmount(t, '0'))
const amountsInList: InputAmount[] = poolStateInput?.tokens.map(t => ({
address: t.address,
decimals: t.decimals,
rawAmount: 0n,
}))

this.amountsInByTokenAddress = keyBy(amountsInList, a => a.token.address)
this.amountsInByTokenAddress = keyBy(amountsInList, a => a.address)
}

get poolId() {
Expand All @@ -59,7 +63,7 @@ export class JoinConfigBuilder {
// REVIEW THIS
// const { amountsIn } = this.getJoinInput()
return `${this.poolStateInput.id}:${this.chainId}:${this.slippage}${JSON.stringify(
this.getJoinInputForSDK()
this.getAddLiquidityInputForSDK()
)}`
}

Expand All @@ -69,9 +73,9 @@ export class JoinConfigBuilder {

public setAmountIn(tokenAddress: Address, humanAmount: HumanAmount): void {
if (this.poolStateInput.tokens.length === 0) return
this.amountsInByTokenAddress[tokenAddress] = TokenAmount.fromHumanAmount(
this.amountsInByTokenAddress[tokenAddress].token,
humanAmount
this.amountsInByTokenAddress[tokenAddress].rawAmount = parseUnits(
humanAmount,
this.amountsInByTokenAddress[tokenAddress].decimals
)
}

Expand All @@ -83,55 +87,62 @@ export class JoinConfigBuilder {
return this.nativeAssetToken.address
}

getJoinInputForSDK() {
if (this.joinType === 'unbalanced') return this.getUnbalancedJoinInput()
if (this.joinType === 'unbalancedNativeAsset') {
return this.getUnbalancedJoinInput({ useNativeAssetAsWrappedAmountIn: true })
getAddLiquidityInputForSDK() {
if (this.addLiquidityType === 'unbalanced') return this.getUnbalancedAddLiquidityInput()
if (this.addLiquidityType === 'unbalancedNativeAsset') {
return this.getUnbalancedAddLiquidityInput({ useNativeAssetAsWrappedAmountIn: true })
}
if (this.joinType === 'singleAsset') return this.getSingleAssetJoinInput()
return this.getUnbalancedJoinInput()
if (this.addLiquidityType === 'singleAsset') return this.getAddLiquiditySingleTokenInput()
return this.getUnbalancedAddLiquidityInput()
}

getJoinInputBase() {
getAddLiquidityInputBase() {
return {
chainId: this.chainId,
rpcUrl: chains[0].rpcUrls.public.http[0], //TODO: create helper to get by current chain? or useNetwork() or similar wagmi hook?
}
}

getUnbalancedJoinInput({ useNativeAssetAsWrappedAmountIn = false } = {}): UnbalancedJoinInput {
getUnbalancedAddLiquidityInput({
useNativeAssetAsWrappedAmountIn = false,
} = {}): AddLiquidityUnbalancedInput {
return {
...this.getJoinInputBase(),
amountsIn: Object.values(this.amountsInByTokenAddress).filter(a => a.amount !== 0n),
kind: JoinKind.Unbalanced,
...this.getAddLiquidityInputBase(),
amountsIn: Object.values(this.amountsInByTokenAddress),
kind: AddLiquidityKind.Unbalanced,
useNativeAssetAsWrappedAmountIn,
}
}

// WIP
// getSingleAssetJoinInput(tokenIn: Address, humanAmount: HumanAmount): SingleAssetJoinInput {
getSingleAssetJoinInput(): SingleAssetJoinInput {
// getAddLiquiditySingleTokenInput(tokenIn: Address, humanAmount: HumanAmount): AddLiquiditySingleTokenInput {
getAddLiquiditySingleTokenInput(): AddLiquiditySingleTokenInput {
// setup BPT token
const bptToken = new Token(this.chainId, this.poolStateInput.address, 18, 'BPT')
const bptOut = TokenAmount.fromHumanAmount(bptToken, '1')
const bptOut: InputAmount = {
address: bptToken.address,
decimals: bptToken.decimals,
rawAmount: parseUnits('1', bptToken.decimals),
}
const tokenIn = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' // WETH asset in eth

// perform join query to get expected bpt out
// perform AddLiquidity query to get expected bpt out
return {
...this.getJoinInputBase(),
...this.getAddLiquidityInputBase(),

bptOut,
tokenIn,
kind: JoinKind.SingleAsset,
kind: AddLiquidityKind.SingleToken,
}
}

public async buildSdkJoinTxConfig(account: Address) {
const joinInput = this.getJoinInputForSDK()
public async buildSdkAddLiquidityTxConfig(account: Address) {
const addLiquidityInput = this.getAddLiquidityInputForSDK()

const poolJoin = new PoolJoin()
const queryResult = await poolJoin.query(joinInput, this.poolStateInput)
const addLiquidity = new AddLiquidity()
const queryResult = await addLiquidity.query(addLiquidityInput, this.poolStateInput)

const { call, to, value, maxAmountsIn, minBptOut } = poolJoin.buildCall({
const { call, to, value, maxAmountsIn, minBptOut } = addLiquidity.buildCall({
...queryResult,
slippage: this.slippage,
sender: account,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import { MockApi } from '@/lib/shared/hooks/balancer-api/MockApi'
import { testHook } from '@/test/utils/custom-renderers'
import { defaultTestUserAccount } from '@/test/utils/wagmi'
import { ChainId } from '@balancer/sdk'
import { ChainId, TokenAmount } from '@balancer/sdk'
import { waitFor } from '@testing-library/react'
import { JoinConfigBuilder } from './JoinConfigBuilder'
import { useJoinPoolConfig } from './useJoinPoolConfig'
import { AddLiquidityConfigBuilder } from './AddLiquidityConfigBuilder'
import { useBuildAddLiquidityQuery } from './useBuildAddLiquidityQuery'

async function buildJoinConfig() {
const poolId = '0x68e3266c9c8bbd44ad9dca5afbfe629022aee9fe000200000000000000000512' // Balancer Weighted wjAura and WETH
const poolStateInput = await new MockApi().getPool(poolId)
return new JoinConfigBuilder(ChainId.MAINNET, poolStateInput)
return new AddLiquidityConfigBuilder(ChainId.MAINNET, poolStateInput)
}

test('fetches join pool config when user is not connected', async () => {
const builder = await buildJoinConfig()
const account = undefined
const { result } = testHook(() => {
return useJoinPoolConfig(builder, account)
return useBuildAddLiquidityQuery(builder, account)
})

await waitFor(() => expect(result.current.isLoading).toBeFalsy())
Expand All @@ -31,11 +31,12 @@ test('fetches join pool config when user is connected', async () => {
builder.setAmountIn('0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '1')

const account = defaultTestUserAccount
const { result } = testHook(() => useJoinPoolConfig(builder, account))
const { result } = testHook(() => useBuildAddLiquidityQuery(builder, account))

await waitFor(() => expect(result.current.isLoading).toBeFalsy())

expect(result.current.data?.config).toBeDefined()
expect(result.current.data?.minBptOut).toBeInstanceOf(TokenAmount)
// This values will be the same if we keep the block between tests
expect(result.current.data?.minBptOut).toBeGreaterThan(400000000000000000000n)
expect(result.current.data?.minBptOut.amount).toBeGreaterThan(400000000000000000000n)
})
23 changes: 23 additions & 0 deletions lib/modules/steps/join/useBuildAddLiquidityQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use client'

import { noUserAddress } from '@/lib/modules/web3/contracts/wagmi-helpers'
import { Address, useQuery } from 'wagmi'
import { AddLiquidityConfigBuilder } from './AddLiquidityConfigBuilder'

// Queries the SDK to create a transaction config to be used by wagmi's useManagedSendTransaction
export function useBuildAddLiquidityQuery(
addLiquidityConfigBuilder: AddLiquidityConfigBuilder,
account?: Address
) {
const addLiquidityQuery = useQuery(
[`useJoinPool:${account}:${addLiquidityConfigBuilder.queryKey}`],
async () => {
return await addLiquidityConfigBuilder.buildSdkAddLiquidityTxConfig(account || noUserAddress)
},
{
enabled: !!account,
}
)

return addLiquidityQuery
}
8 changes: 4 additions & 4 deletions lib/modules/steps/join/useConstructJoinPoolStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { useManagedSendTransaction } from '@/lib/modules/web3/contracts/useManag
import { useUserAccount } from '@/lib/modules/web3/useUserAccount'
import { useEffect } from 'react'
import { Address } from 'wagmi'
import { JoinConfigBuilder } from './JoinConfigBuilder'
import { useJoinPoolConfig } from './useJoinPoolConfig'
import { AddLiquidityConfigBuilder } from './AddLiquidityConfigBuilder'
import { useBuildAddLiquidityQuery } from './useBuildAddLiquidityQuery'
import { usePoolStateInput } from '@/lib/shared/hooks/balancer-api/usePoolStateInput'

export function useConstructJoinPoolStep(poolId: Address) {
Expand All @@ -17,12 +17,12 @@ export function useConstructJoinPoolStep(poolId: Address) {

const poolStateQuery = usePoolStateInput(poolId)

const joinBuilder = new JoinConfigBuilder(chainId, poolStateQuery.data, 'unbalanced')
const joinBuilder = new AddLiquidityConfigBuilder(chainId, poolStateQuery.data, 'unbalanced')

joinBuilder.setAmountIn('0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f', '1')
joinBuilder.setAmountIn('0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '1')

const joinQuery = useJoinPoolConfig(joinBuilder, userAddress)
const joinQuery = useBuildAddLiquidityQuery(joinBuilder, userAddress)

// update relayer approval args
// eslint-disable-next-line @typescript-eslint/no-empty-function
Expand Down
12 changes: 8 additions & 4 deletions lib/modules/steps/join/useConstructNativeAssetJoinStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { useUserAccount } from '@/lib/modules/web3/useUserAccount'
import { FlowStep } from '@/lib/shared/components/btns/transaction-steps/lib'
import { usePoolStateInput } from '@/lib/shared/hooks/balancer-api/usePoolStateInput'
import { Address } from 'wagmi'
import { JoinConfigBuilder } from './JoinConfigBuilder'
import { useJoinPoolConfig } from './useJoinPoolConfig'
import { AddLiquidityConfigBuilder } from './AddLiquidityConfigBuilder'
import { useBuildAddLiquidityQuery } from './useBuildAddLiquidityQuery'
import { BuildTransactionLabels } from '@/lib/modules/web3/contracts/transactionLabels'
import { useManagedSendTransaction } from '@/lib/modules/web3/contracts/useManagedSendTransaction'

Expand All @@ -17,11 +17,15 @@ export function useConstructNativeAssetJoinStep(poolId: Address) {

const poolStateQuery = usePoolStateInput(poolId)

const joinBuilder = new JoinConfigBuilder(chainId, poolStateQuery.data, 'unbalancedNativeAsset')
const joinBuilder = new AddLiquidityConfigBuilder(
agualis marked this conversation as resolved.
Show resolved Hide resolved
chainId,
poolStateQuery.data,
'unbalancedNativeAsset'
)

joinBuilder.setAmountIn(wETHAddress, '1')

const joinQuery = useJoinPoolConfig(joinBuilder, userAddress)
const joinQuery = useBuildAddLiquidityQuery(joinBuilder, userAddress)

const transaction = useManagedSendTransaction(buildJoinPoolLabels(), joinQuery.data?.config)

Expand Down
20 changes: 0 additions & 20 deletions lib/modules/steps/join/useJoinPoolConfig.ts

This file was deleted.

Loading