@paraswap/dex-lib 4.8.36 → 4.8.37-native-dex-math.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/dex/aave-gsm/config.js +2 -2
- package/build/dex/idex.d.ts +1 -1
- package/build/dex/pancakeswap-v3/pancakeswap-v3-pool.d.ts +2 -0
- package/build/dex/pancakeswap-v3/pancakeswap-v3-pool.js +5 -0
- package/build/dex/pancakeswap-v3/pancakeswap-v3-pool.js.map +1 -1
- package/build/dex/pancakeswap-v3/pancakeswap-v3.d.ts +6 -3
- package/build/dex/pancakeswap-v3/pancakeswap-v3.js +85 -9
- package/build/dex/pancakeswap-v3/pancakeswap-v3.js.map +1 -1
- package/build/dex/solidly-v3/solidly-v3-pool.d.ts +3 -0
- package/build/dex/solidly-v3/solidly-v3-pool.js +8 -0
- package/build/dex/solidly-v3/solidly-v3-pool.js.map +1 -1
- package/build/dex/solidly-v3/solidly-v3.d.ts +5 -2
- package/build/dex/solidly-v3/solidly-v3.js +84 -8
- package/build/dex/solidly-v3/solidly-v3.js.map +1 -1
- package/build/dex/uniswap-v3/scripts/measure-calc-time.js +222 -110
- package/build/dex/uniswap-v3/scripts/measure-calc-time.js.map +1 -1
- package/build/dex/uniswap-v3/types.d.ts +1 -0
- package/build/dex/uniswap-v3/types.js.map +1 -1
- package/build/dex/uniswap-v3/uniswap-v3-pool.d.ts +2 -0
- package/build/dex/uniswap-v3/uniswap-v3-pool.js +5 -0
- package/build/dex/uniswap-v3/uniswap-v3-pool.js.map +1 -1
- package/build/dex/uniswap-v3/uniswap-v3.d.ts +11 -3
- package/build/dex/uniswap-v3/uniswap-v3.js +86 -9
- package/build/dex/uniswap-v3/uniswap-v3.js.map +1 -1
- package/build/dex/uniswap-v4/types.d.ts +1 -0
- package/build/dex/uniswap-v4/uniswap-v4-pool-manager.d.ts +2 -0
- package/build/dex/uniswap-v4/uniswap-v4-pool-manager.js +3 -0
- package/build/dex/uniswap-v4/uniswap-v4-pool-manager.js.map +1 -1
- package/build/dex/uniswap-v4/uniswap-v4-pool.d.ts +3 -0
- package/build/dex/uniswap-v4/uniswap-v4-pool.js +18 -0
- package/build/dex/uniswap-v4/uniswap-v4-pool.js.map +1 -1
- package/build/dex/uniswap-v4/uniswap-v4.d.ts +3 -1
- package/build/dex/uniswap-v4/uniswap-v4.js +74 -14
- package/build/dex/uniswap-v4/uniswap-v4.js.map +1 -1
- package/build/pricing-helper.d.ts +1 -1
- package/build/pricing-helper.js +2 -2
- package/build/pricing-helper.js.map +1 -1
- package/native/Cargo.lock +331 -0
- package/native/Cargo.toml +22 -0
- package/native/build.rs +5 -0
- package/native/package-lock.json +32 -0
- package/native/package.json +20 -0
- package/native/src/config.rs +73 -0
- package/native/src/lib.rs +528 -0
- package/native/src/math/bit_math.rs +177 -0
- package/native/src/math/full_math.rs +217 -0
- package/native/src/math/liquidity_math.rs +72 -0
- package/native/src/math/mod.rs +10 -0
- package/native/src/math/oracle.rs +493 -0
- package/native/src/math/sqrt_price_math.rs +272 -0
- package/native/src/math/swap_math.rs +306 -0
- package/native/src/math/tick.rs +239 -0
- package/native/src/math/tick_bitmap.rs +312 -0
- package/native/src/math/tick_math.rs +321 -0
- package/native/src/math/unsafe_math.rs +67 -0
- package/native/src/pool_state.rs +41 -0
- package/native/src/query_outputs.rs +379 -0
- package/native/src/v4_query_outputs.rs +255 -0
- package/package.json +1 -1
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
use ethnum::U256;
|
|
2
|
+
|
|
3
|
+
/// Returns the index of the most significant bit of the number,
|
|
4
|
+
/// where the least significant bit is at index 0 and the most significant bit is at index 255.
|
|
5
|
+
///
|
|
6
|
+
/// Panics if x is zero.
|
|
7
|
+
pub fn most_significant_bit(x: U256) -> u8 {
|
|
8
|
+
assert!(x > U256::ZERO, "x must be > 0");
|
|
9
|
+
let mut x = x;
|
|
10
|
+
let mut r: u8 = 0;
|
|
11
|
+
|
|
12
|
+
if x >= U256::from_words(1, 0) {
|
|
13
|
+
x >>= 128;
|
|
14
|
+
r += 128;
|
|
15
|
+
}
|
|
16
|
+
if x >= U256::from(0x10000000000000000u128) {
|
|
17
|
+
x >>= 64;
|
|
18
|
+
r += 64;
|
|
19
|
+
}
|
|
20
|
+
if x >= U256::from(0x100000000u128) {
|
|
21
|
+
x >>= 32;
|
|
22
|
+
r += 32;
|
|
23
|
+
}
|
|
24
|
+
if x >= U256::from(0x10000u64) {
|
|
25
|
+
x >>= 16;
|
|
26
|
+
r += 16;
|
|
27
|
+
}
|
|
28
|
+
if x >= U256::from(0x100u64) {
|
|
29
|
+
x >>= 8;
|
|
30
|
+
r += 8;
|
|
31
|
+
}
|
|
32
|
+
if x >= U256::from(0x10u64) {
|
|
33
|
+
x >>= 4;
|
|
34
|
+
r += 4;
|
|
35
|
+
}
|
|
36
|
+
if x >= U256::from(0x4u64) {
|
|
37
|
+
x >>= 2;
|
|
38
|
+
r += 2;
|
|
39
|
+
}
|
|
40
|
+
if x >= U256::from(0x2u64) {
|
|
41
|
+
r += 1;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
r
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/// Returns the index of the least significant bit of the number,
|
|
48
|
+
/// where the least significant bit is at index 0 and the most significant bit is at index 255.
|
|
49
|
+
///
|
|
50
|
+
/// Panics if x is zero.
|
|
51
|
+
pub fn least_significant_bit(x: U256) -> u8 {
|
|
52
|
+
assert!(x > U256::ZERO, "x must be > 0");
|
|
53
|
+
let mut x = x;
|
|
54
|
+
let mut r: u8 = 255;
|
|
55
|
+
|
|
56
|
+
let max_uint128: U256 = U256::new(u128::MAX);
|
|
57
|
+
let max_uint64: U256 = U256::from(u64::MAX);
|
|
58
|
+
let max_uint32: U256 = U256::from(u32::MAX as u64);
|
|
59
|
+
let max_uint16: U256 = U256::from(u16::MAX as u64);
|
|
60
|
+
let max_uint8: U256 = U256::from(u8::MAX as u64);
|
|
61
|
+
|
|
62
|
+
if (x & max_uint128) > U256::ZERO {
|
|
63
|
+
r -= 128;
|
|
64
|
+
} else {
|
|
65
|
+
x >>= 128;
|
|
66
|
+
}
|
|
67
|
+
if (x & max_uint64) > U256::ZERO {
|
|
68
|
+
r -= 64;
|
|
69
|
+
} else {
|
|
70
|
+
x >>= 64;
|
|
71
|
+
}
|
|
72
|
+
if (x & max_uint32) > U256::ZERO {
|
|
73
|
+
r -= 32;
|
|
74
|
+
} else {
|
|
75
|
+
x >>= 32;
|
|
76
|
+
}
|
|
77
|
+
if (x & max_uint16) > U256::ZERO {
|
|
78
|
+
r -= 16;
|
|
79
|
+
} else {
|
|
80
|
+
x >>= 16;
|
|
81
|
+
}
|
|
82
|
+
if (x & max_uint8) > U256::ZERO {
|
|
83
|
+
r -= 8;
|
|
84
|
+
} else {
|
|
85
|
+
x >>= 8;
|
|
86
|
+
}
|
|
87
|
+
if (x & U256::from(0xFu64)) > U256::ZERO {
|
|
88
|
+
r -= 4;
|
|
89
|
+
} else {
|
|
90
|
+
x >>= 4;
|
|
91
|
+
}
|
|
92
|
+
if (x & U256::from(0x3u64)) > U256::ZERO {
|
|
93
|
+
r -= 2;
|
|
94
|
+
} else {
|
|
95
|
+
x >>= 2;
|
|
96
|
+
}
|
|
97
|
+
if (x & U256::ONE) > U256::ZERO {
|
|
98
|
+
r -= 1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
r
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
#[cfg(test)]
|
|
105
|
+
mod tests {
|
|
106
|
+
use super::*;
|
|
107
|
+
|
|
108
|
+
#[test]
|
|
109
|
+
fn test_msb_one() {
|
|
110
|
+
assert_eq!(most_significant_bit(U256::ONE), 0);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
#[test]
|
|
114
|
+
fn test_msb_two() {
|
|
115
|
+
assert_eq!(most_significant_bit(U256::from(2u64)), 1);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
#[test]
|
|
119
|
+
fn test_msb_powers_of_two() {
|
|
120
|
+
for i in 0..=255u8 {
|
|
121
|
+
let x = U256::ONE << i;
|
|
122
|
+
assert_eq!(most_significant_bit(x), i);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
#[test]
|
|
127
|
+
fn test_msb_max() {
|
|
128
|
+
assert_eq!(most_significant_bit(U256::MAX), 255);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
#[test]
|
|
132
|
+
#[should_panic]
|
|
133
|
+
fn test_msb_zero_panics() {
|
|
134
|
+
most_significant_bit(U256::ZERO);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
#[test]
|
|
138
|
+
fn test_lsb_one() {
|
|
139
|
+
assert_eq!(least_significant_bit(U256::ONE), 0);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
#[test]
|
|
143
|
+
fn test_lsb_two() {
|
|
144
|
+
assert_eq!(least_significant_bit(U256::from(2u64)), 1);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#[test]
|
|
148
|
+
fn test_lsb_powers_of_two() {
|
|
149
|
+
for i in 0..=255u8 {
|
|
150
|
+
let x = U256::ONE << i;
|
|
151
|
+
assert_eq!(least_significant_bit(x), i);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
#[test]
|
|
156
|
+
fn test_lsb_max() {
|
|
157
|
+
assert_eq!(least_significant_bit(U256::MAX), 0);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
#[test]
|
|
161
|
+
#[should_panic]
|
|
162
|
+
fn test_lsb_zero_panics() {
|
|
163
|
+
least_significant_bit(U256::ZERO);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
#[test]
|
|
167
|
+
fn test_msb_mixed() {
|
|
168
|
+
assert_eq!(most_significant_bit(U256::from(10u64)), 3);
|
|
169
|
+
assert_eq!(most_significant_bit(U256::from(24u64)), 4);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
#[test]
|
|
173
|
+
fn test_lsb_mixed() {
|
|
174
|
+
assert_eq!(least_significant_bit(U256::from(10u64)), 1);
|
|
175
|
+
assert_eq!(least_significant_bit(U256::from(24u64)), 3);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
use ethnum::U256;
|
|
2
|
+
|
|
3
|
+
/// Calculates floor(a * b / denominator).
|
|
4
|
+
///
|
|
5
|
+
/// The TS version uses BigInt which has arbitrary precision, so `a * b` never
|
|
6
|
+
/// overflows. We replicate this by widening to 512-bit via two U256 halves.
|
|
7
|
+
///
|
|
8
|
+
/// Panics if the result exceeds U256::MAX or denominator is zero.
|
|
9
|
+
pub fn mul_div(a: U256, b: U256, denominator: U256) -> U256 {
|
|
10
|
+
assert!(denominator > U256::ZERO, "denominator must be > 0");
|
|
11
|
+
let (lo, hi) = widening_mul(a, b);
|
|
12
|
+
let (quot, _) = div_512_by_256(lo, hi, denominator);
|
|
13
|
+
quot
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/// Calculates ceil(a * b / denominator).
|
|
17
|
+
///
|
|
18
|
+
/// Panics if the result exceeds U256::MAX or denominator is zero.
|
|
19
|
+
pub fn mul_div_rounding_up(a: U256, b: U256, denominator: U256) -> U256 {
|
|
20
|
+
assert!(denominator > U256::ZERO, "denominator must be > 0");
|
|
21
|
+
// result = (a * b + denominator - 1) / denominator
|
|
22
|
+
let (lo, hi) = widening_mul(a, b);
|
|
23
|
+
// add (denominator - 1) to the 512-bit product
|
|
24
|
+
let addend = denominator - U256::ONE;
|
|
25
|
+
let (lo2, carry) = lo.overflowing_add(addend);
|
|
26
|
+
let hi2 = if carry { hi + U256::ONE } else { hi };
|
|
27
|
+
let (quot, _) = div_512_by_256(lo2, hi2, denominator);
|
|
28
|
+
quot
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// Returns (lo, hi) such that a * b = hi * 2^256 + lo.
|
|
32
|
+
fn widening_mul(a: U256, b: U256) -> (U256, U256) {
|
|
33
|
+
let mask128 = (U256::ONE << 128) - U256::ONE;
|
|
34
|
+
|
|
35
|
+
let a_lo = a & mask128;
|
|
36
|
+
let a_hi = a >> 128;
|
|
37
|
+
let b_lo = b & mask128;
|
|
38
|
+
let b_hi = b >> 128;
|
|
39
|
+
|
|
40
|
+
let p0: U256 = a_lo * b_lo;
|
|
41
|
+
let p1: U256 = a_lo * b_hi;
|
|
42
|
+
let p2: U256 = a_hi * b_lo;
|
|
43
|
+
let p3: U256 = a_hi * b_hi;
|
|
44
|
+
|
|
45
|
+
let lo: U256 = p0;
|
|
46
|
+
let hi: U256 = p3;
|
|
47
|
+
|
|
48
|
+
// Add p1 << 128
|
|
49
|
+
let p1_lo = p1 << 128;
|
|
50
|
+
let p1_hi = p1 >> 128;
|
|
51
|
+
let (lo, c1) = lo.overflowing_add(p1_lo);
|
|
52
|
+
let hi = hi + p1_hi + if c1 { U256::ONE } else { U256::ZERO };
|
|
53
|
+
|
|
54
|
+
// Add p2 << 128
|
|
55
|
+
let p2_lo = p2 << 128;
|
|
56
|
+
let p2_hi = p2 >> 128;
|
|
57
|
+
let (lo, c2) = lo.overflowing_add(p2_lo);
|
|
58
|
+
let hi = hi + p2_hi + if c2 { U256::ONE } else { U256::ZERO };
|
|
59
|
+
|
|
60
|
+
(lo, hi)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// Divides a 512-bit number (lo + hi * 2^256) by a 256-bit denominator.
|
|
64
|
+
/// Returns (quotient, remainder). Panics if quotient overflows U256.
|
|
65
|
+
fn div_512_by_256(lo: U256, hi: U256, d: U256) -> (U256, U256) {
|
|
66
|
+
assert!(d > U256::ZERO, "division by zero");
|
|
67
|
+
|
|
68
|
+
if hi == U256::ZERO {
|
|
69
|
+
return (lo / d, lo % d);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
assert!(hi < d, "mul_div result overflows U256");
|
|
73
|
+
|
|
74
|
+
// Split lo into two 128-bit halves and do two rounds of division.
|
|
75
|
+
let mask128 = (U256::ONE << 128) - U256::ONE;
|
|
76
|
+
let lo_hi = (lo >> 128) & mask128;
|
|
77
|
+
let lo_lo = lo & mask128;
|
|
78
|
+
|
|
79
|
+
// First round: divide (hi * 2^128 + lo_hi) by d
|
|
80
|
+
let (q_hi, r1) = div_384_by_256(lo_hi, hi, d);
|
|
81
|
+
|
|
82
|
+
// Second round: divide (r1 * 2^128 + lo_lo) by d
|
|
83
|
+
let (q_lo, rem) = div_384_by_256(lo_lo, r1, d);
|
|
84
|
+
|
|
85
|
+
let quotient = (q_hi << 128) + q_lo;
|
|
86
|
+
(quotient, rem)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/// Divides (hi * 2^128 + lo_128) by d, where hi < d and lo_128 < 2^128.
|
|
90
|
+
/// Returns (quotient, remainder).
|
|
91
|
+
fn div_384_by_256(lo_128: U256, hi: U256, d: U256) -> (U256, U256) {
|
|
92
|
+
let mask128 = (U256::ONE << 128) - U256::ONE;
|
|
93
|
+
let hi_upper = hi >> 128;
|
|
94
|
+
|
|
95
|
+
if hi_upper == U256::ZERO {
|
|
96
|
+
// hi fits in 128 bits, so hi * 2^128 + lo_128 fits in 256 bits
|
|
97
|
+
let numerator = (hi << 128) | lo_128;
|
|
98
|
+
return (numerator / d, numerator % d);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// hi doesn't fit in 128 bits. Use bit-by-bit long division.
|
|
102
|
+
// The quotient fits in at most ~129 bits (since hi < d).
|
|
103
|
+
let _ = mask128;
|
|
104
|
+
let mut remainder = hi;
|
|
105
|
+
let mut quotient = U256::ZERO;
|
|
106
|
+
|
|
107
|
+
for i in (0..128).rev() {
|
|
108
|
+
let bit = (lo_128 >> i) & U256::ONE;
|
|
109
|
+
|
|
110
|
+
// Check if shifting left would overflow
|
|
111
|
+
let overflow = remainder >> 255 != U256::ZERO;
|
|
112
|
+
remainder = (remainder << 1) | bit;
|
|
113
|
+
|
|
114
|
+
if overflow || remainder >= d {
|
|
115
|
+
remainder = remainder.wrapping_sub(d);
|
|
116
|
+
quotient = quotient | (U256::ONE << i);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
(quotient, remainder)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
#[cfg(test)]
|
|
124
|
+
mod tests {
|
|
125
|
+
use super::*;
|
|
126
|
+
|
|
127
|
+
#[test]
|
|
128
|
+
fn test_mul_div_simple() {
|
|
129
|
+
assert_eq!(
|
|
130
|
+
mul_div(U256::from(6u64), U256::from(7u64), U256::from(3u64)),
|
|
131
|
+
U256::from(14u64)
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
#[test]
|
|
136
|
+
fn test_mul_div_large() {
|
|
137
|
+
assert_eq!(
|
|
138
|
+
mul_div(U256::MAX, U256::ONE, U256::ONE),
|
|
139
|
+
U256::MAX
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
#[test]
|
|
144
|
+
fn test_mul_div_rounding_up_exact() {
|
|
145
|
+
assert_eq!(
|
|
146
|
+
mul_div_rounding_up(U256::from(6u64), U256::from(7u64), U256::from(3u64)),
|
|
147
|
+
U256::from(14u64)
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
#[test]
|
|
152
|
+
fn test_mul_div_rounding_up_rounds() {
|
|
153
|
+
// 5 * 7 / 3 = 35/3 = 11.666... -> ceil = 12
|
|
154
|
+
assert_eq!(
|
|
155
|
+
mul_div_rounding_up(U256::from(5u64), U256::from(7u64), U256::from(3u64)),
|
|
156
|
+
U256::from(12u64)
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
#[test]
|
|
161
|
+
fn test_mul_div_floor() {
|
|
162
|
+
// 5 * 7 / 3 = 35/3 = 11.666... -> floor = 11
|
|
163
|
+
assert_eq!(
|
|
164
|
+
mul_div(U256::from(5u64), U256::from(7u64), U256::from(3u64)),
|
|
165
|
+
U256::from(11u64)
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
#[test]
|
|
170
|
+
fn test_mul_div_large_product() {
|
|
171
|
+
let a = U256::ONE << 200;
|
|
172
|
+
let b = U256::ONE << 200;
|
|
173
|
+
let d = U256::ONE << 200;
|
|
174
|
+
assert_eq!(mul_div(a, b, d), U256::ONE << 200);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
#[test]
|
|
178
|
+
fn test_mul_div_max_times_max() {
|
|
179
|
+
assert_eq!(mul_div(U256::MAX, U256::MAX, U256::MAX), U256::MAX);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
#[test]
|
|
183
|
+
#[should_panic]
|
|
184
|
+
fn test_mul_div_overflow() {
|
|
185
|
+
mul_div(U256::MAX, U256::MAX, U256::ONE);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
#[test]
|
|
189
|
+
fn test_mul_div_rounding_up_large() {
|
|
190
|
+
let a = U256::ONE << 128;
|
|
191
|
+
let b = U256::ONE << 128;
|
|
192
|
+
let d = (U256::ONE << 128) + U256::ONE;
|
|
193
|
+
let result = mul_div_rounding_up(a, b, d);
|
|
194
|
+
assert!(result > U256::ZERO);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
#[test]
|
|
198
|
+
fn test_widening_mul_simple() {
|
|
199
|
+
let (lo, hi) = widening_mul(U256::from(3u64), U256::from(7u64));
|
|
200
|
+
assert_eq!(lo, U256::from(21u64));
|
|
201
|
+
assert_eq!(hi, U256::ZERO);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
#[test]
|
|
205
|
+
fn test_widening_mul_large() {
|
|
206
|
+
let (lo, hi) = widening_mul(U256::MAX, U256::from(2u64));
|
|
207
|
+
assert_eq!(hi, U256::ONE);
|
|
208
|
+
assert_eq!(lo, U256::MAX - U256::ONE);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
#[test]
|
|
212
|
+
fn test_mul_div_uniswap_style() {
|
|
213
|
+
// Test case from Uniswap V3: mulDiv(Q128, Q128, Q128) = Q128
|
|
214
|
+
let q128 = U256::ONE << 128;
|
|
215
|
+
assert_eq!(mul_div(q128, q128, q128), q128);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
use ethnum::{I256, U256};
|
|
2
|
+
|
|
3
|
+
/// Adds a signed liquidity delta to an unsigned liquidity value.
|
|
4
|
+
///
|
|
5
|
+
/// In Solidity, when y < 0:
|
|
6
|
+
/// z = x - uint128(-y); require(z < x)
|
|
7
|
+
/// When y >= 0:
|
|
8
|
+
/// z = x + uint128(y); require(z >= x)
|
|
9
|
+
///
|
|
10
|
+
/// Panics with "LS" if y < 0 and the subtraction underflows.
|
|
11
|
+
/// Panics with "LA" if y >= 0 and the addition overflows.
|
|
12
|
+
pub fn add_delta(x: U256, y: I256) -> U256 {
|
|
13
|
+
let mask_128: U256 = (U256::ONE << 128) - U256::ONE;
|
|
14
|
+
|
|
15
|
+
if y < I256::ZERO {
|
|
16
|
+
// _y = BigInt.asUintN(128, -y)
|
|
17
|
+
// (-y) is positive I256; reinterpret as U256 and mask to 128 bits
|
|
18
|
+
let neg_y_u256 = (-y).as_u256();
|
|
19
|
+
let _y = neg_y_u256 & mask_128;
|
|
20
|
+
let z = x.checked_sub(_y).expect("LS");
|
|
21
|
+
assert!(z < x, "LS");
|
|
22
|
+
z
|
|
23
|
+
} else {
|
|
24
|
+
// _y = BigInt.asUintN(128, y)
|
|
25
|
+
let _y = y.as_u256() & mask_128;
|
|
26
|
+
let z = x.checked_add(_y).expect("LA");
|
|
27
|
+
assert!(z >= x, "LA");
|
|
28
|
+
z
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#[cfg(test)]
|
|
33
|
+
mod tests {
|
|
34
|
+
use super::*;
|
|
35
|
+
|
|
36
|
+
#[test]
|
|
37
|
+
fn test_add_positive_delta() {
|
|
38
|
+
let x = U256::from(100u64);
|
|
39
|
+
let y = I256::new(50);
|
|
40
|
+
assert_eq!(add_delta(x, y), U256::from(150u64));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#[test]
|
|
44
|
+
fn test_add_negative_delta() {
|
|
45
|
+
let x = U256::from(100u64);
|
|
46
|
+
let y = I256::new(-50);
|
|
47
|
+
assert_eq!(add_delta(x, y), U256::from(50u64));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#[test]
|
|
51
|
+
fn test_add_zero_delta() {
|
|
52
|
+
let x = U256::from(100u64);
|
|
53
|
+
let y = I256::ZERO;
|
|
54
|
+
assert_eq!(add_delta(x, y), U256::from(100u64));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
#[test]
|
|
58
|
+
#[should_panic(expected = "LS")]
|
|
59
|
+
fn test_subtract_too_much() {
|
|
60
|
+
let x = U256::from(50u64);
|
|
61
|
+
let y = I256::new(-100);
|
|
62
|
+
add_delta(x, y);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#[test]
|
|
66
|
+
#[should_panic(expected = "LA")]
|
|
67
|
+
fn test_add_overflow() {
|
|
68
|
+
let x = U256::MAX;
|
|
69
|
+
let y = I256::new(1);
|
|
70
|
+
add_delta(x, y);
|
|
71
|
+
}
|
|
72
|
+
}
|