DeFi 笔记合集

简介 去中心化金融旨在通过区块链与智能合约,构建一个开放、透明、可组合的金融服务生态系统。本合集从核心协议原理出发,系统梳理各赛道的运行机制、风险模型与演进趋势。 Lending DeFi借贷协议允许用户无需中介即可存入资产获取收益,或超额抵押资产借出其他资产。其核心机制包括资金池、利率模型、清算机制以及治理代币经济学 Flash Loan 👉 Flash Loan 闪电贷 Liquid Staking 流动性质押协议允许用户在参与区块链共识(如质押ETH)的同时,获得代表质押头寸的流动性衍生代币(如stETH),从而解决质押资产流动性锁定的问题 DEX 👉 DEX 经典概念 去中心化交易所(DEX)通过自动做市商机制,允许用户直接在链上交易加密资产。核心在于流动性池、恒定乘积等定价公式、手续费激励以及无常损失管理 RWA 现实世界资产旨在将传统金融资产(如国债、信贷、不动产)通过代币化引入区块链,为DeFi生态系统提供具有实际价值支撑的收益资产,并面临合规、托管与法律映射等独特挑战

August 16, 2025 · 1 min · 20 words · Guangyang Zhong

DEX 经典概念

简介 AMM(Automated Market Maker,自动做市商)是一类无需订单簿、无需对手方撮合就能完成资产交换的机制。它通过一条数学定价曲线(例如最经典的恒定乘积公式 x * y = k)来确定池中两种资产的价格与兑换比例 交易者与 AMM 交互时,并不是与某个具体对手方进行买卖,而是与池子本身交易: 当交易者往池子中加入一种资产时,池子的储备量发生变化 定价曲线根据新储备自动给出另一种资产能取出的数量 由此实现“自动化报价”和“自动化执行” 1. 基本概念与不变式 AMM 的核心思想:用一个自动化的数学不变式替代传统的订单簿,以池内储备(reserves)决定交易价格与数量。 最经典的不变式(恒定乘积)为: x * y = k 其中 x、y 为池内两种资产的数量(reserve of X, reserve of Y),k 为常数(在无手续费的理想情况下保持不变)。 交易通过改变 x 或 y 的值来完成,新的 x 和 y 必须满足不变式(考虑手续费时,换入量先扣手续费再作用于不变式) 2. 交易定价与交换公式(恒定乘积,含手续费) 设池初始为 x(Token X)与 y(Token Y),不变式 k = x * y。有交易者向池中放入 Δx(交易量),手续费比例为 f(例如 0.003 = 0.3%)。实际用于保持不变式的增量为: Δx_eff = Δx * (1 - f) 新的储备为: x' = x + Δx_eff y' = k / x' (保持 x' * y' = k) 交易者能从池中取出的 Y 数量为: ...

August 20, 2025 · 5 min · 953 words · Guangyang Zhong

Flash Loan 闪电贷

