Merge pull request #108 from Instadapp/feat/quickswap

Feat/quickswap
This commit is contained in:
Samyak Jain 2021-12-17 12:46:53 +05:30 committed by GitHub
commit a2be2a1276
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1991 additions and 0 deletions

View File

@ -41,6 +41,10 @@ abstract contract Basic is DSMath, Stores {
_sell = sell == ethAddr ? TokenInterface(wethAddr) : TokenInterface(sell);
}
function changeEthAddrToWethAddr(address token) internal pure returns(address tokenAddr){
tokenAddr = token == ethAddr ? wethAddr : token;
}
function convertEthToWeth(bool isEth, TokenInterface token, uint amount) internal {
if(isEth) token.deposit{value: amount}();
}

View File

@ -8,6 +8,7 @@ interface TokenInterface {
function withdraw(uint) external;
function balanceOf(address) external view returns (uint);
function decimals() external view returns (uint);
function totalSupply() external view returns (uint);
}
interface MemoryInterface {

View File

@ -0,0 +1,31 @@
pragma solidity ^0.7.0;
contract Events {
event LogDeposit(
uint256 indexed pid,
uint256 indexed version,
uint256 amount
);
event LogWithdraw(
uint256 indexed pid,
uint256 indexed version,
uint256 amount
);
event LogEmergencyWithdraw(
uint256 indexed pid,
uint256 indexed version,
uint256 lpAmount,
uint256 rewardsAmount
);
event LogHarvest(
uint256 indexed pid,
uint256 indexed version,
uint256 amount
);
event LogWithdrawAndHarvest(
uint256 indexed pid,
uint256 indexed version,
uint256 widrawAmount,
uint256 harvestAmount
);
}

View File

@ -0,0 +1,88 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import {DSMath} from "../../common/math.sol";
import {Basic} from "../../common/basic.sol";
import "./interface.sol";
contract Helpers is DSMath, Basic {
IMasterChefV2 immutable masterChefV2 =
IMasterChefV2(0xEF0881eC094552b2e128Cf945EF17a6752B4Ec5d);
IMasterChef immutable masterChef =
IMasterChef(0xc2EdaD668740f1aA35E4D8f227fB8E17dcA888Cd);
ISushiSwapFactory immutable factory =
ISushiSwapFactory(0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac);
function _deposit(uint256 _pid, uint256 _amount, uint256 _version) internal {
if(_version == 2)
masterChefV2.deposit(_pid, _amount, address(this));
else
masterChef.deposit(_pid, _amount);
}
function _withdraw(uint256 _pid, uint256 _amount, uint256 _version) internal {
if(_version == 2)
masterChefV2.withdraw(_pid, _amount, address(this));
else
masterChef.withdraw(_pid, _amount);
}
function _harvest(uint256 _pid) internal {
masterChefV2.harvest(_pid, address(this));
}
function _withdrawAndHarvest(uint256 _pid, uint256 _amount, uint256 _version) internal {
if(_version == 2)
masterChefV2.withdrawAndHarvest(_pid, _amount, address(this));
else _withdraw(_pid, _amount, _version);
}
function _emergencyWithdraw(uint256 _pid, uint256 _version) internal {
if(_version == 2)
masterChefV2.emergencyWithdraw(_pid, address(this));
else
masterChef.emergencyWithdraw(_pid, address(this));
}
function _getPoolId(address tokenA, address tokenB)
internal
view
returns (uint256 poolId, uint256 version, address lpToken)
{
address pair = factory.getPair(tokenA, tokenB);
uint256 length = masterChefV2.poolLength();
version = 2;
poolId = uint256(-1);
for (uint256 i = 0; i < length; i++) {
lpToken = masterChefV2.lpToken(i);
if (pair == lpToken) {
poolId = i;
break;
}
}
uint256 lengthV1 = masterChef.poolLength();
for (uint256 i = 0; i < lengthV1; i++) {
(lpToken, , , ) = masterChef.poolInfo(i);
if (pair == lpToken) {
poolId = i;
version = 1;
break;
}
}
}
function _getUserInfo(uint256 _pid, uint256 _version)
internal
view
returns (uint256 lpAmount, uint256 rewardsAmount)
{
if(_version == 2)
(lpAmount, rewardsAmount) = masterChefV2.userInfo(_pid, address(this));
else
(lpAmount, rewardsAmount) = masterChef.userInfo(_pid, address(this));
}
}

View File

@ -0,0 +1,117 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
struct UserInfo {
uint256 amount;
uint256 rewardDebt;
}
struct PoolInfo {
IERC20 lpToken; // Address of LP token contract.
uint256 allocPoint; // How many allocation points assigned to this pool. SUSHIs to distribute per block.
uint256 lastRewardBlock; // Last block number that SUSHIs distribution occurs.
uint256 accSushiPerShare; // Accumulated SUSHIs per share, times 1e12. See below.
}
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
/// @notice EIP 2612
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
interface IMasterChef {
function poolLength() external view returns (uint256);
function updatePool(uint256 pid) external returns (PoolInfo memory);
function poolInfo(uint256 pid) external view returns (address, uint256, uint256, uint256);
function userInfo(uint256 _pid, address _user)
external
view
returns (uint256, uint256);
function deposit(
uint256 pid,
uint256 amount
) external;
function withdraw(
uint256 pid,
uint256 amount
) external;
function emergencyWithdraw(uint256 pid, address to) external;
}
interface IMasterChefV2 {
function poolLength() external view returns (uint256);
function updatePool(uint256 pid) external returns (PoolInfo memory);
function lpToken(uint256 pid) external view returns (address);
function userInfo(uint256 _pid, address _user)
external
view
returns (uint256, uint256);
function deposit(
uint256 pid,
uint256 amount,
address to
) external;
function withdraw(
uint256 pid,
uint256 amount,
address to
) external;
function emergencyWithdraw(uint256 pid, address to) external;
function harvest(uint256 pid, address to) external;
function withdrawAndHarvest(
uint256 pid,
uint256 amount,
address to
) external;
}
interface ISushiSwapFactory {
function getPair(address tokenA, address tokenB)
external
view
returns (address pair);
function allPairs(uint256) external view returns (address pair);
function allPairsLength() external view returns (uint256);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function createPair(address tokenA, address tokenB)
external
returns (address pair);
}

View File

@ -0,0 +1,174 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/**
* @title SushiSwap Double Incentive.
* @dev Decentralized Exchange.
*/
import {TokenInterface} from "../../common/interfaces.sol";
import {Helpers} from "./helpers.sol";
import {Events} from "./events.sol";
abstract contract SushipswapIncentiveResolver is Helpers, Events {
/**
* @dev deposit LP token to masterChef
* @notice deposit LP token to masterChef
* @param token1 token1 of LP token
* @param token2 token2 of LP token
* @param amount amount of LP token
* @param getId ID to retrieve amount
* @param setId ID stores Pool ID
*/
function deposit(
address token1,
address token2,
uint256 amount,
uint256 getId,
uint256 setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
token1 = changeEthAddrToWethAddr(token1);
token2 = changeEthAddrToWethAddr(token2);
amount = getUint(getId, amount);
(uint256 _pid, uint256 _version, address lpTokenAddr) = _getPoolId(
token1,
token2
);
setUint(setId, _pid);
require(_pid != uint256(-1), "pool-does-not-exist");
TokenInterface lpToken = TokenInterface(lpTokenAddr);
lpToken.approve(address(masterChef), amount);
_deposit(_pid, amount, _version);
_eventName = "LogDeposit(uint256,uint256,uint256)";
_eventParam = abi.encode(_pid, _version, amount);
}
/**
* @dev withdraw LP token from masterChef
* @notice withdraw LP token from masterChef
* @param token1 token1 of LP token
* @param token2 token2 of LP token
* @param amount amount of LP token
* @param getId ID to retrieve amount
* @param setId ID stores Pool ID
*/
function withdraw(
address token1,
address token2,
uint256 amount,
uint256 getId,
uint256 setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
token1 = changeEthAddrToWethAddr(token1);
token2 = changeEthAddrToWethAddr(token2);
amount = getUint(getId, amount);
(uint256 _pid, uint256 _version, ) = _getPoolId(token1, token2);
setUint(setId, _pid);
require(_pid != uint256(-1), "pool-does-not-exist");
_withdraw(_pid, amount, _version);
_eventName = "LogWithdraw(uint256,uint256,uint256)";
_eventParam = abi.encode(_pid, _version, amount);
}
/**
* @dev harvest from masterChef
* @notice harvest from masterChef
* @param token1 token1 deposited of LP token
* @param token2 token2 deposited LP token
* @param setId ID stores Pool ID
*/
function harvest(
address token1,
address token2,
uint256 setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
token1 = changeEthAddrToWethAddr(token1);
token2 = changeEthAddrToWethAddr(token2);
(uint256 _pid, uint256 _version, ) = _getPoolId(token1, token2);
setUint(setId, _pid);
require(_pid != uint256(-1), "pool-does-not-exist");
(, uint256 rewardsAmount) = _getUserInfo(_pid, _version);
if (_version == 2) _harvest(_pid);
else _withdraw(_pid, 0, _version);
_eventName = "LogHarvest(uint256,uint256,uint256)";
_eventParam = abi.encode(_pid, _version, rewardsAmount);
}
/**
* @dev withdraw LP token and harvest from masterChef
* @notice withdraw LP token and harvest from masterChef
* @param token1 token1 of LP token
* @param token2 token2 of LP token
* @param amount amount of LP token
* @param getId ID to retrieve amount
* @param setId ID stores Pool ID
*/
function withdrawAndHarvest(
address token1,
address token2,
uint256 amount,
uint256 getId,
uint256 setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
token1 = changeEthAddrToWethAddr(token1);
token2 = changeEthAddrToWethAddr(token2);
amount = getUint(getId, amount);
(uint256 _pid, uint256 _version, ) = _getPoolId(token1, token2);
setUint(setId, _pid);
require(_pid != uint256(-1), "pool-does-not-exist");
(, uint256 rewardsAmount) = _getUserInfo(_pid, _version);
_withdrawAndHarvest(_pid, amount, _version);
_eventName = "LogWithdrawAndHarvest(uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(_pid, _version, amount, rewardsAmount);
}
/**
* @dev emergency withdraw from masterChef
* @notice emergency withdraw from masterChef
* @param token1 token1 deposited of LP token
* @param token2 token2 deposited LP token
* @param setId ID stores Pool ID
*/
function emergencyWithdraw(
address token1,
address token2,
uint256 setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
token1 = changeEthAddrToWethAddr(token1);
token2 = changeEthAddrToWethAddr(token2);
(uint256 _pid, uint256 _version, ) = _getPoolId(token1, token2);
setUint(setId, _pid);
require(_pid != uint256(-1), "pool-does-not-exist");
(uint256 lpAmount, uint256 rewardsAmount) = _getUserInfo(
_pid,
_version
);
_emergencyWithdraw(_pid, _version);
_eventName = "LogEmergencyWithdraw(uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(_pid, _version, lpAmount, rewardsAmount);
}
}
contract ConnectV2SushiswapIncentive is SushipswapIncentiveResolver {
string public constant name = "SushipswapIncentive-v1.1";
}

View File

@ -0,0 +1,41 @@
pragma solidity ^0.7.0;
contract Events {
event LogDepositLiquidity(
address indexed tokenA,
address indexed tokenB,
uint256 amtA,
uint256 amtB,
uint256 uniAmount,
uint256 getId,
uint256 setId
);
event LogWithdrawLiquidity(
address indexed tokenA,
address indexed tokenB,
uint256 amountA,
uint256 amountB,
uint256 uniAmount,
uint256 getId,
uint256[] setId
);
event LogBuy(
address indexed buyToken,
address indexed sellToken,
uint256 buyAmt,
uint256 sellAmt,
uint256 getId,
uint256 setId
);
event LogSell(
address indexed buyToken,
address indexed sellToken,
uint256 buyAmt,
uint256 sellAmt,
uint256 getId,
uint256 setId
);
}

View File

@ -0,0 +1,184 @@
pragma solidity ^0.7.0;
import {TokenInterface} from "../../common/interfaces.sol";
import {DSMath} from "../../common/math.sol";
import {Basic} from "../../common/basic.sol";
import {ISushiSwapRouter, ISushiSwapFactory} from "./interface.sol";
abstract contract Helpers is DSMath, Basic {
/**
* @dev ISushiSwapRouter
*/
ISushiSwapRouter internal constant router =
ISushiSwapRouter(0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F);
function getExpectedBuyAmt(address[] memory paths, uint256 sellAmt)
internal
view
returns (uint256 buyAmt)
{
uint256[] memory amts = router.getAmountsOut(sellAmt, paths);
buyAmt = amts[1];
}
function getExpectedSellAmt(address[] memory paths, uint256 buyAmt)
internal
view
returns (uint256 sellAmt)
{
uint256[] memory amts = router.getAmountsIn(buyAmt, paths);
sellAmt = amts[0];
}
function checkPair(address[] memory paths) internal view {
address pair = ISushiSwapFactory(router.factory()).getPair(
paths[0],
paths[1]
);
require(pair != address(0), "No-exchange-address");
}
function getPaths(address buyAddr, address sellAddr)
internal
pure
returns (address[] memory paths)
{
paths = new address[](2);
paths[0] = address(sellAddr);
paths[1] = address(buyAddr);
}
function getMinAmount(
TokenInterface token,
uint256 amt,
uint256 slippage
) internal view returns (uint256 minAmt) {
uint256 _amt18 = convertTo18(token.decimals(), amt);
minAmt = wmul(_amt18, sub(WAD, slippage));
minAmt = convert18ToDec(token.decimals(), minAmt);
}
function _addLiquidity(
address tokenA,
address tokenB,
uint256 _amt,
uint256 unitAmt,
uint256 slippage
)
internal
returns (
uint256 _amtA,
uint256 _amtB,
uint256 _liquidity
)
{
(TokenInterface _tokenA, TokenInterface _tokenB) = changeEthAddress(
tokenA,
tokenB
);
_amtA = _amt == uint256(-1)
? getTokenBal(TokenInterface(tokenA))
: _amt;
_amtB = convert18ToDec(
_tokenB.decimals(),
wmul(unitAmt, convertTo18(_tokenA.decimals(), _amtA))
);
bool isEth = address(_tokenA) == wethAddr;
convertEthToWeth(isEth, _tokenA, _amtA);
isEth = address(_tokenB) == wethAddr;
convertEthToWeth(isEth, _tokenB, _amtB);
approve(_tokenA, address(router), _amtA);
approve(_tokenB, address(router), _amtB);
uint256 minAmtA = getMinAmount(_tokenA, _amtA, slippage);
uint256 minAmtB = getMinAmount(_tokenB, _amtB, slippage);
(_amtA, _amtB, _liquidity) = router.addLiquidity(
address(_tokenA),
address(_tokenB),
_amtA,
_amtB,
minAmtA,
minAmtB,
address(this),
block.timestamp + 1
);
}
function _removeLiquidity(
address tokenA,
address tokenB,
uint256 _amt,
uint256 unitAmtA,
uint256 unitAmtB
)
internal
returns (
uint256 _amtA,
uint256 _amtB,
uint256 _uniAmt
)
{
TokenInterface _tokenA;
TokenInterface _tokenB;
(_tokenA, _tokenB, _uniAmt) = _getRemoveLiquidityData(
tokenA,
tokenB,
_amt
);
{
uint256 minAmtA = convert18ToDec(
_tokenA.decimals(),
wmul(unitAmtA, _uniAmt)
);
uint256 minAmtB = convert18ToDec(
_tokenB.decimals(),
wmul(unitAmtB, _uniAmt)
);
(_amtA, _amtB) = router.removeLiquidity(
address(_tokenA),
address(_tokenB),
_uniAmt,
minAmtA,
minAmtB,
address(this),
block.timestamp + 1
);
}
bool isEth = address(_tokenA) == wethAddr;
convertWethToEth(isEth, _tokenA, _amtA);
isEth = address(_tokenB) == wethAddr;
convertWethToEth(isEth, _tokenB, _amtB);
}
function _getRemoveLiquidityData(
address tokenA,
address tokenB,
uint256 _amt
)
internal
returns (
TokenInterface _tokenA,
TokenInterface _tokenB,
uint256 _uniAmt
)
{
(_tokenA, _tokenB) = changeEthAddress(tokenA, tokenB);
address exchangeAddr = ISushiSwapFactory(router.factory()).getPair(
address(_tokenA),
address(_tokenB)
);
require(exchangeAddr != address(0), "pair-not-found.");
TokenInterface uniToken = TokenInterface(exchangeAddr);
_uniAmt = _amt == uint256(-1)
? uniToken.balanceOf(address(this))
: _amt;
approve(uniToken, address(router), _uniAmt);
}
}

View File

@ -0,0 +1,57 @@
pragma solidity ^0.7.0;
interface ISushiSwapRouter {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
interface ISushiSwapFactory {
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function createPair(address tokenA, address tokenB) external returns (address pair);
}

View File

@ -0,0 +1,196 @@
pragma solidity ^0.7.0;
/**
* @title SushiSwap.
* @dev Decentralized Exchange.
*/
import { TokenInterface } from "../../common/interfaces.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
abstract contract SushipswapResolver is Helpers, Events {
/**
* @dev Deposit Liquidity.
* @notice Deposit Liquidity to a SushiSwap pool.
* @param tokenA The address of token A.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param tokenB The address of token B.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param amtA The amount of A tokens to deposit.
* @param unitAmt The unit amount of of amtB/amtA with slippage.
* @param slippage Slippage amount.
* @param getId ID to retrieve amtA.
* @param setId ID stores the amount of pools tokens received.
*/
function deposit(
address tokenA,
address tokenB,
uint256 amtA,
uint256 unitAmt,
uint256 slippage,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amtA);
(uint _amtA, uint _amtB, uint _uniAmt) = _addLiquidity(
tokenA,
tokenB,
_amt,
unitAmt,
slippage
);
setUint(setId, _uniAmt);
_eventName = "LogDepositLiquidity(address,address,uint256,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(tokenA, tokenB, _amtA, _amtB, _uniAmt, getId, setId);
}
/**
* @dev Withdraw Liquidity.
* @notice Withdraw Liquidity from a SushiSwap pool.
* @param tokenA The address of token A.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param tokenB The address of token B.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param uniAmt The amount of pool tokens to withdraw.
* @param unitAmtA The unit amount of amtA/uniAmt with slippage.
* @param unitAmtB The unit amount of amtB/uniAmt with slippage.
* @param getId ID to retrieve uniAmt.
* @param setIds Array of IDs to store the amount tokens received.
*/
function withdraw(
address tokenA,
address tokenB,
uint256 uniAmt,
uint256 unitAmtA,
uint256 unitAmtB,
uint256 getId,
uint256[] calldata setIds
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, uniAmt);
(uint _amtA, uint _amtB, uint _uniAmt) = _removeLiquidity(
tokenA,
tokenB,
_amt,
unitAmtA,
unitAmtB
);
setUint(setIds[0], _amtA);
setUint(setIds[1], _amtB);
_eventName = "LogWithdrawLiquidity(address,address,uint256,uint256,uint256,uint256,uint256[])";
_eventParam = abi.encode(tokenA, tokenB, _amtA, _amtB, _uniAmt, getId, setIds);
}
/**
* @dev Buy ETH/ERC20_Token.
* @notice Buy a token using a SushiSwap
* @param buyAddr The address of the token to buy.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param sellAddr The address of the token to sell.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param buyAmt The amount of tokens to buy.
* @param unitAmt The unit amount of sellAmt/buyAmt with slippage.
* @param getId ID to retrieve buyAmt.
* @param setId ID to store the amount of tokens sold.
*/
function buy(
address buyAddr,
address sellAddr,
uint256 buyAmt,
uint256 unitAmt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _buyAmt = getUint(getId, buyAmt);
(TokenInterface _buyAddr, TokenInterface _sellAddr) = changeEthAddress(buyAddr, sellAddr);
address[] memory paths = getPaths(address(_buyAddr), address(_sellAddr));
uint _slippageAmt = convert18ToDec(_sellAddr.decimals(),
wmul(unitAmt, convertTo18(_buyAddr.decimals(), _buyAmt))
);
checkPair(paths);
uint _expectedAmt = getExpectedSellAmt(paths, _buyAmt);
require(_slippageAmt >= _expectedAmt, "Too much slippage");
bool isEth = address(_sellAddr) == wethAddr;
convertEthToWeth(isEth, _sellAddr, _expectedAmt);
approve(_sellAddr, address(router), _expectedAmt);
uint _sellAmt = router.swapTokensForExactTokens(
_buyAmt,
_expectedAmt,
paths,
address(this),
block.timestamp + 1
)[0];
isEth = address(_buyAddr) == wethAddr;
convertWethToEth(isEth, _buyAddr, _buyAmt);
setUint(setId, _sellAmt);
_eventName = "LogBuy(address,address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(buyAddr, sellAddr, _buyAmt, _sellAmt, getId, setId);
}
/**
* @dev Sell ETH/ERC20_Token.
* @notice Sell a token using a SushiSwap
* @param buyAddr The address of the token to buy.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param sellAddr The address of the token to sell.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param sellAmt The amount of the token to sell.
* @param unitAmt The unit amount of buyAmt/sellAmt with slippage.
* @param getId ID to retrieve sellAmt.
* @param setId ID stores the amount of token brought.
*/
function sell(
address buyAddr,
address sellAddr,
uint256 sellAmt,
uint256 unitAmt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _sellAmt = getUint(getId, sellAmt);
(TokenInterface _buyAddr, TokenInterface _sellAddr) = changeEthAddress(buyAddr, sellAddr);
address[] memory paths = getPaths(address(_buyAddr), address(_sellAddr));
if (_sellAmt == uint(-1)) {
_sellAmt = sellAddr == ethAddr ?
address(this).balance :
_sellAddr.balanceOf(address(this));
}
uint _slippageAmt = convert18ToDec(_buyAddr.decimals(),
wmul(unitAmt, convertTo18(_sellAddr.decimals(), _sellAmt))
);
checkPair(paths);
uint _expectedAmt = getExpectedBuyAmt(paths, _sellAmt);
require(_slippageAmt <= _expectedAmt, "Too much slippage");
bool isEth = address(_sellAddr) == wethAddr;
convertEthToWeth(isEth, _sellAddr, _sellAmt);
approve(_sellAddr, address(router), _sellAmt);
uint _buyAmt = router.swapExactTokensForTokens(
_sellAmt,
_expectedAmt,
paths,
address(this),
block.timestamp + 1
)[1];
isEth = address(_buyAddr) == wethAddr;
convertWethToEth(isEth, _buyAddr, _buyAmt);
setUint(setId, _buyAmt);
_eventName = "LogSell(address,address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(buyAddr, sellAddr, _buyAmt, _sellAmt, getId, setId);
}
}
contract ConnectV2Sushiswap is SushipswapResolver {
string public constant name = "Sushipswap-v1.1";
}

