Skip to content

Commit

Permalink
Merge pull request #89 from stabilitydao/iqmf-strategy
Browse files Browse the repository at this point in the history
IQMF related fixes
  • Loading branch information
a17 authored Jan 27, 2024
2 parents fbaf4d1 + df6b8cb commit ce822fc
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 124 deletions.
2 changes: 1 addition & 1 deletion script/DeployStrategyIQMF.Polygon.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.23;
import "forge-std/Script.sol";
import "../src/strategies/IchiQuickSwapMerklFarmStrategy.sol";

contract DeployStrategyDQMFPolygon is Script {
contract DeployStrategyIQMFPolygon is Script {
function run() external {
uint deployerPrivateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);
Expand Down
226 changes: 113 additions & 113 deletions src/strategies/IchiQuickSwapMerklFarmStrategy.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "./base/LPStrategyBase.sol";
import "./base/FarmingStrategyBase.sol";
import "./libs/StrategyIdLib.sol";
Expand All @@ -14,7 +14,14 @@ import "../integrations/ichi/IICHIVault.sol";
contract IchiQuickSwapMerklFarmStrategy is LPStrategyBase, FarmingStrategyBase {
using SafeERC20 for IERC20;

uint public constant PRECISION = 10 ** 18;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/// @inheritdoc IControllable
string public constant VERSION = "1.0.1";

uint internal constant PRECISION = 10 ** 18;

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INITIALIZATION */
Expand Down Expand Up @@ -48,13 +55,6 @@ contract IchiQuickSwapMerklFarmStrategy is LPStrategyBase, FarmingStrategyBase {
IERC20(_assets[1]).forceApprove(farm.addresses[0], type(uint).max);
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/// @inheritdoc IControllable
string public constant VERSION = "1.0.0";

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* VIEW FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
Expand All @@ -69,11 +69,104 @@ contract IchiQuickSwapMerklFarmStrategy is LPStrategyBase, FarmingStrategyBase {
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.ALGEBRA;
}

/// @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 IQMFLib.generateDescription(farm, $lp.ammAdapter);
}

/// @inheritdoc IStrategy
function extra() external pure returns (bytes32) {
return CommonLib.bytesToBytes32(abi.encodePacked(bytes3(0x965fff), bytes3(0x000000)));
}

/// @inheritdoc IStrategy
function getAssetsProportions() public view returns (uint[] memory proportions) {
StrategyBaseStorage storage __$__ = _getStrategyBaseStorage();
IICHIVault _underlying = IICHIVault(__$__._underlying);
proportions = new uint[](2);
if (_underlying.allowToken0()) proportions[0] = 1e18;
if (_underlying.allowToken1()) proportions[1] = 1e18;
}

/// @inheritdoc IStrategy
function getRevenue() external view returns (address[] memory __assets, uint[] memory amounts) {
__assets = _getFarmingStrategyBaseStorage()._rewardAssets;
uint len = __assets.length;
amounts = new uint[](len);
for (uint i; i < len; ++i) {
amounts[i] = StrategyLib.balance(__assets[i]);
}
// just for covergage
_getRewards();
}

/// @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;
}
}

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] = IQMFLib.generateDescription(farm, _ammAdapter);
++localTtotal;
}
}
}

/// @inheritdoc IStrategy
function strategyLogicId() public pure override returns (string memory) {
return StrategyIdLib.ICHI_QUICKSWAP_MERKL_FARM;
}

/// @inheritdoc IStrategy
function getSpecificName() external view override returns (string memory, bool) {
IFactory.Farm memory farm = _getFarm();
string memory shortAddr = IQMFLib.shortAddress(farm.addresses[0]);
return (shortAddr, true);
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FARMING STRATEGY BASE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
Expand All @@ -83,12 +176,6 @@ contract IchiQuickSwapMerklFarmStrategy is LPStrategyBase, FarmingStrategyBase {
// calculated in getRevenue()
}

/// @inheritdoc IFarmingStrategy
function canFarm() external view override returns (bool) {
IFactory.Farm memory farm = _getFarm();
return farm.status == 0;
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRATEGY BASE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
Expand Down Expand Up @@ -204,104 +291,17 @@ contract IchiQuickSwapMerklFarmStrategy is LPStrategyBase, FarmingStrategyBase {
}
}

/// @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 IQMFLib.generateDescription(farm, $lp.ammAdapter);
}

/// @inheritdoc IStrategy
function extra() external pure returns (bytes32) {
return CommonLib.bytesToBytes32(abi.encodePacked(bytes3(0x965fff), bytes3(0x000000)));
}

/// @inheritdoc IStrategy
function getAssetsProportions() public view returns (uint[] memory proportions) {
StrategyBaseStorage storage __$__ = _getStrategyBaseStorage();
IICHIVault _underlying = IICHIVault(__$__._underlying);
proportions = new uint[](2);
if (_underlying.allowToken0()) proportions[0] = 1e18;
if (_underlying.allowToken1()) proportions[1] = 1e18;
}

