This repository has been archived by the owner on Oct 8, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 37
/
flash.sol
183 lines (150 loc) · 6.12 KB
/
flash.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
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2021 Dai Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
pragma solidity 0.6.12;
import "./interface/IERC3156FlashLender.sol";
import "./interface/IERC3156FlashBorrower.sol";
import "./interface/IVatDaiFlashLender.sol";
interface DaiLike {
function balanceOf(address) external returns (uint256);
function transferFrom(address, address, uint256) external returns (bool);
function approve(address, uint256) external returns (bool);
}
interface DaiJoinLike {
function dai() external view returns (address);
function vat() external view returns (address);
function join(address, uint256) external;
function exit(address, uint256) external;
}
interface VatLike {
function hope(address) external;
function dai(address) external view returns (uint256);
function live() external view returns (uint256);
function move(address, address, uint256) external;
function heal(uint256) external;
function suck(address, address, uint256) external;
}
contract DssFlash is IERC3156FlashLender, IVatDaiFlashLender {
// --- Auth ---
function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); }
function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); }
mapping (address => uint256) public wards;
modifier auth {
require(wards[msg.sender] == 1, "DssFlash/not-authorized");
_;
}
// --- Data ---
VatLike public immutable vat;
DaiJoinLike public immutable daiJoin;
DaiLike public immutable dai;
uint256 public max; // Maximum borrowable Dai [wad]
uint256 private locked; // Reentrancy guard
bytes32 public constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
bytes32 public constant CALLBACK_SUCCESS_VAT_DAI = keccak256("VatDaiFlashBorrower.onVatDaiFlashLoan");
// --- Events ---
event Rely(address indexed usr);
event Deny(address indexed usr);
event File(bytes32 indexed what, uint256 data);
event FlashLoan(address indexed receiver, address token, uint256 amount, uint256 fee);
event VatDaiFlashLoan(address indexed receiver, uint256 amount, uint256 fee);
modifier lock {
require(locked == 0, "DssFlash/reentrancy-guard");
locked = 1;
_;
locked = 0;
}
// --- Init ---
constructor(address daiJoin_) public {
wards[msg.sender] = 1;
emit Rely(msg.sender);
VatLike vat_ = vat = VatLike(DaiJoinLike(daiJoin_).vat());
daiJoin = DaiJoinLike(daiJoin_);
DaiLike dai_ = dai = DaiLike(DaiJoinLike(daiJoin_).dai());
vat_.hope(daiJoin_);
dai_.approve(daiJoin_, type(uint256).max);
}
// --- Math ---
uint256 constant RAY = 10 ** 27;
uint256 constant RAD = 10 ** 45;
function _mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x);
}
// --- Administration ---
function file(bytes32 what, uint256 data) external auth {
if (what == "max") {
// Add an upper limit of 10^27 DAI to avoid breaking technical assumptions of DAI << 2^256 - 1
require((max = data) <= RAD, "DssFlash/ceiling-too-high");
}
else revert("DssFlash/file-unrecognized-param");
emit File(what, data);
}
// --- ERC 3156 Spec ---
function maxFlashLoan(
address token
) external override view returns (uint256) {
if (token == address(dai) && locked == 0) {
return max;
} else {
return 0;
}
}
function flashFee(
address token,
uint256 amount
) external override view returns (uint256) {
amount;
require(token == address(dai), "DssFlash/token-unsupported");
return 0;
}
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint256 amount,
bytes calldata data
) external override lock returns (bool) {
require(token == address(dai), "DssFlash/token-unsupported");
require(amount <= max, "DssFlash/ceiling-exceeded");
require(vat.live() == 1, "DssFlash/vat-not-live");
uint256 amt = _mul(amount, RAY);
vat.suck(address(this), address(this), amt);
daiJoin.exit(address(receiver), amount);
emit FlashLoan(address(receiver), token, amount, 0);
require(
receiver.onFlashLoan(msg.sender, token, amount, 0, data) == CALLBACK_SUCCESS,
"DssFlash/callback-failed"
);
dai.transferFrom(address(receiver), address(this), amount);
daiJoin.join(address(this), amount);
vat.heal(amt);
return true;
}
// --- Vat Dai Flash Loan ---
function vatDaiFlashLoan(
IVatDaiFlashBorrower receiver, // address of conformant IVatDaiFlashBorrower
uint256 amount, // amount to flash loan [rad]
bytes calldata data // arbitrary data to pass to the receiver
) external override lock returns (bool) {
require(amount <= _mul(max, RAY), "DssFlash/ceiling-exceeded");
require(vat.live() == 1, "DssFlash/vat-not-live");
vat.suck(address(this), address(receiver), amount);
emit VatDaiFlashLoan(address(receiver), amount, 0);
require(
receiver.onVatDaiFlashLoan(msg.sender, amount, 0, data) == CALLBACK_SUCCESS_VAT_DAI,
"DssFlash/callback-failed"
);
vat.heal(amount);
return true;
}
}