欢迎订阅专栏:3分钟Solidity--智能合约--Web3区块链技术必学
Uniswap V4 闪电贷
Uniswap V4 闪电贷完全免费——零手续费!这得益于其瞬时结算机制。
运作方式:
- 调用
poolManager.unlock()开始 - 在回调中,调用
poolManager.take()借出代币(产生债务) - 使用代币进行套利、清算、抵押品互换等操作
- 通过转回代币并调用
poolManager.settle()来偿还 - 只要净差额为零,交易就会成功
与V3对闪电贷收取费用不同,V4的单例架构和闪电记账使借款基本免费——你只需支付gas费。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
// Uniswap V4 PoolManager on Ethereum mainnet
address constant POOL_MANAGER = 0x000000000004444c5dc75cB358380D2e3dE08A90;
/// @notice Example of flash loans on Uniswap V4
/// @dev V4 flash loans are FREE due to flash accounting - no fees!
/// Borrow tokens during unlock callback, repay before callback ends
contract UniswapV4Flash is IUnlockCallback {
IPoolManager public immutable poolManager;
error NotPoolManager();
error FlashLoanFailed();
constructor() {
poolManager = IPoolManager(POOL_MANAGER);
}
/// @notice Execute a flash loan
/// @param currency The token to borrow (use address(0) for native ETH)
/// @param amount Amount to borrow
/// @param data Arbitrary data to pass to your flash loan logic
function flash(Currency currency, uint256 amount, bytes calldata data)
external
{
bytes memory callbackData = abi.encode(
FlashParams({
currency: currency,
amount: amount,
sender: msg.sender,
data: data
})
);
poolManager.unlock(callbackData);
}
/// @notice Callback from PoolManager - execute flash loan logic here
function unlockCallback(bytes calldata callbackData)
external
override
returns (bytes memory)
{
if (msg.sender != address(poolManager)) revert NotPoolManager();
FlashParams memory params = abi.decode(callbackData, (FlashParams));
// Take tokens from the pool (creates a debt)
poolManager.take(params.currency, address(this), params.amount);
// ============================================
// Your flash loan logic goes here!
// You now have the borrowed tokens to use
// ============================================
// Example: call custom logic
_executeFlashLoanLogic(params.currency, params.amount, params.data);
// ============================================
// Repay the flash loan
// ============================================
// For ERC20: transfer tokens to PoolManager, then settle
if (!isNative(params.currency)) {
IERC20(Currency.unwrap(params.currency)).transfer(
address(poolManager),
params.amount
);
poolManager.settle(params.currency);
} else {
// For native ETH: settle with value
poolManager.settle{value: params.amount}(params.currency);
}
// No fees! Delta is now zero, unlock will succeed
return bytes("");
}
/// @notice Override this to implement your flash loan logic
function _executeFlashLoanLogic(
Currency currency,
uint256 amount,
bytes memory data
) internal virtual {
// Example: arbitrage, liquidation, collateral swap, etc.
// The borrowed tokens are in this contract
}
function isNative(Currency currency) internal pure returns (bool) {
return Currency.unwrap(currency) == address(0);
}
// Allow receiving ETH
receive() external payable {}
struct FlashParams {
Currency currency;
uint256 amount;
address sender;
bytes data;
}
}
// Currency is an address wrapper (address(0) = native ETH)
type Currency is address;
library CurrencyLibrary {
function unwrap(Currency currency) internal pure returns (address) {
return Currency.unwrap(currency);
}
}
using CurrencyLibrary for Currency;
interface IPoolManager {
function unlock(bytes calldata data) external returns (bytes memory);
function settle(Currency currency) external payable returns (uint256);
function take(Currency currency, address to, uint256 amount) external;
}
interface IUnlockCallback {
function unlockCallback(bytes calldata data) external returns (bytes memory);
}
interface IERC20 {
function transfer(address recipient, uint256 amount)
external
returns (bool);
function balanceOf(address account) external view returns (uint256);
}