Skip to content

Commit

Permalink
Merge pull request #98 from EquationDAO/optimize-mixed-executor
Browse files Browse the repository at this point in the history
If the order cannot be triggered due to changes in the market price, …
  • Loading branch information
whyareulaughing authored Dec 5, 2023
2 parents b935aed + 850ec6c commit b050d09
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 13 deletions.
44 changes: 31 additions & 13 deletions contracts/misc/MixedExecutorV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ contract MixedExecutorV2 is Multicall, Governable {
/// @param active Updated status
event ExecutorUpdated(address indexed executor, bool indexed active);

/// @notice Emitted when the increase order execute failed
/// @dev The event is only emitted when the execution error is caused
/// by the `IOrderBook.InvalidMarketPriceToTrigger`
/// @param orderIndex The index of order to execute
event IncreaseOrderExecuteFailed(uint256 indexed orderIndex);
/// @notice Emitted when the increase order cancel succeeded
/// @dev The event is emitted when the cancel order is successful after the execution error
/// @param orderIndex The index of order to cancel
Expand All @@ -48,6 +53,11 @@ contract MixedExecutorV2 is Multicall, Governable {
/// @param shortenedReason2 The shortened reason of the cancel error
event IncreaseOrderCancelFailed(uint256 indexed orderIndex, bytes4 shortenedReason1, bytes4 shortenedReason2);

/// @notice Emitted when the decrease order execute failed
/// @dev The event is only emitted when the execution error is caused
/// by the `IOrderBook.InvalidMarketPriceToTrigger`
/// @param orderIndex The index of order to execute
event DecreaseOrderExecuteFailed(uint256 indexed orderIndex);
/// @notice Emitted when the decrease order cancel succeeded
/// @dev The event is emitted when the cancel order is successful after the execution error
/// @param orderIndex The index of order to cancel
Expand Down Expand Up @@ -224,15 +234,19 @@ contract MixedExecutorV2 is Multicall, Governable {
try orderBook.executeIncreaseOrder(orderIndex, receiver) {} catch (bytes memory reason) {
if (requireSuccess) revert ExecutionFailed(reason);

// If the order cannot be triggered due to changes in the market price,
// it is unnecessary to cancel the order
bytes4 errorTypeSelector = _decodeShortenedReason(reason);
if (errorTypeSelector == IOrderBook.InvalidMarketPriceToTrigger.selector) {
emit IncreaseOrderExecuteFailed(orderIndex);
return;
}

if (cancelOrderIfFailedStatus) {
try orderBook.cancelIncreaseOrder(orderIndex, receiver) {
emit IncreaseOrderCancelSucceeded(orderIndex, _decodeShortenedReason(reason));
emit IncreaseOrderCancelSucceeded(orderIndex, errorTypeSelector);
} catch (bytes memory reason2) {
emit IncreaseOrderCancelFailed(
orderIndex,
_decodeShortenedReason(reason),
_decodeShortenedReason(reason2)
);
emit IncreaseOrderCancelFailed(orderIndex, errorTypeSelector, _decodeShortenedReason(reason2));
}
}
}
Expand All @@ -249,23 +263,27 @@ contract MixedExecutorV2 is Multicall, Governable {
try orderBook.executeDecreaseOrder(orderIndex, receiver) {} catch (bytes memory reason) {
if (requireSuccess) revert ExecutionFailed(reason);

// If the order cannot be triggered due to changes in the market price,
// it is unnecessary to cancel the order
bytes4 errorTypeSelector = _decodeShortenedReason(reason);
if (errorTypeSelector == IOrderBook.InvalidMarketPriceToTrigger.selector) {
emit DecreaseOrderExecuteFailed(orderIndex);
return;
}

if (cancelOrderIfFailedStatus) {
try orderBook.cancelDecreaseOrder(orderIndex, receiver) {
emit DecreaseOrderCancelSucceeded(orderIndex, _decodeShortenedReason(reason));
emit DecreaseOrderCancelSucceeded(orderIndex, errorTypeSelector);
} catch (bytes memory reason2) {
emit DecreaseOrderCancelFailed(
orderIndex,
_decodeShortenedReason(reason),
_decodeShortenedReason(reason2)
);
emit DecreaseOrderCancelFailed(orderIndex, errorTypeSelector, _decodeShortenedReason(reason2));
}
}
}
}

/// @notice Liquidate a liquidity position
/// @param _packedValue The packed values of the pool index, position id, and require success flag:
/// bit 0-23 represent the pool index, bit 24-119 represent the account, and bit 120 represent the
/// bit 0-23 represent the pool index, bit 24-119 represent the position ID, and bit 120 represent the
/// require success flag
function liquidateLiquidityPosition(PackedValue _packedValue) external virtual onlyExecutor {
IPool pool = poolIndexer.indexPools(_packedValue.unpackUint24(0));
Expand Down
123 changes: 123 additions & 0 deletions test/foundry/MixedExecutorV2.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.21;

import "forge-std/Test.sol";
import "../../contracts/misc/MixedExecutorV2.sol";
import "../../contracts/test/MockEFC.sol";
import "../../contracts/test/MockPool.sol";
import "../../contracts/test/MockPoolFactory.sol";
import "../../contracts/test/MockFeeDistributor.sol";

contract MixedExecutorV2Test is Test {
MockPool public pool1;
MockPool public pool2;
MockPoolFactory public poolFactory;

PoolIndexer public poolIndexer;

event IncreaseOrderExecuteFailed(uint256 indexed orderIndex);
event DecreaseOrderExecuteFailed(uint256 indexed orderIndex);

function setUp() public {
pool1 = new MockPool(IERC20(address(0)), IERC20(address(0x101)));
pool2 = new MockPool(IERC20(address(0)), IERC20(address(0x102)));

poolFactory = new MockPoolFactory();
poolFactory.createPool(address(pool1));
poolFactory.createPool(address(pool2));

poolIndexer = new PoolIndexer(IPoolFactory(address(poolFactory)));
poolIndexer.assignPoolIndex(IPool(address(pool1)));
poolIndexer.assignPoolIndex(IPool(address(pool2)));
}

function test_executeIncreaseOrder_revert_if_requireSuccess_is_true() public {
MixedExecutorV2 executor = new MixedExecutorV2(
poolIndexer,
ILiquidator(address(0)),
IPositionRouter(address(0)),
IPriceFeed(address(0)),
IOrderBook(address(new OrderBook_Thrown_InvalidMarketTriggerPrice()))
);
executor.setExecutor(address(this), true);

PackedValue packed = PackedValue.wrap(0);
packed = packed.packUint248(1111, 0);
packed = packed.packBool(true, 248);
vm.expectRevert(
abi.encodeWithSelector(
MixedExecutorV2.ExecutionFailed.selector,
abi.encodeWithSelector(IOrderBook.InvalidMarketPriceToTrigger.selector, 111, 222)
)
);
executor.executeIncreaseOrder(packed);
}

function test_executeIncreaseOrder_not_cancel_order_due_to_invalid_market_trigger_price() public {
MixedExecutorV2 executor = new MixedExecutorV2(
poolIndexer,
ILiquidator(address(0)),
IPositionRouter(address(0)),
IPriceFeed(address(0)),
IOrderBook(address(new OrderBook_Thrown_InvalidMarketTriggerPrice()))
);
executor.setExecutor(address(this), true);

PackedValue packed = PackedValue.wrap(0);
packed = packed.packUint248(1111, 0);
packed = packed.packBool(false, 248);
vm.expectEmit(true, false, false, false);
emit IncreaseOrderExecuteFailed(1111);
executor.executeIncreaseOrder(packed);
}

function test_executeDecreaseOrder_revert_if_requireSuccess_is_true() public {
MixedExecutorV2 executor = new MixedExecutorV2(
poolIndexer,
ILiquidator(address(0)),
IPositionRouter(address(0)),
IPriceFeed(address(0)),
IOrderBook(address(new OrderBook_Thrown_InvalidMarketTriggerPrice()))
);
executor.setExecutor(address(this), true);

PackedValue packed = PackedValue.wrap(0);
packed = packed.packUint248(2222, 0);
packed = packed.packBool(true, 248);
vm.expectRevert(
abi.encodeWithSelector(
MixedExecutorV2.ExecutionFailed.selector,
abi.encodeWithSelector(IOrderBook.InvalidMarketPriceToTrigger.selector, 222, 333)
)
);
executor.executeDecreaseOrder(packed);
}

function test_executeDecreaseOrder_not_cancel_order_due_to_invalid_market_trigger_price() public {
MixedExecutorV2 executor = new MixedExecutorV2(
poolIndexer,
ILiquidator(address(0)),
IPositionRouter(address(0)),
IPriceFeed(address(0)),
IOrderBook(address(new OrderBook_Thrown_InvalidMarketTriggerPrice()))
);
executor.setExecutor(address(this), true);

PackedValue packed = PackedValue.wrap(0);
packed = packed.packUint248(2222, 0);
packed = packed.packBool(false, 248);
vm.expectEmit(true, false, false, false);
emit DecreaseOrderExecuteFailed(2222);
executor.executeDecreaseOrder(packed);
}
}

contract OrderBook_Thrown_InvalidMarketTriggerPrice {
function executeIncreaseOrder(uint256, address) external pure {
revert IOrderBook.InvalidMarketPriceToTrigger(111, 222);
}

function executeDecreaseOrder(uint256, address) external pure {
revert IOrderBook.InvalidMarketPriceToTrigger(222, 333);
}
}

0 comments on commit b050d09

Please sign in to comment.