raydium_sdk_V2/raydium/clmm/utils/
tick_array_bitmap.rs1use std::ops::{Neg, Shl, Shr};
2use carbon_raydium_clmm_decoder::accounts::tick_array_bitmap_extension::TickArrayBitmapExtension;
3use rug::Complete;
4use crate::raydium::clmm::utils::constants::{MAX_TICK, MIN_TICK};
5use crate::raydium::clmm::utils::tick::{TICK_ARRAY_BITMAP_SIZE, TICK_ARRAY_SIZE, TickUtils};
6use crate::raydium::clmm::utils::tick_query::TickQuery;
7use crate::raydium::clmm::utils::util::{is_zero, leading_zeros, least_significant_bit, most_significant_bit, trailing_zeros};
8
9pub struct TickArrayBitmap {}
10
11pub struct TickArrayBitmapExtensionUtils {}
12
13pub struct NextTickArray {
14 pub is_init: bool,
15 pub tick_index: i32,
16}
17
18pub struct GetBitmapTickBoundary {
19 min: i32,
20 max: i32,
21}
22
23impl TickArrayBitmap {
24 pub fn get_bitmap_tick_boundary(tick_array_start_index: i32, tick_spacing: u16) -> GetBitmapTickBoundary {
25 let ticks_in_one_bitmap = Self::max_tick_in_tick_array_bitmap(tick_spacing) as i32;
26 let tick_array_start_index_abs = tick_array_start_index.abs();
27 let mut m = (tick_array_start_index_abs as f32 / ticks_in_one_bitmap as f32).floor() as i32;
28 if tick_array_start_index < 0 && tick_array_start_index_abs % ticks_in_one_bitmap != 0 {
29 m += 1;
30 }
31 let min = ticks_in_one_bitmap * m;
32 if tick_array_start_index < 0 {
33 let min_neg = min.neg();
34 GetBitmapTickBoundary { min: min_neg, max: min_neg + ticks_in_one_bitmap }
35 } else {
36 GetBitmapTickBoundary { min, max: min + ticks_in_one_bitmap }
37 }
38 }
39 pub fn max_tick_in_tick_array_bitmap(tick_spacing: u16) -> u32 {
40 tick_spacing as u32 * TICK_ARRAY_SIZE as u32 * TICK_ARRAY_BITMAP_SIZE as u32
41 }
42 pub fn next_initialized_tick_array_start_index(bitmap: &rug::Integer, last_tick_array_start_index: i32, tick_spacing: u16, zero_for_one: bool) -> Result<NextTickArray, String> {
43 if !TickQuery::check_is_valid_start_index(last_tick_array_start_index, tick_spacing) {
44 return Err("nextInitializedTickArrayStartIndex check error".to_string());
45 }
46 let tick_boundary = Self::max_tick_in_tick_array_bitmap(tick_spacing) as i32;
47 let next_tick_array_start_index = if zero_for_one {
48 last_tick_array_start_index - TickQuery::tick_count(tick_spacing) as i32
49 } else {
50 last_tick_array_start_index + TickQuery::tick_count(tick_spacing) as i32
51 };
52 if next_tick_array_start_index < -tick_boundary || next_tick_array_start_index >= tick_boundary {
53 return Ok(NextTickArray { is_init: false, tick_index: last_tick_array_start_index });
54 }
55 let multiplier = (tick_spacing as usize * TICK_ARRAY_SIZE) as i32;
56 let mut compressed = next_tick_array_start_index / multiplier + 512;
57 if next_tick_array_start_index < 0 && next_tick_array_start_index % multiplier != 0 {
58 compressed -= 1;
59 }
60 let bit_pos = compressed.abs();
61 return if zero_for_one {
62 let offset_bitmap = bitmap.shl(1024 - bit_pos - 1).complete();
63 match most_significant_bit(1024, &offset_bitmap) {
64 None => {
65 Ok(NextTickArray { is_init: false, tick_index: -tick_boundary })
66 }
67 Some(next_bit) => {
68 let next_array_start_index = (bit_pos - next_bit as i32 - 512) * multiplier;
69 Ok(NextTickArray { is_init: true, tick_index: next_array_start_index })
70 }
71 }
72 } else {
73 let offset_bitmap = bitmap.shr(bit_pos).complete();
74 match least_significant_bit(1024, &offset_bitmap) {
75 None => {
76 Ok(NextTickArray { is_init: false, tick_index: tick_boundary - TickQuery::tick_count(tick_spacing) as i32 })
77 }
78 Some(next_bit) => {
79 let next_array_start_index = (bit_pos + next_bit as i32 - 512) * multiplier;
80 Ok(NextTickArray { is_init: true, tick_index: next_array_start_index })
81 }
82 }
83 }
84 }
85}
86
87pub struct CheckTickArrayIsInitResult {
88 pub is_initialized: bool,
89 pub start_index: i32,
90}
91
92pub struct GetBitmapResult {
93 offset: u32,
94 tick_array_bitmap: [u64; 8],
95}
96
97pub struct ExtensionTickBoundaryResult {
98 positive_tick_boundary: i32,
99 negative_tick_boundary: i32,
100}
101
102impl TickArrayBitmapExtensionUtils {
103 pub fn next_initialized_tick_array_in_bitmap(
104 tick_array_bitmap: [u64; 8],
105 next_tick_array_start_index: i32,
106 tick_spacing: u16,
107 zero_for_one: bool,
108 ) -> NextTickArray {
109 let bitmap_tick_boundary = TickArrayBitmap::get_bitmap_tick_boundary(next_tick_array_start_index, tick_spacing);
110 let tick_array_offset_in_bitmap = Self::tick_array_offset_in_bitmap(next_tick_array_start_index, tick_spacing);
111 if zero_for_one {
112 let offset_bitmap = TickUtils::merge_tick_array_bitmap(tick_array_bitmap.as_slice()).shl(TICK_ARRAY_BITMAP_SIZE as u32 - 1 - tick_array_offset_in_bitmap);
113 return if is_zero(512, &offset_bitmap) {
114 NextTickArray { is_init: false, tick_index: bitmap_tick_boundary.min }
115 } else {
116 let next_bit = leading_zeros(512, &offset_bitmap);
117 let next_array_start_index = next_tick_array_start_index - next_bit as i32 * TickQuery::tick_count(tick_spacing) as i32;
118 NextTickArray { is_init: true, tick_index: next_array_start_index }
119 };
120 } else {
121 let offset_bitmap = TickUtils::merge_tick_array_bitmap(tick_array_bitmap.as_slice()).shr(tick_array_offset_in_bitmap);
122 return if is_zero(512, &offset_bitmap) {
123 NextTickArray { is_init: false, tick_index: bitmap_tick_boundary.max - TickQuery::tick_count(tick_spacing) as i32 }
124 } else {
125 let next_bit = trailing_zeros(512, &offset_bitmap);
126 let next_array_start_index = next_tick_array_start_index + next_bit as i32 * TickQuery::tick_count(tick_spacing) as i32;
127 NextTickArray { is_init: true, tick_index: next_array_start_index }
128 };
129 }
130 }
131 pub fn next_initialized_tick_array_from_one_bitmap(
132 last_tick_array_start_index: i32,
133 tick_spacing: u16,
134 zero_for_one: bool,
135 tick_array_bitmap_extension: &carbon_raydium_clmm_decoder::accounts::tick_array_bitmap_extension::TickArrayBitmapExtension,
136 ) -> Result<NextTickArray, String> {
137 let multiplier = TickQuery::tick_count(tick_spacing) as i32;
138 let next_tick_array_start_index = if zero_for_one {
139 last_tick_array_start_index - multiplier as i32
140 } else {
141 last_tick_array_start_index + multiplier
142 };
143 let tick_array_bitmap = Self::get_bitmap(next_tick_array_start_index, tick_spacing, tick_array_bitmap_extension)?;
144 Ok(Self::next_initialized_tick_array_in_bitmap(tick_array_bitmap.tick_array_bitmap, next_tick_array_start_index, tick_spacing, zero_for_one))
145 }
146 pub fn extension_tick_boundary(tick_spacing: u16) -> Result<ExtensionTickBoundaryResult, String> {
147 let positive_tick_boundary = TickArrayBitmap::max_tick_in_tick_array_bitmap(tick_spacing) as i32;
148 let negative_tick_boundary = positive_tick_boundary.neg();
149 if MAX_TICK <= positive_tick_boundary {
150 return Err(format!("extensionTickBoundary check error: {MAX_TICK}, {positive_tick_boundary}"));
151 }
152 if negative_tick_boundary <= MIN_TICK {
153 return Err(format!("extensionTickBoundary check error: {negative_tick_boundary}, {MIN_TICK}"));
154 }
155 Ok(ExtensionTickBoundaryResult { positive_tick_boundary, negative_tick_boundary })
156 }
157 pub fn check_extension_boundary(tick_index: i32, tick_spacing: u16) -> Result<(), String> {
158 let extension_tick_boundary = Self::extension_tick_boundary(tick_spacing)?;
159 if tick_index >= extension_tick_boundary.negative_tick_boundary && tick_index < extension_tick_boundary.positive_tick_boundary {
160 return Err("checkExtensionBoundary -> InvalidTickArrayBoundary".to_string());
161 }
162 Ok(())
163 }
164 pub fn get_bitmap_offset(tick_index: i32, tick_spacing: u16) -> Result<u32, String> {
165 if !TickQuery::check_is_valid_start_index(tick_index, tick_spacing) {
166 return Err("No enough initialized tickArray".to_string());
167 }
168 Self::check_extension_boundary(tick_index, tick_spacing)?;
169
170 let ticks_in_one_bitmap = TickArrayBitmap::max_tick_in_tick_array_bitmap(tick_spacing);
171 let tick_index_abs = tick_index.abs() as u32;
172 let mut offset = (tick_index_abs / ticks_in_one_bitmap) - 1;
174 if tick_index < 0 && tick_index_abs % ticks_in_one_bitmap == 0 {
175 offset -= 1;
176 }
177 Ok(offset)
178 }
179 pub fn get_bitmap(tick_index: i32, tick_spacing: u16, tick_array_bitmap_extension: &TickArrayBitmapExtension) -> Result<GetBitmapResult, String> {
180 let offset = Self::get_bitmap_offset(tick_index, tick_spacing)?;
181 let tick_array_bitmap = if tick_index < 0 {
182 tick_array_bitmap_extension.negative_tick_array_bitmap[offset as usize]
183 } else {
184 tick_array_bitmap_extension.positive_tick_array_bitmap[offset as usize]
185 };
186 Ok(GetBitmapResult { offset, tick_array_bitmap })
187 }
188 pub fn check_tick_array_is_init(tick_array_start_index: i32, tick_spacing: u16, tick_array_bitmap_extension: &TickArrayBitmapExtension) -> Result<CheckTickArrayIsInitResult, String> {
189 let tick_array_bitmap = Self::get_bitmap(tick_array_start_index, tick_spacing, tick_array_bitmap_extension)?;
190 let tick_array_offset_in_bitmap = Self::tick_array_offset_in_bitmap(tick_array_start_index, tick_spacing);
191 let is_initialized = TickUtils::merge_tick_array_bitmap(&tick_array_bitmap.tick_array_bitmap).get_bit(tick_array_offset_in_bitmap);
192 Ok(CheckTickArrayIsInitResult { is_initialized, start_index: tick_array_start_index })
193 }
194 pub fn tick_array_offset_in_bitmap(tick_array_start_index: i32, tick_spacing: u16) -> u32 {
195 let m = tick_array_start_index.abs() as u32 % TickArrayBitmap::max_tick_in_tick_array_bitmap(tick_spacing);
196 let mut tick_array_offset_in_bitmap = m / TickQuery::tick_count(tick_spacing);
198 if tick_array_start_index < 0 && m != 0 {
199 tick_array_offset_in_bitmap = TICK_ARRAY_BITMAP_SIZE as u32 - tick_array_offset_in_bitmap;
200 }
201 tick_array_offset_in_bitmap
202 }
203}