Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update PangolinV2StrategyForLP #248

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
116 changes: 116 additions & 0 deletions contracts/strategies/avalanche/pangolin/PangolinV2StrategyForLP.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.13;

import "../../BaseStrategy.sol";
import "../../../interfaces/IERC20.sol";
import "../../../interfaces/IPair.sol";

import "./interfaces/IMiniChefV2.sol";
import "./interfaces/IPangolinRewarder.sol";

contract PangolinV2StrategyForLP is BaseStrategy {
using SafeERC20 for IERC20;

IMiniChefV2 public immutable miniChef;
uint256 public immutable PID;
address public immutable poolRewardToken;

address internal immutable token0;
address internal immutable token1;

constructor(
address _stakingContract,
uint256 _pid,
BaseStrategySettings memory _baseStrategySettings,
StrategySettings memory _strategySettings
) BaseStrategy(_baseStrategySettings, _strategySettings) {
PID = _pid;
miniChef = IMiniChefV2(_stakingContract);
poolRewardToken = miniChef.REWARD();
token0 = IPair(address(depositToken)).token0();
token1 = IPair(address(depositToken)).token1();
}

function _depositToStakingContract(uint256 _amount, uint256) internal override {
depositToken.approve(address(miniChef), _amount);
miniChef.deposit(PID, _amount, address(this));
}

function _withdrawFromStakingContract(uint256 _amount) internal override returns (uint256 withdrawAmount) {
miniChef.withdraw(PID, _amount, address(this));
return _amount;
}

function _pendingRewards() internal view virtual override returns (Reward[] memory) {
uint256 poolRewardAmount = miniChef.pendingReward(PID, address(this));
IPangolinRewarder rewarder = IPangolinRewarder(miniChef.rewarder(PID));
Reward[] memory pendingRewards;
if (address(rewarder) > address(0)) {
(address[] memory rewardTokens, uint256[] memory rewardAmounts) =
rewarder.pendingTokens(0, address(this), poolRewardAmount);
pendingRewards = new Reward[](rewardTokens.length + 1);
for (uint256 i = 0; i < rewardTokens.length; i++) {
pendingRewards[i + 1] = Reward({reward: rewardTokens[i], amount: rewardAmounts[i]});
}
} else {
pendingRewards = new Reward[](1);
}
pendingRewards[0] = Reward({reward: poolRewardToken, amount: poolRewardAmount});
return pendingRewards;
}

function _getRewards() internal virtual override {
miniChef.harvest(PID, address(this));
}

function _convertRewardTokenToDepositToken(uint256 fromAmount) internal override returns (uint256 toAmount) {
fromAmount = fromAmount / 2;
if (address(rewardToken) != token0) {
FormattedOffer memory offer = simpleRouter.query(fromAmount, address(rewardToken), token0);
rewardToken.approve(address(simpleRouter), fromAmount);
simpleRouter.swap(offer);
}
if (address(rewardToken) != token1) {
FormattedOffer memory offer = simpleRouter.query(fromAmount, address(rewardToken), token1);
rewardToken.approve(address(simpleRouter), fromAmount);
simpleRouter.swap(offer);
}
toAmount = addLiquidity(
address(depositToken), IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this))
);
}

function addLiquidity(address depositToken, uint256 maxAmountIn0, uint256 maxAmountIn1)
internal
returns (uint256)
{
(uint112 reserve0, uint112 reserve1,) = IPair(address(depositToken)).getReserves();
uint256 amountIn1 = _quoteLiquidityAmountOut(maxAmountIn0, reserve0, reserve1);
if (amountIn1 > maxAmountIn1) {
amountIn1 = maxAmountIn1;
maxAmountIn0 = _quoteLiquidityAmountOut(maxAmountIn1, reserve1, reserve0);
}
IERC20(token0).safeTransfer(depositToken, maxAmountIn0);
IERC20(token1).safeTransfer(depositToken, amountIn1);

return IPair(depositToken).mint(address(this));
}

function _quoteLiquidityAmountOut(uint256 amountIn, uint256 reserve0, uint256 reserve1)
private
pure
returns (uint256)
{
return (amountIn * reserve1) / reserve0;
}

function totalDeposits() public view override returns (uint256 amount) {
(amount,) = miniChef.userInfo(PID, address(this));
}

function _emergencyWithdraw() internal override {
miniChef.emergencyWithdraw(PID, address(this));
depositToken.approve(address(miniChef), 0);
}
}

This file was deleted.

22 changes: 6 additions & 16 deletions contracts/strategies/avalanche/pangolin/interfaces/IMiniChefV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,19 @@ interface IMiniChefV2 {
function poolInfo(uint256 pid)
external
view
returns (
uint256 allocPoint,
uint256 lastRewardTime,
uint256 accRewardPerShare
);
returns (uint256 allocPoint, uint256 lastRewardTime, uint256 accRewardPerShare);

function REWARD() external view returns (address);

function rewarder(uint256 pid) external view returns (address);

function lpToken(uint256 pid) external view returns (address);

function pendingReward(uint256 _pid, address _user) external view returns (uint256);

function deposit(
uint256 pid,
uint256 amount,
address to
) external;

function withdraw(
uint256 pid,
uint256 amount,
address to
) external;
function deposit(uint256 pid, uint256 amount, address to) external;

function withdraw(uint256 pid, uint256 amount, address to) external;

function harvest(uint256 pid, address to) external;

Expand Down