@aave/aave-token 中文文档教程

发布于 3年前 浏览 55 更新于 3年前

Aave Token design

AAVE 是 ERC-20 兼容代币。 它实现了受治理启发的功能,并将允许 Aave 引导安全和生态系统增长的奖励计划。 以下文档解释了 AAVE 的主要特征、货币政策以及 LEND 的赎回过程。

Getting Started

您可以将 @aave/aave-token 作为 NPM 包安装在 Hardhat、Buidler 或 Truffle 项目中以导入合约和接口:

npm install @aave/aave-token

在 Solidity 文件中导入:

import {IGovernancePowerDelegationToken} from "aave-token/contracts/interfaces/IGovernancePowerDelegationToken.sol";

contract Misc {
  function getPower(address token, address user, uint8 type) {
    IGovernancePowerDelegationToken(token).getPowerCurrent(user, type);
    {...}
  }
}

带有 ABI 和字节码的 JSON 工件也包含在 artifacts/ 目录中的捆绑 NPM 包中。

通过 Node JS require 导入 JSON 文件:

const AaveTokenV2Artifact = require('@aave/aave-token/artifacts/contracts/token/AaveTokenV2.sol/AaveTokenV2.json');

// Log the ABI into console
console.log(AaveTokenV2Artifact.abi)

Roles

初始 AAVE 令牌实现没有配置任何管理员角色。 合约将使用 EIP-1967 透明代理模式的 Openzeppelin 实现进行代理。 代理具有管理员角色,代理合约的管理员将在部署到 Aave 治理合约时设置。

ERC-20

AAVE 代币实现了 ERC-20 接口的标准方法。 添加了余额快照功能,以跟踪特定区块高度的用户余额。 这将有助于 AAVE 的 Aave 治理集成。 AAVE 还集成了 EIP 2612 permit 功能,这将允许 gas 交易和一次 tx 批准/转移。

LendToAaveMigrator

LEND 代币持有者执行向 AAVE 代币迁移的智能合约,使用 AAVE 的部分初始排放。

该合约由代理人覆盖,其所有者将是 AAVE 的治理者。 一旦治理通过相应的提案,代理将连接到实施,LEND 持有者将能够调用 migrateFromLend() 函数,该函数在 LEND 批准后,将从持有者钱包中提取 LEND并转回由 LEND_AAVE_RATIO 常量定义的等效 AAVE 金额。

migrateFromLend() 的一项权衡是,由于 AAVE 总供应量将低于 LEND,因此 LEND_AAVE_RATIO 将始终 > 1,导致不是 LEND_AAVE_RATIO 倍数的 LEND 数量的精度损失。 例如,发送 1.000000000000000022 LEND 且 LEND_AAVE_RATIO == 100 的人将收到 0.01 AAVE,失去 LEND 最后 22 个小单位的价值。 考虑到 LEND 的当前值和 AAVE 的未来值,小于 LENDAAVERATIO 的小单位缺乏精度表示值比 0.01\$ 小几个数量级。 我们为此评估了一些潜在的解决方案,具体

  1. Rounding half up the amount of AAVE returned from the migration. This opens up to potential attacks where users might purposely migrate less than LENDAAVERATIO to obtain more AAVE as a result of the round up.
  2. Returning back the excess LEND: this would leave LEND in circulation forever, which is not the expected end result of the migration.
  3. Require the users to migrate only amounts that are multiple of LENDAAVERATIO: This presents considerable UX friction.

而言: 这些解决方案都没有比已实施的解决方案更好的结果。

The Redemption process

启动 AAVE 排放的第一步是部署 AAVE 代币合约和  LendToAaveMigrator 合约。 该任务将由 Aave 团队执行。 部署后,AAVE 合约代理和 LendToAaveMigrator 的所有权将设置为 Aave 治理。 为了在那时开始 LEND 赎回过程,Aave 团队将创建一个 AIP(Aave 改进提案)并向 Aave 治理提交提案。 该提案一旦获得批准,将激活 LEND/AAVE 赎回流程和生态系统激励,这将标志着 AAVE 在市场上的首次发行。 迁移过程的结果是,LEND 的供应将逐步锁定在新的 AAVE 智能合约中,同时发行等量的 AAVE。   与 AAVE 协议初始阶段销毁的 LEND 代币相当的 AAVE 数量将保持锁定在 LendToAaveMigrator 合约中。

Technical implementation

Changes to the Openzeppelin original contracts

在此实现的上下文中,我们需要对 OpenZepplin 实现进行以下更改:

  • In /contracts/open-zeppelin/ERC20.sol, line 44 and 45, _name and _symbol have been changed from private to internal
  • We extended the original Initializable class from the Openzeppelin contracts and created a VersionedInitializable contract. The main differences compared to the Initializable are:
  1. The boolean initialized has been replaced with a uint256 latestInitializedRevision.
  2. The initializer() modifier fetch the revision of the implementation using a getRevision() function defined in the implementation contract. The initializer modifier forces that an implementation
  3. with a bigger revision number than the current one is being initialized

