Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
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: 1 addition & 1 deletion .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name: Node.js CI

on:
push:
branches: [ main, tax-token-support, bsc ]
branches: [ main, tax-token-support, bsc, dev, limit-order ]
pull_request:
branches: [ main ]

Expand Down
21 changes: 13 additions & 8 deletions contracts/OpenLevInterface.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ abstract contract OpenLevStorage {
mapping(address => mapping(uint16 => mapping(bool => Types.Trade))) public activeTrades;

//useless
mapping(address => bool) public allowedDepositTokens;
mapping(address => bool) internal allowedDepositTokens;

CalculateConfig public calculateConfig;

Expand All @@ -59,6 +59,8 @@ abstract contract OpenLevStorage {
// map(marketId, tokenAddress, index) => taxRate)
mapping(uint16 => mapping(address => mapping(uint => uint24))) public taxes;

address public opLimitOrder;

event MarginTrade(
address trader,
uint16 marketId,
Expand Down Expand Up @@ -135,21 +137,22 @@ interface OpenLevInterface {
) external returns (uint16);


function marginTrade(uint16 marketId, bool longToken, bool depositToken, uint deposit, uint borrow, uint minBuyAmount, bytes memory dexData) external payable;
function marginTrade(uint16 marketId, bool longToken, bool depositToken, uint deposit, uint borrow, uint minBuyAmount, bytes memory dexData) external payable returns (uint256);

function marginTradeFor(address trader, uint16 marketId, bool longToken, bool depositToken, uint deposit, uint borrow, uint minBuyAmount, bytes memory dexData) external payable returns (uint256);

function closeTrade(uint16 marketId, bool longToken, uint closeAmount, uint minOrMaxAmount, bytes memory dexData) external returns (uint256);

function closeTradeFor(address trader, uint16 marketId, bool longToken, uint closeHeld, uint minOrMaxAmount, bytes memory dexData) external returns (uint256);

function closeTrade(uint16 marketId, bool longToken, uint closeAmount, uint minOrMaxAmount, bytes memory dexData) external;
function payoffTrade(uint16 marketId, bool longToken) external payable;

function liquidate(address owner, uint16 marketId, bool longToken, uint minBuy, uint maxAmount, bytes memory dexData) external;

function marginRatio(address owner, uint16 marketId, bool longToken, bytes memory dexData) external view returns (uint current, uint cAvg, uint hAvg, uint32 limit);

function updatePrice(uint16 marketId, bytes memory dexData) external;

function shouldUpdatePrice(uint16 marketId, bytes memory dexData) external view returns (bool);

function getMarketSupportDexs(uint16 marketId) external view returns (uint32[] memory);

// function getCalculateConfig() external view returns (OpenLevStorage.CalculateConfig memory);

/*** Admin Functions ***/
function setCalculateConfig(uint16 defaultFeesRate, uint8 insuranceRatio, uint16 defaultMarginLimit, uint16 priceDiffientRatio,
Expand All @@ -165,4 +168,6 @@ interface OpenLevInterface {

function setTaxRate(uint16 marketId, address token, uint index, uint24 tax) external;

function setOpLimitOrder(address _opLimitOrder) external;

}
222 changes: 108 additions & 114 deletions contracts/OpenLevV1.sol

Large diffs are not rendered by default.

129 changes: 87 additions & 42 deletions contracts/OpenLevV1Lib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ library OpenLevV1Lib {
mapping(uint8 => bool) storage _supportDexs,
mapping(uint16 => mapping(address => mapping(uint => uint24))) storage taxes
) external {
require(marketId < 65535, "TMP");
address token0 = pool0.underlying();
address token1 = pool1.underlying();
uint8 dex = dexData.toDex();
Expand All @@ -59,7 +60,7 @@ library OpenLevV1Lib {
markets[marketId] = Types.Market(pool0, pool1, token0, token1, marginLimit, config.defaultFeesRate, config.priceDiffientRatio, address(0), 0, 0, dexs);
// Init price oracle
if (dexData.isUniV2Class()) {
updatePriceInternal(token0, token1, dexData);
updatePrice(token0, token1, dexData);
} else if (dex == DexData.DEX_UNIV3) {
addressConfig.dexAggregator.updateV3Observation(token0, token1, dexData);
}
Expand Down Expand Up @@ -116,15 +117,43 @@ library OpenLevV1Lib {
market.priceDiffientRatio = priceDiffientRatio;
}


struct MarketWithoutDexs {// Market info
LPoolInterface pool0;
LPoolInterface pool1;
address token0;
address token1;
uint16 marginLimit;
}

function marginRatio(
uint16 marketId,
address owner,
uint held,
address heldToken,
address sellToken,
LPoolInterface borrowPool,
bool longToken,
bytes memory dexData
) external view returns (uint, uint, uint, uint, uint){
return marginRatioPrivate(owner, held, heldToken, sellToken, borrowPool, false, dexData);
) external view returns (uint current, uint cAvg, uint hAvg, uint32 limit){
address tokenToLong;
MarketWithoutDexs memory market;
(market.pool0, market.pool1, market.token0, market.token1, market.marginLimit,,,,,) = (OpenLevStorage(address(this))).markets(marketId);
tokenToLong = longToken ? market.token1 : market.token0;
limit = market.marginLimit;
(,uint amount,,) = OpenLevStorage(address(this)).activeTrades(owner, marketId, longToken);
amount = shareToAmount(
amount,
OpenLevStorage(address(this)).totalHelds(tokenToLong),
IERC20(tokenToLong).balanceOf(address(this))
);

(current, cAvg, hAvg,,) =
marginRatioPrivate(
owner,
amount,
tokenToLong,
longToken ? market.token0 : market.token1,
longToken ? market.pool0 : market.pool1,
true,
dexData
);
}

function marginRatioPrivate(
Expand Down Expand Up @@ -196,44 +225,35 @@ library OpenLevV1Lib {
}
}

function updatePriceInternal(address token0, address token1, bytes memory dexData) internal returns (bool){
function updatePrice(address token0, address token1, bytes memory dexData) public returns (bool){
(DexAggregatorInterface dexAggregator,,,) = OpenLevStorage(address(this)).addressConfig();
(,,,,,,,,,uint16 twapDuration) = OpenLevStorage(address(this)).calculateConfig();
return dexAggregator.updatePriceOracle(token0, token1, twapDuration, dexData);
}

function shouldUpdatePriceInternal(DexAggregatorInterface dexAggregator, uint16 twapDuration, uint16 priceDiffientRatio, address token0, address token1, bytes memory dexData) public view returns (bool){
if (!dexData.isUniV2Class()) {
return false;
}
(, uint cAvgPrice, uint hAvgPrice,, uint lastUpdateTime) = dexAggregator.getPriceCAvgPriceHAvgPrice(token0, token1, twapDuration, dexData);
if (block.timestamp < lastUpdateTime.add(twapDuration)) {
return false;
}
//Not initialized yet
if (cAvgPrice == 0 || hAvgPrice == 0) {
return true;
}
//price difference
uint one = 100;
uint differencePriceRatio = cAvgPrice.mul(one).div(hAvgPrice);
if (differencePriceRatio >= (one.add(priceDiffientRatio)) || differencePriceRatio <= (one.sub(priceDiffientRatio))) {
return true;
}
return false;
}

function updatePrice(uint16 marketId, Types.Market storage market, OpenLevStorage.AddressConfig storage addressConfig,
OpenLevStorage.CalculateConfig storage calculateConfig, bytes memory dexData) external {
bool shouldUpdate = shouldUpdatePriceInternal(addressConfig.dexAggregator, calculateConfig.twapDuration, market.priceDiffientRatio, market.token1, market.token0, dexData);
bool updateResult = updatePriceInternal(market.token0, market.token1, dexData);
function updatePrice(Types.Market storage market, bytes memory dexData) external {
bool updateResult = updatePrice(market.token0, market.token1, dexData);
if (updateResult) {
//Discount
market.priceUpdater = msg.sender;
//Reward OLE
if (shouldUpdate) {
(ControllerInterface(addressConfig.controller)).updatePriceAllowed(marketId, msg.sender);
}
}
}

function flashSell(address buyToken, address sellToken, uint sellAmount, uint minBuyAmount, bytes memory data, DexAggregatorInterface dexAggregator) external returns (uint buyAmount){
if (sellAmount > 0) {
IERC20(sellToken).safeApprove(address(dexAggregator), sellAmount);
buyAmount = dexAggregator.sell(buyToken, sellToken, sellAmount, minBuyAmount, data);
}
}

function flashBuy(address buyToken, address sellToken, uint buyAmount, uint maxSellAmount, bytes memory data,
DexAggregatorInterface dexAggregator,
uint24 buyTax,
uint24 sellTax) external returns (uint sellAmount){
if (buyAmount > 0) {
IERC20(sellToken).safeApprove(address(dexAggregator), maxSellAmount);
sellAmount = dexAggregator.buy(buyToken, sellToken, buyTax, sellTax, buyAmount, maxSellAmount, data);
}
}

Expand Down Expand Up @@ -281,10 +301,6 @@ library OpenLevV1Lib {
) external returns (uint newFees) {
uint defaultFees = tradeSize.mul(market.feesRate).div(10000);
newFees = defaultFees;
// if trader holds more xOLE, then should enjoy trading discount.
if (XOLEInterface(xOLE).balanceOf(trader) > calculateConfig.feesDiscountThreshold) {
newFees = defaultFees.sub(defaultFees.mul(calculateConfig.feesDiscount).div(100));
}
// if trader update price, then should enjoy trading discount.
if (market.priceUpdater == trader) {
newFees = newFees.sub(defaultFees.mul(calculateConfig.updatePriceDiscount).div(100));
Expand Down Expand Up @@ -366,14 +382,15 @@ library OpenLevV1Lib {
}
}

function verifyTrade(Types.MarketVars memory vars, bool longToken, bool depositToken, uint deposit, uint borrow, bytes memory dexData, OpenLevStorage.AddressConfig memory addressConfig, Types.Trade memory trade) external view {
function verifyTrade(Types.MarketVars memory vars, bool longToken, bool depositToken, uint deposit, uint borrow,
bytes memory dexData, OpenLevStorage.AddressConfig memory addressConfig, Types.Trade memory trade, bool convertWeth) external view {
//verify if deposit token allowed
address depositTokenAddr = depositToken == longToken ? address(vars.buyToken) : address(vars.sellToken);

//verify minimal deposit > absolute value 0.0001
uint decimals = ERC20(depositTokenAddr).decimals();
uint minimalDeposit = decimals > 4 ? 10 ** (decimals - 4) : 1;
uint actualDeposit = depositTokenAddr == addressConfig.wETH ? msg.value : deposit;
uint actualDeposit = depositTokenAddr == addressConfig.wETH && convertWeth ? msg.value : deposit;
require(actualDeposit > minimalDeposit, "DTS");
require(isInSupportDex(vars.dexs, dexData.toDexDetail()), "DNS");

Expand All @@ -386,4 +403,32 @@ library OpenLevV1Lib {
require(depositToken == trade.depositToken && trade.lastBlockNum != uint128(block.number), " DTS");
}
}

function toMarketVar(bool longToken, bool open, Types.Market storage market) external view returns (Types.MarketVars memory) {
return open == longToken ?
Types.MarketVars(
market.pool1,
market.pool0,
IERC20(market.token1),
IERC20(market.token0),
IERC20(market.token1).balanceOf(address(this)),
IERC20(market.token0).balanceOf(address(this)),
market.pool1Insurance,
market.pool0Insurance,
market.marginLimit,
market.priceDiffientRatio,
market.dexs) :
Types.MarketVars(
market.pool0,
market.pool1,
IERC20(market.token0),
IERC20(market.token1),
IERC20(market.token0).balanceOf(address(this)),
IERC20(market.token1).balanceOf(address(this)),
market.pool0Insurance,
market.pool1Insurance,
market.marginLimit,
market.priceDiffientRatio,
market.dexs);
}
}
2 changes: 1 addition & 1 deletion contracts/dex/bsc/BscDexAggregatorV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ contract BscDexAggregatorV1 is DelegateInterface, Adminable, DexAggregatorInterf
mapping(IUniswapV2Pair => V2PriceOracle) public uniV2PriceOracle;
IUniswapV2Factory public pancakeFactory;
address public openLev;
uint8 private constant priceDecimals = 18;
uint8 private constant priceDecimals = 24;

mapping(uint8 => DexInfo) public dexInfo;

Expand Down
7 changes: 6 additions & 1 deletion contracts/dex/bsc/UniV2ClassDex.sol
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,12 @@ contract UniV2ClassDex {

function calTPrice(uint currentPriceCumulativeLast, uint historyPriceCumulativeLast, uint32 timeElapsed, uint8 decimals)
internal pure returns (uint){
return ((currentPriceCumulativeLast.sub(historyPriceCumulativeLast).mul(10 ** decimals)) >> 112).div(timeElapsed);
uint256 diff = currentPriceCumulativeLast.sub(historyPriceCumulativeLast);
if (diff < (2 ** 170)) {
return ((diff.mul(10 ** decimals)) >> 112).div(timeElapsed);
} else {
return ((diff) >> 112).mul(10 ** decimals).div(timeElapsed);
}
}

function toUint32(uint256 y) internal pure returns (uint32 z) {
Expand Down
Loading