剖析Defi之Uinswap_0
Uniswap是什么,不需要讲了吧。YYDS(永远嘀神)
介绍几个概念:
恒定乘积算法:可以简单看作X * Y = K,这里K(乘积)保持不变,所以叫恒定乘积算法,该函数是一个反曲线。
自动流动性协议,一般叫自动做市。在上面的公式里,X/Y的比值一般叫价格。当X发生变化时,根据乘积不变,Y也要发生变化,从而X/Y也就是价格发生了变化, 所以叫自动做市。这里可以根据X和Y的比例同时提供对应的X和Y,这种操作叫增加(提供)流动性。增加流动性后的K值虽然相比以前发生了变化,但是在随后的交易里是不变的。相应的,也有减少流动性的操作。
Uniswap的交易对是任意ERC20交易对,增加流动性(提供相应的两种ERC20币)会获得流动性代币,你也可以随时使用流动性代币赎回你的ERC20代币。增加流动性会减小交易时的价格滑点。
Uniswap采用恒定乘积自动做市,因此大额交易和小额交易相比,其执行时的比率(价格)会指数级变得更差,当然就是这样设计的。
由于套利行为的存在,Uniswap价格始终趋向于结算价。
交易时,Uniswap收取0.3%的手续费,支付给所有流动性提供者。这实质上会使恒定乘积的K变大。
uniswap核心我认为是 X*Y=K。
学习X-Y-K模型,附上链接区块链 - 深入理解Uniswap协议
整个 UniswapV2 产品拆分出了多个小型的开源项目,主要包括:
- uniswap-interface
- uniswap-v2-sdk
- uniswap-sdk-core
- uniswap-info
- uniswap-v2-subgraph
- uniswap-v2-core
- uniswap-v2-periphery
- uniswap-lib
我们主要关注uniswap_v2_core,它是uniswap的核心逻辑;
uniswap_v2_core 有3个主要文件分别是:
- UniswapV2Factory.sol:工厂合约
- UniswapV2Pair.sol:交易兑合约
- UniswapV2ERC20.sol:LPToken 合约
工厂合约是用来部署交易兑合约,调用工厂合约的createPair()创建信的交易对,
交易对合约 管理流动性资金池,UNI-WETH,USDT-WETH。
LP合约:资金池里注入流动性的一种凭证,也称为流动性代币。

