// hevm: flattened sources of src/flash.sol
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity =0.6.12 >=0.6.12;
////// src/interface/IERC3156FlashBorrower.sol
// 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; */
interface IERC3156FlashBorrower {
/**
* @dev Receive a flash loan.
* @param initiator The initiator of the loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param fee The additional amount of tokens to repay.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
* @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan"
*/
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32);
}
////// src/interface/IERC3156FlashLender.sol
// 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 "./IERC3156FlashBorrower.sol"; */
interface IERC3156FlashLender {
/**
* @dev The amount of currency available to be lent.
* @param token The loan currency.
* @return The amount of `token` that can be borrowed.
*/
function maxFlashLoan(
address token
) external view returns (uint256);
/**
* @dev The fee to be charged for a given loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @return The amount of `token` to be charged for the loan, on top of the returned principal.
*/
function flashFee(
address token,
uint256 amount
) external view returns (uint256);
/**
* @dev Initiate a flash loan.
* @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
*/
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint256 amount,
bytes calldata data
) external returns (bool);
}
////// src/interface/IVatDaiFlashBorrower.sol
// 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; */
interface IVatDaiFlashBorrower {
/**
* @dev Receive a flash loan.
* @param initiator The initiator of the loan.
* @param amount The amount of tokens lent. [rad]
* @param fee The additional amount of tokens to repay. [rad]
* @param data Arbitrary data structure, intended to contain user-defined parameters.
* @return The keccak256 hash of "IVatDaiFlashLoanReceiver.onVatDaiFlashLoan"
*/
function onVatDaiFlashLoan(
address initiator,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32);
}
////// src/interface/IVatDaiFlashLender.sol
// 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 "./IVatDaiFlashBorrower.sol"; */
interface IVatDaiFlashLender {
/**
* @dev Initiate a flash loan.
* @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
* @param amount The amount of tokens lent. [rad]
* @param data Arbitrary data structure, intended to contain user-defined parameters.
*/
function vatDaiFlashLoan(
IVatDaiFlashBorrower receiver,
uint256 amount,
bytes calldata data
) external returns (bool);
}
////// src/flash.sol
// 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_4 {
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_4 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_4 vat_ = vat = VatLike_4(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;
}
}
{
"compilationTarget": {
"DssFlash.sol": "DssFlash"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"daiJoin_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"usr","type":"address"}],"name":"Deny","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"what","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"data","type":"uint256"}],"name":"File","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"FlashLoan","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"usr","type":"address"}],"name":"Rely","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"VatDaiFlashLoan","type":"event"},{"inputs":[],"name":"CALLBACK_SUCCESS","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CALLBACK_SUCCESS_VAT_DAI","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dai","outputs":[{"internalType":"contract DaiLike","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"daiJoin","outputs":[{"internalType":"contract DaiJoinLike","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"usr","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"what","type":"bytes32"},{"internalType":"uint256","name":"data","type":"uint256"}],"name":"file","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"flashFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC3156FlashBorrower","name":"receiver","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashLoan","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"max","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"maxFlashLoan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"usr","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vat","outputs":[{"internalType":"contract VatLike_4","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IVatDaiFlashBorrower","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"vatDaiFlashLoan","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]