08-DeFi核心协议-稳定币
第一部分:稳定币基础
1.1 稳定币概述
稳定币是价格与法币(通常是美元)挂钩的加密货币,旨在减少价格波动。
1.1.1 稳定币的重要性
- 价值存储:在加密市场提供稳定的价值载体
- 交易媒介:DeFi中的主要交易对
- 记账单位:衡量其他资产价值的基准
- 桥梁作用:连接传统金融和加密世界
1.2 稳定币分类
稳定币类型
├── 法币抵押型
│ ├── USDT (Tether)
│ ├── USDC (Circle)
│ └── BUSD (Binance)
│
├── 加密资产抵押型
│ ├── DAI (MakerDAO)
│ ├── sUSD (Synthetix)
│ └── LUSD (Liquity)
│
└── 算法稳定币
├── UST (已崩盘)
├── FRAX (部分抵押)
└── AMPL (Rebase机制)
1.3 稳定机制对比
| 类型 | 抵押品 | 去中心化程度 | 资本效率 | 风险 |
|---|---|---|---|---|
| 法币抵押 | 法币 | 低 | 高(1:1) | 中心化风险、监管风险 |
| 加密抵押 | 加密资产 | 高 | 低(超额抵押) | 价格波动风险 |
| 算法稳定 | 算法 | 高 | 高 | 死亡螺旋风险 |
第二部分:法币抵押型稳定币(USDC)
2.1 USDC原理
USDC由Circle发行,每个USDC由1美元储备金支持,储备金由受监管的金融机构托管。
2.2 USDC合约实现
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title USDC
* @dev 法币抵押型稳定币实现(类似USDC)
*/
contract USDC {
string public constant name = "USD Coin";
string public constant symbol = "USDC";
uint8 public constant decimals = 6;
uint256 private _totalSupply;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
// 角色管理
address public owner;
mapping(address => bool) public minters;
mapping(address => bool) public blacklisted;
// 铸造限额
mapping(address => uint256) public minterAllowance;
// 暂停功能
bool public paused;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
event Mint(address indexed minter, address indexed to, uint256 amount);
event Burn(address indexed burner, uint256 amount);
event MinterConfigured(address indexed minter, uint256 allowance);
event MinterRemoved(address indexed minter);
event Blacklisted(address indexed account);
event UnBlacklisted(address indexed account);
event Paused();
event Unpaused();
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
modifier onlyMinters() {
require(minters[msg.sender], "Not minter");
_;
}
modifier notBlacklisted(address account) {
require(!blacklisted[account], "Account blacklisted");
_;
}
modifier whenNotPaused() {
require(!paused, "Paused");
_;
}
constructor() {
owner = msg.sender;
}
/**
* @dev 配置铸造者
*/
function configureMinter(address minter, uint256 allowance) external onlyOwner {
minters[minter] = true;
minterAllowance[minter] = allowance;
emit MinterConfigured(minter, allowance);
}
/**
* @dev 移除铸造者
*/
function removeMinter(address minter) external onlyOwner {
minters[minter] = false;
minterAllowance[minter] = 0;
emit MinterRemoved(minter);
}
/**
* @dev 铸造代币
*/
function mint(address to, uint256 amount)
external
onlyMinters
whenNotPaused
notBlacklisted(to)
returns (bool)
{
require(to != address(0), "Mint to zero address");
require(amount > 0, "Mint amount must be positive");
require(amount <= minterAllowance[msg.sender], "Exceeds minter allowance");
minterAllowance[msg.sender] -= amount;
_totalSupply += amount;
_balances[to] += amount;
emit Mint(msg.sender, to, amount);
emit Transfer(address(0), to, amount);
return true;
}
/**
* @dev 销毁代币
*/
function burn(uint256 amount) external onlyMinters whenNotPaused {
require(amount > 0, "Burn amount must be positive");
require(_balances[msg.sender] >= amount, "Insufficient balance");
_balances[msg.sender] -= amount;
_totalSupply -= amount;
emit Burn(msg.sender, amount);
emit Transfer(msg.sender, address(0), amount);
}
/**
* @dev 加入黑名单
*/
function blacklist(address account) external onlyOwner {
blacklisted[account] = true;
emit Blacklisted(account);
}
/**
* @dev 移出黑名单
*/
function unBlacklist(address account) external onlyOwner {
blacklisted[account] = false;
emit UnBlacklisted(account);
}
/**
* @dev 暂停
*/
function pause() external onlyOwner {
paused = true;
emit Paused();
}
/**
* @dev 恢复
*/
function unpause() external onlyOwner {
paused = false;
emit Unpaused();
}
/**
* @dev 转账
*/
function transfer(address recipient, uint256 amount)
external
whenNotPaused
notBlacklisted(msg.sender)
notBlacklisted(recipient)
returns (bool)
{
_transfer(msg.sender, recipient, amount);
return true;
}
/**
* @dev 授权
*/
function approve(address spender, uint256 amount)
external
whenNotPaused
notBlacklisted(msg.sender)
notBlacklisted(spender)
returns (bool)
{
_approve(msg.sender, spender, amount);
return true;
}
/**
* @dev 授权转账
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
)
external
whenNotPaused
notBlacklisted(sender)
notBlacklisted(msg.sender)
notBlacklisted(recipient)
returns (bool)
{
_transfer(sender, recipient, amount);
uint256 currentAllowance = _allowances[sender][msg.sender];
require(currentAllowance >= amount, "Transfer amount exceeds allowance");
unchecked {
_approve(sender, msg.sender, currentAllowance - amount);
}
return true;
}
// 查询函数
function totalSupply() external view returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) external view returns (uint256) {
return _balances[account];
}
function allowance(address owner_, address spender) external view returns (uint256) {
return _allowances[owner_][spender];
}
// 内部函数
function _transfer(
address sender,
address recipient,
uint256 amount
) internal {
require(sender != address(0), "Transfer from zero address");
require(recipient != address(0), "Transfer to zero address");
uint256 senderBalance = _balances[sender];
require(senderBalance >= amount, "Transfer amount exceeds balance");
unchecked {
_balances[sender] = senderBalance - amount;
}
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
}
function _approve(
address owner_,
address spender,
uint256 amount
) internal {
require(owner_ != address(0), "Approve from zero address");
require(spender != address(0), "Approve to zero address");
_allowances[owner_][spender] = amount;
emit Approval(owner_, spender, amount);
}
}
第三部分:加密资产抵押型稳定币(DAI)
3.1 MakerDAO和DAI原理
DAI是由MakerDAO发行的去中心化稳定币,通过超额抵押加密资产(如ETH)生成。
3.1.1 核心概念
CDP/Vault(金库):
- 用户存入ETH等抵押品
- 生成DAI
- 抵押率通常为150%以上
稳定费(Stability Fee):
- 借DAI的利息
- 用于维持系统稳定
清算:
- 当抵押率低于清算线(如150%)
- 清算人可拍卖抵押品
- 偿还债务并获得折扣
DAI储蓄率(DSR):
- 持有DAI可获得利息
- 吸引用户持有DAI
3.2 MakerDAO核心合约
3.2.1 Vat(核心账本)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title Vat
* @dev MakerDAO的核心账本合约(简化版)
*/
contract Vat {
// 抵押品类型
struct Ilk {
uint256 Art; // 总债务(标准化)
uint256 rate; // 累计利率
uint256 spot; // 清算价格(含安全边际)
uint256 line; // 债务上限
uint256 dust; // 最小债务
}
// 金库(CDP)
struct Urn {
uint256 ink; // 抵押品数量
uint256 art; // 债务(标准化)
}
// 抵押品类型映射
mapping(bytes32 => Ilk) public ilks;
// 金库映射: ilk => user => Urn
mapping(bytes32 => mapping(address => Urn)) public urns;
// 抵押品余额: ilk => user => amount
mapping(bytes32 => mapping(address => uint256)) public gem;
// DAI余额
mapping(address => uint256) public dai;
// 系统债务
uint256 public debt;
// 全局债务上限
uint256 public Line;
// 授权地址
mapping(address => uint256) public wards;
event LogNote(bytes4 indexed sig, bytes32 indexed arg1, bytes32 indexed arg2, bytes data);
modifier auth() {
require(wards[msg.sender] == 1, "Vat/not-authorized");
_;
}
constructor() {
wards[msg.sender] = 1;
}
/**
* @dev 授权地址
*/
function rely(address usr) external auth {
wards[usr] = 1;
}
/**
* @dev 取消授权
*/
function deny(address usr) external auth {
wards[usr] = 0;
}
/**
* @dev 初始化抵押品类型
*/
function init(bytes32 ilk) external auth {
require(ilks[ilk].rate == 0, "Vat/ilk-already-init");
ilks[ilk].rate = 10**27; // 初始利率为1
}
/**
* @dev 存入抵押品
*/
function slip(
bytes32 ilk,
address usr,
int256 wad
) external auth {
gem[ilk][usr] = _add(gem[ilk][usr], wad);
}
/**
* @dev 调整CDP(核心函数)
* @param ilk 抵押品类型
* @param u 金库所有者
* @param v 抵押品接收者
* @param w DAI接收者
* @param dink 抵押品变化量
* @param dart 债务变化量
*/
function frob(
bytes32 ilk,
address u,
address v,
address w,
int256 dink,
int256 dart
) external {
Urn storage urn = urns[ilk][u];
Ilk storage ilkData = ilks[ilk];
// 更新金库
urn.ink = _add(urn.ink, dink);
urn.art = _add(urn.art, dart);
// 更新抵押品类型的总债务
ilkData.Art = _add(ilkData.Art, dart);
// 计算实际债务(debt = art * rate)
int256 dtab = _mul(ilkData.rate, dart);
// 更新总债务
debt = _add(debt, dtab);
// 检查
require(dart <= 0 || (ilkData.Art * ilkData.rate <= ilkData.line && debt <= Line), "Vat/ceiling-exceeded");
require(dart <= 0 || _mul(urn.art, ilkData.rate) >= ilkData.dust, "Vat/dust");
require(
dart >= 0 || _mul(urn.art, ilkData.rate) >= ilkData.dust || (_mul(urn.art, ilkData.rate) == 0),
"Vat/dust"
);
require(
dink >= 0 || urn.ink >= 0,
"Vat/not-safe"
);
require(
dart <= 0 || (_mul(urn.ink, ilkData.spot) >= _mul(urn.art, ilkData.rate)),
"Vat/not-safe"
);
// 转移抵押品
gem[ilk][v] = _sub(gem[ilk][v], dink);
// 转移DAI
dai[w] = _add(dai[w], dtab);
}
/**
* @dev 清算金库
*/
function grab(
bytes32 ilk,
address u,
address v,
address w,
int256 dink,
int256 dart
) external auth {
Urn storage urn = urns[ilk][u];
Ilk storage ilkData = ilks[ilk];
urn.ink = _add(urn.ink, dink);
urn.art = _add(urn.art, dart);
ilkData.Art = _add(ilkData.Art, dart);
int256 dtab = _mul(ilkData.rate, dart);
gem[ilk][v] = _sub(gem[ilk][v], dink);
dai[w] = _sub(dai[w], dtab);
}
/**
* @dev 更新利率
*/
function fold(
bytes32 ilk,
address u,
int256 rate_
) external auth {
Ilk storage ilkData = ilks[ilk];
ilkData.rate = _add(ilkData.rate, rate_);
int256 rad = _mul(ilkData.Art, rate_);
dai[u] = _add(dai[u], rad);
debt = _add(debt, rad);
}
// 数学辅助函数
function _add(uint256 x, int256 y) internal pure returns (uint256 z) {
z = x + uint256(y);
require(y >= 0 || z <= x, "Vat/add-overflow");
require(y <= 0 || z >= x, "Vat/add-underflow");
}
function _sub(uint256 x, int256 y) internal pure returns (uint256 z) {
z = x - uint256(y);
require(y <= 0 || z <= x, "Vat/sub-overflow");
require(y >= 0 || z >= x, "Vat/sub-underflow");
}
function _mul(uint256 x, int256 y) internal pure returns (int256 z) {
z = int256(x) * y;
require(int256(x) >= 0, "Vat/mul-uint-int-overflow");
require(y == 0 || z / y == int256(x), "Vat/mul-overflow");
}
}
3.2.2 简化的DAI合约
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title DAI
* @dev DAI稳定币合约(简化版)
*/
contract DAI {
string public constant name = "Dai Stablecoin";
string public constant symbol = "DAI";
uint8 public constant decimals = 18;
string public constant version = "1";
uint256 private _totalSupply;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
// 授权地址
mapping(address => uint256) public wards;
// EIP-2612 Permit
mapping(address => uint256) public nonces;
bytes32 public DOMAIN_SEPARATOR;
bytes32 public constant PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
modifier auth() {
require(wards[msg.sender] == 1, "DAI/not-authorized");
_;
}
constructor(uint256 chainId) {
wards[msg.sender] = 1;
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256(bytes(version)),
chainId,
address(this)
)
);
}
/**
* @dev 授权
*/
function rely(address usr) external auth {
wards[usr] = 1;
}
/**
* @dev 取消授权
*/
function deny(address usr) external auth {
wards[usr] = 0;
}
/**
* @dev 铸造DAI
*/
function mint(address usr, uint256 wad) external auth {
_balances[usr] += wad;
_totalSupply += wad;
emit Transfer(address(0), usr, wad);
}
/**
* @dev 销毁DAI
*/
function burn(address usr, uint256 wad) external auth {
require(_balances[usr] >= wad, "DAI/insufficient-balance");
_balances[usr] -= wad;
_totalSupply -= wad;
emit Transfer(usr, address(0), wad);
}
/**
* @dev Permit授权
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
require(block.timestamp <= deadline, "DAI/permit-expired");
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, "DAI/invalid-permit");
_allowances[owner][spender] = value;
emit Approval(owner, spender, value);
}
// ERC20标准函数
function totalSupply() external view returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) external view returns (uint256) {
return _balances[account];
}
function allowance(address owner, address spender) external view returns (uint256) {
return _allowances[owner][spender];
}
function transfer(address recipient, uint256 amount) external returns (bool) {
_transfer(msg.sender, recipient, amount);
return true;
}
function approve(address spender, uint256 amount) external returns (bool) {
_allowances[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool) {
require(_allowances[sender][msg.sender] >= amount, "DAI/insufficient-allowance");
_allowances[sender][msg.sender] -= amount;
_transfer(sender, recipient, amount);
return true;
}
function _transfer(
address sender,
address recipient,
uint256 amount
) internal {
require(_balances[sender] >= amount, "DAI/insufficient-balance");
_balances[sender] -= amount;
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
}
}
3.2.3 简化的MakerDAO系统
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title SimpleMaker
* @dev 简化的MakerDAO系统,便于理解核心机制
*/
contract SimpleMaker {
// DAI代币
DAI public dai;
// 抵押品信息
struct Collateral {
uint256 totalDeposited; // 总抵押量
uint256 totalDebt; // 总债务
uint256 liquidationRatio; // 清算比率(150% = 150)
uint256 stabilityFee; // 稳定费率(年化,2% = 2)
uint256 debtCeiling; // 债务上限
uint256 price; // 当前价格
bool isActive; // 是否激活
}
// 金库信息
struct Vault {
uint256 collateral; // 抵押品数量
uint256 debt; // 债务数量
uint256 lastUpdate; // 上次更新时间
uint256 accumulatedFee; // 累计费用
}
// 抵押品类型映射
mapping(address => Collateral) public collaterals;
// 用户金库: user => collateralType => Vault
mapping(address => mapping(address => Vault)) public vaults;
// 清算惩罚(13% = 113)
uint256 public constant LIQUIDATION_PENALTY = 113;
// DSR(DAI储蓄率)
uint256 public dsr = 0; // 0%
// DSR余额
mapping(address => uint256) public dsrBalance;
mapping(address => uint256) public dsrTimestamp;
address public owner;
event VaultOpened(address indexed user, address indexed collateralType);
event CollateralDeposited(address indexed user, address indexed collateralType, uint256 amount);
event CollateralWithdrawn(address indexed user, address indexed collateralType, uint256 amount);
event DAIMinted(address indexed user, address indexed collateralType, uint256 amount);
event DAIRepaid(address indexed user, address indexed collateralType, uint256 amount);
event VaultLiquidated(
address indexed user,
address indexed collateralType,
address indexed liquidator,
uint256 debtRepaid,
uint256 collateralSeized
);
event DSRJoined(address indexed user, uint256 amount);
event DSRExited(address indexed user, uint256 amount);
constructor(address _dai) {
dai = DAI(_dai);
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
/**
* @dev 添加抵押品类型
*/
function addCollateral(
address collateralType,
uint256 liquidationRatio,
uint256 stabilityFee,
uint256 debtCeiling,
uint256 initialPrice
) external onlyOwner {
require(!collaterals[collateralType].isActive, "Collateral already exists");
require(liquidationRatio >= 100, "Invalid liquidation ratio");
collaterals[collateralType] = Collateral({
totalDeposited: 0,
totalDebt: 0,
liquidationRatio: liquidationRatio,
stabilityFee: stabilityFee,
debtCeiling: debtCeiling,
price: initialPrice,
isActive: true
});
}
/**
* @dev 更新抵押品价格(预言机)
*/
function updatePrice(address collateralType, uint256 newPrice) external onlyOwner {
require(collaterals[collateralType].isActive, "Collateral not active");
collaterals[collateralType].price = newPrice;
}
/**
* @dev 存入抵押品
*/
function depositCollateral(address collateralType, uint256 amount) external {
require(collaterals[collateralType].isActive, "Collateral not active");
require(amount > 0, "Amount must be positive");
// 转入抵押品
IERC20(collateralType).transferFrom(msg.sender, address(this), amount);
Vault storage vault = vaults[msg.sender][collateralType];
if (vault.collateral == 0) {
emit VaultOpened(msg.sender, collateralType);
}
vault.collateral += amount;
collaterals[collateralType].totalDeposited += amount;
emit CollateralDeposited(msg.sender, collateralType, amount);
}
/**
* @dev 提取抵押品
*/
function withdrawCollateral(address collateralType, uint256 amount) external {
Vault storage vault = vaults[msg.sender][collateralType];
require(vault.collateral >= amount, "Insufficient collateral");
// 更新累计费用
_updateVault(msg.sender, collateralType);
vault.collateral -= amount;
// 检查抵押率
require(_isVaultSafe(msg.sender, collateralType), "Vault would be unsafe");
collaterals[collateralType].totalDeposited -= amount;
// 转出抵押品
IERC20(collateralType).transfer(msg.sender, amount);
emit CollateralWithdrawn(msg.sender, collateralType, amount);
}
/**
* @dev 生成DAI
*/
function mintDAI(address collateralType, uint256 amount) external {
require(amount > 0, "Amount must be positive");
Collateral storage collateral = collaterals[collateralType];
require(collateral.isActive, "Collateral not active");
// 更新累计费用
_updateVault(msg.sender, collateralType);
Vault storage vault = vaults[msg.sender][collateralType];
vault.debt += amount;
// 检查债务上限
require(
collateral.totalDebt + amount <= collateral.debtCeiling,
"Debt ceiling reached"
);
// 检查抵押率
require(_isVaultSafe(msg.sender, collateralType), "Insufficient collateral");
collateral.totalDebt += amount;
// 铸造DAI
dai.mint(msg.sender, amount);
emit DAIMinted(msg.sender, collateralType, amount);
}
/**
* @dev 偿还DAI
*/
function repayDAI(address collateralType, uint256 amount) external {
Vault storage vault = vaults[msg.sender][collateralType];
// 更新累计费用
_updateVault(msg.sender, collateralType);
uint256 totalDebt = vault.debt + vault.accumulatedFee;
uint256 repayAmount = amount > totalDebt ? totalDebt : amount;
// 销毁DAI
dai.burn(msg.sender, repayAmount);
// 先偿还费用,再偿还本金
if (repayAmount >= vault.accumulatedFee) {
repayAmount -= vault.accumulatedFee;
vault.accumulatedFee = 0;
vault.debt -= repayAmount;
} else {
vault.accumulatedFee -= repayAmount;
}
collaterals[collateralType].totalDebt -= repayAmount;
emit DAIRepaid(msg.sender, collateralType, repayAmount);
}
/**
* @dev 清算金库
*/
function liquidate(address user, address collateralType) external {
Vault storage vault = vaults[user][collateralType];
require(vault.debt > 0, "No debt to liquidate");
// 更新累计费用
_updateVault(user, collateralType);
// 检查是否可以清算
require(!_isVaultSafe(user, collateralType), "Vault is safe");
Collateral storage collateral = collaterals[collateralType];
uint256 totalDebt = vault.debt + vault.accumulatedFee;
// 计算清算金额(最多50%)
uint256 halfDebt = totalDebt / 2;
// 计算需要的抵押品(含惩罚)
uint256 collateralValue = (halfDebt * LIQUIDATION_PENALTY * 1e18) / (collateral.price * 100);
uint256 collateralToSeize = collateralValue > vault.collateral ? vault.collateral : collateralValue;
// 计算实际偿还的债务
uint256 debtRepaid = (collateralToSeize * collateral.price * 100) / (LIQUIDATION_PENALTY * 1e18);
// 转入DAI
dai.burn(msg.sender, debtRepaid);
// 更新金库
vault.collateral -= collateralToSeize;
if (debtRepaid >= vault.accumulatedFee) {
debtRepaid -= vault.accumulatedFee;
vault.accumulatedFee = 0;
vault.debt -= debtRepaid;
} else {
vault.accumulatedFee -= debtRepaid;
}
collateral.totalDebt -= debtRepaid;
collateral.totalDeposited -= collateralToSeize;
// 转出抵押品给清算人
IERC20(collateralType).transfer(msg.sender, collateralToSeize);
emit VaultLiquidated(user, collateralType, msg.sender, debtRepaid, collateralToSeize);
}
/**
* @dev 加入DSR(DAI储蓄)
*/
function joinDSR(uint256 amount) external {
require(amount > 0, "Amount must be positive");
// 转入DAI
dai.burn(msg.sender, amount);
// 计算之前的利息
if (dsrBalance[msg.sender] > 0) {
uint256 interest = _calculateDSRInterest(msg.sender);
dsrBalance[msg.sender] += interest;
}
dsrBalance[msg.sender] += amount;
dsrTimestamp[msg.sender] = block.timestamp;
emit DSRJoined(msg.sender, amount);
}
/**
* @dev 退出DSR
*/
function exitDSR(uint256 amount) external {
uint256 interest = _calculateDSRInterest(msg.sender);
uint256 totalBalance = dsrBalance[msg.sender] + interest;
require(amount <= totalBalance, "Insufficient DSR balance");
dsrBalance[msg.sender] = totalBalance - amount;
dsrTimestamp[msg.sender] = block.timestamp;
// 铸造DAI(本金+利息)
dai.mint(msg.sender, amount);
emit DSRExited(msg.sender, amount);
}
/**
* @dev 更新金库(计算累计费用)
*/
function _updateVault(address user, address collateralType) internal {
Vault storage vault = vaults[user][collateralType];
if (vault.debt == 0) {
return;
}
Collateral storage collateral = collaterals[collateralType];
uint256 timeElapsed = block.timestamp - vault.lastUpdate;
if (timeElapsed > 0) {
// 计算稳定费(简化为线性)
uint256 fee = (vault.debt * collateral.stabilityFee * timeElapsed) / (365 days * 100);
vault.accumulatedFee += fee;
vault.lastUpdate = block.timestamp;
}
}
/**
* @dev 检查金库是否安全
*/
function _isVaultSafe(address user, address collateralType) internal view returns (bool) {
Vault storage vault = vaults[user][collateralType];
if (vault.debt == 0) {
return true;
}
Collateral storage collateral = collaterals[collateralType];
// 抵押品价值
uint256 collateralValue = (vault.collateral * collateral.price) / 1e18;
// 总债务(包含费用)
uint256 totalDebt = vault.debt + vault.accumulatedFee;
// 最小抵押品价值 = 债务 * 清算比率 / 100
uint256 minCollateralValue = (totalDebt * collateral.liquidationRatio) / 100;
return collateralValue >= minCollateralValue;
}
/**
* @dev 计算抵押率
*/
function getCollateralizationRatio(address user, address collateralType)
external
view
returns (uint256)
{
Vault storage vault = vaults[user][collateralType];
if (vault.debt == 0) {
return type(uint256).max;
}
Collateral storage collateral = collaterals[collateralType];
uint256 collateralValue = (vault.collateral * collateral.price) / 1e18;
uint256 totalDebt = vault.debt + vault.accumulatedFee;
return (collateralValue * 100) / totalDebt;
}
/**
* @dev 计算DSR利息
*/
function _calculateDSRInterest(address user) internal view returns (uint256) {
if (dsrBalance[user] == 0 || dsr == 0) {
return 0;
}
uint256 timeElapsed = block.timestamp - dsrTimestamp[user];
return (dsrBalance[user] * dsr * timeElapsed) / (365 days * 100);
}
/**
* @dev 获取金库信息
*/
function getVaultInfo(address user, address collateralType)
external
view
returns (
uint256 collateralAmount,
uint256 debtAmount,
uint256 accumulatedFee,
uint256 collateralizationRatio,
bool isSafe
)
{
Vault storage vault = vaults[user][collateralType];
collateralAmount = vault.collateral;
debtAmount = vault.debt;
accumulatedFee = vault.accumulatedFee;
if (vault.debt > 0) {
Collateral storage collateral = collaterals[collateralType];
uint256 collateralValue = (vault.collateral * collateral.price) / 1e18;
uint256 totalDebt = vault.debt + vault.accumulatedFee;
collateralizationRatio = (collateralValue * 100) / totalDebt;
} else {
collateralizationRatio = type(uint256).max;
}
isSafe = _isVaultSafe(user, collateralType);
}
}
第四部分:算法稳定币
4.1 算法稳定币原理
算法稳定币通过算法调整供应量来维持价格稳定,无需或仅需部分抵押。
4.1.1 常见机制
Rebase机制(如AMPL):
- 价格高于1美元:增加所有人的余额
- 价格低于1美元:减少所有人的余额
双代币模型(如Luna/UST):
- 稳定币和治理代币可互换
- 通过套利维持价格
部分抵押(如FRAX):
- 部分由抵押品支持
- 部分由算法控制
4.2 Rebase代币实现
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title RebaseToken
* @dev 弹性供应代币(类似AMPL)
*/
contract RebaseToken {
string public constant name = "Rebase Token";
string public constant symbol = "REBASE";
uint8 public constant decimals = 18;
// 总Gons(内部单位)
uint256 private constant MAX_UINT256 = type(uint256).max;
uint256 private constant INITIAL_FRAGMENTS_SUPPLY = 50 * 10**6 * 10**decimals;
uint256 private constant TOTAL_GONS = MAX_UINT256 - (MAX_UINT256 % INITIAL_FRAGMENTS_SUPPLY);
// 总供应量(fragments)
uint256 private _totalSupply;
// Gons余额
mapping(address => uint256) private _gonBalances;
// 授权
mapping(address => mapping(address => uint256)) private _allowedFragments;
// Gons per fragment
uint256 private _gonsPerFragment;
// 预言机和rebase控制
address public oracle;
address public monetaryPolicy;
// 价格目标
uint256 public constant TARGET_PRICE = 1e18; // $1
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
event LogRebase(uint256 indexed epoch, uint256 totalSupply);
modifier onlyMonetaryPolicy() {
require(msg.sender == monetaryPolicy, "Not authorized");
_;
}
constructor(address _oracle, address _monetaryPolicy) {
oracle = _oracle;
monetaryPolicy = _monetaryPolicy;
_totalSupply = INITIAL_FRAGMENTS_SUPPLY;
_gonsPerFragment = TOTAL_GONS / _totalSupply;
_gonBalances[msg.sender] = TOTAL_GONS;
emit Transfer(address(0), msg.sender, _totalSupply);
}
/**
* @dev Rebase函数
* @param supplyDelta 供应量变化(正数增加,负数减少)
*/
function rebase(uint256 epoch, int256 supplyDelta) external onlyMonetaryPolicy returns (uint256) {
if (supplyDelta == 0) {
emit LogRebase(epoch, _totalSupply);
return _totalSupply;
}
if (supplyDelta < 0) {
_totalSupply = _totalSupply - uint256(-supplyDelta);
} else {
_totalSupply = _totalSupply + uint256(supplyDelta);
}
if (_totalSupply > MAX_UINT256 / _gonsPerFragment) {
_totalSupply = MAX_UINT256 / _gonsPerFragment;
}
_gonsPerFragment = TOTAL_GONS / _totalSupply;
emit LogRebase(epoch, _totalSupply);
return _totalSupply;
}
/**
* @dev 总供应量
*/
function totalSupply() external view returns (uint256) {
return _totalSupply;
}
/**
* @dev 余额
*/
function balanceOf(address account) external view returns (uint256) {
return _gonBalances[account] / _gonsPerFragment;
}
/**
* @dev 转账
*/
function transfer(address to, uint256 value) external returns (bool) {
uint256 gonValue = value * _gonsPerFragment;
_gonBalances[msg.sender] -= gonValue;
_gonBalances[to] += gonValue;
emit Transfer(msg.sender, to, value);
return true;
}
/**
* @dev 授权
*/
function approve(address spender, uint256 value) external returns (bool) {
_allowedFragments[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
/**
* @dev 授权转账
*/
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool) {
_allowedFragments[from][msg.sender] -= value;
uint256 gonValue = value * _gonsPerFragment;
_gonBalances[from] -= gonValue;
_gonBalances[to] += gonValue;
emit Transfer(from, to, value);
return true;
}
/**
* @dev 授权额度
*/
function allowance(address owner_, address spender) external view returns (uint256) {
return _allowedFragments[owner_][spender];
}
}
/**
* @title MonetaryPolicy
* @dev Rebase策略合约
*/
contract MonetaryPolicy {
RebaseToken public token;
address public oracle;
uint256 public rebaseLag = 10; // rebase平滑系数
uint256 public epoch = 0;
uint256 public lastRebaseTime;
uint256 public rebaseInterval = 24 hours;
event LogRebase(
uint256 indexed epoch,
uint256 marketPrice,
uint256 targetPrice,
int256 supplyDelta,
uint256 timestamp
);
constructor(address _token, address _oracle) {
token = RebaseToken(_token);
oracle = _oracle;
lastRebaseTime = block.timestamp;
}
/**
* @dev 执行rebase
*/
function rebase() external {
require(block.timestamp >= lastRebaseTime + rebaseInterval, "Too soon");
epoch++;
lastRebaseTime = block.timestamp;
// 从预言机获取价格
uint256 marketPrice = getPrice();
uint256 targetPrice = token.TARGET_PRICE();
if (marketPrice == targetPrice) {
emit LogRebase(epoch, marketPrice, targetPrice, 0, block.timestamp);
return;
}
// 计算供应量变化
int256 supplyDelta = computeSupplyDelta(marketPrice, targetPrice);
// 执行rebase
token.rebase(epoch, supplyDelta);
emit LogRebase(epoch, marketPrice, targetPrice, supplyDelta, block.timestamp);
}
/**
* @dev 计算供应量变化
*/
function computeSupplyDelta(uint256 marketPrice, uint256 targetPrice)
internal
view
returns (int256)
{
int256 targetRate = int256(targetPrice);
int256 marketRate = int256(marketPrice);
int256 priceDelta = marketRate - targetRate;
// supplyDelta = totalSupply * (priceDelta / targetPrice) / rebaseLag
int256 totalSupply = int256(token.totalSupply());
int256 supplyDelta = (totalSupply * priceDelta) / targetRate / int256(rebaseLag);
return supplyDelta;
}
/**
* @dev 获取价格(简化,实际应从预言机获取)
*/
function getPrice() public view returns (uint256) {
// 这里应该从实际的预言机获取价格
// 简化起见,返回固定值
return 1e18;
}
}
第五部分:稳定币风险分析
5.1 各类稳定币的风险
5.1.1 法币抵押型稳定币
风险:
- 中心化风险:依赖发行方的信用
- 托管风险:储备金安全
- 监管风险:可能被冻结或限制
- 透明度风险:储备金审计不透明
案例:USDT曾因储备金透明度问题引发争议
5.1.2 加密抵押型稳定币
风险:
- 价格波动风险:抵押品价格剧烈波动
- 清算风险:市场崩盘时清算系统可能失效
- 预言机风险:价格喂价被操纵
- 资本效率低:需要超额抵押
案例:2020年3月12日,ETH价格暴跌,导致大量MakerDAO金库被清算
5.1.3 算法稳定币
风险:
- 死亡螺旋:失去锚定后难以恢复
- 信心风险:完全依赖市场信心
- 复杂性风险:机制复杂,难以理解
- 历史记录差:多个项目已经失败
案例:Terra/UST在2022年5月崩盘,损失超过400亿美元
5.2 稳定币监控指标
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title StablecoinMonitor
* @dev 稳定币健康度监控
*/
contract StablecoinMonitor {
struct HealthMetrics {
uint256 price; // 当前价格
uint256 marketCap; // 市值
uint256 collateralRatio; // 抵押率
uint256 liquidityDepth; // 流动性深度
uint256 peg Deviation; // 锚定偏离度
uint256 timestamp;
}
mapping(address => HealthMetrics[]) public metricsHistory;
event MetricsUpdated(address indexed stablecoin, uint256 timestamp);
event AlertTriggered(address indexed stablecoin, string alertType, uint256 value);
// 警报阈值
uint256 public constant PRICE_DEVIATION_THRESHOLD = 5e16; // 5%
uint256 public constant MIN_COLLATERAL_RATIO = 120e16; // 120%
/**
* @dev 更新指标
*/
function updateMetrics(
address stablecoin,
uint256 price,
uint256 marketCap,
uint256 collateralRatio,
uint256 liquidityDepth
) external {
uint256 pegDeviation = price > 1e18 ? price - 1e18 : 1e18 - price;
HealthMetrics memory metrics = HealthMetrics({
price: price,
marketCap: marketCap,
collateralRatio: collateralRatio,
liquidityDepth: liquidityDepth,
pegDeviation: pegDeviation,
timestamp: block.timestamp
});
metricsHistory[stablecoin].push(metrics);
// 检查警报
if (pegDeviation > PRICE_DEVIATION_THRESHOLD) {
emit AlertTriggered(stablecoin, "PRICE_DEVIATION", pegDeviation);
}
if (collateralRatio < MIN_COLLATERAL_RATIO) {
emit AlertTriggered(stablecoin, "LOW_COLLATERAL", collateralRatio);
}
emit MetricsUpdated(stablecoin, block.timestamp);
}
/**
* @dev 获取最新指标
*/
function getLatestMetrics(address stablecoin) external view returns (HealthMetrics memory) {
HealthMetrics[] storage history = metricsHistory[stablecoin];
require(history.length > 0, "No metrics available");
return history[history.length - 1];
}
/**
* @dev 获取历史指标
*/
function getMetricsHistory(address stablecoin, uint256 count)
external
view
returns (HealthMetrics[] memory)
{
HealthMetrics[] storage history = metricsHistory[stablecoin];
uint256 length = history.length;
uint256 returnCount = count > length ? length : count;
HealthMetrics[] memory result = new HealthMetrics[](returnCount);
for (uint256 i = 0; i < returnCount; i++) {
result[i] = history[length - returnCount + i];
}
return result;
}
}