-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
275 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,275 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.23; | ||
|
||
import "./base/LPStrategyBase.sol"; | ||
import "./base/FarmingStrategyBase.sol"; | ||
import "./libs/StrategyIdLib.sol"; | ||
import "./libs/FarmMechanicsLib.sol"; | ||
import "../adapters/libs/AmmAdapterIdLib.sol"; | ||
import "../integrations/convex/IConvexRewardPool.sol"; | ||
|
||
/// @title Staking Curve LP to Convex | ||
/// @author Alien Deployer (https://github.com/a17) | ||
contract CurveConvexFarmStrategy is LPStrategyBase, FarmingStrategyBase { | ||
using SafeERC20 for IERC20; | ||
|
||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ | ||
/* CONSTANTS */ | ||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ | ||
|
||
/// @inheritdoc IControllable | ||
string public constant VERSION = "1.0.0"; | ||
|
||
// keccak256(abi.encode(uint256(keccak256("erc7201:stability.CurveConvexFarmStrategy")) - 1)) & ~bytes32(uint256(0xff)); | ||
bytes32 private constant CURVE_CONVEX_FARM_STRATEGY_STORAGE_LOCATION = | ||
0xe97e1b58b908486b9bee3f474a5533db9346238783d026373610f149c8ce1e00; | ||
|
||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ | ||
/* DATA TYPES */ | ||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ | ||
|
||
/// @custom:storage-location erc7201:stability.CurveConvexFarmStrategy | ||
struct CurveConvexFarmStrategyStorage { | ||
address booster; | ||
uint pid; | ||
} | ||
|
||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ | ||
/* INITIALIZATION */ | ||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ | ||
|
||
/// @inheritdoc IStrategy | ||
function initialize(address[] memory addresses, uint[] memory nums, int24[] memory ticks) public initializer { | ||
if (addresses.length != 2 || nums.length != 1 || ticks.length != 0) { | ||
revert IControllable.IncorrectInitParams(); | ||
} | ||
|
||
IFactory.Farm memory farm = _getFarm(addresses[0], nums[0]); | ||
if (farm.addresses.length != 1 || farm.nums.length != 0 || farm.ticks.length != 0) { | ||
revert IFarmingStrategy.BadFarm(); | ||
} | ||
CurveConvexFarmStrategyStorage storage $ = _getCurveConvexFarmStorage(); | ||
$.booster = IConvexRewardPool(farm.addresses[0]).convexBooster(); | ||
$.pid = IConvexRewardPool(farm.addresses[0]).convexPoolId(); | ||
|
||
__LPStrategyBase_init( | ||
LPStrategyBaseInitParams({ | ||
id: StrategyIdLib.QUICKSWAP_STATIC_MERKL_FARM, | ||
platform: addresses[0], | ||
vault: addresses[1], | ||
pool: farm.pool, | ||
underlying: farm.addresses[0] | ||
}) | ||
); | ||
|
||
__FarmingStrategyBase_init(addresses[0], nums[0]); | ||
|
||
address[] memory _assets = assets(); | ||
uint len = _assets.length; | ||
for (uint i; i < len; ++i) { | ||
IERC20(_assets[i]).forceApprove(farm.pool, type(uint).max); | ||
} | ||
|
||
IERC20(farm.pool).forceApprove($.booster, type(uint).max); | ||
// console.logBytes32(keccak256(abi.encode(uint256(keccak256("erc7201:stability.CurveConvexFarmStrategy")) - 1)) & ~bytes32(uint256(0xff))); | ||
} | ||
|
||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ | ||
/* VIEW FUNCTIONS */ | ||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ | ||
|
||
/// @inheritdoc IERC165 | ||
function supportsInterface(bytes4 interfaceId) | ||
public | ||
view | ||
override(LPStrategyBase, FarmingStrategyBase) | ||
returns (bool) | ||
{ | ||
return super.supportsInterface(interfaceId); | ||
} | ||
|
||
/// @inheritdoc IFarmingStrategy | ||
function canFarm() external view override returns (bool) { | ||
IFactory.Farm memory farm = _getFarm(); | ||
return farm.status == 0; | ||
} | ||
|
||
/// @inheritdoc ILPStrategy | ||
function ammAdapterId() public pure override returns (string memory) { | ||
return AmmAdapterIdLib.CURVE; | ||
} | ||
|
||
/// @inheritdoc IStrategy | ||
function getRevenue() external view returns (address[] memory __assets, uint[] memory amounts) { | ||
__assets = new address[](0); | ||
amounts = new uint[](0); | ||
} | ||
|
||
/// @inheritdoc IStrategy | ||
function initVariants(address platform_) | ||
public | ||
view | ||
returns (string[] memory variants, address[] memory addresses, uint[] memory nums, int24[] memory ticks) | ||
{ | ||
IAmmAdapter _ammAdapter = IAmmAdapter(IPlatform(platform_).ammAdapter(keccak256(bytes(ammAdapterId()))).proxy); | ||
addresses = new address[](0); | ||
ticks = new int24[](0); | ||
|
||
IFactory.Farm[] memory farms = IFactory(IPlatform(platform_).factory()).farms(); | ||
uint len = farms.length; | ||
//slither-disable-next-line uninitialized-local | ||
uint localTtotal; | ||
// nosemgrep | ||
for (uint i; i < len; ++i) { | ||
// nosemgrep | ||
IFactory.Farm memory farm = farms[i]; | ||
// nosemgrep | ||
if (farm.status == 0 && CommonLib.eq(farm.strategyLogicId, strategyLogicId())) { | ||
++localTtotal; | ||
} | ||
Check notice Code scanning / Semgrep OSS Semgrep Finding: rules.solidity.performance.use-nested-if Note
Using nested is cheaper than using && multiple check combinations.
There are more advantages, such as easier to read code and better coverage reports. |
||
} | ||
|
||
variants = new string[](localTtotal); | ||
nums = new uint[](localTtotal); | ||
localTtotal = 0; | ||
// nosemgrep | ||
for (uint i; i < len; ++i) { | ||
// nosemgrep | ||
IFactory.Farm memory farm = farms[i]; | ||
// nosemgrep | ||
if (farm.status == 0 && CommonLib.eq(farm.strategyLogicId, strategyLogicId())) { | ||
nums[localTtotal] = i; | ||
//slither-disable-next-line calls-loop | ||
variants[localTtotal] = _generateDescription(farm, _ammAdapter); | ||
++localTtotal; | ||
} | ||
Check notice Code scanning / Semgrep OSS Semgrep Finding: rules.solidity.performance.use-nested-if Note
Using nested is cheaper than using && multiple check combinations.
There are more advantages, such as easier to read code and better coverage reports. |
||
} | ||
} | ||
|
||
/// @inheritdoc IStrategy | ||
function strategyLogicId() public pure override returns (string memory) { | ||
return StrategyIdLib.CURVE_CONVEX_FARM; | ||
} | ||
|
||
/// @inheritdoc IStrategy | ||
function getAssetsProportions() external view returns (uint[] memory proportions) { | ||
ILPStrategy.LPStrategyBaseStorage storage $lp = _getLPStrategyBaseStorage(); | ||
proportions = $lp.ammAdapter.getProportions($lp.pool); | ||
} | ||
|
||
/// @inheritdoc IStrategy | ||
function extra() external pure returns (bytes32) { | ||
return CommonLib.bytesToBytes32(abi.encodePacked(bytes3(0xeeeeee), bytes3(0x000000))); | ||
} | ||
Check warning Code scanning / Slither Too many digits Warning
CurveConvexFarmStrategy.extra() uses literals with too many digits:
- CommonLib.bytesToBytes32(abi.encodePacked(bytes3(0xeeeeee),bytes3(0x000000))) |
||
|
||
/// @inheritdoc IStrategy | ||
function getSpecificName() external view override returns (string memory, bool) { | ||
return ("", false); | ||
} | ||
|
||
/// @inheritdoc IStrategy | ||
function description() external view returns (string memory) { | ||
IFarmingStrategy.FarmingStrategyBaseStorage storage $f = _getFarmingStrategyBaseStorage(); | ||
ILPStrategy.LPStrategyBaseStorage storage $lp = _getLPStrategyBaseStorage(); | ||
IFactory.Farm memory farm = IFactory(IPlatform(platform()).factory()).farm($f.farmId); | ||
return _generateDescription(farm, $lp.ammAdapter); | ||
} | ||
|
||
/// @inheritdoc IStrategy | ||
function isHardWorkOnDepositAllowed() external pure returns (bool allowed) { | ||
allowed = true; | ||
} | ||
|
||
/// @inheritdoc IStrategy | ||
function isReadyForHardWork() external view returns (bool) { | ||
return true; | ||
} | ||
|
||
/// @inheritdoc IFarmingStrategy | ||
function farmMechanics() external pure returns (string memory) { | ||
return FarmMechanicsLib.CLASSIC; | ||
} | ||
|
||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ | ||
/* STRATEGY BASE */ | ||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ | ||
|
||
/// @inheritdoc StrategyBase | ||
function _depositAssets(uint[] memory amounts, bool claimRevenue) internal override returns (uint value) { | ||
} | ||
|
||
/// @inheritdoc StrategyBase | ||
function _depositUnderlying(uint amount) internal override returns (uint[] memory amountsConsumed) { | ||
} | ||
|
||
/// @inheritdoc StrategyBase | ||
function _withdrawAssets(uint value, address receiver) internal override returns (uint[] memory amountsOut) { | ||
} | ||
|
||
/// @inheritdoc StrategyBase | ||
function _withdrawUnderlying(uint amount, address receiver) internal override { | ||
} | ||
|
||
/// @inheritdoc StrategyBase | ||
function _claimRevenue() | ||
internal | ||
view | ||
override | ||
returns ( | ||
address[] memory __assets, | ||
uint[] memory __amounts, | ||
address[] memory __rewardAssets, | ||
uint[] memory __rewardAmounts | ||
) | ||
{ | ||
} | ||
|
||
/// @inheritdoc StrategyBase | ||
function _compound() internal override { | ||
} | ||
|
||
/// @inheritdoc StrategyBase | ||
function _previewDepositAssets(uint[] memory amountsMax) | ||
internal | ||
view | ||
override(StrategyBase, LPStrategyBase) | ||
returns (uint[] memory amountsConsumed, uint value) | ||
{ | ||
} | ||
|
||
/// @inheritdoc StrategyBase | ||
function _previewDepositUnderlying(uint amount) internal view override returns (uint[] memory amountsConsumed) { | ||
} | ||
|
||
/// @inheritdoc StrategyBase | ||
function _assetsAmounts() internal view override returns (address[] memory assets_, uint[] memory amounts_) { | ||
} | ||
|
||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ | ||
/* INTERNAL LOGIC */ | ||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ | ||
|
||
function _generateDescription( | ||
IFactory.Farm memory farm, | ||
IAmmAdapter _ammAdapter | ||
) internal view returns (string memory) { | ||
//slither-disable-next-line calls-loop | ||
return string.concat( | ||
"Earn ", | ||
//slither-disable-next-line calls-loop | ||
CommonLib.implode(CommonLib.getSymbols(farm.rewardAssets), ", "), | ||
" on Convex by ", | ||
//slither-disable-next-line calls-loop | ||
CommonLib.implode(CommonLib.getSymbols(_ammAdapter.poolTokens(farm.pool)), "-"), | ||
" Curve LP" | ||
); | ||
} | ||
|
||
function _getCurveConvexFarmStorage() internal pure returns (CurveConvexFarmStrategyStorage storage $) { | ||
//slither-disable-next-line assembly | ||
assembly { | ||
$.slot := CURVE_CONVEX_FARM_STRATEGY_STORAGE_LOCATION | ||
} | ||
} | ||
|
||
} |