Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/interfaces/IBalancerManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.18;

import { IService } from "./IService.sol";

interface IBalancerManager {
struct PoolData {
bytes32 balancerPoolID;
address[] tokens;
uint256[] weights;
uint256[] scalingFactors;
uint256 maximumWeightIndex;
uint8 length;
uint256 swapFee;
address gauge;
address protocolFeeCollector;
}

event PoolWasAdded(address indexed balancerPool);
event PoolWasRemoved(address indexed balancerPool);

function addPool(address poolAddress, bytes32 balancerPoolID, address gauge) external;

function removePool(address poolAddress) external;

function harvest(address gauge, address[] memory tokens) external;

function quote(IService.Agreement memory agreement, PoolData memory pool) external view returns (uint256[] memory);

function getPool(address) external view returns (PoolData memory);
}
102 changes: 99 additions & 3 deletions src/libraries/BalancerHelper.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.18;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IBalancerVault } from "../interfaces/external/balancer/IBalancerVault.sol";
import { IBalancerPool } from "../interfaces/external/balancer/IBalancerPool.sol";
import { IProtocolFeesCollector } from "../interfaces/external/balancer/IProtocolFeesCollector.sol";
import { FloatingPointMath } from "./FloatingPointMath.sol";
import { WeightedMath } from "./external/Balancer/WeightedMath.sol";

Expand All @@ -12,7 +16,7 @@ library BalancerHelper {
uint256[] memory balances,
uint256 bptAmountIn,
uint256 totalSupply
) public pure returns (uint256[] memory) {
) internal pure returns (uint256[] memory) {
uint256[] memory amountsOut = WeightedMath._calcTokensOutGivenExactBptIn(balances, bptAmountIn, totalSupply);
return amountsOut;
}
Expand All @@ -23,7 +27,7 @@ library BalancerHelper {
uint256[] memory amountsOut,
uint256 totalSupply,
uint256 swapFee
) public pure returns (uint256) {
) internal pure returns (uint256) {
// _upscaleArray(amountsOut);

uint256 bptAmountIn = WeightedMath._calcBptInGivenExactTokensOut(
Expand All @@ -37,11 +41,103 @@ library BalancerHelper {
return bptAmountIn;
}

function getTokenIndex(address[] memory tokens, address token) public pure returns (uint8) {
function getTokenIndex(address[] memory tokens, address token) internal pure returns (uint8) {
for (uint8 i = 0; i < tokens.length; i++) {
if (tokens[i] == token) return i;
}

return type(uint8).max;
}

function _modifyBalancesWithFees(
address poolAddress,
address protocolFeeCollector,
uint256[] memory scalingFactors,
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256 maximumWeightIndex
) internal view {
uint256 length = scalingFactors.length;
for (uint256 i = 0; i < length; i++) balances[i] *= scalingFactors[i];

uint256[] memory dueProtocolFeeAmounts = new uint256[](length);
dueProtocolFeeAmounts[maximumWeightIndex] = WeightedMath._calcDueTokenProtocolSwapFeeAmount(
balances[maximumWeightIndex],
normalizedWeights[maximumWeightIndex],
IBalancerPool(poolAddress).getLastInvariant(),
WeightedMath._calculateInvariant(normalizedWeights, balances),
IProtocolFeesCollector(protocolFeeCollector).getSwapFeePercentage()
);

balances[maximumWeightIndex] -= dueProtocolFeeAmounts[maximumWeightIndex];
}

// Assumes balances are already upscaled and downscales them back together with balances
function calculateExpectedBPTToExit(
address poolAddress,
uint256[] memory balances,
uint256[] memory amountsOut,
uint256[] memory scalingFactors,
address protocolFeeCollector,
uint256 maximumWeightIndex
) internal view returns (uint256) {
uint256 length = scalingFactors.length;
uint256[] memory normalizedWeights = IBalancerPool(poolAddress).getNormalizedWeights();
_modifyBalancesWithFees(
poolAddress,
protocolFeeCollector,
scalingFactors,
balances,
normalizedWeights,
maximumWeightIndex
);

for (uint256 i = 0; i < length; i++) amountsOut[i] *= scalingFactors[i];

uint256 expectedBpt = WeightedMath._calcBptInGivenExactTokensOut(
balances,
normalizedWeights,
amountsOut,
IERC20(poolAddress).totalSupply(),
IBalancerPool(poolAddress).getSwapFeePercentage()
);

for (uint256 i = 0; i < length; i++) {
amountsOut[i] /= scalingFactors[i];
balances[i] /= scalingFactors[i];
}

return expectedBpt;
}

// Assumes balances are already upscaled and downscales them back together with balances
function calculateExpectedTokensFromBPT(
address poolAddress,
address protocolFeeCollector,
uint256[] memory balances,
uint256[] memory scalingFactors,
uint256[] memory normalizedWeights,
uint256 maximumWeightIndex,
uint256 amount,
uint256 totalSupply
) internal view returns (uint256[] memory) {
uint256[] memory normalizedWeights = IBalancerPool(poolAddress).getNormalizedWeights();

_modifyBalancesWithFees(
poolAddress,
protocolFeeCollector,
scalingFactors,
balances,
normalizedWeights,
maximumWeightIndex
);
uint256[] memory expectedTokens = WeightedMath._calcTokensOutGivenExactBptIn(balances, amount, totalSupply);

for (uint256 i = 0; i < scalingFactors.length; i++) {
expectedTokens[i] /= scalingFactors[i];
balances[i] /= scalingFactors[i];
}

return expectedTokens;
}
}
Loading