2022-05-12 17:25:46 -04:00
"use strict" ;
2024-04-07 08:13:09 -04:00
/ *
* Copyright Haveno
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
2022-05-12 17:25:46 -04:00
var _ _importDefault = ( this && this . _ _importDefault ) || function ( mod ) {
return ( mod && mod . _ _esModule ) ? mod : { "default" : mod } ;
} ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
const console _1 = _ _importDefault ( require ( "console" ) ) ;
2023-11-13 11:02:09 -05:00
const HavenoError _1 = _ _importDefault ( require ( "./types/HavenoError" ) ) ;
2022-05-12 17:25:46 -04:00
const HavenoUtils _1 = _ _importDefault ( require ( "./utils/HavenoUtils" ) ) ;
const TaskLooper _1 = _ _importDefault ( require ( "./utils/TaskLooper" ) ) ;
const GrpcServiceClientPb _1 = require ( "./protobuf/GrpcServiceClientPb" ) ;
const grpc _pb _1 = require ( "./protobuf/grpc_pb" ) ;
2023-11-13 11:02:09 -05:00
const pb _pb _1 = require ( "./protobuf/pb_pb" ) ;
2022-05-04 21:30:48 -04:00
/ * *
2022-05-10 09:55:41 -04:00
* Haveno daemon client .
2022-05-04 21:30:48 -04:00
* /
2022-05-12 17:25:46 -04:00
class HavenoClient {
2022-05-04 21:30:48 -04:00
/ * *
* Construct a client connected to a Haveno daemon .
*
* @ param { string } url - Haveno daemon url
* @ param { string } password - Haveno daemon password
* /
constructor ( url , password ) {
2022-12-17 05:06:40 -05:00
/** @private */ this . _processLogging = false ;
/** @private */ this . _notificationListeners = [ ] ;
/** @private */ this . _registerNotificationListenerCalled = false ;
/** @private */ this . _keepAlivePeriodMs = 60000 ;
/ * *
* Callback for grpc notifications .
*
* @ private
* /
this . _onNotification = ( data ) => {
2022-09-21 10:41:36 -04:00
if ( data instanceof grpc _pb _1 . NotificationMessage ) {
for ( const listener of this . _notificationListeners )
listener ( data ) ;
}
} ;
2022-05-04 21:30:48 -04:00
if ( ! url )
2022-06-07 17:48:04 -04:00
throw new HavenoError _1 . default ( "Must provide URL of Haveno daemon" ) ;
2022-05-04 21:30:48 -04:00
if ( ! password )
2022-06-07 17:48:04 -04:00
throw new HavenoError _1 . default ( "Must provide password of Haveno daemon" ) ;
2022-05-12 17:25:46 -04:00
HavenoUtils _1 . default . log ( 2 , "Creating Haveno client connected to " + url ) ;
2022-05-04 21:30:48 -04:00
this . _url = url ;
this . _password = password ;
2024-08-07 07:00:58 -04:00
this . _getTradeStatisticsClient = new GrpcServiceClientPb _1 . GetTradeStatisticsClient ( this . _url ) ;
2022-05-12 17:25:46 -04:00
this . _getVersionClient = new GrpcServiceClientPb _1 . GetVersionClient ( this . _url ) ;
this . _accountClient = new GrpcServiceClientPb _1 . AccountClient ( this . _url ) ;
2023-11-25 14:48:58 -05:00
this . _xmrConnectionsClient = new GrpcServiceClientPb _1 . XmrConnectionsClient ( this . _url ) ;
this . _xmrNodeClient = new GrpcServiceClientPb _1 . XmrNodeClient ( this . _url ) ;
2022-05-12 17:25:46 -04:00
this . _disputeAgentsClient = new GrpcServiceClientPb _1 . DisputeAgentsClient ( this . _url ) ;
this . _disputesClient = new GrpcServiceClientPb _1 . DisputesClient ( this . _url ) ;
this . _walletsClient = new GrpcServiceClientPb _1 . WalletsClient ( this . _url ) ;
this . _priceClient = new GrpcServiceClientPb _1 . PriceClient ( this . _url ) ;
this . _paymentAccountsClient = new GrpcServiceClientPb _1 . PaymentAccountsClient ( this . _url ) ;
this . _offersClient = new GrpcServiceClientPb _1 . OffersClient ( this . _url ) ;
this . _tradesClient = new GrpcServiceClientPb _1 . TradesClient ( this . _url ) ;
this . _notificationsClient = new GrpcServiceClientPb _1 . NotificationsClient ( this . _url ) ;
this . _shutdownServerClient = new GrpcServiceClientPb _1 . ShutdownServerClient ( this . _url ) ;
2022-05-04 21:30:48 -04:00
}
/ * *
* Start a new Haveno process .
*
* @ param { string } havenoPath - path to Haveno binaries
* @ 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
2023-02-27 10:23:01 -05:00
* @ return { HavenoClient } a client connected to the newly started Haveno process
2022-05-04 21:30:48 -04:00
* /
static async startProcess ( havenoPath , cmd , url , enableLogging ) {
2022-06-07 17:48:04 -04:00
try {
return await new Promise ( ( resolve , reject ) => {
HavenoUtils _1 . default . log ( 2 , "Starting Haveno process: " + cmd + " on proxy url: " + url ) ;
// state variables
let output = "" ;
let isStarted = false ;
let daemon = undefined ;
// start process
const childProcess = require ( 'child_process' ) . spawn ( cmd [ 0 ] , cmd . slice ( 1 ) , { cwd : havenoPath } ) ;
childProcess . stdout . setEncoding ( 'utf8' ) ;
childProcess . stderr . setEncoding ( 'utf8' ) ;
// handle stdout
childProcess . stdout . on ( 'data' , async function ( data ) {
const line = data . toString ( ) ;
if ( loggingEnabled ( ) )
process . stdout . write ( line ) ;
output += line + '\n' ; // capture output in case of error
// initialize daemon on success or login required message
if ( ! daemon && ( line . indexOf ( HavenoClient . _fullyInitializedMessage ) >= 0 || line . indexOf ( HavenoClient . _loginRequiredMessage ) >= 0 ) ) {
// get api password
const passwordIdx = cmd . indexOf ( "--apiPassword" ) ;
if ( passwordIdx < 0 ) {
reject ( "Must provide API password to start Haveno daemon" ) ;
return ;
}
const password = cmd [ passwordIdx + 1 ] ;
// create client connected to internal process
daemon = new HavenoClient ( url , password ) ;
daemon . _process = childProcess ;
daemon . _processLogging = enableLogging ;
daemon . _appName = cmd [ cmd . indexOf ( "--appName" ) + 1 ] ;
// get wallet rpc port
const walletRpcPortIdx = cmd . indexOf ( "--walletRpcBindPort" ) ;
if ( walletRpcPortIdx >= 0 )
daemon . _walletRpcPort = parseInt ( cmd [ walletRpcPortIdx + 1 ] ) ;
// resolve promise with client connected to internal process
isStarted = true ;
resolve ( daemon ) ;
2022-05-04 21:30:48 -04:00
}
2022-06-07 17:48:04 -04:00
// read error message
if ( line . indexOf ( "[HavenoDaemonMain] ERROR" ) >= 0 ) {
if ( ! isStarted )
await rejectStartup ( new Error ( line ) ) ;
}
} ) ;
// handle stderr
childProcess . stderr . on ( 'data' , function ( data ) {
if ( loggingEnabled ( ) )
process . stderr . write ( data ) ;
} ) ;
// handle exit
childProcess . on ( "exit" , async function ( code ) {
2022-05-04 21:30:48 -04:00
if ( ! isStarted )
2022-06-07 17:48:04 -04:00
await rejectStartup ( new Error ( "Haveno process terminated with exit code " + code + ( output ? ":\n\n" + output : "" ) ) ) ;
} ) ;
// handle error
childProcess . on ( "error" , async function ( err ) {
if ( err . message . indexOf ( "ENOENT" ) >= 0 )
reject ( new Error ( "haveno-daemon does not exist at path '" + cmd [ 0 ] + "'" ) ) ;
if ( ! isStarted )
await rejectStartup ( err ) ;
} ) ;
// handle uncaught exception
childProcess . on ( "uncaughtException" , async function ( err , origin ) {
console _1 . default . error ( "Uncaught exception in Haveno process: " + err . message ) ;
console _1 . default . error ( origin ) ;
2022-05-04 21:30:48 -04:00
await rejectStartup ( err ) ;
2022-06-07 17:48:04 -04:00
} ) ;
async function rejectStartup ( err ) {
await HavenoUtils _1 . default . kill ( childProcess ) ;
reject ( err ) ;
}
function loggingEnabled ( ) {
return ( daemon && daemon . _processLogging ) || ( ! daemon && enableLogging ) ;
}
2022-05-04 21:30:48 -04:00
} ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Return the process running the haveno daemon .
*
* @ return the process running the haveno daemon
* /
getProcess ( ) {
return this . _process ;
}
/ * *
* Enable or disable process logging .
*
* @ param { boolean } enabled - specifies if logging is enabled or disabled
* /
setProcessLogging ( enabled ) {
if ( this . _process === undefined )
2022-06-07 17:48:04 -04:00
throw new HavenoError _1 . default ( "haveno instance not created from new process" ) ;
2022-05-04 21:30:48 -04:00
this . _processLogging = enabled ;
}
/ * *
* Get the URL of the Haveno daemon .
*
* @ return { string } the URL of the Haveno daemon
* /
getUrl ( ) {
return this . _url ;
}
/ * *
* Get the port of the primary wallet rpc instance if known .
*
* @ return { number | undefined } the port of the primary wallet rpc instance if known
* /
getWalletRpcPort ( ) {
return this . _walletRpcPort ;
}
/ * *
* Get the name of the Haveno application folder .
* /
getAppName ( ) {
return this . _appName ;
}
/ * *
* Get the Haveno version .
*
* @ return { string } the Haveno daemon version
* /
async getVersion ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _getVersionClient . getVersion ( new grpc _pb _1 . GetVersionRequest ( ) , { password : this . _password } ) ) . getVersion ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Indicates if connected and authenticated with the Haveno daemon .
*
* @ return { boolean } true if connected with the Haveno daemon , false otherwise
* /
async isConnectedToDaemon ( ) {
try {
await this . getVersion ( ) ;
return true ;
}
catch ( err ) {
return false ;
}
}
/ * *
* Indicates if the Haveno account is created .
*
* @ return { boolean } true if the account is created , false otherwise
* /
async accountExists ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _accountClient . accountExists ( new grpc _pb _1 . AccountExistsRequest ( ) , { password : this . _password } ) ) . getAccountExists ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Indicates if the Haveno account is open and authenticated with the correct password .
*
* @ return { boolean } true if the account is open and authenticated , false otherwise
* /
async isAccountOpen ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _accountClient . isAccountOpen ( new grpc _pb _1 . IsAccountOpenRequest ( ) , { password : this . _password } ) ) . getIsAccountOpen ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Create and open a new Haveno account .
*
* @ param { string } password - the password to encrypt the account
* /
async createAccount ( password ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
await this . _accountClient . createAccount ( new grpc _pb _1 . CreateAccountRequest ( ) . setPassword ( password ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
await this . _awaitAppInitialized ( ) ; // TODO: grpc should not return before setup is complete
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Open existing Haveno account .
*
* @ param { string } password - the account password
* /
async openAccount ( password ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
await this . _accountClient . openAccount ( new grpc _pb _1 . OpenAccountRequest ( ) . setPassword ( password ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
return this . _awaitAppInitialized ( ) ; // TODO: grpc should not return before setup is complete
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Change the Haveno account password .
*
* @ param { string } password - the new account password
* /
2023-02-27 10:23:01 -05:00
async changePassword ( oldPassword , newPassword ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
const request = new grpc _pb _1 . ChangePasswordRequest ( )
. setOldPassword ( oldPassword )
. setNewPassword ( newPassword ) ;
await this . _accountClient . changePassword ( request , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Close the currently open account .
* /
async closeAccount ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
await this . _accountClient . closeAccount ( new grpc _pb _1 . CloseAccountRequest ( ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
2023-02-27 10:23:01 -05:00
* Permanently delete the Haveno account .
2022-05-04 21:30:48 -04:00
* /
async deleteAccount ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
await this . _accountClient . deleteAccount ( new grpc _pb _1 . DeleteAccountRequest ( ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Backup the account to the given stream . TODO : stream type ?
* /
async backupAccount ( stream ) {
2022-06-07 17:48:04 -04:00
try {
return await new Promise ( ( resolve , reject ) => {
let total = 0 ;
const response = this . _accountClient . backupAccount ( new grpc _pb _1 . BackupAccountRequest ( ) , { password : this . _password } ) ;
response . on ( 'data' , ( chunk ) => {
const bytes = chunk . getZipBytes ( ) ; // TODO: right api?
total += bytes . length ;
stream . write ( bytes ) ;
} ) ;
response . on ( 'error' , function ( err ) {
if ( err )
reject ( err ) ;
} ) ;
response . on ( 'end' , function ( ) {
resolve ( total ) ;
} ) ;
2022-05-04 21:30:48 -04:00
} ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Restore the account from zip bytes .
*
* Sends chunked requests if size over max grpc envelope size ( 41943404 bytes ) .
*
* @ param { Uint8Array } zipBytes - the bytes of the zipped account to restore
* /
async restoreAccount ( zipBytes ) {
if ( zipBytes . length === 0 )
2022-06-07 17:48:04 -04:00
throw new HavenoError _1 . default ( "Zip bytes must not be empty" ) ;
2022-05-04 21:30:48 -04:00
const totalLength = zipBytes . byteLength ;
let offset = 0 ;
let chunkSize = 4000000 ; // the max frame size is 4194304 but leave room for http headers
let hasMore = true ;
// eslint-disable-next-line no-constant-condition
while ( true ) {
if ( zipBytes . byteLength <= offset + 1 )
return ;
if ( zipBytes . byteLength <= offset + chunkSize ) {
chunkSize = zipBytes . byteLength - offset - 1 ;
hasMore = false ;
}
const subArray = zipBytes . subarray ( offset , offset + chunkSize ) ;
await this . _restoreAccountChunk ( subArray , offset , totalLength , hasMore ) ;
offset += chunkSize ;
}
}
/ * *
* Add a listener to receive notifications from the Haveno daemon .
*
* @ param { ( notification : NotificationMessage ) => void } listener - the notification listener to add
* /
async addNotificationListener ( listener ) {
this . _notificationListeners . push ( listener ) ;
2022-06-07 17:48:04 -04:00
await this . _updateNotificationListenerRegistration ( ) ;
2022-05-04 21:30:48 -04:00
}
/ * *
* Remove a notification listener .
*
* @ param { ( notification : NotificationMessage ) => void } listener - the notification listener to remove
* /
async removeNotificationListener ( listener ) {
const idx = this . _notificationListeners . indexOf ( listener ) ;
if ( idx > - 1 )
this . _notificationListeners . splice ( idx , 1 ) ;
else
2022-06-07 17:48:04 -04:00
throw new HavenoError _1 . default ( "Notification listener is not registered" ) ;
await this . _updateNotificationListenerRegistration ( ) ;
2022-05-04 21:30:48 -04:00
}
/ * *
* Indicates if connected to the Monero network based on last connection check .
*
* @ return { boolean } true if connected to the Monero network , false otherwise
* /
async isConnectedToMonero ( ) {
const connection = await this . getMoneroConnection ( ) ;
return connection !== undefined &&
2022-05-12 17:25:46 -04:00
connection . getOnlineStatus ( ) === grpc _pb _1 . UrlConnection . OnlineStatus . ONLINE &&
connection . getAuthenticationStatus ( ) !== grpc _pb _1 . UrlConnection . AuthenticationStatus . NOT _AUTHENTICATED ;
2022-05-04 21:30:48 -04:00
}
/ * *
* Add a Monero daemon connection .
*
* @ param { string | UrlConnection } connection - daemon url or connection to add
* /
async addMoneroConnection ( connection ) {
2022-06-07 17:48:04 -04:00
try {
2023-11-25 14:48:58 -05:00
await this . _xmrConnectionsClient . addConnection ( new grpc _pb _1 . AddConnectionRequest ( ) . setConnection ( typeof connection === "string" ? new grpc _pb _1 . UrlConnection ( ) . setUrl ( connection ) : connection ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Remove a Monero daemon connection .
*
* @ param { string } url - url of the daemon connection to remove
* /
async removeMoneroConnection ( url ) {
2022-06-07 17:48:04 -04:00
try {
2023-11-25 14:48:58 -05:00
await this . _xmrConnectionsClient . removeConnection ( new grpc _pb _1 . RemoveConnectionRequest ( ) . setUrl ( url ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Get the current Monero daemon connection .
*
* @ return { UrlConnection | undefined } the current daemon connection , undefined if no current connection
* /
async getMoneroConnection ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-11-25 14:48:58 -05:00
return await ( await this . _xmrConnectionsClient . getConnection ( new grpc _pb _1 . GetConnectionRequest ( ) , { password : this . _password } ) ) . getConnection ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Get all Monero daemon connections .
*
* @ return { UrlConnection [ ] } all daemon connections
* /
async getMoneroConnections ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-11-25 14:48:58 -05:00
return ( await this . _xmrConnectionsClient . getConnections ( new grpc _pb _1 . GetConnectionsRequest ( ) , { password : this . _password } ) ) . getConnectionsList ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Set the current Monero daemon connection .
*
* Add the connection if not previously seen .
* If the connection is provided as string , connect to the URI with any previously set credentials and priority .
* If the connection is provided as UrlConnection , overwrite any previously set credentials and priority .
* If undefined connection provided , disconnect the client .
*
* @ param { string | UrlConnection } connection - connection to set as current
* /
async setMoneroConnection ( connection ) {
2022-05-12 17:25:46 -04:00
const request = new grpc _pb _1 . SetConnectionRequest ( ) ;
2022-05-04 21:30:48 -04:00
if ( typeof connection === "string" )
request . setUrl ( connection ) ;
else
request . setConnection ( connection ) ;
2022-06-07 17:48:04 -04:00
try {
2023-11-25 14:48:58 -05:00
await this . _xmrConnectionsClient . setConnection ( request , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Check the current Monero daemon connection .
*
* If disconnected and auto switch enabled , switch to the best available connection and return its status .
*
* @ return { UrlConnection | undefined } the current daemon connection status , undefined if no current connection
* /
async checkMoneroConnection ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-11-25 14:48:58 -05:00
return ( await this . _xmrConnectionsClient . checkConnection ( new grpc _pb _1 . CheckConnectionRequest ( ) , { password : this . _password } ) ) . getConnection ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Check all Monero daemon connections .
*
* @ return { UrlConnection [ ] } status of all managed connections .
* /
async checkMoneroConnections ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-11-25 14:48:58 -05:00
return ( await this . _xmrConnectionsClient . checkConnections ( new grpc _pb _1 . CheckConnectionsRequest ( ) , { password : this . _password } ) ) . getConnectionsList ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Check the connection and start checking the connection periodically .
*
* @ param { number } refreshPeriod - time between checks in milliseconds ( default 15000 ms or 15 seconds )
* /
async startCheckingConnection ( refreshPeriod ) {
2022-06-07 17:48:04 -04:00
try {
2024-04-23 10:44:13 -04:00
await this . _xmrConnectionsClient . startCheckingConnection ( new grpc _pb _1 . StartCheckingConnectionRequest ( ) . setRefreshPeriod ( refreshPeriod ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Stop checking the connection status periodically .
* /
async stopCheckingConnection ( ) {
2022-06-07 17:48:04 -04:00
try {
2024-04-23 10:44:13 -04:00
await this . _xmrConnectionsClient . stopCheckingConnection ( new grpc _pb _1 . StopCheckingConnectionRequest ( ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Get the best available connection in order of priority then response time .
*
* @ return { UrlConnection | undefined } the best available connection in order of priority then response time , undefined if no connections available
* /
async getBestAvailableConnection ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-11-25 14:48:58 -05:00
return ( await this . _xmrConnectionsClient . getBestAvailableConnection ( new grpc _pb _1 . GetBestAvailableConnectionRequest ( ) , { password : this . _password } ) ) . getConnection ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Automatically switch to the best available connection if current connection is disconnected after being checked .
*
* @ param { boolean } autoSwitch - whether auto switch is enabled or disabled
* /
async setAutoSwitch ( autoSwitch ) {
2022-06-07 17:48:04 -04:00
try {
2023-11-25 14:48:58 -05:00
await this . _xmrConnectionsClient . setAutoSwitch ( new grpc _pb _1 . SetAutoSwitchRequest ( ) . setAutoSwitch ( autoSwitch ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
2024-10-13 12:09:14 -04:00
/ * *
* Get the current auto switch setting .
*
* @ return { boolean } whether auto switch is enabled or disabled
* /
async getAutoSwitch ( ) {
try {
return ( await this . _xmrConnectionsClient . getAutoSwitch ( new grpc _pb _1 . GetAutoSwitchRequest ( ) , { password : this . _password } ) ) . getAutoSwitch ( ) ;
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
}
2022-05-04 21:30:48 -04:00
/ * *
* Returns whether daemon is running a local monero node .
* /
2022-09-21 10:41:36 -04:00
async isMoneroNodeOnline ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-11-25 14:48:58 -05:00
return ( await this . _xmrNodeClient . isXmrNodeOnline ( new grpc _pb _1 . IsXmrNodeOnlineRequest ( ) , { password : this . _password } ) ) . getIsRunning ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Gets the current local monero node settings .
* /
async getMoneroNodeSettings ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-11-25 14:48:58 -05:00
const request = new grpc _pb _1 . GetXmrNodeSettingsRequest ( ) ;
return ( await this . _xmrNodeClient . getXmrNodeSettings ( request , { password : this . _password } ) ) . getSettings ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Starts the local monero node .
*
* @ param { MoneroNodeSettings } settings - the settings to start the local node with
* /
async startMoneroNode ( settings ) {
2022-06-07 17:48:04 -04:00
try {
2023-11-25 14:48:58 -05:00
const request = new grpc _pb _1 . StartXmrNodeRequest ( ) . setSettings ( settings ) ;
await this . _xmrNodeClient . startXmrNode ( request , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Stops the local monero node .
* /
async stopMoneroNode ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-11-25 14:48:58 -05:00
await this . _xmrNodeClient . stopXmrNode ( new grpc _pb _1 . StopXmrNodeRequest ( ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Register as a dispute agent .
*
* @ param { string } disputeAgentType - type of dispute agent to register , e . g . mediator , refundagent
* @ param { string } registrationKey - registration key
* /
async registerDisputeAgent ( disputeAgentType , registrationKey ) {
2022-06-07 17:48:04 -04:00
try {
const request = new grpc _pb _1 . RegisterDisputeAgentRequest ( )
. setDisputeAgentType ( disputeAgentType )
. setRegistrationKey ( registrationKey ) ;
2023-02-27 10:23:01 -05:00
await this . _disputeAgentsClient . registerDisputeAgent ( request , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
2022-09-21 10:41:36 -04:00
/ * *
* Unregister as a dispute agent .
*
* @ param { string } disputeAgentType - type of dispute agent to register , e . g . mediator , refundagent
* /
async unregisterDisputeAgent ( disputeAgentType ) {
try {
2023-02-27 10:23:01 -05:00
await this . _disputeAgentsClient . unregisterDisputeAgent ( new grpc _pb _1 . UnregisterDisputeAgentRequest ( ) . setDisputeAgentType ( disputeAgentType ) , { password : this . _password } ) ;
2022-09-21 10:41:36 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
}
2022-05-04 21:30:48 -04:00
/ * *
* Get the user ' s balances .
*
* @ return { XmrBalanceInfo } the user ' s balances
* /
async getBalances ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _walletsClient . getBalances ( new grpc _pb _1 . GetBalancesRequest ( ) . setCurrencyCode ( "XMR" ) , { password : this . _password } ) ) . getBalances ( ) . getXmr ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
2022-05-10 14:57:20 -04:00
/ * *
* Get the mnemonic seed phrase of the Monero wallet .
*
* @ return { string } the mnemonic seed phrase of the Monero wallet
* /
async getXmrSeed ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _walletsClient . getXmrSeed ( new grpc _pb _1 . GetXmrSeedRequest ( ) , { password : this . _password } ) ) . getSeed ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-10 14:57:20 -04:00
}
2022-05-16 13:47:43 -04:00
/ * *
* Get the primary address of the Monero wallet .
*
* @ return { string } the primary address of the Monero wallet
* /
async getXmrPrimaryAddress ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _walletsClient . getXmrPrimaryAddress ( new grpc _pb _1 . GetXmrPrimaryAddressRequest ( ) , { password : this . _password } ) ) . getPrimaryAddress ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-16 13:47:43 -04:00
}
2022-05-04 21:30:48 -04:00
/ * *
* Get a new subaddress in the Monero wallet to receive deposits .
*
* @ return { string } the deposit address ( a subaddress in the Haveno wallet )
* /
2022-05-16 13:47:43 -04:00
async getXmrNewSubaddress ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _walletsClient . getXmrNewSubaddress ( new grpc _pb _1 . GetXmrNewSubaddressRequest ( ) , { password : this . _password } ) ) . getSubaddress ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Get all transactions in the Monero wallet .
*
* @ return { XmrTx [ ] } the transactions
* /
async getXmrTxs ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _walletsClient . getXmrTxs ( new grpc _pb _1 . GetXmrTxsRequest ( ) , { password : this . _password } ) ) . getTxsList ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Get a transaction by hash in the Monero wallet .
*
* @ param { String } txHash - hash of the transaction to get
* @ return { XmrTx } the transaction with the hash
* /
async getXmrTx ( txHash ) {
const txs = await this . getXmrTxs ( ) ; // TODO (woodser): implement getXmrTx(hash) grpc call
for ( const tx of txs ) {
if ( tx . getHash ( ) === txHash )
return tx ;
}
2022-12-17 05:06:40 -05:00
return undefined ;
2022-05-04 21:30:48 -04:00
}
/ * *
* Create but do not relay a transaction to send funds from the Monero wallet .
*
* @ return { XmrTx } the created transaction
* /
async createXmrTx ( destinations ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _walletsClient . createXmrTx ( new grpc _pb _1 . CreateXmrTxRequest ( ) . setDestinationsList ( destinations ) , { password : this . _password } ) ) . getTx ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Relay a previously created transaction to send funds from the Monero wallet .
*
* @ return { string } the hash of the relayed transaction
* /
async relayXmrTx ( metadata ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _walletsClient . relayXmrTx ( new grpc _pb _1 . RelayXmrTxRequest ( ) . setMetadata ( metadata ) , { password : this . _password } ) ) . getHash ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
2022-05-12 17:25:46 -04:00
/ * *
2023-09-15 09:13:48 -04:00
* Get all asset codes with price information .
2022-05-12 17:25:46 -04:00
*
* TODO : replace this with getSupportedAssetCodes ( ) : Promise < TradeCurrency [ ] > )
*
* @ return { Promise < string [ ] > } all supported trade assets
* /
2023-09-15 09:13:48 -04:00
async getPricedAssetCodes ( ) {
2022-05-12 17:25:46 -04:00
const assetCodes = [ ] ;
for ( const price of await this . getPrices ( ) )
assetCodes . push ( price . getCurrencyCode ( ) ) ;
return assetCodes ;
}
2022-05-04 21:30:48 -04:00
/ * *
* Get the current market price per 1 XMR in the given currency .
*
2022-05-12 17:25:46 -04:00
* @ param { string } assetCode - asset code to get the price of
* @ return { number } the price of the asset per 1 XMR
2022-05-04 21:30:48 -04:00
* /
2022-05-12 17:25:46 -04:00
async getPrice ( assetCode ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _priceClient . getMarketPrice ( new grpc _pb _1 . MarketPriceRequest ( ) . setCurrencyCode ( assetCode ) , { password : this . _password } ) ) . getPrice ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
2022-05-12 17:25:46 -04:00
* Get the current market prices of all a .
2022-05-04 21:30:48 -04:00
*
2022-05-12 17:25:46 -04:00
* @ return { MarketPrice [ ] } prices of the assets per 1 XMR
2022-05-04 21:30:48 -04:00
* /
async getPrices ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _priceClient . getMarketPrices ( new grpc _pb _1 . MarketPricesRequest ( ) , { password : this . _password } ) ) . getMarketPriceList ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Get the market depth of a currency .
*
* @ param { string } assetCode - asset to get the market depth of
* @ return { MarketDepthInfo } market depth of the given currency
* /
async getMarketDepth ( assetCode ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _priceClient . getMarketDepth ( new grpc _pb _1 . MarketDepthRequest ( ) . setCurrencyCode ( assetCode ) , { password : this . _password } ) ) . getMarketDepth ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Get payment methods .
*
2022-05-12 17:25:46 -04:00
* @ param { string } assetCode - get payment methods supporting this asset code ( optional )
2022-05-04 21:30:48 -04:00
* @ return { PaymentMethod [ ] } the payment methods
* /
2022-05-12 17:25:46 -04:00
async getPaymentMethods ( assetCode ) {
2022-06-07 17:48:04 -04:00
try {
if ( ! this . _paymentMethods ) {
2023-02-27 10:23:01 -05:00
this . _paymentMethods = ( await this . _paymentAccountsClient . getPaymentMethods ( new grpc _pb _1 . GetPaymentMethodsRequest ( ) , { password : this . _password } ) ) . getPaymentMethodsList ( ) ;
2022-06-07 17:48:04 -04:00
}
if ( ! assetCode )
return this . _paymentMethods ;
const assetPaymentMethods = [ ] ;
for ( const paymentMethod of this . _paymentMethods ) {
if ( paymentMethod . getSupportedAssetCodesList ( ) . includes ( assetCode ) )
assetPaymentMethods . push ( paymentMethod ) ;
}
return assetPaymentMethods ;
2022-05-12 17:25:46 -04:00
}
2022-06-07 17:48:04 -04:00
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
2022-05-12 17:25:46 -04:00
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Get payment accounts .
*
* @ return { PaymentAccount [ ] } the payment accounts
* /
async getPaymentAccounts ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _paymentAccountsClient . getPaymentAccounts ( new grpc _pb _1 . GetPaymentAccountsRequest ( ) , { password : this . _password } ) ) . getPaymentAccountsList ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Get a payment account by id .
*
* @ param { string } paymentAccountId - the payment account id to get
* @ return { PaymentAccount } the payment account
* /
async getPaymentAccount ( paymentAccountId ) {
// TODO (woodser): implement this on the backend
const paymentAccounts = await this . getPaymentAccounts ( ) ;
for ( const paymentAccount of paymentAccounts ) {
if ( paymentAccount . getId ( ) === paymentAccountId )
return paymentAccount ;
}
2022-06-07 17:48:04 -04:00
throw new HavenoError _1 . default ( "No payment account with id " + paymentAccountId ) ;
2022-05-04 21:30:48 -04:00
}
/ * *
* Get a form for the given payment method to complete and create a new payment account .
*
2023-09-15 09:13:48 -04:00
* @ param { string | PaymentAccountForm . FormId } paymentMethodId - the id of the payment method
2022-09-21 10:41:36 -04:00
* @ return { PaymentAccountForm } the payment account form
2022-05-04 21:30:48 -04:00
* /
async getPaymentAccountForm ( paymentMethodId ) {
2022-06-07 17:48:04 -04:00
try {
2023-09-15 09:13:48 -04:00
paymentMethodId = HavenoUtils _1 . default . getPaymentMethodId ( paymentMethodId ) ; // validate and normalize
2023-02-27 10:23:01 -05:00
return ( await this . _paymentAccountsClient . getPaymentAccountForm ( new grpc _pb _1 . GetPaymentAccountFormRequest ( ) . setPaymentMethodId ( paymentMethodId ) , { password : this . _password } ) ) . getPaymentAccountForm ( ) ;
2022-09-21 10:41:36 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
}
2022-12-17 05:06:40 -05:00
/ * *
* Get a form from the given payment account payload .
*
* @ param { PaymentAccountPayload } paymentAccountPayload - payload to get as a form
* @ return { PaymentAccountForm } the payment account form
* /
async getPaymentAccountPayloadForm ( paymentAccountPayload ) {
try {
2023-02-27 10:23:01 -05:00
return ( await this . _paymentAccountsClient . getPaymentAccountForm ( new grpc _pb _1 . GetPaymentAccountFormRequest ( ) . setPaymentAccountPayload ( paymentAccountPayload ) , { password : this . _password } ) ) . getPaymentAccountForm ( ) ;
2022-12-17 05:06:40 -05:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
}
2022-09-21 10:41:36 -04:00
/ *
* Validate a form field .
*
* @ param { object } form - form context to validate the given value
* @ param { PaymentAccountFormField . FieldId } fieldId - id of the field to validate
* @ param { string } value - input value to validate
* /
async validateFormField ( form , fieldId , value ) {
const request = new grpc _pb _1 . ValidateFormFieldRequest ( )
. setForm ( form )
. setFieldId ( fieldId )
. setValue ( value ) ;
try {
2023-02-27 10:23:01 -05:00
await this . _paymentAccountsClient . validateFormField ( request , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Create a payment account .
*
2022-09-21 10:41:36 -04:00
* @ param { PaymentAccountForm } paymentAccountForm - the completed form to create the payment account
2022-05-04 21:30:48 -04:00
* @ return { PaymentAccount } the created payment account
* /
async createPaymentAccount ( paymentAccountForm ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _paymentAccountsClient . createPaymentAccount ( new grpc _pb _1 . CreatePaymentAccountRequest ( ) . setPaymentAccountForm ( paymentAccountForm ) , { password : this . _password } ) ) . getPaymentAccount ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Create a crypto payment account .
*
* @ param { string } accountName - description of the account
* @ param { string } assetCode - traded asset code
* @ param { string } address - payment address of the account
* @ return { PaymentAccount } the created payment account
* /
async createCryptoPaymentAccount ( accountName , assetCode , address ) {
2022-06-07 17:48:04 -04:00
try {
const request = new grpc _pb _1 . CreateCryptoCurrencyPaymentAccountRequest ( )
. setAccountName ( accountName )
. setCurrencyCode ( assetCode )
. setAddress ( address )
. setTradeInstant ( false ) ; // not using instant trades
2023-02-27 10:23:01 -05:00
return ( await this . _paymentAccountsClient . createCryptoCurrencyPaymentAccount ( request , { password : this . _password } ) ) . getPaymentAccount ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
2024-08-07 07:00:58 -04:00
/ * *
* Delete a payment account .
*
* @ param paymentAccountId { string } the id of the payment account to delete
* /
async deletePaymentAccount ( paymentAccountId ) {
try {
await this . _paymentAccountsClient . deletePaymentAccount ( new grpc _pb _1 . DeletePaymentAccountRequest ( ) . setPaymentAccountId ( paymentAccountId ) , { password : this . _password } ) ;
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
}
2022-05-04 21:30:48 -04:00
/ * *
* Get available offers to buy or sell XMR .
*
* @ param { string } assetCode - traded asset code
2023-11-13 11:02:09 -05:00
* @ param { OfferDirection | undefined } direction - "buy" or "sell" ( default all )
2022-05-04 21:30:48 -04:00
* @ return { OfferInfo [ ] } the available offers
* /
async getOffers ( assetCode , direction ) {
2022-06-07 17:48:04 -04:00
try {
2023-11-13 11:02:09 -05:00
if ( direction === undefined )
return ( await this . getOffers ( assetCode , pb _pb _1 . OfferDirection . BUY ) ) . concat ( await this . getOffers ( assetCode , pb _pb _1 . OfferDirection . SELL ) ) ; // TODO: implement in backend
return ( await this . _offersClient . getOffers ( new grpc _pb _1 . GetOffersRequest ( ) . setDirection ( direction === pb _pb _1 . OfferDirection . BUY ? "buy" : "sell" ) . setCurrencyCode ( assetCode ) , { password : this . _password } ) ) . getOffersList ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Get the user ' s posted offers to buy or sell XMR .
*
2023-02-27 10:23:01 -05:00
* @ param { string | undefined } assetCode - traded asset code
2023-11-13 11:02:09 -05:00
* @ param { OfferDirection | undefined } direction - get offers to buy or sell XMR ( default all )
2022-05-04 21:30:48 -04:00
* @ return { OfferInfo [ ] } the user ' s created offers
* /
async getMyOffers ( assetCode , direction ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
const req = new grpc _pb _1 . GetOffersRequest ( ) ;
if ( assetCode )
req . setCurrencyCode ( assetCode ) ;
2023-11-13 11:02:09 -05:00
if ( direction !== undefined )
req . setDirection ( direction === pb _pb _1 . OfferDirection . BUY ? "buy" : "sell" ) ; // TODO: request should use OfferDirection too?
2023-02-27 10:23:01 -05:00
return ( await this . _offersClient . getMyOffers ( req , { password : this . _password } ) ) . getOffersList ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Get my offer by id .
*
* @ param { string } offerId - id of the user ' s created offer
* @ return { OfferInfo } the user ' s created offer
* /
async getMyOffer ( offerId ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _offersClient . getMyOffer ( new grpc _pb _1 . GetMyOfferRequest ( ) . setId ( offerId ) , { password : this . _password } ) ) . getOffer ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Post an offer .
*
2023-11-13 11:02:09 -05:00
* @ param { OfferDirection } direction - "buy" or "sell" XMR
2022-05-04 21:30:48 -04:00
* @ param { bigint } amount - amount of XMR to trade
* @ param { string } assetCode - asset code to trade for XMR
* @ param { string } paymentAccountId - payment account id
2023-10-30 17:11:33 -04:00
* @ param { number } securityDepositPct - security deposit as % of trade amount for buyer and seller
2022-05-04 21:30:48 -04:00
* @ param { number } price - trade price ( optional , default to market price )
2022-06-07 17:48:04 -04:00
* @ param { number } marketPriceMarginPct - if using market price , % from market price to accept ( optional , default 0 % )
2022-05-04 21:30:48 -04:00
* @ param { number } triggerPrice - price to remove offer ( optional )
2023-07-28 11:14:15 -04:00
* @ param { bigint } minAmount - minimum amount to trade ( optional , default to fixed amount )
2023-07-25 09:15:40 -04:00
* @ param { number } reserveExactAmount - reserve exact amount needed for offer , incurring on - chain transaction and 10 confirmations before the offer goes live ( default = false )
2022-05-04 21:30:48 -04:00
* @ return { OfferInfo } the posted offer
* /
2023-10-30 17:11:33 -04:00
async postOffer ( direction , amount , assetCode , paymentAccountId , securityDepositPct , price , marketPriceMarginPct , triggerPrice , minAmount , reserveExactAmount ) {
console _1 . default . log ( "Posting offer with security deposit %: " + securityDepositPct ) ;
2022-06-07 17:48:04 -04:00
try {
2022-12-17 05:06:40 -05:00
const request = new grpc _pb _1 . PostOfferRequest ( )
2023-11-13 11:02:09 -05:00
. setDirection ( direction === pb _pb _1 . OfferDirection . BUY ? "buy" : "sell" )
2022-06-07 17:48:04 -04:00
. setAmount ( amount . toString ( ) )
. setCurrencyCode ( assetCode )
. setPaymentAccountId ( paymentAccountId )
2023-10-30 17:11:33 -04:00
. setBuyerSecurityDepositPct ( securityDepositPct )
2022-12-17 05:06:40 -05:00
. setUseMarketBasedPrice ( price === undefined )
2022-06-07 17:48:04 -04:00
. setMinAmount ( minAmount ? minAmount . toString ( ) : amount . toString ( ) ) ;
2022-12-17 05:06:40 -05:00
if ( price )
request . setPrice ( price . toString ( ) ) ;
2022-06-07 17:48:04 -04:00
if ( marketPriceMarginPct )
request . setMarketPriceMarginPct ( marketPriceMarginPct ) ;
if ( triggerPrice )
request . setTriggerPrice ( triggerPrice . toString ( ) ) ;
2023-07-25 09:15:40 -04:00
if ( reserveExactAmount )
request . setReserveExactAmount ( reserveExactAmount ) ;
2023-02-27 10:23:01 -05:00
return ( await this . _offersClient . postOffer ( request , { password : this . _password } ) ) . getOffer ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Remove a posted offer , releasing its reserved funds .
*
* @ param { string } offerId - the offer id to cancel
* /
async removeOffer ( offerId ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
await this . _offersClient . cancelOffer ( new grpc _pb _1 . CancelOfferRequest ( ) . setId ( offerId ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Take an offer .
*
* @ param { string } offerId - id of the offer to take
* @ param { string } paymentAccountId - id of the payment account
2023-05-30 18:08:04 -04:00
* @ param { bigint | undefined } amount - amount the taker chooses to buy or sell within the offer range ( default is max offer amount )
2022-05-04 21:30:48 -04:00
* @ return { TradeInfo } the initialized trade
* /
2023-05-30 18:08:04 -04:00
async takeOffer ( offerId , paymentAccountId , amount ) {
2022-06-07 17:48:04 -04:00
try {
const request = new grpc _pb _1 . TakeOfferRequest ( )
. setOfferId ( offerId )
. setPaymentAccountId ( paymentAccountId ) ;
2023-05-30 18:08:04 -04:00
if ( amount )
request . setAmount ( amount . toString ( ) ) ;
2024-01-07 16:15:48 -05:00
const resp = await this . _tradesClient . takeOffer ( request , { password : this . _password } ) ;
if ( resp . getTrade ( ) )
return resp . getTrade ( ) ;
throw new HavenoError _1 . default ( resp . getFailureReason ( ) ? . getDescription ( ) , resp . getFailureReason ( ) ? . getAvailabilityResult ( ) ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Get a trade by id .
*
* @ param { string } tradeId - the id of the trade and its offer
* @ return { TradeInfo } the trade with the given id
* /
async getTrade ( tradeId ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _tradesClient . getTrade ( new grpc _pb _1 . GetTradeRequest ( ) . setTradeId ( tradeId ) , { password : this . _password } ) ) . getTrade ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
2024-08-07 07:00:58 -04:00
/ * *
* Get all trade statistics .
*
* @ return { TradeStatistics3 [ ] } all user trades
* /
async getTradeStatistics ( ) {
try {
return ( await this . _getTradeStatisticsClient . getTradeStatistics ( new grpc _pb _1 . GetTradeStatisticsRequest ( ) , { password : this . _password } ) ) . getTradeStatisticsList ( ) ;
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
}
2022-05-04 21:30:48 -04:00
/ * *
* Get all trades .
*
* @ return { TradeInfo [ ] } all user trades
* /
async getTrades ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _tradesClient . getTrades ( new grpc _pb _1 . GetTradesRequest ( ) , { password : this . _password } ) ) . getTradesList ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
2023-02-27 10:23:01 -05:00
* Confirm a payment is sent .
2022-05-04 21:30:48 -04:00
*
* @ param { string } tradeId - the id of the trade
* /
2023-02-27 10:23:01 -05:00
async confirmPaymentSent ( tradeId ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
await this . _tradesClient . confirmPaymentSent ( new grpc _pb _1 . ConfirmPaymentSentRequest ( ) . setTradeId ( tradeId ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Confirm a payment is received .
*
* @ param { string } tradeId - the id of the trade
* /
async confirmPaymentReceived ( tradeId ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
await this . _tradesClient . confirmPaymentReceived ( new grpc _pb _1 . ConfirmPaymentReceivedRequest ( ) . setTradeId ( tradeId ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
2022-12-17 05:06:40 -05:00
/ * *
* Acknowledge that a trade has completed .
*
* @ param { string } tradeId - the id of the trade
* /
async completeTrade ( tradeId ) {
try {
2023-02-27 10:23:01 -05:00
await this . _tradesClient . completeTrade ( new grpc _pb _1 . CompleteTradeRequest ( ) . setTradeId ( tradeId ) , { password : this . _password } ) ;
2022-12-17 05:06:40 -05:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
}
2022-05-04 21:30:48 -04:00
/ * *
* Get all chat messages for a trade .
*
* @ param { string } tradeId - the id of the trade
* /
async getChatMessages ( tradeId ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
const request = new grpc _pb _1 . GetChatMessagesRequest ( ) . setTradeId ( tradeId ) ;
return ( await this . _tradesClient . getChatMessages ( request , { password : this . _password } ) ) . getMessageList ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Send a trade chat message .
*
* @ param { string } tradeId - the id of the trade
* @ param { string } message - the message
* /
async sendChatMessage ( tradeId , message ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
const request = new grpc _pb _1 . SendChatMessageRequest ( )
. setTradeId ( tradeId )
. setMessage ( message ) ;
await this . _tradesClient . sendChatMessage ( request , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Get a dispute by trade id .
*
* @ param { string } tradeId - the id of the trade
* /
async getDispute ( tradeId ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _disputesClient . getDispute ( new grpc _pb _1 . GetDisputeRequest ( ) . setTradeId ( tradeId ) , { password : this . _password } ) ) . getDispute ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Get all disputes .
* /
async getDisputes ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _disputesClient . getDisputes ( new grpc _pb _1 . GetDisputesRequest ( ) , { password : this . _password } ) ) . getDisputesList ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Open a dispute for a trade .
*
* @ param { string } tradeId - the id of the trade
* /
async openDispute ( tradeId ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
await this . _disputesClient . openDispute ( new grpc _pb _1 . OpenDisputeRequest ( ) . setTradeId ( tradeId ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Resolve a dispute . By default , the winner receives the trade amount and the security deposits are returned ,
2022-12-17 05:06:40 -05:00
* but the arbitrator may award a custom amount to the winner and the loser will get the rest .
2022-05-04 21:30:48 -04:00
*
* @ param { string } tradeId - the id of the trade
* @ param { DisputeResult . Winner } winner - the winner of the dispute
* @ param { DisputeResult . Reason } reason - the reason for the dispute
* @ param { string } summaryNotes - summary of the dispute
* @ param { bigint } customWinnerAmount - custom amount to award the winner ( optional )
* /
async resolveDispute ( tradeId , winner , reason , summaryNotes , customWinnerAmount ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
const request = new grpc _pb _1 . ResolveDisputeRequest ( )
. setTradeId ( tradeId )
. setWinner ( winner )
. setReason ( reason )
. setSummaryNotes ( summaryNotes )
. setCustomPayoutAmount ( customWinnerAmount ? customWinnerAmount . toString ( ) : "0" ) ;
await this . _disputesClient . resolveDispute ( request , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Send a dispute chat message .
*
* @ param { string } disputeId - the id of the dispute
* @ param { string } message - the message
* @ param { Attachment [ ] } attachments - attachments
* /
async sendDisputeChatMessage ( disputeId , message , attachments ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
const request = new grpc _pb _1 . SendDisputeChatMessageRequest ( )
. setDisputeId ( disputeId )
. setMessage ( message )
. setAttachmentsList ( attachments ) ;
await this . _disputesClient . sendDisputeChatMessage ( request , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Disconnect this client from the server .
* /
async disconnect ( ) {
while ( this . _notificationListeners . length )
await this . removeNotificationListener ( this . _notificationListeners [ 0 ] ) ;
}
/ * *
* Shutdown the Haveno daemon server and stop the process if applicable .
* /
async shutdownServer ( ) {
2022-06-07 17:48:04 -04:00
try {
await this . disconnect ( ) ;
2023-02-27 10:23:01 -05:00
await this . _shutdownServerClient . stop ( new grpc _pb _1 . StopRequest ( ) , { password : this . _password } ) ; // process receives 'exit' event
2022-06-07 17:48:04 -04:00
if ( this . _process )
return HavenoUtils _1 . default . kill ( this . _process ) ;
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
// ------------------------------- HELPERS ----------------------------------
/ * *
* Wait for the application to be fully initialized with an account and a
* connection to the Haveno network .
*
* TODO :
*
* Currently when the application starts , the account is first initialized with createAccount ( )
* or openAccount ( ) which return immediately . A notification is sent after all setup is complete and
* the application is connected to the Haveno network .
*
* Ideally when the application starts , the system checks the Haveno network connection , supporting
* havenod . isHavenoConnectionInitialized ( ) and havenod . awaitHavenoConnectionInitialized ( ) .
* Independently , gRPC createAccount ( ) and openAccount ( ) return after all account setup and reading from disk .
*
2022-12-17 05:06:40 -05:00
* @ private
2022-05-04 21:30:48 -04:00
* /
async _awaitAppInitialized ( ) {
2022-06-07 17:48:04 -04:00
try {
// eslint-disable-next-line no-async-promise-executor
await new Promise ( async ( resolve ) => {
let isResolved = false ;
const resolveOnce = async ( ) => {
if ( isResolved )
return ;
isResolved = true ;
await this . removeNotificationListener ( listener ) ;
resolve ( ) ;
} ;
const listener = async function ( notification ) {
if ( notification . getType ( ) === grpc _pb _1 . NotificationMessage . NotificationType . APP _INITIALIZED )
await resolveOnce ( ) ;
} ;
await this . addNotificationListener ( listener ) ;
if ( await this . _isAppInitialized ( ) )
2022-05-04 21:30:48 -04:00
await resolveOnce ( ) ;
2022-06-07 17:48:04 -04:00
} ) ;
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
2022-12-17 05:06:40 -05:00
/** @private */
2022-05-04 21:30:48 -04:00
async _isAppInitialized ( ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
return ( await this . _accountClient . isAppInitialized ( new grpc _pb _1 . IsAppInitializedRequest ( ) , { password : this . _password } ) ) . getIsAppInitialized ( ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Update notification listener registration .
* Due to the nature of grpc streaming , this method returns a promise
* which may be resolved before the listener is actually registered .
2022-12-17 05:06:40 -05:00
*
* @ private
2022-05-04 21:30:48 -04:00
* /
async _updateNotificationListenerRegistration ( ) {
2022-06-07 17:48:04 -04:00
try {
const listening = this . _notificationListeners . length > 0 ;
2023-02-27 10:23:01 -05:00
if ( ( listening && this . _notificationStream ) || ( ! listening && ! this . _notificationStream ) )
2022-06-07 17:48:04 -04:00
return ; // no difference
if ( listening ) {
2023-02-27 10:23:01 -05:00
// send request to register client listener
this . _notificationStream = this . _notificationsClient . registerNotificationListener ( new grpc _pb _1 . RegisterNotificationListenerRequest ( ) , { password : this . _password } )
. on ( 'data' , this . _onNotification ) ;
// periodically send keep alive requests // TODO (woodser): better way to keep notification stream alive?
let firstRequest = true ;
this . _keepAliveLooper = new TaskLooper _1 . default ( async ( ) => {
if ( firstRequest ) {
firstRequest = false ;
return ;
}
try {
2022-06-07 17:48:04 -04:00
await this . _sendNotification ( new grpc _pb _1 . NotificationMessage ( )
. setType ( grpc _pb _1 . NotificationMessage . NotificationType . KEEP _ALIVE )
. setTimestamp ( Date . now ( ) ) ) ;
2023-02-27 10:23:01 -05:00
}
catch ( err ) {
HavenoUtils _1 . default . log ( 0 , "Error sending keep alive request to Haveno daemon " + this . getUrl ( ) + ": " + err . message ) ;
}
2022-05-04 21:30:48 -04:00
} ) ;
2023-02-27 10:23:01 -05:00
this . _keepAliveLooper . start ( this . _keepAlivePeriodMs ) ;
await HavenoUtils _1 . default . waitFor ( 1000 ) ; // TODO: call returns before listener registered
2022-06-07 17:48:04 -04:00
}
else {
2022-12-17 05:06:40 -05:00
this . _notificationStream . removeListener ( 'data' , this . _onNotification ) ;
2022-06-07 17:48:04 -04:00
this . _keepAliveLooper . stop ( ) ;
this . _notificationStream . cancel ( ) ;
this . _notificationStream = undefined ;
}
2022-05-04 21:30:48 -04:00
}
2022-06-07 17:48:04 -04:00
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
2022-05-04 21:30:48 -04:00
}
}
/ * *
* Send a notification .
*
2022-12-17 05:06:40 -05:00
* @ private
2022-05-04 21:30:48 -04:00
* @ param { NotificationMessage } notification - notification to send
* /
async _sendNotification ( notification ) {
2022-06-07 17:48:04 -04:00
try {
2023-02-27 10:23:01 -05:00
await this . _notificationsClient . sendNotification ( new grpc _pb _1 . SendNotificationRequest ( ) . setNotification ( notification ) , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
/ * *
* Restore an account chunk from zip bytes .
*
2022-12-17 05:06:40 -05:00
* @ private
2022-05-04 21:30:48 -04:00
* /
async _restoreAccountChunk ( zipBytes , offset , totalLength , hasMore ) {
2022-06-07 17:48:04 -04:00
try {
const request = new grpc _pb _1 . RestoreAccountRequest ( )
. setZipBytes ( zipBytes )
. setOffset ( offset )
. setTotalLength ( totalLength )
. setHasMore ( hasMore ) ;
2023-02-27 10:23:01 -05:00
await this . _accountClient . restoreAccount ( request , { password : this . _password } ) ;
2022-06-07 17:48:04 -04:00
}
catch ( e ) {
throw new HavenoError _1 . default ( e . message , e . code ) ;
}
2022-05-04 21:30:48 -04:00
}
}
2022-05-12 17:25:46 -04:00
exports . default = HavenoClient ;
2022-05-04 21:30:48 -04:00
// constants
2022-12-17 05:06:40 -05:00
/** @private */ HavenoClient . _fullyInitializedMessage = "Application fully initialized" ;
/** @private */ HavenoClient . _loginRequiredMessage = "Interactive login required" ;
2022-05-04 21:30:48 -04:00
//# sourceMappingURL=HavenoClient.js.map