Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Izumi lp integration #402

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d3431e6
chore: izumi lp integration
zhoujia6139 Aug 14, 2023
9d3a1e4
chore: refactor optimization
zhoujia6139 Aug 15, 2023
0278849
chore: reduce SupplyLogic contract size
zhoujia6139 Aug 15, 2023
c2cdb0d
chore: revert package.json change
zhoujia6139 Aug 15, 2023
987d71d
chore: fix test case
zhoujia6139 Aug 15, 2023
59f8723
Update typos.yml
zhoujia6139 Aug 15, 2023
16635de
chore: add typo config file
zhoujia6139 Aug 15, 2023
c56bd71
Update typos.yml
zhoujia6139 Aug 15, 2023
7fae277
chore: nTokenLiquidity support add liquidity
zhoujia6139 Aug 17, 2023
88c36d2
chore: gas optimization
zhoujia6139 Aug 17, 2023
08178a3
chore: gas optimization and refactor
zhoujia6139 Aug 17, 2023
356d4bb
Merge branch 'izumi_lp_support' of https://github.com/para-space/para…
zhoujia6139 Aug 17, 2023
04453cd
chore: add value check
zhoujia6139 Aug 22, 2023
2fe2c07
chore: add timelock logic for withdraw and decrease liquidity
zhoujia6139 Aug 23, 2023
f317130
chore: timelock fix
zhoujia6139 Aug 24, 2023
2822a96
chore: fix token type
zhoujia6139 Sep 5, 2023
5a3e1bd
chore: merge main
zhoujia6139 Sep 5, 2023
411fd12
chore: fix upgrade script
zhoujia6139 Sep 5, 2023
249f3ff
chore: merge main
zhoujia6139 Sep 6, 2023
0370759
chore: merge main
zhoujia6139 Sep 21, 2023
2cd38d9
chore: Lp token adjust position
zhoujia6139 Sep 25, 2023
a25a3a0
refactor: remove decreaseLiquidity interface
zhoujia6139 Sep 26, 2023
33328c8
chore: small optimization
zhoujia6139 Sep 27, 2023
498f856
chore: add deadline for LP operation
zhoujia6139 Sep 27, 2023
7ab562b
chore: uniswapV2 integration
zhoujia6139 Oct 9, 2023
20a2991
chore: fix lint
zhoujia6139 Oct 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/typos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ jobs:

- name: Check Typos
uses: crate-ci/[email protected]
with:
config: ./_typo.toml
6 changes: 0 additions & 6 deletions .husky/pre-push

This file was deleted.

2 changes: 2 additions & 0 deletions _typo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[files]
extend-exclude = ["test/helpers/izumi-helper.ts"]
167 changes: 167 additions & 0 deletions contracts/dependencies/izumi/izumi-swap-core/flash.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;

import "./interfaces/IiZiSwapPool.sol";
import "./interfaces/IiZiSwapFlashCallback.sol";
import "./interfaces/IiZiSwapCallback.sol";

import "./libraries/Liquidity.sol";
import "./libraries/Point.sol";
import "./libraries/PointBitmap.sol";
import "./libraries/LogPowMath.sol";
import "./libraries/MulDivMath.sol";
import "./libraries/TwoPower.sol";
import "./libraries/LimitOrder.sol";
import "./libraries/SwapMathY2X.sol";
import "./libraries/SwapMathX2Y.sol";
import "./libraries/SwapMathY2XDesire.sol";
import "./libraries/SwapMathX2YDesire.sol";
import "./libraries/TokenTransfer.sol";
import "./libraries/UserEarn.sol";
import "./libraries/State.sol";
import "./libraries/Oracle.sol";
import "./libraries/OrderOrEndpoint.sol";
import "./libraries/MaxMinMath.sol";

