Files
uniswap-v2/contracts/UniswapV2ERC20.sol
NoBey 3586e648b2
Some checks failed
CI / test (10.x, ubuntu-latest) (push) Has been cancelled
CI / test (12.x, ubuntu-latest) (push) Has been cancelled
init
2025-07-08 01:27:47 +08:00

166 lines
5.5 KiB
Solidity
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
// 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; // 授权映射
// EIP-712相关
bytes32 public DOMAIN_SEPARATOR; // 域分隔符
// permit函数的类型哈希
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
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)'),
keccak256(bytes(name)),
keccak256(bytes('1')),
chainId,
address(this)
)
);
}
/**
* @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);
}
_transfer(from, to, value);
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', // 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);
}
}