Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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, cronos ]
branches: [ main, tax-token-support, bsc, financing_payoff ]
pull_request:
branches: [ main ]

Expand Down
4 changes: 2 additions & 2 deletions contracts/OpenLevInterface.sol
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,14 @@ interface OpenLevInterface {

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);
Expand Down
67 changes: 33 additions & 34 deletions contracts/OpenLevV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ contract OpenLevV1 is DelegateInterface, Adminable, ReentrancyGuard, OpenLevInte
function closeTrade(uint16 marketId, bool longToken, uint closeHeld, uint minOrMaxAmount, bytes memory dexData) external override nonReentrant onlySupportDex(dexData) {
Types.Trade storage trade = activeTrades[msg.sender][marketId][longToken];
Types.MarketVars memory marketVars = toMarketVar(longToken, false, markets[marketId]);
bool depositToken = trade.depositToken;

//verify
require(closeHeld <= trade.held, "CBH");
Expand All @@ -204,7 +205,7 @@ contract OpenLevV1 is DelegateInterface, Adminable, ReentrancyGuard, OpenLevInte
closeTradeVars.depositDecrease = trade.deposited;
}

if (trade.depositToken != longToken) {
if (depositToken != longToken) {
minOrMaxAmount = Utils.maxOf(closeTradeVars.repayAmount, minOrMaxAmount);
closeTradeVars.receiveAmount = flashSell(address(marketVars.buyToken), address(marketVars.sellToken), closeTradeVars.closeAmountAfterFees, minOrMaxAmount, dexData);
require(closeTradeVars.receiveAmount >= closeTradeVars.repayAmount, "ISR");
Expand Down Expand Up @@ -244,10 +245,39 @@ contract OpenLevV1 is DelegateInterface, Adminable, ReentrancyGuard, OpenLevInte
OpenLevV1Lib.updatePriceInternal(address(marketVars.buyToken), address(marketVars.sellToken), dexData);
}

emit TradeClosed(msg.sender, marketId, longToken, trade.depositToken, closeHeld, closeTradeVars.depositDecrease, closeTradeVars.depositReturn, closeTradeVars.fees,
emit TradeClosed(msg.sender, marketId, longToken, depositToken, closeHeld, closeTradeVars.depositDecrease, closeTradeVars.depositReturn, closeTradeVars.fees,
closeTradeVars.token0Price, closeTradeVars.dexDetail);
}

/// @notice payoff trade by shares.
/// @dev To support token with tax, function expect to fail if share of borrowed funds not repayed.
/// @param longToken Token to long. False for token0, true for token1.
function payoffTrade(uint16 marketId, bool longToken) external payable override nonReentrant {
Types.Trade storage trade = activeTrades[msg.sender][marketId][longToken];
bool depositToken = trade.depositToken;
uint deposited = trade.deposited;
Types.MarketVars memory marketVars = toMarketVar(longToken, false, markets[marketId]);

//verify
require(trade.held != 0 && trade.lastBlockNum != block.number, "HI0");
(ControllerInterface(addressConfig.controller)).closeTradeAllowed(marketId);
uint heldAmount = trade.held;
uint closeAmount = OpenLevV1Lib.shareToAmount(heldAmount, totalHelds[address(marketVars.sellToken)], marketVars.reserveSellToken);
uint borrowed = marketVars.buyPool.borrowBalanceCurrent(msg.sender);

//first transfer token to OpenLeve, then repay to pool, two transactions with two tax deductions
uint24 taxRate = taxes[marketId][address(marketVars.buyToken)][0];
uint firstAmount = Utils.toAmountBeforeTax(borrowed, taxRate);
uint transferAmount = transferIn(msg.sender, marketVars.buyToken, Utils.toAmountBeforeTax(firstAmount, taxRate));
marketVars.buyPool.repayBorrowBehalf(msg.sender, transferAmount);
require(marketVars.buyPool.borrowBalanceCurrent(msg.sender) == 0, "IRP");
delete activeTrades[msg.sender][marketId][longToken];
totalHelds[address(marketVars.sellToken)] = totalHelds[address(marketVars.sellToken)].sub(heldAmount);
doTransferOut(msg.sender, marketVars.sellToken, closeAmount);

emit TradeClosed(msg.sender, marketId, longToken, depositToken, heldAmount, deposited, heldAmount, 0, 0, 0);
}

/// @notice Liquidate if trade below margin limit.
/// @dev For trades without sufficient funds to repay, use insurance.
/// @param owner Owner of the trade to liquidate.
Expand Down Expand Up @@ -331,31 +361,7 @@ contract OpenLevV1 is DelegateInterface, Adminable, ReentrancyGuard, OpenLevInte
}

function toMarketVar(bool longToken, bool open, Types.Market storage market) internal 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);
return OpenLevV1Lib.toMarketVar(longToken, open, market);
}

/// @notice Get ratios of deposited token value to borrowed token value.
Expand Down Expand Up @@ -391,13 +397,6 @@ contract OpenLevV1 is DelegateInterface, Adminable, ReentrancyGuard, OpenLevInte
);
}

/// @notice Check if a price update is required on Dex.
/// @param dexData Index and fee rate for the trading Dex.
function shouldUpdatePrice(uint16 marketId, bytes memory dexData) external override view returns (bool){
Types.Market memory market = markets[marketId];
return OpenLevV1Lib.shouldUpdatePriceInternal(addressConfig.dexAggregator, calculateConfig.twapDuration, market.priceDiffientRatio, market.token0, market.token1, dexData);
}

/// @notice Update price on Dex.
/// @param dexData Index and fee rate for the trading Dex.
function updatePrice(uint16 marketId, bytes memory dexData) external override {
Expand Down
28 changes: 28 additions & 0 deletions contracts/OpenLevV1Lib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -386,4 +386,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);
}
}
5 changes: 0 additions & 5 deletions test/OpenLevV1UniV2Test1.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,6 @@ contract("OpenLev UniV2", async accounts => {
let priceData0 = await dexAgg.getPriceCAvgPriceHAvgPrice(token0.address, token1.address, 60, Uni2DexData);
m.log("PriceData0: \t", JSON.stringify(priceData0));

let shouldUpatePrice = await openLev.shouldUpdatePrice(pairId, Uni2DexData);
assert.equal(shouldUpatePrice, true);
// should update price first
await assertThrows(openLev.liquidate(trader, pairId, 0, 0, utils.maxUint(), Uni2DexData, {from: liquidator2}), 'MPT');

Expand Down Expand Up @@ -380,9 +378,6 @@ contract("OpenLev UniV2", async accounts => {
let priceData0 = await dexAgg.getPriceCAvgPriceHAvgPrice(token0.address, token1.address, 60, Uni2DexData);
m.log("PriceData0: \t", JSON.stringify(priceData0));

let shouldUpatePrice = await openLev.shouldUpdatePrice(pairId, Uni2DexData);
assert.equal(shouldUpatePrice, true);

// should update price first
await assertThrows(openLev.liquidate(trader, pairId, 0, 0, utils.maxUint(), Uni2DexData, {from: liquidator2}), 'MPT');
await advanceMultipleBlocksAndTime(1000);
Expand Down
Loading