Skip to content

Commit

Permalink
- perf: A code change that improves performance , and testing with se…
Browse files Browse the repository at this point in the history
…polia
  • Loading branch information
Alex992Y committed Apr 13, 2024
1 parent f034371 commit f2fd9bd
Show file tree
Hide file tree
Showing 19 changed files with 372 additions and 160 deletions.
2 changes: 1 addition & 1 deletion basic/19-brownie/README-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ brownie test
### 执行脚本

```sh
brownie run *.py --network goerli
brownie run *.py --network sepolia
```

## pytest
Expand Down
7 changes: 4 additions & 3 deletions basic/19-brownie/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,12 @@ brownie test
```

### execute script
如果编写了自己的脚本,可以执行如下命令执行脚本
If you have written your own script, you can execute the following command to execute the script
```sh
## 设置 INFURA 环境变量,其中 xxx 替换为真实的 INFURA_ID 后执行
##Set the INFURA environment variable, where xxx is replaced with the actual INFURAID and executed

export WEB3_INFURA_PROJECT_ID=xxx
brownie run *.py --network goerli
brownie run *.py --network sepolia
```

## pytest
Expand Down
143 changes: 99 additions & 44 deletions basic/20-flash-loan/aave/README-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,100 +5,155 @@

## 闪电贷智能合约逻辑说明
### Flashloan 说明
来看下 `contracts/Flashloan.sol`
来看下 `contracts/SimpleFlashLoan.sol` (aave v3版本)
```solidity
import "https://github.com/aave/flashloan-box/blob/Remix/contracts/aave/FlashLoanReceiverBase.sol";
import "https://github.com/aave/flashloan-box/blob/Remix/contracts/aave/ILendingPoolAddressesProvider.sol";
import "https://github.com/aave/flashloan-box/blob/Remix/contracts/aave/ILendingPool.sol";
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";
contract Flashloan is FlashLoanReceiverBase {
constructor(address _addressProvider) FlashLoanReceiverBase(_addressProvider) public {}
}
constructor(address _addressProvider) FlashLoanSimpleReceiverBase(IPoolAddressesProvider(_addressProvider)) {
owner = payable(msg.sender);
}
```

这是导入所必要的依赖项,Flashloan 合约继承自`FlashLoanReceiverBase`,它是一个抽象合约,提供了一些有用的方法,比如如偿还闪电贷的方式。 Flashloan.sol 构造函数接受 Aave 的一个贷款池提供者的地址。我们会稍后将介绍。
这是导入所必要的依赖项,Flashloan 合约继承自`FlashLoanSimpleReceiverBase`,它是一个抽象合约,提供了一些有用的方法,比如如偿还闪电贷的方式。
SimpleFlashloan.sol 构造函数接受 Aave 的一借贷池的地址(deploy_aave_flashloan.js 脚本中配置对应的PoolAddressesProvider)。

创建地址类型的变量所有者(有些代码中并未设置此owner,意味着所有人都可以调用该合约),并将其设为可支付。

aave v3 对一些方法做了简化,因此有些方法名称后面加了Simple关键字

aave v3 合约名称相较v1有了变化(其实内部还是调用之前老的合约,可能是觉得之前的名字太长不好记忆,就修改了些), 具体变化参考:[AAVEf : supported-networks](https://docs.aave.com/developers/deployed-contracts/v3-testnet-addresses)
本文以Sepolia测试网络为例,选择Ethereum Sepolia,对于不同的测试网络,需要在deploy_aave_flashloan.js 脚本中配置对应的PoolAddressesProvider
<center><img src="./img/aave-v3-namechange.png?raw=true" /></center>
<center><img src="./img/sepolia-testnet.png?raw=true" /></center>

### flashloan 方法
我们先来看 flashLoan 函数。


### flashloanSimple 方法
requestFlashLoan 方法中的核心是调用 POOL.flashLoanSimple(), POOL 变量被定义在FlashLoanSimpleReceiverBase中,是IPool 的实例
```solidity
function flashloan(address _asset) public { // 去掉 onlyOwner,任何人都可调用 flashloan
bytes memory data = "";
uint amount = 1 ether;
function flashLoanSimple(
address receiverAddress,
address asset,
uint256 amount,
bytes calldata params,
uint16 referralCode
) external;
ILendingPool lendingPool = ILendingPool(addressesProvider.getLendingPool());
lendingPool.flashLoan(address(this), _asset, amount, data);
}
```

flashLoan 的参数`_asset`是我们要用闪电贷借款的资产地址,比如 ETH 或 DAI。
如下是 FlashLoanSimpleReceiverBase 合约中的定义(大致了解即可)
```solidity
abstract contract FlashLoanSimpleReceiverBase is IFlashLoanSimpleReceiver {
IPoolAddressesProvider public immutable override ADDRESSES_PROVIDER;
IPool public immutable override POOL;
constructor(IPoolAddressesProvider provider) {
ADDRESSES_PROVIDER = provider;
POOL = IPool(provider.getPool());
}
```

通过连接 Aave 的FlashLoanSimpleReceiverBase合约来启动SimpleFlashLoan合约

requestFlashLoan 的参数`_asset`是我们要用闪电贷借款的资产地址,比如 ETH, DAI 或者 USDC。
<center><img src="./img/token_address.png?raw=true" /></center>

`uint amount = 1 ether;`
在这里,我们定义的借款金额的单位是`ether`,如果把 ETH 地址传过去,我们就会借到 1 个 ETH,即 10^18 wei。如果把 DAI 地址传给 `_asset`,我们就会借到 1 个 DAI。
amount 是我们将借用的代币数量,如果把 ETH 地址传过去,我们就会借到 1 个 ETH,即 10^18 wei。如果把 DAI 地址传给 `_asset`,我们就会借到 1 个 DAI。
还有两个我们不会使用但 Aave 合约需要的参数。

现在,我们可以使用 Aave 提供的 `ILendingPool`接口,调用`flashLoan`函数,其中包含所有需要的参数,如我们想要借入的资产、该资产的金额和一个额外的`data`参数。
params - 是贷款的一些附加信息,例如消息或短语
ReferralCode - 暂时不明白这个参数的含义

我们还要关注 `executeOperation`
FlashLoanSimpleReceiverBase 内部的 _addressProvider 变量将被传入到 IPoolAddressesProvider 接口中,之后将在那里调用 getPool() 函数,该函数将返回代理池(实现闪贷所有功能的合约)的地址。
而这一切都将保存在 POOL 变量中,该变量需要像我们的地址一样被包装在 IPOOL 接口中,以便访问合约的 Proxy Pool 功能。

### executeOperation 方法

`executeOperation` 函数将被 `LendingPool` 合约在闪电贷中请求有效的资产后被调用。

```solidity
function executeOperation(
address _reserve, uint256 _amount,
uint256 _fee, bytes calldata _params
)
external override
{
require(_amount <= getBalanceInternal(address(this), _reserve), "Invalid balance, was the flashLoan successful?");
function executeOperation(
address asset,
uint256 amount,
uint256 premium,
address initiator,
bytes calldata params
) external override returns(bool){
str = "New Logic in FlashLoans";
//
// Your logic goes here.
// !! Ensure that *this contract* has enough of `_reserve` funds to payback the `_fee` !!
//
uint256 totalAmount = amount + premium;
IERC20(asset).approve(address(POOL),totalAmount);
return true;
uint totalDebt = _amount.add(_fee);
transferFundsBackToPoolInternal(_reserve, totalDebt);
}
}
}
```

在使用 `flashLoan` 函数触发有效的闪电贷后,`executeOperation` 函数的所有参数都将被自动传递,`require` 用来确保收到的闪电贷金额是否正确。
在使用 `requestFlashLoan` 函数触发有效的闪电贷后,`executeOperation` 函数的所有参数都将被自动传递,

接下来,我们可以插入任何想要执行的逻辑。在这个步骤中,我们拥有了来自闪电贷的所有可用资金,因此,我们可以尝试套利机会。

我们在用完闪电贷后,就需要偿还资金了。

`uint totalDebt = _amount.add(_fee);`
`uint totalAmount = amount + premium`

在这里,我们要计算还多少钱,也就是 **借款金额 + Aave借贷手续费(通常为金额的0.05%)** , premium 也可以固定设置 amount * 0.05%。

在这里,我们要计算还多少钱,也就是 **借款金额 + 借款金额的 0.09%(Aave 的闪电贷需要手续费)**
最后一步就是调用 `IERC20(asset).approve(address(POOL),totalAmount)` 来偿还闪电贷

最后一步就是调用 `transferFundsBackToPoolInternal` 来偿还闪电贷。
## AAVE FAUCET
我们的智能合约中需要一些 Testnet USDC(本文使用USD C作为贷款货币) 来支付闪电贷的利息。进入Aave的水龙头,选择Ethereum Market,连接MetaMask,点击USDC附近的 Faucet 即可获取USDC。
<center><img src="./img/aave_faucet.png?raw=true" /></center>

## 操作步骤

## 操作步骤
- 安装依赖
```shell
yarn
#Node 版本v20.11.0
npm init
npm install --save-dev hardhat
npx hardhat
npm install --save-dev "hardhat@^2.21.0" "@nomicfoundation/hardhat-toolbox@^2.0.0"
```

- 安装aav核心包
```shell
npm install @aave/core-v3
```

- 配置环境变量
```shell
cp .env.example .env
# 在 .env 中配置 INFURA_ID , PRIVATE_KEY
# Node version: v20.11.0
```

- 部署合约
```shell
# 这里使用 kovan 测试网进行测试
npx hardhat run scripts/deploy_aave_flashloan.js --network kovan
```
# 这里使用 sepolia 测试网进行测试
npx hardhat run scripts/deploy_aave_flashloan.js --network sepolia

- 发起闪电贷
```shell
npx hardhat test --network kovan
# 交易完成后,根据答应的 tx hash 检查交易细节
```
交易完成后,根据打印的 Transaction hash 登录 [Etherscan](https://sepolia.etherscan.io/)查看交易详情

<center><img src="./img/etherscan_query.png?raw=true" /></center>
<center><img src="./img/transaction_detail.png?raw=true" /></center>

恭喜您执行闪贷;您借了一笔无抵押贷款。在本指南中,我们了解了闪电贷,创建并部署了 Aave V3 闪电贷合约,借入了一些无需抵押的代币,并收取利息费用返还

## 参考

Expand Down
Loading

0 comments on commit f2fd9bd

Please sign in to comment.