UniswapFactory合约代码
1 pragma solidity =0.5.16;
2
3 import './interfaces/IUniswapV2Factory.sol';
4 import './UniswapV2Pair.sol';
5
6 contract UniswapV2Factory is IUniswapV2Factory {
7 address public feeTo;
8 address public feeToSetter;
9
10 mapping(address => mapping(address => address)) public getPair;
11 address[] public allPairs;
12
13 event PairCreated(address indexed token0, address indexed token1, address pair, uint);
14
15 constructor(address _feeToSetter) public {
16 feeToSetter = _feeToSetter;
17 }
18
19 function allPairsLength() external view returns (uint) {
20 return allPairs.length;
21 }
22
23 function createPair(address tokenA, address tokenB) external returns (address pair) {
24 require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES');
25 (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
26 require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS');
27 require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // single check is sufficient
28 bytes memory bytecode = type(UniswapV2Pair).creationCode;
29 bytes32 salt = keccak256(abi.encodePacked(token0, token1));
30 assembly {
31 pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
32 }
33 IUniswapV2Pair(pair).initialize(token0, token1);
34 getPair[token0][token1] = pair;
35 getPair[token1][token0] = pair; // populate mapping in the reverse direction
36 allPairs.push(pair);
37 emit PairCreated(token0, token1, pair, allPairs.length);
38 }
39
40 function setFeeTo(address _feeTo) external {
41 require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
42 feeTo = _feeTo;
43 }
44
45 function setFeeToSetter(address _feeToSetter) external {
46 require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
47 feeToSetter = _feeToSetter;
48 }
49 }
1. 第一行:规定了Solidity编译器的版本,还可以用pragma solidity >=0.5.16,^0.5.16;
2. 第三至第四行则是导入工厂合约所需的接口合约
3. 第六行开始步入正题,继承导入的合约
4 .feeTo 定义了地址类型的状态变量,作用是是否开启手续费,在V2中,当用户交易代币时,会收取0.3%的手续费分给提供流动性的人,当feeTo为零地址(默认值)关闭手续费,反之则收取手续费。
5. feeToSetter记录设置feeto的设置者
6.mapping 映射和py的字典相似,三个address,前两个是交易对相关的币地址,最后一个是交易对本身地址
7 allPairs 记录所有交易对地址,mapping无法遍历。
8. 事件 PairCreated,创建交易对时触发事件,参数有indexed,可以过滤筛选
9. 构造函数,参数_feeToSetter 赋值给feeToSetter,前面提到这是记录feeTo的设置者地址。
10 .函数allPairsLength 返回所有交易对长度 修饰符external,外部调用
11,creatPair是factory的最重要函数,作用是创建交易对。接受2个address参数(任意代币地址),external 意味着合约外都可以直接调用,返回值是 交易对地址
1 function createPair(address tokenA, address tokenB) external returns (address pair) {
2 require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES');
3 (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
4 require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS');
5 require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // single check is sufficient
6 bytes memory bytecode = type(UniswapV2Pair).creationCode;
7 bytes32 salt = keccak256(abi.encodePacked(token0, token1));
8 assembly {
9 pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
10 }
11 IUniswapV2Pair(pair).initialize(token0, token1);
12 getPair[token0][token1] = pair;
13 getPair[token1][token0] = pair; // populate mapping in the reverse direction
14 allPairs.push(pair);
15 emit PairCreated(token0, token1, pair, allPairs.length);
16 }
第一行验证两种代币地址不能相同。
第二行:由于address是uint160可以比较大小,这里是把代币地址排序(从小到大)
第三行 验证 token0不是零地址,由于token1比token0大,所以只验证了一次。
第四行 验证交易对未创建。
创建新合约 还可以使用
UniswapV2Pair newPair = new UniswapV2Pair();
使用 create2 最大的好处其实在于:可以在部署智能合约前预先计算出合约的部署地址
第六行: 获取模板合约UinswapV2Pair合约代码的的创建字节码(creationCode) 返回结果是bytes 的数组,
第七行:abi.encodePacked(对给定的参数进行打包编码,注参数为变量),keccak256 计算哈希。这里的意思是用两个代币地址作为参数 生成一个固定值salt。
第八行: assembly 内联汇编的标志,create2 有四个参数v:发送eth的数量单位wei;p:代码的起始内存地址,
n:代码长度(mload获取长度)s:salt前面计算的哈希
第十一行:调用新创建的交易对合约的初始方法,参数是排序后的两个代币地址。
第十二-十三行:token:0,1/1,0是同一个地址,用户提交的代地址数是未排序,所以添加两次。
第十四行:allpair数组添加新生成的交易对地址。
第十五行:触发交易对创建事件
12:设置新的feeto。切换接受手续费地址
1 function setFeeTo(address _feeTo) external {
2 require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
3 feeTo = _feeTo;
4 }
通过require 验证函数调用者必须是 feeTo的设置者。
13:转让feeToSetter
1 function setFeeToSetter(address _feeToSetter) external {
2 require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
3 feeToSetter = _feeToSetter;
4 }
通过require 验证函数调用者必须是 feeTo的设置者。
以上就是uniswap的工厂合约。通过解读的Zero_Nothing文章
剖析Defi之Uinswap_0的更多相关文章
- 剖析Defi之Uinswap_2
学习核心合约UniswapV2Pair,在父合约UniswapV2ERC20的基础上增加资产交易及流动性提供等功能. 交易对合约本身是erc20合约,代币表示流动性,代币在提供流动性的地址里,当提供流 ...
- 剖析Defi之Uinswap_1
学习UniswapERC20,它是交易对的父合约.UniswapV2ERC20 是流动性代币合约,也称为 LP Token.功能主要实习ERC20代币功能以及对线下签名授权. 1 pragma sol ...
- 探索C#之6.0语法糖剖析
阅读目录: 自动属性默认初始化 自动只读属性默认初始化 表达式为主体的函数 表达式为主体的属性(赋值) 静态类导入 Null条件运算符 字符串格式化 索引初始化 异常过滤器when catch和fin ...
- jQuery之Deferred源码剖析
一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...
- [C#] 剖析 AssemblyInfo.cs - 了解常用的特性 Attribute
剖析 AssemblyInfo.cs - 了解常用的特性 Attribute [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5944391.html 序 ...
- Membership三步曲之进阶篇 - 深入剖析Provider Model
Membership 三步曲之进阶篇 - 深入剖析Provider Model 本文的目标是让每一个人都知道Provider Model 是什么,并且能灵活的在自己的项目中使用它. Membershi ...
- 《AngularJS深度剖析与最佳实践》简介
由于年末将至,前阵子一直忙于工作的事务,不得已暂停了微信订阅号的更新,我将会在后续的时间里尽快的继续为大家推送更多的博文.毕竟一个人的力量微薄,精力有限,希望大家能理解,仍然能一如既往的关注和支持sh ...
- 探索c#之Async、Await剖析
阅读目录: 基本介绍 基本原理剖析 内部实现剖析 重点注意的地方 总结 基本介绍 Async.Await是net4.x新增的异步编程方式,其目的是为了简化异步程序编写,和之前APM方式简单对比如下. ...
- ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程
从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...
随机推荐
- flink---实时项目--day02-----1. 解析参数工具类 2. Flink工具类封装 3. 日志采集架构图 4. 测流输出 5. 将kafka中数据写入HDFS 6 KafkaProducer的使用 7 练习
1. 解析参数工具类(ParameterTool) 该类提供了从不同数据源读取和解析程序参数的简单实用方法,其解析args时,只能支持单只参数. 用来解析main方法传入参数的工具类 public c ...
- ABA 问题
CAS 导致 ABA 问题CAS 算法实现了一个重要的前提,需要取出内存中某时刻的数据,并在当下时刻比较并替换,那么这个时间差会导致数据的变化. 比如说一个线程 one 从内存位置 V 中取出A,这时 ...
- CSS系列,三栏布局的四种方法
三栏布局.两栏布局都是我们在平时项目里经常使用的,今天我们来玩一下三栏布局的四种写法,以及它的使用场景. 所谓三栏布局就是指页面分为左中右三部分然后对中间一部分做自适应的一种布局方式. 1.绝对定位法 ...
- E面波导和H面波导的问题
我感觉与窄壁平行是E面,反之为H面.通常E面(窄面)是指与电场方向平行的方向图切面(窄面):H面(宽面)是指与磁场方向平行的方向图切面(宽面).E面的意思是... ElevationH面的意思是... ...
- Android实现网络监听
一.Android Wifi常用广播 网络开发中主体会使用到的action: ConnectivityManager.CONNECTIVITY_ACTION WifiManager.WIFI_STAT ...
- IDEA 超实用使用技巧分享
前言 工欲善其事 必先利其器 最近受部门的邀请,给入职新人统一培训IDEA,发现有很多新人虽然日常开发使用的是IDEA,但是还是很多好用的技巧没有用到,只是用到一些基本的功能,蛮浪费IDEA这个优 ...
- tomcat 之 session 集群
官网地址 https://tomcat.apache.org/tomcat-8.5-doc/cluster-howto.html #:配置各tomcat节点 [root@node1 ~]# vim / ...
- Servlet(1):Servlet介绍
一. Servlet介绍 Servlet 是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生 ...
- Thymeleaf+layui+jquery复选框回显
一.Thymeleaf+layui+jquery复选框回显 基于Thymeleaf模板下的layui+jquery复选框回显,主要是jquery.大致意思是:把数组转成JSON传到前台,再在前台转回数 ...
- 【Java基础】transient关键字
1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过 ...