View File

@ -0,0 +1,41 @@
pragma solidity ^0.7.0;
contract Events {
event LogDepositLiquidity(
address indexed tokenA,
address indexed tokenB,
uint256 amtA,
uint256 amtB,
uint256 uniAmount,
uint256 getId,
uint256 setId
);
event LogWithdrawLiquidity(
address indexed tokenA,
address indexed tokenB,
uint256 amountA,
uint256 amountB,
uint256 uniAmount,
uint256 getId,
uint256[] setId
);
event LogBuy(
address indexed buyToken,
address indexed sellToken,
uint256 buyAmt,
uint256 sellAmt,
uint256 getId,
uint256 setId
);
event LogSell(
address indexed buyToken,
address indexed sellToken,
uint256 buyAmt,
uint256 sellAmt,
uint256 getId,
uint256 setId
);
}

View File

@ -0,0 +1,184 @@
pragma solidity ^0.7.0;
import { TokenInterface } from "../../common/interfaces.sol";
import { DSMath } from "../../common/math.sol";
import { Basic } from "../../common/basic.sol";
import { IQuickSwapRouter, IQuickSwapFactory } from "./interface.sol";
abstract contract Helpers is DSMath, Basic {
/**
* @dev IQuickSwapRouter
*/
IQuickSwapRouter internal constant router =
IQuickSwapRouter(0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff);
function getExpectedBuyAmt(address[] memory paths, uint256 sellAmt)
internal
view
returns (uint256 buyAmt)
{
uint256[] memory amts = router.getAmountsOut(sellAmt, paths);
buyAmt = amts[1];
}
function getExpectedSellAmt(address[] memory paths, uint256 buyAmt)
internal
view
returns (uint256 sellAmt)
{
uint256[] memory amts = router.getAmountsIn(buyAmt, paths);
sellAmt = amts[0];
}
function checkPair(address[] memory paths) internal view {
address pair = IQuickSwapFactory(router.factory()).getPair(
paths[0],
paths[1]
);
require(pair != address(0), "No-exchange-address");
}
function getPaths(address buyAddr, address sellAddr)
internal
pure
returns (address[] memory paths)
{
paths = new address[](2);
paths[0] = address(sellAddr);
paths[1] = address(buyAddr);
}
function getMinAmount(
TokenInterface token,
uint256 amt,
uint256 slippage
) internal view returns (uint256 minAmt) {
uint256 _amt18 = convertTo18(token.decimals(), amt);
minAmt = wmul(_amt18, sub(WAD, slippage));
minAmt = convert18ToDec(token.decimals(), minAmt);
}
function _addLiquidity(
address tokenA,
address tokenB,
uint256 _amt,
uint256 unitAmt,
uint256 slippage
)
internal
returns (
uint256 _amtA,
uint256 _amtB,
uint256 _liquidity
)
{
(TokenInterface _tokenA, TokenInterface _tokenB) = changeMaticAddress(
tokenA,
tokenB
);
_amtA = _amt == uint256(-1)
? getTokenBal(TokenInterface(tokenA))
: _amt;
_amtB = convert18ToDec(
_tokenB.decimals(),
wmul(unitAmt, convertTo18(_tokenA.decimals(), _amtA))
);
bool isMatic = address(_tokenA) == wmaticAddr;
convertMaticToWmatic(isMatic, _tokenA, _amtA);
isMatic = address(_tokenB) == wmaticAddr;
convertMaticToWmatic(isMatic, _tokenB, _amtB);
approve(_tokenA, address(router), _amtA);
approve(_tokenB, address(router), _amtB);
uint256 minAmtA = getMinAmount(_tokenA, _amtA, slippage);
uint256 minAmtB = getMinAmount(_tokenB, _amtB, slippage);
(_amtA, _amtB, _liquidity) = router.addLiquidity(
address(_tokenA),
address(_tokenB),
_amtA,
_amtB,
minAmtA,
minAmtB,
address(this),
block.timestamp + 1
);
}
function _removeLiquidity(
address tokenA,
address tokenB,
uint256 _amt,
uint256 unitAmtA,
uint256 unitAmtB
)
internal
returns (
uint256 _amtA,
uint256 _amtB,
uint256 _uniAmt
)
{
TokenInterface _tokenA;
TokenInterface _tokenB;
(_tokenA, _tokenB, _uniAmt) = _getRemoveLiquidityData(
tokenA,
tokenB,
_amt
);
{
uint256 minAmtA = convert18ToDec(
_tokenA.decimals(),
wmul(unitAmtA, _uniAmt)
);
uint256 minAmtB = convert18ToDec(
_tokenB.decimals(),
wmul(unitAmtB, _uniAmt)
);
(_amtA, _amtB) = router.removeLiquidity(
address(_tokenA),
address(_tokenB),
_uniAmt,
minAmtA,
minAmtB,
address(this),
block.timestamp + 1
);
}
bool isMatic = address(_tokenA) == wmaticAddr;
convertWmaticToMatic(isMatic, _tokenA, _amtA);
isMatic = address(_tokenB) == wmaticAddr;
convertWmaticToMatic(isMatic, _tokenB, _amtB);
}
function _getRemoveLiquidityData(
address tokenA,
address tokenB,
uint256 _amt
)
internal
returns (
TokenInterface _tokenA,
TokenInterface _tokenB,
uint256 _uniAmt
)
{
(_tokenA, _tokenB) = changeMaticAddress(tokenA, tokenB);
address exchangeAddr = IQuickSwapFactory(router.factory()).getPair(
address(_tokenA),
address(_tokenB)
);
require(exchangeAddr != address(0), "pair-not-found.");
TokenInterface uniToken = TokenInterface(exchangeAddr);
_uniAmt = _amt == uint256(-1)
? uniToken.balanceOf(address(this))
: _amt;
approve(uniToken, address(router), _uniAmt);
}
}

