implement uniswap v3 staker

This commit is contained in:
cryptoDev222 2021-08-24 14:04:17 -05:00
parent 2c1bbf6c36
commit 30eb39378f
5 changed files with 929 additions and 0 deletions

View File

@ -0,0 +1,34 @@
pragma solidity ^0.7.0;
contract Events {
event LogDeposit(
uint256 indexed tokenId,
uint256 liquidity,
uint256 amountA,
uint256 amountB
);
event LogWithdraw(
uint256 indexed tokenId,
uint256 liquidity,
uint256 amountA,
uint256 amountB
);
event LogStake(uint256 tokenId, address refundee);
event LogUnstake(uint256 tokenId, bytes32 incentiveId);
event LogRewardClaimed(
address rewardToken,
address receiver,
uint256 amount
);
event LogIncentiveCreated(
uint256 tokenId,
uint256 startTime,
uint256 endTime,
uint256 reward
);
}

View File

@ -0,0 +1,230 @@
pragma solidity ^0.7.6;
pragma abicoder v2;
import {TokenInterface} from "../../common/interfaces.sol";
import {DSMath} from "../../common/math.sol";
import {Basic} from "../../common/basic.sol";
import "./interface.sol";
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import "@uniswap/v3-core/contracts/libraries/TickMath.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
abstract contract Helpers is DSMath, Basic {
/**
* @dev uniswap v3 NFT Position Manager & Swap Router
*/
INonfungiblePositionManager constant nftManager =
INonfungiblePositionManager(0xC36442b4a4522E871399CD717aBDD847Ab11FE88);
IUniswapV3Staker constant staker =
IUniswapV3Staker(0x1f98407aaB862CdDeF78Ed252D6f557aA5b0f00d);
/**
* @dev Get Last NFT Index
* @param user: User address
*/
function _getLastNftId(address user)
internal
view
returns (uint256 tokenId)
{
uint256 len = nftManager.balanceOf(user);
tokenId = nftManager.tokenOfOwnerByIndex(user, len - 1);
}
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 getNftTokenPairAddresses(uint256 _tokenId)
internal
view
returns (address token0, address token1)
{
(bool success, bytes memory data) = address(nftManager).staticcall(
abi.encodeWithSelector(nftManager.positions.selector, _tokenId)
);
require(success, "fetching positions failed");
{
(, , token0, token1, , , , ) = abi.decode(
data,
(
uint96,
address,
address,
address,
uint24,
int24,
int24,
uint128
)
);
}
}
function getPoolAddress(uint256 _tokenId)
internal
view
returns (address pool)
{
(bool success, bytes memory data) = address(nftManager).staticcall(
abi.encodeWithSelector(nftManager.positions.selector, _tokenId)
);
require(success, "fetching positions failed");
{
(, , address token0, address token1, uint24 fee, , , ) = abi.decode(
data,
(
uint96,
address,
address,
address,
uint24,
int24,
int24,
uint128
)
);
pool = PoolAddress.computeAddress(
nftManager.factory(),
PoolAddress.PoolKey({token0: token0, token1: token1, fee: fee})
);
}
}
/**
* @dev Check if token address is etherAddr and convert it to weth
*/
function _checkETH(
address _token0,
address _token1,
uint256 _amount0,
uint256 _amount1
) internal {
bool isEth0 = _token0 == wethAddr;
bool isEth1 = _token1 == wethAddr;
convertEthToWeth(isEth0, TokenInterface(_token0), _amount0);
convertEthToWeth(isEth1, TokenInterface(_token1), _amount1);
approve(TokenInterface(_token0), address(nftManager), _amount0);
approve(TokenInterface(_token1), address(nftManager), _amount1);
}
/**
* @dev addLiquidityWrapper function wrapper of _addLiquidity
*/
function _addLiquidityWrapper(
uint256 tokenId,
uint256 amountA,
uint256 amountB,
uint256 slippage
)
internal
returns (
uint256 liquidity,
uint256 amtA,
uint256 amtB
)
{
(address token0, address token1) = getNftTokenPairAddresses(tokenId);
(liquidity, amtA, amtB) = _addLiquidity(
tokenId,
token0,
token1,
amountA,
amountB,
slippage
);
}
/**
* @dev addLiquidity function which interact with Uniswap v3
*/
function _addLiquidity(
uint256 _tokenId,
address _token0,
address _token1,
uint256 _amount0,
uint256 _amount1,
uint256 _slippage
)
internal
returns (
uint128 liquidity,
uint256 amount0,
uint256 amount1
)
{
_checkETH(_token0, _token1, _amount0, _amount1);
uint256 _amount0Min = getMinAmount(
TokenInterface(_token0),
_amount0,
_slippage
);
uint256 _amount1Min = getMinAmount(
TokenInterface(_token1),
_amount1,
_slippage
);
INonfungiblePositionManager.IncreaseLiquidityParams
memory params = INonfungiblePositionManager.IncreaseLiquidityParams(
_tokenId,
_amount0,
_amount1,
_amount0Min,
_amount1Min,
block.timestamp
);
(liquidity, amount0, amount1) = nftManager.increaseLiquidity(params);
}
/**
* @dev decreaseLiquidity function which interact with Uniswap v3
*/
function _decreaseLiquidity(
uint256 _tokenId,
uint128 _liquidity,
uint256 _amount0Min,
uint256 _amount1Min
) internal returns (uint256 amount0, uint256 amount1) {
INonfungiblePositionManager.DecreaseLiquidityParams
memory params = INonfungiblePositionManager.DecreaseLiquidityParams(
_tokenId,
_liquidity,
_amount0Min,
_amount1Min,
block.timestamp
);
(amount0, amount1) = nftManager.decreaseLiquidity(params);
}
function _stake(
uint256 _tokenId,
IUniswapV3Staker.IncentiveKey memory _incentiveId
) internal {
staker.stakeToken(_incentiveId, _tokenId);
}
function _unstake(
IUniswapV3Staker.IncentiveKey memory _key,
uint256 _tokenId
) internal {
staker.unstakeToken(_key, _tokenId);
}
function _claimRewards(
IERC20Minimal _rewardToken,
address _to,
uint256 _amountRequested
) internal returns (uint256 rewards) {
rewards = staker.claimReward(_rewardToken, _to, _amountRequested);
}
}

