当前位置: 首页 > news >正文

aave v3.4 利率计算详解

aave v3.4 的代码库中将利率策略地址interestRateStrategyAddress从每个资产的储备配置中移出,改为在Pool合约中作为不可变变量统一管理。这意味着在新版本中,所有资产共享同一个利率策略合约,使用不同的参数配置,本文对v3.4版本利率计算做个解析。合约代码如下:

  function calculateInterestRates(DataTypes.CalculateInterestRatesParams calldata params) external view virtual override returns (uint256, uint256) {InterestRateDataRay memory rateData = _rayifyRateData(_interestRateData[params.reserve]);CalcInterestRatesLocalVars memory vars;vars.currentLiquidityRate = 0;vars.currentVariableBorrowRate = rateData.baseVariableBorrowRate;if (params.totalDebt != 0) {vars.availableLiquidity =params.virtualUnderlyingBalance +params.liquidityAdded -params.liquidityTaken;vars.availableLiquidityPlusDebt = vars.availableLiquidity + params.totalDebt;vars.borrowUsageRatio = params.totalDebt.rayDiv(vars.availableLiquidityPlusDebt);vars.supplyUsageRatio = params.totalDebt.rayDiv(vars.availableLiquidityPlusDebt + params.unbacked);} else {return (0, vars.currentVariableBorrowRate);}if (vars.borrowUsageRatio > rateData.optimalUsageRatio) {uint256 excessBorrowUsageRatio = (vars.borrowUsageRatio - rateData.optimalUsageRatio).rayDiv(WadRayMath.RAY - rateData.optimalUsageRatio);vars.currentVariableBorrowRate +=rateData.variableRateSlope1 +rateData.variableRateSlope2.rayMul(excessBorrowUsageRatio);} else {vars.currentVariableBorrowRate += rateData.variableRateSlope1.rayMul(vars.borrowUsageRatio).rayDiv(rateData.optimalUsageRatio);}vars.currentLiquidityRate = vars.currentVariableBorrowRate.rayMul(vars.supplyUsageRatio).percentMul(PercentageMath.PERCENTAGE_FACTOR - params.reserveFactor);return (vars.currentLiquidityRate, vars.currentVariableBorrowRate);}

参数解析