View File

@ -0,0 +1,97 @@
pragma solidity ^0.7.0;
interface IQuickSwapRouter {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
)
external
returns (
uint256 amountA,
uint256 amountB,
uint256 liquidity
);
function removeLiquidity(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) external pure returns (uint256 amountB);
function getAmountOut(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountOut);
function getAmountIn(
uint256 amountOut,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountIn);
function getAmountsOut(uint256 amountIn, address[] calldata path)
external
view
returns (uint256[] memory amounts);
function getAmountsIn(uint256 amountOut, address[] calldata path)
external
view
returns (uint256[] memory amounts);
}
interface IQuickSwapFactory {
function getPair(address tokenA, address tokenB)
external
view
returns (address pair);
function allPairs(uint256) external view returns (address pair);
function allPairsLength() external view returns (uint256);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function createPair(address tokenA, address tokenB)
external
returns (address pair);
}

View File

@ -0,0 +1,256 @@
pragma solidity ^0.7.0;
/**
* @title QuickSwap.
* @dev Decentralized Exchange.
*/
import { TokenInterface } from "../../common/interfaces.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
abstract contract QuickpswapResolver is Helpers, Events {
/**
* @dev Deposit Liquidity.
* @notice Deposit Liquidity to a QuickSwap pool.
* @param tokenA The address of token A.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param tokenB The address of token B.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param amtA The amount of A tokens to deposit.
* @param unitAmt The unit amount of of amtB/amtA with slippage.
* @param slippage Slippage amount.
* @param getId ID to retrieve amtA.
* @param setId ID stores the amount of pools tokens received.
*/
function deposit(
address tokenA,
address tokenB,
uint256 amtA,
uint256 unitAmt,
uint256 slippage,
uint256 getId,
uint256 setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt = getUint(getId, amtA);
(uint256 _amtA, uint256 _amtB, uint256 _uniAmt) = _addLiquidity(
tokenA,
tokenB,
_amt,
unitAmt,
slippage
);
setUint(setId, _uniAmt);
_eventName = "LogDepositLiquidity(address,address,uint256,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(
tokenA,
tokenB,
_amtA,
_amtB,
_uniAmt,
getId,
setId
);
}
/**
* @dev Withdraw Liquidity.
* @notice Withdraw Liquidity from a QuickSwap pool.
* @param tokenA The address of token A.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param tokenB The address of token B.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param uniAmt The amount of pool tokens to withdraw.
* @param unitAmtA The unit amount of amtA/uniAmt with slippage.
* @param unitAmtB The unit amount of amtB/uniAmt with slippage.
* @param getId ID to retrieve uniAmt.
* @param setIds Array of IDs to store the amount tokens received.
*/
function withdraw(
address tokenA,
address tokenB,
uint256 uniAmt,
uint256 unitAmtA,
uint256 unitAmtB,
uint256 getId,
uint256[] calldata setIds
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt = getUint(getId, uniAmt);
(uint256 _amtA, uint256 _amtB, uint256 _uniAmt) = _removeLiquidity(
tokenA,
tokenB,
_amt,
unitAmtA,
unitAmtB
);
setUint(setIds[0], _amtA);
setUint(setIds[1], _amtB);
_eventName = "LogWithdrawLiquidity(address,address,uint256,uint256,uint256,uint256,uint256[])";
_eventParam = abi.encode(
tokenA,
tokenB,
_amtA,
_amtB,
_uniAmt,
getId,
setIds
);
}
/**
* @dev Buy ETH/ERC20_Token.
* @notice Buy a token using a QuickSwap
* @param buyAddr The address of the token to buy.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param sellAddr The address of the token to sell.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param buyAmt The amount of tokens to buy.
* @param unitAmt The unit amount of sellAmt/buyAmt with slippage.
* @param getId ID to retrieve buyAmt.
* @param setId ID to store the amount of tokens sold.
*/
function buy(
address buyAddr,
address sellAddr,
uint256 buyAmt,
uint256 unitAmt,
uint256 getId,
uint256 setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _buyAmt = getUint(getId, buyAmt);
(
TokenInterface _buyAddr,
TokenInterface _sellAddr
) = changeMaticAddress(buyAddr, sellAddr);
address[] memory paths = getPaths(
address(_buyAddr),
address(_sellAddr)
);
uint256 _slippageAmt = convert18ToDec(
_sellAddr.decimals(),
wmul(unitAmt, convertTo18(_buyAddr.decimals(), _buyAmt))
);
checkPair(paths);
uint256 _expectedAmt = getExpectedSellAmt(paths, _buyAmt);
require(_slippageAmt >= _expectedAmt, "Too much slippage");
bool isEth = address(_sellAddr) == wmaticAddr;
convertMaticToWmatic(isEth, _sellAddr, _expectedAmt);
approve(_sellAddr, address(router), _expectedAmt);
uint256 _sellAmt = router.swapTokensForExactTokens(
_buyAmt,
_expectedAmt,
paths,
address(this),
block.timestamp + 1
)[0];
isEth = address(_buyAddr) == wmaticAddr;
convertWmaticToMatic(isEth, _buyAddr, _buyAmt);
setUint(setId, _sellAmt);
_eventName = "LogBuy(address,address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(
buyAddr,
sellAddr,
_buyAmt,
_sellAmt,
getId,
setId
);
}
/**
* @dev Sell ETH/ERC20_Token.
* @notice Sell a token using a QuickSwap
* @param buyAddr The address of the token to buy.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param sellAddr The address of the token to sell.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param sellAmt The amount of the token to sell.
* @param unitAmt The unit amount of buyAmt/sellAmt with slippage.
* @param getId ID to retrieve sellAmt.
* @param setId ID stores the amount of token brought.
*/
function sell(
address buyAddr,
address sellAddr,
uint256 sellAmt,
uint256 unitAmt,
uint256 getId,
uint256 setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _sellAmt = getUint(getId, sellAmt);
(
TokenInterface _buyAddr,
TokenInterface _sellAddr
) = changeMaticAddress(buyAddr, sellAddr);
address[] memory paths = getPaths(
address(_buyAddr),
address(_sellAddr)
);
if (_sellAmt == uint256(-1)) {
_sellAmt = sellAddr == maticAddr
? address(this).balance
: _sellAddr.balanceOf(address(this));
}
uint256 _slippageAmt = convert18ToDec(
_buyAddr.decimals(),
wmul(unitAmt, convertTo18(_sellAddr.decimals(), _sellAmt))
);
checkPair(paths);
uint256 _expectedAmt = getExpectedBuyAmt(paths, _sellAmt);
require(_slippageAmt <= _expectedAmt, "Too much slippage");
bool isEth = address(_sellAddr) == wmaticAddr;
convertMaticToWmatic(isEth, _sellAddr, _sellAmt);
approve(_sellAddr, address(router), _sellAmt);
uint256 _buyAmt = router.swapExactTokensForTokens(
_sellAmt,
_expectedAmt,
paths,
address(this),
block.timestamp + 1
)[1];
isEth = address(_buyAddr) == wmaticAddr;
convertWmaticToMatic(isEth, _buyAddr, _buyAmt);
setUint(setId, _buyAmt);
_eventName = "LogSell(address,address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(
buyAddr,
sellAddr,
_buyAmt,
_sellAmt,
getId,
setId
);
}
}
contract ConnectV2QuickswapPolygon is QuickpswapResolver {
string public constant name = "Quickpswap-v1.1";
}

