Skip to content

Commit

Permalink
Merge pull request #131 from SweeprFi/4pool_gauge
Browse files Browse the repository at this point in the history
adds staking BPT to Balancer Gauge to boost rewards
  • Loading branch information
CelaPablo authored Dec 1, 2023
2 parents 44172c8 + 87c3218 commit c1df7c9
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 142 deletions.
7 changes: 7 additions & 0 deletions contracts/Assets/Balancer/IBalancer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ pragma solidity 0.8.19;

import "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";

interface IBalancerGauge {
function claim_rewards() external;
function deposit(uint256 _amount) external;
function withdraw(uint256 _amount) external;
function balanceOf(address _address) external view returns(uint256 _balance);
}

interface IBalancerVault {
struct JoinPoolRequest {
IAsset[] assets;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity 0.8.19;

// ====================================================================
// ======================== BalancerAsset.sol =========================
// ======================== Balancer4PoolAsset.sol =========================
// ====================================================================

/**
Expand All @@ -13,18 +13,24 @@ pragma solidity 0.8.19;
* Collects fees from the LP.
*/

import { Stabilizer, TransferHelper } from "../Stabilizer/Stabilizer.sol";
import { IBalancerPool, IBalancerVault, IAsset, JoinKind, ExitKind } from "./Balancer/IBalancer.sol";
import { Stabilizer, TransferHelper, IERC20Metadata } from "../Stabilizer/Stabilizer.sol";
import { IBalancerGauge, IBalancerPool, IBalancerVault, IAsset, JoinKind, ExitKind } from "./Balancer/IBalancer.sol";

contract BalancerAsset is Stabilizer {
import "hardhat/console.sol";

error BadAddress(address asset);
contract Balancer4PoolAsset is Stabilizer {

IBalancerPool public pool;
IBalancerVault public vault;
IBalancerGauge public gauge;

bytes32 public poolId;
IAsset[] public poolAssets;

uint8 public usdxIndexWithBPT;
uint8 public usdxIndexWithoutBPT;

uint24 private constant PRECISION = 1e6;
uint256 private constant ACTION = 1;

event Invested(uint256 indexed usdxAmount);
event Divested(uint256 indexed usdxAmount);
Expand All @@ -33,12 +39,20 @@ contract BalancerAsset is Stabilizer {
string memory _name,
address _sweep,
address _usdx,
address _oracleUsdx,
address _poolAddress,
address _gaugeAddress,
address _oracleUsdx,

address _borrower
) Stabilizer(_name, _sweep, _usdx, _oracleUsdx, _borrower) {
pool = IBalancerPool(_poolAddress);
vault = IBalancerVault(pool.getVault());
gauge = IBalancerGauge(_gaugeAddress);

poolId = pool.getPoolId();
(poolAssets, , ) = vault.getPoolTokens(poolId);
usdxIndexWithBPT = 1;
usdxIndexWithoutBPT = 0;
}

/* ========== Views ========== */
Expand All @@ -57,13 +71,16 @@ contract BalancerAsset is Stabilizer {
* @return the amm usdx amount
*/
function assetValue() public view returns (uint256) {
return _oracleUsdxToUsd(bpt4BalanceInUsdx());
uint256 bptBalance = pool.balanceOf(address(this)) + gauge.balanceOf(address(this));
return _oracleUsdxToUsd(inUSDX(bptBalance));
}

function bpt4BalanceInUsdx() private view returns (uint256) {
uint256 bpt4 = pool.balanceOf(address(this));
uint256 rate = pool.getRate();
return (bpt4 * rate * (10 ** usdx.decimals())) / (10 ** (pool.decimals() * 2));
function inUSDX(uint256 amount) private view returns (uint256) {
return (amount * pool.getRate() * (10 ** usdx.decimals())) / (10 ** (pool.decimals() * 2));
}

function inBPT(uint256 amount) private view returns (uint256) {
return (amount * (10 ** (pool.decimals() * 2))) / (pool.getRate() * (10 ** usdx.decimals()));
}

/* ========== Actions ========== */
Expand All @@ -87,69 +104,62 @@ contract BalancerAsset is Stabilizer {
function divest(uint256 usdxAmount, uint256 slippage)
external onlyBorrower nonReentrant
{
emit Divested(_divest(usdxAmount, slippage));
_divest(usdxAmount, slippage);
}

function _invest(uint256 usdxAmount, uint256, uint256 slippage) internal override {
uint256 usdxBalance = usdx.balanceOf(address(this));
address self = address(this);

uint256 usdxBalance = usdx.balanceOf(self);
if (usdxBalance == 0) revert NotEnoughBalance();
if (usdxBalance < usdxAmount) usdxAmount = usdxBalance;

TransferHelper.safeApprove(address(usdx), address(vault), usdxAmount);

bytes32 poolId = pool.getPoolId();
address self = address(this);

(IAsset[] memory assets, , ) = vault.getPoolTokens(poolId);
uint8 usdxIndex = findAssetIndex(address(usdx), assets);

uint256[] memory amounts = new uint256[](5);
amounts[usdxIndex] = usdxAmount;
amounts[usdxIndexWithBPT] = usdxAmount;

uint256[] memory userDataAmounts = new uint256[](4);
userDataAmounts[usdxIndex-1] = usdxAmount;
userDataAmounts[usdxIndexWithoutBPT] = usdxAmount;

uint256 bptAmount = inBPT(usdxAmount);
uint256 minAmountOut = bptAmount * (PRECISION - slippage) / PRECISION;

uint256 usdxAmountOut = usdxAmount * (10 ** (pool.decimals()+12)) / pool.getTokenRate(address(usdx));
uint256 minAmountOut = usdxAmountOut * (PRECISION - slippage) / PRECISION;
bytes memory userData = abi.encode(JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT, userDataAmounts, minAmountOut);
IBalancerVault.JoinPoolRequest memory request = IBalancerVault.JoinPoolRequest(poolAssets, amounts, userData, false);

IBalancerVault.JoinPoolRequest memory request = IBalancerVault.JoinPoolRequest(assets, amounts, userData, false);
TransferHelper.safeApprove(address(usdx), address(vault), usdxAmount);
vault.joinPool(poolId, self, self, request);

uint256 bptBalance = pool.balanceOf(self);
TransferHelper.safeApprove(address(pool), address(gauge), bptBalance);
gauge.deposit(bptBalance);

emit Invested(usdxAmount);
}

function _divest(uint256 usdxAmount, uint256 slippage) internal override returns (uint256) {
uint256 bpt4UsdxBalance = bpt4BalanceInUsdx();
if (bpt4UsdxBalance < usdxAmount) usdxAmount = bpt4UsdxBalance;

address self = address(this);
bytes32 poolId = pool.getPoolId();
uint256 maxAmountIn = pool.balanceOf(self);
uint maxAmountOut = usdxAmount * (PRECISION - slippage) / PRECISION;
uint256 bptAmount = inBPT(usdxAmount);
uint256 gaugeBalance = gauge.balanceOf(self);
if (gaugeBalance < bptAmount) bptAmount = gaugeBalance;

(IAsset[] memory assets, , ) = vault.getPoolTokens(poolId);
uint8 usdxIndex = findAssetIndex(address(usdx), assets);
gauge.withdraw(bptAmount);

usdxAmount = inUSDX(bptAmount);
uint256 minUsdxAmountOut = usdxAmount * (PRECISION - slippage) / PRECISION;
uint256[] memory amounts = new uint256[](5);
amounts[usdxIndex] = maxAmountOut;
amounts[usdxIndexWithBPT] = minUsdxAmountOut;

uint256[] memory userDataAmounts = new uint256[](4);
userDataAmounts[usdxIndex-1] = maxAmountOut;
bytes memory userData = abi.encode(ExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT, bptAmount, usdxIndexWithoutBPT);
IBalancerVault.ExitPoolRequest memory request = IBalancerVault.ExitPoolRequest(poolAssets, amounts, userData, false);

bytes memory userData = abi.encode(ExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT, userDataAmounts, maxAmountIn);

IBalancerVault.ExitPoolRequest memory request = IBalancerVault.ExitPoolRequest(assets, amounts, userData, false);
vault.exitPool(poolId, self, self, request);

emit Divested(usdxAmount);
return usdxAmount;
}

function findAssetIndex(address asset, IAsset[] memory assets) internal pure returns (uint8) {
for (uint8 i = 0; i < assets.length; i++) {
if ( address(assets[i]) == asset ) {
return i;
}
}
revert BadAddress(asset);
function collect() external onlyBorrower nonReentrant {
gauge.claim_rewards();
}

}
91 changes: 34 additions & 57 deletions contracts/Stabilizer/Stabilizer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,19 @@ contract Stabilizer is Owned, Pausable, ReentrancyGuard {
* @dev this value have a precision of 6 decimals.
*/
function getEquityRatio() public view returns (int256) {
return _calculateEquityRatio(0, 0);
uint256 totalValue = currentValue();

if (totalValue == 0) {
if (sweepBorrowed > 0) return -1e6;
else return 0;
}

uint256 seniorTrancheInUsd = sweep.convertToUSD(sweepBorrowed);
// 1e6 are decimals of the percentage result
int256 equityRatio = ((int256(totalValue) - int256(seniorTrancheInUsd)) * 1e6) / int256(totalValue);

if (equityRatio < -1e6) equityRatio = -1e6;
return equityRatio;
}

/**
Expand Down Expand Up @@ -362,10 +374,11 @@ contract Stabilizer is Owned, Pausable, ReentrancyGuard {
validAmount(sweepAmount)
nonReentrant
{
int256 currentEquityRatio = _calculateEquityRatio(sweepAmount, 0);
if (currentEquityRatio < minEquityRatio) revert EquityRatioExcessed();

_borrow(sweepAmount);

if (getEquityRatio() < minEquityRatio) {
revert EquityRatioExcessed();
}
}

/**
Expand Down Expand Up @@ -501,9 +514,6 @@ contract Stabilizer is Owned, Pausable, ReentrancyGuard {
if (msg.sender != sweep.balancer()) revert NotBalancer();
if (!autoInvestEnabled) revert NotAutoInvest();

int256 currentEquityRatio = _calculateEquityRatio(sweepAmount, 0);
if (currentEquityRatio < autoInvestMinRatio) revert NotAutoInvestMinRatio();

uint256 sweepMinted = _borrow(sweepAmount);
if (sweepMinted < autoInvestMinAmount) revert NotAutoInvestMinAmount();

Expand All @@ -514,6 +524,10 @@ contract Stabilizer is Owned, Pausable, ReentrancyGuard {

_invest(usdxAmount, 0, slippage);

if (getEquityRatio() < autoInvestMinRatio){
revert NotAutoInvestMinRatio();
}

emit AutoInvested(sweepAmount);
}

Expand Down Expand Up @@ -614,8 +628,6 @@ contract Stabilizer is Owned, Pausable, ReentrancyGuard {
external onlyBorrower whenNotPaused validAmount(sweepAmount) nonReentrant
returns(uint256 usdxAmount)
{
int256 currentEquityRatio = _calculateEquityRatio(sweepAmount, 0);
if (currentEquityRatio < minEquityRatio) revert EquityRatioExcessed();
_borrow(sweepAmount);

if(useAMM){
Expand All @@ -627,6 +639,10 @@ contract Stabilizer is Owned, Pausable, ReentrancyGuard {
}

_invest(usdxAmount, 0, slippage);

if (getEquityRatio() < minEquityRatio){
revert EquityRatioExcessed();
}
}

function oneStepDivest(uint256 usdxAmount, uint256 slippage, bool useAMM)
Expand Down Expand Up @@ -660,20 +676,12 @@ contract Stabilizer is Owned, Pausable, ReentrancyGuard {
if (amount > IERC20Metadata(token).balanceOf(address(this)))
revert NotEnoughBalance();

if (sweepBorrowed > 0) {
if (token != address(sweep) && token != address(usdx))
revert InvalidToken();

uint256 usdAmount = token == address(sweep)
? sweep.convertToUSD(amount)
: _oracleUsdxToUsd(amount);
int256 currentEquityRatio = _calculateEquityRatio(0, usdAmount);
if (currentEquityRatio < minEquityRatio)
revert EquityRatioExcessed();
}

TransferHelper.safeTransfer(token, msg.sender, amount);

if (sweepBorrowed > 0 && getEquityRatio() < minEquityRatio) {
revert EquityRatioExcessed();
}

emit Withdrawn(token, amount);
}

Expand Down Expand Up @@ -802,9 +810,6 @@ contract Stabilizer is Owned, Pausable, ReentrancyGuard {
uint256 sweepAvailable = loanLimit - sweepBorrowed;
if (sweepAvailable < sweepAmount) revert NotEnoughBalance();

// int256 currentEquityRatio = _calculateEquityRatio(sweepAmount, 0);
// if (currentEquityRatio < ratio) revert EquityRatioExcessed();

uint256 spreadAmount = accruedFee();
sweep.mint(sweepAmount);
sweepBorrowed += sweepAmount;
Expand All @@ -821,6 +826,10 @@ contract Stabilizer is Owned, Pausable, ReentrancyGuard {

sweepMinted = sweepAmount;

// if (getEquityRatio() < minEquityRatio) {
// revert EquityRatioExcessed();
// }

emit Borrowed(sweepAmount);
}

Expand Down Expand Up @@ -860,39 +869,7 @@ contract Stabilizer is Owned, Pausable, ReentrancyGuard {
if(!isDefaulted()) _stopAuction();
}

/**
* @notice Calculate Equity Ratio
* Calculated the equity ratio based on the internal storage.
* @param sweepDelta Variation of SWEEP to recalculate the new equity ratio.
* @param usdDelta Variation of USD to recalculate the new equity ratio.
* @return the new equity ratio used to control the Mint and Withdraw functions.
* @dev Current Equity Ratio percentage has a precision of 4 decimals.
*/
function _calculateEquityRatio(
uint256 sweepDelta,
uint256 usdDelta
) internal view returns (int256) {
uint256 currentValue_ = currentValue();
uint256 sweepDeltaInUsd = sweep.convertToUSD(sweepDelta);
uint256 totalValue = currentValue_ + sweepDeltaInUsd - usdDelta;

if (totalValue == 0) {
if (sweepBorrowed > 0) return -1e6;
else return 0;
}

uint256 seniorTrancheInUsd = sweep.convertToUSD(
sweepBorrowed + sweepDelta
);

// 1e6 is decimals of the percentage result
int256 currentEquityRatio = ((int256(totalValue) -
int256(seniorTrancheInUsd)) * 1e6) / int256(totalValue);

if (currentEquityRatio < -1e6) currentEquityRatio = -1e6;

return currentEquityRatio;
}


/**
* @notice Get Balances of the usdx and SWEEP.
Expand Down
Loading

0 comments on commit c1df7c9

Please sign in to comment.