Skip to content

zapper update #183

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

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 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
123 changes: 123 additions & 0 deletions contracts/interfaces/kyber.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.7;
pragma experimental ABIEncoderV2;

import "../lib/erc20.sol";

interface IKyber {
function addLiquidityETH(
address token,
address pool,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
uint256[2] calldata vReserveRatioBounds,
address to,
uint256 deadline
)
external
payable
returns (
uint256 amountToken,
uint256 amountETH,
uint256 liquidity
);

function addLiquidity(
address tokenA,
address tokenB,
address pool,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
uint256[2] calldata vReserveRatioBounds,
address to,
uint256 deadline
)
external
returns (
uint256 amountA,
uint256 amountB,
uint256 liquidity
);

function getTradeInfo() external view returns (
uint112 _reserve0,
uint112 _reserve1,
uint112 _vReserve0,
uint112 _vReserve1,
uint256 feeInPrecision
);

function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1);

/**
* @dev Deposit tokens to accumulate rewards
* @param _pid: id of the pool
* @param _amount: amount of stakeToken to be deposited
* @param _shouldHarvest: whether to harvest the reward or not
*/
function deposit(
uint256 _pid,
uint256 _amount,
bool _shouldHarvest
) external;

/**
* @dev Get pending rewards of a user from a pool, mostly for front-end
* @param _pid: id of the pool
* @param _user: user to check for pending rewards
*/
function pendingRewards(uint256 _pid, address _user)
external view
returns (uint256[] memory rewards);

/**
* @dev Return user's info including deposited amount and reward data
*/
function getUserInfo(uint256 _pid, address _account)
external
view
returns (
uint256 amount,
uint256[] memory unclaimedRewards,
uint256[] memory lastRewardPerShares
);

/**
* @dev Withdraw token (of the sender) from pool, also harvest rewards
* @param _pid: id of the pool
* @param _amount: amount of stakeToken to withdraw
*/
function withdraw(uint256 _pid, uint256 _amount) external;

function harvest(uint256 _pid) external;

function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata poolsPath,
IERC20[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
}

interface IRewardLocker {
/**
* @notice Allow a user to vest with specific schedule
*/
function vestScheduleAtIndices(address token, uint256[] calldata indexes) external returns (uint256);

function accountVestedBalance(address, address) external returns(uint256);
}

interface IKyberFactory {
function getPools(IERC20 token0, IERC20 token1) external view returns (address[] memory _tokenPools);
}

