智能合约技术
以太坊采用了Solidity作为智能合约语言,Solidity是一门为实现智能合约而创建的高级编程语言,能在允许以太坊程序的节点上运行。
该语言吸收了C++、JavaScript的一些特性,例如它是静态类型语言,支持继承、库等。
区块链本质上是一种去中心化的分布式数据库,是分布式数据存储、多中心的点对点传输、共识机制和加密算法等多种技术在互联网时代的创新应用模式。
区块链(Blockchain)是一种由多方共同维护,使用密码学保证传输和访问安全,能够实现数据一致存储、难以篡改、防止抵赖的记账技术,也称为分布式账本技术(Distributed Ledger Technology)。
从本质上看,区块链是通过去中心化和去信任化,集体维护、分布式存储的可靠数据库。
智能合约就是可编程的合同,也可以理解为一段自动执行的条文合同,在计算机中,就是一段自动执行的程序片段。它更易于合约保存,并且由确定的算法运行,给定输入,就得到对应的输出,极大保障了合约的执行力。
address pair = UniswapV2Library.pairFor(factory, token, WETH); // 计算该代币对的地址
TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
IWETH(WETH).deposit{value: amountETH}(); // ETH已经转入本合约了,再通过本合约转给WETH合约,转换成WETH
assert(IWETH(WETH).transfer(pair, amountETH));
liquidity = IUniswapV2Pair(pair).mint(to);
// refund dust eth, if any
if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH); // 如果转入的ETH多了,退回去
}
// **** REMOVE LIQUIDITY ****
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountA, uint amountB) {
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // 调用V2Pair下的ERC20合约的transfeerFrom函数转移UNI2代币 *注意此处是transferFrom函数,本合约使用资金需要获得msg.sender的approve 之后将UNI2转到本合约
(uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to);// 将UNI2转入该合约,该合约将UNI2销毁并计算即将换出多少amount0、1,并将对应的token转到对应账户上
(address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB); // 当一个函数返回多个值,但我们只对其中的一些感兴趣时,这就是我们只获得那些值的方式。从gas的角度来说,这比读取一个值并且从不使用它要便宜一些。
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
require(amountA >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
require(amountB >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
// 最后返回能获得多少amountA,amountB
}
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) { // 流程:UNI2->本合约->销毁UNi2->将token,ETH转到本合约->token、ETH转给用户
(amountToken, amountETH) = removeLiquidity(
token,
WETH,
liquidity,
amountTokenMin,
amountETHMin,
address(this), // 注意此函数的to是address(this),而不是直接返还用户,如果to是用户的话则直接转给用户
deadline
); // 同理,此处也需要获得用户approve才有使用权限
TransferHelper.safeTransfer(token, to, amountToken);
IWETH(WETH).withdraw(amountETH); // 流动性池是使用WETH,用户存入的是ETH,合约将其换成了WETH在存进流动性池。因此此处是将WETH换回ETH再给用户
TransferHelper.safeTransferETH(to, amountETH); //转给to
}
// 这些函数通过中继元事务,允许没有以太币的用户使用许可机制从池中退出。(TODO:没有ETH支付gas费?)
// 以太坊上的交易需要以太币(ETH),这相当于真实的货币。如果你有ERC-20代币但没有ETH,你不能发送交易,所以你不能用它们做任何事情
// 因此permit消息允许其他ETh持有者帮忙发送此次流动性移除交易
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountA, uint amountB) {
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
uint value = approveMax ? uint(-1) : liquidity;
// V2Pair下的ERC20合约中实现了permit()函数,验证此approve消息是否真实。可查看[core-ERC20部分](https://blog.csdn.net/weixin_43380357/article/details/129779650?spm=1001.2014.3001.5501)
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
// TODO:这一套下来跟直接调用removeLiquidity有什么不一样吗?
// perimit结束意味着msg.sender给本合约进行了授权,本合约可以支配其资金 即将①msg.sender给合约权限 ②合约转账两笔交易二合一了;否则要先执行 ①approve ②removeLiquidity
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}