关于闪电贷,特别是关于aave闪电贷,
闪电贷是一种以合约为技术手段,利于合约的原子性,即如果中途失败交易金额全部回滚的一种提供合约杠杆的需要合约开发使用的一种合约技术手段。
依旧是 * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
ERC-3156 底层合约协议来在eth链上进行放贷的一种技术实现。

以aave举例是因为aave是最大的Defi也更具有权威性。
https://learnblockchain.cn/article/5634
在等链社区上有相关的代码测试网使用教程。
// SPDX-License-Identifier: MIT
/*
合约是针对AaveV3版本
*/
pragma solidity 0.8.10;
// 引入Aave V3的基础合约、借贷池管理合约、以及openzeppeln erc20合约
import "https://github.com/aave/aave-v3-core/blob/master/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol";
import "https://github.com/aave/aave-v3-core/blob/master/contracts/interfaces/IPoolAddressesProvider.sol";
import "https://github.com/aave/aave-v3-core/blob/master/contracts/dependencies/openzeppelin/contracts/IERC20.sol";
// 继承Aave's FlashLoanSimpleReceiverBase 合约
contract SimpleFlashLoan is FlashLoanSimpleReceiverBase {
address payable owner;
// 初始化合约,在构造器中填入Aave's lending pool的地址,后面会演示到
constructor(address _addressProvider)
FlashLoanSimpleReceiverBase(IPoolAddressesProvider(_addressProvider))
{
}
// 请求借款的函数,
function fn_RequestFlashLoan(address _token, uint256 _amount) public {
address receiverAddress = address(this); // 用来接收闪电贷资金的合约地址,在这个合约中是部署合约的地址
address asset = _token; // 闪电贷的贷款资产代币地址,这次是usdc
uint256 amount = _amount; // 闪电贷的额度,本次是10个usdc
bytes memory params = ""; // 额外信息作为可变参数打包传递给receiver,暂时用不到
uint16 referralCode = 0; // 邀请码,暂时用不到
// 调用aave 的资金池进行交互
POOL.flashLoanSimple(
receiverAddress,
asset,
amount,
params,
referralCode
);
}
/*
闪电贷策略合约必须实现的函数,一般用于授权还款额度给LendPool合约地址,
该函数是在上面的函数执行完毕之后,回调执行该函数,操作approve一定量的币(贷款+手续费)给Lending Pool地址
手续费:借款总额的0.09%.
*/
function executeOperation(
address asset,
uint256 amount,
uint256 premium,
address initiator,
bytes calldata params
) external override returns (bool) {
//具体业务逻辑可以写在这里,当逻辑走完,接下来就是要偿还
// 该合约闪电贷额度+手续费,请确保由足够的资金偿还金额
uint256 totalAmount = amount + premium;
IERC20(asset).approve(address(POOL), totalAmount);
return true;
}
receive() external payable {}
}
executeOperation 作为回调函数可以进行闪电贷的操作逻辑。

以及 pool 的业务流程截图。至于在闪电贷 后面我只看到了授权 IERC20(asset).approve(address(POOL), totalAmount);
没有还款操作,是因为aave实现了隐式还款也就是说,用户只要授权对应的额度就可以完成还款,否则就会遭到原子性失败。
https://github.com/aave/aave-v3-core/blob/master/contracts/protocol/libraries/logic/FlashLoanLogic.sol
关于隐式还款的逻辑在aave3 闪电贷函数中有具体的体现。
所以它的代码有隐式还款的作用,前置条件是必须授权
IERC20(asset).approve(address(POOL), totalAmount);

通过查看代码我们看到aave代码是高度分离抽象且复杂的。
// Pool.sol (行号约为 630-660,具体版本可能略有差异)
function flashLoanSimple(
address receiverAddress,
address asset,
uint256 amount,
bytes calldata params,
uint16 referralCode
) external virtual override {
// 1. 触发闪电贷前的状态检查
DataTypes.FlashloanSimpleMemory memory vars =
_initiateFlashLoanSimple(receiverAddress, asset, amount, referralCode);
// 2. 调用接收者的 executeOperation(开发者自定义逻辑)
IFlashLoanSimpleReceiver(receiverAddress).executeOperation(
asset,
amount,
vars.totalPremium,
msg.sender,
params
);
// 3. 还款验证与执行(核心逻辑)
_handleFlashLoanRepayment(
vars.currentAsset,
vars.currentAmount,
vars.totalPremium,
receiverAddress,
vars.referralCode
);
}
这是我找 AI 分析的相关代码
在 executeFlashLoanSimple 函数中,通过 handleFlashLoanRepayment 完成资金扣款。
// FlashLoanLogic.sol (行号约为 200-240)
function handleFlashLoanRepayment(
DataTypes.FlashLoanRepaymentParams memory params
) internal {
// 1. 计算应还款总额(本金 + 手续费)
uint256 totalAmount = params.amount + params.premium;
// 2. 检查接收者是否已授权足够资金
uint256 allowance = IERC20(params.asset).allowance(
params.receiverAddress,
address(this)
);
require(allowance >= totalAmount, "INSUFFICIENT_ALLOWANCE");
// 3. 从接收者地址扣款至资金池
IERC20(params.asset).safeTransferFrom(
params.receiverAddress,
params.reserveCache.aTokenAddress, // 资金流向 aToken 合约
totalAmount
);
// 4. 更新资金池状态(如利息计算)
params.reserve.updateState(params.reserveCache);
}
也就是说, ERC-3156 协议只是开放了闪电贷功能也就是你这个合约支持闪电贷,但是还款借款流程还是需要业务代码自己构建出来的。

这是它的全流程链路我看下代码还是有很强的严谨性。
文章采用 知识共享署名 4.0 国际许可协议 进行许可,转载时请注明原文链接。