This repository has been archived by the owner on Apr 11, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
price.move
323 lines (300 loc) · 11.3 KB
/
price.move
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
module econia::price {
// Structs >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/// A power of ten, $10^x$.
struct PowerOfTen has drop, store {
/// Absolute value of exponent, $|x|$.
exponent_absolute_value: u8,
/// `true` if $x \geq 0$.
exponent_is_nonnegative: bool
}
// Structs <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// Error codes >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/// Exponent absolute value is out of bounds.
const E_EXPONENT_ABSOLUTE_VALUE_TOO_LARGE: u64 = 0;
/// Price encodes too many digits.
const E_PRICE_TOO_MANY_DIGITS: u64 = 1;
/// Price indicated as zero.
const E_NO_PRICE: u64 = 2;
/// Base amount overflows a `u64`.
const E_BASE_OVERFLOW: u64 = 3;
/// Base amount indicated as zero.
const E_NO_BASE: u64 = 4;
/// Quote amount indicated as zero.
const E_NO_QUOTE: u64 = 5;
/// Quote amount overflows a `u64`.
const E_QUOTE_OVERFLOW: u64 = 6;
/// Exponent of zero is marked as negative.
const E_NOT_NEGATIVE_ZERO_POWER: u64 = 7;
/// Denominator is zero for division operation.
const E_DENOMINATOR_ZERO: u64 = 8;
// Error codes <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// Constants >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/// Base 10 used for decimal pricing.
const BASE_10: u64 = 10;
/// `u64` bitmask with all bits set, generated in Python via
/// `hex(int('1' * 64, 2))`.
const HI_64: u64 = 0xffffffffffffffff;
/// The maximum power of 10 that can fit in a `u64`. Generated in
/// Python via `floor(log(2 ** 64, 10))`.
const MAX_EXPONENT_ABSOLUTE_VALUE: u8 = 19;
/// Maximum price, set to restrict number of significant digits.
const MAX_PRICE: u64 = 999999999;
// Constants <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// Public functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/// Get base amount from given `quote_amount`, `price`, and
/// `tick_size`.
///
/// `base_amount = quote_amount / (price * tick_size)`.
///
/// # Parameters
///
/// * `quote_amount`: Indivisible quote units.
/// * `price`: Number of ticks.
/// * `tick_size`: Tick size.
///
/// # Returns
///
/// * `u64`: Corresponding indivisible base units.
///
/// # Aborts
///
/// * `E_NO_QUOTE`: Quote amount indicated as zero.
/// * `E_NO_PRICE`: Price indicated as zero.
/// * `E_PRICE_TOO_MANY_DIGITS`: Price encodes too many digits.
/// * `E_BASE_OVERFLOW`: Base amount overflows a `u64`.
/// * `E_NO_BASE`: Base amount indicated as zero.
public fun get_base_amount(
quote_amount: u64,
price: u64,
tick_size: PowerOfTen
): u64 {
// Assert nonzero quote amount.
assert!(quote_amount != 0, E_NO_QUOTE);
// Assert nonzero price.
assert!(price != 0, E_NO_PRICE);
// Assert price does not have too many significant digits.
assert!(price <= MAX_PRICE, E_PRICE_TOO_MANY_DIGITS);
let base_amount = divide_with_tick_size_in_divisor(
quote_amount, price, tick_size);
// Assert base amount does not overflow.
assert!(base_amount <= (HI_64 as u128), E_BASE_OVERFLOW);
// Assert nonzero base amount.
assert!(base_amount != 0, E_NO_BASE);
(base_amount as u64) // Return base amount.
}
/// Get price from given `base_amount`, `quote_amount`, and
/// `tick_size`.
///
/// `price = quote_amount / (base_amount * tick_size)`.
///
/// # Parameters
///
/// * `base_amount`: Indivisible base units.
/// * `quote_amount`: Indivisible quote units.
/// * `tick_size`: Tick size.
///
/// # Returns
///
/// * `u64`: Corresponding price.
///
/// # Aborts
///
/// * `E_NO_BASE`: Base amount indicated as zero.
/// * `E_NO_QUOTE`: Quote amount indicated as zero.
/// * `E_PRICE_TOO_MANY_DIGITS`: Price encodes too many digits.
/// * `E_NO_PRICE`: Price indicated as zero.
public fun get_price(
base_amount: u64,
quote_amount: u64,
tick_size: PowerOfTen
): u64 {
// Assert nonzero base amount.
assert!(base_amount != 0, E_NO_BASE);
// Assert nonzero quote amount.
assert!(quote_amount != 0, E_NO_QUOTE);
let price = divide_with_tick_size_in_divisor(
quote_amount, base_amount, tick_size);
// Assert price does not contain too many digits.
assert!(price <= (MAX_PRICE as u128), E_PRICE_TOO_MANY_DIGITS);
// Assert nonzero price.
assert!(price != 0, E_NO_PRICE);
(price as u64) // Return price.
}
/// Get quote amount from given `base_amount`, `price`, and
/// `tick_size`.
///
/// `quote_amount = base_amount * price * tick_size`.
///
/// # Parameters
///
/// * `base_amount`: Indivisible base units.
/// * `price`: Number of ticks.
/// * `tick_size`: Tick size.
///
/// # Returns
///
/// * `u64`: Corresponding indivisible quote units.
///
/// # Aborts
///
/// * `E_NO_BASE`: Base amount indicated as zero.
/// * `E_NO_PRICE`: Price indicated as zero.
/// * `E_PRICE_TOO_MANY_DIGITS`: Price encodes too many digits.
/// * `E_QUOTE_OVERFLOW`: Quote amount overflows a `u64`.
/// * `E_NO_QUOTE`: Quote amount indicated as zero.
public fun get_quote_amount(
base_amount: u64,
price: u64,
tick_size: PowerOfTen
): u64 {
// Assert nonzero base amount.
assert!(base_amount != 0, E_NO_BASE);
// Assert nonzero price.
assert!(price != 0, E_NO_PRICE);
// Assert price does not have too many significant digits.
assert!(price <= MAX_PRICE, E_PRICE_TOO_MANY_DIGITS);
// Calculate product to either multiply or divide.
let product = (base_amount as u128) * (price as u128);
let power_of_ten = // Get power of ten to multiply or divide by.
(ten_to_the(tick_size.exponent_absolute_value) as u128);
// Get quote amount: if tick size is nonnegative, multiply.
let quote_amount = if (tick_size.exponent_is_nonnegative)
((product * power_of_ten)) else
((product / power_of_ten)); // Else divide.
// Assert quote does not overflow.
assert!(quote_amount <= (HI_64 as u128), E_QUOTE_OVERFLOW);
// Assert nonzero quote amount.
assert!(quote_amount != 0, E_NO_QUOTE);
(quote_amount as u64) // Return quote amount.
}
/// Return a new `PowerOfTen`.
///
/// # Parameters
///
/// * `exponent_absolute_value`:
/// `PowerOfTen.exponent_absolute_value`.
/// * `exponent_is_nonnegative`:
/// `PowerOfTen.exponent_is_nonnegative`.
///
/// # Returns
///
/// * `PowerOfTen`: A `PowerOfTen` with indicated fields.
///
/// # Aborts
///
/// * `E_EXPONENT_ABSOLUTE_VALUE_TOO_LARGE`: Exponent absolute value
/// is out of bounds.
/// * `E_NOT_NEGATIVE_ZERO_POWER`: Exponent of zero is marked as
/// negative.
public fun new_power_of_ten(
exponent_absolute_value: u8,
exponent_is_nonnegative: bool
): PowerOfTen {
// Assert exponent absolute value is in bounds.
assert!(exponent_absolute_value <= MAX_EXPONENT_ABSOLUTE_VALUE,
E_EXPONENT_ABSOLUTE_VALUE_TOO_LARGE);
// If exponent absolute value is 0:
if (exponent_absolute_value == 0)
// Assert it is flagged as nonnegative.
assert!(exponent_is_nonnegative, E_NOT_NEGATIVE_ZERO_POWER);
PowerOfTen{exponent_absolute_value, exponent_is_nonnegative}
}
// Public functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// Private functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/// Inner function for both `get_base_amount()` and `get_price()`,
/// which perform similar division operations.
///
/// Divide `numerator` by `denominator`, and divide by `tick_size`
/// again, manipulating operation sequence based sign on `tick_size`
/// exponent.
///
/// # Parameters
///
/// * `numerator`: Numerator for quotient.
/// * `denominator`: Denominator for quotient.
/// * `tick_size`: Tick size to divide by.
///
/// # Returns
///
/// * `u128`: Quotient cast to a `u128`.
///
/// # Aborts
///
/// * `E_DENOMINATOR_ZERO`: Denominator is zero.
///
/// # Overflow commentary
///
/// Since `numerator`, `denominator`, and `power_of_ten` terms are
/// originally `u64` values, there is no way to overflow a `u128`
/// via the product between any of these two terms.
fun divide_with_tick_size_in_divisor(
numerator: u64,
denominator: u64,
tick_size: PowerOfTen
): u128 {
// Assert nonozero denominator.
assert!(denominator != 0, E_DENOMINATOR_ZERO);
// Cast numerator to u128.
let numerator = (numerator as u128);
// Cast denominator to u128.
let denominator = (denominator as u128);
let power_of_ten = // Get power of ten to multiply a term by.
(ten_to_the(tick_size.exponent_absolute_value) as u128);
// If tick size exponent is nonnegative:
if (tick_size.exponent_is_nonnegative) {
// Multiply denominator by the power of ten.
denominator = denominator * power_of_ten;
} else { // If tick size exponent is negative:
// Multiply denominator by the power of ten.
numerator = numerator * power_of_ten;
};
numerator / denominator // Return quotient.
}
/// Return result of ten raised to given `power`.
///
/// # Parameters
///
/// * `power`: Power to raise ten by.
///
/// # Returns
///
/// * `u64`: Ten raised to given `power`.
///
/// # Aborts
///
/// * `E_EXPONENT_ABSOLUTE_VALUE_TOO_LARGE`: Exponent absolute value
/// is out of bounds.
///
/// # Testing
///
/// * `test_ten_to_the`
fun ten_to_the(
power: u8
): u64 {
// Assert exponent absolute value is in bounds.
assert!(power <= MAX_EXPONENT_ABSOLUTE_VALUE,
E_EXPONENT_ABSOLUTE_VALUE_TOO_LARGE);
let result = 1; // Initialize result for zero power.
while (power > 0) { // Loop over power variable:
// Multiply by base.
result = result * BASE_10;
// Decrement power loop counter.
power = power - 1;
};
result // Return result.
}
// Private functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// Tests >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#[test]
fun test_ten_to_the() {
// Verify standard returns.
assert!(ten_to_the(0) == 1, 0);
assert!(ten_to_the(1) == 10, 0);
assert!(ten_to_the(2) == 100, 0);
// Get max power of ten.
let max_power_of_ten = ten_to_the(MAX_EXPONENT_ABSOLUTE_VALUE);
// Assert multiplying it by 10 overflows a u64.
assert!((max_power_of_ten as u128) * 10 > (HI_64 as u128), 0);
}
// Tests <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}