Skip to content

Commit c9ce7c3

Browse files
authored
Merge pull request #50 from OpenLeverageDev/dev
Add methods for limit order and payoff trade
2 parents f5be869 + 0ee9205 commit c9ce7c3

33 files changed

+3175
-319
lines changed

.github/workflows/node.js.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ name: Node.js CI
55

66
on:
77
push:
8-
branches: [ main, tax-token-support, bsc ]
8+
branches: [ main, tax-token-support, bsc, dev, limit-order ]
99
pull_request:
1010
branches: [ main ]
1111

contracts/OpenLevInterface.sol

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ abstract contract OpenLevStorage {
4646
mapping(address => mapping(uint16 => mapping(bool => Types.Trade))) public activeTrades;
4747

4848
//useless
49-
mapping(address => bool) public allowedDepositTokens;
49+
mapping(address => bool) internal allowedDepositTokens;
5050

5151
CalculateConfig public calculateConfig;
5252

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

62+
address public opLimitOrder;
63+
6264
event MarginTrade(
6365
address trader,
6466
uint16 marketId,
@@ -135,21 +137,22 @@ interface OpenLevInterface {
135137
) external returns (uint16);
136138

137139

138-
function marginTrade(uint16 marketId, bool longToken, bool depositToken, uint deposit, uint borrow, uint minBuyAmount, bytes memory dexData) external payable;
140+
function marginTrade(uint16 marketId, bool longToken, bool depositToken, uint deposit, uint borrow, uint minBuyAmount, bytes memory dexData) external payable returns (uint256);
141+
142+
function marginTradeFor(address trader, uint16 marketId, bool longToken, bool depositToken, uint deposit, uint borrow, uint minBuyAmount, bytes memory dexData) external payable returns (uint256);
143+
144+
function closeTrade(uint16 marketId, bool longToken, uint closeAmount, uint minOrMaxAmount, bytes memory dexData) external returns (uint256);
145+
146+
function closeTradeFor(address trader, uint16 marketId, bool longToken, uint closeHeld, uint minOrMaxAmount, bytes memory dexData) external returns (uint256);
139147

140-
function closeTrade(uint16 marketId, bool longToken, uint closeAmount, uint minOrMaxAmount, bytes memory dexData) external;
148+
function payoffTrade(uint16 marketId, bool longToken) external payable;
141149

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

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

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

148-
function shouldUpdatePrice(uint16 marketId, bytes memory dexData) external view returns (bool);
149-
150-
function getMarketSupportDexs(uint16 marketId) external view returns (uint32[] memory);
151-
152-
// function getCalculateConfig() external view returns (OpenLevStorage.CalculateConfig memory);
153156

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

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

171+
function setOpLimitOrder(address _opLimitOrder) external;
172+
168173
}

contracts/OpenLevV1.sol

Lines changed: 108 additions & 114 deletions
Large diffs are not rendered by default.

contracts/OpenLevV1Lib.sol

Lines changed: 87 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ library OpenLevV1Lib {
3434
mapping(uint8 => bool) storage _supportDexs,
3535
mapping(uint16 => mapping(address => mapping(uint => uint24))) storage taxes
3636
) external {
37+
require(marketId < 65535, "TMP");
3738
address token0 = pool0.underlying();
3839
address token1 = pool1.underlying();
3940
uint8 dex = dexData.toDex();
@@ -59,7 +60,7 @@ library OpenLevV1Lib {
5960
markets[marketId] = Types.Market(pool0, pool1, token0, token1, marginLimit, config.defaultFeesRate, config.priceDiffientRatio, address(0), 0, 0, dexs);
6061
// Init price oracle
6162
if (dexData.isUniV2Class()) {
62-
updatePriceInternal(token0, token1, dexData);
63+
updatePrice(token0, token1, dexData);
6364
} else if (dex == DexData.DEX_UNIV3) {
6465
addressConfig.dexAggregator.updateV3Observation(token0, token1, dexData);
6566
}
@@ -116,15 +117,43 @@ library OpenLevV1Lib {
116117
market.priceDiffientRatio = priceDiffientRatio;
117118
}
118119

120+
121+
struct MarketWithoutDexs {// Market info
122+
LPoolInterface pool0;
123+
LPoolInterface pool1;
124+
address token0;
125+
address token1;
126+
uint16 marginLimit;
127+
}
128+
119129
function marginRatio(
130+
uint16 marketId,
120131
address owner,
121-
uint held,
122-
address heldToken,
123-
address sellToken,
124-
LPoolInterface borrowPool,
132+
bool longToken,
125133
bytes memory dexData
126-
) external view returns (uint, uint, uint, uint, uint){
127-
return marginRatioPrivate(owner, held, heldToken, sellToken, borrowPool, false, dexData);
134+
) external view returns (uint current, uint cAvg, uint hAvg, uint32 limit){
135+
address tokenToLong;
136+
MarketWithoutDexs memory market;
137+
(market.pool0, market.pool1, market.token0, market.token1, market.marginLimit,,,,,) = (OpenLevStorage(address(this))).markets(marketId);
138+
tokenToLong = longToken ? market.token1 : market.token0;
139+
limit = market.marginLimit;
140+
(,uint amount,,) = OpenLevStorage(address(this)).activeTrades(owner, marketId, longToken);
141+
amount = shareToAmount(
142+
amount,
143+
OpenLevStorage(address(this)).totalHelds(tokenToLong),
144+
IERC20(tokenToLong).balanceOf(address(this))
145+
);
146+
147+
(current, cAvg, hAvg,,) =
148+
marginRatioPrivate(
149+
owner,
150+
amount,
151+
tokenToLong,
152+
longToken ? market.token0 : market.token1,
153+
longToken ? market.pool0 : market.pool1,
154+
true,
155+
dexData
156+
);
128157
}
129158

130159
function marginRatioPrivate(
@@ -196,44 +225,35 @@ library OpenLevV1Lib {
196225
}
197226
}
198227

199-
function updatePriceInternal(address token0, address token1, bytes memory dexData) internal returns (bool){
228+
function updatePrice(address token0, address token1, bytes memory dexData) public returns (bool){
200229
(DexAggregatorInterface dexAggregator,,,) = OpenLevStorage(address(this)).addressConfig();
201230
(,,,,,,,,,uint16 twapDuration) = OpenLevStorage(address(this)).calculateConfig();
202231
return dexAggregator.updatePriceOracle(token0, token1, twapDuration, dexData);
203232
}
204233

205-
function shouldUpdatePriceInternal(DexAggregatorInterface dexAggregator, uint16 twapDuration, uint16 priceDiffientRatio, address token0, address token1, bytes memory dexData) public view returns (bool){
206-
if (!dexData.isUniV2Class()) {
207-
return false;
208-
}
209-
(, uint cAvgPrice, uint hAvgPrice,, uint lastUpdateTime) = dexAggregator.getPriceCAvgPriceHAvgPrice(token0, token1, twapDuration, dexData);
210-
if (block.timestamp < lastUpdateTime.add(twapDuration)) {
211-
return false;
212-
}
213-
//Not initialized yet
214-
if (cAvgPrice == 0 || hAvgPrice == 0) {
215-
return true;
216-
}
217-
//price difference
218-
uint one = 100;
219-
uint differencePriceRatio = cAvgPrice.mul(one).div(hAvgPrice);
220-
if (differencePriceRatio >= (one.add(priceDiffientRatio)) || differencePriceRatio <= (one.sub(priceDiffientRatio))) {
221-
return true;
222-
}
223-
return false;
224-
}
225234

226-
function updatePrice(uint16 marketId, Types.Market storage market, OpenLevStorage.AddressConfig storage addressConfig,
227-
OpenLevStorage.CalculateConfig storage calculateConfig, bytes memory dexData) external {
228-
bool shouldUpdate = shouldUpdatePriceInternal(addressConfig.dexAggregator, calculateConfig.twapDuration, market.priceDiffientRatio, market.token1, market.token0, dexData);
229-
bool updateResult = updatePriceInternal(market.token0, market.token1, dexData);
235+
function updatePrice(Types.Market storage market, bytes memory dexData) external {
236+
bool updateResult = updatePrice(market.token0, market.token1, dexData);
230237
if (updateResult) {
231238
//Discount
232239
market.priceUpdater = msg.sender;
233-
//Reward OLE
234-
if (shouldUpdate) {
235-
(ControllerInterface(addressConfig.controller)).updatePriceAllowed(marketId, msg.sender);
236-
}
240+
}
241+
}
242+
243+
function flashSell(address buyToken, address sellToken, uint sellAmount, uint minBuyAmount, bytes memory data, DexAggregatorInterface dexAggregator) external returns (uint buyAmount){
244+
if (sellAmount > 0) {
245+
IERC20(sellToken).safeApprove(address(dexAggregator), sellAmount);
246+
buyAmount = dexAggregator.sell(buyToken, sellToken, sellAmount, minBuyAmount, data);
247+
}
248+
}
249+
250+
function flashBuy(address buyToken, address sellToken, uint buyAmount, uint maxSellAmount, bytes memory data,
251+
DexAggregatorInterface dexAggregator,
252+
uint24 buyTax,
253+
uint24 sellTax) external returns (uint sellAmount){
254+
if (buyAmount > 0) {
255+
IERC20(sellToken).safeApprove(address(dexAggregator), maxSellAmount);
256+
sellAmount = dexAggregator.buy(buyToken, sellToken, buyTax, sellTax, buyAmount, maxSellAmount, data);
237257
}
238258
}
239259

@@ -281,10 +301,6 @@ library OpenLevV1Lib {
281301
) external returns (uint newFees) {
282302
uint defaultFees = tradeSize.mul(market.feesRate).div(10000);
283303
newFees = defaultFees;
284-
// if trader holds more xOLE, then should enjoy trading discount.
285-
if (XOLEInterface(xOLE).balanceOf(trader) > calculateConfig.feesDiscountThreshold) {
286-
newFees = defaultFees.sub(defaultFees.mul(calculateConfig.feesDiscount).div(100));
287-
}
288304
// if trader update price, then should enjoy trading discount.
289305
if (market.priceUpdater == trader) {
290306
newFees = newFees.sub(defaultFees.mul(calculateConfig.updatePriceDiscount).div(100));
@@ -366,14 +382,15 @@ library OpenLevV1Lib {
366382
}
367383
}
368384

369-
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 {
385+
function verifyTrade(Types.MarketVars memory vars, bool longToken, bool depositToken, uint deposit, uint borrow,
386+
bytes memory dexData, OpenLevStorage.AddressConfig memory addressConfig, Types.Trade memory trade, bool convertWeth) external view {
370387
//verify if deposit token allowed
371388
address depositTokenAddr = depositToken == longToken ? address(vars.buyToken) : address(vars.sellToken);
372389

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

@@ -386,4 +403,32 @@ library OpenLevV1Lib {
386403
require(depositToken == trade.depositToken && trade.lastBlockNum != uint128(block.number), " DTS");
387404
}
388405
}
406+
407+
function toMarketVar(bool longToken, bool open, Types.Market storage market) external view returns (Types.MarketVars memory) {
408+
return open == longToken ?
409+
Types.MarketVars(
410+
market.pool1,
411+
market.pool0,
412+
IERC20(market.token1),
413+
IERC20(market.token0),
414+
IERC20(market.token1).balanceOf(address(this)),
415+
IERC20(market.token0).balanceOf(address(this)),
416+
market.pool1Insurance,
417+
market.pool0Insurance,
418+
market.marginLimit,
419+
market.priceDiffientRatio,
420+
market.dexs) :
421+
Types.MarketVars(
422+
market.pool0,
423+
market.pool1,
424+
IERC20(market.token0),
425+
IERC20(market.token1),
426+
IERC20(market.token0).balanceOf(address(this)),
427+
IERC20(market.token1).balanceOf(address(this)),
428+
market.pool0Insurance,
429+
market.pool1Insurance,
430+
market.marginLimit,
431+
market.priceDiffientRatio,
432+
market.dexs);
433+
}
389434
}

contracts/dex/bsc/BscDexAggregatorV1.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ contract BscDexAggregatorV1 is DelegateInterface, Adminable, DexAggregatorInterf
2121
mapping(IUniswapV2Pair => V2PriceOracle) public uniV2PriceOracle;
2222
IUniswapV2Factory public pancakeFactory;
2323
address public openLev;
24-
uint8 private constant priceDecimals = 18;
24+
uint8 private constant priceDecimals = 24;
2525

2626
mapping(uint8 => DexInfo) public dexInfo;
2727

contracts/dex/bsc/UniV2ClassDex.sol

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,12 @@ contract UniV2ClassDex {
186186

187187
function calTPrice(uint currentPriceCumulativeLast, uint historyPriceCumulativeLast, uint32 timeElapsed, uint8 decimals)
188188
internal pure returns (uint){
189-
return ((currentPriceCumulativeLast.sub(historyPriceCumulativeLast).mul(10 ** decimals)) >> 112).div(timeElapsed);
189+
uint256 diff = currentPriceCumulativeLast.sub(historyPriceCumulativeLast);
190+
if (diff < (2 ** 170)) {
191+
return ((diff.mul(10 ** decimals)) >> 112).div(timeElapsed);
192+
} else {
193+
return ((diff) >> 112).mul(10 ** decimals).div(timeElapsed);
194+
}
190195
}
191196

192197
function toUint32(uint256 y) internal pure returns (uint32 z) {

0 commit comments

Comments
 (0)