|
| 1 | +pragma solidity ^0.5.12; |
| 2 | + |
| 3 | +import "./CErc20Delegate.sol"; |
| 4 | + |
| 5 | +/** |
| 6 | + * @title Compound's CDai Contract |
| 7 | + * @notice CToken which wraps Multi-Collateral DAI |
| 8 | + * @author Compound |
| 9 | + */ |
| 10 | +contract CDaiDelegate is CErc20Delegate { |
| 11 | + /** |
| 12 | + * @notice DAI adapter address |
| 13 | + */ |
| 14 | + address public daiJoinAddress; |
| 15 | + |
| 16 | + /** |
| 17 | + * @notice DAI Savings Rate (DSR) pot address |
| 18 | + */ |
| 19 | + address public potAddress; |
| 20 | + |
| 21 | + /** |
| 22 | + * @notice DAI vat address |
| 23 | + */ |
| 24 | + address public vatAddress; |
| 25 | + |
| 26 | + /** |
| 27 | + * @notice Delegate interface to become the implementation |
| 28 | + * @param data The encoded arguments for becoming |
| 29 | + */ |
| 30 | + function _becomeImplementation(bytes memory data) public { |
| 31 | + require(msg.sender == admin, "only the admin may initialize the implementation"); |
| 32 | + |
| 33 | + (address daiJoinAddress_, address potAddress_) = abi.decode(data, (address, address)); |
| 34 | + return _becomeImplementation(daiJoinAddress_, potAddress_); |
| 35 | + } |
| 36 | + |
| 37 | + /** |
| 38 | + * @notice Explicit interface to become the implementation |
| 39 | + * @param daiJoinAddress_ DAI adapter address |
| 40 | + * @param potAddress_ DAI Savings Rate (DSR) pot address |
| 41 | + */ |
| 42 | + function _becomeImplementation(address daiJoinAddress_, address potAddress_) internal { |
| 43 | + // Get dai and vat and sanity check the underlying |
| 44 | + DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress_); |
| 45 | + PotLike pot = PotLike(potAddress_); |
| 46 | + GemLike dai = daiJoin.dai(); |
| 47 | + VatLike vat = daiJoin.vat(); |
| 48 | + require(address(dai) == underlying, "DAI must be the same as underlying"); |
| 49 | + |
| 50 | + // Remember the relevant addresses |
| 51 | + daiJoinAddress = daiJoinAddress_; |
| 52 | + potAddress = potAddress_; |
| 53 | + vatAddress = address(vat); |
| 54 | + |
| 55 | + // Approve moving our DAI into the vat through daiJoin |
| 56 | + dai.approve(daiJoinAddress, uint(-1)); |
| 57 | + |
| 58 | + // Approve the pot to transfer our funds within the vat |
| 59 | + vat.hope(potAddress); |
| 60 | + vat.hope(daiJoinAddress); |
| 61 | + |
| 62 | + // Accumulate DSR interest -- must do this in order to doTransferIn |
| 63 | + pot.drip(); |
| 64 | + |
| 65 | + // Transfer all cash in (doTransferIn does this regardless of amount) |
| 66 | + doTransferIn(address(this), 0); |
| 67 | + } |
| 68 | + |
| 69 | + /** |
| 70 | + * @notice Delegate interface to resign the implementation |
| 71 | + */ |
| 72 | + function _resignImplementation() public { |
| 73 | + require(msg.sender == admin, "only the admin may abandon the implementation"); |
| 74 | + |
| 75 | + // Transfer all cash out of the DSR - note that this relies on self-transfer |
| 76 | + DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress); |
| 77 | + PotLike pot = PotLike(potAddress); |
| 78 | + VatLike vat = VatLike(vatAddress); |
| 79 | + |
| 80 | + // Accumulate interest |
| 81 | + pot.drip(); |
| 82 | + |
| 83 | + // Calculate the total amount in the pot, and move it out |
| 84 | + uint pie = pot.pie(address(this)); |
| 85 | + pot.exit(pie); |
| 86 | + |
| 87 | + // Checks the actual balance of DAI in the vat after the pot exit |
| 88 | + uint bal = vat.dai(address(this)); |
| 89 | + |
| 90 | + // Remove our whole balance |
| 91 | + daiJoin.exit(address(this), bal / RAY); |
| 92 | + } |
| 93 | + |
| 94 | + /*** CToken Overrides ***/ |
| 95 | + |
| 96 | + /** |
| 97 | + * @notice Accrues DSR then applies accrued interest to total borrows and reserves |
| 98 | + * @dev This calculates interest accrued from the last checkpointed block |
| 99 | + * up to the current block and writes new checkpoint to storage. |
| 100 | + */ |
| 101 | + function accrueInterest() public returns (uint) { |
| 102 | + // Accumulate DSR interest |
| 103 | + PotLike(potAddress).drip(); |
| 104 | + |
| 105 | + // Accumulate CToken interest |
| 106 | + return super.accrueInterest(); |
| 107 | + } |
| 108 | + |
| 109 | + /*** Safe Token ***/ |
| 110 | + |
| 111 | + /** |
| 112 | + * @notice Gets balance of this contract in terms of the underlying |
| 113 | + * @dev This excludes the value of the current message, if any |
| 114 | + * @return The quantity of underlying tokens owned by this contract |
| 115 | + */ |
| 116 | + function getCashPrior() internal view returns (uint) { |
| 117 | + PotLike pot = PotLike(potAddress); |
| 118 | + uint pie = pot.pie(address(this)); |
| 119 | + return mul(pot.chi(), pie) / RAY; |
| 120 | + } |
| 121 | + |
| 122 | + /** |
| 123 | + * @notice Transfer the underlying to this contract and sweep into DSR pot |
| 124 | + * @param from Address to transfer funds from |
| 125 | + * @param amount Amount of underlying to transfer |
| 126 | + * @return The actual amount that is transferred |
| 127 | + */ |
| 128 | + function doTransferIn(address from, uint amount) internal returns (uint) { |
| 129 | + // Perform the EIP-20 transfer in |
| 130 | + EIP20Interface token = EIP20Interface(underlying); |
| 131 | + require(token.transferFrom(from, address(this), amount), "unexpected EIP-20 transfer in return"); |
| 132 | + |
| 133 | + DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress); |
| 134 | + GemLike dai = GemLike(underlying); |
| 135 | + PotLike pot = PotLike(potAddress); |
| 136 | + VatLike vat = VatLike(vatAddress); |
| 137 | + |
| 138 | + // Convert all our DAI to internal DAI in the vat |
| 139 | + daiJoin.join(address(this), dai.balanceOf(address(this))); |
| 140 | + |
| 141 | + // Checks the actual balance of DAI in the vat after the join |
| 142 | + uint bal = vat.dai(address(this)); |
| 143 | + |
| 144 | + // Calculate the percentage increase to th pot for the entire vat, and move it in |
| 145 | + // Note: We may leave a tiny bit of DAI in the vat...but we do the whole thing every time |
| 146 | + uint pie = bal / pot.chi(); |
| 147 | + pot.join(pie); |
| 148 | + |
| 149 | + return amount; |
| 150 | + } |
| 151 | + |
| 152 | + /** |
| 153 | + * @notice Transfer the underlying from this contract, after sweeping out of DSR pot |
| 154 | + * @param to Address to transfer funds to |
| 155 | + * @param amount Amount of underlying to transfer |
| 156 | + */ |
| 157 | + function doTransferOut(address payable to, uint amount) internal { |
| 158 | + DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress); |
| 159 | + PotLike pot = PotLike(potAddress); |
| 160 | + |
| 161 | + // Calculate the percentage decrease from the pot, and move that much out |
| 162 | + // Note: Use a slightly larger pie size to ensure that we get at least amount in the vat |
| 163 | + uint pie = add(mul(amount, RAY) / pot.chi(), 1); |
| 164 | + pot.exit(pie); |
| 165 | + |
| 166 | + daiJoin.exit(to, amount); |
| 167 | + } |
| 168 | + |
| 169 | + /*** Maker Internals ***/ |
| 170 | + |
| 171 | + uint256 constant RAY = 10 ** 27; |
| 172 | + |
| 173 | + function add(uint x, uint y) internal pure returns (uint z) { |
| 174 | + require((z = x + y) >= x, "add-overflow"); |
| 175 | + } |
| 176 | + |
| 177 | + function mul(uint x, uint y) internal pure returns (uint z) { |
| 178 | + require(y == 0 || (z = x * y) / y == x, "mul-overflow"); |
| 179 | + } |
| 180 | +} |
| 181 | + |
| 182 | +/*** Maker Interfaces ***/ |
| 183 | + |
| 184 | +contract PotLike { |
| 185 | + function chi() public view returns (uint); |
| 186 | + function dsr() public view returns (uint); |
| 187 | + function rho() public view returns (uint); |
| 188 | + function pie(address) public view returns (uint); |
| 189 | + function drip() public returns (uint); |
| 190 | + function join(uint) public; |
| 191 | + function exit(uint) public; |
| 192 | +} |
| 193 | + |
| 194 | +contract GemLike { |
| 195 | + function approve(address, uint) public; |
| 196 | + function balanceOf(address) public view returns (uint); |
| 197 | + function transfer(address, uint) public; |
| 198 | + function transferFrom(address, address, uint) public; |
| 199 | + function deposit() public payable; |
| 200 | + function withdraw(uint) public; |
| 201 | +} |
| 202 | + |
| 203 | +contract VatLike { |
| 204 | + function can(address, address) public view returns (uint); |
| 205 | + function ilks(bytes32) public view returns (uint, uint, uint, uint, uint); |
| 206 | + function dai(address) public view returns (uint); |
| 207 | + function urns(bytes32, address) public view returns (uint, uint); |
| 208 | + function frob(bytes32, address, address, address, int, int) public; |
| 209 | + function hope(address) public; |
| 210 | + function move(address, address, uint) public; |
| 211 | +} |
| 212 | + |
| 213 | +contract DaiJoinLike { |
| 214 | + function vat() public returns (VatLike); |
| 215 | + function dai() public returns (GemLike); |
| 216 | + function join(address, uint) public payable; |
| 217 | + function exit(address, uint) public; |
| 218 | +} |
0 commit comments