mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-20 04:05:52 +00:00
Rename RippleAPI client to Client (#1520)
* rename RippleAPI -> XrplClient * more renames * move API stuff to client folder * rename all api -> client * fix tests * make tests run * fix integ tests * fix urls * fix merge issues * XrplClient -> Client * fix merge issues * rename xrpl-client npm symlink to xrpl-local
This commit is contained in:
29
test/client/combine/index.ts
Normal file
29
test/client/combine/index.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import assert from 'assert-diff'
|
||||
import binary from 'ripple-binary-codec'
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
const {combine: REQUEST_FIXTURES} = requests
|
||||
const {combine: RESPONSE_FIXTURES} = responses
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'combine': async (client, address) => {
|
||||
const combined = client.combine(REQUEST_FIXTURES.setDomain)
|
||||
assertResultMatch(combined, RESPONSE_FIXTURES.single, 'sign')
|
||||
},
|
||||
|
||||
'combine - different transactions': async (client, address) => {
|
||||
const request = [REQUEST_FIXTURES.setDomain[0]]
|
||||
const tx = binary.decode(REQUEST_FIXTURES.setDomain[0])
|
||||
tx.Flags = 0
|
||||
request.push(binary.encode(tx))
|
||||
assert.throws(() => {
|
||||
client.combine(request)
|
||||
}, /txJSON is not the same for all signedTransactions/)
|
||||
}
|
||||
}
|
||||
191
test/client/computeLedgerHash/index.ts
Normal file
191
test/client/computeLedgerHash/index.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
import assert from 'assert-diff'
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
const {computeLedgerHash: REQUEST_FIXTURES} = requests
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'given corrupt data - should fail': async (client, address) => {
|
||||
const request = {
|
||||
includeTransactions: true,
|
||||
includeState: true,
|
||||
includeAllData: true,
|
||||
ledgerVersion: 38129
|
||||
}
|
||||
const ledger = await client.getLedger(request)
|
||||
assert.strictEqual(
|
||||
// @ts-ignore
|
||||
ledger.transactions[0].rawTransaction,
|
||||
'{"Account":"r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV","Amount":"10000000000","Destination":"rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj","Fee":"10","Flags":0,"Sequence":62,"SigningPubKey":"034AADB09CFF4A4804073701EC53C3510CDC95917C2BB0150FB742D0C66E6CEE9E","TransactionType":"Payment","TxnSignature":"3045022022EB32AECEF7C644C891C19F87966DF9C62B1F34BABA6BE774325E4BB8E2DD62022100A51437898C28C2B297112DF8131F2BB39EA5FE613487DDD611525F1796264639","hash":"3B1A4E1C9BB6A7208EB146BCDB86ECEA6068ED01466D933528CA2B4C64F753EF","meta":{"AffectedNodes":[{"CreatedNode":{"LedgerEntryType":"AccountRoot","LedgerIndex":"4C6ACBD635B0F07101F7FA25871B0925F8836155462152172755845CE691C49E","NewFields":{"Account":"rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj","Balance":"10000000000","Sequence":1}}},{"ModifiedNode":{"FinalFields":{"Account":"r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV","Balance":"981481999380","Flags":0,"OwnerCount":0,"Sequence":63},"LedgerEntryType":"AccountRoot","LedgerIndex":"B33FDD5CF3445E1A7F2BE9B06336BEBD73A5E3EE885D3EF93F7E3E2992E46F1A","PreviousFields":{"Balance":"991481999390","Sequence":62},"PreviousTxnID":"2485FDC606352F1B0785DA5DE96FB9DBAF43EB60ECBB01B7F6FA970F512CDA5F","PreviousTxnLgrSeq":31317}}],"TransactionIndex":0,"TransactionResult":"tesSUCCESS"},"ledger_index":38129}'
|
||||
)
|
||||
// @ts-ignore - Change Amount to 12000000000
|
||||
ledger.transactions[0].rawTransaction =
|
||||
'{"Account":"r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV","Amount":"12000000000","Destination":"rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj","Fee":"10","Flags":0,"Sequence":62,"SigningPubKey":"034AADB09CFF4A4804073701EC53C3510CDC95917C2BB0150FB742D0C66E6CEE9E","TransactionType":"Payment","TxnSignature":"3045022022EB32AECEF7C644C891C19F87966DF9C62B1F34BABA6BE774325E4BB8E2DD62022100A51437898C28C2B297112DF8131F2BB39EA5FE613487DDD611525F1796264639","hash":"3B1A4E1C9BB6A7208EB146BCDB86ECEA6068ED01466D933528CA2B4C64F753EF","meta":{"AffectedNodes":[{"CreatedNode":{"LedgerEntryType":"AccountRoot","LedgerIndex":"4C6ACBD635B0F07101F7FA25871B0925F8836155462152172755845CE691C49E","NewFields":{"Account":"rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj","Balance":"10000000000","Sequence":1}}},{"ModifiedNode":{"FinalFields":{"Account":"r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV","Balance":"981481999380","Flags":0,"OwnerCount":0,"Sequence":63},"LedgerEntryType":"AccountRoot","LedgerIndex":"B33FDD5CF3445E1A7F2BE9B06336BEBD73A5E3EE885D3EF93F7E3E2992E46F1A","PreviousFields":{"Balance":"991481999390","Sequence":62},"PreviousTxnID":"2485FDC606352F1B0785DA5DE96FB9DBAF43EB60ECBB01B7F6FA970F512CDA5F","PreviousTxnLgrSeq":31317}}],"TransactionIndex":0,"TransactionResult":"tesSUCCESS"},"ledger_index":38129}'
|
||||
ledger.parentCloseTime = ledger.closeTime
|
||||
let hash
|
||||
try {
|
||||
hash = client.computeLedgerHash(ledger, {computeTreeHashes: true})
|
||||
} catch (error) {
|
||||
assert(error instanceof client.errors.ValidationError)
|
||||
assert.strictEqual(
|
||||
error.message,
|
||||
'transactionHash in header does not match computed hash of transactions'
|
||||
)
|
||||
assert.deepStrictEqual(error.data, {
|
||||
transactionHashInHeader:
|
||||
'DB83BF807416C5B3499A73130F843CF615AB8E797D79FE7D330ADF1BFA93951A',
|
||||
computedHashOfTransactions:
|
||||
'EAA1ADF4D627339450F0E95EA88B7069186DD64230BAEBDCF3EEC4D616A9FC68'
|
||||
})
|
||||
return
|
||||
}
|
||||
assert(
|
||||
false,
|
||||
'Should throw ValidationError instead of producing hash: ' + hash
|
||||
)
|
||||
},
|
||||
|
||||
'given ledger without raw transactions - should throw': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
const request = {
|
||||
includeTransactions: true,
|
||||
includeState: true,
|
||||
includeAllData: true,
|
||||
ledgerVersion: 38129
|
||||
}
|
||||
const ledger = await client.getLedger(request)
|
||||
assert.strictEqual(
|
||||
// @ts-ignore
|
||||
ledger.transactions[0].rawTransaction,
|
||||
'{"Account":"r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV","Amount":"10000000000","Destination":"rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj","Fee":"10","Flags":0,"Sequence":62,"SigningPubKey":"034AADB09CFF4A4804073701EC53C3510CDC95917C2BB0150FB742D0C66E6CEE9E","TransactionType":"Payment","TxnSignature":"3045022022EB32AECEF7C644C891C19F87966DF9C62B1F34BABA6BE774325E4BB8E2DD62022100A51437898C28C2B297112DF8131F2BB39EA5FE613487DDD611525F1796264639","hash":"3B1A4E1C9BB6A7208EB146BCDB86ECEA6068ED01466D933528CA2B4C64F753EF","meta":{"AffectedNodes":[{"CreatedNode":{"LedgerEntryType":"AccountRoot","LedgerIndex":"4C6ACBD635B0F07101F7FA25871B0925F8836155462152172755845CE691C49E","NewFields":{"Account":"rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj","Balance":"10000000000","Sequence":1}}},{"ModifiedNode":{"FinalFields":{"Account":"r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV","Balance":"981481999380","Flags":0,"OwnerCount":0,"Sequence":63},"LedgerEntryType":"AccountRoot","LedgerIndex":"B33FDD5CF3445E1A7F2BE9B06336BEBD73A5E3EE885D3EF93F7E3E2992E46F1A","PreviousFields":{"Balance":"991481999390","Sequence":62},"PreviousTxnID":"2485FDC606352F1B0785DA5DE96FB9DBAF43EB60ECBB01B7F6FA970F512CDA5F","PreviousTxnLgrSeq":31317}}],"TransactionIndex":0,"TransactionResult":"tesSUCCESS"},"ledger_index":38129}'
|
||||
)
|
||||
// Delete rawTransaction
|
||||
// @ts-ignore - Delete rawTransaction
|
||||
delete ledger.transactions[0].rawTransaction
|
||||
ledger.parentCloseTime = ledger.closeTime
|
||||
let hash
|
||||
try {
|
||||
hash = client.computeLedgerHash(ledger, {computeTreeHashes: true})
|
||||
} catch (error) {
|
||||
assert(error instanceof client.errors.ValidationError)
|
||||
assert.strictEqual(
|
||||
error.message,
|
||||
'ledger' + ' is missing raw transactions'
|
||||
)
|
||||
return
|
||||
}
|
||||
assert(
|
||||
false,
|
||||
'Should throw ValidationError instead of producing hash: ' + hash
|
||||
)
|
||||
},
|
||||
|
||||
'given ledger without state or transactions - only compute ledger hash': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
const request = {
|
||||
includeTransactions: true,
|
||||
includeState: true,
|
||||
includeAllData: true,
|
||||
ledgerVersion: 38129
|
||||
}
|
||||
const ledger = await client.getLedger(request)
|
||||
assert.strictEqual(
|
||||
// @ts-ignore
|
||||
ledger.transactions[0].rawTransaction,
|
||||
'{"Account":"r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV","Amount":"10000000000","Destination":"rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj","Fee":"10","Flags":0,"Sequence":62,"SigningPubKey":"034AADB09CFF4A4804073701EC53C3510CDC95917C2BB0150FB742D0C66E6CEE9E","TransactionType":"Payment","TxnSignature":"3045022022EB32AECEF7C644C891C19F87966DF9C62B1F34BABA6BE774325E4BB8E2DD62022100A51437898C28C2B297112DF8131F2BB39EA5FE613487DDD611525F1796264639","hash":"3B1A4E1C9BB6A7208EB146BCDB86ECEA6068ED01466D933528CA2B4C64F753EF","meta":{"AffectedNodes":[{"CreatedNode":{"LedgerEntryType":"AccountRoot","LedgerIndex":"4C6ACBD635B0F07101F7FA25871B0925F8836155462152172755845CE691C49E","NewFields":{"Account":"rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj","Balance":"10000000000","Sequence":1}}},{"ModifiedNode":{"FinalFields":{"Account":"r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV","Balance":"981481999380","Flags":0,"OwnerCount":0,"Sequence":63},"LedgerEntryType":"AccountRoot","LedgerIndex":"B33FDD5CF3445E1A7F2BE9B06336BEBD73A5E3EE885D3EF93F7E3E2992E46F1A","PreviousFields":{"Balance":"991481999390","Sequence":62},"PreviousTxnID":"2485FDC606352F1B0785DA5DE96FB9DBAF43EB60ECBB01B7F6FA970F512CDA5F","PreviousTxnLgrSeq":31317}}],"TransactionIndex":0,"TransactionResult":"tesSUCCESS"},"ledger_index":38129}'
|
||||
)
|
||||
ledger.parentCloseTime = ledger.closeTime
|
||||
const computeLedgerHash = client.computeLedgerHash
|
||||
const ValidationError = client.errors.ValidationError
|
||||
function testCompute(ledger, expectedError) {
|
||||
let hash = computeLedgerHash(ledger)
|
||||
assert.strictEqual(
|
||||
hash,
|
||||
'E6DB7365949BF9814D76BCC730B01818EB9136A89DB224F3F9F5AAE4569D758E'
|
||||
)
|
||||
// fail if required to compute tree hashes
|
||||
try {
|
||||
hash = computeLedgerHash(ledger, {computeTreeHashes: true})
|
||||
} catch (error) {
|
||||
assert(error instanceof ValidationError)
|
||||
assert.strictEqual(error.message, expectedError)
|
||||
return
|
||||
}
|
||||
assert(
|
||||
false,
|
||||
'Should throw ValidationError instead of producing hash: ' + hash
|
||||
)
|
||||
}
|
||||
|
||||
const transactions = ledger.transactions
|
||||
delete ledger.transactions
|
||||
testCompute(ledger, 'transactions property is missing from the ledger')
|
||||
delete ledger.rawState
|
||||
testCompute(ledger, 'transactions property is missing from the ledger')
|
||||
ledger.transactions = transactions
|
||||
testCompute(ledger, 'rawState property is missing from the ledger')
|
||||
},
|
||||
|
||||
'wrong hash': async (client, address) => {
|
||||
const request = {
|
||||
includeTransactions: true,
|
||||
includeState: true,
|
||||
includeAllData: true,
|
||||
ledgerVersion: 38129
|
||||
}
|
||||
const ledger = await client.getLedger(request)
|
||||
assertResultMatch(ledger, responses.getLedger.full, 'getLedger')
|
||||
const newLedger = {
|
||||
...ledger,
|
||||
parentCloseTime: ledger.closeTime,
|
||||
stateHash:
|
||||
'D9ABF622DA26EEEE48203085D4BC23B0F77DC6F8724AC33D975DA3CA492D2E44'
|
||||
}
|
||||
assert.throws(() => {
|
||||
client.computeLedgerHash(newLedger)
|
||||
}, /does not match computed hash of state/)
|
||||
},
|
||||
|
||||
'computeLedgerHash': async (client, address) => {
|
||||
// const client = new Client()
|
||||
const header = REQUEST_FIXTURES.header
|
||||
const ledgerHash = client.computeLedgerHash(header)
|
||||
assert.strictEqual(
|
||||
ledgerHash,
|
||||
'F4D865D83EB88C1A1911B9E90641919A1314F36E1B099F8E95FE3B7C77BE3349'
|
||||
)
|
||||
},
|
||||
|
||||
'computeLedgerHash - with transactions': async (client, address) => {
|
||||
// const client = new Client()
|
||||
const header = {
|
||||
...REQUEST_FIXTURES.header,
|
||||
transactionHash: undefined,
|
||||
rawTransactions: JSON.stringify(REQUEST_FIXTURES.transactions)
|
||||
}
|
||||
const ledgerHash = client.computeLedgerHash(header)
|
||||
assert.strictEqual(
|
||||
ledgerHash,
|
||||
'F4D865D83EB88C1A1911B9E90641919A1314F36E1B099F8E95FE3B7C77BE3349'
|
||||
)
|
||||
},
|
||||
|
||||
'computeLedgerHash - incorrent transaction_hash': async (client, address) => {
|
||||
// const client = new Client()
|
||||
const header = Object.assign({}, REQUEST_FIXTURES.header, {
|
||||
transactionHash:
|
||||
'325EACC5271322539EEEC2D6A5292471EF1B3E72AE7180533EFC3B8F0AD435C9'
|
||||
})
|
||||
header.rawTransactions = JSON.stringify(REQUEST_FIXTURES.transactions)
|
||||
assert.throws(() => client.computeLedgerHash(header))
|
||||
}
|
||||
}
|
||||
29
test/client/constructor/index.ts
Normal file
29
test/client/constructor/index.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import assert from 'assert-diff'
|
||||
import {TestSuite} from '../../utils'
|
||||
import {Client} from 'xrpl-local'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'Client - implicit server port': () => {
|
||||
new Client({server: 'wss://s1.ripple.com'})
|
||||
},
|
||||
|
||||
'Client invalid options': () => {
|
||||
// @ts-ignore - This is intentionally invalid
|
||||
assert.throws(() => new Client({invalid: true}))
|
||||
},
|
||||
|
||||
'Client valid options': () => {
|
||||
const client = new Client({server: 'wss://s:1'})
|
||||
const privateConnectionUrl = (client.connection as any)._url
|
||||
assert.deepEqual(privateConnectionUrl, 'wss://s:1')
|
||||
},
|
||||
|
||||
'Client invalid server uri': () => {
|
||||
assert.throws(() => new Client({server: 'wss//s:1'}))
|
||||
}
|
||||
}
|
||||
16
test/client/deriveAddress/index.ts
Normal file
16
test/client/deriveAddress/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import assert from 'assert-diff'
|
||||
import {TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'returns address for public key': async (client, address) => {
|
||||
var address = client.deriveAddress(
|
||||
'035332FBA71D705BD5D97014A833BE2BBB25BEFCD3506198E14AFEA241B98C2D06'
|
||||
)
|
||||
assert.equal(address, 'rLczgQHxPhWtjkaQqn3Q6UM8AbRbbRvs5K')
|
||||
}
|
||||
}
|
||||
39
test/client/deriveKeypair/index.ts
Normal file
39
test/client/deriveKeypair/index.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import assert from 'assert-diff'
|
||||
import {TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'returns keypair for secret': async (client, address) => {
|
||||
var keypair = client.deriveKeypair('snsakdSrZSLkYpCXxfRkS4Sh96PMK')
|
||||
assert.equal(
|
||||
keypair.privateKey,
|
||||
'008850736302221AFD59FF9CA1A29D4975F491D726249302EE48A3078A8934D335'
|
||||
)
|
||||
assert.equal(
|
||||
keypair.publicKey,
|
||||
'035332FBA71D705BD5D97014A833BE2BBB25BEFCD3506198E14AFEA241B98C2D06'
|
||||
)
|
||||
},
|
||||
|
||||
'returns keypair for ed25519 secret': async (client, address) => {
|
||||
var keypair = client.deriveKeypair('sEdV9eHWbibBnTj7b1H5kHfPfv7gudx')
|
||||
assert.equal(
|
||||
keypair.privateKey,
|
||||
'ED5C2EF6C2E3200DFA6B72F47935C7F64D35453646EA34919192538F458C7BC30F'
|
||||
)
|
||||
assert.equal(
|
||||
keypair.publicKey,
|
||||
'ED0805EC4E728DB87C0CA6C420751F296C57A5F42D02E9E6150CE60694A44593E5'
|
||||
)
|
||||
},
|
||||
|
||||
'throws with an invalid secret': async (client, address) => {
|
||||
assert.throws(() => {
|
||||
client.deriveKeypair('...')
|
||||
}, /^Error: Non-base58 character$/)
|
||||
}
|
||||
}
|
||||
31
test/client/deriveXAddress/index.ts
Normal file
31
test/client/deriveXAddress/index.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import assert from 'assert-diff'
|
||||
import {TestSuite} from '../../utils'
|
||||
import {Client} from '../../../src'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'returns address for public key': async (client, address) => {
|
||||
assert.equal(
|
||||
Client.deriveXAddress({
|
||||
publicKey:
|
||||
'035332FBA71D705BD5D97014A833BE2BBB25BEFCD3506198E14AFEA241B98C2D06',
|
||||
tag: false,
|
||||
test: false
|
||||
}),
|
||||
'XVZVpQj8YSVpNyiwXYSqvQoQqgBttTxAZwMcuJd4xteQHyt'
|
||||
)
|
||||
assert.equal(
|
||||
Client.deriveXAddress({
|
||||
publicKey:
|
||||
'035332FBA71D705BD5D97014A833BE2BBB25BEFCD3506198E14AFEA241B98C2D06',
|
||||
tag: false,
|
||||
test: true
|
||||
}),
|
||||
'TVVrSWtmQQssgVcmoMBcFQZKKf56QscyWLKnUyiuZW8ALU4'
|
||||
)
|
||||
}
|
||||
}
|
||||
119
test/client/dropsToXrp/index.ts
Normal file
119
test/client/dropsToXrp/index.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import assert from 'assert-diff'
|
||||
import {TestSuite} from '../../utils'
|
||||
import BigNumber from 'bignumber.js'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'works with a typical amount': async (client) => {
|
||||
const xrp = client.dropsToXrp('2000000')
|
||||
assert.strictEqual(xrp, '2', '2 million drops equals 2 XRP')
|
||||
},
|
||||
'works with fractions': async (client) => {
|
||||
let xrp = client.dropsToXrp('3456789')
|
||||
assert.strictEqual(xrp, '3.456789', '3,456,789 drops equals 3.456789 XRP')
|
||||
|
||||
xrp = client.dropsToXrp('3400000')
|
||||
assert.strictEqual(xrp, '3.4', '3,400,000 drops equals 3.4 XRP')
|
||||
|
||||
xrp = client.dropsToXrp('1')
|
||||
assert.strictEqual(xrp, '0.000001', '1 drop equals 0.000001 XRP')
|
||||
|
||||
xrp = client.dropsToXrp('1.0')
|
||||
assert.strictEqual(xrp, '0.000001', '1.0 drops equals 0.000001 XRP')
|
||||
|
||||
xrp = client.dropsToXrp('1.00')
|
||||
assert.strictEqual(xrp, '0.000001', '1.00 drops equals 0.000001 XRP')
|
||||
},
|
||||
'works with zero': async (client) => {
|
||||
let xrp = client.dropsToXrp('0')
|
||||
assert.strictEqual(xrp, '0', '0 drops equals 0 XRP')
|
||||
|
||||
// negative zero is equivalent to zero
|
||||
xrp = client.dropsToXrp('-0')
|
||||
assert.strictEqual(xrp, '0', '-0 drops equals 0 XRP')
|
||||
|
||||
xrp = client.dropsToXrp('0.00')
|
||||
assert.strictEqual(xrp, '0', '0.00 drops equals 0 XRP')
|
||||
|
||||
xrp = client.dropsToXrp('000000000')
|
||||
assert.strictEqual(xrp, '0', '000000000 drops equals 0 XRP')
|
||||
},
|
||||
'works with a negative value': async (client) => {
|
||||
const xrp = client.dropsToXrp('-2000000')
|
||||
assert.strictEqual(xrp, '-2', '-2 million drops equals -2 XRP')
|
||||
},
|
||||
'works with a value ending with a decimal point': async (client) => {
|
||||
let xrp = client.dropsToXrp('2000000.')
|
||||
assert.strictEqual(xrp, '2', '2000000. drops equals 2 XRP')
|
||||
|
||||
xrp = client.dropsToXrp('-2000000.')
|
||||
assert.strictEqual(xrp, '-2', '-2000000. drops equals -2 XRP')
|
||||
},
|
||||
'works with BigNumber objects': async (client) => {
|
||||
let xrp = client.dropsToXrp(new BigNumber(2000000))
|
||||
assert.strictEqual(xrp, '2', '(BigNumber) 2 million drops equals 2 XRP')
|
||||
|
||||
xrp = client.dropsToXrp(new BigNumber(-2000000))
|
||||
assert.strictEqual(xrp, '-2', '(BigNumber) -2 million drops equals -2 XRP')
|
||||
|
||||
xrp = client.dropsToXrp(new BigNumber(2345678))
|
||||
assert.strictEqual(
|
||||
xrp,
|
||||
'2.345678',
|
||||
'(BigNumber) 2,345,678 drops equals 2.345678 XRP'
|
||||
)
|
||||
|
||||
xrp = client.dropsToXrp(new BigNumber(-2345678))
|
||||
assert.strictEqual(
|
||||
xrp,
|
||||
'-2.345678',
|
||||
'(BigNumber) -2,345,678 drops equals -2.345678 XRP'
|
||||
)
|
||||
},
|
||||
'works with a number': async (client) => {
|
||||
// This is not recommended. Use strings or BigNumber objects to avoid precision errors.
|
||||
let xrp = client.dropsToXrp(2000000)
|
||||
assert.strictEqual(xrp, '2', '(number) 2 million drops equals 2 XRP')
|
||||
xrp = client.dropsToXrp(-2000000)
|
||||
assert.strictEqual(xrp, '-2', '(number) -2 million drops equals -2 XRP')
|
||||
},
|
||||
'throws with an amount with too many decimal places': async (client) => {
|
||||
assert.throws(() => {
|
||||
client.dropsToXrp('1.2')
|
||||
}, /has too many decimal places/)
|
||||
|
||||
assert.throws(() => {
|
||||
client.dropsToXrp('0.10')
|
||||
}, /has too many decimal places/)
|
||||
},
|
||||
'throws with an invalid value': async (client) => {
|
||||
assert.throws(() => {
|
||||
client.dropsToXrp('FOO')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
client.dropsToXrp('1e-7')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
client.dropsToXrp('2,0')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
client.dropsToXrp('.')
|
||||
}, /dropsToXrp: invalid value '\.', should be a BigNumber or string-encoded number\./)
|
||||
},
|
||||
'throws with an amount more than one decimal point': async (client) => {
|
||||
assert.throws(() => {
|
||||
client.dropsToXrp('1.0.0')
|
||||
}, /dropsToXrp: invalid value '1\.0\.0'/)
|
||||
|
||||
assert.throws(() => {
|
||||
client.dropsToXrp('...')
|
||||
}, /dropsToXrp: invalid value '\.\.\.'/)
|
||||
}
|
||||
}
|
||||
19
test/client/errors/index.ts
Normal file
19
test/client/errors/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import assert from 'assert-diff'
|
||||
import {TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'RippleError with data': async (client, address) => {
|
||||
const error = new client.errors.RippleError('_message_', '_data_')
|
||||
assert.strictEqual(error.toString(), "[RippleError(_message_, '_data_')]")
|
||||
},
|
||||
|
||||
'NotFoundError default message': async (client, address) => {
|
||||
const error = new client.errors.NotFoundError()
|
||||
assert.strictEqual(error.toString(), '[NotFoundError(Not found)]')
|
||||
}
|
||||
}
|
||||
386
test/client/formatBidsAndAsks/index.ts
Normal file
386
test/client/formatBidsAndAsks/index.ts
Normal file
@@ -0,0 +1,386 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import assert from 'assert-diff'
|
||||
import {Client} from 'xrpl-local'
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {TestSuite} from '../../utils'
|
||||
|
||||
function checkSortingOfOrders(orders) {
|
||||
let previousRate = '0'
|
||||
for (var i = 0; i < orders.length; i++) {
|
||||
const order = orders[i]
|
||||
let rate
|
||||
|
||||
// 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,
|
||||
// the quality can differ significantly. However, the offer stays in the
|
||||
// order book where it was originally placed. It would be more consistent
|
||||
// to check the quality from the offer book, but for the test data set,
|
||||
// this calculation holds.
|
||||
|
||||
if (order.specification.direction === 'buy') {
|
||||
rate = new BigNumber(order.specification.quantity.value)
|
||||
.dividedBy(order.specification.totalPrice.value)
|
||||
.toString()
|
||||
} else {
|
||||
rate = new BigNumber(order.specification.totalPrice.value)
|
||||
.dividedBy(order.specification.quantity.value)
|
||||
.toString()
|
||||
}
|
||||
assert(
|
||||
new BigNumber(rate).isGreaterThanOrEqualTo(previousRate),
|
||||
'Rates must be sorted from least to greatest: ' +
|
||||
rate +
|
||||
' should be >= ' +
|
||||
previousRate
|
||||
)
|
||||
previousRate = rate
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'normal': async (client, address) => {
|
||||
const orderbookInfo = {
|
||||
base: {
|
||||
currency: 'USD',
|
||||
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
|
||||
},
|
||||
counter: {
|
||||
currency: 'BTC',
|
||||
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
client.request('book_offers', {
|
||||
taker_gets: Client.renameCounterpartyToIssuer(orderbookInfo.base),
|
||||
taker_pays: Client.renameCounterpartyToIssuer(orderbookInfo.counter),
|
||||
ledger_index: 'validated',
|
||||
limit: 20,
|
||||
taker: address
|
||||
}),
|
||||
client.request('book_offers', {
|
||||
taker_gets: Client.renameCounterpartyToIssuer(orderbookInfo.counter),
|
||||
taker_pays: Client.renameCounterpartyToIssuer(orderbookInfo.base),
|
||||
ledger_index: 'validated',
|
||||
limit: 20,
|
||||
taker: address
|
||||
})
|
||||
]).then(([directOfferResults, reverseOfferResults]) => {
|
||||
const directOffers = (directOfferResults
|
||||
? directOfferResults.offers
|
||||
: []
|
||||
).reduce((acc, res) => acc.concat(res), [])
|
||||
const reverseOffers = (reverseOfferResults
|
||||
? reverseOfferResults.offers
|
||||
: []
|
||||
).reduce((acc, res) => acc.concat(res), [])
|
||||
const orderbook = Client.formatBidsAndAsks(orderbookInfo, [
|
||||
...directOffers,
|
||||
...reverseOffers
|
||||
])
|
||||
assert.deepEqual(orderbook, responses.getOrderbook.normal)
|
||||
})
|
||||
},
|
||||
|
||||
'with XRP': async (client, address) => {
|
||||
const orderbookInfo = {
|
||||
base: {
|
||||
currency: 'USD',
|
||||
counterparty: 'rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw'
|
||||
},
|
||||
counter: {
|
||||
currency: 'XRP'
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
client.request('book_offers', {
|
||||
taker_gets: Client.renameCounterpartyToIssuer(orderbookInfo.base),
|
||||
taker_pays: Client.renameCounterpartyToIssuer(orderbookInfo.counter),
|
||||
ledger_index: 'validated',
|
||||
limit: 20,
|
||||
taker: address
|
||||
}),
|
||||
client.request('book_offers', {
|
||||
taker_gets: Client.renameCounterpartyToIssuer(orderbookInfo.counter),
|
||||
taker_pays: Client.renameCounterpartyToIssuer(orderbookInfo.base),
|
||||
ledger_index: 'validated',
|
||||
limit: 20,
|
||||
taker: address
|
||||
})
|
||||
]).then(([directOfferResults, reverseOfferResults]) => {
|
||||
const directOffers = (directOfferResults
|
||||
? directOfferResults.offers
|
||||
: []
|
||||
).reduce((acc, res) => acc.concat(res), [])
|
||||
const reverseOffers = (reverseOfferResults
|
||||
? reverseOfferResults.offers
|
||||
: []
|
||||
).reduce((acc, res) => acc.concat(res), [])
|
||||
const orderbook = Client.formatBidsAndAsks(orderbookInfo, [
|
||||
...directOffers,
|
||||
...reverseOffers
|
||||
])
|
||||
assert.deepEqual(orderbook, responses.getOrderbook.withXRP)
|
||||
})
|
||||
},
|
||||
|
||||
'sample XRP/JPY book has orders sorted correctly': async (client, address) => {
|
||||
const orderbookInfo = {
|
||||
base: {
|
||||
// the first currency in pair
|
||||
currency: 'XRP'
|
||||
},
|
||||
counter: {
|
||||
currency: 'JPY',
|
||||
counterparty: 'rB3gZey7VWHYRqJHLoHDEJXJ2pEPNieKiS'
|
||||
}
|
||||
}
|
||||
|
||||
const myAddress = 'rE9qNjzJXpiUbVomdv7R4xhrXVeH2oVmGR'
|
||||
|
||||
await Promise.all([
|
||||
client.request('book_offers', {
|
||||
taker_gets: Client.renameCounterpartyToIssuer(orderbookInfo.base),
|
||||
taker_pays: Client.renameCounterpartyToIssuer(orderbookInfo.counter),
|
||||
ledger_index: 'validated',
|
||||
limit: 400, // must match `test/fixtures/rippled/requests/1-taker_gets-XRP-taker_pays-JPY.json`
|
||||
taker: myAddress
|
||||
}),
|
||||
client.request('book_offers', {
|
||||
taker_gets: Client.renameCounterpartyToIssuer(orderbookInfo.counter),
|
||||
taker_pays: Client.renameCounterpartyToIssuer(orderbookInfo.base),
|
||||
ledger_index: 'validated',
|
||||
limit: 400, // must match `test/fixtures/rippled/requests/2-taker_gets-JPY-taker_pays-XRP.json`
|
||||
taker: myAddress
|
||||
})
|
||||
]).then(([directOfferResults, reverseOfferResults]) => {
|
||||
const directOffers = (directOfferResults
|
||||
? directOfferResults.offers
|
||||
: []
|
||||
).reduce((acc, res) => acc.concat(res), [])
|
||||
const reverseOffers = (reverseOfferResults
|
||||
? reverseOfferResults.offers
|
||||
: []
|
||||
).reduce((acc, res) => acc.concat(res), [])
|
||||
const orderbook = Client.formatBidsAndAsks(orderbookInfo, [
|
||||
...directOffers,
|
||||
...reverseOffers
|
||||
])
|
||||
assert.deepStrictEqual([], orderbook.bids)
|
||||
return checkSortingOfOrders(orderbook.asks)
|
||||
})
|
||||
},
|
||||
|
||||
'sample USD/XRP book has orders sorted correctly': async (client, address) => {
|
||||
const orderbookInfo = {
|
||||
counter: {currency: 'XRP'},
|
||||
base: {
|
||||
currency: 'USD',
|
||||
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
|
||||
}
|
||||
}
|
||||
|
||||
const myAddress = 'rE9qNjzJXpiUbVomdv7R4xhrXVeH2oVmGR'
|
||||
|
||||
await Promise.all([
|
||||
client.request('book_offers', {
|
||||
taker_gets: Client.renameCounterpartyToIssuer(orderbookInfo.base),
|
||||
taker_pays: Client.renameCounterpartyToIssuer(orderbookInfo.counter),
|
||||
ledger_index: 'validated',
|
||||
limit: 400, // must match `test/fixtures/rippled/requests/1-taker_gets-XRP-taker_pays-JPY.json`
|
||||
taker: myAddress
|
||||
}),
|
||||
client.request('book_offers', {
|
||||
taker_gets: Client.renameCounterpartyToIssuer(orderbookInfo.counter),
|
||||
taker_pays: Client.renameCounterpartyToIssuer(orderbookInfo.base),
|
||||
ledger_index: 'validated',
|
||||
limit: 400, // must match `test/fixtures/rippled/requests/2-taker_gets-JPY-taker_pays-XRP.json`
|
||||
taker: myAddress
|
||||
})
|
||||
]).then(([directOfferResults, reverseOfferResults]) => {
|
||||
const directOffers = (directOfferResults
|
||||
? directOfferResults.offers
|
||||
: []
|
||||
).reduce((acc, res) => acc.concat(res), [])
|
||||
const reverseOffers = (reverseOfferResults
|
||||
? reverseOfferResults.offers
|
||||
: []
|
||||
).reduce((acc, res) => acc.concat(res), [])
|
||||
const orderbook = Client.formatBidsAndAsks(orderbookInfo, [
|
||||
...directOffers,
|
||||
...reverseOffers
|
||||
])
|
||||
return (
|
||||
checkSortingOfOrders(orderbook.bids) &&
|
||||
checkSortingOfOrders(orderbook.asks)
|
||||
)
|
||||
})
|
||||
},
|
||||
|
||||
'sorted so that best deals come first': async (client, address) => {
|
||||
const orderbookInfo = {
|
||||
base: {
|
||||
currency: 'USD',
|
||||
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
|
||||
},
|
||||
counter: {
|
||||
currency: 'BTC',
|
||||
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
client.request('book_offers', {
|
||||
taker_gets: Client.renameCounterpartyToIssuer(orderbookInfo.base),
|
||||
taker_pays: Client.renameCounterpartyToIssuer(orderbookInfo.counter),
|
||||
ledger_index: 'validated',
|
||||
limit: 20,
|
||||
taker: address
|
||||
}),
|
||||
client.request('book_offers', {
|
||||
taker_gets: Client.renameCounterpartyToIssuer(orderbookInfo.counter),
|
||||
taker_pays: Client.renameCounterpartyToIssuer(orderbookInfo.base),
|
||||
ledger_index: 'validated',
|
||||
limit: 20,
|
||||
taker: address
|
||||
})
|
||||
]).then(([directOfferResults, reverseOfferResults]) => {
|
||||
const directOffers = (directOfferResults
|
||||
? directOfferResults.offers
|
||||
: []
|
||||
).reduce((acc, res) => acc.concat(res), [])
|
||||
const reverseOffers = (reverseOfferResults
|
||||
? reverseOfferResults.offers
|
||||
: []
|
||||
).reduce((acc, res) => acc.concat(res), [])
|
||||
const orderbook = Client.formatBidsAndAsks(orderbookInfo, [
|
||||
...directOffers,
|
||||
...reverseOffers
|
||||
])
|
||||
|
||||
const bidRates = orderbook.bids.map(
|
||||
(bid) => bid.properties.makerExchangeRate
|
||||
)
|
||||
const askRates = orderbook.asks.map(
|
||||
(ask) => ask.properties.makerExchangeRate
|
||||
)
|
||||
// makerExchangeRate = quality = takerPays.value/takerGets.value
|
||||
// so the best deal for the taker is the lowest makerExchangeRate
|
||||
// bids and asks should be sorted so that the best deals come first
|
||||
assert.deepEqual(bidRates.map((x) => Number(x)).sort(), bidRates)
|
||||
assert.deepEqual(askRates.map((x) => Number(x)).sort(), askRates)
|
||||
})
|
||||
},
|
||||
|
||||
'currency & counterparty are correct': async (client, address) => {
|
||||
const orderbookInfo = {
|
||||
base: {
|
||||
currency: 'USD',
|
||||
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
|
||||
},
|
||||
counter: {
|
||||
currency: 'BTC',
|
||||
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
client.request('book_offers', {
|
||||
taker_gets: Client.renameCounterpartyToIssuer(orderbookInfo.base),
|
||||
taker_pays: Client.renameCounterpartyToIssuer(orderbookInfo.counter),
|
||||
ledger_index: 'validated',
|
||||
limit: 20,
|
||||
taker: address
|
||||
}),
|
||||
client.request('book_offers', {
|
||||
taker_gets: Client.renameCounterpartyToIssuer(orderbookInfo.counter),
|
||||
taker_pays: Client.renameCounterpartyToIssuer(orderbookInfo.base),
|
||||
ledger_index: 'validated',
|
||||
limit: 20,
|
||||
taker: address
|
||||
})
|
||||
]).then(([directOfferResults, reverseOfferResults]) => {
|
||||
const directOffers = (directOfferResults
|
||||
? directOfferResults.offers
|
||||
: []
|
||||
).reduce((acc, res) => acc.concat(res), [])
|
||||
const reverseOffers = (reverseOfferResults
|
||||
? reverseOfferResults.offers
|
||||
: []
|
||||
).reduce((acc, res) => acc.concat(res), [])
|
||||
const orderbook = Client.formatBidsAndAsks(orderbookInfo, [
|
||||
...directOffers,
|
||||
...reverseOffers
|
||||
])
|
||||
|
||||
const orders = [...orderbook.bids, ...orderbook.asks]
|
||||
orders.forEach((order) => {
|
||||
const quantity = order.specification.quantity
|
||||
const totalPrice = order.specification.totalPrice
|
||||
const {base, counter} = requests.getOrderbook.normal
|
||||
assert.strictEqual(quantity.currency, base.currency)
|
||||
assert.strictEqual(quantity.counterparty, base.counterparty)
|
||||
assert.strictEqual(totalPrice.currency, counter.currency)
|
||||
assert.strictEqual(totalPrice.counterparty, counter.counterparty)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
'direction is correct for bids and asks': async (client, address) => {
|
||||
const orderbookInfo = {
|
||||
base: {
|
||||
currency: 'USD',
|
||||
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
|
||||
},
|
||||
counter: {
|
||||
currency: 'BTC',
|
||||
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
client.request('book_offers', {
|
||||
taker_gets: Client.renameCounterpartyToIssuer(orderbookInfo.base),
|
||||
taker_pays: Client.renameCounterpartyToIssuer(orderbookInfo.counter),
|
||||
ledger_index: 'validated',
|
||||
limit: 20,
|
||||
taker: address
|
||||
}),
|
||||
client.request('book_offers', {
|
||||
taker_gets: Client.renameCounterpartyToIssuer(orderbookInfo.counter),
|
||||
taker_pays: Client.renameCounterpartyToIssuer(orderbookInfo.base),
|
||||
ledger_index: 'validated',
|
||||
limit: 20,
|
||||
taker: address
|
||||
})
|
||||
]).then(([directOfferResults, reverseOfferResults]) => {
|
||||
const directOffers = (directOfferResults
|
||||
? directOfferResults.offers
|
||||
: []
|
||||
).reduce((acc, res) => acc.concat(res), [])
|
||||
const reverseOffers = (reverseOfferResults
|
||||
? reverseOfferResults.offers
|
||||
: []
|
||||
).reduce((acc, res) => acc.concat(res), [])
|
||||
const orderbook = Client.formatBidsAndAsks(orderbookInfo, [
|
||||
...directOffers,
|
||||
...reverseOffers
|
||||
])
|
||||
|
||||
assert(
|
||||
orderbook.bids.every((bid) => bid.specification.direction === 'buy')
|
||||
)
|
||||
assert(
|
||||
orderbook.asks.every((ask) => ask.specification.direction === 'sell')
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
251
test/client/generateAddress/index.ts
Normal file
251
test/client/generateAddress/index.ts
Normal file
@@ -0,0 +1,251 @@
|
||||
import assert from 'assert-diff'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {TestSuite} from '../../utils'
|
||||
import {GenerateAddressOptions} from '../../../src/offline/generate-address'
|
||||
import ECDSA from '../../../src/common/ecdsa'
|
||||
const {generateAddress: RESPONSE_FIXTURES} = responses
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'generateAddress': async (client) => {
|
||||
// GIVEN entropy of all zeros
|
||||
function random() {
|
||||
return new Array(16).fill(0)
|
||||
}
|
||||
|
||||
assert.deepEqual(
|
||||
// WHEN generating an address
|
||||
client.generateAddress({entropy: random()}),
|
||||
|
||||
// THEN we get the expected return value
|
||||
RESPONSE_FIXTURES
|
||||
)
|
||||
},
|
||||
|
||||
'generateAddress invalid entropy': async (client) => {
|
||||
assert.throws(() => {
|
||||
// GIVEN entropy of 1 byte
|
||||
function random() {
|
||||
return new Array(1).fill(0)
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
client.generateAddress({entropy: random()})
|
||||
|
||||
// THEN an UnexpectedError is thrown
|
||||
// because 16 bytes of entropy are required
|
||||
}, client.errors.UnexpectedError)
|
||||
},
|
||||
|
||||
'generateAddress with no options object': async (client) => {
|
||||
// GIVEN no options
|
||||
|
||||
// WHEN generating an address
|
||||
const account = client.generateAddress()
|
||||
|
||||
// THEN we get an object with an address starting with 'r' and a secret starting with 's'
|
||||
assert(account.address.startsWith('r'), 'Address must start with `r`')
|
||||
assert(account.secret.startsWith('s'), 'Secret must start with `s`')
|
||||
},
|
||||
|
||||
'generateAddress with empty options object': async (client) => {
|
||||
// GIVEN an empty options object
|
||||
const options = {}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = client.generateAddress(options)
|
||||
|
||||
// THEN we get an object with an address starting with 'r' and a secret starting with 's'
|
||||
assert(account.address.startsWith('r'), 'Address must start with `r`')
|
||||
assert(account.secret.startsWith('s'), 'Secret must start with `s`')
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ecdsa-secp256k1`': async (client) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1'
|
||||
const options: GenerateAddressOptions = {algorithm: ECDSA.secp256k1}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = client.generateAddress(options)
|
||||
|
||||
// THEN we get an object with an address starting with 'r' and a secret starting with 's' (not 'sEd')
|
||||
assert(account.address.startsWith('r'), 'Address must start with `r`')
|
||||
assert.deepEqual(
|
||||
account.secret.slice(0, 1),
|
||||
's',
|
||||
`Secret ${account.secret} must start with 's'`
|
||||
)
|
||||
assert.notStrictEqual(
|
||||
account.secret.slice(0, 3),
|
||||
'sEd',
|
||||
`secp256k1 secret ${account.secret} must not start with 'sEd'`
|
||||
)
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ed25519`': async (client) => {
|
||||
// GIVEN we want to use 'ed25519'
|
||||
const options: GenerateAddressOptions = {algorithm: ECDSA.ed25519}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = client.generateAddress(options)
|
||||
|
||||
// THEN we get an object with an address starting with 'r' and a secret starting with 'sEd'
|
||||
assert(account.address.startsWith('r'), 'Address must start with `r`')
|
||||
assert.deepEqual(
|
||||
account.secret.slice(0, 3),
|
||||
'sEd',
|
||||
`Ed25519 secret ${account.secret} must start with 'sEd'`
|
||||
)
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ecdsa-secp256k1` and given entropy': async (
|
||||
client
|
||||
) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options: GenerateAddressOptions = {
|
||||
algorithm: ECDSA.secp256k1,
|
||||
entropy: new Array(16).fill(0)
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = client.generateAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, responses.generateAddress)
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ed25519` and given entropy': async (client) => {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options: GenerateAddressOptions = {
|
||||
algorithm: ECDSA.ed25519,
|
||||
entropy: new Array(16).fill(0)
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = client.generateAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
xAddress: 'X7xq1YJ4xmLSGGLhuakFQB9CebWYthQkgsvFC4LGFH871HB',
|
||||
|
||||
classicAddress: 'r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7',
|
||||
address: 'r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7',
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE'
|
||||
})
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ecdsa-secp256k1` and given entropy; include classic address': async (
|
||||
client
|
||||
) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options: GenerateAddressOptions = {
|
||||
algorithm: ECDSA.secp256k1,
|
||||
entropy: new Array(16).fill(0),
|
||||
includeClassicAddress: true
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = client.generateAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, responses.generateAddress)
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ed25519` and given entropy; include classic address': async (
|
||||
client
|
||||
) => {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options: GenerateAddressOptions = {
|
||||
algorithm: ECDSA.ed25519,
|
||||
entropy: new Array(16).fill(0),
|
||||
includeClassicAddress: true
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = client.generateAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
xAddress: 'X7xq1YJ4xmLSGGLhuakFQB9CebWYthQkgsvFC4LGFH871HB',
|
||||
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE',
|
||||
classicAddress: 'r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7',
|
||||
address: 'r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7'
|
||||
})
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ecdsa-secp256k1` and given entropy; include classic address; for test network use': async (
|
||||
client
|
||||
) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options: GenerateAddressOptions = {
|
||||
algorithm: ECDSA.secp256k1,
|
||||
entropy: new Array(16).fill(0),
|
||||
includeClassicAddress: true,
|
||||
test: true
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = client.generateAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
const response = Object.assign({}, responses.generateAddress, {
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
xAddress: 'TVG3TcCD58BD6MZqsNuTihdrhZwR8SzvYS8U87zvHsAcNw4'
|
||||
})
|
||||
assert.deepEqual(account, response)
|
||||
},
|
||||
|
||||
'generateAddress with algorithm `ed25519` and given entropy; include classic address; for test network use': async (
|
||||
client
|
||||
) => {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options: GenerateAddressOptions = {
|
||||
algorithm: ECDSA.ed25519,
|
||||
entropy: new Array(16).fill(0),
|
||||
includeClassicAddress: true,
|
||||
test: true
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = client.generateAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
xAddress: 'T7t4HeTMF5tT68agwuVbJwu23ssMPeh8dDtGysZoQiij1oo',
|
||||
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE',
|
||||
classicAddress: 'r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7',
|
||||
address: 'r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7'
|
||||
})
|
||||
},
|
||||
|
||||
'generateAddress for test network use': async (client) => {
|
||||
// GIVEN we want an address for test network use
|
||||
const options: GenerateAddressOptions = {test: true}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = client.generateAddress(options)
|
||||
|
||||
// THEN we get an object with xAddress starting with 'T' and a secret starting with 's'
|
||||
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
assert.deepEqual(
|
||||
account.xAddress.slice(0, 1),
|
||||
'T',
|
||||
'Test addresses start with T'
|
||||
)
|
||||
|
||||
assert.deepEqual(
|
||||
account.secret.slice(0, 1),
|
||||
's',
|
||||
`Secret ${account.secret} must start with 's'`
|
||||
)
|
||||
}
|
||||
}
|
||||
252
test/client/generateXAddress/index.ts
Normal file
252
test/client/generateXAddress/index.ts
Normal file
@@ -0,0 +1,252 @@
|
||||
import assert from 'assert-diff'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {TestSuite} from '../../utils'
|
||||
import ECDSA from '../../../src/common/ecdsa'
|
||||
import {GenerateAddressOptions} from '../../../src/offline/generate-address'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'generateXAddress': async (client) => {
|
||||
// GIVEN entropy of all zeros
|
||||
function random() {
|
||||
return new Array(16).fill(0)
|
||||
}
|
||||
|
||||
assert.deepEqual(
|
||||
// WHEN generating an X-address
|
||||
client.generateXAddress({entropy: random()}),
|
||||
|
||||
// THEN we get the expected return value
|
||||
responses.generateXAddress
|
||||
)
|
||||
},
|
||||
|
||||
'generateXAddress invalid entropy': async (client) => {
|
||||
assert.throws(() => {
|
||||
// GIVEN entropy of 1 byte
|
||||
function random() {
|
||||
return new Array(1).fill(0)
|
||||
}
|
||||
|
||||
// WHEN generating an X-address
|
||||
client.generateXAddress({entropy: random()})
|
||||
|
||||
// THEN an UnexpectedError is thrown
|
||||
// because 16 bytes of entropy are required
|
||||
}, client.errors.UnexpectedError)
|
||||
},
|
||||
|
||||
'generateXAddress with no options object': async (client) => {
|
||||
// GIVEN no options
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = client.generateXAddress()
|
||||
|
||||
// THEN we get an object with an xAddress starting with 'X' and a secret starting with 's'
|
||||
assert(
|
||||
account.xAddress.startsWith('X'),
|
||||
'By default X-addresses start with X'
|
||||
)
|
||||
assert(account.secret.startsWith('s'), 'Secrets start with s')
|
||||
},
|
||||
|
||||
'generateXAddress with empty options object': async (client) => {
|
||||
// GIVEN an empty options object
|
||||
const options = {}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = client.generateXAddress(options)
|
||||
|
||||
// THEN we get an object with an xAddress starting with 'X' and a secret starting with 's'
|
||||
assert(
|
||||
account.xAddress.startsWith('X'),
|
||||
'By default X-addresses start with X'
|
||||
)
|
||||
assert(account.secret.startsWith('s'), 'Secrets start with s')
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ecdsa-secp256k1`': async (client) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1'
|
||||
const options: GenerateAddressOptions = {algorithm: ECDSA.secp256k1}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = client.generateXAddress(options)
|
||||
|
||||
// THEN we get an object with an xAddress starting with 'X' and a secret starting with 's'
|
||||
assert(
|
||||
account.xAddress.startsWith('X'),
|
||||
'By default X-addresses start with X'
|
||||
)
|
||||
assert.deepEqual(
|
||||
account.secret.slice(0, 1),
|
||||
's',
|
||||
`Secret ${account.secret} must start with 's'`
|
||||
)
|
||||
assert.notStrictEqual(
|
||||
account.secret.slice(0, 3),
|
||||
'sEd',
|
||||
`secp256k1 secret ${account.secret} must not start with 'sEd'`
|
||||
)
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ed25519`': async (client) => {
|
||||
// GIVEN we want to use 'ed25519'
|
||||
const options: GenerateAddressOptions = {algorithm: ECDSA.ed25519}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = client.generateXAddress(options)
|
||||
|
||||
// THEN we get an object with an xAddress starting with 'X' and a secret starting with 'sEd'
|
||||
assert(
|
||||
account.xAddress.startsWith('X'),
|
||||
'By default X-addresses start with X'
|
||||
)
|
||||
assert.deepEqual(
|
||||
account.secret.slice(0, 3),
|
||||
'sEd',
|
||||
`Ed25519 secret ${account.secret} must start with 'sEd'`
|
||||
)
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ecdsa-secp256k1` and given entropy': async (
|
||||
client
|
||||
) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options: GenerateAddressOptions = {
|
||||
algorithm: ECDSA.secp256k1,
|
||||
entropy: new Array(16).fill(0)
|
||||
}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = client.generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, responses.generateXAddress)
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ed25519` and given entropy': async (
|
||||
client
|
||||
) => {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options: GenerateAddressOptions = {
|
||||
algorithm: ECDSA.ed25519,
|
||||
entropy: new Array(16).fill(0)
|
||||
}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = client.generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
xAddress: 'X7xq1YJ4xmLSGGLhuakFQB9CebWYthQkgsvFC4LGFH871HB',
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE'
|
||||
})
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ecdsa-secp256k1` and given entropy; include classic address': async (
|
||||
client
|
||||
) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options: GenerateAddressOptions = {
|
||||
algorithm: ECDSA.secp256k1,
|
||||
entropy: new Array(16).fill(0),
|
||||
includeClassicAddress: true
|
||||
}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = client.generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, responses.generateAddress)
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ed25519` and given entropy; include classic address': async (
|
||||
client
|
||||
) => {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options: GenerateAddressOptions = {
|
||||
algorithm: ECDSA.ed25519,
|
||||
entropy: new Array(16).fill(0),
|
||||
includeClassicAddress: true
|
||||
}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = client.generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
xAddress: 'X7xq1YJ4xmLSGGLhuakFQB9CebWYthQkgsvFC4LGFH871HB',
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE',
|
||||
classicAddress: 'r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7',
|
||||
address: 'r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7'
|
||||
})
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ecdsa-secp256k1` and given entropy; include classic address; for test network use': async (
|
||||
client
|
||||
) => {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options: GenerateAddressOptions = {
|
||||
algorithm: ECDSA.secp256k1,
|
||||
entropy: new Array(16).fill(0),
|
||||
includeClassicAddress: true,
|
||||
test: true
|
||||
}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = client.generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
const response = Object.assign({}, responses.generateAddress, {
|
||||
xAddress: 'TVG3TcCD58BD6MZqsNuTihdrhZwR8SzvYS8U87zvHsAcNw4'
|
||||
})
|
||||
assert.deepEqual(account, response)
|
||||
},
|
||||
|
||||
'generateXAddress with algorithm `ed25519` and given entropy; include classic address; for test network use': async (
|
||||
client
|
||||
) => {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options: GenerateAddressOptions = {
|
||||
algorithm: ECDSA.ed25519,
|
||||
entropy: new Array(16).fill(0),
|
||||
includeClassicAddress: true,
|
||||
test: true
|
||||
}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = client.generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
xAddress: 'T7t4HeTMF5tT68agwuVbJwu23ssMPeh8dDtGysZoQiij1oo',
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE',
|
||||
classicAddress: 'r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7',
|
||||
address: 'r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7'
|
||||
})
|
||||
},
|
||||
|
||||
'generateXAddress for test network use': async (client) => {
|
||||
// GIVEN we want an X-address for test network use
|
||||
const options: GenerateAddressOptions = {test: true}
|
||||
|
||||
// WHEN generating an X-address
|
||||
const account = client.generateXAddress(options)
|
||||
|
||||
// THEN we get an object with xAddress starting with 'T' and a secret starting with 's'
|
||||
assert.deepEqual(
|
||||
account.xAddress.slice(0, 1),
|
||||
'T',
|
||||
'Test X-addresses start with T'
|
||||
)
|
||||
assert.deepEqual(
|
||||
account.secret.slice(0, 1),
|
||||
's',
|
||||
`Secret ${account.secret} must start with 's'`
|
||||
)
|
||||
}
|
||||
}
|
||||
27
test/client/getAccountInfo/index.ts
Normal file
27
test/client/getAccountInfo/index.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertRejects, assertResultMatch, TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'getAccountInfo': async (client, address) => {
|
||||
const result = await client.getAccountInfo(address)
|
||||
assertResultMatch(result, responses.getAccountInfo, 'getAccountInfo')
|
||||
},
|
||||
|
||||
'getAccountInfo - options undefined': async (client, address) => {
|
||||
const result = await client.getAccountInfo(address, undefined)
|
||||
assertResultMatch(result, responses.getAccountInfo, 'getAccountInfo')
|
||||
},
|
||||
|
||||
'getAccountInfo - invalid options': async (client, address) => {
|
||||
await assertRejects(
|
||||
// @ts-ignore - This is intentionally invalid
|
||||
client.getAccountInfo(address, {invalid: 'options'}),
|
||||
client.errors.ValidationError
|
||||
)
|
||||
}
|
||||
}
|
||||
21
test/client/getAccountObjects/index.ts
Normal file
21
test/client/getAccountObjects/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
const {getAccountObjects: RESPONSE_FIXTURES} = responses
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'getAccountObjects': async (client, address) => {
|
||||
const result = await client.getAccountObjects(address)
|
||||
assertResultMatch(result, RESPONSE_FIXTURES, 'AccountObjectsResponse')
|
||||
},
|
||||
|
||||
'getAccountObjects - invalid options': async (client, address) => {
|
||||
// @ts-ignore - This is intentionally invalid
|
||||
const result = await client.getAccountObjects(address, {invalid: 'options'})
|
||||
assertResultMatch(result, RESPONSE_FIXTURES, 'AccountObjectsResponse')
|
||||
}
|
||||
}
|
||||
26
test/client/getBalanceSheet/index.ts
Normal file
26
test/client/getBalanceSheet/index.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import {assertRejects, assertResultMatch, TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'getBalanceSheet': async (client, address) => {
|
||||
await client.getBalanceSheet(address)
|
||||
},
|
||||
|
||||
'getBalanceSheet - invalid options': async (client, address) => {
|
||||
await assertRejects(
|
||||
// @ts-ignore - This is intentionally invalid
|
||||
client.getBalanceSheet(address, {invalid: 'options'}),
|
||||
client.errors.ValidationError
|
||||
)
|
||||
},
|
||||
|
||||
'getBalanceSheet - empty': async (client, address) => {
|
||||
const options = {ledgerVersion: 123456}
|
||||
const result = await client.getBalanceSheet(address, options)
|
||||
assertResultMatch(result, {}, 'getBalanceSheet')
|
||||
}
|
||||
}
|
||||
47
test/client/getBalances/index.ts
Normal file
47
test/client/getBalances/index.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'getBalances': async (client, address) => {
|
||||
const result = await client.getBalances(address)
|
||||
assertResultMatch(result, responses.getBalances, 'getBalances')
|
||||
},
|
||||
|
||||
'getBalances - limit': async (client, address) => {
|
||||
const options = {limit: 3, ledgerVersion: 123456}
|
||||
const expectedResponse = responses.getBalances.slice(0, 3)
|
||||
const result = await client.getBalances(address, options)
|
||||
assertResultMatch(result, expectedResponse, 'getBalances')
|
||||
},
|
||||
|
||||
'getBalances - limit & currency': async (client, address) => {
|
||||
const options = {currency: 'USD', limit: 3}
|
||||
const expectedResponse = responses.getBalances
|
||||
.filter((item) => item.currency === 'USD')
|
||||
.slice(0, 3)
|
||||
const result = await client.getBalances(address, options)
|
||||
assertResultMatch(result, expectedResponse, 'getBalances')
|
||||
},
|
||||
|
||||
'getBalances - limit & currency & issuer': async (client, address) => {
|
||||
const options = {
|
||||
currency: 'USD',
|
||||
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
limit: 3
|
||||
}
|
||||
const expectedResponse = responses.getBalances
|
||||
.filter(
|
||||
(item) =>
|
||||
item.currency === 'USD' &&
|
||||
item.counterparty === 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
|
||||
)
|
||||
.slice(0, 3)
|
||||
const result = await client.getBalances(address, options)
|
||||
assertResultMatch(result, expectedResponse, 'getBalances')
|
||||
}
|
||||
}
|
||||
64
test/client/getFee/index.ts
Normal file
64
test/client/getFee/index.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import assert from 'assert-diff'
|
||||
import {TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'getFee': async (client, address) => {
|
||||
const fee = await client.getFee()
|
||||
assert.strictEqual(fee, '0.000012')
|
||||
},
|
||||
|
||||
'getFee default': async (client, address) => {
|
||||
client._feeCushion = undefined
|
||||
const fee = await client.getFee()
|
||||
assert.strictEqual(fee, '0.000012')
|
||||
},
|
||||
|
||||
'getFee - high load_factor': async (client, address) => {
|
||||
client.connection.request({
|
||||
command: 'config',
|
||||
data: {highLoadFactor: true}
|
||||
})
|
||||
const fee = await client.getFee()
|
||||
assert.strictEqual(fee, '2')
|
||||
},
|
||||
|
||||
'getFee - high load_factor with custom maxFeeXRP': async (client, address) => {
|
||||
// Ensure that overriding with high maxFeeXRP of '51540' causes no errors.
|
||||
// (fee will actually be 51539.607552)
|
||||
client._maxFeeXRP = '51540'
|
||||
client.connection.request({
|
||||
command: 'config',
|
||||
data: {highLoadFactor: true}
|
||||
})
|
||||
const fee = await client.getFee()
|
||||
assert.strictEqual(fee, '51539.607552')
|
||||
},
|
||||
|
||||
'getFee custom cushion': async (client, address) => {
|
||||
client._feeCushion = 1.4
|
||||
const fee = await client.getFee()
|
||||
assert.strictEqual(fee, '0.000014')
|
||||
},
|
||||
|
||||
// This is not recommended since it may result in attempting to pay
|
||||
// less than the base fee. However, this test verifies the existing behavior.
|
||||
'getFee cushion less than 1.0': async (client, address) => {
|
||||
client._feeCushion = 0.9
|
||||
const fee = await client.getFee()
|
||||
assert.strictEqual(fee, '0.000009')
|
||||
},
|
||||
|
||||
'getFee reporting': async (client, address) => {
|
||||
client.connection.request({
|
||||
command: 'config',
|
||||
data: {reporting: true}
|
||||
})
|
||||
const fee = await client.getFee()
|
||||
assert.strictEqual(fee, '0.000012')
|
||||
}
|
||||
}
|
||||
14
test/client/getFeeBase/index.ts
Normal file
14
test/client/getFeeBase/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import assert from 'assert-diff'
|
||||
import {TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'default test': async (client, address) => {
|
||||
const fee = await client.connection.getFeeBase()
|
||||
assert.strictEqual(fee, 10)
|
||||
}
|
||||
}
|
||||
14
test/client/getFeeRef/index.ts
Normal file
14
test/client/getFeeRef/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import assert from 'assert-diff'
|
||||
import {TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'default test': async (client, address) => {
|
||||
const fee = await client.connection.getFeeRef()
|
||||
assert.strictEqual(fee, 10)
|
||||
}
|
||||
}
|
||||
91
test/client/getLedger/index.ts
Normal file
91
test/client/getLedger/index.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import assert from 'assert-diff'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
import responses from '../../fixtures/responses'
|
||||
const {getLedger: RESPONSE_FIXTURES} = responses
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'simple test': async (client) => {
|
||||
const response = await client.getLedger()
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.header, 'getLedger')
|
||||
},
|
||||
'by hash': async (client) => {
|
||||
const response = await client.getLedger({
|
||||
ledgerHash:
|
||||
'15F20E5FA6EA9770BBFFDBD62787400960B04BE32803B20C41F117F41C13830D'
|
||||
})
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.headerByHash, 'getLedger')
|
||||
},
|
||||
'future ledger version': async (client) => {
|
||||
const response = await client.getLedger({ledgerVersion: 14661789})
|
||||
assert(!!response)
|
||||
},
|
||||
'with state as hashes': async (client) => {
|
||||
const request = {
|
||||
includeTransactions: true,
|
||||
includeAllData: false,
|
||||
includeState: true,
|
||||
ledgerVersion: 6
|
||||
}
|
||||
const response = await client.getLedger(request)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.withStateAsHashes,
|
||||
'getLedger'
|
||||
)
|
||||
},
|
||||
'with settings transaction': async (client) => {
|
||||
const request = {
|
||||
includeTransactions: true,
|
||||
includeAllData: true,
|
||||
ledgerVersion: 4181996
|
||||
}
|
||||
const response = await client.getLedger(request)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.withSettingsTx, 'getLedger')
|
||||
},
|
||||
'with partial payment': async (client) => {
|
||||
const request = {
|
||||
includeTransactions: true,
|
||||
includeAllData: true,
|
||||
ledgerVersion: 22420574
|
||||
}
|
||||
const response = await client.getLedger(request)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.withPartial, 'getLedger')
|
||||
},
|
||||
'pre 2014 with partial payment': async (client) => {
|
||||
const request = {
|
||||
includeTransactions: true,
|
||||
includeAllData: true,
|
||||
ledgerVersion: 100001
|
||||
}
|
||||
const response = await client.getLedger(request)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.pre2014withPartial,
|
||||
'getLedger'
|
||||
)
|
||||
},
|
||||
'full, then computeLedgerHash': async (client) => {
|
||||
const request = {
|
||||
includeTransactions: true,
|
||||
includeState: true,
|
||||
includeAllData: true,
|
||||
ledgerVersion: 38129
|
||||
}
|
||||
const response = await client.getLedger(request)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.full, 'getLedger')
|
||||
const ledger = {
|
||||
...response,
|
||||
parentCloseTime: response.closeTime
|
||||
}
|
||||
const hash = client.computeLedgerHash(ledger, {computeTreeHashes: true})
|
||||
assert.strictEqual(
|
||||
hash,
|
||||
'E6DB7365949BF9814D76BCC730B01818EB9136A89DB224F3F9F5AAE4569D758E'
|
||||
)
|
||||
}
|
||||
}
|
||||
14
test/client/getLedgerVersion/index.ts
Normal file
14
test/client/getLedgerVersion/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import assert from 'assert-diff'
|
||||
import {TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'default test': async (client, address) => {
|
||||
const ver = await client.getLedgerVersion()
|
||||
assert.strictEqual(ver, 8819951)
|
||||
}
|
||||
}
|
||||
154
test/client/getOrderbook/index.ts
Normal file
154
test/client/getOrderbook/index.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import assert from 'assert-diff'
|
||||
import responses from '../../fixtures/responses'
|
||||
import requests from '../../fixtures/requests'
|
||||
import {TestSuite, assertResultMatch, assertRejects} from '../../utils'
|
||||
import BigNumber from 'bignumber.js'
|
||||
|
||||
function checkSortingOfOrders(orders) {
|
||||
let previousRate = '0'
|
||||
for (var i = 0; i < orders.length; i++) {
|
||||
const order = orders[i]
|
||||
let rate
|
||||
|
||||
// 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,
|
||||
// the quality can differ significantly. However, the offer stays in the
|
||||
// order book where it was originally placed. It would be more consistent
|
||||
// to check the quality from the offer book, but for the test data set,
|
||||
// this calculation holds.
|
||||
|
||||
if (order.specification.direction === 'buy') {
|
||||
rate = new BigNumber(order.specification.quantity.value)
|
||||
.dividedBy(order.specification.totalPrice.value)
|
||||
.toString()
|
||||
} else {
|
||||
rate = new BigNumber(order.specification.totalPrice.value)
|
||||
.dividedBy(order.specification.quantity.value)
|
||||
.toString()
|
||||
}
|
||||
assert(
|
||||
new BigNumber(rate).isGreaterThanOrEqualTo(previousRate),
|
||||
'Rates must be sorted from least to greatest: ' +
|
||||
rate +
|
||||
' should be >= ' +
|
||||
previousRate
|
||||
)
|
||||
previousRate = rate
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'normal': async (client, address) => {
|
||||
const response = await client.getOrderbook(
|
||||
address,
|
||||
requests.getOrderbook.normal,
|
||||
{limit: 20}
|
||||
)
|
||||
assertResultMatch(response, responses.getOrderbook.normal, 'getOrderbook')
|
||||
},
|
||||
|
||||
'invalid options': async (client, address) => {
|
||||
assertRejects(
|
||||
client.getOrderbook(address, requests.getOrderbook.normal, {
|
||||
// @ts-ignore
|
||||
invalid: 'options'
|
||||
}),
|
||||
client.errors.ValidationError
|
||||
)
|
||||
},
|
||||
|
||||
'with XRP': async (client, address) => {
|
||||
const response = await client.getOrderbook(
|
||||
address,
|
||||
requests.getOrderbook.withXRP
|
||||
)
|
||||
assertResultMatch(response, responses.getOrderbook.withXRP, 'getOrderbook')
|
||||
},
|
||||
|
||||
'sample XRP/JPY book has orders sorted correctly': async (client, address) => {
|
||||
const orderbookInfo = {
|
||||
base: {
|
||||
// the first currency in pair
|
||||
currency: 'XRP'
|
||||
},
|
||||
counter: {
|
||||
currency: 'JPY',
|
||||
counterparty: 'rB3gZey7VWHYRqJHLoHDEJXJ2pEPNieKiS'
|
||||
}
|
||||
}
|
||||
const myAddress = 'rE9qNjzJXpiUbVomdv7R4xhrXVeH2oVmGR'
|
||||
const response = await client.getOrderbook(myAddress, orderbookInfo)
|
||||
assert.deepStrictEqual([], response.bids)
|
||||
checkSortingOfOrders(response.asks)
|
||||
},
|
||||
|
||||
'sample USD/XRP book has orders sorted correctly': async (client, address) => {
|
||||
const orderbookInfo = {
|
||||
counter: {currency: 'XRP'},
|
||||
base: {
|
||||
currency: 'USD',
|
||||
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
|
||||
}
|
||||
}
|
||||
const myAddress = 'rE9qNjzJXpiUbVomdv7R4xhrXVeH2oVmGR'
|
||||
const response = await client.getOrderbook(myAddress, orderbookInfo)
|
||||
checkSortingOfOrders(response.bids)
|
||||
checkSortingOfOrders(response.asks)
|
||||
},
|
||||
|
||||
// WARNING: This test fails to catch the sorting bug, issue #766
|
||||
'sorted so that best deals come first [bad test]': async (client, address) => {
|
||||
const response = await client.getOrderbook(
|
||||
address,
|
||||
requests.getOrderbook.normal
|
||||
)
|
||||
const bidRates = response.bids.map(
|
||||
(bid) => bid.properties.makerExchangeRate
|
||||
)
|
||||
const askRates = response.asks.map(
|
||||
(ask) => ask.properties.makerExchangeRate
|
||||
)
|
||||
// makerExchangeRate = quality = takerPays.value/takerGets.value
|
||||
// so the best deal for the taker is the lowest makerExchangeRate
|
||||
// bids and asks should be sorted so that the best deals come first
|
||||
assert.deepEqual(
|
||||
bidRates.sort((x) => Number(x)),
|
||||
bidRates
|
||||
)
|
||||
assert.deepEqual(
|
||||
askRates.sort((x) => Number(x)),
|
||||
askRates
|
||||
)
|
||||
},
|
||||
|
||||
'currency & counterparty are correct': async (client, address) => {
|
||||
const response = await client.getOrderbook(
|
||||
address,
|
||||
requests.getOrderbook.normal
|
||||
)
|
||||
;[...response.bids, ...response.asks].forEach((order) => {
|
||||
const quantity = order.specification.quantity
|
||||
const totalPrice = order.specification.totalPrice
|
||||
const {base, counter} = requests.getOrderbook.normal
|
||||
assert.strictEqual(quantity.currency, base.currency)
|
||||
assert.strictEqual(quantity.counterparty, base.counterparty)
|
||||
assert.strictEqual(totalPrice.currency, counter.currency)
|
||||
assert.strictEqual(totalPrice.counterparty, counter.counterparty)
|
||||
})
|
||||
},
|
||||
|
||||
'direction is correct for bids and asks': async (client, address) => {
|
||||
const response = await client.getOrderbook(
|
||||
address,
|
||||
requests.getOrderbook.normal
|
||||
)
|
||||
assert(response.bids.every((bid) => bid.specification.direction === 'buy'))
|
||||
assert(response.asks.every((ask) => ask.specification.direction === 'sell'))
|
||||
}
|
||||
}
|
||||
34
test/client/getOrders/index.ts
Normal file
34
test/client/getOrders/index.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertRejects, assertResultMatch, TestSuite} from '../../utils'
|
||||
|
||||
export const config = {
|
||||
// TODO: The mock server right now returns a hard-coded string, no matter
|
||||
// what "Account" value you pass. We'll need it to support more accurate
|
||||
// responses before we can turn these tests on.
|
||||
skipXAddress: true
|
||||
}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'getOrders': async (client, address) => {
|
||||
const result = await client.getOrders(address)
|
||||
assertResultMatch(result, responses.getOrders, 'getOrders')
|
||||
},
|
||||
|
||||
'getOrders - limit': async (client, address) => {
|
||||
const result = await client.getOrders(address, {limit: 20})
|
||||
assertResultMatch(result, responses.getOrders, 'getOrders')
|
||||
},
|
||||
|
||||
'getOrders - invalid options': async (client, address) => {
|
||||
await assertRejects(
|
||||
// @ts-ignore - This is intentionally invalid
|
||||
client.getOrders(address, {invalid: 'options'}),
|
||||
client.errors.ValidationError
|
||||
)
|
||||
}
|
||||
}
|
||||
95
test/client/getPaths/index.ts
Normal file
95
test/client/getPaths/index.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import assert from 'assert-diff'
|
||||
import {assertResultMatch, assertRejects, TestSuite} from '../../utils'
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import addresses from '../../fixtures/addresses.json'
|
||||
const {getPaths: REQUEST_FIXTURES} = requests
|
||||
const {getPaths: RESPONSE_FIXTURES} = responses
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'simple test': async (client) => {
|
||||
const response = await client.getPaths(REQUEST_FIXTURES.normal)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.XrpToUsd, 'getPaths')
|
||||
},
|
||||
'queuing': async (client) => {
|
||||
const [normalResult, usdOnlyResult, xrpOnlyResult] = await Promise.all([
|
||||
client.getPaths(REQUEST_FIXTURES.normal),
|
||||
client.getPaths(REQUEST_FIXTURES.UsdToUsd),
|
||||
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': async (client) => {
|
||||
const response = await client.getPaths(REQUEST_FIXTURES.UsdToUsd)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.UsdToUsd, 'getPaths')
|
||||
},
|
||||
'getPaths XRP 2 XRP': async (client) => {
|
||||
const response = await client.getPaths(REQUEST_FIXTURES.XrpToXrp)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.XrpToXrp, 'getPaths')
|
||||
},
|
||||
'source with issuer': async (client) => {
|
||||
return assertRejects(
|
||||
client.getPaths(REQUEST_FIXTURES.issuer),
|
||||
client.errors.NotFoundError
|
||||
)
|
||||
},
|
||||
'XRP 2 XRP - not enough': async (client) => {
|
||||
return assertRejects(
|
||||
client.getPaths(REQUEST_FIXTURES.XrpToXrpNotEnough),
|
||||
client.errors.NotFoundError
|
||||
)
|
||||
},
|
||||
'invalid PathFind': async (client) => {
|
||||
assert.throws(() => {
|
||||
client.getPaths(REQUEST_FIXTURES.invalid)
|
||||
}, /Cannot specify both source.amount/)
|
||||
},
|
||||
'does not accept currency': async (client) => {
|
||||
return assertRejects(
|
||||
client.getPaths(REQUEST_FIXTURES.NotAcceptCurrency),
|
||||
client.errors.NotFoundError
|
||||
)
|
||||
},
|
||||
'no paths': async (client) => {
|
||||
return assertRejects(
|
||||
client.getPaths(REQUEST_FIXTURES.NoPaths),
|
||||
client.errors.NotFoundError
|
||||
)
|
||||
},
|
||||
'no paths source amount': async (client) => {
|
||||
return assertRejects(
|
||||
client.getPaths(REQUEST_FIXTURES.NoPathsSource),
|
||||
client.errors.NotFoundError
|
||||
)
|
||||
},
|
||||
'no paths with source currencies': async (client) => {
|
||||
return assertRejects(
|
||||
client.getPaths(REQUEST_FIXTURES.NoPathsWithCurrencies),
|
||||
client.errors.NotFoundError
|
||||
)
|
||||
},
|
||||
'error: srcActNotFound': async (client) => {
|
||||
return assertRejects(
|
||||
client.getPaths({
|
||||
...REQUEST_FIXTURES.normal,
|
||||
source: {address: addresses.NOTFOUND}
|
||||
}),
|
||||
client.errors.RippleError
|
||||
)
|
||||
},
|
||||
'send all': async (client) => {
|
||||
const response = await client.getPaths(REQUEST_FIXTURES.sendAll)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.sendAll, 'getPaths')
|
||||
}
|
||||
}
|
||||
44
test/client/getPaymentChannel/index.ts
Normal file
44
test/client/getPaymentChannel/index.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertRejects, assertResultMatch, TestSuite} from '../../utils'
|
||||
const {getPaymentChannel: RESPONSE_FIXTURES} = responses
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'getPaymentChannel': async (client, address) => {
|
||||
const channelId =
|
||||
'E30E709CF009A1F26E0E5C48F7AA1BFB79393764F15FB108BDC6E06D3CBD8415'
|
||||
const result = await client.getPaymentChannel(channelId)
|
||||
assertResultMatch(result, RESPONSE_FIXTURES.normal, 'getPaymentChannel')
|
||||
},
|
||||
|
||||
'getPaymentChannel - full': async (client, address) => {
|
||||
const channelId =
|
||||
'D77CD4713AA08195E6B6D0E5BC023DA11B052EBFF0B5B22EDA8AE85345BCF661'
|
||||
const result = await client.getPaymentChannel(channelId)
|
||||
assertResultMatch(result, RESPONSE_FIXTURES.full, 'getPaymentChannel')
|
||||
},
|
||||
|
||||
'getPaymentChannel - not found': async (client, address) => {
|
||||
const channelId =
|
||||
'DFA557EA3497585BFE83F0F97CC8E4530BBB99967736BB95225C7F0C13ACE708'
|
||||
await assertRejects(
|
||||
client.getPaymentChannel(channelId),
|
||||
client.errors.RippledError,
|
||||
'entryNotFound'
|
||||
)
|
||||
},
|
||||
|
||||
'getPaymentChannel - wrong type': async (client, address) => {
|
||||
const channelId =
|
||||
'8EF9CCB9D85458C8D020B3452848BBB42EAFDDDB69A93DD9D1223741A4CA562B'
|
||||
await assertRejects(
|
||||
client.getPaymentChannel(channelId),
|
||||
client.errors.NotFoundError,
|
||||
'Payment channel ledger entry not found'
|
||||
)
|
||||
}
|
||||
}
|
||||
44
test/client/getServerInfo/index.ts
Normal file
44
test/client/getServerInfo/index.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import assert from 'assert-diff'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite, assertRejects} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'default': async (client, address) => {
|
||||
const serverInfo = await client.getServerInfo()
|
||||
assertResultMatch(serverInfo, responses.getServerInfo, 'getServerInfo')
|
||||
},
|
||||
|
||||
'error': async (client, address) => {
|
||||
client.connection.request({
|
||||
command: 'config',
|
||||
data: {returnErrorOnServerInfo: true}
|
||||
})
|
||||
try {
|
||||
await client.getServerInfo()
|
||||
throw new Error('Should throw NetworkError')
|
||||
} catch (err) {
|
||||
assert(err instanceof client.errors.RippledError)
|
||||
assert.equal(err.message, 'You are placing too much load on the server.')
|
||||
assert.equal(err.data.error, 'slowDown')
|
||||
}
|
||||
},
|
||||
|
||||
'no validated ledger': async (client, address) => {
|
||||
client.connection.request({
|
||||
command: 'config',
|
||||
data: {serverInfoWithoutValidated: true}
|
||||
})
|
||||
const serverInfo = await client.getServerInfo()
|
||||
assert.strictEqual(serverInfo.networkLedger, 'waiting')
|
||||
},
|
||||
|
||||
'getServerInfo - offline': async (client, address) => {
|
||||
await client.disconnect()
|
||||
return assertRejects(client.getServerInfo(), client.errors.NotConnectedError)
|
||||
}
|
||||
}
|
||||
28
test/client/getSettings/index.ts
Normal file
28
test/client/getSettings/index.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertRejects, assertResultMatch, TestSuite} from '../../utils'
|
||||
const {getSettings: RESPONSE_FIXTURES} = responses
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'getSettings': async (client, address) => {
|
||||
const result = await client.getSettings(address)
|
||||
assertResultMatch(result, RESPONSE_FIXTURES, 'getSettings')
|
||||
},
|
||||
|
||||
'getSettings - options undefined': async (client, address) => {
|
||||
const result = await client.getSettings(address, undefined)
|
||||
assertResultMatch(result, RESPONSE_FIXTURES, 'getSettings')
|
||||
},
|
||||
|
||||
'getSettings - invalid options': async (client, address) => {
|
||||
await assertRejects(
|
||||
// @ts-ignore - This is intentionally invalid
|
||||
client.getSettings(address, {invalid: 'options'}),
|
||||
client.errors.ValidationError
|
||||
)
|
||||
}
|
||||
}
|
||||
508
test/client/getTransaction/index.ts
Normal file
508
test/client/getTransaction/index.ts
Normal file
@@ -0,0 +1,508 @@
|
||||
import assert from 'assert-diff'
|
||||
import {
|
||||
MissingLedgerHistoryError,
|
||||
NotFoundError,
|
||||
UnexpectedError
|
||||
} from 'xrpl-local/common/errors'
|
||||
import {PendingLedgerVersionError} from '../../../src/common/errors'
|
||||
import hashes from '../../fixtures/hashes.json'
|
||||
import responses from '../../fixtures/responses'
|
||||
import ledgerClosed from '../../fixtures/rippled/ledger-close-newer.json'
|
||||
import {assertRejects, assertResultMatch, TestSuite} from '../../utils'
|
||||
const {getTransaction: RESPONSE_FIXTURES} = responses
|
||||
|
||||
function closeLedger(connection) {
|
||||
connection._ws.emit('message', JSON.stringify(ledgerClosed))
|
||||
}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'payment': async (client, address) => {
|
||||
const response = await client.getTransaction(hashes.VALID_TRANSACTION_HASH)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.payment, 'getTransaction')
|
||||
},
|
||||
|
||||
'payment - include raw transaction': async (client, address) => {
|
||||
const options = {
|
||||
includeRawTransaction: true
|
||||
}
|
||||
const response = await client.getTransaction(
|
||||
hashes.VALID_TRANSACTION_HASH,
|
||||
options
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.paymentIncludeRawTransaction,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'settings': async (client, address) => {
|
||||
const hash =
|
||||
'4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA1B'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.settings, 'getTransaction')
|
||||
},
|
||||
|
||||
'settings - include raw transaction': async (client, address) => {
|
||||
const hash =
|
||||
'4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA1B'
|
||||
const options = {
|
||||
includeRawTransaction: true
|
||||
}
|
||||
const expected = Object.assign({}, RESPONSE_FIXTURES.settings) // Avoid mutating test fixture
|
||||
expected.rawTransaction =
|
||||
'{"Account":"rLVKsA4F9iJBbA6rX2x4wCmkj6drgtqpQe","Fee":"10","Flags":2147483648,"Sequence":1,"SetFlag":2,"SigningPubKey":"03EA3ADCA632F125EC2CC4F7F6A82DE0DCE2B65290CAC1F22242C5163F0DA9652D","TransactionType":"AccountSet","TxnSignature":"3045022100DE8B666B1A31EA65011B0F32130AB91A5747E32FA49B3054CEE8E8362DBAB98A022040CF0CF254677A8E5CD04C59CA2ED7F6F15F7E184641BAE169C561650967B226","date":460832270,"hash":"4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA1B","inLedger":8206418,"ledger_index":8206418,"meta":{"AffectedNodes":[{"ModifiedNode":{"FinalFields":{"Account":"rLVKsA4F9iJBbA6rX2x4wCmkj6drgtqpQe","Balance":"29999990","Flags":786432,"OwnerCount":0,"Sequence":2},"LedgerEntryType":"AccountRoot","LedgerIndex":"3F5072C4875F32ED770DAF3610A716600ED7C7BB0348FADC7A98E011BB2CD36F","PreviousFields":{"Balance":"30000000","Flags":4194304,"Sequence":1},"PreviousTxnID":"3FB0350A3742BBCC0D8AA3C5247D1AEC01177D0A24D9C34762BAA2FEA8AD88B3","PreviousTxnLgrSeq":8206397}}],"TransactionIndex":5,"TransactionResult":"tesSUCCESS"},"validated":true}'
|
||||
const response = await client.getTransaction(hash, options)
|
||||
assertResultMatch(response, expected, 'getTransaction')
|
||||
},
|
||||
|
||||
'order': async (client, address) => {
|
||||
const hash =
|
||||
'10A6FB4A66EE80BED46AAE4815D7DC43B97E944984CCD5B93BCF3F8538CABC51'
|
||||
closeLedger(client.connection)
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.order, 'getTransaction')
|
||||
},
|
||||
|
||||
'order with memo': async (client, address) => {
|
||||
const hash = hashes.WITH_MEMOS_OFFER_CREATE_TRANSACTION_HASH
|
||||
closeLedger(client.connection)
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.orderWithMemo, 'getTransaction')
|
||||
},
|
||||
|
||||
'sell order': async (client, address) => {
|
||||
const hash =
|
||||
'458101D51051230B1D56E9ACAFAA34451BF65FA000F95DF6F0FF5B3A62D83FC2'
|
||||
closeLedger(client.connection)
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.orderSell, 'getTransaction')
|
||||
},
|
||||
|
||||
'order cancellation': async (client, address) => {
|
||||
const hash =
|
||||
'809335DD3B0B333865096217AA2F55A4DF168E0198080B3A090D12D88880FF0E'
|
||||
closeLedger(client.connection)
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.orderCancellation,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'order with expiration cancellation': async (client, address) => {
|
||||
const hash =
|
||||
'097B9491CC76B64831F1FEA82EAA93BCD728106D90B65A072C933888E946C40B'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.orderWithExpirationCancellation,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'order cancellation with memo': async (client, address) => {
|
||||
const hash = hashes.WITH_MEMOS_ORDER_CANCELLATION_TRANSACTION_HASH
|
||||
closeLedger(client.connection)
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.orderCancellationWithMemo,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'trustline set': async (client, address) => {
|
||||
const hash =
|
||||
'635A0769BD94710A1F6A76CDE65A3BC661B20B798807D1BBBDADCEA26420538D'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.trustline, 'getTransaction')
|
||||
},
|
||||
|
||||
'trustline frozen off': async (client, address) => {
|
||||
const hash =
|
||||
'FE72FAD0FA7CA904FB6C633A1666EDF0B9C73B2F5A4555D37EEF2739A78A531B'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.trustlineFrozenOff,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'trustline no quality': async (client, address) => {
|
||||
const hash =
|
||||
'BAF1C678323C37CCB7735550C379287667D8288C30F83148AD3C1CB019FC9002'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.trustlineNoQuality,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'trustline add memo': async (client, address) => {
|
||||
const hash =
|
||||
'9D6AC5FD6545B2584885B85E36759EB6440CDD41B6C55859F84AFDEE2B428220'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.trustlineAddMemo,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'not validated': async (client, address) => {
|
||||
const hash =
|
||||
'4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA10'
|
||||
await assertRejects(
|
||||
client.getTransaction(hash),
|
||||
NotFoundError,
|
||||
'Transaction not found'
|
||||
)
|
||||
},
|
||||
|
||||
'tracking on': async (client, address) => {
|
||||
const hash =
|
||||
'8925FC8844A1E930E2CC76AD0A15E7665AFCC5425376D548BB1413F484C31B8C'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.trackingOn, 'getTransaction')
|
||||
},
|
||||
|
||||
'tracking off': async (client, address) => {
|
||||
const hash =
|
||||
'C8C5E20DFB1BF533D0D81A2ED23F0A3CBD1EF2EE8A902A1D760500473CC9C582'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.trackingOff, 'getTransaction')
|
||||
},
|
||||
|
||||
'set regular key': async (client, address) => {
|
||||
const hash =
|
||||
'278E6687C1C60C6873996210A6523564B63F2844FB1019576C157353B1813E60'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.setRegularKey,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'not found in range': async (client, address) => {
|
||||
const hash =
|
||||
'809335DD3B0B333865096217AA2F55A4DF168E0198080B3A090D12D88880FF0E'
|
||||
const options = {
|
||||
minLedgerVersion: 32570,
|
||||
maxLedgerVersion: 32571
|
||||
}
|
||||
await assertRejects(client.getTransaction(hash, options), NotFoundError)
|
||||
},
|
||||
|
||||
'not found by hash': async (client, address) => {
|
||||
const hash = hashes.NOTFOUND_TRANSACTION_HASH
|
||||
|
||||
await assertRejects(client.getTransaction(hash), NotFoundError)
|
||||
},
|
||||
|
||||
'missing ledger history': async (client, address) => {
|
||||
const hash = hashes.NOTFOUND_TRANSACTION_HASH
|
||||
// make gaps in history
|
||||
closeLedger(client.connection)
|
||||
|
||||
await assertRejects(client.getTransaction(hash), MissingLedgerHistoryError)
|
||||
},
|
||||
|
||||
'missing ledger history with ledger range': async (client, address) => {
|
||||
const hash = hashes.NOTFOUND_TRANSACTION_HASH
|
||||
const options = {
|
||||
minLedgerVersion: 32569,
|
||||
maxLedgerVersion: 32571
|
||||
}
|
||||
await assertRejects(
|
||||
client.getTransaction(hash, options),
|
||||
MissingLedgerHistoryError
|
||||
)
|
||||
},
|
||||
|
||||
'not found - future maxLedgerVersion': async (client, address) => {
|
||||
const hash = hashes.NOTFOUND_TRANSACTION_HASH
|
||||
const options = {
|
||||
maxLedgerVersion: 99999999999
|
||||
}
|
||||
await assertRejects(
|
||||
client.getTransaction(hash, options),
|
||||
PendingLedgerVersionError,
|
||||
"maxLedgerVersion is greater than server's most recent validated ledger"
|
||||
)
|
||||
},
|
||||
|
||||
'transaction not validated': async (client, address) => {
|
||||
const hash =
|
||||
'4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA11'
|
||||
await assertRejects(
|
||||
client.getTransaction(hash),
|
||||
NotFoundError,
|
||||
/Transaction has not been validated yet/
|
||||
)
|
||||
},
|
||||
|
||||
'transaction ledger not found': async (client, address) => {
|
||||
const hash =
|
||||
'4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA12'
|
||||
await assertRejects(
|
||||
client.getTransaction(hash),
|
||||
NotFoundError,
|
||||
/ledger not found/
|
||||
)
|
||||
},
|
||||
|
||||
'ledger missing close time': async (client, address) => {
|
||||
const hash =
|
||||
'0F7ED9F40742D8A513AE86029462B7A6768325583DF8EE21B7EC663019DD6A04'
|
||||
closeLedger(client.connection)
|
||||
await assertRejects(client.getTransaction(hash), UnexpectedError)
|
||||
},
|
||||
|
||||
// Checks
|
||||
'CheckCreate': async (client, address) => {
|
||||
const hash =
|
||||
'605A2E2C8E48AECAF5C56085D1AEAA0348DC838CE122C9188F94EB19DA05C2FE'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.checkCreate, 'getTransaction')
|
||||
},
|
||||
|
||||
'CheckCreate with memo': async (client, address) => {
|
||||
const hash = hashes.WITH_MEMOS_CHECK_CREATE_TRANSACTION_HASH
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.checkCreateWithMemo, 'getTransaction')
|
||||
},
|
||||
|
||||
'CheckCancel': async (client, address) => {
|
||||
const hash =
|
||||
'B4105D1B2D83819647E4692B7C5843D674283F669524BD50C9614182E3A12CD4'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.checkCancel, 'getTransaction')
|
||||
},
|
||||
|
||||
'CheckCancel with memo': async (client, address) => {
|
||||
const hash = hashes.WITH_MEMOS_CHECK_CANCEL_TRANSACTION_HASH
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.checkCancelWithMemo, 'getTransaction')
|
||||
},
|
||||
|
||||
'CheckCash': async (client, address) => {
|
||||
const hash =
|
||||
'8321208465F70BA52C28BCC4F646BAF3B012BA13B57576C0336F42D77E3E0749'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.checkCash, 'getTransaction')
|
||||
},
|
||||
|
||||
'CheckCash with memo': async (client, address) => {
|
||||
const hash = hashes.WITH_MEMOS_CHECK_CASH_TRANSACTION_HASH
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.checkCashWithMemo, 'getTransaction')
|
||||
},
|
||||
|
||||
// Escrows
|
||||
'EscrowCreation': async (client, address) => {
|
||||
const hash =
|
||||
'144F272380BDB4F1BD92329A2178BABB70C20F59042C495E10BF72EBFB408EE1'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.escrowCreation,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'EscrowCancellation': async (client, address) => {
|
||||
const hash =
|
||||
'F346E542FFB7A8398C30A87B952668DAB48B7D421094F8B71776DA19775A3B22'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.escrowCancellation,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'EscrowExecution': async (client, address) => {
|
||||
const options = {
|
||||
minLedgerVersion: 10,
|
||||
maxLedgerVersion: 15
|
||||
}
|
||||
const hash =
|
||||
'CC5277137B3F25EE8B86259C83CB0EAADE818505E4E9BCBF19B1AC6FD136993B'
|
||||
const response = await client.getTransaction(hash, options)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.escrowExecution,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'EscrowExecution simple': async (client, address) => {
|
||||
const hash =
|
||||
'CC5277137B3F25EE8B86259C83CB0EAADE818505E4E9BCBF19B1AC6FD1369931'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.escrowExecutionSimple,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'PaymentChannelCreate': async (client, address) => {
|
||||
const hash =
|
||||
'0E9CA3AB1053FC0C1CBAA75F636FE1EC92F118C7056BBEF5D63E4C116458A16D'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.paymentChannelCreate,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'PaymentChannelCreate with memo': async (client, address) => {
|
||||
const hash = hashes.WITH_MEMOS_PAYMENT_CHANNEL_CREATE_TRANSACTION_HASH
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.paymentChannelCreateWithMemo,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'PaymentChannelFund': async (client, address) => {
|
||||
const hash =
|
||||
'CD053D8867007A6A4ACB7A432605FE476D088DCB515AFFC886CF2B4EB6D2AE8B'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.paymentChannelFund,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'PaymentChannelFund with memo': async (client, address) => {
|
||||
const hash = hashes.WITH_MEMOS_PAYMENT_CHANNEL_FUND_TRANSACTION_HASH
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.paymentChannelFundWithMemo,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'PaymentChannelClaim': async (client, address) => {
|
||||
const hash =
|
||||
'81B9ECAE7195EB6E8034AEDF44D8415A7A803E14513FDBB34FA984AB37D59563'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.paymentChannelClaim,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'PaymentChannelClaim with memo': async (client, address) => {
|
||||
const hash = hashes.WITH_MEMOS_PAYMENT_CHANNEL_CLAIM_TRANSACTION_HASH
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.paymentChannelClaimWithMemo,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'AccountDelete': async (client, address) => {
|
||||
const hash =
|
||||
'EC2AB14028DC84DE525470AB4DAAA46358B50A8662C63804BFF38244731C0CB9'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.accountDelete,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'AccountDelete with memo': async (client, address) => {
|
||||
const hash = hashes.WITH_MEMOS_ACCOUNT_DELETE_TRANSACTION_HASH
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.accountDeleteWithMemo,
|
||||
'getTransaction'
|
||||
)
|
||||
},
|
||||
|
||||
'no Meta': async (client, address) => {
|
||||
const hash =
|
||||
'AFB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA1B'
|
||||
const response = await client.getTransaction(hash)
|
||||
assert.deepEqual(response, RESPONSE_FIXTURES.noMeta)
|
||||
},
|
||||
|
||||
'Unrecognized transaction type': async (client, address) => {
|
||||
const hash =
|
||||
'AFB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA11'
|
||||
closeLedger(client.connection)
|
||||
const response = await client.getTransaction(hash)
|
||||
assert.strictEqual(
|
||||
// @ts-ignore
|
||||
response.specification.UNAVAILABLE,
|
||||
'Unrecognized transaction type.'
|
||||
)
|
||||
},
|
||||
|
||||
'amendment': async (client, address) => {
|
||||
const hash =
|
||||
'A971B83ABED51D83749B73F3C1AAA627CD965AFF74BE8CD98299512D6FB0658F'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.amendment)
|
||||
},
|
||||
|
||||
'feeUpdate': async (client, address) => {
|
||||
const hash =
|
||||
'C6A40F56127436DCD830B1B35FF939FD05B5747D30D6542572B7A835239817AF'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.feeUpdate)
|
||||
},
|
||||
|
||||
'feeUpdate with memo': async (client, address) => {
|
||||
const hash = hashes.WITH_MEMOS_FEE_UPDATE_TRANSACTION_HASH
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.feeUpdateWithMemo)
|
||||
},
|
||||
|
||||
'order with one memo': async (client, address) => {
|
||||
const hash =
|
||||
'995570FE1E40F42DF56BFC80503BA9E3C1229619C61A1C279A76BC0805036D74'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.withMemo)
|
||||
},
|
||||
|
||||
'order with more than one memo': async (client, address) => {
|
||||
const hash =
|
||||
'995570FE1E40F42DF56BFC80503BA9E3C1229619C61A1C279A76BC0805036D73'
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.withMemos)
|
||||
},
|
||||
|
||||
'ticketCreate with memo': async (client, address) => {
|
||||
const hash = hashes.WITH_MEMOS_TICKET_CREATE_TRANSACTION_HASH
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.ticketCreateWithMemo)
|
||||
},
|
||||
|
||||
'depositPreauth with memo': async (client, address) => {
|
||||
const hash = hashes.WITH_MEMOS_DEPOSIT_PREAUTH_TRANSACTION_HASH
|
||||
const response = await client.getTransaction(hash)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.depositPreauthWithMemo)
|
||||
}
|
||||
}
|
||||
169
test/client/getTransactions/index.ts
Normal file
169
test/client/getTransactions/index.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
import {Client} from 'xrpl-local'
|
||||
import assert from 'assert-diff'
|
||||
import {assertResultMatch, TestSuite, assertRejects} from '../../utils'
|
||||
import responses from '../../fixtures/responses'
|
||||
import hashes from '../../fixtures/hashes.json'
|
||||
import addresses from '../../fixtures/addresses.json'
|
||||
const utils = Client._PRIVATE.ledgerUtils
|
||||
const {getTransactions: RESPONSE_FIXTURES} = responses
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'default': async (client, address) => {
|
||||
const options = {types: ['payment', 'order'], initiated: true, limit: 2}
|
||||
const response = await client.getTransactions(address, options)
|
||||
hack(response)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.normal, 'getTransactions')
|
||||
},
|
||||
|
||||
'include raw transactions': async (client, address) => {
|
||||
const options = {
|
||||
types: ['payment', 'order'],
|
||||
initiated: true,
|
||||
limit: 2,
|
||||
includeRawTransactions: true
|
||||
}
|
||||
const response = await client.getTransactions(address, options)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.includeRawTransactions,
|
||||
'getTransactions'
|
||||
)
|
||||
},
|
||||
|
||||
'earliest first': async (client, address) => {
|
||||
const options = {
|
||||
types: ['payment', 'order'],
|
||||
initiated: true,
|
||||
limit: 2,
|
||||
earliestFirst: true
|
||||
}
|
||||
const expected = Array.from(RESPONSE_FIXTURES.normal as any[]).sort(
|
||||
utils.compareTransactions
|
||||
)
|
||||
const response = await client.getTransactions(address, options)
|
||||
hack(response)
|
||||
assertResultMatch(response, expected, 'getTransactions')
|
||||
},
|
||||
|
||||
'earliest first with start option': async (client, address) => {
|
||||
const options = {
|
||||
types: ['payment', 'order'],
|
||||
initiated: true,
|
||||
limit: 2,
|
||||
start: hashes.VALID_TRANSACTION_HASH,
|
||||
earliestFirst: true
|
||||
}
|
||||
const response = await client.getTransactions(address, options)
|
||||
assert.strictEqual(response.length, 0)
|
||||
},
|
||||
|
||||
'gap': async (client, address) => {
|
||||
const options = {
|
||||
types: ['payment', 'order'],
|
||||
initiated: true,
|
||||
limit: 2,
|
||||
maxLedgerVersion: 348858000
|
||||
}
|
||||
return assertRejects(
|
||||
client.getTransactions(address, options),
|
||||
client.errors.MissingLedgerHistoryError
|
||||
)
|
||||
},
|
||||
|
||||
'tx not found': async (client, address) => {
|
||||
const options = {
|
||||
types: ['payment', 'order'],
|
||||
initiated: true,
|
||||
limit: 2,
|
||||
start: hashes.NOTFOUND_TRANSACTION_HASH,
|
||||
counterparty: address
|
||||
}
|
||||
return assertRejects(
|
||||
client.getTransactions(address, options),
|
||||
client.errors.NotFoundError
|
||||
)
|
||||
},
|
||||
|
||||
'filters': async (client, address) => {
|
||||
const options = {
|
||||
types: ['payment', 'order'],
|
||||
initiated: true,
|
||||
limit: 10,
|
||||
excludeFailures: true,
|
||||
counterparty: addresses.ISSUER
|
||||
}
|
||||
const response = await client.getTransactions(address, options)
|
||||
hack(response)
|
||||
assert.strictEqual(response.length, 10)
|
||||
response.forEach((t) => assert(t.type === 'payment' || t.type === 'order'))
|
||||
response.forEach((t) => assert(t.outcome.result === 'tesSUCCESS'))
|
||||
},
|
||||
|
||||
'filters for incoming': async (client, address) => {
|
||||
const options = {
|
||||
types: ['payment', 'order'],
|
||||
initiated: false,
|
||||
limit: 10,
|
||||
excludeFailures: true,
|
||||
counterparty: addresses.ISSUER
|
||||
}
|
||||
const response = await client.getTransactions(address, options)
|
||||
hack(response)
|
||||
assert.strictEqual(response.length, 10)
|
||||
response.forEach((t) => assert(t.type === 'payment' || t.type === 'order'))
|
||||
response.forEach((t) => assert(t.outcome.result === 'tesSUCCESS'))
|
||||
},
|
||||
|
||||
// this is the case where core.RippleError just falls
|
||||
// through the client to the user
|
||||
'error': async (client, address) => {
|
||||
const options = {types: ['payment', 'order'], initiated: true, limit: 13}
|
||||
return assertRejects(
|
||||
client.getTransactions(address, options),
|
||||
client.errors.RippleError
|
||||
)
|
||||
},
|
||||
|
||||
// TODO: this doesn't test much, just that it doesn't crash
|
||||
'getTransactions with start option': async (client, address) => {
|
||||
const options = {
|
||||
start: hashes.VALID_TRANSACTION_HASH,
|
||||
earliestFirst: false,
|
||||
limit: 2
|
||||
}
|
||||
const response = await client.getTransactions(address, options)
|
||||
hack(response)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.normal, 'getTransactions')
|
||||
},
|
||||
|
||||
'start transaction with zero ledger version': async (client, address) => {
|
||||
const options = {
|
||||
start: '4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA13',
|
||||
limit: 1
|
||||
}
|
||||
const response = await client.getTransactions(address, options)
|
||||
hack(response)
|
||||
assertResultMatch(response, [], 'getTransactions')
|
||||
},
|
||||
|
||||
'no options': async (client, address) => {
|
||||
const response = await client.getTransactions(addresses.OTHER_ACCOUNT)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.one, 'getTransactions')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// This test relies on the binary (hex string) format, but computed fields like `date`
|
||||
// are not available in this format. To support this field, we need to 'hack' it into
|
||||
// the expected response. Long term, a better approach would be to use/test the json
|
||||
// format responses, instead of the binary.
|
||||
function hack(response) {
|
||||
response.forEach((element) => {
|
||||
element.outcome.timestamp = '2019-04-01T07:39:01.000Z'
|
||||
})
|
||||
}
|
||||
49
test/client/getTrustlines/index.ts
Normal file
49
test/client/getTrustlines/index.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import addresses from '../../fixtures/addresses.json'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
const {getTrustlines: RESPONSE_FIXTURES} = responses
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'getTrustlines - filtered': async (client, address) => {
|
||||
const options = {currency: 'USD'}
|
||||
const result = await client.getTrustlines(address, options)
|
||||
assertResultMatch(result, RESPONSE_FIXTURES.filtered, 'getTrustlines')
|
||||
},
|
||||
|
||||
'getTrustlines - more than 400 items': async (client, address) => {
|
||||
const options = {limit: 401}
|
||||
const result = await client.getTrustlines(addresses.THIRD_ACCOUNT, options)
|
||||
assertResultMatch(
|
||||
result,
|
||||
RESPONSE_FIXTURES.moreThan400Items,
|
||||
'getTrustlines'
|
||||
)
|
||||
},
|
||||
|
||||
'getTrustlines - no options': async (client, address) => {
|
||||
await client.getTrustlines(address)
|
||||
},
|
||||
|
||||
'getTrustlines - ripplingDisabled works properly': async (client, address) => {
|
||||
const result = await client.getTrustlines(addresses.FOURTH_ACCOUNT)
|
||||
assertResultMatch(
|
||||
result,
|
||||
RESPONSE_FIXTURES.ripplingDisabled,
|
||||
'getTrustlines'
|
||||
)
|
||||
},
|
||||
|
||||
'getTrustlines - ledger version option': async (client, address) => {
|
||||
const result = await client.getTrustlines(addresses.FOURTH_ACCOUNT, {ledgerVersion: 5})
|
||||
assertResultMatch(
|
||||
result,
|
||||
RESPONSE_FIXTURES.moreThan400Items,
|
||||
'getTrustlines'
|
||||
)
|
||||
},
|
||||
}
|
||||
24
test/client/hasNextPage/index.ts
Normal file
24
test/client/hasNextPage/index.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import assert from 'assert-diff'
|
||||
import {TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'returns true when there is another page': async (client, address) => {
|
||||
const response = await client.request('ledger_data')
|
||||
assert(client.hasNextPage(response))
|
||||
},
|
||||
|
||||
'returns false when there are no more pages': async (client, address) => {
|
||||
const response = await client.request('ledger_data')
|
||||
const responseNextPage = await client.requestNextPage(
|
||||
'ledger_data',
|
||||
{},
|
||||
response
|
||||
)
|
||||
assert(!client.hasNextPage(responseNextPage))
|
||||
}
|
||||
}
|
||||
15
test/client/isConnected/index.ts
Normal file
15
test/client/isConnected/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import assert from 'assert-diff'
|
||||
import {TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'disconnect & isConnected': async (client, address) => {
|
||||
assert.strictEqual(client.isConnected(), true)
|
||||
await client.disconnect()
|
||||
assert.strictEqual(client.isConnected(), false)
|
||||
}
|
||||
}
|
||||
17
test/client/isValidAddress/index.ts
Normal file
17
test/client/isValidAddress/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import assert from 'assert-diff'
|
||||
import {TestSuite} from '../../utils'
|
||||
import addresses from '../../fixtures/addresses.json'
|
||||
|
||||
export default <TestSuite>{
|
||||
'returns true for valid address': async (client, address) => {
|
||||
assert(client.isValidAddress('rLczgQHxPhWtjkaQqn3Q6UM8AbRbbRvs5K'))
|
||||
assert(client.isValidAddress(addresses.ACCOUNT_X))
|
||||
assert(client.isValidAddress(addresses.ACCOUNT_T))
|
||||
},
|
||||
|
||||
'returns false for invalid address': async (client, address) => {
|
||||
assert(!client.isValidAddress('foobar'))
|
||||
assert(!client.isValidAddress(addresses.ACCOUNT_X.slice(0, -1)))
|
||||
assert(!client.isValidAddress(addresses.ACCOUNT_T.slice(1)))
|
||||
}
|
||||
}
|
||||
12
test/client/isValidSecret/index.ts
Normal file
12
test/client/isValidSecret/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import assert from 'assert-diff'
|
||||
import {TestSuite} from '../../utils'
|
||||
|
||||
export default <TestSuite>{
|
||||
'returns true for valid secret': async (client, address) => {
|
||||
assert(client.isValidSecret('snsakdSrZSLkYpCXxfRkS4Sh96PMK'))
|
||||
},
|
||||
|
||||
'returns false for invalid secret': async (client, address) => {
|
||||
assert(!client.isValidSecret('foobar'))
|
||||
}
|
||||
}
|
||||
33
test/client/prepareCheckCancel/index.ts
Normal file
33
test/client/prepareCheckCancel/index.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'prepareCheckCancel': async (client, address) => {
|
||||
const result = await client.prepareCheckCancel(
|
||||
address,
|
||||
requests.prepareCheckCancel.normal
|
||||
)
|
||||
assertResultMatch(result, responses.prepareCheckCancel.normal, 'prepare')
|
||||
},
|
||||
|
||||
'with ticket': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23
|
||||
}
|
||||
const result = await client.prepareCheckCancel(
|
||||
address,
|
||||
requests.prepareCheckCancel.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(result, responses.prepareCheckCancel.ticket, 'prepare')
|
||||
}
|
||||
}
|
||||
41
test/client/prepareCheckCash/index.ts
Normal file
41
test/client/prepareCheckCash/index.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'prepareCheckCash amount': async (client, address) => {
|
||||
const result = await client.prepareCheckCash(
|
||||
address,
|
||||
requests.prepareCheckCash.amount
|
||||
)
|
||||
assertResultMatch(result, responses.prepareCheckCash.amount, 'prepare')
|
||||
},
|
||||
|
||||
'prepareCheckCash deliverMin': async (client, address) => {
|
||||
const result = await client.prepareCheckCash(
|
||||
address,
|
||||
requests.prepareCheckCash.deliverMin
|
||||
)
|
||||
assertResultMatch(result, responses.prepareCheckCash.deliverMin, 'prepare')
|
||||
},
|
||||
|
||||
'with ticket': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23
|
||||
}
|
||||
const result = await client.prepareCheckCash(
|
||||
address,
|
||||
requests.prepareCheckCash.amount,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(result, responses.prepareCheckCash.ticket, 'prepare')
|
||||
}
|
||||
}
|
||||
46
test/client/prepareCheckCreate/index.ts
Normal file
46
test/client/prepareCheckCreate/index.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'prepareCheckCreate': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012'
|
||||
}
|
||||
const result = await client.prepareCheckCreate(
|
||||
address,
|
||||
requests.prepareCheckCreate.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(result, responses.prepareCheckCreate.normal, 'prepare')
|
||||
},
|
||||
|
||||
'prepareCheckCreate full': async (client, address) => {
|
||||
const result = await client.prepareCheckCreate(
|
||||
address,
|
||||
requests.prepareCheckCreate.full
|
||||
)
|
||||
assertResultMatch(result, responses.prepareCheckCreate.full, 'prepare')
|
||||
},
|
||||
|
||||
'prepareCheckCreate with ticket': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23
|
||||
}
|
||||
const result = await client.prepareCheckCreate(
|
||||
address,
|
||||
requests.prepareCheckCreate.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(result, responses.prepareCheckCreate.ticket, 'prepare')
|
||||
}
|
||||
}
|
||||
54
test/client/prepareEscrowCancellation/index.ts
Normal file
54
test/client/prepareEscrowCancellation/index.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'prepareEscrowCancellation': async (client, address) => {
|
||||
const result = await client.prepareEscrowCancellation(
|
||||
address,
|
||||
requests.prepareEscrowCancellation.normal,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareEscrowCancellation.normal,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
|
||||
'prepareEscrowCancellation with memos': async (client, address) => {
|
||||
const result = await client.prepareEscrowCancellation(
|
||||
address,
|
||||
requests.prepareEscrowCancellation.memos
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareEscrowCancellation.memos,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
|
||||
'with ticket': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23
|
||||
}
|
||||
const result = await client.prepareEscrowCancellation(
|
||||
address,
|
||||
requests.prepareEscrowCancellation.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareEscrowCancellation.ticket,
|
||||
'prepare'
|
||||
)
|
||||
}
|
||||
}
|
||||
63
test/client/prepareEscrowCreation/index.ts
Normal file
63
test/client/prepareEscrowCreation/index.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertRejects, assertResultMatch, TestSuite} from '../../utils'
|
||||
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
|
||||
export const config = {
|
||||
// TODO: The mock server right now returns a hard-coded string, no matter
|
||||
// what "Account" value you pass. We'll need it to support more accurate
|
||||
// responses before we can turn these tests on.
|
||||
skipXAddress: true
|
||||
}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'prepareEscrowCreation': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012'
|
||||
}
|
||||
const result = await client.prepareEscrowCreation(
|
||||
address,
|
||||
requests.prepareEscrowCreation.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(result, responses.prepareEscrowCreation.normal, 'prepare')
|
||||
},
|
||||
|
||||
'prepareEscrowCreation full': async (client, address) => {
|
||||
const result = await client.prepareEscrowCreation(
|
||||
address,
|
||||
requests.prepareEscrowCreation.full
|
||||
)
|
||||
assertResultMatch(result, responses.prepareEscrowCreation.full, 'prepare')
|
||||
},
|
||||
|
||||
'prepareEscrowCreation - invalid': async (client, address) => {
|
||||
const escrow = Object.assign({}, requests.prepareEscrowCreation.full)
|
||||
delete escrow.amount // Make invalid
|
||||
await assertRejects(
|
||||
client.prepareEscrowCreation(address, escrow),
|
||||
client.errors.ValidationError,
|
||||
'instance.escrowCreation requires property "amount"'
|
||||
)
|
||||
},
|
||||
|
||||
'with ticket': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000396',
|
||||
ticketSequence: 23
|
||||
}
|
||||
const result = await client.prepareEscrowCreation(
|
||||
address,
|
||||
requests.prepareEscrowCreation.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(result, responses.prepareEscrowCreation.ticket, 'prepare')
|
||||
}
|
||||
}
|
||||
78
test/client/prepareEscrowExecution/index.ts
Normal file
78
test/client/prepareEscrowExecution/index.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import {TestSuite, assertRejects, assertResultMatch} from '../../utils'
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'prepareEscrowExecution': async (client, address) => {
|
||||
const result = await client.prepareEscrowExecution(
|
||||
address,
|
||||
requests.prepareEscrowExecution.normal,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareEscrowExecution.normal,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
|
||||
'prepareEscrowExecution - simple': async (client, address) => {
|
||||
const result = await client.prepareEscrowExecution(
|
||||
address,
|
||||
requests.prepareEscrowExecution.simple
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareEscrowExecution.simple,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
|
||||
'prepareEscrowExecution - no condition': async (client, address) => {
|
||||
await assertRejects(
|
||||
client.prepareEscrowExecution(
|
||||
address,
|
||||
requests.prepareEscrowExecution.noCondition,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
),
|
||||
client.errors.ValidationError,
|
||||
'"condition" and "fulfillment" fields on EscrowFinish must only be specified together.'
|
||||
)
|
||||
},
|
||||
|
||||
'prepareEscrowExecution - no fulfillment': async (client, address) => {
|
||||
await assertRejects(
|
||||
client.prepareEscrowExecution(
|
||||
address,
|
||||
requests.prepareEscrowExecution.noFulfillment,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
),
|
||||
client.errors.ValidationError,
|
||||
'"condition" and "fulfillment" fields on EscrowFinish must only be specified together.'
|
||||
)
|
||||
},
|
||||
|
||||
'with ticket': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000396',
|
||||
ticketSequence: 23
|
||||
}
|
||||
const result = await client.prepareEscrowExecution(
|
||||
address,
|
||||
requests.prepareEscrowExecution.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareEscrowExecution.ticket,
|
||||
'prepare'
|
||||
)
|
||||
}
|
||||
}
|
||||
63
test/client/prepareOrder/index.ts
Normal file
63
test/client/prepareOrder/index.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertRejects, assertResultMatch, TestSuite} from '../../utils'
|
||||
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'buy order': async (client, address) => {
|
||||
const request = requests.prepareOrder.buy
|
||||
const result = await client.prepareOrder(address, request)
|
||||
assertResultMatch(result, responses.prepareOrder.buy, 'prepare')
|
||||
},
|
||||
|
||||
'buy order with expiration': async (client, address) => {
|
||||
const request = requests.prepareOrder.expiration
|
||||
const response = responses.prepareOrder.expiration
|
||||
const result = await client.prepareOrder(
|
||||
address,
|
||||
request,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(result, response, 'prepare')
|
||||
},
|
||||
|
||||
'sell order': async (client, address) => {
|
||||
const request = requests.prepareOrder.sell
|
||||
const result = await client.prepareOrder(
|
||||
address,
|
||||
request,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(result, responses.prepareOrder.sell, 'prepare')
|
||||
},
|
||||
|
||||
'invalid': async (client, address) => {
|
||||
const request = Object.assign({}, requests.prepareOrder.sell)
|
||||
delete request.direction // Make invalid
|
||||
await assertRejects(
|
||||
client.prepareOrder(
|
||||
address,
|
||||
request,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
),
|
||||
client.errors.ValidationError,
|
||||
'instance.order requires property "direction"'
|
||||
)
|
||||
},
|
||||
|
||||
'with ticket': async (client, address) => {
|
||||
const request = requests.prepareOrder.sell
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23
|
||||
}
|
||||
const result = await client.prepareOrder(address, request, localInstructions)
|
||||
assertResultMatch(result, responses.prepareOrder.ticket, 'prepare')
|
||||
}
|
||||
}
|
||||
78
test/client/prepareOrderCancellation/index.ts
Normal file
78
test/client/prepareOrderCancellation/index.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertRejects, assertResultMatch, TestSuite} from '../../utils'
|
||||
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'prepareOrderCancellation': async (client, address) => {
|
||||
const request = requests.prepareOrderCancellation.simple
|
||||
const result = await client.prepareOrderCancellation(
|
||||
address,
|
||||
request,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareOrderCancellation.normal,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
|
||||
'no instructions': async (client, address) => {
|
||||
const request = requests.prepareOrderCancellation.simple
|
||||
const result = await client.prepareOrderCancellation(address, request)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareOrderCancellation.noInstructions,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
|
||||
'with memos': async (client, address) => {
|
||||
const request = requests.prepareOrderCancellation.withMemos
|
||||
const result = await client.prepareOrderCancellation(address, request)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareOrderCancellation.withMemos,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
|
||||
'invalid': async (client, address) => {
|
||||
const request = Object.assign(
|
||||
{},
|
||||
requests.prepareOrderCancellation.withMemos
|
||||
)
|
||||
delete request.orderSequence // Make invalid
|
||||
|
||||
await assertRejects(
|
||||
client.prepareOrderCancellation(address, request),
|
||||
client.errors.ValidationError,
|
||||
'instance.orderCancellation requires property "orderSequence"'
|
||||
)
|
||||
},
|
||||
|
||||
'with ticket': async (client, address) => {
|
||||
const request = requests.prepareOrderCancellation.simple
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23
|
||||
}
|
||||
const result = await client.prepareOrderCancellation(
|
||||
address,
|
||||
request,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareOrderCancellation.ticket,
|
||||
'prepare'
|
||||
)
|
||||
}
|
||||
}
|
||||
534
test/client/preparePayment/index.ts
Normal file
534
test/client/preparePayment/index.ts
Normal file
@@ -0,0 +1,534 @@
|
||||
import {assertResultMatch, TestSuite, assertRejects} from '../../utils'
|
||||
import responses from '../../fixtures/responses'
|
||||
import requests from '../../fixtures/requests'
|
||||
import {ValidationError} from 'xrpl-local/common/errors'
|
||||
import binary from 'ripple-binary-codec'
|
||||
import assert from 'assert-diff'
|
||||
import {Client} from 'xrpl-local'
|
||||
|
||||
const {schemaValidator} = Client._PRIVATE
|
||||
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
const {preparePayment: REQUEST_FIXTURES} = requests
|
||||
const {preparePayment: RESPONSE_FIXTURES} = responses
|
||||
const RECIPIENT_ADDRESS = 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'normal': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012'
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
REQUEST_FIXTURES.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.normal, 'prepare')
|
||||
},
|
||||
|
||||
'min amount xrp': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012'
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
REQUEST_FIXTURES.minAmountXRP,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.minAmountXRP, 'prepare')
|
||||
},
|
||||
|
||||
'min amount xrp2xrp': async (client, address) => {
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
REQUEST_FIXTURES.minAmount,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.minAmountXRPXRP, 'prepare')
|
||||
},
|
||||
|
||||
'XRP to XRP': async (client, address) => {
|
||||
const payment = {
|
||||
source: {
|
||||
address: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||
maxAmount: {value: '1', currency: 'XRP'}
|
||||
},
|
||||
destination: {
|
||||
address: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
|
||||
amount: {value: '1', currency: 'XRP'}
|
||||
}
|
||||
}
|
||||
const expected = {
|
||||
txJSON:
|
||||
'{"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":"1000000","Flags":2147483648,"LastLedgerSequence":8820051,"Sequence":23,"Fee":"12"}',
|
||||
instructions: {
|
||||
fee: '0.000012',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
payment,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(response, expected, 'prepare')
|
||||
},
|
||||
|
||||
'XRP drops to XRP drops': async (client, address) => {
|
||||
const payment = {
|
||||
source: {
|
||||
address: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||
maxAmount: {value: '1000000', currency: 'drops'}
|
||||
},
|
||||
destination: {
|
||||
address: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
|
||||
amount: {value: '1000000', currency: 'drops'}
|
||||
}
|
||||
}
|
||||
const expected = {
|
||||
txJSON:
|
||||
'{"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":"1000000","Flags":2147483648,"LastLedgerSequence":8820051,"Sequence":23,"Fee":"12"}',
|
||||
instructions: {
|
||||
fee: '0.000012',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
payment,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(response, expected, 'prepare')
|
||||
},
|
||||
|
||||
'XRP drops to XRP': async (client, address) => {
|
||||
const payment = {
|
||||
source: {
|
||||
address: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||
maxAmount: {value: '1000000', currency: 'drops'}
|
||||
},
|
||||
destination: {
|
||||
address: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
|
||||
amount: {value: '1', currency: 'XRP'}
|
||||
}
|
||||
}
|
||||
const expected = {
|
||||
txJSON:
|
||||
'{"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":"1000000","Flags":2147483648,"LastLedgerSequence":8820051,"Sequence":23,"Fee":"12"}',
|
||||
instructions: {
|
||||
fee: '0.000012',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
payment,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(response, expected, 'prepare')
|
||||
},
|
||||
|
||||
'XRP to XRP drops': async (client, address) => {
|
||||
const payment = {
|
||||
source: {
|
||||
address: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||
maxAmount: {value: '1', currency: 'XRP'}
|
||||
},
|
||||
destination: {
|
||||
address: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
|
||||
amount: {value: '1000000', currency: 'drops'}
|
||||
}
|
||||
}
|
||||
const expected = {
|
||||
txJSON:
|
||||
'{"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":"1000000","Flags":2147483648,"LastLedgerSequence":8820051,"Sequence":23,"Fee":"12"}',
|
||||
instructions: {
|
||||
fee: '0.000012',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
payment,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(response, expected, 'prepare')
|
||||
},
|
||||
|
||||
// Errors
|
||||
'rejects promise and does not throw when payment object is invalid': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
const payment = {
|
||||
source: {
|
||||
address: address,
|
||||
// instead of `maxAmount`
|
||||
amount: {value: '1000', currency: 'drops'}
|
||||
},
|
||||
destination: {
|
||||
address: RECIPIENT_ADDRESS,
|
||||
amount: {value: '1000', currency: 'drops'}
|
||||
}
|
||||
}
|
||||
|
||||
return assertRejects(
|
||||
client.preparePayment(address, payment),
|
||||
ValidationError,
|
||||
'payment must specify either (source.maxAmount and destination.amount) or (source.amount and destination.minAmount)'
|
||||
)
|
||||
},
|
||||
|
||||
'rejects promise and does not throw when field is missing': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
// Marking as "any" to get around the fact that TS won't allow this.
|
||||
const payment: any = {
|
||||
source: {address: address},
|
||||
destination: {
|
||||
address: RECIPIENT_ADDRESS,
|
||||
amount: {value: '1000', currency: 'drops'}
|
||||
}
|
||||
}
|
||||
|
||||
return assertRejects(
|
||||
client.preparePayment(address, payment),
|
||||
ValidationError,
|
||||
'instance.payment.source is not exactly one from <sourceExactAdjustment>,<maxAdjustment>'
|
||||
)
|
||||
},
|
||||
|
||||
'rejects promise and does not throw when fee exceeds maxFeeXRP': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
const payment = {
|
||||
source: {
|
||||
address: address,
|
||||
maxAmount: {value: '1000', currency: 'drops'}
|
||||
},
|
||||
destination: {
|
||||
address: RECIPIENT_ADDRESS,
|
||||
amount: {value: '1000', currency: 'drops'}
|
||||
}
|
||||
}
|
||||
return assertRejects(
|
||||
client.preparePayment(address, payment, {fee: '3'}),
|
||||
ValidationError,
|
||||
'Fee of 3 XRP exceeds max of 2 XRP. To use this fee, increase `maxFeeXRP` in the Client constructor.'
|
||||
)
|
||||
},
|
||||
|
||||
'XRP to XRP no partial': async (client, address) => {
|
||||
return assertRejects(
|
||||
client.preparePayment(address, REQUEST_FIXTURES.wrongPartial),
|
||||
ValidationError,
|
||||
'XRP to XRP payments cannot be partial payments'
|
||||
)
|
||||
},
|
||||
|
||||
'address must match payment.source.address': async (client, address) => {
|
||||
return assertRejects(
|
||||
client.preparePayment(address, REQUEST_FIXTURES.wrongAddress),
|
||||
ValidationError,
|
||||
'address must match payment.source.address'
|
||||
)
|
||||
},
|
||||
|
||||
'wrong amount': async (client, address) => {
|
||||
return assertRejects(
|
||||
client.preparePayment(address, REQUEST_FIXTURES.wrongAmount),
|
||||
ValidationError,
|
||||
'payment must specify either (source.maxAmount and destination.amount) or (source.amount and destination.minAmount)'
|
||||
)
|
||||
},
|
||||
|
||||
'throws when fee exceeds 2 XRP': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
fee: '2.1'
|
||||
}
|
||||
return assertRejects(
|
||||
client.preparePayment(address, REQUEST_FIXTURES.normal, localInstructions),
|
||||
ValidationError,
|
||||
'Fee of 2.1 XRP exceeds max of 2 XRP. To use this fee, increase `maxFeeXRP` in the Client constructor.'
|
||||
)
|
||||
},
|
||||
|
||||
'preparePayment with all options specified': async (client, address) => {
|
||||
const version = await client.getLedgerVersion()
|
||||
const localInstructions = {
|
||||
maxLedgerVersion: version + 100,
|
||||
fee: '0.000012'
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
REQUEST_FIXTURES.allOptions,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.allOptions, 'prepare')
|
||||
},
|
||||
|
||||
'preparePayment without counterparty set': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
sequence: 23
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
REQUEST_FIXTURES.noCounterparty,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.noCounterparty, 'prepare')
|
||||
},
|
||||
|
||||
'preparePayment with source.amount/destination.minAmount can be signed': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
// See also: 'sign succeeds with source.amount/destination.minAmount'
|
||||
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
sequence: 23
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
{
|
||||
source: {
|
||||
address,
|
||||
amount: {
|
||||
currency: 'GBP',
|
||||
value: '0.1',
|
||||
counterparty: 'rpat5TmYjDsnFSStmgTumFgXCM9eqsWPro'
|
||||
}
|
||||
},
|
||||
destination: {
|
||||
address: 'rEX4LtGJubaUcMWCJULcy4NVxGT9ZEMVRq',
|
||||
minAmount: {
|
||||
currency: 'USD',
|
||||
value: '0.1248548562296331',
|
||||
counterparty: 'rMaa8VLBTjwTJWA2kSme4Sqgphhr6Lr6FH'
|
||||
}
|
||||
}
|
||||
},
|
||||
localInstructions
|
||||
)
|
||||
|
||||
// Important: check that the prepared transaction can actually be signed
|
||||
// https://github.com/ripple/ripple-lib/issues/1237#issuecomment-631670946
|
||||
|
||||
const secret = 'shotKgaEotpcYsshSE39vmSnBDRim'
|
||||
const result = client.sign(response.txJSON, secret)
|
||||
const expectedResult = {
|
||||
signedTransaction:
|
||||
'12000022800200002400000017201B0086955361EC6386F26FC0FFFF0000000000000000000000005553440000000000DC596C88BCDE4E818D416FCDEEBF2C8656BADC9A68400000000000000C69D4438D7EA4C6800000000000000000000000000047425000000000000C155FFE99C8C91F67083CEFFDB69EBFE76348CA6AD4446F8C5D8A5E0B0000000000000000000000005553440000000000DC596C88BCDE4E818D416FCDEEBF2C8656BADC9A7321022B05847086686F9D0499B13136B94AD4323EE1B67D4C429ECC987AB35ACFA34574473045022100D9634523D8E232D4A7807A71856023D82AC928FA29848571B820867898413B5F022041AC00EC1F81A26A6504EBF844A38CC3204694EF2CC1A97A87632721631F93DA81145E7B112523F68D2F5E879DB4EAC51C6698A6930483149F500E50C2F016CA01945E5A1E5846B61EF2D376',
|
||||
id: '1C558AA9B926C24FB6BBD6950B2DB1350A83F9F12E4385208867907019761A2D'
|
||||
}
|
||||
const decoded = binary.decode(result.signedTransaction)
|
||||
assert(
|
||||
decoded.Flags === 2147614720,
|
||||
`Flags = ${decoded.Flags}, should be 2147614720`
|
||||
)
|
||||
assert.deepEqual(result, expectedResult)
|
||||
schemaValidator.schemaValidate('sign', result)
|
||||
},
|
||||
|
||||
'destination.minAmount': async (client, address) => {
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
responses.getPaths.sendAll[0],
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.minAmount, 'prepare')
|
||||
},
|
||||
|
||||
'caps fee at 2 XRP by default': async (client, address) => {
|
||||
client._feeCushion = 1000000
|
||||
const expectedResponse = {
|
||||
txJSON:
|
||||
'{"Flags":2147483648,"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"SendMax":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"LastLedgerSequence":8820051,"Fee":"2000000","Sequence":23}',
|
||||
instructions: {
|
||||
fee: '2',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
REQUEST_FIXTURES.normal,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(response, expectedResponse, 'prepare')
|
||||
},
|
||||
|
||||
'allows fee exceeding 2 XRP when maxFeeXRP is higher': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
client._maxFeeXRP = '2.2'
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
fee: '2.1'
|
||||
}
|
||||
const expectedResponse = {
|
||||
txJSON:
|
||||
'{"Flags":2147483648,"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"SendMax":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"LastLedgerSequence":8820051,"Fee":"2100000","Sequence":23}',
|
||||
instructions: {
|
||||
fee: '2.1',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
REQUEST_FIXTURES.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(response, expectedResponse, 'prepare')
|
||||
},
|
||||
|
||||
'fee - default maxFee of 2 XRP': async (client, address) => {
|
||||
client._feeCushion = 1000000
|
||||
const expectedResponse = {
|
||||
txJSON:
|
||||
'{"Flags":2147483648,"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"SendMax":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"LastLedgerSequence":8820051,"Fee":"2000000","Sequence":23}',
|
||||
instructions: {
|
||||
fee: '2',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
requests.preparePayment.normal,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(response, expectedResponse, 'prepare')
|
||||
},
|
||||
|
||||
'fee - capped to maxFeeXRP when maxFee exceeds maxFeeXRP': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
client._feeCushion = 1000000
|
||||
client._maxFeeXRP = '3'
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '4'
|
||||
}
|
||||
const expectedResponse = {
|
||||
txJSON:
|
||||
'{"Flags":2147483648,"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"SendMax":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"LastLedgerSequence":8820051,"Fee":"3000000","Sequence":23}',
|
||||
instructions: {
|
||||
fee: '3',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
requests.preparePayment.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(response, expectedResponse, 'prepare')
|
||||
},
|
||||
|
||||
'fee - capped to maxFee': async (client, address) => {
|
||||
client._feeCushion = 1000000
|
||||
client._maxFeeXRP = '5'
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '4'
|
||||
}
|
||||
const expectedResponse = {
|
||||
txJSON:
|
||||
'{"Flags":2147483648,"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"SendMax":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"LastLedgerSequence":8820051,"Fee":"4000000","Sequence":23}',
|
||||
instructions: {
|
||||
fee: '4',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
requests.preparePayment.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(response, expectedResponse, 'prepare')
|
||||
},
|
||||
|
||||
'fee - calculated fee does not use more than 6 decimal places': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
client.connection.request({
|
||||
command: 'config',
|
||||
data: {loadFactor: 5407.96875}
|
||||
})
|
||||
const expectedResponse = {
|
||||
txJSON:
|
||||
'{"Flags":2147483648,"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"SendMax":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"LastLedgerSequence":8820051,"Fee":"64896","Sequence":23}',
|
||||
instructions: {
|
||||
fee: '0.064896',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
requests.preparePayment.normal,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(response, expectedResponse, 'prepare')
|
||||
},
|
||||
|
||||
// Tickets
|
||||
'preparePayment with ticketSequence': async (client, address) => {
|
||||
const version = await client.getLedgerVersion()
|
||||
const localInstructions = {
|
||||
maxLedgerVersion: version + 100,
|
||||
fee: '0.000012',
|
||||
ticketSequence: 23
|
||||
}
|
||||
const response = await client.preparePayment(
|
||||
address,
|
||||
REQUEST_FIXTURES.allOptions,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.ticketSequence, 'prepare')
|
||||
},
|
||||
|
||||
'throws when both sequence and ticketSequence are set': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
const version = await client.getLedgerVersion()
|
||||
const localInstructions = {
|
||||
maxLedgerVersion: version + 100,
|
||||
fee: '0.000012',
|
||||
ticketSequence: 23,
|
||||
sequence: 12
|
||||
}
|
||||
return assertRejects(
|
||||
client.preparePayment(
|
||||
address,
|
||||
REQUEST_FIXTURES.allOptions,
|
||||
localInstructions
|
||||
),
|
||||
ValidationError,
|
||||
'instance.instructions is of prohibited type [object Object]'
|
||||
)
|
||||
}
|
||||
}
|
||||
111
test/client/preparePaymentChannelClaim/index.ts
Normal file
111
test/client/preparePaymentChannelClaim/index.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import assert from 'assert-diff'
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
const {preparePaymentChannelClaim: REQUEST_FIXTURES} = requests
|
||||
const {preparePaymentChannelClaim: RESPONSE_FIXTURES} = responses
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'default': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012'
|
||||
}
|
||||
const response = await client.preparePaymentChannelClaim(
|
||||
address,
|
||||
REQUEST_FIXTURES.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.normal, 'prepare')
|
||||
},
|
||||
|
||||
'with renew': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012'
|
||||
}
|
||||
const response = await client.preparePaymentChannelClaim(
|
||||
address,
|
||||
REQUEST_FIXTURES.renew,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.renew, 'prepare')
|
||||
},
|
||||
|
||||
'with close': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012'
|
||||
}
|
||||
const response = await client.preparePaymentChannelClaim(
|
||||
address,
|
||||
REQUEST_FIXTURES.close,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.close, 'prepare')
|
||||
},
|
||||
|
||||
'with ticket': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23
|
||||
}
|
||||
const response = await client.preparePaymentChannelClaim(
|
||||
address,
|
||||
REQUEST_FIXTURES.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.ticket, 'prepare')
|
||||
},
|
||||
|
||||
'rejects Promise on preparePaymentChannelClaim with renew and close': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
try {
|
||||
const prepared = await client.preparePaymentChannelClaim(
|
||||
address,
|
||||
REQUEST_FIXTURES.full
|
||||
)
|
||||
throw new Error(
|
||||
'Expected method to reject. Prepared transaction: ' +
|
||||
JSON.stringify(prepared)
|
||||
)
|
||||
} catch (err) {
|
||||
assert.strictEqual(err.name, 'ValidationError')
|
||||
assert.strictEqual(
|
||||
err.message,
|
||||
'"renew" and "close" flags on PaymentChannelClaim are mutually exclusive'
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
'rejects Promise on preparePaymentChannelClaim with no signature': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
try {
|
||||
const prepared = await client.preparePaymentChannelClaim(
|
||||
address,
|
||||
REQUEST_FIXTURES.noSignature
|
||||
)
|
||||
throw new Error(
|
||||
'Expected method to reject. Prepared transaction: ' +
|
||||
JSON.stringify(prepared)
|
||||
)
|
||||
} catch (err) {
|
||||
assert.strictEqual(err.name, 'ValidationError')
|
||||
assert.strictEqual(
|
||||
err.message,
|
||||
'"signature" and "publicKey" fields on PaymentChannelClaim must only be specified together.'
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
65
test/client/preparePaymentChannelCreate/index.ts
Normal file
65
test/client/preparePaymentChannelCreate/index.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
|
||||
export const config = {
|
||||
// TODO: The mock server right now returns a hard-coded string, no matter
|
||||
// what "Account" value you pass. We'll need it to support more accurate
|
||||
// responses before we can turn these tests on.
|
||||
skipXAddress: true
|
||||
}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'preparePaymentChannelCreate': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012'
|
||||
}
|
||||
const result = await client.preparePaymentChannelCreate(
|
||||
address,
|
||||
requests.preparePaymentChannelCreate.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.preparePaymentChannelCreate.normal,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
|
||||
'preparePaymentChannelCreate full': async (client, address) => {
|
||||
const result = await client.preparePaymentChannelCreate(
|
||||
address,
|
||||
requests.preparePaymentChannelCreate.full
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.preparePaymentChannelCreate.full,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
|
||||
'preparePaymentChannelCreate with ticket': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23
|
||||
}
|
||||
const result = await client.preparePaymentChannelCreate(
|
||||
address,
|
||||
requests.preparePaymentChannelCreate.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.preparePaymentChannelCreate.ticket,
|
||||
'prepare'
|
||||
)
|
||||
}
|
||||
}
|
||||
58
test/client/preparePaymentChannelFund/index.ts
Normal file
58
test/client/preparePaymentChannelFund/index.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'preparePaymentChannelFund': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012'
|
||||
}
|
||||
const result = await client.preparePaymentChannelFund(
|
||||
address,
|
||||
requests.preparePaymentChannelFund.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.preparePaymentChannelFund.normal,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
|
||||
'preparePaymentChannelFund full': async (client, address) => {
|
||||
const result = await client.preparePaymentChannelFund(
|
||||
address,
|
||||
requests.preparePaymentChannelFund.full
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.preparePaymentChannelFund.full,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
|
||||
'with ticket': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23
|
||||
}
|
||||
const result = await client.preparePaymentChannelFund(
|
||||
address,
|
||||
requests.preparePaymentChannelFund.normal,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.preparePaymentChannelFund.ticket,
|
||||
'prepare'
|
||||
)
|
||||
}
|
||||
}
|
||||
268
test/client/prepareSettings/index.ts
Normal file
268
test/client/prepareSettings/index.ts
Normal file
@@ -0,0 +1,268 @@
|
||||
import assert from 'assert-diff'
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'simple test': async (client, address) => {
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
requests.prepareSettings.domain,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(response, responses.prepareSettings.flags, 'prepare')
|
||||
},
|
||||
'no maxLedgerVersion': async (client, address) => {
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
requests.prepareSettings.domain,
|
||||
{
|
||||
maxLedgerVersion: null
|
||||
}
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.noMaxLedgerVersion,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
'no instructions': async (client, address) => {
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
requests.prepareSettings.domain
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.noInstructions,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
'regularKey': async (client, address) => {
|
||||
const regularKey = {regularKey: 'rAR8rR8sUkBoCZFawhkWzY4Y5YoyuznwD'}
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
regularKey,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(response, responses.prepareSettings.regularKey, 'prepare')
|
||||
},
|
||||
'remove regularKey': async (client, address) => {
|
||||
const regularKey = {regularKey: null}
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
regularKey,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.removeRegularKey,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
'flag set': async (client, address) => {
|
||||
const settings = {requireDestinationTag: true}
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(response, responses.prepareSettings.flagSet, 'prepare')
|
||||
},
|
||||
'flag clear': async (client, address) => {
|
||||
const settings = {requireDestinationTag: false}
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(response, responses.prepareSettings.flagClear, 'prepare')
|
||||
},
|
||||
'set depositAuth flag': async (client, address) => {
|
||||
const settings = {depositAuth: true}
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.flagSetDepositAuth,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
'clear depositAuth flag': async (client, address) => {
|
||||
const settings = {depositAuth: false}
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.flagClearDepositAuth,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
'integer field clear': async (client, address) => {
|
||||
const settings = {transferRate: null}
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assert(response)
|
||||
assert.strictEqual(JSON.parse(response.txJSON).TransferRate, 0)
|
||||
},
|
||||
'set transferRate': async (client, address) => {
|
||||
const settings = {transferRate: 1}
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.setTransferRate,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
'set signers': async (client, address) => {
|
||||
const settings = requests.prepareSettings.signers.normal
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(response, responses.prepareSettings.signers, 'prepare')
|
||||
},
|
||||
'signers no threshold': async (client, address) => {
|
||||
const settings = requests.prepareSettings.signers.noThreshold
|
||||
try {
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
throw new Error(
|
||||
'Expected method to reject. Prepared transaction: ' +
|
||||
JSON.stringify(response)
|
||||
)
|
||||
} catch (err) {
|
||||
assert.strictEqual(
|
||||
err.message,
|
||||
'instance.settings.signers requires property "threshold"'
|
||||
)
|
||||
assert.strictEqual(err.name, 'ValidationError')
|
||||
}
|
||||
},
|
||||
'signers no weights': async (client, address) => {
|
||||
const settings = requests.prepareSettings.signers.noWeights
|
||||
const localInstructions = {
|
||||
signersCount: 1,
|
||||
...instructionsWithMaxLedgerVersionOffset
|
||||
}
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
settings,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(response, responses.prepareSettings.noWeights, 'prepare')
|
||||
},
|
||||
'fee for multisign': async (client, address) => {
|
||||
const localInstructions = {
|
||||
signersCount: 4,
|
||||
...instructionsWithMaxLedgerVersionOffset
|
||||
}
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
requests.prepareSettings.domain,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.flagsMultisign,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
'no signer list': async (client, address) => {
|
||||
const settings = requests.prepareSettings.noSignerEntries
|
||||
const localInstructions = {
|
||||
signersCount: 1,
|
||||
...instructionsWithMaxLedgerVersionOffset
|
||||
}
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
settings,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.noSignerList,
|
||||
'prepare'
|
||||
)
|
||||
},
|
||||
'invalid': async (client, address) => {
|
||||
// domain must be a string
|
||||
const settings = Object.assign({}, requests.prepareSettings.domain, {
|
||||
domain: 123
|
||||
})
|
||||
const localInstructions = {
|
||||
signersCount: 4,
|
||||
...instructionsWithMaxLedgerVersionOffset
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
settings,
|
||||
localInstructions
|
||||
)
|
||||
throw new Error(
|
||||
'Expected method to reject. Prepared transaction: ' +
|
||||
JSON.stringify(response)
|
||||
)
|
||||
} catch (err) {
|
||||
assert.strictEqual(
|
||||
err.message,
|
||||
'instance.settings.domain is not of a type(s) string'
|
||||
)
|
||||
assert.strictEqual(err.name, 'ValidationError')
|
||||
}
|
||||
},
|
||||
'offline': async (client, address) => {
|
||||
// const client = new Client()
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
|
||||
const settings = requests.prepareSettings.domain
|
||||
const instructions = {
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
fee: '0.000012'
|
||||
}
|
||||
const result = await client.prepareSettings(address, settings, instructions)
|
||||
assertResultMatch(result, responses.prepareSettings.flags, 'prepare')
|
||||
assert.deepEqual(
|
||||
client.sign(result.txJSON, secret),
|
||||
responses.prepareSettings.signed
|
||||
)
|
||||
},
|
||||
'prepare settings with ticket': async (client, address) => {
|
||||
const instructions = {
|
||||
ticketSequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
fee: '0.000012'
|
||||
}
|
||||
const response = await client.prepareSettings(
|
||||
address,
|
||||
requests.prepareSettings.domain,
|
||||
instructions
|
||||
)
|
||||
assertResultMatch(response, responses.prepareSettings.ticket, 'prepare')
|
||||
}
|
||||
}
|
||||
56
test/client/prepareTicket/index.ts
Normal file
56
test/client/prepareTicket/index.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
// import responses from '../../fixtures/responses'
|
||||
// import requests from '../../fixtures/requests'
|
||||
// import {ValidationError} from 'xrpl-local/common/errors'
|
||||
// import binary from 'ripple-binary-codec'
|
||||
// import assert from 'assert-diff'
|
||||
// import {Client} from 'xrpl-local'
|
||||
|
||||
// const {schemaValidator} = Client._PRIVATE
|
||||
// const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
// const {preparePayment: REQUEST_FIXTURES} = requests
|
||||
// const {preparePayment: RESPONSE_FIXTURES} = responses
|
||||
// const ADDRESS = 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'creates a ticket successfully with a sequence number': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
const expected = {
|
||||
txJSON:
|
||||
'{"TransactionType":"TicketCreate", "TicketCount": 2, "Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Flags":2147483648,"LastLedgerSequence":8819954,"Sequence":23,"Fee":"12"}',
|
||||
instructions: {
|
||||
maxLedgerVersion: 8819954,
|
||||
sequence: 23,
|
||||
fee: '0.000012'
|
||||
}
|
||||
}
|
||||
const response = await client.prepareTicketCreate(address, 2)
|
||||
assertResultMatch(response, expected, 'prepare')
|
||||
},
|
||||
|
||||
'creates a ticket successfully with another ticket': async (client, address) => {
|
||||
const expected = {
|
||||
txJSON:
|
||||
'{"TransactionType":"TicketCreate", "TicketCount": 1, "Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Flags":2147483648,"LastLedgerSequence":8819954,"Sequence": 0,"TicketSequence":23,"Fee":"12"}',
|
||||
instructions: {
|
||||
maxLedgerVersion: 8819954,
|
||||
ticketSequence: 23,
|
||||
fee: '0.000012'
|
||||
}
|
||||
}
|
||||
const instructions = {
|
||||
maxLedgerVersion: 8819954,
|
||||
ticketSequence: 23,
|
||||
fee: '0.000012'
|
||||
}
|
||||
const response = await client.prepareTicketCreate(address, 1, instructions)
|
||||
assertResultMatch(response, expected, 'prepare')
|
||||
}
|
||||
}
|
||||
1357
test/client/prepareTransaction/index.ts
Normal file
1357
test/client/prepareTransaction/index.ts
Normal file
File diff suppressed because it is too large
Load Diff
75
test/client/prepareTrustline/index.ts
Normal file
75
test/client/prepareTrustline/index.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertRejects, assertResultMatch, TestSuite} from '../../utils'
|
||||
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'simple': async (client, address) => {
|
||||
const result = await client.prepareTrustline(
|
||||
address,
|
||||
requests.prepareTrustline.simple,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(result, responses.prepareTrustline.simple, 'prepare')
|
||||
},
|
||||
|
||||
'frozen': async (client, address) => {
|
||||
const result = await client.prepareTrustline(
|
||||
address,
|
||||
requests.prepareTrustline.frozen
|
||||
)
|
||||
assertResultMatch(result, responses.prepareTrustline.frozen, 'prepare')
|
||||
},
|
||||
|
||||
'complex': async (client, address) => {
|
||||
const result = await client.prepareTrustline(
|
||||
address,
|
||||
requests.prepareTrustline.complex,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(result, responses.prepareTrustline.complex, 'prepare')
|
||||
},
|
||||
|
||||
'invalid': async (client, address) => {
|
||||
const trustline = Object.assign({}, requests.prepareTrustline.complex)
|
||||
delete trustline.limit // Make invalid
|
||||
|
||||
await assertRejects(
|
||||
client.prepareTrustline(
|
||||
address,
|
||||
trustline,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
),
|
||||
client.errors.ValidationError,
|
||||
'instance.trustline requires property "limit"'
|
||||
)
|
||||
},
|
||||
|
||||
'xaddress-issuer': async (client, address) => {
|
||||
const result = await client.prepareTrustline(
|
||||
address,
|
||||
requests.prepareTrustline.issuedXAddress,
|
||||
instructionsWithMaxLedgerVersionOffset
|
||||
)
|
||||
assertResultMatch(result, responses.prepareTrustline.issuedXAddress, 'prepare')
|
||||
},
|
||||
|
||||
'with ticket': async (client, address) => {
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23
|
||||
}
|
||||
const result = await client.prepareTrustline(
|
||||
address,
|
||||
requests.prepareTrustline.simple,
|
||||
localInstructions
|
||||
)
|
||||
assertResultMatch(result, responses.prepareTrustline.ticket, 'prepare')
|
||||
}
|
||||
}
|
||||
35
test/client/request/index.ts
Normal file
35
test/client/request/index.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'request account_objects': async (client, address) => {
|
||||
const result = await client.request('account_objects', {
|
||||
account: address
|
||||
})
|
||||
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.getAccountObjects,
|
||||
'AccountObjectsResponse'
|
||||
)
|
||||
},
|
||||
|
||||
'request account_objects - invalid options': async (client, address) => {
|
||||
// Intentionally no local validation of these options
|
||||
const result = await client.request('account_objects', {
|
||||
account: address,
|
||||
invalid: 'options'
|
||||
})
|
||||
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.getAccountObjects,
|
||||
'AccountObjectsResponse'
|
||||
)
|
||||
}
|
||||
}
|
||||
38
test/client/requestNextPage/index.ts
Normal file
38
test/client/requestNextPage/index.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import assert from 'assert-diff'
|
||||
import {LedgerData} from 'xrpl-local/common/types/objects'
|
||||
import {assertRejects, TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'requests the next page': async (client, address) => {
|
||||
const response = await client.request('ledger_data')
|
||||
const responseNextPage = await client.requestNextPage<LedgerData>(
|
||||
'ledger_data',
|
||||
{},
|
||||
response
|
||||
)
|
||||
assert.equal(
|
||||
responseNextPage.state[0].index,
|
||||
'000B714B790C3C79FEE00D17C4DEB436B375466F29679447BA64F265FD63D731'
|
||||
)
|
||||
},
|
||||
|
||||
'rejects when there are no more pages': async (client, address) => {
|
||||
const response = await client.request('ledger_data')
|
||||
const responseNextPage = await client.requestNextPage(
|
||||
'ledger_data',
|
||||
{},
|
||||
response
|
||||
)
|
||||
assert(!client.hasNextPage(responseNextPage))
|
||||
await assertRejects(
|
||||
client.requestNextPage('ledger_data', {}, responseNextPage),
|
||||
Error,
|
||||
'response does not have a next page'
|
||||
)
|
||||
}
|
||||
}
|
||||
408
test/client/sign/index.ts
Normal file
408
test/client/sign/index.ts
Normal file
@@ -0,0 +1,408 @@
|
||||
import assert from 'assert-diff'
|
||||
import {Client} from 'xrpl-local'
|
||||
import binary from 'ripple-binary-codec'
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {TestSuite} from '../../utils'
|
||||
|
||||
const {schemaValidator} = Client._PRIVATE
|
||||
const {sign: REQUEST_FIXTURES} = requests
|
||||
const {sign: RESPONSE_FIXTURES} = responses
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'sign': async (client, address) => {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const result = client.sign(REQUEST_FIXTURES.normal.txJSON, secret)
|
||||
assert.deepEqual(result, RESPONSE_FIXTURES.normal)
|
||||
schemaValidator.schemaValidate('sign', result)
|
||||
},
|
||||
|
||||
'sign with lowercase hex data in memo (hex should be case insensitive)': async (client, address) => {
|
||||
const secret = 'shd2nxpFD6iBRKWsRss2P4tKMWyy9';
|
||||
const lowercaseMemoTxJson = {
|
||||
"TransactionType" : "Payment",
|
||||
"Flags" : 2147483648,
|
||||
"Account" : "rwiZ3q3D3QuG4Ga2HyGdq3kPKJRGctVG8a",
|
||||
"Amount" : "10000000",
|
||||
"LastLedgerSequence": 14000999,
|
||||
"Destination" : "rUeEBYXHo8vF86Rqir3zWGRQ84W9efdAQd",
|
||||
"Fee" : "12",
|
||||
"Sequence" : 12,
|
||||
"SourceTag" : 8888,
|
||||
"DestinationTag" : 9999,
|
||||
"Memos" : [
|
||||
{
|
||||
"Memo": {
|
||||
"MemoType" :"687474703a2f2f6578616d706c652e636f6d2f6d656d6f2f67656e65726963",
|
||||
"MemoData" :"72656e74"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const txParams = JSON.stringify(lowercaseMemoTxJson);
|
||||
const result = client.sign(txParams, secret);
|
||||
assert.deepEqual(result, {
|
||||
signedTransaction: '120000228000000023000022B8240000000C2E0000270F201B00D5A36761400000000098968068400000000000000C73210305E09ED602D40AB1AF65646A4007C2DAC17CB6CDACDE301E74FB2D728EA057CF744730450221009C00E8439E017CA622A5A1EE7643E26B4DE9C808DE2ABE45D33479D49A4CEC66022062175BE8733442FA2A4D9A35F85A57D58252AE7B19A66401FE238B36FA28E5A081146C1856D0E36019EA75C56D7E8CBA6E35F9B3F71583147FB49CD110A1C46838788CD12764E3B0F837E0DDF9EA7C1F687474703A2F2F6578616D706C652E636F6D2F6D656D6F2F67656E657269637D0472656E74E1F1',
|
||||
id: '41B9CB78D8E18A796CDD4B0BC6FB0EA19F64C4F25FDE23049197852CAB71D10D'
|
||||
})
|
||||
},
|
||||
|
||||
'sign with paths': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const payment = {
|
||||
source: {
|
||||
address: address,
|
||||
amount: {
|
||||
currency: 'drops',
|
||||
value: '100'
|
||||
}
|
||||
},
|
||||
destination: {
|
||||
address: 'rKT4JX4cCof6LcDYRz8o3rGRu7qxzZ2Zwj',
|
||||
minAmount: {
|
||||
currency: 'USD',
|
||||
value: '0.00004579644712312366',
|
||||
counterparty: 'rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc'
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
paths: '[[{\"currency\":\"USD\",\"issuer\":\"rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc\"}]]'
|
||||
}
|
||||
const ret = await client.preparePayment(address, payment, {sequence: 1, maxLedgerVersion: 15696358})
|
||||
const result = client.sign(ret.txJSON, secret)
|
||||
assert.deepEqual(result, {
|
||||
signedTransaction: '12000022800200002400000001201B00EF81E661EC6386F26FC0FFFF0000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D166461968400000000000000C6940000000000000646AD3504529A0465E2E0000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D1664619732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402200A693FB5CA6B21250EBDFD8CFF526EE0DF7C9E4E31EB0660692E75E6A93BF5F802203CC39463DDA21386898CA31E18AD1A6828647D65741DD637BAD71BC83E29DB9481145E7B112523F68D2F5E879DB4EAC51C6698A693048314CA6EDC7A28252DAEA6F2045B24F4D7C333E146170112300000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D166461900',
|
||||
id: '78874FE5F5299FEE3EA85D3CF6C1FB1F1D46BB08F716662A3E3D1F0ADE4EF796'
|
||||
})
|
||||
schemaValidator.schemaValidate('sign', result)
|
||||
},
|
||||
|
||||
'already signed': async (client, address) => {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const result = client.sign(REQUEST_FIXTURES.normal.txJSON, secret)
|
||||
assert.throws(() => {
|
||||
const tx = JSON.stringify(binary.decode(result.signedTransaction))
|
||||
client.sign(tx, secret)
|
||||
}, /txJSON must not contain "TxnSignature" or "Signers" properties/)
|
||||
},
|
||||
|
||||
'EscrowExecution': async (client, address) => {
|
||||
const secret = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb'
|
||||
const result = client.sign(REQUEST_FIXTURES.escrow.txJSON, secret)
|
||||
assert.deepEqual(result, RESPONSE_FIXTURES.escrow)
|
||||
schemaValidator.schemaValidate('sign', result)
|
||||
},
|
||||
|
||||
'signAs': async (client, address) => {
|
||||
const txJSON = REQUEST_FIXTURES.signAs
|
||||
const secret = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb'
|
||||
const signature = client.sign(JSON.stringify(txJSON), secret, {
|
||||
signAs: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'
|
||||
})
|
||||
assert.deepEqual(signature, RESPONSE_FIXTURES.signAs)
|
||||
},
|
||||
|
||||
'withKeypair': async (client, address) => {
|
||||
const keypair = {
|
||||
privateKey:
|
||||
'00ACCD3309DB14D1A4FC9B1DAE608031F4408C85C73EE05E035B7DC8B25840107A',
|
||||
publicKey:
|
||||
'02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8'
|
||||
}
|
||||
const result = client.sign(REQUEST_FIXTURES.normal.txJSON, keypair)
|
||||
assert.deepEqual(result, RESPONSE_FIXTURES.normal)
|
||||
schemaValidator.schemaValidate('sign', result)
|
||||
},
|
||||
|
||||
'withKeypair already signed': async (client, address) => {
|
||||
const keypair = {
|
||||
privateKey:
|
||||
'00ACCD3309DB14D1A4FC9B1DAE608031F4408C85C73EE05E035B7DC8B25840107A',
|
||||
publicKey:
|
||||
'02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8'
|
||||
}
|
||||
const result = client.sign(REQUEST_FIXTURES.normal.txJSON, keypair)
|
||||
assert.throws(() => {
|
||||
const tx = JSON.stringify(binary.decode(result.signedTransaction))
|
||||
client.sign(tx, keypair)
|
||||
}, /txJSON must not contain "TxnSignature" or "Signers" properties/)
|
||||
},
|
||||
|
||||
'withKeypair EscrowExecution': async (client, address) => {
|
||||
const keypair = {
|
||||
privateKey:
|
||||
'001ACAAEDECE405B2A958212629E16F2EB46B153EEE94CDD350FDEFF52795525B7',
|
||||
publicKey:
|
||||
'0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020'
|
||||
}
|
||||
const result = client.sign(REQUEST_FIXTURES.escrow.txJSON, keypair)
|
||||
assert.deepEqual(result, RESPONSE_FIXTURES.escrow)
|
||||
schemaValidator.schemaValidate('sign', result)
|
||||
},
|
||||
|
||||
'withKeypair signAs': async (client, address) => {
|
||||
const txJSON = REQUEST_FIXTURES.signAs
|
||||
const keypair = {
|
||||
privateKey:
|
||||
'001ACAAEDECE405B2A958212629E16F2EB46B153EEE94CDD350FDEFF52795525B7',
|
||||
publicKey:
|
||||
'0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020'
|
||||
}
|
||||
const signature = client.sign(JSON.stringify(txJSON), keypair, {
|
||||
signAs: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'
|
||||
})
|
||||
assert.deepEqual(signature, RESPONSE_FIXTURES.signAs)
|
||||
},
|
||||
|
||||
'succeeds - prepared payment': async (client, address) => {
|
||||
const payment = await client.preparePayment(address, {
|
||||
source: {
|
||||
address: address,
|
||||
maxAmount: {
|
||||
value: '1',
|
||||
currency: 'drops'
|
||||
}
|
||||
},
|
||||
destination: {
|
||||
address: 'rQ3PTWGLCbPz8ZCicV5tCX3xuymojTng5r',
|
||||
amount: {
|
||||
value: '1',
|
||||
currency: 'drops'
|
||||
}
|
||||
}
|
||||
})
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const result = client.sign(payment.txJSON, secret)
|
||||
const expectedResult = {
|
||||
signedTransaction:
|
||||
'12000022800000002400000017201B008694F261400000000000000168400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D874473045022100A9C91D4CFAE45686146EE0B56D4C53A2E7C2D672FB834D43E0BE2D2E9106519A022075DDA2F92DE552B0C45D83D4E6D35889B3FBF51BFBBD9B25EBF70DE3C96D0D6681145E7B112523F68D2F5E879DB4EAC51C6698A693048314FDB08D07AAA0EB711793A3027304D688E10C3648',
|
||||
id: '88D6B913C66279EA31ADC25C5806C48B2D4E5680261666790A736E1961217700'
|
||||
}
|
||||
assert.deepEqual(result, expectedResult)
|
||||
schemaValidator.schemaValidate('sign', result)
|
||||
},
|
||||
|
||||
'succeeds - no flags': async (client, address) => {
|
||||
const txJSON =
|
||||
'{"TransactionType":"Payment","Account":"r45Rev1EXGxy2hAUmJPCne97KUE7qyrD3j","Destination":"rQ3PTWGLCbPz8ZCicV5tCX3xuymojTng5r","Amount":"20000000","Sequence":1,"Fee":"12"}'
|
||||
const secret = 'shotKgaEotpcYsshSE39vmSnBDRim'
|
||||
const result = client.sign(txJSON, secret)
|
||||
const expectedResult = {
|
||||
signedTransaction:
|
||||
'1200002400000001614000000001312D0068400000000000000C7321022B05847086686F9D0499B13136B94AD4323EE1B67D4C429ECC987AB35ACFA34574473045022100C104B7B97C31FACA4597E7D6FCF13BD85BD11375963A62A0AC45B0061236E39802207784F157F6A98DFC85B051CDDF61CC3084C4F5750B82674801C8E9950280D1998114EE3046A5DDF8422C40DDB93F1D522BB4FE6419158314FDB08D07AAA0EB711793A3027304D688E10C3648',
|
||||
id: '0596925967F541BF332FF6756645B2576A9858414B5B363DC3D34915BE8A70D6'
|
||||
}
|
||||
const decoded = binary.decode(result.signedTransaction)
|
||||
assert(
|
||||
decoded.Flags == null,
|
||||
`Flags = ${decoded.Flags}, should be undefined`
|
||||
)
|
||||
assert.deepEqual(result, expectedResult)
|
||||
schemaValidator.schemaValidate('sign', result)
|
||||
},
|
||||
|
||||
'sign succeeds with source.amount/destination.minAmount': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
// See also: 'preparePayment with source.amount/destination.minAmount'
|
||||
|
||||
const txJSON =
|
||||
'{"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rEX4LtGJubaUcMWCJULcy4NVxGT9ZEMVRq","Amount":{"currency":"USD","issuer":"rMaa8VLBTjwTJWA2kSme4Sqgphhr6Lr6FH","value":"999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000"},"Flags":2147614720,"SendMax":{"currency":"GBP","issuer":"rpat5TmYjDsnFSStmgTumFgXCM9eqsWPro","value":"0.1"},"DeliverMin":{"currency":"USD","issuer":"rMaa8VLBTjwTJWA2kSme4Sqgphhr6Lr6FH","value":"0.1248548562296331"},"Sequence":23,"LastLedgerSequence":8820051,"Fee":"12"}'
|
||||
const secret = 'shotKgaEotpcYsshSE39vmSnBDRim'
|
||||
const result = client.sign(txJSON, secret)
|
||||
const expectedResult = {
|
||||
signedTransaction:
|
||||
'12000022800200002400000017201B0086955361EC6386F26FC0FFFF0000000000000000000000005553440000000000DC596C88BCDE4E818D416FCDEEBF2C8656BADC9A68400000000000000C69D4438D7EA4C6800000000000000000000000000047425000000000000C155FFE99C8C91F67083CEFFDB69EBFE76348CA6AD4446F8C5D8A5E0B0000000000000000000000005553440000000000DC596C88BCDE4E818D416FCDEEBF2C8656BADC9A7321022B05847086686F9D0499B13136B94AD4323EE1B67D4C429ECC987AB35ACFA34574473045022100D9634523D8E232D4A7807A71856023D82AC928FA29848571B820867898413B5F022041AC00EC1F81A26A6504EBF844A38CC3204694EF2CC1A97A87632721631F93DA81145E7B112523F68D2F5E879DB4EAC51C6698A6930483149F500E50C2F016CA01945E5A1E5846B61EF2D376',
|
||||
id: '1C558AA9B926C24FB6BBD6950B2DB1350A83F9F12E4385208867907019761A2D'
|
||||
}
|
||||
const decoded = binary.decode(result.signedTransaction)
|
||||
assert(
|
||||
decoded.Flags === 2147614720,
|
||||
`Flags = ${decoded.Flags}, should be 2147614720`
|
||||
)
|
||||
assert.deepEqual(result, expectedResult)
|
||||
schemaValidator.schemaValidate('sign', result)
|
||||
},
|
||||
|
||||
'throws when encoded tx does not match decoded tx - prepared payment': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
const payment = await client.preparePayment(address, {
|
||||
source: {
|
||||
address: address,
|
||||
maxAmount: {
|
||||
value: '1.1234567',
|
||||
currency: 'drops'
|
||||
}
|
||||
},
|
||||
destination: {
|
||||
address: 'rQ3PTWGLCbPz8ZCicV5tCX3xuymojTng5r',
|
||||
amount: {
|
||||
value: '1.1234567',
|
||||
currency: 'drops'
|
||||
}
|
||||
}
|
||||
})
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
assert.throws(() => {
|
||||
client.sign(payment.txJSON, secret)
|
||||
}, /^Error: 1\.1234567 is an illegal amount/)
|
||||
},
|
||||
|
||||
'throws when encoded tx does not match decoded tx - prepared order': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
const order = {
|
||||
direction: 'sell',
|
||||
quantity: {
|
||||
currency: 'USD',
|
||||
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '3.140000'
|
||||
},
|
||||
totalPrice: {
|
||||
currency: 'XRP',
|
||||
value: '31415'
|
||||
}
|
||||
}
|
||||
const prepared = await client.prepareOrder(address, order, {sequence: 123})
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
try {
|
||||
client.sign(prepared.txJSON, secret)
|
||||
return Promise.reject(new Error('client.sign should have thrown'))
|
||||
} catch (error) {
|
||||
assert.equal(error.name, 'ValidationError')
|
||||
assert.equal(
|
||||
error.message,
|
||||
'Serialized transaction does not match original txJSON. See `error.data`'
|
||||
)
|
||||
assert.deepEqual(error.data.diff, {
|
||||
TakerGets: {
|
||||
value: '3.14'
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
'throws when encoded tx does not match decoded tx - AccountSet': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const request = {
|
||||
// TODO: This fails when address is X-address
|
||||
txJSON: `{"Flags":2147483648,"TransactionType":"AccountSet","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Domain":"6578616D706C652E636F6D","LastLedgerSequence":8820051,"Fee":"1.2","Sequence":23,"SigningPubKey":"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8"}`,
|
||||
instructions: {
|
||||
fee: '0.0000012',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
|
||||
assert.throws(() => {
|
||||
client.sign(request.txJSON, secret)
|
||||
}, /Error: 1\.2 is an illegal amount/)
|
||||
},
|
||||
|
||||
'throws when encoded tx does not match decoded tx - higher fee': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const request = {
|
||||
// TODO: This fails when address is X-address
|
||||
txJSON: `{"Flags":2147483648,"TransactionType":"AccountSet","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Domain":"6578616D706C652E636F6D","LastLedgerSequence":8820051,"Fee":"1123456.7","Sequence":23,"SigningPubKey":"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8"}`,
|
||||
instructions: {
|
||||
fee: '1.1234567',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
|
||||
assert.throws(() => {
|
||||
client.sign(request.txJSON, secret)
|
||||
}, /Error: 1123456\.7 is an illegal amount/)
|
||||
},
|
||||
|
||||
'throws when Fee exceeds maxFeeXRP (in drops)': async (client, address) => {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const request = {
|
||||
txJSON: `{"Flags":2147483648,"TransactionType":"AccountSet","Account":"${address}","Domain":"6578616D706C652E636F6D","LastLedgerSequence":8820051,"Fee":"2010000","Sequence":23,"SigningPubKey":"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8"}`,
|
||||
instructions: {
|
||||
fee: '2.01',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
|
||||
assert.throws(() => {
|
||||
client.sign(request.txJSON, secret)
|
||||
}, /Fee" should not exceed "2000000"\. To use a higher fee, set `maxFeeXRP` in the Client constructor\./)
|
||||
},
|
||||
|
||||
'throws when Fee exceeds maxFeeXRP (in drops) - custom maxFeeXRP': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
client._maxFeeXRP = '1.9'
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const request = {
|
||||
txJSON: `{"Flags":2147483648,"TransactionType":"AccountSet","Account":"${address}","Domain":"6578616D706C652E636F6D","LastLedgerSequence":8820051,"Fee":"2010000","Sequence":23,"SigningPubKey":"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8"}`,
|
||||
instructions: {
|
||||
fee: '2.01',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
|
||||
assert.throws(() => {
|
||||
client.sign(request.txJSON, secret)
|
||||
}, /Fee" should not exceed "1900000"\. To use a higher fee, set `maxFeeXRP` in the Client constructor\./)
|
||||
},
|
||||
|
||||
'permits fee exceeding 2000000 drops when maxFeeXRP is higher than 2 XRP': async (
|
||||
client,
|
||||
address
|
||||
) => {
|
||||
client._maxFeeXRP = '2.1'
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const request = {
|
||||
// TODO: This fails when address is X-address
|
||||
txJSON: `{"Flags":2147483648,"TransactionType":"AccountSet","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","LastLedgerSequence":8820051,"Fee":"2010000","Sequence":23,"SigningPubKey":"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8"}`,
|
||||
instructions: {
|
||||
fee: '2.01',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}
|
||||
}
|
||||
|
||||
const result = client.sign(request.txJSON, secret)
|
||||
|
||||
const expectedResponse = {
|
||||
signedTransaction:
|
||||
'12000322800000002400000017201B008695536840000000001EAB90732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402200203F219F5371D2C6506888B1B02B27E74998F7A42D412C32FE319AC1A5B8DEF02205959A1B02253ACCCE542759E9886466C56D16B04676FA492AD34AA0E877E91F381145E7B112523F68D2F5E879DB4EAC51C6698A69304',
|
||||
id: '061D5593E0A117F389826419CAC049A73C7CFCA65A20B788781D41240143D864'
|
||||
}
|
||||
|
||||
assert.deepEqual(result, expectedResponse)
|
||||
schemaValidator.schemaValidate('sign', result)
|
||||
},
|
||||
|
||||
'sign with ticket': async (client, address) => {
|
||||
const secret = 'sn7n5R1cR5Y3fRFkuWXA94Ts1frVJ'
|
||||
const result = client.sign(REQUEST_FIXTURES.ticket.txJSON, secret)
|
||||
assert.deepEqual(result, RESPONSE_FIXTURES.ticket)
|
||||
schemaValidator.schemaValidate('sign', result)
|
||||
}
|
||||
}
|
||||
25
test/client/signPaymentChannelClaim/index.ts
Normal file
25
test/client/signPaymentChannelClaim/index.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import {TestSuite, assertResultMatch} from '../../utils'
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
signPaymentChannelClaim: async (client, address) => {
|
||||
const privateKey =
|
||||
'ACCD3309DB14D1A4FC9B1DAE608031F4408C85C73EE05E035B7DC8B25840107A'
|
||||
const result = client.signPaymentChannelClaim(
|
||||
requests.signPaymentChannelClaim.channel,
|
||||
requests.signPaymentChannelClaim.amount,
|
||||
privateKey
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.signPaymentChannelClaim,
|
||||
'signPaymentChannelClaim'
|
||||
)
|
||||
}
|
||||
}
|
||||
19
test/client/submit/index.ts
Normal file
19
test/client/submit/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertRejects, assertResultMatch, TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'submit': async (client, address) => {
|
||||
const result = await client.submit(responses.sign.normal.signedTransaction)
|
||||
assertResultMatch(result, responses.submit, 'submit')
|
||||
},
|
||||
|
||||
'submit - failure': async (client, address) => {
|
||||
await assertRejects(client.submit('BAD'), client.errors.RippledError)
|
||||
// assert.strictEqual(error.data.resultCode, 'temBAD_FEE')
|
||||
}
|
||||
}
|
||||
34
test/client/verifyPaymentChannelClaim/index.ts
Normal file
34
test/client/verifyPaymentChannelClaim/index.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import requests from '../../fixtures/requests'
|
||||
import responses from '../../fixtures/responses'
|
||||
import {assertResultMatch, TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'verifyPaymentChannelClaim': async (client, address) => {
|
||||
const publicKey =
|
||||
'02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8'
|
||||
const result = client.verifyPaymentChannelClaim(
|
||||
requests.signPaymentChannelClaim.channel,
|
||||
requests.signPaymentChannelClaim.amount,
|
||||
responses.signPaymentChannelClaim,
|
||||
publicKey
|
||||
)
|
||||
assertResultMatch(result, true, 'verifyPaymentChannelClaim')
|
||||
},
|
||||
|
||||
'verifyPaymentChannelClaim - invalid': async (client, address) => {
|
||||
const publicKey =
|
||||
'03A6523FE4281DA48A6FD77FAF3CB77F5C7001ABA0B32BCEDE0369AC009758D7D9'
|
||||
const result = client.verifyPaymentChannelClaim(
|
||||
requests.signPaymentChannelClaim.channel,
|
||||
requests.signPaymentChannelClaim.amount,
|
||||
responses.signPaymentChannelClaim,
|
||||
publicKey
|
||||
)
|
||||
assertResultMatch(result, false, 'verifyPaymentChannelClaim')
|
||||
}
|
||||
}
|
||||
104
test/client/xrpToDrops/index.ts
Normal file
104
test/client/xrpToDrops/index.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import assert from 'assert-diff'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import {TestSuite} from '../../utils'
|
||||
|
||||
/**
|
||||
* Every test suite exports their tests in the default object.
|
||||
* - Check out the "TestSuite" type for documentation on the interface.
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
export default <TestSuite>{
|
||||
'works with a typical amount': function (client) {
|
||||
const drops = client.xrpToDrops('2')
|
||||
assert.strictEqual(drops, '2000000', '2 XRP equals 2 million drops')
|
||||
},
|
||||
'works with fractions': function (client) {
|
||||
let drops = client.xrpToDrops('3.456789')
|
||||
assert.strictEqual(drops, '3456789', '3.456789 XRP equals 3,456,789 drops')
|
||||
drops = client.xrpToDrops('3.400000')
|
||||
assert.strictEqual(drops, '3400000', '3.400000 XRP equals 3,400,000 drops')
|
||||
drops = client.xrpToDrops('0.000001')
|
||||
assert.strictEqual(drops, '1', '0.000001 XRP equals 1 drop')
|
||||
drops = client.xrpToDrops('0.0000010')
|
||||
assert.strictEqual(drops, '1', '0.0000010 XRP equals 1 drop')
|
||||
},
|
||||
'works with zero': function (client) {
|
||||
let drops = client.xrpToDrops('0')
|
||||
assert.strictEqual(drops, '0', '0 XRP equals 0 drops')
|
||||
drops = client.xrpToDrops('-0') // negative zero is equivalent to zero
|
||||
assert.strictEqual(drops, '0', '-0 XRP equals 0 drops')
|
||||
drops = client.xrpToDrops('0.000000')
|
||||
assert.strictEqual(drops, '0', '0.000000 XRP equals 0 drops')
|
||||
drops = client.xrpToDrops('0.0000000')
|
||||
assert.strictEqual(drops, '0', '0.0000000 XRP equals 0 drops')
|
||||
},
|
||||
'works with a negative value': function (client) {
|
||||
const drops = client.xrpToDrops('-2')
|
||||
assert.strictEqual(drops, '-2000000', '-2 XRP equals -2 million drops')
|
||||
},
|
||||
'works with a value ending with a decimal point': function (client) {
|
||||
let drops = client.xrpToDrops('2.')
|
||||
assert.strictEqual(drops, '2000000', '2. XRP equals 2000000 drops')
|
||||
drops = client.xrpToDrops('-2.')
|
||||
assert.strictEqual(drops, '-2000000', '-2. XRP equals -2000000 drops')
|
||||
},
|
||||
'works with BigNumber objects': function (client) {
|
||||
let drops = client.xrpToDrops(new BigNumber(2))
|
||||
assert.strictEqual(
|
||||
drops,
|
||||
'2000000',
|
||||
'(BigNumber) 2 XRP equals 2 million drops'
|
||||
)
|
||||
drops = client.xrpToDrops(new BigNumber(-2))
|
||||
assert.strictEqual(
|
||||
drops,
|
||||
'-2000000',
|
||||
'(BigNumber) -2 XRP equals -2 million drops'
|
||||
)
|
||||
},
|
||||
'works with a number': function (client) {
|
||||
// This is not recommended. Use strings or BigNumber objects to avoid precision errors.
|
||||
let drops = client.xrpToDrops(2)
|
||||
assert.strictEqual(
|
||||
drops,
|
||||
'2000000',
|
||||
'(number) 2 XRP equals 2 million drops'
|
||||
)
|
||||
drops = client.xrpToDrops(-2)
|
||||
assert.strictEqual(
|
||||
drops,
|
||||
'-2000000',
|
||||
'(number) -2 XRP equals -2 million drops'
|
||||
)
|
||||
},
|
||||
'throws with an amount with too many decimal places': function (client) {
|
||||
assert.throws(() => {
|
||||
client.xrpToDrops('1.1234567')
|
||||
}, /has too many decimal places/)
|
||||
assert.throws(() => {
|
||||
client.xrpToDrops('0.0000001')
|
||||
}, /has too many decimal places/)
|
||||
},
|
||||
'throws with an invalid value': function (client) {
|
||||
assert.throws(() => {
|
||||
client.xrpToDrops('FOO')
|
||||
}, /invalid value/)
|
||||
assert.throws(() => {
|
||||
client.xrpToDrops('1e-7')
|
||||
}, /invalid value/)
|
||||
assert.throws(() => {
|
||||
client.xrpToDrops('2,0')
|
||||
}, /invalid value/)
|
||||
assert.throws(() => {
|
||||
client.xrpToDrops('.')
|
||||
}, /xrpToDrops: invalid value '\.', should be a BigNumber or string-encoded number\./)
|
||||
},
|
||||
'throws with an amount more than one decimal point': function (client) {
|
||||
assert.throws(() => {
|
||||
client.xrpToDrops('1.0.0')
|
||||
}, /xrpToDrops: invalid value '1\.0\.0'/)
|
||||
assert.throws(() => {
|
||||
client.xrpToDrops('...')
|
||||
}, /xrpToDrops: invalid value '\.\.\.'/)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user