IFlashLoanReceiver
Never keep funds permanently on your FlashLoanReceiverBase contract as they could be exposed to a 'griefing' attack, where the stored funds are used by an attacker.
When performing a flash loan, the contract receiving the funds must conform to the following solidity interface (also available on Github):
IFlashLoanReceiver.sol
1
// SPDX-License-Identifier: agpl-3.0
2
pragma solidity 0.6.12;
3
4
import { ILendingPoolAddressesProvider } from './ILendingPoolAddressesProvider.sol';
5
import { ILendingPool } from './ILendingPool.sol';
6
7
/**
8
* @title IFlashLoanReceiver interface
9
* @notice Interface for the Aave fee IFlashLoanReceiver.
10
* @author Aave
11
* @dev implement this interface to develop a flashloan-compatible flashLoanReceiver contract
12
**/
13
interface IFlashLoanReceiver {
14
function executeOperation(
15
address[] calldata assets,
16
uint256[] calldata amounts,
17
uint256[] calldata premiums,
18
address initiator,
19
bytes calldata params
20
) external returns (bool);
21
22
function ADDRESSES_PROVIDER() external view returns (ILendingPoolAddressesProvider);
23
24
function LENDING_POOL() external view returns (ILendingPool);
25
}
26
27
Copied!

FlashLoanReceiverBase

