├── .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 | } --------------------------------------------------------------------------------