interface IDMMPool {
function kLast() external view returns (uint256);
}
37 changes: 12 additions & 25 deletions contracts/zapper-contract/SnowglobeZapperPangolin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,8 @@ contract SnowglobeZapAvaxPangolin is ZapperBase {
_removeLiquidity(address(pair), address(this));

address swapToken = token1 == desiredToken ? token0 : token1;
address[] memory path = new address[](2);
path[0] = swapToken;
path[1] = desiredToken;

_approveTokenIfNeeded(path[0], address(router));
IPangolinRouter(router).swapExactTokensForTokens(
IERC20(swapToken).balanceOf(address(this)),
desiredTokenOutMin,
path,
address(this),
block.timestamp
);
_approveTokenIfNeeded(swapToken, address(router));
(IERC20[] memory path, ) = _swapToken(swapToken, desiredToken, IERC20(swapToken).balanceOf(address(this)));

_returnAssets(path);
}
Expand All @@ -46,12 +36,15 @@ contract SnowglobeZapAvaxPangolin is ZapperBase {
(uint256 reserveA, uint256 reserveB, ) = pair.getReserves();
require(reserveA > minimumAmount && reserveB > minimumAmount, "Liquidity pair reserves too low");

bool isInputA = pair.token0() == tokenIn;
require(isInputA || pair.token1() == tokenIn, "Input token not present in liquidity pair");
address token0 = pair.token0(); // first token in the pool
address token1 = pair.token1(); // second token in the pool

bool isInputA = token0 == tokenIn;
require(isInputA || token1 == tokenIn, "Input token not present in liquidity pair");

address[] memory path = new address[](2);
path[0] = tokenIn;
path[1] = isInputA ? pair.token1() : pair.token0();
path[1] = isInputA ? token1 : token0;

uint256 fullInvestment = IERC20(tokenIn).balanceOf(address(this));
uint256 swapAmountIn;
Expand All @@ -62,20 +55,14 @@ contract SnowglobeZapAvaxPangolin is ZapperBase {
}

_approveTokenIfNeeded(path[0], address(router));
uint256[] memory swappedAmounts = IPangolinRouter(router).swapExactTokensForTokens(
swapAmountIn,
tokenAmountOutMin,
path,
address(this),
block.timestamp
);
(IERC20[] memory paths, uint256[] memory amounts) = _swapToken(path[0], path[1] , swapAmountIn);

_approveTokenIfNeeded(path[1], address(router));
(, , uint256 amountLiquidity) = IPangolinRouter(router).addLiquidity(
path[0],
path[1],
fullInvestment.sub(swappedAmounts[0]),
swappedAmounts[1],
fullInvestment.sub(amounts[0]),
amounts[1],
1,
1,
address(this),
Expand All @@ -94,7 +81,7 @@ contract SnowglobeZapAvaxPangolin is ZapperBase {
//deposit for into gauge
IGaugeV2(gaugeAddress).depositFor(vault.balanceOf(msg.sender), msg.sender);

_returnAssets(path);
_returnAssets(paths);
}

function _getSwapAmount(uint256 investmentA, uint256 reserveA, uint256 reserveB) public view override returns (uint256 swapAmount) {
Expand Down
38 changes: 12 additions & 26 deletions contracts/zapper-contract/SnowglobeZapperTraderJoe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,8 @@ contract SnowglobeZapAvaxTraderJoe is ZapperBase {
_removeLiquidity(address(pair), address(this));

address swapToken = token1 == desiredToken ? token0 : token1;
address[] memory path = new address[](2);
path[0] = swapToken;
path[1] = desiredToken;

_approveTokenIfNeeded(path[0], address(router));
IJoeRouter(router).swapExactTokensForTokens(
IERC20(swapToken).balanceOf(address(this)),
desiredTokenOutMin,
path,
address(this),
block.timestamp
);
_approveTokenIfNeeded(swapToken, address(router));
(IERC20[] memory path, ) = _swapToken(swapToken, desiredToken, IERC20(swapToken).balanceOf(address(this)));

_returnAssets(path);
}
Expand All @@ -45,12 +35,15 @@ contract SnowglobeZapAvaxTraderJoe is ZapperBase {
(uint256 reserveA, uint256 reserveB, ) = pair.getReserves();
require(reserveA > minimumAmount && reserveB > minimumAmount, "Liquidity pair reserves too low");

bool isInputA = pair.token0() == tokenIn;
require(isInputA || pair.token1() == tokenIn, "Input token not present in liquidity pair");
address token0 = pair.token0(); // first token in the pool
address token1 = pair.token1(); // second token in the pool

bool isInputA = token0 == tokenIn;
require(isInputA || token1 == tokenIn, "Input token not present in liquidity pair");

address[] memory path = new address[](2);
path[0] = tokenIn;
path[1] = isInputA ? pair.token1() : pair.token0();
path[1] = isInputA ? token1 : token0;

uint256 fullInvestment = IERC20(tokenIn).balanceOf(address(this));
uint256 swapAmountIn;
Expand All @@ -61,21 +54,14 @@ contract SnowglobeZapAvaxTraderJoe is ZapperBase {
}

_approveTokenIfNeeded(path[0], address(router));
uint256[] memory swappedAmounts = IJoeRouter(router)
.swapExactTokensForTokens(
swapAmountIn,
tokenAmountOutMin,
path,
address(this),
block.timestamp
);
(IERC20[] memory paths, uint256[] memory amounts) = _swapToken(path[0], path[1] , swapAmountIn);

_approveTokenIfNeeded(path[1], address(router));
(, , uint256 amountLiquidity) = IJoeRouter(router).addLiquidity(
path[0],
path[1],
fullInvestment.sub(swappedAmounts[0]),
swappedAmounts[1],
fullInvestment.sub(amounts[0]),
amounts[1],
1,
1,
address(this),
Expand All @@ -97,7 +83,7 @@ contract SnowglobeZapAvaxTraderJoe is ZapperBase {
//deposit for into gauge
IGaugeV2(gaugeAddress).depositFor(vault.balanceOf(msg.sender), msg.sender);

_returnAssets(path);
_returnAssets(paths);
}

function _getSwapAmount(uint256 investmentA, uint256 reserveA, uint256 reserveB) public view override returns (uint256 swapAmount) {
Expand Down
125 changes: 125 additions & 0 deletions contracts/zapper-contract/SnowglobeZapperVector.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.7;

import "./zapper-base.sol";
import "../interfaces/gaugeproxy.sol";

contract SnowglobeZapAvaxVector is ZapperBase {
address public gaugeProxy = 0x215D5eDEb6A6a3f84AE9d72962FEaCCdF815BF27;

constructor()
public ZapperBase(0x60aE616a2155Ee3d9A68541Ba4544862310933d4){

}

function zapOutAndSwap(address snowglobe, uint256 withdrawAmount, address desiredToken, uint256 desiredTokenOutMin) public override {
(IGlobe vault, IUniPair pair) = _getVaultPair(snowglobe);
address token0 = pair.token0();
address token1 = pair.token1();
require(token0 == desiredToken || token1 == desiredToken, "desired token not present in liquidity pair");

vault.safeTransferFrom(msg.sender, address(this), withdrawAmount);
vault.withdraw(withdrawAmount);
_removeLiquidity(address(pair), address(this));

address swapToken = token1 == desiredToken ? token0 : token1;
_approveTokenIfNeeded(swapToken, address(router));
(IERC20[] memory path, ) = _swapToken(swapToken, desiredToken, IERC20(swapToken).balanceOf(address(this)));

_returnAssets(path);
}

function _swapAndStake(address snowglobe, uint256 tokenAmountOutMin, address tokenIn) public override {
(IGlobe vault, IUniPair pair) = _getVaultPair(snowglobe);

(uint256 reserveA, uint256 reserveB, ) = pair.getReserves();
require(reserveA > minimumAmount && reserveB > minimumAmount, "Liquidity pair reserves too low");

address token0 = pair.token0(); // first token in the pool
address token1 = pair.token1(); // second token in the pool

bool isInputA = token0 == tokenIn;
require(isInputA || token1 == tokenIn, "Input token not present in liquidity pair");

address[] memory path = new address[](2);
path[0] = tokenIn;
path[1] = isInputA ? token1 : token0;

uint256 fullInvestment = IERC20(tokenIn).balanceOf(address(this));
uint256 swapAmountIn;
if (isInputA) {
swapAmountIn = _getSwapAmount(fullInvestment, reserveA, reserveB);
} else {
swapAmountIn = _getSwapAmount(fullInvestment, reserveB, reserveA);
}

_approveTokenIfNeeded(path[0], address(router));
(IERC20[] memory paths, uint256[] memory amounts) = _swapToken(path[0], path[1] , swapAmountIn);

_approveTokenIfNeeded(path[1], address(router));
(, , uint256 amountLiquidity) = IJoeRouter(router).addLiquidity(
path[0],
path[1],
fullInvestment.sub(amounts[0]),
amounts[1],
1,
1,
address(this),
block.timestamp
);

_approveTokenIfNeeded(address(pair), address(vault));
vault.deposit(amountLiquidity);

//add to guage if possible instead of returning to user, and so no receipt token
vault.safeTransfer(msg.sender, vault.balanceOf(address(this)));

//taking receipt token and sending back to user
vault.safeTransfer(msg.sender, vault.balanceOf(address(this)));

//interact with gauge proxy to get gauge address
address gaugeAddress = IGaugeProxyV2(gaugeProxy).getGauge(snowglobe);

//deposit for into gauge
IGaugeV2(gaugeAddress).depositFor(vault.balanceOf(msg.sender), msg.sender);

_returnAssets(paths);
}

function _getSwapAmount(uint256 investmentA, uint256 reserveA, uint256 reserveB) public view override returns (uint256 swapAmount) {
uint256 halfInvestment = investmentA.div(2);
uint256 nominator = IJoeRouter(router).getAmountOut(
halfInvestment,
reserveA,
reserveB
);
uint256 denominator = IJoeRouter(router).quote(
halfInvestment,
reserveA.add(halfInvestment),
reserveB.sub(nominator)
);
swapAmount = investmentA.sub(
Babylonian.sqrt(
(halfInvestment * halfInvestment * nominator) / denominator
)
);
}

function estimateSwap(address snowglobe, address tokenIn, uint256 fullInvestmentIn) public view returns (uint256 swapAmountIn, uint256 swapAmountOut, address swapTokenOut){
(, IUniPair pair) = _getVaultPair(snowglobe);

bool isInputA = pair.token0() == tokenIn;
require(isInputA || pair.token1() == tokenIn, "Input token not present in liquidity pair");

(uint256 reserveA, uint256 reserveB, ) = pair.getReserves();
(reserveA, reserveB) = isInputA ? (reserveA, reserveB) : (reserveB, reserveA);

swapAmountIn = _getSwapAmount(fullInvestmentIn, reserveA, reserveB);
swapAmountOut = IJoeRouter(router).getAmountOut(
swapAmountIn,
reserveA,
reserveB
);
swapTokenOut = isInputA ? pair.token1() : pair.token0();
}
}
Loading