View File

@ -18,6 +18,7 @@ async function main() {
"GELATO-A": "ConnectV2Gelato",
"MAKERDAO-A": "ConnectV2Maker",
"UNISWAP-A": "ConnectV2UniswapV2",
"QUICKSWAP-A": "ConnectV2QuickswapPolygon"
"UniswapV3-v1" : "ConnectV2UniswapV3Polygon",
"Uniswap-V3-Staker-v1.1" : "ConnectV2UniswapV3StakerPolygon"
};

View File

@ -0,0 +1,147 @@
import { expect } from "chai";
import hre from "hardhat";
const { waffle, ethers } = hre;
const { provider } = waffle;
import { deployAndEnableConnector } from "../../../scripts/tests/deployAndEnableConnector";
import { buildDSAv2 } from "../../../scripts/tests/buildDSAv2";
import { encodeSpells } from "../../../scripts/tests/encodeSpells";
import { getMasterSigner } from "../../../scripts/tests/getMasterSigner";
import { addLiquidity } from "../../../scripts/tests/addLiquidity";
import { addresses } from "../../../scripts/tests/mainnet/addresses";
import { abis } from "../../../scripts/constant/abis";
import { ConnectV2Sushiswap__factory, ConnectV2Sushiswap } from "../../../typechain";
import type { Signer, Contract } from "ethers";
const DAI_ADDR = "0x6b175474e89094c44da98b954eedeac495271d0f";
describe("Sushiswap", function () {
const connectorName = "Sushiswap-v1";
let dsaWallet0: Contract;
let masterSigner: Signer;
let instaConnectorsV2: Contract;
let connector: Contract;
const wallets = provider.getWallets();
const [wallet0, wallet1, wallet2, wallet3] = wallets;
before(async () => {
await hre.network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
// @ts-ignore
jsonRpcUrl: hre.config.networks.hardhat.forking.url,
blockNumber: 13005785
}
}
]
});
masterSigner = await getMasterSigner();
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
connector = await deployAndEnableConnector({
connectorName,
contractArtifact: ConnectV2Sushiswap__factory,
signer: masterSigner,
connectors: instaConnectorsV2
});
console.log("Connector address", connector.address);
});
it("Should have contracts deployed.", async function () {
expect(!!instaConnectorsV2.address).to.be.true;
expect(!!connector.address).to.be.true;
expect(!!(await masterSigner.getAddress())).to.be.true;
});
describe("DSA wallet setup", function () {
it("Should build DSA v2", async function () {
dsaWallet0 = await buildDSAv2(wallet0.address);
expect(!!dsaWallet0.address).to.be.true;
});
it("Deposit ETH & DAI into DSA wallet", async function () {
await wallet0.sendTransaction({
to: dsaWallet0.address,
value: ethers.utils.parseEther("10")
});
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10"));
await addLiquidity("dai", dsaWallet0.address, ethers.utils.parseEther("100000"));
});
it("Deposit ETH & USDT into DSA wallet", async function () {
await wallet0.sendTransaction({
to: dsaWallet0.address,
value: ethers.utils.parseEther("10")
});
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10"));
await addLiquidity("usdt", dsaWallet0.address, ethers.utils.parseEther("100000"));
});
});
describe("Main", function () {
it("Should deposit successfully", async function () {
const ethAmount = ethers.utils.parseEther("0.1"); // 1 ETH
const daiUnitAmount = ethers.utils.parseEther("4000"); // 1 ETH
const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
const getId = "0";
const setId = "0";
const spells = [
{
connector: connectorName,
method: "deposit",
args: [ethAddress, DAI_ADDR, ethAmount, daiUnitAmount, "500000000000000000", getId, setId]
}
];
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address);
let receipt = await tx.wait();
}).timeout(10000000000);
it("Should withdraw successfully", async function () {
const ethAmount = ethers.utils.parseEther("0.1"); // 1 ETH
const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
const getId = "0";
const setIds = ["0", "0"];
const spells = [
{
connector: connectorName,
method: "withdraw",
args: [ethAddress, DAI_ADDR, ethAmount, 0, 0, getId, setIds]
}
];
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address);
let receipt = await tx.wait();
});
it("Should buy successfully", async function () {
const ethAmount = ethers.utils.parseEther("0.1"); // 1 ETH
const daiUnitAmount = ethers.utils.parseEther("4000"); // 1 ETH
const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
const getId = "0";
const setId = "0";
const spells = [
{
connector: connectorName,
method: "buy",
args: [ethAddress, DAI_ADDR, ethAmount, daiUnitAmount, getId, setId]
}
];
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address);
let receipt = await tx.wait();
});
});
});

