mirror of
https://github.com/haveno-dex/haveno-ts.git
synced 2024-12-24 23:09:26 -05:00
rename to haveno.ts, haveno.test.ts
This commit is contained in:
parent
91710b2bcf
commit
1a08f3d15f
@ -25,9 +25,9 @@ This application is a lightly modified [create-react-app](https://github.com/fac
|
||||
|
||||
## Run Tests
|
||||
|
||||
Running the [top-level API tests](./src/HavenoDaemon.test.ts) is a great way to develop and test Haveno end-to-end.
|
||||
Running the [API tests](./src/haveno.test.ts) is the best way to develop and test Haveno end-to-end.
|
||||
|
||||
[`HavenoDaemon`](./src/HavenoDaemon.ts) provides the interface to the Haveno daemon's gRPC API.
|
||||
[`haveno.ts`](./src/haveno.ts) provides the interface to Haveno's backend daemon.
|
||||
|
||||
1. [Run a local Haveno test network](https://github.com/haveno-dex/haveno/blob/master/docs/installing.md) and then shut down the arbitrator, Alice, and Bob or run them as daemons, e.g. `make alice-daemon`. You may omit the arbitrator registration steps since it is done automatically in the tests.
|
||||
2. Clone this project to the same parent directory as the haveno project: `git clone https://github.com/haveno-dex/haveno-ui-poc`
|
||||
|
@ -1,19 +1,19 @@
|
||||
import React from 'react';
|
||||
import logo from './logo.png';
|
||||
import './App.css';
|
||||
import {HavenoDaemon} from './HavenoDaemon';
|
||||
import {haveno} from './haveno';
|
||||
|
||||
const HAVENO_DAEMON_URL = "http://localhost:8080";
|
||||
const HAVENO_DAEMON_PASSWORD = "apitest";
|
||||
|
||||
class App extends React.Component<{}, {daemonVersion: string}> {
|
||||
|
||||
daemon: HavenoDaemon;
|
||||
daemon: haveno;
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.state = {daemonVersion: ""};
|
||||
this.daemon = new HavenoDaemon(HAVENO_DAEMON_URL, HAVENO_DAEMON_PASSWORD);
|
||||
this.daemon = new haveno(HAVENO_DAEMON_URL, HAVENO_DAEMON_PASSWORD);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -1,7 +1,7 @@
|
||||
// --------------------------------- IMPORTS ----------------------------------
|
||||
|
||||
// import haveno types
|
||||
import {HavenoDaemon} from "./HavenoDaemon";
|
||||
import {haveno} from "./haveno";
|
||||
import {HavenoUtils} from "./utils/HavenoUtils";
|
||||
import * as grpcWeb from 'grpc-web';
|
||||
import {MarketPriceInfo, NotificationMessage, OfferInfo, TradeInfo, UrlConnection, XmrBalanceInfo} from './protobuf/grpc_pb'; // TODO (woodser): better names; haveno_grpc_pb, haveno_pb
|
||||
@ -140,17 +140,17 @@ interface TxContext {
|
||||
}
|
||||
|
||||
// clients
|
||||
let startupHavenods: HavenoDaemon[] = [];
|
||||
let arbitrator: HavenoDaemon;
|
||||
let alice: HavenoDaemon;
|
||||
let bob: HavenoDaemon;
|
||||
let startupHavenods: haveno[] = [];
|
||||
let arbitrator: haveno;
|
||||
let alice: haveno;
|
||||
let bob: haveno;
|
||||
let monerod: any;
|
||||
let fundingWallet: any;
|
||||
let aliceWallet: any;
|
||||
let bobWallet: any;
|
||||
|
||||
// track started haveno processes
|
||||
const HAVENO_PROCESSES: HavenoDaemon[] = [];
|
||||
const HAVENO_PROCESSES: haveno[] = [];
|
||||
const HAVENO_PROCESS_PORTS: string[] = [];
|
||||
|
||||
// other config
|
||||
@ -167,10 +167,10 @@ beforeAll(async () => {
|
||||
|
||||
// start configured haveno daemons
|
||||
let promises = [];
|
||||
for (let config of TestConfig.startupHavenods) promises.push(initHavenoDaemon(config));
|
||||
for (let config of TestConfig.startupHavenods) promises.push(initHaveno(config));
|
||||
for (let settledPromise of await Promise.allSettled(promises)) {
|
||||
if (settledPromise.status !== "fulfilled") throw new Error((settledPromise as PromiseRejectedResult).reason);
|
||||
startupHavenods.push((settledPromise as PromiseFulfilledResult<HavenoDaemon>).value);
|
||||
startupHavenods.push((settledPromise as PromiseFulfilledResult<haveno>).value);
|
||||
}
|
||||
|
||||
// assign arbitrator alice, bob
|
||||
@ -209,12 +209,12 @@ test("Can get the version", async () => {
|
||||
});
|
||||
|
||||
test("Can manage an account", async () => {
|
||||
let charlie: HavenoDaemon | undefined;
|
||||
let charlie: haveno | undefined;
|
||||
let err: any;
|
||||
try {
|
||||
|
||||
// start charlie without opening account
|
||||
charlie = await initHavenoDaemon({autoLogin: false});
|
||||
charlie = await initHaveno({autoLogin: false});
|
||||
assert(!await charlie.accountExists());
|
||||
|
||||
// test errors when account not open
|
||||
@ -249,7 +249,7 @@ test("Can manage an account", async () => {
|
||||
// restart charlie
|
||||
let charlieConfig = {appName: charlie.getAppName(), autoLogin: false}
|
||||
await releaseHavenoProcess(charlie);
|
||||
charlie = await initHavenoDaemon(charlieConfig);
|
||||
charlie = await initHaveno(charlieConfig);
|
||||
assert(await charlie.accountExists());
|
||||
assert(!await charlie.isAccountOpen());
|
||||
|
||||
@ -266,7 +266,7 @@ test("Can manage an account", async () => {
|
||||
|
||||
// restart charlie
|
||||
await releaseHavenoProcess(charlie);
|
||||
charlie = await initHavenoDaemon(charlieConfig);
|
||||
charlie = await initHaveno(charlieConfig);
|
||||
await testAccountNotOpen(charlie);
|
||||
|
||||
// open account
|
||||
@ -287,14 +287,14 @@ test("Can manage an account", async () => {
|
||||
await releaseHavenoProcess(charlie);
|
||||
|
||||
// restore account which shuts down server
|
||||
charlie = await initHavenoDaemon(charlieConfig);
|
||||
charlie = await initHaveno(charlieConfig);
|
||||
let zipBytes: Uint8Array = new Uint8Array(fs.readFileSync(zipFile));
|
||||
await charlie.restoreAccount(zipBytes);
|
||||
assert(!await charlie.isConnectedToDaemon());
|
||||
await releaseHavenoProcess(charlie);
|
||||
|
||||
// open restored account
|
||||
charlie = await initHavenoDaemon(charlieConfig);
|
||||
charlie = await initHaveno(charlieConfig);
|
||||
assert(await charlie.accountExists());
|
||||
await charlie.openAccount(password);
|
||||
assert(await charlie.isAccountOpen());
|
||||
@ -308,7 +308,7 @@ test("Can manage an account", async () => {
|
||||
// TODO: how to delete trader app folder at end of test?
|
||||
if (err) throw err;
|
||||
|
||||
async function testAccountNotOpen(havenod: HavenoDaemon): Promise<void> { // TODO: generalize this?
|
||||
async function testAccountNotOpen(havenod: haveno): Promise<void> { // TODO: generalize this?
|
||||
try { await havenod.getMoneroConnections(); throw new Error("Should have thrown"); }
|
||||
catch (err) { assert.equal(err.message, "Account not open"); }
|
||||
try { await havenod.getXmrTxs(); throw new Error("Should have thrown"); }
|
||||
@ -320,12 +320,12 @@ test("Can manage an account", async () => {
|
||||
|
||||
test("Can manage Monero daemon connections", async () => {
|
||||
let monerod2: any;
|
||||
let charlie: HavenoDaemon | undefined;
|
||||
let charlie: haveno | undefined;
|
||||
let err: any;
|
||||
try {
|
||||
|
||||
// start charlie
|
||||
charlie = await initHavenoDaemon();
|
||||
charlie = await initHaveno();
|
||||
|
||||
// test default connections
|
||||
let monerodUrl1 = "http://127.0.0.1:38081"; // TODO: (woodser): move to config
|
||||
@ -398,7 +398,7 @@ test("Can manage Monero daemon connections", async () => {
|
||||
// restart charlie
|
||||
let appName = charlie.getAppName();
|
||||
await releaseHavenoProcess(charlie);
|
||||
charlie = await initHavenoDaemon({appName: appName, accountPassword: password});
|
||||
charlie = await initHaveno({appName: appName, accountPassword: password});
|
||||
|
||||
// connection is restored, online, and authenticated
|
||||
connection = await charlie.getMoneroConnection();
|
||||
@ -687,7 +687,7 @@ test("Can get market depth", async () => {
|
||||
// clear offers
|
||||
await clearOffers(alice, assetCode);
|
||||
await clearOffers(bob, assetCode);
|
||||
async function clearOffers(havenod: HavenoDaemon, assetCode: string) {
|
||||
async function clearOffers(havenod: haveno, assetCode: string) {
|
||||
for (let offer of await havenod.getMyOffers(assetCode)) {
|
||||
if (offer.getBaseCurrencyCode().toLowerCase() === assetCode.toLowerCase()) { // TODO (woodser): offer base currency and counter currency are switched for cryptos
|
||||
await havenod.removeOffer(offer.getId());
|
||||
@ -1282,12 +1282,12 @@ test("Can resolve disputes", async () => {
|
||||
});
|
||||
|
||||
test("Cannot make or take offer with insufficient unlocked funds", async () => {
|
||||
let charlie: HavenoDaemon | undefined;
|
||||
let charlie: haveno | undefined;
|
||||
let err: any;
|
||||
try {
|
||||
|
||||
// start charlie
|
||||
charlie = await initHavenoDaemon();
|
||||
charlie = await initHaveno();
|
||||
|
||||
// charlie creates ethereum payment account
|
||||
let paymentAccount = await createCryptoPaymentAccount(charlie);
|
||||
@ -1405,13 +1405,13 @@ test("Invalidates offers when reserved funds are spent", async () => {
|
||||
// TODO (woodser): test arbitrator state too
|
||||
// TODO (woodser): test breaking protocol after depositing to multisig (e.g. don't send payment account payload by deleting it)
|
||||
test("Handles unexpected errors during trade initialization", async () => {
|
||||
let traders: HavenoDaemon[] = [];
|
||||
let traders: haveno[] = [];
|
||||
let err: any;
|
||||
try {
|
||||
|
||||
// start and fund 3 trader processes
|
||||
HavenoUtils.log(1, "Starting trader processes");
|
||||
traders = await initHavenoDaemons(3);
|
||||
traders = await initHavenos(3);
|
||||
HavenoUtils.log(1, "Funding traders");
|
||||
let tradeAmount: bigint = BigInt("250000000000");
|
||||
await waitForUnlockedBalance(tradeAmount * BigInt("2"), traders[0], traders[1], traders[2]);
|
||||
@ -1498,13 +1498,13 @@ test("Handles unexpected errors during trade initialization", async () => {
|
||||
|
||||
// ------------------------------- HELPERS ------------------------------------
|
||||
|
||||
async function initHavenoDaemons(numDaemons: number, config?: any) {
|
||||
let traderPromises: Promise<HavenoDaemon>[] = [];
|
||||
for (let i = 0; i < numDaemons; i++) traderPromises.push(initHavenoDaemon(config));
|
||||
async function initHavenos(numDaemons: number, config?: any) {
|
||||
let traderPromises: Promise<haveno>[] = [];
|
||||
for (let i = 0; i < numDaemons; i++) traderPromises.push(initHaveno(config));
|
||||
return Promise.all(traderPromises);
|
||||
}
|
||||
|
||||
async function initHavenoDaemon(config?: any): Promise<HavenoDaemon> {
|
||||
async function initHaveno(config?: any): Promise<haveno> {
|
||||
config = Object.assign({}, TestConfig.defaultHavenod, config);
|
||||
if (!config.appName) config.appName = "haveno-XMR_STAGENET_instance_" + GenUtils.getUUID();
|
||||
|
||||
@ -1513,7 +1513,7 @@ async function initHavenoDaemon(config?: any): Promise<HavenoDaemon> {
|
||||
try {
|
||||
|
||||
// try to connect to existing server
|
||||
havenod = new HavenoDaemon(config.url, config.apiPassword);
|
||||
havenod = new haveno(config.url, config.apiPassword);
|
||||
await havenod.getVersion();
|
||||
} catch (err) {
|
||||
|
||||
@ -1545,7 +1545,7 @@ async function initHavenoDaemon(config?: any): Promise<HavenoDaemon> {
|
||||
"--walletRpcBindPort", config.walletUrl ? new URL(config.walletUrl).port : "" + await getAvailablePort(), // use configured port if given
|
||||
"--passwordRequired", (config.accountPasswordRequired ? "true" : "false")
|
||||
];
|
||||
havenod = await HavenoDaemon.startProcess(TestConfig.haveno.path, cmd, "http://localhost:" + proxyPort, config.logProcessOutput);
|
||||
havenod = await haveno.startProcess(TestConfig.haveno.path, cmd, "http://localhost:" + proxyPort, config.logProcessOutput);
|
||||
HAVENO_PROCESSES.push(havenod);
|
||||
}
|
||||
|
||||
@ -1570,7 +1570,7 @@ async function initHavenoDaemon(config?: any): Promise<HavenoDaemon> {
|
||||
/**
|
||||
* Release a Haveno process for reuse and try to shutdown.
|
||||
*/
|
||||
async function releaseHavenoProcess(havenod: HavenoDaemon) {
|
||||
async function releaseHavenoProcess(havenod: haveno) {
|
||||
GenUtils.remove(HAVENO_PROCESSES, havenod);
|
||||
GenUtils.remove(HAVENO_PROCESS_PORTS, new URL(havenod.getUrl()).port); // TODO (woodser): standardize to url
|
||||
try {
|
||||
@ -1583,7 +1583,7 @@ async function releaseHavenoProcess(havenod: HavenoDaemon) {
|
||||
/**
|
||||
* Create or open an account with the given daemon and password.
|
||||
*/
|
||||
async function initHavenoAccount(havenod: HavenoDaemon, password: string) {
|
||||
async function initHavenoAccount(havenod: haveno, password: string) {
|
||||
if (await havenod.isAccountOpen()) return;
|
||||
if (await havenod.accountExists()) return havenod.openAccount(password);
|
||||
await havenod.createAccount(password);
|
||||
@ -1649,17 +1649,17 @@ async function waitForUnlockedBalance(amount: bigint, ...wallets: any[]) {
|
||||
}
|
||||
|
||||
async getUnlockedBalance(): Promise<bigint> {
|
||||
if (this._wallet instanceof HavenoDaemon) return BigInt((await this._wallet.getBalances()).getUnlockedBalance());
|
||||
if (this._wallet instanceof haveno) return BigInt((await this._wallet.getBalances()).getUnlockedBalance());
|
||||
else return BigInt((await this._wallet.getUnlockedBalance()).toString());
|
||||
}
|
||||
|
||||
async getLockedBalance(): Promise<bigint> {
|
||||
if (this._wallet instanceof HavenoDaemon) return BigInt((await this._wallet.getBalances()).getLockedBalance());
|
||||
if (this._wallet instanceof haveno) return BigInt((await this._wallet.getBalances()).getLockedBalance());
|
||||
else return BigInt((await this._wallet.getBalance()).toString()) - await this.getUnlockedBalance();
|
||||
}
|
||||
|
||||
async getDepositAddress(): Promise<string> {
|
||||
if (this._wallet instanceof HavenoDaemon) return await this._wallet.getNewDepositSubaddress();
|
||||
if (this._wallet instanceof haveno) return await this._wallet.getNewDepositSubaddress();
|
||||
else return (await this._wallet.createSubaddress()).getAddress();
|
||||
}
|
||||
}
|
||||
@ -1880,7 +1880,7 @@ function getRandomAssetCode() {
|
||||
return TestConfig.assetCodes[GenUtils.getRandomInt(0, TestConfig.assetCodes.length - 1)];
|
||||
}
|
||||
|
||||
async function createPaymentAccount(trader: HavenoDaemon, assetCode: string): Promise<PaymentAccount> {
|
||||
async function createPaymentAccount(trader: haveno, assetCode: string): Promise<PaymentAccount> {
|
||||
return isCrypto(assetCode) ? createCryptoPaymentAccount(trader, assetCode) : createRevolutPaymentAccount(trader);
|
||||
}
|
||||
|
||||
@ -1894,14 +1894,14 @@ function getCryptoAddress(currencyCode: string): string | undefined {
|
||||
}
|
||||
}
|
||||
|
||||
async function createRevolutPaymentAccount(trader: HavenoDaemon): Promise<PaymentAccount> {
|
||||
async function createRevolutPaymentAccount(trader: haveno): Promise<PaymentAccount> {
|
||||
let accountForm = await trader.getPaymentAccountForm('REVOLUT');
|
||||
accountForm.accountName = "Revolut account " + GenUtils.getUUID();
|
||||
accountForm.userName = "user123";
|
||||
return trader.createPaymentAccount(accountForm);
|
||||
}
|
||||
|
||||
async function createCryptoPaymentAccount(trader: HavenoDaemon, currencyCode = "eth"): Promise<PaymentAccount> {
|
||||
async function createCryptoPaymentAccount(trader: haveno, currencyCode = "eth"): Promise<PaymentAccount> {
|
||||
for (let cryptoAddress of TestConfig.cryptoAddresses) {
|
||||
if (cryptoAddress.currencyCode.toLowerCase() !== currencyCode.toLowerCase()) continue;
|
||||
return trader.createCryptoPaymentAccount(
|
||||
@ -1913,7 +1913,7 @@ async function createCryptoPaymentAccount(trader: HavenoDaemon, currencyCode = "
|
||||
}
|
||||
|
||||
// TODO: specify counter currency code
|
||||
async function postOffer(maker: HavenoDaemon, config?: any) {
|
||||
async function postOffer(maker: haveno, config?: any) {
|
||||
|
||||
// assign default options
|
||||
config = Object.assign({}, TestConfig.postOffer, config);
|
||||
@ -1984,7 +1984,7 @@ function testOffer(offer: OfferInfo, config?: any) {
|
||||
/**
|
||||
* Tests trade chat functionality. Must be called during an open trade.
|
||||
*/
|
||||
async function testTradeChat(tradeId: string, alice: HavenoDaemon, bob: HavenoDaemon) {
|
||||
async function testTradeChat(tradeId: string, alice: haveno, bob: haveno) {
|
||||
HavenoUtils.log(1, "Testing trade chat");
|
||||
|
||||
// invalid trade should throw error
|
@ -10,7 +10,7 @@ const console = require('console');
|
||||
/**
|
||||
* Haveno daemon client using gRPC.
|
||||
*/
|
||||
class HavenoDaemon {
|
||||
class haveno {
|
||||
|
||||
// grpc clients
|
||||
_appName: string|undefined;
|
||||
@ -40,8 +40,8 @@ class HavenoDaemon {
|
||||
_keepAlivePeriodMs: number = 60000;
|
||||
|
||||
// constants
|
||||
static readonly _fullyInitializedMessage = "AppStartupState: Application fully initialized";
|
||||
static readonly _loginRequiredMessage = "HavenoDaemonMain: Interactive login required";
|
||||
static readonly _fullyInitializedMessage = "Application fully initialized";
|
||||
static readonly _loginRequiredMessage = "Interactive login required";
|
||||
|
||||
/**
|
||||
* Construct a client connected to a Haveno daemon.
|
||||
@ -52,7 +52,7 @@ class HavenoDaemon {
|
||||
constructor(url: string, password: string) {
|
||||
if (!url) throw new Error("Must provide URL of Haveno daemon");
|
||||
if (!password) throw new Error("Must provide password of Haveno daemon");
|
||||
HavenoUtils.log(2, "Creating HavenoDaemon(" + url + ", " + password + ")");
|
||||
HavenoUtils.log(2, "Creating Haveno client connected to " + url);
|
||||
this._url = url;
|
||||
this._password = password;
|
||||
this._getVersionClient = new GetVersionClient(this._url);
|
||||
@ -77,9 +77,9 @@ class HavenoDaemon {
|
||||
* @param {string[]} cmd - command to start the process
|
||||
* @param {string} url - Haveno daemon url (must proxy to api port)
|
||||
* @param {boolean} enableLogging - specifies if logging is enabled or disabled at log level 3
|
||||
* @return {HavenoDaemon} a client connected to the newly started Haveno process
|
||||
* @return {haveno} a client connected to the newly started Haveno process
|
||||
*/
|
||||
static async startProcess(havenoPath: string, cmd: string[], url: string, enableLogging: boolean): Promise<HavenoDaemon> {
|
||||
static async startProcess(havenoPath: string, cmd: string[], url: string, enableLogging: boolean): Promise<haveno> {
|
||||
|
||||
// return promise which resolves after starting havenod
|
||||
return new Promise(function(resolve, reject) {
|
||||
@ -88,7 +88,7 @@ class HavenoDaemon {
|
||||
// state variables
|
||||
let output = "";
|
||||
let isStarted = false;
|
||||
let daemon: HavenoDaemon|undefined = undefined;
|
||||
let daemon: haveno|undefined = undefined;
|
||||
|
||||
// start process
|
||||
let childProcess = require('child_process').spawn(cmd[0], cmd.slice(1), {cwd: havenoPath});
|
||||
@ -102,7 +102,7 @@ class HavenoDaemon {
|
||||
output += line + '\n'; // capture output in case of error
|
||||
|
||||
// initialize daemon on success or login required message
|
||||
if (!daemon && (line.indexOf(HavenoDaemon._fullyInitializedMessage) >= 0 || line.indexOf(HavenoDaemon._loginRequiredMessage) >= 0)) {
|
||||
if (!daemon && (line.indexOf(haveno._fullyInitializedMessage) >= 0 || line.indexOf(haveno._loginRequiredMessage) >= 0)) {
|
||||
|
||||
// get api password
|
||||
let passwordIdx = cmd.indexOf("--apiPassword");
|
||||
@ -113,7 +113,7 @@ class HavenoDaemon {
|
||||
let password = cmd[passwordIdx + 1];
|
||||
|
||||
// create client connected to internal process
|
||||
daemon = new HavenoDaemon(url, password);
|
||||
daemon = new haveno(url, password);
|
||||
daemon._process = childProcess;
|
||||
daemon._processLogging = enableLogging;
|
||||
daemon._appName = cmd[cmd.indexOf("--appName") + 1];
|
||||
@ -182,7 +182,7 @@ class HavenoDaemon {
|
||||
* @param {boolean} enabled - specifies if logging is enabled or disabled
|
||||
*/
|
||||
setProcessLogging(enabled: boolean) {
|
||||
if (this._process === undefined) throw new Error("HavenoDaemon instance not created from new process");
|
||||
if (this._process === undefined) throw new Error("haveno instance not created from new process");
|
||||
this._processLogging = enabled;
|
||||
}
|
||||
|
||||
@ -393,7 +393,7 @@ class HavenoDaemon {
|
||||
/**
|
||||
* Add a listener to receive notifications from the Haveno daemon.
|
||||
*
|
||||
* @param {HavenoDaemonListener} listener - the notification listener to add
|
||||
* @param {(notification: NotificationMessage) => void} listener - the notification listener to add
|
||||
*/
|
||||
async addNotificationListener(listener: (notification: NotificationMessage) => void): Promise<void> {
|
||||
this._notificationListeners.push(listener);
|
||||
@ -403,7 +403,7 @@ class HavenoDaemon {
|
||||
/**
|
||||
* Remove a notification listener.
|
||||
*
|
||||
* @param {HavenoDaemonListener} listener - the notification listener to remove
|
||||
* @param {(notification: NotificationMessage) => void} listener - the notification listener to remove
|
||||
*/
|
||||
async removeNotificationListener(listener: (notification: NotificationMessage) => void): Promise<void> {
|
||||
let idx = this._notificationListeners.indexOf(listener);
|
||||
@ -1339,4 +1339,4 @@ class HavenoDaemon {
|
||||
}
|
||||
}
|
||||
|
||||
export {HavenoDaemon};
|
||||
export {haveno};
|
Loading…
Reference in New Issue
Block a user