How to use
Flash loans are instantaneous and unsecured DeFi lending solutions, enabled by smart contract code that reverses a lending transaction if the borrower is unable to fulfill borrowing obligations. Their use cases cover arbitrage, liquidation and so on.
Flash loan borrowers on CHFRY utilize Flash Fryer reserves for flash loan operations, in the same vein as Aave’s offering, and enhance their yields with CHEESE rewards.
In order to use CHFRY flash loans follow the standard proposal EIP-3165.
Flash loan fee
The flash loan fee is currently 0.06%, changeable via the normal governance process. To get the current value, call getConfigValue("FRYER_FLASH_FEE_PROPORTION") on the FryerConfig.sol contract.
Example
For developers, a helpful mental model to consider when developing your solution:
1/ Approve the specific Fryer contract amount and the flashloan fee; fee can be calculated by Fryer's flashFee().
2/ Your contract calls the Fryer contract, requesting a Flash Loan of a certain amount of reserves using flashLoan().
3/ After some sanity checks, the Fryer transfers the requested amount of the reserves to your contract, then calls onFlashLoan() on your contract.
4/ Your contract, now holding the flash loaned amount, executes any arbitrary operation in its code. Keep at least amount + fee in your contract.
5/ Finally, Fryer will transfer amount + fee from your contract. All of the above happens in one transaction (hence in a single ethereum block).
FlashBorrower.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.6.5 <0.8.0;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import './interfaces/IERC3156FlashBorrower.sol';
import './interfaces/IERC3156FlashLender.sol';
import './libraries/TransferHelper.sol';
// FlashLoan DEMO
contract FlashBorrower2 is IERC3156FlashBorrower {
enum Action {
NORMAL,
STEAL,
REENTER
}
using TransferHelper for address;
IERC3156FlashLender lender;
uint256 public flashBalance;
address public flashInitiator;
address public flashToken;
uint256 public flashAmount;
uint256 public flashFee;
address public admin;
constructor(address lender_) public {
admin = msg.sender;
lender = IERC3156FlashLender(lender_);
}
function setLender(address _lender) external {
require(msg.sender == admin, '!admin');
lender = IERC3156FlashLender(_lender);
}
/// @dev ERC-3156 Flash loan callback
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external override returns (bytes32) {
require(msg.sender == address(lender), 'FlashBorrower: Untrusted lender');
require(initiator == address(this), 'FlashBorrower: External loan initiator');
Action action = abi.decode(data, (Action)); // Use this to unpack arbitrary data
flashInitiator = initiator;
flashToken = token;
flashAmount = amount;
flashFee = fee;
if (action == Action.NORMAL) {
flashBalance = IERC20(token).balanceOf(address(this));
} else if (action == Action.STEAL) {
// do nothing
} else if (action == Action.REENTER) {
flashBorrow(token, amount * 2);
}
return keccak256('ERC3156FlashBorrower.onFlashLoan');
}
function flashBorrow(address token, uint256 amount) public {
// Use this to pack arbitrary data to `onFlashLoan`
bytes memory data = abi.encode(Action.NORMAL);
approveRepayment(token, amount);
lender.flashLoan(this, token, amount, data);
}
function flashBorrowAndSteal(address token, uint256 amount) public {
// Use this to pack arbitrary data to `onFlashLoan`
bytes memory data = abi.encode(Action.STEAL);
lender.flashLoan(this, token, amount, data);
}
function flashBorrowAndReenter(address token, uint256 amount) public {
// Use this to pack arbitrary data to `onFlashLoan`
bytes memory data = abi.encode(Action.REENTER);
approveRepayment(token, amount);
lender.flashLoan(this, token, amount, data);
}
function approveRepayment(address token, uint256 amount) public {
uint256 _allowance = IERC20(token).allowance(address(this), address(lender));
uint256 _fee = lender.flashFee(token, amount);
uint256 _repayment = amount + _fee;
token.safeApprove(address(lender), 0);
token.safeApprove(address(lender), _allowance + _repayment);
}
function transferFromAdmin(
address _token,
address _receiver,
uint256 _amount
) external {
require(msg.sender == admin, '!admin');
_token.safeTransfer(_receiver, _amount);
}
}
IERC3156FlashBorrower.sol
IERC3156FlashLender.sol
TransferHelper.sol
Last updated
Was this helpful?