当前位置:网站首页>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)
);
}
}
边栏推荐
- 搭建直播平台,使用node生成验证码图片,并进行验证
- Web APIs BOM- 操作浏览器-Window对象
- Redis是如何轻松实现系统秒杀的?
- matplotlib绘图的核心原理讲解(超详细)
- Command line startup FAQs and solutions
- 若依如何实现添加水印功能
- [c] Detailed explanation of operators (1)
- ML之PDP:基于titanic泰坦尼克是否获救二分类预测数据集利用PDP部分依赖图对RF随机森林和LightGBM模型实现可解释性案例
- I interviewed a 985 graduate, and I will never forget the expression when answering the "performance tuning" question
- 【TypeScript】深入学习TypeScript类(上)
猜你喜欢
创建型模式 - 抽象工厂模式AbstractFactory
LeetCode 2359. 找到离给定两个节点最近的节点 基环树
Add and delete all these years, finally planted in MySQL architecture design!
Command line startup FAQs and solutions
How to seize the new trend of NFT, yuan|universe|universe?
kubernetes pod podsecurityPolicies(PSP)
同样月薪6K,为什么同事跳槽月薪翻倍,而你只涨了1000?
你离「TDengine 开发者大会」只差一条 SQL 语句!
饥荒联机版Mod开发——制作简单的物品(三)
宝塔搭建实测-基于ThinkPHP5.1的wms进销存源码
随机推荐
Ruoyi integrates minio to realize distributed file storage
How many ways do you know the singleton pattern?
双轴晶体中锥形折射的建模与应用
网络运维系列:健康检查的方式
Flink-shell
在迁移测试中,源表、中间表、目标表的迁移规则
万物智联时代,悄然走入生活
学习基因富集工具DAVID(2)
【DEBUG】ImportError: Unable to import required dependencies: numpy: DLL load failed: 找不到指定的模块。
【c】操作符详解(一)
Towards a General Purpose CNN for Long Range Dependencies in ND
today‘s task
word操作:单独调整英文字体
RuoYi-App启动教程
【TypeScript】深入学习TypeScript类(下)
How to seize the new trend of NFT, yuan|universe|universe?
【STM32学习2】存储器相关概念与操作
go os 包
[Dry goods] Best practice of sub-library and sub-table
一群搞社区的人