166 lines
5.5 KiB
Solidity
166 lines
5.5 KiB
Solidity
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);
|
||
}
|
||
}
|