@aave/safety-module 中文文档教程
Aave Incentives contracts
一组智能合约,以实现 Aave 相关资产的股权和基于它们的奖励分配。
Specification
Architecture
一个通用的父合约 AaveDistributionManager
用于保持一组子前端合约的“会计”逻辑每种类型的奖励; 这些,最初是一个 StakedAave
合约,用于在 Aave SM(安全模块)上持有 Aave 代币,这将在不久的将来用作安全基金,以及一个 AaveIncentivesController
Aave 协议将通过该合约进行交互,以提供奖励作为对用户的激励。 这个继承链分为 2 个主要层的基本原理是在分布配置和数学计算的公共部分与每种类型激励的一个特定部分(将资金锁定在股份中,为协议提供流动性以及未来可能更多)。 此外,还有一个奖励金库,用于保存 AAVE 奖励,通过 StakedAave
和 AaveIncentivesController
进行分配。 两者都将提前获得拨款津贴。 以下部分将详细介绍 AaveDistributionManager
和不同的前端合约的规范。
AaveDistributionManager
用于计算具有不同配置的多个分布的核心合同。 用户/aave 协议将与之交互的所有前端合约都继承自 AaveDistributionManager
。 它根据分配的前端合约定义的用户情况计算属于某个用户的奖励有多少。 该计算是通过使用代表每秒排放的奖励累积的分布指数并在每个用户上快照该指数以考虑总数中有多少属于他来完成的。
Data
assets
. Mapping ofAssetData
structs which, for each front contract connected to theAaveDistributionManager
stores 1 or more of:emissionPerSecond
: Amount of rewards per second distribution-wide. It's used to calculate the raw amount of rewards to distribute in a time delta since the last update of the following describedindex
.index
: Variable representing the accumulated rewards distributed distribution-wide per unit of token used in the specific child contract of the distribution (per unit of staked Aave in the case of theStakedAave
child contract). The next index is calculated by the formula on_getNormalizedDistribution()
emissionPerSecond _ timeDelta _ 10^PRECISION / balanceOnFrontContract + previousIndex, scaling it up multiplying by 10^18 in order to not lose precision.lastUpdateTimestamp
: timestamp when the struct was updated.userIndexes
: mapping user address => index snapshotted on the user from the one of the distribution.
对于子 StakedAave
,它们使用的映射的键是 StakedAave
本身的地址。 对于 AaveIncentivesController
,提交给激励的每个 aToken 和 debtToken 都有不同的键和结构。
Logic
该合约允许执行以下操作:
- Configuration of multiple distributions: only allowed to a trusted
EMISSION_MANAGER
, allows to list an specific distribution, with some emission per second and front contract. - Update of user/distribution state on interaction: called by the child contract when something happened concerning the situation on the user, for example when he stakes on
StakedAave
, redeems, deposit on the Aave protocol, etc… - Get the unclaimed rewards of an user: self-explanatory, used by the children contracts to check how much rewards were accrued for an user and store the data if needed on their side, by interacting with the
claimRewards()
function. - Query information about distributions/users: by using the different view functions available.
StakedAave
持有 AAVE 代币的合约,在不久的将来与削减机制连接,以保护 Aave 协议,形成所谓的 Aave SM(安全模块)。 Aave 代币的持有者将他们加入此合约,他们将收到等量的 stkAAVE
代币,并开始在 AAVE 中累积奖励; 先前由受信任的 EMISSION_MANAGER 在父合约 AaveDistributionManager
上配置的奖励。 一旦他们累积了 AAVE 奖励,他们就可以随时领取,但是,要提取他们抵押的 AAVE 代币,他们需要激活并等待一段冷却时间,然后在提取时间窗口内立即提取。
Data
stakerRewardsToClaim
: mapping storing the accrued rewards accrued and stored for an user, not taking into account those accrued but not stored yet.stakersCooldowns
: mapping the timestamp of activation of cooldown period for an user, if activated.
Logic
该合约允许执行以下操作:
- Stake AAVE tokens to start accruing rewards: through the
stake()
function. The AAVE tokens will be locked in this same contract, and stkAAVE tokens will be minted for the user in the same proportion as AAVE staked, the state in the fatherAaveDistributionManager
will be updated and the timestamp of the cooldown will be updated too. - Withdraw staked AAVE tokens: if an user has stkAAVE, he can call the
redeem()
function, burning the stkAAVE and receiving the same proportion of previously staked AAVE. The withdrawal will only suceed if the user in on the withdrawal window after the cooldown period. - Activate the cooldown period: self-explanatory, calling the
cooldown()
function and needed to withdraw the staked AAVE. - Claim the accrued rewards: by calling the
claimRewards()
function, used to update the state and transfer to the user the accrued rewards, consequence of the time he was/is staking. - Query information about users: about their rewards or cooldown period.
Cooldown period
冷却期的主要目标是避免未来安全模块出现的情况,如果发生削减事件,人们开始大量撤回他们的抵押资金,让协议暴露并删除实用程序股份本身。 为实现这一点,涉及 StakedAave
合约的任何状态更新/操作都需要满足的最重要条件是,如果用户质押退出,他已经遵守了冷却时间,这会导致资金流动应该只会对冷却时间产生“负面”影响。 根据操作类型,冷却时间受到以下方式的影响:
- If an user stakes AAVE with/without having any fund staked before, if he didn't have the cooldown activated, it remains the same way.
- If an user stakes AAVE holding already stkAAVE and with cooldown period activated:
- If the cooldown is expired, remains expired.
- If the cooldown is still valid, using the amount staked and the current timestamp, it does the weighted average with the current cooldown timestamp of the user.
- If the user redeems AAVE, the cooldown timestamp is set to 0.
- If the user claims rewards, the cooldown timestamp is not affected.
- On transfer of stkAAVE:
- The cooldown timestamp of the sender remains as it is.
- On the recipient:
- If the recipient is on a valid cooldown period finishing before that the one of the sender, we do the same weighted average as in stake().
- If the recipient has an expired cooldown timestamp, his cooldown timetamp is set to 0.
- If both sender and recipient have valid cooldown period activated and the one of the sender ends before than the recipient, the recipient keeps his own.
AaveIncentivesController
合同负责 Aave 协议上活动的激励,继承自 AaveDistributionManager
。 每次在 Aave 协议上发生涉及用户任何激励的动作时,都会调用该合约来管理激励状态的更新。
Data
_usersUnclaimedRewards
: mapping storing the accrued rewards accrued and stored for an user, not taking into account those accrued but not stored yet.
Logic
该合约允许执行以下操作:
- Communication Aave protocol -> incentives: through the whitelisted function
handleAction()
, only callable by the Aave lending pool. For every asset and user, one call to this function needs to be done, which will trigger a state update in both the rewards of the user and the distribution data. - Claim of user rewards: by
claimRewards()
function, transferring to the user the AAVE rewards. If the user tries to claim his rewards with theStakedAave
as target, a bonus will applied on the rewards accumulated from his activity on the protocol, and thestake()
function on theStakedAave
will be called. - Query information about users: mainly about the state of their rewards.
Audits
该存储库中的 Solidity 代码已经过 Consensys Diligence 和 Certik 的 2 次传统智能合约审计。 报告如下:
- Consensys Diligence
- Certik
Current Mainnet contracts (25/09/2020)
[MAIN]
- StakedAave proxy 0x4da27a545c0c5b758a6ba100e3a049001de870f5
- StakedAave implementation 0x74a7a4e7566a2f523986e500ce35b20d343f6741
Credits
对于与代理相关的合约,我们使用了来自 OpenZeppelin 的朋友的实现。
License
此存储库的内容受 AGPLv3 许可。
Aave Incentives contracts
Sets of smart contracts to enable stake of Aave-related assets and rewards distribution based on them.
Specification
Architecture
A common parent contract AaveDistributionManager
is used to keep the "accounting" logic for a set of children front contracts taking care of each type of incentive; being these, initially, a StakedAave
contract for stake of Aave tokens on the Aave SM (Security Module) which will which be used as security fund in the near future, and a AaveIncentivesController
contract through which the Aave protocol will interact in order to provider rewards as incentives to users. The rationale of this inheritance chain in 2 main layers is the clearly conceptual separation between a common part of configurations of the distributions and mathematical calculation, and one specific part for each type of incentive (locking funds in a stake, providing liquidity to a protocol and potentially more in the future). Additionally, there will be a Rewards vault where the AAVE rewards will be keep, to distribute through the StakedAave
and the AaveIncentivesController
. Both will be granted in advance with allowance to pull funds from. The following sections will go in detail on the specification of both the AaveDistributionManager
and the different front contracts.
AaveDistributionManager
Core contract for calculation of multiple distributions with different configurations. All the front contracts which users/aave protocol will interact with inherit from the AaveDistributionManager
. It calculates how many rewards belong to a certain user depending on the user's situation defined by the front contract of the distribution. This calculation is done by using a distribution index representing the accumulation of rewards from an emission per second and snapshoting that index on each user to take into account how much of the total belongs to him.
Data
assets
. Mapping ofAssetData
structs which, for each front contract connected to theAaveDistributionManager
stores 1 or more of:emissionPerSecond
: Amount of rewards per second distribution-wide. It's used to calculate the raw amount of rewards to distribute in a time delta since the last update of the following describedindex
.index
: Variable representing the accumulated rewards distributed distribution-wide per unit of token used in the specific child contract of the distribution (per unit of staked Aave in the case of theStakedAave
child contract). The next index is calculated by the formula on_getNormalizedDistribution()
emissionPerSecond _ timeDelta _ 10^PRECISION / balanceOnFrontContract + previousIndex, scaling it up multiplying by 10^18 in order to not lose precision.lastUpdateTimestamp
: timestamp when the struct was updated.userIndexes
: mapping user address => index snapshotted on the user from the one of the distribution.
For the child StakedAave
, they key of the mapping used is the address of the StakedAave
itself. In the case of the AaveIncentivesController
, there is a different key and struct for each aToken and debtToken submitted to incentives.
Logic
This contract allows to do the following:
- Configuration of multiple distributions: only allowed to a trusted
EMISSION_MANAGER
, allows to list an specific distribution, with some emission per second and front contract. - Update of user/distribution state on interaction: called by the child contract when something happened concerning the situation on the user, for example when he stakes on
StakedAave
, redeems, deposit on the Aave protocol, etc… - Get the unclaimed rewards of an user: self-explanatory, used by the children contracts to check how much rewards were accrued for an user and store the data if needed on their side, by interacting with the
claimRewards()
function. - Query information about distributions/users: by using the different view functions available.
StakedAave
Contract to stake AAVE token, to be connected with a slashing mechanism in the near future in order to secure the Aave protocol, forming the so called Aave SM (Security Module). Holders of Aave tokens stae them in this contract, they receive equivalent amount in stkAAVE
tokens and start accruing rewards in AAVE; rewards previously configured on the father contract AaveDistributionManager
by the a trusted EMISSION_MANAGER. Once they accrued AAVE rewards, they can claim them at any moment but, to withdraw their staked AAVE tokens, they need to activate and wait a cooldown period, and withdraw just after it, during a withdrawal time window.
Data
stakerRewardsToClaim
: mapping storing the accrued rewards accrued and stored for an user, not taking into account those accrued but not stored yet.stakersCooldowns
: mapping the timestamp of activation of cooldown period for an user, if activated.
Logic
This contract allows to do the following:
- Stake AAVE tokens to start accruing rewards: through the
stake()
function. The AAVE tokens will be locked in this same contract, and stkAAVE tokens will be minted for the user in the same proportion as AAVE staked, the state in the fatherAaveDistributionManager
will be updated and the timestamp of the cooldown will be updated too. - Withdraw staked AAVE tokens: if an user has stkAAVE, he can call the
redeem()
function, burning the stkAAVE and receiving the same proportion of previously staked AAVE. The withdrawal will only suceed if the user in on the withdrawal window after the cooldown period. - Activate the cooldown period: self-explanatory, calling the
cooldown()
function and needed to withdraw the staked AAVE. - Claim the accrued rewards: by calling the
claimRewards()
function, used to update the state and transfer to the user the accrued rewards, consequence of the time he was/is staking. - Query information about users: about their rewards or cooldown period.
Cooldown period
The main objective of the cooldown period is to avoid situations on the future Security Module when, if an slashing event happens, people starts withdrawing in mass their staked funds, leaving the protocol uncover and removing the utility on the stake itself. To achieve this, the most important condition to be fullfilled on any state update/operation involving the StakedAave
contract is that, if a user staking withdraws, he already respected a cooldown period, which leads that movement of funds should only affect "negatively" the cooldown period. Depending on the type of operation, the cooldown period is affected in the following way:
- If an user stakes AAVE with/without having any fund staked before, if he didn't have the cooldown activated, it remains the same way.
- If an user stakes AAVE holding already stkAAVE and with cooldown period activated:
- If the cooldown is expired, remains expired.
- If the cooldown is still valid, using the amount staked and the current timestamp, it does the weighted average with the current cooldown timestamp of the user.
- If the user redeems AAVE, the cooldown timestamp is set to 0.
- If the user claims rewards, the cooldown timestamp is not affected.
- On transfer of stkAAVE:
- The cooldown timestamp of the sender remains as it is.
- On the recipient:
- If the recipient is on a valid cooldown period finishing before that the one of the sender, we do the same weighted average as in stake().
- If the recipient has an expired cooldown timestamp, his cooldown timetamp is set to 0.
- If both sender and recipient have valid cooldown period activated and the one of the sender ends before than the recipient, the recipient keeps his own.
AaveIncentivesController
Contract in charge of the incentives for activity on the Aave protocol, inheriting from the AaveDistributionManager
. Each time an action involving any incentive for an user happens on the Aave protocol, this contract is called to manage the update of the incentives state.
Data
_usersUnclaimedRewards
: mapping storing the accrued rewards accrued and stored for an user, not taking into account those accrued but not stored yet.
Logic
This contract allows to do the following:
- Communication Aave protocol -> incentives: through the whitelisted function
handleAction()
, only callable by the Aave lending pool. For every asset and user, one call to this function needs to be done, which will trigger a state update in both the rewards of the user and the distribution data. - Claim of user rewards: by
claimRewards()
function, transferring to the user the AAVE rewards. If the user tries to claim his rewards with theStakedAave
as target, a bonus will applied on the rewards accumulated from his activity on the protocol, and thestake()
function on theStakedAave
will be called. - Query information about users: mainly about the state of their rewards.
Audits
The Solidity code in this repository has undergone 2 traditional smart contracts' audits by Consensys Diligence and Certik. The reports are:
- Consensys Diligence
- Certik
Current Mainnet contracts (25/09/2020)
[MAIN]
- StakedAave proxy 0x4da27a545c0c5b758a6ba100e3a049001de870f5
- StakedAave implementation 0x74a7a4e7566a2f523986e500ce35b20d343f6741
Credits
For the proxy-related contracts, we have used the implementation of our friend from OpenZeppelin.
License
The contents of this repository are under the AGPLv3 license.