diff --git a/contracts/BIFI/interfaces/curve/ICurveRouterV1.sol b/contracts/BIFI/interfaces/curve/ICurveRouterV1.sol new file mode 100644 index 00000000..d7322343 --- /dev/null +++ b/contracts/BIFI/interfaces/curve/ICurveRouterV1.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +struct CurveRoute { + address[11] route; + uint256[5][5] swapParams; + uint minAmount; +} + +interface ICurveRouterV1 { + + function exchange( + address[11] calldata _route, + uint[5][5] calldata _swap_params, + uint _amount, + uint _expected + ) external returns(uint); +} \ No newline at end of file diff --git a/contracts/BIFI/strategies/Balancer/BalancerActionsLib.sol b/contracts/BIFI/strategies/Balancer/BalancerActionsLib.sol index beef4874..1981228a 100644 --- a/contracts/BIFI/strategies/Balancer/BalancerActionsLib.sol +++ b/contracts/BIFI/strategies/Balancer/BalancerActionsLib.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import "@openzeppelin-4/contracts/token/ERC20/IERC20.sol"; import "../../interfaces/beethovenx/IBalancerVault.sol"; import "./BeefyBalancerStructs.sol"; @@ -18,6 +19,27 @@ library BalancerActionsLib { IBalancerVault(_vault).joinPool(_poolId, address(this), address(this), request); } + function multiJoin(address _vault, address _want, bytes32 _poolId, address _token0In, address _token1In, uint256 _amount0In, uint256 _amount1In) internal { + (address[] memory lpTokens,uint256[] memory balances,) = IBalancerVault(_vault).getPoolTokens(_poolId); + uint256 supply = IERC20(_want).totalSupply(); + uint256[] memory amounts = new uint256[](lpTokens.length); + for (uint256 i = 0; i < amounts.length;) { + if (lpTokens[i] == _token0In) amounts[i] = _amount0In; + else if (lpTokens[i] == _token1In) amounts[i] = _amount1In; + else amounts[i] = 0; + unchecked { ++i; } + } + + uint256 bpt0 = (amounts[0] * supply / balances[0]) - 100; + uint256 bpt1 = (amounts[1] * supply / balances[1]) - 100; + + uint256 bptOut = bpt0 > bpt1 ? bpt1 : bpt0; + bytes memory userData = abi.encode(3, bptOut); + + IBalancerVault.JoinPoolRequest memory request = IBalancerVault.JoinPoolRequest(lpTokens, amounts, userData, false); + IBalancerVault(_vault).joinPool(_poolId, address(this), address(this), request); + } + function buildSwapStructArray(BeefyBalancerStructs.BatchSwapStruct[] memory _route, uint256 _amountIn) internal pure returns (IBalancerVault.BatchSwapStep[] memory) { IBalancerVault.BatchSwapStep[] memory swaps = new IBalancerVault.BatchSwapStep[](_route.length); for (uint i; i < _route.length;) { diff --git a/contracts/BIFI/strategies/Balancer/StrategyAuraGyroMainnet.sol b/contracts/BIFI/strategies/Balancer/StrategyAuraGyroMainnet.sol new file mode 100644 index 00000000..a9dea21b --- /dev/null +++ b/contracts/BIFI/strategies/Balancer/StrategyAuraGyroMainnet.sol @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@openzeppelin-4/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin-4/contracts/token/ERC20/utils/SafeERC20.sol"; + +import "../../interfaces/aura/IAuraBooster.sol"; +import "../../interfaces/aura/IAuraRewardPool.sol"; +import "../../interfaces/beethovenx/IBalancerVault.sol"; +import "../Common/StratFeeManagerInitializable.sol"; +import "./BalancerActionsLib.sol"; +import "./BeefyBalancerStructs.sol"; +import "../../utils/UniV3Actions.sol"; + +interface IBalancerPool { + function getPoolId() external view returns (bytes32); + function getTokenRates() external view returns (uint256, uint256); +} + +contract StrategyAuraGyroMainnet is StratFeeManagerInitializable { + using SafeERC20 for IERC20; + + uint256 public constant DURATION = 1 days; + + // Tokens used + address public want; + address public output; + address public native; + address public lp0; + address public lp1; + + BeefyBalancerStructs.Input public input; + + // Third party contracts + address public booster; + address public rewardPool; + uint256 public pid; + bool public composable; + + IBalancerVault.SwapKind public swapKind; + IBalancerVault.FundManagement public funds; + + BeefyBalancerStructs.BatchSwapStruct[] public nativeToLp0Route; + BeefyBalancerStructs.BatchSwapStruct[] public lp0ToLp1Route; + BeefyBalancerStructs.BatchSwapStruct[] public outputToNativeRoute; + address[] public nativeToLp0Assets; + address[] public lp0Tolp1Assets; + address[] public outputToNativeAssets; + + mapping(address => BeefyBalancerStructs.Reward) public rewards; + address[] public rewardTokens; + + address public uniswapRouter; + bool public earmark; + bool public shouldSweep; + bool public harvestOnDeposit; + uint256 public lastHarvest; + uint256 public totalLocked; + + event StratHarvest(address indexed harvester, uint256 indexed wantHarvested, uint256 indexed tvl); + event Deposit(uint256 indexed tvl); + event Withdraw(uint256 indexed tvl); + event ChargedFees(uint256 indexed callFees, uint256 indexed beefyFees, uint256 indexed strategistFees); + + function initialize( + address _want, + BeefyBalancerStructs.BatchSwapStruct[] memory _nativeToLp0Route, + BeefyBalancerStructs.BatchSwapStruct[] memory _lp0ToLp1Route, + BeefyBalancerStructs.BatchSwapStruct[] memory _outputToNativeRoute, + address _booster, + uint256 _pid, + address[] memory _nativeToLp0, + address[] memory _lp0ToLp1, + address[] memory _outputToNative, + CommonAddresses calldata _commonAddresses + ) public initializer { + __StratFeeManager_init(_commonAddresses); + + for (uint i; i < _nativeToLp0Route.length; ++i) { + nativeToLp0Route.push(_nativeToLp0Route[i]); + } + + for (uint j; j < _lp0ToLp1Route.length; ++j) { + lp0ToLp1Route.push(_lp0ToLp1Route[j]); + } + + for (uint k; k < _outputToNativeRoute.length; ++k) { + outputToNativeRoute.push(_outputToNativeRoute[k]); + } + + want = _want; + booster = _booster; + pid = _pid; + outputToNativeAssets = _outputToNative; + nativeToLp0Assets = _nativeToLp0; + lp0Tolp1Assets = _lp0ToLp1; + output = outputToNativeAssets[0]; + native = nativeToLp0Assets[0]; + lp0 = lp0Tolp1Assets[0]; + lp1 = lp0Tolp1Assets[lp0Tolp1Assets.length - 1]; + uniswapRouter = address(0xE592427A0AEce92De3Edee1F18E0157C05861564); + shouldSweep = true; + + (,,,rewardPool,,) = IAuraBooster(booster).poolInfo(pid); + + swapKind = IBalancerVault.SwapKind.GIVEN_IN; + funds = IBalancerVault.FundManagement(address(this), false, payable(address(this)), false); + + _giveAllowances(); + } + + function deposit() public whenNotPaused { + if (shouldSweep) { + _deposit(); + } + } + + // puts the funds to work + function _deposit() internal whenNotPaused { + uint256 wantBal = IERC20(want).balanceOf(address(this)); + + if (wantBal > 0) { + IAuraBooster(booster).deposit(pid, wantBal, true); + emit Deposit(balanceOf()); + } + } + + function withdraw(uint256 _amount) external { + require(msg.sender == vault, "!vault"); + + uint256 wantBal = IERC20(want).balanceOf(address(this)); + + if (wantBal < _amount) { + IAuraRewardPool(rewardPool).withdrawAndUnwrap(_amount - wantBal, false); + wantBal = IERC20(want).balanceOf(address(this)); + } + + if (wantBal > _amount) { + wantBal = _amount; + } + + if (tx.origin != owner() && !paused()) { + uint256 withdrawalFeeAmount = wantBal * withdrawalFee / WITHDRAWAL_MAX; + wantBal = wantBal - withdrawalFeeAmount; + } + + IERC20(want).safeTransfer(vault, wantBal); + + emit Withdraw(balanceOf()); + } + + function beforeDeposit() external override { + if (harvestOnDeposit) { + require(msg.sender == vault, "!vault"); + _harvest(tx.origin); + } + } + + function harvest() external virtual { + _harvest(tx.origin); + } + + function harvest(address callFeeRecipient) external virtual { + _harvest(callFeeRecipient); + } + + function managerHarvest() external onlyManager { + _harvest(tx.origin); + } + + // compounds earnings and charges performance fee + function _harvest(address callFeeRecipient) internal whenNotPaused { + if (earmark) IAuraBooster(booster).earmarkRewards(pid); + IAuraRewardPool(rewardPool).getReward(); + swapRewardsToNative(); + uint256 nativeBal = IERC20(native).balanceOf(address(this)); + uint256 before = balanceOfWant(); + + if (nativeBal > 0) { + chargeFees(callFeeRecipient); + addLiquidity(); + uint256 wantHarvested = balanceOfWant() - before; + totalLocked = wantHarvested + lockedProfit(); + _deposit(); + + lastHarvest = block.timestamp; + emit StratHarvest(msg.sender, wantHarvested, balanceOf()); + } + } + + function swapRewardsToNative() internal { + uint256 outputBal = IERC20(output).balanceOf(address(this)); + if (outputBal > 0) { + IBalancerVault.BatchSwapStep[] memory _swaps = BalancerActionsLib.buildSwapStructArray(outputToNativeRoute, outputBal); + BalancerActionsLib.balancerSwap(unirouter, swapKind, _swaps, outputToNativeAssets, funds, int256(outputBal)); + } + // extras + for (uint i; i < rewardTokens.length; ++i) { + uint bal = IERC20(rewardTokens[i]).balanceOf(address(this)); + if (bal >= rewards[rewardTokens[i]].minAmount) { + if (rewards[rewardTokens[i]].assets[0] != address(0)) { + BeefyBalancerStructs.BatchSwapStruct[] memory swapInfo = new BeefyBalancerStructs.BatchSwapStruct[](rewards[rewardTokens[i]].assets.length - 1); + for (uint j; j < rewards[rewardTokens[i]].assets.length - 1;) { + swapInfo[j] = rewards[rewardTokens[i]].swapInfo[j]; + unchecked { + ++j; + } + } + IBalancerVault.BatchSwapStep[] memory _swaps = BalancerActionsLib.buildSwapStructArray(swapInfo, bal); + BalancerActionsLib.balancerSwap(unirouter, swapKind, _swaps, rewards[rewardTokens[i]].assets, funds, int256(bal)); + } else { + UniV3Actions.swapV3WithDeadline(uniswapRouter, rewards[rewardTokens[i]].routeToNative, bal); + } + } + } + } + + // performance fees + function chargeFees(address callFeeRecipient) internal { + IFeeConfig.FeeCategory memory fees = getFees(); + uint256 nativeBal = IERC20(native).balanceOf(address(this)) * fees.total / DIVISOR; + + uint256 callFeeAmount = nativeBal * fees.call / DIVISOR; + IERC20(native).safeTransfer(callFeeRecipient, callFeeAmount); + + uint256 beefyFeeAmount = nativeBal * fees.beefy / DIVISOR; + IERC20(native).safeTransfer(beefyFeeRecipient, beefyFeeAmount); + + uint256 strategistFeeAmount = nativeBal * fees.strategist / DIVISOR; + IERC20(native).safeTransfer(strategist, strategistFeeAmount); + + emit ChargedFees(callFeeAmount, beefyFeeAmount, strategistFeeAmount); + } + + // Adds liquidity to AMM and gets more LP tokens. + function addLiquidity() internal { + uint256 nativeBal = IERC20(native).balanceOf(address(this)); + bytes32 poolId = IBalancerPool(want).getPoolId(); + (address[] memory lpTokens,,) = IBalancerVault(unirouter).getPoolTokens(poolId); + + if (lpTokens[0] != native) { + IBalancerVault.BatchSwapStep[] memory _swaps = BalancerActionsLib.buildSwapStructArray(nativeToLp0Route, nativeBal); + BalancerActionsLib.balancerSwap(unirouter, swapKind, _swaps, nativeToLp0Assets, funds, int256(nativeBal)); + } + + if (nativeBal > 0) { + uint256 lp0Bal = IERC20(lpTokens[0]).balanceOf(address(this)); + (uint256 lp0Amt, uint256 lp1Amt) = _calcSwapAmount(lp0Bal); + + IBalancerVault.BatchSwapStep[] memory _swaps = BalancerActionsLib.buildSwapStructArray(lp0ToLp1Route, lp1Amt); + BalancerActionsLib.balancerSwap(unirouter, swapKind, _swaps, lp0Tolp1Assets, funds, int256(lp1Amt)); + + BalancerActionsLib.multiJoin(unirouter, want, poolId, lpTokens[0], lpTokens[1], lp0Amt, IERC20(lpTokens[1]).balanceOf(address(this))); + } + } + + function _calcSwapAmount(uint256 _bal) private view returns (uint256 lp0Amt, uint256 lp1Amt) { + lp0Amt = _bal / 2; + lp1Amt = _bal - lp0Amt; + + (uint256 rate0, uint256 rate1) = IBalancerPool(want).getTokenRates(); + + (, uint256[] memory balances,) = IBalancerVault(unirouter).getPoolTokens(IBalancerPool(want).getPoolId()); + uint256 supply = IERC20(want).totalSupply(); + + uint256 amountA = balances[0] * 1e18 / supply; + uint256 amountB = balances[1] * 1e18 / supply; + + uint256 ratio = rate0 * 1e18 / rate1 * amountB / amountA; + lp0Amt = _bal * 1e18 / (ratio + 1e18); + lp1Amt = _bal - lp0Amt; + } + + function lockedProfit() public view returns (uint256) { + uint256 elapsed = block.timestamp - lastHarvest; + uint256 remaining = elapsed < DURATION ? DURATION - elapsed : 0; + return totalLocked * remaining / DURATION; + } + + // calculate the total underlaying 'want' held by the strat. + function balanceOf() public view returns (uint256) { + return balanceOfWant() + balanceOfPool() - lockedProfit(); + } + + // it calculates how much 'want' this contract holds. + function balanceOfWant() public view returns (uint256) { + return IERC20(want).balanceOf(address(this)); + } + + // it calculates how much 'want' the strategy has working in the farm. + function balanceOfPool() public view returns (uint256) { + return IAuraRewardPool(rewardPool).balanceOf(address(this)); + } + + // returns rewards unharvested + function rewardsAvailable() public view returns (uint256) { + return IAuraRewardPool(rewardPool).earned(address(this)); + } + + // native reward amount for calling harvest + function callReward() public pure returns (uint256) { + return 0; // multiple swap providers with no easy way to estimate native output. + } + + function addRewardToken(address _token, BeefyBalancerStructs.BatchSwapStruct[] memory _swapInfo, address[] memory _assets, bytes calldata _routeToNative, uint _minAmount) external onlyOwner { + require(_token != want, "!want"); + require(_token != native, "!native"); + if (_assets[0] != address(0)) { + IERC20(_token).safeApprove(unirouter, 0); + IERC20(_token).safeApprove(unirouter, type(uint).max); + } else { + IERC20(_token).safeApprove(uniswapRouter, 0); + IERC20(_token).safeApprove(uniswapRouter, type(uint).max); + } + + rewards[_token].assets = _assets; + rewards[_token].routeToNative = _routeToNative; + rewards[_token].minAmount = _minAmount; + + for (uint i; i < _swapInfo.length; ++i) { + rewards[_token].swapInfo[i].poolId = _swapInfo[i].poolId; + rewards[_token].swapInfo[i].assetInIndex = _swapInfo[i].assetInIndex; + rewards[_token].swapInfo[i].assetOutIndex = _swapInfo[i].assetOutIndex; + } + rewardTokens.push(_token); + } + + function resetRewardTokens() external onlyManager { + for (uint i; i < rewardTokens.length; ++i) { + delete rewards[rewardTokens[i]]; + } + delete rewardTokens; + } + + function setHarvestOnDeposit(bool _harvestOnDeposit) external onlyManager { + harvestOnDeposit = _harvestOnDeposit; + + if (harvestOnDeposit) { + setWithdrawalFee(0); + } else { + setWithdrawalFee(10); + } + } + + function setEarmark(bool _earmark) external onlyManager { + earmark = _earmark; + } + + function setShouldSweep(bool _shouldSweep) external onlyManager { + shouldSweep = _shouldSweep; + } + + // called as part of strat migration. Sends all the available funds back to the vault. + function retireStrat() external { + require(msg.sender == vault, "!vault"); + + IAuraRewardPool(rewardPool).withdrawAndUnwrap(balanceOfPool(), false); + + uint256 wantBal = IERC20(want).balanceOf(address(this)); + IERC20(want).transfer(vault, wantBal); + } + + // pauses deposits and withdraws all funds from third party systems. + function panic() public onlyManager { + pause(); + IAuraRewardPool(rewardPool).withdrawAndUnwrap(balanceOfPool(), false); + } + + function pause() public onlyManager { + _pause(); + + _removeAllowances(); + } + + function unpause() external onlyManager { + _unpause(); + + _giveAllowances(); + + deposit(); + } + + function _giveAllowances() internal { + IERC20(want).safeApprove(booster, type(uint).max); + IERC20(output).safeApprove(unirouter, type(uint).max); + IERC20(native).safeApprove(unirouter, type(uint).max); + + IERC20(lp0).safeApprove(unirouter, 0); + IERC20(lp0).safeApprove(unirouter, type(uint).max); + + IERC20(lp1).safeApprove(unirouter, 0); + IERC20(lp1).safeApprove(unirouter, type(uint).max); + + if (rewardTokens.length != 0) { + for (uint i; i < rewardTokens.length; ++i) { + if (rewards[rewardTokens[i]].assets[0] != address(0)) { + IERC20(rewardTokens[i]).safeApprove(unirouter, 0); + IERC20(rewardTokens[i]).safeApprove(unirouter, type(uint).max); + } else { + IERC20(rewardTokens[i]).safeApprove(uniswapRouter, 0); + IERC20(rewardTokens[i]).safeApprove(uniswapRouter, type(uint).max); + } + } + } + } + + function _removeAllowances() internal { + IERC20(want).safeApprove(booster, 0); + IERC20(output).safeApprove(unirouter, 0); + IERC20(native).safeApprove(unirouter, 0); + IERC20(lp0).safeApprove(unirouter, 0); + IERC20(lp1).safeApprove(unirouter, 0); + if (rewardTokens.length != 0) { + for (uint i; i < rewardTokens.length; ++i) { + if (rewards[rewardTokens[i]].assets[0] != address(0)) { + IERC20(rewardTokens[i]).safeApprove(unirouter, 0); + } else { + IERC20(rewardTokens[i]).safeApprove(uniswapRouter, 0); + } + } + } + } +} \ No newline at end of file diff --git a/contracts/BIFI/strategies/Curve/StrategyCurveConvexL2.sol b/contracts/BIFI/strategies/Curve/StrategyCurveConvexL2.sol index 41a85357..65504b62 100644 --- a/contracts/BIFI/strategies/Curve/StrategyCurveConvexL2.sol +++ b/contracts/BIFI/strategies/Curve/StrategyCurveConvexL2.sol @@ -7,7 +7,7 @@ import "@openzeppelin-4/contracts/token/ERC20/utils/SafeERC20.sol"; import "../../interfaces/common/IWrappedNative.sol"; import "../../interfaces/convex/IConvex.sol"; import "../../interfaces/curve/ICrvMinter.sol"; -import "../../interfaces/curve/ICurveRouter.sol"; +import "../../interfaces/curve/ICurveRouterV1.sol"; import "../../interfaces/curve/IRewardsGauge.sol"; import "../Common/StratFeeManagerInitializable.sol"; import "../../utils/UniV3Actions.sol"; @@ -31,11 +31,6 @@ contract StrategyCurveConvexL2 is StratFeeManagerInitializable { address public rewardPool; // convex base reward pool uint public pid; // convex booster poolId - struct CurveRoute { - address[9] route; - uint256[3][4] swapParams; - uint minAmount; // minimum amount to be swapped to native - } CurveRoute[] public curveRewards; struct RewardV3 { @@ -67,7 +62,7 @@ contract StrategyCurveConvexL2 is StratFeeManagerInitializable { address _gauge, uint _pid, bytes calldata _nativeToDepositPath, - CurveRoute calldata _crvToNative, + CurveRoute[] calldata _rewardsToNative, CurveRoute calldata _depositToWant, CommonAddresses calldata _commonAddresses ) public initializer { @@ -85,8 +80,11 @@ contract StrategyCurveConvexL2 is StratFeeManagerInitializable { isCrvMintable = true; } - if (_crvToNative.route[0] != address(0)) { - addReward(_crvToNative.route, _crvToNative.swapParams, _crvToNative.minAmount); + for (uint i; i < _rewardsToNative.length; i++) { + addReward(_rewardsToNative[i].route, _rewardsToNative[i].swapParams, _rewardsToNative[i].minAmount); + } + if (_rewardsToNative.length > 1) { + isCurveRewardsClaimable = true; } setNativeToDepositPath(_nativeToDepositPath); setDepositToWant(_depositToWant.route, _depositToWant.swapParams, _depositToWant.minAmount); @@ -189,7 +187,7 @@ contract StrategyCurveConvexL2 is StratFeeManagerInitializable { for (uint i; i < curveRewards.length; ++i) { uint bal = IERC20(curveRewards[i].route[0]).balanceOf(address(this)); if (bal > curveRewards[i].minAmount) { - ICurveRouter(curveRouter).exchange_multiple(curveRewards[i].route, curveRewards[i].swapParams, bal, 0); + ICurveRouterV1(curveRouter).exchange(curveRewards[i].route, curveRewards[i].swapParams, bal, 0); } } for (uint i; i < rewardsV3.length; ++i) { @@ -226,7 +224,7 @@ contract StrategyCurveConvexL2 is StratFeeManagerInitializable { uint bal = IERC20(depositToWant.route[0]).balanceOf(address(this)); if (bal > depositToWant.minAmount) { - ICurveRouter(curveRouter).exchange_multiple(depositToWant.route, depositToWant.swapParams, bal, 0); + ICurveRouterV1(curveRouter).exchange(depositToWant.route, depositToWant.swapParams, bal, 0); } } @@ -252,7 +250,7 @@ contract StrategyCurveConvexL2 is StratFeeManagerInitializable { nativeToDepositPath = _nativeToDepositPath; } - function setDepositToWant(address[9] calldata _route, uint[3][4] calldata _swapParams, uint minAmount) public onlyManager { + function setDepositToWant(address[11] calldata _route, uint[5][5] calldata _swapParams, uint minAmount) public onlyManager { address token = _route[0]; _checkSwapToken(token, true); @@ -261,7 +259,7 @@ contract StrategyCurveConvexL2 is StratFeeManagerInitializable { _approve(token, curveRouter, type(uint).max); } - function addReward(address[9] calldata _rewardToNativeRoute, uint[3][4] calldata _swapParams, uint _minAmount) public onlyManager { + function addReward(address[11] calldata _rewardToNativeRoute, uint[5][5] calldata _swapParams, uint _minAmount) public onlyManager { address token = _rewardToNativeRoute[0]; _checkSwapToken(token, false); @@ -314,11 +312,11 @@ contract StrategyCurveConvexL2 is StratFeeManagerInitializable { } } - function depositToWantRoute() external view returns (address[9] memory, uint256[3][4] memory, uint) { + function depositToWantRoute() external view returns (address[11] memory, uint256[5][5] memory, uint) { return (depositToWant.route, depositToWant.swapParams, depositToWant.minAmount); } - function curveReward(uint i) external view returns (address[9] memory, uint256[3][4] memory, uint) { + function curveReward(uint i) external view returns (address[11] memory, uint256[5][5] memory, uint) { return (curveRewards[i].route, curveRewards[i].swapParams, curveRewards[i].minAmount); } diff --git a/forge/test/strategy/BaseStrategyTest.t.sol b/forge/test/strategy/BaseStrategyTest.t.sol index 08b93208..4f028339 100644 --- a/forge/test/strategy/BaseStrategyTest.t.sol +++ b/forge/test/strategy/BaseStrategyTest.t.sol @@ -197,7 +197,7 @@ abstract contract BaseStrategyTest is Test { t = string.concat(t, "]"); } - function uintsToStr(uint[3] memory a) public pure returns (string memory t) { + function uintsToStr(uint[5] memory a) public pure returns (string memory t) { if (a.length == 0) return "[]"; if (a.length == 1) return string.concat("[", vm.toString(a[0]), "]"); t = string.concat("[", vm.toString(a[0])); diff --git a/forge/test/strategy/StrategyAuraGyro.t.sol b/forge/test/strategy/StrategyAuraGyro.t.sol new file mode 100644 index 00000000..0a4e5d95 --- /dev/null +++ b/forge/test/strategy/StrategyAuraGyro.t.sol @@ -0,0 +1,211 @@ +//import "forge-std/Test.sol"; +pragma solidity ^0.8.0; + +import "../../../node_modules/forge-std/src/Test.sol"; + +import "../interfaces/IVault.sol"; +import "../interfaces/IStrategy.sol"; +import "../../../contracts/BIFI/vaults/BeefyVaultV7.sol"; +import "../../../contracts/BIFI/strategies/Balancer/StrategyAuraGyroMainnet.sol"; +import "../../../contracts/BIFI/strategies/Balancer/BeefyBalancerStructs.sol"; +import "../../../contracts/BIFI/strategies/Common/StratFeeManager.sol"; + +contract StrategyAuraGyroTest is Test { + + BeefyVaultV7 vault; + StrategyAuraGyroMainnet strategy; + + struct CommonAddresses { + address vault; + address unirouter; + address keeper; + address strategist; + address beefyFeeRecipient; + address beefyFeeConfig; + } + + address user = 0x161D61e30284A33Ab1ed227beDcac6014877B3DE; + address keeper = 0x4fED5491693007f0CD49f4614FFC38Ab6A04B619; + address feeRecipient = 0x8237f3992526036787E8178Def36291Ab94638CD; + address feeConfig = 0x3d38BA27974410679afF73abD096D7Ba58870EAd; + + address want = 0xf01b0684C98CD7aDA480BFDF6e43876422fa1Fc1; + address lp0 = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; + address lp1 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + address booster = 0xA57b8d98dAE62B26Ec3bcC4a365338157060B234; + address router = 0xBA12222222228d8Ba445958a75a0704d566BF2C8; + address native = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + address bal = 0xba100000625a3754423978a60c9317c58a424e3D; + address aura = 0xC0c293ce456fF0ED870ADd98a0828Dd4d2903DBF; + + uint256 pid = 162; + + error PPFS_NOT_INCREASED(); + + function routes() public view returns ( + BeefyBalancerStructs.BatchSwapStruct[] memory _outputToNativeRoute, + BeefyBalancerStructs.BatchSwapStruct[] memory _nativeToLp0Route, + BeefyBalancerStructs.BatchSwapStruct[] memory _lp0ToLp1Route, + BeefyBalancerStructs.BatchSwapStruct[] memory _auraToNativeRoute, + address[] memory _outputToNativeAssests, + address[] memory _nativeToLp0Assests, + address[] memory _lp0ToLp1Assests, + address[] memory _auraToNativeAssests + ) { + _outputToNativeRoute = new BeefyBalancerStructs.BatchSwapStruct[](1); + _outputToNativeRoute[0] = BeefyBalancerStructs.BatchSwapStruct({ + poolId: 0x5c6ee304399dbdb9c8ef030ab642b10820db8f56000200000000000000000014, + assetInIndex: 0, + assetOutIndex: 1 + }); + + _nativeToLp0Route = new BeefyBalancerStructs.BatchSwapStruct[](1); + _nativeToLp0Route[0] = BeefyBalancerStructs.BatchSwapStruct({ + poolId: 0x93d199263632a4ef4bb438f1feb99e57b4b5f0bd0000000000000000000005c2, + assetInIndex: 0, + assetOutIndex: 1 + }); + + _lp0ToLp1Route = new BeefyBalancerStructs.BatchSwapStruct[](1); + _lp0ToLp1Route[0] = BeefyBalancerStructs.BatchSwapStruct({ + poolId: 0x93d199263632a4ef4bb438f1feb99e57b4b5f0bd0000000000000000000005c2, + assetInIndex: 0, + assetOutIndex: 1 + }); + + _auraToNativeRoute = new BeefyBalancerStructs.BatchSwapStruct[](1); + _auraToNativeRoute[0] = BeefyBalancerStructs.BatchSwapStruct({ + poolId: 0xc29562b045d80fd77c69bec09541f5c16fe20d9d000200000000000000000251, + assetInIndex: 0, + assetOutIndex: 1 + }); + + _outputToNativeAssests = new address[](2); + _outputToNativeAssests[0] = bal; + _outputToNativeAssests[1] = native; + + _nativeToLp0Assests = new address[](2); + _nativeToLp0Assests[0] = native; + _nativeToLp0Assests[1] = lp0; + + _lp0ToLp1Assests = new address[](2); + _lp0ToLp1Assests[0] = lp0; + _lp0ToLp1Assests[1] = lp1; + + _auraToNativeAssests = new address[](2); + _auraToNativeAssests[0] = aura; + _auraToNativeAssests[1] = native; + } + + function setUp() public { + vault = new BeefyVaultV7(); + strategy = new StrategyAuraGyroMainnet(); + + ( + BeefyBalancerStructs.BatchSwapStruct[] memory _outputToNativeRoute, + BeefyBalancerStructs.BatchSwapStruct[] memory _nativeToLp0Route, + BeefyBalancerStructs.BatchSwapStruct[] memory _lp0ToLp1Route, + BeefyBalancerStructs.BatchSwapStruct[] memory _auraToNativeRoute, + address[] memory _outputToNativeAssests, + address[] memory _nativeToLp0Assests, + address[] memory _lp0ToLp1Assests, + address[] memory _auraToNativeAssests + ) = routes(); + + StratFeeManagerInitializable.CommonAddresses memory commonAddresses = StratFeeManagerInitializable.CommonAddresses({ + vault: address(vault), + unirouter: router, + keeper: keeper, + strategist: user, + beefyFeeRecipient: feeRecipient, + beefyFeeConfig: feeConfig + }); + + vault.initialize(IStrategyV7(address(strategy)), "MooTest", "mooTest", 0); + strategy.initialize( + want, + _nativeToLp0Route, + _lp0ToLp1Route, + _outputToNativeRoute, + booster, + pid, + _nativeToLp0Assests, + _lp0ToLp1Assests, + _outputToNativeAssests, + commonAddresses + ); + + strategy.addRewardToken(aura, _auraToNativeRoute, _auraToNativeAssests, bytes("0x"), 0); + strategy.setWithdrawalFee(0); + } + + function test_depositAndWithdraw() public { + vm.startPrank(user); + + deal(want, user, 10 ether); + + IERC20(want).approve(address(vault), 10 ether); + vault.deposit(10 ether); + + assertEq(IERC20(want).balanceOf(address(user)), 0); + + vault.withdraw(10 ether); + + assertEq(IERC20(want).balanceOf(address(user)), 10 ether); + vm.stopPrank(); + } + + function test_harvest() public { + vm.startPrank(user); + + deal(want, user, 10 ether); + + IERC20(want).approve(address(vault), 10 ether); + vault.deposit(10 ether); + + uint256 ppfs = vault.getPricePerFullShare(); + skip(1 days); + + strategy.harvest(); + + skip(1 minutes); + uint256 afterPpfs = vault.getPricePerFullShare(); + + if (afterPpfs <= ppfs) revert PPFS_NOT_INCREASED(); + vm.stopPrank(); + } + + function test_panic() public { + vm.startPrank(user); + + deal(want, user, 10 ether); + + IERC20(want).approve(address(vault), 10 ether); + vault.deposit(10 ether); + + vm.stopPrank(); + vm.startPrank(keeper); + + strategy.panic(); + + vm.stopPrank(); + vm.startPrank(user); + + vault.withdraw(5 ether); + + vm.expectRevert(); + vault.deposit(5 ether); + + vm.stopPrank(); + + vm.startPrank(keeper); + + strategy.unpause(); + + skip(1 days); + + strategy.harvest(); + + vm.stopPrank(); + } +} diff --git a/forge/test/strategy/StrategyCurveConvexL2.t.sol b/forge/test/strategy/StrategyCurveConvexL2.t.sol index 99d93962..4f9050d8 100644 --- a/forge/test/strategy/StrategyCurveConvexL2.t.sol +++ b/forge/test/strategy/StrategyCurveConvexL2.t.sol @@ -25,7 +25,7 @@ contract StrategyCurveConvexL2Test is BaseStrategyTest { address public native = PROD_STRAT.native(); address constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; address constant crv = 0x8Ee73c484A26e0A5df2Ee2a4960B789967dd0415; - address constant curveRouter = 0xC02b26ba08c3507D46E5c45fA09FEf44a7C5378d; + address constant curveRouter = 0xd6681e74eEA20d196c15038C580f721EF2aB6320; address constant usdc = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913; address constant cbEth = 0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22; @@ -41,49 +41,70 @@ contract StrategyCurveConvexL2Test is BaseStrategyTest { uint24[] fee10000 = [10000]; uint24[] fee10000_500 = [10000, 500]; + // usd+-crvusd +// address want = 0xda3de145054ED30Ee937865D31B500505C4bDfe7; +// address gauge = 0xc0798d022eEE81F1408895325A9fBe171d2a24f1; +// uint pid = 42069; +// bytes nativeToDepositPath = ""; +// address[11] depositToWant = [native, baseTriCrypto, baseCrvUSD, want, want]; +// uint[5][5] depositToWantParams = [[2, 0, 1, 2, 3], [1, 0, 4, 1, 2]]; // crv-crvusd address want = 0x6DfE79cecE4f64c1a34F48cF5802492aB595257E; address gauge = 0x89289DC2192914a9F0674f1E9A17C56456549b8A; uint pid = 42069; bytes nativeToDepositPath = ""; - address[9] depositToWant = [native, baseTriCrypto, baseCrvUSD, baseCrvCrvUSDPool, want]; - uint[3][4] depositToWantParams = [[2,0,3], [1,0,7]]; + address[11] depositToWant = [native, baseTriCrypto, baseCrvUSD, baseCrvCrvUSDPool, want]; + uint[5][5] depositToWantParams = [[2, 0, 1, 2, 3], [1, 0, 4, 2, 2]]; // 4-pool // address want = 0xf6C5F01C7F3148891ad0e19DF78743D31E390D1f; // address gauge = 0x79edc58C471Acf2244B8f93d6f425fD06A439407; // uint pid = 42069; // bytes nativeToDepositPath = ""; -// address[9] depositToWant = [native, baseTriCrypto, baseCrvUSD, want, want]; -// uint[3][4] depositToWantParams = [[2,0,3], [3,0,10]]; +// address[11] depositToWant = [native, baseTriCrypto, baseCrvUSD, want, want]; +// uint[5][5] depositToWantParams = [[2, 0, 1, 2, 3], [3, 0, 4, 1, 4]]; // TriCrypto // address want = 0x6e53131F68a034873b6bFA15502aF094Ef0c5854; // address gauge = 0x93933FA992927284e9d508339153B31eb871e1f4; // uint pid = 42069; // bytes nativeToDepositPath = ""; -// address[9] depositToWant = [native, want, want]; -// uint[3][4] depositToWantParams = [[2,0,8]]; +// address[11] depositToWant = [native, want, want]; +// uint[5][5] depositToWantParams = [[2, 0, 4, 2, 3]]; // cbETH-ETH // address want = 0x98244d93D42b42aB3E3A4D12A5dc0B3e7f8F32f9; // address gauge = 0xE9c898BA654deC2bA440392028D2e7A194E6dc3e; // uint pid = 42069; // bytes nativeToDepositPath = ""; -// address[9] depositToWant = [native, 0x11C1fBd4b3De66bC0565779b35171a6CF3E71f59, want]; -// uint[3][4] depositToWantParams = [[0,0,7]]; - - StrategyCurveConvexL2.CurveRoute depositToWantRoute = StrategyCurveConvexL2.CurveRoute( - depositToWant, depositToWantParams, 0); +// address[11] depositToWant = [native, 0x11C1fBd4b3De66bC0565779b35171a6CF3E71f59, want]; +// uint[5][5] depositToWantParams = [[0, 0, 4, 2, 2]]; + CurveRoute depositToWantRoute = CurveRoute(depositToWant, depositToWantParams, 0); address unirouter = uniV3; address[] rewardsV3; uint24[] rewardsV3Fee = fee10000_500; - address[9] crvToNative = [crv, baseCrvCrvUSDPool, baseCrvUSD, baseTriCrypto, native]; - uint[3][4] crvParams = [[0, 1, 3], [0, 2, 3]]; - StrategyCurveConvexL2.CurveRoute crvToNativeRoute = StrategyCurveConvexL2.CurveRoute(crvToNative, crvParams, 0); + address[11] crvToNative = [crv, baseCrvCrvUSDPool, baseCrvUSD, baseTriCrypto, native]; + uint[5][5] crvParams = [[0, 1, 1, 2, 2], [0, 2, 1, 2, 3]]; + CurveRoute crvToNativeRoute = CurveRoute(crvToNative, crvParams, 0); + + address[11] crvUsdToNative = [baseCrvUSD, baseTriCrypto, native]; + uint[5][5] crvUsdToNativeParams = [[0, 2, 1, 2, 3]]; + CurveRoute crvUsdToNativeRoute = CurveRoute(crvUsdToNative, crvUsdToNativeParams, 0); + + address baseUsdPlus = 0xB79DD08EA68A908A97220C76d19A6aA9cBDE4376; + address[11] usdPlusToNative = [baseUsdPlus, want, baseCrvUSD, baseTriCrypto, native]; + uint[5][5] usdPlusParams = [[0, 1, 1, 1, 2], [0, 2, 1, 2, 3]]; + CurveRoute usdPlusRoute = CurveRoute(usdPlusToNative, usdPlusParams, 0); + + function rewardsToNative() internal view returns (CurveRoute[] memory rewards) { + rewards = new CurveRoute[](2); + rewards[0] = crvToNativeRoute; + rewards[1] = crvUsdToNativeRoute; +// rewards[2] = usdPlusRoute; + } IVault vault; StrategyCurveConvexL2 strategy; @@ -111,7 +132,7 @@ contract StrategyCurveConvexL2Test is BaseStrategyTest { beefyFeeRecipient: PROD_STRAT.beefyFeeRecipient(), beefyFeeConfig: PROD_STRAT.beefyFeeConfig() }); - strategy.initialize(native, curveRouter, want, gauge, pid, nativeToDepositPath, crvToNativeRoute, depositToWantRoute, commons); + strategy.initialize(native, curveRouter, want, gauge, pid, nativeToDepositPath, rewardsToNative(), depositToWantRoute, commons); console.log("Strategy initialized", IERC20Extended(strategy.want()).symbol(), strategy.pid(), strategy.rewardPool()); if (nativeToDepositPath.length > 0) { @@ -146,7 +167,7 @@ contract StrategyCurveConvexL2Test is BaseStrategyTest { beefyFeeConfig : PROD_STRAT.beefyFeeConfig() }); console.log("Init Strategy NO_PID"); - strategyNoPid.initialize(native, curveRouter, want, gauge, strategy.NO_PID(), nativeToDepositPath, crvToNativeRoute, depositToWantRoute, commons); + strategyNoPid.initialize(native, curveRouter, want, gauge, strategy.NO_PID(), nativeToDepositPath, rewardsToNative(), depositToWantRoute, commons); user.approve(want, address(vaultNoPid), wantAmount); user.depositAll(vaultNoPid); @@ -203,15 +224,17 @@ contract StrategyCurveConvexL2Test is BaseStrategyTest { function test_setDepositToWant() external { vm.startPrank(strategy.keeper()); - uint[3][4] memory p; + address[11] memory r; + uint[5][5] memory p; console.log("Want as deposit token reverts"); - address w = strategy.want(); + r[0] = strategy.want(); vm.expectRevert(); - strategy.setDepositToWant([w, a0, a0, a0, a0, a0, a0, a0, a0], p, 1e18); + strategy.setDepositToWant(r, p, 1e18); console.log("Deposit token approved on curve router"); address token = native; - strategy.setDepositToWant([token, a0, a0, a0, a0, a0, a0, a0, a0], p, 1e18); + r[0] = token; + strategy.setDepositToWant(r, p, 1e18); uint allowed = IERC20(token).allowance(address(strategy), strategy.curveRouter()); assertEq(allowed, type(uint).max); } @@ -245,10 +268,10 @@ contract StrategyCurveConvexL2Test is BaseStrategyTest { strategy.resetRewardsV3(); console.log("Add curveReward"); - uint[3] memory p = [uint(1),uint(0), uint(0)]; - uint[3][4] memory _params = [p,p,p,p]; - strategy.addReward([crv,a0,a0,a0,a0,a0,a0,a0,a0], _params, 1); - (address[9] memory r, uint256[3][4] memory params, uint minAmount) = strategy.curveReward(0); + uint[5] memory p = [uint(1),uint(0), uint(0), uint(0), uint(0)]; + uint[5][5] memory _params = [p,p,p,p,p]; + strategy.addReward([crv,a0,a0,a0,a0,a0,a0,a0,a0,a0,a0], _params, 1); + (address[11] memory r, uint256[5][5] memory params, uint minAmount) = strategy.curveReward(0); address token0 = r[0]; assertEq(token0, crv, "!crv"); assertEq(params[0][0], _params[0][0], "!params"); @@ -301,7 +324,7 @@ contract StrategyCurveConvexL2Test is BaseStrategyTest { address[] memory rewards = new address[](strategy.curveRewardsLength() + strategy.rewardsV3Length()); for(uint i; i < strategy.curveRewardsLength(); ++i) { - (address[9] memory route,,) = strategy.curveReward(i); + (address[11] memory route,,) = strategy.curveReward(i); rewards[i] = route[0]; } for(uint i; i < strategy.rewardsV3Length(); ++i) { @@ -327,7 +350,9 @@ contract StrategyCurveConvexL2Test is BaseStrategyTest { IRewardsGauge(strategy.gauge()).claim_rewards(address(strategy)); } if (strategy.isCrvMintable()) { + vm.startPrank(address(strategy)); strategy.minter().mint(strategy.gauge()); + vm.stopPrank(); } for (uint i; i < rewards.length; ++i) { string memory s = IERC20Extended(rewards[i]).symbol(); @@ -357,10 +382,19 @@ contract StrategyCurveConvexL2Test is BaseStrategyTest { console.log(string.concat('pid: ', vm.toString(pid), ',')); console.log(string.concat('nativeToDeposit: "', bytesToStr(nativeToDepositPath), '",')); console.log('depositToWant:', string.concat(curveRouteToStr(depositToWantRoute), ',')); - console.log('crvToNative:', string.concat(curveRouteToStr(crvToNativeRoute), ',')); + string memory rewards = '['; + CurveRoute[] memory r = rewardsToNative(); + for (uint i; i < r.length; i++) { + rewards = string.concat(rewards, curveRouteToStr(r[i])); + if (i != r.length - 1) { + rewards = string.concat(rewards, ','); + } + } + rewards = string.concat(rewards, '],'); + console.log('rewardsToNative:', rewards); } - function curveRouteToStr(StrategyCurveConvexL2.CurveRoute memory a) public pure returns (string memory t) { + function curveRouteToStr(CurveRoute memory a) public pure returns (string memory t) { t = string.concat('[\n["', addrToStr(a.route[0]), '"'); for (uint i = 1; i < a.route.length; i++) { t = string.concat(t, ", ", string.concat('"', addrToStr(a.route[i]), '"')); diff --git a/forge/test/strategy/StrategyVelodrome.t.sol b/forge/test/strategy/StrategyVelodrome.t.sol index 8c81c702..d1f8a491 100644 --- a/forge/test/strategy/StrategyVelodrome.t.sol +++ b/forge/test/strategy/StrategyVelodrome.t.sol @@ -29,6 +29,10 @@ contract StrategyVelodrome is BaseStrategyTest { address factory = ISolidlyRouter(unirouter).defaultFactory(); address constant usdc = 0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA; + // ovn-usd+ + address constant want = 0x61366A4e6b1DB1b85DD701f2f4BFa275EF271197; + address constant gauge = 0x00B2149d89677a5069eD4D303941614A33700146; + // DAI-USDbC // address constant want = 0x6EAB8c1B93f5799daDf2C687a30230a540DbD636; // address constant gauge = 0xCF1D5Aa63083fda05c7f8871a9fDbfed7bA49060; @@ -54,8 +58,8 @@ contract StrategyVelodrome is BaseStrategyTest { // address constant gauge = 0xeca7Ff920E7162334634c721133F3183B83B0323; // "name": "aerodrome-mai-usdbc", - address constant want = 0xf6Aec4F97623E691a9426a69BaF5501509fCa05D; - address constant gauge = 0xC01E2ff20501839db7B28F5Cb3eD2876fEa3d6b1; +// address constant want = 0xf6Aec4F97623E691a9426a69BaF5501509fCa05D; +// address constant gauge = 0xC01E2ff20501839db7B28F5Cb3eD2876fEa3d6b1; //"name": "aerodrome-dola-usdbc", // address constant want = 0x0B25c51637c43decd6CC1C1e3da4518D54ddb528; @@ -90,6 +94,12 @@ contract StrategyVelodrome is BaseStrategyTest { } else if (t1 == usdc) { outputToLp0[0] = outputToUsdc[0]; outputToLp0[1] = ISolidlyRouter.Route(usdc, t0, stable, factory); + } else { + // manual per want + outputToLp0 = new ISolidlyRouter.Route[](3); + outputToLp0[0] = outputToUsdc[0]; + outputToLp0[1] = ISolidlyRouter.Route(usdc, t1, true, factory); + outputToLp0[2] = ISolidlyRouter.Route(t1, t0, false, factory); } } @@ -104,6 +114,11 @@ contract StrategyVelodrome is BaseStrategyTest { } else if (t0 == usdc) { outputToLp1[0] = outputToUsdc[0]; outputToLp1[1] = ISolidlyRouter.Route(usdc, t1, stable, factory); + } else { + // manual per want + outputToLp1 = new ISolidlyRouter.Route[](2); + outputToLp1[0] = outputToUsdc[0]; + outputToLp1[1] = ISolidlyRouter.Route(usdc, t1, true, factory); } } } diff --git a/hardhat.config.ts b/hardhat.config.ts index 622d1cce..1ce839cb 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -161,6 +161,7 @@ const config: DeploymentConfig = { // Your API key for Etherscan // Obtain one at https://etherscan.io/ apiKey: { + mainnet: process.env.MAINNET_API_KEY!, polygon: process.env.POLYGON_API_KEY!, zkevm: process.env.ZKEVM_API_KEY!, bsc: process.env.BSC_API_KEY!, diff --git a/package.json b/package.json index 3a54c001..bccfb04b 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "@uniswap/lib": "^4.0.1-alpha", "@uniswap/v2-core": "^1.0.1", "bignumber.js": "^9.0.1", - "blockchain-addressbook": "^0.44.5", + "blockchain-addressbook": "^0.44.19", "keccak": "^3.0.1", "node-fetch": "2.6.1", "rlp": "^2.2.6", @@ -33,6 +33,7 @@ "test:harvester": "hardhat test --network localhost test/infra/BeefyAutoHarvester.test.ts", "deploy:chef": "hardhat run scripts/vault/deploy-generic-chef-strat.ts --network", "deploy:balancer": "hardhat run scripts/vault/deploy-balancer-strat-type.ts --network", + "deploy:aura": "hardhat run scripts/vault/deploy-balancer-strat-eth.ts --network", "deploy:bifiMaxi": "hardhat run scripts/vault/deploy-bifi-maxi.js --network", "deploy:curve": "hardhat run scripts/vault/deploy-curve-strat.ts --network", "deploy:rewardPool": "hardhat run scripts/vault/deploy-generic-rewardPool-strat.ts --network", @@ -58,6 +59,7 @@ "forgeTest:wrapper": "forge test --force --fork-url https://arb1.arbitrum.io/rpc --match-contract WrapperTest", "forgeTest:oracle": "forge test --force --fork-url https://polygon-rpc.com --match-contract Oracle", "forgeTest:swapper": "forge test --force --fork-url https://polygon-rpc.com --match-contract Swapper", + "forgeTest:aura": "forge test --force --fork-url https://rpc.ankr.com/eth --match-contract StrategyAuraGyroTest", "deploy:vaultFactory": "hardhat run scripts/deploy-vault-proxyFactory.js --network", "fork:bsc": "hardhat node --fork bsc", "deploy:tutorial": "hardhat run tutorials/deploy-pancakeswap-vault.js --network localhost" diff --git a/scripts/infra/deployContract.js b/scripts/infra/deployContract.js index 7a62421b..be64d573 100644 --- a/scripts/infra/deployContract.js +++ b/scripts/infra/deployContract.js @@ -4,7 +4,7 @@ const { startingEtherPerAccount } = require("../../utils/configInit"); const ethers = hardhat.ethers; -const contractName = "StrategyQuickGamma"; +const contractName = "StrategyAuraGyroMainnet"; const factoryName = "BeefyVaultV7Factory"; const config = {}; diff --git a/scripts/vault/deploy-balancer-strat-eth.ts b/scripts/vault/deploy-balancer-strat-eth.ts index d8affc1a..8f3b4c13 100644 --- a/scripts/vault/deploy-balancer-strat-eth.ts +++ b/scripts/vault/deploy-balancer-strat-eth.ts @@ -2,38 +2,36 @@ import hardhat, { ethers, web3 } from "hardhat"; import { addressBook } from "blockchain-addressbook"; import vaultV7 from "../../artifacts/contracts/BIFI/vaults/BeefyVaultV7.sol/BeefyVaultV7.json"; import vaultV7Factory from "../../artifacts/contracts/BIFI/vaults/BeefyVaultV7Factory.sol/BeefyVaultV7Factory.json"; -import stratAbi from "../../artifacts/contracts/BIFI/strategies/Balancer/StrategyAuraBalancerMultiRewardGaugeUniV3.sol/StrategyAuraBalancerMultiRewardGaugeUniV3.json"; +import stratAbi from "../../artifacts/contracts/BIFI/strategies/Balancer/StrategyAuraGyroMainnet.sol/StrategyAuraGyroMainnet.json"; const { platforms: { balancer, beefyfinance }, tokens: { BAL: { address: BAL }, ETH: { address: ETH }, - bbaUSDC: { address: bbaUSDC }, - bbaUSD: { address: bbaUSD }, - USDC: { address: USDC }, - MAI: { address: MAI }, + cbETH: { address: cbETH }, + wstETH: { address: wstETH }, AURA: { address: AURA }, - rETH: { address: rETH }, + }, } = addressBook.ethereum; const bytes0 = '0x0000000000000000000000000000000000000000000000000000000000000000'; -const booster = web3.utils.toChecksumAddress("0x7818A1DA7BD1E64c199029E86Ba244a9798eEE10"); -const want = web3.utils.toChecksumAddress("0x334C96d792e4b26B841d28f53235281cec1be1F2"); +const booster = web3.utils.toChecksumAddress("0xA57b8d98dAE62B26Ec3bcC4a365338157060B234"); +const want = web3.utils.toChecksumAddress("0xf01b0684C98CD7aDA480BFDF6e43876422fa1Fc1"); const vaultParams = { - mooName: "Moo Aura rETH-bbaUSD", - mooSymbol: "mooAurarETH-bbaUSD", + mooName: "Moo Aura Gyro wstETH-ETH", + mooSymbol: "mooAuraGyrowstETH-ETH", delay: 21600, }; const strategyParams = { want: want, booster: booster, - pid: 52, - input: rETH, + pid: 162, + input: wstETH, isComposable: false, unirouter: balancer.router, strategist: process.env.STRATEGIST_ADDRESS, @@ -41,7 +39,7 @@ const strategyParams = { beefyFeeRecipient: beefyfinance.beefyFeeRecipient, beefyFeeConfig: beefyfinance.beefyFeeConfig, beefyVaultProxy: "0xC551dDCE8e5E657503Cd67A39713c06F2c0d2e97", //beefyfinance.vaultProxy, - strategyImplementation: "0xc0fbb8F79e6AB8cB0dCE77359748517F9DF1FE19", + strategyImplementation: "0x2b494952C10632B11fEf3139C38fE2AD939F4243", useVaultProxy: true, outputToNativeAssets: [ BAL, @@ -54,17 +52,28 @@ const strategyParams = { 1 ] ], - nativeToWantAssets: [ + nativeToLp0Assets: [ ETH, - rETH + wstETH ], - nativeToWantRouteBytes: [ + nativeToLp0RouteBytes: [ [ - "0x1e19cf2d73a72ef1332c882f20534b6519be0276000200000000000000000112", + "0x93d199263632a4ef4bb438f1feb99e57b4b5f0bd0000000000000000000005c2", 0, 1 ] ], + lp0ToLp1Assets: [ + wstETH, + ETH + ], + lp0ToLp1RouteBytes: [ + [ + "0x93d199263632a4ef4bb438f1feb99e57b4b5f0bd0000000000000000000005c2", + 0, + 1 + ] + ], auraToNativeAssets: [AURA, ETH], auraToNativePath: [ [ @@ -125,12 +134,13 @@ async function main() { const strategyConstructorArguments = [ strategyParams.want, - strategyParams.isComposable, - strategyParams.nativeToWantRouteBytes, + strategyParams.nativeToLp0RouteBytes, + strategyParams.lp0ToLp1RouteBytes, strategyParams.outputToNativeRouteBytes, strategyParams.booster, strategyParams.pid, - strategyParams.nativeToWantAssets, + strategyParams.nativeToLp0Assets, + strategyParams.lp0ToLp1Assets, strategyParams.outputToNativeAssets, [vault, strategyParams.unirouter, diff --git a/yarn.lock b/yarn.lock index 6fa8170d..855a8133 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2566,10 +2566,10 @@ blakejs@^1.1.0: resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.1.tgz#bf313053978b2cd4c444a48795710be05c785702" integrity sha512-bLG6PHOCZJKNshTjGRBvET0vTciwQE6zFKOKKXPDJfwFBd4Ac0yBfPZqcGvGJap50l7ktvlpFqc2jGVaUgbJgg== -blockchain-addressbook@^0.44.5: - version "0.44.5" - resolved "https://registry.yarnpkg.com/blockchain-addressbook/-/blockchain-addressbook-0.44.5.tgz#290dd4bcc1960269e30b6cbc96310e6a5cd76266" - integrity sha512-5sP3V7HOokIFCVZ5pVZv4WWQL3Dm+jAah04DvTVNX55GCLWwLC8H8MeacuALQLxHXGvqgndzLaB79fOODjCCQg== +blockchain-addressbook@^0.44.19: + version "0.44.19" + resolved "https://registry.yarnpkg.com/blockchain-addressbook/-/blockchain-addressbook-0.44.19.tgz#4fad84901bdb7197397dfab3d6ced2cb95d97390" + integrity sha512-QjrmMSLuSoPCxvBgit+wvJNFrK+HlD5oWtDUMnA7wWxPMT3YFbrM0aX4YSlP4GdZ5RM4Z87Wpdc8fh7bIEj1mw== bluebird@^3.5.0, bluebird@^3.5.2: version "3.7.2"