mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-12-06 17:27:59 +00:00
* update definitions
* add network id to base transaction
* update server info
* update base tx
* add network id to autofill
* update tests and fixtures
* network id option 3
fixup
add network id to server info fixture
fixup!
Revert "update tests and fixtures"
This reverts commit a5deee1274.
* update autofill
* update getNetworkID
* remove set network func
* fixup!
remove autoset network id
remove my mistake
fixup!
658 lines
20 KiB
TypeScript
658 lines
20 KiB
TypeScript
/* eslint-disable jsdoc/require-jsdoc -- Request has many aliases, but they don't need unique docs */
|
|
/* eslint-disable @typescript-eslint/member-ordering -- TODO: remove when instance methods aren't members */
|
|
/* eslint-disable max-lines -- Client is a large file w/ lots of imports/exports */
|
|
import * as assert from 'assert'
|
|
import { EventEmitter } from 'events'
|
|
|
|
import { NotFoundError, ValidationError, XrplError } from '../errors'
|
|
import {
|
|
Request,
|
|
Response,
|
|
// account methods
|
|
AccountChannelsRequest,
|
|
AccountChannelsResponse,
|
|
AccountCurrenciesRequest,
|
|
AccountCurrenciesResponse,
|
|
AccountInfoRequest,
|
|
AccountInfoResponse,
|
|
AccountLinesRequest,
|
|
AccountLinesResponse,
|
|
AccountNFTsRequest,
|
|
AccountNFTsResponse,
|
|
AccountObjectsRequest,
|
|
AccountObjectsResponse,
|
|
AccountOffersRequest,
|
|
AccountOffersResponse,
|
|
AccountTxRequest,
|
|
AccountTxResponse,
|
|
GatewayBalancesRequest,
|
|
GatewayBalancesResponse,
|
|
NoRippleCheckRequest,
|
|
NoRippleCheckResponse,
|
|
// ledger methods
|
|
LedgerRequest,
|
|
LedgerResponse,
|
|
LedgerClosedRequest,
|
|
LedgerClosedResponse,
|
|
LedgerCurrentRequest,
|
|
LedgerCurrentResponse,
|
|
LedgerDataRequest,
|
|
LedgerDataResponse,
|
|
LedgerEntryRequest,
|
|
LedgerEntryResponse,
|
|
// transaction methods
|
|
SubmitRequest,
|
|
SubmitResponse,
|
|
SubmitMultisignedRequest,
|
|
SubmitMultisignedResponse,
|
|
TransactionEntryRequest,
|
|
TransactionEntryResponse,
|
|
TxRequest,
|
|
TxResponse,
|
|
// path and order book methods
|
|
BookOffersRequest,
|
|
BookOffersResponse,
|
|
DepositAuthorizedRequest,
|
|
DepositAuthorizedResponse,
|
|
PathFindRequest,
|
|
PathFindResponse,
|
|
RipplePathFindRequest,
|
|
RipplePathFindResponse,
|
|
// payment channel methods
|
|
ChannelVerifyRequest,
|
|
ChannelVerifyResponse,
|
|
// server info methods
|
|
FeeRequest,
|
|
FeeResponse,
|
|
ManifestRequest,
|
|
ManifestResponse,
|
|
ServerInfoRequest,
|
|
ServerInfoResponse,
|
|
ServerStateRequest,
|
|
ServerStateResponse,
|
|
// utility methods
|
|
PingRequest,
|
|
PingResponse,
|
|
RandomRequest,
|
|
RandomResponse,
|
|
LedgerStream,
|
|
ValidationStream,
|
|
TransactionStream,
|
|
PathFindStream,
|
|
PeerStatusStream,
|
|
ConsensusStream,
|
|
SubscribeRequest,
|
|
SubscribeResponse,
|
|
UnsubscribeRequest,
|
|
UnsubscribeResponse,
|
|
// NFT methods
|
|
NFTBuyOffersRequest,
|
|
NFTBuyOffersResponse,
|
|
NFTSellOffersRequest,
|
|
NFTSellOffersResponse,
|
|
} from '../models/methods'
|
|
import { BaseRequest, BaseResponse } from '../models/methods/baseMethod'
|
|
import {
|
|
autofill,
|
|
ensureClassicAddress,
|
|
getLedgerIndex,
|
|
getOrderbook,
|
|
getBalances,
|
|
getXrpBalance,
|
|
submit,
|
|
submitAndWait,
|
|
getNetworkID,
|
|
} from '../sugar'
|
|
import fundWallet from '../Wallet/fundWallet'
|
|
|
|
import {
|
|
Connection,
|
|
ConnectionUserOptions,
|
|
INTENTIONAL_DISCONNECT_CODE,
|
|
} from './connection'
|
|
import {
|
|
handlePartialPayment,
|
|
handleStreamPartialPayment,
|
|
} from './partialPayment'
|
|
|
|
export interface ClientOptions extends ConnectionUserOptions {
|
|
feeCushion?: number
|
|
maxFeeXRP?: string
|
|
proxy?: string
|
|
timeout?: number
|
|
}
|
|
|
|
/**
|
|
* Get the response key / property name that contains the listed data for a
|
|
* command. This varies from command to command, but we need to know it to
|
|
* properly count across many requests.
|
|
*
|
|
* @param command - The rippled request command.
|
|
* @returns The property key corresponding to the command.
|
|
*/
|
|
function getCollectKeyFromCommand(command: string): string | null {
|
|
switch (command) {
|
|
case 'account_channels':
|
|
return 'channels'
|
|
case 'account_lines':
|
|
return 'lines'
|
|
case 'account_objects':
|
|
return 'account_objects'
|
|
case 'account_tx':
|
|
return 'transactions'
|
|
case 'account_offers':
|
|
case 'book_offers':
|
|
return 'offers'
|
|
case 'ledger_data':
|
|
return 'state'
|
|
default:
|
|
return null
|
|
}
|
|
}
|
|
|
|
function clamp(value: number, min: number, max: number): number {
|
|
assert.ok(min <= max, 'Illegal clamp bounds')
|
|
return Math.min(Math.max(value, min), max)
|
|
}
|
|
|
|
interface MarkerRequest extends BaseRequest {
|
|
limit?: number
|
|
marker?: unknown
|
|
}
|
|
|
|
interface MarkerResponse extends BaseResponse {
|
|
result: {
|
|
marker?: unknown
|
|
}
|
|
}
|
|
|
|
const DEFAULT_FEE_CUSHION = 1.2
|
|
const DEFAULT_MAX_FEE_XRP = '2'
|
|
|
|
const MIN_LIMIT = 10
|
|
const MAX_LIMIT = 400
|
|
|
|
const NORMAL_DISCONNECT_CODE = 1000
|
|
|
|
/**
|
|
* Client for interacting with rippled servers.
|
|
*
|
|
* @category Clients
|
|
*/
|
|
class Client extends EventEmitter {
|
|
/*
|
|
* Underlying connection to rippled.
|
|
*/
|
|
public readonly connection: Connection
|
|
|
|
/**
|
|
* Factor to multiply estimated fee by to provide a cushion in case the
|
|
* required fee rises during submission of a transaction. Defaults to 1.2.
|
|
*
|
|
* @category Fee
|
|
*/
|
|
public readonly feeCushion: number
|
|
|
|
/**
|
|
* Maximum transaction cost to allow, in decimal XRP. Must be a string-encoded
|
|
* number. Defaults to '2'.
|
|
*
|
|
* @category Fee
|
|
*/
|
|
public readonly maxFeeXRP: string
|
|
|
|
/**
|
|
* Network ID of the server this sdk is connected to
|
|
*
|
|
* @category Fee
|
|
*/
|
|
public networkID: number
|
|
|
|
/**
|
|
* Creates a new Client with a websocket connection to a rippled server.
|
|
*
|
|
* @param server - URL of the server to connect to.
|
|
* @param options - Options for client settings.
|
|
* @category Constructor
|
|
*/
|
|
// eslint-disable-next-line max-lines-per-function -- okay because we have to set up all the connection handlers
|
|
public constructor(server: string, options: ClientOptions = {}) {
|
|
super()
|
|
if (typeof server !== 'string' || !/wss?(?:\+unix)?:\/\//u.exec(server)) {
|
|
throw new ValidationError(
|
|
'server URI must start with `wss://`, `ws://`, `wss+unix://`, or `ws+unix://`.',
|
|
)
|
|
}
|
|
|
|
this.feeCushion = options.feeCushion ?? DEFAULT_FEE_CUSHION
|
|
this.maxFeeXRP = options.maxFeeXRP ?? DEFAULT_MAX_FEE_XRP
|
|
this.networkID = 1
|
|
|
|
this.connection = new Connection(server, options)
|
|
|
|
this.connection.on('error', (errorCode, errorMessage, data) => {
|
|
this.emit('error', errorCode, errorMessage, data)
|
|
})
|
|
|
|
this.connection.on('connected', () => {
|
|
this.emit('connected')
|
|
})
|
|
|
|
this.connection.on('disconnected', (code: number) => {
|
|
let finalCode = code
|
|
/*
|
|
* 4000: Connection uses a 4000 code internally to indicate a manual disconnect/close
|
|
* Since 4000 is a normal disconnect reason, we convert this to the standard exit code 1000
|
|
*/
|
|
if (finalCode === INTENTIONAL_DISCONNECT_CODE) {
|
|
finalCode = NORMAL_DISCONNECT_CODE
|
|
}
|
|
this.emit('disconnected', finalCode)
|
|
})
|
|
|
|
this.connection.on('ledgerClosed', (ledger) => {
|
|
this.emit('ledgerClosed', ledger)
|
|
})
|
|
|
|
this.connection.on('transaction', (tx) => {
|
|
// mutates `tx` to add warnings
|
|
handleStreamPartialPayment(tx, this.connection.trace)
|
|
this.emit('transaction', tx)
|
|
})
|
|
|
|
this.connection.on('validationReceived', (validation) => {
|
|
this.emit('validationReceived', validation)
|
|
})
|
|
|
|
this.connection.on('manifestReceived', (manifest) => {
|
|
this.emit('manifestReceived', manifest)
|
|
})
|
|
|
|
this.connection.on('peerStatusChange', (status) => {
|
|
this.emit('peerStatusChange', status)
|
|
})
|
|
|
|
this.connection.on('consensusPhase', (consensus) => {
|
|
this.emit('consensusPhase', consensus)
|
|
})
|
|
|
|
this.connection.on('path_find', (path) => {
|
|
this.emit('path_find', path)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Get the url that the client is connected to.
|
|
*
|
|
* @returns The URL of the server this client is connected to.
|
|
* @category Network
|
|
*/
|
|
public get url(): string {
|
|
return this.connection.getUrl()
|
|
}
|
|
|
|
/**
|
|
* @category Network
|
|
*/
|
|
public async request(
|
|
r: AccountChannelsRequest,
|
|
): Promise<AccountChannelsResponse>
|
|
public async request(
|
|
r: AccountCurrenciesRequest,
|
|
): Promise<AccountCurrenciesResponse>
|
|
public async request(r: AccountInfoRequest): Promise<AccountInfoResponse>
|
|
public async request(r: AccountLinesRequest): Promise<AccountLinesResponse>
|
|
public async request(r: AccountNFTsRequest): Promise<AccountNFTsResponse>
|
|
public async request(
|
|
r: AccountObjectsRequest,
|
|
): Promise<AccountObjectsResponse>
|
|
public async request(r: AccountOffersRequest): Promise<AccountOffersResponse>
|
|
public async request(r: AccountTxRequest): Promise<AccountTxResponse>
|
|
public async request(r: BookOffersRequest): Promise<BookOffersResponse>
|
|
public async request(r: ChannelVerifyRequest): Promise<ChannelVerifyResponse>
|
|
public async request(
|
|
r: DepositAuthorizedRequest,
|
|
): Promise<DepositAuthorizedResponse>
|
|
public async request(r: FeeRequest): Promise<FeeResponse>
|
|
public async request(
|
|
r: GatewayBalancesRequest,
|
|
): Promise<GatewayBalancesResponse>
|
|
public async request(r: LedgerRequest): Promise<LedgerResponse>
|
|
public async request(r: LedgerClosedRequest): Promise<LedgerClosedResponse>
|
|
public async request(r: LedgerCurrentRequest): Promise<LedgerCurrentResponse>
|
|
public async request(r: LedgerDataRequest): Promise<LedgerDataResponse>
|
|
public async request(r: LedgerEntryRequest): Promise<LedgerEntryResponse>
|
|
public async request(r: ManifestRequest): Promise<ManifestResponse>
|
|
public async request(r: NFTBuyOffersRequest): Promise<NFTBuyOffersResponse>
|
|
public async request(r: NFTSellOffersRequest): Promise<NFTSellOffersResponse>
|
|
public async request(r: NoRippleCheckRequest): Promise<NoRippleCheckResponse>
|
|
public async request(r: PathFindRequest): Promise<PathFindResponse>
|
|
public async request(r: PingRequest): Promise<PingResponse>
|
|
public async request(r: RandomRequest): Promise<RandomResponse>
|
|
public async request(
|
|
r: RipplePathFindRequest,
|
|
): Promise<RipplePathFindResponse>
|
|
public async request(r: ServerInfoRequest): Promise<ServerInfoResponse>
|
|
public async request(r: ServerStateRequest): Promise<ServerStateResponse>
|
|
public async request(r: SubmitRequest): Promise<SubmitResponse>
|
|
public async request(
|
|
r: SubmitMultisignedRequest,
|
|
): Promise<SubmitMultisignedResponse>
|
|
public request(r: SubscribeRequest): Promise<SubscribeResponse>
|
|
public request(r: UnsubscribeRequest): Promise<UnsubscribeResponse>
|
|
public async request(
|
|
r: TransactionEntryRequest,
|
|
): Promise<TransactionEntryResponse>
|
|
public async request(r: TxRequest): Promise<TxResponse>
|
|
public async request<R extends BaseRequest, T extends BaseResponse>(
|
|
r: R,
|
|
): Promise<T>
|
|
/**
|
|
* Makes a request to the client with the given command and
|
|
* additional request body parameters.
|
|
*
|
|
* @param req - Request to send to the server.
|
|
* @returns The response from the server.
|
|
* @category Network
|
|
*/
|
|
public async request<R extends Request, T extends Response>(
|
|
req: R,
|
|
): Promise<T> {
|
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Necessary for overloading
|
|
const response = (await this.connection.request({
|
|
...req,
|
|
account: req.account
|
|
? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Must be string
|
|
ensureClassicAddress(req.account as string)
|
|
: undefined,
|
|
})) as T
|
|
|
|
// mutates `response` to add warnings
|
|
handlePartialPayment(req.command, response)
|
|
|
|
return response
|
|
}
|
|
|
|
/**
|
|
* @category Network
|
|
*/
|
|
public async requestNextPage(
|
|
req: AccountChannelsRequest,
|
|
resp: AccountChannelsResponse,
|
|
): Promise<AccountChannelsResponse>
|
|
public async requestNextPage(
|
|
req: AccountLinesRequest,
|
|
resp: AccountLinesResponse,
|
|
): Promise<AccountLinesResponse>
|
|
public async requestNextPage(
|
|
req: AccountObjectsRequest,
|
|
resp: AccountObjectsResponse,
|
|
): Promise<AccountObjectsResponse>
|
|
public async requestNextPage(
|
|
req: AccountOffersRequest,
|
|
resp: AccountOffersResponse,
|
|
): Promise<AccountOffersResponse>
|
|
public async requestNextPage(
|
|
req: AccountTxRequest,
|
|
resp: AccountTxResponse,
|
|
): Promise<AccountTxResponse>
|
|
public async requestNextPage(
|
|
req: LedgerDataRequest,
|
|
resp: LedgerDataResponse,
|
|
): Promise<LedgerDataResponse>
|
|
/**
|
|
* Requests the next page of data.
|
|
*
|
|
* @param req - Request to send.
|
|
* @param resp - Response with the marker to use in the request.
|
|
* @returns The response with the next page of data.
|
|
*/
|
|
public async requestNextPage<
|
|
T extends MarkerRequest,
|
|
U extends MarkerResponse,
|
|
>(req: T, resp: U): Promise<U> {
|
|
if (!resp.result.marker) {
|
|
return Promise.reject(
|
|
new NotFoundError('response does not have a next page'),
|
|
)
|
|
}
|
|
const nextPageRequest = { ...req, marker: resp.result.marker }
|
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Necessary for overloading
|
|
return this.request(nextPageRequest) as unknown as U
|
|
}
|
|
|
|
/**
|
|
* Event handler for subscription streams.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const api = new Client('wss://s.altnet.rippletest.net:51233')
|
|
*
|
|
* api.on('transactions', (tx: TransactionStream) => {
|
|
* console.log("Received Transaction")
|
|
* console.log(tx)
|
|
* })
|
|
*
|
|
* await api.connect()
|
|
* const response = await api.request({
|
|
* command: 'subscribe',
|
|
* streams: ['transactions_proposed']
|
|
* })
|
|
* ```
|
|
*
|
|
* @category Network
|
|
*/
|
|
public on(event: 'connected', listener: () => void): this
|
|
public on(event: 'disconnected', listener: (code: number) => void): this
|
|
public on(
|
|
event: 'ledgerClosed',
|
|
listener: (ledger: LedgerStream) => void,
|
|
): this
|
|
public on(
|
|
event: 'validationReceived',
|
|
listener: (validation: ValidationStream) => void,
|
|
): this
|
|
public on(
|
|
event: 'transaction',
|
|
listener: (tx: TransactionStream) => void,
|
|
): this
|
|
public on(
|
|
event: 'peerStatusChange',
|
|
listener: (status: PeerStatusStream) => void,
|
|
): this
|
|
public on(
|
|
event: 'consensusPhase',
|
|
listener: (phase: ConsensusStream) => void,
|
|
): this
|
|
public on(
|
|
event: 'manifestReceived',
|
|
listener: (manifest: ManifestResponse) => void,
|
|
): this
|
|
public on(event: 'path_find', listener: (path: PathFindStream) => void): this
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- needs to be any for overload
|
|
public on(event: 'error', listener: (...err: any[]) => void): this
|
|
/**
|
|
* Event handler for subscription streams.
|
|
*
|
|
* @param eventName - Name of the event. Only forwards streams.
|
|
* @param listener - Function to run on event.
|
|
* @returns This, because it inherits from EventEmitter.
|
|
*/
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- needs to be any for overload
|
|
public on(eventName: string, listener: (...args: any[]) => void): this {
|
|
return super.on(eventName, listener)
|
|
}
|
|
|
|
/**
|
|
* @category Network
|
|
*/
|
|
public async requestAll(
|
|
req: AccountChannelsRequest,
|
|
): Promise<AccountChannelsResponse[]>
|
|
public async requestAll(
|
|
req: AccountLinesRequest,
|
|
): Promise<AccountLinesResponse[]>
|
|
public async requestAll(
|
|
req: AccountObjectsRequest,
|
|
): Promise<AccountObjectsResponse[]>
|
|
public async requestAll(
|
|
req: AccountOffersRequest,
|
|
): Promise<AccountOffersResponse[]>
|
|
public async requestAll(req: AccountTxRequest): Promise<AccountTxResponse[]>
|
|
public async requestAll(req: BookOffersRequest): Promise<BookOffersResponse[]>
|
|
public async requestAll(req: LedgerDataRequest): Promise<LedgerDataResponse[]>
|
|
/**
|
|
* Makes multiple paged requests to the client to return a given number of
|
|
* resources. Multiple paged requests will be made until the `limit`
|
|
* number of resources is reached (if no `limit` is provided, a single request
|
|
* will be made).
|
|
*
|
|
* If the command is unknown, an additional `collect` property is required to
|
|
* know which response key contains the array of resources.
|
|
*
|
|
* NOTE: This command is used by existing methods and is not recommended for
|
|
* general use. Instead, use rippled's built-in pagination and make multiple
|
|
* requests as needed.
|
|
*
|
|
* @param request - The initial request to send to the server.
|
|
* @param collect - (Optional) the param to use to collect the array of resources (only needed if command is unknown).
|
|
* @returns The array of all responses.
|
|
* @throws ValidationError if there is no collection key (either from a known command or for the unknown command).
|
|
*/
|
|
public async requestAll<T extends MarkerRequest, U extends MarkerResponse>(
|
|
request: T,
|
|
collect?: string,
|
|
): Promise<U[]> {
|
|
/*
|
|
* The data under collection is keyed based on the command. Fail if command
|
|
* not recognized and collection key not provided.
|
|
*/
|
|
const collectKey = collect ?? getCollectKeyFromCommand(request.command)
|
|
if (!collectKey) {
|
|
throw new ValidationError(`no collect key for command ${request.command}`)
|
|
}
|
|
/*
|
|
* If limit is not provided, fetches all data over multiple requests.
|
|
* NOTE: This may return much more than needed. Set limit when possible.
|
|
*/
|
|
const countTo: number = request.limit == null ? Infinity : request.limit
|
|
let count = 0
|
|
let marker: unknown = request.marker
|
|
let lastBatchLength: number
|
|
const results: U[] = []
|
|
do {
|
|
const countRemaining = clamp(countTo - count, MIN_LIMIT, MAX_LIMIT)
|
|
const repeatProps = {
|
|
...request,
|
|
limit: countRemaining,
|
|
marker,
|
|
}
|
|
// eslint-disable-next-line no-await-in-loop -- Necessary for this, it really has to wait
|
|
const singleResponse = await this.connection.request(repeatProps)
|
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Should be true
|
|
const singleResult = (singleResponse as U).result
|
|
if (!(collectKey in singleResult)) {
|
|
throw new XrplError(`${collectKey} not in result`)
|
|
}
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Should be true
|
|
const collectedData = singleResult[collectKey]
|
|
marker = singleResult.marker
|
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Should be true
|
|
results.push(singleResponse as U)
|
|
// Make sure we handle when no data (not even an empty array) is returned.
|
|
if (Array.isArray(collectedData)) {
|
|
count += collectedData.length
|
|
lastBatchLength = collectedData.length
|
|
} else {
|
|
lastBatchLength = 0
|
|
}
|
|
} while (Boolean(marker) && count < countTo && lastBatchLength !== 0)
|
|
return results
|
|
}
|
|
|
|
/**
|
|
* Tells the Client instance to connect to its rippled server.
|
|
*
|
|
* @returns A promise that resolves with a void value when a connection is established.
|
|
* @category Network
|
|
*/
|
|
public async connect(): Promise<void> {
|
|
return this.connection.connect()
|
|
}
|
|
|
|
/**
|
|
* Tells the Client instance to disconnect from it's rippled server.
|
|
*
|
|
* @returns A promise that resolves with a void value when a connection is destroyed.
|
|
* @category Network
|
|
*/
|
|
public async disconnect(): Promise<void> {
|
|
/*
|
|
* backwards compatibility: connection.disconnect() can return a number, but
|
|
* this method returns nothing. SO we await but don't return any result.
|
|
*/
|
|
await this.connection.disconnect()
|
|
}
|
|
|
|
/**
|
|
* Checks if the Client instance is connected to its rippled server.
|
|
*
|
|
* @returns Whether the client instance is connected.
|
|
* @category Network
|
|
*/
|
|
public isConnected(): boolean {
|
|
return this.connection.isConnected()
|
|
}
|
|
|
|
/**
|
|
* @category Core
|
|
*/
|
|
public autofill = autofill
|
|
|
|
/**
|
|
* @category Core
|
|
*/
|
|
public submit = submit
|
|
/**
|
|
* @category Core
|
|
*/
|
|
public submitAndWait = submitAndWait
|
|
|
|
/**
|
|
* @deprecated Use autofill instead, provided for users familiar with v1
|
|
*/
|
|
public prepareTransaction = autofill
|
|
|
|
/**
|
|
* @category Abstraction
|
|
*/
|
|
public getXrpBalance = getXrpBalance
|
|
|
|
/**
|
|
* @category Abstraction
|
|
*/
|
|
public getBalances = getBalances
|
|
|
|
/**
|
|
* @category Abstraction
|
|
*/
|
|
public getOrderbook = getOrderbook
|
|
|
|
/**
|
|
* @category Abstraction
|
|
*/
|
|
public getLedgerIndex = getLedgerIndex
|
|
|
|
/**
|
|
* @category Abstraction
|
|
*/
|
|
public getNetworkID = getNetworkID
|
|
|
|
/**
|
|
* @category Faucet
|
|
*/
|
|
public fundWallet = fundWallet
|
|
}
|
|
|
|
export { Client }
|