From 1ca2458201b51144948259f25d779e833b453111 Mon Sep 17 00:00:00 2001 From: elshan_eth Date: Tue, 24 Dec 2024 16:44:26 +0100 Subject: [PATCH 01/30] fist iteration --- .../vault/ICompositeLiquidityRouter.sol | 32 +- .../contracts/CompositeLiquidityRouter.sol | 222 +++++++----- .../.contract-sizes/CompositeLiquidityRouter | 4 +- .../CompositeLiquidityRouterERC4626Pool.t.sol | 321 +++++++++++++++--- 4 files changed, 422 insertions(+), 157 deletions(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index 1c2f6cd7e..2dcfa40ee 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -30,7 +30,8 @@ interface ICompositeLiquidityRouter { * the "parent" pool, and also make sure limits are set properly. * * @param pool Address of the liquidity pool - * @param exactUnderlyingAmountsIn Exact amounts of underlying tokens in, sorted in token registration order of + * @param useWrappedTokens An array indicating whether the input token is a wrapper or underlying token + * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order of * wrapped tokens in the pool * @param minBptAmountOut Minimum amount of pool tokens to be received * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH @@ -39,7 +40,8 @@ interface ICompositeLiquidityRouter { */ function addLiquidityUnbalancedToERC4626Pool( address pool, - uint256[] memory exactUnderlyingAmountsIn, + bool[] memory useWrappedTokens, + uint256[] memory exactAmountsIn, uint256 minBptAmountOut, bool wethIsEth, bytes memory userData @@ -52,7 +54,8 @@ interface ICompositeLiquidityRouter { * the "parent" pool, and also make sure limits are set properly. * * @param pool Address of the liquidity pool - * @param maxUnderlyingAmountsIn Maximum amounts of underlying tokens in, sorted in token registration order of + * @param useWrappedTokens An array indicating whether the input token is a wrapper or underlying token + * @param maxAmountsIn Maximum amounts of underlying/wrapped tokens in, sorted in token registration order of * wrapped tokens in the pool * @param exactBptAmountOut Exact amount of pool tokens to be received * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH @@ -62,7 +65,8 @@ interface ICompositeLiquidityRouter { */ function addLiquidityProportionalToERC4626Pool( address pool, - uint256[] memory maxUnderlyingAmountsIn, + bool[] memory useWrappedTokens, + uint256[] memory maxAmountsIn, uint256 exactBptAmountOut, bool wethIsEth, bytes memory userData @@ -72,27 +76,30 @@ interface ICompositeLiquidityRouter { * @notice Remove proportional amounts of underlying from an ERC4626 pool, burning an exact pool token amount. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool + * @param useWrappedTokens An array indicating whether the output token is a wrapper or underlying token * @param exactBptAmountIn Exact amount of pool tokens provided - * @param minUnderlyingAmountsOut Minimum amounts of underlying tokens out, sorted in token registration order of + * @param minAmountsOut Minimum amounts of underlying tokens out, sorted in token registration order of * wrapped tokens in the pool * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH * @param userData Additional (optional) data required for removing liquidity - * @return underlyingAmountsOut Actual amounts of tokens received, sorted in token registration order of wrapped + * @return amountsOut Actual amounts of tokens received, sorted in token registration order of wrapped * tokens in the pool */ function removeLiquidityProportionalFromERC4626Pool( address pool, + bool[] memory useWrappedTokens, uint256 exactBptAmountIn, - uint256[] memory minUnderlyingAmountsOut, + uint256[] memory minAmountsOut, bool wethIsEth, bytes memory userData - ) external payable returns (uint256[] memory underlyingAmountsOut); + ) external payable returns (uint256[] memory amountsOut); /** * @notice Queries an `addLiquidityUnbalancedToERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param exactUnderlyingAmountsIn Exact amounts of underlying tokens in, sorted in token registration order of + * @param useWrappedTokens An array indicating whether the input token is a wrapper or underlying token + * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order of * wrapped tokens in the pool * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query @@ -100,7 +107,8 @@ interface ICompositeLiquidityRouter { */ function queryAddLiquidityUnbalancedToERC4626Pool( address pool, - uint256[] memory exactUnderlyingAmountsIn, + bool[] memory useWrappedTokens, + uint256[] memory exactAmountsIn, address sender, bytes memory userData ) external returns (uint256 bptAmountOut); @@ -109,6 +117,7 @@ interface ICompositeLiquidityRouter { * @notice Queries an `addLiquidityProportionalToERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool + * @param useWrappedTokens An array indicating whether the input token is a wrapper or underlying token * @param exactBptAmountOut Exact amount of pool tokens to be received * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query @@ -117,6 +126,7 @@ interface ICompositeLiquidityRouter { */ function queryAddLiquidityProportionalToERC4626Pool( address pool, + bool[] memory useWrappedTokens, uint256 exactBptAmountOut, address sender, bytes memory userData @@ -126,6 +136,7 @@ interface ICompositeLiquidityRouter { * @notice Queries a `removeLiquidityProportionalFromERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool + * @param useWrappedTokens An array indicating whether the output token is a wrapper or underlying token * @param exactBptAmountIn Exact amount of pool tokens provided for the query * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query @@ -134,6 +145,7 @@ interface ICompositeLiquidityRouter { */ function queryRemoveLiquidityProportionalFromERC4626Pool( address pool, + bool[] memory useWrappedTokens, uint256 exactBptAmountIn, address sender, bytes memory userData diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index ec7bc6104..46f25ea65 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.24; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IPermit2 } from "permit2/src/interfaces/IPermit2.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ICompositeLiquidityRouter } from "@balancer-labs/v3-interfaces/contracts/vault/ICompositeLiquidityRouter.sol"; import { IVaultErrors } from "@balancer-labs/v3-interfaces/contracts/vault/IVaultErrors.sol"; @@ -48,7 +48,8 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function addLiquidityUnbalancedToERC4626Pool( address pool, - uint256[] memory exactUnderlyingAmountsIn, + bool[] memory useWrappedTokens, + uint256[] memory exactAmountsIn, uint256 minBptAmountOut, bool wethIsEth, bytes memory userData @@ -57,15 +58,18 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo _vault.unlock( abi.encodeCall( CompositeLiquidityRouter.addLiquidityERC4626PoolUnbalancedHook, - AddLiquidityHookParams({ - sender: msg.sender, - pool: pool, - maxAmountsIn: exactUnderlyingAmountsIn, - minBptAmountOut: minBptAmountOut, - kind: AddLiquidityKind.UNBALANCED, - wethIsEth: wethIsEth, - userData: userData - }) + ( + AddLiquidityHookParams({ + sender: msg.sender, + pool: pool, + maxAmountsIn: exactAmountsIn, + minBptAmountOut: minBptAmountOut, + kind: AddLiquidityKind.UNBALANCED, + wethIsEth: wethIsEth, + userData: userData + }), + useWrappedTokens + ) ) ), (uint256) @@ -75,24 +79,28 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function addLiquidityProportionalToERC4626Pool( address pool, - uint256[] memory maxUnderlyingAmountsIn, + bool[] memory useWrappedTokens, + uint256[] memory maxAmountsIn, uint256 exactBptAmountOut, bool wethIsEth, bytes memory userData - ) external payable saveSender(msg.sender) returns (uint256[] memory underlyingAmountsIn) { - underlyingAmountsIn = abi.decode( + ) external payable saveSender(msg.sender) returns (uint256[] memory amountsIn) { + amountsIn = abi.decode( _vault.unlock( abi.encodeCall( CompositeLiquidityRouter.addLiquidityERC4626PoolProportionalHook, - AddLiquidityHookParams({ - sender: msg.sender, - pool: pool, - maxAmountsIn: maxUnderlyingAmountsIn, - minBptAmountOut: exactBptAmountOut, - kind: AddLiquidityKind.PROPORTIONAL, - wethIsEth: wethIsEth, - userData: userData - }) + ( + AddLiquidityHookParams({ + sender: msg.sender, + pool: pool, + maxAmountsIn: maxAmountsIn, + minBptAmountOut: exactBptAmountOut, + kind: AddLiquidityKind.PROPORTIONAL, + wethIsEth: wethIsEth, + userData: userData + }), + useWrappedTokens + ) ) ), (uint256[]) @@ -102,24 +110,28 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function removeLiquidityProportionalFromERC4626Pool( address pool, + bool[] memory useWrappedTokens, uint256 exactBptAmountIn, - uint256[] memory minUnderlyingAmountsOut, + uint256[] memory minAmountsOut, bool wethIsEth, bytes memory userData - ) external payable saveSender(msg.sender) returns (uint256[] memory underlyingAmountsOut) { - underlyingAmountsOut = abi.decode( + ) external payable saveSender(msg.sender) returns (uint256[] memory amountsOut) { + amountsOut = abi.decode( _vault.unlock( abi.encodeCall( CompositeLiquidityRouter.removeLiquidityERC4626PoolProportionalHook, - RemoveLiquidityHookParams({ - sender: msg.sender, - pool: pool, - minAmountsOut: minUnderlyingAmountsOut, - maxBptAmountIn: exactBptAmountIn, - kind: RemoveLiquidityKind.PROPORTIONAL, - wethIsEth: wethIsEth, - userData: userData - }) + ( + RemoveLiquidityHookParams({ + sender: msg.sender, + pool: pool, + minAmountsOut: minAmountsOut, + maxBptAmountIn: exactBptAmountIn, + kind: RemoveLiquidityKind.PROPORTIONAL, + wethIsEth: wethIsEth, + userData: userData + }), + useWrappedTokens + ) ) ), (uint256[]) @@ -129,7 +141,8 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function queryAddLiquidityUnbalancedToERC4626Pool( address pool, - uint256[] memory exactUnderlyingAmountsIn, + bool[] memory useWrappedTokens, + uint256[] memory exactAmountsIn, address sender, bytes memory userData ) external saveSender(sender) returns (uint256 bptAmountOut) { @@ -137,15 +150,18 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo _vault.quote( abi.encodeCall( CompositeLiquidityRouter.addLiquidityERC4626PoolUnbalancedHook, - AddLiquidityHookParams({ - sender: address(this), - pool: pool, - maxAmountsIn: exactUnderlyingAmountsIn, - minBptAmountOut: 0, - kind: AddLiquidityKind.UNBALANCED, - wethIsEth: false, - userData: userData - }) + ( + AddLiquidityHookParams({ + sender: address(this), + pool: pool, + maxAmountsIn: exactAmountsIn, + minBptAmountOut: 0, + kind: AddLiquidityKind.UNBALANCED, + wethIsEth: false, + userData: userData + }), + useWrappedTokens + ) ) ), (uint256) @@ -155,23 +171,27 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function queryAddLiquidityProportionalToERC4626Pool( address pool, + bool[] memory useWrappedTokens, uint256 exactBptAmountOut, address sender, bytes memory userData - ) external saveSender(sender) returns (uint256[] memory underlyingAmountsIn) { - underlyingAmountsIn = abi.decode( + ) external saveSender(sender) returns (uint256[] memory amountsIn) { + amountsIn = abi.decode( _vault.quote( abi.encodeCall( CompositeLiquidityRouter.addLiquidityERC4626PoolProportionalHook, - AddLiquidityHookParams({ - sender: address(this), - pool: pool, - maxAmountsIn: _maxTokenLimits(pool), - minBptAmountOut: exactBptAmountOut, - kind: AddLiquidityKind.PROPORTIONAL, - wethIsEth: false, - userData: userData - }) + ( + AddLiquidityHookParams({ + sender: address(this), + pool: pool, + maxAmountsIn: _maxTokenLimits(pool), + minBptAmountOut: exactBptAmountOut, + kind: AddLiquidityKind.PROPORTIONAL, + wethIsEth: false, + userData: userData + }), + useWrappedTokens + ) ) ), (uint256[]) @@ -181,6 +201,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function queryRemoveLiquidityProportionalFromERC4626Pool( address pool, + bool[] memory useWrappedTokens, uint256 exactBptAmountIn, address sender, bytes memory userData @@ -190,15 +211,18 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo _vault.quote( abi.encodeCall( CompositeLiquidityRouter.removeLiquidityERC4626PoolProportionalHook, - RemoveLiquidityHookParams({ - sender: address(this), - pool: pool, - minAmountsOut: new uint256[](erc4626PoolTokens.length), - maxBptAmountIn: exactBptAmountIn, - kind: RemoveLiquidityKind.PROPORTIONAL, - wethIsEth: false, - userData: userData - }) + ( + RemoveLiquidityHookParams({ + sender: address(this), + pool: pool, + minAmountsOut: new uint256[](erc4626PoolTokens.length), + maxBptAmountIn: exactBptAmountIn, + kind: RemoveLiquidityKind.PROPORTIONAL, + wethIsEth: false, + userData: userData + }), + useWrappedTokens + ) ) ), (uint256[]) @@ -206,7 +230,8 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo } function addLiquidityERC4626PoolUnbalancedHook( - AddLiquidityHookParams calldata params + AddLiquidityHookParams calldata params, + bool[] calldata useWrappedTokens ) external nonReentrant onlyVault returns (uint256 bptAmountOut) { IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; @@ -214,8 +239,9 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo // Revert if tokensIn length does not match with maxAmountsIn length. InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length); - (, uint256[] memory wrappedAmountsIn) = _wrapTokens( + uint256[] memory amountsIn = _prepareTokens( params, + useWrappedTokens, erc4626PoolTokens, params.maxAmountsIn, SwapKind.EXACT_IN, @@ -227,7 +253,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo AddLiquidityParams({ pool: params.pool, to: params.sender, - maxAmountsIn: wrappedAmountsIn, + maxAmountsIn: amountsIn, minBptAmountOut: params.minBptAmountOut, kind: params.kind, userData: params.userData @@ -236,8 +262,9 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo } function addLiquidityERC4626PoolProportionalHook( - AddLiquidityHookParams calldata params - ) external nonReentrant onlyVault returns (uint256[] memory underlyingAmountsIn) { + AddLiquidityHookParams calldata params, + bool[] calldata useWrappedTokens + ) external nonReentrant onlyVault returns (uint256[] memory amountsIn) { IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; @@ -258,8 +285,9 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo }) ); - (underlyingAmountsIn, ) = _wrapTokens( + amountsIn = _prepareTokens( params, + useWrappedTokens, erc4626PoolTokens, wrappedAmountsIn, SwapKind.EXACT_OUT, @@ -268,11 +296,12 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo } function removeLiquidityERC4626PoolProportionalHook( - RemoveLiquidityHookParams calldata params - ) external nonReentrant onlyVault returns (uint256[] memory underlyingAmountsOut) { + RemoveLiquidityHookParams calldata params, + bool[] calldata useWrappedTokens + ) external nonReentrant onlyVault returns (uint256[] memory amountsOut) { IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; - underlyingAmountsOut = new uint256[](poolTokensLength); + amountsOut = new uint256[](poolTokensLength); (, uint256[] memory wrappedAmountsOut, ) = _vault.removeLiquidity( RemoveLiquidityParams({ @@ -291,6 +320,14 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); + if (useWrappedTokens[i] == true) { + amountsOut[i] = wrappedAmountsOut[i]; + if (isStaticCall == false) { + _sendTokenOut(params.sender, erc4626PoolTokens[i], amountsOut[i], params.wethIsEth); + } + continue; + } + // If the Vault returns address 0 as underlying, it means that the ERC4626 token buffer was not // initialized. Thus, the Router treats it as a non-ERC4626 token. if (address(underlyingToken) == address(0)) { @@ -302,15 +339,15 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo ); } - underlyingAmountsOut[i] = wrappedAmountsOut[i]; + amountsOut[i] = wrappedAmountsOut[i]; if (isStaticCall == false) { - _sendTokenOut(params.sender, erc4626PoolTokens[i], underlyingAmountsOut[i], params.wethIsEth); + _sendTokenOut(params.sender, erc4626PoolTokens[i], amountsOut[i], params.wethIsEth); } continue; } // `erc4626BufferWrapOrUnwrap` will fail if the wrappedToken is not ERC4626-conforming. - (, , underlyingAmountsOut[i]) = _vault.erc4626BufferWrapOrUnwrap( + (, , amountsOut[i]) = _vault.erc4626BufferWrapOrUnwrap( BufferWrapOrUnwrapParams({ kind: SwapKind.EXACT_IN, direction: WrappingDirection.UNWRAP, @@ -321,22 +358,22 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo ); if (isStaticCall == false) { - _sendTokenOut(params.sender, underlyingToken, underlyingAmountsOut[i], params.wethIsEth); + _sendTokenOut(params.sender, underlyingToken, amountsOut[i], params.wethIsEth); } } } /// @dev Assumes array lengths have been checked externally. - function _wrapTokens( + function _prepareTokens( AddLiquidityHookParams calldata params, + bool[] memory useWrappedTokens, IERC20[] memory erc4626PoolTokens, uint256[] memory amountsIn, SwapKind kind, uint256[] memory limits - ) private returns (uint256[] memory underlyingAmounts, uint256[] memory wrappedAmounts) { + ) private returns (uint256[] memory finalAmountsIn) { uint256 poolTokensLength = erc4626PoolTokens.length; - underlyingAmounts = new uint256[](poolTokensLength); - wrappedAmounts = new uint256[](poolTokensLength); + finalAmountsIn = new uint256[](poolTokensLength); bool isStaticCall = EVMCallModeHelpers.isStaticCall(); @@ -347,6 +384,12 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); + if (useWrappedTokens[i] == true) { + finalAmountsIn[i] = amountsIn[i]; + _takeTokenIn(params.sender, wrappedToken, finalAmountsIn[i], params.wethIsEth); + continue; + } + // If the Vault returns address 0 as underlying, it means that the ERC4626 token buffer was not // initialized. Thus, the Router treats it as a non-ERC4626 token. if (address(underlyingToken) == address(0)) { @@ -354,8 +397,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo revert IVaultErrors.AmountInAboveMax(erc4626PoolTokens[i], amountsIn[i], params.maxAmountsIn[i]); } - underlyingAmounts[i] = amountsIn[i]; - wrappedAmounts[i] = amountsIn[i]; + finalAmountsIn[i] = amountsIn[i]; if (isStaticCall == false) { _takeTokenIn(params.sender, erc4626PoolTokens[i], amountsIn[i], params.wethIsEth); @@ -376,9 +418,11 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo } } + uint256 underlyingAmount; + uint256 wrappedAmount; if (amountsIn[i] > 0) { // `erc4626BufferWrapOrUnwrap` will fail if the wrappedToken isn't ERC4626-conforming. - (, underlyingAmounts[i], wrappedAmounts[i]) = _vault.erc4626BufferWrapOrUnwrap( + (, underlyingAmount, wrappedAmount) = _vault.erc4626BufferWrapOrUnwrap( BufferWrapOrUnwrapParams({ kind: kind, direction: WrappingDirection.WRAP, @@ -387,16 +431,16 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo limitRaw: limits[i] }) ); - } else { - underlyingAmounts[i] = 0; - wrappedAmounts[i] = 0; } if (isStaticCall == false && kind == SwapKind.EXACT_OUT) { + bool wethIsEth = params.wethIsEth; // If the SwapKind is EXACT_OUT, the limit of underlying tokens was taken from the user, so the // difference between limit and exact underlying amount needs to be returned to the sender. - _sendTokenOut(params.sender, underlyingToken, limits[i] - underlyingAmounts[i], params.wethIsEth); + _sendTokenOut(params.sender, underlyingToken, limits[i] - underlyingAmount, wethIsEth); } + + finalAmountsIn[i] = kind == SwapKind.EXACT_IN ? wrappedAmount : underlyingAmount; } // If there's a leftover of eth, send it back to the sender. The router should not keep ETH. diff --git a/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter b/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter index c5c2d49d6..7e609dca6 100644 --- a/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter +++ b/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter @@ -1,2 +1,2 @@ -Bytecode 21.554 -InitCode 23.372 \ No newline at end of file +Bytecode 21.938 +InitCode 23.749 \ No newline at end of file diff --git a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol index d09da8588..f0688e83d 100644 --- a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol +++ b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol @@ -112,6 +112,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( pool, + new bool[](exactUnderlyingAmountsIn.length), exactUnderlyingAmountsIn, 1, false, @@ -127,7 +128,55 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vars.wrappedWethPoolDelta = exactWrappedAmountsIn[waWethIdx]; vars.isPartialERC4626Pool = false; - _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars); + _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars, false); + + assertEq(bptOut, expectBPTOut, "BPT operationAmount should match expected"); + assertEq(IERC20(pool).balanceOf(alice), bptOut, "Alice: wrong BPT balance"); + } + + function testAddLiquidityUnbalancedToERC4626PoolWithWrappedToken__Fuzz(uint256 rawOperationAmount) public { + uint256 operationAmount = bound(rawOperationAmount, MIN_AMOUNT, bufferInitialAmount / 2); + uint256[] memory exactUnderlyingAmountsIn = [operationAmount, operationAmount].toMemoryArray(); + + uint256[] memory exactWrappedAmountsIn = new uint256[](2); + exactWrappedAmountsIn[waDaiIdx] = operationAmount; + exactWrappedAmountsIn[waWethIdx] = _vaultPreviewDeposit(waWETH, operationAmount); + + bool[] memory useWrappedTokens = new bool[](exactUnderlyingAmountsIn.length); + useWrappedTokens[waDaiIdx] = true; + + uint256 snapshot = vm.snapshot(); + _prankStaticCall(); + uint256 expectBPTOut = router.queryAddLiquidityUnbalanced( + pool, + exactWrappedAmountsIn, + address(this), + bytes("") + ); + vm.revertTo(snapshot); + + TestBalances memory balancesBefore = _getTestBalances(alice); + + vm.prank(alice); + uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( + pool, + useWrappedTokens, + exactUnderlyingAmountsIn, + 1, + false, + bytes("") + ); + + TestBalances memory balancesAfter = _getTestBalances(alice); + + TestLocals memory vars; + vars.underlyingDaiAmountDelta = 0; + vars.underlyingWethAmountDelta = exactUnderlyingAmountsIn[waWethIdx]; + vars.wrappedDaiPoolDelta = exactWrappedAmountsIn[waDaiIdx]; + vars.wrappedWethPoolDelta = exactWrappedAmountsIn[waWethIdx]; + vars.isPartialERC4626Pool = false; + + _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars, true); assertEq(bptOut, expectBPTOut, "BPT operationAmount should match expected"); assertEq(IERC20(pool).balanceOf(alice), bptOut, "Alice: wrong BPT balance"); @@ -159,7 +208,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) - }(pool, exactUnderlyingAmountsIn, 1, true, bytes("")); + }(pool, new bool[](exactUnderlyingAmountsIn.length), exactUnderlyingAmountsIn, 1, true, bytes("")); TestBalances memory balancesAfter = _getTestBalances(alice); @@ -171,7 +220,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vars.isPartialERC4626Pool = false; vars.wethIsEth = true; - _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars); + _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars, false); assertEq(bptOut, expectBPTOut, "BPT operationAmount should match expected"); assertEq(IERC20(pool).balanceOf(alice), bptOut, "Alice: wrong BPT balance"); @@ -203,6 +252,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( pool, + new bool[](exactUnderlyingAmountsIn.length), exactUnderlyingAmountsIn, 1, false, @@ -218,7 +268,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vars.wrappedWethPoolDelta = exactWrappedAmountsIn[waWethIdx]; vars.isPartialERC4626Pool = false; - _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars); + _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars, false); assertEq(bptOut, expectBPTOut, "BPT operationAmount should match expected"); assertEq(IERC20(pool).balanceOf(alice), bptOut, "Alice: wrong BPT balance"); @@ -247,6 +297,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, + new bool[](exactUnderlyingAmountsIn.length), exactUnderlyingAmountsIn, 0, false, @@ -261,7 +312,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vars.wrappedDaiPoolDelta = exactWrappedAmountsIn[partialWaDaiIdx]; vars.isPartialERC4626Pool = true; - _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars); + _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars, false); assertEq(bptOut, expectBPTOut, "Wrong BPT out"); assertEq(IERC20(address(partialErc4626Pool)).balanceOf(alice), bptOut, "Alice: wrong BPT balance"); @@ -293,7 +344,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) - }(partialErc4626Pool, exactUnderlyingAmountsIn, 0, true, bytes("")); + }( + partialErc4626Pool, + new bool[](exactUnderlyingAmountsIn.length), + exactUnderlyingAmountsIn, + 0, + true, + bytes("") + ); TestBalances memory balancesAfter = _getTestBalances(alice); @@ -304,7 +362,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vars.isPartialERC4626Pool = true; vars.wethIsEth = true; - _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars); + _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars, false); assertEq(bptOut, expectBPTOut, "Wrong BPT out"); assertEq(IERC20(address(partialErc4626Pool)).balanceOf(alice), bptOut, "Alice: wrong BPT balance"); @@ -317,6 +375,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { _prankStaticCall(); compositeLiquidityRouter.queryAddLiquidityUnbalancedToERC4626Pool( pool, + new bool[](exactUnderlyingAmountsIn.length), exactUnderlyingAmountsIn, address(this), bytes("") @@ -331,6 +390,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { _prankStaticCall(); uint256 queryBptAmountOut = compositeLiquidityRouter.queryAddLiquidityUnbalancedToERC4626Pool( pool, + new bool[](exactUnderlyingAmountsIn.length), exactUnderlyingAmountsIn, address(this), bytes("") @@ -340,6 +400,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 actualBptAmountOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( pool, + new bool[](exactUnderlyingAmountsIn.length), exactUnderlyingAmountsIn, 1, false, @@ -357,6 +418,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { _prankStaticCall(); uint256 queryBptAmountOut = compositeLiquidityRouter.queryAddLiquidityUnbalancedToERC4626Pool( pool, + new bool[](exactUnderlyingAmountsIn.length), exactUnderlyingAmountsIn, address(this), bytes("") @@ -366,6 +428,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 actualBptAmountOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( pool, + new bool[](exactUnderlyingAmountsIn.length), exactUnderlyingAmountsIn, 1, false, @@ -383,6 +446,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { _prankStaticCall(); uint256 queryBptAmountOut = compositeLiquidityRouter.queryAddLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, + new bool[](exactUnderlyingAmountsIn.length), exactUnderlyingAmountsIn, address(this), bytes("") @@ -392,6 +456,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 actualBptAmountOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, + new bool[](exactUnderlyingAmountsIn.length), exactUnderlyingAmountsIn, 1, false, @@ -422,6 +487,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( pool, + new bool[](maxAmountsIn.length), maxAmountsIn, exactBptAmountOut, false, @@ -437,7 +503,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vars.wrappedWethPoolDelta = expectedWrappedAmountsIn[waWethIdx]; vars.isPartialERC4626Pool = false; - _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars); + _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars, false); assertEq( actualUnderlyingAmountsIn[waDaiIdx], @@ -477,7 +543,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) - }(pool, maxAmountsIn, exactBptAmountOut, true, bytes("")); + }(pool, new bool[](maxAmountsIn.length), maxAmountsIn, exactBptAmountOut, true, bytes("")); TestBalances memory balancesAfter = _getTestBalances(alice); @@ -489,7 +555,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vars.isPartialERC4626Pool = false; vars.wethIsEth = true; - _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars); + _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars, false); assertEq( actualUnderlyingAmountsIn[waDaiIdx], @@ -534,6 +600,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, + new bool[](maxAmountsIn.length), maxAmountsIn, exactBptAmountOut, false, @@ -548,7 +615,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vars.wrappedDaiPoolDelta = expectedWrappedAmountsIn[partialWaDaiIdx]; vars.isPartialERC4626Pool = true; - _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars); + _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars, false); assertEq( actualUnderlyingAmountsIn[partialWaDaiIdx], @@ -596,7 +663,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) - }(partialErc4626Pool, maxAmountsIn, exactBptAmountOut, true, bytes("")); + }(partialErc4626Pool, new bool[](maxAmountsIn.length), maxAmountsIn, exactBptAmountOut, true, bytes("")); TestBalances memory balancesAfter = _getTestBalances(alice); @@ -607,7 +674,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vars.isPartialERC4626Pool = true; vars.wethIsEth = true; - _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars); + _checkBalancesAfterAddLiquidity(balancesBefore, balancesAfter, vars, false); assertEq( actualUnderlyingAmountsIn[partialWaDaiIdx], @@ -629,6 +696,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { _prankStaticCall(); compositeLiquidityRouter.queryAddLiquidityProportionalToERC4626Pool( pool, + new bool[](2), operationAmount, address(this), bytes("") @@ -667,6 +735,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, + new bool[](maxAmountsIn.length), maxAmountsIn, exactBptAmountOut, false, @@ -683,6 +752,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { _prankStaticCall(); uint256[] memory queryUnderlyingAmountsIn = compositeLiquidityRouter.queryAddLiquidityProportionalToERC4626Pool( pool, + new bool[](maxAmountsIn.length), exactBptAmountOut, address(this), bytes("") @@ -692,6 +762,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( pool, + new bool[](maxAmountsIn.length), maxAmountsIn, exactBptAmountOut, false, @@ -716,6 +787,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { _prankStaticCall(); uint256[] memory queryUnderlyingAmountsIn = compositeLiquidityRouter.queryAddLiquidityProportionalToERC4626Pool( partialErc4626Pool, + new bool[](maxAmountsIn.length), exactBptAmountOut, address(this), bytes("") @@ -725,6 +797,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, + new bool[](maxAmountsIn.length), maxAmountsIn, exactBptAmountOut, false, @@ -767,7 +840,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(bob); uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter - .removeLiquidityProportionalFromERC4626Pool(pool, exactBptAmountIn, minAmountsOut, false, bytes("")); + .removeLiquidityProportionalFromERC4626Pool( + pool, + new bool[](minAmountsOut.length), + exactBptAmountIn, + minAmountsOut, + false, + bytes("") + ); TestBalances memory balancesAfter = _getTestBalances(bob); @@ -778,7 +858,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vars.wrappedWethPoolDelta = expectedWrappedAmountsOut[waWethIdx]; vars.isPartialERC4626Pool = false; - _checkBalancesAfterRemoveLiquidity(balancesBefore, balancesAfter, vars); + _checkBalancesAfterRemoveLiquidity(balancesBefore, balancesAfter, vars, false); assertEq( actualUnderlyingAmountsOut[waDaiIdx], @@ -795,6 +875,67 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { assertEq(afterBPTBalance, beforeBPTBalance - exactBptAmountIn, "Bob: wrong BPT balance"); } + function testRemoveLiquidityProportionalFromERC4626PoolWithWrappedToken__Fuzz(uint256 rawOperationAmount) public { + uint256 exactBptAmountIn = bound(rawOperationAmount, MIN_AMOUNT, bufferInitialAmount / 2); + + uint256 snapshot = vm.snapshot(); + _prankStaticCall(); + uint256[] memory expectedWrappedAmountsOut = router.queryRemoveLiquidityProportional( + pool, + exactBptAmountIn, + address(this), + bytes("") + ); + vm.revertTo(snapshot); + + uint256 beforeBPTBalance = IERC20(pool).balanceOf(bob); + + uint256[] memory minAmountsOut = new uint256[](2); + minAmountsOut[waWethIdx] = _vaultPreviewRedeem(waWETH, expectedWrappedAmountsOut[waWethIdx]); + minAmountsOut[waDaiIdx] = expectedWrappedAmountsOut[waDaiIdx]; + + bool[] memory useWrappedTokens = new bool[](2); + useWrappedTokens[waDaiIdx] = true; + + TestBalances memory balancesBefore = _getTestBalances(bob); + + vm.prank(bob); + uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter + .removeLiquidityProportionalFromERC4626Pool( + pool, + useWrappedTokens, + exactBptAmountIn, + minAmountsOut, + false, + bytes("") + ); + + TestBalances memory balancesAfter = _getTestBalances(bob); + + TestLocals memory vars; + vars.underlyingDaiAmountDelta = 0; + vars.underlyingWethAmountDelta = actualUnderlyingAmountsOut[waWethIdx]; + vars.wrappedDaiPoolDelta = expectedWrappedAmountsOut[waDaiIdx]; + vars.wrappedWethPoolDelta = expectedWrappedAmountsOut[waWethIdx]; + vars.isPartialERC4626Pool = false; + + _checkBalancesAfterRemoveLiquidity(balancesBefore, balancesAfter, vars, true); + + assertEq( + actualUnderlyingAmountsOut[waDaiIdx], + expectedWrappedAmountsOut[waDaiIdx], + "DAI actualUnderlyingAmountsOut should match expected" + ); + assertEq( + actualUnderlyingAmountsOut[waWethIdx], + _vaultPreviewRedeem(waWETH, expectedWrappedAmountsOut[waWethIdx]), + "WETH actualUnderlyingAmountsOut should match expected" + ); + + uint256 afterBPTBalance = IERC20(pool).balanceOf(bob); + assertEq(afterBPTBalance, beforeBPTBalance - exactBptAmountIn, "Bob: wrong BPT balance"); + } + function testRemoveLiquidityProportionalFromERC4626PoolWithEth__Fuzz(uint256 rawOperationAmount) public { uint256 exactBptAmountIn = bound(rawOperationAmount, MIN_AMOUNT, bufferInitialAmount / 2); @@ -818,7 +959,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(bob); uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter - .removeLiquidityProportionalFromERC4626Pool(pool, exactBptAmountIn, minAmountsOut, true, bytes("")); + .removeLiquidityProportionalFromERC4626Pool( + pool, + new bool[](minAmountsOut.length), + exactBptAmountIn, + minAmountsOut, + true, + bytes("") + ); TestBalances memory balancesAfter = _getTestBalances(bob); @@ -830,7 +978,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vars.isPartialERC4626Pool = false; vars.wethIsEth = true; - _checkBalancesAfterRemoveLiquidity(balancesBefore, balancesAfter, vars); + _checkBalancesAfterRemoveLiquidity(balancesBefore, balancesAfter, vars, false); assertEq( actualUnderlyingAmountsOut[waDaiIdx], @@ -872,6 +1020,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, + new bool[](minAmountsOut.length), exactBptAmountIn, minAmountsOut, false, @@ -886,7 +1035,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vars.wrappedDaiPoolDelta = expectedWrappedAmountsOut[partialWaDaiIdx]; vars.isPartialERC4626Pool = true; - _checkBalancesAfterRemoveLiquidity(balancesBefore, balancesAfter, vars); + _checkBalancesAfterRemoveLiquidity(balancesBefore, balancesAfter, vars, false); assertEq( actualUnderlyingAmountsOut[partialWaDaiIdx], @@ -929,6 +1078,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, + new bool[](minAmountsOut.length), exactBptAmountIn, minAmountsOut, true, @@ -944,7 +1094,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vars.isPartialERC4626Pool = true; vars.wethIsEth = true; - _checkBalancesAfterRemoveLiquidity(balancesBefore, balancesAfter, vars); + _checkBalancesAfterRemoveLiquidity(balancesBefore, balancesAfter, vars, false); assertEq( actualUnderlyingAmountsOut[partialWaDaiIdx], @@ -968,6 +1118,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { _prankStaticCall(); compositeLiquidityRouter.queryRemoveLiquidityProportionalFromERC4626Pool( pool, + new bool[](2), exactBptAmountIn, address(this), bytes("") @@ -1003,6 +1154,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(bob); compositeLiquidityRouter.removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, + new bool[](minAmountsOut.length), exactBptAmountIn, minAmountsOut, false, @@ -1030,13 +1182,20 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 snapshotId = vm.snapshot(); _prankStaticCall(); uint256[] memory queryUnderlyingAmountsOut = compositeLiquidityRouter - .queryRemoveLiquidityProportionalFromERC4626Pool(pool, exactBptAmountIn, address(this), bytes("")); + .queryRemoveLiquidityProportionalFromERC4626Pool( + pool, + new bool[](minUnderlyingAmountsOut.length), + exactBptAmountIn, + address(this), + bytes("") + ); vm.revertTo(snapshotId); vm.prank(bob); uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( pool, + new bool[](minUnderlyingAmountsOut.length), exactBptAmountIn, minUnderlyingAmountsOut, false, @@ -1077,6 +1236,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256[] memory queryUnderlyingAmountsOut = compositeLiquidityRouter .queryRemoveLiquidityProportionalFromERC4626Pool( partialErc4626Pool, + new bool[](minUnderlyingAmountsOut.length), exactBptAmountIn, address(this), bytes("") @@ -1087,6 +1247,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, + new bool[](minUnderlyingAmountsOut.length), exactBptAmountIn, minUnderlyingAmountsOut, false, @@ -1133,7 +1294,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { function _checkBalancesAfterAddLiquidity( TestBalances memory balancesBefore, TestBalances memory balancesAfter, - TestLocals memory vars + TestLocals memory vars, + bool useWrappedDai ) private { address ybPool = vars.isPartialERC4626Pool ? partialErc4626Pool : pool; uint256 ybDaiIdx = vars.isPartialERC4626Pool ? partialWaDaiIdx : waDaiIdx; @@ -1162,23 +1324,44 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { ); } - assertEq( - balancesAfter.balances.aliceTokens[balancesAfter.daiIdx], - balancesBefore.balances.aliceTokens[balancesBefore.daiIdx] - vars.underlyingDaiAmountDelta, - "Alice: wrong DAI balance" - ); + if (useWrappedDai == false) { + assertEq( + balancesAfter.balances.aliceTokens[balancesAfter.daiIdx], + balancesBefore.balances.aliceTokens[balancesBefore.daiIdx] - vars.underlyingDaiAmountDelta, + "Alice: wrong DAI balance" + ); - // The underlying tokens are wrapped in the buffer, so the buffer gains underlying and loses wrapped tokens. - assertEq( - balancesAfter.waDAIBuffer.underlying, - balancesBefore.waDAIBuffer.underlying + vars.underlyingDaiAmountDelta, - "Vault: wrong waDAI underlying buffer balance" - ); - assertEq( - balancesAfter.waDAIBuffer.wrapped, - balancesBefore.waDAIBuffer.wrapped - vars.wrappedDaiPoolDelta, - "Vault: wrong waDAI wrapped buffer balance" - ); + // The underlying tokens are wrapped in the buffer, so the buffer gains underlying and loses wrapped tokens. + assertEq( + balancesAfter.waDAIBuffer.underlying, + balancesBefore.waDAIBuffer.underlying + vars.underlyingDaiAmountDelta, + "Vault: wrong waDAI underlying buffer balance" + ); + + assertEq( + balancesAfter.waDAIBuffer.wrapped, + balancesBefore.waDAIBuffer.wrapped - vars.wrappedDaiPoolDelta, + "Vault: wrong waDAI wrapped buffer balance" + ); + } else { + assertEq( + balancesAfter.balances.aliceTokens[balancesAfter.waDaiIdx], + balancesBefore.balances.aliceTokens[balancesBefore.waDaiIdx] - vars.wrappedDaiPoolDelta, + "Alice: wrong DAI balance" + ); + + assertEq( + balancesAfter.waDAIBuffer.underlying, + balancesBefore.waDAIBuffer.underlying, + "Vault: wrong waDAI underlying buffer balance" + ); + + assertEq( + balancesAfter.waDAIBuffer.wrapped, + balancesBefore.waDAIBuffer.wrapped, + "Vault: wrong waDAI wrapped buffer balance" + ); + } // The pool gains the wrapped tokens from the buffer and mints BPT to the user. assertApproxEqAbs( @@ -1228,7 +1411,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { function _checkBalancesAfterRemoveLiquidity( TestBalances memory balancesBefore, TestBalances memory balancesAfter, - TestLocals memory vars + TestLocals memory vars, + bool useWrappedDai ) private { address ybPool = vars.isPartialERC4626Pool ? partialErc4626Pool : pool; uint256 ybDaiIdx = vars.isPartialERC4626Pool ? partialWaDaiIdx : waDaiIdx; @@ -1243,18 +1427,34 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { 2, "ERC4626 Pool: wrong waDAI balance" ); - // The wrapped tokens removed from the pool are unwrapped in the buffer, so the user will receive underlying - // tokens. The buffer loses underlying and gains the wrapped tokens. - assertEq( - balancesAfter.waDAIBuffer.wrapped, - balancesBefore.waDAIBuffer.wrapped + vars.wrappedDaiPoolDelta, - "Vault: wrong waDAI wrapped buffer balance" - ); - assertEq( - balancesAfter.waDAIBuffer.underlying, - balancesBefore.waDAIBuffer.underlying - vars.underlyingDaiAmountDelta, - "Vault: wrong waDAI underlying buffer balance" - ); + + if (useWrappedDai == false) { + // The wrapped tokens removed from the pool are unwrapped in the buffer, so the user will receive underlying + // tokens. The buffer loses underlying and gains the wrapped tokens. + assertEq( + balancesAfter.waDAIBuffer.wrapped, + balancesBefore.waDAIBuffer.wrapped + vars.wrappedDaiPoolDelta, + "Vault: wrong waDAI wrapped buffer balance" + ); + + assertEq( + balancesAfter.waDAIBuffer.underlying, + balancesBefore.waDAIBuffer.underlying - vars.underlyingDaiAmountDelta, + "Vault: wrong waDAI underlying buffer balance" + ); + } else { + assertEq( + balancesAfter.waDAIBuffer.wrapped, + balancesBefore.waDAIBuffer.wrapped, + "Vault: wrong waDAI wrapped buffer balance" + ); + + assertEq( + balancesAfter.waDAIBuffer.underlying, + balancesBefore.waDAIBuffer.underlying, + "Vault: wrong waDAI underlying buffer balance" + ); + } if (vars.isPartialERC4626Pool == false) { // The yield-bearing pool holds yield-bearing tokens, so in a remove liquidity event we remove @@ -1287,12 +1487,21 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { ); } - // When removing liquidity, Bob gets underlying tokens. - assertEq( - balancesAfter.balances.bobTokens[balancesAfter.daiIdx], - balancesBefore.balances.bobTokens[balancesBefore.daiIdx] + vars.underlyingDaiAmountDelta, - "Bob: wrong DAI balance" - ); + if (useWrappedDai == false) { + // When removing liquidity, Bob gets underlying tokens. + assertEq( + balancesAfter.balances.bobTokens[balancesAfter.daiIdx], + balancesBefore.balances.bobTokens[balancesBefore.daiIdx] + vars.underlyingDaiAmountDelta, + "Bob: wrong DAI balance" + ); + } else { + // When removing liquidity, Bob gets wrapped tokens. + assertEq( + balancesAfter.balances.bobTokens[balancesAfter.waDaiIdx], + balancesBefore.balances.bobTokens[balancesBefore.waDaiIdx] + vars.wrappedDaiPoolDelta, + "Bob: wrong DAI balance" + ); + } if (vars.wethIsEth) { assertEq( From 757545a214b612dc75a981cfc34fb5d4e20328c0 Mon Sep 17 00:00:00 2001 From: elshan_eth <22689890+elshan-eth@users.noreply.github.com> Date: Tue, 7 Jan 2025 18:03:03 +0100 Subject: [PATCH 02/30] fix code and tests --- .../contracts/CompositeLiquidityRouter.sol | 136 ++++++++---------- .../.contract-sizes/CompositeLiquidityRouter | 4 +- .../CompositeLiquidityRouterERC4626Pool.t.sol | 68 ++++++--- 3 files changed, 112 insertions(+), 96 deletions(-) diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index 46f25ea65..e8ad4c3eb 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -322,43 +322,34 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo if (useWrappedTokens[i] == true) { amountsOut[i] = wrappedAmountsOut[i]; - if (isStaticCall == false) { - _sendTokenOut(params.sender, erc4626PoolTokens[i], amountsOut[i], params.wethIsEth); - } - continue; - } - // If the Vault returns address 0 as underlying, it means that the ERC4626 token buffer was not - // initialized. Thus, the Router treats it as a non-ERC4626 token. - if (address(underlyingToken) == address(0)) { - if (wrappedAmountsOut[i] < params.minAmountsOut[i]) { - revert IVaultErrors.AmountOutBelowMin( - erc4626PoolTokens[i], - wrappedAmountsOut[i], - params.minAmountsOut[i] - ); + if (amountsOut[i] < params.minAmountsOut[i]) { + revert IVaultErrors.AmountOutBelowMin(erc4626PoolTokens[i], amountsOut[i], params.minAmountsOut[i]); } - amountsOut[i] = wrappedAmountsOut[i]; if (isStaticCall == false) { _sendTokenOut(params.sender, erc4626PoolTokens[i], amountsOut[i], params.wethIsEth); } - continue; - } + } else { + require( + address(underlyingToken) != address(0), + "CompositeLiquidityRouter: ERC4626 buffer not initialized" + ); - // `erc4626BufferWrapOrUnwrap` will fail if the wrappedToken is not ERC4626-conforming. - (, , amountsOut[i]) = _vault.erc4626BufferWrapOrUnwrap( - BufferWrapOrUnwrapParams({ - kind: SwapKind.EXACT_IN, - direction: WrappingDirection.UNWRAP, - wrappedToken: wrappedToken, - amountGivenRaw: wrappedAmountsOut[i], - limitRaw: params.minAmountsOut[i] - }) - ); + // `erc4626BufferWrapOrUnwrap` will fail if the wrappedToken is not ERC4626-conforming. + (, , amountsOut[i]) = _vault.erc4626BufferWrapOrUnwrap( + BufferWrapOrUnwrapParams({ + kind: SwapKind.EXACT_IN, + direction: WrappingDirection.UNWRAP, + wrappedToken: wrappedToken, + amountGivenRaw: wrappedAmountsOut[i], + limitRaw: params.minAmountsOut[i] + }) + ); - if (isStaticCall == false) { - _sendTokenOut(params.sender, underlyingToken, amountsOut[i], params.wethIsEth); + if (isStaticCall == false) { + _sendTokenOut(params.sender, underlyingToken, amountsOut[i], params.wethIsEth); + } } } } @@ -386,61 +377,60 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo if (useWrappedTokens[i] == true) { finalAmountsIn[i] = amountsIn[i]; - _takeTokenIn(params.sender, wrappedToken, finalAmountsIn[i], params.wethIsEth); - continue; - } - // If the Vault returns address 0 as underlying, it means that the ERC4626 token buffer was not - // initialized. Thus, the Router treats it as a non-ERC4626 token. - if (address(underlyingToken) == address(0)) { - if (amountsIn[i] > params.maxAmountsIn[i]) { - revert IVaultErrors.AmountInAboveMax(erc4626PoolTokens[i], amountsIn[i], params.maxAmountsIn[i]); + if (finalAmountsIn[i] > params.maxAmountsIn[i]) { + revert IVaultErrors.AmountInAboveMax( + erc4626PoolTokens[i], + finalAmountsIn[i], + params.maxAmountsIn[i] + ); } - finalAmountsIn[i] = amountsIn[i]; - if (isStaticCall == false) { - _takeTokenIn(params.sender, erc4626PoolTokens[i], amountsIn[i], params.wethIsEth); + _takeTokenIn(params.sender, wrappedToken, finalAmountsIn[i], params.wethIsEth); } + } else { + require( + address(underlyingToken) != address(0), + "CompositeLiquidityRouter: ERC4626 buffer not initialized" + ); - continue; - } + if (isStaticCall == false) { + if (kind == SwapKind.EXACT_IN) { + // If the SwapKind is EXACT_IN, take the exact amount in from the sender. + _takeTokenIn(params.sender, underlyingToken, amountsIn[i], params.wethIsEth); + } else { + // If the SwapKind is EXACT_OUT, the exact amount in is not known, because amountsIn is the + // amount of wrapped tokens. Therefore, take the limit. After the wrap operation, the difference + // between the limit and the actual underlying amount is returned to the sender. + _takeTokenIn(params.sender, underlyingToken, limits[i], params.wethIsEth); + } + } - if (isStaticCall == false) { - if (kind == SwapKind.EXACT_IN) { - // If the SwapKind is EXACT_IN, take the exact amount in from the sender. - _takeTokenIn(params.sender, underlyingToken, amountsIn[i], params.wethIsEth); - } else { - // If the SwapKind is EXACT_OUT, the exact amount in is not known, because amountsIn is the - // amount of wrapped tokens. Therefore, take the limit. After the wrap operation, the difference - // between the limit and the actual underlying amount is returned to the sender. - _takeTokenIn(params.sender, underlyingToken, limits[i], params.wethIsEth); + uint256 underlyingAmount; + uint256 wrappedAmount; + if (amountsIn[i] > 0) { + // `erc4626BufferWrapOrUnwrap` will fail if the wrappedToken isn't ERC4626-conforming. + (, underlyingAmount, wrappedAmount) = _vault.erc4626BufferWrapOrUnwrap( + BufferWrapOrUnwrapParams({ + kind: kind, + direction: WrappingDirection.WRAP, + wrappedToken: wrappedToken, + amountGivenRaw: amountsIn[i], + limitRaw: limits[i] + }) + ); } - } - uint256 underlyingAmount; - uint256 wrappedAmount; - if (amountsIn[i] > 0) { - // `erc4626BufferWrapOrUnwrap` will fail if the wrappedToken isn't ERC4626-conforming. - (, underlyingAmount, wrappedAmount) = _vault.erc4626BufferWrapOrUnwrap( - BufferWrapOrUnwrapParams({ - kind: kind, - direction: WrappingDirection.WRAP, - wrappedToken: wrappedToken, - amountGivenRaw: amountsIn[i], - limitRaw: limits[i] - }) - ); - } + if (isStaticCall == false && kind == SwapKind.EXACT_OUT) { + bool wethIsEth = params.wethIsEth; + // If the SwapKind is EXACT_OUT, the limit of underlying tokens was taken from the user, so the + // difference between limit and exact underlying amount needs to be returned to the sender. + _sendTokenOut(params.sender, underlyingToken, limits[i] - underlyingAmount, wethIsEth); + } - if (isStaticCall == false && kind == SwapKind.EXACT_OUT) { - bool wethIsEth = params.wethIsEth; - // If the SwapKind is EXACT_OUT, the limit of underlying tokens was taken from the user, so the - // difference between limit and exact underlying amount needs to be returned to the sender. - _sendTokenOut(params.sender, underlyingToken, limits[i] - underlyingAmount, wethIsEth); + finalAmountsIn[i] = kind == SwapKind.EXACT_IN ? wrappedAmount : underlyingAmount; } - - finalAmountsIn[i] = kind == SwapKind.EXACT_IN ? wrappedAmount : underlyingAmount; } // If there's a leftover of eth, send it back to the sender. The router should not keep ETH. diff --git a/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter b/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter index 7e609dca6..0e442f50f 100644 --- a/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter +++ b/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter @@ -1,2 +1,2 @@ -Bytecode 21.938 -InitCode 23.749 \ No newline at end of file +Bytecode 21.945 +InitCode 23.757 \ No newline at end of file diff --git a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol index f0688e83d..a85cbaa4c 100644 --- a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol +++ b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol @@ -294,10 +294,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); + bool[] memory useWrappedTokens = new bool[](exactUnderlyingAmountsIn.length); + useWrappedTokens[partialWethIdx] = true; + vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, - new bool[](exactUnderlyingAmountsIn.length), + useWrappedTokens, exactUnderlyingAmountsIn, 0, false, @@ -341,17 +344,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); + bool[] memory useWrappedTokens = new bool[](exactUnderlyingAmountsIn.length); + useWrappedTokens[partialWethIdx] = true; + vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) - }( - partialErc4626Pool, - new bool[](exactUnderlyingAmountsIn.length), - exactUnderlyingAmountsIn, - 0, - true, - bytes("") - ); + }(partialErc4626Pool, useWrappedTokens, exactUnderlyingAmountsIn, 0, true, bytes("")); TestBalances memory balancesAfter = _getTestBalances(alice); @@ -442,11 +441,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 operationAmount = bufferInitialAmount / 2; uint256[] memory exactUnderlyingAmountsIn = [operationAmount, operationAmount].toMemoryArray(); + bool[] memory useWrappedTokens = new bool[](exactUnderlyingAmountsIn.length); + useWrappedTokens[partialWethIdx] = true; + uint256 snapshotId = vm.snapshot(); _prankStaticCall(); uint256 queryBptAmountOut = compositeLiquidityRouter.queryAddLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, - new bool[](exactUnderlyingAmountsIn.length), + useWrappedTokens, exactUnderlyingAmountsIn, address(this), bytes("") @@ -456,7 +458,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 actualBptAmountOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, - new bool[](exactUnderlyingAmountsIn.length), + useWrappedTokens, exactUnderlyingAmountsIn, 1, false, @@ -597,10 +599,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); + bool[] memory useWrappedTokens = new bool[](maxAmountsIn.length); + useWrappedTokens[partialWethIdx] = true; + vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, - new bool[](maxAmountsIn.length), + useWrappedTokens, maxAmountsIn, exactBptAmountOut, false, @@ -660,10 +665,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); + bool[] memory useWrappedTokens = new bool[](maxAmountsIn.length); + useWrappedTokens[partialWethIdx] = true; + vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) - }(partialErc4626Pool, new bool[](maxAmountsIn.length), maxAmountsIn, exactBptAmountOut, true, bytes("")); + }(partialErc4626Pool, useWrappedTokens, maxAmountsIn, exactBptAmountOut, true, bytes("")); TestBalances memory balancesAfter = _getTestBalances(alice); @@ -724,6 +732,9 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { maxAmountsIn[partialWaDaiIdx] = operationAmount; maxAmountsIn[partialWethIdx] = expectedWrappedAmountsIn[partialWethIdx] - 1; + bool[] memory useWrappedTokens = new bool[](maxAmountsIn.length); + useWrappedTokens[partialWethIdx] = true; + vm.expectRevert( abi.encodeWithSelector( IVaultErrors.AmountInAboveMax.selector, @@ -735,7 +746,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, - new bool[](maxAmountsIn.length), + useWrappedTokens, maxAmountsIn, exactBptAmountOut, false, @@ -783,11 +794,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256[] memory maxAmountsIn = [operationAmount, operationAmount].toMemoryArray(); uint256 exactBptAmountOut = operationAmount; + bool[] memory useWrappedTokens = new bool[](maxAmountsIn.length); + useWrappedTokens[partialWethIdx] = true; + uint256 snapshotId = vm.snapshot(); _prankStaticCall(); uint256[] memory queryUnderlyingAmountsIn = compositeLiquidityRouter.queryAddLiquidityProportionalToERC4626Pool( partialErc4626Pool, - new bool[](maxAmountsIn.length), + useWrappedTokens, exactBptAmountOut, address(this), bytes("") @@ -797,7 +811,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, - new bool[](maxAmountsIn.length), + useWrappedTokens, maxAmountsIn, exactBptAmountOut, false, @@ -1016,11 +1030,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); + bool[] memory useWrappedTokens = new bool[](minAmountsOut.length); + useWrappedTokens[partialWethIdx] = true; + vm.prank(bob); uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - new bool[](minAmountsOut.length), + useWrappedTokens, exactBptAmountIn, minAmountsOut, false, @@ -1074,11 +1091,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); + bool[] memory useWrappedTokens = new bool[](minAmountsOut.length); + useWrappedTokens[partialWethIdx] = true; + vm.prank(bob); uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - new bool[](minAmountsOut.length), + useWrappedTokens, exactBptAmountIn, minAmountsOut, true, @@ -1143,6 +1163,9 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { minAmountsOut[partialWethIdx] = expectedWrappedAmountsOut[partialWethIdx] + 1; minAmountsOut[partialWaDaiIdx] = _vaultPreviewRedeem(waDAI, expectedWrappedAmountsOut[partialWaDaiIdx]); + bool[] memory useWrappedTokens = new bool[](minAmountsOut.length); + useWrappedTokens[partialWethIdx] = true; + vm.expectRevert( abi.encodeWithSelector( IVaultErrors.AmountOutBelowMin.selector, @@ -1154,7 +1177,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(bob); compositeLiquidityRouter.removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - new bool[](minAmountsOut.length), + useWrappedTokens, exactBptAmountIn, minAmountsOut, false, @@ -1231,12 +1254,15 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { expectedWrappedAmountsOut[partialWaDaiIdx] ); + bool[] memory useWrappedTokens = new bool[](minUnderlyingAmountsOut.length); + useWrappedTokens[partialWethIdx] = true; + uint256 snapshotId = vm.snapshot(); _prankStaticCall(); uint256[] memory queryUnderlyingAmountsOut = compositeLiquidityRouter .queryRemoveLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - new bool[](minUnderlyingAmountsOut.length), + useWrappedTokens, exactBptAmountIn, address(this), bytes("") @@ -1247,7 +1273,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - new bool[](minUnderlyingAmountsOut.length), + useWrappedTokens, exactBptAmountIn, minUnderlyingAmountsOut, false, From 9dbf7fc8432ea88821ed21109cf95af725da6a69 Mon Sep 17 00:00:00 2001 From: elshan_eth <22689890+elshan-eth@users.noreply.github.com> Date: Wed, 8 Jan 2025 18:56:54 +0100 Subject: [PATCH 03/30] change var name --- .../contracts/CompositeLiquidityRouter.sol | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index e8ad4c3eb..e00bc3a9e 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -359,12 +359,12 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo AddLiquidityHookParams calldata params, bool[] memory useWrappedTokens, IERC20[] memory erc4626PoolTokens, - uint256[] memory amountsIn, + uint256[] memory amountsInRaw, SwapKind kind, uint256[] memory limits - ) private returns (uint256[] memory finalAmountsIn) { + ) private returns (uint256[] memory amountsIn) { uint256 poolTokensLength = erc4626PoolTokens.length; - finalAmountsIn = new uint256[](poolTokensLength); + amountsIn = new uint256[](poolTokensLength); bool isStaticCall = EVMCallModeHelpers.isStaticCall(); @@ -376,18 +376,14 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); if (useWrappedTokens[i] == true) { - finalAmountsIn[i] = amountsIn[i]; + amountsIn[i] = amountsInRaw[i]; - if (finalAmountsIn[i] > params.maxAmountsIn[i]) { - revert IVaultErrors.AmountInAboveMax( - erc4626PoolTokens[i], - finalAmountsIn[i], - params.maxAmountsIn[i] - ); + if (amountsIn[i] > params.maxAmountsIn[i]) { + revert IVaultErrors.AmountInAboveMax(erc4626PoolTokens[i], amountsIn[i], params.maxAmountsIn[i]); } if (isStaticCall == false) { - _takeTokenIn(params.sender, wrappedToken, finalAmountsIn[i], params.wethIsEth); + _takeTokenIn(params.sender, wrappedToken, amountsIn[i], params.wethIsEth); } } else { require( @@ -398,7 +394,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo if (isStaticCall == false) { if (kind == SwapKind.EXACT_IN) { // If the SwapKind is EXACT_IN, take the exact amount in from the sender. - _takeTokenIn(params.sender, underlyingToken, amountsIn[i], params.wethIsEth); + _takeTokenIn(params.sender, underlyingToken, amountsInRaw[i], params.wethIsEth); } else { // If the SwapKind is EXACT_OUT, the exact amount in is not known, because amountsIn is the // amount of wrapped tokens. Therefore, take the limit. After the wrap operation, the difference @@ -409,14 +405,14 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo uint256 underlyingAmount; uint256 wrappedAmount; - if (amountsIn[i] > 0) { + if (amountsInRaw[i] > 0) { // `erc4626BufferWrapOrUnwrap` will fail if the wrappedToken isn't ERC4626-conforming. (, underlyingAmount, wrappedAmount) = _vault.erc4626BufferWrapOrUnwrap( BufferWrapOrUnwrapParams({ kind: kind, direction: WrappingDirection.WRAP, wrappedToken: wrappedToken, - amountGivenRaw: amountsIn[i], + amountGivenRaw: amountsInRaw[i], limitRaw: limits[i] }) ); @@ -429,7 +425,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo _sendTokenOut(params.sender, underlyingToken, limits[i] - underlyingAmount, wethIsEth); } - finalAmountsIn[i] = kind == SwapKind.EXACT_IN ? wrappedAmount : underlyingAmount; + amountsIn[i] = kind == SwapKind.EXACT_IN ? wrappedAmount : underlyingAmount; } } From 4b39b72594e0eaa9a559704dbf5b573c5cc3f65d Mon Sep 17 00:00:00 2001 From: elshan_eth <22689890+elshan-eth@users.noreply.github.com> Date: Thu, 9 Jan 2025 20:29:15 +0100 Subject: [PATCH 04/30] refactoring prepareTokens --- .../contracts/CompositeLiquidityRouter.sol | 135 ++++++++++++------ 1 file changed, 94 insertions(+), 41 deletions(-) diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index e00bc3a9e..c45e67ee6 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -239,13 +239,12 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo // Revert if tokensIn length does not match with maxAmountsIn length. InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length); - uint256[] memory amountsIn = _prepareTokens( - params, + uint256[] memory amountsIn = _wrapTokensExactInIfRequired( + params.sender, useWrappedTokens, erc4626PoolTokens, params.maxAmountsIn, - SwapKind.EXACT_IN, - new uint256[](poolTokensLength) + params.wethIsEth ); // Add wrapped amounts to the ERC4626 pool. @@ -285,13 +284,13 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo }) ); - amountsIn = _prepareTokens( - params, + amountsIn = _wrapTokensExactOutIfRequired( + params.sender, useWrappedTokens, erc4626PoolTokens, wrappedAmountsIn, - SwapKind.EXACT_OUT, - params.maxAmountsIn + params.maxAmountsIn, + params.wethIsEth ); } @@ -355,13 +354,71 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo } /// @dev Assumes array lengths have been checked externally. - function _prepareTokens( - AddLiquidityHookParams calldata params, + function _wrapTokensExactInIfRequired( + address sender, bool[] memory useWrappedTokens, IERC20[] memory erc4626PoolTokens, - uint256[] memory amountsInRaw, - SwapKind kind, - uint256[] memory limits + uint256[] memory amountsIn, + bool wethIsEth + ) private returns (uint256[] memory wrappedAmountsIn) { + uint256 poolTokensLength = erc4626PoolTokens.length; + wrappedAmountsIn = new uint256[](poolTokensLength); + + bool isStaticCall = EVMCallModeHelpers.isStaticCall(); + + // Wrap given underlying tokens for wrapped tokens. + for (uint256 i = 0; i < poolTokensLength; ++i) { + // Treat all ERC4626 pool tokens as wrapped. The next step will verify if we can use the wrappedToken as + // a valid ERC4626. + IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); + IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); + + if (useWrappedTokens[i] == true) { + wrappedAmountsIn[i] = amountsIn[i]; + + if (isStaticCall == false) { + _takeTokenIn(sender, wrappedToken, wrappedAmountsIn[i], wethIsEth); + } + } else { + if (address(underlyingToken) == address(0)) { + revert IVaultErrors.BufferNotInitialized(wrappedToken); + } + + uint256 wrappedAmount; + if (amountsIn[i] > 0) { + if (isStaticCall == false) { + // If the SwapKind is EXACT_IN, take the exact amount in from the sender. + _takeTokenIn(sender, underlyingToken, amountsIn[i], wethIsEth); + } + + // `erc4626BufferWrapOrUnwrap` will fail if the wrappedToken isn't ERC4626-conforming. + (, , wrappedAmount) = _vault.erc4626BufferWrapOrUnwrap( + BufferWrapOrUnwrapParams({ + kind: SwapKind.EXACT_IN, + direction: WrappingDirection.WRAP, + wrappedToken: wrappedToken, + amountGivenRaw: amountsIn[i], + limitRaw: 0 + }) + ); + } + + wrappedAmountsIn[i] = wrappedAmount; + } + } + + // If there's a leftover of eth, send it back to the sender. The router should not keep ETH. + _returnEth(sender); + } + + /// @dev Assumes array lengths have been checked externally. + function _wrapTokensExactOutIfRequired( + address sender, + bool[] memory useWrappedTokens, + IERC20[] memory erc4626PoolTokens, + uint256[] memory wrappedAmountsIn, + uint256[] memory maxAmountsIn, + bool wethIsEth ) private returns (uint256[] memory amountsIn) { uint256 poolTokensLength = erc4626PoolTokens.length; amountsIn = new uint256[](poolTokensLength); @@ -376,61 +433,57 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); if (useWrappedTokens[i] == true) { - amountsIn[i] = amountsInRaw[i]; - - if (amountsIn[i] > params.maxAmountsIn[i]) { - revert IVaultErrors.AmountInAboveMax(erc4626PoolTokens[i], amountsIn[i], params.maxAmountsIn[i]); + if (wrappedAmountsIn[i] > maxAmountsIn[i]) { + revert IVaultErrors.AmountInAboveMax(wrappedToken, wrappedAmountsIn[i], maxAmountsIn[i]); } if (isStaticCall == false) { - _takeTokenIn(params.sender, wrappedToken, amountsIn[i], params.wethIsEth); + _takeTokenIn(sender, wrappedToken, wrappedAmountsIn[i], wethIsEth); } + + amountsIn[i] = wrappedAmountsIn[i]; } else { - require( - address(underlyingToken) != address(0), - "CompositeLiquidityRouter: ERC4626 buffer not initialized" - ); + if (address(underlyingToken) == address(0)) { + revert IVaultErrors.BufferNotInitialized(wrappedToken); + } - if (isStaticCall == false) { - if (kind == SwapKind.EXACT_IN) { - // If the SwapKind is EXACT_IN, take the exact amount in from the sender. - _takeTokenIn(params.sender, underlyingToken, amountsInRaw[i], params.wethIsEth); - } else { + uint256 underlyingAmount; + if (wrappedAmountsIn[i] > 0) { + if (isStaticCall == false) { // If the SwapKind is EXACT_OUT, the exact amount in is not known, because amountsIn is the // amount of wrapped tokens. Therefore, take the limit. After the wrap operation, the difference // between the limit and the actual underlying amount is returned to the sender. - _takeTokenIn(params.sender, underlyingToken, limits[i], params.wethIsEth); + _takeTokenIn(sender, underlyingToken, maxAmountsIn[i], wethIsEth); } - } - uint256 underlyingAmount; - uint256 wrappedAmount; - if (amountsInRaw[i] > 0) { // `erc4626BufferWrapOrUnwrap` will fail if the wrappedToken isn't ERC4626-conforming. - (, underlyingAmount, wrappedAmount) = _vault.erc4626BufferWrapOrUnwrap( + (, underlyingAmount, ) = _vault.erc4626BufferWrapOrUnwrap( BufferWrapOrUnwrapParams({ - kind: kind, + kind: SwapKind.EXACT_OUT, direction: WrappingDirection.WRAP, wrappedToken: wrappedToken, - amountGivenRaw: amountsInRaw[i], - limitRaw: limits[i] + amountGivenRaw: wrappedAmountsIn[i], + limitRaw: maxAmountsIn[i] }) ); } - if (isStaticCall == false && kind == SwapKind.EXACT_OUT) { - bool wethIsEth = params.wethIsEth; + if (underlyingAmount > maxAmountsIn[i]) { + revert IVaultErrors.AmountInAboveMax(underlyingToken, underlyingAmount, maxAmountsIn[i]); + } + + if (isStaticCall == false) { // If the SwapKind is EXACT_OUT, the limit of underlying tokens was taken from the user, so the // difference between limit and exact underlying amount needs to be returned to the sender. - _sendTokenOut(params.sender, underlyingToken, limits[i] - underlyingAmount, wethIsEth); + _sendTokenOut(sender, underlyingToken, maxAmountsIn[i] - underlyingAmount, wethIsEth); } - amountsIn[i] = kind == SwapKind.EXACT_IN ? wrappedAmount : underlyingAmount; + amountsIn[i] = underlyingAmount; } } // If there's a leftover of eth, send it back to the sender. The router should not keep ETH. - _returnEth(params.sender); + _returnEth(sender); } /*************************************************************************** From f6bcd4e280f09dc9e9e0db660fc3d8d0bc209a09 Mon Sep 17 00:00:00 2001 From: elshan_eth <22689890+elshan-eth@users.noreply.github.com> Date: Fri, 10 Jan 2025 14:33:46 +0100 Subject: [PATCH 05/30] fixes --- .../contracts/CompositeLiquidityRouter.sol | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index c45e67ee6..d7d5ace78 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -330,10 +330,9 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo _sendTokenOut(params.sender, erc4626PoolTokens[i], amountsOut[i], params.wethIsEth); } } else { - require( - address(underlyingToken) != address(0), - "CompositeLiquidityRouter: ERC4626 buffer not initialized" - ); + if (address(underlyingToken) == address(0)) { + revert IVaultErrors.BufferNotInitialized(wrappedToken); + } // `erc4626BufferWrapOrUnwrap` will fail if the wrappedToken is not ERC4626-conforming. (, , amountsOut[i]) = _vault.erc4626BufferWrapOrUnwrap( @@ -346,6 +345,10 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo }) ); + if (amountsOut[i] < params.minAmountsOut[i]) { + revert IVaultErrors.AmountOutBelowMin(underlyingToken, amountsOut[i], params.minAmountsOut[i]); + } + if (isStaticCall == false) { _sendTokenOut(params.sender, underlyingToken, amountsOut[i], params.wethIsEth); } @@ -366,13 +369,13 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo bool isStaticCall = EVMCallModeHelpers.isStaticCall(); - // Wrap given underlying tokens for wrapped tokens. for (uint256 i = 0; i < poolTokensLength; ++i) { // Treat all ERC4626 pool tokens as wrapped. The next step will verify if we can use the wrappedToken as // a valid ERC4626. IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); + // if caller wants to use wrapped token, we will use it directly if (useWrappedTokens[i] == true) { wrappedAmountsIn[i] = amountsIn[i]; @@ -387,7 +390,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo uint256 wrappedAmount; if (amountsIn[i] > 0) { if (isStaticCall == false) { - // If the SwapKind is EXACT_IN, take the exact amount in from the sender. + // Take the exact amount in from the sender. _takeTokenIn(sender, underlyingToken, amountsIn[i], wethIsEth); } @@ -425,13 +428,13 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo bool isStaticCall = EVMCallModeHelpers.isStaticCall(); - // Wrap given underlying tokens for wrapped tokens. for (uint256 i = 0; i < poolTokensLength; ++i) { // Treat all ERC4626 pool tokens as wrapped. The next step will verify if we can use the wrappedToken as // a valid ERC4626. IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); + // if caller wants to use wrapped token, we will use it directly if (useWrappedTokens[i] == true) { if (wrappedAmountsIn[i] > maxAmountsIn[i]) { revert IVaultErrors.AmountInAboveMax(wrappedToken, wrappedAmountsIn[i], maxAmountsIn[i]); @@ -450,9 +453,9 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo uint256 underlyingAmount; if (wrappedAmountsIn[i] > 0) { if (isStaticCall == false) { - // If the SwapKind is EXACT_OUT, the exact amount in is not known, because amountsIn is the - // amount of wrapped tokens. Therefore, take the limit. After the wrap operation, the difference - // between the limit and the actual underlying amount is returned to the sender. + // The exact amount in is not known, because we have only + // wrappedAmountsIn. Therefore, take the maxAmountsIn. After the wrap operation, the difference + // between the maxAmountsIn and the actual underlying amount is returned to the sender. _takeTokenIn(sender, underlyingToken, maxAmountsIn[i], wethIsEth); } @@ -473,8 +476,8 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo } if (isStaticCall == false) { - // If the SwapKind is EXACT_OUT, the limit of underlying tokens was taken from the user, so the - // difference between limit and exact underlying amount needs to be returned to the sender. + // The maxAmountsIn of underlying tokens was taken from the user, so the + // difference between maxAmountsIn and exact underlying amount needs to be returned to the sender. _sendTokenOut(sender, underlyingToken, maxAmountsIn[i] - underlyingAmount, wethIsEth); } From 413315d57319a50d1e955d23cb443923e701b19a Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:10:58 +0100 Subject: [PATCH 06/30] Update pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index 2dcfa40ee..6585bb179 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -30,8 +30,8 @@ interface ICompositeLiquidityRouter { * the "parent" pool, and also make sure limits are set properly. * * @param pool Address of the liquidity pool - * @param useWrappedTokens An array indicating whether the input token is a wrapper or underlying token - * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order of + * @param useWrappedTokens An array indicating whether the input token is a wrapped or underlying token + * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order * wrapped tokens in the pool * @param minBptAmountOut Minimum amount of pool tokens to be received * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH From c4419339bb966477f9c9183f64e23e17c605854e Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:11:06 +0100 Subject: [PATCH 07/30] Update pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index 6585bb179..5015501df 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -82,7 +82,7 @@ interface ICompositeLiquidityRouter { * wrapped tokens in the pool * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH * @param userData Additional (optional) data required for removing liquidity - * @return amountsOut Actual amounts of tokens received, sorted in token registration order of wrapped + * @return amountsOut Actual amounts of tokens received, sorted in token registration order * tokens in the pool */ function removeLiquidityProportionalFromERC4626Pool( From 164cdae56a49e89d520b35b8b4e91b48588dd49c Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:11:13 +0100 Subject: [PATCH 08/30] Update pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index 5015501df..3ea242273 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -78,7 +78,7 @@ interface ICompositeLiquidityRouter { * @param pool Address of the liquidity pool * @param useWrappedTokens An array indicating whether the output token is a wrapper or underlying token * @param exactBptAmountIn Exact amount of pool tokens provided - * @param minAmountsOut Minimum amounts of underlying tokens out, sorted in token registration order of + * @param minAmountsOut Minimum amounts of underlying tokens out, sorted in token registration order * wrapped tokens in the pool * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH * @param userData Additional (optional) data required for removing liquidity From 6d7f53822f5576ed9f1705fea69777edd51eea18 Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:11:19 +0100 Subject: [PATCH 09/30] Update pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index 3ea242273..2a12de2b4 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -54,8 +54,8 @@ interface ICompositeLiquidityRouter { * the "parent" pool, and also make sure limits are set properly. * * @param pool Address of the liquidity pool - * @param useWrappedTokens An array indicating whether the input token is a wrapper or underlying token - * @param maxAmountsIn Maximum amounts of underlying/wrapped tokens in, sorted in token registration order of + * @param useWrappedTokens An array indicating whether the input token is a wrappe or underlying token + * @param maxAmountsIn Maximum amounts of underlying/wrapped tokens in, sorted in token registration order * wrapped tokens in the pool * @param exactBptAmountOut Exact amount of pool tokens to be received * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH From c4a26621f87618667c31653cf58e890f9959074c Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:11:25 +0100 Subject: [PATCH 10/30] Update pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index 2a12de2b4..42cdea946 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -98,8 +98,8 @@ interface ICompositeLiquidityRouter { * @notice Queries an `addLiquidityUnbalancedToERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useWrappedTokens An array indicating whether the input token is a wrapper or underlying token - * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order of + * @param useWrappedTokens An array indicating whether the input token is a wrapped or underlying token + * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order * wrapped tokens in the pool * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query From 6b1c8dbcee289e233e1549f0724d4650cf330db4 Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:11:51 +0100 Subject: [PATCH 11/30] Update pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index 42cdea946..a35f65d6f 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -117,7 +117,7 @@ interface ICompositeLiquidityRouter { * @notice Queries an `addLiquidityProportionalToERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useWrappedTokens An array indicating whether the input token is a wrapper or underlying token + * @param useWrappedTokens An array indicating whether the input token is a wrapped or underlying token * @param exactBptAmountOut Exact amount of pool tokens to be received * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query From b0eeb6edeceb74971ef56994b4266c68ea5c25ae Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:20:01 +0100 Subject: [PATCH 12/30] Update pkg/vault/contracts/CompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/vault/contracts/CompositeLiquidityRouter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index d7d5ace78..a8d20ff58 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -430,7 +430,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo for (uint256 i = 0; i < poolTokensLength; ++i) { // Treat all ERC4626 pool tokens as wrapped. The next step will verify if we can use the wrappedToken as - // a valid ERC4626. + // a valid ERC4626. Note that if `useWrappedTokens[i]` is false, we will treat it as a standard token. IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); From 6008eca08c10eca9da6414eab099fc8b9ff592d7 Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:20:06 +0100 Subject: [PATCH 13/30] Update pkg/vault/contracts/CompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/vault/contracts/CompositeLiquidityRouter.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index a8d20ff58..9cb5c95a9 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -236,8 +236,8 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; - // Revert if tokensIn length does not match with maxAmountsIn length. - InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length); + // Revert if `tokensIn` length does not match `maxAmountsIn` and `useWrappedTokens`. + InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, useWrappedTokens.length); uint256[] memory amountsIn = _wrapTokensExactInIfRequired( params.sender, From 06ab630130e4be16c207dedbb281db4dcd669ac4 Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:20:18 +0100 Subject: [PATCH 14/30] Update pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index a35f65d6f..a4a53f35e 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -136,7 +136,7 @@ interface ICompositeLiquidityRouter { * @notice Queries a `removeLiquidityProportionalFromERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useWrappedTokens An array indicating whether the output token is a wrapper or underlying token + * @param useWrappedTokens An array indicating whether the output token is a wrapped or underlying token * @param exactBptAmountIn Exact amount of pool tokens provided for the query * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query From 9fe324249c6cdd1e458489b7ec5ccbaba0d0c653 Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:44:39 +0100 Subject: [PATCH 15/30] Update pkg/vault/contracts/CompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/vault/contracts/CompositeLiquidityRouter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index 9cb5c95a9..618866ce1 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -371,7 +371,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo for (uint256 i = 0; i < poolTokensLength; ++i) { // Treat all ERC4626 pool tokens as wrapped. The next step will verify if we can use the wrappedToken as - // a valid ERC4626. + // a valid ERC4626. Note that if `useWrappedTokens[i]` is false, we will treat it as a standard token. IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); From acac9ec07eaca966ae765718341132a7a07acbbb Mon Sep 17 00:00:00 2001 From: elshan_eth <22689890+elshan-eth@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:49:55 +0100 Subject: [PATCH 16/30] small fixes --- .../vault/ICompositeLiquidityRouter.sol | 24 +++--- .../contracts/CompositeLiquidityRouter.sol | 64 +++++++------- .../CompositeLiquidityRouterERC4626Pool.t.sol | 84 +++++++++---------- 3 files changed, 90 insertions(+), 82 deletions(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index a4a53f35e..9aed6527e 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -30,7 +30,7 @@ interface ICompositeLiquidityRouter { * the "parent" pool, and also make sure limits are set properly. * * @param pool Address of the liquidity pool - * @param useWrappedTokens An array indicating whether the input token is a wrapped or underlying token + * @param isWrappedToken An array indicating whether the input token is a wrapped or underlying token * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order * wrapped tokens in the pool * @param minBptAmountOut Minimum amount of pool tokens to be received @@ -40,7 +40,7 @@ interface ICompositeLiquidityRouter { */ function addLiquidityUnbalancedToERC4626Pool( address pool, - bool[] memory useWrappedTokens, + bool[] memory isWrappedToken, uint256[] memory exactAmountsIn, uint256 minBptAmountOut, bool wethIsEth, @@ -54,7 +54,7 @@ interface ICompositeLiquidityRouter { * the "parent" pool, and also make sure limits are set properly. * * @param pool Address of the liquidity pool - * @param useWrappedTokens An array indicating whether the input token is a wrappe or underlying token + * @param isWrappedToken An array indicating whether the input token is a wrappe or underlying token * @param maxAmountsIn Maximum amounts of underlying/wrapped tokens in, sorted in token registration order * wrapped tokens in the pool * @param exactBptAmountOut Exact amount of pool tokens to be received @@ -65,7 +65,7 @@ interface ICompositeLiquidityRouter { */ function addLiquidityProportionalToERC4626Pool( address pool, - bool[] memory useWrappedTokens, + bool[] memory isWrappedToken, uint256[] memory maxAmountsIn, uint256 exactBptAmountOut, bool wethIsEth, @@ -76,7 +76,7 @@ interface ICompositeLiquidityRouter { * @notice Remove proportional amounts of underlying from an ERC4626 pool, burning an exact pool token amount. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useWrappedTokens An array indicating whether the output token is a wrapper or underlying token + * @param isWrappedToken An array indicating whether the output token is a wrapper or underlying token * @param exactBptAmountIn Exact amount of pool tokens provided * @param minAmountsOut Minimum amounts of underlying tokens out, sorted in token registration order * wrapped tokens in the pool @@ -87,7 +87,7 @@ interface ICompositeLiquidityRouter { */ function removeLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory useWrappedTokens, + bool[] memory isWrappedToken, uint256 exactBptAmountIn, uint256[] memory minAmountsOut, bool wethIsEth, @@ -98,7 +98,7 @@ interface ICompositeLiquidityRouter { * @notice Queries an `addLiquidityUnbalancedToERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useWrappedTokens An array indicating whether the input token is a wrapped or underlying token + * @param isWrappedToken An array indicating whether the input token is a wrapped or underlying token * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order * wrapped tokens in the pool * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) @@ -107,7 +107,7 @@ interface ICompositeLiquidityRouter { */ function queryAddLiquidityUnbalancedToERC4626Pool( address pool, - bool[] memory useWrappedTokens, + bool[] memory isWrappedToken, uint256[] memory exactAmountsIn, address sender, bytes memory userData @@ -117,7 +117,7 @@ interface ICompositeLiquidityRouter { * @notice Queries an `addLiquidityProportionalToERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useWrappedTokens An array indicating whether the input token is a wrapped or underlying token + * @param isWrappedToken An array indicating whether the input token is a wrapped or underlying token * @param exactBptAmountOut Exact amount of pool tokens to be received * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query @@ -126,7 +126,7 @@ interface ICompositeLiquidityRouter { */ function queryAddLiquidityProportionalToERC4626Pool( address pool, - bool[] memory useWrappedTokens, + bool[] memory isWrappedToken, uint256 exactBptAmountOut, address sender, bytes memory userData @@ -136,7 +136,7 @@ interface ICompositeLiquidityRouter { * @notice Queries a `removeLiquidityProportionalFromERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useWrappedTokens An array indicating whether the output token is a wrapped or underlying token + * @param isWrappedToken An array indicating whether the output token is a wrapped or underlying token * @param exactBptAmountIn Exact amount of pool tokens provided for the query * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query @@ -145,7 +145,7 @@ interface ICompositeLiquidityRouter { */ function queryRemoveLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory useWrappedTokens, + bool[] memory isWrappedToken, uint256 exactBptAmountIn, address sender, bytes memory userData diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index 9cb5c95a9..de2b765a8 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.24; -import { IPermit2 } from "permit2/src/interfaces/IPermit2.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { IPermit2 } from "permit2/src/interfaces/IPermit2.sol"; import { ICompositeLiquidityRouter } from "@balancer-labs/v3-interfaces/contracts/vault/ICompositeLiquidityRouter.sol"; import { IVaultErrors } from "@balancer-labs/v3-interfaces/contracts/vault/IVaultErrors.sol"; @@ -48,7 +48,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function addLiquidityUnbalancedToERC4626Pool( address pool, - bool[] memory useWrappedTokens, + bool[] memory isWrappedToken, uint256[] memory exactAmountsIn, uint256 minBptAmountOut, bool wethIsEth, @@ -68,7 +68,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: wethIsEth, userData: userData }), - useWrappedTokens + isWrappedToken ) ) ), @@ -79,7 +79,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function addLiquidityProportionalToERC4626Pool( address pool, - bool[] memory useWrappedTokens, + bool[] memory isWrappedToken, uint256[] memory maxAmountsIn, uint256 exactBptAmountOut, bool wethIsEth, @@ -99,7 +99,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: wethIsEth, userData: userData }), - useWrappedTokens + isWrappedToken ) ) ), @@ -110,7 +110,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function removeLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory useWrappedTokens, + bool[] memory isWrappedToken, uint256 exactBptAmountIn, uint256[] memory minAmountsOut, bool wethIsEth, @@ -130,7 +130,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: wethIsEth, userData: userData }), - useWrappedTokens + isWrappedToken ) ) ), @@ -141,7 +141,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function queryAddLiquidityUnbalancedToERC4626Pool( address pool, - bool[] memory useWrappedTokens, + bool[] memory isWrappedToken, uint256[] memory exactAmountsIn, address sender, bytes memory userData @@ -160,7 +160,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: false, userData: userData }), - useWrappedTokens + isWrappedToken ) ) ), @@ -171,7 +171,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function queryAddLiquidityProportionalToERC4626Pool( address pool, - bool[] memory useWrappedTokens, + bool[] memory isWrappedToken, uint256 exactBptAmountOut, address sender, bytes memory userData @@ -190,7 +190,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: false, userData: userData }), - useWrappedTokens + isWrappedToken ) ) ), @@ -201,7 +201,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function queryRemoveLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory useWrappedTokens, + bool[] memory isWrappedToken, uint256 exactBptAmountIn, address sender, bytes memory userData @@ -221,7 +221,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: false, userData: userData }), - useWrappedTokens + isWrappedToken ) ) ), @@ -231,17 +231,17 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo function addLiquidityERC4626PoolUnbalancedHook( AddLiquidityHookParams calldata params, - bool[] calldata useWrappedTokens + bool[] calldata isWrappedToken ) external nonReentrant onlyVault returns (uint256 bptAmountOut) { IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; - // Revert if `tokensIn` length does not match `maxAmountsIn` and `useWrappedTokens`. - InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, useWrappedTokens.length); + // Revert if `tokensIn` length does not match `maxAmountsIn` and `isWrappedToken`. + InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, isWrappedToken.length); uint256[] memory amountsIn = _wrapTokensExactInIfRequired( params.sender, - useWrappedTokens, + isWrappedToken, erc4626PoolTokens, params.maxAmountsIn, params.wethIsEth @@ -262,8 +262,11 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo function addLiquidityERC4626PoolProportionalHook( AddLiquidityHookParams calldata params, - bool[] calldata useWrappedTokens + bool[] calldata isWrappedToken ) external nonReentrant onlyVault returns (uint256[] memory amountsIn) { + // Revert if `tokensIn` length does not match `maxAmountsIn` and `useWrappedTokens`. + InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, useWrappedTokens.length); + IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; @@ -286,7 +289,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo amountsIn = _wrapTokensExactOutIfRequired( params.sender, - useWrappedTokens, + isWrappedToken, erc4626PoolTokens, wrappedAmountsIn, params.maxAmountsIn, @@ -296,8 +299,11 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo function removeLiquidityERC4626PoolProportionalHook( RemoveLiquidityHookParams calldata params, - bool[] calldata useWrappedTokens + bool[] calldata isWrappedToken ) external nonReentrant onlyVault returns (uint256[] memory amountsOut) { + // Revert if `tokensOut` length does not match `minAmountsOut` and `useWrappedTokens`. + InputHelpers.ensureInputLengthMatch(poolTokensLength, params.minAmountsOut.length, useWrappedTokens.length); + IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; amountsOut = new uint256[](poolTokensLength); @@ -319,7 +325,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); - if (useWrappedTokens[i] == true) { + if (isWrappedToken[i]) { amountsOut[i] = wrappedAmountsOut[i]; if (amountsOut[i] < params.minAmountsOut[i]) { @@ -359,7 +365,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @dev Assumes array lengths have been checked externally. function _wrapTokensExactInIfRequired( address sender, - bool[] memory useWrappedTokens, + bool[] memory isWrappedToken, IERC20[] memory erc4626PoolTokens, uint256[] memory amountsIn, bool wethIsEth @@ -375,8 +381,9 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); - // if caller wants to use wrapped token, we will use it directly - if (useWrappedTokens[i] == true) { + // Check whether the caller wants to use the token as an ERC4626 (i.e., wrap/unwrap it), or just use it as + // a standard token. + if (isWrappedToken[i]) { wrappedAmountsIn[i] = amountsIn[i]; if (isStaticCall == false) { @@ -417,7 +424,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @dev Assumes array lengths have been checked externally. function _wrapTokensExactOutIfRequired( address sender, - bool[] memory useWrappedTokens, + bool[] memory isWrappedToken, IERC20[] memory erc4626PoolTokens, uint256[] memory wrappedAmountsIn, uint256[] memory maxAmountsIn, @@ -430,12 +437,13 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo for (uint256 i = 0; i < poolTokensLength; ++i) { // Treat all ERC4626 pool tokens as wrapped. The next step will verify if we can use the wrappedToken as - // a valid ERC4626. Note that if `useWrappedTokens[i]` is false, we will treat it as a standard token. + // a valid ERC4626. Note that if `isWrappedToken[i]` is false, we will treat it as a standard token. IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); - // if caller wants to use wrapped token, we will use it directly - if (useWrappedTokens[i] == true) { + // Check whether the caller wants to use the token as an ERC4626 (i.e., wrap/unwrap it), or just use it as + // a standard token. + if (isWrappedToken[i]) { if (wrappedAmountsIn[i] > maxAmountsIn[i]) { revert IVaultErrors.AmountInAboveMax(wrappedToken, wrappedAmountsIn[i], maxAmountsIn[i]); } diff --git a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol index a85cbaa4c..7ae6fad27 100644 --- a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol +++ b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol @@ -142,8 +142,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { exactWrappedAmountsIn[waDaiIdx] = operationAmount; exactWrappedAmountsIn[waWethIdx] = _vaultPreviewDeposit(waWETH, operationAmount); - bool[] memory useWrappedTokens = new bool[](exactUnderlyingAmountsIn.length); - useWrappedTokens[waDaiIdx] = true; + bool[] memory isWrappedToken = new bool[](exactUnderlyingAmountsIn.length); + isWrappedToken[waDaiIdx] = true; uint256 snapshot = vm.snapshot(); _prankStaticCall(); @@ -160,7 +160,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( pool, - useWrappedTokens, + isWrappedToken, exactUnderlyingAmountsIn, 1, false, @@ -294,13 +294,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory useWrappedTokens = new bool[](exactUnderlyingAmountsIn.length); - useWrappedTokens[partialWethIdx] = true; + bool[] memory isWrappedToken = new bool[](exactUnderlyingAmountsIn.length); + isWrappedToken[partialWethIdx] = true; vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, - useWrappedTokens, + isWrappedToken, exactUnderlyingAmountsIn, 0, false, @@ -344,13 +344,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory useWrappedTokens = new bool[](exactUnderlyingAmountsIn.length); - useWrappedTokens[partialWethIdx] = true; + bool[] memory isWrappedToken = new bool[](exactUnderlyingAmountsIn.length); + isWrappedToken[partialWethIdx] = true; vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) - }(partialErc4626Pool, useWrappedTokens, exactUnderlyingAmountsIn, 0, true, bytes("")); + }(partialErc4626Pool, isWrappedToken, exactUnderlyingAmountsIn, 0, true, bytes("")); TestBalances memory balancesAfter = _getTestBalances(alice); @@ -441,14 +441,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 operationAmount = bufferInitialAmount / 2; uint256[] memory exactUnderlyingAmountsIn = [operationAmount, operationAmount].toMemoryArray(); - bool[] memory useWrappedTokens = new bool[](exactUnderlyingAmountsIn.length); - useWrappedTokens[partialWethIdx] = true; + bool[] memory isWrappedToken = new bool[](exactUnderlyingAmountsIn.length); + isWrappedToken[partialWethIdx] = true; uint256 snapshotId = vm.snapshot(); _prankStaticCall(); uint256 queryBptAmountOut = compositeLiquidityRouter.queryAddLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, - useWrappedTokens, + isWrappedToken, exactUnderlyingAmountsIn, address(this), bytes("") @@ -458,7 +458,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 actualBptAmountOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, - useWrappedTokens, + isWrappedToken, exactUnderlyingAmountsIn, 1, false, @@ -599,13 +599,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory useWrappedTokens = new bool[](maxAmountsIn.length); - useWrappedTokens[partialWethIdx] = true; + bool[] memory isWrappedToken = new bool[](maxAmountsIn.length); + isWrappedToken[partialWethIdx] = true; vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, - useWrappedTokens, + isWrappedToken, maxAmountsIn, exactBptAmountOut, false, @@ -665,13 +665,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory useWrappedTokens = new bool[](maxAmountsIn.length); - useWrappedTokens[partialWethIdx] = true; + bool[] memory isWrappedToken = new bool[](maxAmountsIn.length); + isWrappedToken[partialWethIdx] = true; vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) - }(partialErc4626Pool, useWrappedTokens, maxAmountsIn, exactBptAmountOut, true, bytes("")); + }(partialErc4626Pool, isWrappedToken, maxAmountsIn, exactBptAmountOut, true, bytes("")); TestBalances memory balancesAfter = _getTestBalances(alice); @@ -732,8 +732,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { maxAmountsIn[partialWaDaiIdx] = operationAmount; maxAmountsIn[partialWethIdx] = expectedWrappedAmountsIn[partialWethIdx] - 1; - bool[] memory useWrappedTokens = new bool[](maxAmountsIn.length); - useWrappedTokens[partialWethIdx] = true; + bool[] memory isWrappedToken = new bool[](maxAmountsIn.length); + isWrappedToken[partialWethIdx] = true; vm.expectRevert( abi.encodeWithSelector( @@ -746,7 +746,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, - useWrappedTokens, + isWrappedToken, maxAmountsIn, exactBptAmountOut, false, @@ -794,14 +794,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256[] memory maxAmountsIn = [operationAmount, operationAmount].toMemoryArray(); uint256 exactBptAmountOut = operationAmount; - bool[] memory useWrappedTokens = new bool[](maxAmountsIn.length); - useWrappedTokens[partialWethIdx] = true; + bool[] memory isWrappedToken = new bool[](maxAmountsIn.length); + isWrappedToken[partialWethIdx] = true; uint256 snapshotId = vm.snapshot(); _prankStaticCall(); uint256[] memory queryUnderlyingAmountsIn = compositeLiquidityRouter.queryAddLiquidityProportionalToERC4626Pool( partialErc4626Pool, - useWrappedTokens, + isWrappedToken, exactBptAmountOut, address(this), bytes("") @@ -811,7 +811,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, - useWrappedTokens, + isWrappedToken, maxAmountsIn, exactBptAmountOut, false, @@ -908,8 +908,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { minAmountsOut[waWethIdx] = _vaultPreviewRedeem(waWETH, expectedWrappedAmountsOut[waWethIdx]); minAmountsOut[waDaiIdx] = expectedWrappedAmountsOut[waDaiIdx]; - bool[] memory useWrappedTokens = new bool[](2); - useWrappedTokens[waDaiIdx] = true; + bool[] memory isWrappedToken = new bool[](2); + isWrappedToken[waDaiIdx] = true; TestBalances memory balancesBefore = _getTestBalances(bob); @@ -917,7 +917,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( pool, - useWrappedTokens, + isWrappedToken, exactBptAmountIn, minAmountsOut, false, @@ -1030,14 +1030,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); - bool[] memory useWrappedTokens = new bool[](minAmountsOut.length); - useWrappedTokens[partialWethIdx] = true; + bool[] memory isWrappedToken = new bool[](minAmountsOut.length); + isWrappedToken[partialWethIdx] = true; vm.prank(bob); uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - useWrappedTokens, + isWrappedToken, exactBptAmountIn, minAmountsOut, false, @@ -1091,14 +1091,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); - bool[] memory useWrappedTokens = new bool[](minAmountsOut.length); - useWrappedTokens[partialWethIdx] = true; + bool[] memory isWrappedToken = new bool[](minAmountsOut.length); + isWrappedToken[partialWethIdx] = true; vm.prank(bob); uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - useWrappedTokens, + isWrappedToken, exactBptAmountIn, minAmountsOut, true, @@ -1163,8 +1163,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { minAmountsOut[partialWethIdx] = expectedWrappedAmountsOut[partialWethIdx] + 1; minAmountsOut[partialWaDaiIdx] = _vaultPreviewRedeem(waDAI, expectedWrappedAmountsOut[partialWaDaiIdx]); - bool[] memory useWrappedTokens = new bool[](minAmountsOut.length); - useWrappedTokens[partialWethIdx] = true; + bool[] memory isWrappedToken = new bool[](minAmountsOut.length); + isWrappedToken[partialWethIdx] = true; vm.expectRevert( abi.encodeWithSelector( @@ -1177,7 +1177,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(bob); compositeLiquidityRouter.removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - useWrappedTokens, + isWrappedToken, exactBptAmountIn, minAmountsOut, false, @@ -1254,15 +1254,15 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { expectedWrappedAmountsOut[partialWaDaiIdx] ); - bool[] memory useWrappedTokens = new bool[](minUnderlyingAmountsOut.length); - useWrappedTokens[partialWethIdx] = true; + bool[] memory isWrappedToken = new bool[](minUnderlyingAmountsOut.length); + isWrappedToken[partialWethIdx] = true; uint256 snapshotId = vm.snapshot(); _prankStaticCall(); uint256[] memory queryUnderlyingAmountsOut = compositeLiquidityRouter .queryRemoveLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - useWrappedTokens, + isWrappedToken, exactBptAmountIn, address(this), bytes("") @@ -1273,7 +1273,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - useWrappedTokens, + isWrappedToken, exactBptAmountIn, minUnderlyingAmountsOut, false, From cf437026284aac73a82c6953d5bc51d13d717e3e Mon Sep 17 00:00:00 2001 From: elshan_eth <22689890+elshan-eth@users.noreply.github.com> Date: Mon, 13 Jan 2025 19:02:18 +0100 Subject: [PATCH 17/30] fixes --- ...swapExactIn - with buffer liquidity - warm slots | 2 +- ... swapExactOut - no buffer liquidity - warm slots | 2 +- ...wapExactOut - with buffer liquidity - warm slots | 2 +- ...uidity unbalanced using swapExactIn - warm slots | 2 +- ...r] add liquidity using swapExactOur - warm slots | 2 +- ...remove liquidity using swapExactOut - warm slots | 2 +- ...ap exact in with one token and fees - cold slots | 2 +- ...tablePool - Standard] add liquidity proportional | 2 +- ...dd liquidity single token exact out - warm slots | 2 +- .../[StablePool - Standard] donation | 2 +- .../[StablePool - Standard] initialize with ETH | 2 +- .../[StablePool - Standard] initialize without ETH | 2 +- ...lePool - Standard] remove liquidity proportional | 2 +- ...ove liquidity single token exact in - warm slots | 2 +- ...wap single token exact in with fees - cold slots | 2 +- ...wap single token exact in with fees - warm slots | 2 +- ...ool - BatchRouter] swap exact in - tokenA-tokenD | 2 +- ...uidity unbalanced using swapExactIn - warm slots | 2 +- ...r] add liquidity using swapExactOur - warm slots | 2 +- ... remove liquidity using swapExactIn - warm slots | 2 +- ...ap exact in with one token and fees - cold slots | 2 +- ...tablePool - WithRate] add liquidity proportional | 2 +- ...dd liquidity single token exact out - warm slots | 2 +- ... WithRate] add liquidity unbalanced - warm slots | 2 +- ...lePool - WithRate] remove liquidity proportional | 2 +- ...ove liquidity single token exact in - warm slots | 2 +- ...ve liquidity single token exact out - warm slots | 2 +- ...wap single token exact in with fees - cold slots | 2 +- ...wap single token exact in with fees - warm slots | 2 +- ...wapExactOut - with buffer liquidity - warm slots | 2 +- ...r] add liquidity using swapExactOur - warm slots | 2 +- ...remove liquidity using swapExactOut - warm slots | 2 +- ...ap exact in with one token and fees - cold slots | 2 +- ...ap exact in with one token and fees - warm slots | 2 +- ...ghtedPool - Standard] add liquidity proportional | 2 +- ...dd liquidity single token exact out - warm slots | 2 +- ... Standard] add liquidity unbalanced - warm slots | 2 +- .../[WeightedPool - Standard] donation | 2 +- .../[WeightedPool - Standard] initialize with ETH | 2 +- ...[WeightedPool - Standard] initialize without ETH | 2 +- ...edPool - Standard] remove liquidity proportional | 2 +- ...ove liquidity single token exact in - warm slots | 2 +- ...ve liquidity single token exact out - warm slots | 2 +- ...wap single token exact in with fees - cold slots | 2 +- ...wap single token exact in with fees - warm slots | 2 +- ...r] add liquidity using swapExactOur - warm slots | 2 +- ... remove liquidity using swapExactIn - warm slots | 2 +- ...remove liquidity using swapExactOut - warm slots | 2 +- ...ghtedPool - WithRate] add liquidity proportional | 2 +- ...dd liquidity single token exact out - warm slots | 2 +- ... WithRate] add liquidity unbalanced - warm slots | 2 +- ...ove liquidity single token exact in - warm slots | 2 +- ...ve liquidity single token exact out - warm slots | 2 +- ...wap single token exact in with fees - cold slots | 2 +- ...wap single token exact in with fees - warm slots | 2 +- pkg/vault/contracts/CompositeLiquidityRouter.sol | 13 +++++++------ 56 files changed, 62 insertions(+), 61 deletions(-) diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactIn - with buffer liquidity - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactIn - with buffer liquidity - warm slots index 1afba7063..3c6ece1ca 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactIn - with buffer liquidity - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactIn - with buffer liquidity - warm slots @@ -1 +1 @@ -245.0k \ No newline at end of file +245.1k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - no buffer liquidity - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - no buffer liquidity - warm slots index cba6a2769..24bbfa4e3 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - no buffer liquidity - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - no buffer liquidity - warm slots @@ -1 +1 @@ -334.6k \ No newline at end of file +334.7k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots index 8f7230cba..c1495e78b 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots @@ -1 +1 @@ -258.4k \ No newline at end of file +258.5k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots index 9dd99b8b4..dbba43d6f 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots @@ -1 +1 @@ -196.3k \ No newline at end of file +196.4k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots index cc6877811..9f03a77e5 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots @@ -1 +1 @@ -180.8k \ No newline at end of file +180.9k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots index 8d0a3504f..2e853f7ae 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots @@ -1 +1 @@ -209.8k \ No newline at end of file +209.9k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] swap exact in with one token and fees - cold slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] swap exact in with one token and fees - cold slots index 850b54988..cf1fe3b12 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] swap exact in with one token and fees - cold slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] swap exact in with one token and fees - cold slots @@ -1 +1 @@ -194.5k \ No newline at end of file +194.6k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity proportional b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity proportional index 32a6c77e7..184d05cb6 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity proportional +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity proportional @@ -1 +1 @@ -179.2k \ No newline at end of file +179.3k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity single token exact out - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity single token exact out - warm slots index eec4e69d4..43e844943 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity single token exact out - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity single token exact out - warm slots @@ -1 +1 @@ -172.1k \ No newline at end of file +172.2k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] donation b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] donation index 5f4b8010a..e1c39f087 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] donation +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] donation @@ -1 +1 @@ -171.0k \ No newline at end of file +171.1k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize with ETH b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize with ETH index 7faabe4fc..d5ce4e317 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize with ETH +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize with ETH @@ -1 +1 @@ -347.9k \ No newline at end of file +348.3k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize without ETH b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize without ETH index 02b7f4b6d..8d41f35e7 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize without ETH +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize without ETH @@ -1 +1 @@ -335.4k \ No newline at end of file +335.8k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity proportional b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity proportional index 60bcf4864..abc6469ef 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity proportional +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity proportional @@ -1 +1 @@ -167.1k \ No newline at end of file +167.2k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity single token exact in - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity single token exact in - warm slots index 0be376f1e..c7e7b4544 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity single token exact in - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity single token exact in - warm slots @@ -1 +1 @@ -166.4k \ No newline at end of file +166.5k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - cold slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - cold slots index 68b670a11..34e80eef2 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - cold slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - cold slots @@ -1 +1 @@ -178.8k \ No newline at end of file +178.9k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - warm slots index 77bc6d810..28fbaf434 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - warm slots @@ -1 +1 @@ -164.9k \ No newline at end of file +165.0k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithNestedPool - BatchRouter] swap exact in - tokenA-tokenD b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithNestedPool - BatchRouter] swap exact in - tokenA-tokenD index 722192bb8..4aa3cb8e1 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithNestedPool - BatchRouter] swap exact in - tokenA-tokenD +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithNestedPool - BatchRouter] swap exact in - tokenA-tokenD @@ -1 +1 @@ -558.6k \ No newline at end of file +558.7k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots index beb043c93..007fed429 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots @@ -1 +1 @@ -217.7k \ No newline at end of file +217.8k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots index 4b78b5ecf..804746be2 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots @@ -1 +1 @@ -202.2k \ No newline at end of file +202.3k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots index 11eae2457..6a6d4e231 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots @@ -1 +1 @@ -211.9k \ No newline at end of file +212.0k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] swap exact in with one token and fees - cold slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] swap exact in with one token and fees - cold slots index 5b0408bcc..4c4616edc 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] swap exact in with one token and fees - cold slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] swap exact in with one token and fees - cold slots @@ -1 +1 @@ -227.6k \ No newline at end of file +227.7k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity proportional b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity proportional index d4f0a3a17..0718ec32c 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity proportional +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity proportional @@ -1 +1 @@ -234.3k \ No newline at end of file +234.4k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity single token exact out - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity single token exact out - warm slots index ad087e174..7c6a6731a 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity single token exact out - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity single token exact out - warm slots @@ -1 +1 @@ -193.5k \ No newline at end of file +193.6k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity unbalanced - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity unbalanced - warm slots index 69b363ada..43f1f83db 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity unbalanced - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity unbalanced - warm slots @@ -1 +1 @@ -230.5k \ No newline at end of file +230.6k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity proportional b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity proportional index c4f48aed1..01db6fe9f 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity proportional +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity proportional @@ -1 +1 @@ -222.1k \ No newline at end of file +222.2k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact in - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact in - warm slots index 0d3d71a36..a1a745b5f 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact in - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact in - warm slots @@ -1 +1 @@ -187.7k \ No newline at end of file +187.8k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact out - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact out - warm slots index 47f39a685..04c51970a 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact out - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact out - warm slots @@ -1 +1 @@ -198.1k \ No newline at end of file +198.2k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - cold slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - cold slots index 11eae2457..6a6d4e231 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - cold slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - cold slots @@ -1 +1 @@ -211.9k \ No newline at end of file +212.0k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - warm slots index 9f03a77e5..bba55110e 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - warm slots @@ -1 +1 @@ -180.9k \ No newline at end of file +181.0k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots index 5e97e74e1..74805369f 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots @@ -1 +1 @@ -244.7k \ No newline at end of file +244.8k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots index abc6469ef..eba3d018d 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots @@ -1 +1 @@ -167.2k \ No newline at end of file +167.3k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots index 2937f7eca..33862ebdb 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots @@ -1 +1 @@ -208.9k \ No newline at end of file +209.0k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - cold slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - cold slots index 9078b2e18..dc58fb784 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - cold slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - cold slots @@ -1 +1 @@ -184.0k \ No newline at end of file +184.1k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - warm slots index f1c01191f..b6426f9ae 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - warm slots @@ -1 +1 @@ -166.9k \ No newline at end of file +167.0k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity proportional b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity proportional index 32a6c77e7..184d05cb6 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity proportional +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity proportional @@ -1 +1 @@ -179.2k \ No newline at end of file +179.3k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity single token exact out - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity single token exact out - warm slots index 7eca5dd03..235d9b73c 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity single token exact out - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity single token exact out - warm slots @@ -1 +1 @@ -158.5k \ No newline at end of file +158.6k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity unbalanced - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity unbalanced - warm slots index 85f89ffc8..330ac4a8c 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity unbalanced - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity unbalanced - warm slots @@ -1 +1 @@ -212.2k \ No newline at end of file +212.3k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] donation b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] donation index 5f4b8010a..e1c39f087 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] donation +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] donation @@ -1 +1 @@ -171.0k \ No newline at end of file +171.1k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize with ETH b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize with ETH index 13e58083b..6b56207f8 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize with ETH +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize with ETH @@ -1 +1 @@ -348.8k \ No newline at end of file +349.3k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize without ETH b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize without ETH index 3958ab300..d79069749 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize without ETH +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize without ETH @@ -1 +1 @@ -336.4k \ No newline at end of file +336.8k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity proportional b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity proportional index 60bcf4864..abc6469ef 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity proportional +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity proportional @@ -1 +1 @@ -167.1k \ No newline at end of file +167.2k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact in - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact in - warm slots index 896629134..ecea21dfe 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact in - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact in - warm slots @@ -1 +1 @@ -152.8k \ No newline at end of file +152.9k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact out - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact out - warm slots index 5c1048bec..281d84625 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact out - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact out - warm slots @@ -1 +1 @@ -176.1k \ No newline at end of file +176.2k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - cold slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - cold slots index 7f24db840..fcaa01729 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - cold slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - cold slots @@ -1 +1 @@ -168.3k \ No newline at end of file +168.4k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - warm slots index a794c44b2..1d32b9dab 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - warm slots @@ -1 +1 @@ -151.2k \ No newline at end of file +151.3k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots index a6a4e56f4..cdf9810ea 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots @@ -1 +1 @@ -188.6k \ No newline at end of file +188.7k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots index 04c51970a..a5dc1053f 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots @@ -1 +1 @@ -198.2k \ No newline at end of file +198.3k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactOut - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactOut - warm slots index fc0174c73..1e3020238 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactOut - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactOut - warm slots @@ -1 +1 @@ -230.2k \ No newline at end of file +230.3k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity proportional b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity proportional index d4f0a3a17..0718ec32c 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity proportional +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity proportional @@ -1 +1 @@ -234.3k \ No newline at end of file +234.4k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity single token exact out - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity single token exact out - warm slots index a87088349..438d6c8b8 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity single token exact out - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity single token exact out - warm slots @@ -1 +1 @@ -179.9k \ No newline at end of file +180.0k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity unbalanced - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity unbalanced - warm slots index 6f08b2604..15b423cf0 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity unbalanced - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity unbalanced - warm slots @@ -1 +1 @@ -228.6k \ No newline at end of file +228.7k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact in - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact in - warm slots index d3fa14d41..61e5d8518 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact in - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact in - warm slots @@ -1 +1 @@ -174.0k \ No newline at end of file +174.1k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact out - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact out - warm slots index e25cfa980..c041f7749 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact out - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact out - warm slots @@ -1 +1 @@ -197.4k \ No newline at end of file +197.5k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - cold slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - cold slots index ff670bcec..eaaca87af 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - cold slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - cold slots @@ -1 +1 @@ -201.4k \ No newline at end of file +201.5k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - warm slots index abc6469ef..eba3d018d 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - warm slots @@ -1 +1 @@ -167.2k \ No newline at end of file +167.3k \ No newline at end of file diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index e6083dbef..f2bc0966c 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -264,12 +264,12 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo AddLiquidityHookParams calldata params, bool[] calldata isWrappedToken ) external nonReentrant onlyVault returns (uint256[] memory amountsIn) { - // Revert if `tokensIn` length does not match `maxAmountsIn` and `useWrappedTokens`. - InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, useWrappedTokens.length); - IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; + // Revert if `tokensIn` length does not match `maxAmountsIn` and `isWrappedToken`. + InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, isWrappedToken.length); + uint256[] memory maxAmounts = new uint256[](poolTokensLength); for (uint256 i = 0; i < poolTokensLength; ++i) { maxAmounts[i] = _MAX_AMOUNT; @@ -301,11 +301,12 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo RemoveLiquidityHookParams calldata params, bool[] calldata isWrappedToken ) external nonReentrant onlyVault returns (uint256[] memory amountsOut) { - // Revert if `tokensOut` length does not match `minAmountsOut` and `useWrappedTokens`. - InputHelpers.ensureInputLengthMatch(poolTokensLength, params.minAmountsOut.length, useWrappedTokens.length); - IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; + + // Revert if `tokensOut` length does not match `minAmountsOut` and `isWrappedToken`. + InputHelpers.ensureInputLengthMatch(poolTokensLength, params.minAmountsOut.length, isWrappedToken.length); + amountsOut = new uint256[](poolTokensLength); (, uint256[] memory wrappedAmountsOut, ) = _vault.removeLiquidity( From af63d706fe2991b42ce3eb0b7003e17a34242040 Mon Sep 17 00:00:00 2001 From: elshan_eth <22689890+elshan-eth@users.noreply.github.com> Date: Mon, 13 Jan 2025 19:12:11 +0100 Subject: [PATCH 18/30] update snapshots --- pkg/vault/test/.contract-sizes/CompositeLiquidityRouter | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter b/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter index 0e442f50f..8390458a0 100644 --- a/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter +++ b/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter @@ -1,2 +1,2 @@ -Bytecode 21.945 -InitCode 23.757 \ No newline at end of file +Bytecode 21.953 +InitCode 23.765 \ No newline at end of file From 8ca5aa619a46c67a153414acb9fdae99b653d242 Mon Sep 17 00:00:00 2001 From: elshan_eth <22689890+elshan-eth@users.noreply.github.com> Date: Tue, 14 Jan 2025 18:34:02 +0100 Subject: [PATCH 19/30] small fixes --- .../vault/ICompositeLiquidityRouter.sol | 62 +++++++------- .../contracts/CompositeLiquidityRouter.sol | 58 ++++++------- .../CompositeLiquidityRouterERC4626Pool.t.sol | 84 +++++++++---------- 3 files changed, 105 insertions(+), 99 deletions(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index 9aed6527e..54e889a4c 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -30,7 +30,8 @@ interface ICompositeLiquidityRouter { * the "parent" pool, and also make sure limits are set properly. * * @param pool Address of the liquidity pool - * @param isWrappedToken An array indicating whether the input token is a wrapped or underlying token + * @param useAsStandardToken An array indicating whether to use the token as standard or wrap it, + * sorted in token registration order of wrapped tokens in the pool * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order * wrapped tokens in the pool * @param minBptAmountOut Minimum amount of pool tokens to be received @@ -40,7 +41,7 @@ interface ICompositeLiquidityRouter { */ function addLiquidityUnbalancedToERC4626Pool( address pool, - bool[] memory isWrappedToken, + bool[] memory useAsStandardToken, uint256[] memory exactAmountsIn, uint256 minBptAmountOut, bool wethIsEth, @@ -54,51 +55,54 @@ interface ICompositeLiquidityRouter { * the "parent" pool, and also make sure limits are set properly. * * @param pool Address of the liquidity pool - * @param isWrappedToken An array indicating whether the input token is a wrappe or underlying token + * @param useAsStandardToken An array indicating whether to use the token as standard or wrap it, + * sorted in token registration order of wrapped tokens in the pool * @param maxAmountsIn Maximum amounts of underlying/wrapped tokens in, sorted in token registration order * wrapped tokens in the pool * @param exactBptAmountOut Exact amount of pool tokens to be received * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH * @param userData Additional (optional) data required for adding liquidity - * @return underlyingAmountsIn Actual amounts of tokens added, sorted in token registration order of wrapped tokens - * in the pool + * @return tokensIn Actual tokens added in the pool + * @return amountsIn Actual amounts of tokens added in the pool */ function addLiquidityProportionalToERC4626Pool( address pool, - bool[] memory isWrappedToken, + bool[] memory useAsStandardToken, uint256[] memory maxAmountsIn, uint256 exactBptAmountOut, bool wethIsEth, bytes memory userData - ) external payable returns (uint256[] memory underlyingAmountsIn); + ) external payable returns (address[] memory tokensIn, uint256[] memory amountsIn); /** * @notice Remove proportional amounts of underlying from an ERC4626 pool, burning an exact pool token amount. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param isWrappedToken An array indicating whether the output token is a wrapper or underlying token + * @param useAsStandardToken An array indicating whether to use the token as standard or unwrap it, + * sorted in token registration order of wrapped tokens in the pool * @param exactBptAmountIn Exact amount of pool tokens provided - * @param minAmountsOut Minimum amounts of underlying tokens out, sorted in token registration order + * @param minAmountsOut Minimum amounts of each token, sorted according to tokensIn array * wrapped tokens in the pool * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH * @param userData Additional (optional) data required for removing liquidity - * @return amountsOut Actual amounts of tokens received, sorted in token registration order - * tokens in the pool + * @return tokensOut Actual tokens received + * @return amountsOut Actual amounts of tokens received */ function removeLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory isWrappedToken, + bool[] memory useAsStandardToken, uint256 exactBptAmountIn, uint256[] memory minAmountsOut, bool wethIsEth, bytes memory userData - ) external payable returns (uint256[] memory amountsOut); + ) external payable returns (address[] memory tokensOut, uint256[] memory amountsOut); /** * @notice Queries an `addLiquidityUnbalancedToERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param isWrappedToken An array indicating whether the input token is a wrapped or underlying token + * @param useAsStandardToken An array indicating whether to use the token as standard or wrap it, + * sorted in token registration order of wrapped tokens in the pool * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order * wrapped tokens in the pool * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) @@ -107,7 +111,7 @@ interface ICompositeLiquidityRouter { */ function queryAddLiquidityUnbalancedToERC4626Pool( address pool, - bool[] memory isWrappedToken, + bool[] memory useAsStandardToken, uint256[] memory exactAmountsIn, address sender, bytes memory userData @@ -117,39 +121,41 @@ interface ICompositeLiquidityRouter { * @notice Queries an `addLiquidityProportionalToERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param isWrappedToken An array indicating whether the input token is a wrapped or underlying token + * @param useAsStandardToken An array indicating whether to use the token as standard or wrap/unwrap it, + * sorted in token registration order of wrapped tokens in the pool * @param exactBptAmountOut Exact amount of pool tokens to be received * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query - * @return underlyingAmountsIn Expected amounts of tokens to add, sorted in token registration order of wrapped - * tokens in the pool + * @return tokensIn Expected tokens added in the pool + * @return amountsIn Expected amounts of tokens added in the pool */ function queryAddLiquidityProportionalToERC4626Pool( address pool, - bool[] memory isWrappedToken, + bool[] memory useAsStandardToken, uint256 exactBptAmountOut, address sender, bytes memory userData - ) external returns (uint256[] memory underlyingAmountsIn); + ) external returns (address[] memory tokensIn, uint256[] memory amountsIn); /** * @notice Queries a `removeLiquidityProportionalFromERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param isWrappedToken An array indicating whether the output token is a wrapped or underlying token + * @param useAsStandardToken An array indicating whether to use the token as standard or unwrap it, + * sorted in token registration order of wrapped tokens in the pool * @param exactBptAmountIn Exact amount of pool tokens provided for the query * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query - * @return underlyingAmountsOut Expected amounts of tokens to receive, sorted in token registration order of - * wrapped tokens in the pool + * @return tokensOut Expected tokens to receive + * @return amountsOut Expected amounts of tokens to receive */ function queryRemoveLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory isWrappedToken, + bool[] memory useAsStandardToken, uint256 exactBptAmountIn, address sender, bytes memory userData - ) external returns (uint256[] memory underlyingAmountsOut); + ) external returns (address[] memory tokensOut, uint256[] memory amountsOut); /*************************************************************************** Nested pools @@ -164,7 +170,7 @@ interface ICompositeLiquidityRouter { * @param parentPool Address of the highest level pool (which contains BPTs of other pools) * @param tokensIn Input token addresses, sorted by user preference. `tokensIn` array must have all tokens from * child pools and all tokens that are not BPTs from the nested pool (parent pool). - * @param exactAmountsIn Amount of each underlying token in, sorted according to tokensIn array + * @param exactAmountsIn Amount of each token in, sorted according to tokensIn array * @param minBptAmountOut Expected minimum amount of parent pool tokens to receive * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH * @param userData Additional (optional) data required for the operation @@ -184,7 +190,7 @@ interface ICompositeLiquidityRouter { * @param parentPool Address of the highest level pool (which contains BPTs of other pools) * @param tokensIn Input token addresses, sorted by user preference. `tokensIn` array must have all tokens from * child pools and all tokens that are not BPTs from the nested pool (parent pool). - * @param exactAmountsIn Amount of each underlying token in, sorted according to tokensIn array + * @param exactAmountsIn Amount of each token in, sorted according to tokensIn array * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the operation * @return bptAmountOut Expected amount of parent pool tokens to receive @@ -208,7 +214,7 @@ interface ICompositeLiquidityRouter { * @param tokensOut Output token addresses, sorted by user preference. `tokensOut` array must have all tokens from * child pools and all tokens that are not BPTs from the nested pool (parent pool). If not all tokens are informed, * balances are not settled and the operation reverts. Tokens that repeat must be informed only once. - * @param minAmountsOut Minimum amounts of each outgoing underlying token, sorted according to tokensIn array + * @param minAmountsOut Minimum amounts of each token, sorted according to tokensIn array * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH * @param userData Additional (optional) data required for the operation * @return amountsOut Actual amounts of tokens received, parallel to `tokensOut` diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index f2bc0966c..0cc737dd8 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -48,7 +48,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function addLiquidityUnbalancedToERC4626Pool( address pool, - bool[] memory isWrappedToken, + bool[] memory useAsStandardToken, uint256[] memory exactAmountsIn, uint256 minBptAmountOut, bool wethIsEth, @@ -68,7 +68,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: wethIsEth, userData: userData }), - isWrappedToken + useAsStandardToken ) ) ), @@ -79,7 +79,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function addLiquidityProportionalToERC4626Pool( address pool, - bool[] memory isWrappedToken, + bool[] memory useAsStandardToken, uint256[] memory maxAmountsIn, uint256 exactBptAmountOut, bool wethIsEth, @@ -99,7 +99,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: wethIsEth, userData: userData }), - isWrappedToken + useAsStandardToken ) ) ), @@ -110,7 +110,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function removeLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory isWrappedToken, + bool[] memory useAsStandardToken, uint256 exactBptAmountIn, uint256[] memory minAmountsOut, bool wethIsEth, @@ -130,7 +130,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: wethIsEth, userData: userData }), - isWrappedToken + useAsStandardToken ) ) ), @@ -141,7 +141,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function queryAddLiquidityUnbalancedToERC4626Pool( address pool, - bool[] memory isWrappedToken, + bool[] memory useAsStandardToken, uint256[] memory exactAmountsIn, address sender, bytes memory userData @@ -160,7 +160,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: false, userData: userData }), - isWrappedToken + useAsStandardToken ) ) ), @@ -171,7 +171,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function queryAddLiquidityProportionalToERC4626Pool( address pool, - bool[] memory isWrappedToken, + bool[] memory useAsStandardToken, uint256 exactBptAmountOut, address sender, bytes memory userData @@ -190,7 +190,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: false, userData: userData }), - isWrappedToken + useAsStandardToken ) ) ), @@ -201,7 +201,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function queryRemoveLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory isWrappedToken, + bool[] memory useAsStandardToken, uint256 exactBptAmountIn, address sender, bytes memory userData @@ -221,7 +221,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: false, userData: userData }), - isWrappedToken + useAsStandardToken ) ) ), @@ -231,17 +231,17 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo function addLiquidityERC4626PoolUnbalancedHook( AddLiquidityHookParams calldata params, - bool[] calldata isWrappedToken + bool[] calldata useAsStandardToken ) external nonReentrant onlyVault returns (uint256 bptAmountOut) { IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; - // Revert if `tokensIn` length does not match `maxAmountsIn` and `isWrappedToken`. - InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, isWrappedToken.length); + // Revert if `tokensIn` length does not match `maxAmountsIn` and `useAsStandardToken`. + InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, useAsStandardToken.length); uint256[] memory amountsIn = _wrapTokensExactInIfRequired( params.sender, - isWrappedToken, + useAsStandardToken, erc4626PoolTokens, params.maxAmountsIn, params.wethIsEth @@ -262,13 +262,13 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo function addLiquidityERC4626PoolProportionalHook( AddLiquidityHookParams calldata params, - bool[] calldata isWrappedToken + bool[] calldata useAsStandardToken ) external nonReentrant onlyVault returns (uint256[] memory amountsIn) { IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; - // Revert if `tokensIn` length does not match `maxAmountsIn` and `isWrappedToken`. - InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, isWrappedToken.length); + // Revert if `tokensIn` length does not match `maxAmountsIn` and `useAsStandardToken`. + InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, useAsStandardToken.length); uint256[] memory maxAmounts = new uint256[](poolTokensLength); for (uint256 i = 0; i < poolTokensLength; ++i) { @@ -289,7 +289,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo amountsIn = _wrapTokensExactOutIfRequired( params.sender, - isWrappedToken, + useAsStandardToken, erc4626PoolTokens, wrappedAmountsIn, params.maxAmountsIn, @@ -299,13 +299,13 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo function removeLiquidityERC4626PoolProportionalHook( RemoveLiquidityHookParams calldata params, - bool[] calldata isWrappedToken + bool[] calldata useAsStandardToken ) external nonReentrant onlyVault returns (uint256[] memory amountsOut) { IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; - // Revert if `tokensOut` length does not match `minAmountsOut` and `isWrappedToken`. - InputHelpers.ensureInputLengthMatch(poolTokensLength, params.minAmountsOut.length, isWrappedToken.length); + // Revert if `tokensOut` length does not match `minAmountsOut` and `useAsStandardToken`. + InputHelpers.ensureInputLengthMatch(poolTokensLength, params.minAmountsOut.length, useAsStandardToken.length); amountsOut = new uint256[](poolTokensLength); @@ -326,7 +326,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); - if (isWrappedToken[i]) { + if (useAsStandardToken[i]) { amountsOut[i] = wrappedAmountsOut[i]; if (amountsOut[i] < params.minAmountsOut[i]) { @@ -366,7 +366,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @dev Assumes array lengths have been checked externally. function _wrapTokensExactInIfRequired( address sender, - bool[] memory isWrappedToken, + bool[] memory useAsStandardToken, IERC20[] memory erc4626PoolTokens, uint256[] memory amountsIn, bool wethIsEth @@ -384,7 +384,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo // Check whether the caller wants to use the token as an ERC4626 (i.e., wrap/unwrap it), or just use it as // a standard token. - if (isWrappedToken[i]) { + if (useAsStandardToken[i]) { wrappedAmountsIn[i] = amountsIn[i]; if (isStaticCall == false) { @@ -425,7 +425,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @dev Assumes array lengths have been checked externally. function _wrapTokensExactOutIfRequired( address sender, - bool[] memory isWrappedToken, + bool[] memory useAsStandardToken, IERC20[] memory erc4626PoolTokens, uint256[] memory wrappedAmountsIn, uint256[] memory maxAmountsIn, @@ -438,13 +438,13 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo for (uint256 i = 0; i < poolTokensLength; ++i) { // Treat all ERC4626 pool tokens as wrapped. The next step will verify if we can use the wrappedToken as - // a valid ERC4626. Note that if `isWrappedToken[i]` is false, we will treat it as a standard token. + // a valid ERC4626. Note that if `useAsStandardToken[i]` is false, we will treat it as a standard token. IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); // Check whether the caller wants to use the token as an ERC4626 (i.e., wrap/unwrap it), or just use it as // a standard token. - if (isWrappedToken[i]) { + if (useAsStandardToken[i]) { if (wrappedAmountsIn[i] > maxAmountsIn[i]) { revert IVaultErrors.AmountInAboveMax(wrappedToken, wrappedAmountsIn[i], maxAmountsIn[i]); } diff --git a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol index 7ae6fad27..e1476b67e 100644 --- a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol +++ b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol @@ -142,8 +142,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { exactWrappedAmountsIn[waDaiIdx] = operationAmount; exactWrappedAmountsIn[waWethIdx] = _vaultPreviewDeposit(waWETH, operationAmount); - bool[] memory isWrappedToken = new bool[](exactUnderlyingAmountsIn.length); - isWrappedToken[waDaiIdx] = true; + bool[] memory useAsStandardToken = new bool[](exactUnderlyingAmountsIn.length); + useAsStandardToken[waDaiIdx] = true; uint256 snapshot = vm.snapshot(); _prankStaticCall(); @@ -160,7 +160,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( pool, - isWrappedToken, + useAsStandardToken, exactUnderlyingAmountsIn, 1, false, @@ -294,13 +294,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory isWrappedToken = new bool[](exactUnderlyingAmountsIn.length); - isWrappedToken[partialWethIdx] = true; + bool[] memory useAsStandardToken = new bool[](exactUnderlyingAmountsIn.length); + useAsStandardToken[partialWethIdx] = true; vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, - isWrappedToken, + useAsStandardToken, exactUnderlyingAmountsIn, 0, false, @@ -344,13 +344,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory isWrappedToken = new bool[](exactUnderlyingAmountsIn.length); - isWrappedToken[partialWethIdx] = true; + bool[] memory useAsStandardToken = new bool[](exactUnderlyingAmountsIn.length); + useAsStandardToken[partialWethIdx] = true; vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) - }(partialErc4626Pool, isWrappedToken, exactUnderlyingAmountsIn, 0, true, bytes("")); + }(partialErc4626Pool, useAsStandardToken, exactUnderlyingAmountsIn, 0, true, bytes("")); TestBalances memory balancesAfter = _getTestBalances(alice); @@ -441,14 +441,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 operationAmount = bufferInitialAmount / 2; uint256[] memory exactUnderlyingAmountsIn = [operationAmount, operationAmount].toMemoryArray(); - bool[] memory isWrappedToken = new bool[](exactUnderlyingAmountsIn.length); - isWrappedToken[partialWethIdx] = true; + bool[] memory useAsStandardToken = new bool[](exactUnderlyingAmountsIn.length); + useAsStandardToken[partialWethIdx] = true; uint256 snapshotId = vm.snapshot(); _prankStaticCall(); uint256 queryBptAmountOut = compositeLiquidityRouter.queryAddLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, - isWrappedToken, + useAsStandardToken, exactUnderlyingAmountsIn, address(this), bytes("") @@ -458,7 +458,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 actualBptAmountOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, - isWrappedToken, + useAsStandardToken, exactUnderlyingAmountsIn, 1, false, @@ -599,13 +599,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory isWrappedToken = new bool[](maxAmountsIn.length); - isWrappedToken[partialWethIdx] = true; + bool[] memory useAsStandardToken = new bool[](maxAmountsIn.length); + useAsStandardToken[partialWethIdx] = true; vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, - isWrappedToken, + useAsStandardToken, maxAmountsIn, exactBptAmountOut, false, @@ -665,13 +665,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory isWrappedToken = new bool[](maxAmountsIn.length); - isWrappedToken[partialWethIdx] = true; + bool[] memory useAsStandardToken = new bool[](maxAmountsIn.length); + useAsStandardToken[partialWethIdx] = true; vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) - }(partialErc4626Pool, isWrappedToken, maxAmountsIn, exactBptAmountOut, true, bytes("")); + }(partialErc4626Pool, useAsStandardToken, maxAmountsIn, exactBptAmountOut, true, bytes("")); TestBalances memory balancesAfter = _getTestBalances(alice); @@ -732,8 +732,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { maxAmountsIn[partialWaDaiIdx] = operationAmount; maxAmountsIn[partialWethIdx] = expectedWrappedAmountsIn[partialWethIdx] - 1; - bool[] memory isWrappedToken = new bool[](maxAmountsIn.length); - isWrappedToken[partialWethIdx] = true; + bool[] memory useAsStandardToken = new bool[](maxAmountsIn.length); + useAsStandardToken[partialWethIdx] = true; vm.expectRevert( abi.encodeWithSelector( @@ -746,7 +746,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, - isWrappedToken, + useAsStandardToken, maxAmountsIn, exactBptAmountOut, false, @@ -794,14 +794,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256[] memory maxAmountsIn = [operationAmount, operationAmount].toMemoryArray(); uint256 exactBptAmountOut = operationAmount; - bool[] memory isWrappedToken = new bool[](maxAmountsIn.length); - isWrappedToken[partialWethIdx] = true; + bool[] memory useAsStandardToken = new bool[](maxAmountsIn.length); + useAsStandardToken[partialWethIdx] = true; uint256 snapshotId = vm.snapshot(); _prankStaticCall(); uint256[] memory queryUnderlyingAmountsIn = compositeLiquidityRouter.queryAddLiquidityProportionalToERC4626Pool( partialErc4626Pool, - isWrappedToken, + useAsStandardToken, exactBptAmountOut, address(this), bytes("") @@ -811,7 +811,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, - isWrappedToken, + useAsStandardToken, maxAmountsIn, exactBptAmountOut, false, @@ -908,8 +908,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { minAmountsOut[waWethIdx] = _vaultPreviewRedeem(waWETH, expectedWrappedAmountsOut[waWethIdx]); minAmountsOut[waDaiIdx] = expectedWrappedAmountsOut[waDaiIdx]; - bool[] memory isWrappedToken = new bool[](2); - isWrappedToken[waDaiIdx] = true; + bool[] memory useAsStandardToken = new bool[](2); + useAsStandardToken[waDaiIdx] = true; TestBalances memory balancesBefore = _getTestBalances(bob); @@ -917,7 +917,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( pool, - isWrappedToken, + useAsStandardToken, exactBptAmountIn, minAmountsOut, false, @@ -1030,14 +1030,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); - bool[] memory isWrappedToken = new bool[](minAmountsOut.length); - isWrappedToken[partialWethIdx] = true; + bool[] memory useAsStandardToken = new bool[](minAmountsOut.length); + useAsStandardToken[partialWethIdx] = true; vm.prank(bob); uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - isWrappedToken, + useAsStandardToken, exactBptAmountIn, minAmountsOut, false, @@ -1091,14 +1091,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); - bool[] memory isWrappedToken = new bool[](minAmountsOut.length); - isWrappedToken[partialWethIdx] = true; + bool[] memory useAsStandardToken = new bool[](minAmountsOut.length); + useAsStandardToken[partialWethIdx] = true; vm.prank(bob); uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - isWrappedToken, + useAsStandardToken, exactBptAmountIn, minAmountsOut, true, @@ -1163,8 +1163,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { minAmountsOut[partialWethIdx] = expectedWrappedAmountsOut[partialWethIdx] + 1; minAmountsOut[partialWaDaiIdx] = _vaultPreviewRedeem(waDAI, expectedWrappedAmountsOut[partialWaDaiIdx]); - bool[] memory isWrappedToken = new bool[](minAmountsOut.length); - isWrappedToken[partialWethIdx] = true; + bool[] memory useAsStandardToken = new bool[](minAmountsOut.length); + useAsStandardToken[partialWethIdx] = true; vm.expectRevert( abi.encodeWithSelector( @@ -1177,7 +1177,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(bob); compositeLiquidityRouter.removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - isWrappedToken, + useAsStandardToken, exactBptAmountIn, minAmountsOut, false, @@ -1254,15 +1254,15 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { expectedWrappedAmountsOut[partialWaDaiIdx] ); - bool[] memory isWrappedToken = new bool[](minUnderlyingAmountsOut.length); - isWrappedToken[partialWethIdx] = true; + bool[] memory useAsStandardToken = new bool[](minUnderlyingAmountsOut.length); + useAsStandardToken[partialWethIdx] = true; uint256 snapshotId = vm.snapshot(); _prankStaticCall(); uint256[] memory queryUnderlyingAmountsOut = compositeLiquidityRouter .queryRemoveLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - isWrappedToken, + useAsStandardToken, exactBptAmountIn, address(this), bytes("") @@ -1273,7 +1273,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - isWrappedToken, + useAsStandardToken, exactBptAmountIn, minUnderlyingAmountsOut, false, From 537f45f12fa429a4e6f78697aee799ce1cbc1d04 Mon Sep 17 00:00:00 2001 From: elshan_eth <22689890+elshan-eth@users.noreply.github.com> Date: Tue, 14 Jan 2025 18:50:33 +0100 Subject: [PATCH 20/30] small fixes --- ...actIn - with buffer liquidity - warm slots | 2 +- ...xactOut - no buffer liquidity - warm slots | 2 +- ...ctOut - with buffer liquidity - warm slots | 2 +- ... unbalanced using swapExactIn - warm slots | 2 +- ... liquidity using swapExactOur - warm slots | 2 +- ... liquidity using swapExactOut - warm slots | 2 +- ...ct in with one token and fees - cold slots | 2 +- ...ool - Standard] add liquidity proportional | 2 +- ...uidity single token exact out - warm slots | 2 +- .../[StablePool - Standard] donation | 2 +- ...StablePool - Standard] initialize with ETH | 2 +- ...blePool - Standard] initialize without ETH | 2 +- ... - Standard] remove liquidity proportional | 2 +- ...quidity single token exact in - warm slots | 2 +- ...ngle token exact in with fees - cold slots | 2 +- ...ngle token exact in with fees - warm slots | 2 +- ...BatchRouter] swap exact in - tokenA-tokenD | 2 +- ... unbalanced using swapExactIn - warm slots | 2 +- ... liquidity using swapExactOur - warm slots | 2 +- ...e liquidity using swapExactIn - warm slots | 2 +- ...ct in with one token and fees - cold slots | 2 +- ...ool - WithRate] add liquidity proportional | 2 +- ...uidity single token exact out - warm slots | 2 +- ...ate] add liquidity unbalanced - warm slots | 2 +- ... - WithRate] remove liquidity proportional | 2 +- ...quidity single token exact in - warm slots | 2 +- ...uidity single token exact out - warm slots | 2 +- ...ngle token exact in with fees - cold slots | 2 +- ...ngle token exact in with fees - warm slots | 2 +- ...ctOut - with buffer liquidity - warm slots | 2 +- ... liquidity using swapExactOur - warm slots | 2 +- ... liquidity using swapExactOut - warm slots | 2 +- ...ct in with one token and fees - cold slots | 2 +- ...ct in with one token and fees - warm slots | 2 +- ...ool - Standard] add liquidity proportional | 2 +- ...uidity single token exact out - warm slots | 2 +- ...ard] add liquidity unbalanced - warm slots | 2 +- .../[WeightedPool - Standard] donation | 2 +- ...ightedPool - Standard] initialize with ETH | 2 +- ...tedPool - Standard] initialize without ETH | 2 +- ... - Standard] remove liquidity proportional | 2 +- ...quidity single token exact in - warm slots | 2 +- ...uidity single token exact out - warm slots | 2 +- ...ngle token exact in with fees - cold slots | 2 +- ...ngle token exact in with fees - warm slots | 2 +- ... liquidity using swapExactOur - warm slots | 2 +- ...e liquidity using swapExactIn - warm slots | 2 +- ... liquidity using swapExactOut - warm slots | 2 +- ...ool - WithRate] add liquidity proportional | 2 +- ...uidity single token exact out - warm slots | 2 +- ...ate] add liquidity unbalanced - warm slots | 2 +- ...quidity single token exact in - warm slots | 2 +- ...uidity single token exact out - warm slots | 2 +- ...ngle token exact in with fees - cold slots | 2 +- ...ngle token exact in with fees - warm slots | 2 +- .../contracts/CompositeLiquidityRouter.sol | 45 ++++++++------ .../.contract-sizes/CompositeLiquidityRouter | 4 +- .../CompositeLiquidityRouterERC4626Pool.t.sol | 60 ++++++++++--------- 58 files changed, 114 insertions(+), 105 deletions(-) diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactIn - with buffer liquidity - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactIn - with buffer liquidity - warm slots index 3c6ece1ca..1afba7063 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactIn - with buffer liquidity - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactIn - with buffer liquidity - warm slots @@ -1 +1 @@ -245.1k \ No newline at end of file +245.0k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - no buffer liquidity - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - no buffer liquidity - warm slots index 24bbfa4e3..cba6a2769 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - no buffer liquidity - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - no buffer liquidity - warm slots @@ -1 +1 @@ -334.7k \ No newline at end of file +334.6k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots index c1495e78b..8f7230cba 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots @@ -1 +1 @@ -258.5k \ No newline at end of file +258.4k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots index dbba43d6f..9dd99b8b4 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots @@ -1 +1 @@ -196.4k \ No newline at end of file +196.3k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots index 9f03a77e5..cc6877811 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots @@ -1 +1 @@ -180.9k \ No newline at end of file +180.8k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots index 2e853f7ae..8d0a3504f 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots @@ -1 +1 @@ -209.9k \ No newline at end of file +209.8k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] swap exact in with one token and fees - cold slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] swap exact in with one token and fees - cold slots index cf1fe3b12..850b54988 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] swap exact in with one token and fees - cold slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard - BatchRouter] swap exact in with one token and fees - cold slots @@ -1 +1 @@ -194.6k \ No newline at end of file +194.5k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity proportional b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity proportional index 184d05cb6..32a6c77e7 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity proportional +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity proportional @@ -1 +1 @@ -179.3k \ No newline at end of file +179.2k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity single token exact out - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity single token exact out - warm slots index 43e844943..eec4e69d4 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity single token exact out - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] add liquidity single token exact out - warm slots @@ -1 +1 @@ -172.2k \ No newline at end of file +172.1k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] donation b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] donation index e1c39f087..5f4b8010a 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] donation +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] donation @@ -1 +1 @@ -171.1k \ No newline at end of file +171.0k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize with ETH b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize with ETH index d5ce4e317..7faabe4fc 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize with ETH +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize with ETH @@ -1 +1 @@ -348.3k \ No newline at end of file +347.9k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize without ETH b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize without ETH index 8d41f35e7..02b7f4b6d 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize without ETH +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] initialize without ETH @@ -1 +1 @@ -335.8k \ No newline at end of file +335.4k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity proportional b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity proportional index abc6469ef..60bcf4864 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity proportional +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity proportional @@ -1 +1 @@ -167.2k \ No newline at end of file +167.1k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity single token exact in - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity single token exact in - warm slots index c7e7b4544..0be376f1e 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity single token exact in - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] remove liquidity single token exact in - warm slots @@ -1 +1 @@ -166.5k \ No newline at end of file +166.4k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - cold slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - cold slots index 34e80eef2..68b670a11 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - cold slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - cold slots @@ -1 +1 @@ -178.9k \ No newline at end of file +178.8k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - warm slots index 28fbaf434..77bc6d810 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - Standard] swap single token exact in with fees - warm slots @@ -1 +1 @@ -165.0k \ No newline at end of file +164.9k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithNestedPool - BatchRouter] swap exact in - tokenA-tokenD b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithNestedPool - BatchRouter] swap exact in - tokenA-tokenD index 4aa3cb8e1..722192bb8 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithNestedPool - BatchRouter] swap exact in - tokenA-tokenD +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithNestedPool - BatchRouter] swap exact in - tokenA-tokenD @@ -1 +1 @@ -558.7k \ No newline at end of file +558.6k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots index 007fed429..beb043c93 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity unbalanced using swapExactIn - warm slots @@ -1 +1 @@ -217.8k \ No newline at end of file +217.7k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots index 804746be2..4b78b5ecf 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots @@ -1 +1 @@ -202.3k \ No newline at end of file +202.2k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots index 6a6d4e231..11eae2457 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots @@ -1 +1 @@ -212.0k \ No newline at end of file +211.9k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] swap exact in with one token and fees - cold slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] swap exact in with one token and fees - cold slots index 4c4616edc..5b0408bcc 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] swap exact in with one token and fees - cold slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate - BatchRouter] swap exact in with one token and fees - cold slots @@ -1 +1 @@ -227.7k \ No newline at end of file +227.6k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity proportional b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity proportional index 0718ec32c..d4f0a3a17 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity proportional +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity proportional @@ -1 +1 @@ -234.4k \ No newline at end of file +234.3k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity single token exact out - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity single token exact out - warm slots index 7c6a6731a..ad087e174 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity single token exact out - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity single token exact out - warm slots @@ -1 +1 @@ -193.6k \ No newline at end of file +193.5k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity unbalanced - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity unbalanced - warm slots index 43f1f83db..69b363ada 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity unbalanced - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] add liquidity unbalanced - warm slots @@ -1 +1 @@ -230.6k \ No newline at end of file +230.5k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity proportional b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity proportional index 01db6fe9f..c4f48aed1 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity proportional +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity proportional @@ -1 +1 @@ -222.2k \ No newline at end of file +222.1k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact in - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact in - warm slots index a1a745b5f..0d3d71a36 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact in - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact in - warm slots @@ -1 +1 @@ -187.8k \ No newline at end of file +187.7k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact out - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact out - warm slots index 04c51970a..47f39a685 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact out - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] remove liquidity single token exact out - warm slots @@ -1 +1 @@ -198.2k \ No newline at end of file +198.1k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - cold slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - cold slots index 6a6d4e231..11eae2457 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - cold slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - cold slots @@ -1 +1 @@ -212.0k \ No newline at end of file +211.9k \ No newline at end of file diff --git a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - warm slots b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - warm slots index bba55110e..9f03a77e5 100644 --- a/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - warm slots +++ b/pkg/pool-stable/test/gas/.hardhat-snapshots/[StablePool - WithRate] swap single token exact in with fees - warm slots @@ -1 +1 @@ -181.0k \ No newline at end of file +180.9k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots index 74805369f..5e97e74e1 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - ERC4626 - BatchRouter] swapExactOut - with buffer liquidity - warm slots @@ -1 +1 @@ -244.8k \ No newline at end of file +244.7k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots index eba3d018d..abc6469ef 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] add liquidity using swapExactOur - warm slots @@ -1 +1 @@ -167.3k \ No newline at end of file +167.2k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots index 33862ebdb..2937f7eca 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] remove liquidity using swapExactOut - warm slots @@ -1 +1 @@ -209.0k \ No newline at end of file +208.9k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - cold slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - cold slots index dc58fb784..9078b2e18 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - cold slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - cold slots @@ -1 +1 @@ -184.1k \ No newline at end of file +184.0k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - warm slots index b6426f9ae..f1c01191f 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard - BatchRouter] swap exact in with one token and fees - warm slots @@ -1 +1 @@ -167.0k \ No newline at end of file +166.9k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity proportional b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity proportional index 184d05cb6..32a6c77e7 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity proportional +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity proportional @@ -1 +1 @@ -179.3k \ No newline at end of file +179.2k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity single token exact out - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity single token exact out - warm slots index 235d9b73c..7eca5dd03 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity single token exact out - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity single token exact out - warm slots @@ -1 +1 @@ -158.6k \ No newline at end of file +158.5k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity unbalanced - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity unbalanced - warm slots index 330ac4a8c..85f89ffc8 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity unbalanced - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] add liquidity unbalanced - warm slots @@ -1 +1 @@ -212.3k \ No newline at end of file +212.2k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] donation b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] donation index e1c39f087..5f4b8010a 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] donation +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] donation @@ -1 +1 @@ -171.1k \ No newline at end of file +171.0k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize with ETH b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize with ETH index 6b56207f8..13e58083b 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize with ETH +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize with ETH @@ -1 +1 @@ -349.3k \ No newline at end of file +348.8k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize without ETH b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize without ETH index d79069749..3958ab300 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize without ETH +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] initialize without ETH @@ -1 +1 @@ -336.8k \ No newline at end of file +336.4k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity proportional b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity proportional index abc6469ef..60bcf4864 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity proportional +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity proportional @@ -1 +1 @@ -167.2k \ No newline at end of file +167.1k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact in - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact in - warm slots index ecea21dfe..896629134 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact in - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact in - warm slots @@ -1 +1 @@ -152.9k \ No newline at end of file +152.8k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact out - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact out - warm slots index 281d84625..5c1048bec 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact out - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] remove liquidity single token exact out - warm slots @@ -1 +1 @@ -176.2k \ No newline at end of file +176.1k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - cold slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - cold slots index fcaa01729..7f24db840 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - cold slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - cold slots @@ -1 +1 @@ -168.4k \ No newline at end of file +168.3k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - warm slots index 1d32b9dab..a794c44b2 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - Standard] swap single token exact in with fees - warm slots @@ -1 +1 @@ -151.3k \ No newline at end of file +151.2k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots index cdf9810ea..a6a4e56f4 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] add liquidity using swapExactOur - warm slots @@ -1 +1 @@ -188.7k \ No newline at end of file +188.6k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots index a5dc1053f..04c51970a 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactIn - warm slots @@ -1 +1 @@ -198.3k \ No newline at end of file +198.2k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactOut - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactOut - warm slots index 1e3020238..fc0174c73 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactOut - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate - BatchRouter] remove liquidity using swapExactOut - warm slots @@ -1 +1 @@ -230.3k \ No newline at end of file +230.2k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity proportional b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity proportional index 0718ec32c..d4f0a3a17 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity proportional +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity proportional @@ -1 +1 @@ -234.4k \ No newline at end of file +234.3k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity single token exact out - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity single token exact out - warm slots index 438d6c8b8..a87088349 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity single token exact out - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity single token exact out - warm slots @@ -1 +1 @@ -180.0k \ No newline at end of file +179.9k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity unbalanced - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity unbalanced - warm slots index 15b423cf0..6f08b2604 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity unbalanced - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] add liquidity unbalanced - warm slots @@ -1 +1 @@ -228.7k \ No newline at end of file +228.6k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact in - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact in - warm slots index 61e5d8518..d3fa14d41 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact in - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact in - warm slots @@ -1 +1 @@ -174.1k \ No newline at end of file +174.0k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact out - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact out - warm slots index c041f7749..e25cfa980 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact out - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] remove liquidity single token exact out - warm slots @@ -1 +1 @@ -197.5k \ No newline at end of file +197.4k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - cold slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - cold slots index eaaca87af..ff670bcec 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - cold slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - cold slots @@ -1 +1 @@ -201.5k \ No newline at end of file +201.4k \ No newline at end of file diff --git a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - warm slots b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - warm slots index eba3d018d..abc6469ef 100644 --- a/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - warm slots +++ b/pkg/pool-weighted/test/gas/.hardhat-snapshots/[WeightedPool - WithRate] swap single token exact in with fees - warm slots @@ -1 +1 @@ -167.3k \ No newline at end of file +167.2k \ No newline at end of file diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index 0cc737dd8..31d96751e 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -84,8 +84,8 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo uint256 exactBptAmountOut, bool wethIsEth, bytes memory userData - ) external payable saveSender(msg.sender) returns (uint256[] memory amountsIn) { - amountsIn = abi.decode( + ) external payable saveSender(msg.sender) returns (address[] memory tokensIn, uint256[] memory amountsIn) { + (tokensIn, amountsIn) = abi.decode( _vault.unlock( abi.encodeCall( CompositeLiquidityRouter.addLiquidityERC4626PoolProportionalHook, @@ -103,7 +103,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo ) ) ), - (uint256[]) + (address[], uint256[]) ); } @@ -115,8 +115,8 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo uint256[] memory minAmountsOut, bool wethIsEth, bytes memory userData - ) external payable saveSender(msg.sender) returns (uint256[] memory amountsOut) { - amountsOut = abi.decode( + ) external payable saveSender(msg.sender) returns (address[] memory tokensOut, uint256[] memory amountsOut) { + (tokensOut, amountsOut) = abi.decode( _vault.unlock( abi.encodeCall( CompositeLiquidityRouter.removeLiquidityERC4626PoolProportionalHook, @@ -134,7 +134,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo ) ) ), - (uint256[]) + (address[], uint256[]) ); } @@ -175,8 +175,8 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo uint256 exactBptAmountOut, address sender, bytes memory userData - ) external saveSender(sender) returns (uint256[] memory amountsIn) { - amountsIn = abi.decode( + ) external saveSender(sender) returns (address[] memory tokensIn, uint256[] memory amountsIn) { + (tokensIn, amountsIn) = abi.decode( _vault.quote( abi.encodeCall( CompositeLiquidityRouter.addLiquidityERC4626PoolProportionalHook, @@ -194,7 +194,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo ) ) ), - (uint256[]) + (address[], uint256[]) ); } @@ -205,9 +205,9 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo uint256 exactBptAmountIn, address sender, bytes memory userData - ) external saveSender(sender) returns (uint256[] memory underlyingAmountsOut) { + ) external saveSender(sender) returns (address[] memory tokensOut, uint256[] memory amountsOut) { IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(pool); - underlyingAmountsOut = abi.decode( + (tokensOut, amountsOut) = abi.decode( _vault.quote( abi.encodeCall( CompositeLiquidityRouter.removeLiquidityERC4626PoolProportionalHook, @@ -225,7 +225,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo ) ) ), - (uint256[]) + (address[], uint256[]) ); } @@ -236,7 +236,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; - // Revert if `tokensIn` length does not match `maxAmountsIn` and `useAsStandardToken`. + // Revert if `poolTokens` length does not match `maxAmountsIn` and `useAsStandardToken`. InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, useAsStandardToken.length); uint256[] memory amountsIn = _wrapTokensExactInIfRequired( @@ -263,11 +263,11 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo function addLiquidityERC4626PoolProportionalHook( AddLiquidityHookParams calldata params, bool[] calldata useAsStandardToken - ) external nonReentrant onlyVault returns (uint256[] memory amountsIn) { + ) external nonReentrant onlyVault returns (address[] memory tokensIn, uint256[] memory amountsIn) { IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; - // Revert if `tokensIn` length does not match `maxAmountsIn` and `useAsStandardToken`. + // Revert if `poolTokens` length does not match `maxAmountsIn` and `useAsStandardToken`. InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, useAsStandardToken.length); uint256[] memory maxAmounts = new uint256[](poolTokensLength); @@ -287,7 +287,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo }) ); - amountsIn = _wrapTokensExactOutIfRequired( + (tokensIn, amountsIn) = _wrapTokensExactOutIfRequired( params.sender, useAsStandardToken, erc4626PoolTokens, @@ -300,11 +300,11 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo function removeLiquidityERC4626PoolProportionalHook( RemoveLiquidityHookParams calldata params, bool[] calldata useAsStandardToken - ) external nonReentrant onlyVault returns (uint256[] memory amountsOut) { + ) external nonReentrant onlyVault returns (address[] memory tokensOut, uint256[] memory amountsOut) { IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; - // Revert if `tokensOut` length does not match `minAmountsOut` and `useAsStandardToken`. + // Revert if `poolTokens` length does not match `minAmountsOut` and `useAsStandardToken`. InputHelpers.ensureInputLengthMatch(poolTokensLength, params.minAmountsOut.length, useAsStandardToken.length); amountsOut = new uint256[](poolTokensLength); @@ -322,12 +322,14 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo bool isStaticCall = EVMCallModeHelpers.isStaticCall(); + tokensOut = new address[](poolTokensLength); for (uint256 i = 0; i < poolTokensLength; ++i) { IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); if (useAsStandardToken[i]) { amountsOut[i] = wrappedAmountsOut[i]; + tokensOut[i] = address(wrappedToken); if (amountsOut[i] < params.minAmountsOut[i]) { revert IVaultErrors.AmountOutBelowMin(erc4626PoolTokens[i], amountsOut[i], params.minAmountsOut[i]); @@ -351,6 +353,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo limitRaw: params.minAmountsOut[i] }) ); + tokensOut[i] = address(underlyingToken); if (amountsOut[i] < params.minAmountsOut[i]) { revert IVaultErrors.AmountOutBelowMin(underlyingToken, amountsOut[i], params.minAmountsOut[i]); @@ -430,12 +433,14 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo uint256[] memory wrappedAmountsIn, uint256[] memory maxAmountsIn, bool wethIsEth - ) private returns (uint256[] memory amountsIn) { + ) private returns (address[] memory tokensIn, uint256[] memory amountsIn) { uint256 poolTokensLength = erc4626PoolTokens.length; amountsIn = new uint256[](poolTokensLength); bool isStaticCall = EVMCallModeHelpers.isStaticCall(); + tokensIn = new address[](poolTokensLength); + for (uint256 i = 0; i < poolTokensLength; ++i) { // Treat all ERC4626 pool tokens as wrapped. The next step will verify if we can use the wrappedToken as // a valid ERC4626. Note that if `useAsStandardToken[i]` is false, we will treat it as a standard token. @@ -454,6 +459,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo } amountsIn[i] = wrappedAmountsIn[i]; + tokensIn[i] = address(wrappedToken); } else { if (address(underlyingToken) == address(0)) { revert IVaultErrors.BufferNotInitialized(wrappedToken); @@ -491,6 +497,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo } amountsIn[i] = underlyingAmount; + tokensIn[i] = address(underlyingToken); } } diff --git a/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter b/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter index 8390458a0..1ac900f58 100644 --- a/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter +++ b/pkg/vault/test/.contract-sizes/CompositeLiquidityRouter @@ -1,2 +1,2 @@ -Bytecode 21.953 -InitCode 23.765 \ No newline at end of file +Bytecode 22.513 +InitCode 24.338 \ No newline at end of file diff --git a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol index e1476b67e..1641816a0 100644 --- a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol +++ b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol @@ -487,7 +487,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); vm.prank(alice); - uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( + (, uint256[] memory actualUnderlyingAmountsIn) = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( pool, new bool[](maxAmountsIn.length), maxAmountsIn, @@ -543,7 +543,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); vm.prank(alice); - uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool{ + (, uint256[] memory actualUnderlyingAmountsIn) = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) }(pool, new bool[](maxAmountsIn.length), maxAmountsIn, exactBptAmountOut, true, bytes("")); @@ -603,7 +603,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { useAsStandardToken[partialWethIdx] = true; vm.prank(alice); - uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( + (, uint256[] memory actualUnderlyingAmountsIn) = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, useAsStandardToken, maxAmountsIn, @@ -669,7 +669,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { useAsStandardToken[partialWethIdx] = true; vm.prank(alice); - uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool{ + (, uint256[] memory actualUnderlyingAmountsIn) = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) }(partialErc4626Pool, useAsStandardToken, maxAmountsIn, exactBptAmountOut, true, bytes("")); @@ -761,17 +761,18 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 snapshotId = vm.snapshot(); _prankStaticCall(); - uint256[] memory queryUnderlyingAmountsIn = compositeLiquidityRouter.queryAddLiquidityProportionalToERC4626Pool( - pool, - new bool[](maxAmountsIn.length), - exactBptAmountOut, - address(this), - bytes("") - ); + (, uint256[] memory queryUnderlyingAmountsIn) = compositeLiquidityRouter + .queryAddLiquidityProportionalToERC4626Pool( + pool, + new bool[](maxAmountsIn.length), + exactBptAmountOut, + address(this), + bytes("") + ); vm.revertTo(snapshotId); vm.prank(alice); - uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( + (, uint256[] memory actualUnderlyingAmountsIn) = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( pool, new bool[](maxAmountsIn.length), maxAmountsIn, @@ -799,17 +800,18 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 snapshotId = vm.snapshot(); _prankStaticCall(); - uint256[] memory queryUnderlyingAmountsIn = compositeLiquidityRouter.queryAddLiquidityProportionalToERC4626Pool( - partialErc4626Pool, - useAsStandardToken, - exactBptAmountOut, - address(this), - bytes("") - ); + (, uint256[] memory queryUnderlyingAmountsIn) = compositeLiquidityRouter + .queryAddLiquidityProportionalToERC4626Pool( + partialErc4626Pool, + useAsStandardToken, + exactBptAmountOut, + address(this), + bytes("") + ); vm.revertTo(snapshotId); vm.prank(alice); - uint256[] memory actualUnderlyingAmountsIn = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( + (, uint256[] memory actualUnderlyingAmountsIn) = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, useAsStandardToken, maxAmountsIn, @@ -853,7 +855,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); vm.prank(bob); - uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter + (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( pool, new bool[](minAmountsOut.length), @@ -914,7 +916,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); vm.prank(bob); - uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter + (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( pool, useAsStandardToken, @@ -972,7 +974,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); vm.prank(bob); - uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter + (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( pool, new bool[](minAmountsOut.length), @@ -1034,7 +1036,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { useAsStandardToken[partialWethIdx] = true; vm.prank(bob); - uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter + (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, useAsStandardToken, @@ -1095,7 +1097,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { useAsStandardToken[partialWethIdx] = true; vm.prank(bob); - uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter + (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, useAsStandardToken, @@ -1204,7 +1206,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 snapshotId = vm.snapshot(); _prankStaticCall(); - uint256[] memory queryUnderlyingAmountsOut = compositeLiquidityRouter + (, uint256[] memory queryUnderlyingAmountsOut) = compositeLiquidityRouter .queryRemoveLiquidityProportionalFromERC4626Pool( pool, new bool[](minUnderlyingAmountsOut.length), @@ -1215,7 +1217,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.revertTo(snapshotId); vm.prank(bob); - uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter + (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( pool, new bool[](minUnderlyingAmountsOut.length), @@ -1259,7 +1261,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 snapshotId = vm.snapshot(); _prankStaticCall(); - uint256[] memory queryUnderlyingAmountsOut = compositeLiquidityRouter + (, uint256[] memory queryUnderlyingAmountsOut) = compositeLiquidityRouter .queryRemoveLiquidityProportionalFromERC4626Pool( partialErc4626Pool, useAsStandardToken, @@ -1270,7 +1272,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.revertTo(snapshotId); vm.prank(bob); - uint256[] memory actualUnderlyingAmountsOut = compositeLiquidityRouter + (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, useAsStandardToken, From 7119580ae2ee6297abbba33c6fe5bf0c3a0e98fc Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:18:28 +0100 Subject: [PATCH 21/30] Update pkg/vault/contracts/CompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/vault/contracts/CompositeLiquidityRouter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index 31d96751e..e5fb9c1c4 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -443,7 +443,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo for (uint256 i = 0; i < poolTokensLength; ++i) { // Treat all ERC4626 pool tokens as wrapped. The next step will verify if we can use the wrappedToken as - // a valid ERC4626. Note that if `useAsStandardToken[i]` is false, we will treat it as a standard token. + // a valid ERC4626. IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); From 782818421908998884363a1c4acac39276913b4e Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:18:40 +0100 Subject: [PATCH 22/30] Update pkg/vault/contracts/CompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/vault/contracts/CompositeLiquidityRouter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index e5fb9c1c4..70da4c2c1 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -381,7 +381,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo for (uint256 i = 0; i < poolTokensLength; ++i) { // Treat all ERC4626 pool tokens as wrapped. The next step will verify if we can use the wrappedToken as - // a valid ERC4626. Note that if `useWrappedTokens[i]` is false, we will treat it as a standard token. + // a valid ERC4626. IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); From 853d161c1aae262d07e8773ebb67f303ad7543a4 Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:19:08 +0100 Subject: [PATCH 23/30] Update pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index 54e889a4c..924fc6fde 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -190,7 +190,7 @@ interface ICompositeLiquidityRouter { * @param parentPool Address of the highest level pool (which contains BPTs of other pools) * @param tokensIn Input token addresses, sorted by user preference. `tokensIn` array must have all tokens from * child pools and all tokens that are not BPTs from the nested pool (parent pool). - * @param exactAmountsIn Amount of each token in, sorted according to tokensIn array + * @param exactAmountsIn Amount of each token in, corresponding to `tokensIn` * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the operation * @return bptAmountOut Expected amount of parent pool tokens to receive From af362c2226eedfd4ff6628c9f2a7edfb386ce12c Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:19:19 +0100 Subject: [PATCH 24/30] Update pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index 924fc6fde..d7b856f43 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -170,7 +170,7 @@ interface ICompositeLiquidityRouter { * @param parentPool Address of the highest level pool (which contains BPTs of other pools) * @param tokensIn Input token addresses, sorted by user preference. `tokensIn` array must have all tokens from * child pools and all tokens that are not BPTs from the nested pool (parent pool). - * @param exactAmountsIn Amount of each token in, sorted according to tokensIn array + * @param exactAmountsIn Amount of each token in, corresponding to `tokensIn` * @param minBptAmountOut Expected minimum amount of parent pool tokens to receive * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH * @param userData Additional (optional) data required for the operation From fafa55ee6d99371357bfcb5b9488a378c31822ee Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:22:44 +0100 Subject: [PATCH 25/30] Update pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index d7b856f43..b8299be94 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -62,8 +62,8 @@ interface ICompositeLiquidityRouter { * @param exactBptAmountOut Exact amount of pool tokens to be received * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH * @param userData Additional (optional) data required for adding liquidity - * @return tokensIn Actual tokens added in the pool - * @return amountsIn Actual amounts of tokens added in the pool + * @return tokensIn Actual tokens added to the pool + * @return amountsIn Actual amounts of tokens added to the pool */ function addLiquidityProportionalToERC4626Pool( address pool, From e54e48526a53b1a8b8fd52e97dd2d12d9667badf Mon Sep 17 00:00:00 2001 From: Elshan Dzhafarov <22689890+elshan-eth@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:23:29 +0100 Subject: [PATCH 26/30] Update pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol Co-authored-by: EndymionJkb --- pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index b8299be94..fbbdbf482 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -126,8 +126,8 @@ interface ICompositeLiquidityRouter { * @param exactBptAmountOut Exact amount of pool tokens to be received * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query - * @return tokensIn Expected tokens added in the pool - * @return amountsIn Expected amounts of tokens added in the pool + * @return tokensIn Expected tokens added to the pool + * @return amountsIn Expected amounts of tokens added to the pool */ function queryAddLiquidityProportionalToERC4626Pool( address pool, From 21c8a886da2696a81aae3fec58b980b73c5f0871 Mon Sep 17 00:00:00 2001 From: elshan_eth <22689890+elshan-eth@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:28:22 +0100 Subject: [PATCH 27/30] fix comments --- .../vault/ICompositeLiquidityRouter.sol | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index 54e889a4c..ddc2937f3 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -24,16 +24,15 @@ interface ICompositeLiquidityRouter { ***************************************************************************/ /** - * @notice Add arbitrary amounts of underlying tokens to an ERC4626 pool through the buffer. + * @notice Add arbitrary amounts of tokens to an ERC4626 pool through the buffer. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). Ensure that any buffers associated * with the wrapped tokens in the ERC4626 pool have been initialized before initializing or adding liquidity to * the "parent" pool, and also make sure limits are set properly. * * @param pool Address of the liquidity pool - * @param useAsStandardToken An array indicating whether to use the token as standard or wrap it, - * sorted in token registration order of wrapped tokens in the pool + * @param useAsStandardToken Flags indicating whether the corresponding token should be treated as an ERC4626 + * (unwrap and transfer the underlying asset) or as a standard ERC20 (transfer the wrapped token directly) * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order - * wrapped tokens in the pool * @param minBptAmountOut Minimum amount of pool tokens to be received * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH * @param userData Additional (optional) data required for adding liquidity @@ -49,14 +48,14 @@ interface ICompositeLiquidityRouter { ) external payable returns (uint256 bptAmountOut); /** - * @notice Add proportional amounts of underlying tokens to an ERC4626 pool through the buffer. + * @notice Add proportional amounts of tokens to an ERC4626 pool through the buffer. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). Ensure that any buffers associated * with the wrapped tokens in the ERC4626 pool have been initialized before initializing or adding liquidity to * the "parent" pool, and also make sure limits are set properly. * * @param pool Address of the liquidity pool - * @param useAsStandardToken An array indicating whether to use the token as standard or wrap it, - * sorted in token registration order of wrapped tokens in the pool + * @param useAsStandardToken Flags indicating whether the corresponding token should be treated as an ERC4626 + * (unwrap and transfer the underlying asset) or as a standard ERC20 (transfer the wrapped token directly) * @param maxAmountsIn Maximum amounts of underlying/wrapped tokens in, sorted in token registration order * wrapped tokens in the pool * @param exactBptAmountOut Exact amount of pool tokens to be received @@ -75,14 +74,13 @@ interface ICompositeLiquidityRouter { ) external payable returns (address[] memory tokensIn, uint256[] memory amountsIn); /** - * @notice Remove proportional amounts of underlying from an ERC4626 pool, burning an exact pool token amount. + * @notice Remove proportional amounts of tokens from an ERC4626 pool, burning an exact pool token amount. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useAsStandardToken An array indicating whether to use the token as standard or unwrap it, - * sorted in token registration order of wrapped tokens in the pool + * @param useAsStandardToken Flags indicating whether the corresponding token should be treated as an ERC4626 + * (unwrap and transfer the underlying asset) or as a standard ERC20 (transfer the wrapped token directly) * @param exactBptAmountIn Exact amount of pool tokens provided - * @param minAmountsOut Minimum amounts of each token, sorted according to tokensIn array - * wrapped tokens in the pool + * @param minAmountsOut Minimum amounts of each token, corresponding to `tokensOut` * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH * @param userData Additional (optional) data required for removing liquidity * @return tokensOut Actual tokens received @@ -101,10 +99,9 @@ interface ICompositeLiquidityRouter { * @notice Queries an `addLiquidityUnbalancedToERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useAsStandardToken An array indicating whether to use the token as standard or wrap it, - * sorted in token registration order of wrapped tokens in the pool + * @param useAsStandardToken Flags indicating whether the corresponding token should be treated as an ERC4626 + * (unwrap and transfer the underlying asset) or as a standard ERC20 (transfer the wrapped token directly) * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order - * wrapped tokens in the pool * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query * @return bptAmountOut Expected amount of pool tokens to receive @@ -121,8 +118,8 @@ interface ICompositeLiquidityRouter { * @notice Queries an `addLiquidityProportionalToERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useAsStandardToken An array indicating whether to use the token as standard or wrap/unwrap it, - * sorted in token registration order of wrapped tokens in the pool + * @param useAsStandardToken Flags indicating whether the corresponding token should be treated as an ERC4626 + * (unwrap and transfer the underlying asset) or as a standard ERC20 (transfer the wrapped token directly) * @param exactBptAmountOut Exact amount of pool tokens to be received * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query @@ -141,8 +138,8 @@ interface ICompositeLiquidityRouter { * @notice Queries a `removeLiquidityProportionalFromERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useAsStandardToken An array indicating whether to use the token as standard or unwrap it, - * sorted in token registration order of wrapped tokens in the pool + * @param useAsStandardToken Flags indicating whether the corresponding token should be treated as an ERC4626 + * (unwrap and transfer the underlying asset) or as a standard ERC20 (transfer the wrapped token directly) * @param exactBptAmountIn Exact amount of pool tokens provided for the query * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query @@ -214,7 +211,7 @@ interface ICompositeLiquidityRouter { * @param tokensOut Output token addresses, sorted by user preference. `tokensOut` array must have all tokens from * child pools and all tokens that are not BPTs from the nested pool (parent pool). If not all tokens are informed, * balances are not settled and the operation reverts. Tokens that repeat must be informed only once. - * @param minAmountsOut Minimum amounts of each token, sorted according to tokensIn array + * @param minAmountsOut Minimum amounts of each outgoing token, corresponding to `tokensOut` * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH * @param userData Additional (optional) data required for the operation * @return amountsOut Actual amounts of tokens received, parallel to `tokensOut` From 2a58957bf1b1cdee462c8345422fa66ce75da145 Mon Sep 17 00:00:00 2001 From: elshan_eth <22689890+elshan-eth@users.noreply.github.com> Date: Fri, 17 Jan 2025 23:46:47 +0100 Subject: [PATCH 28/30] fix tests --- .../vault/ICompositeLiquidityRouter.sol | 36 ++-- .../contracts/CompositeLiquidityRouter.sol | 114 ++++++----- .../CompositeLiquidityRouterERC4626Pool.t.sol | 181 ++++++++++++------ 3 files changed, 196 insertions(+), 135 deletions(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index 0b6bdaca0..92fef4601 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -30,8 +30,8 @@ interface ICompositeLiquidityRouter { * the "parent" pool, and also make sure limits are set properly. * * @param pool Address of the liquidity pool - * @param useAsStandardToken Flags indicating whether the corresponding token should be treated as an ERC4626 - * (unwrap and transfer the underlying asset) or as a standard ERC20 (transfer the wrapped token directly) + * @param wrapUnderlying Flags indicating whether the corresponding token should be wrapped or + * use as a standard ERC20 * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order * @param minBptAmountOut Minimum amount of pool tokens to be received * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH @@ -40,7 +40,7 @@ interface ICompositeLiquidityRouter { */ function addLiquidityUnbalancedToERC4626Pool( address pool, - bool[] memory useAsStandardToken, + bool[] memory wrapUnderlying, uint256[] memory exactAmountsIn, uint256 minBptAmountOut, bool wethIsEth, @@ -54,8 +54,8 @@ interface ICompositeLiquidityRouter { * the "parent" pool, and also make sure limits are set properly. * * @param pool Address of the liquidity pool - * @param useAsStandardToken Flags indicating whether the corresponding token should be treated as an ERC4626 - * (unwrap and transfer the underlying asset) or as a standard ERC20 (transfer the wrapped token directly) + * @param wrapUnderlying Flags indicating whether the corresponding token should be wrapped or + * use as a standard ERC20 * @param maxAmountsIn Maximum amounts of underlying/wrapped tokens in, sorted in token registration order * wrapped tokens in the pool * @param exactBptAmountOut Exact amount of pool tokens to be received @@ -66,7 +66,7 @@ interface ICompositeLiquidityRouter { */ function addLiquidityProportionalToERC4626Pool( address pool, - bool[] memory useAsStandardToken, + bool[] memory wrapUnderlying, uint256[] memory maxAmountsIn, uint256 exactBptAmountOut, bool wethIsEth, @@ -77,8 +77,8 @@ interface ICompositeLiquidityRouter { * @notice Remove proportional amounts of tokens from an ERC4626 pool, burning an exact pool token amount. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useAsStandardToken Flags indicating whether the corresponding token should be treated as an ERC4626 - * (unwrap and transfer the underlying asset) or as a standard ERC20 (transfer the wrapped token directly) + * @param unwrapWrapper Flags indicating whether the corresponding token should be unwrapped or + * use as a standard ERC20 * @param exactBptAmountIn Exact amount of pool tokens provided * @param minAmountsOut Minimum amounts of each token, corresponding to `tokensOut` * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH @@ -88,7 +88,7 @@ interface ICompositeLiquidityRouter { */ function removeLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory useAsStandardToken, + bool[] memory unwrapWrapper, uint256 exactBptAmountIn, uint256[] memory minAmountsOut, bool wethIsEth, @@ -99,8 +99,8 @@ interface ICompositeLiquidityRouter { * @notice Queries an `addLiquidityUnbalancedToERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useAsStandardToken Flags indicating whether the corresponding token should be treated as an ERC4626 - * (unwrap and transfer the underlying asset) or as a standard ERC20 (transfer the wrapped token directly) + * @param wrapUnderlying Flags indicating whether the corresponding token should be wrapped or + * use as a standard ERC20 * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query @@ -108,7 +108,7 @@ interface ICompositeLiquidityRouter { */ function queryAddLiquidityUnbalancedToERC4626Pool( address pool, - bool[] memory useAsStandardToken, + bool[] memory wrapUnderlying, uint256[] memory exactAmountsIn, address sender, bytes memory userData @@ -118,8 +118,8 @@ interface ICompositeLiquidityRouter { * @notice Queries an `addLiquidityProportionalToERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useAsStandardToken Flags indicating whether the corresponding token should be treated as an ERC4626 - * (unwrap and transfer the underlying asset) or as a standard ERC20 (transfer the wrapped token directly) + * @param wrapUnderlying Flags indicating whether the corresponding token should be wrapped or + * use as a standard ERC20 * @param exactBptAmountOut Exact amount of pool tokens to be received * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query @@ -128,7 +128,7 @@ interface ICompositeLiquidityRouter { */ function queryAddLiquidityProportionalToERC4626Pool( address pool, - bool[] memory useAsStandardToken, + bool[] memory wrapUnderlying, uint256 exactBptAmountOut, address sender, bytes memory userData @@ -138,8 +138,8 @@ interface ICompositeLiquidityRouter { * @notice Queries a `removeLiquidityProportionalFromERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param useAsStandardToken Flags indicating whether the corresponding token should be treated as an ERC4626 - * (unwrap and transfer the underlying asset) or as a standard ERC20 (transfer the wrapped token directly) + * @param unwrapWrapper Flags indicating whether the corresponding token should be unwrapped or + * use as a standard ERC20 * @param exactBptAmountIn Exact amount of pool tokens provided for the query * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query @@ -148,7 +148,7 @@ interface ICompositeLiquidityRouter { */ function queryRemoveLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory useAsStandardToken, + bool[] memory unwrapWrapper, uint256 exactBptAmountIn, address sender, bytes memory userData diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index 70da4c2c1..883a4bb17 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -48,7 +48,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function addLiquidityUnbalancedToERC4626Pool( address pool, - bool[] memory useAsStandardToken, + bool[] memory wrapUnderlying, uint256[] memory exactAmountsIn, uint256 minBptAmountOut, bool wethIsEth, @@ -68,7 +68,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: wethIsEth, userData: userData }), - useAsStandardToken + wrapUnderlying ) ) ), @@ -79,7 +79,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function addLiquidityProportionalToERC4626Pool( address pool, - bool[] memory useAsStandardToken, + bool[] memory wrapUnderlying, uint256[] memory maxAmountsIn, uint256 exactBptAmountOut, bool wethIsEth, @@ -99,7 +99,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: wethIsEth, userData: userData }), - useAsStandardToken + wrapUnderlying ) ) ), @@ -110,7 +110,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function removeLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory useAsStandardToken, + bool[] memory unwrapWrapper, uint256 exactBptAmountIn, uint256[] memory minAmountsOut, bool wethIsEth, @@ -130,7 +130,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: wethIsEth, userData: userData }), - useAsStandardToken + unwrapWrapper ) ) ), @@ -141,7 +141,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function queryAddLiquidityUnbalancedToERC4626Pool( address pool, - bool[] memory useAsStandardToken, + bool[] memory wrapUnderlying, uint256[] memory exactAmountsIn, address sender, bytes memory userData @@ -160,7 +160,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: false, userData: userData }), - useAsStandardToken + wrapUnderlying ) ) ), @@ -171,7 +171,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function queryAddLiquidityProportionalToERC4626Pool( address pool, - bool[] memory useAsStandardToken, + bool[] memory wrapUnderlying, uint256 exactBptAmountOut, address sender, bytes memory userData @@ -190,7 +190,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: false, userData: userData }), - useAsStandardToken + wrapUnderlying ) ) ), @@ -201,7 +201,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function queryRemoveLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory useAsStandardToken, + bool[] memory unwrapWrapper, uint256 exactBptAmountIn, address sender, bytes memory userData @@ -221,7 +221,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: false, userData: userData }), - useAsStandardToken + unwrapWrapper ) ) ), @@ -231,17 +231,17 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo function addLiquidityERC4626PoolUnbalancedHook( AddLiquidityHookParams calldata params, - bool[] calldata useAsStandardToken + bool[] calldata wrapUnderlying ) external nonReentrant onlyVault returns (uint256 bptAmountOut) { IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; - // Revert if `poolTokens` length does not match `maxAmountsIn` and `useAsStandardToken`. - InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, useAsStandardToken.length); + // Revert if `poolTokens` length does not match `maxAmountsIn` and `wrapUnderlying`. + InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, wrapUnderlying.length); uint256[] memory amountsIn = _wrapTokensExactInIfRequired( params.sender, - useAsStandardToken, + wrapUnderlying, erc4626PoolTokens, params.maxAmountsIn, params.wethIsEth @@ -262,13 +262,13 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo function addLiquidityERC4626PoolProportionalHook( AddLiquidityHookParams calldata params, - bool[] calldata useAsStandardToken + bool[] calldata wrapUnderlying ) external nonReentrant onlyVault returns (address[] memory tokensIn, uint256[] memory amountsIn) { IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; - // Revert if `poolTokens` length does not match `maxAmountsIn` and `useAsStandardToken`. - InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, useAsStandardToken.length); + // Revert if `poolTokens` length does not match `maxAmountsIn` and `wrapUnderlying`. + InputHelpers.ensureInputLengthMatch(poolTokensLength, params.maxAmountsIn.length, wrapUnderlying.length); uint256[] memory maxAmounts = new uint256[](poolTokensLength); for (uint256 i = 0; i < poolTokensLength; ++i) { @@ -289,7 +289,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo (tokensIn, amountsIn) = _wrapTokensExactOutIfRequired( params.sender, - useAsStandardToken, + wrapUnderlying, erc4626PoolTokens, wrappedAmountsIn, params.maxAmountsIn, @@ -299,13 +299,13 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo function removeLiquidityERC4626PoolProportionalHook( RemoveLiquidityHookParams calldata params, - bool[] calldata useAsStandardToken + bool[] calldata unwrapWrapper ) external nonReentrant onlyVault returns (address[] memory tokensOut, uint256[] memory amountsOut) { IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; - // Revert if `poolTokens` length does not match `minAmountsOut` and `useAsStandardToken`. - InputHelpers.ensureInputLengthMatch(poolTokensLength, params.minAmountsOut.length, useAsStandardToken.length); + // Revert if `poolTokens` length does not match `minAmountsOut` and `unwrapWrapper`. + InputHelpers.ensureInputLengthMatch(poolTokensLength, params.minAmountsOut.length, unwrapWrapper.length); amountsOut = new uint256[](poolTokensLength); @@ -327,18 +327,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); - if (useAsStandardToken[i]) { - amountsOut[i] = wrappedAmountsOut[i]; - tokensOut[i] = address(wrappedToken); - - if (amountsOut[i] < params.minAmountsOut[i]) { - revert IVaultErrors.AmountOutBelowMin(erc4626PoolTokens[i], amountsOut[i], params.minAmountsOut[i]); - } - - if (isStaticCall == false) { - _sendTokenOut(params.sender, erc4626PoolTokens[i], amountsOut[i], params.wethIsEth); - } - } else { + if (unwrapWrapper[i]) { if (address(underlyingToken) == address(0)) { revert IVaultErrors.BufferNotInitialized(wrappedToken); } @@ -355,21 +344,28 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo ); tokensOut[i] = address(underlyingToken); - if (amountsOut[i] < params.minAmountsOut[i]) { - revert IVaultErrors.AmountOutBelowMin(underlyingToken, amountsOut[i], params.minAmountsOut[i]); + if (isStaticCall == false) { + _sendTokenOut(params.sender, underlyingToken, amountsOut[i], params.wethIsEth); } + } else { + amountsOut[i] = wrappedAmountsOut[i]; + tokensOut[i] = address(wrappedToken); if (isStaticCall == false) { - _sendTokenOut(params.sender, underlyingToken, amountsOut[i], params.wethIsEth); + _sendTokenOut(params.sender, erc4626PoolTokens[i], amountsOut[i], params.wethIsEth); } } + + if (amountsOut[i] < params.minAmountsOut[i]) { + revert IVaultErrors.AmountOutBelowMin(IERC20(tokensOut[i]), amountsOut[i], params.minAmountsOut[i]); + } } } /// @dev Assumes array lengths have been checked externally. function _wrapTokensExactInIfRequired( address sender, - bool[] memory useAsStandardToken, + bool[] memory wrapUnderlying, IERC20[] memory erc4626PoolTokens, uint256[] memory amountsIn, bool wethIsEth @@ -387,13 +383,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo // Check whether the caller wants to use the token as an ERC4626 (i.e., wrap/unwrap it), or just use it as // a standard token. - if (useAsStandardToken[i]) { - wrappedAmountsIn[i] = amountsIn[i]; - - if (isStaticCall == false) { - _takeTokenIn(sender, wrappedToken, wrappedAmountsIn[i], wethIsEth); - } - } else { + if (wrapUnderlying[i]) { if (address(underlyingToken) == address(0)) { revert IVaultErrors.BufferNotInitialized(wrappedToken); } @@ -418,6 +408,12 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo } wrappedAmountsIn[i] = wrappedAmount; + } else { + wrappedAmountsIn[i] = amountsIn[i]; + + if (isStaticCall == false) { + _takeTokenIn(sender, wrappedToken, wrappedAmountsIn[i], wethIsEth); + } } } @@ -428,7 +424,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @dev Assumes array lengths have been checked externally. function _wrapTokensExactOutIfRequired( address sender, - bool[] memory useAsStandardToken, + bool[] memory wrapUnderlying, IERC20[] memory erc4626PoolTokens, uint256[] memory wrappedAmountsIn, uint256[] memory maxAmountsIn, @@ -449,18 +445,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo // Check whether the caller wants to use the token as an ERC4626 (i.e., wrap/unwrap it), or just use it as // a standard token. - if (useAsStandardToken[i]) { - if (wrappedAmountsIn[i] > maxAmountsIn[i]) { - revert IVaultErrors.AmountInAboveMax(wrappedToken, wrappedAmountsIn[i], maxAmountsIn[i]); - } - - if (isStaticCall == false) { - _takeTokenIn(sender, wrappedToken, wrappedAmountsIn[i], wethIsEth); - } - - amountsIn[i] = wrappedAmountsIn[i]; - tokensIn[i] = address(wrappedToken); - } else { + if (wrapUnderlying[i]) { if (address(underlyingToken) == address(0)) { revert IVaultErrors.BufferNotInitialized(wrappedToken); } @@ -498,6 +483,17 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo amountsIn[i] = underlyingAmount; tokensIn[i] = address(underlyingToken); + } else { + if (wrappedAmountsIn[i] > maxAmountsIn[i]) { + revert IVaultErrors.AmountInAboveMax(wrappedToken, wrappedAmountsIn[i], maxAmountsIn[i]); + } + + if (isStaticCall == false) { + _takeTokenIn(sender, wrappedToken, wrappedAmountsIn[i], wethIsEth); + } + + amountsIn[i] = wrappedAmountsIn[i]; + tokensIn[i] = address(wrappedToken); } } diff --git a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol index 1641816a0..7ef5861b3 100644 --- a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol +++ b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol @@ -109,10 +109,15 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); + bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); + for (uint256 i = 0; i < wrapUnderlying.length; i++) { + wrapUnderlying[i] = true; + } + vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( pool, - new bool[](exactUnderlyingAmountsIn.length), + wrapUnderlying, exactUnderlyingAmountsIn, 1, false, @@ -142,8 +147,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { exactWrappedAmountsIn[waDaiIdx] = operationAmount; exactWrappedAmountsIn[waWethIdx] = _vaultPreviewDeposit(waWETH, operationAmount); - bool[] memory useAsStandardToken = new bool[](exactUnderlyingAmountsIn.length); - useAsStandardToken[waDaiIdx] = true; + bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); + wrapUnderlying[waWethIdx] = true; uint256 snapshot = vm.snapshot(); _prankStaticCall(); @@ -160,7 +165,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( pool, - useAsStandardToken, + wrapUnderlying, exactUnderlyingAmountsIn, 1, false, @@ -205,10 +210,15 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); + bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); + for (uint256 i = 0; i < wrapUnderlying.length; i++) { + wrapUnderlying[i] = true; + } + vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) - }(pool, new bool[](exactUnderlyingAmountsIn.length), exactUnderlyingAmountsIn, 1, true, bytes("")); + }(pool, wrapUnderlying, exactUnderlyingAmountsIn, 1, true, bytes("")); TestBalances memory balancesAfter = _getTestBalances(alice); @@ -249,10 +259,15 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); + bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); + for (uint256 i = 0; i < wrapUnderlying.length; i++) { + wrapUnderlying[i] = true; + } + vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( pool, - new bool[](exactUnderlyingAmountsIn.length), + wrapUnderlying, exactUnderlyingAmountsIn, 1, false, @@ -294,13 +309,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory useAsStandardToken = new bool[](exactUnderlyingAmountsIn.length); - useAsStandardToken[partialWethIdx] = true; + bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); + wrapUnderlying[partialWaDaiIdx] = true; vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, - useAsStandardToken, + wrapUnderlying, exactUnderlyingAmountsIn, 0, false, @@ -344,13 +359,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory useAsStandardToken = new bool[](exactUnderlyingAmountsIn.length); - useAsStandardToken[partialWethIdx] = true; + bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); + wrapUnderlying[partialWaDaiIdx] = true; vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) - }(partialErc4626Pool, useAsStandardToken, exactUnderlyingAmountsIn, 0, true, bytes("")); + }(partialErc4626Pool, wrapUnderlying, exactUnderlyingAmountsIn, 0, true, bytes("")); TestBalances memory balancesAfter = _getTestBalances(alice); @@ -371,10 +386,15 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 operationAmount = bufferInitialAmount / 2; uint256[] memory exactUnderlyingAmountsIn = [operationAmount, operationAmount].toMemoryArray(); + bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); + for (uint256 i = 0; i < wrapUnderlying.length; i++) { + wrapUnderlying[i] = true; + } + _prankStaticCall(); compositeLiquidityRouter.queryAddLiquidityUnbalancedToERC4626Pool( pool, - new bool[](exactUnderlyingAmountsIn.length), + wrapUnderlying, exactUnderlyingAmountsIn, address(this), bytes("") @@ -385,11 +405,16 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 operationAmount = bufferInitialAmount / 2; uint256[] memory exactUnderlyingAmountsIn = [operationAmount, operationAmount].toMemoryArray(); + bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); + for (uint256 i = 0; i < wrapUnderlying.length; i++) { + wrapUnderlying[i] = true; + } + uint256 snapshotId = vm.snapshot(); _prankStaticCall(); uint256 queryBptAmountOut = compositeLiquidityRouter.queryAddLiquidityUnbalancedToERC4626Pool( pool, - new bool[](exactUnderlyingAmountsIn.length), + wrapUnderlying, exactUnderlyingAmountsIn, address(this), bytes("") @@ -399,7 +424,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 actualBptAmountOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( pool, - new bool[](exactUnderlyingAmountsIn.length), + wrapUnderlying, exactUnderlyingAmountsIn, 1, false, @@ -413,11 +438,16 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 operationAmount = bufferInitialAmount / 2; uint256[] memory exactUnderlyingAmountsIn = [0, operationAmount].toMemoryArray(); + bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); + for (uint256 i = 0; i < wrapUnderlying.length; i++) { + wrapUnderlying[i] = true; + } + uint256 snapshotId = vm.snapshot(); _prankStaticCall(); uint256 queryBptAmountOut = compositeLiquidityRouter.queryAddLiquidityUnbalancedToERC4626Pool( pool, - new bool[](exactUnderlyingAmountsIn.length), + wrapUnderlying, exactUnderlyingAmountsIn, address(this), bytes("") @@ -427,7 +457,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 actualBptAmountOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( pool, - new bool[](exactUnderlyingAmountsIn.length), + wrapUnderlying, exactUnderlyingAmountsIn, 1, false, @@ -441,14 +471,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 operationAmount = bufferInitialAmount / 2; uint256[] memory exactUnderlyingAmountsIn = [operationAmount, operationAmount].toMemoryArray(); - bool[] memory useAsStandardToken = new bool[](exactUnderlyingAmountsIn.length); - useAsStandardToken[partialWethIdx] = true; + bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); + wrapUnderlying[partialWaDaiIdx] = true; uint256 snapshotId = vm.snapshot(); _prankStaticCall(); uint256 queryBptAmountOut = compositeLiquidityRouter.queryAddLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, - useAsStandardToken, + wrapUnderlying, exactUnderlyingAmountsIn, address(this), bytes("") @@ -458,7 +488,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); uint256 actualBptAmountOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( partialErc4626Pool, - useAsStandardToken, + wrapUnderlying, exactUnderlyingAmountsIn, 1, false, @@ -486,10 +516,15 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); + bool[] memory wrapUnderlying = new bool[](maxAmountsIn.length); + for (uint256 i = 0; i < wrapUnderlying.length; i++) { + wrapUnderlying[i] = true; + } + vm.prank(alice); (, uint256[] memory actualUnderlyingAmountsIn) = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( pool, - new bool[](maxAmountsIn.length), + wrapUnderlying, maxAmountsIn, exactBptAmountOut, false, @@ -542,10 +577,15 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); + bool[] memory wrapUnderlying = new bool[](maxAmountsIn.length); + for (uint256 i = 0; i < wrapUnderlying.length; i++) { + wrapUnderlying[i] = true; + } + vm.prank(alice); (, uint256[] memory actualUnderlyingAmountsIn) = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) - }(pool, new bool[](maxAmountsIn.length), maxAmountsIn, exactBptAmountOut, true, bytes("")); + }(pool, wrapUnderlying, maxAmountsIn, exactBptAmountOut, true, bytes("")); TestBalances memory balancesAfter = _getTestBalances(alice); @@ -599,13 +639,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory useAsStandardToken = new bool[](maxAmountsIn.length); - useAsStandardToken[partialWethIdx] = true; + bool[] memory wrapUnderlying = new bool[](maxAmountsIn.length); + wrapUnderlying[partialWaDaiIdx] = true; vm.prank(alice); (, uint256[] memory actualUnderlyingAmountsIn) = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, - useAsStandardToken, + wrapUnderlying, maxAmountsIn, exactBptAmountOut, false, @@ -665,13 +705,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory useAsStandardToken = new bool[](maxAmountsIn.length); - useAsStandardToken[partialWethIdx] = true; + bool[] memory wrapUnderlying = new bool[](maxAmountsIn.length); + wrapUnderlying[partialWaDaiIdx] = true; vm.prank(alice); (, uint256[] memory actualUnderlyingAmountsIn) = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool{ value: operationAmount + (forceEthLeftover ? 1e18 : 0) - }(partialErc4626Pool, useAsStandardToken, maxAmountsIn, exactBptAmountOut, true, bytes("")); + }(partialErc4626Pool, wrapUnderlying, maxAmountsIn, exactBptAmountOut, true, bytes("")); TestBalances memory balancesAfter = _getTestBalances(alice); @@ -701,10 +741,15 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { function testAddLiquidityProportionalToERC4626PoolWhenStaticCall() public checkBuffersWhenStaticCall(alice) { uint256 operationAmount = bufferInitialAmount / 2; + bool[] memory wrapUnderlying = new bool[](2); + for (uint256 i = 0; i < wrapUnderlying.length; i++) { + wrapUnderlying[i] = true; + } + _prankStaticCall(); compositeLiquidityRouter.queryAddLiquidityProportionalToERC4626Pool( pool, - new bool[](2), + wrapUnderlying, operationAmount, address(this), bytes("") @@ -732,8 +777,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { maxAmountsIn[partialWaDaiIdx] = operationAmount; maxAmountsIn[partialWethIdx] = expectedWrappedAmountsIn[partialWethIdx] - 1; - bool[] memory useAsStandardToken = new bool[](maxAmountsIn.length); - useAsStandardToken[partialWethIdx] = true; + bool[] memory wrapUnderlying = new bool[](maxAmountsIn.length); + wrapUnderlying[partialWaDaiIdx] = true; vm.expectRevert( abi.encodeWithSelector( @@ -746,7 +791,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, - useAsStandardToken, + wrapUnderlying, maxAmountsIn, exactBptAmountOut, false, @@ -759,12 +804,17 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256[] memory maxAmountsIn = [operationAmount, operationAmount].toMemoryArray(); uint256 exactBptAmountOut = operationAmount; + bool[] memory wrapUnderlying = new bool[](maxAmountsIn.length); + for (uint256 i = 0; i < wrapUnderlying.length; i++) { + wrapUnderlying[i] = true; + } + uint256 snapshotId = vm.snapshot(); _prankStaticCall(); (, uint256[] memory queryUnderlyingAmountsIn) = compositeLiquidityRouter .queryAddLiquidityProportionalToERC4626Pool( pool, - new bool[](maxAmountsIn.length), + wrapUnderlying, exactBptAmountOut, address(this), bytes("") @@ -774,7 +824,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); (, uint256[] memory actualUnderlyingAmountsIn) = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( pool, - new bool[](maxAmountsIn.length), + wrapUnderlying, maxAmountsIn, exactBptAmountOut, false, @@ -795,15 +845,15 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256[] memory maxAmountsIn = [operationAmount, operationAmount].toMemoryArray(); uint256 exactBptAmountOut = operationAmount; - bool[] memory useAsStandardToken = new bool[](maxAmountsIn.length); - useAsStandardToken[partialWethIdx] = true; + bool[] memory wrapUnderlying = new bool[](maxAmountsIn.length); + wrapUnderlying[partialWaDaiIdx] = true; uint256 snapshotId = vm.snapshot(); _prankStaticCall(); (, uint256[] memory queryUnderlyingAmountsIn) = compositeLiquidityRouter .queryAddLiquidityProportionalToERC4626Pool( partialErc4626Pool, - useAsStandardToken, + wrapUnderlying, exactBptAmountOut, address(this), bytes("") @@ -813,7 +863,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(alice); (, uint256[] memory actualUnderlyingAmountsIn) = compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( partialErc4626Pool, - useAsStandardToken, + wrapUnderlying, maxAmountsIn, exactBptAmountOut, false, @@ -854,11 +904,16 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); + bool[] memory unwrapWrapper = new bool[](minAmountsOut.length); + for (uint256 i = 0; i < unwrapWrapper.length; i++) { + unwrapWrapper[i] = true; + } + vm.prank(bob); (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( pool, - new bool[](minAmountsOut.length), + unwrapWrapper, exactBptAmountIn, minAmountsOut, false, @@ -910,8 +965,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { minAmountsOut[waWethIdx] = _vaultPreviewRedeem(waWETH, expectedWrappedAmountsOut[waWethIdx]); minAmountsOut[waDaiIdx] = expectedWrappedAmountsOut[waDaiIdx]; - bool[] memory useAsStandardToken = new bool[](2); - useAsStandardToken[waDaiIdx] = true; + bool[] memory unwrapWrapper = new bool[](minAmountsOut.length); + unwrapWrapper[waWethIdx] = true; TestBalances memory balancesBefore = _getTestBalances(bob); @@ -919,7 +974,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( pool, - useAsStandardToken, + unwrapWrapper, exactBptAmountIn, minAmountsOut, false, @@ -973,11 +1028,16 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); + bool[] memory unwrapWrapper = new bool[](minAmountsOut.length); + for (uint256 i = 0; i < unwrapWrapper.length; i++) { + unwrapWrapper[i] = true; + } + vm.prank(bob); (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( pool, - new bool[](minAmountsOut.length), + unwrapWrapper, exactBptAmountIn, minAmountsOut, true, @@ -1032,14 +1092,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); - bool[] memory useAsStandardToken = new bool[](minAmountsOut.length); - useAsStandardToken[partialWethIdx] = true; + bool[] memory unwrapWrapper = new bool[](minAmountsOut.length); + unwrapWrapper[partialWaDaiIdx] = true; vm.prank(bob); (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - useAsStandardToken, + unwrapWrapper, exactBptAmountIn, minAmountsOut, false, @@ -1093,14 +1153,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); - bool[] memory useAsStandardToken = new bool[](minAmountsOut.length); - useAsStandardToken[partialWethIdx] = true; + bool[] memory unwrapWrapper = new bool[](minAmountsOut.length); + unwrapWrapper[partialWaDaiIdx] = true; vm.prank(bob); (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - useAsStandardToken, + unwrapWrapper, exactBptAmountIn, minAmountsOut, true, @@ -1137,10 +1197,15 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { function testRemoveLiquidityProportionalFromERC4626PoolWhenStaticCall() public checkBuffersWhenStaticCall(bob) { uint256 exactBptAmountIn = bufferInitialAmount / 2; + bool[] memory unwrapWrapper = new bool[](2); + for (uint256 i = 0; i < unwrapWrapper.length; i++) { + unwrapWrapper[i] = true; + } + _prankStaticCall(); compositeLiquidityRouter.queryRemoveLiquidityProportionalFromERC4626Pool( pool, - new bool[](2), + unwrapWrapper, exactBptAmountIn, address(this), bytes("") @@ -1165,8 +1230,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { minAmountsOut[partialWethIdx] = expectedWrappedAmountsOut[partialWethIdx] + 1; minAmountsOut[partialWaDaiIdx] = _vaultPreviewRedeem(waDAI, expectedWrappedAmountsOut[partialWaDaiIdx]); - bool[] memory useAsStandardToken = new bool[](minAmountsOut.length); - useAsStandardToken[partialWethIdx] = true; + bool[] memory unwrapWrapper = new bool[](minAmountsOut.length); + unwrapWrapper[partialWaDaiIdx] = true; vm.expectRevert( abi.encodeWithSelector( @@ -1179,7 +1244,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(bob); compositeLiquidityRouter.removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - useAsStandardToken, + unwrapWrapper, exactBptAmountIn, minAmountsOut, false, @@ -1256,15 +1321,15 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { expectedWrappedAmountsOut[partialWaDaiIdx] ); - bool[] memory useAsStandardToken = new bool[](minUnderlyingAmountsOut.length); - useAsStandardToken[partialWethIdx] = true; + bool[] memory unwrapWrapper = new bool[](minUnderlyingAmountsOut.length); + unwrapWrapper[partialWaDaiIdx] = true; uint256 snapshotId = vm.snapshot(); _prankStaticCall(); (, uint256[] memory queryUnderlyingAmountsOut) = compositeLiquidityRouter .queryRemoveLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - useAsStandardToken, + unwrapWrapper, exactBptAmountIn, address(this), bytes("") @@ -1275,7 +1340,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - useAsStandardToken, + unwrapWrapper, exactBptAmountIn, minUnderlyingAmountsOut, false, From 07480903926060fc49a5aca1af637a4a6995479d Mon Sep 17 00:00:00 2001 From: elshan_eth <22689890+elshan-eth@users.noreply.github.com> Date: Sat, 18 Jan 2025 00:21:15 +0100 Subject: [PATCH 29/30] add rest tests --- .../contracts/CompositeLiquidityRouter.sol | 12 ++-- .../CompositeLiquidityRouterERC4626Pool.t.sol | 72 +++++++++++++++++++ 2 files changed, 76 insertions(+), 8 deletions(-) diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index 883a4bb17..b6b933907 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -471,10 +471,6 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo ); } - if (underlyingAmount > maxAmountsIn[i]) { - revert IVaultErrors.AmountInAboveMax(underlyingToken, underlyingAmount, maxAmountsIn[i]); - } - if (isStaticCall == false) { // The maxAmountsIn of underlying tokens was taken from the user, so the // difference between maxAmountsIn and exact underlying amount needs to be returned to the sender. @@ -484,10 +480,6 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo amountsIn[i] = underlyingAmount; tokensIn[i] = address(underlyingToken); } else { - if (wrappedAmountsIn[i] > maxAmountsIn[i]) { - revert IVaultErrors.AmountInAboveMax(wrappedToken, wrappedAmountsIn[i], maxAmountsIn[i]); - } - if (isStaticCall == false) { _takeTokenIn(sender, wrappedToken, wrappedAmountsIn[i], wethIsEth); } @@ -495,6 +487,10 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo amountsIn[i] = wrappedAmountsIn[i]; tokensIn[i] = address(wrappedToken); } + + if (amountsIn[i] > maxAmountsIn[i]) { + revert IVaultErrors.AmountInAboveMax(IERC20(tokensIn[i]), amountsIn[i], maxAmountsIn[i]); + } } // If there's a leftover of eth, send it back to the sender. The router should not keep ETH. diff --git a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol index 7ef5861b3..e1733060f 100644 --- a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol +++ b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol @@ -1370,6 +1370,78 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { assertEq(compositeLiquidityRouter.version(), MOCK_CL_ROUTER_VERSION, "CL BatchRouter version mismatch"); } + function testAddLiquidityERC4626PoolProportionalIfAmountAboveMax() public { + uint256 exactBptAmountOut = bufferInitialAmount / 2; + + uint256 snapshot = vm.snapshot(); + _prankStaticCall(); + uint256[] memory expectedWrappedAmountsIn = router.queryAddLiquidityProportional( + pool, + exactBptAmountOut, + address(this), + bytes("") + ); + vm.revertTo(snapshot); + + uint256[] memory maxAmountsIn = new uint256[](2); + maxAmountsIn[waDaiIdx] = expectedWrappedAmountsIn[waDaiIdx] - 1; + maxAmountsIn[waWethIdx] = expectedWrappedAmountsIn[waWethIdx]; + + vm.expectRevert( + abi.encodeWithSelector( + IVaultErrors.AmountInAboveMax.selector, + waDAI, + expectedWrappedAmountsIn[waDaiIdx], + maxAmountsIn[waDaiIdx] + ) + ); + vm.prank(alice); + compositeLiquidityRouter.addLiquidityProportionalToERC4626Pool( + pool, + new bool[](maxAmountsIn.length), + maxAmountsIn, + exactBptAmountOut, + false, + bytes("") + ); + } + + function testRemoveLiquidityProportionalFromERC4626PoolIfAmountBelowMin() public { + uint256 exactBptAmountIn = bufferInitialAmount / 2; + + uint256 snapshot = vm.snapshot(); + _prankStaticCall(); + uint256[] memory expectedWrappedAmountsOut = router.queryRemoveLiquidityProportional( + pool, + exactBptAmountIn, + address(this), + bytes("") + ); + vm.revertTo(snapshot); + + uint256[] memory minAmountsOut = new uint256[](2); + minAmountsOut[waDaiIdx] = _vaultPreviewRedeem(waDAI, expectedWrappedAmountsOut[waDaiIdx]); + minAmountsOut[waWethIdx] = expectedWrappedAmountsOut[waWethIdx] + 1; + + vm.expectRevert( + abi.encodeWithSelector( + IVaultErrors.AmountOutBelowMin.selector, + waWETH, + expectedWrappedAmountsOut[waWethIdx], + minAmountsOut[waWethIdx] + ) + ); + vm.prank(bob); + compositeLiquidityRouter.removeLiquidityProportionalFromERC4626Pool( + pool, + new bool[](minAmountsOut.length), + exactBptAmountIn, + minAmountsOut, + false, + bytes("") + ); + } + struct TestLocals { uint256 underlyingDaiAmountDelta; uint256 underlyingWethAmountDelta; From c2943caa7c4e977586457becfc1e83f84d033c56 Mon Sep 17 00:00:00 2001 From: elshan_eth <22689890+elshan-eth@users.noreply.github.com> Date: Mon, 20 Jan 2025 12:49:28 +0100 Subject: [PATCH 30/30] fix naming --- .../vault/ICompositeLiquidityRouter.sol | 20 ++-- .../contracts/CompositeLiquidityRouter.sol | 16 +-- .../CompositeLiquidityRouterERC4626Pool.t.sol | 99 +++++++++---------- 3 files changed, 62 insertions(+), 73 deletions(-) diff --git a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol index 92fef4601..fc84b8b8e 100644 --- a/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol +++ b/pkg/interfaces/contracts/vault/ICompositeLiquidityRouter.sol @@ -31,7 +31,7 @@ interface ICompositeLiquidityRouter { * * @param pool Address of the liquidity pool * @param wrapUnderlying Flags indicating whether the corresponding token should be wrapped or - * use as a standard ERC20 + * used as a standard ERC20 * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order * @param minBptAmountOut Minimum amount of pool tokens to be received * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH @@ -55,7 +55,7 @@ interface ICompositeLiquidityRouter { * * @param pool Address of the liquidity pool * @param wrapUnderlying Flags indicating whether the corresponding token should be wrapped or - * use as a standard ERC20 + * used as a standard ERC20 * @param maxAmountsIn Maximum amounts of underlying/wrapped tokens in, sorted in token registration order * wrapped tokens in the pool * @param exactBptAmountOut Exact amount of pool tokens to be received @@ -77,8 +77,8 @@ interface ICompositeLiquidityRouter { * @notice Remove proportional amounts of tokens from an ERC4626 pool, burning an exact pool token amount. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param unwrapWrapper Flags indicating whether the corresponding token should be unwrapped or - * use as a standard ERC20 + * @param unwrapWrapped Flags indicating whether the corresponding token should be unwrapped or + * used as a standard ERC20 * @param exactBptAmountIn Exact amount of pool tokens provided * @param minAmountsOut Minimum amounts of each token, corresponding to `tokensOut` * @param wethIsEth If true, incoming ETH will be wrapped to WETH and outgoing WETH will be unwrapped to ETH @@ -88,7 +88,7 @@ interface ICompositeLiquidityRouter { */ function removeLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory unwrapWrapper, + bool[] memory unwrapWrapped, uint256 exactBptAmountIn, uint256[] memory minAmountsOut, bool wethIsEth, @@ -100,7 +100,7 @@ interface ICompositeLiquidityRouter { * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool * @param wrapUnderlying Flags indicating whether the corresponding token should be wrapped or - * use as a standard ERC20 + * used as a standard ERC20 * @param exactAmountsIn Exact amounts of underlying/wrapped tokens in, sorted in token registration order * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query @@ -119,7 +119,7 @@ interface ICompositeLiquidityRouter { * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool * @param wrapUnderlying Flags indicating whether the corresponding token should be wrapped or - * use as a standard ERC20 + * used as a standard ERC20 * @param exactBptAmountOut Exact amount of pool tokens to be received * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query @@ -138,8 +138,8 @@ interface ICompositeLiquidityRouter { * @notice Queries a `removeLiquidityProportionalFromERC4626Pool` operation without actually executing it. * @dev An "ERC4626 pool" contains IERC4626 yield-bearing tokens (e.g., waDAI). * @param pool Address of the liquidity pool - * @param unwrapWrapper Flags indicating whether the corresponding token should be unwrapped or - * use as a standard ERC20 + * @param unwrapWrapped Flags indicating whether the corresponding token should be unwrapped or + * used as a standard ERC20 * @param exactBptAmountIn Exact amount of pool tokens provided for the query * @param sender The sender passed to the operation. It can influence results (e.g., with user-dependent hooks) * @param userData Additional (optional) data required for the query @@ -148,7 +148,7 @@ interface ICompositeLiquidityRouter { */ function queryRemoveLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory unwrapWrapper, + bool[] memory unwrapWrapped, uint256 exactBptAmountIn, address sender, bytes memory userData diff --git a/pkg/vault/contracts/CompositeLiquidityRouter.sol b/pkg/vault/contracts/CompositeLiquidityRouter.sol index f6f73a2e1..1effba3a1 100644 --- a/pkg/vault/contracts/CompositeLiquidityRouter.sol +++ b/pkg/vault/contracts/CompositeLiquidityRouter.sol @@ -114,7 +114,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function removeLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory unwrapWrapper, + bool[] memory unwrapWrapped, uint256 exactBptAmountIn, uint256[] memory minAmountsOut, bool wethIsEth, @@ -134,7 +134,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: wethIsEth, userData: userData }), - unwrapWrapper + unwrapWrapped ) ) ), @@ -205,7 +205,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo /// @inheritdoc ICompositeLiquidityRouter function queryRemoveLiquidityProportionalFromERC4626Pool( address pool, - bool[] memory unwrapWrapper, + bool[] memory unwrapWrapped, uint256 exactBptAmountIn, address sender, bytes memory userData @@ -225,7 +225,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo wethIsEth: false, userData: userData }), - unwrapWrapper + unwrapWrapped ) ) ), @@ -303,13 +303,13 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo function removeLiquidityERC4626PoolProportionalHook( RemoveLiquidityHookParams calldata params, - bool[] calldata unwrapWrapper + bool[] calldata unwrapWrapped ) external nonReentrant onlyVault returns (address[] memory tokensOut, uint256[] memory amountsOut) { IERC20[] memory erc4626PoolTokens = _vault.getPoolTokens(params.pool); uint256 poolTokensLength = erc4626PoolTokens.length; - // Revert if `poolTokens` length does not match `minAmountsOut` and `unwrapWrapper`. - InputHelpers.ensureInputLengthMatch(poolTokensLength, params.minAmountsOut.length, unwrapWrapper.length); + // Revert if `poolTokens` length does not match `minAmountsOut` and `unwrapWrapped`. + InputHelpers.ensureInputLengthMatch(poolTokensLength, params.minAmountsOut.length, unwrapWrapped.length); amountsOut = new uint256[](poolTokensLength); @@ -331,7 +331,7 @@ contract CompositeLiquidityRouter is ICompositeLiquidityRouter, BatchRouterCommo IERC4626 wrappedToken = IERC4626(address(erc4626PoolTokens[i])); IERC20 underlyingToken = IERC20(_vault.getBufferAsset(wrappedToken)); - if (unwrapWrapper[i]) { + if (unwrapWrapped[i]) { if (address(underlyingToken) == address(0)) { revert IVaultErrors.BufferNotInitialized(wrappedToken); } diff --git a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol index d3e666439..27898cb27 100644 --- a/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol +++ b/pkg/vault/test/foundry/CompositeLiquidityRouterERC4626Pool.t.sol @@ -109,10 +109,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); - for (uint256 i = 0; i < wrapUnderlying.length; i++) { - wrapUnderlying[i] = true; - } + bool[] memory wrapUnderlying = _getDefaultWrapUnderlying(exactUnderlyingAmountsIn.length); vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( @@ -210,10 +207,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); - for (uint256 i = 0; i < wrapUnderlying.length; i++) { - wrapUnderlying[i] = true; - } + bool[] memory wrapUnderlying = _getDefaultWrapUnderlying(exactUnderlyingAmountsIn.length); vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool{ @@ -259,10 +253,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(alice); - bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); - for (uint256 i = 0; i < wrapUnderlying.length; i++) { - wrapUnderlying[i] = true; - } + bool[] memory wrapUnderlying = _getDefaultWrapUnderlying(exactUnderlyingAmountsIn.length); vm.prank(alice); uint256 bptOut = compositeLiquidityRouter.addLiquidityUnbalancedToERC4626Pool( @@ -386,10 +377,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 operationAmount = bufferInitialAmount / 2; uint256[] memory exactUnderlyingAmountsIn = [operationAmount, operationAmount].toMemoryArray(); - bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); - for (uint256 i = 0; i < wrapUnderlying.length; i++) { - wrapUnderlying[i] = true; - } + bool[] memory wrapUnderlying = _getDefaultWrapUnderlying(exactUnderlyingAmountsIn.length); _prankStaticCall(); compositeLiquidityRouter.queryAddLiquidityUnbalancedToERC4626Pool( @@ -405,10 +393,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 operationAmount = bufferInitialAmount / 2; uint256[] memory exactUnderlyingAmountsIn = [operationAmount, operationAmount].toMemoryArray(); - bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); - for (uint256 i = 0; i < wrapUnderlying.length; i++) { - wrapUnderlying[i] = true; - } + bool[] memory wrapUnderlying = _getDefaultWrapUnderlying(exactUnderlyingAmountsIn.length); uint256 snapshotId = vm.snapshot(); _prankStaticCall(); @@ -438,10 +423,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { uint256 operationAmount = bufferInitialAmount / 2; uint256[] memory exactUnderlyingAmountsIn = [0, operationAmount].toMemoryArray(); - bool[] memory wrapUnderlying = new bool[](exactUnderlyingAmountsIn.length); - for (uint256 i = 0; i < wrapUnderlying.length; i++) { - wrapUnderlying[i] = true; - } + bool[] memory wrapUnderlying = _getDefaultWrapUnderlying(exactUnderlyingAmountsIn.length); uint256 snapshotId = vm.snapshot(); _prankStaticCall(); @@ -904,16 +886,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); - bool[] memory unwrapWrapper = new bool[](minAmountsOut.length); - for (uint256 i = 0; i < unwrapWrapper.length; i++) { - unwrapWrapper[i] = true; - } + bool[] memory unwrapWrapped = _getDefaultUnwrapWrapped(minAmountsOut.length); vm.prank(bob); (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( pool, - unwrapWrapper, + unwrapWrapped, exactBptAmountIn, minAmountsOut, false, @@ -965,8 +944,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { minAmountsOut[waWethIdx] = _vaultPreviewRedeem(waWETH, expectedWrappedAmountsOut[waWethIdx]); minAmountsOut[waDaiIdx] = expectedWrappedAmountsOut[waDaiIdx]; - bool[] memory unwrapWrapper = new bool[](minAmountsOut.length); - unwrapWrapper[waWethIdx] = true; + bool[] memory unwrapWrapped = new bool[](minAmountsOut.length); + unwrapWrapped[waWethIdx] = true; TestBalances memory balancesBefore = _getTestBalances(bob); @@ -974,7 +953,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( pool, - unwrapWrapper, + unwrapWrapped, exactBptAmountIn, minAmountsOut, false, @@ -1028,16 +1007,13 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); - bool[] memory unwrapWrapper = new bool[](minAmountsOut.length); - for (uint256 i = 0; i < unwrapWrapper.length; i++) { - unwrapWrapper[i] = true; - } + bool[] memory unwrapWrapped = _getDefaultUnwrapWrapped(minAmountsOut.length); vm.prank(bob); (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( pool, - unwrapWrapper, + unwrapWrapped, exactBptAmountIn, minAmountsOut, true, @@ -1092,14 +1068,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); - bool[] memory unwrapWrapper = new bool[](minAmountsOut.length); - unwrapWrapper[partialWaDaiIdx] = true; + bool[] memory unwrapWrapped = new bool[](minAmountsOut.length); + unwrapWrapped[partialWaDaiIdx] = true; vm.prank(bob); (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - unwrapWrapper, + unwrapWrapped, exactBptAmountIn, minAmountsOut, false, @@ -1153,14 +1129,14 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { TestBalances memory balancesBefore = _getTestBalances(bob); - bool[] memory unwrapWrapper = new bool[](minAmountsOut.length); - unwrapWrapper[partialWaDaiIdx] = true; + bool[] memory unwrapWrapped = new bool[](minAmountsOut.length); + unwrapWrapped[partialWaDaiIdx] = true; vm.prank(bob); (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - unwrapWrapper, + unwrapWrapped, exactBptAmountIn, minAmountsOut, true, @@ -1197,15 +1173,12 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { function testRemoveLiquidityProportionalFromERC4626PoolWhenStaticCall() public checkBuffersWhenStaticCall(bob) { uint256 exactBptAmountIn = bufferInitialAmount / 2; - bool[] memory unwrapWrapper = new bool[](2); - for (uint256 i = 0; i < unwrapWrapper.length; i++) { - unwrapWrapper[i] = true; - } + bool[] memory unwrapWrapped = _getDefaultUnwrapWrapped(2); _prankStaticCall(); compositeLiquidityRouter.queryRemoveLiquidityProportionalFromERC4626Pool( pool, - unwrapWrapper, + unwrapWrapped, exactBptAmountIn, address(this), bytes("") @@ -1230,8 +1203,8 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { minAmountsOut[partialWethIdx] = expectedWrappedAmountsOut[partialWethIdx] + 1; minAmountsOut[partialWaDaiIdx] = _vaultPreviewRedeem(waDAI, expectedWrappedAmountsOut[partialWaDaiIdx]); - bool[] memory unwrapWrapper = new bool[](minAmountsOut.length); - unwrapWrapper[partialWaDaiIdx] = true; + bool[] memory unwrapWrapped = new bool[](minAmountsOut.length); + unwrapWrapped[partialWaDaiIdx] = true; vm.expectRevert( abi.encodeWithSelector( @@ -1244,7 +1217,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.prank(bob); compositeLiquidityRouter.removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - unwrapWrapper, + unwrapWrapped, exactBptAmountIn, minAmountsOut, false, @@ -1321,15 +1294,15 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { expectedWrappedAmountsOut[partialWaDaiIdx] ); - bool[] memory unwrapWrapper = new bool[](minUnderlyingAmountsOut.length); - unwrapWrapper[partialWaDaiIdx] = true; + bool[] memory unwrapWrapped = new bool[](minUnderlyingAmountsOut.length); + unwrapWrapped[partialWaDaiIdx] = true; uint256 snapshotId = vm.snapshot(); _prankStaticCall(); (, uint256[] memory queryUnderlyingAmountsOut) = compositeLiquidityRouter .queryRemoveLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - unwrapWrapper, + unwrapWrapped, exactBptAmountIn, address(this), bytes("") @@ -1340,7 +1313,7 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { (, uint256[] memory actualUnderlyingAmountsOut) = compositeLiquidityRouter .removeLiquidityProportionalFromERC4626Pool( partialErc4626Pool, - unwrapWrapper, + unwrapWrapped, exactBptAmountIn, minUnderlyingAmountsOut, false, @@ -1732,6 +1705,22 @@ contract CompositeLiquidityRouterERC4626PoolTest is BaseERC4626BufferTest { vm.stopPrank(); } + function _getDefaultUnwrapWrapped(uint256 length) private pure returns (bool[] memory) { + return _setupTrueBoolArray(length); + } + + function _getDefaultWrapUnderlying(uint256 length) private pure returns (bool[] memory) { + return _setupTrueBoolArray(length); + } + + function _setupTrueBoolArray(uint256 length) private pure returns (bool[] memory) { + bool[] memory boolArray = new bool[](length); + for (uint256 i = 0; i < boolArray.length; i++) { + boolArray[i] = true; + } + return boolArray; + } + struct BufferBalances { uint256 underlying; uint256 wrapped;