uniswap v3 中的tick管理

2024-02-02 08:20
文章标签 管理 uniswap v3 tick

本文主要是介绍uniswap v3 中的tick管理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先看一下tick的存储结构

struct Info {// 所有引用这个tick的position的流动性总和uint128 liquidityGross;//当tick被从左到右(从右到左)穿过时,流动性应该增加或减少的数值int128 liquidityNet;。。。}

其他字段和本节无关暂且略过。

比方说有两个 position 中的流动性相等,例如 L = 500,并且这两个 position 同时引用了一个 tick,其中一个为 lower tick ,另一个为 upper tick,那么对于这个 tick,它的 liquidityNet = +500-500=0。而liquidityGross=500+500=1000

当价格变动导致 tickcurrent 越过一个 position 的 lower/upper tick 时,我们需要根据 tick 中记录的值来更新当前价格所对应的总体流动性。假设 position 的流动性值为 ΔL,会有以下四种情况:

价格上涨,从左到右穿过一个 lower tick:liquidityNet = liquidityNet + ΔL;

价格上涨,从左到右穿过一个 upper tick:liquidityNet = liquidityNet - ΔL;

价格下降,从右到左穿过一个 upper tick:liquidityNet = liquidityNet + ΔL;

价格下降,从右到左穿过一个 lower tick:liquidityNet = liquidityNet - ΔL;

tick状态存储

uniswap v3 版本对价格的计算为了减少开根号的的计算成本直接存储的是,并且使用Q64.94精度的定点数来保存。首先解释下这个Q64.94代表什么意思。

Q (number format)是一种指定二进制定点数的格式的方法。例如Q8.8表示的数字格式意味着这种格式中的定点数字整数部分有8位,小数数部分有8位。对于Q64.94而言,其代表的数值范围是0 至

也就是说

对应的

于是得出tickMax = 887272 为了做对应 tickMin = -887272

这就意味着v3版本的智能合约需要管理887272*2个tick,达到了百万级,这个数量是不小的。

而实际上这么多的tick其中绝大部分是没有必要初始化的。合约代码中对这些tick做了二级管理。

mapping(int16 => uint256) public override tickBitmap;

    function position(int24 tick) private pure returns (int16 wordPos, uint8 bitPos) {wordPos = int16(tick >> 8);bitPos = uint8(tick % 256);}

887272*2个tick合约中用int24来表示;int16(tick >> 8)代表取高16位,uint8(tick % 256)代表取低8位,在tickBitmap中高16位作为key,那么为什么用uint256作为value呢?剩下的低8位是2的8次方一共256个数。也就是说tickBitmap每一条记录需要管理256个tick状态,最高效的方法就是使用位图,把256个数转换成256个二进制数表示,也就是uint256,相应的位上为1代表当前的tick被引用。

tick转换为价格

我们知道,公式很简单,但是当我们要计算价格P的时候入股直接带入tick这个计算量是非常庞大的,比如tick=887272。uniswap在这能合约中的计算代码如下:

function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));require(absTick <= uint256(MAX_TICK), 'T');uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;if (tick > 0) ratio = type(uint256).max / ratio;// this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.// we then downcast because we know the result always fits within 160 bits due to our tick input constraint// we round up in the division so getTickAtSqrtRatio of the output price is always consistentsqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));}

乍一看很懵,先了解一下背后的算法。

首先tick的取值范围是i属于[-887272,887272],而任何正整数都可以表示为如下形式:

随便举个例子,比如

那么[1,887272]范围内的数表示如下

上面代码中的0x1,0x2,0x4...一直到0x80000就是一直到的16进制表示

还是拿tick=25举例:

根据上面的公式推导

如果从我们都事先计算好的话,即便是也能将步骤简化成有限的几个数字相乘,很好的控制了计算量,这样的话下面这行代码就很好理解了。

if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128

ratio的初始值为1,如果tick的绝对值进行分解后,包含,那么

实际上在代码层面在上面的算法基础上还做了一层优化:

当i为正数时,其计算结果有可能很大,中间涉及到的乘法运算可能会造成溢出,所以实际计算的是i为负数时的值,因为当i为负数时,是一个小于1的小数,所以不会产生溢出,即上面代码中的那些魔数应当是,,.....。每一次计算要右移128位,只取高128位的数。

if (tick > 0) ratio = type(uint256).max / ratio;

最后这行代码的意思是,如果tick为正数,需要把计算的结果求导,即,再用转换为Q128.128格式,1<<256用type(uint256).max代替

sqrtPriceX96 =uint160((ratio >>32)+(ratio %(1<<32)==0?0:1));

分开两部分:

(ratio >>32)代表省略小数的后32位,

(ratio %(1<<32)==0?0:1)倒数第32位小数四舍五入。

总的来说就是把Q128.128 转换为 Q128.96.

未完待续。。。

这篇关于uniswap v3 中的tick管理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/670068

相关文章

SpringBoot中使用 ThreadLocal 进行多线程上下文管理及注意事项小结

《SpringBoot中使用ThreadLocal进行多线程上下文管理及注意事项小结》本文详细介绍了ThreadLocal的原理、使用场景和示例代码,并在SpringBoot中使用ThreadLo... 目录前言技术积累1.什么是 ThreadLocal2. ThreadLocal 的原理2.1 线程隔离2

Linux内存泄露的原因排查和解决方案(内存管理方法)

《Linux内存泄露的原因排查和解决方案(内存管理方法)》文章主要介绍了运维团队在Linux处理LB服务内存暴涨、内存报警问题的过程,从发现问题、排查原因到制定解决方案,并从中学习了Linux内存管理... 目录一、问题二、排查过程三、解决方案四、内存管理方法1)linux内存寻址2)Linux分页机制3)

高效管理你的Linux系统: Debian操作系统常用命令指南

《高效管理你的Linux系统:Debian操作系统常用命令指南》在Debian操作系统中,了解和掌握常用命令对于提高工作效率和系统管理至关重要,本文将详细介绍Debian的常用命令,帮助读者更好地使... Debian是一个流行的linux发行版,它以其稳定性、强大的软件包管理和丰富的社区资源而闻名。在使用

SpringBoot使用minio进行文件管理的流程步骤

《SpringBoot使用minio进行文件管理的流程步骤》MinIO是一个高性能的对象存储系统,兼容AmazonS3API,该软件设计用于处理非结构化数据,如图片、视频、日志文件以及备份数据等,本文... 目录一、拉取minio镜像二、创建配置文件和上传文件的目录三、启动容器四、浏览器登录 minio五、

IDEA中的Kafka管理神器详解

《IDEA中的Kafka管理神器详解》这款基于IDEA插件实现的Kafka管理工具,能够在本地IDE环境中直接运行,简化了设置流程,为开发者提供了更加紧密集成、高效且直观的Kafka操作体验... 目录免安装:IDEA中的Kafka管理神器!简介安装必要的插件创建 Kafka 连接第一步:创建连接第二步:选

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

安全管理体系化的智慧油站开源了。

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界面上进行简单的操作,就可以实现全视频的接入及布控。摄像头管理模块用于多种终端设备、智能设备的接入及管理。平台支持包括摄像头等终端感知设备接入,为整个平台提

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Sentinel 高可用流量管理框架

Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。 Sentinel 具有以下特性: 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应