更改允许我们在多个实现上调用 initialize(),这在原始 Initializable< 中是不可能的/code> 来自 OZ 的实现。

_beforeTokenTransfer hook

我们覆盖 OZ 基础 ERC20 实现上的 _beforeTokenTransfer 函数,以包括以下功能:

  1. Snapshotting of balances every time an action involved a transfer happens (mint, burn, transfer or transferFrom). If the account does a transfer to itself, no new snapshot is done.
  2. Call to the Aave governance contract forwarding the same input parameters of the _beforeTokenTransfer hook. Its an assumption that the Aave governance contract is a trustable party, being its responsibility to control all potential reentrancies if calling back the AaveToken. If the account does a transfer to itself, no interaction with the Aave governance contract should happen.

Development deployment

出于开发目的,您可以通过以下命令将 AaveToken 和 LendToAaveMigrator 部署到本地网络:

npm run dev:deployment

对于任何其他网络,您可以在按照以下方式

npm run ropsten:deployment

您还可以设置一个可选的 $AAVE_ADMIN 环境变量来将 ETH 地址设置为 AaveToken 和 LendToAaveMigrator 代理的管理员。 如果未设置,部署将在 buidler.config.ts 中设置 accounts 网络配置的第二个帐户。

Mainnet deployment

您可以通过以下命令将 AaveToken 和 LendToAaveMigrator 部署到主网网络:

AAVE_ADMIN=governance_or_ETH_address
LEND_TOKEN=lend_token_address
npm run main:deployment

$AAVE_ADMIN 环境变量需要运行,设置一个 ETH 地址作为 AaveToken 和 LendToAaveMigrator 代理的管理员。 检查 buidler.config.ts 以获取主网部署所需的更多环境变量。

代理将在部署期间使用 $AAVE_ADMIN 地址初始化,但智能合约实现不会被初始化。

Enviroment Variables

VariableDescription
\$AAVE_ADMINETH Address of the admin of Proxy contracts. Optional for development.
\$LEND_TOKENETH Address of the LEND token. Optional for development.
\$INFURA_KEYInfura key, only required when using a network different than local network.
\$MNEMONIC_\<NETWORK>Mnemonic phrase, only required when using a network different than local network.
\$ETHERESCAN_KEYEtherscan key, not currently used, but will be required for contracts verification.

Audits

该存储库中的 Solidity 代码已经过 Consensys Diligence 和 Certik 的 2 次传统智能合约审计,以及 Certora 的属性验证过程。 报告如下:

Current Mainnet contracts (25/09/2020)

Credits

对于与代理相关的合约,我们使用了来自 OpenZeppelin 的朋友的实现。

License

此存储库的内容受 AGPLv3 许可。

Aave Token design

AAVE is an ERC-20 compatible token. It implements governance-inspired features, and will allow Aave to bootstrap the rewards program for safety and ecosystem growth. The following document explains the main features of AAVE, it’s monetary policy, and the redemption process from LEND.

Getting Started

You can install @aave/aave-token as an NPM package in your Hardhat, Buidler or Truffle project to import the contracts and interfaces:

npm install @aave/aave-token

Import at Solidity files:

import {IGovernancePowerDelegationToken} from "aave-token/contracts/interfaces/IGovernancePowerDelegationToken.sol";

contract Misc {
  function getPower(address token, address user, uint8 type) {
    IGovernancePowerDelegationToken(token).getPowerCurrent(user, type);
    {...}
  }
}

The JSON artifacts with the ABI and Bytecode are also included into the bundled NPM package at artifacts/ directory.

Import JSON file via Node JS require:

const AaveTokenV2Artifact = require('@aave/aave-token/artifacts/contracts/token/AaveTokenV2.sol/AaveTokenV2.json');

// Log the ABI into console
console.log(AaveTokenV2Artifact.abi)

Roles

The initial AAVE token implementation does not have any admin roles configured. The contract will be proxied using the Openzeppelin implementation of the EIP-1967 Transparent Proxy pattern. The proxy has an Admin role, and the Admin of the proxy contract will be set upon deployment to the Aave governance contracts.

ERC-20

The AAVE token implements the standard methods of the ERC-20 interface. A balance snapshot feature has been added to keep track of the balances of the users at specific block heights. This will help with the Aave governance integration of AAVE. AAVE also integrates the EIP 2612 permit function, that will allow gasless transaction and one tx approval/transfer.

LendToAaveMigrator

Smart contract for LEND token holders to execute the migration to the AAVE token, using part of the initial emission of AAVE for it.

The contract is covered by a proxy, whose owner will be the AAVE governance. Once the governance passes the corresponding proposal, the proxy will be connected to the implementation and LEND holders will be able to call the migrateFromLend() function, which, after LEND approval, will pull LEND from the holder wallet and transfer back an equivalent AAVE amount defined by the LEND_AAVE_RATIO constant.