View File

@ -0,0 +1,235 @@
import { expect } from "chai";
import hre from "hardhat";
const { waffle, ethers } = hre;
const { provider } = waffle
import {deployAndEnableConnector} from "../../../scripts/tests/deployAndEnableConnector";
import {buildDSAv2} from "../../../scripts/tests/buildDSAv2";
import {encodeSpells} from "../../../scripts/tests/encodeSpells";
import {getMasterSigner} from "../../../scripts/tests/getMasterSigner";
import {addLiquidity} from "../../../scripts/tests/addLiquidity";
import {addresses} from "../../../scripts/tests/mainnet/addresses";
import {abis} from "../../../scripts/constant/abis";
import { ConnectV2Sushiswap__factory, ConnectV2Sushiswap, ConnectV2SushiswapIncentive, ConnectV2SushiswapIncentive__factory } from "../../../typechain";
import { Contract, Signer } from "ethers";
const DAI_ADDR = "0x6b175474e89094c44da98b954eedeac495271d0f"
const WETH_ADDR = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
describe("Sushiswap", function () {
const connectorName = "Sushiswap-v1"
const incentiveConnectorName = "Sushiswp-Incentive-v1"
let dsaWallet0: Contract;
let masterSigner: Signer;
let instaConnectorsV2: Contract;
let connector: Contract, connectorIncentive;
const wallets = provider.getWallets()
const [wallet0, wallet1, wallet2, wallet3] = wallets
before(async () => {
await hre.network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
// @ts-ignore
jsonRpcUrl: hre.config.networks.hardhat.forking.url,
blockNumber: 13005785,
},
},
],
});
masterSigner = await getMasterSigner()
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
connector = await deployAndEnableConnector({
connectorName,
contractArtifact: ConnectV2Sushiswap__factory,
signer: masterSigner,
connectors: instaConnectorsV2
})
console.log("Connector address", connector.address)
connectorIncentive = await deployAndEnableConnector({
connectorName: incentiveConnectorName,
contractArtifact: ConnectV2SushiswapIncentive__factory,
signer: masterSigner,
connectors: instaConnectorsV2
})
console.log("Incentive Connector address", connectorIncentive.address)
})
it("Should have contracts deployed.", async function () {
expect(!!instaConnectorsV2.address).to.be.true;
expect(!!connector.address).to.be.true;
expect(!!(await masterSigner.getAddress())).to.be.true;
});
describe("DSA wallet setup", function () {
it("Should build DSA v2", async function () {
dsaWallet0 = await buildDSAv2(wallet0.address)
expect(!!dsaWallet0.address).to.be.true;
});
it("Deposit ETH & DAI into DSA wallet", async function () {
await wallet0.sendTransaction({
to: dsaWallet0.address,
value: ethers.utils.parseEther("10")
});
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10"));
await addLiquidity("dai", dsaWallet0.address, ethers.utils.parseEther("100000"));
});
it("Deposit ETH & USDT into DSA wallet", async function () {
await wallet0.sendTransaction({
to: dsaWallet0.address,
value: ethers.utils.parseEther("10")
});
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10"));
await addLiquidity("usdt", dsaWallet0.address, ethers.utils.parseEther("100000"));
});
});
describe("Main", function () {
it("Should deposit successfully", async function () {
const ethAmount = ethers.utils.parseEther("2") // 1 ETH
const daiUnitAmount = ethers.utils.parseEther("4000") // 1 ETH
const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
const getId = "0"
const setId = "0"
const spells = [
{
connector: connectorName,
method: "deposit",
args: [
ethAddress,
DAI_ADDR,
ethAmount,
daiUnitAmount,
"500000000000000000",
getId,
setId
],
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
await tx.wait()
describe("Incentive", () => {
it("Should deposit successfully", async () => {
const getId = 0
const setId = 0
const spells = [
{
connector: incentiveConnectorName,
method: "deposit",
args: [
WETH_ADDR,
DAI_ADDR,
ethers.utils.parseEther("10"),
getId,
setId
]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet0.address)
await tx.wait();
})
it("Should harvest successfully", async () => {
const setId = 0
const spells = [
{
connector: incentiveConnectorName,
method: "harvest",
args: [
WETH_ADDR,
DAI_ADDR,
setId
]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet0.address)
await tx.wait();
})
it("Should harvest and withdraw successfully", async () => {
const getId = 0
const setId = 0
const spells = [
{
connector: incentiveConnectorName,
method: "withdrawAndHarvest",
args: [
WETH_ADDR,
DAI_ADDR,
ethers.utils.parseEther("1"),
getId,
setId
]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet0.address)
await tx.wait();
})
it("Should withdraw successfully", async () => {
const getId = 0
const setId = 0
const spells = [
{
connector: incentiveConnectorName,
method: "withdraw",
args: [
WETH_ADDR,
DAI_ADDR,
ethers.utils.parseEther("1"),
getId,
setId
]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet0.address)
await tx.wait();
})
})
}).timeout(10000000000);
it("Should buy successfully", async function () {
const ethAmount = ethers.utils.parseEther("0.1") // 1 ETH
const daiUnitAmount = ethers.utils.parseEther("4000") // 1 ETH
const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
const getId = "0"
const setId = "0"
const spells = [
{
connector: connectorName,
method: "buy",
args: [
ethAddress,
DAI_ADDR,
ethAmount,
daiUnitAmount,
getId,
setId
]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
let receipt = await tx.wait()
});
});
})

View File

@ -0,0 +1,137 @@
import { expect } from "chai";
import hre from "hardhat";
const { waffle, ethers } = hre;
const { provider } = waffle;
import { deployAndEnableConnector } from "../../../scripts/tests/deployAndEnableConnector";
import { buildDSAv2 } from "../../../scripts/tests/buildDSAv2";
import { encodeSpells } from "../../../scripts/tests/encodeSpells";
import { getMasterSigner } from "../../../scripts/tests/getMasterSigner";
import { addLiquidity } from "../../../scripts/tests/addLiquidity";
import { addresses } from "../../../scripts/tests/polygon/addresses";
import { abis } from "../../../scripts/constant/abis";
import { ConnectV2QuickswapPolygon__factory, ConnectV2QuickswapPolygon } from "../../../typechain";
import type { Signer, Contract } from "ethers";
const DAI_ADDR = "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063";
describe("Quickswap", function () {
const connectorName = "Quickswap-v1";
let dsaWallet0: Contract;
let masterSigner: Signer;
let instaConnectorsV2: Contract;
let connector: Contract;
const wallets = provider.getWallets();
const [wallet0, wallet1, wallet2, wallet3] = wallets;
before(async () => {
await hre.network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
// @ts-ignore
jsonRpcUrl: hre.config.networks.hardhat.forking.url
// blockNumber: 13005785
}
}
]
});
masterSigner = await getMasterSigner();
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
connector = await deployAndEnableConnector({
connectorName,
contractArtifact: ConnectV2QuickswapPolygon__factory,
signer: masterSigner,
connectors: instaConnectorsV2
});
console.log("Connector address", connector.address);
});
it("Should have contracts deployed.", async function () {
expect(!!instaConnectorsV2.address).to.be.true;
expect(!!connector.address).to.be.true;
expect(!!(await masterSigner.getAddress())).to.be.true;
});
describe("DSA wallet setup", function () {
it("Should build DSA v2", async function () {
dsaWallet0 = await buildDSAv2(wallet0.address);
expect(!!dsaWallet0.address).to.be.true;
});
it("Deposit ETH & DAI into DSA wallet", async function () {
await wallet0.sendTransaction({
to: dsaWallet0.address,
value: ethers.utils.parseEther("10")
});
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10"));
await addLiquidity("dai", dsaWallet0.address, ethers.utils.parseEther("10000"));
});
});
describe("Main", function () {
it("Should deposit successfully", async function () {
const ethAmount = ethers.utils.parseEther("0.1"); // 1 ETH
const daiUnitAmount = ethers.utils.parseEther("1"); // 1 ETH
const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
const getId = "0";
const setId = "0";
const spells = [
{
connector: connectorName,
method: "deposit",
args: [ethAddress, DAI_ADDR, ethAmount, daiUnitAmount, "500000000000000000", getId, setId]
}
];
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address);
let receipt = await tx.wait();
}).timeout(10000000000);
it("Should withdraw successfully", async function () {
const ethAmount = ethers.utils.parseEther("0.001"); // 1 ETH
const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
const getId = "0";
const setIds = ["0", "0"];
const spells = [
{
connector: connectorName,
method: "withdraw",
args: [ethAddress, DAI_ADDR, ethAmount, 0, 0, getId, setIds]
}
];
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address);
let receipt = await tx.wait();
});
it("Should buy successfully", async function () {
const ethAmount = ethers.utils.parseEther("0.1"); // 1 ETH
const daiUnitAmount = ethers.utils.parseEther("4000"); // 1 ETH
const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
const getId = "0";
const setId = "0";
const spells = [
{
connector: connectorName,
method: "buy",
args: [ethAddress, DAI_ADDR, ethAmount, daiUnitAmount, getId, setId]
}
];
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address);
let receipt = await tx.wait();
});
});
});