View File

@ -0,0 +1,183 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.7.6;
pragma abicoder v2;
import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol';
import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol';
import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol';
import '@uniswap/v3-core/contracts/interfaces/IERC20Minimal.sol';
import '@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol';
import '@uniswap/v3-periphery/contracts/interfaces/IMulticall.sol';
/// @title Uniswap V3 Staker Interface
/// @notice Allows staking nonfungible liquidity tokens in exchange for reward tokens
interface IUniswapV3Staker is IERC721Receiver, IMulticall {
/// @param rewardToken The token being distributed as a reward
/// @param pool The Uniswap V3 pool
/// @param startTime The time when the incentive program begins
/// @param endTime The time when rewards stop accruing
/// @param refundee The address which receives any remaining reward tokens when the incentive is ended
struct IncentiveKey {
IERC20Minimal rewardToken;
IUniswapV3Pool pool;
uint256 startTime;
uint256 endTime;
address refundee;
}
/// @notice The Uniswap V3 Factory
function factory() external view returns (IUniswapV3Factory);
/// @notice The nonfungible position manager with which this staking contract is compatible
function nonfungiblePositionManager() external view returns (INonfungiblePositionManager);
/// @notice The max duration of an incentive in seconds
function maxIncentiveDuration() external view returns (uint256);
/// @notice The max amount of seconds into the future the incentive startTime can be set
function maxIncentiveStartLeadTime() external view returns (uint256);
/// @notice Represents a staking incentive
/// @param incentiveId The ID of the incentive computed from its parameters
/// @return totalRewardUnclaimed The amount of reward token not yet claimed by users
/// @return totalSecondsClaimedX128 Total liquidity-seconds claimed, represented as a UQ32.128
/// @return numberOfStakes The count of deposits that are currently staked for the incentive
function incentives(bytes32 incentiveId)
external
view
returns (
uint256 totalRewardUnclaimed,
uint160 totalSecondsClaimedX128,
uint96 numberOfStakes
);
/// @notice Returns information about a deposited NFT
/// @return owner The owner of the deposited NFT
/// @return numberOfStakes Counter of how many incentives for which the liquidity is staked
/// @return tickLower The lower tick of the range
/// @return tickUpper The upper tick of the range
function deposits(uint256 tokenId)
external
view
returns (
address owner,
uint48 numberOfStakes,
int24 tickLower,
int24 tickUpper
);
/// @notice Returns information about a staked liquidity NFT
/// @param tokenId The ID of the staked token
/// @param incentiveId The ID of the incentive for which the token is staked
/// @return secondsPerLiquidityInsideInitialX128 secondsPerLiquidity represented as a UQ32.128
/// @return liquidity The amount of liquidity in the NFT as of the last time the rewards were computed
function stakes(uint256 tokenId, bytes32 incentiveId)
external
view
returns (uint160 secondsPerLiquidityInsideInitialX128, uint128 liquidity);
/// @notice Returns amounts of reward tokens owed to a given address according to the last time all stakes were updated
/// @param rewardToken The token for which to check rewards
/// @param owner The owner for which the rewards owed are checked
/// @return rewardsOwed The amount of the reward token claimable by the owner
function rewards(IERC20Minimal rewardToken, address owner) external view returns (uint256 rewardsOwed);
/// @notice Creates a new liquidity mining incentive program
/// @param key Details of the incentive to create
/// @param reward The amount of reward tokens to be distributed
function createIncentive(IncentiveKey memory key, uint256 reward) external;
/// @notice Ends an incentive after the incentive end time has passed and all stakes have been withdrawn
/// @param key Details of the incentive to end
/// @return refund The remaining reward tokens when the incentive is ended
function endIncentive(IncentiveKey memory key) external returns (uint256 refund);
/// @notice Transfers ownership of a deposit from the sender to the given recipient
/// @param tokenId The ID of the token (and the deposit) to transfer
/// @param to The new owner of the deposit
function transferDeposit(uint256 tokenId, address to) external;
/// @notice Withdraws a Uniswap V3 LP token `tokenId` from this contract to the recipient `to`
/// @param tokenId The unique identifier of an Uniswap V3 LP token
/// @param to The address where the LP token will be sent
/// @param data An optional data array that will be passed along to the `to` address via the NFT safeTransferFrom
function withdrawToken(
uint256 tokenId,
address to,
bytes memory data
) external;
/// @notice Stakes a Uniswap V3 LP token
/// @param key The key of the incentive for which to stake the NFT
/// @param tokenId The ID of the token to stake
function stakeToken(IncentiveKey memory key, uint256 tokenId) external;
/// @notice Unstakes a Uniswap V3 LP token
/// @param key The key of the incentive for which to unstake the NFT
/// @param tokenId The ID of the token to unstake
function unstakeToken(IncentiveKey memory key, uint256 tokenId) external;
/// @notice Transfers `amountRequested` of accrued `rewardToken` rewards from the contract to the recipient `to`
/// @param rewardToken The token being distributed as a reward
/// @param to The address where claimed rewards will be sent to
/// @param amountRequested The amount of reward tokens to claim. Claims entire reward amount if set to 0.
/// @return reward The amount of reward tokens claimed
function claimReward(
IERC20Minimal rewardToken,
address to,
uint256 amountRequested
) external returns (uint256 reward);
/// @notice Calculates the reward amount that will be received for the given stake
/// @param key The key of the incentive
/// @param tokenId The ID of the token
/// @return reward The reward accrued to the NFT for the given incentive thus far
function getRewardInfo(IncentiveKey memory key, uint256 tokenId)
external
returns (uint256 reward, uint160 secondsInsideX128);
/// @notice Event emitted when a liquidity mining incentive has been created
/// @param rewardToken The token being distributed as a reward
/// @param pool The Uniswap V3 pool
/// @param startTime The time when the incentive program begins
/// @param endTime The time when rewards stop accruing
/// @param refundee The address which receives any remaining reward tokens after the end time
/// @param reward The amount of reward tokens to be distributed
event IncentiveCreated(
IERC20Minimal indexed rewardToken,
IUniswapV3Pool indexed pool,
uint256 startTime,
uint256 endTime,
address refundee,
uint256 reward
);
/// @notice Event that can be emitted when a liquidity mining incentive has ended
/// @param incentiveId The incentive which is ending
/// @param refund The amount of reward tokens refunded
event IncentiveEnded(bytes32 indexed incentiveId, uint256 refund);
/// @notice Emitted when ownership of a deposit changes
/// @param tokenId The ID of the deposit (and token) that is being transferred
/// @param oldOwner The owner before the deposit was transferred
/// @param newOwner The owner after the deposit was transferred
event DepositTransferred(uint256 indexed tokenId, address indexed oldOwner, address indexed newOwner);
/// @notice Event emitted when a Uniswap V3 LP token has been staked
/// @param tokenId The unique identifier of an Uniswap V3 LP token
/// @param liquidity The amount of liquidity staked
/// @param incentiveId The incentive in which the token is staking
event TokenStaked(uint256 indexed tokenId, bytes32 indexed incentiveId, uint128 liquidity);
/// @notice Event emitted when a Uniswap V3 LP token has been unstaked
/// @param tokenId The unique identifier of an Uniswap V3 LP token
/// @param incentiveId The incentive in which the token is staking
event TokenUnstaked(uint256 indexed tokenId, bytes32 indexed incentiveId);
/// @notice Event emitted when a reward token has been claimed
/// @param to The address where claimed rewards were sent to
/// @param reward The amount of reward tokens claimed
event RewardClaimed(address indexed to, uint256 reward);
}

