Flash Loans and Flash Mints
Flash loans, inspired by Aave, is a DeFi feature allowing smart contracts to borrow all available collateral in the Cryndex treasury. This enables operations like arbitrage or liquidations without needing collateral for borrowing. In order for a flash loan to be successful, a borrower must repay the full loan amount plus a fee otherwise the transaction is reverted and it is as if the funds never left the treasury. Given that there will be idle capital backing all Cryndex Assets in the treasury, this is a great way to increase capital efficiency whilst also minimising risk for lenders.
Flash minting is the process of minting an infinite amount of tokens for any given Cryndex Asset, similar to a flash loan. Flash minting is essential to the Cryndex ecosystem as it allows arbitragers to keep the price of Cryndex Assets pegged to the correct value across different decentralised exchanges.
Flash minting works in exactly the same way as flash loans, the only difference to flash loans is that the funds will not be transferred back to the treasury and will instead be burned from the borrower's account. If the borrower doesn't have the funds they borrowed plus the fees, the transaction will be reverted.
Here is an example contract to initiate a flash loan/mint:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
// Interface required by the treasury
interface IFlashLoanReceiver {
function executeOperation(
address[] memory assets,
uint256[] memory amounts,
uint112[] memory fees,
bytes calldata params
) external returns (bool);
}
interface ICryndexTreasury {
function flashLoan(
address receiver,
address[] memory tokens,
uint256[] memory amounts,
bytes calldata params
) external;
}
// FlashLoanReceiver contract to handle flash loans
contract FlashLoanReceiver is IFlashLoanReceiver {
// Address of the wrapped native token (e.g., WBNB)
address public immutable wbnb;
// Address of the Cryndex treasury
address public immutable treasury;
// Constructor to set the WBNB address
constructor(address _wbnb, address _treasury) {
wbnb = _wbnb;
treasury = _treasury;
}
/**
* @notice Handles the flash loan operation
* @param assets Array of token addresses (address(0) means WBNB)
* @param amounts Array of borrowed amounts
* @param fees Array of fees to be paid
* @param params Extra data passed from the flash loan call
* @return bool Returns true if the operation is successful
*/
function executeOperation(
address[] memory assets,
uint256[] memory amounts,
uint112[] memory fees,
bytes calldata params
) external override returns (bool) {
require(msg.sender == treasury, "Unauthorised");
// Iterate over all assets
for (uint256 i = 0; i < assets.length; i++) {
// Determine the actual token address (use WBNB if asset is address(0))
address token = assets[i] == address(0) ? wbnb : assets[i];
// Calculate total repayment amount (borrowed amount + fee)
uint256 amountOwing = amounts[i] + uint256(fees[i]);
// Approve the liquidity pool to spend the total amount
IERC20(token).approve(msg.sender, amountOwing);
}
// In a real scenario, perform operations here with the borrowed funds
// to generate enough profit to cover the fees.
// For this example, we assume the contract already has sufficient balance.
// Return true to indicate successful execution
return true;
}
/**
* @notice Initiates a flash loan by calling the treasury
* @param tokens Array of token and asset addresses to borrow or mint (address(0) for WBNB)
* @param amounts Array of amounts to borrow
* @param params Extra data to pass to the flash loan
*/
function initiateFlashLoan(
address[] memory tokens,
uint256[] memory amounts,
bytes calldata params
) external {
require(tokens.length == amounts.length, "Mismatched tokens and amounts");
require(tokens.length > 0, "No tokens specified");
// Call the liquidity pool's flashLoan function
IFlashLoanPool(pool).flashLoan(address(this), tokens, amounts, params);
}
}
Last updated