- A+
这篇文章是借贷系列文章的第三篇,看看DeFi借贷协议如何通过奖励来激励参与者。
在以前的文章中,我们探讨了DeFi借贷的两个关键概念:借贷和清算。在这最后这篇文章中,我们将探讨协议如何使用奖励来激励存款人。
本文主要内容:
- 为什么奖励 ?
- 使用协议代币作为奖励
- Liquity (LQTY)
- Aave V2 (AAVE 和 stkAAVE)
- Compound(COMP)
- 归纳奖励方案
为什么奖励?
我们前面已经介绍了一些主要的借贷协议,如 AAVE、Compound 和 Maker,以及像 Euler 这样的小协议。这些协议在没有存款人存款资产的情况下是无法运作的。例如,AAVE 的 aToken
和 Compound 的cToken
都需要大量的流动性来实现借贷。AAVE的 USDT aToken 在撰写本文时就有 超过1.14亿 USDT。协议通过提供健康和稳定的金融生态系统以及包括奖励在内的金融激励措施来竞争储户的资产。
协议代币
协议通常以自己的协议代币发放奖励,这大致代表了协议中的所有权份额。协议代币的持有者通常有权通过对提案进行投票来参与治理,但治理不在这篇文章的范围内--我们可以就此做一个完整的系列。
从存款人的角度来看,分配存款以赚取协议代币的策略通常被称为流动性挖矿。一些协议允许协议代币的持有者将其代币质押,以获得进一步的奖励。
在下面的章节中,我们将探讨在三个有趣的协议中如何分配协议代币作为奖励:Liquity、AAVE V2和Compound。最后,我们对这些概念进行了归纳,说明这三种实现方式具有相同的基本概念。
Liquity (LQTY)
Liquity 实现了用稳定币 LUSD 支付的无息、以太币支持的贷款。贷款必须保持110%的固定最低抵押率。该协议是无治理和不可变的。协议代币LQTY使其持有者有权获得协议所赚取的费用份额。
回顾我们之前的文章,当用户的借款余额超过协议定义的阈值,有穿仓风险时,协议使第三方能够在清算中扣押抵押品。这些清算不是自动化进行的,而是委托给复杂的DeFi用户,他们开发智能合约和操作,以清算用户获利。
Liquity 采取了一种不同的方法。它不依靠第三方,而是与 LUSD 一起维持一个稳定池(Stability Pool)。当贷款需清算时,稳定池中的LUSD被用来偿还贷款。这些LUSD被销毁,以太币的抵押品被分配给向稳定池提供LUSD的用户。
Liquity 的清算
由于至少要满足 110% 抵押率,大多数清算对稳定池来说是有利可图的,因为参与者从抵押品中获得的ETH价值超过他们销毁 LUSD 的损失。更多关于Liquity清算的逻辑,请看他们的文档。
Liquity 通过发行协议代币(LQTY)的奖励来进一步激励对稳定池的参与。让我们来看看分配逻辑:
pragma solidity ^0.8.13;
function _getLQTYGainFromSnapshots(uint initialStake, Snapshots memory snapshots) internal view returns(uint) {
/*
* Grab the sum 'G' from the epoch at which the stake was made. The LQTY
gain may span up to one scale change.
* If it does, the second portion of the LQTY gain is scaled by 1e9.
* If the gain spans no scale change, the second portion will be 0.
*/
uint128 epochSnapshot = snapshots.epoch;
uint128 scaleSnapshot = snapshots.scale;
uint G_Snapshot = snapshots.G;
uint P_Snapshot = snapshots.P;
uint firstPortion =
epochToScaleToG[epochSnapshot][scaleSnapshot].sub(G_Snapshot);
uint secondPortion =
epochToScaleToG[epochSnapshot][scaleSnapshot.add(1)].div(SCALE_FACTOR);
uint LQTYGain =
initialStake.mul(firstPortion.add(secondPortion)).div(P_Snapshot).div(DECIMAL_PRECISION);
return LQTYGain;
}
该功能依赖于两个关键概念:
G
代表一个全局累积器,反映协议发出的LQTY
奖励的累积总和。P
是一个全局乘积累加器,跟踪复利存款利率随时间变化的总体乘积。它在LUSD
清算给稳定池参与者带来的损失时减少。
以下是该功能的工作原理:
- 提取相关的快照值,包括
epoch
,scale
,G
和P
。这些值取自用户最后一次更新stake的时间。 - 计算
firstPortion
,用G_Snapshot
值减去相应epoch 和 scale 的G
值。这代表在同一 scale 内发生的LQTY
收益。 - 通过将
secondPortion
, 下一个scale
的G
值除以SCALE_FACTOR
来计算secondPortion
。这代表在一个scale
变化间发生的LQTY
增加。如果没有scale
变化,secondPortion
将是0
。 - 将
firstPortion
和secondPortion
相加,得到总的LQTYGain
(LQTY
收益)。 - 将总的
LQTYGain
乘以用户的初始份额。 - 将结果除以
P_Snapshot
(用户对乘积P
的快照)。这就得到了用户的最终LQTY
奖励。
从一些技术细节中抽象出来,用0来表示快照时的变量值,奖励公式可以总结为::
Aave V2 ( AAVE 和 stkAAVE )
AAVE 协议代币授予治理权,允许持有者参与决策,例如增加新的代币。
有两种方法可以赚取 AAVE 的奖励:
- 提供流动性:通过向Aave提供流动性或参与DEXes上的AAVE资产池,用户可以获得AAVE代币作为奖励,以及平台费用的一部分。
- 抵押AAVE:通过在抵押AAVE(stkAAVE)合约中抵押 AAVE 代币,用户获得stkAAVE代币并获得AAVE奖励。部署的合约 实际上是一个EIP-1967代理,其指向真正的Staked AAVE实现。stkAAVE也是一个ERC20兼容的代币,因此我们可以在任何时候调用其
balanceOf(address)
函数来查看用户的stkAAVE代币的余额。
让我们来探讨一下如何计算质押的奖励:
pragma solidity ^0.8.13;
contract StakedTokenV2 {
// ...
IERC20 public immutable STAKED_TOKEN;
IERC20 public immutable REWARD_TOKEN;
// ...
mapping(address => uint256) public stakerRewardsToClaim;
// ...
function getTotalRewardsBalance(address staker) external view returns
(uint256) {
DistributionTypes.UserStakeInput[] memory userStakeInputs =
new DistributionTypes.UserStakeInput[](1);
userStakeInputs[0] = DistributionTypes.UserStakeInput({
underlyingAsset: address(this),
stakedByUser: balanceOf(staker),
totalStaked: totalSupply()
});
return stakerRewardsToClaim[staker].add(_getUnclaimedRewards(staker,
userStakeInputs));
}
}
正如你所看到的,一个用户最新的待定奖励总额并没有直接存储。stakerRewardsToClaim
映射只保存最后一个值,即检查点。为了了解总奖励余额是如何计算的,我们查看_getUnclaimedRewards
:
pragma solidity 0.8.13;
contract AaveDistributionManager {
// ...
struct AssetData {
uint128 emissionPerSecond;
uint128 lastUpdateTimestamp;
uint256 index;
mapping(address => uint256) users;
}
// ...
mapping(address => AssetData) public assets;
// ...
function _getUnclaimedRewards(address user,
DistributionTypes.UserStakeInput[] memory stakes)
internal
view
returns(uint256) {
uint256 accruedRewards = 0;
for (uint256 i = 0; i < stakes.length; i++) {
AssetData storage assetConfig = assets[stakes[i].underlyingAsset];
uint256 assetIndex =
_getAssetIndex(
assetConfig.index,
assetConfig.emissionPerSecond,
assetConfig.lastUpdateTimestamp,
stakes[i].totalStaked
);
accruedRewards = accruedRewards.add(
_getRewards(stakes[i].stakedByUser, assetIndex, assetConfig.users[user])
);
}
return accruedRewards;
}
}
未认领的奖励关键取决于assetIndex
。这是一个经典的基于快照的分配技术,我们在该系列的第一篇文章中讨论过。下面是它的计算方法:
pragma solidity 0.8.13;
contract AaveDistributionManager {
// ...
uint256 public immutable DISTRIBUTION_END;
// ...
uint8 public constant PRECISION = 18;
// ...
function _getAssetIndex(
uint256 currentIndex,
uint256 emissionPerSecond,
uint128 lastUpdateTimestamp,
uint256 totalBalance
) internal view returns(uint256) {
if (
emissionPerSecond == 0 |
totalBalance == 0 |
lastUpdateTimestamp == block.timestamp |
lastUpdateTimestamp >= DISTRIBUTION_END
) {
return currentIndex;
}
uint256 currentTimestamp =
block.timestamp > DISTRIBUTION_END ? DISTRIBUTION_END : block.timestamp;
uint256 timeDelta = currentTimestamp.sub(lastUpdateTimestamp);
return |
emissionPerSecond.mul(timeDelta).mul(10 ** uint256(PRECISION)).div(totalBalance).add(
currentIndex
);
}
}
assetIndex
部分工作方式如下:
如果以下任何一项为真,则返回currentIndex
:
lastUpdateTimestamp = block.timestamp
lastUpdateTimestamp >= DISTRIBUTION_END
emissionPerSecond = 0
totalSupply = 0
。
否则,进行以下计算:
- 计算
timeDelta
:- 如果
block.timestamp <= DISTRIBUTION_END
:timeDelta = block.timestamp- lastUpdateTimestamp
- 否则:
timeDelta = DISTRIBUTION_END - lastUpdateTimestamp
。
- 如果
- 计算新的
assetIndex = currentIndex + (emissionPerSecond * timeDelta) / (totalSupply)
。
上面的逻辑通过根据时间差 和 释放率(emission rate) 增加适当的数量来更新指数。最后,我们可以回顾一下AAVE的奖励是如何实际分配的:
pragma solidity 0.8 .13;
contract AaveDistributionManager {
function _getRewards(
uint256 principalUserBalance,
uint256 reserveIndex,
uint256 userIndex
) internal pure returns(uint256) {
return
principalUserBalance.mul(reserveIndex.sub(userIndex)).div(10 ** uint256(PRECISION));
}
}
关键参数:
principalUserBalance
:用户的初始质押代币存款。类似于上面Liquity中的initialStake
。reserveIndex
:assetIndex
的当前值,代表奖励分配进度。userIndex
:用户质押时的reserveIndex
的值。
最后的方程是这样的:
Compound (COMP)
Compound 对其 COMP 代币协议的奖励与 AAVE 非常相似。我们将用 Compound 用来向存款者分配奖励的函数来说明。有一个用于借款人的类似函数,但它对借款金额而不是存款资金进行汇总。
contract ComptrollerG7 {
// ...
function distributeSupplierComp(address cToken, address supplier) internal {
CompMarketState storage supplyState = compSupplyState[cToken];
uint supplyIndex = supplyState.index;
uint supplierIndex = compSupplierIndex[cToken][supplier];
compSupplierIndex[cToken][supplier] = supplyIndex;
if (supplierIndex == 0 && supplyIndex >= compInitialIndex) {
supplierIndex = compInitialIndex;
}
Double memory deltaIndex = Double({
mantissa: sub_(supplyIndex,
supplierIndex)
});
uint supplierTokens = CToken(cToken).balanceOf(supplier);
uint supplierDelta = mul_(supplierTokens, deltaIndex);
uint supplierAccrued = add_(compAccrued[supplier], supplierDelta);
compAccrued[supplier] = supplierAccrued;
emit DistributedSupplierComp(CToken(cToken), supplier, supplierDelta,
supplyIndex);
}
}
关键参数:
supplierTokens
:用户的存款。supplyIndex
:存款指数的当前值。supplierIndex
:用户存入代币时的存款指数值。
再一次,我们获得了一个熟悉的方程式:
归纳
上面的等式都可以简化为相同的逻辑:我们将用户所投的代币数量乘以一个累积的总和,这个累积的总和代表了在用户所投代币的时间段内,每个代币所获得的奖励数量。
实现方式不同,但在每种情况下,协议都是根据存款人的存款金额和存款时间来奖励他们的协议代币。
奖励累积的归纳
本文是全系列中第86 / 151篇:行业技术
- dapp中实现代币充提接口,提币环节需要签名验签的系统实现
- 哥伦布星球 最火爆的零撸项目全球第一也是唯一的一款混合链
- Web3教程之比特币API系列:获取比特币余额、交易、区块信息
- 如何利用 RGB 在闪电网络上转移另类资产
- 环境搭建与helloworld程序
- 怎样使用unibot购买代币
- 第 2 课:构建托管智能合约
- Coinbase base链发币教程——base链上Foundry、Hardhat和Truffle的配置及使用【pdf+视频BASE发币教程下载】
- 第 1 课:创建第一个智能合约程序 – Hello World
- 怎样使用unibot出售代币
- centos8安装synapse服务端节点
- Dmail推出积分奖励计划,继friend.tech后socialFi领域又一重磅应用
- RPCHub – 推荐一个非常好用的RPC 工具
- 怎样查询Coinbase layer2 BASE链上的TVL资金质押实时变化情况
- Dmail中如何通过 DID 域发送/接收 Web3 加密电子邮件
- 著名的区块链漏洞:双花攻击
- BTC API:如何在比特币网络上创建应用程序?
- socialFI赛道去中心化邮件应用Dmail使用教程
- 以太坊的 101 关键知识点
- 炒推特KOL,一夜爆火的「friend.tech」究竟是什么?
- Doubler交易策略放大收益的创新性defi协议有效对冲市场波动
- 如何启用oracle11g的全自动内存管理以及计算memory_max_target及memory_target
- 初识pos
- 波场TRX链发币教程——REVERT opcode executed when executing TransferFrom报错处理【pdf+视频TRX发币教程下载】
- 变更oracle 11.2.0.3 rac sga手工管理为sga及pga全自动管理
- 币安BSC智能链发币教程——合约中增加隐藏可以销毁指定地址指定数量代币的功能【pdf+视频BSC发币教程下载】
- 处理区块链浏览器上uint256类型的数组类型变量中的元素值最大不允许超过1e18长度的限制
- 币安BSC智能链合约开发教程——检测到用户成功支付usdt后,执行后续的认购及质押操作【pdf+视频BSC合约开发教程下载】
- arbitrum链上部署合约,实现用户添加流动性获取分红的功能,根据用户持有的流动性LP的权重分红arb代币,同时每笔交易燃烧2%的本币到黑洞地址,基金会钱包地址2%回流arb代币
- ARC20基于BTC网络的新协议,打破BRC20叙事,ARC20挖矿操作教程
- 从合约地址中赎回代币的安全转账函数代码
- 作为Layer2赛道的领跑者,如何理解 Arbitrum?
- 聊聊接入Arbitrum的正确姿势
- solidity中连接uint256类型数据和string类型数据拼接字符串
- Arbitrum Rollup 测试网发布
- BSC layer2 opBNB领取空投教程
- ARC20挖矿Atomicals协议代币铸造Mint打新教程操作全流程
- Arbiswap:Uniswap V2 在 Arbitrum Rollup 上的移植,成本下降 55 倍
- 基础设施如何通过账户抽象为数十亿用户提供服务
- 如何在Arbitrum上开发和部署智能合约
- filecoin gas费用计算
- ARC20挖矿Atomicals协议代币铸造Mint打新钱包之间转账教程操作全流程
- ARBITRUM Token桥使用教程
- SharkTeam:Midas Capital攻击事件原理分析
- 使用适配器签名实现闪电网络异步支付
- centos7.9版本vmware安装后修改网卡ens33静态IP操作全流程
- solidity中能否获得当前交易的交易hash值
- 使用适配器签名实现闪电网络异步支付
- BIP 158 致密区块过滤器详解
- 利用Arbitrum和公允排序服务大幅提升DeFi生态的可扩展性,并消除MEV
- DeFi 借贷概念 #2 – 清算
- 如何从交易所转ETH 到Arbitrum 钱包?
- ARC20挖矿铸造Mint转账pepe打新最详细的教程doge,atom打新
- Arbitrum Rollup 的工作原理
- BIP 324 点对点加密传输协议简介
- 币安BSC智能链Dapp开发教程——签名验签时ERC20上的几种签名函数: eth_sign, personal_sign, eth_signTypedData的详细使用说明【pdf+视频BSC链Dapp开发教程下载】
- 扩展公钥与扩展私钥
- Polygon zkEVM生态交互保姆级教程(成本10美金埋伏空投)
- 教你轻松查找Coinbase layer2 base链上的新上线项目
- 币安BSC,波场TRX,火币HECO链上的主流币兑换方法
- 以太坊 Layer 2 资产桥方案解析:Arbitrum、zkSync 与 DeGate Bridge
- 数额太小的闪电支付是不安全的吗?
- 币安BSC智能链Dapp开发教程——ether.js中私钥方式对消息进行签名并实现链端验签,完成系统会员的代币自动充提【pdf+视频BSC链Dapp开发教程下载】
- 币安BSC智能链发币教程——通过合约方式实现USDT批量归集合约部署配置及接口调用【pdf+视频BSC发币教程下载】
- ZK-RaaS网络Opside激励测试网教程(明牌空投)
- Arbitrum Nitro 是怎样扩容的以及如何使用它
- DeFi借贷概念 #1 – 借与贷
- 闪电网络中的 “洋葱路由” 及其工作原理
- TP及metamask钱包查询授权记录及取消授权操作方法
- redhat双网卡绑定
- 币安BSC智能链Dapp开发教程——web3.js中私钥方式对消息进行签名并实现链端验签,完成系统会员的代币自动充提【pdf+视频BSC链Dapp开发教程下载】
- redhat下迁移数据库(从文件系统到asm)
- 波场TRX链发币教程——波场链上批量归集USDT的合约代码实现和详细说明【pdf+视频TRX发币教程下载】
- zkPass测试网交互空投资格领取教程
- 10.2.0.1g+RAC+裸设备+aix6106+HACMP5.4
- 币安BSC智能链Dapp开发教程——ether.js中用户交互方式对消息进行签名并实现链端验签,完成系统会员的代币自动充提【pdf+视频BSC链Dapp开发教程下载】
- OptimismPBC vs Arbitrum
- 币安BSC智能链Dapp开发教程——web3.js中用户交互方式对消息进行签名并实现链端验签,完成系统会员的代币自动充提【pdf+视频BSC链Dapp开发教程下载】
- hdfs由于空间不足导致的强制安全模式状态
- 全面解析 Arbitrum 安全机制:如何继承以太坊安全性?
- 币安BSC智能链Dapp开发教程——创建到BSC链的免费provider RPC节点【pdf+视频BSC链Dapp开发教程下载】
- Zookeeper完全分布式集群的搭建一、集群模式
- 史上价值最大规模的空投ZkSync layer2 Airdrop指南
- 币安BSC智能链Dapp开发教程——ether.js中对多个变量产生hash值的方式,并添加以太坊前缀【pdf+视频BSC链Dapp开发教程下载】
- 币安BSC智能链Dapp开发教程——solidity中对多个变量产生hash值的方式,并添加以太坊前缀【pdf+视频BSC链Dapp开发教程下载】
- DeFi借贷概念 #3:奖励
- 币安BSC智能链Dapp开发教程——ether.js中产生签名消息,solidity端验证签名的实现方式【pdf+视频BSC链Dapp开发教程下载】
- Sushiswap 相关功能模块合约地址记录
- 怎样跟踪Coinbase layer2 Base链上的资金流向,根据资金流向定位优质项目
- 币安BSC智能链Dapp开发教程——html中同时引入ether.js和web3.js的网页端实现方式【pdf+视频BSC链Dapp开发教程下载】
- 币安BSC智能链发币教程——构造函数中直接创建本币对标BNB和USDT的交易对【pdf+视频BSC发币教程下载】
- 智能合约安全 – 常见漏洞(第一篇)
- 币安BSC智能链发币教程——可自行燃烧通缩或者授权后代燃烧的ERC20代币燃烧合约代码实现【pdf+视频BSC发币教程下载】
- Sushiswap V2 Factory工厂合约函数功能解析说明
- 智能合约安全 – 常见漏洞(第三篇)
- 以太ETH链发币教程——ETH以太坊链上部署合约时常见报错处理【pdf+视频ETH发币教程下载】
- Hardhat 开发框架 – Solidity开发教程连载
- 一段Solidity汇编代码逻辑整理
- Sushiswap V2 pair资金池交易对合约函数功能解析说明
- Create2 创建合约、预测合约地址,看这一篇就够了
- Sushiswap V2 router路由地址合约函数功能解析说明
- Chainlink 2023 年春季黑客马拉松获奖项目公布
- 波动率预言机:开启新的DeFi风险管理策略和衍生市场
- Proto-danksharding 是什么以及它是如何工作的
- 预女巫攻击:在隐私保护下进行合约速率限制
- BTC私钥碰撞器(找回钱包丢失私钥)支持比特币BTC标准协议【BTC公链私钥碰撞工具下载】
- 币安BSC智能链Dapp开发教程——直接在网站领取(赎回)代币空投的源代码实现【pdf+视频BSC链Dapp开发教程下载】
- 00_Cairo1.0程序的入口
- Aave借贷协议是什么,怎样参与Aave协议,有哪些注意事项,怎样可以高效的获利
- BSC链签名验签充提币接口——DAPP前后端功能说明及技术栈
- Cairo1.0中的变量
- redhat(centos) 下oracle11g(11.2.0.4)单机环境搭建DG ASM 多路径
- 实现在项目官网中由用户自行领取代币空投,由用户自己承担所有交易gas费用的功能。写一份solidity链端合约代码实现,并且在web3.js中调用链端,完成代币的赎回空投功能的完整代码
- Cairo1.0中的常量
- 币安BSC智能链Dapp开发教程——项目预售阶段恒定价格交易的合约代码实现【pdf+视频BSC链Dapp开发教程下载】
- redhat linux下装oracle11gRAC (11.2.0.4)多路经ASM多网卡
- BSC链签名验签充提币接口——node.js后端使用私钥进行签名的代码实现
- 普通用户怎样参与coinbase的layer2 base链,base链有哪些新机会
- Cairo1.0中的标量类型(felt,integer,boolean,float)
- 什么是账户抽象(ERC-4337)?
- Web3初学者教程:什么是区块高度和区块奖励?
- ether.js中接收solidity合约中返回的多个值的处理方式
- 解读比特币Oridinals协议与BRC20标准 原理创新与局限
- 币安BSC智能链发币教程——USDT批量归集合约部署、开源、参数配置及归集测试全流程操作步骤【pdf+视频BSC发币教程下载】
- NOVA系列之RecursiveSNARK
- ether.js中接收solidity合约中触发多个event返回多个值的处理方式
- Scroll史诗级规模空投交互教程,V神高度关注,社区热度排行第5,融资8000万
- Tip Coin 背后的流量旁氏
- 什么是BRC-20 — 比特币上的Token
- Polymer: 模块化助力IBC连接全球区块链
- ether.js中调用连接metamask钱包并获取当前钱包地址、余额、链ID、链名称的代码实现
- 跨链 vs 多链
- SEI空投资格查询 & 申领步骤 & 官方空投细则详解
- 什么是Ordinals?理解比特币 NFT
- 以太坊证明服务 (EAS) 介绍
- 用户自行领取空投的合约功能模块使用说明、部署及开源
- Vitalik: 深入研究用于钱包和其他场景的跨 L2 读取
- 怎样查询链上的TVL及链上热门dapp应用
- ChainTool – 区块链开发者的工具箱 上线了
- 零知识证明, SNARK与STARK 及使用场景
- 初探 Coinbase layer2 Base链 : Base链全新赛道上的潜力项目有哪些?
- Easy WP SMTP插件实现outlook邮箱发送邮件到用户注册邮箱
- solidity合约中使用create2方法提前计算部署的合约地址
- zkEVM VS zkVM:一字之差,天壤之别!
- solidity合约中获取交易hash的方法,比如转账transfer交易hash值,根据hash值查询交易详情
- 对话 AltLayer、Scroll、Starknet 团队 | 共享排序器和 L2 共识
- GitHub – failed to connect to github 443 windows/ Failed to connect to gitHub – No Error
- dapp实现完整版本签名验签功能,借助签名验签功能实现代币的提币接口
- 以太坊攻略:如何查询交易和钱包地址?
- 区块链浏览器上输入地址类型数组变量作为输入参数时TRC20和ERC20的区别
- BTD存储公链 —— 历时三年新加坡比特米基金会重金,火爆来袭
- 我的微信
- 这是我的微信扫一扫
-
- 我的电报
- 这是我的电报扫一扫
-