Skip to content

Commit

Permalink
Merge pull request #262 from balancer/223-v3-pool-init
Browse files Browse the repository at this point in the history
V3 Initialize Pool
  • Loading branch information
brunoguerios authored Mar 5, 2024
2 parents 703b5b6 + 9f394b1 commit 7ac10d7
Show file tree
Hide file tree
Showing 22 changed files with 477 additions and 107 deletions.
5 changes: 5 additions & 0 deletions .changeset/early-glasses-shout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@balancer/sdk": minor
---

Adds Initialize Pool functionality for V3 pools;
90 changes: 46 additions & 44 deletions src/data/providers/initPoolDataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import {
getContract,
http,
} from 'viem';
import { CHAINS, VAULT } from '../../utils';
import { CHAINS } from '../../utils';
import { PoolState } from '../../entities';
import { getTokenDecimals } from '../../utils/tokens';
import { vaultV2Abi } from '@/abi';
import {
getPoolTokensV2,
getPoolTokensV3,
getTokenDecimals,
} from '../../utils/tokens';

export class InitPoolDataProvider {
private readonly client: PublicClient;
Expand Down Expand Up @@ -55,59 +58,58 @@ export class InitPoolDataProvider {
poolAddress: Address,
poolType: string,
): Promise<PoolState> {
const chainId = await this.client.getChainId();
const poolContract = getContract({
abi: this.simplePoolAbi,
address: poolAddress,
client: this.client,
});

const vaultV2 = getContract({
abi: vaultV2Abi,
address: VAULT[chainId],
client: this.client,
});

try {
const poolId = (await poolContract.read.getPoolId()) as Hex;
const poolTokensFromVault = await vaultV2.read.getPoolTokens([
poolId,
]);
const poolTokens = await Promise.all(
poolTokensFromVault[0].map(async (address, index) => {
const decimals = await getTokenDecimals(
address,
this.client,
);
return {
address: address.toLowerCase() as Address,
index,
decimals,
};
}),
);
return {
id: poolId,
address: poolAddress.toLowerCase() as Address,
type: poolType,
tokens: poolTokens,
vaultVersion: 2,
};
} catch (e) {
console.warn(e);
throw new Error(
'Invalid pool address, not possible to retrieve Pool Id',
);
}
const poolId = (await poolContract.read.getPoolId()) as Hex;
const poolTokensFromVault = await getPoolTokensV2(poolId, this.client);
const poolTokens = await Promise.all(
poolTokensFromVault[0].map(async (address, index) => {
const decimals = await getTokenDecimals(address, this.client);
return {
address: address.toLowerCase() as Address,
index,
decimals,
};
}),
);
return {
id: poolId,
address: poolAddress.toLowerCase() as Address,
type: poolType,
tokens: poolTokens,
vaultVersion: 2,
};
}

private async getInitPoolDataV3(
poolAddress: Address,
poolType: string,
): Promise<PoolState> {
console.log(poolAddress, poolType);
throw new Error(
'InitPoolData fetcher not implemented for Balancer V3 yet',
const poolTokensFromVault: Address[] = await getPoolTokensV3(
poolAddress,
this.client,
);

const poolTokens = await Promise.all(
poolTokensFromVault.map(async (address, index) => {
const decimals = await getTokenDecimals(address, this.client);
return {
address: address.toLowerCase() as Address,
index,
decimals,
};
}),
);
return {
id: poolAddress,
address: poolAddress.toLowerCase() as Address,
type: poolType,
tokens: poolTokens,
vaultVersion: 3,
};
}
}
20 changes: 16 additions & 4 deletions src/entities/initPool/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { InputValidator } from '../inputValidator/inputValidator';
import { PoolState } from '../types';
import { InitPoolBuildOutput, InitPoolConfig, InitPoolInput } from './types';
import {
InitPoolBuildOutput,
InitPoolConfig,
InitPoolInput,
InitPoolInputV2,
InitPoolInputV3,
} from './types';
import { InitPoolV2 } from './initPoolV2';
import { InitPoolV3 } from './initPoolV3';

Expand All @@ -12,12 +18,18 @@ export class InitPool {
constructor(public config?: InitPoolConfig) {}

buildCall(input: InitPoolInput, poolState: PoolState): InitPoolBuildOutput {
this.inputValidator.validateAddLiquidity(input, poolState);
this.inputValidator.validateInitPool(input, poolState);
switch (poolState.vaultVersion) {
case 2:
return new InitPoolV2().buildCall(input, poolState);
return new InitPoolV2().buildCall(
input as InitPoolInputV2,
poolState,
);
case 3:
return new InitPoolV3().buildCall(input, poolState);
return new InitPoolV3().buildCall(
input as InitPoolInputV3,
poolState,
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@ import {
getSortedTokens,
parseAddLiquidityArgs,
} from '../../../utils';
import { InitPoolBase, InitPoolBuildOutput, InitPoolInput } from '../../types';
import {
InitPoolBase,
InitPoolBuildOutput,
InitPoolInputV2,
} from '../../types';
import { vaultV2Abi } from '../../../../abi';
import { VAULT, MAX_UINT256, ZERO_ADDRESS } from '../../../../utils';
import { Token } from '@/entities/token';

export class InitPoolComposableStable implements InitPoolBase {
buildCall(input: InitPoolInput, poolState: PoolState): InitPoolBuildOutput {
buildCall(
input: InitPoolInputV2,
poolState: PoolState,
): InitPoolBuildOutput {
const sortedTokens = getSortedTokens(poolState.tokens, input.chainId);
const amounts = this.getAmounts(input, poolState.address, sortedTokens);

Expand Down Expand Up @@ -45,7 +52,7 @@ export class InitPoolComposableStable implements InitPoolBase {
}

private getAmounts(
input: InitPoolInput,
input: InitPoolInputV2,
poolAddress: Address,
poolTokens: Token[],
): InitPoolAmountsComposableStable {
Expand Down
7 changes: 5 additions & 2 deletions src/entities/initPool/initPoolV2/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
InitPoolBase,
InitPoolBuildOutput,
InitPoolConfig,
InitPoolInput,
InitPoolInputV2,
} from '../types';
import { InitPoolWeighted } from './weighted/initPoolWeighted';

Expand All @@ -29,7 +29,10 @@ export class InitPoolV2 implements InitPoolBase {
return this.initPoolTypes[poolType];
}

buildCall(input: InitPoolInput, poolState: PoolState): InitPoolBuildOutput {
buildCall(
input: InitPoolInputV2,
poolState: PoolState,
): InitPoolBuildOutput {
return this.getInitPool(poolState.type).buildCall(input, poolState);
}
}
13 changes: 10 additions & 3 deletions src/entities/initPool/initPoolV2/weighted/initPoolWeighted.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { Address, encodeFunctionData } from 'viem';
import { InitPoolAmounts, PoolState } from '../../../types';
import { InitPoolBase, InitPoolBuildOutput, InitPoolInput } from '../../types';
import {
InitPoolBase,
InitPoolBuildOutput,
InitPoolInputV2,
} from '../../types';
import { VAULT, ZERO_ADDRESS } from '../../../../utils';
import { vaultV2Abi } from '../../../../abi';
import {
Expand All @@ -12,7 +16,10 @@ import { Token } from '../../../token';
import { WeightedEncoder } from '../../../encoders';

export class InitPoolWeighted implements InitPoolBase {
buildCall(input: InitPoolInput, poolState: PoolState): InitPoolBuildOutput {
buildCall(
input: InitPoolInputV2,
poolState: PoolState,
): InitPoolBuildOutput {
const sortedTokens = getSortedTokens(poolState.tokens, input.chainId);
const amounts = this.getAmounts(input, sortedTokens);
const userData = WeightedEncoder.encodeInitPoolUserData(amounts);
Expand Down Expand Up @@ -43,7 +50,7 @@ export class InitPoolWeighted implements InitPoolBase {
}

private getAmounts(
input: InitPoolInput,
input: InitPoolInputV2,
poolTokens: Token[],
): InitPoolAmounts {
return {
Expand Down
56 changes: 52 additions & 4 deletions src/entities/initPool/initPoolV3.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,57 @@
import { balancerRouterAbi } from '@/abi';
import { PoolState } from '../types';
import { InitPoolBase, InitPoolBuildOutput, InitPoolInput } from './types';
import { InitPoolBase, InitPoolBuildOutput, InitPoolInputV3 } from './types';
import { BALANCER_ROUTER, NATIVE_ASSETS, isSameAddress } from '@/utils';
import { encodeFunctionData, Address } from 'viem';
import { getSortedTokens, parseInitializeArgs, getAmounts } from '../utils';
import { Token } from '../token';

export class InitPoolV3 implements InitPoolBase {
buildCall(input: InitPoolInput, poolState: PoolState): InitPoolBuildOutput {
console.log(input, poolState);
throw new Error('Method not implemented.');
buildCall(
input: InitPoolInputV3,
poolState: PoolState,
): InitPoolBuildOutput {
const sortedTokens = getSortedTokens(poolState.tokens, input.chainId);
const { exactAmountsIn } = this.getAmounts(input, sortedTokens);
const { args } = parseInitializeArgs({
...input,
exactAmountsIn,
poolAddress: poolState.address,
sortedTokens,
});

const call = encodeFunctionData({
abi: balancerRouterAbi,
functionName: 'initialize',
args,
});

const value = this.value(input);

return {
call,
to: BALANCER_ROUTER[input.chainId] as Address,
value,
};
}

private getAmounts(
input: InitPoolInputV3,
tokens: Token[],
): { exactAmountsIn: bigint[] } {
return {
exactAmountsIn: getAmounts(tokens, input.amountsIn),
};
}

private value(input: InitPoolInputV3) {
return input.wethIsEth
? (input.amountsIn.find((a) =>
isSameAddress(
a.address,
NATIVE_ASSETS[input.chainId].wrapped,
),
)?.rawAmount as bigint)
: 0n;
}
}
26 changes: 22 additions & 4 deletions src/entities/initPool/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Address } from 'viem';
import { Address, Hex } from 'viem';
import {
AddLiquidityBaseInput,
AddLiquidityBuildOutput,
} from '../addLiquidity/types';
import { InputAmountInit } from '../../types';
import { InputAmount } from '../../types';
import { PoolState } from '../types';

export interface InitPoolBase {
Expand All @@ -15,13 +15,31 @@ export type InitPoolBuildOutput = Omit<
'minBptOut' | 'maxAmountsIn'
>;

export type InitPoolInput = Omit<AddLiquidityBaseInput, 'rpcUrl'> & {
export type InitPoolInput = InitPoolInputV2 | InitPoolInputV3;

export type InitPoolInputV2 = Omit<AddLiquidityBaseInput, 'rpcUrl'> & {
sender: Address;
recipient: Address;
amountsIn: InputAmountInit[];
amountsIn: InputAmount[];
chainId: number;
};

export type InitPoolInputV3 = {
amountsIn: InputAmount[];
minBptAmountOut: bigint;
wethIsEth?: boolean;
chainId: number;
};

export type InitPoolConfig = {
initPoolTypes: Record<string, InitPoolBase>;
};

export type InitializeArgs = [
Address,
Address[],
bigint[],
bigint,
boolean,
Hex,
];
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { areTokensInArray } from '@/entities/utils/areTokensInArray';
import { AddLiquidityInput } from '../../addLiquidity/types';
import { CreatePoolV2ComposableStableInput } from '../../createPool/types';
import { InitPoolInput } from '../../initPool/types';
Expand All @@ -12,8 +13,15 @@ import {
} from '../utils/validateTokens';

export class InputValidatorComposableStable implements InputValidatorBase {
validateInitPool(initPoolInput: InitPoolInput, poolState: PoolState): void {
areTokensInArray(
initPoolInput.amountsIn.map((a) => a.address),
poolState.tokens.map((t) => t.address),
);
}

validateAddLiquidity(
addLiquidityInput: AddLiquidityInput | InitPoolInput,
addLiquidityInput: AddLiquidityInput,
poolState: PoolState,
): void {
validatePoolHasBpt(poolState);
Expand Down
Loading

0 comments on commit 7ac10d7

Please sign in to comment.