-
Notifications
You must be signed in to change notification settings - Fork 2
/
LibSettlement.sol
118 lines (108 loc) · 5.06 KB
/
LibSettlement.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// SPDX-License-Identifier: SYMM-Core-Business-Source-License-1.1
// This contract is licensed under the SYMM Core Business Source License 1.1
// Copyright (c) 2023 Symmetry Labs AG
// For more information, see https://docs.symm.io/legal-disclaimer/license
pragma solidity >=0.8.18;
import "../storages/MAStorage.sol";
import "../storages/MuonStorage.sol";
import "../storages/AccountStorage.sol";
import "./LibQuote.sol";
import "./LibAccount.sol";
import "hardhat/console.sol";
library LibSettlement {
function settleUpnl(
SettlementSig memory settleSig,
uint256[] memory updatedPrices,
address partyA,
bool isForceClose
) internal returns (uint256[] memory newPartyBsAllocatedBalances) {
QuoteStorage.Layout storage quoteLayout = QuoteStorage.layout();
AccountStorage.Layout storage accountLayout = AccountStorage.layout();
require(settleSig.quotesSettlementsData.length == updatedPrices.length, "LibSettlement: Invalid length");
require(
LibAccount.partyAAvailableBalanceForLiquidation(settleSig.upnlPartyA, accountLayout.allocatedBalances[partyA], partyA) >= 0,
"LibSettlement: PartyA is insolvent"
);
require(
isForceClose || quoteLayout.partyBOpenPositions[msg.sender][partyA].length > 0,
"LibSettlement: Sender should have a position with partyA"
);
accountLayout.partyANonces[partyA] += 1;
int256[] memory settleAmounts = new int256[](settleSig.upnlPartyBs.length);
address[] memory partyBs = new address[](settleSig.upnlPartyBs.length);
newPartyBsAllocatedBalances = new uint256[](settleSig.upnlPartyBs.length);
for (uint8 i = 0; i < settleSig.quotesSettlementsData.length; i++) {
QuoteSettlementData memory data = settleSig.quotesSettlementsData[i];
Quote storage quote = quoteLayout.quotes[data.quoteId];
require(quote.partyA == partyA, "LibSettlement: PartyA is invalid");
require(
quote.quoteStatus == QuoteStatus.OPENED ||
quote.quoteStatus == QuoteStatus.CLOSE_PENDING ||
quote.quoteStatus == QuoteStatus.CANCEL_CLOSE_PENDING,
"LibSettlement: Invalid state"
);
require(data.partyBUpnlIndex <= settleSig.upnlPartyBs.length, "LibSettlement: Invalid partyBUpnlIndex in signature");
require(
partyBs[data.partyBUpnlIndex] == address(0) || partyBs[data.partyBUpnlIndex] == quote.partyB,
"LibSettlement: Invalid upnlPartyBs list"
);
partyBs[data.partyBUpnlIndex] = quote.partyB;
if (quote.openedPrice > data.currentPrice) {
require(
updatedPrices[i] < quote.openedPrice && updatedPrices[i] >= data.currentPrice,
"LibSettlement: Updated price is out of range"
);
} else {
require(
updatedPrices[i] > quote.openedPrice && updatedPrices[i] <= data.currentPrice,
"LibSettlement: Updated price is out of range"
);
}
if (quote.positionType == PositionType.LONG) {
settleAmounts[data.partyBUpnlIndex] +=
((int256(updatedPrices[i]) - int256(quote.openedPrice)) * int256(LibQuote.quoteOpenAmount(quote))) /
1e18;
} else {
settleAmounts[data.partyBUpnlIndex] +=
((int256(quote.openedPrice) - int256(updatedPrices[i])) * int256(LibQuote.quoteOpenAmount(quote))) /
1e18;
}
quote.openedPrice = updatedPrices[i];
}
int256 totalSettlementAmount;
for (uint8 i = 0; i < partyBs.length; i++) {
address partyB = partyBs[i];
require(
LibAccount.partyBAvailableBalanceForLiquidation(settleSig.upnlPartyBs[i], partyB, partyA) >= 0,
"LibSettlement: PartyB should be solvent"
);
require(!MAStorage.layout().partyBLiquidationStatus[partyB][partyA], "LibSettlement: PartyB is in liquidation process");
if (!isForceClose && msg.sender != partyB) {
require(
block.timestamp >=
MAStorage.layout().lastUpnlSettlementTimestamp[msg.sender][partyB][partyA] + MAStorage.layout().settlementCooldown,
"LibSettlement: Cooldown should be passed"
);
MAStorage.layout().lastUpnlSettlementTimestamp[msg.sender][partyB][partyA] = block.timestamp;
}
accountLayout.partyBNonces[partyB][partyA] += 1;
int256 settlementAmount = settleAmounts[i];
totalSettlementAmount += settlementAmount;
if (settlementAmount >= 0) {
accountLayout.partyBAllocatedBalances[partyB][partyA] -= uint256(settlementAmount);
emit SharedEvents.BalanceChangePartyB(partyB, partyA, uint256(settlementAmount), SharedEvents.BalanceChangeType.REALIZED_PNL_OUT);
} else {
accountLayout.partyBAllocatedBalances[partyB][partyA] += uint256(-settlementAmount);
emit SharedEvents.BalanceChangePartyB(partyB, partyA, uint256(-settlementAmount), SharedEvents.BalanceChangeType.REALIZED_PNL_IN);
}
newPartyBsAllocatedBalances[i] = accountLayout.partyBAllocatedBalances[partyB][partyA];
}
if (totalSettlementAmount >= 0) {
accountLayout.allocatedBalances[partyA] += uint256(totalSettlementAmount);
emit SharedEvents.BalanceChangePartyA(partyA, uint256(totalSettlementAmount), SharedEvents.BalanceChangeType.REALIZED_PNL_IN);
} else {
accountLayout.allocatedBalances[partyA] -= uint256(-totalSettlementAmount);
emit SharedEvents.BalanceChangePartyA(partyA, uint256(-totalSettlementAmount), SharedEvents.BalanceChangeType.REALIZED_PNL_OUT);
}
}
}