An example of an abstract contract that can be used as a base in production is below (also available on Github):
The interface for ILendingPoolAddressesProvider can be found here.
FlashLoanReceiverBase.sol
IERC20.sol
SafeERC20.sol
SafeMath.sol
Address.sol
1
// SPDX-License-Identifier: agpl-3.0
2
pragma solidity ^0.6.8;
3
4
import { SafeMath } from './SafeMath.sol';
5
import { IERC20 } from './IERC20.sol';
6
import { SafeERC20 } from './SafeERC20.sol';
7
import { IFlashLoanReceiver } from './IFlashLoanReceiver.sol';
8
import { ILendingPoolAddressesProvider } from './ILendingPoolAddressesProvider.sol';
9
import { ILendingPool } from './ILendingPool.sol';
10
11
/**
12
!!!
13
Never keep funds permanently on your FlashLoanReceiverBase contract as they could be
14
exposed to a 'griefing' attack, where the stored funds are used by an attacker.
15
!!!
16
*/
17
abstract contract FlashLoanReceiverBase is IFlashLoanReceiver {
18
using SafeERC20 for IERC20;
19
using SafeMath for uint256;
20
21
ILendingPoolAddressesProvider public immutable override ADDRESSES_PROVIDER;
22
ILendingPool public immutable override LENDING_POOL;
23
24
constructor(ILendingPoolAddressesProvider provider) public {
25
ADDRESSES_PROVIDER = provider;
26
LENDING_POOL = ILendingPool(provider.getLendingPool());
27
}
28
}
Copied!
1
// SPDX-License-Identifier: agpl-3.0
2
pragma solidity 0.6.8;
3
4
/**
5
* @dev Interface of the ERC20 standard as defined in the EIP.
6
*/
7
interface IERC20 {
8
/**
9
* @dev Returns the amount of tokens in existence.
10
*/
11
function totalSupply() external view returns (uint256);
12
13
/**
14
* @dev Returns the amount of tokens owned by `account`.
15
*/
16
function balanceOf(address account) external view returns (uint256);
17
18
/**
19
* @dev Moves `amount` tokens from the caller's account to `recipient`.
20
*
21
* Returns a boolean value indicating whether the operation succeeded.
22
*
23
* Emits a {Transfer} event.
24
*/
25
function transfer(address recipient, uint256 amount) external returns (bool);
26
27
/**
28
* @dev Returns the remaining number of tokens that `spender` will be
29
* allowed to spend on behalf of `owner` through {transferFrom}. This is
30
* zero by default.
31
*
32
* This value changes when {approve} or {transferFrom} are called.
33
*/
34
function allowance(address owner, address spender) external view returns (uint256);
35
36
/**
37
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
38
*
39
* Returns a boolean value indicating whether the operation succeeded.
40
*
41
* IMPORTANT: Beware that changing an allowance with this method brings the risk
42
* that someone may use both the old and the new allowance by unfortunate
43
* transaction ordering. One possible solution to mitigate this race
44
* condition is to first reduce the spender's allowance to 0 and set the
45
* desired value afterwards:
46
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
47
*
48
* Emits an {Approval} event.
49
*/
50
function approve(address spender, uint256 amount) external returns (bool);
51
52
/**
53
* @dev Moves `amount` tokens from `sender` to `recipient` using the
54
* allowance mechanism. `amount` is then deducted from the caller's
55
* allowance.
56
*
57
* Returns a boolean value indicating whether the operation succeeded.
58
*
59
* Emits a {Transfer} event.
60
*/
61
function transferFrom(
62
address sender,
63
address recipient,
64
uint256 amount
65
) external returns (bool);
66
67
/**
68
* @dev Emitted when `value` tokens are moved from one account (`from`) to
69
* another (`to`).
70
*
71
* Note that `value` may be zero.
72
*/
73
event Transfer(address indexed from, address indexed to, uint256 value);
74
75
/**
76
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
77
* a call to {approve}. `value` is the new allowance.
78
*/
79
event Approval(address indexed owner, address indexed spender, uint256 value);
80
}
81
Copied!
1
// SPDX-License-Identifier: MIT
2
pragma solidity 0.6.8;
3
4
import {IERC20} from './IERC20.sol';
5
import {SafeMath} from './SafeMath.sol';
6
import {Address} from './Address.sol';
7
8
/**
9
* @title SafeERC20
10
* @dev Wrappers around ERC20 operations that throw on failure (when the token
11
* contract returns false). Tokens that return no value (and instead revert or
12
* throw on failure) are also supported, non-reverting calls are assumed to be
13
* successful.
14
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
15
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
16
*/
17
library SafeERC20 {
18
using SafeMath for uint256;
19
using Address for address;
20
21
function safeTransfer(
22
IERC20 token,
23
address to,
24
uint256 value
25
) internal {
26
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
27
}
28
29
function safeTransferFrom(
30
IERC20 token,
31
address from,
32
address to,
33
uint256 value
34
) internal {
35
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
36
}
37
38
function safeApprove(
39
IERC20 token,
40
address spender,
41
uint256 value
42
) internal {
43
require(
44
(value == 0) || (token.allowance(address(this), spender) == 0),
45
'SafeERC20: approve from non-zero to non-zero allowance'
46
);
47
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
48
}
49
50
function callOptionalReturn(IERC20 token, bytes memory data) private {
51
require(address(token).isContract(), 'SafeERC20: call to non-contract');
52
53
// solhint-disable-next-line avoid-low-level-calls
54
(bool success, bytes memory returndata) = address(token).call(data);
55
require(success, 'SafeERC20: low-level call failed');
56
57
if (returndata.length > 0) {
58
// Return data is optional
59
// solhint-disable-next-line max-line-length
60
require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed');
61
}
62
}
63
}
64
Copied!
1
// SPDX-License-Identifier: agpl-3.0
2
pragma solidity 0.6.8;
3
4
/**
5
* @dev Wrappers over Solidity's arithmetic operations with added overflow
6
* checks.
7
*
8
* Arithmetic operations in Solidity wrap on overflow. This can easily result
9
* in bugs, because programmers usually assume that an overflow raises an
10
* error, which is the standard behavior in high level programming languages.
11
* `SafeMath` restores this intuition by reverting the transaction when an
12
* operation overflows.
13
*
14
* Using this library instead of the unchecked operations eliminates an entire
15
* class of bugs, so it's recommended to use it always.
16
*/
17
library SafeMath {
18
/**
19
* @dev Returns the addition of two unsigned integers, reverting on
20
* overflow.
21
*
22
* Counterpart to Solidity's `+` operator.
23
*
24
* Requirements:
25
* - Addition cannot overflow.
26
*/
27
function add(uint256 a, uint256 b) internal pure returns (uint256) {
28
uint256 c = a + b;
29
require(c >= a, 'SafeMath: addition overflow');
30
31
return c;
32
}
33
34
/**
35
* @dev Returns the subtraction of two unsigned integers, reverting on
36
* overflow (when the result is negative).
37
*
38
* Counterpart to Solidity's `-` operator.
39
*
40
* Requirements:
41
* - Subtraction cannot overflow.
42
*/
43
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
44
return sub(a, b, 'SafeMath: subtraction overflow');
45
}
46
47
/**
48
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
49
* overflow (when the result is negative).
50
*
51
* Counterpart to Solidity's `-` operator.
52
*
53
* Requirements:
54
* - Subtraction cannot overflow.
55
*/
56
function sub(
57
uint256 a,
58
uint256 b,
59
string memory errorMessage
60
) internal pure returns (uint256) {
61
require(b <= a, errorMessage);
62
uint256 c = a - b;
63
64
return c;
65
}
66
67
/**
68
* @dev Returns the multiplication of two unsigned integers, reverting on
69
* overflow.
70
*
71
* Counterpart to Solidity's `*` operator.
72
*
73
* Requirements:
74
* - Multiplication cannot overflow.
75
*/
76
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
77
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
78
// benefit is lost if 'b' is also tested.
79
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
80
if (a == 0) {
81
return 0;
82
}
83
84
uint256 c = a * b;
85
require(c / a == b, 'SafeMath: multiplication overflow');
86
87
return c;
88
}
89
90
/**
91
* @dev Returns the integer division of two unsigned integers. Reverts on
92
* division by zero. The result is rounded towards zero.
93
*
94
* Counterpart to Solidity's `/` operator. Note: this function uses a
95
* `revert` opcode (which leaves remaining gas untouched) while Solidity
96
* uses an invalid opcode to revert (consuming all remaining gas).
97
*
98
* Requirements:
99
* - The divisor cannot be zero.
100
*/
101
function div(uint256 a, uint256 b) internal pure returns (uint256) {
102
return div(a, b, 'SafeMath: division by zero');
103
}
104
105
/**
106
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
107
* division by zero. The result is rounded towards zero.
108
*
109
* Counterpart to Solidity's `/` operator. Note: this function uses a
110
* `revert` opcode (which leaves remaining gas untouched) while Solidity
111
* uses an invalid opcode to revert (consuming all remaining gas).
112
*
113
* Requirements:
114
* - The divisor cannot be zero.
115
*/
116
function div(
117
uint256 a,
118
uint256 b,
119
string memory errorMessage
120
) internal pure returns (uint256) {
121
// Solidity only automatically asserts when dividing by 0
122
require(b > 0, errorMessage);
123
uint256 c = a / b;
124
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
125
126
return c;
127
}
128
129
/**
130
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
131
* Reverts when dividing by zero.
132
*
133
* Counterpart to Solidity's `%` operator. This function uses a `revert`
134
* opcode (which leaves remaining gas untouched) while Solidity uses an
135
* invalid opcode to revert (consuming all remaining gas).
136
*
137
* Requirements:
138
* - The divisor cannot be zero.
139
*/
140
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
141
return mod(a, b, 'SafeMath: modulo by zero');
142
}
143
144
/**
145
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
146
* Reverts with custom message when dividing by zero.
147
*
148
* Counterpart to Solidity's `%` operator. This function uses a `revert`
149
* opcode (which leaves remaining gas untouched) while Solidity uses an
150
* invalid opcode to revert (consuming all remaining gas).
151
*
152
* Requirements:
153
* - The divisor cannot be zero.
154
*/
155
function mod(
156
uint256 a,
157
uint256 b,
158
string memory errorMessage
159
) internal pure returns (uint256) {
160
require(b != 0, errorMessage);
161
return a % b;
162
}
163
}
164
Copied!
1
// SPDX-License-Identifier: agpl-3.0
2
pragma solidity 0.6.8;
3
4
/**
5
* @dev Collection of functions related to the address type
6
*/
7
library Address {
8
/**
9
* @dev Returns true if `account` is a contract.
10
*
11
* [IMPORTANT]
12
* ====
13
* It is unsafe to assume that an address for which this function returns
14
* false is an externally-owned account (EOA) and not a contract.
15
*
16
* Among others, `isContract` will return false for the following
17
* types of addresses:
18
*
19
* - an externally-owned account
20
* - a contract in construction
21
* - an address where a contract will be created
22
* - an address where a contract lived, but was destroyed
23
* ====
24
*/
25
function isContract(address account) internal view returns (bool) {
26
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
27
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
28
// for accounts without code, i.e. `keccak256('')`
29
bytes32 codehash;
30
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
31
// solhint-disable-next-line no-inline-assembly
32
assembly {
33
codehash := extcodehash(account)
34
}
35
return (codehash != accountHash && codehash != 0x0);
36
}
37
38
/**
39
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
40
* `recipient`, forwarding all available gas and reverting on errors.
41
*
42
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
43
* of certain opcodes, possibly making contracts go over the 2300 gas limit
44
* imposed by `transfer`, making them unable to receive funds via
45
* `transfer`. {sendValue} removes this limitation.
46
*
47
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
48
*
49
* IMPORTANT: because control is transferred to `recipient`, care must be
50
* taken to not create reentrancy vulnerabilities. Consider using
51
* {ReentrancyGuard} or the
52
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
53
*/
54
function sendValue(address payable recipient, uint256 amount) internal {
55
require(address(this).balance >= amount, 'Address: insufficient balance');
56
57
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
58
(bool success, ) = recipient.call{value: amount}('');
59
require(success, 'Address: unable to send value, recipient may have reverted');
60
}
61
}
62
Copied!
Last modified 9mo ago
Copy link