View File

@ -0,0 +1,237 @@
pragma solidity ^0.7.6;
pragma abicoder v2;
/**
* @title Uniswap v3.
* @dev Decentralized Exchange.
*/
import {TokenInterface} from "../../common/interfaces.sol";
import "./interface.sol";
import {Helpers} from "./helpers.sol";
import {Events} from "./events.sol";
abstract contract UniswapResolver is Helpers, Events {
/**
* @dev Increase Liquidity
* @notice Increase Liquidity of NFT Position
* @param tokenId NFT LP Token ID.
* @param amountA tokenA amounts.
* @param amountB tokenB amounts.
* @param slippage slippage.
* @param getIds IDs to retrieve token amounts
* @param setId stores the liquidity amount
*/
function deposit(
uint256 tokenId,
uint256 amountA,
uint256 amountB,
uint256 slippage,
uint256[] calldata getIds,
uint256 setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
if (tokenId == 0) tokenId = _getLastNftId(address(this));
amountA = getUint(getIds[0], amountA);
amountB = getUint(getIds[1], amountB);
(
uint256 _liquidity,
uint256 _amtA,
uint256 _amtB
) = _addLiquidityWrapper(tokenId, amountA, amountB, slippage);
setUint(setId, _liquidity);
_eventName = "LogDeposit(uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(tokenId, _liquidity, _amtA, _amtB);
}
/**
* @dev Decrease Liquidity
* @notice Decrease Liquidity of NFT Position
* @param tokenId NFT LP Token ID.
* @param liquidity LP Token amount.
* @param amountAMin Min amount of tokenA.
* @param amountBMin Min amount of tokenB.
* @param getId ID to retrieve LP token amounts
* @param setIds stores the amount of output tokens
*/
function withdraw(
uint256 tokenId,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
uint256 getId,
uint256[] calldata setIds
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
if (tokenId == 0) tokenId = _getLastNftId(address(this));
uint128 _liquidity = uint128(getUint(getId, liquidity));
(uint256 _amtA, uint256 _amtB) = _decreaseLiquidity(
tokenId,
_liquidity,
amountAMin,
amountBMin
);
setUint(setIds[0], _amtA);
setUint(setIds[1], _amtB);
_eventName = "LogWithdraw(uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(tokenId, _liquidity, _amtA, _amtB);
}
/**
* @dev Stake NFT LP token
* @notice Stake NFT LP Position
* @param _rewardToken _rewardToken address
* @param _startTime stake start time
* @param _endTime stake end time
* @param _refundee refundee address
* @param _tokenId NFT LP token id
*/
function stake(
address _rewardToken,
uint256 _startTime,
uint256 _endTime,
address _refundee,
uint256 _tokenId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
nftManager.safeTransferFrom(
address(this),
address(staker),
_tokenId,
""
);
address poolAddr = getPoolAddress(_tokenId);
IUniswapV3Pool pool = IUniswapV3Pool(poolAddr);
IUniswapV3Staker.IncentiveKey memory _key = IUniswapV3Staker
.IncentiveKey(
IERC20Minimal(_rewardToken),
pool,
_startTime,
_endTime,
_refundee
);
_stake(_tokenId, _key);
_eventName = "LogStake(uint256, address)";
_eventParam = abi.encode(_tokenId, _refundee);
}
/**
* @dev Unstake NFT LP token
* @notice Unstake NFT LP Position
* @param _rewardToken _rewardToken address
* @param _startTime stake start time
* @param _endTime stake end time
* @param _refundee refundee address
* @param _tokenId NFT LP token id
*/
function unstake(
address _rewardToken,
uint256 _startTime,
uint256 _endTime,
address _refundee,
uint256 _tokenId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
address poolAddr = getPoolAddress(_tokenId);
IUniswapV3Pool pool = IUniswapV3Pool(poolAddr);
IUniswapV3Staker.IncentiveKey memory _key = IUniswapV3Staker
.IncentiveKey(
IERC20Minimal(_rewardToken),
pool,
_startTime,
_endTime,
_refundee
);
_unstake(_key, _tokenId);
_eventName = "LogUnstake(uint256,bytes32)";
_eventParam = abi.encode(_tokenId, _key);
}
/**
* @dev Claim rewards
* @notice Claim rewards
* @param _rewardToken _rewardToken address
* @param _to address to receive
* @param _amountRequested requested amount
*/
function claimRewards(
address _rewardToken,
address _to,
uint256 _amountRequested
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 rewards = _claimRewards(
IERC20Minimal(_rewardToken),
_to,
_amountRequested
);
_eventName = "LogRewardClaimed(address,address,uint256)";
_eventParam = abi.encode(_rewardToken, _to, rewards);
}
/**
* @dev Create incentive
* @notice Create incentive
* @param _rewardToken _rewardToken address
* @param _length incentive length
* @param _refundee refundee address
* @param _tokenId NFT LP token id
* @param _reward reward amount
*/
function createIncentive(
address _rewardToken,
uint256 _length,
address _refundee,
uint256 _tokenId,
uint256 _reward
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
address poolAddr = getPoolAddress(_tokenId);
IUniswapV3Pool pool = IUniswapV3Pool(poolAddr);
uint256 _startTime = block.timestamp;
uint256 _endTime = _startTime + _length;
IUniswapV3Staker.IncentiveKey memory _key = IUniswapV3Staker
.IncentiveKey(
IERC20Minimal(_rewardToken),
pool,
_startTime,
_endTime,
_refundee
);
staker.createIncentive(_key, _reward);
_eventName = "LogIncentiveCreated(uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(_tokenId, _startTime, _endTime, _reward);
}
}
contract ConnectV2UniswapV3Staker is UniswapResolver {
string public constant name = "UniswapStaker-v1";
}

