-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathFlashLender.sol
93 lines (78 loc) · 3.42 KB
/
FlashLender.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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./interfaces/IERC3156FlashBorrower.sol";
import "./interfaces/IERC3156FlashLender.sol";
/**
* @dev Extension of {ERC20} that allows flash lending.
*/
contract FlashLender is IERC3156FlashLender {
bytes32 public constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
mapping(address => bool) public supportedTokens;
uint256 public fee; // 1 == 0.01 %
/**
* @param supportedTokens_ Token contracts supported for flash lending.
* @param fee_ The percentage of the loan `amount` that needs to be repaid, in addition to `amount`.
*/
constructor(address[] memory supportedTokens_, uint256 fee_) {
for (uint256 i = 0; i < supportedTokens_.length; i++) {
supportedTokens[supportedTokens_[i]] = true;
}
fee = fee_;
}
/**
* @dev Loan `amount` tokens to `receiver`, and takes it back plus a `flashFee` after the callback.
* @param receiver The contract receiving the tokens, needs to implement the `onFlashLoan(address user, uint256 amount, uint256 fee, bytes calldata)` interface.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param data A data parameter to be passed on to the `receiver` for any custom use.
*/
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint256 amount,
bytes calldata data
) external override returns (bool) {
require(supportedTokens[token], "FlashLender: Unsupported currency");
uint256 _fee = _flashFee(token, amount);
require(IERC20(token).transfer(address(receiver), amount), "FlashLender: Transfer failed");
require(
receiver.onFlashLoan(msg.sender, token, amount, _fee, data) == CALLBACK_SUCCESS,
"FlashLender: Callback failed"
);
require(
IERC20(token).transferFrom(address(receiver), address(this), amount + _fee),
"FlashLender: Repay failed"
);
return true;
}
/**
* @dev The amount of currency available to be lent.
* @param token The loan currency.
* @return The amount of `token` that can be borrowed.
*/
function maxFlashFloan(address token) external view override returns (uint256) {
return supportedTokens[token] ? IERC20(token).balanceOf(address(this)) : 0;
}
/**
* @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 override returns (uint256) {
require(supportedTokens[token], "FlashLender: Unsupported currency");
return _flashFee(token, amount);
}
/**
* @dev The fee to be charged for a given loan. Internal function with no checks.
* @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) internal view returns (uint256) {
// silence warning about unused variable without the addition of bytecode.
token;
return (amount * fee) / 10000;
}
}