forked from Synthetixio/synthetix
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFeePoolState.sol
160 lines (133 loc) · 6.46 KB
/
FeePoolState.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
154
155
156
157
158
159
160
pragma solidity ^0.5.16;
// Inheritance
import "./Owned.sol";
import "./LimitedSetup.sol";
// Libraries
import "./SafeDecimalMath.sol";
// Internal references
import "./interfaces/IFeePool.sol";
// https://docs.synthetix.io/contracts/source/contracts/feepoolstate
contract FeePoolState is Owned, LimitedSetup {
using SafeMath for uint;
using SafeDecimalMath for uint;
/* ========== STATE VARIABLES ========== */
uint8 public constant FEE_PERIOD_LENGTH = 6;
address public feePool;
// The IssuanceData activity that's happened in a fee period.
struct IssuanceData {
uint debtPercentage;
uint debtEntryIndex;
}
// The IssuanceData activity that's happened in a fee period.
mapping(address => IssuanceData[FEE_PERIOD_LENGTH]) public accountIssuanceLedger;
constructor(address _owner, IFeePool _feePool) public Owned(_owner) LimitedSetup(6 weeks) {
feePool = address(_feePool);
}
/* ========== SETTERS ========== */
/**
* @notice set the FeePool contract as it is the only authority to be able to call
* appendAccountIssuanceRecord with the onlyFeePool modifer
* @dev Must be set by owner when FeePool logic is upgraded
*/
function setFeePool(IFeePool _feePool) external onlyOwner {
feePool = address(_feePool);
}
/* ========== VIEWS ========== */
/**
* @notice Get an accounts issuanceData for
* @param account users account
* @param index Index in the array to retrieve. Upto FEE_PERIOD_LENGTH
*/
function getAccountsDebtEntry(address account, uint index)
public
view
returns (uint debtPercentage, uint debtEntryIndex)
{
require(index < FEE_PERIOD_LENGTH, "index exceeds the FEE_PERIOD_LENGTH");
debtPercentage = accountIssuanceLedger[account][index].debtPercentage;
debtEntryIndex = accountIssuanceLedger[account][index].debtEntryIndex;
}
/**
* @notice Find the oldest debtEntryIndex for the corresponding closingDebtIndex
* @param account users account
* @param closingDebtIndex the last periods debt index on close
*/
function applicableIssuanceData(address account, uint closingDebtIndex) external view returns (uint, uint) {
IssuanceData[FEE_PERIOD_LENGTH] memory issuanceData = accountIssuanceLedger[account];
// We want to use the user's debtEntryIndex at when the period closed
// Find the oldest debtEntryIndex for the corresponding closingDebtIndex
for (uint i = 0; i < FEE_PERIOD_LENGTH; i++) {
if (closingDebtIndex >= issuanceData[i].debtEntryIndex) {
return (issuanceData[i].debtPercentage, issuanceData[i].debtEntryIndex);
}
}
}
/* ========== MUTATIVE FUNCTIONS ========== */
/**
* @notice Logs an accounts issuance data in the current fee period which is then stored historically
* @param account Message.Senders account address
* @param debtRatio Debt of this account as a percentage of the global debt.
* @param debtEntryIndex The index in the global debt ledger. synthetix.synthetixState().issuanceData(account)
* @param currentPeriodStartDebtIndex The startingDebtIndex of the current fee period
* @dev onlyFeePool to call me on synthetix.issue() & synthetix.burn() calls to store the locked SNX
* per fee period so we know to allocate the correct proportions of fees and rewards per period
accountIssuanceLedger[account][0] has the latest locked amount for the current period. This can be update as many time
accountIssuanceLedger[account][1-2] has the last locked amount for a previous period they minted or burned
*/
function appendAccountIssuanceRecord(
address account,
uint debtRatio,
uint debtEntryIndex,
uint currentPeriodStartDebtIndex
) external onlyFeePool {
// Is the current debtEntryIndex within this fee period
if (accountIssuanceLedger[account][0].debtEntryIndex < currentPeriodStartDebtIndex) {
// If its older then shift the previous IssuanceData entries periods down to make room for the new one.
issuanceDataIndexOrder(account);
}
// Always store the latest IssuanceData entry at [0]
accountIssuanceLedger[account][0].debtPercentage = debtRatio;
accountIssuanceLedger[account][0].debtEntryIndex = debtEntryIndex;
}
/**
* @notice Pushes down the entire array of debt ratios per fee period
*/
function issuanceDataIndexOrder(address account) private {
for (uint i = FEE_PERIOD_LENGTH - 2; i < FEE_PERIOD_LENGTH; i--) {
uint next = i + 1;
accountIssuanceLedger[account][next].debtPercentage = accountIssuanceLedger[account][i].debtPercentage;
accountIssuanceLedger[account][next].debtEntryIndex = accountIssuanceLedger[account][i].debtEntryIndex;
}
}
/**
* @notice Import issuer data from synthetixState.issuerData on FeePeriodClose() block #
* @dev Only callable by the contract owner, and only for 6 weeks after deployment.
* @param accounts Array of issuing addresses
* @param ratios Array of debt ratios
* @param periodToInsert The Fee Period to insert the historical records into
* @param feePeriodCloseIndex An accounts debtEntryIndex is valid when within the fee peroid,
* since the input ratio will be an average of the pervious periods it just needs to be
* > recentFeePeriods[periodToInsert].startingDebtIndex
* < recentFeePeriods[periodToInsert - 1].startingDebtIndex
*/
function importIssuerData(
address[] calldata accounts,
uint[] calldata ratios,
uint periodToInsert,
uint feePeriodCloseIndex
) external onlyOwner onlyDuringSetup {
require(accounts.length == ratios.length, "Length mismatch");
for (uint i = 0; i < accounts.length; i++) {
accountIssuanceLedger[accounts[i]][periodToInsert].debtPercentage = ratios[i];
accountIssuanceLedger[accounts[i]][periodToInsert].debtEntryIndex = feePeriodCloseIndex;
emit IssuanceDebtRatioEntry(accounts[i], ratios[i], feePeriodCloseIndex);
}
}
/* ========== MODIFIERS ========== */
modifier onlyFeePool {
require(msg.sender == address(feePool), "Only the FeePool contract can perform this action");
_;
}
/* ========== Events ========== */
event IssuanceDebtRatioEntry(address indexed account, uint debtRatio, uint feePeriodCloseIndex);
}