闪电贷
Uniswap V2和V3都实现了闪电贷:无限制且无抵押的贷款,必须在同一笔交易中偿还。资金池给用户他们请求的任意数量的代币,但在调用结束时,这些数量必须被偿还,并附加一小笔费用。
闪电贷必须在同一笔交易中偿还这一事实意味着普通用户无法进行闪电贷:作为用户,你无法在交易中编程自定义逻辑。闪电贷只能由智能合约进行和偿还。
闪电贷是DeFi中一种强大的金融工具。虽然它经常被用来利用DeFi协议中的漏洞(通过膨胀资金池余额和滥用有缺陷的状态管理),但它也有许多好的应用(例如,在借贷协议上管理杠杆头寸)——这就是为什么存储流动性的DeFi应用程序提供无需许可的闪电贷。
实现闪电贷
在Uniswap V2中,闪电贷是交换功能的一部分:可以在交换过程中借入代币,但你必须在同一笔交易中归还它们或等量的另一种资金池代币。在V3中,闪电贷与交换分离——它只是一个函数,给调用者他们请求的数量的代币,在调用者上调用回调,并确保闪电贷被偿还:
function flash(
uint256 amount0,
uint256 amount1,
bytes calldata data
) public {
uint256 balance0Before = IERC20(token0).balanceOf(address(this));
uint256 balance1Before = IERC20(token1).balanceOf(address(this));
if (amount0 > 0) IERC20(token0).transfer(msg.sender, amount0);
if (amount1 > 0) IERC20(token1).transfer(msg.sender, amount1);
IUniswapV3FlashCallback(msg.sender).uniswapV3FlashCallback(data);
require(IERC20(token0).balanceOf(address(this)) >= balance0Before);
require(IERC20(token1).balanceOf(address(this)) >= balance1Before);
emit Flash(msg.sender, amount0, amount1);
}
该函数将代币发送给调用者,然后在调用者上调用uniswapV3FlashCallback
——这是期望调用者偿还贷款的地方。然后,该函数确保其余额没有减少。注意,允许将自定义数据传递给回调。
以下是回调实现的一个例子:
function uniswapV3FlashCallback(bytes calldata data) public {
(uint256 amount0, uint256 amount1) = abi.decode(
data,
(uint256, uint256)
);
if (amount0 > 0) token0.transfer(msg.sender, amount0);
if (amount1 > 0) token1.transfer(msg.sender, amount1);
}
在这个实现中,我们只是简单地将代币发送回资金池(我在flash
函数测试中使用了这个回调)。在实际情况下,它可以使用借来的金额在其他DeFi协议上执行一些操作。但它总是必须在这个回调中偿还贷款。
就是这样!