@atomiqlabs/sdk
Version:
atomiq labs SDK for cross-chain swaps between smart chains and bitcoin
215 lines (214 loc) • 7.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseHashValueExact32Bytes = exports.toDecimal = exports.fromDecimal = exports.getTxoHash = exports.randomBytes = exports.toBigInt = exports.bigIntCompare = exports.bigIntMax = exports.bigIntMin = exports.extendAbortController = exports.mapToArray = exports.objectMap = exports.mapArrayToObject = exports.promiseAny = exports.throwIfUndefined = void 0;
const buffer_1 = require("buffer");
const utils_1 = require("@noble/hashes/utils");
const sha2_1 = require("@noble/hashes/sha2");
const base_1 = require("@atomiqlabs/base");
const UserError_1 = require("../errors/UserError");
/**
* Returns a promise that rejects if the passed promise resolves to `undefined` or `null`
*
* @param promise Promise to check resolve value of
* @param msg Optional message to pass to the thrown `Error`
* @category Utilities
*/
function throwIfUndefined(promise, msg) {
return promise.then(val => {
if (val == undefined)
throw new Error(msg ?? "Promise value is undefined!");
return val;
});
}
exports.throwIfUndefined = throwIfUndefined;
/**
* Returns a promise that resolves when any of the passed promises resolves, and rejects if all the underlying
* promises fail with an array of errors returned by the respective promises
*
* @param promises A list of promises
* @category Utilities
*/
function promiseAny(promises) {
return new Promise((resolve, reject) => {
let numRejected = 0;
const rejectReasons = Array(promises.length);
promises.forEach((promise, index) => {
promise.then((val) => {
if (resolve != null)
resolve(val);
resolve = null;
}).catch(err => {
rejectReasons[index] = err;
numRejected++;
if (numRejected === promises.length) {
reject(rejectReasons);
}
});
});
});
}
exports.promiseAny = promiseAny;
/**
* Maps an array to object properties using the translation function
*
* @param array
* @param translator
*/
function mapArrayToObject(array, translator) {
const obj = {};
array.forEach((item) => {
obj[item] = translator(item);
});
return obj;
}
exports.mapArrayToObject = mapArrayToObject;
/**
* Maps a JS object to another JS object based on the translation function, the translation function is called for every
* property (value/key) of the old object and returns the new value of for this property
*
* @param obj
* @param translator
*/
function objectMap(obj, translator) {
const resp = {};
for (let key in obj) {
resp[key] = translator(obj[key], key);
}
return resp;
}
exports.objectMap = objectMap;
/**
* Maps the entries from the map to the array using the translator function
*
* @param map
* @param translator
*/
function mapToArray(map, translator) {
const arr = Array(map.size);
let pointer = 0;
for (let entry of map.entries()) {
arr[pointer++] = translator(entry[0], entry[1]);
}
return arr;
}
exports.mapToArray = mapToArray;
/**
* Creates a new abort controller that will abort if the passed abort signal aborts
*
* @param abortSignal
* @param timeoutSeconds
* @param timeoutMessage
*/
function extendAbortController(abortSignal, timeoutSeconds, timeoutMessage) {
const _abortController = new AbortController();
if (abortSignal != null) {
abortSignal.throwIfAborted();
abortSignal.onabort = () => _abortController.abort(abortSignal.reason);
}
if (timeoutSeconds != null) {
const timeout = setTimeout(() => _abortController.abort(new Error(timeoutMessage ?? "Timed out")), timeoutSeconds * 1000);
_abortController.signal.addEventListener("abort", () => clearTimeout(timeout));
}
return _abortController;
}
exports.extendAbortController = extendAbortController;
function bigIntMin(a, b) {
if (a == null)
return b;
if (b == null)
return a;
return a > b ? b : a;
}
exports.bigIntMin = bigIntMin;
function bigIntMax(a, b) {
if (a == null)
return b;
if (b == null)
return a;
return b > a ? b : a;
}
exports.bigIntMax = bigIntMax;
function bigIntCompare(a, b) {
return a > b ? 1 : a === b ? 0 : -1;
}
exports.bigIntCompare = bigIntCompare;
function toBigInt(value) {
if (value == null)
return undefined;
return BigInt(value);
}
exports.toBigInt = toBigInt;
function randomBytes(bytesLength) {
return buffer_1.Buffer.from((0, utils_1.randomBytes)(bytesLength));
}
exports.randomBytes = randomBytes;
function getTxoHash(outputScriptHex, value) {
return buffer_1.Buffer.from((0, sha2_1.sha256)(buffer_1.Buffer.concat([
base_1.BigIntBufferUtils.toBuffer(BigInt(value), "le", 8),
buffer_1.Buffer.from(outputScriptHex, "hex")
])));
}
exports.getTxoHash = getTxoHash;
function fromDecimal(amount, decimalCount) {
if (amount.includes(".")) {
const [before, after] = amount.split(".");
if (decimalCount < 0) {
return BigInt(before.substring(0, before.length + decimalCount));
}
if (after.length > decimalCount) {
//Cut the last digits
return BigInt((before === "0" ? "" : before) + after.substring(0, decimalCount));
}
return BigInt((before === "0" ? "" : before) + after.padEnd(decimalCount, "0"));
}
else {
if (decimalCount < 0) {
return BigInt(amount.substring(0, amount.length + decimalCount));
}
else {
return BigInt(amount + "0".repeat(decimalCount));
}
}
}
exports.fromDecimal = fromDecimal;
function toDecimal(amount, decimalCount, cut, displayDecimals) {
if (decimalCount <= 0) {
return amount.toString(10) + "0".repeat(-decimalCount);
}
const amountStr = amount.toString(10).padStart(decimalCount + 1, "0");
const splitPoint = amountStr.length - decimalCount;
const decimalPart = amountStr.substring(splitPoint, amountStr.length);
let cutTo = decimalPart.length;
if (cut && cutTo > 0) {
for (let i = decimalPart.length - 1; i--; i >= 0) {
if (decimalPart.charAt(i) === "0") {
cutTo = i;
}
else
break;
}
if (cutTo === 0)
cutTo = 1;
}
if (displayDecimals === 0)
return amountStr.substring(0, splitPoint);
if (displayDecimals != null && cutTo > displayDecimals)
cutTo = displayDecimals;
return amountStr.substring(0, splitPoint) + "." + decimalPart.substring(0, cutTo);
}
exports.toDecimal = toDecimal;
function parseHashValueExact32Bytes(value, variableName) {
let hash;
if (typeof (value) === "string") {
if (value.length !== 64)
throw new UserError_1.UserError(`Invalid ${variableName} length, must be exactly 64 hexadecimal characters!`);
hash = buffer_1.Buffer.from(value, "hex");
}
else {
hash = value;
}
if (hash != null && hash.length !== 32)
throw new UserError_1.UserError(`Invalid ${variableName} length, must be exactly 32 bytes!`);
return hash;
}
exports.parseHashValueExact32Bytes = parseHashValueExact32Bytes;