在uniV2中,关于erc20的合约其实有两部分,一个是erc20合约的接口部分,一个是接口合约对应的实现。、
IUniswapV2 ERC20解析
接口合约规定了需要实现的所有erc20标准方法,以下主要是接口合约的代码

UniswapV2 ERC20解析
其实现代码如下:
pragma solidity =0.5.16;
import "./interfaces/IUniswapV2ERC20.sol";
import "./libraries/SafeMath.sol";
contract UniswapV2ERC20 is IUniswapV2ERC20 {
using SafeMath for uint256;
//token名称
string public constant name = "Uniswap V2";
//token缩写
string public constant symbol = "UNI-V2";
//token精度
uint8 public constant decimals = 18;
//累计流动性LP总量
uint256 public totalSupply;
//余额映射
mapping(address => uint256) public balanceOf;
//批准映射
mapping(address => mapping(address => uint256)) public allowance;
//域分割
bytes32 public DOMAIN_SEPARATOR;
// keccak256('Permit(address owner,address spender,uint value,uint nonce,uint deadline)');
bytes32
public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
//nonces映射
mapping(address => uint256) public nonces;
//批准事件
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
//发送事件
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev 构造函数
*/
constructor() public {
uint256 chainId;
// solium-disable-next-line
assembly {
chainId := chainid
}
//EIP712Domain
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
),
keccak256(bytes(name)),
keccak256(bytes("1")),
chainId,
address(this)
)
);
}
function _mint(address to, uint256 value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _burn(address from, uint256 value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
function _approve(
address owner,
address spender,
uint256 value
) private {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(
address from,
address to,
uint256 value
) private {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint256 value) external returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function transfer(address to, uint256 value) external returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool) {
if (allowance[from][msg.sender] != uint256(-1)) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(
value
);
}
_transfer(from, to, value);
return true;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
// solium-disable-next-line security/no-block-members
require(deadline >= block.timestamp, "UniswapV2: EXPIRED");
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
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);
}
}
以上我只调选核心的函数进行说明

铸币方法:主要是向某个地址发送一定数量的token

销毁方法: 目的是销毁某个地址所持有的token
授权私有方法:修改allowance对应的映射并发出event

私有 转账方法:其逻辑就是将from对应的balanceO减去value,to对应的balanceOf加上value,最后触发Transfer事件。
以上就是erc20的主要常用的方法,实际上UniswapV2 中并没有直接使用上述erc20合约,在智能合约中部署的是配对合约,而配对合约是继承自上述合约。
常见问题解答:
为什么在一些合约中要用call方法,而不是把合约的接口引入进去直接用该方法?

主要原因是想获得某些函数的返回直接结果 来判断该方法执行是否执行成功!
而一些函数的实现并没有按照标准的erc20的要求返回一个是否成功的标识状态。
2. 有小伙伴问在工厂合约中uniswapV2Factory继承了IUniswapV2Factory接口,而IUniswapV2Factory中有八个未实现方法,而uniswapV2Factory中只实现四种方法,为什么没有全部实现接口方法呢?


是这样,在uniswapV2Factory中状态变量的类型是public类型,而public类型是自动会生成对应名称的getter函数。具体可参考这篇文章。
https://learnblockchain.cn/docs/solidity/contracts.html#getter-functions
