Merge pull request #1 from Lixir-Team/lix

ready for insta PR
This commit is contained in:
buffal0bill 2022-01-12 13:44:57 -06:00 committed by GitHub
commit 4548cad2cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 582 additions and 4 deletions

View File

@ -0,0 +1,16 @@
pragma solidity ^0.7.0;
contract Events {
event LogDeposit(
address indexed vault,
uint256 shares,
uint256 amount0In,
uint256 amount1In
);
event LogWithdraw(
address indexed vault,
uint256 amount0Out,
uint256 amount1Out
);
}

View File

@ -0,0 +1,78 @@
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";
abstract contract Helpers is DSMath, Basic {
function _deposit(
address payable vaultAddress,
uint256 amount0Desired,
uint256 amount1Desired,
uint256 amount0Min,
uint256 amount1Min,
address recipient,
uint256 deadline
) internal returns (
uint256 shares,
uint256 amount0In,
uint256 amount1In
) {
uint256 shares;
uint256 amount0In;
uint256 amount1In;
if (msg.value > 0) {
ILixirVaultETH vault = ILixirVaultETH(vaultAddress);
(
shares,
amount0In,
amount1In
) = vault.depositETH(
uint8(vault.WETH_TOKEN()) == 1 ? amount0Desired : amount1Desired,
uint8(vault.WETH_TOKEN()) == 1 ? amount0Min : amount1Min,
uint8(vault.WETH_TOKEN()) == 1 ? amount1Min : amount0Min,
recipient,
deadline
);
} else {
ILixirVault vault = ILixirVault(vaultAddress);
(
shares,
amount0In,
amount1In
) = vault.deposit(
amount0Desired,
amount1Desired,
amount0Min,
amount1Min,
recipient,
deadline
);
}
}
function _withdraw(
address vaultAddress,
uint256 shares,
uint256 amount0Min,
uint256 amount1Min,
address recipient,
uint256 deadline
) internal returns (uint256 amount0Out, uint256 amount1Out) {
ILixirVault vault = ILixirVault(vaultAddress);
(
amount0Out,
amount1Out
) = vault.withdraw(
shares,
amount0Min,
amount1Min,
recipient,
deadline
);
}
}

View File

@ -0,0 +1,204 @@
pragma solidity ^0.7.6;
import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over `owner`'s tokens,
* given `owner`'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for `permit`, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
interface ILixirVaultToken is IERC20, IERC20Permit {
}
interface ILixirVault is ILixirVaultToken {
function initialize(
string memory name,
string memory symbol,
address _token0,
address _token1,
address _strategist,
address _keeper,
address _strategy
) external;
function token0() external view returns (IERC20);
function token1() external view returns (IERC20);
function activeFee() external view returns (uint24);
function activePool() external view returns (IUniswapV3Pool);
function performanceFee() external view returns (uint24);
function strategist() external view returns (address);
function strategy() external view returns (address);
function keeper() external view returns (address);
function setKeeper(address _keeper) external;
function setStrategist(address _strategist) external;
function setStrategy(address _strategy) external;
function setPerformanceFee(uint24 newFee) external;
function mainPosition()
external
view
returns (int24 tickLower, int24 tickUpper);
function rangePosition()
external
view
returns (int24 tickLower, int24 tickUpper);
function rebalance(
int24 mainTickLower,
int24 mainTickUpper,
int24 rangeTickLower0,
int24 rangeTickUpper0,
int24 rangeTickLower1,
int24 rangeTickUpper1,
uint24 fee
) external;
function withdraw(
uint256 shares,
uint256 amount0Min,
uint256 amount1Min,
address receiver,
uint256 deadline
) external returns (uint256 amount0Out, uint256 amount1Out);
function withdrawFrom(
address withdrawer,
uint256 shares,
uint256 amount0Min,
uint256 amount1Min,
address recipient,
uint256 deadline
) external returns (uint256 amount0Out, uint256 amount1Out);
function deposit(
uint256 amount0Desired,
uint256 amount1Desired,
uint256 amount0Min,
uint256 amount1Min,
address recipient,
uint256 deadline
)
external
returns (
uint256 shares,
uint256 amount0,
uint256 amount1
);
function calculateTotals()
external
view
returns (
uint256 total0,
uint256 total1,
uint128 mL,
uint128 rL
);
function calculateTotalsFromTick(int24 virtualTick)
external
view
returns (
uint256 total0,
uint256 total1,
uint128 mL,
uint128 rL
);
}
interface ILixirVaultETH is ILixirVault {
enum TOKEN {ZERO, ONE}
function WETH_TOKEN() external view returns (TOKEN);
function depositETH(
uint256 amountDesired,
uint256 amountEthMin,
uint256 amountMin,
address recipient,
uint256 deadline
)
external
payable
returns (
uint256 shares,
uint256 amountEthIn,
uint256 amountIn
);
function withdrawETHFrom(
address withdrawer,
uint256 shares,
uint256 amountEthMin,
uint256 amountMin,
address payable recipient,
uint256 deadline
) external returns (uint256 amountEthOut, uint256 amountOut);
function withdrawETH(
uint256 shares,
uint256 amountEthMin,
uint256 amountMin,
address payable recipient,
uint256 deadline
) external returns (uint256 amountEthOut, uint256 amountOut);
receive() external payable;
}

