-
Notifications
You must be signed in to change notification settings - Fork 2
/
MErc20DelegateFixer.sol
136 lines (105 loc) · 4.93 KB
/
MErc20DelegateFixer.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
pragma solidity 0.5.17;
import "./MErc20Delegate.sol";
import "./SafeMath.sol";
//// @title MErc20DelegateMadFixer contract
contract MErc20DelegateFixer is MErc20Delegate {
/// @notice bad debt counter
uint256 public badDebt;
/// @notice user fixed event (user, liquidator, amount)
event UserFixed(address, address, uint256);
/// @notice bad debt repayed event (amount)
event BadDebtRepayed(uint256);
/// @notice bad debt repayed with reserves
event BadDebtRepayedWithReserves(
uint256 badDebt,
uint256 previousBadDebt,
uint256 reserves,
uint256 previousReserves
);
/// @notice repay bad debt with cash, can only reduce the bad debt
/// @param amount the amount of bad debt to repay
/// invariant, calling this function can only reduce the bad debt
/// it cannot increase it, which is what would happen on an underflow
/// this function cannot change the share price of the mToken
function repayBadDebtWithCash(uint256 amount) external nonReentrant {
/// Checks and Effects
badDebt = SafeMath.sub(badDebt, amount, "amount exceeds bad debt");
EIP20Interface token = EIP20Interface(underlying);
/// Interactions
require(
token.transferFrom(msg.sender, address(this), amount),
"transfer in failed"
);
emit BadDebtRepayed(amount);
}
/// @notice function can only decrease bad debt and reserves
/// if this function is called, both bad debt and reserves will be decreased
/// calling this function cannot change the share price
/// both bad debt and reserves will decrement by the same amount
function repayBadDebtWithReserves() external nonReentrant {
uint256 currentReserves = totalReserves;
uint256 currentBadDebt = badDebt;
require(currentReserves != 0, "reserves are zero");
require(currentBadDebt != 0, "bad debt is zero");
/// no reverts possible past this point
/// take the lesser of the two, subtract it from both numbers
uint256 subtractAmount = currentBadDebt < currentReserves
? currentBadDebt
: currentReserves;
/// bad debt -= subtract amount
badDebt = SafeMath.sub(currentBadDebt, subtractAmount);
/// current reserves -= subtract amount
totalReserves = SafeMath.sub(currentReserves, subtractAmount);
emit BadDebtRepayedWithReserves(
badDebt,
currentBadDebt,
totalReserves,
currentReserves
);
}
/// @notice fix a user
/// @param liquidator the account to transfer the tokens to
/// @param user the account with bad debt
/// invariant, this can only reduce or keep user and total debt the same
/// liquidator will never be the same as user, only governance can call this function
/// assumes governance is non malicious, and that all users liquidated have active borrows
function fixUser(address liquidator, address user) external {
/// @dev check user is admin
require(msg.sender == admin, "only the admin may call fixUser");
/// ensure nothing strange can happen with incorrect liquidator
require(liquidator != user, "liquidator cannot be user");
require(accrueInterest() == 0, "accrue interest failed");
/// @dev fetch user's current borrow balance, first updating interest index
uint256 principal = borrowBalanceStored(user);
require(principal != 0, "cannot liquidate user without borrows");
/// user effects
/// @dev zero balance
accountBorrows[user].principal = 0;
accountBorrows[user].interestIndex = borrowIndex;
/// @dev current amount for a user that we'll transfer to the liquidator
uint256 liquidated = accountTokens[user];
/// can only seize collateral assets if they exist
if (liquidated != 0) {
/// if assets were liquidated, give them to the liquidator
accountTokens[liquidator] = SafeMath.add(
accountTokens[liquidator],
liquidated
);
/// zero out the user's tokens
delete accountTokens[user];
}
/// global effects
/// @dev increment the bad debt counter
badDebt = SafeMath.add(badDebt, principal);
/// @dev subtract the previous balance from the totalBorrows balance
totalBorrows = SafeMath.sub(totalBorrows, principal);
emit UserFixed(user, liquidator, liquidated);
}
/// @notice get cash for the market, including bad debt in this calculation
/// bad debt must be included in order to maintain the market share price
function getCashPrior() internal view returns (uint256) {
/// safe math unused intentionally, should never overflow as the sum
/// should never be greater than UINT_MAX
return EIP20Interface(underlying).balanceOf(address(this)) + badDebt;
}
}