本文主要是介绍Solidity Uniswap V2 Flash loans,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Flash loans是一种非常强大的金融工具,在传统金融中没有类似的工具。它是一种无限制、无抵押的贷款,必须在接受贷款的同一交易中偿还。Uniswap 就是能提供闪电贷款的平台之一。让我们把它们添加到合同中,看看它们是如何工作的。
GitHub - XuHugo/solidityproject: DApp go go go !!!
关于闪电贷款的实现,你需要知道的第一件事就是它们只能由智能合约使用。下面是闪贷的借款和还款方式:
1一个智能合约从另一个合约借入闪贷。
2出借合约向借款合约发送代币,并调用该合约中的一个特殊函数。
3在特殊函数中,借款合约对贷款执行一些操作,然后将贷款转回。
4贷方合约确保全额还款。如果有费用,它也会确保费用已支付。
5控制流返回借款合同。
要在 Zuniswap 中添加闪贷,我们需要做一些改动。首先,更新 swap,增加一个参数:
function swap(uint256 amount0Out,uint256 amount1Out,address to,bytes calldata data) public {
新参数是一个字节数组数据。它可以包含任何文学内容。
下一步是实际发放贷款。请记住,我们在交换函数中进行了乐观的转账:
...if (amount0Out > 0) _safeTransfer(token0, to, amount0Out);if (amount1Out > 0) _safeTransfer(token1, to, amount1Out);...
这意味着我们已经在不要求抵押的情况下提供了任意数量(输出量由用户指定)的代币!我们唯一需要做的就是让调用者偿还贷款。为此,我们需要调用调用者合约中的一个特殊函数:
...if (amount0Out > 0) _safeTransfer(token0, to, amount0Out);if (amount1Out > 0) _safeTransfer(token1, to, amount1Out);if (data.length > 0) IZuniswapV2Callee(to).zuniswapV2Call(msg.sender, amount0Out, amount1Out, data);...
根据我们定义的约定,我们希望调用者合约实现 zuniswapV2Call 函数,该函数接收:发送者地址、第一输出量、第二输出量和新数据参数。合同中的其他内容保持不变!同样,这也是一个非常优雅和简单的解决方案。
基本上就是这样!事实证明,我们已经实现了检查贷款是否偿还的逻辑--这与检查新 K 是否有效的逻辑相同!
现在,让我们来测试一下 Flash 贷款!我希望在添加测试后,整个流程会更加清晰。
如上所述,要使用闪电贷款,我们需要一个智能合约。为了测试闪电贷款,我们需要一个单独的合约--让我们称它为 Flashloaner:
contract Flashloaner {error InsufficientFlashLoanAmount();uint256 expectedLoanAmount;...}
合同将实现两个功能:
第一个函数将从 Zuniswap 借入闪存贷款。
第二个函数 zuniswapV2Call 将处理贷款并偿还贷款。
获取闪贷和swap一样简单:
function flashloan(address pairAddress,uint256 amount0Out,uint256 amount1Out,address tokenAddress) public {if (amount0Out > 0) {expectedLoanAmount = amount0Out;}if (amount1Out > 0) {expectedLoanAmount = amount1Out;}ZuniswapV2Pair(pairAddress).swap(amount0Out,amount1Out,address(this),abi.encode(tokenAddress));}
在进行swap之前,我们要设置预期贷款额,以便日后检查所请求的token数额是否确实已发放给我们。
在swap函数中,请注意我们传递了 tokenAddress 作为数据参数--我们稍后将使用它来偿还贷款。或者,我们也可以将该地址存储在状态变量中。由于数据是字节数组,我们需要一种将地址转换为字节的方法,而 abi.encode 是一种常用的解决方案。
现在是闪存贷款处理程序:
function zuniswapV2Call(address sender,uint256 amount0Out,uint256 amount1Out,bytes calldata data) public {address tokenAddress = abi.decode(data, (address));uint256 balance = ERC20(tokenAddress).balanceOf(address(this));if (balance < expectedLoanAmount) revert InsufficientFlashLoanAmount();ERC20(tokenAddress).transfer(msg.sender, balance);}
这是我们在 flashloan 中调用的交换函数中的配对合约将调用的函数。pair合约还会把我们输入的任何数据传给swap。
在处理函数中,我们要确保我们确实获得了所请求的贷款,而且我们只是在还贷。与其偿还贷款,我们还可以将其用于杠杆、套利或利用智能合约中的漏洞等用途。Flash 贷款是一个非常强大的工具,可以用来做好事,也可以用来做坏事。
最后,让我们添加一个测试,获取贷款并确保偿还正确的金额:
function testFlashloan() public {token0.transfer(address(pair), 1 ether);token1.transfer(address(pair), 2 ether);pair.mint(address(this));uint256 flashloanAmount = 0.1 ether;uint256 flashloanFee = (flashloanAmount * 1000) / 997 - flashloanAmount + 1;Flashloaner fl = new Flashloaner();token1.transfer(address(fl), flashloanFee);fl.flashloan(address(pair), 0, flashloanAmount, address(token1));assertEq(token1.balanceOf(address(fl)), 0);assertEq(token1.balanceOf(address(pair)), 2 ether + flashloanFee);}
问题是,Uniswap V2 对闪贷收取了费用:我们必须支付闪贷的交换费。回想一下,我们并没有对闪贷是否偿还进行额外检查,我们只是使用了新的 k 计算方法。这种计算方法会从余额中减去掉期费用!因此,在归还闪贷时,我们必须支付所借金额 + 0.3%(实际略高于 0.3009027%)。
为了让 Flashloaner 全额还款,我们要计算 flashloanFee 并将其发送到合同中。闪贷还清后,Flashloaner 的余额为 0,而pair合约将获得手续费。
这篇关于Solidity Uniswap V2 Flash loans的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!