mirror of
https://github.com/haveno-dex/haveno-ts.git
synced 2024-12-28 08:49:39 -05:00
update to monero-ts v0.9.2 with typescript
This commit is contained in:
parent
c6eb746e86
commit
90f59155e1
8
dist/utils/HavenoUtils.d.ts
vendored
8
dist/utils/HavenoUtils.d.ts
vendored
@ -74,17 +74,17 @@ export default class HavenoUtils {
|
||||
/**
|
||||
* Convert XMR to atomic units.
|
||||
*
|
||||
* @param {number|string} amountXmr - amount in XMR to convert to atomic units
|
||||
* @return {BigInt} amount in atomic units
|
||||
* @param {number | string} amountXmr - amount in XMR to convert to atomic units
|
||||
* @return {bigint} amount in atomic units
|
||||
*/
|
||||
static xmrToAtomicUnits(amountXmr: number | string): bigint;
|
||||
/**
|
||||
* Convert atomic units to XMR.
|
||||
*
|
||||
* @param {BigInt|string} amountAtomicUnits - amount in atomic units to convert to XMR
|
||||
* @param {bigint | string} amountAtomicUnits - amount in atomic units to convert to XMR
|
||||
* @return {number} amount in XMR
|
||||
*/
|
||||
static atomicUnitsToXmr(amountAtomicUnits: BigInt | string): number;
|
||||
static atomicUnitsToXmr(amountAtomicUnits: bigint | string): number;
|
||||
/**
|
||||
* Get a validated payment method id from a string or form id.
|
||||
*
|
||||
|
10
dist/utils/HavenoUtils.js
vendored
10
dist/utils/HavenoUtils.js
vendored
@ -107,14 +107,12 @@ class HavenoUtils {
|
||||
/**
|
||||
* Convert XMR to atomic units.
|
||||
*
|
||||
* @param {number|string} amountXmr - amount in XMR to convert to atomic units
|
||||
* @return {BigInt} amount in atomic units
|
||||
* @param {number | string} amountXmr - amount in XMR to convert to atomic units
|
||||
* @return {bigint} amount in atomic units
|
||||
*/
|
||||
static xmrToAtomicUnits(amountXmr) {
|
||||
if (typeof amountXmr === "number")
|
||||
amountXmr = "" + amountXmr;
|
||||
else if (typeof amountXmr !== "string")
|
||||
throw new Error("Must provide XMR amount as a string or js number to convert to atomic units");
|
||||
let decimalDivisor = 1;
|
||||
let decimalIdx = amountXmr.indexOf('.');
|
||||
if (decimalIdx > -1) {
|
||||
@ -126,14 +124,12 @@ class HavenoUtils {
|
||||
/**
|
||||
* Convert atomic units to XMR.
|
||||
*
|
||||
* @param {BigInt|string} amountAtomicUnits - amount in atomic units to convert to XMR
|
||||
* @param {bigint | string} amountAtomicUnits - amount in atomic units to convert to XMR
|
||||
* @return {number} amount in XMR
|
||||
*/
|
||||
static atomicUnitsToXmr(amountAtomicUnits) {
|
||||
if (typeof amountAtomicUnits === "string")
|
||||
amountAtomicUnits = BigInt(amountAtomicUnits);
|
||||
else if (typeof amountAtomicUnits !== "bigint")
|
||||
throw new Error("Must provide atomic units as BigInt or string to convert to XMR");
|
||||
const quotient = amountAtomicUnits / HavenoUtils.AU_PER_XMR;
|
||||
const remainder = amountAtomicUnits % HavenoUtils.AU_PER_XMR;
|
||||
return Number(quotient) + Number(remainder) / Number(HavenoUtils.AU_PER_XMR);
|
||||
|
2
dist/utils/HavenoUtils.js.map
vendored
2
dist/utils/HavenoUtils.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/utils/TaskLooper.js
vendored
2
dist/utils/TaskLooper.js
vendored
@ -20,6 +20,8 @@ class TaskLooper {
|
||||
* @param {int} periodInMs the loop period in milliseconds
|
||||
*/
|
||||
start(periodInMs) {
|
||||
if (periodInMs <= 0)
|
||||
throw new Error("Looper period must be greater than 0 ms");
|
||||
if (this._isStarted)
|
||||
return;
|
||||
this._isStarted = true;
|
||||
|
2
dist/utils/TaskLooper.js.map
vendored
2
dist/utils/TaskLooper.js.map
vendored
@ -1 +1 @@
|
||||
{"version":3,"file":"TaskLooper.js","sourceRoot":"","sources":["../../src/utils/TaskLooper.ts"],"names":[],"mappings":";;AAAA;;GAEG;AACH,MAAqB,UAAU;IAO7B;;;;OAIG;IACH,YAAY,EAAuB;QACjC,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QACd,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,UAAkB;QACtB,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO;QAC5B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,IAAI;QACF,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACzF,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,YAAY,CAAC,IAAI,CAAC,QAAS,CAAC,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,UAAkB;QAC/B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,OAAO,IAAI,CAAC,UAAU,EAAE;YACtB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7B,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;YACjB,IAAI,IAAI,CAAC,UAAU;gBAAE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACtI;QACD,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IAC1B,CAAC;CACF;AAhDD,6BAgDC"}
|
||||
{"version":3,"file":"TaskLooper.js","sourceRoot":"","sources":["../../src/utils/TaskLooper.ts"],"names":[],"mappings":";;AAAA;;GAEG;AACH,MAAqB,UAAU;IAO7B;;;;OAIG;IACH,YAAY,EAAuB;QACjC,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QACd,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,UAAkB;QACtB,IAAI,UAAU,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAChF,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO;QAC5B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,IAAI;QACF,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACzF,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,YAAY,CAAC,IAAI,CAAC,QAAS,CAAC,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,UAAkB;QAC/B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,OAAO,IAAI,CAAC,UAAU,EAAE;YACtB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7B,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;YACjB,IAAI,IAAI,CAAC,UAAU;gBAAE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACtI;QACD,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IAC1B,CAAC;CACF;AAjDD,6BAiDC"}
|
534
package-lock.json
generated
534
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -47,7 +47,7 @@
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||
"jest": "^26.6.0",
|
||||
"monero-javascript": "^0.8.0",
|
||||
"monero-ts": "0.9.2",
|
||||
"typedoc": "^0.23.26",
|
||||
"typedoc-plugin-missing-exports": "^1.0.0",
|
||||
"typedoc-plugin-rename-defaults": "^0.6.4",
|
||||
|
@ -1,6 +1,6 @@
|
||||
// --------------------------------- IMPORTS ----------------------------------
|
||||
|
||||
// import haveno types
|
||||
// haveno imports
|
||||
import HavenoClient from "./HavenoClient";
|
||||
import HavenoError from "./utils/HavenoError";
|
||||
import HavenoUtils from "./utils/HavenoUtils";
|
||||
@ -10,15 +10,6 @@ import { XmrDestination, XmrTx, XmrIncomingTransfer, XmrOutgoingTransfer } from
|
||||
import AuthenticationStatus = UrlConnection.AuthenticationStatus;
|
||||
import OnlineStatus = UrlConnection.OnlineStatus;
|
||||
|
||||
// import monero-javascript
|
||||
const monerojs = require("monero-javascript"); // TODO (woodser): support typescript and `npm install @types/monero-javascript` in monero-javascript
|
||||
const GenUtils = monerojs.GenUtils;
|
||||
const BigInteger = monerojs.BigInteger;
|
||||
const MoneroTxConfig = monerojs.MoneroTxConfig;
|
||||
const MoneroDestination = monerojs.MoneroDestination;
|
||||
const MoneroUtils = monerojs.MoneroUtils;
|
||||
const TaskLooper = monerojs.TaskLooper;
|
||||
|
||||
// other imports
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
@ -26,6 +17,7 @@ import net from "net";
|
||||
import assert from "assert";
|
||||
import console from "console"; // import console because jest swallows messages in real time
|
||||
import * as os from 'os';
|
||||
import * as moneroTs from "monero-ts";
|
||||
|
||||
// ------------------------------ TEST CONFIG ---------------------------------
|
||||
|
||||
@ -40,16 +32,16 @@ const startupHavenods: HavenoClient[] = [];
|
||||
let arbitrator: HavenoClient;
|
||||
let user1: HavenoClient;
|
||||
let user2: HavenoClient;
|
||||
let monerod: any;
|
||||
let fundingWallet: any;
|
||||
let user1Wallet: any;
|
||||
let user2Wallet: any;
|
||||
let monerod: moneroTs.MoneroDaemon;
|
||||
let fundingWallet: moneroTs.MoneroWalletRpc;
|
||||
let user1Wallet: moneroTs.MoneroWalletRpc;
|
||||
let user2Wallet: moneroTs.MoneroWalletRpc;
|
||||
|
||||
// default test configuration
|
||||
const TestConfig = {
|
||||
logLevel: 2,
|
||||
baseCurrencyNetwork: getBaseCurrencyNetwork(),
|
||||
networkType: getBaseCurrencyNetwork() == BaseCurrencyNetwork.XMR_MAINNET ? monerojs.MoneroNetworkType.MAINNET : getBaseCurrencyNetwork() == BaseCurrencyNetwork.XMR_LOCAL ? monerojs.MoneroNetworkType.TESTNET : monerojs.MoneroNetworkType.STAGENET,
|
||||
networkType: getBaseCurrencyNetwork() == BaseCurrencyNetwork.XMR_MAINNET ? moneroTs.MoneroNetworkType.MAINNET : getBaseCurrencyNetwork() == BaseCurrencyNetwork.XMR_LOCAL ? moneroTs.MoneroNetworkType.TESTNET : moneroTs.MoneroNetworkType.STAGENET,
|
||||
moneroBinsDir: "../haveno/.localnet",
|
||||
testDataDir: "./testdata",
|
||||
haveno: {
|
||||
@ -113,7 +105,7 @@ const TestConfig = {
|
||||
}
|
||||
],
|
||||
maxFee: HavenoUtils.xmrToAtomicUnits(0.5), // local testnet fees can be relatively high
|
||||
minSecurityDeposit: MoneroUtils.xmrToAtomicUnits(0.1),
|
||||
minSecurityDeposit: moneroTs.MoneroUtils.xmrToAtomicUnits(0.1),
|
||||
maxAdjustmentPct: 0.2,
|
||||
daemonPollPeriodMs: 5000,
|
||||
maxWalletStartupMs: 10000, // TODO (woodser): make shorter by switching to jni
|
||||
@ -322,7 +314,7 @@ beforeAll(async () => {
|
||||
|
||||
// initialize monerod
|
||||
try {
|
||||
monerod = await monerojs.connectToDaemonRpc(TestConfig.monerod.url, TestConfig.monerod.username, TestConfig.monerod.password);
|
||||
monerod = await moneroTs.connectToDaemonRpc(TestConfig.monerod.url, TestConfig.monerod.username, TestConfig.monerod.password);
|
||||
await mineToHeight(160); // initialize blockchain to latest block type
|
||||
} catch (err) {
|
||||
HavenoUtils.log(0, "Error initializing internal monerod: " + err.message); // allowed in order to test starting and stopping local node
|
||||
@ -347,8 +339,8 @@ beforeAll(async () => {
|
||||
TestConfig.trade.taker = user2;
|
||||
|
||||
// connect client wallets
|
||||
user1Wallet = await monerojs.connectToWalletRpc(TestConfig.startupHavenods[1].walletUrl, TestConfig.defaultHavenod.walletUsername, TestConfig.startupHavenods[1].accountPasswordRequired ? TestConfig.startupHavenods[1].accountPassword : TestConfig.defaultHavenod.walletDefaultPassword);
|
||||
user2Wallet = await monerojs.connectToWalletRpc(TestConfig.startupHavenods[2].walletUrl, TestConfig.defaultHavenod.walletUsername, TestConfig.startupHavenods[2].accountPasswordRequired ? TestConfig.startupHavenods[2].accountPassword : TestConfig.defaultHavenod.walletDefaultPassword);
|
||||
user1Wallet = await moneroTs.connectToWalletRpc(TestConfig.startupHavenods[1].walletUrl!, TestConfig.defaultHavenod.walletUsername, TestConfig.startupHavenods[1].accountPasswordRequired ? TestConfig.startupHavenods[1].accountPassword : TestConfig.defaultHavenod.walletDefaultPassword);
|
||||
user2Wallet = await moneroTs.connectToWalletRpc(TestConfig.startupHavenods[2].walletUrl!, TestConfig.defaultHavenod.walletUsername, TestConfig.startupHavenods[2].accountPasswordRequired ? TestConfig.startupHavenods[2].accountPassword : TestConfig.defaultHavenod.walletDefaultPassword);
|
||||
|
||||
// register arbitrator dispute agent
|
||||
await arbitrator.registerDisputeAgent("arbitrator", getArbitratorPrivKey(0));
|
||||
@ -379,7 +371,7 @@ async function shutDown() {
|
||||
await Promise.all(promises);
|
||||
|
||||
// terminate monero-javascript worker
|
||||
await monerojs.LibraryUtils.terminateWorker();
|
||||
await moneroTs.LibraryUtils.terminateWorker();
|
||||
}
|
||||
|
||||
// ----------------------------------- TESTS ----------------------------------
|
||||
@ -531,7 +523,7 @@ test("Can manage an account (CI)", async () => {
|
||||
});
|
||||
|
||||
test("Can manage Monero daemon connections (CI)", async () => {
|
||||
let monerod2: any;
|
||||
let monerod2: moneroTs.MoneroDaemonRpc | undefined = undefined;
|
||||
let user3: HavenoClient|undefined;
|
||||
let err: any;
|
||||
try {
|
||||
@ -578,9 +570,9 @@ test("Can manage Monero daemon connections (CI)", async () => {
|
||||
"--rpc-bind-port", TestConfig.monerod2.rpcBindPort,
|
||||
"--no-zmq"
|
||||
];
|
||||
if (getBaseCurrencyNetwork() !== BaseCurrencyNetwork.XMR_MAINNET) cmd.push("--" + monerojs.MoneroNetworkType.toString(TestConfig.networkType).toLowerCase());
|
||||
if (getBaseCurrencyNetwork() !== BaseCurrencyNetwork.XMR_MAINNET) cmd.push("--" + moneroTs.MoneroNetworkType.toString(TestConfig.networkType).toLowerCase());
|
||||
if (TestConfig.monerod2.username) cmd.push("--rpc-login", TestConfig.monerod2.username + ":" + TestConfig.monerod2.password);
|
||||
monerod2 = await monerojs.connectToDaemonRpc(cmd);
|
||||
monerod2 = await moneroTs.connectToDaemonRpc(cmd);
|
||||
|
||||
// connection is online and not authenticated
|
||||
connection = await user3.checkMoneroConnection();
|
||||
@ -624,7 +616,7 @@ test("Can manage Monero daemon connections (CI)", async () => {
|
||||
|
||||
// stop monerod
|
||||
//await monerod2.stopProcess(); // TODO (monero-javascript): monerod remains available after await monerod.stopProcess() for up to 40 seconds
|
||||
await GenUtils.killProcess(monerod2.process, "SIGKILL");
|
||||
await moneroTs.GenUtils.killProcess(monerod2.getProcess(), "SIGKILL");
|
||||
|
||||
// test auto switch after periodic connection check
|
||||
await wait(TestConfig.daemonPollPeriodMs * 2);
|
||||
@ -744,7 +736,7 @@ test("Can start and stop a local Monero node (CI)", async() => {
|
||||
|
||||
// expect connection to local monero node to succeed
|
||||
const rpcUrl = "http://127.0.0.1:" + rpcPort.toString();
|
||||
let daemon = await monerojs.connectToDaemonRpc(rpcUrl, "superuser", "abctesting123");
|
||||
let daemon = await moneroTs.connectToDaemonRpc(rpcUrl, "superuser", "abctesting123");
|
||||
let height = await daemon.getHeight();
|
||||
assert(height >= 0);
|
||||
|
||||
@ -762,7 +754,7 @@ test("Can start and stop a local Monero node (CI)", async() => {
|
||||
isMoneroNodeOnline = await user1.isMoneroNodeOnline();
|
||||
assert(!isMoneroNodeOnline);
|
||||
try {
|
||||
daemon = await monerojs.connectToDaemonRpc(rpcUrl);
|
||||
daemon = await moneroTs.connectToDaemonRpc(rpcUrl);
|
||||
height = await daemon.getHeight();
|
||||
throw new Error("should have thrown");
|
||||
} catch (err: any) {
|
||||
@ -776,11 +768,11 @@ test("Has a Monero wallet (CI)", async () => {
|
||||
|
||||
// get seed phrase
|
||||
const seed = await user1.getXmrSeed();
|
||||
await MoneroUtils.validateMnemonic(seed);
|
||||
await moneroTs.MoneroUtils.validateMnemonic(seed);
|
||||
|
||||
// get primary address
|
||||
const primaryAddress = await user1.getXmrPrimaryAddress();
|
||||
await MoneroUtils.validateAddress(primaryAddress, TestConfig.networkType);
|
||||
await moneroTs.MoneroUtils.validateAddress(primaryAddress, TestConfig.networkType);
|
||||
|
||||
// wait for user1 to have unlocked balance
|
||||
const tradeAmount = BigInt("250000000000");
|
||||
@ -801,7 +793,7 @@ test("Has a Monero wallet (CI)", async () => {
|
||||
// get new subaddresses
|
||||
for (let i = 0; i < 0; i++) {
|
||||
const address = await user1.getXmrNewSubaddress();
|
||||
await MoneroUtils.validateAddress(address, TestConfig.networkType);
|
||||
await moneroTs.MoneroUtils.validateAddress(address, TestConfig.networkType);
|
||||
}
|
||||
|
||||
// create withdraw tx
|
||||
@ -1051,7 +1043,7 @@ test("Can validate payment account forms (CI, sanity check)", async () => {
|
||||
const paymentMethods = await user1.getPaymentMethods();
|
||||
expect(paymentMethods.length).toEqual(expectedPaymentMethods.length);
|
||||
for (const paymentMethod of paymentMethods) {
|
||||
assert(GenUtils.arrayContains(expectedPaymentMethods, paymentMethod.getId()), "Payment method is not expected: " + paymentMethod.getId());
|
||||
assert(moneroTs.GenUtils.arrayContains(expectedPaymentMethods, paymentMethod.getId()), "Payment method is not expected: " + paymentMethod.getId());
|
||||
}
|
||||
|
||||
// test form for each payment method
|
||||
@ -1105,7 +1097,7 @@ test("Can create fiat payment accounts (CI)", async () => {
|
||||
const accountForm = await user1.getPaymentAccountForm(paymentMethodId);
|
||||
|
||||
// edit form
|
||||
HavenoUtils.setFormValue(PaymentAccountFormField.FieldId.ACCOUNT_NAME, "Revolut account " + GenUtils.getUUID(), accountForm);
|
||||
HavenoUtils.setFormValue(PaymentAccountFormField.FieldId.ACCOUNT_NAME, "Revolut account " + moneroTs.GenUtils.getUUID(), accountForm);
|
||||
HavenoUtils.setFormValue(PaymentAccountFormField.FieldId.USER_NAME, "user123", accountForm);
|
||||
HavenoUtils.setFormValue(PaymentAccountFormField.FieldId.TRADE_CURRENCIES, "gbp,eur,usd", accountForm);
|
||||
|
||||
@ -1134,7 +1126,7 @@ test("Can create crypto payment accounts (CI)", async () => {
|
||||
for (const testAccount of TestConfig.cryptoAddresses) {
|
||||
|
||||
// create payment account
|
||||
const name = testAccount.currencyCode + " " + testAccount.address.substr(0, 8) + "... " + GenUtils.getUUID();
|
||||
const name = testAccount.currencyCode + " " + testAccount.address.substr(0, 8) + "... " + moneroTs.GenUtils.getUUID();
|
||||
const paymentAccount: PaymentAccount = await user1.createCryptoPaymentAccount(name, testAccount.currencyCode, testAccount.address);
|
||||
testCryptoPaymentAccount(paymentAccount);
|
||||
testCryptoPaymentAccountEquals(paymentAccount, testAccount, name);
|
||||
@ -1163,7 +1155,7 @@ test("Can create crypto payment accounts (CI)", async () => {
|
||||
.toThrow('123 is not a valid eth address');
|
||||
|
||||
// test address duplicity
|
||||
let uid = "Unique account name " + GenUtils.getUUID();
|
||||
let uid = "Unique account name " + moneroTs.GenUtils.getUUID();
|
||||
await user1.createCryptoPaymentAccount(uid, TestConfig.cryptoAddresses[0].currencyCode, TestConfig.cryptoAddresses[0].address)
|
||||
await expect(async () => { await user1.createCryptoPaymentAccount(uid, TestConfig.cryptoAddresses[0].currencyCode, TestConfig.cryptoAddresses[0].address); })
|
||||
.rejects
|
||||
@ -1250,7 +1242,7 @@ test("Can schedule offers with locked funds (CI)", async () => {
|
||||
|
||||
// start user3
|
||||
user3 = await initHaveno();
|
||||
const user3Wallet = await monerojs.connectToWalletRpc("http://127.0.0.1:" + user3.getWalletRpcPort(), TestConfig.defaultHavenod.walletUsername, TestConfig.defaultHavenod.accountPassword);
|
||||
const user3Wallet = await moneroTs.connectToWalletRpc("http://127.0.0.1:" + user3.getWalletRpcPort(), TestConfig.defaultHavenod.walletUsername, TestConfig.defaultHavenod.accountPassword);
|
||||
|
||||
// fund user3 with 2 outputs of 0.5 XMR
|
||||
const outputAmt = BigInt("500000000000");
|
||||
@ -1708,7 +1700,7 @@ test("Can handle unexpected errors during trade initialization", async () => {
|
||||
let paymentAccount = await createCryptoPaymentAccount(traders[1]);
|
||||
wait(3000).then(async function() {
|
||||
try {
|
||||
const traderWallet = await monerojs.connectToWalletRpc("http://localhost:" + traders[1].getWalletRpcPort(), TestConfig.defaultHavenod.walletUsername, TestConfig.defaultHavenod.accountPassword);
|
||||
const traderWallet = await moneroTs.connectToWalletRpc("http://localhost:" + traders[1].getWalletRpcPort(), TestConfig.defaultHavenod.walletUsername, TestConfig.defaultHavenod.accountPassword);
|
||||
for (const frozenOutput of await traderWallet.getOutputs({isFrozen: true})) await traderWallet.thawOutput(frozenOutput.getKeyImage().getHex());
|
||||
HavenoUtils.log(1, "Sweeping trade funds");
|
||||
await traderWallet.sweepUnlocked({address: await traderWallet.getPrimaryAddress(), relay: true});
|
||||
@ -1742,7 +1734,7 @@ test("Can handle unexpected errors during trade initialization", async () => {
|
||||
// trader 0 spends trade funds after trader 2 takes offer
|
||||
wait(3000).then(async function() {
|
||||
try {
|
||||
const traderWallet = await monerojs.connectToWalletRpc("http://localhost:" + traders[0].getWalletRpcPort(), TestConfig.defaultHavenod.walletUsername, TestConfig.defaultHavenod.accountPassword);
|
||||
const traderWallet = await moneroTs.connectToWalletRpc("http://localhost:" + traders[0].getWalletRpcPort(), TestConfig.defaultHavenod.walletUsername, TestConfig.defaultHavenod.accountPassword);
|
||||
for (const frozenOutput of await traderWallet.getOutputs({isFrozen: true})) await traderWallet.thawOutput(frozenOutput.getKeyImage().getHex());
|
||||
HavenoUtils.log(1, "Sweeping offer funds");
|
||||
await traderWallet.sweepUnlocked({address: await traderWallet.getPrimaryAddress(), relay: true});
|
||||
@ -1972,7 +1964,7 @@ async function executeTrades(ctxs: TradeContext[], executionCtx?: TradeContext):
|
||||
// execute trades in thread pool unless serial
|
||||
if (executionCtx.concurrentTrades) {
|
||||
const tradePromises: Promise<string>[] = [];
|
||||
const pool = new monerojs.ThreadPool(executionCtx.maxConcurrency!);
|
||||
const pool = new moneroTs.ThreadPool(executionCtx.maxConcurrency!);
|
||||
for (const ctx of ctxs) tradePromises.push(pool.submit(() => executeTrade(Object.assign(ctx, {concurrentTrades: executionCtx!.concurrentTrades}))));
|
||||
try {
|
||||
offerIds = await Promise.all(tradePromises);
|
||||
@ -2299,7 +2291,7 @@ async function testTradePayoutUnlock(ctx: TradeContext) {
|
||||
|
||||
async function testTradeState(trade: TradeInfo, ctx: TradeContext) {
|
||||
assert.equal(trade.getPhase(), ctx.phase, "expected trade phase to be " + ctx.phase + " but was " + trade.getPhase() + " for trade " + trade.getTradeId());
|
||||
assert(GenUtils.arrayContains(ctx.payoutState, trade.getPayoutState()), "expected one of payout state " + ctx.payoutState + " but was " + trade.getPayoutState() + " for trade " + trade.getTradeId());
|
||||
assert(moneroTs.GenUtils.arrayContains(ctx.payoutState, trade.getPayoutState()), "expected one of payout state " + ctx.payoutState + " but was " + trade.getPayoutState() + " for trade " + trade.getTradeId());
|
||||
if (ctx.disputeState) expect(trade.getDisputeState()).toEqual(ctx.disputeState);
|
||||
if (ctx.isCompleted !== undefined) expect(trade.getIsCompleted()).toEqual(ctx.isCompleted);
|
||||
if (ctx.isPayoutPublished !== undefined) expect(trade.getIsPayoutPublished()).toEqual(ctx.isPayoutPublished);
|
||||
@ -2423,7 +2415,7 @@ async function takeOffer(ctx: TradeContext): Promise<TradeInfo> {
|
||||
await wait(ctx.maxTimePeerNoticeMs!);
|
||||
const tradeNotifications = getNotifications(makerNotifications, NotificationMessage.NotificationType.TRADE_UPDATE, trade.getTradeId());
|
||||
expect(tradeNotifications.length).toBe(1);
|
||||
assert(GenUtils.arrayContains(["DEPOSITS_PUBLISHED", "DEPOSITS_CONFIRMED", "DEPOSITS_UNLOCKED"], tradeNotifications[0].getTrade()!.getPhase(), "Unexpected trade phase: " + tradeNotifications[0].getTrade()!.getPhase()));
|
||||
assert(moneroTs.GenUtils.arrayContains(["DEPOSITS_PUBLISHED", "DEPOSITS_CONFIRMED", "DEPOSITS_UNLOCKED"], tradeNotifications[0].getTrade()!.getPhase()), "Unexpected trade phase: " + tradeNotifications[0].getTrade()!.getPhase());
|
||||
expect(tradeNotifications[0].getTitle()).toEqual("Offer Taken");
|
||||
expect(tradeNotifications[0].getMessage()).toEqual("Your offer " + ctx.offerId + " has been accepted");
|
||||
|
||||
@ -2431,7 +2423,7 @@ async function takeOffer(ctx: TradeContext): Promise<TradeInfo> {
|
||||
|
||||
// taker can get trade
|
||||
let fetchedTrade: TradeInfo = await ctx.taker!.getTrade(trade.getTradeId());
|
||||
assert(GenUtils.arrayContains(["DEPOSITS_PUBLISHED", "DEPOSITS_CONFIRMED", "DEPOSITS_UNLOCKED"], fetchedTrade.getPhase()), "Unexpected trade phase: " + fetchedTrade.getPhase());
|
||||
assert(moneroTs.GenUtils.arrayContains(["DEPOSITS_PUBLISHED", "DEPOSITS_CONFIRMED", "DEPOSITS_UNLOCKED"], fetchedTrade.getPhase()), "Unexpected trade phase: " + fetchedTrade.getPhase());
|
||||
// TODO: more fetched trade tests
|
||||
|
||||
// market-priced offer amounts are unadjusted, fixed-priced offer amounts are adjusted (e.g. cash at atm is $10 increments)
|
||||
@ -2445,7 +2437,7 @@ async function takeOffer(ctx: TradeContext): Promise<TradeInfo> {
|
||||
|
||||
// maker can get trade
|
||||
fetchedTrade = await ctx.maker!.getTrade(trade.getTradeId());
|
||||
assert(GenUtils.arrayContains(["DEPOSITS_PUBLISHED", "DEPOSITS_CONFIRMED", "DEPOSITS_UNLOCKED"], fetchedTrade.getPhase()), "Unexpected trade phase: " + fetchedTrade.getPhase());
|
||||
assert(moneroTs.GenUtils.arrayContains(["DEPOSITS_PUBLISHED", "DEPOSITS_CONFIRMED", "DEPOSITS_UNLOCKED"], fetchedTrade.getPhase()), "Unexpected trade phase: " + fetchedTrade.getPhase());
|
||||
return trade;
|
||||
}
|
||||
|
||||
@ -2802,7 +2794,7 @@ async function initHavenos(numDaemons: number, config?: any) {
|
||||
async function initHaveno(ctx?: HavenodContext): Promise<HavenoClient> {
|
||||
if (!ctx) ctx = {};
|
||||
Object.assign(ctx, TestConfig.defaultHavenod, Object.assign({}, ctx));
|
||||
if (!ctx.appName) ctx.appName = "haveno-" + TestConfig.baseCurrencyNetwork + "_instance_" + GenUtils.getUUID();
|
||||
if (!ctx.appName) ctx.appName = "haveno-" + TestConfig.baseCurrencyNetwork + "_instance_" + moneroTs.GenUtils.getUUID();
|
||||
|
||||
// connect to existing server or start new process
|
||||
let havenod: HavenoClient;
|
||||
@ -2818,7 +2810,7 @@ async function initHaveno(ctx?: HavenodContext): Promise<HavenoClient> {
|
||||
if (!ctx.port) {
|
||||
for (const httpPort of Array.from(TestConfig.ports.keys())) {
|
||||
if (httpPort === "8079" || httpPort === "8080" || httpPort === "8081") continue; // reserved for arbitrator, user1, and user2
|
||||
if (!GenUtils.arrayContains(HAVENO_PROCESS_PORTS, httpPort) && (!ctx.excludePorts || !GenUtils.arrayContains(ctx.excludePorts, httpPort))) {
|
||||
if (!moneroTs.GenUtils.arrayContains(HAVENO_PROCESS_PORTS, httpPort) && (!ctx.excludePorts || !moneroTs.GenUtils.arrayContains(ctx.excludePorts, httpPort))) {
|
||||
HAVENO_PROCESS_PORTS.push(httpPort);
|
||||
ctx.port = httpPort;
|
||||
break;
|
||||
@ -2876,8 +2868,8 @@ async function initHaveno(ctx?: HavenodContext): Promise<HavenoClient> {
|
||||
* Release a Haveno process for reuse and try to shutdown.
|
||||
*/
|
||||
async function releaseHavenoProcess(havenod: HavenoClient, deleteAppDir?: boolean) {
|
||||
GenUtils.remove(HAVENO_PROCESSES, havenod);
|
||||
GenUtils.remove(HAVENO_PROCESS_PORTS, getPort(havenod.getUrl()));
|
||||
moneroTs.GenUtils.remove(HAVENO_PROCESSES, havenod);
|
||||
moneroTs.GenUtils.remove(HAVENO_PROCESS_PORTS, getPort(havenod.getUrl()));
|
||||
try {
|
||||
await havenod.shutdownServer();
|
||||
} catch (err: any) {
|
||||
@ -2916,7 +2908,7 @@ async function initHavenoAccount(havenod: HavenoClient, password: string) {
|
||||
async function initFundingWallet() {
|
||||
|
||||
// init client connected to monero-wallet-rpc
|
||||
fundingWallet = await monerojs.connectToWalletRpc(TestConfig.fundingWallet.url, TestConfig.fundingWallet.username, TestConfig.fundingWallet.password);
|
||||
fundingWallet = await moneroTs.connectToWalletRpc(TestConfig.fundingWallet.url, TestConfig.fundingWallet.username, TestConfig.fundingWallet.password);
|
||||
|
||||
// check if wallet is open
|
||||
let walletIsOpen = false
|
||||
@ -2934,7 +2926,7 @@ async function initFundingWallet() {
|
||||
try {
|
||||
await fundingWallet.openWallet({path: TestConfig.fundingWallet.defaultPath, password: TestConfig.fundingWallet.walletPassword});
|
||||
} catch (err: any) {
|
||||
if (!(err instanceof monerojs.MoneroRpcError)) throw err;
|
||||
if (!(err instanceof moneroTs.MoneroRpcError)) throw err;
|
||||
|
||||
// -1 returned when wallet does not exist or fails to open e.g. it's already open by another application
|
||||
if (err.getCode() === -1) {
|
||||
@ -2976,7 +2968,7 @@ async function getWallet(havenod: HavenoClient) {
|
||||
let wallet: any;
|
||||
if (havenod === user1) wallet = user1Wallet;
|
||||
else if (havenod === user2) wallet = user2Wallet;
|
||||
else wallet = await monerojs.connectToWalletRpc("http://127.0.0.1:" + havenod.getWalletRpcPort(), TestConfig.defaultHavenod.walletUsername, TestConfig.defaultHavenod.accountPassword);
|
||||
else wallet = await moneroTs.connectToWalletRpc("http://127.0.0.1:" + havenod.getWalletRpcPort(), TestConfig.defaultHavenod.walletUsername, TestConfig.defaultHavenod.accountPassword);
|
||||
HAVENO_WALLETS.set(havenod, wallet);
|
||||
}
|
||||
return HAVENO_WALLETS.get(havenod);
|
||||
@ -3008,7 +3000,7 @@ async function mineToHeight(height: number) {
|
||||
if (await monerod.getHeight() >= height) return;
|
||||
const miningStarted = await startMining();
|
||||
while (await monerod.getHeight() < height) {
|
||||
await GenUtils.waitFor(TestConfig.trade.walletSyncPeriodMs);
|
||||
await moneroTs.GenUtils.waitFor(TestConfig.trade.walletSyncPeriodMs);
|
||||
}
|
||||
if (miningStarted) await stopMining();
|
||||
}
|
||||
@ -3048,7 +3040,7 @@ async function waitForAvailableBalance(amount: bigint, ...wallets: any[]) {
|
||||
|
||||
// fund wallets with insufficient balance
|
||||
let miningNeeded = false;
|
||||
const fundConfig = new MoneroTxConfig().setAccountIndex(0).setRelay(true);
|
||||
const fundConfig: moneroTs.MoneroTxConfig = new moneroTs.MoneroTxConfig({accountIndex: 0, relay: true});
|
||||
for (const wallet of wallets) {
|
||||
const availableBalance = await wallet.getAvailableBalance();
|
||||
if (availableBalance < amount) miningNeeded = true;
|
||||
@ -3079,7 +3071,7 @@ async function waitForAvailableBalance(amount: bigint, ...wallets: any[]) {
|
||||
}
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
promises.push(new Promise(async (resolve) => {
|
||||
const taskLooper: any = new TaskLooper(async function() {
|
||||
const taskLooper: any = new moneroTs.TaskLooper(async function() {
|
||||
if (await wallet.getAvailableBalance() >= amount) {
|
||||
taskLooper.stop();
|
||||
resolve();
|
||||
@ -3101,10 +3093,10 @@ async function waitForUnlockedTxs(...txHashes: string[]) {
|
||||
for (const txHash of txHashes) {
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
promises.push(new Promise(async (resolve) => {
|
||||
const taskLooper = new TaskLooper(async function() {
|
||||
const taskLooper = new moneroTs.TaskLooper(async function() {
|
||||
const tx = await monerod.getTx(txHash);
|
||||
if (!tx) HavenoUtils.log(1, "WARNING: tx hash " + txHash + " not found");
|
||||
else if (tx.isConfirmed() && tx.getBlock().getHeight() <= await monerod.getHeight() - 10) {
|
||||
else if (tx.getIsConfirmed() && tx.getBlock().getHeight() <= await monerod.getHeight() - 10) {
|
||||
taskLooper.stop();
|
||||
resolve();
|
||||
}
|
||||
@ -3128,7 +3120,7 @@ async function waitForUnlockedTxs(...txHashes: string[]) {
|
||||
async function hasUnspentOutputs(wallets: any[], amt: BigInt, numOutputs?: number, isLocked?: boolean): Promise<boolean> {
|
||||
if (numOutputs === undefined) numOutputs = 1;
|
||||
for (const wallet of wallets) {
|
||||
const unspentOutputs = await wallet.getOutputs({isSpent: false, isFrozen: false, minAmount: monerojs.BigInteger(amt.toString()), txQuery: {isLocked: isLocked}});
|
||||
const unspentOutputs = await wallet.getOutputs({isSpent: false, isFrozen: false, minAmount: BigInt(amt.toString()), txQuery: {isLocked: isLocked}});
|
||||
if (unspentOutputs.length < numOutputs) return false;
|
||||
}
|
||||
return true;
|
||||
@ -3139,36 +3131,36 @@ async function hasUnspentOutputs(wallets: any[], amt: BigInt, numOutputs?: numbe
|
||||
*
|
||||
* @param {MoneroWallet} wallets - monerojs wallets
|
||||
* @param {BigInt} amt - the amount to fund
|
||||
* @param {number?} numOutputs - the number of outputs of the given amount (default 1)
|
||||
* @param {boolean?} waitForUnlock - wait for outputs to unlock (default false)
|
||||
* @param {number} [numOutputs] - the number of outputs of the given amount (default 1)
|
||||
* @param {boolean} [waitForUnlock] - wait for outputs to unlock (default false)
|
||||
*/
|
||||
async function fundOutputs(wallets: any[], amt: bigint, numOutputs?: number, waitForUnlock?: boolean): Promise<void> {
|
||||
if (numOutputs === undefined) numOutputs = 1;
|
||||
if (waitForUnlock === undefined) waitForUnlock = true;
|
||||
|
||||
// collect destinations
|
||||
const destinations: any[] = [];
|
||||
const destinations: moneroTs.MoneroDestination[] = [];
|
||||
for (const wallet of wallets) {
|
||||
if (await hasUnspentOutputs([wallet], amt, numOutputs, undefined)) continue;
|
||||
for (let i = 0; i < numOutputs; i++) {
|
||||
destinations.push(new MoneroDestination((await wallet.createSubaddress()).getAddress(), monerojs.BigInteger(amt.toString())));
|
||||
destinations.push(new moneroTs.MoneroDestination((await wallet.createSubaddress()).getAddress(), BigInt(amt.toString())));
|
||||
}
|
||||
}
|
||||
if (!destinations.length) return;
|
||||
|
||||
// fund destinations
|
||||
let txConfig = new MoneroTxConfig().setAccountIndex(0).setRelay(true);
|
||||
let txConfig = new moneroTs.MoneroTxConfig().setAccountIndex(0).setRelay(true);
|
||||
const txHashes: string[] = [];
|
||||
let sendAmt = BigInteger("0");
|
||||
let sendAmt = 0n;
|
||||
for (let i = 0; i < destinations.length; i++) {
|
||||
txConfig.addDestination(destinations[i]);
|
||||
sendAmt = sendAmt.add(destinations[i].getAmount());
|
||||
txConfig.addDestination(destinations[i], undefined); // TODO: remove once converted to MoneroTxConfig.ts
|
||||
sendAmt = sendAmt + destinations[i].getAmount();
|
||||
if (i === destinations.length - 1 || (i > 0 && i % 15 === 0)) {
|
||||
await waitForAvailableBalance(toBigInt(sendAmt), fundingWallet);
|
||||
const txs = await fundingWallet.createTxs(txConfig);
|
||||
for (const tx of txs) txHashes.push(tx.getHash());
|
||||
txConfig = new MoneroTxConfig().setAccountIndex(0).setRelay(true);
|
||||
sendAmt = BigInteger("0");
|
||||
txConfig = new moneroTs.MoneroTxConfig().setAccountIndex(0).setRelay(true);
|
||||
sendAmt = 0n;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3296,7 +3288,7 @@ function testDestination(destination: XmrDestination) {
|
||||
}
|
||||
|
||||
function getRandomAssetCode() {
|
||||
return TestConfig.assetCodes[GenUtils.getRandomInt(0, TestConfig.assetCodes.length - 1)];
|
||||
return TestConfig.assetCodes[moneroTs.GenUtils.getRandomInt(0, TestConfig.assetCodes.length - 1)];
|
||||
}
|
||||
|
||||
async function hasPaymentAccount(trader: HavenoClient, assetCode: string): Promise<boolean> {
|
||||
@ -3328,7 +3320,7 @@ async function createCryptoPaymentAccount(trader: HavenoClient, currencyCode = "
|
||||
for (const cryptoAddress of TestConfig.cryptoAddresses) {
|
||||
if (cryptoAddress.currencyCode.toLowerCase() !== currencyCode.toLowerCase()) continue;
|
||||
return trader.createCryptoPaymentAccount(
|
||||
cryptoAddress.currencyCode + " " + cryptoAddress.address.substr(0, 8) + "... " + GenUtils.getUUID(),
|
||||
cryptoAddress.currencyCode + " " + cryptoAddress.address.substr(0, 8) + "... " + moneroTs.GenUtils.getUUID(),
|
||||
cryptoAddress.currencyCode,
|
||||
cryptoAddress.address);
|
||||
}
|
||||
@ -3402,7 +3394,7 @@ function getValidFormInput(form: PaymentAccountForm, fieldId: PaymentAccountForm
|
||||
case PaymentAccountFormField.FieldId.ACCOUNT_ID:
|
||||
return "jdoe@no.com";
|
||||
case PaymentAccountFormField.FieldId.ACCOUNT_NAME:
|
||||
return "Form_" + form.getId() + " " + GenUtils.getUUID(); // TODO: rename to form.getPaymentMethodId()
|
||||
return "Form_" + form.getId() + " " + moneroTs.GenUtils.getUUID(); // TODO: rename to form.getPaymentMethodId()
|
||||
case PaymentAccountFormField.FieldId.ACCOUNT_NR:
|
||||
return "12345678";
|
||||
case PaymentAccountFormField.FieldId.ACCOUNT_OWNER:
|
||||
@ -3503,7 +3495,7 @@ function getValidFormInput(form: PaymentAccountForm, fieldId: PaymentAccountForm
|
||||
return "asap plz";
|
||||
case PaymentAccountFormField.FieldId.STATE:
|
||||
const country = HavenoUtils.getFormValue(form, PaymentAccountFormField.FieldId.COUNTRY);
|
||||
return GenUtils.arrayContains(field.getRequiredForCountriesList(), country) ? "My state" : "";
|
||||
return moneroTs.GenUtils.arrayContains(field.getRequiredForCountriesList(), country) ? "My state" : "";
|
||||
case PaymentAccountFormField.FieldId.TRADE_CURRENCIES:
|
||||
if (field.getComponent() === PaymentAccountFormField.Component.SELECT_ONE) {
|
||||
if (form.getId() === PaymentAccountForm.FormId.F2F) return "XAU";
|
||||
@ -3638,7 +3630,7 @@ function getInvalidFormInput(form: PaymentAccountForm, fieldId: PaymentAccountFo
|
||||
throw new Error("Special instructions have no invalid input");
|
||||
case PaymentAccountFormField.FieldId.STATE: {
|
||||
const country = HavenoUtils.getFormValue(form, PaymentAccountFormField.FieldId.COUNTRY);
|
||||
return GenUtils.arrayContains(field.getRequiredForCountriesList(), country) ? "" : "My state";
|
||||
return moneroTs.GenUtils.arrayContains(field.getRequiredForCountriesList(), country) ? "" : "My state";
|
||||
}
|
||||
case PaymentAccountFormField.FieldId.TRADE_CURRENCIES:
|
||||
return "abc,def";
|
||||
|
@ -118,12 +118,11 @@ export default class HavenoUtils {
|
||||
/**
|
||||
* Convert XMR to atomic units.
|
||||
*
|
||||
* @param {number|string} amountXmr - amount in XMR to convert to atomic units
|
||||
* @return {BigInt} amount in atomic units
|
||||
* @param {number | string} amountXmr - amount in XMR to convert to atomic units
|
||||
* @return {bigint} amount in atomic units
|
||||
*/
|
||||
static xmrToAtomicUnits(amountXmr: number|string): bigint {
|
||||
static xmrToAtomicUnits(amountXmr: number | string): bigint {
|
||||
if (typeof amountXmr === "number") amountXmr = "" + amountXmr;
|
||||
else if (typeof amountXmr !== "string") throw new Error("Must provide XMR amount as a string or js number to convert to atomic units");
|
||||
let decimalDivisor = 1;
|
||||
let decimalIdx = amountXmr.indexOf('.');
|
||||
if (decimalIdx > -1) {
|
||||
@ -136,14 +135,13 @@ export default class HavenoUtils {
|
||||
/**
|
||||
* Convert atomic units to XMR.
|
||||
*
|
||||
* @param {BigInt|string} amountAtomicUnits - amount in atomic units to convert to XMR
|
||||
* @param {bigint | string} amountAtomicUnits - amount in atomic units to convert to XMR
|
||||
* @return {number} amount in XMR
|
||||
*/
|
||||
static atomicUnitsToXmr(amountAtomicUnits: BigInt|string) {
|
||||
static atomicUnitsToXmr(amountAtomicUnits: bigint | string) {
|
||||
if (typeof amountAtomicUnits === "string") amountAtomicUnits = BigInt(amountAtomicUnits);
|
||||
else if (typeof amountAtomicUnits !== "bigint") throw new Error("Must provide atomic units as BigInt or string to convert to XMR");
|
||||
const quotient: bigint = amountAtomicUnits as bigint / HavenoUtils.AU_PER_XMR;
|
||||
const remainder: bigint = amountAtomicUnits as bigint % HavenoUtils.AU_PER_XMR;
|
||||
const quotient: bigint = amountAtomicUnits / HavenoUtils.AU_PER_XMR;
|
||||
const remainder: bigint = amountAtomicUnits % HavenoUtils.AU_PER_XMR;
|
||||
return Number(quotient) + Number(remainder) / Number(HavenoUtils.AU_PER_XMR);
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ export default class TaskLooper {
|
||||
* @param {int} periodInMs the loop period in milliseconds
|
||||
*/
|
||||
start(periodInMs: number) {
|
||||
if (periodInMs <= 0) throw new Error("Looper period must be greater than 0 ms");
|
||||
if (this._isStarted) return;
|
||||
this._isStarted = true;
|
||||
this._runLoop(periodInMs);
|
||||
|
@ -19,8 +19,7 @@
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx"
|
||||
"isolatedModules": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "**/*.test.ts"]
|
||||
|
Loading…
Reference in New Issue
Block a user