Files
xahau.js/packages/xrpl/test/client/getOrderbook.test.ts
2023-02-03 17:03:07 -06:00

235 lines
7.1 KiB
TypeScript

import BigNumber from 'bignumber.js'
import { assert } from 'chai'
import { BookOffersRequest, type Request } from '../../src'
import { ValidationError, XrplError } from '../../src/errors'
import { OfferFlags } from '../../src/models/ledger'
import requests from '../fixtures/requests'
import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled'
import {
setupClient,
teardownClient,
type XrplTestContext,
} from '../setupClient'
import { assertResultMatch, assertRejects } from '../testUtils'
function checkSortingOfOrders(orders): void {
let previousRate = '0'
for (const order of orders) {
assert(
new BigNumber(order.quality).isGreaterThanOrEqualTo(previousRate),
`Rates must be sorted from least to greatest: ${
order.quality as number
} should be >= ${previousRate}`,
)
previousRate = order.quality
}
}
function isUSD(currency: string): boolean {
return (
currency === 'USD' ||
currency === '0000000000000000000000005553440000000000'
)
}
function isBTC(currency: string): boolean {
return (
currency === 'BTC' ||
currency === '0000000000000000000000004254430000000000'
)
}
function normalRippledResponse(request: Request): Record<string, unknown> {
if (
isBTC((request as BookOffersRequest).taker_gets.currency) &&
isUSD((request as BookOffersRequest).taker_pays.currency)
) {
return rippled.book_offers.fabric.requestBookOffersBidsResponse(request)
}
if (
isUSD((request as BookOffersRequest).taker_gets.currency) &&
isBTC((request as BookOffersRequest).taker_pays.currency)
) {
return rippled.book_offers.fabric.requestBookOffersAsksResponse(request)
}
throw new XrplError('unexpected end')
}
function xrpRippledResponse(request: Request): Record<string, unknown> {
if (
(request as BookOffersRequest).taker_pays.issuer ===
'rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw'
) {
return rippled.book_offers.xrp_usd
}
if (
(request as BookOffersRequest).taker_gets.issuer ===
'rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw'
) {
return rippled.book_offers.usd_xrp
}
throw new Error('unexpected end')
}
describe('client.getOrderbook', function () {
let testContext: XrplTestContext
beforeEach(async () => {
testContext = await setupClient()
})
afterEach(async () => teardownClient(testContext))
it('normal', async function () {
testContext.mockRippled!.addResponse('book_offers', normalRippledResponse)
const request = {
takerPays: requests.getOrderbook.normal.takerPays,
takerGets: requests.getOrderbook.normal.takerGets,
options: {
limit: 1,
},
}
const response = await testContext.client.getOrderbook(
request.takerPays,
request.takerGets,
request.options,
)
const expectedResponse = {
buy: responses.getOrderbook.normal.buy.slice(0, request.options.limit),
sell: responses.getOrderbook.normal.sell.slice(0, request.options.limit),
}
assertResultMatch(response, expectedResponse, 'getOrderbook')
})
it('invalid options', async function () {
const invalidOptions = [
{
option: 'invalid',
},
{
limit: 'invalid',
},
{
ledger_index: 'invalid',
},
{
ledger_hash: 0,
},
{
taker: 0,
},
]
testContext.mockRippled!.addResponse('book_offers', normalRippledResponse)
await Promise.all(
invalidOptions.map(
async (invalidOptionObject) =>
new Promise<void>((resolve) => {
assertRejects(
testContext.client
.getOrderbook(
requests.getOrderbook.normal.takerPays,
requests.getOrderbook.normal.takerGets,
// @ts-expect-error Meant to be invalid for testing purposes
invalidOptionObject,
)
.catch((error) => {
resolve()
throw error
}),
ValidationError,
)
}),
),
)
})
it('with XRP', async function () {
testContext.mockRippled!.addResponse('book_offers', xrpRippledResponse)
const response = await testContext.client.getOrderbook(
requests.getOrderbook.withXRP.takerPays,
requests.getOrderbook.withXRP.takerGets,
)
assertResultMatch(response, responses.getOrderbook.withXRP, 'getOrderbook')
})
it('sample USD/XRP book has orders sorted correctly', async function () {
testContext.mockRippled!.addResponse('book_offers', xrpRippledResponse)
const response = await testContext.client.getOrderbook(
requests.getOrderbook.withXRP.takerPays,
requests.getOrderbook.withXRP.takerGets,
)
checkSortingOfOrders(response.buy)
checkSortingOfOrders(response.sell)
})
it('sorted so that best deals come first [failure test]', async function () {
testContext.mockRippled!.addResponse('book_offers', normalRippledResponse)
const response = await testContext.client.getOrderbook(
requests.getOrderbook.normal.takerPays,
requests.getOrderbook.normal.takerGets,
)
const buyRates = response.buy.map(async (item) => Number(item.quality))
const sellRates = response.sell.map(async (item) => Number(item.quality))
// buy and sell orders should be sorted so that the best deals come first
assert.deepEqual(
buyRates.sort((item) => Number(item)),
buyRates,
)
assert.deepEqual(
sellRates.sort((item) => Number(item)),
sellRates,
)
})
it('sorted so that best deals come first [bad test](XRP)', async function () {
testContext.mockRippled!.addResponse('book_offers', xrpRippledResponse)
const response = await testContext.client.getOrderbook(
requests.getOrderbook.withXRP.takerPays,
requests.getOrderbook.withXRP.takerGets,
)
const buyRates = response.buy.map(async (item) => Number(item.quality))
const sellRates = response.sell.map(async (item) => Number(item.quality))
// buy and sell orders should be sorted so that the best deals come first
assert.deepEqual(
buyRates.sort((item) => Number(item)),
buyRates,
)
assert.deepEqual(
sellRates.sort((item) => Number(item)),
sellRates,
)
})
it('direction is correct for buy and sell', async function () {
testContext.mockRippled!.addResponse('book_offers', normalRippledResponse)
const response = await testContext.client.getOrderbook(
requests.getOrderbook.normal.takerPays,
requests.getOrderbook.normal.takerGets,
)
assert.strictEqual(
response.buy.every((item) => item.Flags !== OfferFlags.lsfSell),
true,
)
assert.strictEqual(
response.sell.every((item) => item.Flags === OfferFlags.lsfSell),
true,
)
})
it('getOrderbook - limit', async function () {
testContext.mockRippled!.addResponse('book_offers', normalRippledResponse)
const LIMIT = 3
const response = await testContext.client.getOrderbook(
requests.getOrderbook.normal.takerPays,
requests.getOrderbook.normal.takerGets,
{
limit: LIMIT,
},
)
assert(response.buy.length <= LIMIT)
assert(response.sell.length <= LIMIT)
})
})