Skip to content

Commit b6658e3

Browse files
committed
- Initial commit
0 parents  commit b6658e3

File tree

96 files changed

+34523
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+34523
-0
lines changed

.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.env
2+
#Buidler files
3+
cache
4+
artifacts
5+
6+
node_modules
7+
dist/
8+
build/
9+
.vscode
10+
11+
coverage
12+
.coverage_artifacts
13+
.coverage_cache
14+
.coverage_contracts

.solcover.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const accounts = require(`./test-wallets.js`).accounts;
2+
3+
module.exports = {
4+
skipFiles: ["open-zeppelin/"],
5+
mocha: {
6+
enableTimeouts: false,
7+
},
8+
providerOptions: {
9+
accounts,
10+
_chainId: 1337,
11+
_chainIdRpc: 1337,
12+
network_id: 1337,
13+
},
14+
};

Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
FROM ethereum/solc:0.6.10 as build-deps
2+
3+
FROM node:13
4+
COPY --from=build-deps /usr/bin/solc /usr/bin/solc

LICENSE.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
3+
Aave Token
4+
5+
Copyright (C) 2020 Aave
6+
7+
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.
8+
9+
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details

README.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Aave Token design
2+
3+
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.
4+
The following document explains the main features of AAVE, it’s monetary policy, and the redemption process from LEND.
5+
6+
## Roles
7+
8+
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.
9+
10+
## ERC-20
11+
12+
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.
13+
AAVE also integrates the EIP 2612 `permit` function, that will allow gasless transaction and one tx approval/transfer.
14+
15+
# LendToAaveMigrator
16+
17+
Smart contract for LEND token holders to execute the migration to the AAVE token, using part of the initial emission of AAVE for it.
18+
19+
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.
20+
21+
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.
22+
Taking into account the current value of LEND and the future value of AAVE, a lack of precision for less than LEND_AAVE_RATIO small units represents a value several orders of magnitude smaller than 0.01\$. We evaluated some potential solutions for this, specifically:
23+
24+
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 LEND_AAVE_RATIO to obtain more AAVE as a result of the round up.
25+
2. Returning back the excess LEND: this would leave LEND in circulation forever, which is not the expected end result of the migration.
26+
3. Require the users to migrate only amounts that are multiple of LEND_AAVE_RATIO: This presents considerable UX friction.
27+
28+
None of those present a better outcome than the implemented solution.
29+
30+
## The Redemption process
31+
32+
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.
33+
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.  
34+
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.
35+
36+
## Technical implementation
37+
38+
### Changes to the Openzeppelin original contracts
39+
40+
In the context of this implementation, we needed apply the following changes to the OpenZepplin implementation:
41+
42+
- In `/contracts/open-zeppelin/ERC20.sol`, line 44 and 45, `_name` and `_symbol` have been changed from `private` to `internal`
43+
- We extended the original `Initializable` class from the Openzeppelin contracts and created a `VersionedInitializable` contract. The main differences compared to the `Initializable` are:
44+
45+
1. The boolean `initialized` has been replaced with a `uint256 latestInitializedRevision`.
46+
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
47+
3. with a bigger revision number than the current one is being initialized
48+
49+
The change allows us to call `initialize()` on multiple implementations, that was not possible with the original `Initializable` implementation from OZ.
50+
51+
### \_beforeTokenTransfer hook
52+
53+
We override the \_beforeTokenTransfer function on the OZ base ERC20 implementation in order to include the following features:
54+
55+
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.
56+
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.
57+
58+
## Development deployment
59+
60+
For development purposes, you can deploy AaveToken and LendToAaveMigrator to a local network via the following command:
61+
62+
```
63+
npm run dev:deployment
64+
```
65+
66+
For any other network, you can run the deployment in the following way
67+
68+
```
69+
npm run ropsten:deployment
70+
```
71+
72+
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`.
73+
74+
## Mainnet deployment
75+
76+
You can deploy AaveToken and LendToAaveMigrator to the mainnet network via the following command:
77+
78+
```
79+
AAVE_ADMIN=governance_or_ETH_address
80+
LEND_TOKEN=lend_token_address
81+
npm run main:deployment
82+
```
83+
84+
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.
85+
86+
The proxies will be initialized during the deployment with the `$AAVE_ADMIN` address, but the smart contracts implementations will not be initialized.
87+
88+
## Enviroment Variables
89+
90+
| Variable | Description |
91+
| ----------------------- | ----------------------------------------------------------------------------------- |
92+
| \$AAVE_ADMIN | ETH Address of the admin of Proxy contracts. Optional for development. |
93+
| \$LEND_TOKEN | ETH Address of the LEND token. Optional for development. |
94+
| \$INFURA_KEY | Infura key, only required when using a network different than local network. |
95+
| \$MNEMONIC\_\<NETWORK\> | Mnemonic phrase, only required when using a network different than local network. |
96+
| \$ETHERESCAN_KEY | Etherscan key, not currently used, but will be required for contracts verification. |
97+
98+
## Audits
99+
100+
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:
101+
- [Consensys Diligence](https://diligence.consensys.net/audits/private/g6kd633m-aave-token/)
102+
- [Certik](audits/AaveTokenReport_CertiK.pdf)
103+
- [Certora](audits/AaveTokenVerification_by_Certora.pdf)
104+
105+
## Credits
106+
107+
For the proxy-related contracts, we have used the implementation of our friend from [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-sdk/).
108+
109+
## License
110+
111+
The contents of this repository are under the AGPLv3 license.

audits/AaveTokenReport_CertiK.pdf

238 KB
Binary file not shown.
83.1 KB
Binary file not shown.

buidler.config.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { usePlugin, BuidlerConfig } from "@nomiclabs/buidler/config";
2+
import path from "path";
3+
import fs from "fs";
4+
// @ts-ignore
5+
import { accounts } from "./test-wallets.js";
6+
import { eEthereumNetwork } from "./helpers/types";
7+
import { BUIDLEREVM_CHAINID, COVERAGE_CHAINID } from "./helpers/constants";
8+
9+
usePlugin("@nomiclabs/buidler-ethers");
10+
usePlugin("buidler-typechain");
11+
usePlugin("solidity-coverage");
12+
usePlugin("@nomiclabs/buidler-waffle");
13+
usePlugin("@nomiclabs/buidler-etherscan");
14+
usePlugin("solidity-coverage");
15+
16+
["misc", "deployments", "migrations"].forEach((folder) => {
17+
const tasksPath = path.join(__dirname, "tasks", folder);
18+
fs.readdirSync(tasksPath).forEach((task) => require(`${tasksPath}/${task}`));
19+
});
20+
21+
const DEFAULT_BLOCK_GAS_LIMIT = 12500000;
22+
const DEFAULT_GAS_PRICE = 1;
23+
const HARDFORK = "istanbul";
24+
const INFURA_KEY = process.env.INFURA_KEY || "";
25+
const ETHERSCAN_KEY = process.env.ETHERSCAN_KEY || "";
26+
const MNEMONIC_PATH = "m/44'/60'/0'/0";
27+
const MNEMONICS: { [network: string]: string } = {
28+
[eEthereumNetwork.kovan]: process.env.MNEMONIC_KOVAN || "",
29+
[eEthereumNetwork.ropsten]: process.env.MNEMONIC_ROPSTEN || "",
30+
[eEthereumNetwork.main]: process.env.MNEMONIC_MAIN || "",
31+
};
32+
33+
const getCommonNetworkConfig = (
34+
networkName: eEthereumNetwork,
35+
networkId: number
36+
) => {
37+
return {
38+
url: `https://${networkName}.infura.io/v3/${INFURA_KEY}`,
39+
hardfork: HARDFORK,
40+
blockGasLimit: DEFAULT_BLOCK_GAS_LIMIT,
41+
gasPrice: 4000000000,
42+
gasMultiplier: DEFAULT_GAS_PRICE,
43+
chainId: networkId,
44+
accounts: {
45+
mnemonic: MNEMONICS[networkName],
46+
path: MNEMONIC_PATH,
47+
initialIndex: 0,
48+
count: 20,
49+
},
50+
};
51+
};
52+
53+
const config: BuidlerConfig = {
54+
solc: {
55+
version: "0.6.10",
56+
optimizer: { enabled: true, runs: 200 },
57+
evmVersion: "istanbul",
58+
},
59+
typechain: {
60+
outDir: "types",
61+
target: "ethers-v4",
62+
},
63+
etherscan: {
64+
apiKey: ETHERSCAN_KEY,
65+
},
66+
defaultNetwork: "buidlerevm",
67+
mocha: {
68+
timeout: 0,
69+
},
70+
networks: {
71+
kovan: getCommonNetworkConfig(eEthereumNetwork.kovan, 42),
72+
ropsten: getCommonNetworkConfig(eEthereumNetwork.ropsten, 3),
73+
main: getCommonNetworkConfig(eEthereumNetwork.main, 1),
74+
buidlerevm: {
75+
hardfork: "istanbul",
76+
blockGasLimit: DEFAULT_BLOCK_GAS_LIMIT,
77+
gas: DEFAULT_BLOCK_GAS_LIMIT,
78+
gasPrice: 8000000000,
79+
chainId: BUIDLEREVM_CHAINID,
80+
throwOnTransactionFailures: true,
81+
throwOnCallFailures: true,
82+
accounts: accounts.map(
83+
({ secretKey, balance }: { secretKey: string; balance: string }) => ({
84+
privateKey: secretKey,
85+
balance,
86+
})
87+
),
88+
},
89+
buidlerevm_docker: {
90+
hardfork: "istanbul",
91+
blockGasLimit: 9500000,
92+
gas: 9500000,
93+
gasPrice: 8000000000,
94+
chainId: BUIDLEREVM_CHAINID,
95+
throwOnTransactionFailures: true,
96+
throwOnCallFailures: true,
97+
url: "http://localhost:8545",
98+
},
99+
ganache: {
100+
url: "http://ganache:8545",
101+
accounts: {
102+
mnemonic:
103+
"fox sight canyon orphan hotel grow hedgehog build bless august weather swarm",
104+
path: "m/44'/60'/0'/0",
105+
initialIndex: 0,
106+
count: 20,
107+
},
108+
},
109+
coverage: {
110+
url: "http://localhost:8555",
111+
chainId: COVERAGE_CHAINID,
112+
},
113+
},
114+
};
115+
116+
export default config;