/// @inheritdoc IStrategy
function getRevenue() external view returns (address[] memory __assets, uint[] memory amounts) {
__assets = _getFarmingStrategyBaseStorage()._rewardAssets;
uint len = __assets.length;
amounts = new uint[](len);
for (uint i; i < len; ++i) {
amounts[i] = StrategyLib.balance(__assets[i]);
}
// just for covergage
_getRewards();
}

/// @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;
}
}

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] = IQMFLib.generateDescription(farm, _ammAdapter);
++localTtotal;
}
}
}

/// @inheritdoc IStrategy
function strategyLogicId() public pure override returns (string memory) {
return StrategyIdLib.ICHI_QUICKSWAP_MERKL_FARM;
}

/// @inheritdoc IStrategy
function getSpecificName() external view override returns (string memory, bool) {
IFactory.Farm memory farm = _getFarm();
string memory shortAddr = IQMFLib.shortAddress(farm.addresses[0]);
return (shortAddr, true);
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/**
* @notice returns equivalent _tokenOut for _amountIn, _tokenIn using spot price
* @param _tokenIn token the input amount is in
* @param _tokenOut token for the output amount
* @param _tick tick for the spot price
* @param _amountIn amount in _tokenIn
* @return amountOut equivalent anount in _tokenOut
* @param _tokenIn token the input amount is in
* @param _tokenOut token for the output amount
* @param _tick tick for the spot price
* @param _amountIn amount in _tokenIn
* @return amountOut equivalent anount in _tokenOut
*/
function _fetchSpot(
address _tokenIn,
Expand All @@ -314,12 +314,12 @@ contract IchiQuickSwapMerklFarmStrategy is LPStrategyBase, FarmingStrategyBase {

/**
* @notice returns equivalent _tokenOut for _amountIn, _tokenIn using TWAP price
* @param _pool Pool address to be used for price checking
* @param _tokenIn token the input amount is in
* @param _tokenOut token for the output amount
* @param _twapPeriod the averaging time period
* @param _amountIn amount in _tokenIn
* @return amountOut equivalent anount in _tokenOut
* @param _pool Pool address to be used for price checking
* @param _tokenIn token the input amount is in
* @param _tokenOut token for the output amount
* @param _twapPeriod the averaging time period
* @param _amountIn amount in _tokenIn
* @return amountOut equivalent anount in _tokenOut
*/
function _fetchTwap(
address _pool,
Expand Down
14 changes: 5 additions & 9 deletions src/strategies/libs/IQMFLib.sol
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import "../../integrations/algebra/IAlgebraPool.sol";
import "./ALMPositionNameLib.sol";
import "../../core/libs/CommonLib.sol";
import "../libs/UniswapV3MathLib.sol";
import "../../core/libs/CommonLib.sol";
import "../../interfaces/IFactory.sol";
import "../../interfaces/IAmmAdapter.sol";
import "../../integrations/algebra/IAlgebraPool.sol";

/// @title DataStorage library
/// @notice Provides functions to integrate with pool dataStorage
library IQMFLib {
error PoolIsLocked();
/// @notice Fetches time-weighted average tick using Algebra dataStorage
/// @param pool Address of Algebra pool that we want to getTimepoints
/// @param period Number of seconds in the past to start calculating time-weighted average
/// @return timeWeightedAverageTick The time-weighted average tick from (block.timestamp - period) to block.timestamp

function consult(address pool, uint32 period) internal view returns (int24 timeWeightedAverageTick) {
function consult(address pool, uint32 period) external view returns (int24 timeWeightedAverageTick) {
require(period != 0, "BP");

uint32[] memory secondAgos = new uint32[](2);
Expand All @@ -44,9 +41,8 @@ library IQMFLib {
uint128 baseAmount,
address baseToken,
address quoteToken
) internal pure returns (uint quoteAmount) {
) external pure returns (uint quoteAmount) {
uint160 sqrtRatioX96 = UniswapV3MathLib.getSqrtRatioAtTick(tick);

// Calculate quoteAmount with better precision if it doesn't overflow when multiplied by itself
if (sqrtRatioX96 <= type(uint128).max) {
uint ratioX192 = uint(sqrtRatioX96) * sqrtRatioX96;
Expand All @@ -73,7 +69,7 @@ library IQMFLib {
" on QuickSwap by ",
//slither-disable-next-line calls-loop
CommonLib.implode(CommonLib.getSymbols(ammAdapter.poolTokens(farm.pool)), "-"),
" ICHI strategy",
" Ichi Yield IQ strategy ",
shortAddress(farm.addresses[0])
);
}
Expand Down
2 changes: 1 addition & 1 deletion test/base/UniversalTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ abstract contract UniversalTest is Test, ChainSetup, Utils {

{
uint[] memory assetsProportions = IStrategy(address(strategy)).getAssetsProportions();
bool isZero;
bool isZero = true;
for (uint x; x < assetsProportions.length; x++) {
if (assetsProportions[x] != 0) {
isZero = false;
Expand Down

0 comments on commit ce822fc

Please sign in to comment.