forked from Synthetixio/synthetix
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDebtCache.sol
153 lines (121 loc) · 5.87 KB
/
DebtCache.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
pragma solidity ^0.5.16;
// Libraries
import "./SafeDecimalMath.sol";
// Inheritance
import "./BaseDebtCache.sol";
// https://docs.synthetix.io/contracts/source/contracts/debtcache
contract DebtCache is BaseDebtCache {
using SafeDecimalMath for uint;
bytes32 public constant CONTRACT_NAME = "DebtCache";
constructor(address _owner, address _resolver) public BaseDebtCache(_owner, _resolver) {}
bytes32 internal constant EXCLUDED_DEBT_KEY = "EXCLUDED_DEBT";
bytes32 internal constant FUTURES_DEBT_KEY = "FUTURES_DEBT";
/* ========== MUTATIVE FUNCTIONS ========== */
// This function exists in case a synth is ever somehow removed without its snapshot being updated.
function purgeCachedSynthDebt(bytes32 currencyKey) external onlyOwner {
require(issuer().synths(currencyKey) == ISynth(0), "Synth exists");
delete _cachedSynthDebt[currencyKey];
}
function takeDebtSnapshot() external requireSystemActiveIfNotOwner {
bytes32[] memory currencyKeys = issuer().availableCurrencyKeys();
(uint[] memory values, uint futuresDebt, uint excludedDebt, bool isInvalid) = _currentSynthDebts(currencyKeys);
// The total SNX-backed debt is the debt of futures markets plus the debt of circulating synths.
uint snxCollateralDebt = futuresDebt;
_cachedSynthDebt[FUTURES_DEBT_KEY] = futuresDebt;
uint numValues = values.length;
for (uint i; i < numValues; i++) {
uint value = values[i];
snxCollateralDebt = snxCollateralDebt.add(value);
_cachedSynthDebt[currencyKeys[i]] = value;
}
// Subtract out the excluded non-SNX backed debt from our total
_cachedSynthDebt[EXCLUDED_DEBT_KEY] = excludedDebt;
uint newDebt = snxCollateralDebt.floorsub(excludedDebt);
_cachedDebt = newDebt;
_cacheTimestamp = block.timestamp;
emit DebtCacheUpdated(newDebt);
emit DebtCacheSnapshotTaken(block.timestamp);
// (in)validate the cache if necessary
_updateDebtCacheValidity(isInvalid);
}
function updateCachedSynthDebts(bytes32[] calldata currencyKeys) external requireSystemActiveIfNotOwner {
(uint[] memory rates, bool anyRateInvalid) = exchangeRates().ratesAndInvalidForCurrencies(currencyKeys);
_updateCachedSynthDebtsWithRates(currencyKeys, rates, anyRateInvalid);
}
function updateCachedSynthDebtWithRate(bytes32 currencyKey, uint currencyRate) external onlyIssuer {
bytes32[] memory synthKeyArray = new bytes32[](1);
synthKeyArray[0] = currencyKey;
uint[] memory synthRateArray = new uint[](1);
synthRateArray[0] = currencyRate;
_updateCachedSynthDebtsWithRates(synthKeyArray, synthRateArray, false);
}
function updateCachedSynthDebtsWithRates(bytes32[] calldata currencyKeys, uint[] calldata currencyRates)
external
onlyIssuerOrExchanger
{
_updateCachedSynthDebtsWithRates(currencyKeys, currencyRates, false);
}
function updateDebtCacheValidity(bool currentlyInvalid) external onlyIssuer {
_updateDebtCacheValidity(currentlyInvalid);
}
function recordExcludedDebtChange(bytes32 currencyKey, int256 delta) external onlyDebtIssuer {
int256 newExcludedDebt = int256(_excludedIssuedDebt[currencyKey]) + delta;
require(newExcludedDebt >= 0, "Excluded debt cannot become negative");
_excludedIssuedDebt[currencyKey] = uint(newExcludedDebt);
}
function updateCachedsUSDDebt(int amount) external onlyIssuer {
uint delta = SafeDecimalMath.abs(amount);
if (amount > 0) {
_cachedSynthDebt[sUSD] = _cachedSynthDebt[sUSD].add(delta);
_cachedDebt = _cachedDebt.add(delta);
} else {
_cachedSynthDebt[sUSD] = _cachedSynthDebt[sUSD].sub(delta);
_cachedDebt = _cachedDebt.sub(delta);
}
emit DebtCacheUpdated(_cachedDebt);
}
/* ========== INTERNAL FUNCTIONS ========== */
function _updateDebtCacheValidity(bool currentlyInvalid) internal {
if (_cacheInvalid != currentlyInvalid) {
_cacheInvalid = currentlyInvalid;
emit DebtCacheValidityChanged(currentlyInvalid);
}
}
// Updated the global debt according to a rate/supply change in a subset of issued synths.
function _updateCachedSynthDebtsWithRates(
bytes32[] memory currencyKeys,
uint[] memory currentRates,
bool anyRateIsInvalid
) internal {
uint numKeys = currencyKeys.length;
require(numKeys == currentRates.length, "Input array lengths differ");
// Compute the cached and current debt sum for the subset of synths provided.
uint cachedSum;
uint currentSum;
uint[] memory currentValues = _issuedSynthValues(currencyKeys, currentRates);
for (uint i = 0; i < numKeys; i++) {
bytes32 key = currencyKeys[i];
uint currentSynthDebt = currentValues[i];
cachedSum = cachedSum.add(_cachedSynthDebt[key]);
currentSum = currentSum.add(currentSynthDebt);
_cachedSynthDebt[key] = currentSynthDebt;
}
// Apply the debt update.
if (cachedSum != currentSum) {
uint debt = _cachedDebt;
// apply the delta between the cachedSum and currentSum
// add currentSum before sub cachedSum to prevent overflow as cachedSum > debt for large amount of excluded debt
debt = debt.add(currentSum).sub(cachedSum);
_cachedDebt = debt;
emit DebtCacheUpdated(debt);
}
// Invalidate the cache if necessary
if (anyRateIsInvalid) {
_updateDebtCacheValidity(anyRateIsInvalid);
}
}
/* ========== EVENTS ========== */
event DebtCacheUpdated(uint cachedDebt);
event DebtCacheSnapshotTaken(uint timestamp);
event DebtCacheValidityChanged(bool indexed isInvalid);
}