View File

@ -0,0 +1,245 @@
const { expect } = require("chai");
const hre = require("hardhat");
const { waffle, ethers } = hre;
const { provider, deployContract } = waffle
const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js")
const buildDSAv2 = require("../../scripts/buildDSAv2")
const encodeSpells = require("../../scripts/encodeSpells.js")
const getMasterSigner = require("../../scripts/getMasterSigner")
const addLiquidity = require("../../scripts/addLiquidity");
const addresses = require("../../scripts/constant/addresses");
const abis = require("../../scripts/constant/abis");
const { abi: nftManagerAbi } = require("@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json")
const connectV2UniswapStakerArtifacts = require("../../artifacts/contracts/mainnet/connectors/uniswapStaker/main.sol/ConnectV2UniswapV3Staker.json");
const connectV2UniswapV3Artifacts = require("../../artifacts/contracts/mainnet/connectors/uniswapV3/main.sol/ConnectV2UniswapV3.json");
const FeeAmount = {
LOW: 500,
MEDIUM: 3000,
HIGH: 10000,
}
const TICK_SPACINGS = {
500: 10,
3000: 60,
10000: 200
}
const DAI_ADDR = "0x6b175474e89094c44da98b954eedeac495271d0f"
const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
let tokenIds = []
const abiCoder = ethers.utils.defaultAbiCoder
describe("UniswapV3", function () {
const connectorStaker = "UniswapStaker-v1"
const connectorUniswap = "UniswapV3-v1"
let dsaWallet0
let masterSigner;
let instaConnectorsV2;
let connector;
let startTime, endTime;
const wallets = provider.getWallets()
const [wallet0, wallet1, wallet2, wallet3] = wallets
before(async () => {
masterSigner = await getMasterSigner(wallet3)
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
nftManager = await ethers.getContractAt(nftManagerAbi, "0xC36442b4a4522E871399CD717aBDD847Ab11FE88");
connector = await deployAndEnableConnector({
connectorName: connectorStaker,
contractArtifact: connectV2UniswapStakerArtifacts,
signer: masterSigner,
connectors: instaConnectorsV2
})
console.log("Connector address", connector.address)
uniswapConnector = await deployAndEnableConnector({
connectorName: connectorUniswap,
contractArtifact: connectV2UniswapV3Artifacts,
signer: masterSigner,
connectors: instaConnectorsV2
});
})
it("Should have contracts deployed.", async function () {
expect(!!instaConnectorsV2.address).to.be.true;
expect(!!connector.address).to.be.true;
expect(!!masterSigner.address).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("dai", dsaWallet0.address, ethers.utils.parseEther("100000"));
await addLiquidity("usdt", dsaWallet0.address, ethers.utils.parseEther("100000"));
});
});
describe("Main", function () {
const ethAmount = ethers.utils.parseEther("0.1") // 1 ETH
const daiAmount = ethers.utils.parseEther("400") // 1 ETH
it("Should mint successfully", async function () {
const getIds = ["0", "0"]
const setId = "0"
const spells = [
{
connector: connectorUniswap,
method: "mint",
args: [
DAI_ADDR,
ethAddress,
FeeAmount.MEDIUM,
getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
daiAmount,
ethAmount,
"500000000000000000",
getIds,
setId
],
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
let receipt = await tx.wait()
let castEvent = new Promise((resolve, reject) => {
dsaWallet0.on('LogCast', (origin, sender, value, targetNames, targets, eventNames, eventParams, event) => {
const params = abiCoder.decode(["uint256", "uint256", "uint256", "uint256", "int24", "int24"], eventParams[0]);
tokenIds.push(params[0]);
event.removeListener();
resolve({
eventNames,
});
});
setTimeout(() => {
reject(new Error('timeout'));
}, 60000)
});
let event = await castEvent
});
it("Should create incentive successfully", async function () {
const spells = [
{
connector: connectorStaker,
method: "createIncentive",
args: [
ethAddress,
"1000",
dsaWallet0.address,
tokenIds[0],
ethers.utils.parseEther("0.01")
],
}]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
let receipt = await tx.wait()
let castEvent = new Promise((resolve, reject) => {
dsaWallet0.on('LogCast', (origin, sender, value, targetNames, targets, eventNames, eventParams, event) => {
const params = abiCoder.decode(["uint256", "uint256", "uint256", "uint256"], eventParams[0]);
event.removeListener();
resolve({ start: params[1], end: params[2] });
});
setTimeout(() => {
reject(new Error('timeout'));
}, 60000)
});
let event = await castEvent
startTime = event.start;
endTime = event.end;
});
it("Should stake successfully", async function () {
const spells = [
{
connector: connectorStaker,
method: "stake",
args: [
ethAddress,
startTime,
endTime,
dsaWallet0.address,
tokenIds[0]
],
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
let receipt = await tx.wait()
});
it("Should claim rewards successfully", async function () {
const spells = [
{
connector: connectorStaker,
method: "claimRewards",
args: [
ethAddress,
dsaWallet0.address,
"1000",
],
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
let receipt = await tx.wait()
});
it("Should unstake successfully", async function () {
const spells = [
{
connector: connectorStaker,
method: "unstake",
args: [
ethAddress,
startTime,
endTime,
dsaWallet0.address,
tokenIds[0]
],
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
let receipt = await tx.wait()
});
})
})
const getMinTick = (tickSpacing) => Math.ceil(-887272 / tickSpacing) * tickSpacing
const getMaxTick = (tickSpacing) => Math.floor(887272 / tickSpacing) * tickSpacing