Skip to content

Richer Futures position and margin events #1456

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

Merged
merged 3 commits into from
Aug 16, 2021
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
112 changes: 75 additions & 37 deletions contracts/FuturesMarket.sol
Original file line number Diff line number Diff line change
Expand Up @@ -745,8 +745,10 @@ contract FuturesMarket is Owned, Proxyable, MixinFuturesMarketSettings, IFutures
function _recomputeFunding(uint price) internal returns (uint lastIndex) {
uint sequenceLength = fundingSequence.length;

fundingSequence.push(_nextFundingEntry(sequenceLength, price));
int funding = _nextFundingEntry(sequenceLength, price);
fundingSequence.push(funding);
fundingLastRecomputed = block.timestamp;
emitFundingRecomputed(funding);

return sequenceLength;
}
Expand Down Expand Up @@ -791,7 +793,7 @@ contract FuturesMarket is Owned, Proxyable, MixinFuturesMarketSettings, IFutures
return (uMargin, Status.Ok);
}

function _modifyMargin(
function _transferMargin(
int marginDelta,
uint price,
uint fundingIndex,
Expand Down Expand Up @@ -830,35 +832,50 @@ contract FuturesMarket is Owned, Proxyable, MixinFuturesMarketSettings, IFutures

// Update the account's position with the realised margin.
position.margin = margin;
position.lastPrice = price;
position.fundingIndex = fundingIndex;
// We only need to update their funding/PnL details if they actually have a position open
if (positionSize > 0) {
position.lastPrice = price;
position.fundingIndex = fundingIndex;
}

// The user can decrease their position if they have no position, or as long as:
// * they have sufficient margin to do so
// * the resulting margin would not be lower than the minimum margin
// * the resulting leverage is lower than the maximum leverage
if (0 < position.size && marginDelta <= 0) {
if (0 < positionSize && marginDelta <= 0) {
if (margin < _minInitialMargin()) {
status = Status.InsufficientMargin;
} else if (_maxLeverage(baseAsset) < _abs(_currentLeverage(position, price, margin))) {
status = Status.MaxLeverageExceeded;
}
_revertIfError(status);
}

// Emit relevant events
if (marginDelta != 0) {
emitMarginTransferred(sender, marginDelta);
}
emitPositionModified(
sender,
margin,
positionSize,
positionSize > 0 ? price : 0,
positionSize > 0 ? fundingIndex : 0
);
}

function modifyMargin(int marginDelta) external optionalProxy {
function transferMargin(int marginDelta) external optionalProxy {
uint price = _assetPriceRequireNotInvalid();
uint fundingIndex = _recomputeFunding(price);
_modifyMargin(marginDelta, price, fundingIndex, messageSender);
_transferMargin(marginDelta, price, fundingIndex, messageSender);
}

function withdrawAllMargin() external optionalProxy {
address sender = messageSender;
uint price = _assetPriceRequireNotInvalid();
uint fundingIndex = _recomputeFunding(price);
int marginDelta = -int(_remainingMargin(positions[sender], fundingIndex, price));
_modifyMargin(marginDelta, price, fundingIndex, sender);
_transferMargin(marginDelta, price, fundingIndex, sender);
}

function _cancelOrder(address account) internal {
Expand Down Expand Up @@ -961,7 +978,7 @@ contract FuturesMarket is Owned, Proxyable, MixinFuturesMarketSettings, IFutures
_submitOrder(0, price, [0, uint(-1)], fundingIndex, messageSender);
}

function modifyMarginAndSubmitOrderWithPriceBounds(
function transferMarginAndSubmitOrderWithPriceBounds(
int marginDelta,
int leverage,
uint minPrice,
Expand All @@ -970,12 +987,12 @@ contract FuturesMarket is Owned, Proxyable, MixinFuturesMarketSettings, IFutures
uint price = _assetPriceRequireNotInvalid();
uint fundingIndex = _recomputeFunding(price);
address sender = messageSender;
_modifyMargin(marginDelta, price, fundingIndex, sender);
_transferMargin(marginDelta, price, fundingIndex, sender);
_submitOrder(leverage, price, [minPrice, maxPrice], fundingIndex, sender);
}

function modifyMarginAndSubmitOrder(int marginDelta, int leverage) external optionalProxy {
modifyMarginAndSubmitOrderWithPriceBounds(marginDelta, leverage, 0, uint(-1));
function transferMarginAndSubmitOrder(int marginDelta, int leverage) external optionalProxy {
transferMarginAndSubmitOrderWithPriceBounds(marginDelta, leverage, 0, uint(-1));
}

function confirmOrder(address account) external optionalProxy {
Expand Down Expand Up @@ -1013,13 +1030,15 @@ contract FuturesMarket is Owned, Proxyable, MixinFuturesMarketSettings, IFutures
delete position.size;
delete position.lastPrice;
delete position.fundingIndex;
emitPositionModified(account, margin, 0, 0, 0);
} else {
position.size = newSize;
position.lastPrice = price;
position.fundingIndex = fundingIndex;
emitPositionModified(account, margin, newSize, price, fundingIndex);
}
Order storage order = orders[account];
emitOrderConfirmed(order.id, account, margin, newSize, price, fundingIndex);
emitOrderConfirmed(order.id, account, price);
delete orders[account];
}

Expand Down Expand Up @@ -1057,7 +1076,8 @@ contract FuturesMarket is Owned, Proxyable, MixinFuturesMarketSettings, IFutures
// Issue the reward to the liquidator.
_manager().issueSUSD(liquidator, liquidationFee);

emitPositionLiquidated(account, liquidator, positionSize, lPrice);
emitPositionModified(account, 0, 0, 0, 0);
emitPositionLiquidated(account, liquidator, positionSize, lPrice, liquidationFee);
}

function liquidatePosition(address account) external optionalProxy {
Expand All @@ -1081,11 +1101,11 @@ contract FuturesMarket is Owned, Proxyable, MixinFuturesMarketSettings, IFutures
return bytes32(uint256(uint160(input)));
}

event ParameterUpdated(bytes32 indexed parameter, uint value);
bytes32 internal constant SIG_PARAMETERUPDATED = keccak256("ParameterUpdated(bytes32,uint256)");
event MarginTransferred(address indexed account, int marginDelta);
bytes32 internal constant SIG_MARGINTRANSFERRED = keccak256("MarginTransferred(address,int256)");

function emitParameterUpdated(bytes32 parameter, uint value) internal {
proxy._emit(abi.encode(value), 2, SIG_PARAMETERUPDATED, parameter, 0, 0);
function emitMarginTransferred(address account, int marginDelta) internal {
proxy._emit(abi.encode(marginDelta), 2, SIG_MARGINTRANSFERRED, addressToBytes32(account), 0, 0);
}

event OrderSubmitted(
Expand Down Expand Up @@ -1119,26 +1139,15 @@ contract FuturesMarket is Owned, Proxyable, MixinFuturesMarketSettings, IFutures
);
}

event OrderConfirmed(uint indexed id, address indexed account, uint margin, int size, uint price, uint fundingIndex);
bytes32 internal constant SIG_ORDERCONFIRMED =
keccak256("OrderConfirmed(uint256,address,uint256,int256,uint256,uint256)");
event OrderConfirmed(uint indexed id, address indexed account, uint price);
bytes32 internal constant SIG_ORDERCONFIRMED = keccak256("OrderConfirmed(uint256,address,uint256)");

function emitOrderConfirmed(
uint id,
address account,
uint margin,
int size,
uint price,
uint fundingIndex
uint price
) internal {
proxy._emit(
abi.encode(margin, size, price, fundingIndex),
3,
SIG_ORDERCONFIRMED,
bytes32(id),
addressToBytes32(account),
0
);
proxy._emit(abi.encode(price), 3, SIG_ORDERCONFIRMED, bytes32(id), addressToBytes32(account), 0);
}

event OrderCancelled(uint indexed id, address indexed account);
Expand All @@ -1148,22 +1157,51 @@ contract FuturesMarket is Owned, Proxyable, MixinFuturesMarketSettings, IFutures
proxy._emit(abi.encode(), 3, SIG_ORDERCANCELLED, bytes32(id), addressToBytes32(account), 0);
}

event PositionLiquidated(address indexed account, address indexed liquidator, int size, uint price);
bytes32 internal constant SIG_POSITIONLIQUIDATED = keccak256("PositionLiquidated(address,address,int256,uint256)");
event PositionModified(address indexed account, uint margin, int size, uint lastPrice, uint fundingIndex);
bytes32 internal constant SIG_POSITIONMODIFIED = keccak256("PositionModified(address,uint256,int256,uint256,uint256)");

function emitPositionModified(
address account,
uint margin,
int size,
uint lastPrice,
uint fundingIndex
) internal {
proxy._emit(
abi.encode(margin, size, lastPrice, fundingIndex),
2,
SIG_POSITIONMODIFIED,
addressToBytes32(account),
0,
0
);
}

event PositionLiquidated(address indexed account, address indexed liquidator, int size, uint price, uint fee);
bytes32 internal constant SIG_POSITIONLIQUIDATED =
keccak256("PositionLiquidated(address,address,int256,uint256,uint256)");

function emitPositionLiquidated(
address account,
address liquidator,
int size,
uint price
uint price,
uint fee
) internal {
proxy._emit(
abi.encode(size, price),
abi.encode(size, price, fee),
3,
SIG_POSITIONLIQUIDATED,
addressToBytes32(account),
addressToBytes32(liquidator),
0
);
}

event FundingRecomputed(int funding);
bytes32 internal constant SIG_FUNDINGRECOMPUTED = keccak256("FundingRecomputed(int256)");

function emitFundingRecomputed(int funding) internal {
proxy._emit(abi.encode(funding), 1, SIG_FUNDINGRECOMPUTED, 0, 0, 0);
}
}
6 changes: 3 additions & 3 deletions contracts/interfaces/IFuturesMarket.sol
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ interface IFuturesMarket {

function recomputeFunding() external returns (uint lastIndex);

function modifyMargin(int marginDelta) external;
function transferMargin(int marginDelta) external;

function withdrawAllMargin() external;

Expand All @@ -161,14 +161,14 @@ interface IFuturesMarket {

function closePosition() external;

function modifyMarginAndSubmitOrderWithPriceBounds(
function transferMarginAndSubmitOrderWithPriceBounds(
int marginDelta,
int leverage,
uint minPrice,
uint maxPrice
) external;

function modifyMarginAndSubmitOrder(int marginDelta, int leverage) external;
function transferMarginAndSubmitOrder(int marginDelta, int leverage) external;

function confirmOrder(address account) external;

Expand Down
Loading