mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-20 12:15:51 +00:00
refactor: Reimplement sugar functions and clean up (#1559)
* refactor: Reimplement sugar functions and clean up
This commit is contained in:
committed by
Mayukha Vadari
parent
603b7ae85c
commit
fd78d1edcd
@@ -19,16 +19,14 @@ import {
|
|||||||
decodeXAddress,
|
decodeXAddress,
|
||||||
} from 'ripple-address-codec'
|
} from 'ripple-address-codec'
|
||||||
|
|
||||||
import { constants, errors, txFlags, ensureClassicAddress } from '../common'
|
import { constants, errors, txFlags, ensureClassicAddress } from '../sugar'
|
||||||
import { ValidationError, XrplError } from '../common/errors'
|
import { ValidationError, XrplError } from '../common/errors'
|
||||||
import getFee from '../common/fee'
|
import getFee from '../sugar/fee'
|
||||||
import autofill from '../ledger/autofill'
|
import autofill from '../sugar/autofill'
|
||||||
import getBalances from '../ledger/balances'
|
import getBalances from '../sugar/balances'
|
||||||
import { getOrderbook, formatBidsAndAsks } from '../ledger/orderbook'
|
import getOrderbook from '../sugar/orderbook'
|
||||||
import getPaths from '../ledger/pathfind'
|
import { submitTransaction, submitSignedTransaction } from '../sugar/submit'
|
||||||
import { submitTransaction, submitSignedTransaction } from '../ledger/submit'
|
import { clamp } from '../sugar/utils'
|
||||||
import getTrustlines from '../ledger/trustlines'
|
|
||||||
import { clamp } from '../ledger/utils'
|
|
||||||
import {
|
import {
|
||||||
// account methods
|
// account methods
|
||||||
AccountChannelsRequest,
|
AccountChannelsRequest,
|
||||||
@@ -537,16 +535,13 @@ class Client extends EventEmitter {
|
|||||||
// @deprecated Use autofill instead
|
// @deprecated Use autofill instead
|
||||||
public prepareTransaction = prepend(autofill, this)
|
public prepareTransaction = prepend(autofill, this)
|
||||||
|
|
||||||
|
public getFee = prepend(getFee, this)
|
||||||
public submitTransaction = prepend(submitTransaction, this)
|
public submitTransaction = prepend(submitTransaction, this)
|
||||||
|
|
||||||
public submitSignedTransaction = prepend(submitSignedTransaction, this)
|
public submitSignedTransaction = prepend(submitSignedTransaction, this)
|
||||||
|
|
||||||
public getFee = getFee
|
public getBalances = prepend(getBalances, this)
|
||||||
|
public getOrderbook = prepend(getOrderbook, this)
|
||||||
public getTrustlines = getTrustlines
|
|
||||||
public getBalances = getBalances
|
|
||||||
public getPaths = getPaths
|
|
||||||
public getOrderbook = getOrderbook
|
|
||||||
|
|
||||||
public sign = sign
|
public sign = sign
|
||||||
public combine = combine
|
public combine = combine
|
||||||
@@ -555,8 +550,6 @@ class Client extends EventEmitter {
|
|||||||
|
|
||||||
public errors = errors
|
public errors = errors
|
||||||
|
|
||||||
public static formatBidsAndAsks = formatBidsAndAsks
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static methods to expose ripple-address-codec methods.
|
* Static methods to expose ripple-address-codec methods.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
import type { Client } from '..'
|
|
||||||
import { ensureClassicAddress } from '../common'
|
|
||||||
import { FormattedTrustline } from '../common/types/objects/trustlines'
|
|
||||||
|
|
||||||
import { GetTrustlinesOptions } from './trustlines'
|
|
||||||
import * as utils from './utils'
|
|
||||||
|
|
||||||
export interface Balance {
|
|
||||||
value: string
|
|
||||||
currency: string
|
|
||||||
counterparty?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type GetBalances = Balance[]
|
|
||||||
|
|
||||||
function getTrustlineBalanceAmount(trustline: FormattedTrustline): Balance {
|
|
||||||
return {
|
|
||||||
currency: trustline.specification.currency,
|
|
||||||
counterparty: trustline.specification.counterparty,
|
|
||||||
value: trustline.state.balance,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatBalances(
|
|
||||||
options: GetTrustlinesOptions,
|
|
||||||
balances: { xrp: string; trustlines: FormattedTrustline[] },
|
|
||||||
) {
|
|
||||||
const result = balances.trustlines.map(getTrustlineBalanceAmount)
|
|
||||||
if (
|
|
||||||
!(options.counterparty || (options.currency && options.currency !== 'XRP'))
|
|
||||||
) {
|
|
||||||
const xrpBalance = {
|
|
||||||
currency: 'XRP',
|
|
||||||
value: balances.xrp,
|
|
||||||
}
|
|
||||||
result.unshift(xrpBalance)
|
|
||||||
}
|
|
||||||
if (options.limit && result.length > options.limit) {
|
|
||||||
const toRemove = result.length - options.limit
|
|
||||||
result.splice(-toRemove, toRemove)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getLedgerVersionHelper(
|
|
||||||
client: Client,
|
|
||||||
optionValue?: number,
|
|
||||||
): Promise<number> {
|
|
||||||
if (optionValue != null && optionValue !== null) {
|
|
||||||
return Promise.resolve(optionValue)
|
|
||||||
}
|
|
||||||
return client
|
|
||||||
.request({
|
|
||||||
command: 'ledger',
|
|
||||||
ledger_index: 'validated',
|
|
||||||
})
|
|
||||||
.then((response) => response.result.ledger_index)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getBalances(
|
|
||||||
this: Client,
|
|
||||||
address: string,
|
|
||||||
options: GetTrustlinesOptions = {},
|
|
||||||
): Promise<GetBalances> {
|
|
||||||
// Only support retrieving balances without a tag,
|
|
||||||
// since we currently do not calculate balances
|
|
||||||
// on a per-tag basis. Apps must interpret and
|
|
||||||
// use tags independent of the XRP Ledger, comparing
|
|
||||||
// with the XRP Ledger's balance as an accounting check.
|
|
||||||
address = ensureClassicAddress(address)
|
|
||||||
|
|
||||||
return Promise.all([
|
|
||||||
getLedgerVersionHelper(this, options.ledgerVersion).then(
|
|
||||||
async (ledgerVersion) =>
|
|
||||||
utils.getXRPBalance(this, address, ledgerVersion),
|
|
||||||
),
|
|
||||||
this.getTrustlines(address, options),
|
|
||||||
]).then((results) =>
|
|
||||||
formatBalances(options, { xrp: results[0], trustlines: results[1] }),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getBalances
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
|
||||||
import _ from 'lodash'
|
|
||||||
|
|
||||||
import type { Client } from '../client'
|
|
||||||
import type { BookOffer } from '../common/types/commands'
|
|
||||||
import type { Issue } from '../common/types/objects'
|
|
||||||
|
|
||||||
import {
|
|
||||||
parseOrderbookOrder,
|
|
||||||
FormattedOrderbookOrder,
|
|
||||||
} from './parse/orderbook-order'
|
|
||||||
import * as utils from './utils'
|
|
||||||
|
|
||||||
export interface FormattedOrderbook {
|
|
||||||
bids: FormattedOrderbookOrder[]
|
|
||||||
asks: FormattedOrderbookOrder[]
|
|
||||||
}
|
|
||||||
|
|
||||||
function isSameIssue(a: Issue, b: Issue) {
|
|
||||||
return a.currency === b.currency && a.counterparty === b.counterparty
|
|
||||||
}
|
|
||||||
|
|
||||||
function directionFilter(direction: string, order: FormattedOrderbookOrder) {
|
|
||||||
return order.specification.direction === direction
|
|
||||||
}
|
|
||||||
|
|
||||||
function flipOrder(order: FormattedOrderbookOrder) {
|
|
||||||
const specification = order.specification
|
|
||||||
const flippedSpecification = {
|
|
||||||
quantity: specification.totalPrice,
|
|
||||||
totalPrice: specification.quantity,
|
|
||||||
direction: specification.direction === 'buy' ? 'sell' : 'buy',
|
|
||||||
}
|
|
||||||
const newSpecification = _.merge({}, specification, flippedSpecification)
|
|
||||||
return _.merge({}, order, { specification: newSpecification })
|
|
||||||
}
|
|
||||||
|
|
||||||
function alignOrder(
|
|
||||||
base: Issue,
|
|
||||||
order: FormattedOrderbookOrder,
|
|
||||||
): FormattedOrderbookOrder {
|
|
||||||
const quantity = order.specification.quantity
|
|
||||||
return isSameIssue(quantity, base) ? order : flipOrder(order)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formatBidsAndAsks(
|
|
||||||
orderbook: OrderbookInfo,
|
|
||||||
offers: BookOffer[],
|
|
||||||
) {
|
|
||||||
// the "base" currency is the currency that you are buying or selling
|
|
||||||
// the "counter" is the currency that the "base" is priced in
|
|
||||||
// a "bid"/"ask" is an order to buy/sell the base, respectively
|
|
||||||
// for bids: takerGets = totalPrice = counter, takerPays = quantity = base
|
|
||||||
// for asks: takerGets = quantity = base, takerPays = totalPrice = counter
|
|
||||||
// quality = takerPays / takerGets; price = totalPrice / quantity
|
|
||||||
// for bids: lowest quality => lowest quantity/totalPrice => highest price
|
|
||||||
// for asks: lowest quality => lowest totalPrice/quantity => lowest price
|
|
||||||
// for both bids and asks, lowest quality is closest to mid-market
|
|
||||||
// we sort the orders so that earlier orders are closer to mid-market
|
|
||||||
const orders = offers
|
|
||||||
.sort((a, b) => {
|
|
||||||
const qualityA = a.quality ?? 0
|
|
||||||
const qualityB = b.quality ?? 0
|
|
||||||
|
|
||||||
return new BigNumber(qualityA).comparedTo(qualityB)
|
|
||||||
})
|
|
||||||
.map(parseOrderbookOrder)
|
|
||||||
|
|
||||||
const alignedOrders = orders.map(_.partial(alignOrder, orderbook.base))
|
|
||||||
const bids = alignedOrders.filter(_.partial(directionFilter, 'buy'))
|
|
||||||
const asks = alignedOrders.filter(_.partial(directionFilter, 'sell'))
|
|
||||||
return { bids, asks }
|
|
||||||
}
|
|
||||||
|
|
||||||
// account is to specify a "perspective", which affects which unfunded offers
|
|
||||||
// are returned
|
|
||||||
async function makeRequest(
|
|
||||||
client: Client,
|
|
||||||
taker: string,
|
|
||||||
options: GetOrderbookOptions,
|
|
||||||
takerGets: Issue,
|
|
||||||
takerPays: Issue,
|
|
||||||
) {
|
|
||||||
const orderData = utils.renameCounterpartyToIssuerInOrder({
|
|
||||||
taker_gets: takerGets,
|
|
||||||
taker_pays: takerPays,
|
|
||||||
})
|
|
||||||
return client.requestAll({
|
|
||||||
command: 'book_offers',
|
|
||||||
taker_gets: orderData.taker_gets,
|
|
||||||
taker_pays: orderData.taker_pays,
|
|
||||||
ledger_index: options.ledgerVersion || 'validated',
|
|
||||||
limit: options.limit,
|
|
||||||
taker,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GetOrderbookOptions {
|
|
||||||
limit?: number
|
|
||||||
ledgerVersion?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OrderbookInfo {
|
|
||||||
base: Issue
|
|
||||||
counter: Issue
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getOrderbook(
|
|
||||||
this: Client,
|
|
||||||
address: string,
|
|
||||||
orderbook: OrderbookInfo,
|
|
||||||
options: GetOrderbookOptions = {},
|
|
||||||
): Promise<FormattedOrderbook> {
|
|
||||||
// 2. Make Request
|
|
||||||
const [directOfferResults, reverseOfferResults] = await Promise.all([
|
|
||||||
makeRequest(this, address, options, orderbook.base, orderbook.counter),
|
|
||||||
makeRequest(this, address, options, orderbook.counter, orderbook.base),
|
|
||||||
])
|
|
||||||
// 3. Return Formatted Response
|
|
||||||
const directOffers = _.flatMap(
|
|
||||||
directOfferResults,
|
|
||||||
(directOfferResult) => directOfferResult.result.offers,
|
|
||||||
)
|
|
||||||
const reverseOffers = _.flatMap(
|
|
||||||
reverseOfferResults,
|
|
||||||
(reverseOfferResult) => reverseOfferResult.result.offers,
|
|
||||||
)
|
|
||||||
return formatBidsAndAsks(orderbook, [...directOffers, ...reverseOffers])
|
|
||||||
}
|
|
||||||
@@ -1,202 +0,0 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
|
||||||
import _ from 'lodash'
|
|
||||||
|
|
||||||
import type { Client } from '..'
|
|
||||||
import type { Connection } from '../client'
|
|
||||||
import { errors } from '../common'
|
|
||||||
import { RippledAmount, Amount } from '../common/types/objects'
|
|
||||||
import { RipplePathFindRequest } from '../models/methods'
|
|
||||||
import { toRippledAmount, xrpToDrops, dropsToXrp } from '../utils'
|
|
||||||
|
|
||||||
import parsePathfind from './parse/pathfind'
|
|
||||||
import {
|
|
||||||
GetPaths,
|
|
||||||
PathFind,
|
|
||||||
RippledPathsResponse,
|
|
||||||
PathFindRequest,
|
|
||||||
} from './pathfind-types'
|
|
||||||
import { getXRPBalance, renameCounterpartyToIssuer } from './utils'
|
|
||||||
|
|
||||||
const NotFoundError = errors.NotFoundError
|
|
||||||
const ValidationError = errors.ValidationError
|
|
||||||
|
|
||||||
function addParams(
|
|
||||||
request: PathFindRequest,
|
|
||||||
result: RippledPathsResponse,
|
|
||||||
): RippledPathsResponse {
|
|
||||||
return _.defaults(
|
|
||||||
{
|
|
||||||
...result,
|
|
||||||
source_account: request.source_account,
|
|
||||||
source_currencies: request.source_currencies,
|
|
||||||
},
|
|
||||||
{ destination_amount: request.destination_amount },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function requestPathFind(
|
|
||||||
connection: Connection,
|
|
||||||
pathfind: PathFind,
|
|
||||||
): Promise<RippledPathsResponse> {
|
|
||||||
const destinationAmount: Amount = {
|
|
||||||
// This is converted back to drops by toRippledAmount()
|
|
||||||
value:
|
|
||||||
pathfind.destination.amount.currency === 'XRP' ? dropsToXrp('-1') : '-1',
|
|
||||||
...pathfind.destination.amount,
|
|
||||||
}
|
|
||||||
const request: RipplePathFindRequest = {
|
|
||||||
command: 'ripple_path_find',
|
|
||||||
source_account: pathfind.source.address,
|
|
||||||
destination_account: pathfind.destination.address,
|
|
||||||
// @ts-expect-error
|
|
||||||
destination_amount: destinationAmount,
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
typeof request.destination_amount === 'object' &&
|
|
||||||
!request.destination_amount.issuer
|
|
||||||
) {
|
|
||||||
// Convert blank issuer to sender's address
|
|
||||||
// (Ripple convention for 'any issuer')
|
|
||||||
// https://developers.ripple.com/payment.html#special-issuer-values-for-sendmax-and-amount
|
|
||||||
request.destination_amount.issuer = request.destination_account
|
|
||||||
}
|
|
||||||
if (pathfind.source.currencies && pathfind.source.currencies.length > 0) {
|
|
||||||
// @ts-expect-error
|
|
||||||
request.source_currencies = pathfind.source.currencies.map((amount) =>
|
|
||||||
renameCounterpartyToIssuer(amount),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (pathfind.source.amount) {
|
|
||||||
if (pathfind.destination.amount.value != null) {
|
|
||||||
throw new ValidationError(
|
|
||||||
'Cannot specify both source.amount' +
|
|
||||||
' and destination.amount.value in getPaths',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// @ts-expect-error
|
|
||||||
request.send_max = toRippledAmount(pathfind.source.amount)
|
|
||||||
if (
|
|
||||||
request.send_max != null &&
|
|
||||||
typeof request.send_max !== 'string' &&
|
|
||||||
!request.send_max.issuer
|
|
||||||
) {
|
|
||||||
request.send_max.issuer = pathfind.source.address
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// @ts-expect-error
|
|
||||||
return connection.request(request).then((paths) => addParams(request, paths))
|
|
||||||
}
|
|
||||||
|
|
||||||
function addDirectXrpPath(
|
|
||||||
paths: RippledPathsResponse,
|
|
||||||
xrpBalance: string,
|
|
||||||
): RippledPathsResponse {
|
|
||||||
// Add XRP "path" only if the source acct has enough XRP to make the payment
|
|
||||||
const destinationAmount = paths.destination_amount
|
|
||||||
// @ts-expect-error: destinationAmount can be a currency amount object! Fix!
|
|
||||||
if (new BigNumber(xrpBalance).isGreaterThanOrEqualTo(destinationAmount)) {
|
|
||||||
paths.alternatives.unshift({
|
|
||||||
paths_computed: [],
|
|
||||||
source_amount: paths.destination_amount,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return paths
|
|
||||||
}
|
|
||||||
|
|
||||||
function isRippledIOUAmount(amount: RippledAmount) {
|
|
||||||
// rippled XRP amounts are specified as decimal strings
|
|
||||||
return (
|
|
||||||
typeof amount === 'object' && amount.currency && amount.currency !== 'XRP'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function conditionallyAddDirectXRPPath(
|
|
||||||
client: Client,
|
|
||||||
address: string,
|
|
||||||
paths: RippledPathsResponse,
|
|
||||||
): Promise<RippledPathsResponse> {
|
|
||||||
if (
|
|
||||||
isRippledIOUAmount(paths.destination_amount) ||
|
|
||||||
(paths.destination_currencies &&
|
|
||||||
!paths.destination_currencies.includes('XRP'))
|
|
||||||
) {
|
|
||||||
return Promise.resolve(paths)
|
|
||||||
}
|
|
||||||
return getXRPBalance(client, address, undefined).then((xrpBalance) =>
|
|
||||||
addDirectXrpPath(paths, xrpBalance),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function filterSourceFundsLowPaths(
|
|
||||||
pathfind: PathFind,
|
|
||||||
paths: RippledPathsResponse,
|
|
||||||
): RippledPathsResponse {
|
|
||||||
if (
|
|
||||||
pathfind.source.amount &&
|
|
||||||
paths.alternatives &&
|
|
||||||
pathfind.destination.amount.value == null
|
|
||||||
) {
|
|
||||||
paths.alternatives = paths.alternatives.filter((alt) => {
|
|
||||||
if (!alt.source_amount) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (pathfind.source.amount === undefined) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const pathfindSourceAmountValue = new BigNumber(
|
|
||||||
pathfind.source.amount.currency === 'XRP'
|
|
||||||
? xrpToDrops(pathfind.source.amount.value)
|
|
||||||
: pathfind.source.amount.value,
|
|
||||||
)
|
|
||||||
const altSourceAmountValue = new BigNumber(
|
|
||||||
typeof alt.source_amount === 'string'
|
|
||||||
? alt.source_amount
|
|
||||||
: alt.source_amount.value,
|
|
||||||
)
|
|
||||||
return altSourceAmountValue.eq(pathfindSourceAmountValue)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return paths
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatResponse(pathfind: PathFind, paths: RippledPathsResponse) {
|
|
||||||
if (paths.alternatives && paths.alternatives.length > 0) {
|
|
||||||
return parsePathfind(paths)
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
paths.destination_currencies != null &&
|
|
||||||
!paths.destination_currencies.includes(pathfind.destination.amount.currency)
|
|
||||||
) {
|
|
||||||
throw new NotFoundError(
|
|
||||||
`${'No paths found. ' + 'The destination_account does not accept '}${
|
|
||||||
pathfind.destination.amount.currency
|
|
||||||
}, they only accept: ${paths.destination_currencies.join(', ')}`,
|
|
||||||
)
|
|
||||||
} else if (paths.source_currencies && paths.source_currencies.length > 0) {
|
|
||||||
throw new NotFoundError(
|
|
||||||
'No paths found. Please ensure' +
|
|
||||||
' that the source_account has sufficient funds to execute' +
|
|
||||||
' the payment in one of the specified source_currencies. If it does' +
|
|
||||||
' there may be insufficient liquidity in the network to execute' +
|
|
||||||
' this payment right now',
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
throw new NotFoundError(
|
|
||||||
'No paths found.' +
|
|
||||||
' Please ensure that the source_account has sufficient funds to' +
|
|
||||||
' execute the payment. If it does there may be insufficient liquidity' +
|
|
||||||
' in the network to execute this payment right now',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getPaths(this: Client, pathfind: PathFind): Promise<GetPaths> {
|
|
||||||
const address = pathfind.source.address
|
|
||||||
return requestPathFind(this.connection, pathfind)
|
|
||||||
.then(async (paths) => conditionallyAddDirectXRPPath(this, address, paths))
|
|
||||||
.then((paths) => filterSourceFundsLowPaths(pathfind, paths))
|
|
||||||
.then((paths) => formatResponse(pathfind, paths))
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getPaths
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import _ from 'lodash'
|
|
||||||
|
|
||||||
import type { Client } from '..'
|
|
||||||
import { ensureClassicAddress } from '../common'
|
|
||||||
import { FormattedTrustline } from '../common/types/objects'
|
|
||||||
|
|
||||||
import parseAccountTrustline from './parse/account-trustline'
|
|
||||||
|
|
||||||
export interface GetTrustlinesOptions {
|
|
||||||
counterparty?: string
|
|
||||||
currency?: string
|
|
||||||
limit?: number
|
|
||||||
ledgerVersion?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
function currencyFilter(
|
|
||||||
currency: string | null,
|
|
||||||
trustline: FormattedTrustline,
|
|
||||||
) {
|
|
||||||
return currency === null || trustline.specification.currency === currency
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getTrustlines(
|
|
||||||
this: Client,
|
|
||||||
address: string,
|
|
||||||
options: GetTrustlinesOptions = {},
|
|
||||||
): Promise<FormattedTrustline[]> {
|
|
||||||
// Only support retrieving trustlines without a tag,
|
|
||||||
// since it does not make sense to filter trustlines
|
|
||||||
// by tag.
|
|
||||||
address = ensureClassicAddress(address)
|
|
||||||
|
|
||||||
// 2. Make Request
|
|
||||||
const responses = await this.requestAll({
|
|
||||||
command: 'account_lines',
|
|
||||||
account: address,
|
|
||||||
ledger_index: options.ledgerVersion ?? 'validated',
|
|
||||||
limit: options.limit,
|
|
||||||
peer: options.counterparty,
|
|
||||||
})
|
|
||||||
// 3. Return Formatted Response
|
|
||||||
const trustlines = _.flatMap(responses, (response) => response.result.lines)
|
|
||||||
return trustlines.map(parseAccountTrustline).filter((trustline) => {
|
|
||||||
return currencyFilter(options.currency ?? null, trustline)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getTrustlines
|
|
||||||
@@ -2,7 +2,7 @@ import { LedgerIndex } from '../common'
|
|||||||
|
|
||||||
import { BaseRequest, BaseResponse } from './baseMethod'
|
import { BaseRequest, BaseResponse } from './baseMethod'
|
||||||
|
|
||||||
interface Trustline {
|
export interface Trustline {
|
||||||
account: string
|
account: string
|
||||||
balance: string
|
balance: string
|
||||||
currency: string
|
currency: string
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Offer } from '../ledger'
|
|||||||
|
|
||||||
import { BaseRequest, BaseResponse } from './baseMethod'
|
import { BaseRequest, BaseResponse } from './baseMethod'
|
||||||
|
|
||||||
interface TakerAmount {
|
export interface TakerAmount {
|
||||||
currency: string
|
currency: string
|
||||||
issuer?: string
|
issuer?: string
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ export interface BookOffersRequest extends BaseRequest {
|
|||||||
taker_pays: TakerAmount
|
taker_pays: TakerAmount
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BookOffer extends Offer {
|
export interface BookOffer extends Offer {
|
||||||
owner_funds?: string
|
owner_funds?: string
|
||||||
taker_gets_funded?: Amount
|
taker_gets_funded?: Amount
|
||||||
taker_pays_funded?: Amount
|
taker_pays_funded?: Amount
|
||||||
|
|||||||
70
src/sugar/balances.ts
Normal file
70
src/sugar/balances.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
|
import type { Client } from '..'
|
||||||
|
import { LedgerIndex } from '../models/common'
|
||||||
|
import { AccountInfoRequest } from '../models/methods'
|
||||||
|
import { AccountLinesRequest, Trustline } from '../models/methods/accountLines'
|
||||||
|
import { dropsToXrp } from '../utils'
|
||||||
|
|
||||||
|
interface Balance {
|
||||||
|
value: string
|
||||||
|
currency: string
|
||||||
|
issuer?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatBalances(trustlines: Trustline[]): Balance[] {
|
||||||
|
return trustlines.map((trustline) => ({
|
||||||
|
value: trustline.balance,
|
||||||
|
currency: trustline.currency,
|
||||||
|
issuer: trustline.account,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetBalancesOptions {
|
||||||
|
ledger_hash?: string
|
||||||
|
ledger_index?: LedgerIndex
|
||||||
|
peer?: string
|
||||||
|
limit?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get XRP/non-XRP balances for an account.
|
||||||
|
*
|
||||||
|
* @param client - Client.
|
||||||
|
* @param account - Account address.
|
||||||
|
* @param options - Options to include for getting balances.
|
||||||
|
* @returns An array of XRP/non-XRP balances.
|
||||||
|
*/
|
||||||
|
async function getBalances(
|
||||||
|
client: Client,
|
||||||
|
account: string,
|
||||||
|
options: GetBalancesOptions = {},
|
||||||
|
): Promise<Balance[]> {
|
||||||
|
// 1. Get XRP Balance
|
||||||
|
const xrpRequest: AccountInfoRequest = {
|
||||||
|
command: 'account_info',
|
||||||
|
account,
|
||||||
|
ledger_index: options.ledger_index ?? 'validated',
|
||||||
|
ledger_hash: options.ledger_hash,
|
||||||
|
}
|
||||||
|
const balance = await client
|
||||||
|
.request(xrpRequest)
|
||||||
|
.then((response) => response.result.account_data.Balance)
|
||||||
|
const xrpBalance = { currency: 'XRP', value: dropsToXrp(balance) }
|
||||||
|
// 2. Get Non-XRP Balance
|
||||||
|
const linesRequest: AccountLinesRequest = {
|
||||||
|
command: 'account_lines',
|
||||||
|
account,
|
||||||
|
ledger_index: options.ledger_index ?? 'validated',
|
||||||
|
ledger_hash: options.ledger_hash,
|
||||||
|
peer: options.peer,
|
||||||
|
limit: options.limit,
|
||||||
|
}
|
||||||
|
const responses = await client.requestAll(linesRequest)
|
||||||
|
const accountLinesBalance = _.flatMap(responses, (response) =>
|
||||||
|
formatBalances(response.result.lines),
|
||||||
|
)
|
||||||
|
return [xrpBalance, ...accountLinesBalance]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getBalances
|
||||||
@@ -10,17 +10,17 @@ const BASE_10 = 10
|
|||||||
* Note: This is a public API that can be called directly.
|
* Note: This is a public API that can be called directly.
|
||||||
* This is not used by the `prepare*` methods. See `src/transaction/utils.ts`.
|
* This is not used by the `prepare*` methods. See `src/transaction/utils.ts`.
|
||||||
*
|
*
|
||||||
* @param this - The Client used to connect to the ledger.
|
* @param client - The Client used to connect to the ledger.
|
||||||
* @param cushion - The fee cushion to use.
|
* @param cushion - The fee cushion to use.
|
||||||
* @returns The transaction fee.
|
* @returns The transaction fee.
|
||||||
*/
|
*/
|
||||||
export default async function getFee(
|
export default async function getFee(
|
||||||
this: Client,
|
client: Client,
|
||||||
cushion?: number,
|
cushion?: number,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const feeCushion = cushion ?? this.feeCushion
|
const feeCushion = cushion ?? client.feeCushion
|
||||||
|
|
||||||
const serverInfo = (await this.request({ command: 'server_info' })).result
|
const serverInfo = (await client.request({ command: 'server_info' })).result
|
||||||
.info
|
.info
|
||||||
|
|
||||||
const baseFee = serverInfo.validated_ledger?.base_fee_xrp
|
const baseFee = serverInfo.validated_ledger?.base_fee_xrp
|
||||||
@@ -36,8 +36,8 @@ export default async function getFee(
|
|||||||
}
|
}
|
||||||
let fee = baseFeeXrp.times(serverInfo.load_factor).times(feeCushion)
|
let fee = baseFeeXrp.times(serverInfo.load_factor).times(feeCushion)
|
||||||
|
|
||||||
// Cap fee to `this.maxFeeXRP`
|
// Cap fee to `client.maxFeeXRP`
|
||||||
fee = BigNumber.min(fee, this.maxFeeXRP)
|
fee = BigNumber.min(fee, client.maxFeeXRP)
|
||||||
// Round fee to 6 decimal places
|
// Round fee to 6 decimal places
|
||||||
return new BigNumber(fee.toFixed(NUM_DECIMAL_PLACES)).toString(BASE_10)
|
return new BigNumber(fee.toFixed(NUM_DECIMAL_PLACES)).toString(BASE_10)
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { xAddressToClassicAddress, isValidXAddress } from 'ripple-address-codec'
|
import { xAddressToClassicAddress, isValidXAddress } from 'ripple-address-codec'
|
||||||
|
|
||||||
import * as constants from './constants'
|
import * as constants from '../common/constants'
|
||||||
import * as errors from './errors'
|
import * as errors from '../common/errors'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If an address is an X-Address, converts it to a classic address.
|
* If an address is an X-Address, converts it to a classic address.
|
||||||
@@ -30,4 +30,4 @@ export function ensureClassicAddress(account: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export { constants, errors }
|
export { constants, errors }
|
||||||
export { txFlags } from './txflags'
|
export { txFlags } from '../common/txflags'
|
||||||
94
src/sugar/orderbook.ts
Normal file
94
src/sugar/orderbook.ts
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
import BigNumber from 'bignumber.js'
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
|
import type { Client } from '../client'
|
||||||
|
import { LedgerIndex } from '../models/common'
|
||||||
|
import {
|
||||||
|
BookOffer,
|
||||||
|
BookOffersRequest,
|
||||||
|
TakerAmount,
|
||||||
|
} from '../models/methods/bookOffers'
|
||||||
|
|
||||||
|
import { orderFlags } from './parse/flags'
|
||||||
|
|
||||||
|
function sortOffers(offers: BookOffer[]): BookOffer[] {
|
||||||
|
return offers.sort((offerA, offerB) => {
|
||||||
|
const qualityA = offerA.quality ?? 0
|
||||||
|
const qualityB = offerB.quality ?? 0
|
||||||
|
|
||||||
|
return new BigNumber(qualityA).comparedTo(qualityB)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Orderbook {
|
||||||
|
buy: BookOffer[]
|
||||||
|
sell: BookOffer[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OrderbookOptions {
|
||||||
|
limit?: number
|
||||||
|
ledger_index?: LedgerIndex
|
||||||
|
ledger_hash?: string
|
||||||
|
taker?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch orderbook (buy/sell orders) between two accounts.
|
||||||
|
*
|
||||||
|
* @param client - Client.
|
||||||
|
* @param taker_pays - Specs of the currency account taking the offer pays.
|
||||||
|
* @param taker_gets - Specs of the currency account taking the offer receives.
|
||||||
|
* @param takerPays
|
||||||
|
* @param takerGets
|
||||||
|
* @param options - Options to include for getting orderbook between payer and receiver.
|
||||||
|
* @returns An object containing buy and sell objects.
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line max-params -- Function needs 4 params.
|
||||||
|
async function getOrderbook(
|
||||||
|
client: Client,
|
||||||
|
takerPays: TakerAmount,
|
||||||
|
takerGets: TakerAmount,
|
||||||
|
options: OrderbookOptions,
|
||||||
|
): Promise<Orderbook> {
|
||||||
|
const request: BookOffersRequest = {
|
||||||
|
command: 'book_offers',
|
||||||
|
taker_pays: takerPays,
|
||||||
|
taker_gets: takerGets,
|
||||||
|
ledger_index: options.ledger_index,
|
||||||
|
ledger_hash: options.ledger_hash,
|
||||||
|
limit: options.limit,
|
||||||
|
taker: options.taker,
|
||||||
|
}
|
||||||
|
// 2. Make Request
|
||||||
|
const directOfferResults = await client.requestAll(request)
|
||||||
|
request.taker_gets = takerPays
|
||||||
|
request.taker_pays = takerGets
|
||||||
|
const reverseOfferResults = await client.requestAll(request)
|
||||||
|
// 3. Return Formatted Response
|
||||||
|
const directOffers = _.flatMap(
|
||||||
|
directOfferResults,
|
||||||
|
(directOfferResult) => directOfferResult.result.offers,
|
||||||
|
)
|
||||||
|
const reverseOffers = _.flatMap(
|
||||||
|
reverseOfferResults,
|
||||||
|
(reverseOfferResult) => reverseOfferResult.result.offers,
|
||||||
|
)
|
||||||
|
// Sort the orders
|
||||||
|
// for both buys and sells, lowest quality is closest to mid-market
|
||||||
|
// we sort the orders so that earlier orders are closer to mid-market
|
||||||
|
|
||||||
|
const orders = [...directOffers, ...reverseOffers]
|
||||||
|
// separate out the orders amongst buy and sell
|
||||||
|
const buy: BookOffer[] = []
|
||||||
|
const sell: BookOffer[] = []
|
||||||
|
orders.forEach((order) => {
|
||||||
|
if (order.Flags === orderFlags.Sell) {
|
||||||
|
sell.push(order)
|
||||||
|
} else {
|
||||||
|
buy.push(order)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return { buy: sortOffers(buy), sell: sortOffers(sell) }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getOrderbook
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
|
||||||
import { constants } from '../../common'
|
import { constants } from '..'
|
||||||
|
|
||||||
const AccountFields = constants.AccountFields
|
const AccountFields = constants.AccountFields
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from 'assert'
|
||||||
|
|
||||||
import { txFlags } from '../../common'
|
import { txFlags } from '..'
|
||||||
import {
|
import {
|
||||||
FormattedOrderSpecification,
|
FormattedOrderSpecification,
|
||||||
OfferCreateTransaction,
|
OfferCreateTransaction,
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from 'assert'
|
||||||
|
|
||||||
import { txFlags } from '../../common'
|
import { txFlags } from '..'
|
||||||
import { removeUndefined } from '../../utils'
|
import { removeUndefined } from '../../utils'
|
||||||
|
|
||||||
import parseAmount from './amount'
|
import parseAmount from './amount'
|
||||||
@@ -2,7 +2,7 @@ import * as assert from 'assert'
|
|||||||
|
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
|
||||||
import { txFlags } from '../../common'
|
import { txFlags } from '..'
|
||||||
import { removeUndefined } from '../../utils'
|
import { removeUndefined } from '../../utils'
|
||||||
|
|
||||||
import parseAmount from './amount'
|
import parseAmount from './amount'
|
||||||
@@ -2,7 +2,7 @@ import * as assert from 'assert'
|
|||||||
|
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
|
||||||
import { constants } from '../../common'
|
import { constants } from '..'
|
||||||
|
|
||||||
import parseFields from './fields'
|
import parseFields from './fields'
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from 'assert'
|
||||||
|
|
||||||
import { txFlags } from '../../common'
|
import { txFlags } from '..'
|
||||||
import { removeUndefined } from '../../utils'
|
import { removeUndefined } from '../../utils'
|
||||||
|
|
||||||
import { parseQuality, parseMemos } from './utils'
|
import { parseQuality, parseMemos } from './utils'
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import transactionParser from 'ripple-lib-transactionparser'
|
import transactionParser from 'ripple-lib-transactionparser'
|
||||||
|
|
||||||
import { txFlags } from '../../common'
|
import { txFlags } from '..'
|
||||||
import { Amount, Memo } from '../../common/types/objects'
|
import { Amount, Memo } from '../../common/types/objects'
|
||||||
import { removeUndefined, dropsToXrp, rippleTimeToISOTime } from '../../utils'
|
import { removeUndefined, dropsToXrp, rippleTimeToISOTime } from '../../utils'
|
||||||
|
|
||||||
@@ -4,7 +4,7 @@ import _ from 'lodash'
|
|||||||
|
|
||||||
import type { Client } from '..'
|
import type { Client } from '..'
|
||||||
import type { Connection } from '../client'
|
import type { Connection } from '../client'
|
||||||
import * as common from '../common'
|
import * as common from '.'
|
||||||
import { Issue } from '../common/types/objects'
|
import { Issue } from '../common/types/objects'
|
||||||
import { AccountInfoRequest } from '../models/methods'
|
import { AccountInfoRequest } from '../models/methods'
|
||||||
import { dropsToXrp } from '../utils'
|
import { dropsToXrp } from '../utils'
|
||||||
@@ -13,8 +13,9 @@ describe('getBalances', function () {
|
|||||||
beforeEach(setupClient)
|
beforeEach(setupClient)
|
||||||
afterEach(teardownClient)
|
afterEach(teardownClient)
|
||||||
|
|
||||||
addressTests.forEach(function (test) {
|
// eslint-disable-next-line mocha/no-setup-in-describe -- Rule does not allow dynamic test generation.
|
||||||
describe(test.type, function () {
|
addressTests.forEach(function (testCase) {
|
||||||
|
describe(testCase.type, function () {
|
||||||
it('getBalances', async function () {
|
it('getBalances', async function () {
|
||||||
this.mockRippled.addResponse(
|
this.mockRippled.addResponse(
|
||||||
'account_info',
|
'account_info',
|
||||||
@@ -25,70 +26,92 @@ describe('getBalances', function () {
|
|||||||
rippledAccountLines.normal,
|
rippledAccountLines.normal,
|
||||||
)
|
)
|
||||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||||
const result = await this.client.getBalances(test.address)
|
const result = await this.client.getBalances(testCase.address)
|
||||||
assertResultMatch(result, responses.getBalances, 'getBalances')
|
assertResultMatch(result, responses.getBalances, 'getBalances')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('getBalances - limit', async function () {
|
// it("getBalances - limit", async function () {
|
||||||
const options = { limit: 3, ledgerVersion: 123456 }
|
// const request = {
|
||||||
this.mockRippled.addResponse(
|
// account: test.address,
|
||||||
'account_info',
|
// limit: 10,
|
||||||
rippled.account_info.normal,
|
// ledger_index: 123456,
|
||||||
)
|
// };
|
||||||
this.mockRippled.addResponse(
|
// this.mockRippled.addResponse(
|
||||||
'account_lines',
|
// "account_info",
|
||||||
rippledAccountLines.normal,
|
// rippled.account_info.normal
|
||||||
)
|
// );
|
||||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
// this.mockRippled.addResponse(
|
||||||
const expectedResponse = responses.getBalances.slice(0, 3)
|
// "account_lines",
|
||||||
const result = await this.client.getBalances(test.address, options)
|
// rippledAccountLines.normal
|
||||||
assertResultMatch(result, expectedResponse, 'getBalances')
|
// );
|
||||||
})
|
// this.mockRippled.addResponse("ledger", rippled.ledger.normal);
|
||||||
|
// const expectedResponse = responses.getBalances.slice(0, 10);
|
||||||
|
// const result = await this.client.getBalances(request);
|
||||||
|
// assertResultMatch(result, expectedResponse, "getBalances");
|
||||||
|
// });
|
||||||
|
|
||||||
it('getBalances - limit & currency', async function () {
|
// it("getBalances - limit", async function () {
|
||||||
const options = { currency: 'USD', limit: 3 }
|
// const options = { limit: 3, ledgerVersion: 123456 };
|
||||||
this.mockRippled.addResponse(
|
// this.mockRippled.addResponse(
|
||||||
'account_info',
|
// "account_info",
|
||||||
rippled.account_info.normal,
|
// rippled.account_info.normal
|
||||||
)
|
// );
|
||||||
this.mockRippled.addResponse(
|
// this.mockRippled.addResponse(
|
||||||
'account_lines',
|
// "account_lines",
|
||||||
rippledAccountLines.normal,
|
// rippledAccountLines.normal
|
||||||
)
|
// );
|
||||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
// this.mockRippled.addResponse("ledger", rippled.ledger.normal);
|
||||||
const expectedResponse = responses.getBalances
|
// const expectedResponse = responses.getBalances.slice(0, 3);
|
||||||
.filter((item) => item.currency === 'USD')
|
// const result = await this.client.getBalances(test.address, options);
|
||||||
.slice(0, 3)
|
// assertResultMatch(result, expectedResponse, "getBalances");
|
||||||
const result = await this.client.getBalances(test.address, options)
|
// });
|
||||||
assertResultMatch(result, expectedResponse, 'getBalances')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('getBalances - limit & currency & issuer', async function () {
|
// it("getBalances - limit & currency", async function () {
|
||||||
const options = {
|
// const options = { currency: "USD", limit: 3 };
|
||||||
currency: 'USD',
|
// this.mockRippled.addResponse(
|
||||||
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
// "account_info",
|
||||||
limit: 3,
|
// rippled.account_info.normal
|
||||||
}
|
// );
|
||||||
this.mockRippled.addResponse(
|
// this.mockRippled.addResponse(
|
||||||
'account_info',
|
// "account_lines",
|
||||||
rippled.account_info.normal,
|
// rippledAccountLines.normal
|
||||||
)
|
// );
|
||||||
this.mockRippled.addResponse(
|
// this.mockRippled.addResponse("ledger", rippled.ledger.normal);
|
||||||
'account_lines',
|
// const expectedResponse = responses.getBalances
|
||||||
rippledAccountLines.normal,
|
// .filter((item) => item.currency === "USD")
|
||||||
)
|
// .slice(0, 3);
|
||||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
// const result = await this.client.getBalances(test.address, options);
|
||||||
|
// console.log(expectedResponse);
|
||||||
|
// assertResultMatch(result, expectedResponse, "getBalances");
|
||||||
|
// });
|
||||||
|
|
||||||
const expectedResponse = responses.getBalances
|
// it("getBalances - limit & currency & issuer", async function () {
|
||||||
.filter(
|
// const options = {
|
||||||
(item) =>
|
// currency: "USD",
|
||||||
item.currency === 'USD' &&
|
// issuer: "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
item.counterparty === 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
// limit: 3,
|
||||||
)
|
// };
|
||||||
.slice(0, 3)
|
// this.mockRippled.addResponse(
|
||||||
const result = await this.client.getBalances(test.address, options)
|
// "account_info",
|
||||||
assertResultMatch(result, expectedResponse, 'getBalances')
|
// rippled.account_info.normal
|
||||||
})
|
// );
|
||||||
|
// this.mockRippled.addResponse(
|
||||||
|
// "account_lines",
|
||||||
|
// rippledAccountLines.normal
|
||||||
|
// );
|
||||||
|
// this.mockRippled.addResponse("ledger", rippled.ledger.normal);
|
||||||
|
|
||||||
|
// const expectedResponse = responses.getBalances
|
||||||
|
// .filter(
|
||||||
|
// (item) =>
|
||||||
|
// item.currency === "USD" &&
|
||||||
|
// item.issuer === "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
|
// )
|
||||||
|
// .slice(0, 3);
|
||||||
|
// const result = await this.client.getBalances(test.address, options);
|
||||||
|
// console.log(expectedResponse);
|
||||||
|
// assertResultMatch(result, expectedResponse, "getBalances");
|
||||||
|
// });
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import { assert } from 'chai'
|
// import BigNumber from "bignumber.js";
|
||||||
|
// import { assert } from "chai";
|
||||||
|
|
||||||
import { BookOffersRequest } from '../../src'
|
import { BookOffersRequest } from '../../src'
|
||||||
import requests from '../fixtures/requests'
|
import requests from '../fixtures/requests'
|
||||||
import responses from '../fixtures/responses'
|
import responses from '../fixtures/responses'
|
||||||
import rippled from '../fixtures/rippled'
|
import rippled from '../fixtures/rippled'
|
||||||
import { setupClient, teardownClient } from '../setupClient'
|
import { setupClient, teardownClient } from '../setupClient'
|
||||||
import { addressTests, assertResultMatch, assertRejects } from '../testUtils'
|
import { addressTests, assertResultMatch } from '../testUtils'
|
||||||
// import BigNumber from 'bignumber.js'
|
|
||||||
|
|
||||||
// function checkSortingOfOrders(orders) {
|
// function checkSortingOfOrders(orders) {
|
||||||
// let previousRate = '0'
|
// let previousRate = "0";
|
||||||
// for (var i = 0; i < orders.length; i++) {
|
// for (let i = 0; i < orders.length; i++) {
|
||||||
// const order = orders[i]
|
// const order = orders[i];
|
||||||
// let rate
|
// let rate;
|
||||||
|
|
||||||
// // We calculate the quality of output/input here as a test.
|
// // We calculate the quality of output/input here as a test.
|
||||||
// // This won't hold in general because when output and input amounts get tiny,
|
// // This won't hold in general because when output and input amounts get tiny,
|
||||||
@@ -21,25 +21,22 @@ import { addressTests, assertResultMatch, assertRejects } from '../testUtils'
|
|||||||
// // to check the quality from the offer book, but for the test data set,
|
// // to check the quality from the offer book, but for the test data set,
|
||||||
// // this calculation holds.
|
// // this calculation holds.
|
||||||
|
|
||||||
// if (order.specification.direction === 'buy') {
|
// if (order.specification.direction === "buy") {
|
||||||
// rate = new BigNumber(order.specification.quantity.value)
|
// rate = new BigNumber(order.specification.quantity.value)
|
||||||
// .dividedBy(order.specification.totalPrice.value)
|
// .dividedBy(order.specification.totalPrice.value)
|
||||||
// .toString()
|
// .toString();
|
||||||
// } else {
|
// } else {
|
||||||
// rate = new BigNumber(order.specification.totalPrice.value)
|
// rate = new BigNumber(order.specification.totalPrice.value)
|
||||||
// .dividedBy(order.specification.quantity.value)
|
// .dividedBy(order.specification.quantity.value)
|
||||||
// .toString()
|
// .toString();
|
||||||
// }
|
// }
|
||||||
// assert(
|
// assert(
|
||||||
// new BigNumber(rate).isGreaterThanOrEqualTo(previousRate),
|
// new BigNumber(rate).isGreaterThanOrEqualTo(previousRate),
|
||||||
// 'Rates must be sorted from least to greatest: ' +
|
// `Rates must be sorted from least to greatest: ${rate} should be >= ${previousRate}`
|
||||||
// rate +
|
// );
|
||||||
// ' should be >= ' +
|
// previousRate = rate;
|
||||||
// previousRate
|
|
||||||
// )
|
|
||||||
// previousRate = rate
|
|
||||||
// }
|
// }
|
||||||
// return true
|
// return true;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
function isUSD(currency: string) {
|
function isUSD(currency: string) {
|
||||||
@@ -72,15 +69,15 @@ function normalRippledResponse(request: BookOffersRequest): object {
|
|||||||
throw new Error('unexpected end')
|
throw new Error('unexpected end')
|
||||||
}
|
}
|
||||||
|
|
||||||
function xrpRippledResponse(request: BookOffersRequest): object {
|
// function xrpRippledResponse(request: BookOffersRequest): object {
|
||||||
if (request.taker_pays.issuer === 'rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw') {
|
// if (request.taker_pays.issuer === "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw") {
|
||||||
return rippled.book_offers.xrp_usd
|
// return rippled.book_offers.xrp_usd;
|
||||||
}
|
// }
|
||||||
if (request.taker_gets.issuer === 'rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw') {
|
// if (request.taker_gets.issuer === "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw") {
|
||||||
return rippled.book_offers.usd_xrp
|
// return rippled.book_offers.usd_xrp;
|
||||||
}
|
// }
|
||||||
throw new Error('unexpected end')
|
// throw new Error("unexpected end");
|
||||||
}
|
// }
|
||||||
|
|
||||||
describe('client.getOrderbook', function () {
|
describe('client.getOrderbook', function () {
|
||||||
beforeEach(setupClient)
|
beforeEach(setupClient)
|
||||||
@@ -91,9 +88,11 @@ describe('client.getOrderbook', function () {
|
|||||||
it('normal', async function () {
|
it('normal', async function () {
|
||||||
this.mockRippled.addResponse('book_offers', normalRippledResponse)
|
this.mockRippled.addResponse('book_offers', normalRippledResponse)
|
||||||
const response = await this.client.getOrderbook(
|
const response = await this.client.getOrderbook(
|
||||||
test.address,
|
requests.getOrderbook.normal.taker_pays,
|
||||||
requests.getOrderbook.normal,
|
requests.getOrderbook.normal.taker_gets,
|
||||||
{ limit: 20 },
|
{
|
||||||
|
limit: 1,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
assertResultMatch(
|
assertResultMatch(
|
||||||
response,
|
response,
|
||||||
@@ -102,28 +101,28 @@ describe('client.getOrderbook', function () {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('invalid options', async function () {
|
// it("invalid options", async function () {
|
||||||
this.mockRippled.addResponse('book_offers', normalRippledResponse)
|
// this.mockRippled.addResponse("book_offers", normalRippledResponse);
|
||||||
assertRejects(
|
// assertRejects(
|
||||||
this.client.getOrderbook(test.address, requests.getOrderbook.normal, {
|
// this.client.getOrderbook(test.address, requests.getOrderbook.normal, {
|
||||||
invalid: 'options',
|
// invalid: "options",
|
||||||
}),
|
// }),
|
||||||
this.client.errors.ValidationError,
|
// this.client.errors.ValidationError
|
||||||
)
|
// );
|
||||||
})
|
// });
|
||||||
|
|
||||||
it('with XRP', async function () {
|
// it("with XRP", async function () {
|
||||||
this.mockRippled.addResponse('book_offers', xrpRippledResponse)
|
// this.mockRippled.addResponse("book_offers", xrpRippledResponse);
|
||||||
const response = await this.client.getOrderbook(
|
// const response = await this.client.getOrderbook(
|
||||||
test.address,
|
// test.address,
|
||||||
requests.getOrderbook.withXRP,
|
// requests.getOrderbook.withXRP
|
||||||
)
|
// );
|
||||||
assertResultMatch(
|
// assertResultMatch(
|
||||||
response,
|
// response,
|
||||||
responses.getOrderbook.withXRP,
|
// responses.getOrderbook.withXRP,
|
||||||
'getOrderbook',
|
// "getOrderbook"
|
||||||
)
|
// );
|
||||||
})
|
// });
|
||||||
|
|
||||||
// 'sample XRP/JPY book has orders sorted correctly', async function () {
|
// 'sample XRP/JPY book has orders sorted correctly', async function () {
|
||||||
// const orderbookInfo = {
|
// const orderbookInfo = {
|
||||||
@@ -157,61 +156,61 @@ describe('client.getOrderbook', function () {
|
|||||||
// },
|
// },
|
||||||
|
|
||||||
// WARNING: This test fails to catch the sorting bug, issue #766
|
// WARNING: This test fails to catch the sorting bug, issue #766
|
||||||
it('sorted so that best deals come first [bad test]', async function () {
|
// it("sorted so that best deals come first [bad test]", async function () {
|
||||||
this.mockRippled.addResponse('book_offers', normalRippledResponse)
|
// this.mockRippled.addResponse("book_offers", normalRippledResponse);
|
||||||
const response = await this.client.getOrderbook(
|
// const response = await this.client.getOrderbook(
|
||||||
test.address,
|
// test.address,
|
||||||
requests.getOrderbook.normal,
|
// requests.getOrderbook.normal
|
||||||
)
|
// );
|
||||||
const bidRates = response.bids.map(
|
// const bidRates = response.bids.map(
|
||||||
(bid) => bid.properties.makerExchangeRate,
|
// (bid) => bid.properties.makerExchangeRate
|
||||||
)
|
// );
|
||||||
const askRates = response.asks.map(
|
// const askRates = response.asks.map(
|
||||||
(ask) => ask.properties.makerExchangeRate,
|
// (ask) => ask.properties.makerExchangeRate
|
||||||
)
|
// );
|
||||||
// makerExchangeRate = quality = takerPays.value/takerGets.value
|
// // makerExchangeRate = quality = takerPays.value/takerGets.value
|
||||||
// so the best deal for the taker is the lowest makerExchangeRate
|
// // so the best deal for the taker is the lowest makerExchangeRate
|
||||||
// bids and asks should be sorted so that the best deals come first
|
// // bids and asks should be sorted so that the best deals come first
|
||||||
assert.deepEqual(
|
// assert.deepEqual(
|
||||||
bidRates.sort((x) => Number(x)),
|
// bidRates.sort((x) => Number(x)),
|
||||||
bidRates,
|
// bidRates
|
||||||
)
|
// );
|
||||||
assert.deepEqual(
|
// assert.deepEqual(
|
||||||
askRates.sort((x) => Number(x)),
|
// askRates.sort((x) => Number(x)),
|
||||||
askRates,
|
// askRates
|
||||||
)
|
// );
|
||||||
})
|
// });
|
||||||
|
|
||||||
it('currency & counterparty are correct', async function () {
|
// it("currency & counterparty are correct", async function () {
|
||||||
this.mockRippled.addResponse('book_offers', normalRippledResponse)
|
// this.mockRippled.addResponse("book_offers", normalRippledResponse);
|
||||||
const response = await this.client.getOrderbook(
|
// const response = await this.client.getOrderbook(
|
||||||
test.address,
|
// test.address,
|
||||||
requests.getOrderbook.normal,
|
// requests.getOrderbook.normal
|
||||||
)
|
// );
|
||||||
;[...response.bids, ...response.asks].forEach((order) => {
|
// [...response.bids, ...response.asks].forEach((order) => {
|
||||||
const quantity = order.specification.quantity
|
// const quantity = order.specification.quantity;
|
||||||
const totalPrice = order.specification.totalPrice
|
// const totalPrice = order.specification.totalPrice;
|
||||||
const { base, counter } = requests.getOrderbook.normal
|
// const { base, counter } = requests.getOrderbook.normal;
|
||||||
assert.strictEqual(quantity.currency, base.currency)
|
// assert.strictEqual(quantity.currency, base.currency);
|
||||||
assert.strictEqual(quantity.counterparty, base.counterparty)
|
// assert.strictEqual(quantity.counterparty, base.counterparty);
|
||||||
assert.strictEqual(totalPrice.currency, counter.currency)
|
// assert.strictEqual(totalPrice.currency, counter.currency);
|
||||||
assert.strictEqual(totalPrice.counterparty, counter.counterparty)
|
// assert.strictEqual(totalPrice.counterparty, counter.counterparty);
|
||||||
})
|
// });
|
||||||
})
|
// });
|
||||||
|
|
||||||
it('direction is correct for bids and asks', async function () {
|
// it("direction is correct for bids and asks", async function () {
|
||||||
this.mockRippled.addResponse('book_offers', normalRippledResponse)
|
// this.mockRippled.addResponse("book_offers", normalRippledResponse);
|
||||||
const response = await this.client.getOrderbook(
|
// const response = await this.client.getOrderbook(
|
||||||
test.address,
|
// test.address,
|
||||||
requests.getOrderbook.normal,
|
// requests.getOrderbook.normal
|
||||||
)
|
// );
|
||||||
assert(
|
// assert(
|
||||||
response.bids.every((bid) => bid.specification.direction === 'buy'),
|
// response.bids.every((bid) => bid.specification.direction === "buy")
|
||||||
)
|
// );
|
||||||
assert(
|
// assert(
|
||||||
response.asks.every((ask) => ask.specification.direction === 'sell'),
|
// response.asks.every((ask) => ask.specification.direction === "sell")
|
||||||
)
|
// );
|
||||||
})
|
// });
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
import addresses from '../fixtures/addresses.json'
|
|
||||||
import requests from '../fixtures/requests'
|
|
||||||
import rippled from '../fixtures/rippled'
|
|
||||||
import { setupClient, teardownClient } from '../setupClient'
|
|
||||||
import { assertRejects } from '../testUtils'
|
|
||||||
// import responses from '../fixtures/responses'
|
|
||||||
const { getPaths: REQUEST_FIXTURES } = requests
|
|
||||||
// const {getPaths: RESPONSE_FIXTURES} = responses
|
|
||||||
|
|
||||||
const rippledResponse = rippled.path_find.generate.generateIOUPaymentPaths(
|
|
||||||
0,
|
|
||||||
REQUEST_FIXTURES.normal.source.address,
|
|
||||||
REQUEST_FIXTURES.normal.destination.address,
|
|
||||||
REQUEST_FIXTURES.normal.destination.amount,
|
|
||||||
)
|
|
||||||
|
|
||||||
describe('client.getPaths', function () {
|
|
||||||
beforeEach(setupClient)
|
|
||||||
afterEach(teardownClient)
|
|
||||||
// 'simple test', function () {
|
|
||||||
// const response = await this.client.getPaths(REQUEST_FIXTURES.normal)
|
|
||||||
// assertResultMatch(response, RESPONSE_FIXTURES.XrpToUsd, 'getPaths')
|
|
||||||
// })
|
|
||||||
// 'queuing', function () {
|
|
||||||
// const [normalResult, usdOnlyResult, xrpOnlyResult] = await Promise.all([
|
|
||||||
// this.client.getPaths(REQUEST_FIXTURES.normal),
|
|
||||||
// this.client.getPaths(REQUEST_FIXTURES.UsdToUsd),
|
|
||||||
// this.client.getPaths(REQUEST_FIXTURES.XrpToXrp)
|
|
||||||
// ])
|
|
||||||
// assertResultMatch(normalResult, RESPONSE_FIXTURES.XrpToUsd, 'getPaths')
|
|
||||||
// assertResultMatch(usdOnlyResult, RESPONSE_FIXTURES.UsdToUsd, 'getPaths')
|
|
||||||
// assertResultMatch(xrpOnlyResult, RESPONSE_FIXTURES.XrpToXrp, 'getPaths')
|
|
||||||
// })
|
|
||||||
// // @TODO
|
|
||||||
// // need decide what to do with currencies/XRP:
|
|
||||||
// // if add 'XRP' in currencies, then there will be exception in
|
|
||||||
// // xrpToDrops function (called from toRippledAmount)
|
|
||||||
// 'getPaths USD 2 USD', function () {
|
|
||||||
// const response = await this.client.getPaths(REQUEST_FIXTURES.UsdToUsd)
|
|
||||||
// assertResultMatch(response, RESPONSE_FIXTURES.UsdToUsd, 'getPaths')
|
|
||||||
// })
|
|
||||||
// 'getPaths XRP 2 XRP', function () {
|
|
||||||
// const response = await this.client.getPaths(REQUEST_FIXTURES.XrpToXrp)
|
|
||||||
// assertResultMatch(response, RESPONSE_FIXTURES.XrpToXrp, 'getPaths')
|
|
||||||
// })
|
|
||||||
it('source with issuer', async function () {
|
|
||||||
this.mockRippled.addResponse('ripple_path_find', rippledResponse)
|
|
||||||
return assertRejects(
|
|
||||||
this.client.getPaths(REQUEST_FIXTURES.issuer),
|
|
||||||
this.client.errors.NotFoundError,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
// 'XRP 2 XRP - not enough', function () {
|
|
||||||
// return assertRejects(
|
|
||||||
// this.client.getPaths(REQUEST_FIXTURES.XrpToXrpNotEnough),
|
|
||||||
// this.client.errors.NotFoundError
|
|
||||||
// )
|
|
||||||
// })
|
|
||||||
// it("invalid PathFind", function () {
|
|
||||||
// this.mockRippled.addResponse("ripple_path_find", rippledResponse);
|
|
||||||
// assert.throws(() => {
|
|
||||||
// this.client.getPaths(REQUEST_FIXTURES.invalid);
|
|
||||||
// }, /Cannot specify both source.amount/);
|
|
||||||
// });
|
|
||||||
it('does not accept currency', async function () {
|
|
||||||
this.mockRippled.addResponse('ripple_path_find', rippledResponse)
|
|
||||||
return assertRejects(
|
|
||||||
this.client.getPaths(REQUEST_FIXTURES.NotAcceptCurrency),
|
|
||||||
this.client.errors.NotFoundError,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
it('no paths', async function () {
|
|
||||||
this.mockRippled.addResponse('ripple_path_find', rippledResponse)
|
|
||||||
return assertRejects(
|
|
||||||
this.client.getPaths(REQUEST_FIXTURES.NoPaths),
|
|
||||||
this.client.errors.NotFoundError,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
it('no paths source amount', async function () {
|
|
||||||
this.mockRippled.addResponse('ripple_path_find', rippledResponse)
|
|
||||||
return assertRejects(
|
|
||||||
this.client.getPaths(REQUEST_FIXTURES.NoPathsSource),
|
|
||||||
this.client.errors.NotFoundError,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
it('no paths with source currencies', async function () {
|
|
||||||
this.mockRippled.addResponse('ripple_path_find', rippledResponse)
|
|
||||||
return assertRejects(
|
|
||||||
this.client.getPaths(REQUEST_FIXTURES.NoPathsWithCurrencies),
|
|
||||||
this.client.errors.NotFoundError,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
it('error: srcActNotFound', async function () {
|
|
||||||
this.mockRippled.addResponse('ripple_path_find', rippledResponse)
|
|
||||||
return assertRejects(
|
|
||||||
this.client.getPaths({
|
|
||||||
...REQUEST_FIXTURES.normal,
|
|
||||||
source: { address: addresses.NOTFOUND },
|
|
||||||
}),
|
|
||||||
this.client.errors.XrplError,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
// 'send all', function () {
|
|
||||||
// const response = await this.client.getPaths(REQUEST_FIXTURES.sendAll)
|
|
||||||
// assertResultMatch(response, RESPONSE_FIXTURES.sendAll, 'getPaths')
|
|
||||||
// })
|
|
||||||
})
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
import responses from '../fixtures/responses'
|
|
||||||
import rippled from '../fixtures/rippled/accountLines'
|
|
||||||
import { setupClient, teardownClient } from '../setupClient'
|
|
||||||
import { assertResultMatch, addressTests } from '../testUtils'
|
|
||||||
|
|
||||||
const { getTrustlines: RESPONSE_FIXTURES } = responses
|
|
||||||
|
|
||||||
describe('client.getTrustlines', function () {
|
|
||||||
beforeEach(setupClient)
|
|
||||||
afterEach(teardownClient)
|
|
||||||
|
|
||||||
addressTests.forEach(function (test) {
|
|
||||||
describe(test.type, function () {
|
|
||||||
it('getTrustlines - filtered', async function () {
|
|
||||||
this.mockRippled.addResponse('account_lines', rippled.normal)
|
|
||||||
const options = { currency: 'USD' }
|
|
||||||
const result = await this.client.getTrustlines(test.address, options)
|
|
||||||
assertResultMatch(result, RESPONSE_FIXTURES.filtered, 'getTrustlines')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('getTrustlines - more than 400 items', async function () {
|
|
||||||
this.mockRippled.addResponse('account_lines', rippled.manyItems)
|
|
||||||
const options = { limit: 401 }
|
|
||||||
const result = await this.client.getTrustlines(test.address, options)
|
|
||||||
assertResultMatch(
|
|
||||||
result,
|
|
||||||
RESPONSE_FIXTURES.moreThan400Items,
|
|
||||||
'getTrustlines',
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('getTrustlines - no options', async function () {
|
|
||||||
this.mockRippled.addResponse('account_lines', rippled.normal)
|
|
||||||
await this.client.getTrustlines(test.address)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('getTrustlines - ripplingDisabled works properly', async function () {
|
|
||||||
this.mockRippled.addResponse('account_lines', rippled.ripplingDisabled)
|
|
||||||
const result = await this.client.getTrustlines(test.address)
|
|
||||||
assertResultMatch(
|
|
||||||
result,
|
|
||||||
RESPONSE_FIXTURES.ripplingDisabled,
|
|
||||||
'getTrustlines',
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('getTrustlines - ledger version option', async function () {
|
|
||||||
this.mockRippled.addResponse('account_lines', rippled.manyItems)
|
|
||||||
const result = await this.client.getTrustlines(test.address, {
|
|
||||||
ledgerVersion: 5,
|
|
||||||
})
|
|
||||||
assertResultMatch(
|
|
||||||
result,
|
|
||||||
RESPONSE_FIXTURES.moreThan400Items,
|
|
||||||
'getTrustlines',
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
8
test/fixtures/requests/getOrderbook.json
vendored
8
test/fixtures/requests/getOrderbook.json
vendored
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"base": {
|
"taker_pays": {
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
},
|
},
|
||||||
"counter": {
|
"taker_gets": {
|
||||||
"currency": "BTC",
|
"currency": "BTC",
|
||||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
48
test/fixtures/responses/getBalances.json
vendored
48
test/fixtures/responses/getBalances.json
vendored
@@ -6,121 +6,121 @@
|
|||||||
{
|
{
|
||||||
"value": "0",
|
"value": "0",
|
||||||
"currency": "ASP",
|
"currency": "ASP",
|
||||||
"counterparty": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z"
|
"issuer": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "0",
|
"value": "0",
|
||||||
"currency": "XAU",
|
"currency": "XAU",
|
||||||
"counterparty": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z"
|
"issuer": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "2.497605752725159",
|
"value": "2.497605752725159",
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"counterparty": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "481.992867407479",
|
"value": "481.992867407479",
|
||||||
"currency": "MXN",
|
"currency": "MXN",
|
||||||
"counterparty": "rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4"
|
"issuer": "rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "0.793598266778297",
|
"value": "0.793598266778297",
|
||||||
"currency": "EUR",
|
"currency": "EUR",
|
||||||
"counterparty": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"
|
"issuer": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "0",
|
"value": "0",
|
||||||
"currency": "CNY",
|
"currency": "CNY",
|
||||||
"counterparty": "rnuF96W4SZoCJmbHYBFoJZpR8eCaxNvekK"
|
"issuer": "rnuF96W4SZoCJmbHYBFoJZpR8eCaxNvekK"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "1.294889190631542",
|
"value": "1.294889190631542",
|
||||||
"currency": "DYM",
|
"currency": "DYM",
|
||||||
"counterparty": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E"
|
"issuer": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "0.3488146605801446",
|
"value": "0.3488146605801446",
|
||||||
"currency": "CHF",
|
"currency": "CHF",
|
||||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "2.114103174931847",
|
"value": "2.114103174931847",
|
||||||
"currency": "BTC",
|
"currency": "BTC",
|
||||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "0",
|
"value": "0",
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "-0.00111",
|
"value": "-0.00111",
|
||||||
"currency": "BTC",
|
"currency": "BTC",
|
||||||
"counterparty": "rpgKWEmNqSDAGFhy5WDnsyPqfQxbWxKeVd"
|
"issuer": "rpgKWEmNqSDAGFhy5WDnsyPqfQxbWxKeVd"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "-0.1010780000080207",
|
"value": "-0.1010780000080207",
|
||||||
"currency": "BTC",
|
"currency": "BTC",
|
||||||
"counterparty": "rBJ3YjwXi2MGbg7GVLuTXUWQ8DjL7tDXh4"
|
"issuer": "rBJ3YjwXi2MGbg7GVLuTXUWQ8DjL7tDXh4"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "1",
|
"value": "1",
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"counterparty": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"
|
"issuer": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "8.07619790068559",
|
"value": "8.07619790068559",
|
||||||
"currency": "CNY",
|
"currency": "CNY",
|
||||||
"counterparty": "razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA"
|
"issuer": "razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "7.292695098901099",
|
"value": "7.292695098901099",
|
||||||
"currency": "JPY",
|
"currency": "JPY",
|
||||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "0",
|
"value": "0",
|
||||||
"currency": "AUX",
|
"currency": "AUX",
|
||||||
"counterparty": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z"
|
"issuer": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "0",
|
"value": "0",
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"counterparty": "r9vbV3EHvXWjSkeQ6CAcYVPGeq7TuiXY2X"
|
"issuer": "r9vbV3EHvXWjSkeQ6CAcYVPGeq7TuiXY2X"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "12.41688780720394",
|
"value": "12.41688780720394",
|
||||||
"currency": "EUR",
|
"currency": "EUR",
|
||||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "35",
|
"value": "35",
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"counterparty": "rfF3PNkwkq1DygW2wum2HK3RGfgkJjdPVD"
|
"issuer": "rfF3PNkwkq1DygW2wum2HK3RGfgkJjdPVD"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "-5",
|
"value": "-5",
|
||||||
"currency": "JOE",
|
"currency": "JOE",
|
||||||
"counterparty": "rwUVoVMSURqNyvocPCcvLu3ygJzZyw8qwp"
|
"issuer": "rwUVoVMSURqNyvocPCcvLu3ygJzZyw8qwp"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "0",
|
"value": "0",
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"counterparty": "rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2"
|
"issuer": "rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "0",
|
"value": "0",
|
||||||
"currency": "JOE",
|
"currency": "JOE",
|
||||||
"counterparty": "rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2"
|
"issuer": "rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "0",
|
"value": "0",
|
||||||
"currency": "015841551A748AD2C1F76FF6ECB0CCCD00000000",
|
"currency": "015841551A748AD2C1F76FF6ECB0CCCD00000000",
|
||||||
"counterparty": "rs9M85karFkCRjvc6KMWn8Coigm9cbcgcx"
|
"issuer": "rs9M85karFkCRjvc6KMWn8Coigm9cbcgcx"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "0",
|
"value": "0",
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"counterparty": "rEhDDUUNxpXgEHVJtC2cjXAgyx5VCFxdMF"
|
"issuer": "rEhDDUUNxpXgEHVJtC2cjXAgyx5VCFxdMF"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
1257
test/fixtures/responses/getOrderbook.json
vendored
1257
test/fixtures/responses/getOrderbook.json
vendored
File diff suppressed because it is too large
Load Diff
56
test/fixtures/responses/getPaths.json
vendored
56
test/fixtures/responses/getPaths.json
vendored
@@ -1,56 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
|
||||||
"maxAmount": {
|
|
||||||
"currency": "JPY",
|
|
||||||
"value": "0.1117218827811721"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"destination": {
|
|
||||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
|
||||||
"amount": {
|
|
||||||
"currency": "USD",
|
|
||||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
|
|
||||||
"value": "100"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"paths": "[[{\"account\":\"rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6\"},{\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},{\"account\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"}],[{\"account\":\"rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6\"},{\"currency\":\"XRP\"},{\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},{\"account\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"}],[{\"account\":\"rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6\"},{\"currency\":\"XRP\"},{\"currency\":\"USD\",\"issuer\":\"rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT\"},{\"account\":\"rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT\"},{\"account\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"}],[{\"account\":\"rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6\"},{\"currency\":\"XRP\"},{\"currency\":\"USD\",\"issuer\":\"rHHa9t2kLQyXRbdLkSzEgkzwf9unmFgZs9\"},{\"account\":\"rHHa9t2kLQyXRbdLkSzEgkzwf9unmFgZs9\"},{\"account\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"}]]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
|
||||||
"maxAmount": {
|
|
||||||
"currency": "USD",
|
|
||||||
"value": "0.001002"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"destination": {
|
|
||||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
|
||||||
"amount": {
|
|
||||||
"currency": "USD",
|
|
||||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
|
|
||||||
"value": "100"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"paths": "[[{\"account\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"}],[{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\"},{\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},{\"account\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"}],[{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\"},{\"currency\":\"XRP\"},{\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},{\"account\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"}],[{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\"},{\"currency\":\"XRP\"},{\"currency\":\"USD\",\"issuer\":\"rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT\"},{\"account\":\"rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT\"},{\"account\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"}]]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
|
||||||
"maxAmount": {
|
|
||||||
"currency": "XRP",
|
|
||||||
"value": "0.207669"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"destination": {
|
|
||||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
|
||||||
"amount": {
|
|
||||||
"currency": "USD",
|
|
||||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
|
|
||||||
"value": "100"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"paths": "[[{\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},{\"account\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"}],[{\"currency\":\"USD\",\"issuer\":\"rsP3mgGb2tcYUrxiLFiHJiQXhsziegtwBc\"},{\"account\":\"rsP3mgGb2tcYUrxiLFiHJiQXhsziegtwBc\"},{\"account\":\"rf9X8QoYnWLHMHuDfjkmRcD2UE5qX5aYV\"},{\"account\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"}],[{\"currency\":\"USD\",\"issuer\":\"rDVdJ62foD1sn7ZpxtXyptdkBSyhsQGviT\"},{\"account\":\"rDVdJ62foD1sn7ZpxtXyptdkBSyhsQGviT\"},{\"account\":\"rfQPFZ3eLcaSUKjUy7A3LAmDNM4F9Hz9j1\"},{\"account\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"}],[{\"currency\":\"USD\",\"issuer\":\"rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT\"},{\"account\":\"rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT\"},{\"account\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"}]]"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
19
test/fixtures/responses/getPathsSendUsd.json
vendored
19
test/fixtures/responses/getPathsSendUsd.json
vendored
@@ -1,19 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
|
||||||
"maxAmount": {
|
|
||||||
"currency": "USD",
|
|
||||||
"value": "0.000001002"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"destination": {
|
|
||||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
|
||||||
"amount": {
|
|
||||||
"value": "0.000001",
|
|
||||||
"currency": "USD"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"paths": "[[{\"account\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\"}],[{\"account\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\"},{\"account\":\"rLMJ4db4uwHcd6NHg6jvTaYb8sH5Gy4tg5\"},{\"account\":\"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun\"}],[{\"account\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\"},{\"currency\":\"USD\",\"issuer\":\"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun\"},{\"account\":\"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun\"}],[{\"account\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\"},{\"account\":\"rLMJ4db4uwHcd6NHg6jvTaYb8sH5Gy4tg5\"},{\"account\":\"r9vbV3EHvXWjSkeQ6CAcYVPGeq7TuiXY2X\"}]]"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
19
test/fixtures/responses/getPathsXrpToXrp.json
vendored
19
test/fixtures/responses/getPathsXrpToXrp.json
vendored
@@ -1,19 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"address": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J",
|
|
||||||
"maxAmount": {
|
|
||||||
"currency": "XRP",
|
|
||||||
"value": "0.000002"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"destination": {
|
|
||||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
|
||||||
"amount": {
|
|
||||||
"value": "0.000002",
|
|
||||||
"currency": "XRP"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"paths": "[]"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
25
test/fixtures/responses/index.ts
vendored
25
test/fixtures/responses/index.ts
vendored
@@ -16,10 +16,7 @@ import withStateAsHashes from './getLedgerWithStateAsHashes.json'
|
|||||||
import normalOrderBook from './getOrderbook.json'
|
import normalOrderBook from './getOrderbook.json'
|
||||||
import withXRPOrderBook from './getOrderbookWithXrp.json'
|
import withXRPOrderBook from './getOrderbookWithXrp.json'
|
||||||
import getOrders from './getOrders.json'
|
import getOrders from './getOrders.json'
|
||||||
import XrpToUsd from './getPaths.json'
|
|
||||||
import sendAll from './getPathsSendAll.json'
|
import sendAll from './getPathsSendAll.json'
|
||||||
import UsdToUsd from './getPathsSendUsd.json'
|
|
||||||
import XrpToXrp from './getPathsXrpToXrp.json'
|
|
||||||
import normalPayChan from './getPaymentChannel.json'
|
import normalPayChan from './getPaymentChannel.json'
|
||||||
import fullPayChan from './getPaymentChannelFull.json'
|
import fullPayChan from './getPaymentChannelFull.json'
|
||||||
import getServerInfo from './getServerInfo.json'
|
import getServerInfo from './getServerInfo.json'
|
||||||
@@ -70,9 +67,6 @@ import trustlineNoQuality from './getTransactionTrustNoQuality.json'
|
|||||||
import trustlineFrozenOff from './getTransactionTrustSetFrozenOff.json'
|
import trustlineFrozenOff from './getTransactionTrustSetFrozenOff.json'
|
||||||
import withMemo from './getTransactionWithMemo.json'
|
import withMemo from './getTransactionWithMemo.json'
|
||||||
import withMemos from './getTransactionWithMemos.json'
|
import withMemos from './getTransactionWithMemos.json'
|
||||||
import filteredLines from './getTrustlines.json'
|
|
||||||
import allTrustlines from './getTrustlinesAll.json'
|
|
||||||
import ripplingDisabledLines from './getTrustlinesRipplingDisabled.json'
|
|
||||||
import ledgerEvent from './ledgerEvent.json'
|
import ledgerEvent from './ledgerEvent.json'
|
||||||
import normalCheckCancel from './prepareCheckCancel.json'
|
import normalCheckCancel from './prepareCheckCancel.json'
|
||||||
import ticketCheckCancel from './prepareCheckCancelTicket.json'
|
import ticketCheckCancel from './prepareCheckCancelTicket.json'
|
||||||
@@ -145,11 +139,6 @@ import escrowSign from './signEscrow.json'
|
|||||||
import signPaymentChannelClaim from './signPaymentChannelClaim.json'
|
import signPaymentChannelClaim from './signPaymentChannelClaim.json'
|
||||||
import ticketSign from './signTicket.json'
|
import ticketSign from './signTicket.json'
|
||||||
import submit from './submit.json'
|
import submit from './submit.json'
|
||||||
import trustlineItems from './trustlineItem.json'
|
|
||||||
|
|
||||||
function buildList(options: { item: any; count: number }): any[] {
|
|
||||||
return new Array(options.count).fill(options.item)
|
|
||||||
}
|
|
||||||
|
|
||||||
const getPaymentChannel = {
|
const getPaymentChannel = {
|
||||||
normal: normalPayChan,
|
normal: normalPayChan,
|
||||||
@@ -162,9 +151,6 @@ const getOrderbook = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getPaths = {
|
const getPaths = {
|
||||||
XrpToUsd,
|
|
||||||
XrpToXrp,
|
|
||||||
UsdToUsd,
|
|
||||||
sendAll,
|
sendAll,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,16 +206,6 @@ const getTransactions = {
|
|||||||
one: oneTransaction,
|
one: oneTransaction,
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTrustlines = {
|
|
||||||
filtered: filteredLines,
|
|
||||||
moreThan400Items: buildList({
|
|
||||||
item: trustlineItems,
|
|
||||||
count: 401,
|
|
||||||
}),
|
|
||||||
all: allTrustlines,
|
|
||||||
ripplingDisabled: ripplingDisabledLines,
|
|
||||||
}
|
|
||||||
|
|
||||||
const getLedger = {
|
const getLedger = {
|
||||||
header,
|
header,
|
||||||
headerByHash,
|
headerByHash,
|
||||||
@@ -377,7 +353,6 @@ const responses = {
|
|||||||
getPaths,
|
getPaths,
|
||||||
getTransaction,
|
getTransaction,
|
||||||
getTransactions,
|
getTransactions,
|
||||||
getTrustlines,
|
|
||||||
getLedger,
|
getLedger,
|
||||||
prepareOrder,
|
prepareOrder,
|
||||||
prepareOrderCancellation,
|
prepareOrderCancellation,
|
||||||
|
|||||||
Reference in New Issue
Block a user