mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
fix: Replace constructor with initialize function and remove immutables
This commit is contained in:
parent
7f9108d1f8
commit
1bf28602a3
|
@ -41,8 +41,8 @@ contract ERC20 is Context, IERC20 {
|
|||
|
||||
uint256 private _totalSupply;
|
||||
|
||||
string private _name;
|
||||
string private _symbol;
|
||||
string internal _name;
|
||||
string internal _symbol;
|
||||
uint8 private _decimals;
|
||||
|
||||
/**
|
||||
|
|
40
contracts/interfaces/IInitializableStaticATokenLM.sol
Normal file
40
contracts/interfaces/IInitializableStaticATokenLM.sol
Normal file
|
@ -0,0 +1,40 @@
|
|||
// SPDX-License-Identifier: agpl-3.0
|
||||
pragma solidity 0.6.12;
|
||||
|
||||
import {ILendingPool} from './ILendingPool.sol';
|
||||
import {IAaveIncentivesController} from './IAaveIncentivesController.sol';
|
||||
|
||||
/**
|
||||
* @title IInitializableStaticATokenLM
|
||||
* @notice Interface for the initialize function on StaticATokenLM
|
||||
* @author Aave
|
||||
**/
|
||||
interface IInitializableStaticATokenLM {
|
||||
/**
|
||||
* @dev Emitted when a StaticATokenLM is initialized
|
||||
* @param pool The address of the lending pool where this aToken will be used
|
||||
* @param aToken The address of the underlying asset of this aToken (aWETH)
|
||||
* @param staticATokenName The name of the Static aToken
|
||||
* @param staticATokenSymbol The symbol of the Static aToken
|
||||
**/
|
||||
event Initialized(
|
||||
address indexed pool,
|
||||
address aToken,
|
||||
string staticATokenName,
|
||||
string staticATokenSymbol
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Initializes the StaticATokenLM
|
||||
* @param pool The address of the lending pool where this aToken will be used
|
||||
* @param aToken The address of the underlying aToken (aWETH)
|
||||
* @param staticATokenName The name of the stat Static aToken
|
||||
* @param staticATokenSymbol The symbol of the Static aToken
|
||||
*/
|
||||
function initialize(
|
||||
ILendingPool pool,
|
||||
address aToken,
|
||||
string calldata staticATokenName,
|
||||
string calldata staticATokenSymbol
|
||||
) external;
|
||||
}
|
|
@ -3,8 +3,11 @@ pragma solidity 0.6.12;
|
|||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
|
||||
import {ILendingPool} from './ILendingPool.sol';
|
||||
import {IAaveIncentivesController} from './IAaveIncentivesController.sol';
|
||||
import {IInitializableStaticATokenLM} from './IInitializableStaticATokenLM.sol';
|
||||
|
||||
interface IStaticATokenLM is IERC20 {
|
||||
interface IStaticATokenLM is IERC20, IInitializableStaticATokenLM {
|
||||
struct SignatureParams {
|
||||
uint8 v;
|
||||
bytes32 r;
|
||||
|
@ -226,4 +229,14 @@ interface IStaticATokenLM is IERC20 {
|
|||
function getLifetimeRewards() external view returns (uint256);
|
||||
|
||||
function getLastRewardBlock() external view returns (uint256);
|
||||
|
||||
function LENDING_POOL() external returns (ILendingPool);
|
||||
|
||||
function INCENTIVES_CONTROLLER() external returns (IAaveIncentivesController);
|
||||
|
||||
function ATOKEN() external returns (IERC20);
|
||||
|
||||
function ASSET() external returns (IERC20);
|
||||
|
||||
function REWARD_TOKEN() external returns (IERC20);
|
||||
}
|
||||
|
|
|
@ -4,9 +4,12 @@ pragma experimental ABIEncoderV2;
|
|||
|
||||
import {ILendingPool} from '../../interfaces/ILendingPool.sol';
|
||||
import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol';
|
||||
import {IERC20Detailed} from '../../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
|
||||
import {IAToken} from '../../interfaces/IAToken.sol';
|
||||
import {IStaticATokenLM} from '../../interfaces/IStaticATokenLM.sol';
|
||||
import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol';
|
||||
import {IInitializableStaticATokenLM} from '../../interfaces/IInitializableStaticATokenLM.sol';
|
||||
import {VersionedInitializable} from '../libraries/aave-upgradeability/VersionedInitializable.sol';
|
||||
|
||||
import {StaticATokenErrors} from '../libraries/helpers/StaticATokenErrors.sol';
|
||||
|
||||
|
@ -23,7 +26,11 @@ import {SafeMath} from '../../dependencies/openzeppelin/contracts/SafeMath.sol';
|
|||
* The token support claiming liquidity mining rewards from the Aave system.
|
||||
* @author Aave
|
||||
**/
|
||||
contract StaticATokenLM is IStaticATokenLM, ERC20 {
|
||||
contract StaticATokenLM is
|
||||
VersionedInitializable,
|
||||
ERC20('STATIC_ATOKEN_IMPL', 'STATIC_ATOKEN_IMPL'),
|
||||
IStaticATokenLM
|
||||
{
|
||||
using SafeERC20 for IERC20;
|
||||
using SafeMath for uint256;
|
||||
using WadRayMath for uint256;
|
||||
|
@ -43,11 +50,13 @@ contract StaticATokenLM is IStaticATokenLM, ERC20 {
|
|||
'Withdraw(address owner,address recipient,uint256 staticAmount,uint256 dynamicAmount,bool toUnderlying,uint256 nonce,uint256 deadline)'
|
||||
);
|
||||
|
||||
ILendingPool public immutable LENDING_POOL;
|
||||
IAaveIncentivesController public immutable INCENTIVES_CONTROLLER;
|
||||
IERC20 public immutable ATOKEN;
|
||||
IERC20 public immutable ASSET;
|
||||
IERC20 public immutable REWARD_TOKEN;
|
||||
uint256 public constant STATIC_ATOKEN_LM_REVISION = 0x1;
|
||||
|
||||
ILendingPool public override LENDING_POOL;
|
||||
IAaveIncentivesController public override INCENTIVES_CONTROLLER;
|
||||
IERC20 public override ATOKEN;
|
||||
IERC20 public override ASSET;
|
||||
IERC20 public override REWARD_TOKEN;
|
||||
|
||||
mapping(address => uint256) public _nonces;
|
||||
|
||||
|
@ -61,21 +70,32 @@ contract StaticATokenLM is IStaticATokenLM, ERC20 {
|
|||
// user => unclaimedRewards (in RAYs)
|
||||
mapping(address => uint256) private _unclaimedRewards;
|
||||
|
||||
constructor(
|
||||
ILendingPool lendingPool,
|
||||
///@inheritdoc VersionedInitializable
|
||||
function getRevision() internal pure virtual override returns (uint256) {
|
||||
return STATIC_ATOKEN_LM_REVISION;
|
||||
}
|
||||
|
||||
///@inheritdoc IInitializableStaticATokenLM
|
||||
function initialize(
|
||||
ILendingPool pool,
|
||||
address aToken,
|
||||
string memory wrappedTokenName,
|
||||
string memory wrappedTokenSymbol
|
||||
) public ERC20(wrappedTokenName, wrappedTokenSymbol) {
|
||||
LENDING_POOL = lendingPool;
|
||||
string calldata staticATokenName,
|
||||
string calldata staticATokenSymbol
|
||||
) external override initializer {
|
||||
LENDING_POOL = pool;
|
||||
ATOKEN = IERC20(aToken);
|
||||
|
||||
IERC20 underlyingAsset = ASSET = IERC20(IAToken(aToken).UNDERLYING_ASSET_ADDRESS());
|
||||
underlyingAsset.safeApprove(address(lendingPool), type(uint256).max);
|
||||
_name = staticATokenName;
|
||||
_symbol = staticATokenSymbol;
|
||||
_setupDecimals(IERC20Detailed(aToken).decimals());
|
||||
|
||||
IAaveIncentivesController incentivesController =
|
||||
INCENTIVES_CONTROLLER = IAToken(aToken).getIncentivesController();
|
||||
REWARD_TOKEN = IERC20(incentivesController.REWARD_TOKEN());
|
||||
ASSET = IERC20(IAToken(aToken).UNDERLYING_ASSET_ADDRESS());
|
||||
ASSET.safeApprove(address(pool), type(uint256).max);
|
||||
|
||||
INCENTIVES_CONTROLLER = IAToken(aToken).getIncentivesController();
|
||||
REWARD_TOKEN = IERC20(INCENTIVES_CONTROLLER.REWARD_TOKEN());
|
||||
|
||||
emit Initialized(address(pool), aToken, staticATokenName, staticATokenSymbol);
|
||||
}
|
||||
|
||||
///@inheritdoc IStaticATokenLM
|
||||
|
|
|
@ -30,6 +30,7 @@ import { _TypedDataEncoder } from 'ethers/lib/utils';
|
|||
|
||||
import { expect, use } from 'chai';
|
||||
import { getCurrentBlock } from '../../../../helpers/contracts-helpers';
|
||||
import { stat } from 'fs';
|
||||
|
||||
//use(solidity);
|
||||
|
||||
|
@ -99,13 +100,18 @@ describe('StaticATokenLM: aToken wrapper with static balances and liquidity mini
|
|||
aweth = ATokenFactory.connect(AWETH, userSigner);
|
||||
stkAave = ERC20Factory.connect(STKAAVE, userSigner);
|
||||
|
||||
staticAToken = await new StaticATokenLMFactory(userSigner).deploy(
|
||||
staticAToken = await new StaticATokenLMFactory(userSigner).deploy();
|
||||
await staticAToken.initialize(
|
||||
LENDING_POOL,
|
||||
AWETH,
|
||||
'Static Aave Interest Bearing WETH',
|
||||
'stataAAVE'
|
||||
);
|
||||
|
||||
expect(await staticAToken.decimals()).to.be.eq(18);
|
||||
expect(await staticAToken.name()).to.be.eq('Static Aave Interest Bearing WETH');
|
||||
expect(await staticAToken.symbol()).to.be.eq('stataAAVE');
|
||||
|
||||
snap = await evmSnapshot();
|
||||
});
|
||||
|
||||
|
@ -188,6 +194,11 @@ describe('StaticATokenLM: aToken wrapper with static balances and liquidity mini
|
|||
it('Check getters', async () => {
|
||||
const amountToDeposit = utils.parseEther('5');
|
||||
|
||||
const accRewardsPerTokenPre = await staticAToken.getAccRewardsPerToken();
|
||||
const lifetimeRewardsClaimedPre = await staticAToken.getLifetimeRewardsClaimed();
|
||||
const lifetimeRewards = await staticAToken.getLifetimeRewards();
|
||||
const lastRewardBlock = await staticAToken.getLastRewardBlock();
|
||||
|
||||
// Just preparation
|
||||
await waitForTx(await weth.deposit({ value: amountToDeposit.mul(2) }));
|
||||
await waitForTx(
|
||||
|
@ -207,6 +218,13 @@ describe('StaticATokenLM: aToken wrapper with static balances and liquidity mini
|
|||
|
||||
expect(staticBalance).to.be.eq(staticBalanceFromDynamic);
|
||||
expect(dynamicBalance).to.be.eq(dynamicBalanceFromStatic);
|
||||
|
||||
await staticAToken.collectAndUpdateRewards();
|
||||
|
||||
expect(await staticAToken.getAccRewardsPerToken()).to.be.gt(accRewardsPerTokenPre);
|
||||
expect(await staticAToken.getLifetimeRewardsClaimed()).to.be.gt(lifetimeRewardsClaimedPre);
|
||||
expect(await staticAToken.getLifetimeRewards()).to.be.gt(lifetimeRewards);
|
||||
expect(await staticAToken.getLastRewardBlock()).to.be.gt(lastRewardBlock);
|
||||
});
|
||||
|
||||
it('Multiple deposits in one block (Breaks if GasReport enabled)', async () => {
|
||||
|
|
|
@ -162,7 +162,8 @@ describe('StaticATokenLM: aToken wrapper with static balances and liquidity mini
|
|||
aweth = ATokenFactory.connect(AWETH, userSigner);
|
||||
stkAave = ERC20Factory.connect(STKAAVE, userSigner);
|
||||
|
||||
staticAToken = await new StaticATokenLMFactory(userSigner).deploy(
|
||||
staticAToken = await new StaticATokenLMFactory(userSigner).deploy();
|
||||
await staticAToken.initialize(
|
||||
LENDING_POOL,
|
||||
AWETH,
|
||||
'Static Aave Interest Bearing WETH',
|
||||
|
|
|
@ -1,224 +0,0 @@
|
|||
import rawDRE from 'hardhat';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import {
|
||||
LendingPoolFactory,
|
||||
WETH9Factory,
|
||||
StaticATokenFactory,
|
||||
ATokenFactory,
|
||||
ERC20,
|
||||
LendingPool,
|
||||
} from '../../types';
|
||||
import { impersonateAccountsHardhat, DRE, waitForTx } from '../../helpers/misc-utils';
|
||||
import { utils } from 'ethers';
|
||||
import { rayMul } from '../../helpers/ray-math';
|
||||
import { MAX_UINT_AMOUNT } from '../../helpers/constants';
|
||||
import { tEthereumAddress } from '../../helpers/types';
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const DEFAULT_GAS_LIMIT = 10000000;
|
||||
const DEFAULT_GAS_PRICE = utils.parseUnits('100', 'gwei');
|
||||
|
||||
const defaultTxParams = { gasLimit: DEFAULT_GAS_LIMIT, gasPrice: DEFAULT_GAS_PRICE };
|
||||
|
||||
const ETHER_BANK = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
||||
const LENDING_POOL = '0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9';
|
||||
|
||||
const WETH = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
||||
|
||||
const AWETH = '0x030bA81f1c18d280636F32af80b9AAd02Cf0854e';
|
||||
|
||||
const TEST_USERS = ['0x0F4ee9631f4be0a63756515141281A3E2B293Bbe'];
|
||||
|
||||
type tBalancesInvolved = {
|
||||
aTokenBalanceStaticAToken: BigNumber;
|
||||
aTokenBalanceUser: BigNumber;
|
||||
underlyingBalanceUser: BigNumber;
|
||||
underlyingBalanceStaticAToken: BigNumber;
|
||||
userStaticATokenBalance: BigNumber;
|
||||
userDynamicStaticATokenBalance: BigNumber;
|
||||
currentRate: BigNumber;
|
||||
staticATokenSupply: BigNumber;
|
||||
};
|
||||
|
||||
type tContextParams = {
|
||||
staticAToken: ERC20;
|
||||
underlying: ERC20;
|
||||
aToken: ERC20;
|
||||
user: tEthereumAddress;
|
||||
lendingPool: LendingPool;
|
||||
};
|
||||
|
||||
const getContext = async ({
|
||||
staticAToken,
|
||||
underlying,
|
||||
aToken,
|
||||
user,
|
||||
lendingPool,
|
||||
}: tContextParams): Promise<tBalancesInvolved> => ({
|
||||
aTokenBalanceStaticAToken: new BigNumber(
|
||||
(await aToken.balanceOf(staticAToken.address)).toString()
|
||||
),
|
||||
aTokenBalanceUser: new BigNumber((await aToken.balanceOf(user)).toString()),
|
||||
underlyingBalanceUser: new BigNumber((await underlying.balanceOf(user)).toString()),
|
||||
underlyingBalanceStaticAToken: new BigNumber(
|
||||
(await underlying.balanceOf(staticAToken.address)).toString()
|
||||
),
|
||||
userStaticATokenBalance: new BigNumber((await staticAToken.balanceOf(user)).toString()),
|
||||
userDynamicStaticATokenBalance: new BigNumber(
|
||||
rayMul(
|
||||
new BigNumber((await staticAToken.balanceOf(user)).toString()),
|
||||
new BigNumber((await lendingPool.getReserveNormalizedIncome(WETH)).toString())
|
||||
)
|
||||
),
|
||||
currentRate: new BigNumber((await lendingPool.getReserveNormalizedIncome(WETH)).toString()),
|
||||
staticATokenSupply: new BigNumber((await staticAToken.totalSupply()).toString()),
|
||||
});
|
||||
|
||||
before(async () => {
|
||||
await rawDRE.run('set-DRE');
|
||||
|
||||
// Impersonations
|
||||
await impersonateAccountsHardhat([ETHER_BANK, ...TEST_USERS]);
|
||||
|
||||
const ethHolderSigner = DRE.ethers.provider.getSigner(ETHER_BANK);
|
||||
for (const recipientOfEth of [...TEST_USERS]) {
|
||||
await ethHolderSigner.sendTransaction({
|
||||
from: ethHolderSigner._address,
|
||||
to: recipientOfEth,
|
||||
value: utils.parseEther('100'),
|
||||
...defaultTxParams,
|
||||
});
|
||||
}
|
||||
|
||||
console.log('\n***************');
|
||||
console.log('Test setup finished');
|
||||
console.log('***************\n');
|
||||
});
|
||||
|
||||
describe('StaticAToken: aToken wrapper with static balances', () => {
|
||||
it('Deposit WETH on stataWETH, then withdraw of the whole balance in underlying', async () => {
|
||||
const userSigner = DRE.ethers.provider.getSigner(TEST_USERS[0]);
|
||||
|
||||
const lendingPool = LendingPoolFactory.connect(LENDING_POOL, userSigner);
|
||||
|
||||
const weth = WETH9Factory.connect(WETH, userSigner);
|
||||
|
||||
const aweth = ATokenFactory.connect(AWETH, userSigner);
|
||||
|
||||
const amountToDeposit = utils.parseEther('5');
|
||||
|
||||
await waitForTx(await weth.deposit({ value: amountToDeposit }));
|
||||
|
||||
const staticAToken = await new StaticATokenFactory(userSigner).deploy(
|
||||
LENDING_POOL,
|
||||
AWETH,
|
||||
'Static Aave Interest Bearing WETH',
|
||||
'stataAAVE'
|
||||
);
|
||||
|
||||
const ctxtParams: tContextParams = {
|
||||
staticAToken: <ERC20>staticAToken,
|
||||
underlying: <ERC20>(<unknown>weth),
|
||||
aToken: <ERC20>aweth,
|
||||
user: userSigner._address,
|
||||
lendingPool,
|
||||
};
|
||||
|
||||
const ctxtBeforeDeposit = await getContext(ctxtParams);
|
||||
|
||||
await waitForTx(await weth.approve(staticAToken.address, amountToDeposit, defaultTxParams));
|
||||
|
||||
await waitForTx(
|
||||
await staticAToken.deposit(userSigner._address, amountToDeposit, 0, true, defaultTxParams)
|
||||
);
|
||||
|
||||
const ctxtAfterDeposit = await getContext(ctxtParams);
|
||||
|
||||
expect(ctxtAfterDeposit.aTokenBalanceStaticAToken.toString()).to.be.equal(
|
||||
ctxtBeforeDeposit.aTokenBalanceStaticAToken
|
||||
.plus(new BigNumber(amountToDeposit.toString()))
|
||||
.toString()
|
||||
);
|
||||
|
||||
expect(ctxtAfterDeposit.underlyingBalanceUser.toString()).to.be.equal(
|
||||
ctxtBeforeDeposit.underlyingBalanceUser
|
||||
.minus(new BigNumber(amountToDeposit.toString()))
|
||||
.toString()
|
||||
);
|
||||
|
||||
expect(ctxtAfterDeposit.userDynamicStaticATokenBalance.toString()).to.be.equal(
|
||||
ctxtBeforeDeposit.userDynamicStaticATokenBalance
|
||||
.plus(new BigNumber(amountToDeposit.toString()))
|
||||
.toString()
|
||||
);
|
||||
|
||||
expect(ctxtAfterDeposit.underlyingBalanceStaticAToken.toString()).to.be.equal(
|
||||
ctxtBeforeDeposit.underlyingBalanceStaticAToken.toString()
|
||||
);
|
||||
|
||||
expect(ctxtBeforeDeposit.aTokenBalanceUser.toString()).to.be.equal(
|
||||
ctxtAfterDeposit.aTokenBalanceUser.toString()
|
||||
);
|
||||
|
||||
const ctxtBeforeWithdrawal = await getContext(ctxtParams);
|
||||
|
||||
const amountToWithdraw = MAX_UINT_AMOUNT;
|
||||
|
||||
await waitForTx(
|
||||
await staticAToken.withdraw(userSigner._address, amountToWithdraw, true, defaultTxParams)
|
||||
);
|
||||
|
||||
const ctxtAfterWithdrawal = await getContext(ctxtParams);
|
||||
|
||||
expect(
|
||||
ctxtAfterWithdrawal.aTokenBalanceStaticAToken.toString(),
|
||||
'INVALID_ATOKEN_BALANCE_ON_STATICATOKEN_AFTER_WITHDRAW'
|
||||
).to.be.equal(
|
||||
rayMul(
|
||||
ctxtAfterWithdrawal.staticATokenSupply.plus(ctxtBeforeWithdrawal.userStaticATokenBalance),
|
||||
ctxtAfterWithdrawal.currentRate
|
||||
)
|
||||
.minus(
|
||||
rayMul(ctxtBeforeWithdrawal.userStaticATokenBalance, ctxtAfterWithdrawal.currentRate)
|
||||
)
|
||||
.toString()
|
||||
);
|
||||
|
||||
expect(
|
||||
ctxtAfterWithdrawal.underlyingBalanceUser.toString(),
|
||||
'INVALID_UNDERLYING_BALANCE_OF_USER_AFTER_WITHDRAWAL'
|
||||
).to.be.equal(
|
||||
ctxtBeforeWithdrawal.underlyingBalanceUser
|
||||
.plus(rayMul(ctxtBeforeWithdrawal.userStaticATokenBalance, ctxtAfterWithdrawal.currentRate))
|
||||
.toString()
|
||||
);
|
||||
|
||||
expect(
|
||||
ctxtAfterWithdrawal.userStaticATokenBalance.toString(),
|
||||
'INVALID_STATICATOKEN_BALANCE_OF_USER_AFTER_WITHDRAWAL'
|
||||
).to.be.equal('0');
|
||||
|
||||
expect(
|
||||
ctxtAfterDeposit.underlyingBalanceStaticAToken.toString(),
|
||||
'INVALID_UNDERLYNG_BALANCE_OF_STATICATOKEN_AFTER_WITHDRAWAL'
|
||||
).to.be.equal(ctxtBeforeDeposit.underlyingBalanceStaticAToken.toString());
|
||||
|
||||
expect(
|
||||
ctxtBeforeDeposit.aTokenBalanceUser.toString(),
|
||||
'INVALID_ATOKEN_BALANCE_OF_USER_AFTER_WITHDRAWAL'
|
||||
).to.be.equal(ctxtAfterDeposit.aTokenBalanceUser.toString());
|
||||
});
|
||||
|
||||
it('Deposit WETH on stataWETH and then withdraw some balance in underlying', async () => {});
|
||||
|
||||
it('Deposit WETH on stataWETH and then withdraw all the balance in aToken', async () => {});
|
||||
|
||||
it('Deposit aWETH on stataWETH and then withdraw some balance in aToken', async () => {});
|
||||
|
||||
it('Deposit using metaDeposit()', async () => {});
|
||||
|
||||
it('Withdraw using withdrawDynamicAmount()', async () => {});
|
||||
|
||||
it('Withdraw using metaWithdraw()', async () => {});
|
||||
});
|
Loading…
Reference in New Issue
Block a user