├── .gitignore
├── README.md
└── clmm
├── Move.lock
├── Move.toml
└── sources
├── acl.move
├── fee.move
├── lib
├── full_math_u128.move
├── full_math_u32.move
├── full_math_u64.move
├── i128.move
├── i32.move
├── i64.move
├── math_bit.move
├── math_liquidity.move
├── math_sqrt_price.move
├── math_swap.move
├── math_tick.move
├── math_u128.move
├── math_u256.move
├── math_u64.move
└── string_tools.move
├── partner.move
├── pool.move
├── pool_factory.move
├── pool_fetcher.move
├── position_manager.move
├── position_nft.move
└── swap_router.move
/.gitignore:
--------------------------------------------------------------------------------
1 | # Generated by Cargo
2 | # will have compiled files and executables
3 | /target/
4 |
5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
7 | Cargo.lock
8 |
9 | # These are backup files generated by rustfmt
10 | **/*.rs.bk
11 | build/
12 |
13 | *.log.*
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # turbos-sui-move-interface
2 | [Read Document](https://turbos.gitbook.io/turbos/developer-docs/via-contract/get-started)
3 |
4 | [Move Registry](https://www.moveregistry.com/package/@turbos/turbos?tab=versions)
5 |
6 | [Latest Published](https://turbos.gitbook.io/turbos/developer-docs/dev-overview)
--------------------------------------------------------------------------------
/clmm/Move.lock:
--------------------------------------------------------------------------------
1 | # @generated by Move, please check-in and do not edit manually.
2 |
3 | [move]
4 | version = 3
5 |
6 | dependencies = [
7 | { id = "Sui", name = "Sui" },
8 | ]
9 | manifest_digest = "386A589C486EB44CF6E5886FD934E758640ECBDF4BE539E10D1F1921C6752D0B"
10 | deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082"
11 |
12 | [[move.package]]
13 | id = "MoveStdlib"
14 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet", subdir = "crates/sui-framework/packages/move-stdlib" }
15 |
16 | [[move.package]]
17 | id = "Sui"
18 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "testnet", subdir = "crates/sui-framework/packages/sui-framework" }
19 |
20 | dependencies = [
21 | { id = "MoveStdlib", name = "MoveStdlib" },
22 | ]
23 |
24 | [move.toolchain-version]
25 | compiler-version = "1.55.0"
26 | edition = "2024"
27 | flavor = "sui"
28 |
--------------------------------------------------------------------------------
/clmm/Move.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "TurbosCLMM"
3 | version = "0.1.8"
4 | published-at = "0xa5a0c25c79e428eba04fb98b3fb2a34db45ab26d4c8faf0d7e39d66a63891e64"
5 |
6 | [dependencies]
7 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir="crates/sui-framework/packages/sui-framework", rev = "testnet", override = true }
8 |
9 | [addresses]
10 | turbos_clmm = "0x91bfbc386a41afcfd9b2533058d7e915a1d3829089cc268ff4333d54d6339ca1"
--------------------------------------------------------------------------------
/clmm/sources/acl.move:
--------------------------------------------------------------------------------
1 | module turbos_clmm::acl {
2 |
3 | use sui::linked_table::{LinkedTable};
4 | use sui::object::{UID};
5 |
6 | struct ACL has key, store {
7 | id: UID,
8 | permissions: LinkedTable
,
9 | }
10 |
11 | struct Member has store, drop, copy {
12 | address: address,
13 | permission: u128,
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/clmm/sources/fee.move:
--------------------------------------------------------------------------------
1 | // Copyright (c) Turbos Finance, Inc.
2 | // SPDX-License-Identifier: MIT
3 |
4 | module turbos_clmm::fee {
5 |
6 | use sui::object::{Self, UID};
7 | use sui::tx_context::{TxContext};
8 |
9 | struct Fee has key, store {
10 | id: UID,
11 | fee: u32,
12 | tick_spacing: u32,
13 | }
14 |
15 | public fun get_fee(_self: &Fee): u32 {
16 | abort 0
17 | }
18 |
19 | public fun get_tick_spacing(_self: &Fee): u32 {
20 | abort 0
21 | }
22 | }
--------------------------------------------------------------------------------
/clmm/sources/lib/full_math_u128.move:
--------------------------------------------------------------------------------
1 | module turbos_clmm::full_math_u128 {
2 | public fun mul_div_floor(num1: u128, num2: u128, denom: u128): u128 {
3 | let r = full_mul(num1, num2) / (denom as u256);
4 | (r as u128)
5 | }
6 |
7 | public fun mul_div_round(num1: u128, num2: u128, denom: u128): u128 {
8 | let r = (full_mul(num1, num2) + ((denom as u256) >> 1)) / (denom as u256);
9 | (r as u128)
10 | }
11 |
12 | public fun mul_div_ceil(num1: u128, num2: u128, denom: u128): u128 {
13 | let r = (full_mul(num1, num2) + ((denom as u256) - 1)) / (denom as u256);
14 | (r as u128)
15 | }
16 |
17 | public fun mul_shr(num1: u128, num2: u128, shift: u8): u128 {
18 | let product = full_mul(num1, num2) >> shift;
19 | (product as u128)
20 | }
21 |
22 | public fun mul_shl(num1: u128, num2: u128, shift: u8): u128 {
23 | let product = full_mul(num1, num2) << shift;
24 | (product as u128)
25 | }
26 |
27 | public fun full_mul(num1: u128, num2: u128): u256 {
28 | (num1 as u256) * (num2 as u256)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/clmm/sources/lib/full_math_u32.move:
--------------------------------------------------------------------------------
1 | module turbos_clmm::full_math_u32 {
2 | public fun mul_div_floor(num1: u32, num2: u32, denom: u32): u32 {
3 | let r = full_mul(num1, num2) / (denom as u64);
4 | (r as u32)
5 | }
6 |
7 | public fun mul_div_round(num1: u32, num2: u32, denom: u32): u32 {
8 | let r = (full_mul(num1, num2) + ((denom as u64) >> 1)) / (denom as u64);
9 | (r as u32)
10 | }
11 |
12 | public fun mul_div_ceil(num1: u32, num2: u32, denom: u32): u32 {
13 | let r = (full_mul(num1, num2) + ((denom as u64) - 1)) / (denom as u64);
14 | (r as u32)
15 | }
16 |
17 | public fun mul_shr(num1: u32, num2: u32, shift: u8): u32 {
18 | let r = full_mul(num1, num2) >> shift;
19 | (r as u32)
20 | }
21 |
22 | public fun mul_shl(num1: u32, num2: u32, shift: u8): u32 {
23 | let r = full_mul(num1, num2) << shift;
24 | (r as u32)
25 | }
26 |
27 | public fun full_mul(num1: u32, num2: u32): u64 {
28 | ((num1 as u64) * (num2 as u64))
29 | }
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/clmm/sources/lib/full_math_u64.move:
--------------------------------------------------------------------------------
1 | module turbos_clmm::full_math_u64 {
2 | public fun mul_div_floor(num1: u64, num2: u64, denom: u64): u64 {
3 | let r = full_mul(num1, num2) / (denom as u128);
4 | (r as u64)
5 | }
6 |
7 | public fun mul_div_round(num1: u64, num2: u64, denom: u64): u64 {
8 | let r = (full_mul(num1, num2) + ((denom as u128) >> 1)) / (denom as u128);
9 | (r as u64)
10 | }
11 |
12 | public fun mul_div_ceil(num1: u64, num2: u64, denom: u64): u64 {
13 | let r = (full_mul(num1, num2) + ((denom as u128) - 1)) / (denom as u128);
14 | (r as u64)
15 | }
16 |
17 | public fun mul_shr(num1: u64, num2: u64, shift: u8): u64 {
18 | let r = full_mul(num1, num2) >> shift;
19 | (r as u64)
20 | }
21 |
22 | public fun mul_shl(num1: u64, num2: u64, shift: u8): u64 {
23 | let r = full_mul(num1, num2) << shift;
24 | (r as u64)
25 | }
26 |
27 | public fun full_mul(num1: u64, num2: u64): u128 {
28 | ((num1 as u128) * (num2 as u128))
29 | }
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/clmm/sources/lib/i128.move:
--------------------------------------------------------------------------------
1 | module turbos_clmm::i128 {
2 | use turbos_clmm::i64;
3 | use turbos_clmm::i32;
4 |
5 | const EOverflow: u64 = 0;
6 |
7 | const MIN_AS_U128: u128 = 1 << 127;
8 | const MAX_AS_U128: u128 = 0x7fffffffffffffffffffffffffffffff;
9 |
10 | const LT: u8 = 0;
11 | const EQ: u8 = 1;
12 | const GT: u8 = 2;
13 |
14 | struct I128 has copy, drop, store {
15 | bits: u128
16 | }
17 |
18 | public fun zero(): I128 {
19 | I128 {
20 | bits: 0
21 | }
22 | }
23 |
24 | public fun from(v: u128): I128 {
25 | assert!(v <= MAX_AS_U128, EOverflow);
26 | I128 {
27 | bits: v
28 | }
29 | }
30 |
31 | public fun neg_from(v: u128): I128 {
32 | assert!(v <= MIN_AS_U128, EOverflow);
33 | if (v == 0) {
34 | I128 {
35 | bits: v
36 | }
37 | } else {
38 | I128 {
39 | bits: (u128_neg(v) + 1) | (1 << 127)
40 | }
41 | }
42 | }
43 |
44 | public fun neg(v: I128): I128 {
45 | if (is_neg(v)) {
46 | abs(v)
47 | } else {
48 | neg_from(v.bits)
49 | }
50 | }
51 |
52 | public fun wrapping_add(num1: I128, num2:I128): I128 {
53 | let sum = num1.bits ^ num2.bits;
54 | let carry = (num1.bits & num2.bits) << 1;
55 | while (carry != 0) {
56 | let a = sum;
57 | let b = carry;
58 | sum = a ^ b;
59 | carry = (a & b) << 1;
60 | };
61 | I128 {
62 | bits: sum
63 | }
64 | }
65 |
66 | public fun add(num1: I128, num2: I128): I128 {
67 | let sum = wrapping_add(num1, num2);
68 | let overflow = (sign(num1) & sign(num2) & u8_neg(sign(sum))) + (u8_neg(sign(num1)) & u8_neg(sign(num2)) & sign(sum));
69 | assert!(overflow == 0, EOverflow);
70 | sum
71 | }
72 |
73 | public fun overflowing_add(num1: I128, num2: I128): (I128, bool) {
74 | let sum = wrapping_add(num1, num2);
75 | let overflow = (sign(num1) & sign(num2) & u8_neg(sign(sum))) + (u8_neg(sign(num1)) & u8_neg(sign(num2)) & sign(sum));
76 | (sum, overflow != 0)
77 | }
78 |
79 | public fun wrapping_sub(num1: I128, num2: I128): I128 {
80 | let sub_num = wrapping_add(I128 {
81 | bits: u128_neg(num2.bits)
82 | }, from(1));
83 | wrapping_add(num1, sub_num)
84 | }
85 |
86 | public fun sub(num1: I128, num2: I128): I128 {
87 | let sub_num = wrapping_add(I128 {
88 | bits: u128_neg(num2.bits)
89 | }, from(1));
90 | add(num1, sub_num)
91 | }
92 |
93 | public fun overflowing_sub(num1: I128, num2: I128): (I128, bool) {
94 | let sub_num = wrapping_add(I128 {
95 | bits: u128_neg(num2.bits)
96 | }, from(1));
97 | let sum = wrapping_add(num1, sub_num);
98 | let overflow = (sign(num1) & sign(sub_num) & u8_neg(sign(sum))) + (u8_neg(sign(num1)) & u8_neg(sign(sub_num)) & sign(sum));
99 | (sum, overflow != 0)
100 | }
101 |
102 | public fun mul(num1: I128, num2: I128): I128 {
103 | let product = abs_u128(num1) * abs_u128(num2);
104 | if (sign(num1) != sign(num2)) {
105 | return neg_from(product)
106 | };
107 | return from(product)
108 | }
109 |
110 | public fun div(num1: I128, num2: I128): I128 {
111 | let result = abs_u128(num1) / abs_u128(num2);
112 | if (sign(num1) != sign(num2)) {
113 | return neg_from(result)
114 | };
115 | return from(result)
116 | }
117 |
118 | public fun abs(v: I128): I128 {
119 | if (sign(v) == 0) {
120 | v
121 | } else {
122 | assert!(v.bits > MIN_AS_U128, EOverflow);
123 | I128 {
124 | bits: u128_neg(v.bits - 1)
125 | }
126 | }
127 | }
128 |
129 | public fun abs_u128(v: I128): u128 {
130 | if (sign(v) == 0) {
131 | v.bits
132 | } else {
133 | u128_neg(v.bits - 1)
134 | }
135 | }
136 |
137 | public fun shl(v: I128, shift: u8): I128 {
138 | I128 {
139 | bits: v.bits << shift
140 | }
141 | }
142 |
143 | public fun shr(v: I128, shift: u8): I128 {
144 | if (shift == 0) {
145 | return v
146 | };
147 | let mask = 0xffffffffffffffffffffffffffffffff << (128 - shift);
148 | if (sign(v) == 1) {
149 | return I128 {
150 | bits: (v.bits >> shift) | mask
151 | }
152 | };
153 | I128 {
154 | bits: v.bits >> shift
155 | }
156 | }
157 |
158 | public fun as_u128(v: I128): u128 {
159 | v.bits
160 | }
161 |
162 | public fun as_i64(v: I128): i64::I64 {
163 | if (is_neg(v)) {
164 | return i64::neg_from((abs_u128(v) as u64))
165 | } else {
166 | return i64::from((abs_u128(v) as u64))
167 | }
168 | }
169 |
170 | public fun as_i32(v: I128): i32::I32 {
171 | if (is_neg(v)) {
172 | return i32::neg_from((abs_u128(v) as u32))
173 | } else {
174 | return i32::from((abs_u128(v) as u32))
175 | }
176 | }
177 |
178 | public fun sign(v: I128): u8 {
179 | ((v.bits >> 127) as u8)
180 | }
181 |
182 | public fun is_neg(v: I128): bool {
183 | sign(v) == 1
184 | }
185 |
186 | public fun cmp(num1: I128, num2: I128): u8 {
187 | if (num1.bits == num2.bits) return EQ;
188 | if (sign(num1) > sign(num2)) return LT;
189 | if (sign(num1) < sign(num2)) return GT;
190 | if (sign(num1) == 0) {
191 | if (num1.bits > num2.bits) {
192 | return GT
193 | } else {
194 | return LT
195 | }
196 | } else {
197 | if (num1.bits < num2.bits) {
198 | return LT
199 | } else {
200 | return GT
201 | }
202 | }
203 | }
204 |
205 | public fun eq(num1: I128, num2: I128): bool {
206 | num1.bits == num2.bits
207 | }
208 |
209 | public fun gt(num1: I128, num2: I128): bool {
210 | cmp(num1, num2) == GT
211 | }
212 |
213 | public fun gte(num1: I128, num2: I128): bool {
214 | cmp(num1, num2) >= EQ
215 | }
216 |
217 | public fun lt(num1: I128, num2: I128): bool {
218 | cmp(num1, num2) == LT
219 | }
220 |
221 | public fun lte(num1: I128, num2: I128): bool {
222 | cmp(num1, num2) <= EQ
223 | }
224 |
225 | public fun or(num1: I128, num2: I128): I128 {
226 | I128 {
227 | bits: (num1.bits | num2.bits)
228 | }
229 | }
230 |
231 | public fun and(num1: I128, num2: I128): I128 {
232 | I128 {
233 | bits: (num1.bits & num2.bits)
234 | }
235 | }
236 |
237 | fun u128_neg(v :u128) : u128 {
238 | v ^ 0xffffffffffffffffffffffffffffffff
239 | }
240 |
241 | fun u8_neg(v: u8): u8 {
242 | v ^ 0xff
243 | }
244 |
245 | #[test]
246 | fun test_from_ok() {
247 | assert!(as_u128(from(0)) == 0, 0);
248 | assert!(as_u128(from(10)) == 10, 1);
249 | }
250 |
251 | #[test]
252 | #[expected_failure]
253 | fun test_from_overflow() {
254 | as_u128(from(MIN_AS_U128));
255 | as_u128(from(0xffffffffffffffffffffffffffffffff));
256 | }
257 |
258 | #[test]
259 | fun test_neg_from() {
260 | assert!(as_u128(neg_from(0)) == 0, 0);
261 | assert!(as_u128(neg_from(1)) == 0xffffffffffffffffffffffffffffffff, 1);
262 | assert!(as_u128(neg_from(0x7fffffffffffffffffffffffffffffff)) == 0x80000000000000000000000000000001, 2);
263 | assert!(as_u128(neg_from(MIN_AS_U128)) == MIN_AS_U128, 2);
264 | }
265 |
266 | #[test]
267 | #[expected_failure]
268 | fun test_neg_from_overflow() {
269 | neg_from(0x80000000000000000000000000000001);
270 | }
271 |
272 | #[test]
273 | fun test_abs() {
274 | assert!(as_u128(from(10)) == 10u128, 0);
275 | assert!(as_u128(abs(neg_from(10))) == 10u128, 1);
276 | assert!(as_u128(abs(neg_from(0))) == 0u128, 2);
277 | assert!(as_u128(abs(neg_from(0x7fffffffffffffffffffffffffffffff))) == 0x7fffffffffffffffffffffffffffffff, 3);
278 | assert!(as_u128(neg_from(MIN_AS_U128)) == MIN_AS_U128, 4);
279 | }
280 |
281 | #[test]
282 | #[expected_failure]
283 | fun test_abs_overflow() {
284 | abs(neg_from(1<<127));
285 | }
286 |
287 | #[test]
288 | fun test_wrapping_add() {
289 | assert!(as_u128(wrapping_add(from(0), from(1))) == 1, 0);
290 | assert!(as_u128(wrapping_add(from(1), from(0))) == 1, 0);
291 | assert!(as_u128(wrapping_add(from(10000), from(99999))) == 109999, 0);
292 | assert!(as_u128(wrapping_add(from(99999), from(10000))) == 109999, 0);
293 | assert!(as_u128(wrapping_add(from(MAX_AS_U128-1), from(1))) == MAX_AS_U128, 0);
294 | assert!(as_u128(wrapping_add(from(0), from(0))) == 0, 0);
295 |
296 | assert!(as_u128(wrapping_add(neg_from(0), neg_from(0))) == 0, 1);
297 | assert!(as_u128(wrapping_add(neg_from(1), neg_from(0))) == 0xffffffffffffffffffffffffffffffff, 1);
298 | assert!(as_u128(wrapping_add(neg_from(0), neg_from(1))) == 0xffffffffffffffffffffffffffffffff, 1);
299 | assert!(as_u128(wrapping_add(neg_from(10000), neg_from(99999))) == 0xfffffffffffffffffffffffffffe5251, 1);
300 | assert!(as_u128(wrapping_add(neg_from(99999), neg_from(10000))) == 0xfffffffffffffffffffffffffffe5251, 1);
301 | assert!(as_u128(wrapping_add(neg_from(MIN_AS_U128-1), neg_from(1))) == MIN_AS_U128, 1);
302 |
303 | assert!(as_u128(wrapping_add(from(0), neg_from(0))) == 0, 2);
304 | assert!(as_u128(wrapping_add(neg_from(0), from(0))) == 0, 2);
305 | assert!(as_u128(wrapping_add(neg_from(1), from(1))) == 0, 2);
306 | assert!(as_u128(wrapping_add(from(1), neg_from(1))) == 0, 2);
307 | assert!(as_u128(wrapping_add(from(10000), neg_from(99999))) == 0xfffffffffffffffffffffffffffea071, 2);
308 | assert!(as_u128(wrapping_add(from(99999), neg_from(10000))) == 89999, 2);
309 | assert!(as_u128(wrapping_add(neg_from(MIN_AS_U128), from(1))) == 0x80000000000000000000000000000001, 2);
310 | assert!(as_u128(wrapping_add(from(MAX_AS_U128), neg_from(1))) == MAX_AS_U128 - 1, 2);
311 |
312 | assert!(as_u128(wrapping_add(from(MAX_AS_U128), from(1))) == MIN_AS_U128, 2);
313 | }
314 |
315 | #[test]
316 | fun test_add() {
317 | assert!(as_u128(add(from(0), from(0))) == 0, 0);
318 | assert!(as_u128(add(from(0), from(1))) == 1, 0);
319 | assert!(as_u128(add(from(1), from(0))) == 1, 0);
320 | assert!(as_u128(add(from(10000), from(99999))) == 109999, 0);
321 | assert!(as_u128(add(from(99999), from(10000))) == 109999, 0);
322 | assert!(as_u128(add(from(MAX_AS_U128-1), from(1))) == MAX_AS_U128, 0);
323 |
324 | assert!(as_u128(add(neg_from(0), neg_from(0))) == 0, 1);
325 | assert!(as_u128(add(neg_from(1), neg_from(0))) == 0xffffffffffffffffffffffffffffffff, 1);
326 | assert!(as_u128(add(neg_from(0), neg_from(1))) == 0xffffffffffffffffffffffffffffffff, 1);
327 | assert!(as_u128(add(neg_from(10000), neg_from(99999))) == 0xfffffffffffffffffffffffffffe5251, 1);
328 | assert!(as_u128(add(neg_from(99999), neg_from(10000))) == 0xfffffffffffffffffffffffffffe5251, 1);
329 | assert!(as_u128(add(neg_from(MIN_AS_U128-1), neg_from(1))) == MIN_AS_U128, 1);
330 |
331 | assert!(as_u128(add(from(0), neg_from(0))) == 0, 2);
332 | assert!(as_u128(add(neg_from(0), from(0))) == 0, 2);
333 | assert!(as_u128(add(neg_from(1), from(1))) == 0, 2);
334 | assert!(as_u128(add(from(1), neg_from(1))) == 0, 2);
335 | assert!(as_u128(add(from(10000), neg_from(99999))) == 0xfffffffffffffffffffffffffffea071, 2);
336 | assert!(as_u128(add(from(99999), neg_from(10000))) == 89999, 2);
337 | assert!(as_u128(add(neg_from(MIN_AS_U128), from(1))) == 0x80000000000000000000000000000001, 2);
338 | assert!(as_u128(add(from(MAX_AS_U128), neg_from(1))) == MAX_AS_U128 - 1, 2);
339 | }
340 |
341 | #[test]
342 | fun test_overflowing_add() {
343 | let (result, overflow) = overflowing_add(from(MAX_AS_U128), neg_from(1));
344 | assert!(overflow == false && as_u128(result) == MAX_AS_U128 - 1, 1);
345 | let (_, overflow) = overflowing_add(from(MAX_AS_U128), from(1));
346 | assert!(overflow == true, 1);
347 | let (_, overflow) = overflowing_add(neg_from(MIN_AS_U128), neg_from(1));
348 | assert!(overflow == true, 1);
349 | }
350 |
351 | #[test]
352 | #[expected_failure]
353 | fun test_add_overflow() {
354 | add(from(MAX_AS_U128), from(1));
355 | }
356 |
357 | #[test]
358 | #[expected_failure]
359 | fun test_add_underflow() {
360 | add(neg_from(MIN_AS_U128), neg_from(1));
361 | }
362 |
363 | #[test]
364 | fun test_wrapping_sub() {
365 | assert!(as_u128(wrapping_sub(from(0), from(0))) == 0, 0);
366 | assert!(as_u128(wrapping_sub(from(1), from(0))) == 1, 0);
367 | assert!(as_u128(wrapping_sub(from(0), from(1))) == as_u128(neg_from(1)), 0);
368 | assert!(as_u128(wrapping_sub(from(1), from(1))) == as_u128(neg_from(0)), 0);
369 | assert!(as_u128(wrapping_sub(from(1), neg_from(1))) == as_u128(from(2)), 0);
370 | assert!(as_u128(wrapping_sub(neg_from(1), from(1))) == as_u128(neg_from(2)), 0);
371 | assert!(as_u128(wrapping_sub(from(1000000), from(1))) == 999999, 0);
372 | assert!(as_u128(wrapping_sub(neg_from(1000000), neg_from(1))) == as_u128(neg_from(999999)), 0);
373 | assert!(as_u128(wrapping_sub(from(1), from(1000000))) == as_u128(neg_from(999999)), 0);
374 | assert!(as_u128(wrapping_sub(from(MAX_AS_U128), from(MAX_AS_U128))) == as_u128(from(0)), 0);
375 | assert!(as_u128(wrapping_sub(from(MAX_AS_U128), from(1))) == as_u128(from(MAX_AS_U128 - 1)), 0);
376 | assert!(as_u128(wrapping_sub(from(MAX_AS_U128), neg_from(1))) == as_u128(neg_from(MIN_AS_U128)), 0);
377 | assert!(as_u128(wrapping_sub(neg_from(MIN_AS_U128), neg_from(1))) == as_u128(neg_from(MIN_AS_U128 - 1)), 0);
378 | assert!(as_u128(wrapping_sub(neg_from(MIN_AS_U128), from(1))) == as_u128(from(MAX_AS_U128)), 0);
379 | }
380 |
381 | #[test]
382 | fun test_sub() {
383 | assert!(as_u128(sub(from(0), from(0))) == 0, 0);
384 | assert!(as_u128(sub(from(1), from(0))) == 1, 0);
385 | assert!(as_u128(sub(from(0), from(1))) == as_u128(neg_from(1)), 0);
386 | assert!(as_u128(sub(from(1), from(1))) == as_u128(neg_from(0)), 0);
387 | assert!(as_u128(sub(from(1), neg_from(1))) == as_u128(from(2)), 0);
388 | assert!(as_u128(sub(neg_from(1), from(1))) == as_u128(neg_from(2)), 0);
389 | assert!(as_u128(sub(from(1000000), from(1))) == 999999, 0);
390 | assert!(as_u128(sub(neg_from(1000000), neg_from(1))) == as_u128(neg_from(999999)), 0);
391 | assert!(as_u128(sub(from(1), from(1000000))) == as_u128(neg_from(999999)), 0);
392 | assert!(as_u128(sub(from(MAX_AS_U128), from(MAX_AS_U128))) == as_u128(from(0)), 0);
393 | assert!(as_u128(sub(from(MAX_AS_U128), from(1))) == as_u128(from(MAX_AS_U128 - 1)), 0);
394 | assert!(as_u128(sub(neg_from(MIN_AS_U128), neg_from(1))) == as_u128(neg_from(MIN_AS_U128 - 1)), 0);
395 | }
396 |
397 | #[test]
398 | fun test_checked_sub() {
399 | let (result, overflowing) = overflowing_sub(from(MAX_AS_U128), from(1));
400 | assert!(overflowing == false && as_u128(result) == MAX_AS_U128 - 1, 1);
401 |
402 | let (_, overflowing) = overflowing_sub(neg_from(MIN_AS_U128), from(1));
403 | assert!(overflowing == true, 1);
404 |
405 | let (_, overflowing) = overflowing_sub(from(MAX_AS_U128), neg_from(1));
406 | assert!(overflowing == true, 1);
407 | }
408 |
409 | #[test]
410 | #[expected_failure]
411 | fun test_sub_overflow() {
412 | sub(from(MAX_AS_U128), neg_from(1));
413 | }
414 |
415 | #[test]
416 | #[expected_failure]
417 | fun test_sub_underflow() {
418 | sub(neg_from(MIN_AS_U128), from(1));
419 | }
420 |
421 | #[test]
422 | fun test_mul() {
423 | assert!(as_u128(mul(from(1), from(1))) == 1, 0);
424 | assert!(as_u128(mul(from(10), from(10))) == 100, 0);
425 | assert!(as_u128(mul(from(100), from(100))) == 10000, 0);
426 | assert!(as_u128(mul(from(10000), from(10000))) == 100000000, 0);
427 |
428 | assert!(as_u128(mul(neg_from(1), from(1))) == as_u128(neg_from(1)), 0);
429 | assert!(as_u128(mul(neg_from(10), from(10))) == as_u128(neg_from(100)), 0);
430 | assert!(as_u128(mul(neg_from(100), from(100))) == as_u128(neg_from(10000)), 0);
431 | assert!(as_u128(mul(neg_from(10000), from(10000))) == as_u128(neg_from(100000000)), 0);
432 |
433 | assert!(as_u128(mul(from(1), neg_from(1))) == as_u128(neg_from(1)), 0);
434 | assert!(as_u128(mul(from(10), neg_from(10))) == as_u128(neg_from(100)), 0);
435 | assert!(as_u128(mul(from(100), neg_from(100))) == as_u128(neg_from(10000)), 0);
436 | assert!(as_u128(mul(from(10000), neg_from(10000))) == as_u128(neg_from(100000000)), 0);
437 | assert!(as_u128(mul(from(MIN_AS_U128/2), neg_from(2))) == as_u128(neg_from(MIN_AS_U128)), 0);
438 | }
439 |
440 | #[test]
441 | #[expected_failure]
442 | fun test_mul_overflow() {
443 | mul(from(MIN_AS_U128/2), from(1));
444 | mul(neg_from(MIN_AS_U128/2), neg_from(2));
445 | }
446 |
447 | #[test]
448 | fun test_div() {
449 | assert!(as_u128(div(from(0), from(1))) == 0, 0);
450 | assert!(as_u128(div(from(10), from(1))) == 10, 0);
451 | assert!(as_u128(div(from(10), neg_from(1))) == as_u128(neg_from(10)), 0);
452 | assert!(as_u128(div(neg_from(10), neg_from(1))) == as_u128(from(10)), 0);
453 |
454 | assert!(abs_u128(neg_from(MIN_AS_U128)) == MIN_AS_U128, 0);
455 | assert!(as_u128(div(neg_from(MIN_AS_U128), from(1))) == MIN_AS_U128, 0);
456 | }
457 |
458 | #[test]
459 | #[expected_failure]
460 | fun test_div_overflow() {
461 | div(neg_from(MIN_AS_U128), neg_from(1));
462 | }
463 |
464 | #[test]
465 | fun test_shl() {
466 | assert!(as_u128(shl(from(10), 0)) == 10, 0);
467 | assert!(as_u128(shl(neg_from(10), 0)) == as_u128(neg_from(10)), 0);
468 |
469 | assert!(as_u128(shl(from(10), 1)) == 20, 0);
470 | assert!(as_u128(shl(neg_from(10), 1)) == as_u128(neg_from(20)), 0);
471 |
472 | assert!(as_u128(shl(from(10), 8)) == 2560, 0);
473 | assert!(as_u128(shl(neg_from(10), 8)) == as_u128(neg_from(2560)), 0);
474 |
475 | assert!(as_u128(shl(from(10), 32)) == 42949672960, 0);
476 | assert!(as_u128(shl(neg_from(10), 32)) == as_u128(neg_from(42949672960)), 0);
477 |
478 | assert!(as_u128(shl(from(10), 64)) == 184467440737095516160, 0);
479 | assert!(as_u128(shl(neg_from(10), 64)) == as_u128(neg_from(184467440737095516160)), 0);
480 |
481 | assert!(as_u128(shl(from(10), 127)) == 0, 0);
482 | assert!(as_u128(shl(neg_from(10), 127)) == 0, 0);
483 | }
484 |
485 | #[test]
486 | fun test_shr() {
487 | assert!(as_u128(shr(from(10), 0)) == 10, 0);
488 | assert!(as_u128(shr(neg_from(10), 0)) == as_u128(neg_from(10)), 0);
489 |
490 | assert!(as_u128(shr(from(10), 1)) == 5, 0);
491 | assert!(as_u128(shr(neg_from(10), 1)) == as_u128(neg_from(5)), 0);
492 |
493 | assert!(as_u128(shr(from(MAX_AS_U128), 8)) == 0x7fffffffffffffffffffffffffffff, 0);
494 | assert!(as_u128(shr(neg_from(MIN_AS_U128), 8)) == 0xff800000000000000000000000000000, 0);
495 |
496 | assert!(as_u128(shr(from(MAX_AS_U128), 96)) == 0x7fffffff, 0);
497 | assert!(as_u128(shr(neg_from(MIN_AS_U128), 96)) == 0xffffffffffffffffffffffff80000000, 0);
498 |
499 | assert!(as_u128(shr(from(MAX_AS_U128), 127)) == 0, 0);
500 | assert!(as_u128(shr(neg_from(MIN_AS_U128), 127)) == 0xffffffffffffffffffffffffffffffff, 0);
501 | }
502 |
503 | #[test]
504 | fun test_sign() {
505 | assert!(sign(neg_from(10)) == 1u8, 0);
506 | assert!(sign(from(10)) == 0u8, 0);
507 | }
508 |
509 | #[test]
510 | fun test_cmp() {
511 | assert!(cmp(from(1), from(0)) == GT, 0);
512 | assert!(cmp(from(0), from(1)) == LT, 0);
513 |
514 | assert!(cmp(from(0), neg_from(1)) == GT, 0);
515 | assert!(cmp(neg_from(0), neg_from(1)) == GT, 0);
516 | assert!(cmp(neg_from(1), neg_from(0)) == LT, 0);
517 |
518 | assert!(cmp(neg_from(MIN_AS_U128), from(MAX_AS_U128)) == LT, 0);
519 | assert!(cmp(from(MAX_AS_U128), neg_from(MIN_AS_U128)) == GT, 0);
520 |
521 | assert!(cmp(from(MAX_AS_U128), from(MAX_AS_U128-1)) == GT, 0);
522 | assert!(cmp(from(MAX_AS_U128-1), from(MAX_AS_U128)) == LT, 0);
523 |
524 | assert!(cmp(neg_from(MIN_AS_U128), neg_from(MIN_AS_U128-1)) == LT, 0);
525 | assert!(cmp(neg_from(MIN_AS_U128-1), neg_from(MIN_AS_U128)) == GT, 0);
526 | }
527 |
528 | #[test]
529 | fun test_castdown() {
530 | assert!((1u128 as u8) == 1u8, 0);
531 | }
532 | }
533 |
534 |
--------------------------------------------------------------------------------
/clmm/sources/lib/i32.move:
--------------------------------------------------------------------------------
1 | module turbos_clmm::i32 {
2 | const EOverflow: u64 = 0;
3 |
4 | const MIN_AS_U32: u32 = 1 << 31;
5 | const MAX_AS_U32: u32 = 0x7fffffff;
6 |
7 | const LT: u8 = 0;
8 | const EQ: u8 = 1;
9 | const GT: u8 = 2;
10 |
11 | struct I32 has copy, drop, store {
12 | bits: u32
13 | }
14 |
15 | public fun zero(): I32 {
16 | I32 {
17 | bits: 0
18 | }
19 | }
20 |
21 | public fun from_u32_neg(v: u32, is_neg: bool): I32 {
22 | if (is_neg) {
23 | neg_from(v)
24 | } else {
25 | from(v)
26 | }
27 | }
28 |
29 | public fun from_u32(v: u32): I32 {
30 | I32 {
31 | bits: v
32 | }
33 | }
34 |
35 | public fun from(v: u32): I32 {
36 | assert!(v <= MAX_AS_U32, EOverflow);
37 | I32 {
38 | bits: v
39 | }
40 | }
41 |
42 | public fun neg_from(v: u32): I32 {
43 | assert!(v <= MIN_AS_U32, EOverflow);
44 | if (v == 0) {
45 | I32 {
46 | bits: v
47 | }
48 | } else {
49 | I32 {
50 | bits: (u32_neg(v) + 1) | (1 << 31)
51 | }
52 | }
53 | }
54 |
55 | public fun wrapping_add(num1: I32, num2: I32): I32 {
56 | let sum = num1.bits ^ num2.bits;
57 | let carry = (num1.bits & num2.bits) << 1;
58 | while (carry != 0) {
59 | let a = sum;
60 | let b = carry;
61 | sum = a ^ b;
62 | carry = (a & b) << 1;
63 | };
64 | I32 {
65 | bits: sum
66 | }
67 | }
68 |
69 | public fun add(num1: I32, num2: I32): I32 {
70 | let sum = wrapping_add(num1, num2);
71 | let overflow = (sign(num1) & sign(num2) & u8_neg(sign(sum))) +
72 | (u8_neg(sign(num1)) & u8_neg(sign(num2)) & sign(sum));
73 | assert!(overflow == 0, EOverflow);
74 | sum
75 | }
76 |
77 | public fun wrapping_sub(num1: I32, num2: I32): I32 {
78 | let sub_num = wrapping_add(I32 {
79 | bits: u32_neg(num2.bits)
80 | }, from(1));
81 | wrapping_add(num1, sub_num)
82 | }
83 |
84 | public fun sub(num1: I32, num2: I32): I32 {
85 | let sub_num = wrapping_add(I32 {
86 | bits: u32_neg(num2.bits)
87 | }, from(1));
88 | add(num1, sub_num)
89 | }
90 |
91 | public fun mul(num1: I32, num2: I32): I32 {
92 | let product = abs_u32(num1) * abs_u32(num2);
93 | if (sign(num1) != sign(num2)) {
94 | return neg_from(product)
95 | };
96 | return from(product)
97 | }
98 |
99 | public fun div(num1: I32, num2: I32): I32 {
100 | let result = abs_u32(num1) / abs_u32(num2);
101 | if (sign(num1) != sign(num2)) {
102 | return neg_from(result)
103 | };
104 | return from(result)
105 | }
106 |
107 | public fun abs(v: I32): I32 {
108 | if (sign(v) == 0) {
109 | v
110 | } else {
111 | assert!(v.bits > MIN_AS_U32, EOverflow);
112 | I32 {
113 | bits: u32_neg(v.bits - 1)
114 | }
115 | }
116 | }
117 |
118 | public fun abs_u32(v: I32): u32 {
119 | if (sign(v) == 0) {
120 | v.bits
121 | } else {
122 | u32_neg(v.bits - 1)
123 | }
124 | }
125 |
126 | public fun shl(v: I32, shift: u8): I32 {
127 | I32 {
128 | bits: v.bits << shift
129 | }
130 | }
131 |
132 | public fun shr(v: I32, shift: u8): I32 {
133 | if (shift == 0) {
134 | return v
135 | };
136 | let mask = 0xffffffff << (32 - shift);
137 | if (sign(v) == 1) {
138 | return I32 {
139 | bits: (v.bits >> shift) | mask
140 | }
141 | };
142 | I32 {
143 | bits: v.bits >> shift
144 | }
145 | }
146 |
147 | public fun mod(v: I32, n: I32): I32 {
148 | if (sign(v) == 1) {
149 | neg_from((abs_u32(v) % abs_u32(n)))
150 | } else {
151 | from((as_u32(v) % abs_u32(n)))
152 | }
153 | }
154 |
155 | public fun mod_euclidean(v: I32, n: u32): I32 {
156 | let n_i32 = from(n);
157 | let r = mod(v, n_i32);
158 | if (sign(r) == 1) {
159 | add(r, n_i32)
160 | } else {
161 | r
162 | }
163 | }
164 |
165 | public fun as_u32(v: I32): u32 {
166 | v.bits
167 | }
168 |
169 | public fun sign(v: I32): u8 {
170 | ((v.bits >> 31) as u8)
171 | }
172 |
173 | public fun is_neg(v: I32): bool {
174 | sign(v) == 1
175 | }
176 |
177 | public fun cmp(num1: I32, num2: I32): u8 {
178 | if (num1.bits == num2.bits) return EQ;
179 | if (sign(num1) > sign(num2)) return LT;
180 | if (sign(num1) < sign(num2)) return GT;
181 | if (sign(num1) == 0) {
182 | if (num1.bits > num2.bits) {
183 | return GT
184 | } else {
185 | return LT
186 | }
187 | } else {
188 | if (num1.bits < num2.bits) {
189 | return LT
190 | } else {
191 | return GT
192 | }
193 | }
194 | }
195 |
196 | public fun eq(num1: I32, num2: I32): bool {
197 | num1.bits == num2.bits
198 | }
199 |
200 | public fun gt(num1: I32, num2: I32): bool {
201 | cmp(num1, num2) == GT
202 | }
203 |
204 | public fun gte(num1: I32, num2: I32): bool {
205 | cmp(num1, num2) >= EQ
206 | }
207 |
208 | public fun lt(num1: I32, num2: I32): bool {
209 | cmp(num1, num2) == LT
210 | }
211 |
212 | public fun lte(num1: I32, num2: I32): bool {
213 | cmp(num1, num2) <= EQ
214 | }
215 |
216 | public fun or(num1: I32, num2: I32): I32 {
217 | I32 {
218 | bits: (num1.bits | num2.bits)
219 | }
220 | }
221 |
222 | public fun and(num1: I32, num2: I32): I32 {
223 | I32 {
224 | bits: (num1.bits & num2.bits)
225 | }
226 | }
227 |
228 | fun u32_neg(v: u32): u32 {
229 | v ^ 0xffffffff
230 | }
231 |
232 | fun u8_neg(v: u8): u8 {
233 | v ^ 0xff
234 | }
235 |
236 | #[test]
237 | fun test_from_ok() {
238 | assert!(as_u32(from(0)) == 0, 0);
239 | assert!(as_u32(from(10)) == 10, 1);
240 | }
241 |
242 | #[test]
243 | #[expected_failure]
244 | fun test_from_overflow() {
245 | as_u32(from(MIN_AS_U32));
246 | as_u32(from(0xffffffff));
247 | }
248 |
249 | #[test]
250 | fun test_neg_from() {
251 | assert!(as_u32(neg_from(0)) == 0, 0);
252 | assert!(as_u32(neg_from(1)) == 0xffffffff, 1);
253 | assert!(as_u32(neg_from(0x7fffffff)) == 0x80000001, 2);
254 | assert!(as_u32(neg_from(MIN_AS_U32)) == MIN_AS_U32, 2);
255 | }
256 |
257 | #[test]
258 | #[expected_failure]
259 | fun test_neg_from_overflow() {
260 | neg_from(0x80000001);
261 | }
262 |
263 | #[test]
264 | fun test_abs() {
265 | assert!(as_u32(from(10)) == 10u32, 0);
266 | assert!(as_u32(abs(neg_from(10))) == 10u32, 1);
267 | assert!(as_u32(abs(neg_from(0))) == 0u32, 2);
268 | assert!(as_u32(abs(neg_from(0x7fffffff))) == 0x7fffffff, 3);
269 | assert!(as_u32(neg_from(MIN_AS_U32)) == MIN_AS_U32, 4);
270 | }
271 |
272 | #[test]
273 | #[expected_failure]
274 | fun test_abs_overflow() {
275 | abs(neg_from(1 << 31));
276 | }
277 |
278 | #[test]
279 | fun test_wrapping_add() {
280 | assert!(as_u32(wrapping_add(from(0), from(1))) == 1, 0);
281 | assert!(as_u32(wrapping_add(from(1), from(0))) == 1, 0);
282 | assert!(as_u32(wrapping_add(from(10000), from(99999))) == 109999, 0);
283 | assert!(as_u32(wrapping_add(from(99999), from(10000))) == 109999, 0);
284 | assert!(as_u32(wrapping_add(from(MAX_AS_U32 - 1), from(1))) == MAX_AS_U32, 0);
285 | assert!(as_u32(wrapping_add(from(0), from(0))) == 0, 0);
286 |
287 | assert!(as_u32(wrapping_add(neg_from(0), neg_from(0))) == 0, 1);
288 | assert!(as_u32(wrapping_add(neg_from(1), neg_from(0))) == 0xffffffff, 1);
289 | assert!(as_u32(wrapping_add(neg_from(0), neg_from(1))) == 0xffffffff, 1);
290 | assert!(as_u32(wrapping_add(neg_from(10000), neg_from(99999))) == 0xfffe5251, 1);
291 | assert!(as_u32(wrapping_add(neg_from(99999), neg_from(10000))) == 0xfffe5251, 1);
292 | assert!(as_u32(wrapping_add(neg_from(MIN_AS_U32 - 1), neg_from(1))) == MIN_AS_U32, 1);
293 |
294 | assert!(as_u32(wrapping_add(from(0), neg_from(0))) == 0, 2);
295 | assert!(as_u32(wrapping_add(neg_from(0), from(0))) == 0, 2);
296 | assert!(as_u32(wrapping_add(neg_from(1), from(1))) == 0, 2);
297 | assert!(as_u32(wrapping_add(from(1), neg_from(1))) == 0, 2);
298 | assert!(as_u32(wrapping_add(from(10000), neg_from(99999))) == 0xfffea071, 2);
299 | assert!(as_u32(wrapping_add(from(99999), neg_from(10000))) == 89999, 2);
300 | assert!(as_u32(wrapping_add(neg_from(MIN_AS_U32), from(1))) == 0x80000001, 2);
301 | assert!(as_u32(wrapping_add(from(MAX_AS_U32), neg_from(1))) == MAX_AS_U32 - 1, 2);
302 |
303 | assert!(as_u32(wrapping_add(from(MAX_AS_U32), from(1))) == MIN_AS_U32, 2);
304 | }
305 |
306 | #[test]
307 | fun test_add() {
308 | assert!(as_u32(add(from(0), from(0))) == 0, 0);
309 | assert!(as_u32(add(from(0), from(1))) == 1, 0);
310 | assert!(as_u32(add(from(1), from(0))) == 1, 0);
311 | assert!(as_u32(add(from(10000), from(99999))) == 109999, 0);
312 | assert!(as_u32(add(from(99999), from(10000))) == 109999, 0);
313 | assert!(as_u32(add(from(MAX_AS_U32 - 1), from(1))) == MAX_AS_U32, 0);
314 |
315 | assert!(as_u32(add(neg_from(0), neg_from(0))) == 0, 1);
316 | assert!(as_u32(add(neg_from(1), neg_from(0))) == 0xffffffff, 1);
317 | assert!(as_u32(add(neg_from(0), neg_from(1))) == 0xffffffff, 1);
318 | assert!(as_u32(add(neg_from(10000), neg_from(99999))) == 0xfffe5251, 1);
319 | assert!(as_u32(add(neg_from(99999), neg_from(10000))) == 0xfffe5251, 1);
320 | assert!(as_u32(add(neg_from(MIN_AS_U32 - 1), neg_from(1))) == MIN_AS_U32, 1);
321 |
322 | assert!(as_u32(add(from(0), neg_from(0))) == 0, 2);
323 | assert!(as_u32(add(neg_from(0), from(0))) == 0, 2);
324 | assert!(as_u32(add(neg_from(1), from(1))) == 0, 2);
325 | assert!(as_u32(add(from(1), neg_from(1))) == 0, 2);
326 | assert!(as_u32(add(from(10000), neg_from(99999))) == 0xfffea071, 2);
327 | assert!(as_u32(add(from(99999), neg_from(10000))) == 89999, 2);
328 | assert!(as_u32(add(neg_from(MIN_AS_U32), from(1))) == 0x80000001, 2);
329 | assert!(as_u32(add(from(MAX_AS_U32), neg_from(1))) == MAX_AS_U32 - 1, 2);
330 | }
331 |
332 | #[test]
333 | #[expected_failure]
334 | fun test_add_overflow() {
335 | add(from(MAX_AS_U32), from(1));
336 | }
337 |
338 | #[test]
339 | #[expected_failure]
340 | fun test_add_underflow() {
341 | add(neg_from(MIN_AS_U32), neg_from(1));
342 | }
343 |
344 | #[test]
345 | fun test_wrapping_sub() {
346 | assert!(as_u32(wrapping_sub(from(0), from(0))) == 0, 0);
347 | assert!(as_u32(wrapping_sub(from(1), from(0))) == 1, 0);
348 | assert!(as_u32(wrapping_sub(from(0), from(1))) == as_u32(neg_from(1)), 0);
349 | assert!(as_u32(wrapping_sub(from(1), from(1))) == as_u32(neg_from(0)), 0);
350 | assert!(as_u32(wrapping_sub(from(1), neg_from(1))) == as_u32(from(2)), 0);
351 | assert!(as_u32(wrapping_sub(neg_from(1), from(1))) == as_u32(neg_from(2)), 0);
352 | assert!(as_u32(wrapping_sub(from(1000000), from(1))) == 999999, 0);
353 | assert!(as_u32(wrapping_sub(neg_from(1000000), neg_from(1))) == as_u32(neg_from(999999)), 0);
354 | assert!(as_u32(wrapping_sub(from(1), from(1000000))) == as_u32(neg_from(999999)), 0);
355 | assert!(as_u32(wrapping_sub(from(MAX_AS_U32), from(MAX_AS_U32))) == as_u32(from(0)), 0);
356 | assert!(as_u32(wrapping_sub(from(MAX_AS_U32), from(1))) == as_u32(from(MAX_AS_U32 - 1)), 0);
357 | assert!(as_u32(wrapping_sub(from(MAX_AS_U32), neg_from(1))) == as_u32(neg_from(MIN_AS_U32)), 0);
358 | assert!(as_u32(wrapping_sub(neg_from(MIN_AS_U32), neg_from(1))) == as_u32(neg_from(MIN_AS_U32 - 1)), 0);
359 | assert!(as_u32(wrapping_sub(neg_from(MIN_AS_U32), from(1))) == as_u32(from(MAX_AS_U32)), 0);
360 | }
361 |
362 | #[test]
363 | fun test_sub() {
364 | assert!(as_u32(sub(from(0), from(0))) == 0, 0);
365 | assert!(as_u32(sub(from(1), from(0))) == 1, 0);
366 | assert!(as_u32(sub(from(0), from(1))) == as_u32(neg_from(1)), 0);
367 | assert!(as_u32(sub(from(1), from(1))) == as_u32(neg_from(0)), 0);
368 | assert!(as_u32(sub(from(1), neg_from(1))) == as_u32(from(2)), 0);
369 | assert!(as_u32(sub(neg_from(1), from(1))) == as_u32(neg_from(2)), 0);
370 | assert!(as_u32(sub(from(1000000), from(1))) == 999999, 0);
371 | assert!(as_u32(sub(neg_from(1000000), neg_from(1))) == as_u32(neg_from(999999)), 0);
372 | assert!(as_u32(sub(from(1), from(1000000))) == as_u32(neg_from(999999)), 0);
373 | assert!(as_u32(sub(from(MAX_AS_U32), from(MAX_AS_U32))) == as_u32(from(0)), 0);
374 | assert!(as_u32(sub(from(MAX_AS_U32), from(1))) == as_u32(from(MAX_AS_U32 - 1)), 0);
375 | assert!(as_u32(sub(neg_from(MIN_AS_U32), neg_from(1))) == as_u32(neg_from(MIN_AS_U32 - 1)), 0);
376 | }
377 |
378 | #[test]
379 | #[expected_failure]
380 | fun test_sub_overflow() {
381 | sub(from(MAX_AS_U32), neg_from(1));
382 | }
383 |
384 | #[test]
385 | #[expected_failure]
386 | fun test_sub_underflow() {
387 | sub(neg_from(MIN_AS_U32), from(1));
388 | }
389 |
390 | #[test]
391 | fun test_mul() {
392 | assert!(as_u32(mul(from(1), from(1))) == 1, 0);
393 | assert!(as_u32(mul(from(10), from(10))) == 100, 0);
394 | assert!(as_u32(mul(from(100), from(100))) == 10000, 0);
395 | assert!(as_u32(mul(from(10000), from(10000))) == 100000000, 0);
396 |
397 | assert!(as_u32(mul(neg_from(1), from(1))) == as_u32(neg_from(1)), 0);
398 | assert!(as_u32(mul(neg_from(10), from(10))) == as_u32(neg_from(100)), 0);
399 | assert!(as_u32(mul(neg_from(100), from(100))) == as_u32(neg_from(10000)), 0);
400 | assert!(as_u32(mul(neg_from(10000), from(10000))) == as_u32(neg_from(100000000)), 0);
401 |
402 | assert!(as_u32(mul(from(1), neg_from(1))) == as_u32(neg_from(1)), 0);
403 | assert!(as_u32(mul(from(10), neg_from(10))) == as_u32(neg_from(100)), 0);
404 | assert!(as_u32(mul(from(100), neg_from(100))) == as_u32(neg_from(10000)), 0);
405 | assert!(as_u32(mul(from(10000), neg_from(10000))) == as_u32(neg_from(100000000)), 0);
406 | assert!(as_u32(mul(from(MIN_AS_U32 / 2), neg_from(2))) == as_u32(neg_from(MIN_AS_U32)), 0);
407 | }
408 |
409 | #[test]
410 | #[expected_failure]
411 | fun test_mul_overflow() {
412 | mul(from(MIN_AS_U32 / 2), from(1));
413 | mul(neg_from(MIN_AS_U32 / 2), neg_from(2));
414 | }
415 |
416 | #[test]
417 | fun test_div() {
418 | assert!(as_u32(div(from(0), from(1))) == 0, 0);
419 | assert!(as_u32(div(from(10), from(1))) == 10, 0);
420 | assert!(as_u32(div(from(10), neg_from(1))) == as_u32(neg_from(10)), 0);
421 | assert!(as_u32(div(neg_from(10), neg_from(1))) == as_u32(from(10)), 0);
422 |
423 | assert!(abs_u32(neg_from(MIN_AS_U32)) == MIN_AS_U32, 0);
424 | assert!(as_u32(div(neg_from(MIN_AS_U32), from(1))) == MIN_AS_U32, 0);
425 | }
426 |
427 | #[test]
428 | #[expected_failure]
429 | fun test_div_overflow() {
430 | div(neg_from(MIN_AS_U32), neg_from(1));
431 | }
432 |
433 | #[test]
434 | fun test_shl() {
435 | assert!(as_u32(shl(from(10), 0)) == 10, 0);
436 | assert!(as_u32(shl(neg_from(10), 0)) == as_u32(neg_from(10)), 0);
437 |
438 | assert!(as_u32(shl(from(10), 1)) == 20, 0);
439 | assert!(as_u32(shl(neg_from(10), 1)) == as_u32(neg_from(20)), 0);
440 |
441 | assert!(as_u32(shl(from(10), 8)) == 2560, 0);
442 | assert!(as_u32(shl(neg_from(10), 8)) == as_u32(neg_from(2560)), 0);
443 |
444 | assert!(as_u32(shl(from(10), 31)) == 0, 0);
445 | assert!(as_u32(shl(neg_from(10), 31)) == 0, 0);
446 | }
447 |
448 | #[test]
449 | fun test_shr() {
450 | assert!(as_u32(shr(from(10), 0)) == 10, 0);
451 | assert!(as_u32(shr(neg_from(10), 0)) == as_u32(neg_from(10)), 0);
452 |
453 | assert!(as_u32(shr(from(10), 1)) == 5, 0);
454 | assert!(as_u32(shr(neg_from(10), 1)) == as_u32(neg_from(5)), 0);
455 |
456 | assert!(as_u32(shr(from(MAX_AS_U32), 8)) == MAX_AS_U32 >> 8, 0);
457 | assert!(as_u32(shr(neg_from(MIN_AS_U32), 8)) == 0xff800000, 0);
458 | }
459 |
460 | #[test]
461 | fun test_sign() {
462 | assert!(sign(neg_from(10)) == 1u8, 0);
463 | assert!(sign(from(10)) == 0u8, 0);
464 | }
465 |
466 | #[test]
467 | fun test_cmp() {
468 | assert!(cmp(from(1), from(0)) == GT, 0);
469 | assert!(cmp(from(0), from(1)) == LT, 0);
470 |
471 | assert!(cmp(from(0), neg_from(1)) == GT, 0);
472 | assert!(cmp(neg_from(0), neg_from(1)) == GT, 0);
473 | assert!(cmp(neg_from(1), neg_from(0)) == LT, 0);
474 |
475 | assert!(cmp(neg_from(MIN_AS_U32), from(MAX_AS_U32)) == LT, 0);
476 | assert!(cmp(from(MAX_AS_U32), neg_from(MIN_AS_U32)) == GT, 0);
477 |
478 | assert!(cmp(from(MAX_AS_U32), from(MAX_AS_U32 - 1)) == GT, 0);
479 | assert!(cmp(from(MAX_AS_U32 - 1), from(MAX_AS_U32)) == LT, 0);
480 |
481 | assert!(cmp(neg_from(MIN_AS_U32), neg_from(MIN_AS_U32 - 1)) == LT, 0);
482 | assert!(cmp(neg_from(MIN_AS_U32 - 1), neg_from(MIN_AS_U32)) == GT, 0);
483 | }
484 |
485 | #[test]
486 | fun test_castdown() {
487 | assert!((1u32 as u8) == 1u8, 0);
488 | }
489 |
490 | #[test]
491 | fun test_mod() {
492 | let i = mod(neg_from(2), from(5));
493 | assert!(cmp(i, neg_from(2)) == EQ, 0);
494 |
495 | i = mod(neg_from(2), neg_from(5));
496 | assert!(cmp(i, neg_from(2)) == EQ, 0);
497 |
498 | i = mod(from(2), from(5));
499 | assert!(cmp(i, from(2)) == EQ, 0);
500 |
501 | i = mod(from(2), neg_from(5));
502 | assert!(cmp(i, from(2)) == EQ, 0);
503 | }
504 |
505 | #[test]
506 | fun test_mod_euclidean() {
507 | let i = mod_euclidean(neg_from(257), 256);
508 | assert!(cmp(i, from(255)) == EQ, 0);
509 |
510 | i = mod_euclidean(neg_from(100), 10);
511 | assert!(cmp(i, from(0)) == EQ, 0);
512 |
513 | i = mod_euclidean(from(2), 5);
514 | assert!(cmp(i, from(2)) == EQ, 0);
515 | }
516 | }
517 |
518 |
--------------------------------------------------------------------------------
/clmm/sources/lib/i64.move:
--------------------------------------------------------------------------------
1 | module turbos_clmm::i64 {
2 | const EOverflow: u64 = 0;
3 |
4 | const MIN_AS_U64: u64 = 1 << 63;
5 | const MAX_AS_U64: u64 = 0x7fffffffffffffff;
6 |
7 | const LT: u8 = 0;
8 | const EQ: u8 = 1;
9 | const GT: u8 = 2;
10 |
11 | struct I64 has copy, drop, store {
12 | bits: u64
13 | }
14 |
15 | public fun zero(): I64 {
16 | I64 {
17 | bits: 0
18 | }
19 | }
20 |
21 | public fun from_u64(v: u64): I64 {
22 | I64 {
23 | bits: v
24 | }
25 | }
26 |
27 | public fun from(v: u64): I64 {
28 | assert!(v <= MAX_AS_U64, EOverflow);
29 | I64 {
30 | bits: v
31 | }
32 | }
33 |
34 | public fun neg_from(v: u64): I64 {
35 | assert!(v <= MIN_AS_U64, EOverflow);
36 | if (v == 0) {
37 | I64 {
38 | bits: v
39 | }
40 | } else {
41 | I64 {
42 | bits: (u64_neg(v) + 1) | (1 << 63)
43 | }
44 | }
45 | }
46 |
47 | public fun wrapping_add(num1: I64, num2: I64): I64 {
48 | let sum = num1.bits ^ num2.bits;
49 | let carry = (num1.bits & num2.bits) << 1;
50 | while (carry != 0) {
51 | let a = sum;
52 | let b = carry;
53 | sum = a ^ b;
54 | carry = (a & b) << 1;
55 | };
56 | I64 {
57 | bits: sum
58 | }
59 | }
60 |
61 | public fun add(num1: I64, num2: I64): I64 {
62 | let sum = wrapping_add(num1, num2);
63 | let overflow = (sign(num1) & sign(num2) & u8_neg(sign(sum))) + (u8_neg(sign(num1)) & u8_neg(sign(num2)) & sign(
64 | sum
65 | ));
66 | assert!(overflow == 0, EOverflow);
67 | sum
68 | }
69 |
70 | public fun wrapping_sub(num1: I64, num2: I64): I64 {
71 | let sub_num = wrapping_add(I64 {
72 | bits: u64_neg(num2.bits)
73 | }, from(1));
74 | wrapping_add(num1, sub_num)
75 | }
76 |
77 | public fun sub(num1: I64, num2: I64): I64 {
78 | let sub_num = wrapping_add(I64 {
79 | bits: u64_neg(num2.bits)
80 | }, from(1));
81 | add(num1, sub_num)
82 | }
83 |
84 | public fun mul(num1: I64, num2: I64): I64 {
85 | let product = abs_u64(num1) * abs_u64(num2);
86 | if (sign(num1) != sign(num2)) {
87 | return neg_from(product)
88 | };
89 | return from(product)
90 | }
91 |
92 | public fun div(num1: I64, num2: I64): I64 {
93 | let result = abs_u64(num1) / abs_u64(num2);
94 | if (sign(num1) != sign(num2)) {
95 | return neg_from(result)
96 | };
97 | return from(result)
98 | }
99 |
100 | public fun abs(v: I64): I64 {
101 | if (sign(v) == 0) {
102 | v
103 | } else {
104 | assert!(v.bits > MIN_AS_U64, EOverflow);
105 | I64 {
106 | bits: u64_neg(v.bits - 1)
107 | }
108 | }
109 | }
110 |
111 | public fun abs_u64(v: I64): u64 {
112 | if (sign(v) == 0) {
113 | v.bits
114 | } else {
115 | u64_neg(v.bits - 1)
116 | }
117 | }
118 |
119 | public fun shl(v: I64, shift: u8): I64 {
120 | I64 {
121 | bits: v.bits << shift
122 | }
123 | }
124 |
125 | public fun shr(v: I64, shift: u8): I64 {
126 | if (shift == 0) {
127 | return v
128 | };
129 | let mask = 0xffffffffffffffff << (64 - shift);
130 | if (sign(v) == 1) {
131 | return I64 {
132 | bits: (v.bits >> shift) | mask
133 | }
134 | };
135 | I64 {
136 | bits: v.bits >> shift
137 | }
138 | }
139 |
140 | public fun mod(v: I64, n: I64): I64 {
141 | if (sign(v) == 1) {
142 | neg_from((abs_u64(v) % abs_u64(n)))
143 | } else {
144 | from((as_u64(v) % abs_u64(n)))
145 | }
146 | }
147 |
148 | public fun as_u64(v: I64): u64 {
149 | v.bits
150 | }
151 |
152 | public fun sign(v: I64): u8 {
153 | ((v.bits >> 63) as u8)
154 | }
155 |
156 | public fun is_neg(v: I64): bool {
157 | sign(v) == 1
158 | }
159 |
160 | public fun cmp(num1: I64, num2: I64): u8 {
161 | if (num1.bits == num2.bits) return EQ;
162 | if (sign(num1) > sign(num2)) return LT;
163 | if (sign(num1) < sign(num2)) return GT;
164 | if (sign(num1) == 0) {
165 | if (num1.bits > num2.bits) {
166 | return GT
167 | } else {
168 | return LT
169 | }
170 | } else {
171 | if (num1.bits < num2.bits) {
172 | return LT
173 | } else {
174 | return GT
175 | }
176 | }
177 | }
178 |
179 | public fun eq(num1: I64, num2: I64): bool {
180 | num1.bits == num2.bits
181 | }
182 |
183 | public fun gt(num1: I64, num2: I64): bool {
184 | cmp(num1, num2) == GT
185 | }
186 |
187 | public fun gte(num1: I64, num2: I64): bool {
188 | cmp(num1, num2) >= EQ
189 | }
190 |
191 | public fun lt(num1: I64, num2: I64): bool {
192 | cmp(num1, num2) == LT
193 | }
194 |
195 | public fun lte(num1: I64, num2: I64): bool {
196 | cmp(num1, num2) <= EQ
197 | }
198 |
199 | public fun or(num1: I64, num2: I64): I64 {
200 | I64 {
201 | bits: (num1.bits | num2.bits)
202 | }
203 | }
204 |
205 | public fun and(num1: I64, num2: I64): I64 {
206 | I64 {
207 | bits: (num1.bits & num2.bits)
208 | }
209 | }
210 |
211 | fun u64_neg(v: u64): u64 {
212 | v ^ 0xffffffffffffffff
213 | }
214 |
215 | fun u8_neg(v: u8): u8 {
216 | v ^ 0xff
217 | }
218 |
219 | #[test]
220 | fun test_from_ok() {
221 | assert!(as_u64(from(0)) == 0, 0);
222 | assert!(as_u64(from(10)) == 10, 1);
223 | }
224 |
225 | #[test]
226 | #[expected_failure]
227 | fun test_from_overflow() {
228 | as_u64(from(MIN_AS_U64));
229 | as_u64(from(0xffffffffffffffff));
230 | }
231 |
232 | #[test]
233 | fun test_neg_from() {
234 | assert!(as_u64(neg_from(0)) == 0, 0);
235 | assert!(as_u64(neg_from(1)) == 0xffffffffffffffff, 1);
236 | assert!(as_u64(neg_from(0x7fffffffffffffff)) == 0x8000000000000001, 2);
237 | assert!(as_u64(neg_from(MIN_AS_U64)) == MIN_AS_U64, 2);
238 | }
239 |
240 | #[test]
241 | #[expected_failure]
242 | fun test_neg_from_overflow() {
243 | neg_from(0x8000000000000001);
244 | }
245 |
246 | #[test]
247 | fun test_abs() {
248 | assert!(as_u64(from(10)) == 10u64, 0);
249 | assert!(as_u64(abs(neg_from(10))) == 10u64, 1);
250 | assert!(as_u64(abs(neg_from(0))) == 0u64, 2);
251 | assert!(as_u64(abs(neg_from(0x7fffffffffffffff))) == 0x7fffffffffffffff, 3);
252 | assert!(as_u64(neg_from(MIN_AS_U64)) == MIN_AS_U64, 4);
253 | }
254 |
255 | #[test]
256 | #[expected_failure]
257 | fun test_abs_overflow() {
258 | abs(neg_from(1 << 63));
259 | }
260 |
261 | #[test]
262 | fun test_wrapping_add() {
263 | assert!(as_u64(wrapping_add(from(0), from(1))) == 1, 0);
264 | assert!(as_u64(wrapping_add(from(1), from(0))) == 1, 0);
265 | assert!(as_u64(wrapping_add(from(10000), from(99999))) == 109999, 0);
266 | assert!(as_u64(wrapping_add(from(99999), from(10000))) == 109999, 0);
267 | assert!(as_u64(wrapping_add(from(MAX_AS_U64 - 1), from(1))) == MAX_AS_U64, 0);
268 | assert!(as_u64(wrapping_add(from(0), from(0))) == 0, 0);
269 |
270 | assert!(as_u64(wrapping_add(neg_from(0), neg_from(0))) == 0, 1);
271 | assert!(as_u64(wrapping_add(neg_from(1), neg_from(0))) == 0xffffffffffffffff, 1);
272 | assert!(as_u64(wrapping_add(neg_from(0), neg_from(1))) == 0xffffffffffffffff, 1);
273 | assert!(as_u64(wrapping_add(neg_from(10000), neg_from(99999))) == 0xfffffffffffe5251, 1);
274 | assert!(as_u64(wrapping_add(neg_from(99999), neg_from(10000))) == 0xfffffffffffe5251, 1);
275 | assert!(as_u64(wrapping_add(neg_from(MIN_AS_U64 - 1), neg_from(1))) == MIN_AS_U64, 1);
276 |
277 | assert!(as_u64(wrapping_add(from(0), neg_from(0))) == 0, 2);
278 | assert!(as_u64(wrapping_add(neg_from(0), from(0))) == 0, 2);
279 | assert!(as_u64(wrapping_add(neg_from(1), from(1))) == 0, 2);
280 | assert!(as_u64(wrapping_add(from(1), neg_from(1))) == 0, 2);
281 | assert!(as_u64(wrapping_add(from(10000), neg_from(99999))) == 0xfffffffffffea071, 2);
282 | assert!(as_u64(wrapping_add(from(99999), neg_from(10000))) == 89999, 2);
283 | assert!(as_u64(wrapping_add(neg_from(MIN_AS_U64), from(1))) == 0x8000000000000001, 2);
284 | assert!(as_u64(wrapping_add(from(MAX_AS_U64), neg_from(1))) == MAX_AS_U64 - 1, 2);
285 |
286 | assert!(as_u64(wrapping_add(from(MAX_AS_U64), from(1))) == MIN_AS_U64, 2);
287 | }
288 |
289 | #[test]
290 | fun test_add() {
291 | assert!(as_u64(add(from(0), from(0))) == 0, 0);
292 | assert!(as_u64(add(from(0), from(1))) == 1, 0);
293 | assert!(as_u64(add(from(1), from(0))) == 1, 0);
294 | assert!(as_u64(add(from(10000), from(99999))) == 109999, 0);
295 | assert!(as_u64(add(from(99999), from(10000))) == 109999, 0);
296 | assert!(as_u64(add(from(MAX_AS_U64 - 1), from(1))) == MAX_AS_U64, 0);
297 |
298 | assert!(as_u64(add(neg_from(0), neg_from(0))) == 0, 1);
299 | assert!(as_u64(add(neg_from(1), neg_from(0))) == 0xffffffffffffffff, 1);
300 | assert!(as_u64(add(neg_from(0), neg_from(1))) == 0xffffffffffffffff, 1);
301 | assert!(as_u64(add(neg_from(10000), neg_from(99999))) == 0xfffffffffffe5251, 1);
302 | assert!(as_u64(add(neg_from(99999), neg_from(10000))) == 0xfffffffffffe5251, 1);
303 | assert!(as_u64(add(neg_from(MIN_AS_U64 - 1), neg_from(1))) == MIN_AS_U64, 1);
304 |
305 | assert!(as_u64(add(from(0), neg_from(0))) == 0, 2);
306 | assert!(as_u64(add(neg_from(0), from(0))) == 0, 2);
307 | assert!(as_u64(add(neg_from(1), from(1))) == 0, 2);
308 | assert!(as_u64(add(from(1), neg_from(1))) == 0, 2);
309 | assert!(as_u64(add(from(10000), neg_from(99999))) == 0xfffffffffffea071, 2);
310 | assert!(as_u64(add(from(99999), neg_from(10000))) == 89999, 2);
311 | assert!(as_u64(add(neg_from(MIN_AS_U64), from(1))) == 0x8000000000000001, 2);
312 | assert!(as_u64(add(from(MAX_AS_U64), neg_from(1))) == MAX_AS_U64 - 1, 2);
313 | }
314 |
315 | #[test]
316 | #[expected_failure]
317 | fun test_add_overflow() {
318 | add(from(MAX_AS_U64), from(1));
319 | }
320 |
321 | #[test]
322 | #[expected_failure]
323 | fun test_add_underflow() {
324 | add(neg_from(MIN_AS_U64), neg_from(1));
325 | }
326 |
327 | #[test]
328 | fun test_wrapping_sub() {
329 | assert!(as_u64(wrapping_sub(from(0), from(0))) == 0, 0);
330 | assert!(as_u64(wrapping_sub(from(1), from(0))) == 1, 0);
331 | assert!(as_u64(wrapping_sub(from(0), from(1))) == as_u64(neg_from(1)), 0);
332 | assert!(as_u64(wrapping_sub(from(1), from(1))) == as_u64(neg_from(0)), 0);
333 | assert!(as_u64(wrapping_sub(from(1), neg_from(1))) == as_u64(from(2)), 0);
334 | assert!(as_u64(wrapping_sub(neg_from(1), from(1))) == as_u64(neg_from(2)), 0);
335 | assert!(as_u64(wrapping_sub(from(1000000), from(1))) == 999999, 0);
336 | assert!(as_u64(wrapping_sub(neg_from(1000000), neg_from(1))) == as_u64(neg_from(999999)), 0);
337 | assert!(as_u64(wrapping_sub(from(1), from(1000000))) == as_u64(neg_from(999999)), 0);
338 | assert!(as_u64(wrapping_sub(from(MAX_AS_U64), from(MAX_AS_U64))) == as_u64(from(0)), 0);
339 | assert!(as_u64(wrapping_sub(from(MAX_AS_U64), from(1))) == as_u64(from(MAX_AS_U64 - 1)), 0);
340 | assert!(as_u64(wrapping_sub(from(MAX_AS_U64), neg_from(1))) == as_u64(neg_from(MIN_AS_U64)), 0);
341 | assert!(as_u64(wrapping_sub(neg_from(MIN_AS_U64), neg_from(1))) == as_u64(neg_from(MIN_AS_U64 - 1)), 0);
342 | assert!(as_u64(wrapping_sub(neg_from(MIN_AS_U64), from(1))) == as_u64(from(MAX_AS_U64)), 0);
343 | }
344 |
345 | #[test]
346 | fun test_sub() {
347 | assert!(as_u64(sub(from(0), from(0))) == 0, 0);
348 | assert!(as_u64(sub(from(1), from(0))) == 1, 0);
349 | assert!(as_u64(sub(from(0), from(1))) == as_u64(neg_from(1)), 0);
350 | assert!(as_u64(sub(from(1), from(1))) == as_u64(neg_from(0)), 0);
351 | assert!(as_u64(sub(from(1), neg_from(1))) == as_u64(from(2)), 0);
352 | assert!(as_u64(sub(neg_from(1), from(1))) == as_u64(neg_from(2)), 0);
353 | assert!(as_u64(sub(from(1000000), from(1))) == 999999, 0);
354 | assert!(as_u64(sub(neg_from(1000000), neg_from(1))) == as_u64(neg_from(999999)), 0);
355 | assert!(as_u64(sub(from(1), from(1000000))) == as_u64(neg_from(999999)), 0);
356 | assert!(as_u64(sub(from(MAX_AS_U64), from(MAX_AS_U64))) == as_u64(from(0)), 0);
357 | assert!(as_u64(sub(from(MAX_AS_U64), from(1))) == as_u64(from(MAX_AS_U64 - 1)), 0);
358 | assert!(as_u64(sub(neg_from(MIN_AS_U64), neg_from(1))) == as_u64(neg_from(MIN_AS_U64 - 1)), 0);
359 | }
360 |
361 | #[test]
362 | #[expected_failure]
363 | fun test_sub_overflow() {
364 | sub(from(MAX_AS_U64), neg_from(1));
365 | }
366 |
367 | #[test]
368 | #[expected_failure]
369 | fun test_sub_underflow() {
370 | sub(neg_from(MIN_AS_U64), from(1));
371 | }
372 |
373 | #[test]
374 | fun test_mul() {
375 | assert!(as_u64(mul(from(1), from(1))) == 1, 0);
376 | assert!(as_u64(mul(from(10), from(10))) == 100, 0);
377 | assert!(as_u64(mul(from(100), from(100))) == 10000, 0);
378 | assert!(as_u64(mul(from(10000), from(10000))) == 100000000, 0);
379 |
380 | assert!(as_u64(mul(neg_from(1), from(1))) == as_u64(neg_from(1)), 0);
381 | assert!(as_u64(mul(neg_from(10), from(10))) == as_u64(neg_from(100)), 0);
382 | assert!(as_u64(mul(neg_from(100), from(100))) == as_u64(neg_from(10000)), 0);
383 | assert!(as_u64(mul(neg_from(10000), from(10000))) == as_u64(neg_from(100000000)), 0);
384 |
385 | assert!(as_u64(mul(from(1), neg_from(1))) == as_u64(neg_from(1)), 0);
386 | assert!(as_u64(mul(from(10), neg_from(10))) == as_u64(neg_from(100)), 0);
387 | assert!(as_u64(mul(from(100), neg_from(100))) == as_u64(neg_from(10000)), 0);
388 | assert!(as_u64(mul(from(10000), neg_from(10000))) == as_u64(neg_from(100000000)), 0);
389 | assert!(as_u64(mul(from(MIN_AS_U64 / 2), neg_from(2))) == as_u64(neg_from(MIN_AS_U64)), 0);
390 | }
391 |
392 | #[test]
393 | #[expected_failure]
394 | fun test_mul_overflow() {
395 | mul(from(MIN_AS_U64 / 2), from(1));
396 | mul(neg_from(MIN_AS_U64 / 2), neg_from(2));
397 | }
398 |
399 | #[test]
400 | fun test_div() {
401 | assert!(as_u64(div(from(0), from(1))) == 0, 0);
402 | assert!(as_u64(div(from(10), from(1))) == 10, 0);
403 | assert!(as_u64(div(from(10), neg_from(1))) == as_u64(neg_from(10)), 0);
404 | assert!(as_u64(div(neg_from(10), neg_from(1))) == as_u64(from(10)), 0);
405 |
406 | assert!(abs_u64(neg_from(MIN_AS_U64)) == MIN_AS_U64, 0);
407 | assert!(as_u64(div(neg_from(MIN_AS_U64), from(1))) == MIN_AS_U64, 0);
408 | }
409 |
410 | #[test]
411 | #[expected_failure]
412 | fun test_div_overflow() {
413 | div(neg_from(MIN_AS_U64), neg_from(1));
414 | }
415 |
416 | #[test]
417 | fun test_shl() {
418 | assert!(as_u64(shl(from(10), 0)) == 10, 0);
419 | assert!(as_u64(shl(neg_from(10), 0)) == as_u64(neg_from(10)), 0);
420 |
421 | assert!(as_u64(shl(from(10), 1)) == 20, 0);
422 | assert!(as_u64(shl(neg_from(10), 1)) == as_u64(neg_from(20)), 0);
423 |
424 | assert!(as_u64(shl(from(10), 8)) == 2560, 0);
425 | assert!(as_u64(shl(neg_from(10), 8)) == as_u64(neg_from(2560)), 0);
426 |
427 | assert!(as_u64(shl(from(10), 32)) == 42949672960, 0);
428 | assert!(as_u64(shl(neg_from(10), 32)) == as_u64(neg_from(42949672960)), 0);
429 |
430 | assert!(as_u64(shl(from(10), 63)) == 0, 0);
431 | assert!(as_u64(shl(neg_from(10), 63)) == 0, 0);
432 | }
433 |
434 | #[test]
435 | fun test_shr() {
436 | assert!(as_u64(shr(from(10), 0)) == 10, 0);
437 | assert!(as_u64(shr(neg_from(10), 0)) == as_u64(neg_from(10)), 0);
438 |
439 | assert!(as_u64(shr(from(10), 1)) == 5, 0);
440 | assert!(as_u64(shr(neg_from(10), 1)) == as_u64(neg_from(5)), 0);
441 |
442 | assert!(as_u64(shr(from(MAX_AS_U64), 8)) == 36028797018963967, 0);
443 | assert!(as_u64(shr(neg_from(MIN_AS_U64), 8)) == 0xff80000000000000, 0);
444 |
445 | assert!(as_u64(shr(from(MAX_AS_U64), 32)) == 2147483647, 0);
446 | assert!(as_u64(shr(neg_from(MIN_AS_U64), 32)) == 0xffffffff80000000, 0);
447 |
448 | assert!(as_u64(shr(from(MAX_AS_U64), 63)) == 0, 0);
449 | assert!(as_u64(shr(neg_from(MIN_AS_U64), 63)) == 0xffffffffffffffff, 0);
450 | }
451 |
452 | #[test]
453 | fun test_sign() {
454 | assert!(sign(neg_from(10)) == 1u8, 0);
455 | assert!(sign(from(10)) == 0u8, 0);
456 | }
457 |
458 | #[test]
459 | fun test_cmp() {
460 | assert!(cmp(from(1), from(0)) == GT, 0);
461 | assert!(cmp(from(0), from(1)) == LT, 0);
462 |
463 | assert!(cmp(from(0), neg_from(1)) == GT, 0);
464 | assert!(cmp(neg_from(0), neg_from(1)) == GT, 0);
465 | assert!(cmp(neg_from(1), neg_from(0)) == LT, 0);
466 |
467 | assert!(cmp(neg_from(MIN_AS_U64), from(MAX_AS_U64)) == LT, 0);
468 | assert!(cmp(from(MAX_AS_U64), neg_from(MIN_AS_U64)) == GT, 0);
469 |
470 | assert!(cmp(from(MAX_AS_U64), from(MAX_AS_U64 - 1)) == GT, 0);
471 | assert!(cmp(from(MAX_AS_U64 - 1), from(MAX_AS_U64)) == LT, 0);
472 |
473 | assert!(cmp(neg_from(MIN_AS_U64), neg_from(MIN_AS_U64 - 1)) == LT, 0);
474 | assert!(cmp(neg_from(MIN_AS_U64 - 1), neg_from(MIN_AS_U64)) == GT, 0);
475 | }
476 |
477 | #[test]
478 | fun test_castdown() {
479 | assert!((1u64 as u8) == 1u8, 0);
480 | }
481 |
482 | #[test]
483 | fun test_mod() {
484 | let i = mod(neg_from(2), from(5));
485 | assert!(cmp(i, neg_from(2)) == EQ, 0);
486 |
487 | i = mod(neg_from(2), neg_from(5));
488 | assert!(cmp(i, neg_from(2)) == EQ, 0);
489 |
490 | i = mod(from(2), from(5));
491 | assert!(cmp(i, from(2)) == EQ, 0);
492 |
493 | i = mod(from(2), neg_from(5));
494 | assert!(cmp(i, from(2)) == EQ, 0);
495 | }
496 | }
497 |
498 |
--------------------------------------------------------------------------------
/clmm/sources/lib/math_bit.move:
--------------------------------------------------------------------------------
1 | // Copyright (c) Turbos Finance, Inc.
2 | // SPDX-License-Identifier: MIT
3 |
4 | module turbos_clmm::math_bit {
5 |
6 | const EXMustGtZero: u64 = 0;
7 | /// @notice Returns the index of the most significant bit of the number,
8 | /// where the least significant bit is at index 0 and the most significant bit is at index 255
9 | /// @dev The function satisfies the property:
10 | /// x >= 2**mostSignificantBit(x) and x < 2**(mostSignificantBit(x)+1)
11 | /// @param x the value for which to compute the most significant bit, must be greater than 0
12 | /// @return r the index of the most significant bit
13 | public fun most_significant_bit(x: u256): u8 {
14 | assert!(x > 0, EXMustGtZero);
15 | let r: u8 = 0;
16 |
17 | if (x >= 0x100000000000000000000000000000000) {
18 | x = x >> 128;
19 | r = r + 128;
20 | };
21 | if (x >= 0x10000000000000000) {
22 | x = x >> 64;
23 | r = r + 64;
24 | };
25 | if (x >= 0x100000000) {
26 | x = x >> 32;
27 | r = r + 32;
28 | };
29 | if (x >= 0x10000) {
30 | x = x >> 16;
31 | r = r + 16;
32 | };
33 | if (x >= 0x100) {
34 | x = x >> 8;
35 | r = r + 8;
36 | };
37 | if (x >= 0x10) {
38 | x = x >> 4;
39 | r = r + 4;
40 | };
41 | if (x >= 0x4) {
42 | x = x >> 2;
43 | r = r + 2;
44 | };
45 | if (x >= 0x2) r = r + 1;
46 |
47 | r
48 | }
49 |
50 | /// @notice Returns the index of the least significant bit of the number,
51 | /// where the least significant bit is at index 0 and the most significant bit is at index 255
52 | /// @dev The function satisfies the property:
53 | /// (x & 2**leastSignificantBit(x)) != 0 and (x & (2**(leastSignificantBit(x)) - 1)) == 0)
54 | /// @param x the value for which to compute the least significant bit, must be greater than 0
55 | /// @return r the index of the least significant bit
56 | public fun least_significant_bit(x: u256): u8 {
57 | assert!(x > 0, EXMustGtZero);
58 |
59 | let r: u8 = 255;
60 | if (x & 0xffffffffffffffffffffffffffffffff > 0) {
61 | r = r - 128;
62 | } else {
63 | x = x >> 128;
64 | };
65 | if (x & 0xffffffffffffffff > 0) {
66 | r = r - 64;
67 | } else {
68 | x = x >> 64;
69 | };
70 | if (x & 0xffffffff > 0) {
71 | r = r - 32;
72 | } else {
73 | x = x >> 32;
74 | };
75 | if (x & 0xffff > 0) {
76 | r = r - 16;
77 | } else {
78 | x = x >> 16;
79 | };
80 | if (x & 0xff > 0) {
81 | r = r - 8;
82 | } else {
83 | x = x >> 8;
84 | };
85 | if (x & 0xf > 0) {
86 | r = r - 4;
87 | } else {
88 | x = x >> 4;
89 | };
90 | if (x & 0x3 > 0) {
91 | r = r - 2;
92 | } else {
93 | x = x >> 2;
94 | };
95 | if (x & 0x1 > 0) r = r - 1;
96 |
97 | r
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/clmm/sources/lib/math_liquidity.move:
--------------------------------------------------------------------------------
1 | // Copyright (c) Turbos Finance, Inc.
2 | // SPDX-License-Identifier: MIT
3 |
4 | module turbos_clmm::math_liquidity {
5 | use turbos_clmm::full_math_u128;
6 | use turbos_clmm::i128::{Self, I128};
7 |
8 | const EAddDelta: u64 = 0;
9 |
10 | const Q64: u128 = 0x10000000000000000;
11 | const RESOLUTION: u8 = 64;
12 |
13 | /// Computes the maximum amount of liquidity received for a given amount of token_a, token_b, the current
14 | /// pool prices and the prices at the tick boundaries
15 | public fun get_liquidity_for_amounts(
16 | sqrt_price: u128,
17 | sqrt_price_a: u128,
18 | sqrt_price_b: u128,
19 | amount_a: u128,
20 | amount_b: u128
21 | ): u128 {
22 | let liquidity;
23 | if (sqrt_price_a > sqrt_price_b) (sqrt_price_a, sqrt_price_b) = (sqrt_price_b, sqrt_price_a);
24 |
25 | if (sqrt_price <= sqrt_price_a) {
26 | liquidity = get_liquidity_for_amount_a(sqrt_price_a, sqrt_price_b, amount_a);
27 | } else if (sqrt_price < sqrt_price_b) {
28 | let liquidity_a = get_liquidity_for_amount_a(sqrt_price, sqrt_price_b, amount_a);
29 | let liquidity_b = get_liquidity_for_amount_b(sqrt_price_a, sqrt_price, amount_b);
30 |
31 | liquidity = if (liquidity_a < liquidity_b) liquidity_a else liquidity_b;
32 | } else {
33 | liquidity = get_liquidity_for_amount_b(sqrt_price_a, sqrt_price_b, amount_b);
34 | };
35 |
36 | liquidity
37 | }
38 |
39 | /// Calculates amount_a * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower))
40 | public fun get_liquidity_for_amount_a(
41 | sqrt_price_a: u128,
42 | sqrt_price_b: u128,
43 | amount_a: u128,
44 | ): u128 {
45 | if (sqrt_price_a > sqrt_price_b) (sqrt_price_a, sqrt_price_b) = (sqrt_price_b, sqrt_price_a);
46 | let intermediate = full_math_u128::mul_div_floor(sqrt_price_a, sqrt_price_b, Q64);
47 |
48 | full_math_u128::mul_div_floor(amount_a, intermediate, sqrt_price_b - sqrt_price_a)
49 | }
50 |
51 | /// Calculates amount_b / (sqrt(upper) - sqrt(lower)).
52 | public fun get_liquidity_for_amount_b(
53 | sqrt_price_a: u128,
54 | sqrt_price_b: u128,
55 | amount_b: u128,
56 | ): u128 {
57 | if (sqrt_price_a > sqrt_price_b) (sqrt_price_a, sqrt_price_b) = (sqrt_price_b, sqrt_price_a);
58 |
59 | full_math_u128::mul_div_floor(amount_b, Q64, sqrt_price_b - sqrt_price_a)
60 | }
61 |
62 | public fun add_delta(x: u128, y: I128): u128 {
63 | let z;
64 | let abs_y = i128::abs_u128(y);
65 | if (i128::is_neg(y)) {
66 | assert!(x >= abs_y, EAddDelta);
67 | z = x - abs_y;
68 | } else {
69 | z = x + abs_y;
70 | assert!(z >= x, EAddDelta);
71 | };
72 |
73 | z
74 | }
75 |
76 | public fun get_amount_for_liquidity(
77 | sqrt_price: u128,
78 | sqrt_price_a: u128,
79 | sqrt_price_b: u128,
80 | liquidity: u128
81 | ): (u128, u128) {
82 | if (sqrt_price_a > sqrt_price_b) (sqrt_price_a, sqrt_price_b) = (sqrt_price_b, sqrt_price_a);
83 | let amount_a = 0;
84 | let amount_b = 0;
85 |
86 | if (sqrt_price <= sqrt_price_a) {
87 | amount_a = get_amount_a_for_liquidity(sqrt_price_a, sqrt_price_b, liquidity);
88 | } else if (sqrt_price < sqrt_price_b) {
89 | amount_a = get_amount_a_for_liquidity(sqrt_price, sqrt_price_b, liquidity);
90 | amount_b = get_amount_b_for_liquidity(sqrt_price_a, sqrt_price, liquidity);
91 | } else {
92 | amount_b = get_amount_b_for_liquidity(sqrt_price_a, sqrt_price_b, liquidity);
93 | };
94 |
95 | (amount_a, amount_b)
96 | }
97 |
98 | public fun get_amount_a_for_liquidity(
99 | sqrt_price_a: u128,
100 | sqrt_price_b: u128,
101 | liquidity: u128
102 | ): u128 {
103 | if (sqrt_price_a > sqrt_price_b) (sqrt_price_a, sqrt_price_b) = (sqrt_price_b, sqrt_price_a);
104 |
105 | full_math_u128::mul_div_floor(
106 | liquidity << RESOLUTION,
107 | sqrt_price_b - sqrt_price_a,
108 | sqrt_price_b
109 | ) / sqrt_price_a
110 | }
111 |
112 | public fun get_amount_b_for_liquidity(
113 | sqrt_price_a: u128,
114 | sqrt_price_b: u128,
115 | liquidity: u128
116 | ): u128 {
117 | if (sqrt_price_a > sqrt_price_b) (sqrt_price_a, sqrt_price_b) = (sqrt_price_b, sqrt_price_a);
118 |
119 | full_math_u128::mul_div_floor(
120 | liquidity,
121 | sqrt_price_b - sqrt_price_a,
122 | Q64
123 | )
124 | }
125 |
126 | #[test]
127 | fun test_get_liquidity_for_amounts() {
128 | let l = get_liquidity_for_amounts(
129 | 1832814330046721231834,
130 | 1353803200641628255991,
131 | 2466716266253144737284,
132 | 1000000000,
133 | 9871826150795
134 | );
135 | assert!(380164550184 == l, 1);
136 | }
137 |
138 | #[test]
139 | fun test_get_amount_for_liquidity() {
140 | let (a, b) = get_amount_for_liquidity(
141 | 3545820817480387689280,
142 | 3514404592553427687975,
143 | 3556829366031005702047,
144 | 10000000,
145 | );
146 | assert!(161 == a, 1);
147 | assert!(17030769 == b, 1);
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/clmm/sources/lib/math_sqrt_price.move:
--------------------------------------------------------------------------------
1 | // Copyright (c) Turbos Finance, Inc.
2 | // SPDX-License-Identifier: MIT
3 |
4 | module turbos_clmm::math_sqrt_price {
5 | use turbos_clmm::math_u128;
6 | use turbos_clmm::math_u256;
7 | use turbos_clmm::full_math_u128;
8 | use turbos_clmm::i128::{Self, I128};
9 |
10 | const EInvildSqrtPrice: u64 = 0;
11 | const ELiquidity: u64 = 1;
12 | const EDenominatorOverflow: u64 = 2;
13 |
14 | const RESOLUTION: u8 = 64;
15 | const Q64: u128 = 0x10000000000000000;
16 | const MAX_U64: u128 = 0xffffffffffffffff;
17 | const SCALE_FACTOR: u128 = 10000;
18 | const DECIMAL_PLACES: u8 = 64;
19 |
20 | /// @notice Gets the amount0 delta between two prices
21 | /// @dev Calculates liquidity / sqrt(lower) - liquidity / sqrt(upper),
22 | /// i.e. liquidity * (sqrt(upper) - sqrt(lower)) / (sqrt(upper) * sqrt(lower))
23 | /// @param sqrt_price_a A sqrt price
24 | /// @param sqrt_price_b Another sqrt price
25 | /// @param liquidity The amount of usable liquidity
26 | /// @param round_up Whether to round the amount up or down
27 | /// @return amount0 Amount of token0 required to cover a position of size liquidity between the two passed prices
28 | public fun get_amount_a_delta_(
29 | sqrt_price_a: u128,
30 | sqrt_price_b: u128,
31 | liquidity: u128,
32 | round_up: bool,
33 | ): u128 {
34 | assert!(sqrt_price_a > 0, EInvildSqrtPrice);
35 | if (sqrt_price_a > sqrt_price_b) (sqrt_price_a, sqrt_price_b) = (sqrt_price_b, sqrt_price_a);
36 | let (sqrt_price_a_u256, sqrt_price_b_u256, liquidity_u256) = ((sqrt_price_a as u256), (sqrt_price_b as u256), (liquidity as u256));
37 |
38 | let numerator1 = liquidity_u256 << RESOLUTION;
39 | let numerator2 = sqrt_price_b_u256 - sqrt_price_a_u256;
40 |
41 | let amount_a;
42 | if (round_up) {
43 | amount_a = math_u256::div_round(
44 | numerator1 * numerator2 / sqrt_price_b_u256,
45 | sqrt_price_a_u256,
46 | true
47 | );
48 | } else {
49 | amount_a = numerator1 * numerator2 / sqrt_price_b_u256 / sqrt_price_a_u256;
50 | };
51 |
52 | (amount_a as u128)
53 | }
54 |
55 | /// @notice Gets the amount1 delta between two prices
56 | /// @dev Calculates liquidity * (sqrt(upper) - sqrt(lower))
57 | /// @param sqrt_price_a A sqrt price
58 | /// @param sqrt_price_b Another sqrt price
59 | /// @param liquidity The amount of usable liquidity
60 | /// @param round_up Whether to round the amount up, or down
61 | /// @return amount1 Amount of token1 required to cover a position of size liquidity between the two passed prices
62 | public fun get_amount_b_delta_(
63 | sqrt_price_a: u128,
64 | sqrt_price_b: u128,
65 | liquidity: u128,
66 | round_up: bool,
67 | ): u128 {
68 | if (sqrt_price_a > sqrt_price_b) (sqrt_price_a, sqrt_price_b) = (sqrt_price_b, sqrt_price_a);
69 |
70 | let amount_b;
71 | if (round_up) {
72 | amount_b = full_math_u128::mul_div_round(liquidity, sqrt_price_b - sqrt_price_a, Q64);
73 | } else {
74 | amount_b = full_math_u128::mul_div_floor(liquidity, sqrt_price_b - sqrt_price_a, Q64);
75 | };
76 |
77 | amount_b
78 | }
79 |
80 | public fun get_amount_a_delta(
81 | sqrt_price_a: u128,
82 | sqrt_price_b: u128,
83 | liquidity: I128,
84 | ): I128 {
85 | if (i128::is_neg(liquidity)) {
86 | i128::neg_from(
87 | get_amount_a_delta_(
88 | sqrt_price_a,
89 | sqrt_price_b,
90 | i128::abs_u128(liquidity),
91 | false
92 | )
93 | )
94 | } else {
95 | i128::from(
96 | get_amount_a_delta_(
97 | sqrt_price_a,
98 | sqrt_price_b,
99 | i128::abs_u128(liquidity),
100 | true
101 | )
102 | )
103 | }
104 | }
105 |
106 | /// @notice Helper that gets signed token1 delta
107 | /// @param sqrtRatioAX96 A sqrt price
108 | /// @param sqrtRatioBX96 Another sqrt price
109 | /// @param liquidity The change in liquidity for which to compute the amount1 delta
110 | /// @return amount1 Amount of token1 corresponding to the passed liquidityDelta between the two prices
111 | public fun get_amount_b_delta(
112 | sqrt_price_a: u128,
113 | sqrt_price_b: u128,
114 | liquidity: I128,
115 | ): I128 {
116 | if (i128::is_neg(liquidity)) {
117 | i128::neg_from(
118 | get_amount_b_delta_(
119 | sqrt_price_a,
120 | sqrt_price_b,
121 | i128::abs_u128(liquidity),
122 | false
123 | )
124 | )
125 | } else {
126 | i128::from(
127 | get_amount_b_delta_(
128 | sqrt_price_a,
129 | sqrt_price_b,
130 | i128::abs_u128(liquidity),
131 | true
132 | )
133 | )
134 | }
135 | }
136 |
137 | public fun get_next_sqrt_price(
138 | sqrt_price: u128,
139 | liquidity: u128,
140 | amount: u128,
141 | amount_specified_is_input: bool,
142 | a_to_b: bool,
143 | ): u128 {
144 | if (amount_specified_is_input == a_to_b) {
145 | get_next_sqrt_price_from_amount_a_rounding_up(
146 | sqrt_price,
147 | liquidity,
148 | amount,
149 | amount_specified_is_input,
150 | )
151 | } else {
152 | get_next_sqrt_price_from_amount_b_rounding_down(
153 | sqrt_price,
154 | liquidity,
155 | amount,
156 | amount_specified_is_input,
157 | )
158 | }
159 | }
160 |
161 | /// @notice Gets the next sqrt price given a delta of token0
162 | /// @dev Always rounds up, because in the exact output case (increasing price) we need to move the price at least
163 | /// far enough to get the desired output amount, and in the exact input case (decreasing price) we need to move the
164 | /// price less in order to not send too much output.
165 | /// The most precise formula for this is liquidity * sqrt_price / (liquidity +- amount * sqrt_price),
166 | /// if this is impossible because of overflow, we calculate liquidity / (liquidity / sqrt_price +- amount).
167 | /// @param sqrt_price The starting price, i.e. before accounting for the token0 delta
168 | /// @param liquidity The amount of usable liquidity
169 | /// @param amount How much of token0 to add or remove from virtual reserves
170 | /// @param add Whether to add or remove the amount of token0
171 | /// @return The price after adding or removing amount, depending on add
172 | fun get_next_sqrt_price_from_amount_a_rounding_up(
173 | sqrt_price: u128,
174 | liquidity: u128,
175 | amount: u128,
176 | add: bool
177 | ): u128 {
178 | if (amount == 0) return sqrt_price;
179 | let (sqrt_price_u256, liquidity_u256, amount_u256) = ((sqrt_price as u256), (liquidity as u256), (amount as u256));
180 |
181 | let p = amount_u256 * sqrt_price_u256;
182 | let numerator = (liquidity_u256 * sqrt_price_u256) << RESOLUTION;
183 | //todo check numerator overflow u256
184 | let liquidity_shl = liquidity_u256 << RESOLUTION;
185 | let denominator = if (add) liquidity_shl + p else liquidity_shl - p;
186 |
187 | (math_u256::div_round(numerator, denominator, true) as u128)
188 | }
189 |
190 | public fun mul_div_round_fixed(num1: u256, num2: u256, denom: u256): u128 {
191 | let r = (num1 * num2 + (denom >> 1)) / denom;
192 | (r as u128)
193 | }
194 |
195 | /// @notice Gets the next sqrt price given a delta of token1
196 | /// @dev Always rounds down, because in the exact output case (decreasing price) we need to move the price at least
197 | /// far enough to get the desired output amount, and in the exact input case (increasing price) we need to move the
198 | /// price less in order to not send too much output.
199 | /// The formula we compute is within <1 wei of the lossless version: sqrt_price +- amount / liquidity
200 | /// @param sqrt_price The starting price, i.e., before accounting for the token1 delta
201 | /// @param liquidity The amount of usable liquidity
202 | /// @param amount How much of token1 to add, or remove, from virtual reserves
203 | /// @param add Whether to add, or remove, the amount of token1
204 | /// @return The price after adding or removing `amount`
205 | fun get_next_sqrt_price_from_amount_b_rounding_down(
206 | sqrt_price: u128,
207 | liquidity: u128,
208 | amount: u128,
209 | add: bool
210 | ): u128 {
211 | // if we're adding (subtracting), rounding down requires rounding the quotient down (up)
212 | // in both cases, avoid a mulDiv for most inputs
213 | if (add) {
214 | let quotient = if (amount <= MAX_U64) {
215 | (amount << RESOLUTION) / liquidity
216 | } else {
217 | full_math_u128::mul_div_floor(amount, Q64, liquidity)
218 | };
219 | sqrt_price + quotient
220 | } else {
221 | let quotient = if (amount <= MAX_U64) {
222 | math_u128::checked_div_round(amount << RESOLUTION, liquidity, true)
223 | } else {
224 | full_math_u128::mul_div_round(amount, Q64, liquidity)
225 | };
226 |
227 | assert!(sqrt_price > quotient, EInvildSqrtPrice);
228 |
229 | sqrt_price - quotient
230 | }
231 | }
232 |
233 | #[test_only]
234 | fun div_with_scale(a: u128, b: u128): u128 {
235 | (a * SCALE_FACTOR) / b
236 | }
237 |
238 | #[test_only]
239 | fun div_with_decimal(a: u128, b: u128, decimal_places: u8): u128 {
240 | (a << decimal_places) / b
241 | }
242 |
243 | #[test_only]
244 | public fun encode_price_sqrt(reserve1: u128, reserve0: u128): u128 {
245 | // Calculate the square root of (reserve1 * SCALE_FACTOR) / reserve0
246 | let ratio = div_with_scale(reserve1, reserve0);
247 | let sqrt_ratio = sui::math::sqrt_u128(ratio);
248 |
249 | // Multiply by 2^64 and round to the nearest integer
250 | //let integer_result = sqrt_ratio * (1 << 64) / sqrt scale;
251 | let integer_result = sqrt_ratio * (1 << 64) / sui::math::sqrt_u128(SCALE_FACTOR);
252 |
253 | integer_result
254 | }
255 |
256 | #[test]
257 | fun test_get_amount_b_delta_() {
258 | let delta = get_amount_b_delta_(
259 | 18446743083709604748,
260 | 18446744073709551616,
261 | 18446744073709551616,
262 | false
263 | );
264 | assert!(delta == 989999946868, 1);
265 | }
266 |
267 | #[test]
268 | fun test_encode_price_sqrt() {
269 | assert!(encode_price_sqrt(1, 1) == 18446744073709551616, 0);
270 | assert!(encode_price_sqrt(1, 100) == 1844674407370955161, 0);
271 | }
272 | }
273 |
--------------------------------------------------------------------------------
/clmm/sources/lib/math_swap.move:
--------------------------------------------------------------------------------
1 | // Copyright (c) Turbos Finance, Inc.
2 | // SPDX-License-Identifier: MIT
3 |
4 | module turbos_clmm::math_swap {
5 | use turbos_clmm::full_math_u128;
6 | use turbos_clmm::math_sqrt_price;
7 |
8 | const EInvildSqrtPrice: u64 = 0;
9 | const ELiquidity: u64 = 1;
10 | const EDenominatorOverflow: u64 = 2;
11 |
12 | const RESOLUTION: u8 = 64;
13 | const Q64: u128 = 0x10000000000000000;
14 | const MAX_U64: u128 = 0xffffffffffffffff;
15 | const SCALE_FACTOR: u128 = 10000;
16 | const DECIMAL_PLACES: u8 = 64;
17 |
18 | public fun compute_swap(
19 | sqrt_price_current: u128,
20 | sqrt_price_target: u128,
21 | liquidity: u128,
22 | amount_remaining: u128,
23 | amount_specified_is_input: bool,
24 | fee_rate: u32,
25 | ): (u128, u128, u128, u128) {
26 | let a_to_b = sqrt_price_current >= sqrt_price_target;
27 | let fee_amount;
28 |
29 | let amount_fixed_delta = get_amount_fixed_delta(
30 | sqrt_price_current,
31 | sqrt_price_target,
32 | liquidity,
33 | amount_specified_is_input,
34 | a_to_b,
35 | );
36 |
37 | let amount_calc = amount_remaining;
38 | if (amount_specified_is_input) {
39 | amount_calc = full_math_u128::mul_div_floor(
40 | amount_remaining,
41 | ((1000000 - fee_rate) as u128),
42 | 1000000,
43 | );
44 | };
45 |
46 | let next_sqrt_price = if (amount_calc >= amount_fixed_delta) {
47 | sqrt_price_target
48 | } else {
49 | math_sqrt_price::get_next_sqrt_price(
50 | sqrt_price_current,
51 | liquidity,
52 | amount_calc,
53 | amount_specified_is_input,
54 | a_to_b,
55 | )
56 | };
57 |
58 | let is_max_swap = next_sqrt_price == sqrt_price_target;
59 |
60 | let amount_unfixed_delta = get_amount_unfixed_delta(
61 | sqrt_price_current,
62 | next_sqrt_price,
63 | liquidity,
64 | amount_specified_is_input,
65 | a_to_b,
66 | );
67 |
68 | // If the swap is not at the max, we need to readjust the amount of the fixed token we are using
69 | if (!is_max_swap) {
70 | amount_fixed_delta = get_amount_fixed_delta(
71 | sqrt_price_current,
72 | next_sqrt_price,
73 | liquidity,
74 | amount_specified_is_input,
75 | a_to_b,
76 | );
77 | };
78 |
79 | let (amount_in, amount_out) = if (amount_specified_is_input) {
80 | (amount_fixed_delta, amount_unfixed_delta)
81 | } else {
82 | (amount_unfixed_delta, amount_fixed_delta)
83 | };
84 |
85 | // Cap output amount if using output
86 | if (!amount_specified_is_input && amount_out > amount_remaining) {
87 | amount_out = amount_remaining;
88 | };
89 |
90 | if (amount_specified_is_input && !is_max_swap) {
91 | fee_amount = amount_remaining - amount_in;
92 | } else {
93 | fee_amount = full_math_u128::mul_div_round(
94 | amount_in,
95 | (fee_rate as u128),
96 | ((1000000 - fee_rate) as u128),
97 | );
98 | };
99 |
100 | (next_sqrt_price, amount_in, amount_out, fee_amount)
101 | }
102 |
103 | public fun get_amount_fixed_delta(
104 | sqrt_price_current: u128,
105 | sqrt_price_target: u128,
106 | liquidity: u128,
107 | amount_specified_is_input: bool,
108 | a_to_b: bool,
109 | ): u128 {
110 | if (a_to_b == amount_specified_is_input) {
111 | math_sqrt_price::get_amount_a_delta_(
112 | sqrt_price_current,
113 | sqrt_price_target,
114 | liquidity,
115 | amount_specified_is_input,
116 | )
117 | } else {
118 | math_sqrt_price::get_amount_b_delta_(
119 | sqrt_price_current,
120 | sqrt_price_target,
121 | liquidity,
122 | amount_specified_is_input,
123 | )
124 | }
125 | }
126 |
127 | public fun get_amount_unfixed_delta(
128 | sqrt_price_current: u128,
129 | sqrt_price_target: u128,
130 | liquidity: u128,
131 | amount_specified_is_input: bool,
132 | a_to_b: bool,
133 | ): u128 {
134 | if (a_to_b == amount_specified_is_input) {
135 | math_sqrt_price::get_amount_b_delta_(
136 | sqrt_price_current,
137 | sqrt_price_target,
138 | liquidity,
139 | !amount_specified_is_input,
140 | )
141 | } else {
142 | math_sqrt_price::get_amount_a_delta_(
143 | sqrt_price_current,
144 | sqrt_price_target,
145 | liquidity,
146 | !amount_specified_is_input,
147 | )
148 | }
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/clmm/sources/lib/math_tick.move:
--------------------------------------------------------------------------------
1 | // Copyright (c) Turbos Finance, Inc.
2 | // SPDX-License-Identifier: MIT
3 |
4 | module turbos_clmm::math_tick {
5 | use turbos_clmm::i32::{Self, I32};
6 | use turbos_clmm::i128;
7 | use turbos_clmm::math_u128;
8 | use turbos_clmm::full_math_u128;
9 |
10 | const MAX_U64: u64 = 0xffffffffffffffff;
11 | const MAX_U128: u128 = 0xffffffffffffffffffffffffffffffff;
12 | const MAX_TICK_INDEX: u32 = 443636;
13 | const MAX_SQRT_PRICE_X64: u128 = 79226673515401279992447579055;
14 | const MIN_SQRT_PRICE_X64: u128 = 4295048016;
15 | const BIT_PRECISION: u32 = 14;
16 | const LOG_B_2_X32: u128 = 59543866431248;
17 | const LOG_B_P_ERR_MARGIN_LOWER_X64: u128 = 184467440737095516; // 0.01
18 | const LOG_B_P_ERR_MARGIN_UPPER_X64: u128 = 15793534762490258745; // 2^-precision / log_2_b + 0.01
19 |
20 | public fun get_min_tick(tick_sacing: u32): I32 {
21 | i32::neg_from(MAX_TICK_INDEX / tick_sacing * tick_sacing)
22 | }
23 |
24 | public fun get_max_tick(tick_sacing: u32): I32 {
25 | i32::from(MAX_TICK_INDEX / tick_sacing * tick_sacing)
26 | }
27 |
28 | public fun max_liquidity_per_tick(tick_spacing: u32): u128 {
29 | let min_tick_index = get_min_tick(tick_spacing);
30 | let max_tick_index = get_max_tick(tick_spacing);
31 | let num_ticks = i32::abs_u32(
32 | i32::div(
33 | i32::sub(max_tick_index, min_tick_index),
34 | i32::from(tick_spacing)
35 | )
36 | ) + 1;
37 | let liquidity = MAX_U128 / (num_ticks as u128);
38 |
39 | liquidity
40 | }
41 |
42 | public fun tick_index_from_sqrt_price(sqrt_price_x64: u128): i32::I32 {
43 | let msb: u8 = 128 - math_u128::leading_zeros(sqrt_price_x64) - 1;
44 | let log2p_integer_x32: i128::I128 = i128::shl(i128::sub(i128::from((msb as u128)), i128::from(64)), 32u8);
45 |
46 | let bit: i128::I128 = i128::from(0x8000_0000_0000_0000);
47 | let precision = 0;
48 | let log2p_fraction_x64: i128::I128 = i128::zero();
49 | let r: u128 = if (msb >= 64) sqrt_price_x64 >> (msb - 63) else sqrt_price_x64 << (63 - msb);
50 |
51 | while (i128::gt(bit, i128::zero()) && precision < BIT_PRECISION) {
52 | r = r * r;
53 | let is_r_more_than_two = (r >> 127 as u32);
54 | r = r >> (63 + is_r_more_than_two as u8);
55 | log2p_fraction_x64 = i128::add(log2p_fraction_x64, i128::mul(bit, i128::from((is_r_more_than_two as u128))));
56 | bit = i128::shr(bit, 1u8);
57 | precision = precision + 1;
58 | };
59 |
60 | let log2p_fraction_x32 = i128::shr(log2p_fraction_x64, 32u8);
61 | let log2p_x32: i128::I128 = i128::add(log2p_integer_x32, log2p_fraction_x32);
62 |
63 | // Transform from base 2 to base b
64 | let logbp_x64: i128::I128 = i128::mul(log2p_x32, i128::from(LOG_B_2_X32));
65 |
66 | let tick_low: i32::I32 = i128::as_i32(i128::shr(i128::sub(logbp_x64, i128::from(LOG_B_P_ERR_MARGIN_LOWER_X64)), 64u8));
67 | let tick_high: i32::I32 = i128::as_i32(i128::shr(i128::add(logbp_x64, i128::from(LOG_B_P_ERR_MARGIN_UPPER_X64)), 64u8));
68 |
69 | let result_tick;
70 | if (i32::eq(tick_low, tick_high)) {
71 | result_tick = tick_low;
72 | } else {
73 | let actual_tick_high_sqrt_price_x64 = sqrt_price_from_tick_index(tick_high);
74 | if (actual_tick_high_sqrt_price_x64 <= sqrt_price_x64) {
75 | result_tick = tick_high
76 | } else {
77 | result_tick = tick_low
78 | };
79 | };
80 |
81 | result_tick
82 | }
83 |
84 | public fun sqrt_price_from_tick_index(tick: i32::I32) : u128 {
85 | let sqrt_price;
86 | if (i32::gte(tick, i32::zero())) {
87 | sqrt_price = get_sqrt_price_positive_tick(tick)
88 | } else {
89 | sqrt_price = get_sqrt_price_negative_tick(tick)
90 | };
91 |
92 | sqrt_price
93 | }
94 |
95 | // Performs the exponential conversion with Q64.64 precision
96 | public fun get_sqrt_price_positive_tick(tick: i32::I32) : u128 {
97 | let ratio: u128;
98 | if (!i32::eq(i32::and(tick, i32::from(1u32)), i32::zero())) {
99 | ratio = 79232123823359799118286999567
100 | } else {
101 | ratio = 79228162514264337593543950336
102 | };
103 | if (!i32::eq(i32::and(tick, i32::from(2u32)), i32::zero())) {
104 | ratio = full_math_u128::mul_shr(ratio, 79236085330515764027303304731, 96u8);
105 | };
106 | if (!i32::eq(i32::and(tick, i32::from(4u32)), i32::zero())) {
107 | ratio = full_math_u128::mul_shr(ratio, 79244008939048815603706035061, 96u8);
108 | };
109 | if (!i32::eq(i32::and(tick, i32::from(8u32)), i32::zero())) {
110 | ratio = full_math_u128::mul_shr(ratio, 79259858533276714757314932305, 96u8);
111 | };
112 | if (!i32::eq(i32::and(tick, i32::from(16u32)), i32::zero())) {
113 | ratio = full_math_u128::mul_shr(ratio, 79291567232598584799939703904, 96u8);
114 | };
115 | if (!i32::eq(i32::and(tick, i32::from(32u32)), i32::zero())) {
116 | ratio = full_math_u128::mul_shr(ratio, 79355022692464371645785046466, 96u8);
117 | };
118 | if (!i32::eq(i32::and(tick, i32::from(64u32)), i32::zero())) {
119 | ratio = full_math_u128::mul_shr(ratio, 79482085999252804386437311141, 96u8);
120 | };
121 | if (!i32::eq(i32::and(tick, i32::from(128u32)), i32::zero())) {
122 | ratio = full_math_u128::mul_shr(ratio, 79736823300114093921829183326, 96u8);
123 | };
124 | if (!i32::eq(i32::and(tick, i32::from(256u32)), i32::zero())) {
125 | ratio = full_math_u128::mul_shr(ratio, 80248749790819932309965073892, 96u8);
126 | };
127 | if (!i32::eq(i32::and(tick, i32::from(512u32)), i32::zero())) {
128 | ratio = full_math_u128::mul_shr(ratio, 81282483887344747381513967011, 96u8);
129 | };
130 | if (!i32::eq(i32::and(tick, i32::from(1024u32)), i32::zero())) {
131 | ratio = full_math_u128::mul_shr(ratio, 83390072131320151908154831281, 96u8);
132 | };
133 | if (!i32::eq(i32::and(tick, i32::from(2048u32)), i32::zero())) {
134 | ratio = full_math_u128::mul_shr(ratio, 87770609709833776024991924138, 96u8);
135 | };
136 | if (!i32::eq(i32::and(tick, i32::from(4096u32)), i32::zero())) {
137 | ratio = full_math_u128::mul_shr(ratio, 97234110755111693312479820773, 96u8);
138 | };
139 | if (!i32::eq(i32::and(tick, i32::from(8192u32)), i32::zero())) {
140 | ratio = full_math_u128::mul_shr(ratio, 119332217159966728226237229890, 96u8);
141 | };
142 | if (!i32::eq(i32::and(tick, i32::from(16384u32)), i32::zero())) {
143 | ratio = full_math_u128::mul_shr(ratio, 179736315981702064433883588727, 96u8);
144 | };
145 | if (!i32::eq(i32::and(tick, i32::from(32768u32)), i32::zero())) {
146 | ratio = full_math_u128::mul_shr(ratio, 407748233172238350107850275304, 96u8);
147 | };
148 | if (!i32::eq(i32::and(tick, i32::from(65536u32)), i32::zero())) {
149 | ratio = full_math_u128::mul_shr(ratio, 2098478828474011932436660412517, 96u8);
150 | };
151 | if (!i32::eq(i32::and(tick, i32::from(131072u32)), i32::zero())) {
152 | ratio = full_math_u128::mul_shr(ratio, 55581415166113811149459800483533, 96u8);
153 | };
154 | if (!i32::eq(i32::and(tick, i32::from(262144u32)), i32::zero())) {
155 | ratio = full_math_u128::mul_shr(ratio, 38992368544603139932233054999993551, 96u8);
156 | };
157 |
158 | (ratio >> 32)
159 | }
160 |
161 | public fun get_sqrt_price_negative_tick(tick: i32::I32) : u128 {
162 | let abs_tick = i32::abs(tick);
163 | let ratio: u128;
164 | if (!i32::eq(i32::and(abs_tick, i32::from(1u32)), i32::zero())) {
165 | ratio = 18445821805675392311
166 | } else {
167 | ratio = 18446744073709551616
168 | };
169 |
170 | if (!i32::eq(i32::and(abs_tick, i32::from(2u32)), i32::zero())) {
171 | ratio = full_math_u128::mul_shr(ratio, 18444899583751176498, 64u8);
172 | };
173 | if (!i32::eq(i32::and(abs_tick, i32::from(4u32)), i32::zero())) {
174 | ratio = full_math_u128::mul_shr(ratio, 18443055278223354162, 64u8);
175 | };
176 | if (!i32::eq(i32::and(abs_tick, i32::from(8u32)), i32::zero())) {
177 | ratio = full_math_u128::mul_shr(ratio, 18439367220385604838, 64u8);
178 | };
179 | if (!i32::eq(i32::and(abs_tick, i32::from(16u32)), i32::zero())) {
180 | ratio = full_math_u128::mul_shr(ratio, 18431993317065449817, 64u8);
181 | };
182 | if (!i32::eq(i32::and(abs_tick, i32::from(32u32)), i32::zero())) {
183 | ratio = full_math_u128::mul_shr(ratio, 18417254355718160513, 64u8);
184 | };
185 | if (!i32::eq(i32::and(abs_tick, i32::from(64u32)), i32::zero())) {
186 | ratio = full_math_u128::mul_shr(ratio, 18387811781193591352, 64u8);
187 | };
188 | if (!i32::eq(i32::and(abs_tick, i32::from(128u32)), i32::zero())) {
189 | ratio = full_math_u128::mul_shr(ratio, 18329067761203520168, 64u8);
190 | };
191 | if (!i32::eq(i32::and(abs_tick, i32::from(256u32)), i32::zero())) {
192 | ratio = full_math_u128::mul_shr(ratio, 18212142134806087854, 64u8);
193 | };
194 | if (!i32::eq(i32::and(abs_tick, i32::from(512u32)), i32::zero())) {
195 | ratio = full_math_u128::mul_shr(ratio, 17980523815641551639, 64u8);
196 | };
197 | if (!i32::eq(i32::and(abs_tick, i32::from(1024u32)), i32::zero())) {
198 | ratio = full_math_u128::mul_shr(ratio, 17526086738831147013, 64u8);
199 | };
200 | if (!i32::eq(i32::and(abs_tick, i32::from(2048u32)), i32::zero())) {
201 | ratio = full_math_u128::mul_shr(ratio, 16651378430235024244, 64u8);
202 | };
203 | if (!i32::eq(i32::and(abs_tick, i32::from(4096u32)), i32::zero())) {
204 | ratio = full_math_u128::mul_shr(ratio, 15030750278693429944, 64u8);
205 | };
206 | if (!i32::eq(i32::and(abs_tick, i32::from(8192u32)), i32::zero())) {
207 | ratio = full_math_u128::mul_shr(ratio, 12247334978882834399, 64u8);
208 | };
209 | if (!i32::eq(i32::and(abs_tick, i32::from(16384u32)), i32::zero())) {
210 | ratio = full_math_u128::mul_shr(ratio, 8131365268884726200, 64u8);
211 | };
212 | if (!i32::eq(i32::and(abs_tick, i32::from(32768u32)), i32::zero())) {
213 | ratio = full_math_u128::mul_shr(ratio, 3584323654723342297, 64u8);
214 | };
215 | if (!i32::eq(i32::and(abs_tick, i32::from(65536u32)), i32::zero())) {
216 | ratio = full_math_u128::mul_shr(ratio, 696457651847595233, 64u8);
217 | };
218 | if (!i32::eq(i32::and(abs_tick, i32::from(131072u32)), i32::zero())) {
219 | ratio = full_math_u128::mul_shr(ratio, 26294789957452057, 64u8);
220 | };
221 | if (!i32::eq(i32::and(abs_tick, i32::from(262144u32)), i32::zero())) {
222 | ratio = full_math_u128::mul_shr(ratio, 37481735321082, 64u8);
223 | };
224 |
225 | ratio
226 | }
227 |
228 | #[test]
229 | fun test_sqrt_price_from_tick_index_at_max() {
230 | let r = tick_index_from_sqrt_price(MAX_SQRT_PRICE_X64);
231 | assert!(i32::eq(r, i32::from(MAX_TICK_INDEX)), 0);
232 | }
233 |
234 | #[test]
235 | fun test_sqrt_price_from_tick_index_at_min() {
236 | let r = tick_index_from_sqrt_price(MIN_SQRT_PRICE_X64);
237 | assert!(i32::eq(r, i32::neg_from(MAX_TICK_INDEX)), 0);
238 | }
239 |
240 | #[test]
241 | fun test_sqrt_price_from_tick_index_at_max_add_one() {
242 | let sqrt_price_x64_max_add_one = MAX_SQRT_PRICE_X64 + 1;
243 | let tick_from_max_add_one = tick_index_from_sqrt_price(sqrt_price_x64_max_add_one);
244 | let sqrt_price_x64_max = MAX_SQRT_PRICE_X64;
245 | let tick_from_max = tick_index_from_sqrt_price(sqrt_price_x64_max);
246 |
247 | // We don't care about accuracy over the limit. We just care about it's equality properties.
248 | assert!(i32::eq(tick_from_max_add_one, tick_from_max), 0);
249 | }
250 |
251 | #[test]
252 | fun test_sqrt_price_from_tick_index_at_min_add_one() {
253 | let sqrt_price_x64 = MIN_SQRT_PRICE_X64 + 1;
254 | let r = tick_index_from_sqrt_price(sqrt_price_x64);
255 | assert!(i32::eq(r, i32::neg_from(MAX_TICK_INDEX)), 0);
256 | }
257 |
258 | #[test]
259 | fun test_sqrt_price_from_tick_index_at_max_sub_one() {
260 | let sqrt_price_x64 = MAX_SQRT_PRICE_X64 - 1;
261 | let r = tick_index_from_sqrt_price(sqrt_price_x64);
262 | assert!(i32::eq(r, i32::from(MAX_TICK_INDEX-1)), 0);
263 | }
264 |
265 | #[test]
266 | fun test_sqrt_price_from_tick_index_at_one() {
267 | let sqrt_price_x64: u128 = (MAX_U64 as u128) + 1;
268 | let r = tick_index_from_sqrt_price(sqrt_price_x64);
269 | assert!(i32::eq(r, i32::zero()), 0);
270 | }
271 |
272 | #[test]
273 | fun test_sqrt_price_from_tick_index_at_one_add_one() {
274 | let sqrt_price_x64: u128 = (MAX_U64 as u128) + 2;
275 | let r = tick_index_from_sqrt_price(sqrt_price_x64);
276 | assert!(i32::eq(r, i32::zero()), 0);
277 | }
278 |
279 | #[test]
280 | fun test_sqrt_price_from_tick_index_at_one_sub_one() {
281 | let sqrt_price_x64: u128 = (MAX_U64 as u128) - 1;
282 | let r = tick_index_from_sqrt_price(sqrt_price_x64);
283 | assert!(i32::eq(r, i32::neg_from(1)), 0);
284 | }
285 |
286 | #[test]
287 | #[expected_failure]
288 | fun test_tick_exceed_max() {
289 | let sqrt_price_from_max_tick_add_one = sqrt_price_from_tick_index(i32::from(MAX_TICK_INDEX + 1));
290 | let sqrt_price_from_max_tick = sqrt_price_from_tick_index(i32::from(MAX_TICK_INDEX));
291 | assert!(sqrt_price_from_max_tick_add_one > sqrt_price_from_max_tick, 0);
292 | }
293 |
294 | #[test]
295 | fun test_tick_below_min() {
296 | let sqrt_price_from_min_tick_sub_one = sqrt_price_from_tick_index(i32::sub(i32::neg_from(MAX_TICK_INDEX), (i32::from(1))));
297 | let sqrt_price_from_min_tick = sqrt_price_from_tick_index(i32::neg_from(MAX_TICK_INDEX));
298 | assert!(sqrt_price_from_min_tick_sub_one < sqrt_price_from_min_tick, 0);
299 | }
300 |
301 | #[test]
302 | fun test_tick_at_max() {
303 | let max_tick = i32::from(MAX_TICK_INDEX);
304 | let r = sqrt_price_from_tick_index(max_tick);
305 | assert!(r == MAX_SQRT_PRICE_X64, 0);
306 | }
307 |
308 | #[test]
309 | fun test_tick_at_min() {
310 | let min_tick = i32::neg_from(MAX_TICK_INDEX);
311 | let r = sqrt_price_from_tick_index(min_tick);
312 | assert!(r == MIN_SQRT_PRICE_X64, 0);
313 | }
314 |
315 | #[test]
316 | fun test_get_min_tick_10() {
317 | let min_tick = get_min_tick(10);
318 | let max_tick = get_max_tick(10);
319 | assert!(i32::eq(min_tick, i32::neg_from(443630)), 0);
320 | assert!(i32::eq(max_tick, i32::from(443630)), 0);
321 | }
322 |
323 | #[test]
324 | fun test_get_min_tick_300() {
325 | let min_tick = get_min_tick(200);
326 | let max_tick = get_max_tick(200);
327 | assert!(i32::eq(min_tick, i32::neg_from(443600)), 0);
328 | assert!(i32::eq(max_tick, i32::from(443600)), 0);
329 | }
330 |
331 | #[test]
332 | fun test_get_min_tick_max() {
333 | let min_tick = get_min_tick(16383);
334 | let max_tick = get_max_tick(16383);
335 | assert!(i32::eq(min_tick, i32::neg_from(442341)), 0);
336 | assert!(i32::eq(max_tick, i32::from(442341)), 0);
337 | }
338 | }
339 |
--------------------------------------------------------------------------------
/clmm/sources/lib/math_u128.move:
--------------------------------------------------------------------------------
1 | module turbos_clmm::math_u128 {
2 | use turbos_clmm::math_u64;
3 |
4 | const MAX_U128: u128 = 0xffffffffffffffffffffffffffffffff;
5 |
6 | const HI_64_MASK: u128 = 0xffffffffffffffff0000000000000000;
7 | const LO_64_MASK: u128 = 0x0000000000000000ffffffffffffffff;
8 |
9 | const DIV_BY_ZERO: u64 = 1;
10 |
11 | public fun wrapping_add(n1: u128, n2: u128): u128 {
12 | let (sum, _) = overflowing_add(n1, n2);
13 | sum
14 | }
15 |
16 | public fun overflowing_add(n1: u128, n2: u128): (u128, bool) {
17 | let (sum0, carry0) = math_u64::carry_add(lo(n1), lo(n2), 0);
18 | let (sum1, carry1) = math_u64::carry_add(hi(n1), hi(n2), carry0);
19 | ((((sum1 as u128) << 64) + (sum0 as u128)), carry1 == 1)
20 | }
21 |
22 | public fun wrapping_sub(n1: u128, n2: u128): u128 {
23 | let (result, _) = overflowing_sub(n1, n2);
24 | result
25 | }
26 |
27 | public fun overflowing_sub(n1: u128, n2: u128): (u128, bool) {
28 | if (n1 >= n2) {
29 | ((n1 - n2), false)
30 | } else {
31 | ((MAX_U128 - n2 + n1 + 1), true)
32 | }
33 | }
34 |
35 | public fun wrapping_mul(n1: u128, n2: u128): u128 {
36 | let (m, _) = overflowing_mul(n1, n2);
37 | m
38 | }
39 |
40 | public fun overflowing_mul(n1: u128, n2: u128): (u128, bool) {
41 | let (c0, c1) = full_mul(n1, n2);
42 | if (c1 > 0) {
43 | (c0, true)
44 | } else {
45 | (c0, false)
46 | }
47 | }
48 |
49 | public fun full_mul(n1: u128, n2: u128): (u128, u128) {
50 | let hi_mask: u256 = 0xffffffffffffffffffffffffffffffff00000000000000000000000000000000;
51 | let lo_mask: u256 = 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;
52 | let r = (n1 as u256) * (n2 as u256);
53 | let hi = (((r & hi_mask) >> 128) as u128);
54 | let lo = ((r & lo_mask) as u128);
55 | (lo, hi)
56 | }
57 |
58 | public fun hi(n: u128): u64 {
59 | (((n & HI_64_MASK) >> 64) as u64)
60 | }
61 |
62 | public fun lo(n: u128): u64 {
63 | ((n & LO_64_MASK) as u64)
64 | }
65 |
66 | public fun hi_u128(n: u128): u128 {
67 | (n & HI_64_MASK) >> 64
68 | }
69 |
70 | public fun lo_u128(n: u128): u128 {
71 | (n & LO_64_MASK)
72 | }
73 |
74 | public fun from_lo_hi(lo: u64, hi: u64): u128 {
75 | ((hi as u128) << 64) + (lo as u128)
76 | }
77 |
78 | public fun checked_div_round(num: u128, denom: u128, round_up: bool): u128 {
79 | if (denom == 0) {
80 | abort DIV_BY_ZERO
81 | };
82 | let quotient = num / denom;
83 | let remainer = num % denom;
84 | if (round_up && (remainer > 0)) {
85 | return (quotient + 1)
86 | };
87 | quotient
88 | }
89 |
90 | public fun max(num1: u128, num2: u128): u128 {
91 | if (num1 > num2) {
92 | num1
93 | } else {
94 | num2
95 | }
96 | }
97 |
98 | public fun min(num1: u128, num2: u128): u128 {
99 | if (num1 < num2) {
100 | num1
101 | } else {
102 | num2
103 | }
104 | }
105 |
106 | public fun leading_zeros(a: u128): u8 {
107 | if (a == 0) {
108 | return 128
109 | };
110 |
111 | let a1 = a & 0xFFFFFFFFFFFFFFFF;
112 | let a2 = a >> 64;
113 |
114 | if (a2 == 0) {
115 | let bit = 64;
116 |
117 | while (bit >= 1) {
118 | let b = (a1 >> (bit - 1)) & 1;
119 | if (b != 0) {
120 | break
121 | };
122 |
123 | bit = bit - 1;
124 | };
125 |
126 | return (64 - bit) + 64
127 | } else {
128 | let bit = 128;
129 | while (bit >= 1) {
130 | let b = (a >> (bit - 1)) & 1;
131 | if (b != 0) {
132 | break
133 | };
134 | bit = bit - 1;
135 | };
136 |
137 | return 128 - bit
138 | }
139 | }
140 |
141 | /// Return the value of a base raised to a power
142 | public fun pow(base: u128, exponent: u8): u128 {
143 | let res = 1;
144 | while (exponent >= 1) {
145 | if (exponent % 2 == 0) {
146 | base = base * base;
147 | exponent = exponent / 2;
148 | } else {
149 | res = res * base;
150 | exponent = exponent - 1;
151 | }
152 | };
153 |
154 | res
155 | }
156 |
157 | #[test]
158 | fun test_overflowing_add() {
159 | let (m, o) = overflowing_add(10, 10);
160 | assert!(m == 20u128 && o == false, 0);
161 |
162 | let (m, o) = overflowing_add(MAX_U128, 10);
163 | assert!(m == 9u128 && o == true, 0);
164 | }
165 |
166 | #[test]
167 | fun test_full_mul() {
168 | let (lo, hi) = full_mul(0, 10);
169 | assert!(hi == 0 && lo == 0, 0);
170 |
171 | let (lo, hi) = full_mul(10, 10);
172 | assert!(hi == 0 && lo == 100, 0);
173 |
174 | let (lo, hi) = full_mul(9999, 10);
175 | assert!(hi == 0 && lo == 99990, 0);
176 |
177 | let (lo, hi) = full_mul(MAX_U128, 0);
178 | assert!(hi == 0 && lo == 0, 0);
179 |
180 | let (lo, hi) = full_mul(MAX_U128, 1);
181 | assert!(hi == 0 && lo == MAX_U128, 0);
182 |
183 | let (lo, hi) = full_mul(MAX_U128, 10);
184 | assert!(hi == 9 && lo == 0xfffffffffffffffffffffffffffffff6, 0);
185 |
186 | let (lo, hi) = full_mul(10, MAX_U128);
187 | assert!(hi == 9 && lo == 0xfffffffffffffffffffffffffffffff6, 0);
188 |
189 | let (lo, hi) = full_mul(MAX_U128, MAX_U128);
190 | assert!(hi == 0xfffffffffffffffffffffffffffffffe && lo == 1, 0);
191 | }
192 |
193 | #[test]
194 | fun test_wrapping_mul() {
195 | assert!(wrapping_mul(0, 10) == 0, 0);
196 | assert!(wrapping_mul(10, 0) == 0, 0);
197 | assert!(wrapping_mul(10, 10) == 100, 0);
198 | assert!(wrapping_mul(99999, 10) == 10 * 99999, 0);
199 | assert!(wrapping_mul(MAX_U128, 0) == 0, 0);
200 | assert!(wrapping_mul(MAX_U128, 1) == MAX_U128, 0);
201 | assert!(wrapping_mul(MAX_U128, 10) == 0xfffffffffffffffffffffffffffffff6, 0);
202 | assert!(wrapping_mul(10, MAX_U128) == 0xfffffffffffffffffffffffffffffff6, 0);
203 | assert!(wrapping_mul(MAX_U128, MAX_U128) == 1, 0);
204 | }
205 |
206 | #[test]
207 | fun test_overflowing_mul() {
208 | let (r, o) = overflowing_mul(0, 10);
209 | assert!(r == 0 && o == false, 0);
210 |
211 | let (r, o) = overflowing_mul(10, 10);
212 | assert!(r == 100 && o == false, 0);
213 |
214 | let (r, o) = overflowing_mul(MAX_U128, 10);
215 | assert!(r == 0xfffffffffffffffffffffffffffffff6 && o == true, 0);
216 | }
217 |
218 | #[test]
219 | fun test_leading_zeros() {
220 | let one = leading_zeros(1u128);
221 | let zero = leading_zeros(0u128);
222 | let max = leading_zeros(MAX_U128);
223 | assert!(one == 127, 0);
224 | assert!(zero == 128, 0);
225 | assert!(max == 0, 0);
226 | }
227 |
228 | }
229 |
--------------------------------------------------------------------------------
/clmm/sources/lib/math_u256.move:
--------------------------------------------------------------------------------
1 | module turbos_clmm::math_u256 {
2 | const MASK_U128: u256 = 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;
3 | const MASK_U64: u256 = 0x000000000000000000000000000000000000000000000000ffffffffffffffff;
4 |
5 | public fun div_mod(num: u256, denom: u256): (u256, u256) {
6 | let p = num / denom;
7 | let r: u256 = num - (p * denom);
8 | (p, r)
9 | }
10 |
11 | public fun shlw(n: u256): u256 {
12 | n << 64
13 | }
14 |
15 | public fun shrw(n: u256): u256 {
16 | n >> 64
17 | }
18 |
19 | public fun checked_shlw(n: u256): (u256, bool) {
20 | let mask = 0xffffffffffffffff << 192;
21 | if (n > mask) {
22 | (0, true)
23 | } else {
24 | ((n << 64), false)
25 | }
26 | }
27 |
28 | public fun div_round(num: u256, denom: u256, round_up: bool): u256 {
29 | let p = num / denom;
30 | if (round_up && ((p * denom) != num)) {
31 | p + 1
32 | } else {
33 | p
34 | }
35 | }
36 |
37 | #[test]
38 | fun test_div_round() {
39 | div_round(1, 1, true);
40 | }
41 |
42 | #[test]
43 | fun test_add() {
44 | 1000u256 + 1000u256;
45 | }
46 | }
--------------------------------------------------------------------------------
/clmm/sources/lib/math_u64.move:
--------------------------------------------------------------------------------
1 | module turbos_clmm::math_u64 {
2 | const MAX_U64: u64 = 0xffffffffffffffff;
3 |
4 | const HI_64_MASK: u128 = 0xffffffffffffffff0000000000000000;
5 | const LO_64_MASK: u128 = 0x0000000000000000ffffffffffffffff;
6 |
7 | public fun wrapping_add(n1: u64, n2: u64): u64 {
8 | let (sum, _) = overflowing_add(n1, n2);
9 | sum
10 | }
11 |
12 | public fun overflowing_add(n1: u64, n2: u64): (u64, bool) {
13 | let sum = (n1 as u128) + (n2 as u128);
14 | if (sum > (MAX_U64 as u128)) {
15 | (((sum & LO_64_MASK) as u64), true)
16 | } else {
17 | ((sum as u64), false)
18 | }
19 | }
20 |
21 | public fun wrapping_sub(n1: u64, n2: u64): u64 {
22 | let (result, _) = overflowing_sub(n1, n2);
23 | result
24 | }
25 |
26 | public fun overflowing_sub(n1: u64, n2: u64): (u64, bool) {
27 | if (n1 >= n2) {
28 | ((n1 - n2), false)
29 | } else {
30 | ((MAX_U64 - n2 + n1 + 1), true)
31 | }
32 | }
33 |
34 | public fun wrapping_mul(n1: u64, n2: u64): u64 {
35 | let (m, _) = overflowing_mul(n1, n2);
36 | m
37 | }
38 |
39 | public fun overflowing_mul(n1: u64, n2: u64): (u64, bool) {
40 | let m = (n1 as u128) * (n2 as u128);
41 | (((m & LO_64_MASK) as u64), (m & HI_64_MASK) > 0)
42 | }
43 |
44 | public fun carry_add(n1: u64, n2: u64, carry: u64): (u64, u64) {
45 | assert!(carry <= 1, 0);
46 | let sum = (n1 as u128) + (n2 as u128) + (carry as u128);
47 | if (sum > LO_64_MASK) {
48 | (((sum & LO_64_MASK) as u64), 1)
49 | } else {
50 | ((sum as u64), 0)
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/clmm/sources/lib/string_tools.move:
--------------------------------------------------------------------------------
1 | // Copyright (c) Turbos Finance, Inc.
2 | // SPDX-License-Identifier: MIT
3 |
4 | module turbos_clmm::string_tools {
5 | use std::vector;
6 | use std::bcs;
7 | use std::string::{Self, String};
8 | use sui::math;
9 |
10 | const ERR_DIVIDE_BY_ZERO: u64 = 2000;
11 |
12 | //(owner, tickLower, tickUpper);
13 | public fun get_position_key(
14 | owner: address,
15 | tick_lower_index: u32,
16 | tick_lower_index_is_neg: bool,
17 | tick_upper_index: u32,
18 | tick_upper_index_is_neg: bool,
19 | ): String {
20 | let address_str = address_to_hexstring(&owner);
21 | let tick_lower_index_str = u64_to_string((tick_lower_index as u64));
22 | let tick_lower_index_is_neg_str = if(tick_lower_index_is_neg) string::utf8(b"-") else string::utf8(b"+");
23 | let tick_upper_index_str = u64_to_string((tick_upper_index as u64));
24 | let tick_upper_index_is_neg_str = if(tick_upper_index_is_neg) string::utf8(b"-") else string::utf8(b"+");
25 | string::append(&mut address_str, tick_lower_index_is_neg_str);
26 | string::append(&mut address_str, tick_lower_index_str);
27 | string::append(&mut address_str, tick_upper_index_is_neg_str);
28 | string::append(&mut address_str, tick_upper_index_str);
29 |
30 | address_str
31 | }
32 |
33 | public fun address_to_hexstring(addr: &address): String {
34 | let bytes = bcs::to_bytes(addr);
35 | let char_mappping = &b"0123456789abcdef";
36 |
37 | let result_bytes = &mut b"0x";
38 | let index = 0;
39 | let still_zero = true;
40 |
41 | while (index < vector::length(&bytes)) {
42 | let byte = *vector::borrow(&bytes, index);
43 | index = index + 1;
44 |
45 | if (byte != 0) still_zero = false;
46 | if (still_zero) continue;
47 |
48 | vector::push_back(result_bytes, *vector::borrow(char_mappping, ((byte / 16) as u64)));
49 | vector::push_back(result_bytes, *vector::borrow(char_mappping, ((byte % 16) as u64)));
50 | };
51 |
52 | string::utf8(*result_bytes)
53 | }
54 |
55 | public fun u64_to_hexstring(num: u64): String {
56 | let a1 = num / 16;
57 | let a2 = num % 16;
58 | let alpha = &b"0123456789abcdef";
59 | let r = &mut b"";
60 | vector::push_back(r, *vector::borrow(alpha, a1));
61 | vector::push_back(r, *vector::borrow(alpha, a2));
62 |
63 | string::utf8(*r)
64 | }
65 |
66 | public fun bytes_to_hexstring(bytes: &vector): String {
67 | let r = &mut string::utf8(b"");
68 |
69 | let index = 0;
70 | while (index < vector::length(bytes)) {
71 | let byte = vector::borrow(bytes, index);
72 | string::append(r, u64_to_hexstring((*byte as u64)));
73 |
74 | index = index + 1;
75 | };
76 |
77 | *r
78 | }
79 |
80 | public fun u64_to_string(number: u64): String {
81 | if (number == 0) {
82 | return string::utf8(b"0")
83 | };
84 | let places = 20;
85 | let base = math::pow(10, 19);
86 | let i = places;
87 |
88 | let str = &mut string::utf8(vector[]);
89 |
90 | while (i > 0) {
91 | let quotient = number / base;
92 | if (quotient != 0) {
93 | number = number - quotient * base
94 | };
95 |
96 | if (!string::is_empty(str) || quotient != 0) {
97 | string::append_utf8(str, vector[((quotient + 0x30) as u8)])
98 | };
99 |
100 | base = base / 10;
101 | i = i - 1;
102 | };
103 |
104 | *str
105 | }
106 |
107 | #[test]
108 | public fun test_u64_to_string() {
109 | assert!(
110 | u64_to_string(123456) == string::utf8(b"123456"),
111 | 1
112 | );
113 | assert!(
114 | u64_to_string(18446744073709551615) == string::utf8(b"18446744073709551615"),
115 | 2
116 | );
117 | assert!(
118 | u64_to_string(124563165615123165) == string::utf8(b"124563165615123165"),
119 | 3
120 | );
121 | }
122 |
123 | #[test]
124 | public fun test_address_to_hexstring() {
125 | assert!(address_to_hexstring(&@0xabcdef) == string::utf8(b"0xabcdef"), 1);
126 | }
127 |
128 | #[test]
129 | fun test_u64_to_hexstring() {
130 | assert!(u64_to_hexstring(72) == string::utf8(b"48"), 1);
131 | assert!(u64_to_hexstring(108) == string::utf8(b"6c"), 1);
132 | assert!(u64_to_hexstring(1) == string::utf8(b"01"), 1);
133 | assert!(u64_to_hexstring(0) == string::utf8(b"00"), 1);
134 | }
135 |
136 | #[test]
137 | fun test_zero_string() {
138 | assert!(u64_to_string(0) == string::utf8(b"0"), 0);
139 | }
140 | }
--------------------------------------------------------------------------------
/clmm/sources/partner.move:
--------------------------------------------------------------------------------
1 | module turbos_clmm::partner {
2 | use sui::object::{UID, ID};
3 | use sui::vec_map::{Self};
4 | use std::string::{String};
5 | use sui::bag::{Self};
6 | use sui::tx_context::{TxContext};
7 |
8 | friend turbos_clmm::pool_factory;
9 |
10 | struct PartnerAdminCap has key, store {
11 | id: UID
12 | }
13 |
14 | struct Partners has key {
15 | id: UID,
16 | partners: vec_map::VecMap,
17 | }
18 |
19 | struct PartnerCap has store, key {
20 | id: UID,
21 | name: String,
22 | partner_id: ID,
23 | }
24 |
25 | struct Partner has store, key {
26 | id: UID,
27 | name: String,
28 | ref_fee_rate: u64,
29 | start_time: u64,
30 | end_time: u64,
31 | balances: bag::Bag,
32 | }
33 |
34 | public fun claim_ref_fee(_partner_cap: &PartnerCap, _partner: &mut Partner, _ctx: &mut TxContext) {
35 | abort 0
36 | }
37 |
38 | public fun balances(_partner: &Partner) : &bag::Bag {
39 | abort 0
40 | }
41 |
42 | public fun current_ref_fee_rate(_partner: &Partner, _current_time: u64) : u64 {
43 | abort 0
44 | }
45 |
46 | public fun end_time(_partner: &Partner) : u64 {
47 | abort 0
48 | }
49 |
50 | public fun name(_partner: &Partner) : String {
51 | abort 0
52 | }
53 |
54 | public fun ref_fee_rate(_partner: &Partner) : u64 {
55 | abort 0
56 | }
57 |
58 | public fun start_time(_partner: &Partner) : u64 {
59 | abort 0
60 | }
61 | }
--------------------------------------------------------------------------------
/clmm/sources/pool.move:
--------------------------------------------------------------------------------
1 | // Copyright (c) Turbos Finance, Inc.
2 | // SPDX-License-Identifier: MIT
3 |
4 | module turbos_clmm::pool {
5 | use std::vector;
6 | use std::type_name;
7 | use sui::pay;
8 | use sui::event;
9 | use sui::transfer;
10 | use std::string::{Self, String};
11 | use sui::object::{Self, UID, ID};
12 | use sui::tx_context::{Self, TxContext};
13 | use sui::dynamic_object_field as dof;
14 | use sui::dynamic_field as df;
15 | use sui::balance::{Self, Balance};
16 | use sui::coin::{Self, Coin};
17 | use turbos_clmm::math_tick;
18 | use turbos_clmm::math_swap;
19 | use turbos_clmm::string_tools;
20 | use turbos_clmm::i32::{Self, I32};
21 | use turbos_clmm::i128::{Self, I128};
22 | use turbos_clmm::math_liquidity;
23 | use turbos_clmm::math_sqrt_price;
24 | use turbos_clmm::math_u64;
25 | use turbos_clmm::full_math_u128;
26 | use turbos_clmm::math_u128;
27 | use turbos_clmm::math_bit;
28 | use turbos_clmm::partner::{Partner};
29 | use sui::table::{Self, Table};
30 | use sui::clock::{Self, Clock};
31 |
32 | struct Versioned has key, store {
33 | id: UID,
34 | version: u64,
35 | }
36 |
37 | struct Tick has key, store {
38 | id: UID,
39 | liquidity_gross: u128,
40 | liquidity_net: I128,
41 | fee_growth_outside_a: u128,
42 | fee_growth_outside_b: u128,
43 | reward_growths_outside: vector,
44 | initialized: bool,
45 | }
46 |
47 | struct PositionRewardInfo has store {
48 | reward_growth_inside: u128,
49 | amount_owed: u64,
50 | }
51 |
52 | struct Position has key, store {
53 | id: UID,
54 | // the amount of liquidity owned by this position
55 | liquidity: u128,
56 | // fee growth per unit of liquidity as of the last update to liquidity or fees owed
57 | fee_growth_inside_a: u128,
58 | fee_growth_inside_b: u128,
59 | // the fees owed to the position owner in token0/token1
60 | tokens_owed_a: u64,
61 | tokens_owed_b: u64,
62 | reward_infos: vector,
63 | }
64 |
65 | struct PoolRewardVault has key, store {
66 | id: UID,
67 | coin: Balance,
68 | }
69 |
70 | struct PoolRewardInfo has key, store {
71 | id: UID,
72 | vault: address,
73 | vault_coin_type: String,
74 | emissions_per_second: u128,
75 | growth_global: u128,
76 | manager: address,
77 | }
78 |
79 | struct Pool has key, store {
80 | id: UID,
81 | coin_a: Balance,
82 | coin_b: Balance,
83 | protocol_fees_a: u64,
84 | protocol_fees_b: u64,
85 | sqrt_price: u128,
86 | tick_current_index: I32,
87 | tick_spacing: u32,
88 | max_liquidity_per_tick: u128,
89 | fee: u32,
90 | fee_protocol: u32,
91 | unlocked: bool,
92 | fee_growth_global_a: u128,
93 | fee_growth_global_b: u128,
94 | liquidity: u128,
95 | tick_map: Table,
96 | deploy_time_ms: u64,
97 | reward_infos: vector,
98 | reward_last_updated_time_ms: u64,
99 | }
100 |
101 | struct FlashSwapReceipt {
102 | pool_id: ID,
103 | a_to_b: bool,
104 | pay_amount: u64,
105 | }
106 |
107 | struct FlashSwapReceiptPartner {
108 | pool_id: ID,
109 | a_to_b: bool,
110 | pay_amount: u64,
111 | partner_id: ID,
112 | partner_fee_amount: u64,
113 | }
114 |
115 | struct ComputeSwapState has copy, drop {
116 | amount_a: u128,
117 | amount_b: u128,
118 | amount_specified_remaining: u128,
119 | amount_calculated: u128,
120 | sqrt_price: u128,
121 | tick_current_index: I32,
122 | fee_growth_global: u128,
123 | protocol_fee: u128,
124 | liquidity: u128,
125 | fee_amount: u128,
126 | }
127 |
128 | public fun version(_versioned: &Versioned): u64 {
129 | abort 0
130 | }
131 |
132 | public fun check_version(_versioned: &Versioned) {
133 | abort 0
134 | }
135 |
136 | public fun position_tick(_tick: I32): (I32, u8) {
137 | abort 0
138 | }
139 |
140 | public fun get_tick(
141 | _pool: &Pool,
142 | _index: I32
143 | ): &Tick {
144 | abort 0
145 | }
146 |
147 | public fun get_position(
148 | _pool: &Pool,
149 | _owner: address,
150 | _tick_lower_index: I32,
151 | _tick_upper_index: I32,
152 | ): &Position {
153 | abort 0
154 | }
155 |
156 | public fun check_position_exists(
157 | _pool: &Pool,
158 | _owner: address,
159 | _tick_lower_index: I32,
160 | _tick_upper_index: I32,
161 | ): bool {
162 | abort 0
163 | }
164 |
165 | public fun get_position_key(
166 | _owner: address,
167 | _tick_lower_index: I32,
168 | _tick_upper_index: I32,
169 | ): String {
170 | abort 0
171 | }
172 |
173 | public fun get_pool_fee(
174 | _pool: &Pool,
175 | ): u32 {
176 | abort 0
177 | }
178 |
179 | public fun get_pool_unlocked(
180 | _pool: &Pool,
181 | ): bool {
182 | abort 0
183 | }
184 |
185 | public fun get_pool_sqrt_price(
186 | _pool: &Pool,
187 | ): u128 {
188 | abort 0
189 | }
190 |
191 | public fun get_pool_tick_spacing(
192 | _pool: &Pool,
193 | ): u32 {
194 | abort 0
195 | }
196 |
197 | public fun get_pool_current_index(
198 | _pool: &Pool,
199 | ): I32 {
200 | abort 0
201 | }
202 |
203 | public fun get_pool_liquidity(
204 | _pool: &Pool,
205 | ): u128 {
206 | abort 0
207 | }
208 |
209 | public fun get_tick_liquidity_gross(
210 | _tick: &Tick,
211 | ): u128 {
212 | abort 0
213 | }
214 |
215 | public fun get_tick_liquidity_net(
216 | _tick: &Tick,
217 | ): I128 {
218 | abort 0
219 | }
220 |
221 | public fun get_tick_initialized(
222 | _tick: &Tick,
223 | ): bool {
224 | abort 0
225 | }
226 |
227 | public fun get_tick_fee_growth_outside(
228 | _tick: &Tick,
229 | ): (u128, u128) {
230 | abort 0
231 | }
232 |
233 | public fun get_tick_reward_growths_outside(
234 | _tick: &Tick,
235 | ): vector {
236 | abort 0
237 | }
238 |
239 | public fun get_pool_fee_growth_global(
240 | _pool: &Pool,
241 | ): (u128, u128) {
242 | abort 0
243 | }
244 |
245 | public fun get_pool_reward_last_updated_time_ms(
246 | _pool: &Pool,
247 | ): u64 {
248 | abort 0
249 | }
250 |
251 | public fun get_position_fee_growth_inside_a(
252 | _pool: &Pool,
253 | _key: String
254 | ): u128 {
255 | abort 0
256 | }
257 |
258 | // position.liquidity,
259 | // position.fee_growth_inside_a,
260 | // position.fee_growth_inside_b,
261 | // position.tokens_owed_a,
262 | // position.tokens_owed_b,
263 | // &position.reward_infos
264 | public fun get_position_base_info(
265 | _pool: &Pool,
266 | _key: String
267 | ): (u128, u128, u128, u64, u64, &vector) {
268 | abort 0
269 | }
270 |
271 | public fun get_position_reward_infos(
272 | _pool: &Pool,
273 | _key: String
274 | ): &vector {
275 | abort 0
276 | }
277 |
278 | public fun get_position_reward_info(
279 | _reawrd_info: &PositionRewardInfo
280 | ): (u128, u64) {
281 | abort 0
282 | }
283 |
284 | public fun get_position_fee_growth_inside_b(
285 | _pool: &Pool,
286 | _key: String
287 | ): u128 {
288 | abort 0
289 | }
290 |
291 | public fun get_pool_balance(
292 | _pool: &Pool,
293 | ): (u64, u64) {
294 | abort 0
295 | }
296 |
297 | public fun flash_swap(
298 | _pool: &mut Pool,
299 | _recipient: address,
300 | _a_to_b: bool,
301 | _amount_specified: u128,
302 | _amount_specified_is_input: bool,
303 | _sqrt_price_limit: u128,
304 | _clock: &Clock,
305 | _versioned: &Versioned,
306 | _ctx: &mut TxContext,
307 | ): (Coin, Coin, FlashSwapReceipt) {
308 | abort 0
309 | }
310 |
311 | public fun flash_swap_partner(
312 | _pool: &mut Pool,
313 | _partner: &Partner,
314 | _a_to_b: bool,
315 | _amount_specified: u128,
316 | _amount_specified_is_input: bool,
317 | _sqrt_price_limit: u128,
318 | _clock: &Clock,
319 | _versioned: &Versioned,
320 | _ctx: &mut TxContext,
321 | ): (Coin, Coin, FlashSwapReceiptPartner) {
322 | abort 0
323 | }
324 |
325 | public fun repay_flash_swap(
326 | _pool: &mut Pool,
327 | _coin_a: Coin,
328 | _coin_b: Coin,
329 | _receipt: FlashSwapReceipt,
330 | _versioned: &Versioned
331 | ) {
332 | abort 0
333 | }
334 |
335 | public fun repay_flash_swap_partner(
336 | _pool: &mut Pool,
337 | _partner: &mut Partner,
338 | _coin_a: Coin,
339 | _coin_b: Coin,
340 | _receipt: FlashSwapReceiptPartner,
341 | _versioned: &Versioned,
342 | ) {
343 | abort 0
344 | }
345 |
346 | public fun next_initialized_tick_within_one_word(
347 | _pool: &mut Pool,
348 | _tick_current_index: I32,
349 | _lte: bool
350 | ): (I32, bool) {
351 | abort 0
352 | }
353 | }
--------------------------------------------------------------------------------
/clmm/sources/pool_factory.move:
--------------------------------------------------------------------------------
1 | // Copyright (c) Turbos Finance, Inc.
2 | // SPDX-License-Identifier: MIT
3 |
4 | module turbos_clmm::pool_factory {
5 | use std::type_name::{TypeName};
6 | use sui::vec_map::{VecMap};
7 | use sui::object::{UID, ID};
8 | use sui::tx_context::{TxContext};
9 | use sui::coin::{Coin};
10 | use turbos_clmm::position_manager::{Positions};
11 | use turbos_clmm::position_nft::{TurbosPositionNFT};
12 | use turbos_clmm::fee::{Fee};
13 | use sui::clock::{Clock};
14 | use turbos_clmm::pool::{Versioned, Pool};
15 | use std::string::{String};
16 | use sui::table::{Table};
17 | use std::option::{Option};
18 | use turbos_clmm::acl;
19 |
20 | struct PoolFactoryAdminCap has key, store { id: UID }
21 |
22 | struct PoolSimpleInfo has copy, store {
23 | pool_id: ID,
24 | pool_key: ID,
25 | coin_type_a: TypeName,
26 | coin_type_b: TypeName,
27 | fee_type: TypeName,
28 | fee: u32,
29 | tick_spacing: u32,
30 | }
31 |
32 | struct PoolConfig has key, store {
33 | id: UID,
34 | fee_map: VecMap,
35 | fee_protocol: u32,
36 | pools: Table,
37 | }
38 |
39 | struct AclConfig has key, store {
40 | id: UID,
41 | acl: acl::ACL,
42 | }
43 |
44 | public entry fun deploy_pool_and_mint(
45 | _pool_config: &mut PoolConfig,
46 | _feeType: &Fee,
47 | _sqrt_price: u128,
48 | _positions: &mut Positions,
49 | _coins_a: vector>,
50 | _coins_b: vector>,
51 | _tick_lower_index: u32,
52 | _tick_lower_index_is_neg: bool,
53 | _tick_upper_index: u32,
54 | _tick_upper_index_is_neg: bool,
55 | _amount_a_desired: u64,
56 | _amount_b_desired: u64,
57 | _amount_a_min: u64,
58 | _amount_b_min: u64,
59 | _recipient: address,
60 | _deadline: u64,
61 | _clock: &Clock,
62 | _versioned: &Versioned,
63 | _ctx: &mut TxContext
64 | ) {
65 | abort 0
66 | }
67 |
68 | public fun deploy_pool_and_mint_with_return_(
69 | _pool_config: &mut PoolConfig,
70 | _feeType: &Fee,
71 | _sqrt_price: u128,
72 | _positions: &mut Positions,
73 | _coins_a: vector>,
74 | _coins_b: vector>,
75 | _tick_lower_index: u32,
76 | _tick_lower_index_is_neg: bool,
77 | _tick_upper_index: u32,
78 | _tick_upper_index_is_neg: bool,
79 | _amount_a_desired: u64,
80 | _amount_b_desired: u64,
81 | _amount_a_min: u64,
82 | _amount_b_min: u64,
83 | _deadline: u64,
84 | _clock: &Clock,
85 | _versioned: &Versioned,
86 | _ctx: &mut TxContext
87 | ): (TurbosPositionNFT, Coin, Coin, ID) {
88 | abort 0
89 | }
90 |
91 | public entry fun deploy_pool(
92 | _pool_config: &mut PoolConfig,
93 | _feeType: &Fee,
94 | _sqrt_price: u128,
95 | _clock: &Clock,
96 | _versioned: &Versioned,
97 | _ctx: &mut TxContext
98 | ) {
99 | abort 0
100 | }
101 |
102 | public fun get_pool_id(
103 | _pool_config: &mut PoolConfig,
104 | ): Option {
105 | abort 0
106 | }
107 |
108 | public entry fun toggle_pool_status_v2(
109 | _acl_config: &AclConfig,
110 | _pool: &mut Pool,
111 | _versioned: &Versioned,
112 | _ctx: &mut TxContext,
113 | ) {
114 | abort 0
115 | }
116 | }
--------------------------------------------------------------------------------
/clmm/sources/pool_fetcher.move:
--------------------------------------------------------------------------------
1 | // Copyright (c) Turbos Finance, Inc.
2 | // SPDX-License-Identifier: MIT
3 |
4 | module turbos_clmm::pool_fetcher {
5 | use sui::tx_context::{Self, TxContext};
6 | use sui::clock::{Clock};
7 | use turbos_clmm::pool::{Self, Pool, ComputeSwapState, Versioned};
8 |
9 | public entry fun compute_swap_result(
10 | _pool: &mut Pool,
11 | _a_to_b: bool,
12 | _amount_specified: u128,
13 | _amount_specified_is_input: bool,
14 | _sqrt_price_limit: u128,
15 | _clock: &Clock,
16 | _versioned: &Versioned,
17 | _ctx: &mut TxContext,
18 | ): ComputeSwapState {
19 | abort 0
20 | }
21 |
22 | public entry fun fetch_ticks(
23 | _pool: &mut Pool,
24 | _start: vector,
25 | _start_index_is_neg: bool,
26 | _limit: u64,
27 | _versioned: &Versioned,
28 | ) {
29 | abort 0
30 | }
31 | }
--------------------------------------------------------------------------------
/clmm/sources/position_manager.move:
--------------------------------------------------------------------------------
1 | // Copyright (c) Turbos Finance, Inc.
2 | // SPDX-License-Identifier: MIT
3 |
4 | module turbos_clmm::position_manager {
5 | use std::vector;
6 | use std::type_name::{Self};
7 | use sui::transfer;
8 | use sui::event;
9 | use std::string::{Self, String};
10 | use sui::object::{Self, UID, ID};
11 | use sui::tx_context::{Self, TxContext};
12 | use sui::dynamic_object_field as dof;
13 | use sui::coin::{Coin};
14 | use sui::table::{Self, Table};
15 | use turbos_clmm::i32::{Self, I32};
16 | use turbos_clmm::math_liquidity;
17 | use turbos_clmm::math_tick;
18 | use turbos_clmm::pool::{Self, Pool, PositionRewardInfo as PositionRewardInfoInPool, PoolRewardVault, Versioned};
19 | use turbos_clmm::position_nft::{Self, TurbosPositionNFT};
20 | use sui::clock::{Self, Clock};
21 |
22 | struct PositionRewardInfo has store {
23 | reward_growth_inside: u128,
24 | amount_owed: u64,
25 | }
26 |
27 | struct Position has key, store {
28 | id: UID,
29 | tick_lower_index: I32,
30 | tick_upper_index: I32,
31 | liquidity: u128,
32 | fee_growth_inside_a: u128,
33 | fee_growth_inside_b: u128,
34 | tokens_owed_a: u64,
35 | tokens_owed_b: u64,
36 | reward_infos: vector,
37 | }
38 |
39 | struct Positions has key, store {
40 | id: UID,
41 | nft_minted: u64,
42 | user_position: Table,
43 | nft_name: String,
44 | nft_description: String,
45 | nft_img_url: String,
46 | }
47 |
48 | public fun mint_with_return_(
49 | _pool: &mut Pool,
50 | _positions: &mut Positions,
51 | _coins_a: vector>,
52 | _coins_b: vector>,
53 | _tick_lower_index: u32,
54 | _tick_lower_index_is_neg: bool,
55 | _tick_upper_index: u32,
56 | _tick_upper_index_is_neg: bool,
57 | _amount_a_desired: u64,
58 | _amount_b_desired: u64,
59 | _amount_a_min: u64,
60 | _amount_b_min: u64,
61 | _deadline: u64,
62 | _clock: &Clock,
63 | _versioned: &Versioned,
64 | _ctx: &mut TxContext
65 | ): (TurbosPositionNFT, Coin, Coin) {
66 | abort 0
67 | }
68 |
69 | public fun increase_liquidity_with_return_(
70 | _pool: &mut Pool,
71 | _positions: &mut Positions,
72 | _coins_a: vector>,
73 | _coins_b: vector>,
74 | _nft: &mut TurbosPositionNFT,
75 | _amount_a_desired: u64,
76 | _amount_b_desired: u64,
77 | _amount_a_min: u64,
78 | _amount_b_min: u64,
79 | _deadline: u64,
80 | _clock: &Clock,
81 | _versioned: &Versioned,
82 | _ctx: &mut TxContext
83 | ): (Coin, Coin) {
84 | abort 0
85 | }
86 |
87 | public fun decrease_liquidity_with_return_(
88 | _pool: &mut Pool,
89 | _positions: &mut Positions,
90 | _nft: &mut TurbosPositionNFT,
91 | _liquidity: u128,
92 | _amount_a_min: u64,
93 | _amount_b_min: u64,
94 | _deadline: u64,
95 | _clock: &Clock,
96 | _versioned: &Versioned,
97 | _ctx: &mut TxContext
98 | ): (Coin, Coin) {
99 | abort 0
100 | }
101 |
102 | public entry fun mint(
103 | _pool: &mut Pool,
104 | _positions: &mut Positions,
105 | _coins_a: vector>,
106 | _coins_b: vector>,
107 | _tick_lower_index: u32,
108 | _tick_lower_index_is_neg: bool,
109 | _tick_upper_index: u32,
110 | _tick_upper_index_is_neg: bool,
111 | _amount_a_desired: u64,
112 | _amount_b_desired: u64,
113 | _amount_a_min: u64,
114 | _amount_b_min: u64,
115 | _recipient: address,
116 | _deadline: u64,
117 | _clock: &Clock,
118 | _versioned: &Versioned,
119 | _ctx: &mut TxContext
120 | ) {
121 | abort 0
122 | }
123 |
124 | public entry fun burn(
125 | _positions: &mut Positions,
126 | _nft: TurbosPositionNFT,
127 | _versioned: &Versioned,
128 | _ctx: &mut TxContext
129 | ) {
130 | abort 0
131 | }
132 |
133 | public entry fun increase_liquidity(
134 | _pool: &mut Pool,
135 | _positions: &mut Positions,
136 | _coins_a: vector>,
137 | _coins_b: vector>,
138 | _nft: &mut TurbosPositionNFT,
139 | _amount_a_desired: u64,
140 | _amount_b_desired: u64,
141 | _amount_a_min: u64,
142 | _amount_b_min: u64,
143 | _deadline: u64,
144 | _clock: &Clock,
145 | _versioned: &Versioned,
146 | _ctx: &mut TxContext
147 | ) {
148 | abort 0
149 | }
150 |
151 | public entry fun decrease_liquidity(
152 | _pool: &mut Pool,
153 | _positions: &mut Positions,
154 | _nft: &mut TurbosPositionNFT,
155 | _liquidity: u128,
156 | _amount_a_min: u64,
157 | _amount_b_min: u64,
158 | _deadline: u64,
159 | _clock: &Clock,
160 | _versioned: &Versioned,
161 | _ctx: &mut TxContext
162 | ) {
163 | abort 0
164 | }
165 |
166 | public fun collect_with_return_(
167 | _pool: &mut Pool,
168 | _positions: &mut Positions,
169 | _nft: &mut TurbosPositionNFT,
170 | _amount_a_max: u64,
171 | _amount_b_max: u64,
172 | _recipient: address,
173 | _deadline: u64,
174 | _clock: &Clock,
175 | _versioned: &Versioned,
176 | _ctx: &mut TxContext
177 | ): (Coin, Coin) {
178 | abort 0
179 | }
180 |
181 | public entry fun collect(
182 | _pool: &mut Pool,
183 | _positions: &mut Positions,
184 | _nft: &mut TurbosPositionNFT,
185 | _amount_a_max: u64,
186 | _amount_b_max: u64,
187 | _recipient: address,
188 | _deadline: u64,
189 | _clock: &Clock,
190 | _versioned: &Versioned,
191 | _ctx: &mut TxContext
192 | ) {
193 | abort 0
194 | }
195 |
196 | public fun collect_reward_with_return_(
197 | _pool: &mut Pool,
198 | _positions: &mut Positions,
199 | _nft: &mut TurbosPositionNFT,
200 | _vault: &mut PoolRewardVault,
201 | _reward_index: u64,
202 | _amount_max: u64,
203 | _recipient: address,
204 | _deadline: u64,
205 | _clock: &Clock,
206 | _versioned: &Versioned,
207 | _ctx: &mut TxContext
208 | ): Coin {
209 | abort 0
210 | }
211 |
212 | public entry fun collect_reward(
213 | _pool: &mut Pool,
214 | _positions: &mut Positions,
215 | _nft: &mut TurbosPositionNFT,
216 | _vault: &mut PoolRewardVault,
217 | _reward_index: u64,
218 | _amount_max: u64,
219 | _recipient: address,
220 | _deadline: u64,
221 | _clock: &Clock,
222 | _versioned: &Versioned,
223 | _ctx: &mut TxContext
224 | ) {
225 | abort 0
226 | }
227 |
228 | public fun get_position_info(
229 | _positions: &Positions,
230 | _nft_address: address,
231 | ): (I32, I32, u128) {
232 | abort 0
233 | }
234 | }
--------------------------------------------------------------------------------
/clmm/sources/position_nft.move:
--------------------------------------------------------------------------------
1 | // Copyright (c) Turbos Finance, Inc.
2 | // SPDX-License-Identifier: MIT
3 |
4 | module turbos_clmm::position_nft {
5 | use std::vector;
6 | use sui::transfer;
7 | use sui::url::{Self, Url};
8 | use std::string::{Self, utf8, String};
9 | use sui::object::{Self, ID, UID};
10 | use sui::event;
11 | use sui::display;
12 | use sui::package;
13 | use sui::tx_context::{Self, TxContext};
14 | use std::type_name::{TypeName};
15 |
16 | struct TurbosPositionNFT has key, store {
17 | id: UID,
18 | name: String,
19 | description: String,
20 | img_url: Url,
21 | pool_id: ID,
22 | position_id: ID,
23 | coin_type_a: TypeName,
24 | coin_type_b: TypeName,
25 | fee_type: TypeName,
26 | }
27 |
28 | public fun pool_id(_nft: &TurbosPositionNFT): ID {
29 | abort 0
30 | }
31 |
32 | public fun position_id(_nft: &TurbosPositionNFT): ID {
33 | abort 0
34 | }
35 |
36 | }
--------------------------------------------------------------------------------
/clmm/sources/swap_router.move:
--------------------------------------------------------------------------------
1 | // Copyright (c) Turbos Finance, Inc.
2 | // SPDX-License-Identifier: MIT
3 |
4 | module turbos_clmm::swap_router {
5 | use sui::tx_context::{TxContext};
6 | use turbos_clmm::pool::{Pool, Versioned};
7 | use sui::coin::{Coin};
8 | use sui::clock::{Clock};
9 | use turbos_clmm::partner::{Partner};
10 |
11 | public fun swap_a_b_with_return_(
12 | _pool: &mut Pool,
13 | _coins_a: vector>,
14 | _amount: u64,
15 | _amount_threshold: u64,
16 | _sqrt_price_limit: u128,
17 | _is_exact_in: bool,
18 | _recipient: address,
19 | _deadline: u64,
20 | _clock: &Clock,
21 | _versioned: &Versioned,
22 | _ctx: &mut TxContext
23 | ): (Coin, Coin) {
24 | abort 0
25 | }
26 |
27 | public entry fun swap_a_b(
28 | _pool: &mut Pool,
29 | _coins_a: vector>,
30 | _amount: u64,
31 | _amount_threshold: u64,
32 | _sqrt_price_limit: u128,
33 | _is_exact_in: bool,
34 | _recipient: address,
35 | _deadline: u64,
36 | _clock: &Clock,
37 | _versioned: &Versioned,
38 | _ctx: &mut TxContext
39 | ) {
40 | abort 0
41 | }
42 |
43 | public fun swap_b_a_with_return_(
44 | _pool: &mut Pool,
45 | _coins_b: vector>,
46 | _amount: u64,
47 | _amount_threshold: u64,
48 | _sqrt_price_limit: u128,
49 | _is_exact_in: bool,
50 | _recipient: address,
51 | _deadline: u64,
52 | _clock: &Clock,
53 | _versioned: &Versioned,
54 | _ctx: &mut TxContext
55 | ): (Coin, Coin) {
56 | abort 0
57 | }
58 |
59 | public entry fun swap_b_a(
60 | _pool: &mut Pool,
61 | _coins_b: vector>,
62 | _amount: u64,
63 | _amount_threshold: u64,
64 | _sqrt_price_limit: u128,
65 | _is_exact_in: bool,
66 | _recipient: address,
67 | _deadline: u64,
68 | _clock: &Clock,
69 | _versioned: &Versioned,
70 | _ctx: &mut TxContext
71 | ) {
72 | abort 0
73 | }
74 |
75 | public fun swap_a_b_b_c_with_return_(
76 | _pool_a: &mut Pool,
77 | _pool_b: &mut Pool,
78 | _coins_a: vector>,
79 | _amount: u64,
80 | _amount_threshold: u64,
81 | _sqrt_price_limit_one: u128,
82 | _sqrt_price_limit_two: u128,
83 | _is_exact_in: bool,
84 | _recipient: address,
85 | _deadline: u64,
86 | _clock: &Clock,
87 | _versioned: &Versioned,
88 | _ctx: &mut TxContext
89 | ): (Coin, Coin) {
90 | abort 0
91 | }
92 |
93 | // such as: pool a: BTC/USDC, pool b: USDC/ETH
94 | // if swap BTC to ETH,route is BTC -> USDC -> ETH,fee paid in BTC and USDC
95 | // step one: swap BTC to USDC (a to b), step two: swap USDC to ETH (a to b)
96 | public entry fun swap_a_b_b_c(
97 | _pool_a: &mut Pool,
98 | _pool_b: &mut Pool,
99 | _coins_a: vector>,
100 | _amount: u64,
101 | _amount_threshold: u64,
102 | _sqrt_price_limit_one: u128,
103 | _sqrt_price_limit_two: u128,
104 | _is_exact_in: bool,
105 | _recipient: address,
106 | _deadline: u64,
107 | _clock: &Clock,
108 | _versioned: &Versioned,
109 | _ctx: &mut TxContext
110 | ) {
111 | abort 0
112 | }
113 |
114 | public fun swap_a_b_c_b_with_return_(
115 | _pool_a: &mut Pool,
116 | _pool_b: &mut Pool,
117 | _coins_a: vector>,
118 | _amount: u64,
119 | _amount_threshold: u64,
120 | _sqrt_price_limit_one: u128,
121 | _sqrt_price_limit_two: u128,
122 | _is_exact_in: bool,
123 | _recipient: address,
124 | _deadline: u64,
125 | _clock: &Clock,
126 | _versioned: &Versioned,
127 | _ctx: &mut TxContext
128 | ): (Coin, Coin) {
129 | abort 0
130 | }
131 |
132 | // such as: pool a: BTC/USDC, pool b: ETH/USDC
133 | // if swap BTC to ETH, route is BTC -> USDC -> ETH,fee paid in BTC and USDC
134 | // step one: swap BTC to USDC (a to b), step two: swap USDC to ETH (b to a)
135 | public entry fun swap_a_b_c_b(
136 | _pool_a: &mut Pool,
137 | _pool_b: &mut Pool,
138 | _coins_a: vector>,
139 | _amount: u64,
140 | _amount_threshold: u64,
141 | _sqrt_price_limit_one: u128,
142 | _sqrt_price_limit_two: u128,
143 | _is_exact_in: bool,
144 | _recipient: address,
145 | _deadline: u64,
146 | _clock: &Clock,
147 | _versioned: &Versioned,
148 | _ctx: &mut TxContext
149 | ) {
150 | abort 0
151 | }
152 |
153 | public fun swap_b_a_b_c_with_return_(
154 | _pool_a: &mut Pool,
155 | _pool_b: &mut Pool,
156 | _coins_a: vector>,
157 | _amount: u64,
158 | _amount_threshold: u64,
159 | _sqrt_price_limit_one: u128,
160 | _sqrt_price_limit_two: u128,
161 | _is_exact_in: bool,
162 | _recipient: address,
163 | _deadline: u64,
164 | _clock: &Clock,
165 | _versioned: &Versioned,
166 | _ctx: &mut TxContext
167 | ): (Coin, Coin) {
168 | abort 0
169 | }
170 |
171 | // such as: pool a: USDC/BTC, pool b: USDC/ETH
172 | // if swap BTC to ETH, route is BTC -> USDC -> ETH, fee paid in BTC and USDC
173 | // step one: swap BTC to USDC (b to a), step two: swap USDC to ETH (a to b)
174 | public entry fun swap_b_a_b_c(
175 | _pool_a: &mut Pool,
176 | _pool_b: &mut Pool,
177 | _coins_a: vector>,
178 | _amount: u64,
179 | _amount_threshold: u64,
180 | _sqrt_price_limit_one: u128,
181 | _sqrt_price_limit_two: u128,
182 | _is_exact_in: bool,
183 | _recipient: address,
184 | _deadline: u64,
185 | _clock: &Clock,
186 | _versioned: &Versioned,
187 | _ctx: &mut TxContext
188 | ) {
189 | abort 0
190 | }
191 |
192 | public fun swap_b_a_c_b_with_return_(
193 | _pool_a: &mut Pool,
194 | _pool_b: &mut Pool,
195 | _coins_a: vector>,
196 | _amount: u64,
197 | _amount_threshold: u64,
198 | _sqrt_price_limit_one: u128,
199 | _sqrt_price_limit_two: u128,
200 | _is_exact_in: bool,
201 | _recipient: address,
202 | _deadline: u64,
203 | _clock: &Clock,
204 | _versioned: &Versioned,
205 | _ctx: &mut TxContext
206 | ): (Coin, Coin) {
207 | abort 0
208 | }
209 |
210 | // such as: pool a: USDC/BTC, pool b: ETH/USDC
211 | // if swap BTC to ETH, route is BTC -> USDC -> ETH, fee paid in BTC and USDC
212 | // step one: swap BTC to USDC (b to a), step two: swap USDC to ETH (b to a)
213 | public entry fun swap_b_a_c_b(
214 | _pool_a: &mut Pool,
215 | _pool_b: &mut Pool,
216 | _coins_a: vector>,
217 | _amount: u64,
218 | _amount_threshold: u64,
219 | _sqrt_price_limit_one: u128,
220 | _sqrt_price_limit_two: u128,
221 | _is_exact_in: bool,
222 | _recipient: address,
223 | _deadline: u64,
224 | _clock: &Clock,
225 | _versioned: &Versioned,
226 | _ctx: &mut TxContext
227 | ) {
228 | abort 0
229 | }
230 |
231 | public fun swap_with_partner(
232 | _pool: &mut Pool,
233 | _partner: &mut Partner,
234 | _coin_a: Coin,
235 | _coin_b: Coin,
236 | _a_to_b: bool,
237 | _amount: u64,
238 | _amount_threshold: u64,
239 | _sqrt_price_limit: u128,
240 | _is_exact_in: bool,
241 | _deadline: u64,
242 | _clock: &Clock,
243 | _versioned: &Versioned,
244 | _ctx: &mut TxContext
245 | ): (Coin, Coin) {
246 | abort 0
247 | }
248 | public fun swap_a_b_with_partner(
249 | _pool: &mut Pool,
250 | _partner: &mut Partner,
251 | _coin_a: Coin,
252 | _amount: u64,
253 | _amount_threshold: u64,
254 | _sqrt_price_limit: u128,
255 | _is_exact_in: bool,
256 | _deadline: u64,
257 | _clock: &Clock,
258 | _versioned: &Versioned,
259 | _ctx: &mut TxContext
260 | ): (Coin, Coin) {
261 | abort 0
262 | }
263 |
264 | public fun swap_b_a_with_partner(
265 | _pool: &mut Pool,
266 | _partner: &mut Partner,
267 | _coin_b: Coin,
268 | _amount: u64,
269 | _amount_threshold: u64,
270 | _sqrt_price_limit: u128,
271 | _is_exact_in: bool,
272 | _deadline: u64,
273 | _clock: &Clock,
274 | _versioned: &Versioned,
275 | _ctx: &mut TxContext
276 | ): (Coin, Coin) {
277 | abort 0
278 | }
279 | }
--------------------------------------------------------------------------------