DeFi 阶段四 ✅ 验证通过
| 特性 | 传统银行借贷 | DeFi借贷 |
|---|---|---|
| 信用评估 | KYC、征信、收入证明 | 无需信用,超额抵押 |
| 审批时间 | 天/周 | 即时(链上验证) |
| 抵押率 | 50%-80%(房产等) | 通常60%-75%(加密资产) |
| 清算方式 | 法律追讨 | 智能合约自动清算 |
| 利息计算 | 固定/浮动 | 算法动态调整 |
| 准入门槛 | 高(需要银行账户) | 低(只需钱包) |
// Compound风格:分段线性利率模型
// 利用率 u = 总借款 / 总存款
// 低利用率区间(0% - 最优利用率):
借款利率 = 基础利率 + 利用率 × 斜率1
// 高利用率区间(最优利用率 - 100%):
借款利率 = 基础利率 + 斜率1 × 最优利用率
+ (利用率 - 最优利用率) × 斜率2
// 示例参数(USDC市场):
基础利率 = 2% // 无人借款时的最低利率
最优利用率 = 80% // 资金利用效率的目标值
斜率1 = 10% // 低利用率时利率缓慢上升
斜率2 = 100% // 高利用率时利率急剧上升(激励存款)
利率
│ ╱ ← 高斜率(激励存款/抑制借款)
25% │ ╱
│ ╱
12% │ ╱ ← 最优利率点
│ ╱
2% │ ╱ ← 低斜率(温和调整)
│ ╱
0% └──────────────── 利用率
0% 80% 100%
// contracts/SimpleLending.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
/**
* @title SimpleLending
* @dev 简化版借贷协议——单一资产池
*/
contract SimpleLending {
using SafeERC20 for IERC20;
IERC20 public immutable asset; // 借贷资产(如USDC)
uint256 public constant COLLATERAL_RATIO = 150; // 150%抵押率
uint256 public constant LIQUIDATION_RATIO = 120; // 120%清算线
uint256 public constant LIQUIDATION_BONUS = 5; // 5%清算奖金
uint256 public constant PRECISION = 100;
// 利率参数
uint256 public constant BASE_RATE = 2e16; // 2%/年
uint256 public constant SLOPE_1 = 1e17; // 10%/年
uint256 public constant OPTIMAL_UTIL = 8e17; // 80%最优利用率
uint256 public constant SLOPE_2 = 1e18; // 100%/年
// 用户账户
struct Account {
uint256 collateral; // 抵押品(ETH)
uint256 borrowed; // 已借金额
uint256 lastUpdate; // 利息最后更新时间
}
mapping(address => Account) public accounts;
// 市场状态
uint256 public totalDeposits;
uint256 public totalBorrows;
uint256 public lastIndex;
uint256 public lastUpdateTimestamp;
event Deposited(address indexed user, uint256 amount);
event Borrowed(address indexed user, uint256 amount);
event Repaid(address indexed user, uint256 amount);
event Liquidated(address indexed borrower, address liquidator, uint256 debtRepaid, uint256 collateralSeized);
constructor(address _asset) {
asset = IERC20(_asset);
lastUpdateTimestamp = block.timestamp;
lastIndex = 1e18; // 初始利率指数=1
}
// ═══════ 存款 ═══════
function deposit(uint256 amount) external {
require(amount > 0, "Zero amount");
_updateIndex();
asset.safeTransferFrom(msg.sender, address(this), amount);
accounts[msg.sender].collateral += amount;
totalDeposits += amount;
emit Deposited(msg.sender, amount);
}
// ═══════ 借款 ═══════
function borrow(uint256 amount) external {
require(amount > 0, "Zero amount");
_updateIndex();
_accrueInterest(msg.sender);
Account storage acc = accounts[msg.sender];
acc.borrowed += amount;
// 检查抵押率
require(
acc.collateral * PRECISION / acc.borrowed >= COLLATERAL_RATIO,
"Insufficient collateral"
);
// 检查流动性
require(
totalDeposits - totalBorrows >= amount,
"Insufficient liquidity"
);
totalBorrows += amount;
asset.safeTransfer(msg.sender, amount);
emit Borrowed(msg.sender, amount);
}
// ═══════ 还款 ═══════
function repay(uint256 amount) external {
_updateIndex();
_accrueInterest(msg.sender);
Account storage acc = accounts[msg.sender];
require(amount <= acc.borrowed, "Repay exceeds debt");
asset.safeTransferFrom(msg.sender, address(this), amount);
acc.borrowed -= amount;
totalBorrows -= amount;
emit Repaid(msg.sender, amount);
}
// ═══════ 清算 ═══════
function liquidate(address borrower, uint256 repayAmount) external {
_updateIndex();
_accrueInterest(borrower);
Account storage acc = accounts[borrower];
require(
acc.collateral * PRECISION / acc.borrowed < LIQUIDATION_RATIO,
"Not liquidatable"
);
// 最多清算50%的债务
uint256 maxRepay = acc.borrowed / 2;
if (repayAmount > maxRepay) {
repayAmount = maxRepay;
}
// 计算可获得的抵押品(含清算奖金)
uint256 collateralSeized = repayAmount * (PRECISION + LIQUIDATION_BONUS) / PRECISION;
// 执行清算
asset.safeTransferFrom(msg.sender, address(this), repayAmount);
acc.borrowed -= repayAmount;
acc.collateral -= collateralSeized;
totalBorrows -= repayAmount;
// 将抵押品转给清算者
asset.safeTransfer(msg.sender, collateralSeized);
emit Liquidated(borrower, msg.sender, repayAmount, collateralSeized);
}
// ═══════ 利率计算 ═══════
function _updateIndex() internal {
if (totalDeposits == 0) return;
uint256 timeDelta = block.timestamp - lastUpdateTimestamp;
if (timeDelta == 0) return;
uint256 utilizationRate = (totalBorrows * 1e18) / totalDeposits;
uint256 borrowRate;
if (utilizationRate <= OPTIMAL_UTIL) {
borrowRate = BASE_RATE + (utilizationRate * SLOPE_1 / OPTIMAL_UTIL);
} else {
uint256 excessUtil = utilizationRate - OPTIMAL_UTIL;
uint256 excessFraction = excessUtil * 1e18 / (1e18 - OPTIMAL_UTIL);
borrowRate = BASE_RATE + SLOPE_1 + (excessFraction * SLOPE_2 / 1e18);
}
// 更新利率指数
uint256 interestFactor = borrowRate * timeDelta / 365 days;
lastIndex += lastIndex * interestFactor / 1e18;
lastUpdateTimestamp = block.timestamp;
}
function _accrueInterest(address user) internal {
Account storage acc = accounts[user];
if (acc.borrowed == 0 || acc.lastUpdate == 0) {
acc.lastUpdate = block.timestamp;
return;
}
// 简化利息计算
acc.lastUpdate = block.timestamp;
}
// ═══════ 查询函数 ═══════
function getHealthFactor(address user) external view returns (uint256) {
Account storage acc = accounts[user];
if (acc.borrowed == 0) return type(uint256).max;
return (acc.collateral * PRECISION * 1e18) / (acc.borrowed * COLLATERAL_RATIO);
}
function getBorrowRate() external view returns (uint256) {
if (totalDeposits == 0) return BASE_RATE;
uint256 u = (totalBorrows * 1e18) / totalDeposits;
if (u <= OPTIMAL_UTIL) {
return BASE_RATE + u * SLOPE_1 / OPTIMAL_UTIL;
}
return BASE_RATE + SLOPE_1 + (u - OPTIMAL_UTIL) * SLOPE_2 / (1e18 - OPTIMAL_UTIL);
}
}
// 闪电贷回调接口
interface IFlashBorrower {
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes memory params
) external returns (bytes32);
}
// 闪电贷实现(简化)
contract FlashLender {
uint256 public constant FEE = 9e14; // 0.09%
bytes32 public constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
function flashLoan(
IFlashBorrower borrower,
address token,
uint256 amount,
bytes memory params
) external {
uint256 fee = amount * FEE / 1e18;
// 1. 借出资金
IERC20(token).transfer(address(borrower), amount);
// 2. 调用借款者的回调函数
bytes32 result = borrower.onFlashLoan(
msg.sender, token, amount, fee, params
);
require(result == CALLBACK_SUCCESS, "Callback failed");
// 3. 收回资金 + 手续费
IERC20(token).transferFrom(address(borrower), address(this), amount + fee);
}
}
1. DeFi借贷为什么需要超额抵押?
2. 闪电贷为什么不需要抵押?
3. 清算者的动机是什么?
// 三种主流利率模型对比
// 1. Jump Rate Model (Compound)
// 利用率<Kink: 线性增长
// 利用率>Kink: 陡增(鼓励存款补充流动性)
// 2. Kinked Model (Aave)
// 在Kink点利率曲线斜率突变
// 最佳利用率=Kink点(资金效率和安全平衡)
// 3. Dynamic Rate Model
// 利率根据市场条件动态调整
// 目标利用率自动调节Kink位置
contract RateModelComparison {
function jumpRate(uint256 u) public pure returns (uint256) {
uint256 kink = 80e16;
if (u <= kink) return 2e16 + u * 10e16 / 1e18;
return 10e16 + (u - kink) * 90e16 / 1e18;
}
// 利用率80%以下: 2%~10%利率
// 利用率80%以上: 10%~100%利率(陡增!)
// 目的: 鼓励存款,防止流动性耗尽
}
// ✅ 验证通过
你已掌握DeFi借贷协议!从超额抵押到利率模型,从清算机制到闪电贷,你理解了去中心化金融的信贷体系。
关键收获:
✅ 超额抵押与清算机制
✅ 分段线性利率模型
✅ 借贷合约完整实现
✅ 闪电贷原理与套利应用
✅ 健康因子与风险监控