View File

@ -0,0 +1,116 @@
pragma solidity ^0.7.6;
pragma abicoder v2;
/**
* @title Lixir Finance.
* @dev Automated Liquidity Concentrator.
*/
import { TokenInterface } from "../../common/interfaces.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
abstract contract LixirResolver is Helpers, Events {
/**
* @dev Add liqudity to the vault
* @notice Mint Lixir Vault Tokens
* @param vault vault address
* @param amount0Desired amount of tokenA
* @param amount1Desired amount of tokenB
* @param amount0Min amount of tokenA
* @param amount1Min amount of tokenB
* @param recipient recipient of the Lixir Vault Tokens
* @param deadline unix timestamp
* @param getIds ID to retrieve amtA
* @param setId ID stores the amount of LP token
*/
function deposit(
address payable vault,
uint256 amount0Desired,
uint256 amount1Desired,
uint256 amount0Min,
uint256 amount1Min,
address recipient,
uint256 deadline,
uint256[] calldata getIds,
uint256 setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
amount0Desired = getUint(getIds[0], amount0Desired);
amount1Desired = getUint(getIds[1], amount1Desired);
(
uint256 shares,
uint256 amount0In,
uint256 amount1In
) = _deposit(
vault,
amount0Desired,
amount1Desired,
amount0Min,
amount1Min,
recipient,
deadline
);
setUint(setId, shares);
_eventName = "LogDeposit(address,uint256,uint256,uint256)";
_eventParam = abi.encode(
vault,
shares,
amount0In,
amount1In
);
}
/**
* @dev Decrease Liquidity
* @notice Withdraw Liquidity from Lixir Vault
* @param vault Lixir vault address
* @param shares the amount of Lixir Vault Tokens to remove
* @param amount0Min Min amount of token0.
* @param amount1Min Min amount of token1.
* @param deadline unix timestamp
* @param getId ID to retrieve LP token amounts
* @param setIds stores the amount of output tokens
*/
function withdraw(
address vault,
uint256 shares,
uint256 amount0Min,
uint256 amount1Min,
address recipient,
uint256 deadline,
uint256 getId,
uint256[] calldata setIds
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
address vault = address(getUint(getId, uint256(vault))); // unsure of this...
(uint256 amount0Out, uint256 amount1Out) = _withdraw(
vault,
shares,
amount0Min,
amount1Min,
recipient,
deadline
);
setUint(setIds[0], amount0Out);
setUint(setIds[1], amount1Out);
_eventName = "LogWithdraw(address,uint256,uint256)";
_eventParam = abi.encode(vault, amount0Out, amount1Out);
}
}
contract ConnectV2Lixir is LixirResolver {
string public constant name = "Lixir-v1";
}