contract FlashModule {

using Liquidity for mapping(bytes32 =>Liquidity.Data);
using Liquidity for Liquidity.Data;
using Point for mapping(int24 =>Point.Data);
using Point for Point.Data;
using PointBitmap for mapping(int16 =>uint256);
using LimitOrder for LimitOrder.Data;
using UserEarn for UserEarn.Data;
using UserEarn for mapping(bytes32 =>UserEarn.Data);
using SwapMathY2X for SwapMathY2X.RangeRetState;
using SwapMathX2Y for SwapMathX2Y.RangeRetState;
using Oracle for Oracle.Observation[65535];
using OrderOrEndpoint for mapping(int24 =>int24);

int24 internal constant LEFT_MOST_PT = -800000;
int24 internal constant RIGHT_MOST_PT = 800000;

/// @notice left most point regularized by pointDelta
int24 public leftMostPt;
/// @notice right most point regularized by pointDelta
int24 public rightMostPt;
/// @notice maximum liquidSum for each point, see points() in IiZiSwapPool or library Point
uint128 public maxLiquidPt;

/// @notice address of iZiSwapFactory
address public factory;

/// @notice address of tokenX
address public tokenX;
/// @notice address of tokenY
address public tokenY;
/// @notice fee amount of this swap pool, 3000 means 0.3%
uint24 public fee;

/// @notice minimum number of distance between initialized or limitorder points
int24 public pointDelta;

/// @notice The fee growth as a 128-bit fixpoing fees of tokenX collected per 1 liquidity of the pool
uint256 public feeScaleX_128;
/// @notice The fee growth as a 128-bit fixpoing fees of tokenY collected per 1 liquidity of the pool
uint256 public feeScaleY_128;

uint160 sqrtRate_96;

/// @notice some values of pool
/// see library State or IiZiSwapPool#state for more infomation
State public state;

/// @notice the information about a liquidity by the liquidity's key
mapping(bytes32 =>Liquidity.Data) public liquidities;

/// @notice 256 packed point (orderOrEndpoint>0) boolean values. See PointBitmap for more information
mapping(int16 =>uint256) public pointBitmap;

/// @notice returns infomation of a point in the pool, see Point library of IiZiSwapPool#poitns for more information
mapping(int24 =>Point.Data) public points;
/// @notice infomation about a point whether has limit order and whether as an liquidity's endpoint
mapping(int24 =>int24) public orderOrEndpoint;
/// @notice limitOrder info on a given point
mapping(int24 =>LimitOrder.Data) public limitOrderData;
/// @notice information about a user's limit order (sell tokenY and earn tokenX)
mapping(bytes32 => UserEarn.Data) public userEarnX;
/// @notice information about a user's limit order (sell tokenX and earn tokenY)
mapping(bytes32 => UserEarn.Data) public userEarnY;
/// @notice observation data array
Oracle.Observation[65535] public observations;

uint256 public totalFeeXCharged;
uint256 public totalFeeYCharged;

address private original;

address private swapModuleX2Y;
address private swapModuleY2X;
address private liquidityModule;
address private limitOrderModule;
address private flashModule;

/// @notice percent to charge from miner's fee
uint24 public feeChargePercent;

function balanceX() private view returns (uint256) {
(bool success, bytes memory data) =
tokenX.staticcall(abi.encodeWithSelector(IERC20Minimal.balanceOf.selector, address(this)));
require(success && data.length >= 32);
return abi.decode(data, (uint256));
}

function balanceY() private view returns (uint256) {
(bool success, bytes memory data) =
tokenY.staticcall(abi.encodeWithSelector(IERC20Minimal.balanceOf.selector, address(this)));
require(success && data.length >= 32);
return abi.decode(data, (uint256));
}


/// Delegate call implementation for IiZiSwapPool#flash.
function flash(
address recipient,
uint256 amountX,
uint256 amountY,
bytes calldata data
) external returns (uint256 actualAmountX, uint256 actualAmountY, uint256 paidX, uint256 paidY) {
uint128 currentLiquidity = state.liquidity;
require(currentLiquidity > 0, 'L');

// even the balance if not enough, the full fees are required to pay
uint256 feeX = MulDivMath.mulDivCeil(amountX, fee, 1e6);
uint256 feeY = MulDivMath.mulDivCeil(amountY, fee, 1e6);
uint256 balanceXBefore = balanceX();
uint256 balanceYBefore = balanceY();

actualAmountX = MaxMinMath.min256(amountX, balanceXBefore);
actualAmountY = MaxMinMath.min256(amountY, balanceYBefore);

if (actualAmountX > 0) TokenTransfer.transferToken(tokenX, recipient, actualAmountX);
if (actualAmountY > 0) TokenTransfer.transferToken(tokenY, recipient, actualAmountY);

IiZiSwapFlashCallback(msg.sender).flashCallback(feeX, feeY, data);
uint256 balanceXAfter = balanceX();
uint256 balanceYAfter = balanceY();

require(balanceXBefore + feeX <= balanceXAfter, 'FX');
require(balanceYBefore + feeY <= balanceYAfter, 'FY');

paidX = balanceXAfter - balanceXBefore;
paidY = balanceYAfter - balanceYBefore;

if (paidX > 0) {
uint256 chargedFeeAmount = paidX * feeChargePercent / 100;
totalFeeXCharged += chargedFeeAmount;
feeScaleX_128 = feeScaleX_128 + MulDivMath.mulDivFloor(paidX - chargedFeeAmount, TwoPower.Pow128, currentLiquidity);
}
if (paidY > 0) {
uint256 chargedFeeAmount = paidY * feeChargePercent / 100;
totalFeeYCharged += chargedFeeAmount;
feeScaleY_128 = feeScaleY_128 + MulDivMath.mulDivFloor(paidY - chargedFeeAmount, TwoPower.Pow128, currentLiquidity);
}

}
}
138 changes: 138 additions & 0 deletions contracts/dependencies/izumi/izumi-swap-core/iZiSwapFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;

