当前位置:网站首页>IDO代币预售合约系统开发技术详细
IDO代币预售合约系统开发技术详细
2022-08-02 21:56:00 【DD_MrsFu123】
Uniswap代码结构
Uniswap智能合约代码由两个github项目组成。一个是core,一个是periphery。
core偏核心逻辑,单个swap的逻辑。periphery偏外围服务,一个个swap的基础上构建服务。单个swap,两种代币形成的交易对,俗称“池子”。每个交易对有一些基本属性:reserve0/reserve1以及total supply。reserve0/reserve1是交易对的两种代币的储存量。total supply是当前流动性代币的总量。每个交易对都对应一个流动性代币(LPT - liquidity provider token)。简单的说,LPT记录了所有流动性提供者的贡献。所有流动性代币的总和就是total supply。Uniswap协议的思想是reserve0*reserve1的乘积不变。
Periphery逻辑
核心逻辑实现在UniswapV2Router02.sol中。称为Router,因为Periphery实现了“路由”,支持各个swap之间的连接。基本上实现了三个功能:1/ add liquidity(增加流动性)2/remove liqudity (抽取流动性) 3/ swap(交换)。
1. add liqudity
增加流动性,就是同时提供两种代币。因为代币有可能是ETH,针对不同情况有不同的接口。逻辑类似。
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity)
add liqudity查看之前有没有创建相应的交易对。如果有相应的交易对,确定目前的兑换比例在希望的范围内(期望amountDesired和不低于amountMin)。如果兑换比例OK,将相应的代币转入对应的交易对池子,并调用其的mint函数。
2. remove liqudity
提供流动性的相反的操作就是抽取流动性。也就是说,流动性提供者不再提供相应的流动性:
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) {
liquidity是抽取的流动性的量。amountMin是抽取代币的最小的个数。to是抽取代币的目标地址。deadline是个有意思的设计:抽取的操作有时效性。超过了一定的deadline(区块高度),这次抽取操作看成无效。
先收回需要抽取的Token,并且销毁:
IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
(uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to);
3. swap
swap是普通用户进行代币交易的操作。普通用户通过swap操作实现两种token之间的交易。
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
Uniswap支持多种代币的交换。具体的含义是,Uniswap提供了多级交易池的路由功能。举个例子,已有两个交易对TokenA-TokenB,以及TokenB-TokenC,通过swap接口,可以实现TokenA-TokenC的交换,其中经过的TokenA-TokenB,TokenB-TokenC,称为路径(path)。amountIn是路径中的第一个代币的数量,amountOutMin是期望的交换后的最少的数量。
amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
amounts是每个路径上的交换后的数量。amounts[amounts.length-1]也就是最后一条路径的输出数量。注意,UniswapV2Library.getAmountsOut的实现(在获取每个交易对的reserve信息后,调用getAmountOut函数):
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {
require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
uint amountInWithFee = amountIn.mul(997);
uint numerator = amountInWithFee.mul(reserveOut);
uint denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}
注意,其中的997/1000的系数。在进入每个交易池之前,进入的金额先扣除了0.3%的本金。这个就是交易费。注意的是,路径上的交易池,每个池子都收。有点像高速收费站,一段段的收。
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
将代币path[0],转入到交易对,数量为amounts[0]。转入代币后,进行真正的swap操作:
function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = UniswapV2Library.sortTokens(input, output);
uint amountOut = amounts[i + 1];
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to;
IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output)).swap(
amount0Out, amount1Out, to, new bytes(0)
);
}
}
边栏推荐
- 谷粒商城-day14-商城业务与压力测试
- 面试官居然问我:删库后,除了跑路还能干什么?
- Interviewer: can you talk about optimistic locking and pessimistic locks
- MySQL删除数据后,释放磁盘空间
- go 反射 reflect 包
- Flink优化的方方面面
- The interviewer asked me: delete library, in addition to run do?
- Ruoyi integrates minio to realize distributed file storage
- Summary of @Transactional transaction invocation and effective scenarios
- 【学习笔记】博弈论
猜你喜欢
UDP (User Datagram Protocol)
搭建Spark开发环境(第二弹)
【使用pyside2遇到的问题】This application failed to start because no Qt platform plugin could be initialized.
Learn more TypeScript 】 【 TypeScript modular
Software testing pen questions 1 (with answers)
LeetCode 2360. 图中的最长环 基环树找环+时间戳
创建型模式 - 抽象工厂模式AbstractFactory
# 医院管理系统完整项目代码以及数据库建表语句分享
总数据量超万亿行,玉溪卷烟厂通过正确选择时序数据库轻松应对
VS保存后Unity不刷新
随机推荐
如何通过开源数据库管理工具 DBeaver 连接 TDengine
Auto.js脚本程序打包
测试ESP32-Zigbee转发命令 : 滑轨、继电器控制
工业元宇宙的价值和发展
面试官居然问我:删库后,除了跑路还能干什么?
学习基因富集工具DAVID(2)
一个很少见但很有用的SQL功能
SRv6网络演进面临的挑战
Win10怎么开启自带的游戏录屏功能?
“百日行动”进行时:700余交通安全隐患被揪出
PHP实现登录失败三次需要输入验证码需求
双轴晶体中锥形折射的建模与应用
MySql查询某个时间段内的数据(前一周、前三个月、前一年等)
Software testing pen questions 1 (with answers)
go os 包
Shunted Self-Attention via Multi-Scale Token Aggregation
一群搞社区的人
终于明白:有了线程,为什么还要有协程?
CodeTON Round 2 A - D
H.265视频流媒体播放器EasyPlayer.js集成时出现“SourceBuffer ”报错,该如何解决?