简介 闪电贷(Flash Loan) 是一种在单笔区块链交易内借入资产、使用资产并在同一交易内归还借款(含手续费)的借贷模式。核心特点是 “原子性”:借款、使用和还款必须在同一笔交易内完成,否则交易会回滚,借款不会生效。 这种机制使得借款人在不提供抵押的情况下临时动用大量资产,用于套利、清算、头寸迁移等操作;同时也被用于发动复杂的攻击(如操纵价格、闪电清算等)。 原理与执行流程 典型单笔闪电贷交易包含三步(原子性): 借款(Borrow) 在交易开始阶段通过闪电贷提供方(Lending Pool/Router)请求借入若干资产。 使用(Use) 在同一交易中,用借入资金执行任意链上操作,例如在不同 DEX 之间套利、进行清算、调整抵押头寸、执行跨协议操作等。 还款(Repay) 在交易结束前,将借入金额加上借贷方要求的手续费一并偿还给闪电贷提供方。如果无法偿还(余额不足或逻辑失败),整笔交易 revert,等同于“未发生”。 关键点:闪电贷的安全性与“回滚语义”绑定;若中间步骤出错,借贷不会被实际放出和使用。 常见闪电贷提供方 Aave(flashLoan / flashLoanSimple 接口) DyDx(Solo or v3) Uniswap(flash swap:允许先输出资产,再在同一交易内履约) Balancer / Curve / 其它支持 flash 的池子 (实现细节与接口在不同协议间不同) 典型用途(Use cases) 跨 DEX 套利:利用不同交易所价格差套利,套利收益用于偿还贷款并留盈利 清算(Liquidation):借资产替别人清算欠债(避免自己需提前持有资产) 头寸迁移 / 债务重组:一笔交易内把抵押品替换、债务迁移到另一个协议或仓位 杠杆构建 / 扩展:临时放大仓位用于策略 原子化多步操作:把多个必须同时完成的步骤整合为一笔交易,避免中间状态风险 代码示例 // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.20; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { AssetToken } from "./AssetToken.sol"; import { IERC20, IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { Oracle } from "./Oracle.sol"; interface IFlashLoanReceiver { function executeOperation(address token, uint256 amount, uint256 fee, address initiator, bytes calldata params) external; } contract ThunderLoan is Ownable, Oracle { using SafeERC20 for IERC20; /*////////////////////////////////////////////////////////////// STATE VARIABLES //////////////////////////////////////////////////////////////*/ mapping(IERC20 => AssetToken) public s_tokenToAssetToken; mapping(IERC20 => bool) private s_currentlyFlashLoaning; uint256 private constant FEE_PRECISION = 1e18; uint256 private s_flashLoanFee = 3e15; // 0.3% /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Deposit(address indexed account, IERC20 indexed token, uint256 amount); event Withdraw(address indexed account, IERC20 indexed token, uint256 amount); event FlashLoan(address indexed receiver, IERC20 indexed token, uint256 amount, uint256 fee); event TokenAllowed(IERC20 indexed token, bool allowed); /*////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////*/ modifier notZero(uint256 amount) { require(amount > 0, "Amount cannot be zero"); _; } modifier allowedToken(IERC20 token) { require(address(s_tokenToAssetToken[token]) != address(0), "Token not allowed"); _; } /*////////////////////////////////////////////////////////////// EXTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ constructor(address oracle) Oracle(oracle) Ownable(msg.sender) {} function deposit(IERC20 token, uint256 amount) external notZero(amount) allowedToken(token) { AssetToken assetToken = s_tokenToAssetToken[token]; // 计算应铸造的资产代币数量 uint256 mintAmount = (amount * FEE_PRECISION) / assetToken.getExchangeRate(); // 铸造资产代币给用户 assetToken.mint(msg.sender, mintAmount); // 更新汇率(包含手续费) assetToken.updateExchangeRate(calculateFee(token, amount)); // 将底层代币转移到资产代币合约 token.safeTransferFrom(msg.sender, address(assetToken), amount); emit Deposit(msg.sender, token, amount); } function withdraw(IERC20 token, uint256 assetAmount) external notZero(assetAmount) allowedToken(token) { AssetToken assetToken = s_tokenToAssetToken[token]; // 计算可取回的底层代币数量 uint256 underlyingAmount = (assetAmount * assetToken.getExchangeRate()) / FEE_PRECISION; // 销毁用户的资产代币 assetToken.burn(msg.sender, assetAmount); // 将底层代币转给用户 assetToken.transferUnderlyingTo(msg.sender, underlyingAmount); emit Withdraw(msg.sender, token, underlyingAmount); } function flashLoan( address receiver, IERC20 token, uint256 amount, bytes calldata params ) external notZero(amount) allowedToken(token) { AssetToken assetToken = s_tokenToAssetToken[token]; // 检查合约余额是否足够 uint256 poolBalance = token.balanceOf(address(assetToken)); require(amount <= poolBalance, "Insufficient pool balance"); // 检查接收者是合约 require(receiver.code.length > 0, "Receiver must be contract"); // 计算手续费 uint256 fee = calculateFee(token, amount); // 更新汇率 assetToken.updateExchangeRate(fee); // 标记为正在闪电贷 s_currentlyFlashLoaning[token] = true; // 将资金转给接收者 assetToken.transferUnderlyingTo(receiver, amount); // 调用接收者的回调函数 IFlashLoanReceiver(receiver).executeOperation( address(token), amount, fee, msg.sender, params ); // 验证还款 uint256 newBalance = token.balanceOf(address(assetToken)); require(newBalance >= poolBalance + fee, "Flash loan not repaid"); // 重置闪电贷状态 s_currentlyFlashLoaning[token] = false; emit FlashLoan(receiver, token, amount, fee); } function repay(IERC20 token, uint256 amount) external { require(s_currentlyFlashLoaning[token], "Not in flash loan"); token.safeTransferFrom(msg.sender, address(s_tokenToAssetToken[token]), amount); } /*////////////////////////////////////////////////////////////// ADMIN FUNCTIONS //////////////////////////////////////////////////////////////*/ function setAllowedToken(IERC20 token, bool allowed) external onlyOwner { if (allowed) { require(address(s_tokenToAssetToken[token]) == address(0), "Already allowed"); string memory name = string.concat("ThunderLoan ", IERC20Metadata(address(token)).name()); string memory symbol = string.concat("tl", IERC20Metadata(address(token)).symbol()); AssetToken assetToken = new AssetToken(address(this), token, name, symbol); s_tokenToAssetToken[token] = assetToken; } else { delete s_tokenToAssetToken[token]; } emit TokenAllowed(token, allowed); } function setFlashLoanFee(uint256 newFee) external onlyOwner { require(newFee <= FEE_PRECISION, "Fee too high"); s_flashLoanFee = newFee; } /*////////////////////////////////////////////////////////////// VIEW FUNCTIONS //////////////////////////////////////////////////////////////*/ function calculateFee(IERC20 token, uint256 amount) public view returns (uint256) { uint256 tokenValue = (amount * getPriceInWeth(address(token))) / FEE_PRECISION; return (tokenValue * s_flashLoanFee) / FEE_PRECISION; } function isAllowedToken(IERC20 token) public view returns (bool) { return address(s_tokenToAssetToken[token]) != address(0); } function getFlashLoanFee() external view returns (uint256) { return s_flashLoanFee; } } 经济可行性与可行性检查 在执行闪电贷策略前需判断经济可行性,常见校验条目: ...

August 20, 2025 · 3 min · 549 words · Guangyang Zhong