mirror of
https://github.com/Instadapp/dsa-connectors.git
synced 2024-07-29 22:37:00 +00:00
fix: minor
This commit is contained in:
parent
a1c6607cdc
commit
ea3072e802
56
contracts/sample/helpers.sol
Normal file
56
contracts/sample/helpers.sol
Normal file
|
@ -0,0 +1,56 @@
|
|||
pragma solidity ^0.7.6;
|
||||
pragma abicoder v2;
|
||||
|
||||
import "./interface.sol";
|
||||
import {SqrtPriceMath} from "./libraries/SqrtPriceMath.sol";
|
||||
import "./libraries/TransferHelper.sol";
|
||||
|
||||
abstract contract Helpers is ISwapRouter {
|
||||
ISwapRouter router =
|
||||
ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);
|
||||
|
||||
UniswapV3Pool state =
|
||||
UniswapV3Pool(0xCEda10b4d3bdE429DdA3A6daB87b38360313CBdB);
|
||||
|
||||
uint24 public constant poolFee = 3000;
|
||||
|
||||
function getPriceLimit(
|
||||
ISwapRouter.ExactInputSingleParams memory params,
|
||||
bool zeroForOne
|
||||
) public returns (uint160) {
|
||||
return (
|
||||
SqrtPriceMath.getNextSqrtPriceFromInput(
|
||||
state.slot0().sqrtPriceX96,
|
||||
state.liquidity(),
|
||||
params.amountIn,
|
||||
zeroForOne
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function approveTransfer(
|
||||
ISwapRouter.ExactInputSingleParams memory params,
|
||||
address sender,
|
||||
address recipient
|
||||
) public {
|
||||
TransferHelper.safeTransferFrom(
|
||||
params.tokenIn,
|
||||
sender,
|
||||
recipient,
|
||||
params.amountIn
|
||||
);
|
||||
|
||||
TransferHelper.safeApprove(
|
||||
params.tokenIn,
|
||||
address(router),
|
||||
params.amountIn
|
||||
);
|
||||
}
|
||||
|
||||
function getSingleInput(ISwapRouter.ExactInputSingleParams memory params)
|
||||
public
|
||||
returns (uint256)
|
||||
{
|
||||
return (uint256(router.exactInputSingle(params)));
|
||||
}
|
||||
}
|
36
contracts/sample/interface.sol
Normal file
36
contracts/sample/interface.sol
Normal file
|
@ -0,0 +1,36 @@
|
|||
pragma solidity ^0.7.6;
|
||||
pragma abicoder v2;
|
||||
|
||||
interface UniswapV3Pool {
|
||||
struct Slot0 {
|
||||
uint160 sqrtPriceX96;
|
||||
int24 tick;
|
||||
uint16 observationIndex;
|
||||
uint16 observationCardinality;
|
||||
uint16 observationCardinalityNext;
|
||||
uint8 feeProtocol;
|
||||
bool unlocked;
|
||||
}
|
||||
|
||||
function liquidity() external view returns (uint128);
|
||||
|
||||
function slot0() external view returns (Slot0 memory);
|
||||
}
|
||||
|
||||
interface ISwapRouter {
|
||||
struct ExactInputSingleParams {
|
||||
address tokenIn;
|
||||
address tokenOut;
|
||||
uint24 fee;
|
||||
address recipient;
|
||||
uint256 deadline;
|
||||
uint256 amountIn;
|
||||
uint256 amountOutMinimum;
|
||||
uint160 sqrtPriceLimitX96;
|
||||
}
|
||||
|
||||
function exactInputSingle(ExactInputSingleParams calldata params)
|
||||
external
|
||||
payable
|
||||
returns (uint256 amountOut);
|
||||
}
|
61
contracts/sample/libraries/IERC20Minimal.sol
Normal file
61
contracts/sample/libraries/IERC20Minimal.sol
Normal file
|
@ -0,0 +1,61 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
pragma solidity >=0.5.0;
|
||||
|
||||
/// @title Minimal ERC20 interface for Uniswap
|
||||
/// @notice Contains a subset of the full ERC20 interface that is used in Uniswap V3
|
||||
interface IERC20Minimal {
|
||||
/// @notice Returns the balance of a token
|
||||
/// @param account The account for which to look up the number of tokens it has, i.e. its balance
|
||||
/// @return The number of tokens held by the account
|
||||
function balanceOf(address account) external view returns (uint256);
|
||||
|
||||
/// @notice Transfers the amount of token from the `msg.sender` to the recipient
|
||||
/// @param recipient The account that will receive the amount transferred
|
||||
/// @param amount The number of tokens to send from the sender to the recipient
|
||||
/// @return Returns true for a successful transfer, false for an unsuccessful transfer
|
||||
function transfer(address recipient, uint256 amount)
|
||||
external
|
||||
returns (bool);
|
||||
|
||||
/// @notice Returns the current allowance given to a spender by an owner
|
||||
/// @param owner The account of the token owner
|
||||
/// @param spender The account of the token spender
|
||||
/// @return The current allowance granted by `owner` to `spender`
|
||||
function allowance(address owner, address spender)
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
|
||||
/// @notice Sets the allowance of a spender from the `msg.sender` to the value `amount`
|
||||
/// @param spender The account which will be allowed to spend a given amount of the owners tokens
|
||||
/// @param amount The amount of tokens allowed to be used by `spender`
|
||||
/// @return Returns true for a successful approval, false for unsuccessful
|
||||
function approve(address spender, uint256 amount) external returns (bool);
|
||||
|
||||
/// @notice Transfers `amount` tokens from `sender` to `recipient` up to the allowance given to the `msg.sender`
|
||||
/// @param sender The account from which the transfer will be initiated
|
||||
/// @param recipient The recipient of the transfer
|
||||
/// @param amount The amount of the transfer
|
||||
/// @return Returns true for a successful transfer, false for unsuccessful
|
||||
function transferFrom(
|
||||
address sender,
|
||||
address recipient,
|
||||
uint256 amount
|
||||
) external returns (bool);
|
||||
|
||||
/// @notice Event emitted when tokens are transferred from one address to another, either via `#transfer` or `#transferFrom`.
|
||||
/// @param from The account from which the tokens were sent, i.e. the balance decreased
|
||||
/// @param to The account to which the tokens were sent, i.e. the balance increased
|
||||
/// @param value The amount of tokens that were transferred
|
||||
event Transfer(address indexed from, address indexed to, uint256 value);
|
||||
|
||||
/// @notice Event emitted when the approval amount for the spender of a given owner's tokens changes.
|
||||
/// @param owner The account that approved spending of its tokens
|
||||
/// @param spender The account for which the spending allowance was modified
|
||||
/// @param value The new allowance from the owner to the spender
|
||||
event Approval(
|
||||
address indexed owner,
|
||||
address indexed spender,
|
||||
uint256 value
|
||||
);
|
||||
}
|
|
@ -1,13 +1,37 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
pragma solidity >=0.6.0;
|
||||
|
||||
import '../interfaces/IERC20Minimal.sol';
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
|
||||
/// @title TransferHelper
|
||||
/// @notice Contains helper methods for interacting with ERC20 tokens that do not consistently return true/false
|
||||
library TransferHelper {
|
||||
/// @notice Transfers tokens from the targeted address to the given destination
|
||||
/// @notice Errors with 'STF' if transfer fails
|
||||
/// @param token The contract address of the token to be transferred
|
||||
/// @param from The originating address from which the tokens will be transferred
|
||||
/// @param to The destination address of the transfer
|
||||
/// @param value The amount to be transferred
|
||||
function safeTransferFrom(
|
||||
address token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 value
|
||||
) internal {
|
||||
(bool success, bytes memory data) = token.call(
|
||||
abi.encodeWithSelector(
|
||||
IERC20.transferFrom.selector,
|
||||
from,
|
||||
to,
|
||||
value
|
||||
)
|
||||
);
|
||||
require(
|
||||
success && (data.length == 0 || abi.decode(data, (bool))),
|
||||
"STF"
|
||||
);
|
||||
}
|
||||
|
||||
/// @notice Transfers tokens from msg.sender to a recipient
|
||||
/// @dev Calls transfer on token contract, errors with TF if transfer fails
|
||||
/// @dev Errors with ST if transfer fails
|
||||
/// @param token The contract address of the token which will be transferred
|
||||
/// @param to The recipient of the transfer
|
||||
/// @param value The value of the transfer
|
||||
|
@ -16,8 +40,40 @@ library TransferHelper {
|
|||
address to,
|
||||
uint256 value
|
||||
) internal {
|
||||
(bool success, bytes memory data) =
|
||||
token.call(abi.encodeWithSelector(IERC20Minimal.transfer.selector, to, value));
|
||||
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TF');
|
||||
(bool success, bytes memory data) = token.call(
|
||||
abi.encodeWithSelector(IERC20.transfer.selector, to, value)
|
||||
);
|
||||
require(
|
||||
success && (data.length == 0 || abi.decode(data, (bool))),
|
||||
"ST"
|
||||
);
|
||||
}
|
||||
|
||||
/// @notice Approves the stipulated contract to spend the given allowance in the given token
|
||||
/// @dev Errors with 'SA' if transfer fails
|
||||
/// @param token The contract address of the token to be approved
|
||||
/// @param to The target of the approval
|
||||
/// @param value The amount of the given token the target will be allowed to spend
|
||||
function safeApprove(
|
||||
address token,
|
||||
address to,
|
||||
uint256 value
|
||||
) internal {
|
||||
(bool success, bytes memory data) = token.call(
|
||||
abi.encodeWithSelector(IERC20.approve.selector, to, value)
|
||||
);
|
||||
require(
|
||||
success && (data.length == 0 || abi.decode(data, (bool))),
|
||||
"SA"
|
||||
);
|
||||
}
|
||||
|
||||
/// @notice Transfers ETH to the recipient address
|
||||
/// @dev Fails with `STE`
|
||||
/// @param to The destination of the transfer
|
||||
/// @param value The value to be transferred
|
||||
function safeTransferETH(address to, uint256 value) internal {
|
||||
(bool success, ) = to.call{value: value}(new bytes(0));
|
||||
require(success, "STE");
|
||||
}
|
||||
}
|
||||
|
|
32
contracts/sample/main.sol
Normal file
32
contracts/sample/main.sol
Normal file
|
@ -0,0 +1,32 @@
|
|||
pragma solidity ^0.7.6;
|
||||
pragma abicoder v2;
|
||||
|
||||
import "./helpers.sol";
|
||||
import "./interface.sol";
|
||||
|
||||
abstract contract uniswapSample is Helpers {
|
||||
function sell(
|
||||
ISwapRouter.ExactInputSingleParams memory params,
|
||||
bool zeroForOne
|
||||
) public returns (uint256 amountOut) {
|
||||
approveTransfer(params, msg.sender, address(this));
|
||||
|
||||
ISwapRouter.ExactInputSingleParams memory params1 = ISwapRouter
|
||||
.ExactInputSingleParams({
|
||||
tokenIn: params.tokenIn,
|
||||
tokenOut: params.tokenOut,
|
||||
fee: poolFee,
|
||||
recipient: address(this),
|
||||
deadline: block.timestamp + 1,
|
||||
amountIn: params.amountIn,
|
||||
amountOutMinimum: 0,
|
||||
sqrtPriceLimitX96: getPriceLimit(params, true)
|
||||
});
|
||||
|
||||
amountOut = getSingleInput(params1);
|
||||
}
|
||||
}
|
||||
|
||||
abstract contract UniswapArbitrum is uniswapSample {
|
||||
string public constant name = "UniswapSample-v1";
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
pragma solidity ^0.7.6;
|
||||
pragma abicoder v2;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import "./libraries/SqrtPriceMath.sol";
|
||||
|
||||
interface UniswapV3Pool {
|
||||
struct Slot0 {
|
||||
uint160 sqrtPriceX96;
|
||||
int24 tick;
|
||||
uint16 observationIndex;
|
||||
uint16 observationCardinality;
|
||||
uint16 observationCardinalityNext;
|
||||
uint8 feeProtocol;
|
||||
bool unlocked;
|
||||
}
|
||||
|
||||
function liquidity() external view returns (uint128);
|
||||
|
||||
function slot0() external view returns (Slot0);
|
||||
}
|
||||
|
||||
interface ISwapRouter {
|
||||
struct ExactInputSingleParams {
|
||||
address tokenIn;
|
||||
address tokenOut;
|
||||
uint24 fee;
|
||||
address recipient;
|
||||
uint256 deadline;
|
||||
uint256 amountIn;
|
||||
uint256 amountOutMinimum;
|
||||
uint160 sqrtPriceLimitX96;
|
||||
}
|
||||
|
||||
function exactInputSingle(ExactInputSingleParams calldata params)
|
||||
external
|
||||
payable
|
||||
returns (uint256 amountOut);
|
||||
}
|
||||
|
||||
contract uniswapSample {
|
||||
ISwapRouter router =
|
||||
ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);
|
||||
|
||||
UniswapV3Pool state =
|
||||
UniswapV3Pool(0xCEda10b4d3bdE429DdA3A6daB87b38360313CBdB);
|
||||
uint24 public constant poolFee = 3000;
|
||||
|
||||
function getPriceLimit(
|
||||
ISwapRouter.ExactInputSingleParams params,
|
||||
bool zeroForOne
|
||||
) public returns (uint160) {
|
||||
return (
|
||||
getNextSqrtPriceFromInput(
|
||||
state.slot0().sqrtPriceX96,
|
||||
state.liquidity(),
|
||||
params.amountIn,
|
||||
zeroForOne
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function sell(ISwapRouter.ExactInputSingleParams params, bool zeroForOne) {
|
||||
TransferHelper.safeTransferFrom(
|
||||
params.tokenIn,
|
||||
msg.sender,
|
||||
address(this),
|
||||
params.amountIn
|
||||
);
|
||||
|
||||
TransferHelper.safeApprove(
|
||||
params.tokenIn,
|
||||
address(swapRouter),
|
||||
params.amountIn
|
||||
);
|
||||
|
||||
ISwapRouter.ExactInputSingleParams memory params1 = ISwapRouter
|
||||
.ExactInputSingleParams({
|
||||
tokenIn: params.tokenIn
|
||||
tokenOut: params.tokenOut,
|
||||
fee: poolFee,
|
||||
recipient: address(this),
|
||||
deadline: block.timestamp + 1,
|
||||
amountIn: params.amountIn,
|
||||
amountOutMinimum: 0,
|
||||
sqrtPriceLimitX96: getPriceLimit(params, true)
|
||||
});
|
||||
|
||||
amountOut = swapRouter.exactInputSingle(params1);
|
||||
return (amountOut);
|
||||
}
|
||||
}
|
|
@ -44,21 +44,6 @@ module.exports = {
|
|||
],
|
||||
},
|
||||
networks: {
|
||||
kovan: {
|
||||
url: `https://eth-kovan.alchemyapi.io/v2/${ALCHEMY_ID}`,
|
||||
accounts: [`0x${PRIVATE_KEY}`],
|
||||
},
|
||||
mainnet: {
|
||||
url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`,
|
||||
accounts: [`0x${PRIVATE_KEY}`],
|
||||
timeout: 150000,
|
||||
gasPrice: parseInt(utils.parseUnits("30", "gwei")),
|
||||
},
|
||||
rinkeby: {
|
||||
url: `https://eth-rinkeby.alchemyapi.io/v2/${ALCHEMY_ID}`,
|
||||
accounts: [`0x${PRIVATE_KEY}`],
|
||||
timeout: 150000,
|
||||
},
|
||||
hardhat: {
|
||||
forking: {
|
||||
url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`,
|
||||
|
@ -66,26 +51,6 @@ module.exports = {
|
|||
},
|
||||
blockGasLimit: 12000000,
|
||||
},
|
||||
matic: {
|
||||
url: "https://rpc-mainnet.maticvigil.com/",
|
||||
accounts: [`0x${PRIVATE_KEY}`],
|
||||
timeout: 150000,
|
||||
gasPrice: parseInt(utils.parseUnits("1", "gwei")),
|
||||
},
|
||||
arbitrum: {
|
||||
chainId: 42161,
|
||||
url: `https://arb-mainnet.g.alchemy.com/v2/${ALCHEMY_ID}`,
|
||||
accounts: [`0x${PRIVATE_KEY}`],
|
||||
timeout: 150000,
|
||||
gasPrice: parseInt(utils.parseUnits("2", "gwei")),
|
||||
},
|
||||
avax: {
|
||||
url: 'https://api.avax.network/ext/bc/C/rpc',
|
||||
chainId: 43114,
|
||||
accounts: [`0x${PRIVATE_KEY}`],
|
||||
timeout: 150000,
|
||||
gasPrice: parseInt(utils.parseUnits("225", "gwei"))
|
||||
}
|
||||
},
|
||||
etherscan: {
|
||||
apiKey: ETHERSCAN_API_KEY,
|
||||
|
@ -97,4 +62,4 @@ module.exports = {
|
|||
mocha: {
|
||||
timeout: 100 * 1000,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
80
test/sample/uniswap.js
Normal file
80
test/sample/uniswap.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
const { expect } = require("chai");
|
||||
const hre = require("hardhat");
|
||||
const { web3, deployments, 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 addresses = require("../../scripts/constant/addresses");
|
||||
const abis = require("../../scripts/constant/abis");
|
||||
|
||||
const FeeAmount = {
|
||||
LOW: 500,
|
||||
MEDIUM: 3000,
|
||||
HIGH: 10000,
|
||||
};
|
||||
|
||||
const TICK_SPACINGS = {
|
||||
500: 10,
|
||||
3000: 60,
|
||||
10000: 200,
|
||||
};
|
||||
|
||||
const USDT_ADDR = "0xdac17f958d2ee523a2206206994597c13d831ec7";
|
||||
const DAI_ADDR = "0x6b175474e89094c44da98b954eedeac495271d0f";
|
||||
|
||||
describe("UniswapV3", function() {
|
||||
const connectorName = "UniswapV3-v1";
|
||||
let dsaWallet0;
|
||||
let masterSigner;
|
||||
let instaConnectorsV2;
|
||||
let connector;
|
||||
let nftManager;
|
||||
|
||||
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
|
||||
);
|
||||
connector = await deployAndEnableConnector({
|
||||
connectorName,
|
||||
contractArtifact: connectV2UniswapV3Artifacts,
|
||||
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(!!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("Perfrom a swap", 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")
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,335 +1,374 @@
|
|||
const { expect } = require("chai");
|
||||
const hre = require("hardhat");
|
||||
const { web3, deployments, waffle, ethers } = hre;
|
||||
const { provider, deployContract } = waffle
|
||||
const { provider, deployContract } = waffle;
|
||||
|
||||
const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js")
|
||||
const buildDSAv2 = require("../../scripts/buildDSAv2")
|
||||
const encodeSpells = require("../../scripts/encodeSpells.js")
|
||||
const encodeFlashcastData = require("../../scripts/encodeFlashcastData.js")
|
||||
const getMasterSigner = require("../../scripts/getMasterSigner")
|
||||
const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js");
|
||||
const buildDSAv2 = require("../../scripts/buildDSAv2");
|
||||
const encodeSpells = require("../../scripts/encodeSpells.js");
|
||||
const encodeFlashcastData = require("../../scripts/encodeFlashcastData.js");
|
||||
const getMasterSigner = require("../../scripts/getMasterSigner");
|
||||
const addLiquidity = require("../../scripts/addLiquidity");
|
||||
|
||||
const addresses = require("../../scripts/constant/addresses");
|
||||
const abis = require("../../scripts/constant/abis");
|
||||
const constants = require("../../scripts/constant/constant");
|
||||
const tokens = require("../../scripts/constant/tokens");
|
||||
const { abi: nftManagerAbi } = require("@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json")
|
||||
const {
|
||||
abi: nftManagerAbi,
|
||||
} = require("@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json");
|
||||
|
||||
const connectV2UniswapV3Artifacts = require("../../artifacts/contracts/mainnet/connectors/uniswap/v3/main.sol/ConnectV2UniswapV3.json");
|
||||
const { eth } = require("../../scripts/constant/tokens");
|
||||
const { BigNumber } = require("ethers");
|
||||
|
||||
const FeeAmount = {
|
||||
LOW: 500,
|
||||
MEDIUM: 3000,
|
||||
HIGH: 10000,
|
||||
}
|
||||
LOW: 500,
|
||||
MEDIUM: 3000,
|
||||
HIGH: 10000,
|
||||
};
|
||||
|
||||
const TICK_SPACINGS = {
|
||||
500: 10,
|
||||
3000: 60,
|
||||
10000: 200
|
||||
}
|
||||
500: 10,
|
||||
3000: 60,
|
||||
10000: 200,
|
||||
};
|
||||
|
||||
const USDT_ADDR = "0xdac17f958d2ee523a2206206994597c13d831ec7"
|
||||
const DAI_ADDR = "0x6b175474e89094c44da98b954eedeac495271d0f"
|
||||
const USDT_ADDR = "0xdac17f958d2ee523a2206206994597c13d831ec7";
|
||||
const DAI_ADDR = "0x6b175474e89094c44da98b954eedeac495271d0f";
|
||||
|
||||
let tokenIds = []
|
||||
let liquidities = []
|
||||
const abiCoder = ethers.utils.defaultAbiCoder
|
||||
let tokenIds = [];
|
||||
let liquidities = [];
|
||||
const abiCoder = ethers.utils.defaultAbiCoder;
|
||||
|
||||
describe("UniswapV3", function () {
|
||||
const connectorName = "UniswapV3-v1"
|
||||
describe("UniswapV3", function() {
|
||||
const connectorName = "UniswapV3-v1";
|
||||
|
||||
let dsaWallet0
|
||||
let masterSigner;
|
||||
let instaConnectorsV2;
|
||||
let connector;
|
||||
let nftManager;
|
||||
let dsaWallet0;
|
||||
let masterSigner;
|
||||
let instaConnectorsV2;
|
||||
let connector;
|
||||
let nftManager;
|
||||
|
||||
const wallets = provider.getWallets()
|
||||
const [wallet0, wallet1, wallet2, wallet3] = wallets
|
||||
before(async () => {
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_reset",
|
||||
params: [
|
||||
{
|
||||
forking: {
|
||||
jsonRpcUrl: hre.config.networks.hardhat.forking.url,
|
||||
blockNumber: 13005785,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
masterSigner = await getMasterSigner(wallet3)
|
||||
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
|
||||
nftManager = await ethers.getContractAt(nftManagerAbi, "0xC36442b4a4522E871399CD717aBDD847Ab11FE88");
|
||||
connector = await deployAndEnableConnector({
|
||||
connectorName,
|
||||
contractArtifact: connectV2UniswapV3Artifacts,
|
||||
signer: masterSigner,
|
||||
connectors: instaConnectorsV2
|
||||
})
|
||||
console.log("Connector address", connector.address)
|
||||
})
|
||||
const wallets = provider.getWallets();
|
||||
const [wallet0, wallet1, wallet2, wallet3] = wallets;
|
||||
before(async () => {
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_reset",
|
||||
params: [
|
||||
{
|
||||
forking: {
|
||||
jsonRpcUrl: hre.config.networks.hardhat.forking.url,
|
||||
blockNumber: 13005785,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
masterSigner = await getMasterSigner(wallet3);
|
||||
instaConnectorsV2 = await ethers.getContractAt(
|
||||
abis.core.connectorsV2,
|
||||
addresses.core.connectorsV2
|
||||
);
|
||||
nftManager = await ethers.getContractAt(
|
||||
nftManagerAbi,
|
||||
"0xC36442b4a4522E871399CD717aBDD847Ab11FE88"
|
||||
);
|
||||
connector = await deployAndEnableConnector({
|
||||
connectorName,
|
||||
contractArtifact: connectV2UniswapV3Artifacts,
|
||||
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(!!masterSigner.address).to.be.true;
|
||||
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;
|
||||
});
|
||||
|
||||
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")
|
||||
);
|
||||
|
||||
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"));
|
||||
});
|
||||
await addLiquidity(
|
||||
"dai",
|
||||
dsaWallet0.address,
|
||||
ethers.utils.parseEther("100000")
|
||||
);
|
||||
});
|
||||
|
||||
describe("Main", function () {
|
||||
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")
|
||||
);
|
||||
|
||||
it("Should mint successfully", async function () {
|
||||
const ethAmount = ethers.utils.parseEther("0.1") // 1 ETH
|
||||
const daiAmount = ethers.utils.parseEther("400") // 1 ETH
|
||||
const usdtAmount = ethers.utils.parseEther("400") / Math.pow(10, 12) // 1 ETH
|
||||
const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
|
||||
await addLiquidity(
|
||||
"usdt",
|
||||
dsaWallet0.address,
|
||||
ethers.utils.parseEther("100000")
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
const getIds = ["0", "0"]
|
||||
const setId = "0"
|
||||
describe("Main", function() {
|
||||
it("Should mint successfully", async function() {
|
||||
const ethAmount = ethers.utils.parseEther("0.1"); // 1 ETH
|
||||
const daiAmount = ethers.utils.parseEther("400"); // 1 ETH
|
||||
const usdtAmount = ethers.utils.parseEther("400") / Math.pow(10, 12); // 1 ETH
|
||||
const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "mint",
|
||||
args: [
|
||||
ethAddress,
|
||||
DAI_ADDR,
|
||||
FeeAmount.MEDIUM,
|
||||
getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
|
||||
getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
|
||||
ethAmount,
|
||||
daiAmount,
|
||||
"500000000000000000",
|
||||
getIds,
|
||||
setId
|
||||
],
|
||||
},
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "mint",
|
||||
args: [
|
||||
DAI_ADDR,
|
||||
USDT_ADDR,
|
||||
FeeAmount.MEDIUM,
|
||||
getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
|
||||
getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
|
||||
daiAmount,
|
||||
usdtAmount,
|
||||
"300000000000000000",
|
||||
getIds,
|
||||
setId
|
||||
],
|
||||
},
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "mint",
|
||||
args: [
|
||||
ethAddress,
|
||||
USDT_ADDR,
|
||||
FeeAmount.MEDIUM,
|
||||
getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
|
||||
getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
|
||||
ethAmount,
|
||||
usdtAmount,
|
||||
"300000000000000000",
|
||||
getIds,
|
||||
setId
|
||||
],
|
||||
}
|
||||
]
|
||||
const getIds = ["0", "0"];
|
||||
const setId = "0";
|
||||
|
||||
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]);
|
||||
const params1 = abiCoder.decode(["uint256", "uint256", "uint256", "uint256", "int24", "int24"], eventParams[2]);
|
||||
tokenIds.push(params[0]);
|
||||
tokenIds.push(params1[0]);
|
||||
liquidities.push(params[1]);
|
||||
event.removeListener();
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "mint",
|
||||
args: [
|
||||
ethAddress,
|
||||
DAI_ADDR,
|
||||
FeeAmount.MEDIUM,
|
||||
getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
|
||||
getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
|
||||
ethAmount,
|
||||
daiAmount,
|
||||
"500000000000000000",
|
||||
getIds,
|
||||
setId,
|
||||
],
|
||||
},
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "mint",
|
||||
args: [
|
||||
DAI_ADDR,
|
||||
USDT_ADDR,
|
||||
FeeAmount.MEDIUM,
|
||||
getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
|
||||
getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
|
||||
daiAmount,
|
||||
usdtAmount,
|
||||
"300000000000000000",
|
||||
getIds,
|
||||
setId,
|
||||
],
|
||||
},
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "mint",
|
||||
args: [
|
||||
ethAddress,
|
||||
USDT_ADDR,
|
||||
FeeAmount.MEDIUM,
|
||||
getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
|
||||
getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
|
||||
ethAmount,
|
||||
usdtAmount,
|
||||
"300000000000000000",
|
||||
getIds,
|
||||
setId,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
resolve({
|
||||
eventNames,
|
||||
});
|
||||
});
|
||||
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]
|
||||
);
|
||||
const params1 = abiCoder.decode(
|
||||
["uint256", "uint256", "uint256", "uint256", "int24", "int24"],
|
||||
eventParams[2]
|
||||
);
|
||||
tokenIds.push(params[0]);
|
||||
tokenIds.push(params1[0]);
|
||||
liquidities.push(params[1]);
|
||||
event.removeListener();
|
||||
|
||||
setTimeout(() => {
|
||||
reject(new Error('timeout'));
|
||||
}, 60000)
|
||||
resolve({
|
||||
eventNames,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
let event = await castEvent
|
||||
setTimeout(() => {
|
||||
reject(new Error("timeout"));
|
||||
}, 60000);
|
||||
});
|
||||
|
||||
const data = await nftManager.positions(tokenIds[0])
|
||||
let event = await castEvent;
|
||||
|
||||
expect(data.liquidity).to.be.equals(liquidities[0]);
|
||||
}).timeout(10000000000);
|
||||
const data = await nftManager.positions(tokenIds[0]);
|
||||
|
||||
it("Should deposit successfully", async function () {
|
||||
const daiAmount = ethers.utils.parseEther("400") // 1 ETH
|
||||
const ethAmount = ethers.utils.parseEther("0.1") // 1 ETH
|
||||
const usdtAmount = ethers.utils.parseEther("400") / Math.pow(10, 12) // 1 ETH
|
||||
const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
|
||||
expect(data.liquidity).to.be.equals(liquidities[0]);
|
||||
}).timeout(10000000000);
|
||||
|
||||
const getIds = ["0", "0"]
|
||||
const setId = "0"
|
||||
it("Should deposit successfully", async function() {
|
||||
const daiAmount = ethers.utils.parseEther("400"); // 1 ETH
|
||||
const ethAmount = ethers.utils.parseEther("0.1"); // 1 ETH
|
||||
const usdtAmount = ethers.utils.parseEther("400") / Math.pow(10, 12); // 1 ETH
|
||||
const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "deposit",
|
||||
args: [
|
||||
tokenIds[0],
|
||||
daiAmount,
|
||||
ethAmount,
|
||||
"500000000000000000",
|
||||
getIds,
|
||||
setId
|
||||
],
|
||||
}
|
||||
]
|
||||
const getIds = ["0", "0"];
|
||||
const setId = "0";
|
||||
|
||||
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
|
||||
const receipt = await tx.wait()
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "deposit",
|
||||
args: [
|
||||
tokenIds[0],
|
||||
daiAmount,
|
||||
ethAmount,
|
||||
"500000000000000000",
|
||||
getIds,
|
||||
setId,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
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]);
|
||||
liquidities[0] = liquidities[0].add(params[1]);
|
||||
event.removeListener();
|
||||
const tx = await dsaWallet0
|
||||
.connect(wallet0)
|
||||
.cast(...encodeSpells(spells), wallet1.address);
|
||||
const receipt = await tx.wait();
|
||||
|
||||
resolve({
|
||||
eventNames,
|
||||
});
|
||||
});
|
||||
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]
|
||||
);
|
||||
liquidities[0] = liquidities[0].add(params[1]);
|
||||
event.removeListener();
|
||||
|
||||
setTimeout(() => {
|
||||
reject(new Error('timeout'));
|
||||
}, 60000)
|
||||
resolve({
|
||||
eventNames,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
let event = await castEvent
|
||||
setTimeout(() => {
|
||||
reject(new Error("timeout"));
|
||||
}, 60000);
|
||||
});
|
||||
|
||||
const data = await nftManager.positions(tokenIds[0])
|
||||
expect(data.liquidity).to.be.equals(liquidities[0]);
|
||||
})
|
||||
let event = await castEvent;
|
||||
|
||||
it("Should withdraw successfully", async function () {
|
||||
const data = await nftManager.positions(tokenIds[0]);
|
||||
expect(data.liquidity).to.be.equals(liquidities[0]);
|
||||
});
|
||||
|
||||
const getId = "0"
|
||||
const setIds = ["0", "0"]
|
||||
it("Should withdraw successfully", async function() {
|
||||
const getId = "0";
|
||||
const setIds = ["0", "0"];
|
||||
|
||||
const data = await nftManager.positions(tokenIds[0])
|
||||
let data1 = await nftManager.positions(tokenIds[1])
|
||||
const data = await nftManager.positions(tokenIds[0]);
|
||||
let data1 = await nftManager.positions(tokenIds[1]);
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "withdraw",
|
||||
args: [
|
||||
tokenIds[0],
|
||||
data.liquidity,
|
||||
0,
|
||||
0,
|
||||
getId,
|
||||
setIds
|
||||
],
|
||||
},
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "withdraw",
|
||||
args: [
|
||||
0,
|
||||
data1.liquidity,
|
||||
0,
|
||||
0,
|
||||
getId,
|
||||
setIds
|
||||
],
|
||||
},
|
||||
]
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "withdraw",
|
||||
args: [tokenIds[0], data.liquidity, 0, 0, getId, setIds],
|
||||
},
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "withdraw",
|
||||
args: [0, data1.liquidity, 0, 0, getId, setIds],
|
||||
},
|
||||
];
|
||||
|
||||
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
|
||||
const receipt = await tx.wait()
|
||||
const tx = await dsaWallet0
|
||||
.connect(wallet0)
|
||||
.cast(...encodeSpells(spells), wallet1.address);
|
||||
const receipt = await tx.wait();
|
||||
|
||||
data1 = await nftManager.positions(tokenIds[1])
|
||||
expect(data1.liquidity.toNumber()).to.be.equals(0);
|
||||
})
|
||||
data1 = await nftManager.positions(tokenIds[1]);
|
||||
expect(data1.liquidity.toNumber()).to.be.equals(0);
|
||||
});
|
||||
|
||||
it("Should collect successfully", async function () {
|
||||
it("Should collect successfully", async function() {
|
||||
const ethAmount = ethers.utils.parseEther("0.2"); // 1 ETH
|
||||
const daiAmount = ethers.utils.parseEther("800"); // 1 ETH
|
||||
const getIds = ["0", "0"];
|
||||
const setIds = ["0", "0"];
|
||||
|
||||
const ethAmount = ethers.utils.parseEther("0.2") // 1 ETH
|
||||
const daiAmount = ethers.utils.parseEther("800") // 1 ETH
|
||||
const getIds = ["0", "0"]
|
||||
const setIds = ["0", "0"]
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "collect",
|
||||
args: [tokenIds[0], daiAmount, ethAmount, getIds, setIds],
|
||||
},
|
||||
];
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "collect",
|
||||
args: [
|
||||
tokenIds[0],
|
||||
daiAmount,
|
||||
ethAmount,
|
||||
getIds,
|
||||
setIds
|
||||
],
|
||||
}
|
||||
]
|
||||
const tx = await dsaWallet0
|
||||
.connect(wallet0)
|
||||
.cast(...encodeSpells(spells), wallet1.address);
|
||||
const receipt = await tx.wait();
|
||||
});
|
||||
|
||||
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
|
||||
const receipt = await tx.wait()
|
||||
})
|
||||
it("Should burn successfully", async function() {
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "burn",
|
||||
args: [tokenIds[0]],
|
||||
},
|
||||
];
|
||||
|
||||
it("Should burn successfully", async function () {
|
||||
const tx = await dsaWallet0
|
||||
.connect(wallet0)
|
||||
.cast(...encodeSpells(spells), wallet1.address);
|
||||
const receipt = await tx.wait();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "burn",
|
||||
args: [
|
||||
tokenIds[0]
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
|
||||
const receipt = await tx.wait()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const getMinTick = (tickSpacing) => Math.ceil(-887272 / tickSpacing) * tickSpacing
|
||||
const getMaxTick = (tickSpacing) => Math.floor(887272 / tickSpacing) * tickSpacing
|
||||
const getMinTick = (tickSpacing) =>
|
||||
Math.ceil(-887272 / tickSpacing) * tickSpacing;
|
||||
const getMaxTick = (tickSpacing) =>
|
||||
Math.floor(887272 / tickSpacing) * tickSpacing;
|
||||
|
|
Loading…
Reference in New Issue
Block a user