- Implemented protocol changes to enable re-usage of implementations.

This commit is contained in:
eboado 2021-01-28 11:05:19 +01:00
parent 29448c19c1
commit 80fd095723
21 changed files with 741 additions and 537 deletions

View File

@ -20,6 +20,20 @@ contract ATokensAndRatesHelper is Ownable {
address private poolConfigurator;
event deployedContracts(address aToken, address strategy);
struct InitDeploymentInput {
address asset;
uint256[6] rates;
}
struct ConfigureReserveInput {
address asset;
uint256 baseLTV;
uint256 liquidationThreshold;
uint256 liquidationBonus;
uint256 reserveFactor;
bool stableBorrowingEnabled;
}
constructor(
address payable _pool,
address _addressesProvider,
@ -30,93 +44,40 @@ contract ATokensAndRatesHelper is Ownable {
poolConfigurator = _poolConfigurator;
}
function initDeployment(
address[] calldata assets,
string[] calldata symbols,
uint256[6][] calldata rates,
address treasuryAddress,
address incentivesController
) external onlyOwner {
require(assets.length == symbols.length, 't Arrays not same length');
require(rates.length == symbols.length, 'r Arrays not same length');
for (uint256 i = 0; i < assets.length; i++) {
function initDeployment(InitDeploymentInput[] calldata inputParams) external onlyOwner {
for (uint256 i = 0; i < inputParams.length; i++) {
emit deployedContracts(
address(
new AToken(
LendingPool(pool),
assets[i],
treasuryAddress,
StringLib.concat('Aave interest bearing ', symbols[i]),
StringLib.concat('a', symbols[i]),
incentivesController
)
),
address(new AToken()),
address(
new DefaultReserveInterestRateStrategy(
LendingPoolAddressesProvider(addressesProvider),
rates[i][0],
rates[i][1],
rates[i][2],
rates[i][3],
rates[i][4],
rates[i][5]
inputParams[i].rates[0],
inputParams[i].rates[1],
inputParams[i].rates[2],
inputParams[i].rates[3],
inputParams[i].rates[4],
inputParams[i].rates[5]
)
)
);
}
}
function initReserve(
address[] calldata stables,
address[] calldata variables,
address[] calldata aTokens,
address[] calldata strategies,
uint8[] calldata reserveDecimals
) external onlyOwner {
require(variables.length == stables.length);
require(aTokens.length == stables.length);
require(strategies.length == stables.length);
require(reserveDecimals.length == stables.length);
for (uint256 i = 0; i < stables.length; i++) {
LendingPoolConfigurator(poolConfigurator).initReserve(
aTokens[i],
stables[i],
variables[i],
reserveDecimals[i],
strategies[i]
);
}
}
function configureReserves(
address[] calldata assets,
uint256[] calldata baseLTVs,
uint256[] calldata liquidationThresholds,
uint256[] calldata liquidationBonuses,
uint256[] calldata reserveFactors,
bool[] calldata stableBorrowingEnabled
) external onlyOwner {
require(baseLTVs.length == assets.length);
require(liquidationThresholds.length == assets.length);
require(liquidationBonuses.length == assets.length);
require(stableBorrowingEnabled.length == assets.length);
require(reserveFactors.length == assets.length);
function configureReserves(ConfigureReserveInput[] calldata inputParams) external onlyOwner {
LendingPoolConfigurator configurator = LendingPoolConfigurator(poolConfigurator);
for (uint256 i = 0; i < assets.length; i++) {
for (uint256 i = 0; i < inputParams.length; i++) {
configurator.configureReserveAsCollateral(
assets[i],
baseLTVs[i],
liquidationThresholds[i],
liquidationBonuses[i]
inputParams[i].asset,
inputParams[i].baseLTV,
inputParams[i].liquidationThreshold,
inputParams[i].liquidationBonus
);
configurator.enableBorrowingOnReserve(
assets[i],
stableBorrowingEnabled[i]
inputParams[i].asset,
inputParams[i].stableBorrowingEnabled
);
configurator.setReserveFactor(assets[i], reserveFactors[i]);
configurator.setReserveFactor(inputParams[i].asset, inputParams[i].reserveFactor);
}
}
}

View File

@ -18,34 +18,11 @@ contract StableAndVariableTokensHelper is Ownable {
addressesProvider = _addressesProvider;
}
function initDeployment(
address[] calldata tokens,
string[] calldata symbols,
address incentivesController
) external onlyOwner {
function initDeployment(address[] calldata tokens, string[] calldata symbols) external onlyOwner {
require(tokens.length == symbols.length, 'Arrays not same length');
require(pool != address(0), 'Pool can not be zero address');
for (uint256 i = 0; i < tokens.length; i++) {
emit deployedContracts(
address(
new StableDebtToken(
pool,
tokens[i],
StringLib.concat('Aave stable debt bearing ', symbols[i]),
StringLib.concat('stableDebt', symbols[i]),
incentivesController
)
),
address(
new VariableDebtToken(
pool,
tokens[i],
StringLib.concat('Aave variable debt bearing ', symbols[i]),
StringLib.concat('variableDebt', symbols[i]),
incentivesController
)
)
);
emit deployedContracts(address(new StableDebtToken()), address(new VariableDebtToken()));
}
}

View File

@ -3,8 +3,10 @@ pragma solidity 0.6.12;
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
import {IScaledBalanceToken} from './IScaledBalanceToken.sol';
import {IInitializableAToken} from './IInitializableAToken.sol';
import {IAaveIncentivesController} from './IAaveIncentivesController.sol';
interface IAToken is IERC20, IScaledBalanceToken {
interface IAToken is IERC20, IScaledBalanceToken, IInitializableAToken {
/**
* @dev Emitted after the mint action
* @param from The address performing the mint
@ -85,4 +87,9 @@ interface IAToken is IERC20, IScaledBalanceToken {
* @return The amount transferred
**/
function transferUnderlyingTo(address user, uint256 amount) external returns (uint256);
/**
* @dev Returns the address of the incentives controller contract
**/
function getIncentivesController() external view returns (IAaveIncentivesController);
}

View File

@ -0,0 +1,32 @@
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.12;
import {ILendingPool} from './ILendingPool.sol';
import {IAaveIncentivesController} from './IAaveIncentivesController.sol';
/**
* @title IInitializableAToken
* @notice Interface for the initialize function on AToken
* @author Aave
**/
interface IInitializableAToken {
/**
* @dev Initializes the aToken
* @param pool The address of the lending pool where this aToken will be used
* @param treasury The address of the Aave treasury, receiving the fees on this aToken
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
* @param incentivesController The smart contract managing potential incentives distribution
* @param aTokenDecimals The decimals of the aToken, same as the underlying asset's
* @param aTokenName The name of the aToken
* @param aTokenSymbol The symbol of the aToken
*/
function initialize(
ILendingPool pool,
address treasury,
address underlyingAsset,
IAaveIncentivesController incentivesController,
uint8 aTokenDecimals,
string calldata aTokenName,
string calldata aTokenSymbol
) external;
}

View File

@ -0,0 +1,30 @@
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.12;
import {ILendingPool} from './ILendingPool.sol';
import {IAaveIncentivesController} from './IAaveIncentivesController.sol';
/**
* @title IInitializableDebtToken
* @notice Interface for the initialize function common between debt tokens
* @author Aave
**/
interface IInitializableDebtToken {
/**
* @dev Initializes the debt token.
* @param pool The address of the lending pool where this aToken will be used
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
* @param incentivesController The smart contract managing potential incentives distribution
* @param debtTokenDecimals The decimals of the debtToken, same as the underlying asset's
* @param debtTokenName The name of the token
* @param debtTokenSymbol The symbol of the token
*/
function initialize(
ILendingPool pool,
address underlyingAsset,
IAaveIncentivesController incentivesController,
uint8 debtTokenDecimals,
string memory debtTokenName,
string memory debtTokenSymbol
) external;
}

View File

@ -0,0 +1,176 @@
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
interface ILendingPoolConfigurator {
struct InitReserveInput {
address aTokenImpl;
address stableDebtTokenImpl;
address variableDebtTokenImpl;
uint8 underlyingAssetDecimals;
address interestRateStrategyAddress;
address underlyingAsset;
address treasury;
address incentivesController;
string underlyingAssetName;
string aTokenName;
string aTokenSymbol;
string variableDebtTokenName;
string variableDebtTokenSymbol;
string stableDebtTokenName;
string stableDebtTokenSymbol;
}
struct UpdateATokenInput {
address asset;
address treasury;
address incentivesController;
string name;
string symbol;
address implementation;
}
struct UpdateDebtTokenInput {
address asset;
address incentivesController;
string name;
string symbol;
address implementation;
}
/**
* @dev Emitted when a reserve is initialized.
* @param asset The address of the underlying asset of the reserve
* @param aToken The address of the associated aToken contract
* @param stableDebtToken The address of the associated stable rate debt token
* @param variableDebtToken The address of the associated variable rate debt token
* @param interestRateStrategyAddress The address of the interest rate strategy for the reserve
**/
event ReserveInitialized(
address indexed asset,
address indexed aToken,
address stableDebtToken,
address variableDebtToken,
address interestRateStrategyAddress
);
/**
* @dev Emitted when borrowing is enabled on a reserve
* @param asset The address of the underlying asset of the reserve
* @param stableRateEnabled True if stable rate borrowing is enabled, false otherwise
**/
event BorrowingEnabledOnReserve(address indexed asset, bool stableRateEnabled);
/**
* @dev Emitted when borrowing is disabled on a reserve
* @param asset The address of the underlying asset of the reserve
**/
event BorrowingDisabledOnReserve(address indexed asset);
/**
* @dev Emitted when the collateralization risk parameters for the specified asset are updated.
* @param asset The address of the underlying asset of the reserve
* @param ltv The loan to value of the asset when used as collateral
* @param liquidationThreshold The threshold at which loans using this asset as collateral will be considered undercollateralized
* @param liquidationBonus The bonus liquidators receive to liquidate this asset
**/
event CollateralConfigurationChanged(
address indexed asset,
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus
);
/**
* @dev Emitted when stable rate borrowing is enabled on a reserve
* @param asset The address of the underlying asset of the reserve
**/
event StableRateEnabledOnReserve(address indexed asset);
/**
* @dev Emitted when stable rate borrowing is disabled on a reserve
* @param asset The address of the underlying asset of the reserve
**/
event StableRateDisabledOnReserve(address indexed asset);
/**
* @dev Emitted when a reserve is activated
* @param asset The address of the underlying asset of the reserve
**/
event ReserveActivated(address indexed asset);
/**
* @dev Emitted when a reserve is deactivated
* @param asset The address of the underlying asset of the reserve
**/
event ReserveDeactivated(address indexed asset);
/**
* @dev Emitted when a reserve is frozen
* @param asset The address of the underlying asset of the reserve
**/
event ReserveFrozen(address indexed asset);
/**
* @dev Emitted when a reserve is unfrozen
* @param asset The address of the underlying asset of the reserve
**/
event ReserveUnfrozen(address indexed asset);
/**
* @dev Emitted when a reserve factor is updated
* @param asset The address of the underlying asset of the reserve
* @param factor The new reserve factor
**/
event ReserveFactorChanged(address indexed asset, uint256 factor);
/**
* @dev Emitted when the reserve decimals are updated
* @param asset The address of the underlying asset of the reserve
* @param decimals The new decimals
**/
event ReserveDecimalsChanged(address indexed asset, uint256 decimals);
/**
* @dev Emitted when a reserve interest strategy contract is updated
* @param asset The address of the underlying asset of the reserve
* @param strategy The new address of the interest strategy contract
**/
event ReserveInterestRateStrategyChanged(address indexed asset, address strategy);
/**
* @dev Emitted when an aToken implementation is upgraded
* @param asset The address of the underlying asset of the reserve
* @param proxy The aToken proxy address
* @param implementation The new aToken implementation
**/
event ATokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation
);
/**
* @dev Emitted when the implementation of a stable debt token is upgraded
* @param asset The address of the underlying asset of the reserve
* @param proxy The stable debt token proxy address
* @param implementation The new aToken implementation
**/
event StableDebtTokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation
);
/**
* @dev Emitted when the implementation of a variable debt token is upgraded
* @param asset The address of the underlying asset of the reserve
* @param proxy The variable debt token proxy address
* @param implementation The new aToken implementation
**/
event VariableDebtTokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation
);
}

View File

@ -1,6 +1,9 @@
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.12;
import {IInitializableDebtToken} from './IInitializableDebtToken.sol';
import {IAaveIncentivesController} from './IAaveIncentivesController.sol';
/**
* @title IStableDebtToken
* @notice Defines the interface for the stable debt token
@ -8,7 +11,7 @@ pragma solidity 0.6.12;
* @author Aave
**/
interface IStableDebtToken {
interface IStableDebtToken is IInitializableDebtToken {
/**
* @dev Emitted when new stable debt is minted
* @param user The address of the user who triggered the minting
@ -122,4 +125,9 @@ interface IStableDebtToken {
* @return The debt balance of the user since the last burn/mint action
**/
function principalBalanceOf(address user) external view returns (uint256);
/**
* @dev Returns the address of the incentives controller contract
**/
function getIncentivesController() external view returns (IAaveIncentivesController);
}

View File

@ -1,14 +0,0 @@
// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.12;
/**
* @title ITokenConfiguration
* @author Aave
* @dev Common interface between aTokens and debt tokens to fetch the
* token configuration
**/
interface ITokenConfiguration {
function UNDERLYING_ASSET_ADDRESS() external view returns (address);
function POOL() external view returns (address);
}

View File

@ -2,13 +2,15 @@
pragma solidity 0.6.12;
import {IScaledBalanceToken} from './IScaledBalanceToken.sol';
import {IInitializableDebtToken} from './IInitializableDebtToken.sol';
import {IAaveIncentivesController} from './IAaveIncentivesController.sol';
/**
* @title IVariableDebtToken
* @author Aave
* @notice Defines the basic interface for a variable debt token.
**/
interface IVariableDebtToken is IScaledBalanceToken {
interface IVariableDebtToken is IScaledBalanceToken, IInitializableDebtToken {
/**
* @dev Emitted after the mint action
* @param from The address performing the mint
@ -52,4 +54,9 @@ interface IVariableDebtToken is IScaledBalanceToken {
uint256 amount,
uint256 index
) external;
/**
* @dev Returns the address of the incentives controller contract
**/
function getIncentivesController() external view returns (IAaveIncentivesController);
}

View File

@ -2,39 +2,11 @@
pragma solidity 0.6.12;
import {AToken} from '../../protocol/tokenization/AToken.sol';
import {LendingPool} from '../../protocol/lendingpool/LendingPool.sol';
import {ILendingPool} from '../../interfaces/ILendingPool.sol';
import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol';
contract MockAToken is AToken {
constructor(
LendingPool pool,
address underlyingAssetAddress,
address reserveTreasury,
string memory tokenName,
string memory tokenSymbol,
address incentivesController
)
public
AToken(
pool,
underlyingAssetAddress,
reserveTreasury,
tokenName,
tokenSymbol,
incentivesController
)
{}
function getRevision() internal pure override returns (uint256) {
return 0x2;
}
function initialize(
uint8 _underlyingAssetDecimals,
string calldata _tokenName,
string calldata _tokenSymbol
) external virtual override initializer {
_setName(_tokenName);
_setSymbol(_tokenSymbol);
_setDecimals(_underlyingAssetDecimals);
}
}

View File

@ -4,17 +4,6 @@ pragma solidity 0.6.12;
import {StableDebtToken} from '../../protocol/tokenization/StableDebtToken.sol';
contract MockStableDebtToken is StableDebtToken {
constructor(
address _pool,
address _underlyingAssetAddress,
string memory _tokenName,
string memory _tokenSymbol,
address incentivesController
)
public
StableDebtToken(_pool, _underlyingAssetAddress, _tokenName, _tokenSymbol, incentivesController)
{}
function getRevision() internal pure override returns (uint256) {
return 0x2;
}

View File

@ -4,23 +4,6 @@ pragma solidity 0.6.12;
import {VariableDebtToken} from '../../protocol/tokenization/VariableDebtToken.sol';
contract MockVariableDebtToken is VariableDebtToken {
constructor(
address _pool,
address _underlyingAssetAddress,
string memory _tokenName,
string memory _tokenSymbol,
address incentivesController
)
public
VariableDebtToken(
_pool,
_underlyingAssetAddress,
_tokenName,
_tokenSymbol,
incentivesController
)
{}
function getRevision() internal pure override returns (uint256) {
return 0x2;
}

View File

@ -49,10 +49,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
using PercentageMath for uint256;
using SafeERC20 for IERC20;
//main configuration parameters
uint256 public constant MAX_STABLE_RATE_BORROW_SIZE_PERCENT = 2500;
uint256 public constant FLASHLOAN_PREMIUM_TOTAL = 9;
uint256 public constant MAX_NUMBER_RESERVES = 128;
uint256 public constant LENDINGPOOL_REVISION = 0x2;
modifier whenNotPaused() {
@ -86,9 +82,20 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
* - Caching the address of the LendingPoolAddressesProvider in order to reduce gas consumption
* on subsequent operations
* @param provider The address of the LendingPoolAddressesProvider
* @param maxStableRateBorrowSizePercent The percentage of available liquidity that can be borrowed at once at stable rate
* @param flashLoanPremiumTotal The fee on flash loans
* @param maxNumberOfReserves Maximum number of reserves supported to be listed in this LendingPool
**/
function initialize(ILendingPoolAddressesProvider provider) public initializer {
function initialize(
ILendingPoolAddressesProvider provider,
uint256 maxStableRateBorrowSizePercent,
uint256 flashLoanPremiumTotal,
uint256 maxNumberOfReserves
) public initializer {
_addressesProvider = provider;
_maxStableRateBorrowSizePercent = maxStableRateBorrowSizePercent;
_flashLoanPremiumTotal = flashLoanPremiumTotal;
_maxNumberOfReserves = maxNumberOfReserves;
}
/**
@ -144,7 +151,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
address asset,
uint256 amount,
address to
) external override whenNotPaused returns (uint256) {
) external override whenNotPaused returns (uint256) {
DataTypes.ReserveData storage reserve = _reserves[asset];
address aToken = reserve.aTokenAddress;
@ -499,7 +506,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
for (vars.i = 0; vars.i < assets.length; vars.i++) {
aTokenAddresses[vars.i] = _reserves[assets[vars.i]].aTokenAddress;
premiums[vars.i] = amounts[vars.i].mul(FLASHLOAN_PREMIUM_TOTAL).div(10000);
premiums[vars.i] = amounts[vars.i].mul(_flashLoanPremiumTotal).div(10000);
IAToken(aTokenAddresses[vars.i]).transferUnderlyingTo(receiverAddress, amounts[vars.i]);
}
@ -703,6 +710,27 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
return _addressesProvider;
}
/**
* @dev Returns the percentage of available liquidity that can be borrowed at once at stable rate
*/
function MAX_STABLE_RATE_BORROW_SIZE_PERCENT() public view returns (uint256) {
return _maxStableRateBorrowSizePercent;
}
/**
* @dev Returns the fee on flash loans
*/
function FLASHLOAN_PREMIUM_TOTAL() public view returns (uint256) {
return _flashLoanPremiumTotal;
}
/**
* @dev Returns the maximum number of reserves supported to be listed in this LendingPool
*/
function MAX_NUMBER_RESERVES() public view returns (uint256) {
return _maxNumberOfReserves;
}
/**
* @dev Validates and finalizes an aToken transfer
* - Only callable by the overlying aToken of the `asset`
@ -847,7 +875,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
vars.amount,
amountInETH,
vars.interestRateMode,
MAX_STABLE_RATE_BORROW_SIZE_PERCENT,
_maxStableRateBorrowSizePercent,
_reserves,
userConfig,
_reservesList,
@ -909,7 +937,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
function _addReserveToList(address asset) internal {
uint256 reservesCount = _reservesCount;
require(reservesCount < MAX_NUMBER_RESERVES, Errors.LP_NO_MORE_RESERVES_ALLOWED);
require(reservesCount < _maxNumberOfReserves, Errors.LP_NO_MORE_RESERVES_ALLOWED);
bool reserveAlreadyAdded = _reserves[asset].id != 0 || _reservesList[0] == asset;

View File

@ -10,11 +10,14 @@ import {
import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol';
import {ILendingPoolAddressesProvider} from '../../interfaces/ILendingPoolAddressesProvider.sol';
import {ILendingPool} from '../../interfaces/ILendingPool.sol';
import {ITokenConfiguration} from '../../interfaces/ITokenConfiguration.sol';
import {IERC20Detailed} from '../../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
import {Errors} from '../libraries/helpers/Errors.sol';
import {PercentageMath} from '../libraries/math/PercentageMath.sol';
import {DataTypes} from '../libraries/types/DataTypes.sol';
import {IInitializableDebtToken} from '../../interfaces/IInitializableDebtToken.sol';
import {IInitializableAToken} from '../../interfaces/IInitializableAToken.sol';
import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol';
import {ILendingPoolConfigurator} from '../../interfaces/ILendingPoolConfigurator.sol';
/**
* @title LendingPoolConfigurator contract
@ -22,147 +25,11 @@ import {DataTypes} from '../libraries/types/DataTypes.sol';
* @dev Implements the configuration methods for the Aave protocol
**/
contract LendingPoolConfigurator is VersionedInitializable {
contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigurator {
using SafeMath for uint256;
using PercentageMath for uint256;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
/**
* @dev Emitted when a reserve is initialized.
* @param asset The address of the underlying asset of the reserve
* @param aToken The address of the associated aToken contract
* @param stableDebtToken The address of the associated stable rate debt token
* @param variableDebtToken The address of the associated variable rate debt token
* @param interestRateStrategyAddress The address of the interest rate strategy for the reserve
**/
event ReserveInitialized(
address indexed asset,
address indexed aToken,
address stableDebtToken,
address variableDebtToken,
address interestRateStrategyAddress
);
/**
* @dev Emitted when borrowing is enabled on a reserve
* @param asset The address of the underlying asset of the reserve
* @param stableRateEnabled True if stable rate borrowing is enabled, false otherwise
**/
event BorrowingEnabledOnReserve(address indexed asset, bool stableRateEnabled);
/**
* @dev Emitted when borrowing is disabled on a reserve
* @param asset The address of the underlying asset of the reserve
**/
event BorrowingDisabledOnReserve(address indexed asset);
/**
* @dev Emitted when the collateralization risk parameters for the specified asset are updated.
* @param asset The address of the underlying asset of the reserve
* @param ltv The loan to value of the asset when used as collateral
* @param liquidationThreshold The threshold at which loans using this asset as collateral will be considered undercollateralized
* @param liquidationBonus The bonus liquidators receive to liquidate this asset
**/
event CollateralConfigurationChanged(
address indexed asset,
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus
);
/**
* @dev Emitted when stable rate borrowing is enabled on a reserve
* @param asset The address of the underlying asset of the reserve
**/
event StableRateEnabledOnReserve(address indexed asset);
/**
* @dev Emitted when stable rate borrowing is disabled on a reserve
* @param asset The address of the underlying asset of the reserve
**/
event StableRateDisabledOnReserve(address indexed asset);
/**
* @dev Emitted when a reserve is activated
* @param asset The address of the underlying asset of the reserve
**/
event ReserveActivated(address indexed asset);
/**
* @dev Emitted when a reserve is deactivated
* @param asset The address of the underlying asset of the reserve
**/
event ReserveDeactivated(address indexed asset);
/**
* @dev Emitted when a reserve is frozen
* @param asset The address of the underlying asset of the reserve
**/
event ReserveFrozen(address indexed asset);
/**
* @dev Emitted when a reserve is unfrozen
* @param asset The address of the underlying asset of the reserve
**/
event ReserveUnfrozen(address indexed asset);
/**
* @dev Emitted when a reserve factor is updated
* @param asset The address of the underlying asset of the reserve
* @param factor The new reserve factor
**/
event ReserveFactorChanged(address indexed asset, uint256 factor);
/**
* @dev Emitted when the reserve decimals are updated
* @param asset The address of the underlying asset of the reserve
* @param decimals The new decimals
**/
event ReserveDecimalsChanged(address indexed asset, uint256 decimals);
/**
* @dev Emitted when a reserve interest strategy contract is updated
* @param asset The address of the underlying asset of the reserve
* @param strategy The new address of the interest strategy contract
**/
event ReserveInterestRateStrategyChanged(address indexed asset, address strategy);
/**
* @dev Emitted when an aToken implementation is upgraded
* @param asset The address of the underlying asset of the reserve
* @param proxy The aToken proxy address
* @param implementation The new aToken implementation
**/
event ATokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation
);
/**
* @dev Emitted when the implementation of a stable debt token is upgraded
* @param asset The address of the underlying asset of the reserve
* @param proxy The stable debt token proxy address
* @param implementation The new aToken implementation
**/
event StableDebtTokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation
);
/**
* @dev Emitted when the implementation of a variable debt token is upgraded
* @param asset The address of the underlying asset of the reserve
* @param proxy The variable debt token proxy address
* @param implementation The new aToken implementation
**/
event VariableDebtTokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation
);
ILendingPoolAddressesProvider internal addressesProvider;
ILendingPool internal pool;
@ -191,114 +58,186 @@ contract LendingPoolConfigurator is VersionedInitializable {
}
/**
* @dev Initializes a reserve
* @param aTokenImpl The address of the aToken contract implementation
* @param stableDebtTokenImpl The address of the stable debt token contract
* @param variableDebtTokenImpl The address of the variable debt token contract
* @param underlyingAssetDecimals The decimals of the reserve underlying asset
* @param interestRateStrategyAddress The address of the interest rate strategy contract for this reserve
* @dev Initializes reserves in batch
**/
function initReserve(
address aTokenImpl,
address stableDebtTokenImpl,
address variableDebtTokenImpl,
uint8 underlyingAssetDecimals,
address interestRateStrategyAddress
) public onlyPoolAdmin {
address asset = ITokenConfiguration(aTokenImpl).UNDERLYING_ASSET_ADDRESS();
function batchInitReserve(InitReserveInput[] calldata inputParams) public onlyPoolAdmin {
ILendingPool cachedPool = pool;
for (uint256 i = 0; i < inputParams.length; i++) {
_initReserve(cachedPool, inputParams[i]);
}
}
require(
address(pool) == ITokenConfiguration(aTokenImpl).POOL(),
Errors.LPC_INVALID_ATOKEN_POOL_ADDRESS
);
require(
address(pool) == ITokenConfiguration(stableDebtTokenImpl).POOL(),
Errors.LPC_INVALID_STABLE_DEBT_TOKEN_POOL_ADDRESS
);
require(
address(pool) == ITokenConfiguration(variableDebtTokenImpl).POOL(),
Errors.LPC_INVALID_VARIABLE_DEBT_TOKEN_POOL_ADDRESS
);
require(
asset == ITokenConfiguration(stableDebtTokenImpl).UNDERLYING_ASSET_ADDRESS(),
Errors.LPC_INVALID_STABLE_DEBT_TOKEN_UNDERLYING_ADDRESS
);
require(
asset == ITokenConfiguration(variableDebtTokenImpl).UNDERLYING_ASSET_ADDRESS(),
Errors.LPC_INVALID_VARIABLE_DEBT_TOKEN_UNDERLYING_ADDRESS
);
address aTokenProxyAddress = _initTokenWithProxy(aTokenImpl, underlyingAssetDecimals);
function _initReserve(ILendingPool pool, InitReserveInput calldata inputParams) internal {
address aTokenProxyAddress =
_initTokenWithProxy(
inputParams.aTokenImpl,
abi.encodeWithSelector(
IInitializableAToken.initialize.selector,
pool,
inputParams.treasury,
inputParams.underlyingAsset,
IAaveIncentivesController(inputParams.incentivesController),
inputParams.underlyingAssetDecimals,
inputParams.aTokenName,
inputParams.aTokenSymbol
)
);
address stableDebtTokenProxyAddress =
_initTokenWithProxy(stableDebtTokenImpl, underlyingAssetDecimals);
_initTokenWithProxy(
inputParams.stableDebtTokenImpl,
abi.encodeWithSelector(
IInitializableDebtToken.initialize.selector,
pool,
inputParams.underlyingAsset,
IAaveIncentivesController(inputParams.incentivesController),
inputParams.underlyingAssetDecimals,
inputParams.stableDebtTokenName,
inputParams.stableDebtTokenSymbol
)
);
address variableDebtTokenProxyAddress =
_initTokenWithProxy(variableDebtTokenImpl, underlyingAssetDecimals);
_initTokenWithProxy(
inputParams.variableDebtTokenImpl,
abi.encodeWithSelector(
IInitializableDebtToken.initialize.selector,
pool,
inputParams.underlyingAsset,
IAaveIncentivesController(inputParams.incentivesController),
inputParams.underlyingAssetDecimals,
inputParams.variableDebtTokenName,
inputParams.variableDebtTokenSymbol
)
);
pool.initReserve(
asset,
inputParams.underlyingAsset,
aTokenProxyAddress,
stableDebtTokenProxyAddress,
variableDebtTokenProxyAddress,
interestRateStrategyAddress
inputParams.interestRateStrategyAddress
);
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
DataTypes.ReserveConfigurationMap memory currentConfig =
pool.getConfiguration(inputParams.underlyingAsset);
currentConfig.setDecimals(underlyingAssetDecimals);
currentConfig.setDecimals(inputParams.underlyingAssetDecimals);
currentConfig.setActive(true);
currentConfig.setFrozen(false);
pool.setConfiguration(asset, currentConfig.data);
pool.setConfiguration(inputParams.underlyingAsset, currentConfig.data);
emit ReserveInitialized(
asset,
inputParams.underlyingAsset,
aTokenProxyAddress,
stableDebtTokenProxyAddress,
variableDebtTokenProxyAddress,
interestRateStrategyAddress
inputParams.interestRateStrategyAddress
);
}
/**
* @dev Updates the aToken implementation for the reserve
* @param asset The address of the underlying asset of the reserve to be updated
* @param implementation The address of the new aToken implementation
**/
function updateAToken(address asset, address implementation) external onlyPoolAdmin {
DataTypes.ReserveData memory reserveData = pool.getReserveData(asset);
function updateAToken(UpdateATokenInput calldata inputParams) external onlyPoolAdmin {
ILendingPool cachedPool = pool;
_upgradeTokenImplementation(asset, reserveData.aTokenAddress, implementation);
DataTypes.ReserveData memory reserveData = cachedPool.getReserveData(inputParams.asset);
emit ATokenUpgraded(asset, reserveData.aTokenAddress, implementation);
DataTypes.ReserveConfigurationMap memory configuration =
cachedPool.getConfiguration(inputParams.asset);
(, , , uint256 decimals, ) = configuration.getParamsMemory();
_upgradeTokenImplementation(
reserveData.aTokenAddress,
inputParams.implementation,
abi.encodeWithSelector(
IInitializableAToken.initialize.selector,
cachedPool,
inputParams.treasury,
inputParams.asset,
inputParams.incentivesController,
decimals,
inputParams.name,
inputParams.symbol
)
);
emit ATokenUpgraded(inputParams.asset, reserveData.aTokenAddress, inputParams.implementation);
}
/**
* @dev Updates the stable debt token implementation for the reserve
* @param asset The address of the underlying asset of the reserve to be updated
* @param implementation The address of the new aToken implementation
**/
function updateStableDebtToken(address asset, address implementation) external onlyPoolAdmin {
DataTypes.ReserveData memory reserveData = pool.getReserveData(asset);
function updateStableDebtToken(UpdateDebtTokenInput calldata inputParams) external onlyPoolAdmin {
ILendingPool cachedPool = pool;
_upgradeTokenImplementation(asset, reserveData.stableDebtTokenAddress, implementation);
DataTypes.ReserveData memory reserveData = cachedPool.getReserveData(inputParams.asset);
emit StableDebtTokenUpgraded(asset, reserveData.stableDebtTokenAddress, implementation);
DataTypes.ReserveConfigurationMap memory configuration =
cachedPool.getConfiguration(inputParams.asset);
(, , , uint256 decimals, ) = configuration.getParamsMemory();
_upgradeTokenImplementation(
reserveData.stableDebtTokenAddress,
inputParams.implementation,
abi.encodeWithSelector(
IInitializableDebtToken.initialize.selector,
cachedPool,
inputParams.asset,
inputParams.incentivesController,
decimals,
inputParams.name,
inputParams.symbol
)
);
emit StableDebtTokenUpgraded(
inputParams.asset,
reserveData.stableDebtTokenAddress,
inputParams.implementation
);
}
/**
* @dev Updates the variable debt token implementation for the asset
* @param asset The address of the underlying asset of the reserve to be updated
* @param implementation The address of the new aToken implementation
**/
function updateVariableDebtToken(address asset, address implementation) external onlyPoolAdmin {
DataTypes.ReserveData memory reserveData = pool.getReserveData(asset);
function updateVariableDebtToken(UpdateDebtTokenInput calldata inputParams)
external
onlyPoolAdmin
{
ILendingPool cachedPool = pool;
_upgradeTokenImplementation(asset, reserveData.variableDebtTokenAddress, implementation);
DataTypes.ReserveData memory reserveData = cachedPool.getReserveData(inputParams.asset);
emit VariableDebtTokenUpgraded(asset, reserveData.variableDebtTokenAddress, implementation);
DataTypes.ReserveConfigurationMap memory configuration =
cachedPool.getConfiguration(inputParams.asset);
(, , , uint256 decimals, ) = configuration.getParamsMemory();
_upgradeTokenImplementation(
reserveData.variableDebtTokenAddress,
inputParams.implementation,
abi.encodeWithSelector(
IInitializableDebtToken.initialize.selector,
cachedPool,
inputParams.asset,
inputParams.incentivesController,
decimals,
inputParams.name,
inputParams.symbol
)
);
emit VariableDebtTokenUpgraded(
inputParams.asset,
reserveData.variableDebtTokenAddress,
inputParams.implementation
);
}
/**
@ -509,44 +448,27 @@ contract LendingPoolConfigurator is VersionedInitializable {
pool.setPause(val);
}
function _initTokenWithProxy(address implementation, uint8 decimals) internal returns (address) {
function _initTokenWithProxy(address implementation, bytes memory initParams)
internal
returns (address)
{
InitializableImmutableAdminUpgradeabilityProxy proxy =
new InitializableImmutableAdminUpgradeabilityProxy(address(this));
bytes memory params =
abi.encodeWithSignature(
'initialize(uint8,string,string)',
decimals,
IERC20Detailed(implementation).name(),
IERC20Detailed(implementation).symbol()
);
proxy.initialize(implementation, params);
proxy.initialize(implementation, initParams);
return address(proxy);
}
function _upgradeTokenImplementation(
address asset,
address proxyAddress,
address implementation
address implementation,
bytes memory initParams
) internal {
InitializableImmutableAdminUpgradeabilityProxy proxy =
InitializableImmutableAdminUpgradeabilityProxy(payable(proxyAddress));
DataTypes.ReserveConfigurationMap memory configuration = pool.getConfiguration(asset);
(, , , uint256 decimals, ) = configuration.getParamsMemory();
bytes memory params =
abi.encodeWithSignature(
'initialize(uint8,string,string)',
uint8(decimals),
IERC20Detailed(implementation).name(),
IERC20Detailed(implementation).symbol()
);
proxy.upgradeToAndCall(implementation, params);
proxy.upgradeToAndCall(implementation, initParams);
}
function _checkNoLiquidity(address asset) internal view {

View File

@ -23,4 +23,10 @@ contract LendingPoolStorage {
uint256 internal _reservesCount;
bool internal _paused;
uint256 internal _maxStableRateBorrowSizePercent;
uint256 internal _flashLoanPremiumTotal;
uint256 internal _maxNumberOfReserves;
}

View File

@ -9,13 +9,18 @@ import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {Errors} from '../libraries/helpers/Errors.sol';
import {VersionedInitializable} from '../libraries/aave-upgradeability/VersionedInitializable.sol';
import {IncentivizedERC20} from './IncentivizedERC20.sol';
import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol';
/**
* @title Aave ERC20 AToken
* @dev Implementation of the interest bearing token for the Aave protocol
* @author Aave
*/
contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
contract AToken is
VersionedInitializable,
IncentivizedERC20('ATOKEN_IMPL', 'ATOKEN_IMPL', 0),
IAToken
{
using WadRayMath for uint256;
using SafeERC20 for IERC20;
@ -25,44 +30,46 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
bytes32 public constant PERMIT_TYPEHASH =
keccak256('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)');
uint256 public constant UINT_MAX_VALUE = uint256(-1);
uint256 public constant ATOKEN_REVISION = 0x1;
address public immutable UNDERLYING_ASSET_ADDRESS;
address public immutable RESERVE_TREASURY_ADDRESS;
ILendingPool public immutable POOL;
/// @dev owner => next valid nonce to submit with permit()
mapping(address => uint256) public _nonces;
bytes32 public DOMAIN_SEPARATOR;
modifier onlyLendingPool {
require(_msgSender() == address(POOL), Errors.CT_CALLER_MUST_BE_LENDING_POOL);
_;
}
ILendingPool internal _pool;
address internal _treasury;
address internal _underlyingAsset;
IAaveIncentivesController internal _incentivesController;
constructor(
ILendingPool pool,
address underlyingAssetAddress,
address reserveTreasuryAddress,
string memory tokenName,
string memory tokenSymbol,
address incentivesController
) public IncentivizedERC20(tokenName, tokenSymbol, 18, incentivesController) {
POOL = pool;
UNDERLYING_ASSET_ADDRESS = underlyingAssetAddress;
RESERVE_TREASURY_ADDRESS = reserveTreasuryAddress;
modifier onlyLendingPool {
require(_msgSender() == address(_pool), Errors.CT_CALLER_MUST_BE_LENDING_POOL);
_;
}
function getRevision() internal pure virtual override returns (uint256) {
return ATOKEN_REVISION;
}
/**
* @dev Initializes the aToken
* @param pool The address of the lending pool where this aToken will be used
* @param treasury The address of the Aave treasury, receiving the fees on this aToken
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
* @param incentivesController The smart contract managing potential incentives distribution
* @param aTokenDecimals The decimals of the aToken, same as the underlying asset's
* @param aTokenName The name of the aToken
* @param aTokenSymbol The symbol of the aToken
*/
function initialize(
uint8 underlyingAssetDecimals,
string calldata tokenName,
string calldata tokenSymbol
) external virtual initializer {
ILendingPool pool,
address treasury,
address underlyingAsset,
IAaveIncentivesController incentivesController,
uint8 aTokenDecimals,
string calldata aTokenName,
string calldata aTokenSymbol
) external override initializer {
uint256 chainId;
//solium-disable-next-line
@ -73,16 +80,21 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
DOMAIN_SEPARATOR = keccak256(
abi.encode(
EIP712_DOMAIN,
keccak256(bytes(tokenName)),
keccak256(bytes(aTokenName)),
keccak256(EIP712_REVISION),
chainId,
address(this)
)
);
_setName(tokenName);
_setSymbol(tokenSymbol);
_setDecimals(underlyingAssetDecimals);
_setName(aTokenName);
_setSymbol(aTokenSymbol);
_setDecimals(aTokenDecimals);
_pool = pool;
_treasury = treasury;
_underlyingAsset = underlyingAsset;
_incentivesController = incentivesController;
}
/**
@ -103,7 +115,7 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
require(amountScaled != 0, Errors.CT_INVALID_BURN_AMOUNT);
_burn(user, amountScaled);
IERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(receiverOfUnderlying, amount);
IERC20(_underlyingAsset).safeTransfer(receiverOfUnderlying, amount);
emit Transfer(user, address(0), amount);
emit Burn(user, receiverOfUnderlying, amount, index);
@ -145,14 +157,16 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
return;
}
address treasury = _treasury;
// Compared to the normal mint, we don't check for rounding errors.
// The amount to mint can easily be very small since it is a fraction of the interest ccrued.
// In that case, the treasury will experience a (very small) loss, but it
// wont cause potentially valid transactions to fail.
_mint(RESERVE_TREASURY_ADDRESS, amount.rayDiv(index));
_mint(treasury, amount.rayDiv(index));
emit Transfer(address(0), RESERVE_TREASURY_ADDRESS, amount);
emit Mint(RESERVE_TREASURY_ADDRESS, amount, index);
emit Transfer(address(0), treasury, amount);
emit Mint(treasury, amount, index);
}
/**
@ -185,7 +199,7 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
override(IncentivizedERC20, IERC20)
returns (uint256)
{
return super.balanceOf(user).rayMul(POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS));
return super.balanceOf(user).rayMul(_pool.getReserveNormalizedIncome(_underlyingAsset));
}
/**
@ -226,7 +240,7 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
return 0;
}
return currentSupplyScaled.rayMul(POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS));
return currentSupplyScaled.rayMul(_pool.getReserveNormalizedIncome(_underlyingAsset));
}
/**
@ -237,6 +251,41 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
return super.totalSupply();
}
/**
* @dev Returns the address of the Aave treasury, receiving the fees on this aToken
**/
function RESERVE_TREASURY_ADDRESS() public view returns (address) {
return _treasury;
}
/**
* @dev Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
**/
function UNDERLYING_ASSET_ADDRESS() public view returns (address) {
return _underlyingAsset;
}
/**
* @dev Returns the address of the lending pool where this aToken is used
**/
function POOL() public view returns (ILendingPool) {
return _pool;
}
/**
* @dev For internal usage in the logic of the parent contract IncentivizedERC20
**/
function _getIncentivesController() internal view override returns (IAaveIncentivesController) {
return _incentivesController;
}
/**
* @dev Returns the address of the incentives controller contract
**/
function getIncentivesController() external view override returns (IAaveIncentivesController) {
return _getIncentivesController();
}
/**
* @dev Transfers the underlying asset to `target`. Used by the LendingPool to transfer
* assets in borrow(), withdraw() and flashLoan()
@ -250,7 +299,7 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
onlyLendingPool
returns (uint256)
{
IERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(target, amount);
IERC20(_underlyingAsset).safeTransfer(target, amount);
return amount;
}
@ -305,7 +354,10 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
uint256 amount,
bool validate
) internal {
uint256 index = POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS);
address underlyingAsset = _underlyingAsset;
ILendingPool pool = _pool;
uint256 index = pool.getReserveNormalizedIncome(underlyingAsset);
uint256 fromBalanceBefore = super.balanceOf(from).rayMul(index);
uint256 toBalanceBefore = super.balanceOf(to).rayMul(index);
@ -313,14 +365,7 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
super._transfer(from, to, amount.rayDiv(index));
if (validate) {
POOL.finalizeTransfer(
UNDERLYING_ASSET_ADDRESS,
from,
to,
amount,
fromBalanceBefore,
toBalanceBefore
);
pool.finalizeTransfer(underlyingAsset, from, to, amount, fromBalanceBefore, toBalanceBefore);
}
emit BalanceTransfer(from, to, amount, index);

View File

@ -14,36 +14,17 @@ import {AToken} from './AToken.sol';
contract DelegationAwareAToken is AToken {
modifier onlyPoolAdmin {
require(
_msgSender() == ILendingPool(POOL).getAddressesProvider().getPoolAdmin(),
_msgSender() == ILendingPool(_pool).getAddressesProvider().getPoolAdmin(),
Errors.CALLER_NOT_POOL_ADMIN
);
_;
}
constructor(
ILendingPool pool,
address underlyingAssetAddress,
address reserveTreasury,
string memory tokenName,
string memory tokenSymbol,
address incentivesController
)
public
AToken(
pool,
underlyingAssetAddress,
reserveTreasury,
tokenName,
tokenSymbol,
incentivesController
)
{}
/**
* @dev Delegates voting power of the underlying asset to a `delegatee` address
* @param delegatee The address that will receive the delegation
**/
function delegateUnderlyingTo(address delegatee) external onlyPoolAdmin {
IDelegationToken(UNDERLYING_ASSET_ADDRESS).delegate(delegatee);
IDelegationToken(_underlyingAsset).delegate(delegatee);
}
}

View File

@ -12,11 +12,9 @@ import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesControl
* @notice Basic ERC20 implementation
* @author Aave, inspired by the Openzeppelin ERC20 implementation
**/
contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
abstract contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
using SafeMath for uint256;
IAaveIncentivesController internal immutable _incentivesController;
mapping(address => uint256) internal _balances;
mapping(address => mapping(address => uint256)) private _allowances;
@ -28,13 +26,11 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
constructor(
string memory name,
string memory symbol,
uint8 decimals,
address incentivesController
uint8 decimals
) public {
_name = name;
_symbol = symbol;
_decimals = decimals;
_incentivesController = IAaveIncentivesController(incentivesController);
}
/**
@ -72,6 +68,12 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
return _balances[account];
}
/**
* @return Abstract function implemented by the child aToken/debtToken.
* Done this way in order to not break compatibility with previous versions of aTokens/debtTokens
**/
function _getIncentivesController() internal view virtual returns(IAaveIncentivesController);
/**
* @dev Executes a transfer of tokens from _msgSender() to recipient
* @param recipient The recipient of the tokens
@ -180,11 +182,11 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
uint256 oldRecipientBalance = _balances[recipient];
_balances[recipient] = _balances[recipient].add(amount);
if (address(_incentivesController) != address(0)) {
if (address(_getIncentivesController()) != address(0)) {
uint256 currentTotalSupply = _totalSupply;
_incentivesController.handleAction(sender, currentTotalSupply, oldSenderBalance);
_getIncentivesController().handleAction(sender, currentTotalSupply, oldSenderBalance);
if (sender != recipient) {
_incentivesController.handleAction(recipient, currentTotalSupply, oldRecipientBalance);
_getIncentivesController().handleAction(recipient, currentTotalSupply, oldRecipientBalance);
}
}
}
@ -200,8 +202,8 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
uint256 oldAccountBalance = _balances[account];
_balances[account] = oldAccountBalance.add(amount);
if (address(_incentivesController) != address(0)) {
_incentivesController.handleAction(account, oldTotalSupply, oldAccountBalance);
if (address(_getIncentivesController()) != address(0)) {
_getIncentivesController().handleAction(account, oldTotalSupply, oldAccountBalance);
}
}
@ -216,8 +218,8 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
uint256 oldAccountBalance = _balances[account];
_balances[account] = oldAccountBalance.sub(amount, 'ERC20: burn amount exceeds balance');
if (address(_incentivesController) != address(0)) {
_incentivesController.handleAction(account, oldTotalSupply, oldAccountBalance);
if (address(_getIncentivesController()) != address(0)) {
_getIncentivesController().handleAction(account, oldTotalSupply, oldAccountBalance);
}
}

View File

@ -5,6 +5,8 @@ import {DebtTokenBase} from './base/DebtTokenBase.sol';
import {MathUtils} from '../libraries/math/MathUtils.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {IStableDebtToken} from '../../interfaces/IStableDebtToken.sol';
import {ILendingPool} from '../../interfaces/ILendingPool.sol';
import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol';
import {Errors} from '../libraries/helpers/Errors.sol';
/**
@ -23,13 +25,35 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
mapping(address => uint256) internal _usersStableRate;
uint40 internal _totalSupplyTimestamp;
constructor(
address pool,
ILendingPool internal _pool;
address internal _underlyingAsset;
IAaveIncentivesController internal _incentivesController;
/**
* @dev Initializes the debt token.
* @param pool The address of the lending pool where this aToken will be used
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
* @param incentivesController The smart contract managing potential incentives distribution
* @param debtTokenDecimals The decimals of the debtToken, same as the underlying asset's
* @param debtTokenName The name of the token
* @param debtTokenSymbol The symbol of the token
*/
function initialize(
ILendingPool pool,
address underlyingAsset,
string memory name,
string memory symbol,
address incentivesController
) public DebtTokenBase(pool, underlyingAsset, name, symbol, incentivesController) {}
IAaveIncentivesController incentivesController,
uint8 debtTokenDecimals,
string memory debtTokenName,
string memory debtTokenSymbol
) public override initializer {
_setName(debtTokenName);
_setSymbol(debtTokenSymbol);
_setDecimals(debtTokenDecimals);
_pool = pool;
_underlyingAsset = underlyingAsset;
_incentivesController = incentivesController;
}
/**
* @dev Gets the revision of the stable debt token implementation
@ -300,6 +324,48 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
return super.balanceOf(user);
}
/**
* @dev Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
**/
function UNDERLYING_ASSET_ADDRESS() public view returns (address) {
return _underlyingAsset;
}
/**
* @dev Returns the address of the lending pool where this aToken is used
**/
function POOL() public view returns (ILendingPool) {
return _pool;
}
/**
* @dev Returns the address of the incentives controller contract
**/
function getIncentivesController() external view override returns (IAaveIncentivesController) {
return _getIncentivesController();
}
/**
* @dev For internal usage in the logic of the parent contracts
**/
function _getIncentivesController() internal view override returns (IAaveIncentivesController) {
return _incentivesController;
}
/**
* @dev For internal usage in the logic of the parent contracts
**/
function _getUnderlyingAssetAddress() internal view override returns (address) {
return _underlyingAsset;
}
/**
* @dev For internal usage in the logic of the parent contracts
**/
function _getLendingPool() internal view override returns (ILendingPool) {
return _pool;
}
/**
* @dev Calculates the total supply
* @param avgRate The average rate at which the total supply increases

View File

@ -5,6 +5,8 @@ import {IVariableDebtToken} from '../../interfaces/IVariableDebtToken.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {Errors} from '../libraries/helpers/Errors.sol';
import {DebtTokenBase} from './base/DebtTokenBase.sol';
import {ILendingPool} from '../../interfaces/ILendingPool.sol';
import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol';
/**
* @title VariableDebtToken
@ -17,13 +19,35 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
uint256 public constant DEBT_TOKEN_REVISION = 0x1;
constructor(
address pool,
ILendingPool internal _pool;
address internal _underlyingAsset;
IAaveIncentivesController internal _incentivesController;
/**
* @dev Initializes the debt token.
* @param pool The address of the lending pool where this aToken will be used
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
* @param incentivesController The smart contract managing potential incentives distribution
* @param debtTokenDecimals The decimals of the debtToken, same as the underlying asset's
* @param debtTokenName The name of the token
* @param debtTokenSymbol The symbol of the token
*/
function initialize(
ILendingPool pool,
address underlyingAsset,
string memory name,
string memory symbol,
address incentivesController
) public DebtTokenBase(pool, underlyingAsset, name, symbol, incentivesController) {}
IAaveIncentivesController incentivesController,
uint8 debtTokenDecimals,
string memory debtTokenName,
string memory debtTokenSymbol
) public override initializer {
_setName(debtTokenName);
_setSymbol(debtTokenSymbol);
_setDecimals(debtTokenDecimals);
_pool = pool;
_underlyingAsset = underlyingAsset;
_incentivesController = incentivesController;
}
/**
* @dev Gets the revision of the stable debt token implementation
@ -44,7 +68,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
return 0;
}
return scaledBalance.rayMul(POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET_ADDRESS));
return scaledBalance.rayMul(_pool.getReserveNormalizedVariableDebt(_underlyingAsset));
}
/**
@ -113,8 +137,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
* @return The total supply
**/
function totalSupply() public view virtual override returns (uint256) {
return
super.totalSupply().rayMul(POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET_ADDRESS));
return super.totalSupply().rayMul(_pool.getReserveNormalizedVariableDebt(_underlyingAsset));
}
/**
@ -139,4 +162,37 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
{
return (super.balanceOf(user), super.totalSupply());
}
/**
* @dev Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
**/
function UNDERLYING_ASSET_ADDRESS() public view returns (address) {
return _underlyingAsset;
}
/**
* @dev Returns the address of the incentives controller contract
**/
function getIncentivesController() external view override returns (IAaveIncentivesController) {
return _getIncentivesController();
}
/**
* @dev Returns the address of the lending pool where this aToken is used
**/
function POOL() public view returns (ILendingPool) {
return _pool;
}
function _getIncentivesController() internal view override returns (IAaveIncentivesController) {
return _incentivesController;
}
function _getUnderlyingAssetAddress() internal view override returns (address) {
return _underlyingAsset;
}
function _getLendingPool() internal view override returns (ILendingPool) {
return _pool;
}
}

View File

@ -16,54 +16,20 @@ import {Errors} from '../../libraries/helpers/Errors.sol';
*/
abstract contract DebtTokenBase is
IncentivizedERC20,
IncentivizedERC20('DEBTTOKEN_IMPL', 'DEBTTOKEN_IMPL', 0),
VersionedInitializable,
ICreditDelegationToken
{
address public immutable UNDERLYING_ASSET_ADDRESS;
ILendingPool public immutable POOL;
mapping(address => mapping(address => uint256)) internal _borrowAllowances;
/**
* @dev Only lending pool can call functions marked by this modifier
**/
modifier onlyLendingPool {
require(_msgSender() == address(POOL), Errors.CT_CALLER_MUST_BE_LENDING_POOL);
require(_msgSender() == address(_getLendingPool()), Errors.CT_CALLER_MUST_BE_LENDING_POOL);
_;
}
/**
* @dev The metadata of the token will be set on the proxy, that the reason of
* passing "NULL" and 0 as metadata
*/
constructor(
address pool,
address underlyingAssetAddress,
string memory name,
string memory symbol,
address incentivesController
) public IncentivizedERC20(name, symbol, 18, incentivesController) {
POOL = ILendingPool(pool);
UNDERLYING_ASSET_ADDRESS = underlyingAssetAddress;
}
/**
* @dev Initializes the debt token.
* @param name The name of the token
* @param symbol The symbol of the token
* @param decimals The decimals of the token
*/
function initialize(
uint8 decimals,
string memory name,
string memory symbol
) public initializer {
_setName(name);
_setSymbol(symbol);
_setDecimals(decimals);
}
/**
* @dev delegates borrowing power to a user on the specific debt token
* @param delegatee the address receiving the delegated borrowing power
@ -73,7 +39,7 @@ abstract contract DebtTokenBase is
**/
function approveDelegation(address delegatee, uint256 amount) external override {
_borrowAllowances[_msgSender()][delegatee] = amount;
emit BorrowAllowanceDelegated(_msgSender(), delegatee, UNDERLYING_ASSET_ADDRESS, amount);
emit BorrowAllowanceDelegated(_msgSender(), delegatee, _getUnderlyingAssetAddress(), amount);
}
/**
@ -162,6 +128,10 @@ abstract contract DebtTokenBase is
_borrowAllowances[delegator][delegatee] = newAllowance;
emit BorrowAllowanceDelegated(delegator, delegatee, UNDERLYING_ASSET_ADDRESS, newAllowance);
emit BorrowAllowanceDelegated(delegator, delegatee, _getUnderlyingAssetAddress(), newAllowance);
}
function _getUnderlyingAssetAddress() internal view virtual returns (address);
function _getLendingPool() internal view virtual returns (ILendingPool);
}