View File

@ -9,15 +9,15 @@ const mineTx = async (tx: any) => {
const tokenMapping: Record<string, any> = {
usdc: {
impersonateSigner: "0xfcb19e6a322b27c06842a71e8c725399f049ae3a",
impersonateSigner: "0x47ac0fb4f2d84898e4d9e7b4dab3c24507a6d503",
address: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
abi: [
"function mint(address _to, uint256 _amount) external returns (bool);",
"function transfer(address to, uint value)"
],
process: async function(owner: Signer | Provider, to: any, amt: any) {
const contract = new ethers.Contract(this.address, this.abi, owner);
await mineTx(contract.mint(to, amt));
await mineTx(contract.transfer(to, amt));
},
},
dai: {

View File

@ -0,0 +1,164 @@
import { expect } from "chai";
import hre from "hardhat";
const { waffle, ethers, network } = hre;
const { provider, deployContract } = 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 type { Signer, Contract } from "ethers";
import { ConnectV2Lixir__factory, ILixirVault__factory } from "../../../typechain";
const USDC_WETH_VAULT = "0x453A9f40a24DbE3CdB4edC988aF9bfE0F5602b15"
const abiCoder = ethers.utils.defaultAbiCoder;
describe("Lixir", function() {
const connectorName = "Lixir-v1";
let dsaWallet0: any;
let masterSigner: Signer;
let instaConnectorsV2: Contract;
let connector: Contract;
let vault: Contract;
const wallets = provider.getWallets();
const [wallet0, wallet1, wallet2, wallet3] = wallets;
before(async () => {
await network.provider.send("evm_setAutomine", [false]);
await network.provider.send("evm_setIntervalMining", [3000]);
await network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
// @ts-ignore
jsonRpcUrl: hre.config.networks.hardhat.forking.url,
blockNumber: 13298611,
},
},
],
});
masterSigner = await getMasterSigner();
instaConnectorsV2 = await ethers.getContractAt(
abis.core.connectorsV2,
addresses.core.connectorsV2
);
vault = await ethers.getContractAt(
ILixirVault__factory.abi,
USDC_WETH_VAULT
);
connector = await deployAndEnableConnector({
connectorName,
contractArtifact: ConnectV2Lixir__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 & USDC 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(
"usdc",
dsaWallet0.address,
1000000 * 10**6 // USDC has 6 decimals
);
});
});
describe("Main", function() {
it("Should deposit successfully", async function() {
const usdcAmount = ethers.BigNumber.from(10**6).mul(4000); // ~1 ETH
const ethAmount = ethers.utils.parseEther("1"); // 1 ETH
const getIds = ["0", "0"];
const setId = "0";
const spells = [
{
connector: connectorName,
method: "deposit",
args: [ // get these right
vault.address,
usdcAmount,
ethAmount,
0, // any slippage lol
0, // any slippage lol
dsaWallet0.address,
1740297687, // high deadline
getIds,
setId,
],
},
];
const tx = await dsaWallet0
.connect(wallet0)
.cast(...encodeSpells(spells), wallet1.address);
const receipt = await tx.wait();
console.log(await vault.balanceOf(wallet1.address));
// console.log(await vault.balanceOf(dsaWallet0.address));
// const dsaLvtBalance = await vault.balanceOf(dsaWallet0.address);
// console.log(dsaLvtBalance);
// expect(dsaLvtBalance).gte(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 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();
// data1 = await nftManager.positions(tokenIds[1]);
// expect(data1.liquidity.toNumber()).to.be.equals(0);
// });
});
});

View File

@ -12707,4 +12707,4 @@
"yn@3.1.1":
"integrity" "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="
"resolved" "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz"
"version" "3.1.1"
"version" "3.1.1"