入参结构如下:

  struct CalculateInterestRatesParams {uint256 unbacked;uint256 liquidityAdded;uint256 liquidityTaken;uint256 totalDebt;uint256 reserveFactor;address reserve;// @notice DEPRECATED in 3.4, but kept for backwards compatibilitybool usingVirtualBalance;uint256 virtualUnderlyingBalance;}

unbacked(废弃):未抵押的资产数量;这个在 Aave 中是一个特殊概念,与普通的借贷抵押完全不同。这个概念主要是为了支持跨链操作而设计的;用户在链 A 上锁定资产--》跨链桥在链 B 上的 Aave 协议中先创建"未抵押资产"--》这些资产可以立即在链 B 上使用--》当链 A 的确认最终到达时,这些资产会被"支持"(backed)
Aave 设计了一个特殊的"Bridge"角色,只有被授权的桥接合约可以创建未抵押资产,这需要特殊权限,普通用户无法创建。

这个功能实际上从未在生产环境中使用过,并已在 V3.4 版本中被移除。虽然代码中仍然保留了这个参数,但在实际运行中,这个参数的值应该总是为 0,仅为了保持向后兼容性。这里大概说下,不用太关注。

liquidityAdded:添加到储备中的流动性数量

liquidityTaken:从储备中提取的流动性数量

totalDebt:储备的总债务指的是资产池中所有用户借出的资产总量

reserveFactor:协议收取的费用比例,比如 10% 意味着利息收入的 10% 归协议

reserve:储备资产的地址,比如usdt的地址

usingVirtualBalance(废弃):是否启用虚拟余额(已废弃,不必关注)

virtualUnderlyingBalance:虚拟余额,用户 supply(存款)、repay(还款)时, virtualUnderlyingBalance 增加;用户 withdraw(提取)、borrow(借款)时, virtualUnderlyingBalance 减少

virtualUnderlyingBalance =总存款金额 - 总提取金额 - 总借出金额 + 总还款金额

看似是资金池总的剩余金额,但其实不完全一样,具体看aave v3 合约解析 状态存储相关部分的介绍。

第一步是获取当前资产的利率配置参数

InterestRateDataRay memory rateData = _rayifyRateData(_interestRateData[params.reserve]);

返回结构如下:

struct InterestRateDataRay {uint256 optimalUsageRatio;uint256 baseVariableBorrowRate;uint256 variableRateSlope1;uint256 variableRateSlope2;
}

optimalUsageRatio :最佳使用率,这是资金池的理想使用率,当实际使用率接近这个值时,利率会保持在相对稳定的水平
baseVariableBorrowRate :基础可变借款利率;即使使用率为零,借款人也需要支付的最低利率
variableRateSlope1 :第一阶段可变利率斜率;当使用率低于最佳使用率时,利率增长的斜率
variableRateSlope2 :第二阶段可变利率斜率;当使用率超过最佳使用率时,利率增长的斜率

计算的一开始定义了一个中间变量CalcInterestRatesLocalVars 结构如下

  struct CalcInterestRatesLocalVars {uint256 availableLiquidity;uint256 currentVariableBorrowRate;uint256 currentLiquidityRate;uint256 borrowUsageRatio;uint256 supplyUsageRatio;uint256 availableLiquidityPlusDebt;}

然后对这些参数进行了初始化

if (params.totalDebt != 0) {vars.availableLiquidity =params.virtualUnderlyingBalance +params.liquidityAdded -params.liquidityTaken;vars.availableLiquidityPlusDebt = vars.availableLiquidity + params.totalDebt;vars.borrowUsageRatio = params.totalDebt.rayDiv(vars.availableLiquidityPlusDebt);vars.supplyUsageRatio = params.totalDebt.rayDiv(vars.availableLiquidityPlusDebt + params.unbacked);
} else {return (0, vars.currentVariableBorrowRate);
}

availableLiquidity:可用流动性,表示资产池中当前可供借出的资产数量,计算公式: virtualUnderlyingBalance + liquidityAdded - liquidityTaken


currentVariableBorrowRate: 当前可变借款利率;表示资产池当前的可变借款利率,初始值为基础可变借款利率( baseVariableBorrowRate ),根据使用率动态调整,使用率越高,利率越高


currentLiquidityRate: 当前流动性利率,表示存款人获得的利率
计算公式: currentVariableBorrowRate * supplyUsageRatio * (100% - reserveFactor)

borrowUsageRatio: 借款使用率;表示已借出资产占总可用资产的比例,用于确定借款利率的调整幅度
计算公式: totalDebt / (availableLiquidity + totalDebt)

supplyUsageRatio:供应使用率,表示已借出资产占总供应资产的比例,用于计算存款利率
计算公式: totalDebt / (availableLiquidity + totalDebt + unbacked)
 

availableLiquidityPlusDebt:可用流动性加债务总额,表示资产池的总规模(可用资金加已借出资金)
- 计算公式: availableLiquidity + totalDebt

借款利息

if (vars.borrowUsageRatio > rateData.optimalUsageRatio) {uint256 excessBorrowUsageRatio = (vars.borrowUsageRatio - rateData.optimalUsageRatio).rayDiv(WadRayMath.RAY - rateData.optimalUsageRatio);vars.currentVariableBorrowRate +=rateData.variableRateSlope1 +rateData.variableRateSlope2.rayMul(excessBorrowUsageRatio);
} else {vars.currentVariableBorrowRate += rateData.variableRateSlope1.rayMul(vars.borrowUsageRatio).rayDiv(rateData.optimalUsageRatio);
}

当借款使用率超过最佳使用率时,计算超额使用率比例:

excessBorrowUsageRatio =\frac{ (borrowUsageRatio - optimalUsageRatio)}{ (1 - optimalUsageRatio)}

接下来计算借款利息:

currentVariableBorrowRate = baseVariableBorrowRate + variableRateSlope1 + (variableRateSlope2 * excessBorrowUsageRatio)

此时的利率由三部分组成:

  • 基础利率(baseVariableBorrowRate)
  • 第一斜率(variableRateSlope1)全额计入
  • 第二斜率(variableRateSlope2)按超额使用率比例计入

当借款使用率不超过最佳使用率时(低使用率场景)

currentVariableBorrowRate = baseVariableBorrowRate + variableRateSlope1 * (\frac{borrowUsageRatio}{optimalUsageRatio} )

在这种情况下,利率由两部分组成:

  • 基础利率(baseVariableBorrowRate)
  • 第一斜率(variableRateSlope1)按使用率与最佳使用率的比例计入

存款利息

vars.currentLiquidityRate = vars.currentVariableBorrowRate.rayMul(vars.supplyUsageRatio).percentMul(PercentageMath.PERCENTAGE_FACTOR - params.reserveFactor);

翻译成公式就是:存款利率 = 借款利率 × 供应使用率 × (1 - 储备因子)

举个例子:借款利息是5%,此时资金池中80%的资金被借出,代表这个资金池只有80%的资金产生了利息,那么存款利息就是5% × 80% = 4%;

如果储备因子为10%,代表这4%的利息中有10%归协议所有,那么存款利息为
存款利率 = 4% × (1 - 10%) = 4% × 90% = 3.6%

http://www.dtcms.com/a/391474.html

相关文章:

  • rook-ceph CRD资源配置时效问题
  • MySQL学习笔记-进阶篇
  • Rust 关键字
  • 排版使用latex排版还是word排版更容易通过mdpi remote sensing的审稿?
  • Qt QML ToolTip弹出方向控制问题探讨
  • [Windows] PDFQFZ(PDF加盖骑缝章) v1.31
  • 四网络层IP-子网掩码-路由表-真题
  • 安装QT6.9.2
  • 使用 NodePort
  • IP6163至为芯具备MPPT硬件算法的太阳能光伏降压DC-DC芯片
  • 从“道生一”理念看宇宙规律与现代科技之关联
  • CKS-CN 考试知识点分享(9) 关闭API凭据自动挂载
  • 初次接触MCP
  • 高防服务器按照应用场景划分为哪些类型
  • 【项目】基于One Thread One Loop模型的高性能网络库实现 - 服务器模块实现
  • 京准电钟NTP时间同步服务器通信系统技术应用方案
  • Next.js 错误处理:自定义错误页面和错误边界
  • 操作教程|使用Cursor工具连接JumpServer资产
  • prefix Lm和causal LM encoder-decoder区别以及各自有什么缺点
  • 从零开始学习PX4源码29(Commander 任务)
  • 基于高速摄像机与6Dof测量的手机跌落实验分析
  • 大恒2509新版本掉线重连
  • 基于Docker Desktop和Windows的Milvus本地部署教程
  • 【Kubernetes】-- Gonzo 之 Go 基于 TUI 的日志分析工具
  • 无人驾驶技术:智能决策与精准执行的融合
  • YOLO11 改进、魔改|RFA(Receptive Field Aggregator)通过分层聚合多尺度感受野,提高多尺度目标检测能力
  • 【人工智能99问】QWen中的动态RoPE与LLaMA中的RoPE有什么区别?(40/99)
  • Function Calling:让语言模型调用外部功能
  • UI动画设计基础:提升用户体验的动效设计技巧
  • 业务视角下的主机维护模式:三重自动化,提升运维效率与业务连续性