import "./interfaces/IiZiSwapFactory.sol";
import "./iZiSwapPool.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

struct DeployPoolParams {
address tokenX;
address tokenY;
uint24 fee;
int24 currentPoint;
int24 pointDelta;
uint24 feeChargePercent;
}

contract iZiSwapFactory is Ownable, IiZiSwapFactory {

/// @notice charge receiver of all pools in this factory
address public override chargeReceiver;

/// @notice tokenX/tokenY/fee => pool address
mapping(address => mapping(address => mapping(uint24 => address))) public override pool;

/// @notice mapping from fee amount to pointDelta
mapping(uint24 => int24) public override fee2pointDelta;

/// @notice mark contract address in constructor to avoid delegate call
address public only_addr_;

/// @notice address of module to support swapX2Y(DesireY)
address public override swapX2YModule;

/// @notice address of module to support swapY2X(DesireX)
address public override swapY2XModule;

/// @notice address of module to support liquidity
address public override liquidityModule;

/// @notice address of module for user to manage limit orders
address public override limitOrderModule;

/// @notice address of module to support flash loan
address public override flashModule;

/// @notice default fee rate from miner's fee gain * 100
uint24 public override defaultFeeChargePercent;

DeployPoolParams public override deployPoolParams;

/// @notice Construct the factory
/// @param _swapX2YModule swap module to support swapX2Y(DesireY)
/// @param _swapY2XModule swap module to support swapY2X(DesireX)
/// @param _liquidityModule liquidity module to support mint/burn/collect
/// @param _limitOrderModule module for user to manage limit orders
/// @param _flashModule module for user to flash
/// @param _defaultFeeChargePercent default fee rate from miner's fee gain * 100
constructor(
address _chargeReceiver,
address _swapX2YModule,
address _swapY2XModule,
address _liquidityModule,
address _limitOrderModule,
address _flashModule,
uint24 _defaultFeeChargePercent
) {
only_addr_ = address(this);
fee2pointDelta[100] = 1;
fee2pointDelta[400] = 8;
fee2pointDelta[2000] = 40;
fee2pointDelta[10000] = 200;
swapX2YModule = _swapX2YModule;
swapY2XModule = _swapY2XModule;
liquidityModule = _liquidityModule;
chargeReceiver = _chargeReceiver;
limitOrderModule = _limitOrderModule;
flashModule = _flashModule;
defaultFeeChargePercent = _defaultFeeChargePercent;
}

modifier noDelegateCall() {
require(address(this) == only_addr_);
_;
}

/// @inheritdoc IiZiSwapFactory
function enableFeeAmount(uint24 fee, uint24 pointDelta) external override noDelegateCall onlyOwner {
require(pointDelta > 0, "P0");
require(fee2pointDelta[fee] == 0, "FD0");
fee2pointDelta[fee] = int24(pointDelta);
}

/// @inheritdoc IiZiSwapFactory
function newPool(
address tokenX,
address tokenY,
uint24 fee,
int24 currentPoint
) external override noDelegateCall returns (address addr) {
require(tokenX != tokenY, "SmTK");
if (tokenX > tokenY) {
(tokenX, tokenY) = (tokenY, tokenX);
}
require(pool[tokenX][tokenY][fee] == address(0));
int24 pointDelta = fee2pointDelta[fee];

require(pointDelta > 0, 'pd');
// now creating
bytes32 salt = keccak256(abi.encode(tokenX, tokenY, fee));

deployPoolParams = DeployPoolParams({
tokenX: tokenX,
tokenY: tokenY,
fee: fee,
currentPoint: currentPoint,
pointDelta: pointDelta,
feeChargePercent: defaultFeeChargePercent
});
addr = address(new iZiSwapPool{salt: salt}());
delete deployPoolParams;

pool[tokenX][tokenY][fee] = addr;
pool[tokenY][tokenX][fee] = addr;
emit NewPool(tokenX, tokenY, fee, uint24(pointDelta), addr);
}

/// @inheritdoc IiZiSwapFactory
function modifyChargeReceiver(address _chargeReceiver) external override onlyOwner {
chargeReceiver = _chargeReceiver;
}

/// @inheritdoc IiZiSwapFactory
function modifyDefaultFeeChargePercent(uint24 _defaultFeeChargePercent) external override onlyOwner {
defaultFeeChargePercent = _defaultFeeChargePercent;
}

}
Loading
Loading