contracts/interfaces/IERC20.sol

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// SPDX-License-Identifier: agpl-3.0
2+
pragma solidity 0.6.10;
3+
4+
/**
5+
* @dev Interface of the ERC20 standard as defined in the EIP.
6+
*/
7+
interface IERC20 {
8+
/**
9+
* @dev Returns the amount of tokens in existence.
10+
*/
11+
function totalSupply() external view returns (uint256);
12+
13+
/**
14+
* @dev Returns the amount of tokens owned by `account`.
15+
*/
16+
function balanceOf(address account) external view returns (uint256);
17+
18+
/**
19+
* @dev Moves `amount` tokens from the caller's account to `recipient`.
20+
*
21+
* Returns a boolean value indicating whether the operation succeeded.
22+
*
23+
* Emits a {Transfer} event.
24+
*/
25+
function transfer(address recipient, uint256 amount) external returns (bool);
26+
27+
/**
28+
* @dev Returns the remaining number of tokens that `spender` will be
29+
* allowed to spend on behalf of `owner` through {transferFrom}. This is
30+
* zero by default.
31+
*
32+
* This value changes when {approve} or {transferFrom} are called.
33+
*/
34+
function allowance(address owner, address spender) external view returns (uint256);
35+
36+
/**
37+
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
38+
*
39+
* Returns a boolean value indicating whether the operation succeeded.
40+
*
41+
* IMPORTANT: Beware that changing an allowance with this method brings the risk
42+
* that someone may use both the old and the new allowance by unfortunate
43+
* transaction ordering. One possible solution to mitigate this race
44+
* condition is to first reduce the spender's allowance to 0 and set the
45+
* desired value afterwards:
46+
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
47+
*
48+
* Emits an {Approval} event.
49+
*/
50+
function approve(address spender, uint256 amount) external returns (bool);
51+
52+
/**
53+
* @dev Moves `amount` tokens from `sender` to `recipient` using the
54+
* allowance mechanism. `amount` is then deducted from the caller's
55+
* allowance.
56+
*
57+
* Returns a boolean value indicating whether the operation succeeded.
58+
*
59+
* Emits a {Transfer} event.
60+
*/
61+
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
62+
63+
/**
64+
* @dev Emitted when `value` tokens are moved from one account (`from`) to
65+
* another (`to`).
66+
*
67+
* Note that `value` may be zero.
68+
*/
69+
event Transfer(address indexed from, address indexed to, uint256 value);
70+
71+
/**
72+
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
73+
* a call to {approve}. `value` is the new allowance.
74+
*/
75+
event Approval(address indexed owner, address indexed spender, uint256 value);
76+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// SPDX-License-Identifier: agpl-3.0
2+
pragma solidity 0.6.10;
3+
4+
import {IERC20} from "./IERC20.sol";
5+
6+
interface IERC20Detailed is IERC20 {
7+
function name() external view returns(string memory);
8+
function symbol() external view returns(string memory);
9+
function decimals() external view returns(uint8);
10+
}

0 commit comments

Comments
 (0)