-
Notifications
You must be signed in to change notification settings - Fork 1
[ENG-284] Port the price crate to the ts-sdk
#100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5e8fb4a
302f9a6
85d62cf
ccd6b4d
9039dce
bf9a12b
63ae612
fcc1845
eff74a6
bb2d58a
21229a6
462425b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,6 @@ | ||
| export * from "./dropset-interface"; | ||
| export * from "./generated"; | ||
| export * from "./price"; | ||
| export * from "./rust-types"; | ||
| export * from "./types"; | ||
| export * from "./utils"; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| import { Decimal } from "decimal.js"; | ||
| import { | ||
| ensureU8, | ||
| ensureU64, | ||
| type U8, | ||
| type U32, | ||
| type U64, | ||
| } from "../rust-types"; | ||
| import { decodedPriceToDecimal, decodePrice } from "./decoded-price"; | ||
| import { PriceError } from "./error"; | ||
| import { | ||
| BIAS, | ||
| normalizePriceMantissa, | ||
| UNBIASED_MAX, | ||
| UNBIASED_MIN, | ||
| } from "./lib"; | ||
|
|
||
| /** Multiply `value` by `10^pow`. Port of `decimal_pow10` in `price/src/client_helpers.rs`. */ | ||
| export function decimalPow10(value: Decimal, pow: number): Decimal { | ||
| if (pow === 0) return value; | ||
| return value.times(new Decimal(10).pow(pow)); | ||
| } | ||
|
|
||
| /** Port of `try_to_biased_exponent` in `price/src/client_helpers.rs`. */ | ||
| export function toBiasedExponent(unbiased: number): U8 { | ||
| if (unbiased < UNBIASED_MIN || unbiased > UNBIASED_MAX) { | ||
| throw new Error(PriceError.InvalidBiasedExponent); | ||
| } | ||
| return ensureU8(unbiased + BIAS); | ||
| } | ||
|
|
||
| /** Port of `atoms_to_ui_amount` in `price/src/client_helpers.rs`. */ | ||
| export function atomsToUiAmount( | ||
| atomsAmount: bigint, | ||
| mintDecimals: number | bigint, | ||
| ): Decimal { | ||
| const dec = ensureU8(mintDecimals); | ||
| return decimalPow10(new Decimal(atomsAmount.toString()), -dec); | ||
| } | ||
|
|
||
| /** | ||
| * Convert a UI price (human-readable quote/base) to an atoms-denominated price, | ||
| * accounting for differing base/quote decimals. | ||
| * | ||
| * `atomsPrice = uiPrice * 10^(quoteDecimals - baseDecimals)` | ||
| * | ||
| * Port of `ui_price_to_atoms_price` in `price/src/client_helpers.rs`. | ||
| */ | ||
| export function uiPriceToAtomsPrice( | ||
| uiPrice: Decimal, | ||
| baseDecimals: number | bigint, | ||
| quoteDecimals: number | bigint, | ||
| ): Decimal { | ||
| const base = ensureU8(baseDecimals); | ||
| const quote = ensureU8(quoteDecimals); | ||
| return decimalPow10(uiPrice, quote - base); | ||
| } | ||
|
|
||
| /** Port of `try_encoded_u32_to_decoded_decimal` in `price/src/client_helpers.rs`. */ | ||
| export function encodedU32ToDecimal(encodedU32: number | bigint): Decimal { | ||
| return decodedPriceToDecimal(decodePrice(encodedU32)); | ||
| } | ||
|
|
||
| /** Port of `get_sig_figs` in `price/src/client_helpers.rs`. */ | ||
| function getSigFigs(value: bigint): { scalar: bigint; pow: number } { | ||
| if (value === 0n) throw new Error(PriceError.AmountCannotBeZero); | ||
| let x = value; | ||
| let pow = 0; | ||
| while (x % 10n === 0n) { | ||
| x /= 10n; | ||
| pow += 1; | ||
| } | ||
| return { scalar: x, pow }; | ||
| } | ||
|
|
||
| /** | ||
| * Convert a decimal price and base-atoms order size into `OrderInfoArgs`-equivalent values. | ||
| * | ||
| * Port of `to_order_info_args` in `price/src/client_helpers.rs`. | ||
| */ | ||
| export function toOrderInfoArgs( | ||
| price: Decimal, | ||
| orderSizeBaseAtoms: bigint, | ||
| ): { | ||
| priceMantissa: U32; | ||
| baseScalar: U64; | ||
| baseExponentBiased: U8; | ||
| quoteExponentBiased: U8; | ||
| } { | ||
| const { mantissa, scale: priceExponent } = normalizePriceMantissa(price); | ||
|
|
||
| if (orderSizeBaseAtoms === 0n) throw new Error(PriceError.AmountCannotBeZero); | ||
| ensureU64(orderSizeBaseAtoms); | ||
|
|
||
| const { scalar: baseScalar, pow: baseExponentUnbiased } = | ||
| getSigFigs(orderSizeBaseAtoms); | ||
| const quoteExponentUnbiased = priceExponent + baseExponentUnbiased; | ||
|
|
||
| return { | ||
| priceMantissa: mantissa.value, | ||
| baseScalar: ensureU64(baseScalar), | ||
| baseExponentBiased: toBiasedExponent(baseExponentUnbiased), | ||
| quoteExponentBiased: toBiasedExponent(quoteExponentUnbiased), | ||
| }; | ||
xbtmatt marked this conversation as resolved.
Show resolved
Hide resolved
xbtmatt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| import { Decimal } from "decimal.js"; | ||
| import { ensureU8, ensureU32, type U8 } from "../rust-types"; | ||
| import { decimalPow10 } from "./client-helpers"; | ||
| import { ENCODED_PRICE_INFINITY, ENCODED_PRICE_ZERO } from "./encoded-price"; | ||
| import { PriceError } from "./error"; | ||
| import { BIAS, PRICE_MANTISSA_BITS, PRICE_MANTISSA_MASK } from "./lib"; | ||
|
Comment on lines
+1
to
+6
|
||
| import { | ||
| type ValidatedPriceMantissa, | ||
| validatePriceMantissa, | ||
| } from "./validated-mantissa"; | ||
|
|
||
| /** | ||
| * An enum representing a decoded `EncodedPrice`. | ||
| * | ||
| * Port of `DecodedPrice` in `price/src/decoded_price.rs`. | ||
| */ | ||
| export type DecodedPrice = | ||
| | { kind: "zero" } | ||
| | { kind: "infinity" } | ||
| | { | ||
| kind: "value"; | ||
| biasedExponent: U8; | ||
| mantissa: ValidatedPriceMantissa; | ||
| }; | ||
|
|
||
| /** Port of `DecodedPrice::try_from(EncodedPrice)` in `price/src/decoded_price.rs`. */ | ||
| export function decodePrice(encoded: number | bigint): DecodedPrice { | ||
| const v = ensureU32(encoded); | ||
| if (v === ENCODED_PRICE_ZERO) return { kind: "zero" }; | ||
| if (v === ENCODED_PRICE_INFINITY) return { kind: "infinity" }; | ||
|
|
||
| const biasedExponent = ensureU8(v >>> PRICE_MANTISSA_BITS); | ||
| const mantissa = validatePriceMantissa(v & PRICE_MANTISSA_MASK); | ||
| return { kind: "value", biasedExponent, mantissa }; | ||
| } | ||
|
|
||
| /** Port of `Decimal::try_from(DecodedPrice)` in `price/src/decoded_price.rs`. */ | ||
| export function decodedPriceToDecimal(decoded: DecodedPrice): Decimal { | ||
| switch (decoded.kind) { | ||
| case "zero": | ||
| return new Decimal(0); | ||
| case "infinity": | ||
| throw new Error(PriceError.InfinityIsNotADecimal); | ||
| case "value": | ||
| return decimalPow10( | ||
| new Decimal(decoded.mantissa.value), | ||
| decoded.biasedExponent - BIAS, | ||
| ); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import { ensureU8, type U32, U32_MAX } from "../rust-types"; | ||
| import { PriceError } from "./error"; | ||
| import { PRICE_EXPONENT_MAX, PRICE_MANTISSA_BITS } from "./lib"; | ||
| import type { ValidatedPriceMantissa } from "./validated-mantissa"; | ||
|
|
||
| /** | ||
| * An encoded price packed into a u32: `[exponent_bits | mantissa_bits]`. | ||
| * | ||
| * Port of `EncodedPrice` in `price/src/encoded_price.rs`. | ||
| */ | ||
| export type EncodedPrice = U32; | ||
|
|
||
| const ENCODED_PRICE_INFINITY = U32_MAX as EncodedPrice; | ||
| const ENCODED_PRICE_ZERO = 0 as EncodedPrice; | ||
|
|
||
| export { ENCODED_PRICE_INFINITY, ENCODED_PRICE_ZERO }; | ||
|
|
||
| /** Port of `EncodedPrice::new` in `price/src/encoded_price.rs`. */ | ||
| export function encodePrice( | ||
| mantissa: ValidatedPriceMantissa, | ||
| biasedExponent: number | bigint, | ||
| ): EncodedPrice { | ||
| const exp = ensureU8(biasedExponent); | ||
| if (exp > PRICE_EXPONENT_MAX) { | ||
| throw new Error(PriceError.InvalidBiasedExponent); | ||
| } | ||
| return (((exp << PRICE_MANTISSA_BITS) | mantissa.value) >>> | ||
| 0) as EncodedPrice; | ||
| } | ||
xbtmatt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| export function isEncodedPriceInfinity(encoded: EncodedPrice): boolean { | ||
| return encoded === ENCODED_PRICE_INFINITY; | ||
| } | ||
|
|
||
| export function isEncodedPriceZero(encoded: EncodedPrice): boolean { | ||
| return encoded === ENCODED_PRICE_ZERO; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| /** Port of `OrderInfoError` in `price/src/error.rs`. */ | ||
| export enum PriceError { | ||
| ExponentUnderflow = "ExponentUnderflow", | ||
| ArithmeticOverflow = "ArithmeticOverflow", | ||
| InvalidPriceMantissa = "InvalidPriceMantissa", | ||
| InvalidBiasedExponent = "InvalidBiasedExponent", | ||
| InfinityIsNotADecimal = "InfinityIsNotADecimal", | ||
| AmountCannotBeZero = "AmountCannotBeZero", | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| export * from "./client-helpers"; | ||
| export * from "./decoded-price"; | ||
| export * from "./encoded-price"; | ||
| export * from "./error"; | ||
| export * from "./lib"; | ||
| export * from "./utils"; | ||
| export * from "./validated-mantissa"; |
Uh oh!
There was an error while loading. Please reload this page.