> For the complete documentation index, see [llms.txt](https://docs-chfry.gitbook.io/doc/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs-chfry.gitbook.io/doc/flashloan/how-to-use.md).

# 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. &#x20;

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`](https://eips.ethereum.org/EIPS/eip-3156).&#x20;

### 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&#x20;

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()`.&#x20;

2/ Your contract calls the Fryer contract, requesting a Flash Loan of a certain `amount` of reserves using `flashLoan()`.&#x20;

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

```javascript
//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

```javascript
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <=0.8.0;


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);
}

```

#### IERC3156FlashLender.sol

```javascript
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <=0.8.0;
import "./IERC3156FlashBorrower.sol";


interface IERC3156FlashLender {

    /**
     * @dev The amount of currency available to be lended.
     * @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);
}
```

#### TransferHelper.sol

```javascript
//SPDX-License-Identifier: MIT
pragma solidity >=0.6.5 <0.8.0;

library TransferHelper {
    function safeApprove(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
    }

    function safeTransfer(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
    }

    function safeTransferFrom(address token, address from, address to, uint value) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
    }

    function safeTransferETH(address to, uint value) internal {
        (bool success,) = to.call{value:value}(new bytes(0));
        require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
    }
}

```
