@pontem/liquidswap-widget
Version:
Liquidswap widget as custom web component
228 lines (190 loc) • 5.21 kB
text/typescript
import Decimal from 'decimal.js';
import { Buffer } from "buffer";
export function d(value?: Decimal.Value): Decimal.Instance {
if (Decimal.isDecimal(value)) {
return value as Decimal;
}
return new Decimal(value === undefined ? 0 : value);
}
export function decimalsMultiplier(decimals?: Decimal.Value): Decimal.Instance {
return d(10).pow(d(decimals).abs());
}
const HEX_REGEXP = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/;
export function checkAddress(
address: any,
options: { leadingZero: boolean } = { leadingZero: true },
): boolean {
if (typeof address !== 'string') {
return false;
}
let str = address;
if (options.leadingZero) {
if (!address.startsWith('0x')) {
return false;
} else {
str = str.substring(2);
}
}
return HEX_REGEXP.test(str);
}
export function checkAptosType(
type: any,
options: { leadingZero: boolean } = { leadingZero: true },
): boolean {
if (typeof type !== 'string') {
return false;
}
let _type = type.replace(/\s/g, '');
const openBracketsCount = _type.match(/</g)?.length ?? 0;
const closeBracketsCount = _type.match(/>/g)?.length ?? 0;
if (openBracketsCount !== closeBracketsCount) {
return false;
}
const genericsString = _type.match(/(<.+>)$/);
const generics = genericsString?.[1]?.match(
/(\w+::\w+::\w+)(?:<.*?>(?!>))?/g,
);
if (generics) {
_type = _type.slice(0, _type.indexOf('<'));
const validGenerics = generics.every((g) => {
const gOpenCount = g.match(/</g)?.length ?? 0;
const gCloseCount = g.match(/>/g)?.length ?? 0;
let t = g;
if (gOpenCount !== gCloseCount) {
t = t.slice(0, -(gCloseCount - gOpenCount));
}
return checkAptosType(t, options);
});
if (!validGenerics) {
return false;
}
}
const parts = _type.split('::');
if (parts.length !== 3) {
return false;
}
return (
checkAddress(parts[0], options) &&
parts[1].length >= 1 &&
parts[2].length >= 1
);
}
const EQUAL = 0;
const LESS_THAN = 1;
const GREATER_THAN = 2;
function cmp(a: number, b: number) {
if (a === b) {
return EQUAL;
} else if (a < b) {
return LESS_THAN;
} else {
return GREATER_THAN;
}
}
function compare(symbolX: string, symbolY: string) {
const lenCmp = cmp(symbolX.length, symbolY.length);
if (lenCmp != EQUAL) {
return lenCmp;
}
let i = 0;
while (i < symbolX.length && i < symbolY.length) {
const elem_cmp = cmp(symbolX.charCodeAt(i), symbolY.charCodeAt(i));
if (elem_cmp != EQUAL) return elem_cmp;
i++;
}
return EQUAL;
}
function cmp_addresses(a: string, b: string) {
if (a.startsWith('0x')) {
a = a.substring(2);
}
if (a.length != 64) {
while (a.length < 64) {
a = '0' + a;
}
}
if (b.startsWith('0x')) {
b = b.substring(2);
}
if (b.length != 64) {
while (b.length < 64) {
b = '0' + b;
}
}
const a_buf = Buffer.from(a, 'hex');
const b_buf = Buffer.from(b, 'hex');
for (let i = 0; i < 32; i++) {
if (a_buf[i] < b_buf[i]) {
return LESS_THAN;
} else if (a_buf[i] > b_buf[i]) {
return GREATER_THAN;
}
}
return EQUAL;
}
function compare_types(coin_x: string, coin_y: string) {
const coin_x_parts = coin_x.split('::').reverse();
const coin_y_parts = coin_y.split('::').reverse();
const coin_x_address = coin_x_parts.pop() as string;
const coin_y_address = coin_y_parts.pop() as string;
for (let i = 0; i < 2; i++) {
const c = compare(coin_x_parts[i], coin_y_parts[i]);
if (c != EQUAL) {
return c;
}
}
return cmp_addresses(coin_x_address, coin_y_address);
}
/**
* Compare sorting between two coin types
*
* @param coin_x string with full address of coin
* @param coin_y string with full address of coin
* @returns boolean
*/
export function is_sorted(coin_x: string, coin_y: string) {
return compare_types(coin_x, coin_y) == LESS_THAN;
}
export const splitValue = (value: string) => {
const spiltValue_ = String(value).split('.');
const decimalLength = spiltValue_[1] && spiltValue_[1].length;
return {
spiltValue_,
lastIndex: Number(decimalLength) - 1,
};
};
export function camelCaseKeysToUnderscore(obj: any) {
if (typeof obj !== 'object') {
return obj;
}
for (const oldName in obj) {
// Camel to underscore
const newName = oldName.replace(/([A-Z])/g, function ($1) {
return '_' + $1.toLowerCase();
});
// Only process if names are different
if (newName != oldName) {
// Check for the old property name to avoid a ReferenceError in strict mode.
// eslint-disable-next-line
if (obj.hasOwnProperty(oldName)) {
obj[newName] = obj[oldName];
delete obj[oldName];
}
}
// Recursion
if (typeof obj[newName] == 'object') {
obj[newName] = camelCaseKeysToUnderscore(obj[newName]);
}
}
return obj;
}
export function getFormattedValidationCode(error: Error) {
return JSON.parse(error.message)
.message.split('Validation Code:')
.pop()
.split('_')
.join(' ')
.toLowerCase();
}
// eslint-disable-next-line @typescript-eslint/no-empty-function
export function nope() {}