One tradeOff of migrateFromLend() is that, as the AAVE total supply will be lower than LEND, the LEND_AAVE_RATIO will be always > 1, causing a loss of precision for amounts of LEND that are not multiple of LEND_AAVE_RATIO. E.g. a person sending 1.000000000000000022 LEND, with a LEND_AAVE_RATIO == 100, will receive 0.01 AAVE, losing the value of the last 22 small units of LEND. Taking into account the current value of LEND and the future value of AAVE, a lack of precision for less than LENDAAVERATIO small units represents a value several orders of magnitude smaller than 0.01\$. We evaluated some potential solutions for this, specifically:

  1. Rounding half up the amount of AAVE returned from the migration. This opens up to potential attacks where users might purposely migrate less than LENDAAVERATIO to obtain more AAVE as a result of the round up.
  2. Returning back the excess LEND: this would leave LEND in circulation forever, which is not the expected end result of the migration.
  3. Require the users to migrate only amounts that are multiple of LENDAAVERATIO: This presents considerable UX friction.

None of those present a better outcome than the implemented solution.

The Redemption process

The first step to bootstrap the AAVE emission is to deploy the AAVE token contract and the  LendToAaveMigrator contract. This task will be performed by the Aave team. Upon deployment, the ownership of the Proxy of the AAVE contract and the LendToAaveMigrator will be set to the Aave Governance. To start the LEND redemption process at that point, the Aave team will create an AIP (Aave Improvement Proposal) and submit a proposal to the Aave governance. The proposal will, once approved, activate the LEND/AAVE redemption process and the ecosystem incentives, which will mark the initial emission of AAVE on the market. The result of the migration procedure will see the supply of LEND being progressively locked within the new AAVE smart contract, while at the same time an equivalent amount of AAVE is being issued.   The amount of AAVE equivalent to the LEND tokens burned in the initial phase of the AAVE protocol will remain locked in the LendToAaveMigrator contract.

Technical implementation

Changes to the Openzeppelin original contracts

In the context of this implementation, we needed apply the following changes to the OpenZepplin implementation:

  • In /contracts/open-zeppelin/ERC20.sol, line 44 and 45, _name and _symbol have been changed from private to internal
  • We extended the original Initializable class from the Openzeppelin contracts and created a VersionedInitializable contract. The main differences compared to the Initializable are:
  1. The boolean initialized has been replaced with a uint256 latestInitializedRevision.
  2. The initializer() modifier fetch the revision of the implementation using a getRevision() function defined in the implementation contract. The initializer modifier forces that an implementation
  3. with a bigger revision number than the current one is being initialized

The change allows us to call initialize() on multiple implementations, that was not possible with the original Initializable implementation from OZ.

_beforeTokenTransfer hook

We override the _beforeTokenTransfer function on the OZ base ERC20 implementation in order to include the following features:

  1. Snapshotting of balances every time an action involved a transfer happens (mint, burn, transfer or transferFrom). If the account does a transfer to itself, no new snapshot is done.
  2. Call to the Aave governance contract forwarding the same input parameters of the _beforeTokenTransfer hook. Its an assumption that the Aave governance contract is a trustable party, being its responsibility to control all potential reentrancies if calling back the AaveToken. If the account does a transfer to itself, no interaction with the Aave governance contract should happen.

Development deployment

For development purposes, you can deploy AaveToken and LendToAaveMigrator to a local network via the following command:

npm run dev:deployment

For any other network, you can run the deployment in the following way

npm run ropsten:deployment

You can also set an optional $AAVE_ADMIN enviroment variable to set an ETH address as the admin of the AaveToken and LendToAaveMigrator proxies. If not set, the deployment will set the second account of the accounts network configuration at buidler.config.ts.

Mainnet deployment

You can deploy AaveToken and LendToAaveMigrator to the mainnet network via the following command:

AAVE_ADMIN=governance_or_ETH_address
LEND_TOKEN=lend_token_address
npm run main:deployment

The $AAVE_ADMIN enviroment variable is required to run, set an ETH address as the admin of the AaveToken and LendToAaveMigrator proxies. Check buidler.config.ts for more required enviroment variables for Mainnet deployment.

The proxies will be initialized during the deployment with the $AAVE_ADMIN address, but the smart contracts implementations will not be initialized.

Enviroment Variables

VariableDescription
\$AAVE_ADMINETH Address of the admin of Proxy contracts. Optional for development.
\$LEND_TOKENETH Address of the LEND token. Optional for development.
\$INFURA_KEYInfura key, only required when using a network different than local network.
\$MNEMONIC_\<NETWORK>Mnemonic phrase, only required when using a network different than local network.
\$ETHERESCAN_KEYEtherscan key, not currently used, but will be required for contracts verification.

Audits

The Solidity code in this repository has undergone 2 traditional smart contracts' audits by Consensys Diligence and Certik, and properties' verification process by Certora. The reports are:

Current Mainnet contracts (25/09/2020)

Credits

For the proxy-related contracts, we have used the implementation of our friend from OpenZeppelin.

License

The contents of this repository are under the AGPLv3 license.

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文