解释了实现第一笔闪电贷最基本的方法和原理
闪电贷(Flash loan)是 DeFi 中一个独特的产品,在传统金融活动中没有与之对应的事物。会编写和使用闪电贷也是一项很重要的技能。
闪电贷是一种无抵押、借贷金额无上限(可以借光池中所有的钱)的贷款。它要求借贷人快借快还,快到还款和借款在同一个交易内(同一个以太坊 transaction)。
闪电贷要求每笔借款在归还时,除了归还本金,还要支付一定利息。该利息(或称手续费)由系统动态计算。
很多人对理解闪电贷有一定的难度。因为这需要了解智能合约执行原理和以太坊状态变化的机制。我们通过自己编写一个闪电贷合约,来理解其背后的运行原理。
以使用 Aave 提供的闪电贷为例,编写一个你自己的合约非常简单,你只需要实现一个叫 executeOperation 的方法。
executeOperation 方法参数中 _reserve 是所借代币的合约地址,如果是 ETH 则是一个特殊的地址(在 Aave 中用 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 来表示 ETH),_amount 是借款的金额,_fee 是本次借款要偿还的利息。_params 暂时可忽略。
function executeOperation(
address _reserve,
uint256 _amount,
uint256 _fee,
bytes calldata _params
)
external
{
require(_amount <= getBalanceInternal(address(this), _reserve), "借款失败");
//
// 用借来的 ETH 去赚取更多的 ETH
//
// 还款
uint totalDebt = _amount.add(_fee);
transferFundsBackToPoolInternal(_reserve, totalDebt);
}
当代码执行到 executeOperation 时,你已经拿到了借来的钱,你主要是写如何利用这些钱赚取更多钱的逻辑。例如你发现同一个交易对 A/ETH 在 DEX1(价格低) 和 DEX2(价格高) 的价格差较大,那么你的赚钱逻辑为:
已借得 100 ETH;
在价格低的 DEX1 中买入A;
在价格高的 DEX2 中卖出A;
卖得 110 ETH。
executeOperation 是借款成功后要执行的逻辑。而开始借款的逻辑需要用户自己触发(通过发送交易调用合约),或者直接写在合约的构造函数里。例如:
function flashloan() public onlyOwner {
bytes memory data = "";
uint amount = 100 ether;
address asset = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); //借 ETH
ILendingPool lendingPool = ILendingPool(addressesProvider.getLendingPool());
lendingPool.flashLoan(address(this), asset, amount, data);
}
flashLoan() 是真正的借款函数,例子中是借入 100 ETH。闪电贷由此方法触发(开始),也由此方法结束。要完全理解它,我们需要看看 flashLoan() 的内部逻辑。我们摘取最重要的部分。
flashLoan() 中首先进行各项数据验证,然后便借款给你,紧接着调用你的 executeOperation 的赚钱逻辑,最后验证你是否归还了本金加利息。主要逻辑如下所示:
//各种数据验证,池中是否还有足够的钱可以贷出?计算手续费等等
//将借款转给你
core.transferToUser(_reserve, userPayable, _amount);
//执行你的合约的赚钱逻辑(步骤1中所写的函数)
receiver.executeOperation(_reserve, _amount, amountFee, _params);
//检查目前池中余额
uint256 availableLiquidityAfter = _reserve == EthAddressLib.ethAddress()
? address(core).balance
: IERC20(_reserve).balanceOf(address(core));
//通过池中余额变化来确认你是否已经归还了借款+利息
require(
availableLiquidityAfter == availableLiquidityBefore.add(amountFee),
"The actual balance of the protocol is inconsistent"
);
如果 require() 验证失败,它将 revert 整个交易,让借款无效,从而保证借出方总是安全的。
以上解释了实现第一笔闪电贷最基本的方法和原理。编译源码,以及部署到线上,大家可以参考 Aave 相关官方文档,这里就不一一介绍了。
编写闪电贷合约总体并不复杂。使用闪电贷风险也比较小。如果赚钱逻辑失败,变成了亏钱逻辑,不能完成还款,那么也不用担心借来的巨款(如 1万 ETH)无力偿还。整个交易将会执行失败,就如同借款从来没有发生过一样。
转自公众号”谈谈区块链“ 链接:https://mp.weixin.qq.com/s/6BpXMj9hRfnLheFFQsykWA
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!