-
Notifications
You must be signed in to change notification settings - Fork 12
/
DharmaDaiImplementationV1.sol
186 lines (162 loc) · 6.74 KB
/
DharmaDaiImplementationV1.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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
pragma solidity 0.5.11;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "./DharmaTokenV1.sol";
import "../../interfaces/CTokenInterface.sol";
import "../../interfaces/ERC20Interface.sol";
import "../../interfaces/CDaiInterestRateModelInterface.sol";
import "../../interfaces/PotInterface.sol";
/**
* @title DharmaDaiImplementationV1
* @author 0age (dToken mechanics derived from Compound cTokens, ERC20 methods
* derived from Open Zeppelin's ERC20 contract)
* @notice This contract provides the V1 implementation of Dharma Dai (or dDai),
* an upgradeable, interest-bearing ERC20 token with cDai as the backing token
* and Dai as the underlying token. The V1 dDai exchange rate will grow at 90%
* the rate of the backing cDai exchange rate. Dharma Dai also supports
* meta-transactions originating from externally-owned accounts, as well as from
* contract accounts via ERC-1271.
*/
contract DharmaDaiImplementationV1 is DharmaTokenV1 {
string internal constant _NAME = "Dharma Dai";
string internal constant _SYMBOL = "dDai";
string internal constant _UNDERLYING_NAME = "Dai";
string internal constant _CTOKEN_SYMBOL = "cDai";
CTokenInterface internal constant _CDAI = CTokenInterface(
0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643 // mainnet
);
ERC20Interface internal constant _DAI = ERC20Interface(
0x6B175474E89094C44Da98b954EedeAC495271d0F // mainnet
);
PotInterface internal constant _POT = PotInterface(
0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7 // mainnet
);
address internal constant _VAULT = 0x7e4A8391C728fEd9069B2962699AB416628B19Fa;
/**
* @notice Internal view function to get the current cDai exchange rate and
* supply rate per block.
* @return The current cDai exchange rate, or amount of Dai that is redeemable
* for each cDai, and the cDai supply rate per block (with 18 decimal places
* added to each returned rate).
*/
function _getCurrentCTokenRates() internal view returns (
uint256 exchangeRate, uint256 supplyRate
) {
// Determine the number of blocks that have elapsed since last cDai accrual.
uint256 blockDelta = block.number.sub(_CDAI.accrualBlockNumber());
// Return stored values if accrual has already been performed this block.
if (blockDelta == 0) return (
_CDAI.exchangeRateStored(), _CDAI.supplyRatePerBlock()
);
// Determine total "cash" held by cDai contract by calculating DSR interest.
uint256 cash = ( // solhint-disable-next-line not-rely-on-time
_rpow(_POT.dsr(), now.sub(_POT.rho()), 1e27).mul(_POT.chi()) / 1e27 // chi
).mul(_POT.pie(address(_CDAI))) / 1e27;
// Get the latest interest rate model from the cDai contract.
CDaiInterestRateModelInterface interestRateModel = (
CDaiInterestRateModelInterface(_CDAI.interestRateModel())
);
// Get the current stored total borrows, reserves, and reserve factor.
uint256 borrows = _CDAI.totalBorrows();
uint256 reserves = _CDAI.totalReserves();
uint256 reserveFactor = _CDAI.reserveFactorMantissa();
// Get accumulated borrow interest via interest rate model and block delta.
uint256 interest = interestRateModel.getBorrowRate(
cash, borrows, reserves
).mul(blockDelta).mul(borrows) / _SCALING_FACTOR;
// Update total borrows and reserves using calculated accumulated interest.
borrows = borrows.add(interest);
reserves = reserves.add(reserveFactor.mul(interest) / _SCALING_FACTOR);
// Determine cDai exchange rate: (cash + borrows - reserves) / total supply
exchangeRate = (
((cash.add(borrows)).sub(reserves)).mul(_SCALING_FACTOR)
).div(_CDAI.totalSupply());
// Get supply rate via interest rate model and calculated parameters.
supplyRate = interestRateModel.getSupplyRate(
cash, borrows, reserves, reserveFactor
);
}
/**
* @notice Internal pure function to supply the name of the underlying token.
* @return The name of the underlying token.
*/
function _getUnderlyingName() internal pure returns (string memory underlyingName) {
underlyingName = _UNDERLYING_NAME;
}
/**
* @notice Internal pure function to supply the address of the underlying
* token.
* @return The address of the underlying token.
*/
function _getUnderlying() internal pure returns (address underlying) {
underlying = address(_DAI);
}
/**
* @notice Internal pure function to supply the symbol of the backing cToken.
* @return The symbol of the backing cToken.
*/
function _getCTokenSymbol() internal pure returns (string memory cTokenSymbol) {
cTokenSymbol = _CTOKEN_SYMBOL;
}
/**
* @notice Internal pure function to supply the address of the backing cToken.
* @return The address of the backing cToken.
*/
function _getCToken() internal pure returns (address cToken) {
cToken = address(_CDAI);
}
/**
* @notice Internal pure function to supply the name of the dToken.
* @return The name of the dToken.
*/
function _getDTokenName() internal pure returns (string memory dTokenName) {
dTokenName = _NAME;
}
/**
* @notice Internal pure function to supply the symbol of the dToken.
* @return The symbol of the dToken.
*/
function _getDTokenSymbol() internal pure returns (string memory dTokenSymbol) {
dTokenSymbol = _SYMBOL;
}
/**
* @notice Internal pure function to supply the address of the vault that
* receives surplus cTokens whenever the surplus is pulled.
* @return The address of the vault.
*/
function _getVault() internal pure returns (address vault) {
vault = _VAULT;
}
/**
* @notice Internal pure function to directly emulate exponentiation performed
* by the Dai Savings Rate contract.
* @param x uint256 The number that will be raised to the given power.
* @param n uint256 The power to raise that number by.
* @param base uint256 The scaling factor that will be applied to n and z.
* @return The number raised to the given power.
*/
function _rpow(
uint256 x, uint256 n, uint256 base
) internal pure returns (uint256 z) {
assembly {
switch x case 0 {switch n case 0 {z := base} default {z := 0}}
default {
switch mod(n, 2) case 0 { z := base } default { z := x }
let half := div(base, 2) // for rounding.
for { n := div(n, 2) } n { n := div(n, 2) } {
let xx := mul(x, x)
if iszero(eq(div(xx, x), x)) { revert(0, 0) }
let xxRound := add(xx, half)
if lt(xxRound, xx) { revert(0, 0) }
x := div(xxRound, base)
if mod(n, 2) {
let zx := mul(z, x)
if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) }
let zxRound := add(zx, half)
if lt(zxRound, zx) { revert(0, 0) }
z := div(zxRound, base)
}
}
}
}
}
}