22 KiB
22 KiB
DeFi协议与AMM
问题
- 什么是DeFi(去中心化金融)?与传统金融的区别?
- 什么是AMM(自动做市商)?它如何工作?
- Uniswap V2、V3的区别是什么?
- 什么是流动性池(Liquidity Pool)?
- 什么是无常损失(Impermanent Loss)?如何计算?
- 什么是流动性挖矿(Yield Farming)?
- 什么是闪电贷(Flash Loan)?有什么应用场景?
- 什么是DEX聚合器?1inch如何工作?
- 借贷协议(Aave、Compound)如何工作?
- 什么是清算(Liquidation)?如何避免被清算?
标准答案
1. DeFi vs 传统金融
对比表
| 特性 | 传统金融(CeFi) | 去中心化金融(DeFi) |
|---|---|---|
| 中介 | 银行、券商 | 智能合约 |
| 准入门槛 | 需要KYC、银行账户 | 只需要钱包 |
| 营业时间 | 工作日 9-5 | 24/7 |
| 透明度 | 不透明 | 完全透明 |
| 速度 | 1-3天 | 几秒到几分钟 |
| 成本 | 高(中介费) | 低(Gas费) |
| 风险 | 信用风险、操作风险 | 智能合约风险、黑客攻击 |
DeFi核心组件
1. 交易所(DEX)
- Uniswap(AMM)
- Curve(稳定币)
- Balancer
2. 借贷
- Aave
- Compound
- MakerDAO
3. 稳定币
- USDT、USDC(中心化)
- DAI(去中心化)
4. 衍生品
- dYdX
- Synthetix
- GMX
5. 聚合器
- 1inch
- Paraswap
2. AMM(自动做市商)
传统订单簿 vs AMM
传统订单簿(CEX):
买单(Bid) 卖单(Ask)
100 USDT @ 2000 101 USDT @ 2001
150 USDT @ 1999 200 USDT @ 2002
200 USDT @ 1998 150 USDT @ 2003
需要:
- 买卖双方
- 撮合引擎
- 做市商提供流动性
AMM(DEX):
流动性池:
- ETH/USDT 池
- 100 ETH + 200,000 USDT
- 价格 = 2000 USDT/ETH
不需要:
- 买卖双方匹配
- 撮合引擎
- 传统做市商
由算法自动定价
Uniswap V2:恒定乘积公式
x * y = k
x = Token A 的数量
y = Token B 的数量
k = 恒定值(常数)
示例:
// Uniswap V2 核心公式
function getAmountOut(
uint amountIn,
uint reserveIn,
uint reserveOut
) public pure returns (uint amountOut) {
uint amountInWithFee = amountIn * 997; // 0.3% 手续费
uint numerator = amountInWithFee * reserveOut;
uint denominator = reserveIn * 1000 + amountInWithFee;
amountOut = numerator / denominator;
}
交易示例:
初始状态:
ETH Reserve: 100 ETH
USDT Reserve: 200,000 USDT
k = 100 * 200,000 = 20,000,000
用户用 1 ETH 买 USDT:
1. 输入:1 ETH
2. 手续费:1 * 0.3% = 0.003 ETH
3. 实际参与定价:0.997 ETH
4. 新的 ETH 储备:100 + 0.997 = 100.997 ETH
5. 新的 USDT 储备:20,000,000 / 100.997 ≈ 198,025.94 USDT
6. 用户获得:200,000 - 198,025.94 ≈ 1,974.06 USDT
价格影响:
- 实际价格:1,974.06 USDT/ETH
- 理论价格:2,000 USDT/ETH
- 滑点:(2000 - 1974.06) / 2000 ≈ 1.3%
价格滑点(Slippage)
交易量越大,价格滑点越大
公式:
新价格 = (reserveOut * amountIn) / (reserveIn + amountIn)
滑点 = (原价格 - 新价格) / 原价格
代码示例:
type AMM struct {
ReserveTokenA float64
ReserveTokenB float64
Fee float64 // 0.003 = 0.3%
}
func (a *AMM) Swap(amountIn float64, tokenIn string) float64 {
if tokenIn == "A" {
amountInWithFee := amountIn * (1 - a.Fee)
amountOut := (a.ReserveTokenB * amountInWithFee) / (a.ReserveTokenA + amountInWithFee)
// 更新储备
a.ReserveTokenA += amountIn
a.ReserveTokenB -= amountOut
return amountOut
}
// 反向交易类似
return 0
}
func (a *AMM) GetPrice() float64 {
return a.ReserveTokenB / a.ReserveTokenA
}
func (a *AMM) GetSlippage(amountIn float64) float64 {
spotPrice := a.GetPrice()
amountOut := a.Swap(amountIn, "A")
executionPrice := amountIn / amountOut
return (executionPrice - spotPrice) / spotPrice
}
3. Uniswap V3:集中流动性
V2 vs V3 对比
| 特性 | Uniswap V2 | Uniswap V3 |
|---|---|---|
| 流动性范围 | 0 ~ ∞(全范围) | 自定义价格区间 |
| 资金效率 | 低 | 高(最高4000倍) |
| 手续费 | 固定0.3% | 0.01%/0.05%/0.3%/1% |
| LP Token | ERC-20(可替换) | NFT(不可替换) |
| 适用场景 | 通用 | 稳定币、高波动币 |
V3核心创新:集中流动性
V2(全范围流动性):
ETH价格:2000 USDT
LP提供流动性:
- 范围:0 ~ ∞
- 实际交易区间:1800 ~ 2200 USDT
- 资金利用率:(2200-1800) / ∞ ≈ 0%
大部分资金永远不会被使用
V3(集中流动性):
LP可以选择价格区间:
- 下限:1800 USDT
- 上限:2200 USDT
- 当前价格:2000 USDT
资金集中在这个区间,利用率大幅提高
数学公式:
// V3 流动性计算
function getLiquidityForAmounts(
uint160 sqrtRatioX96, // 当前价格的平方根
uint160 sqrtRatioAX96, // 价格区间下限的平方根
uint160 sqrtRatioBX96, // 价格区间上限的平方根
uint256 amount0,
uint256 amount1
) internal pure returns (uint128 liquidity) {
if (sqrtRatioAX96 > sqrtRatioBX96) {
(sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
}
if (sqrtRatioX96 <= sqrtRatioAX96) {
// 当前价格低于区间
liquidity = getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0);
} else if (sqrtRatioX96 < sqrtRatioBX96) {
// 当前价格在区间内
uint128 liquidity0 = getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0);
uint128 liquidity1 = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1);
liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;
} else {
// 当前价格高于区间
liquidity = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1);
}
}
V3实际应用
稳定币池(USDC/USDT):
价格区间:0.999 ~ 1.001
手续费:0.01%
资金效率:V2的2000倍
原因:
- 稳定币价格几乎1:1
- 集中在极小区间
- 极高资金利用率
高波动币(ETH/SHIB):
价格区间:0.00000001 ~ 0.0000001
手续费:1%
资金效率:V2的100倍
原因:
- 波动大,需要更宽区间
- 高风险,高手续费
4. 流动性池(Liquidity Pool)
工作原理
1. 流动性提供者(LP)存入两种代币
- 例如:10 ETH + 20,000 USDT
2. 获得LP Token
- 代表池子份额
- 例如:100 LP Token
3. 交易者交易
- 支付手续费(0.3%)
- 手续费留在池中
4. LP提取
- 返还LP Token
- 获得本金 + 手续费收益
代码实现
pragma solidity ^0.8.0;
contract LiquidityPool {
uint256 public reserve0; // Token0 储备
uint256 public reserve1; // Token1 储备
uint256 public totalSupply; // LP Token 总量
mapping(address => uint256) public balanceOf; // LP Token 余额
// 添加流动性
function addLiquidity(
uint256 amount0,
uint256 amount1
) external returns (uint256 liquidity) {
// 转入代币
IERC20(token0).transferFrom(msg.sender, address(this), amount0);
IERC20(token1).transferFrom(msg.sender, address(this), amount1);
// 计算LP Token数量
if (totalSupply == 0) {
// 首次添加
liquidity = sqrt(amount0 * amount1);
} else {
liquidity = min(
(amount0 * totalSupply) / reserve0,
(amount1 * totalSupply) / reserve1
);
}
// 铸造LP Token
balanceOf[msg.sender] += liquidity;
totalSupply += liquidity;
// 更新储备
reserve0 += amount0;
reserve1 += amount1;
}
// 移除流动性
function removeLiquidity(
uint256 liquidity
) external returns (uint256 amount0, uint256 amount1) {
// 计算可提取数量
amount0 = (liquidity * reserve0) / totalSupply;
amount1 = (liquidity * reserve1) / totalSupply;
// 销毁LP Token
balanceOf[msg.sender] -= liquidity;
totalSupply -= liquidity;
// 更新储备
reserve0 -= amount0;
reserve1 -= amount1;
// 转出代币
IERC20(token0).transfer(msg.sender, amount0);
IERC20(token1).transfer(msg.sender, amount1);
}
}
5. 无常损失(Impermanent Loss)
定义
无常损失是指:LP提供流动性后,因价格变化导致的损失(相对于单纯持有代币)。
计算公式
无常损失 = (池中资产价值 - 单纯持有价值) / 单纯持有价值
简化公式:
IL = 2 * sqrt(price_ratio) / (1 + price_ratio) - 1
price_ratio = 新价格 / 初始价格
示例
初始状态:
- ETH价格:2000 USDT
- 存入:1 ETH + 2000 USDT
- 总价值:4000 USDT
价格上涨到 3000 USDT:
1. 池子调整(套利者搬砖):
- 新储备:0.816 ETH + 2449 USDT
- 池中价值:0.816 * 3000 + 2449 = 4897 USDT
2. 单纯持有:
- 1 ETH + 2000 USDT
- 价值:1 * 3000 + 2000 = 5000 USDT
3. 无常损失:
IL = (4897 - 5000) / 5000 = -2.06%
损失:103 USDT
代码计算
package main
import (
"fmt"
"math"
)
// 计算无常损失
func CalculateImpermanentLoss(priceRatio float64) float64 {
// IL = 2 * sqrt(r) / (1 + r) - 1
sqrtR := math.Sqrt(priceRatio)
il := (2*sqrtR)/(1+priceRatio) - 1
return il
}
// 计算LP收益(考虑手续费)
func CalculateLPReturn(
initialPrice float64,
finalPrice float64,
feeRate float64,
volume float64,
) float64 {
priceRatio := finalPrice / initialPrice
// 无常损失
il := CalculateImpermanentLoss(priceRatio)
// 手续费收益(假设交易量)
feeReturn := volume * feeRate
// 总收益 = 手续费收益 + 无常损失
totalReturn := feeReturn + il
return totalReturn
}
func main() {
// 价格从 2000 涨到 3000(价格比率 1.5)
il := CalculateImpermanentLoss(1.5)
fmt.Printf("无常损失: %.2f%%\n", il*100)
// 价格从 2000 跌到 1000(价格比率 0.5)
il2 := CalculateImpermanentLoss(0.5)
fmt.Printf("无常损失: %.2f%%\n", il2*100)
// 考虑手续费
totalReturn := CalculateLPReturn(2000, 3000, 0.003, 1000000)
fmt.Printf("总收益(含手续费): %.2f%%\n", totalReturn*100)
}
输出:
无常损失: -2.06%
无常损失: -2.06%
总收益(含手续费): 1.94%
无常损失表
| 价格变化 | 无常损失 |
|---|---|
| 1.25x | -0.6% |
| 1.50x | -2.0% |
| 1.75x | -3.8% |
| 2.00x | -5.7% |
| 3.00x | -13.4% |
| 4.00x | -20.0% |
| 5.00x | -25.5% |
结论:
- 价格变化越大,无常损失越大
- 稳定币池无常损失最小
- 高波动币池需要高手续费补偿
6. 流动性挖矿(Yield Farming)
定义
通过提供流动性或借贷,获得代币奖励,实现收益最大化。
收益来源
1. 交易手续费
- Uniswap: 0.3%
- Curve: 0.04%
2. 借贷利息
- 存款利息
- 借款利率差
3. 代币激励
- COMP(Compound)
- AAVE(Aave)
- UNI(Uniswap)
4. 挖矿奖励
- 质押LP Token
- 获得项目代币
APY计算
APY = (1 + APR/365)^365 - 1
APR(年化收益率):
- 交易手续费收益
- 借贷利息收益
- 代币激励收益
示例:
APR = 30%
APY = (1 + 0.3/365)^365 - 1 = 34.97%
策略示例
type YieldFarm struct {
Pool string
TVL float64 // 总锁仓量
DailyVolume float64 // 日交易量
FeeRate float64 // 手续费率
RewardAPR float64 // 代币奖励APR
}
func (yf *YieldFarm) CalculateAPY() float64 {
// 手续费收益
dailyFee := yf.DailyVolume * yf.FeeRate
yearlyFee := dailyFee * 365
feeAPR := yearlyFee / yf.TVL
// 总APR
totalAPR := feeAPR + yf.RewardAPR
// APY
APY := math.Pow(1+totalAPR/365, 365) - 1
return APY
}
func main() {
// Uniswap ETH/USDT 池
pool := YieldFarm{
Pool: "ETH/USDT",
TVL: 10000000, // 1000万
DailyVolume: 5000000, // 500万
FeeRate: 0.003, // 0.3%
RewardAPR: 0.1, // 10% 代币奖励
}
apy := pool.CalculateAPY()
fmt.Printf("APY: %.2f%%\n", apy*100)
}
7. 闪电贷(Flash Loan)
定义
无需抵押,在一笔交易内借款并还款的贷款。
特点
1. 无需抵押
2. 必须在同一笔交易内还款
3. 如果还款失败,整个交易回滚
4. 手续费:0.09%(Aave)
应用场景
1. 套利
// 套利示例
function executeArbitrage() external {
// 1. 闪电贷借入 1000 ETH
uint256 loanAmount = 1000 ether;
flashLoan(loanAmount);
// 2. 在 Uniswap 用 ETH 买 USDT
// 价格:1 ETH = 2000 USDT
uint256 usdtAmount = uniswap.swap(loanAmount);
// 3. 在 SushiSwap 用 USDT 买回 ETH
// 价格:1 ETH = 2010 USDT
uint256 ethAmount = sushiswap.swap(usdtAmount);
// 4. 还款 1000 ETH + 手续费
uint256 repayment = loanAmount * 10009 / 10000;
repay(repayment);
// 5. 利润 = ethAmount - repayment
// 如果利润 < 0,交易回滚
}
2. 清算
// 清算获利
function liquidate(address borrower) external {
// 1. 闪电贷借入 USDT
flashLoan(10000 * 1e6);
// 2. 清算借款人
// 清算折扣:5%
uint256 collateral = liquidateBorrower(borrower);
// 3. 卖掉抵押品
uint256 usdtReceived = sellCollateral(collateral);
// 4. 还款 + 赚取清算奖励
repay(10000 * 1e6);
// 利润 = usdtReceived - 10000 USDT + 清算奖励
}
3. 更改DeFi头寸
// 无需本金切换协议
function switchProtocol() external {
// 1. 闪电贷借入资金
flashLoan(amount);
// 2. 从 Aave 取出抵押品
aave.withdraw(collateral);
// 3. 存入 Compound
compound.deposit(collateral);
// 4. 还款
repay(amount);
// 实现无本金迁移
}
8. DEX聚合器(1inch)
工作原理
1. 用户发起交易请求
- 输入:1 ETH
- 输出:期望获得最多 USDT
2. 聚合器查询多个DEX
- Uniswap: 2000 USDT
- SushiSwap: 1995 USDT
- Curve: 1998 USDT
3. 拆分订单(最优路径)
- Uniswap: 0.6 ETH → 1201 USDT
- SushiSwap: 0.4 ETH → 799 USDT
- 总计:2000 USDT
4. 执行交易
路径优化算法
type DEX struct {
Name string
Reserve0 float64
Reserve1 float64
Fee float64
}
type Router struct {
Dexs []DEX
}
// 计算最优路径
func (r *Router) FindBestRoute(
amountIn float64,
) []struct {
Dex string
Amount float64
} {
type Route struct {
Dex string
AmountIn float64
AmountOut float64
}
var routes []Route
// 1. 单DEX路由
for _, dex := range r.Dexs {
amountOut := r.calculateOutput(dex, amountIn)
routes = append(routes, Route{
Dex: dex.Name,
AmountIn: amountIn,
AmountOut: amountOut,
})
}
// 2. 多DEX拆分(二分查找最优解)
for _, dex1 := range r.Dexs {
for _, dex2 := range r.Dexs {
if dex1.Name == dex2.Name {
continue
}
// 二分查找最优拆分
left, right := 0.0, amountIn
for i := 0; i < 50; i++ {
mid1 := (left + right) / 2
mid2 := amountIn - mid1
out1 := r.calculateOutput(dex1, mid1)
out2 := r.calculateOutput(dex2, mid2)
total := out1 + out2
routes = append(routes, Route{
Dex: dex1.Name + " + " + dex2.Name,
AmountIn: amountIn,
AmountOut: total,
})
}
}
}
// 3. 选择最优
sort.Slice(routes, func(i, j int) bool {
return routes[i].AmountOut > routes[j].AmountOut
})
return routes[0]
}
9. 借贷协议(Aave、Compound)
工作原理
存款人:
1. 存入资产(如USDT)
2. 获得利息
3. 获得aToken(Aave)或cToken(Compound)
借款人:
1. 存入抵押品(如ETH)
2. 根据抵押率借款
3. 支付利息
利率模型
// Compound 利率模型
function getBorrowRate(uint256 cash, uint256 borrows) public view returns (uint256) {
uint256 utilization = borrows * 1e18 / (cash + borrows);
// 分段利率
if (utilization < kink) {
// 低利用率:利率增长慢
return baseRate + utilization * multiplier;
} else {
// 高利用率:利率增长快
uint256 normalRate = baseRate + kink * multiplier;
uint256 excessUtil = utilization - kink;
return normalRate + excessUtil * jumpMultiplier;
}
}
// 示例:
// 利用率 < 80%: 利率 = 2% + 利用率 * 10%
// 利用率 > 80%: 利率快速增长到 20%+
利用率(Utilization Rate):
利用率 = 总借款 / (总存款 + 总借款)
例如:
存款:1000万 USDT
借款:800万 USDT
利用率:800 / 1000 = 80%
利率与利用率的关系:
- 利用率越高,利率越高
- 鼓励存款,抑制借款
抵押率(Collateral Factor)
抵押率决定了可以借多少
例如:
- ETH抵押率:75%
- 存入10 ETH(价值$20,000)
- 可借款:20,000 * 75% = $15,000
不同资产抵押率:
- ETH: 75%
- WBTC: 70%
- USDC: 80%
- SHIB: 40%(高风险资产)
10. 清算(Liquidation)
清算机制
健康因子(Health Factor):
HF = (抵押品价值 * 抵押率) / 借款价值
HF > 1: 安全
HF < 1: 可被清算
清算奖励:5-15%(激励清算人)
清算示例
// 清算逻辑
function liquidate(
address borrower,
address collateralAsset,
address debtAsset,
uint256 debtToCover
) external {
// 1. 检查健康因子
uint256 healthFactor = getHealthFactor(borrower);
require(healthFactor < 1e18, "Cannot liquidate");
// 2. 计算可清算数量
uint256 maxDebt = getMaxDebt(borrower);
uint256 debt = min(debtToCover, maxDebt);
// 3. 清算人偿还债务
IERC20(debtAsset).transferFrom(msg.sender, address(this), debt);
// 4. 给清算人抵押品(折扣5%)
uint256 collateral = (debt * 105) / 100;
IERC20(collateralAsset).transfer(msg.sender, collateral);
// 5. 更新借款人状态
updateBorrowerState(borrower, debt, collateral);
}
示例:
借款人状态:
- 存入:10 ETH($20,000)
- 借款:15,000 USDT
- ETH价格跌到 $1,800
- 抵押品价值:$18,000
健康因子:
HF = (18,000 * 0.75) / 15,000 = 0.9 < 1
可被清算:
- 清算人偿还 15,000 USDT
- 获得抵押品:15,000 * 1.05 = 15,750 USDT价值
- 实际获得:15,750 / 1,800 ≈ 8.75 ETH
- 清算人利润:0.75 ETH($1,350)
避免被清算
1. 监控健康因子
- 设置告警(HF < 1.2)
- 及时还款或增加抵押品
2. 选择稳定抵押品
- 避免高波动资产
- 优先选择ETH、WBTC
3. 不要满仓借款
- 保持安全边际
- 借款不超过50%
4. 使用DeFi Saver等工具
- 自动化风险管理
- 自动还款/增加抵押
结合简历的面试题
1. 高并发与AMM
面试官会问:
"你做过50k+ QPS的消费券系统,AMM DEX如何处理高并发?"
参考回答:
传统高并发(Web2):
- 消费券抢购:50k QPS
- 使用Redis缓存
- 使用消息队列削峰
- 使用分布式锁
AMM DEX高并发(Web3):
- 区块链TPS限制(Ethereum: 15 TPS)
- 解决方案:
1. Layer2
- Arbitrum: 4000+ TPS
- Optimism: 2000+ TPS
- 使用Rollup扩容
2. 交易池管理
- Gas Price竞价
- 优先级队列
- 交易打包优化
3. MEV(矿工可提取价值)
- 套利机器人
- 三明治攻击
- 需要抗MEV设计
4. 链下撮合 + 链上结算
- Loopring(ZK-Rollup DEX)
- dYdX(链下订单簿)
2. 低代码与智能合约开发
面试官会问:
"你做过低代码平台,智能合约开发有哪些低代码/无代码方案?"
参考回答:
传统低代码:
- aPaaS平台
- 可视化搭建
- 模板+配置
Web3低代码:
1. 智能合约模板
- OpenZeppelin Wizard
- 拖拽式生成合约
- 自动安全审计
2. 无代码部署
- Thirdweb
- 无需写代码部署NFT、Token
- 一键发币
3. 可视化IDE
- Remix IDE
- 图形化调试
- 在线编译部署
4. SDK封装
- Ethers.js
- Web3.js
- 简化合约交互
对比:
- 传统:降本增效
- Web3:降低开发门槛,加速生态发展
3. 营销系统与DeFi激励
面试官会问:
"你做过营销表达和策略玩法,DeFi的激励机制如何设计?"
参考回答:
传统营销:
- 消费券
- 满减活动
- 会员等级
DeFi激励:
1. 流动性挖矿
- 提供流动性获得代币奖励
- 类似消费券:吸引用户
2. 交易挖矿
- 交易即挖矿
- 类似满减:降低交易成本
3. 治理权
- 持有代币可投票
- 类似会员:参与决策
4. 质押奖励
- 锁仓获得高收益
- 类似定期存款
关键差异:
- 传统:中心化决策
- DeFi:代币化激励,社区治理
DeFi面试加分项
1. 实战经验
- 参与过DeFi项目开发
- 熟悉主流协议(Uniswap、Aave、Compound)
- 了解链上数据分析(Dune Analytics)
- 有MEV研究经验
2. 技术深度
- 理解AMM数学原理
- 了解利率模型设计
- 熟悉预言机机制
- 掌握Gas优化技巧
3. 安全意识
- 智能合约审计经验
- 了解常见漏洞(重入攻击、闪电贷攻击)
- 熟悉安全工具(Slither、MythX)
4. 行业理解
- DeFi生态全景
- 协议间组合性
- 监管趋势
- 风险管理