Skip to content
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

Add Add/Remove Liquidity Nested #99

Merged
merged 92 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
3161895
Initial draft with hardcoded values to focus on lower level methods (…
brunoguerios Sep 22, 2023
4e046fd
Grant proper roles to relayer deployed locally
brunoguerios Sep 25, 2023
74268bc
Fix relayer approval signature within multicall
brunoguerios Sep 25, 2023
aeaf966
First working version of nested-joins
brunoguerios Sep 27, 2023
d2081da
Merge remote-tracking branch 'origin/fix-circular-deps' into nested-join
brunoguerios Sep 27, 2023
f0edb4a
Minor refactors
brunoguerios Sep 27, 2023
2902554
Remove unused comment
brunoguerios Sep 28, 2023
af4e5c2
Add ComposableStableEncoder
brunoguerios Sep 28, 2023
4780328
Update BALANCER_RELAYER constant to be per chain
brunoguerios Sep 28, 2023
034fa83
Move level from token to pool data
brunoguerios Sep 28, 2023
cfda997
Refactor nested pool data structure
brunoguerios Sep 28, 2023
0a7aeaf
Add test case for all tokens join
brunoguerios Sep 28, 2023
1aed248
Add native asset nested join
brunoguerios Sep 28, 2023
b64e29a
Refactor methods to improve code readability
brunoguerios Sep 28, 2023
61ae94f
Fix address comparison
brunoguerios Oct 9, 2023
584914b
Add changeset
brunoguerios Oct 11, 2023
4e64197
Minor refactors
brunoguerios Oct 11, 2023
3ab481d
Fix incorrect refactor
brunoguerios Oct 16, 2023
685fa83
Add proportional nested exit
brunoguerios Oct 17, 2023
331aa25
Extract getPeekCalls to external function
brunoguerios Oct 17, 2023
4b402bb
Add single token nested exit
brunoguerios Oct 18, 2023
1170151
Add test for single token nested exit to native asset (commented out)
brunoguerios Oct 18, 2023
f437da1
Merge pull request #107 from balancer/nested-exit
brunoguerios Oct 19, 2023
cb8a11b
Remove stable encoder
brunoguerios Oct 19, 2023
4dda5a2
Remove outputRef workaround
brunoguerios Oct 19, 2023
a178ec8
Update swift-wasps-flash.md
brunoguerios Oct 19, 2023
af92b91
Remove unnecessary outputRefKey offset
brunoguerios Oct 19, 2023
f5dcf3c
Remove chainId from join/exit buildCall inputs
brunoguerios Oct 20, 2023
aa3f628
Rename join/exit calls to callsAttributes
brunoguerios Oct 20, 2023
7c4d8c8
Refactor parseNestedJoinCall and parseNestedExitCalls to encodeCalls
brunoguerios Oct 20, 2023
2a0af4d
Better describe logic to build amountsIn for nested join calls
brunoguerios Oct 20, 2023
739ebb5
Expose isProportional boolean on nestedExit main function
brunoguerios Oct 23, 2023
aa68125
Remove non-temp flag from peek calls
brunoguerios Oct 23, 2023
96b2dd4
Remove decimals from amountsIn input
brunoguerios Oct 23, 2023
42ef791
Move specific logic into getProportionalExitCalls and getSingleTokenE…
brunoguerios Oct 23, 2023
a3198b7
Extract getExitPath to separate function
brunoguerios Oct 23, 2023
3a19c81
Refactor tests to separate functionality from test setup
brunoguerios Oct 23, 2023
51efe34
Remaining test refactors
brunoguerios Oct 23, 2023
9f02490
Add comments explaining getPeekCall logic
brunoguerios Oct 23, 2023
a8fc342
Add input validation
brunoguerios Oct 23, 2023
7b260de
Minor refactor
brunoguerios Oct 23, 2023
1c9b7f3
Merge remote-tracking branch 'origin/join' into nested-join
brunoguerios Oct 23, 2023
43ddadb
Update anvil global setup to enable skipping it
brunoguerios Oct 24, 2023
392a858
Move hasApproved to a separate helper function
brunoguerios Oct 24, 2023
322cf43
Minor refactor on assertResults
brunoguerios Oct 24, 2023
98baead
Extract relayer helpers so they can be reused
brunoguerios Oct 24, 2023
ef38be8
Update chainId from number to ChainId
brunoguerios Oct 24, 2023
97fd6f4
Add PoolKind enum
brunoguerios Oct 24, 2023
a6ee413
Simplified getQueryCallsAttributes input parameter
brunoguerios Oct 24, 2023
3fc0eae
Refactor getBptAmountIn and getMaxAmountsIn logic
brunoguerios Oct 25, 2023
1f23c28
Refactor outputReference logic
brunoguerios Oct 25, 2023
998c3d0
Refactor input validation
brunoguerios Oct 25, 2023
76073ae
Extract getUserData into separate functions
brunoguerios Oct 25, 2023
2c10248
Update sender/recipient logic for nestedJoin
brunoguerios Oct 25, 2023
c306371
Update sender/recipient logic for nestedExit
brunoguerios Oct 25, 2023
efc84c1
Refactor getRecipients so the whole logic is in one single place
brunoguerios Oct 25, 2023
db96a69
Minor refactor
brunoguerios Oct 25, 2023
f04ce9c
Merge remote-tracking branch 'origin/join' into nested-join
brunoguerios Oct 25, 2023
97d7817
Fix small typo on batchRelayerLibraryAbi
brunoguerios Oct 30, 2023
d628fb5
Add comment explaining getExitPath logic
brunoguerios Oct 30, 2023
c3fd6a7
feat: Add constraint validation with tests.
johngrantuk Nov 1, 2023
1125808
chore: Add validation checks to nested joins/exits.
johngrantuk Nov 1, 2023
c5de0ff
fix: Get top level without assuming pool ordering.
johngrantuk Nov 1, 2023
8788ff5
chore: Fix lock.
johngrantuk Nov 1, 2023
fc8c2c6
Merge pull request #113 from balancer/constraint-validations
johngrantuk Nov 1, 2023
bdd2204
Merge branch 'nested-join' of github.com:balancer/b-sdk into nested-join
brunoguerios Nov 7, 2023
2823ccb
Add API integration for nested joins and exits
brunoguerios Nov 7, 2023
78dba48
Add nestedJoin example
brunoguerios Nov 7, 2023
54e6c84
Merge remote-tracking branch 'origin/join' into nested-join
brunoguerios Nov 10, 2023
9afc5bb
Remove commented out workaround
brunoguerios Nov 13, 2023
fb8f4cf
Merge remote-tracking branch 'origin/main' into nested-join
brunoguerios Nov 14, 2023
b9b4953
Refactor nested join into add liquidity nested
brunoguerios Nov 16, 2023
639b13f
Refactor nested exit into remove liquidity nested
brunoguerios Nov 16, 2023
ec774b2
Merge remote-tracking branch 'origin/main' into nested-join
brunoguerios Nov 21, 2023
3497b56
Hardcode token slots to improve test performance
brunoguerios Nov 21, 2023
39bcd43
Update blockNumber to avoid moving to an archived RPC url
brunoguerios Nov 21, 2023
ed0f7ab
Skip nested liquidity integration tests (until relayerV6 is working a…
brunoguerios Nov 21, 2023
2bd8639
Merge remote-tracking branch 'origin/main' into nested-join
brunoguerios Jan 10, 2024
310aa55
Update relayer address to v6
brunoguerios Jan 11, 2024
ef5769c
Make biome the default formatter
brunoguerios Jan 11, 2024
29491e4
Fix lint issues
brunoguerios Jan 11, 2024
14624d2
Allow custom blockNumber setup for PriceImpact tests
brunoguerios Jan 11, 2024
3ea99bd
Fix blockNumber to match hardcoded comparison results
brunoguerios Jan 11, 2024
eced858
Reverted hardcoded comparison values
brunoguerios Jan 11, 2024
fd97739
Merge remote-tracking branch 'origin/main' into nested-join
brunoguerios Jan 12, 2024
6e90721
chore: fix COMPOSABLE_STABLE api breaking change
agualis Jan 15, 2024
042c1ac
Merge pull request #201 from balancer/nested-join-composable-stable
brunoguerios Jan 15, 2024
6a4ce99
Fix add liquidity nested example
brunoguerios Jan 16, 2024
ac574bb
Expose nested liquidity types
agualis Jan 17, 2024
2370310
Merge remote-tracking branch 'origin/main' into nested-join
brunoguerios Jan 17, 2024
ef5c88d
Update to work with viem v2
brunoguerios Jan 17, 2024
47f952b
Improve pool type mapper safety by checking for unsupported types
brunoguerios Jan 17, 2024
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
7 changes: 7 additions & 0 deletions .changeset/swift-wasps-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@balancer/sdk": minor
---

- Add AddLiquidityNested
- Add RemoveLiquidityNestedProportional
- Add RemoveLiquidityNestedSingleToken
7 changes: 2 additions & 5 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
{
"editor.defaultFormatter": "rome.rome",
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"[json]": {
"editor.defaultFormatter": "rome.rome"
},
"[typescript]": {
"editor.defaultFormatter": "rome.rome"
"editor.defaultFormatter": "biomejs.biome"
}
}
174 changes: 174 additions & 0 deletions examples/addLiquidityNested.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// pnpm example ./examples/addLiquidityNested.ts
import { config } from 'dotenv';
config();

import {
Address,
BALANCER_RELAYER,
BalancerApi,
ChainId,
CHAINS,
AddLiquidityNested,
NestedPoolState,
replaceWrapped,
Slippage,
} from '../src';
import {
Client,
createTestClient,
http,
parseUnits,
PublicActions,
publicActions,
TestActions,
WalletActions,
walletActions,
} from 'viem';
import { AddLiquidityNestedInput } from '../src/entities/addLiquidityNested/types';
import { Relayer } from '../src/entities/relayer';
import {
forkSetup,
sendTransactionGetBalances,
} from '../test/lib/utils/helper';
import { ANVIL_NETWORKS, startFork } from '../test/anvil/anvil-global-setup';

const balancerApiUrl = 'https://backend-v3-canary.beets-ftm-node.com/graphql';
const poolId =
'0x08775ccb6674d6bdceb0797c364c2653ed84f3840002000000000000000004f0'; // WETH-3POOL
const chainId = ChainId.MAINNET;

const addLiquidityNested = async () => {
// User approve vault to spend their tokens and update user balance
const { client, accountAddress, nestedPoolState, rpcUrl } =
await exampleSetup();

// setup add liquidity helper
const addLiquidityNested = new AddLiquidityNested();

const amountsIn = [
{
address: '0x6b175474e89094c44da98b954eedeac495271d0f' as Address, // DAI
rawAmount: parseUnits('1', 18),
},
];

const useNativeAssetAsWrappedAmountIn = false;

const addLiquidityInput: AddLiquidityNestedInput = {
amountsIn,
chainId,
rpcUrl,
accountAddress,
useNativeAssetAsWrappedAmountIn,
};
const queryOutput = await addLiquidityNested.query(
addLiquidityInput,
nestedPoolState,
);

// build add liquidity nested call with expected minBpOut based on slippage
const slippage = Slippage.fromPercentage('1'); // 1%

const signature = await Relayer.signRelayerApproval(
BALANCER_RELAYER[chainId],
accountAddress,
client,
);

const { call, to, value } = addLiquidityNested.buildCall({
...queryOutput,
slippage,
sender: accountAddress,
recipient: accountAddress,
relayerApprovalSignature: signature,
});

let tokensIn = queryOutput.amountsIn.map((a) => a.token);
if (useNativeAssetAsWrappedAmountIn) {
tokensIn = replaceWrapped(tokensIn, chainId);
}

const tokens = [
...tokensIn.map((t) => t.address),
queryOutput.bptOut.token.address,
];

// send add liquidity nested transaction and check balance changes
const { transactionReceipt, balanceDeltas } =
await sendTransactionGetBalances(
tokens,
client,
accountAddress,
to,
call,
value,
);
console.log(`transaction status: ${transactionReceipt.status}`);
console.table({
tokens,
balanceDeltas,
});
};

const exampleSetup = async (): Promise<{
client: Client & PublicActions & TestActions & WalletActions;
accountAddress: Address;
nestedPoolState: NestedPoolState;
rpcUrl: string;
}> => {
const { rpcUrl } = await startFork(ANVIL_NETWORKS.MAINNET);
const balancerApi = new BalancerApi(balancerApiUrl, chainId);
const nestedPoolState =
await balancerApi.nestedPools.fetchNestedPoolState(poolId);

const client: Client & PublicActions & TestActions & WalletActions =
createTestClient({
mode: 'anvil',
chain: CHAINS[chainId],
transport: http(rpcUrl),
})
.extend(publicActions)
.extend(walletActions);

const accountAddress = (await client.getAddresses())[0];

const mainTokens = [
{
address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' as Address,
balance: parseUnits('1000', 18),
slot: 3,
},
{
address: '0x6b175474e89094c44da98b954eedeac495271d0f' as Address,
balance: parseUnits('1000', 18),
slot: 2,
},
{
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' as Address,
balance: parseUnits('1000', 6),
slot: 9,
},
{
address: '0xdac17f958d2ee523a2206206994597c13d831ec7' as Address,
balance: parseUnits('1000', 6),
slot: 2,
},
];

await forkSetup(
client,
accountAddress,
mainTokens.map((t) => t.address),
mainTokens.map((t) => t.slot),
mainTokens.map((t) => t.balance),
);

return {
client,
accountAddress,
nestedPoolState,
rpcUrl,
};
};

export default addLiquidityNested;
7 changes: 3 additions & 4 deletions examples/createPoolComposableStable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const createPoolComposableStable = async (): Promise<{
const createPoolComposableStableInput: CreatePoolComposableStableInput = {
name: 'Test Pool',
symbol: '50BAL-50WETH',
poolType,
tokens: [
{
tokenAddress: '0xba100000625a3754423978a60c9317c58a424e3d',
Expand All @@ -62,11 +63,9 @@ const createPoolComposableStable = async (): Promise<{
exemptFromYieldProtocolFeeFlag: false,
swapFee: '0.01',
poolOwnerAddress: signerAddress, // Balancer DAO Multisig
balancerVersion: 2,
};
const { call } = createPool.buildCall(
poolType,
createPoolComposableStableInput,
);
const { call } = createPool.buildCall(createPoolComposableStableInput);
const hash = await client.sendTransaction({
to: COMPOSABLE_STABLE_POOL_FACTORY[chainId],
data: call,
Expand Down
8 changes: 5 additions & 3 deletions examples/createPoolWeighted.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
startFork,
stopAnvilForks,
} from '../test/anvil/anvil-global-setup';
import { CHAINS, ChainId, WEIGHTED_POOL_FACTORY } from '../src';
import { CHAINS, ChainId, PoolType, WEIGHTED_POOL_FACTORY } from '../src';
import { findEventInReceiptLogs } from '../test/lib/utils/findEventInReceiptLogs';
import { weightedFactoryV4Abi } from '../src/abi/weightedFactoryV4';
import { CreatePoolWeightedInput } from '../src/entities/createPool/types';
Expand All @@ -33,10 +33,11 @@ const createPool = async (stopForkAfterExecution = true) => {
.extend(walletActions);
const signerAddress = (await client.getAddresses())[0];
const createPool = new CreatePool();
const poolType = 'WEIGHTED';
const poolType = PoolType.Weighted;
const createWeightedPoolInput: CreatePoolWeightedInput = {
name: 'Test Pool',
symbol: '50BAL-25WETH-25DAI',
poolType,
tokens: [
{
tokenAddress: '0xba100000625a3754423978a60c9317c58a424e3d',
Expand All @@ -56,8 +57,9 @@ const createPool = async (stopForkAfterExecution = true) => {
],
swapFee: '0.01',
poolOwnerAddress: signerAddress, // Balancer DAO Multisig
balancerVersion: 2,
};
const { call } = createPool.buildCall(poolType, createWeightedPoolInput);
const { call } = createPool.buildCall(createWeightedPoolInput);
const hash = await client.sendTransaction({
to: WEIGHTED_POOL_FACTORY[chainId],
data: call,
Expand Down
3 changes: 2 additions & 1 deletion examples/executeExample.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { stopAnvilForks } from '../test/anvil/anvil-global-setup';

const executeExample = async (filePath) => {
const example = require(`../${filePath}`).default;
const exampleModule = await import(`../${filePath}`);
const example = exampleModule.default;
await example();
stopAnvilForks();
};
Expand Down
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
"type": "module",
"types": "dist/index.d.ts",
"typings": "dist/index.d.ts",
"files": [
"dist/"
],
"files": ["dist/"],
"scripts": {
"build": "tsup",
"format": "biome format --write .",
Expand All @@ -26,6 +24,7 @@
"test:ci": "vitest run",
"changeset": "changeset",
"changeset:release": "pnpm build && changeset publish",
"anvil": "anvil --fork-url $(. ./.env && echo $ETHEREUM_RPC_URL)",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only needed until Relayer V6 is deployed right? Note to remove once we have updated tests.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brunoguerios do we have an expected date for this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet. It's currently being audited and after that it needs to go through governance approval. My guess is that it will be live in ~1 month.

"example": "npx tsx ./examples/executeExample.ts"
},
"dependencies": {
Expand Down
28 changes: 28 additions & 0 deletions src/abi/authorizer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export const authorizerAbi = [
{
inputs: [
{ internalType: 'bytes32', name: 'role', type: 'bytes32' },
{ internalType: 'address', name: 'account', type: 'address' },
],
name: 'grantRole',
outputs: [],
stateMutability: 'payable',
type: 'function',
},
{
inputs: [
{ internalType: 'bytes32', name: 'role', type: 'bytes32' },
{ internalType: 'address', name: 'account', type: 'address' },
],
name: 'hasRole',
outputs: [
{
internalType: 'bool',
name: '',
type: 'bool',
},
],
stateMutability: 'view',
type: 'function',
},
] as const;
86 changes: 86 additions & 0 deletions src/abi/balancerRelayer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
export const balancerRelayerAbi = [
{
inputs: [
{
internalType: 'contract IVault',
name: 'vault',
type: 'address',
},
{
internalType: 'address',
name: 'libraryAddress',
type: 'address',
},
],
stateMutability: 'nonpayable',
type: 'constructor',
},
{
inputs: [],
name: 'getLibrary',
outputs: [
{
internalType: 'address',
name: '',
type: 'address',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'getVault',
outputs: [
{
internalType: 'contract IVault',
name: '',
type: 'address',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{
internalType: 'bytes[]',
name: 'data',
type: 'bytes[]',
},
],
name: 'multicall',
outputs: [
{
internalType: 'bytes[]',
name: 'results',
type: 'bytes[]',
},
],
stateMutability: 'payable',
type: 'function',
},
{
inputs: [
{
internalType: 'bytes[]',
name: 'data',
type: 'bytes[]',
},
],
name: 'vaultActionsQueryMulticall',
outputs: [
{
internalType: 'bytes[]',
name: 'results',
type: 'bytes[]',
},
],
stateMutability: 'nonpayable',
type: 'function',
},
{
stateMutability: 'payable',
type: 'receive',
},
] as const;
Loading
Loading