diff --git a/README.md b/README.md
index 1d72187..5a6fc8e 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,270 @@
-# Uniswap V2
+# Uniswap V2 Core 核心合约
[](https://github.com/Uniswap/uniswap-v2-core/actions)
[](https://www.npmjs.com/package/@uniswap/v2-core)
-In-depth documentation on Uniswap V2 is available at [uniswap.org](https://uniswap.org/docs).
+## 📋 项目概述
-The built contract artifacts can be browsed via [unpkg.com](https://unpkg.com/browse/@uniswap/v2-core@latest/).
+Uniswap V2 Core 是去中心化交易协议 Uniswap V2 的核心智能合约集合,实现了自动化做市商(AMM)机制。本项目包含了创建和管理流动性池、执行代币交换等核心功能的智能合约。
-# Local Development
+### 🎯 核心特性
-The following assumes the use of `node@>=10`.
+- **自动化做市商(AMM)**: 基于恒定乘积公式 `x * y = k` 的去中心化交易
+- **流动性挖矿**: 用户可以提供流动性获得手续费收入
+- **CREATE2 部署**: 使用确定性地址部署,便于前端集成
+- **EIP-712 支持**: 支持链下签名授权,提升用户体验
+- **时间加权平均价格(TWAP)**: 内置价格预言机功能
-## Install Dependencies
+## 🏗️ 项目架构
-`yarn`
+### 核心合约
-## Compile Contracts
+```
+contracts/
+├── UniswapV2Factory.sol # 工厂合约,管理所有交易对的创建
+├── UniswapV2Pair.sol # 交易对合约,实现AMM核心逻辑
+├── UniswapV2ERC20.sol # 流动性代币,支持EIP-712
+├── interfaces/ # 接口定义
+│ ├── IUniswapV2Factory.sol
+│ ├── IUniswapV2Pair.sol
+│ ├── IUniswapV2ERC20.sol
+│ ├── IERC20.sol
+│ └── IUniswapV2Callee.sol
+├── libraries/ # 工具库
+│ ├── Math.sol # 数学运算库
+│ ├── SafeMath.sol # 安全数学运算
+│ └── UQ112x112.sol # 定点数运算
+└── test/ # 测试合约
+```
-`yarn compile`
+### 合约关系图
-## Run Tests
+```mermaid
+graph TB
+ Factory[UniswapV2Factory
工厂合约] --> Pair[UniswapV2Pair
交易对合约]
+ Pair --> ERC20[UniswapV2ERC20
流动性代币]
+ Pair --> SafeMath[SafeMath
安全数学运算]
+ Pair --> Math[Math
数学库]
+ Pair --> UQ112x112[UQ112x112
定点数库]
+
+ User[用户] --> Factory
+ User --> Pair
+ LP[流动性提供者] --> Pair
+ Trader[交易者] --> Pair
+```
-`yarn test`
+## 🔧 核心概念
+
+### 1. 自动化做市商(AMM)
+
+Uniswap V2 使用恒定乘积公式实现自动化做市:
+
+```
+x * y = k
+```
+
+其中:
+- `x` 和 `y` 是池中两种代币的数量
+- `k` 是恒定值,只在添加/移除流动性时改变
+
+### 2. 流动性提供
+
+用户可以向交易对提供流动性,获得:
+- **流动性代币(LP Token)**: 代表在池中的份额
+- **交易手续费**: 每笔交易的0.3%手续费按比例分配
+
+流动性计算公式:
+```solidity
+// 首次添加流动性
+liquidity = sqrt(amount0 * amount1) - MINIMUM_LIQUIDITY
+
+// 后续添加流动性
+liquidity = min(amount0 * totalSupply / reserve0, amount1 * totalSupply / reserve1)
+```
+
+### 3. 价格发现机制
+
+交易价格由池中代币比例决定:
+```
+price = reserve1 / reserve0
+```
+
+每次交易后,价格会自动调整以维持恒定乘积。
+
+### 4. 时间加权平均价格(TWAP)
+
+合约内置价格累积器,可以计算任意时间段的平均价格:
+```solidity
+price0CumulativeLast += (reserve1 / reserve0) * timeElapsed
+price1CumulativeLast += (reserve0 / reserve1) * timeElapsed
+```
+
+## 💼 主要功能
+
+### UniswapV2Factory (工厂合约)
+
+**职责**: 创建和管理所有交易对
+
+**核心函数**:
+- `createPair(address tokenA, address tokenB)`: 创建新的交易对
+- `getPair(address tokenA, address tokenB)`: 获取交易对地址
+- `allPairs(uint index)`: 按索引获取交易对
+- `setFeeTo(address feeTo)`: 设置协议费接收地址
+
+**特点**:
+- 使用CREATE2确定性部署,地址可预测
+- 任何人都可以创建交易对
+- 自动排序代币地址确保唯一性
+
+### UniswapV2Pair (交易对合约)
+
+**职责**: 实现具体的AMM交易逻辑
+
+**核心函数**:
+- `mint(address to)`: 铸造流动性代币
+- `burn(address to)`: 销毁流动性代币,取回资产
+- `swap(uint amount0Out, uint amount1Out, address to, bytes calldata data)`: 执行代币交换
+- `getReserves()`: 获取当前储备量和时间戳
+
+**安全机制**:
+- 重入锁防止重入攻击
+- 最小流动性锁定防止攻击
+- 完整性检查确保K值不减少
+
+### UniswapV2ERC20 (流动性代币)
+
+**职责**: 标准ERC20流动性代币,支持高级功能
+
+**核心功能**:
+- 标准ERC20功能 (转账、授权等)
+- EIP-712签名授权 (`permit`)
+- 域分隔符确保跨链安全
+
+## 🚀 快速开始
+
+### 环境要求
+
+- Node.js >= 10
+- Yarn 包管理器
+
+### 安装依赖
+
+```bash
+yarn install
+```
+
+### 编译合约
+
+```bash
+yarn compile
+```
+
+### 运行测试
+
+```bash
+yarn test
+```
+
+### 代码检查
+
+```bash
+yarn lint
+```
+
+## 📖 使用示例
+
+### 1. 部署工厂合约
+
+```solidity
+// 部署工厂合约
+UniswapV2Factory factory = new UniswapV2Factory(msg.sender);
+```
+
+### 2. 创建交易对
+
+```solidity
+// 创建 WETH/USDC 交易对
+address pair = factory.createPair(WETH, USDC);
+```
+
+### 3. 添加流动性
+
+```solidity
+// 向交易对转入代币
+IERC20(WETH).transfer(pair, wethAmount);
+IERC20(USDC).transfer(pair, usdcAmount);
+
+// 铸造流动性代币
+uint liquidity = IUniswapV2Pair(pair).mint(msg.sender);
+```
+
+### 4. 执行交换
+
+```solidity
+// 计算输出数量 (需要使用路由合约)
+uint amountOut = getAmountOut(amountIn, reserveIn, reserveOut);
+
+// 转入代币
+IERC20(tokenIn).transfer(pair, amountIn);
+
+// 执行交换
+IUniswapV2Pair(pair).swap(amount0Out, amount1Out, msg.sender, "");
+```
+
+## 🔐 安全考虑
+
+### 重入攻击防护
+- 所有状态修改函数都使用重入锁
+- 采用检查-生效-交互模式
+
+### 整数溢出防护
+- 使用SafeMath库防止算术溢出
+- 严格的边界检查
+
+### 经济安全
+- 最小流动性锁定(1000 wei)
+- K值单调性检查
+- 合理的手续费机制
+
+### 前端安全
+- CREATE2确定性地址
+- 完整的事件日志
+- 标准化接口
+
+## 📚 深入学习
+
+### 相关资源
+
+- [Uniswap V2 白皮书](https://uniswap.org/whitepaper.pdf)
+- [官方文档](https://uniswap.org/docs)
+- [Solidity 最佳实践](https://consensys.github.io/smart-contract-best-practices/)
+
+### 构建工件
+
+编译后的合约可通过 [unpkg.com](https://unpkg.com/browse/@uniswap/v2-core@latest/) 浏览。
+
+## 🤝 贡献指南
+
+欢迎提交 Issue 和 Pull Request!
+
+### 开发流程
+
+1. Fork 本仓库
+2. 创建功能分支
+3. 提交更改
+4. 运行测试
+5. 提交 Pull Request
+
+## 📄 许可证
+
+本项目采用 [GPL-3.0-or-later](LICENSE) 许可证。
+
+## 🙏 致谢
+
+- Uniswap 团队的创新设计
+- DappHub 的 SafeMath 库
+- 以太坊社区的支持
+
+---
+
+**⚠️ 风险提示**: 本项目仅供学习和研究使用。在生产环境中使用前,请进行充分的安全审计。去中心化金融存在智能合约风险、无常损失等风险,请谨慎参与。
diff --git a/contracts/UniswapV2ERC20.sol b/contracts/UniswapV2ERC20.sol
index 404a8be..ca4dc37 100644
--- a/contracts/UniswapV2ERC20.sol
+++ b/contracts/UniswapV2ERC20.sol
@@ -3,29 +3,42 @@ pragma solidity =0.5.16;
import './interfaces/IUniswapV2ERC20.sol';
import './libraries/SafeMath.sol';
+/**
+ * @title UniswapV2ERC20 流动性代币合约
+ * @notice 实现ERC20标准的流动性代币,支持EIP-712 permit功能
+ * @dev 为Uniswap V2交易对提供流动性代币功能
+ */
contract UniswapV2ERC20 is IUniswapV2ERC20 {
using SafeMath for uint;
- string public constant name = 'Uniswap V2';
- string public constant symbol = 'UNI-V2';
- uint8 public constant decimals = 18;
- uint public totalSupply;
- mapping(address => uint) public balanceOf;
- mapping(address => mapping(address => uint)) public allowance;
+ // ERC20标准属性
+ string public constant name = 'Uniswap V2'; // 代币名称
+ string public constant symbol = 'UNI-V2'; // 代币符号
+ uint8 public constant decimals = 18; // 小数位数
+ uint public totalSupply; // 总供应量
+ mapping(address => uint) public balanceOf; // 余额映射
+ mapping(address => mapping(address => uint)) public allowance; // 授权映射
- bytes32 public DOMAIN_SEPARATOR;
- // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
+ // EIP-712相关
+ bytes32 public DOMAIN_SEPARATOR; // 域分隔符
+ // permit函数的类型哈希
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
- mapping(address => uint) public nonces;
+ mapping(address => uint) public nonces; // 防重放nonce
+ // ERC20标准事件
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
+ /**
+ * @dev 构造函数,初始化EIP-712域分隔符
+ */
constructor() public {
uint chainId;
+ // 内联汇编获取链ID
assembly {
chainId := chainid
}
+ // 计算域分隔符
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
@@ -37,40 +50,82 @@ contract UniswapV2ERC20 is IUniswapV2ERC20 {
);
}
+ /**
+ * @dev 内部函数:铸造代币
+ * @param to 接收地址
+ * @param value 铸造数量
+ */
function _mint(address to, uint value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
+ /**
+ * @dev 内部函数:销毁代币
+ * @param from 销毁地址
+ * @param value 销毁数量
+ */
function _burn(address from, uint value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
+ /**
+ * @dev 内部函数:设置授权
+ * @param owner 授权者
+ * @param spender 被授权者
+ * @param value 授权数量
+ */
function _approve(address owner, address spender, uint value) private {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
+ /**
+ * @dev 内部函数:转账
+ * @param from 发送者
+ * @param to 接收者
+ * @param value 转账数量
+ */
function _transfer(address from, address to, uint value) private {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
+ /**
+ * @notice 授权spender使用value数量的代币
+ * @param spender 被授权地址
+ * @param value 授权数量
+ * @return 是否成功
+ */
function approve(address spender, uint value) external returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
+ /**
+ * @notice 转账代币给to地址
+ * @param to 接收地址
+ * @param value 转账数量
+ * @return 是否成功
+ */
function transfer(address to, uint value) external returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
+ /**
+ * @notice 从from地址转账代币给to地址(需要授权)
+ * @param from 发送地址
+ * @param to 接收地址
+ * @param value 转账数量
+ * @return 是否成功
+ */
function transferFrom(address from, address to, uint value) external returns (bool) {
+ // 如果授权量不是最大值,则减少授权量
if (allowance[from][msg.sender] != uint(-1)) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
@@ -78,17 +133,33 @@ contract UniswapV2ERC20 is IUniswapV2ERC20 {
return true;
}
+ /**
+ * @notice EIP-712签名授权,无需发送交易即可设置授权
+ * @param owner 代币所有者
+ * @param spender 被授权者
+ * @param value 授权数量
+ * @param deadline 授权截止时间
+ * @param v 签名参数v
+ * @param r 签名参数r
+ * @param s 签名参数s
+ */
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
require(deadline >= block.timestamp, 'UniswapV2: EXPIRED');
+
+ // 构造EIP-712消息哈希
bytes32 digest = keccak256(
abi.encodePacked(
- '\x19\x01',
+ '\x19\x01', // EIP-191前缀
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, 'UniswapV2: INVALID_SIGNATURE');
+
+ // 设置授权
_approve(owner, spender, value);
}
}
diff --git a/contracts/UniswapV2Factory.sol b/contracts/UniswapV2Factory.sol
index a66ad82..c74f72a 100644
--- a/contracts/UniswapV2Factory.sol
+++ b/contracts/UniswapV2Factory.sol
@@ -3,45 +3,94 @@ pragma solidity =0.5.16;
import './interfaces/IUniswapV2Factory.sol';
import './UniswapV2Pair.sol';
+/**
+ * @title UniswapV2Factory 工厂合约
+ * @notice Uniswap V2协议的工厂合约,负责创建和管理所有交易对
+ * @dev 使用CREATE2确定性部署,可预测交易对地址
+ */
contract UniswapV2Factory is IUniswapV2Factory {
+ // 协议手续费接收地址
address public feeTo;
+ // 有权设置feeTo的地址
address public feeToSetter;
+ // 双重映射:token地址 => token地址 => 交易对地址
mapping(address => mapping(address => address)) public getPair;
+ // 所有交易对地址的数组
address[] public allPairs;
+ // 创建交易对时触发的事件
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
+ /**
+ * @dev 构造函数
+ * @param _feeToSetter 初始的手续费设置者地址
+ */
constructor(address _feeToSetter) public {
feeToSetter = _feeToSetter;
}
+ /**
+ * @notice 获取所有交易对的数量
+ * @return 交易对总数
+ */
function allPairsLength() external view returns (uint) {
return allPairs.length;
}
+ /**
+ * @notice 创建交易对
+ * @dev 使用CREATE2确定性部署,任何人都可以调用
+ * @param tokenA 第一个代币地址
+ * @param tokenB 第二个代币地址
+ * @return pair 新创建的交易对地址
+ */
function createPair(address tokenA, address tokenB) external returns (address pair) {
require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES');
+ // 按字典顺序排序代币地址,确保token0 < token1
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS');
- require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // single check is sufficient
+ require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS');
+
+ // 获取UniswapV2Pair合约的字节码
bytes memory bytecode = type(UniswapV2Pair).creationCode;
+ // 使用两个代币地址生成salt
bytes32 salt = keccak256(abi.encodePacked(token0, token1));
+
+ // 使用CREATE2部署合约,地址可预测
assembly {
pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
+
+ // 初始化交易对
IUniswapV2Pair(pair).initialize(token0, token1);
+
+ // 在映射中记录交易对(双向)
getPair[token0][token1] = pair;
- getPair[token1][token0] = pair; // populate mapping in the reverse direction
+ getPair[token1][token0] = pair;
+
+ // 添加到数组中
allPairs.push(pair);
+
+ // 触发创建事件
emit PairCreated(token0, token1, pair, allPairs.length);
}
+ /**
+ * @notice 设置协议手续费接收地址
+ * @dev 只有feeToSetter可以调用
+ * @param _feeTo 新的手续费接收地址
+ */
function setFeeTo(address _feeTo) external {
require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
feeTo = _feeTo;
}
+ /**
+ * @notice 设置有权修改feeTo的地址
+ * @dev 只有当前feeToSetter可以调用
+ * @param _feeToSetter 新的手续费设置者地址
+ */
function setFeeToSetter(address _feeToSetter) external {
require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
feeToSetter = _feeToSetter;
diff --git a/contracts/UniswapV2Pair.sol b/contracts/UniswapV2Pair.sol
index f87a1db..30ca4be 100644
--- a/contracts/UniswapV2Pair.sol
+++ b/contracts/UniswapV2Pair.sol
@@ -8,26 +8,42 @@ import './interfaces/IERC20.sol';
import './interfaces/IUniswapV2Factory.sol';
import './interfaces/IUniswapV2Callee.sol';
+/**
+ * @title UniswapV2Pair 交易对合约
+ * @notice 这是Uniswap V2协议的核心合约,实现了自动做市商(AMM)机制
+ * @dev 继承自IUniswapV2Pair接口和UniswapV2ERC20合约,实现流动性代币功能
+ */
contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 {
using SafeMath for uint;
using UQ112x112 for uint224;
+ // 最小流动性常量,防止除零错误和攻击
uint public constant MINIMUM_LIQUIDITY = 10**3;
+ // ERC20 transfer函数的选择器,用于安全转账
bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
+ // 工厂合约地址
address public factory;
+ // 交易对中的两个代币地址(token0 < token1)
address public token0;
address public token1;
- uint112 private reserve0; // uses single storage slot, accessible via getReserves
- uint112 private reserve1; // uses single storage slot, accessible via getReserves
- uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves
+ // 储备量,使用uint112节省gas,三个变量共用一个存储槽
+ uint112 private reserve0; // token0的储备量
+ uint112 private reserve1; // token1的储备量
+ uint32 private blockTimestampLast; // 上次更新的区块时间戳
- uint public price0CumulativeLast;
- uint public price1CumulativeLast;
- uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event
+ // 价格累积器,用于计算时间加权平均价格(TWAP)
+ uint public price0CumulativeLast; // token0相对于token1的累积价格
+ uint public price1CumulativeLast; // token1相对于token0的累积价格
+ uint public kLast; // 上次流动性事件后的k值 (reserve0 * reserve1)
+ // 重入锁状态
uint private unlocked = 1;
+
+ /**
+ * @dev 重入锁修饰符,防止重入攻击
+ */
modifier lock() {
require(unlocked == 1, 'UniswapV2: LOCKED');
unlocked = 0;
@@ -35,17 +51,30 @@ contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 {
unlocked = 1;
}
+ /**
+ * @notice 获取当前储备量和最后更新时间
+ * @return _reserve0 token0的储备量
+ * @return _reserve1 token1的储备量
+ * @return _blockTimestampLast 最后更新的区块时间戳
+ */
function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
_reserve0 = reserve0;
_reserve1 = reserve1;
_blockTimestampLast = blockTimestampLast;
}
+ /**
+ * @dev 安全转账函数,确保代币转账成功
+ * @param token 代币合约地址
+ * @param to 接收地址
+ * @param value 转账数量
+ */
function _safeTransfer(address token, address to, uint value) private {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED');
}
+ // 事件定义
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
@@ -58,13 +87,20 @@ contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 {
);
event Sync(uint112 reserve0, uint112 reserve1);
+ /**
+ * @dev 构造函数,设置工厂地址为部署者
+ */
constructor() public {
factory = msg.sender;
}
- // called once by the factory at time of deployment
+ /**
+ * @notice 初始化交易对,只能由工厂调用一次
+ * @param _token0 第一个代币地址
+ * @param _token1 第二个代币地址
+ */
function initialize(address _token0, address _token1) external {
- require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check
+ require(msg.sender == factory, 'UniswapV2: FORBIDDEN');
token0 = _token0;
token1 = _token1;
}
diff --git a/contracts/interfaces/IUniswapV2Factory.sol b/contracts/interfaces/IUniswapV2Factory.sol
index e73dc59..70cfcc1 100644
--- a/contracts/interfaces/IUniswapV2Factory.sol
+++ b/contracts/interfaces/IUniswapV2Factory.sol
@@ -1,17 +1,34 @@
pragma solidity >=0.5.0;
+/**
+ * @title IUniswapV2Factory 工厂合约接口
+ * @notice 定义Uniswap V2工厂合约的标准接口
+ */
interface IUniswapV2Factory {
+ /// @notice 创建新交易对时触发的事件
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
+ /// @notice 协议手续费接收地址
function feeTo() external view returns (address);
+
+ /// @notice 有权设置feeTo的地址
function feeToSetter() external view returns (address);
+ /// @notice 获取指定代币对的交易对地址
function getPair(address tokenA, address tokenB) external view returns (address pair);
+
+ /// @notice 按索引获取交易对地址
function allPairs(uint) external view returns (address pair);
+
+ /// @notice 获取交易对总数
function allPairsLength() external view returns (uint);
+ /// @notice 创建新的交易对
function createPair(address tokenA, address tokenB) external returns (address pair);
+ /// @notice 设置协议手续费接收地址
function setFeeTo(address) external;
+
+ /// @notice 设置手续费设置者地址
function setFeeToSetter(address) external;
}
diff --git a/contracts/libraries/Math.sol b/contracts/libraries/Math.sol
index 1cab10d..6d00708 100644
--- a/contracts/libraries/Math.sol
+++ b/contracts/libraries/Math.sol
@@ -1,17 +1,32 @@
pragma solidity =0.5.16;
-// a library for performing various math operations
-
+/**
+ * @title Math 数学计算库
+ * @notice 提供各种数学运算函数
+ * @dev 包含最小值计算和平方根计算等工具函数
+ */
library Math {
+ /**
+ * @notice 返回两个数中的较小值
+ * @param x 第一个数
+ * @param y 第二个数
+ * @return z 较小的数
+ */
function min(uint x, uint y) internal pure returns (uint z) {
z = x < y ? x : y;
}
- // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
+ /**
+ * @notice 计算平方根(巴比伦算法)
+ * @dev 使用巴比伦方法计算平方根,参考: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
+ * @param y 需要计算平方根的数
+ * @return z 平方根结果
+ */
function sqrt(uint y) internal pure returns (uint z) {
if (y > 3) {
z = y;
uint x = y / 2 + 1;
+ // 迭代逼近,直到找到最优解
while (x < z) {
z = x;
x = (y / x + x) / 2;
@@ -19,5 +34,6 @@ library Math {
} else if (y != 0) {
z = 1;
}
+ // 如果y为0,则z保持为0(默认值)
}
}
diff --git a/contracts/libraries/SafeMath.sol b/contracts/libraries/SafeMath.sol
index f2fbe16..ee83e2b 100644
--- a/contracts/libraries/SafeMath.sol
+++ b/contracts/libraries/SafeMath.sol
@@ -1,16 +1,41 @@
pragma solidity =0.5.16;
-// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
-
+/**
+ * @title SafeMath 安全数学运算库
+ * @notice 提供防止溢出的数学运算函数
+ * @dev 来自DappHub的ds-math库 (https://github.com/dapphub/ds-math)
+ * @dev 在Solidity 0.8.0之前,需要手动检查算术溢出
+ */
library SafeMath {
+ /**
+ * @notice 安全加法,防止溢出
+ * @param x 第一个加数
+ * @param y 第二个加数
+ * @return z 两数之和
+ * @dev 如果结果溢出则回滚交易
+ */
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x, 'ds-math-add-overflow');
}
+ /**
+ * @notice 安全减法,防止下溢
+ * @param x 被减数
+ * @param y 减数
+ * @return z 两数之差
+ * @dev 如果结果下溢则回滚交易
+ */
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x, 'ds-math-sub-underflow');
}
+ /**
+ * @notice 安全乘法,防止溢出
+ * @param x 第一个乘数
+ * @param y 第二个乘数
+ * @return z 两数之积
+ * @dev 如果结果溢出则回滚交易,使用除法检查溢出
+ */
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
}
diff --git a/contracts/libraries/UQ112x112.sol b/contracts/libraries/UQ112x112.sol
index a453f72..81854ef 100644
--- a/contracts/libraries/UQ112x112.sol
+++ b/contracts/libraries/UQ112x112.sol
@@ -1,19 +1,32 @@
pragma solidity =0.5.16;
-// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))
-
-// range: [0, 2**112 - 1]
-// resolution: 1 / 2**112
-
+/**
+ * @title UQ112x112 定点数运算库
+ * @notice 处理二进制定点数的库 (Q数字格式)
+ * @dev 参考: https://en.wikipedia.org/wiki/Q_(number_format)
+ * @dev 范围: [0, 2**112 - 1],精度: 1 / 2**112
+ */
library UQ112x112 {
+ // Q112常量,表示2^112,用于编码和解码
uint224 constant Q112 = 2**112;
- // encode a uint112 as a UQ112x112
+ /**
+ * @notice 将uint112编码为UQ112x112格式
+ * @param y 要编码的uint112数值
+ * @return z 编码后的UQ112x112数值
+ * @dev 乘以Q112进行编码,永不溢出
+ */
function encode(uint112 y) internal pure returns (uint224 z) {
- z = uint224(y) * Q112; // never overflows
+ z = uint224(y) * Q112; // 永不溢出
}
- // divide a UQ112x112 by a uint112, returning a UQ112x112
+ /**
+ * @notice UQ112x112除以uint112,返回UQ112x112
+ * @param x UQ112x112格式的被除数
+ * @param y uint112格式的除数
+ * @return z UQ112x112格式的商
+ * @dev 用于价格计算,保持定点数精度
+ */
function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {
z = x / uint224(y);
}