mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-12-06 17:27:59 +00:00
convert existing xrpl library into a lerna monorepo
This commit is contained in:
26
packages/xrpl/test/utils/deriveXAddress.ts
Normal file
26
packages/xrpl/test/utils/deriveXAddress.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { deriveXAddress } from 'xrpl-local'
|
||||
|
||||
describe('deriveXAddress', function () {
|
||||
it('returns address for public key', function () {
|
||||
assert.equal(
|
||||
deriveXAddress({
|
||||
publicKey:
|
||||
'035332FBA71D705BD5D97014A833BE2BBB25BEFCD3506198E14AFEA241B98C2D06',
|
||||
tag: false,
|
||||
test: false,
|
||||
}),
|
||||
'XVZVpQj8YSVpNyiwXYSqvQoQqgBttTxAZwMcuJd4xteQHyt',
|
||||
)
|
||||
assert.equal(
|
||||
deriveXAddress({
|
||||
publicKey:
|
||||
'035332FBA71D705BD5D97014A833BE2BBB25BEFCD3506198E14AFEA241B98C2D06',
|
||||
tag: false,
|
||||
test: true,
|
||||
}),
|
||||
'TVVrSWtmQQssgVcmoMBcFQZKKf56QscyWLKnUyiuZW8ALU4',
|
||||
)
|
||||
})
|
||||
})
|
||||
133
packages/xrpl/test/utils/dropsToXrp.ts
Normal file
133
packages/xrpl/test/utils/dropsToXrp.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { dropsToXrp } from 'xrpl-local/utils'
|
||||
|
||||
describe('dropsToXrp', function () {
|
||||
it('works with a typical amount', function () {
|
||||
const xrp = dropsToXrp('2000000')
|
||||
assert.strictEqual(xrp, '2', '2 million drops equals 2 XRP')
|
||||
})
|
||||
|
||||
it('works with fractions', function () {
|
||||
let xrp = dropsToXrp('3456789')
|
||||
assert.strictEqual(xrp, '3.456789', '3,456,789 drops equals 3.456789 XRP')
|
||||
|
||||
xrp = dropsToXrp('3400000')
|
||||
assert.strictEqual(xrp, '3.4', '3,400,000 drops equals 3.4 XRP')
|
||||
|
||||
xrp = dropsToXrp('1')
|
||||
assert.strictEqual(xrp, '0.000001', '1 drop equals 0.000001 XRP')
|
||||
|
||||
xrp = dropsToXrp('1.0')
|
||||
assert.strictEqual(xrp, '0.000001', '1.0 drops equals 0.000001 XRP')
|
||||
|
||||
xrp = dropsToXrp('1.00')
|
||||
assert.strictEqual(xrp, '0.000001', '1.00 drops equals 0.000001 XRP')
|
||||
})
|
||||
|
||||
it('works with zero', function () {
|
||||
let xrp = dropsToXrp('0')
|
||||
assert.strictEqual(xrp, '0', '0 drops equals 0 XRP')
|
||||
|
||||
// negative zero is equivalent to zero
|
||||
xrp = dropsToXrp('-0')
|
||||
assert.strictEqual(xrp, '0', '-0 drops equals 0 XRP')
|
||||
|
||||
xrp = dropsToXrp('0.00')
|
||||
assert.strictEqual(xrp, '0', '0.00 drops equals 0 XRP')
|
||||
|
||||
xrp = dropsToXrp('000000000')
|
||||
assert.strictEqual(xrp, '0', '000000000 drops equals 0 XRP')
|
||||
})
|
||||
|
||||
it('works with a negative value', function () {
|
||||
const xrp = dropsToXrp('-2000000')
|
||||
assert.strictEqual(xrp, '-2', '-2 million drops equals -2 XRP')
|
||||
})
|
||||
|
||||
it('works with a value ending with a decimal point', function () {
|
||||
let xrp = dropsToXrp('2000000.')
|
||||
assert.strictEqual(xrp, '2', '2000000. drops equals 2 XRP')
|
||||
|
||||
xrp = dropsToXrp('-2000000.')
|
||||
assert.strictEqual(xrp, '-2', '-2000000. drops equals -2 XRP')
|
||||
})
|
||||
|
||||
it('works with BigNumber objects', function () {
|
||||
let xrp = dropsToXrp(new BigNumber(2000000))
|
||||
assert.strictEqual(xrp, '2', '(BigNumber) 2 million drops equals 2 XRP')
|
||||
|
||||
xrp = dropsToXrp(new BigNumber(-2000000))
|
||||
assert.strictEqual(xrp, '-2', '(BigNumber) -2 million drops equals -2 XRP')
|
||||
|
||||
xrp = dropsToXrp(new BigNumber(2345678))
|
||||
assert.strictEqual(
|
||||
xrp,
|
||||
'2.345678',
|
||||
'(BigNumber) 2,345,678 drops equals 2.345678 XRP',
|
||||
)
|
||||
|
||||
xrp = dropsToXrp(new BigNumber(-2345678))
|
||||
assert.strictEqual(
|
||||
xrp,
|
||||
'-2.345678',
|
||||
'(BigNumber) -2,345,678 drops equals -2.345678 XRP',
|
||||
)
|
||||
})
|
||||
|
||||
it('works with a number', function () {
|
||||
// This is not recommended. Use strings or BigNumber objects to avoid precision errors.
|
||||
let xrp = dropsToXrp(2000000)
|
||||
assert.strictEqual(xrp, '2', '(number) 2 million drops equals 2 XRP')
|
||||
xrp = dropsToXrp(-2000000)
|
||||
assert.strictEqual(xrp, '-2', '(number) -2 million drops equals -2 XRP')
|
||||
})
|
||||
|
||||
it('works with scientific notation', function () {
|
||||
const xrp = dropsToXrp('1e6')
|
||||
assert.strictEqual(
|
||||
xrp,
|
||||
'1',
|
||||
'(scientific notation string) 1e6 drops equals 1 XRP',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws with an amount with too many decimal places', function () {
|
||||
assert.throws(() => {
|
||||
dropsToXrp('1.2')
|
||||
}, /has too many decimal places/u)
|
||||
|
||||
assert.throws(() => {
|
||||
dropsToXrp('0.10')
|
||||
}, /has too many decimal places/u)
|
||||
})
|
||||
|
||||
it('throws with an invalid value', function () {
|
||||
assert.throws(() => {
|
||||
dropsToXrp('FOO')
|
||||
}, /invalid value/u)
|
||||
|
||||
assert.throws(() => {
|
||||
dropsToXrp('1e-7')
|
||||
}, /decimal place/u)
|
||||
|
||||
assert.throws(() => {
|
||||
dropsToXrp('2,0')
|
||||
}, /invalid value/u)
|
||||
|
||||
assert.throws(() => {
|
||||
dropsToXrp('.')
|
||||
}, /dropsToXrp: invalid value '\.', should be a BigNumber or string-encoded number\./u)
|
||||
})
|
||||
|
||||
it('throws with an amount more than one decimal point', function () {
|
||||
assert.throws(() => {
|
||||
dropsToXrp('1.0.0')
|
||||
}, /dropsToXrp: invalid value '1\.0\.0'/u)
|
||||
|
||||
assert.throws(() => {
|
||||
dropsToXrp('...')
|
||||
}, /dropsToXrp: invalid value '\.\.\.'/u)
|
||||
})
|
||||
})
|
||||
455
packages/xrpl/test/utils/getBalanceChanges.ts
Normal file
455
packages/xrpl/test/utils/getBalanceChanges.ts
Normal file
@@ -0,0 +1,455 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { getBalanceChanges } from 'xrpl-local/utils'
|
||||
|
||||
import paymentToken from '../fixtures/utils/paymentToken.json'
|
||||
import paymentTokenDestinationNoBalance from '../fixtures/utils/paymentTokenDestinationNoBalance.json'
|
||||
import paymentTokenMultipath from '../fixtures/utils/paymentTokenMultipath.json'
|
||||
import paymentTokenRedeem from '../fixtures/utils/paymentTokenRedeem.json'
|
||||
import paymentTokenRedeemThenIssue from '../fixtures/utils/paymentTokenRedeemThenIssue.json'
|
||||
import paymentTokenSpendFullBalance from '../fixtures/utils/paymentTokenSpendFullBalance.json'
|
||||
import paymentXrpCreateAccount from '../fixtures/utils/paymentXrpCreateAccount.json'
|
||||
import trustlineCreate from '../fixtures/utils/trustlineCreate.json'
|
||||
import trustlineDelete from '../fixtures/utils/trustlineDelete.json'
|
||||
import trustlineSetLimit from '../fixtures/utils/trustlineSetLimit.json'
|
||||
import trustlineSetLimit2 from '../fixtures/utils/trustlineSetLimit2.json'
|
||||
import trustlineSetLimitZero from '../fixtures/utils/trustlineSetLimitZero.json'
|
||||
|
||||
describe('getBalanceChanges', function () {
|
||||
it('XRP create account', function () {
|
||||
const result = getBalanceChanges(paymentXrpCreateAccount.metadata)
|
||||
const expected = [
|
||||
{
|
||||
account: 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K',
|
||||
balances: [{ currency: 'XRP', value: '100' }],
|
||||
},
|
||||
{
|
||||
account: 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc',
|
||||
balances: [{ currency: 'XRP', value: '-100.012' }],
|
||||
},
|
||||
]
|
||||
assert.deepStrictEqual(result, expected)
|
||||
})
|
||||
|
||||
it('USD payment to account with no USD', function () {
|
||||
const result = getBalanceChanges(paymentTokenDestinationNoBalance.metadata)
|
||||
const expected = [
|
||||
{
|
||||
account: 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc',
|
||||
balances: [
|
||||
{
|
||||
value: '-0.01',
|
||||
currency: 'USD',
|
||||
issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
},
|
||||
{
|
||||
value: '-0.012',
|
||||
currency: 'XRP',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
balances: [
|
||||
{
|
||||
issuer: 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc',
|
||||
currency: 'USD',
|
||||
value: '0.01',
|
||||
},
|
||||
{
|
||||
issuer: 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K',
|
||||
currency: 'USD',
|
||||
value: '-0.01',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K',
|
||||
balances: [
|
||||
{
|
||||
issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
currency: 'USD',
|
||||
value: '0.01',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
assert.deepStrictEqual(result, expected)
|
||||
})
|
||||
|
||||
it('USD payment of all USD in source account', function () {
|
||||
const result = getBalanceChanges(paymentTokenSpendFullBalance.metadata)
|
||||
const expected = [
|
||||
{
|
||||
account: 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc',
|
||||
balances: [
|
||||
{
|
||||
value: '0.2',
|
||||
currency: 'USD',
|
||||
issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
balances: [
|
||||
{
|
||||
value: '-0.2',
|
||||
currency: 'USD',
|
||||
issuer: 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc',
|
||||
},
|
||||
{
|
||||
value: '0.2',
|
||||
currency: 'USD',
|
||||
issuer: 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K',
|
||||
balances: [
|
||||
{
|
||||
value: '-0.2',
|
||||
currency: 'USD',
|
||||
issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
},
|
||||
{
|
||||
value: '-0.012',
|
||||
currency: 'XRP',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
assert.deepStrictEqual(result, expected)
|
||||
})
|
||||
|
||||
it('USD payment to account with USD', function () {
|
||||
const result = getBalanceChanges(paymentToken.metadata)
|
||||
const expected = [
|
||||
{
|
||||
account: 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc',
|
||||
balances: [
|
||||
{
|
||||
value: '-0.01',
|
||||
currency: 'USD',
|
||||
issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
},
|
||||
{
|
||||
value: '-0.012',
|
||||
currency: 'XRP',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
balances: [
|
||||
{
|
||||
issuer: 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc',
|
||||
currency: 'USD',
|
||||
value: '0.01',
|
||||
},
|
||||
{
|
||||
issuer: 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K',
|
||||
currency: 'USD',
|
||||
value: '-0.01',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K',
|
||||
balances: [
|
||||
{
|
||||
issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
currency: 'USD',
|
||||
value: '0.01',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
assert.deepStrictEqual(result, expected)
|
||||
})
|
||||
|
||||
it('Set trust limit to 0 with balance remaining', function () {
|
||||
const result = getBalanceChanges(trustlineSetLimitZero.metadata)
|
||||
const expected = [
|
||||
{
|
||||
account: 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K',
|
||||
balances: [
|
||||
{
|
||||
value: '-0.012',
|
||||
currency: 'XRP',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
assert.deepStrictEqual(result, expected)
|
||||
})
|
||||
|
||||
it('Create trustline', function () {
|
||||
const result = getBalanceChanges(trustlineCreate.metadata)
|
||||
const expected = [
|
||||
{
|
||||
account: 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K',
|
||||
balances: [
|
||||
{
|
||||
issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
currency: 'USD',
|
||||
value: '10',
|
||||
},
|
||||
{
|
||||
currency: 'XRP',
|
||||
value: '-0.012',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
balances: [
|
||||
{
|
||||
issuer: 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K',
|
||||
currency: 'USD',
|
||||
value: '-10',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
assert.deepStrictEqual(result, expected)
|
||||
})
|
||||
|
||||
it('Set trustline', function () {
|
||||
const result = getBalanceChanges(trustlineSetLimit.metadata)
|
||||
const expected = [
|
||||
{
|
||||
account: 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K',
|
||||
balances: [
|
||||
{
|
||||
value: '-0.012',
|
||||
currency: 'XRP',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
assert.deepStrictEqual(result, expected)
|
||||
})
|
||||
|
||||
it('Set trustline 2', function () {
|
||||
const result = getBalanceChanges(trustlineSetLimit2.metadata)
|
||||
const expected = [
|
||||
{
|
||||
account: 'rsApBGKJmMfExxZBrGnzxEXyq7TMhMRg4e',
|
||||
balances: [
|
||||
{
|
||||
currency: 'XRP',
|
||||
value: '-0.00001',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
assert.deepStrictEqual(result, expected)
|
||||
})
|
||||
|
||||
it('Delete trustline', function () {
|
||||
const result = getBalanceChanges(trustlineDelete.metadata)
|
||||
const expected = [
|
||||
{
|
||||
account: 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc',
|
||||
balances: [
|
||||
{
|
||||
value: '0.02',
|
||||
currency: 'USD',
|
||||
issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
balances: [
|
||||
{
|
||||
value: '-0.02',
|
||||
currency: 'USD',
|
||||
issuer: 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc',
|
||||
},
|
||||
{
|
||||
value: '0.02',
|
||||
currency: 'USD',
|
||||
issuer: 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K',
|
||||
balances: [
|
||||
{
|
||||
value: '-0.02',
|
||||
currency: 'USD',
|
||||
issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
},
|
||||
{
|
||||
value: '-0.012',
|
||||
currency: 'XRP',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
assert.deepStrictEqual(result, expected)
|
||||
})
|
||||
|
||||
it('Redeem USD', function () {
|
||||
const result = getBalanceChanges(paymentTokenRedeem.result.meta)
|
||||
const expected = [
|
||||
{
|
||||
account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
balances: [
|
||||
{
|
||||
currency: 'USD',
|
||||
issuer: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK',
|
||||
value: '100',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK',
|
||||
balances: [
|
||||
{
|
||||
currency: 'USD',
|
||||
issuer: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
value: '-100',
|
||||
},
|
||||
{
|
||||
currency: 'XRP',
|
||||
value: '-0.00001',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
assert.deepStrictEqual(result, expected)
|
||||
})
|
||||
|
||||
it('Redeem then issue USD', function () {
|
||||
const result = getBalanceChanges(paymentTokenRedeemThenIssue.result.meta)
|
||||
const expected = [
|
||||
{
|
||||
account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
balances: [
|
||||
{
|
||||
currency: 'USD',
|
||||
issuer: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK',
|
||||
value: '200',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK',
|
||||
balances: [
|
||||
{
|
||||
currency: 'USD',
|
||||
issuer: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
value: '-200',
|
||||
},
|
||||
{
|
||||
currency: 'XRP',
|
||||
value: '-0.00001',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
assert.deepStrictEqual(result, expected)
|
||||
})
|
||||
|
||||
it('Multipath USD payment', function () {
|
||||
const result = getBalanceChanges(paymentTokenMultipath.result.meta)
|
||||
const expected = [
|
||||
{
|
||||
account: 'rrnsYgWn13Z28GtRgznrSUsLfMkvsXCZSu',
|
||||
balances: [
|
||||
{
|
||||
issuer: 'r4nmQNH4Fhjfh6cHDbvVSsBv7KySbj4cBf',
|
||||
currency: 'USD',
|
||||
value: '100',
|
||||
},
|
||||
{
|
||||
issuer: 'rnYDWQaRdMb5neCGgvFfhw3MBoxmv5LtfH',
|
||||
currency: 'USD',
|
||||
value: '-100',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'r4nmQNH4Fhjfh6cHDbvVSsBv7KySbj4cBf',
|
||||
balances: [
|
||||
{
|
||||
issuer: 'rrnsYgWn13Z28GtRgznrSUsLfMkvsXCZSu',
|
||||
currency: 'USD',
|
||||
value: '-100',
|
||||
},
|
||||
{
|
||||
currency: 'XRP',
|
||||
value: '-0.00001',
|
||||
},
|
||||
{
|
||||
issuer: 'rJsaPnGdeo7BhMnHjuc3n44Mf7Ra1qkSVJ',
|
||||
currency: 'USD',
|
||||
value: '-100',
|
||||
},
|
||||
{
|
||||
issuer: 'rGpeQzUWFu4fMhJHZ1Via5aqFC3A5twZUD',
|
||||
currency: 'USD',
|
||||
value: '-100',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'rJsaPnGdeo7BhMnHjuc3n44Mf7Ra1qkSVJ',
|
||||
balances: [
|
||||
{
|
||||
issuer: 'r4nmQNH4Fhjfh6cHDbvVSsBv7KySbj4cBf',
|
||||
currency: 'USD',
|
||||
value: '100',
|
||||
},
|
||||
{
|
||||
issuer: 'rnYDWQaRdMb5neCGgvFfhw3MBoxmv5LtfH',
|
||||
currency: 'USD',
|
||||
value: '-100',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'rGpeQzUWFu4fMhJHZ1Via5aqFC3A5twZUD',
|
||||
balances: [
|
||||
{
|
||||
issuer: 'r4nmQNH4Fhjfh6cHDbvVSsBv7KySbj4cBf',
|
||||
currency: 'USD',
|
||||
value: '100',
|
||||
},
|
||||
{
|
||||
issuer: 'rnYDWQaRdMb5neCGgvFfhw3MBoxmv5LtfH',
|
||||
currency: 'USD',
|
||||
value: '-100',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
account: 'rnYDWQaRdMb5neCGgvFfhw3MBoxmv5LtfH',
|
||||
balances: [
|
||||
{
|
||||
issuer: 'rJsaPnGdeo7BhMnHjuc3n44Mf7Ra1qkSVJ',
|
||||
currency: 'USD',
|
||||
value: '100',
|
||||
},
|
||||
{
|
||||
issuer: 'rrnsYgWn13Z28GtRgznrSUsLfMkvsXCZSu',
|
||||
currency: 'USD',
|
||||
value: '100',
|
||||
},
|
||||
{
|
||||
issuer: 'rGpeQzUWFu4fMhJHZ1Via5aqFC3A5twZUD',
|
||||
currency: 'USD',
|
||||
value: '100',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
assert.deepStrictEqual(result, expected)
|
||||
})
|
||||
})
|
||||
17
packages/xrpl/test/utils/hasNextPage.ts
Normal file
17
packages/xrpl/test/utils/hasNextPage.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { hasNextPage } from 'xrpl-local'
|
||||
|
||||
import fixtures from '../fixtures/rippled'
|
||||
|
||||
describe('hasNextPage', function () {
|
||||
it('returns true when response has marker', function () {
|
||||
const firstPage = fixtures.ledger_data.first_page
|
||||
assert.isTrue(hasNextPage(firstPage))
|
||||
})
|
||||
|
||||
it('returns false when response does not have marker', function () {
|
||||
const lastPage = fixtures.ledger_data.last_page
|
||||
assert.isFalse(hasNextPage(lastPage))
|
||||
})
|
||||
})
|
||||
154
packages/xrpl/test/utils/hashLedger.ts
Normal file
154
packages/xrpl/test/utils/hashLedger.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { ValidationError, XrplError } from 'xrpl-local'
|
||||
import { hashes } from 'xrpl-local/utils'
|
||||
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
|
||||
const { hashLedger } = hashes
|
||||
const { hashLedger: REQUEST_FIXTURES } = requests
|
||||
|
||||
describe('hashLedger', function () {
|
||||
let ledger
|
||||
beforeEach(function () {
|
||||
ledger = JSON.parse(JSON.stringify(responses.getLedger.full))
|
||||
|
||||
if (ledger.rawState != null) {
|
||||
ledger.accountState = JSON.parse(ledger.rawState)
|
||||
}
|
||||
})
|
||||
|
||||
it('given corrupt data - should fail', function () {
|
||||
ledger.transactions[0] = JSON.parse(
|
||||
'{"Account":"r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV","Amount":"12000000000","Destination":"rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj","Fee":"10","Flags":0,"Sequence":62,"SigningPubKey":"034AADB09CFF4A4804073701EC53C3510CDC95917C2BB0150FB742D0C66E6CEE9E","TransactionType":"Payment","TxnSignature":"3045022022EB32AECEF7C644C891C19F87966DF9C62B1F34BABA6BE774325E4BB8E2DD62022100A51437898C28C2B297112DF8131F2BB39EA5FE613487DDD611525F1796264639","hash":"3B1A4E1C9BB6A7208EB146BCDB86ECEA6068ED01466D933528CA2B4C64F753EF","metaData":{"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.parent_close_time = ledger.close_time
|
||||
let hash: string
|
||||
try {
|
||||
hash = hashLedger(ledger, { computeTreeHashes: true })
|
||||
} catch (error) {
|
||||
if (!(error instanceof XrplError)) {
|
||||
throw error
|
||||
}
|
||||
|
||||
assert(error instanceof ValidationError)
|
||||
if (error instanceof 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}`,
|
||||
)
|
||||
})
|
||||
|
||||
it('given ledger without raw transactions - should throw', function () {
|
||||
delete ledger.transactions
|
||||
ledger.parentCloseTime = ledger.closeTime
|
||||
|
||||
assert.throws(
|
||||
() => hashLedger(ledger, { computeTreeHashes: true }),
|
||||
ValidationError,
|
||||
'transactions is missing from the ledger',
|
||||
)
|
||||
})
|
||||
|
||||
it('given ledger without state or transactions - only compute ledger hash', function () {
|
||||
ledger.transactions[0] = JSON.parse(
|
||||
'{"Account":"r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV","Amount":"10000000000","Destination":"rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj","Fee":"10","Flags":0,"Sequence":62,"SigningPubKey":"034AADB09CFF4A4804073701EC53C3510CDC95917C2BB0150FB742D0C66E6CEE9E","TransactionType":"Payment","TxnSignature":"3045022022EB32AECEF7C644C891C19F87966DF9C62B1F34BABA6BE774325E4BB8E2DD62022100A51437898C28C2B297112DF8131F2BB39EA5FE613487DDD611525F1796264639","hash":"3B1A4E1C9BB6A7208EB146BCDB86ECEA6068ED01466D933528CA2B4C64F753EF","metaData":{"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.parent_close_time = ledger.close_time
|
||||
|
||||
function testCompute(ledgerToTest, expectedError): void {
|
||||
const hash = hashLedger(ledgerToTest)
|
||||
assert.strictEqual(
|
||||
hash,
|
||||
'E6DB7365949BF9814D76BCC730B01818EB9136A89DB224F3F9F5AAE4569D758E',
|
||||
)
|
||||
|
||||
// fail if required to compute tree hashes
|
||||
assert.throws(
|
||||
() => hashLedger(ledgerToTest, { computeTreeHashes: true }),
|
||||
ValidationError,
|
||||
expectedError,
|
||||
)
|
||||
}
|
||||
|
||||
const transactions = ledger.transactions
|
||||
delete ledger.transactions
|
||||
testCompute(ledger, 'transactions is missing from the ledger')
|
||||
delete ledger.accountState
|
||||
testCompute(ledger, 'transactions is missing from the ledger')
|
||||
ledger.transactions = transactions
|
||||
testCompute(ledger, 'accountState is missing from the ledger')
|
||||
})
|
||||
|
||||
it('wrong hash', function () {
|
||||
const newLedger = {
|
||||
...ledger,
|
||||
parent_close_time: ledger.close_time,
|
||||
account_hash:
|
||||
'D9ABF622DA26EEEE48203085D4BC23B0F77DC6F8724AC33D975DA3CA492D2E44',
|
||||
}
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
hashLedger(newLedger, { computeTreeHashes: true })
|
||||
},
|
||||
ValidationError,
|
||||
'does not match computed hash of state',
|
||||
)
|
||||
})
|
||||
|
||||
it('hashLedger', function () {
|
||||
const header = REQUEST_FIXTURES.header
|
||||
const ledgerHash = hashLedger(header)
|
||||
|
||||
assert.strictEqual(
|
||||
ledgerHash,
|
||||
'F4D865D83EB88C1A1911B9E90641919A1314F36E1B099F8E95FE3B7C77BE3349',
|
||||
)
|
||||
})
|
||||
|
||||
it('hashLedger - with transactions', function () {
|
||||
const header = {
|
||||
...REQUEST_FIXTURES.header,
|
||||
transactionHash: undefined,
|
||||
rawTransactions: REQUEST_FIXTURES.transactions,
|
||||
}
|
||||
const ledgerHash = hashLedger(header)
|
||||
assert.strictEqual(
|
||||
ledgerHash,
|
||||
'F4D865D83EB88C1A1911B9E90641919A1314F36E1B099F8E95FE3B7C77BE3349',
|
||||
)
|
||||
})
|
||||
|
||||
it('hashLedger - incorrect transaction_hash', function () {
|
||||
const header = {
|
||||
...REQUEST_FIXTURES.header,
|
||||
transaction_hash:
|
||||
'325EACC5271322539EEEC2D6A5292471EF1B3E72AE7180533EFC3B8F0AD435C9',
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- okay for tests
|
||||
transactions: REQUEST_FIXTURES.transactions as any,
|
||||
}
|
||||
|
||||
assert.throws(
|
||||
() => hashLedger(header, { computeTreeHashes: true }),
|
||||
ValidationError,
|
||||
'transactionHash in header does not match computed hash of transactions',
|
||||
)
|
||||
})
|
||||
})
|
||||
193
packages/xrpl/test/utils/hashes.ts
Normal file
193
packages/xrpl/test/utils/hashes.ts
Normal file
@@ -0,0 +1,193 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
import { assert } from 'chai'
|
||||
import { encode } from 'ripple-binary-codec'
|
||||
|
||||
import { OfferCreate, Transaction, ValidationError } from 'xrpl-local'
|
||||
import {
|
||||
hashStateTree,
|
||||
hashTxTree,
|
||||
hashTrustline,
|
||||
hashEscrow,
|
||||
hashPaymentChannel,
|
||||
hashSignedTx,
|
||||
hashAccountRoot,
|
||||
hashOfferId,
|
||||
hashSignerListId,
|
||||
} from 'xrpl-local/utils/hashes'
|
||||
|
||||
import fixtures from '../fixtures/rippled'
|
||||
import { assertResultMatch } from '../testUtils'
|
||||
|
||||
/**
|
||||
* Expects a corresponding ledger dump in $repo/test/fixtures/rippled folder.
|
||||
*
|
||||
* @param ledgerIndex - The ledger index of the desired dump.
|
||||
*/
|
||||
function createLedgerTest(ledgerIndex: number): void {
|
||||
const ledgerIndexString = String(ledgerIndex)
|
||||
const fileLocation = path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
`fixtures/rippled/ledgerFull${ledgerIndex}.json`,
|
||||
)
|
||||
|
||||
// eslint-disable-next-line node/no-sync -- must be sync version when not in async method
|
||||
const ledgerRaw = fs.readFileSync(fileLocation, { encoding: 'utf8' })
|
||||
const ledgerJSON = JSON.parse(ledgerRaw)
|
||||
|
||||
const hasAccounts =
|
||||
Array.isArray(ledgerJSON.accountState) && ledgerJSON.accountState.length > 0
|
||||
|
||||
describe(`ledger hashes ${ledgerIndexString}`, function () {
|
||||
if (hasAccounts) {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- known to be a string
|
||||
it(`has account_hash of ${ledgerJSON.account_hash}`, function () {
|
||||
assert.equal(
|
||||
ledgerJSON.account_hash,
|
||||
hashStateTree(ledgerJSON.accountState),
|
||||
)
|
||||
})
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- known to be a string
|
||||
it(`has transaction_hash of ${ledgerJSON.transaction_hash}`, function () {
|
||||
assert.equal(
|
||||
ledgerJSON.transaction_hash,
|
||||
hashTxTree(ledgerJSON.transactions),
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
describe('Hashes', function () {
|
||||
// This is the first recorded ledger with a non empty transaction set
|
||||
// eslint-disable-next-line mocha/no-setup-in-describe -- runs tests
|
||||
createLedgerTest(38129)
|
||||
// Because, why not.
|
||||
// eslint-disable-next-line mocha/no-setup-in-describe -- runs tests
|
||||
createLedgerTest(40000)
|
||||
// 1311 AffectedNodes, no accounts
|
||||
// eslint-disable-next-line mocha/no-setup-in-describe -- runs tests
|
||||
createLedgerTest(7501326)
|
||||
|
||||
it('calcAccountRootEntryHash', function () {
|
||||
const account = 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'
|
||||
const expectedEntryHash =
|
||||
'2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8'
|
||||
const actualEntryHash = hashAccountRoot(account)
|
||||
|
||||
assert.equal(actualEntryHash, expectedEntryHash)
|
||||
})
|
||||
|
||||
it('calcRippleStateEntryHash', function () {
|
||||
const account1 = 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'
|
||||
const account2 = 'rB5TihdPbKgMrkFqrqUC3yLdE8hhv4BdeY'
|
||||
const currency = 'USD'
|
||||
|
||||
const expectedEntryHash =
|
||||
'C683B5BB928F025F1E860D9D69D6C554C2202DE0D45877ADB3077DA4CB9E125C'
|
||||
const actualEntryHash1 = hashTrustline(account1, account2, currency)
|
||||
const actualEntryHash2 = hashTrustline(account2, account1, currency)
|
||||
|
||||
assert.equal(actualEntryHash1, expectedEntryHash)
|
||||
assert.equal(actualEntryHash2, expectedEntryHash)
|
||||
})
|
||||
|
||||
it('will calculate the RippleState entry hash for r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV and rUAMuQTfVhbfqUDuro7zzy4jj4Wq57MPTj in UAM', function () {
|
||||
const account1 = 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV'
|
||||
const account2 = 'rUAMuQTfVhbfqUDuro7zzy4jj4Wq57MPTj'
|
||||
const currency = 'UAM'
|
||||
|
||||
const expectedEntryHash =
|
||||
'AE9ADDC584358E5847ADFC971834E471436FC3E9DE6EA1773DF49F419DC0F65E'
|
||||
const actualEntryHash1 = hashTrustline(account1, account2, currency)
|
||||
const actualEntryHash2 = hashTrustline(account2, account1, currency)
|
||||
|
||||
assert.equal(actualEntryHash1, expectedEntryHash)
|
||||
assert.equal(actualEntryHash2, expectedEntryHash)
|
||||
})
|
||||
|
||||
it('calcOfferEntryHash', function () {
|
||||
const account = 'r32UufnaCGL82HubijgJGDmdE5hac7ZvLw'
|
||||
const sequence = 137
|
||||
const expectedEntryHash =
|
||||
'03F0AED09DEEE74CEF85CD57A0429D6113507CF759C597BABB4ADB752F734CE3'
|
||||
const actualEntryHash = hashOfferId(account, sequence)
|
||||
|
||||
assert.equal(actualEntryHash, expectedEntryHash)
|
||||
})
|
||||
|
||||
it('hashSignerListId', function () {
|
||||
const account = 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'
|
||||
const expectedEntryHash =
|
||||
'778365D5180F5DF3016817D1F318527AD7410D83F8636CF48C43E8AF72AB49BF'
|
||||
const actualEntryHash = hashSignerListId(account)
|
||||
assert.equal(actualEntryHash, expectedEntryHash)
|
||||
})
|
||||
|
||||
it('calcEscrowEntryHash', function () {
|
||||
const account = 'rDx69ebzbowuqztksVDmZXjizTd12BVr4x'
|
||||
const sequence = 84
|
||||
const expectedEntryHash =
|
||||
'61E8E8ED53FA2CEBE192B23897071E9A75217BF5A410E9CB5B45AAB7AECA567A'
|
||||
const actualEntryHash = hashEscrow(account, sequence)
|
||||
|
||||
assert.equal(actualEntryHash, expectedEntryHash)
|
||||
})
|
||||
|
||||
it('calcPaymentChannelEntryHash', function () {
|
||||
const account = 'rDx69ebzbowuqztksVDmZXjizTd12BVr4x'
|
||||
const dstAccount = 'rLFtVprxUEfsH54eCWKsZrEQzMDsx1wqso'
|
||||
const sequence = 82
|
||||
const expectedEntryHash =
|
||||
'E35708503B3C3143FB522D749AAFCC296E8060F0FB371A9A56FAE0B1ED127366'
|
||||
const actualEntryHash = hashPaymentChannel(account, dstAccount, sequence)
|
||||
|
||||
assert.equal(actualEntryHash, expectedEntryHash)
|
||||
})
|
||||
|
||||
it('Hash a signed transaction correctly', function () {
|
||||
const expected_hash =
|
||||
'458101D51051230B1D56E9ACAFAA34451BF65FA000F95DF6F0FF5B3A62D83FC2'
|
||||
|
||||
assertResultMatch(
|
||||
hashSignedTx(fixtures.tx.OfferCreateSell.result as Transaction),
|
||||
expected_hash,
|
||||
)
|
||||
})
|
||||
|
||||
it('Hash a signed transaction blob correctly', function () {
|
||||
const expected_hash =
|
||||
'458101D51051230B1D56E9ACAFAA34451BF65FA000F95DF6F0FF5B3A62D83FC2'
|
||||
|
||||
assertResultMatch(
|
||||
hashSignedTx(encode(fixtures.tx.OfferCreateSell.result)),
|
||||
expected_hash,
|
||||
)
|
||||
})
|
||||
|
||||
it('Throw an error when hashing an unsigned transaction', function () {
|
||||
const offerCreateWithNoSignature: OfferCreate = {
|
||||
...(fixtures.tx.OfferCreateSell.result as OfferCreate),
|
||||
TxnSignature: undefined,
|
||||
}
|
||||
|
||||
assert.throws(
|
||||
() => hashSignedTx(offerCreateWithNoSignature),
|
||||
ValidationError,
|
||||
)
|
||||
})
|
||||
|
||||
it('Throw when hashing an unsigned transaction blob', function () {
|
||||
const encodedOfferCreateWithNoSignature: string = encode({
|
||||
...fixtures.tx.OfferCreateSell.result,
|
||||
TxnSignature: undefined,
|
||||
})
|
||||
|
||||
assert.throws(
|
||||
() => hashSignedTx(encodedOfferCreateWithNoSignature),
|
||||
ValidationError,
|
||||
)
|
||||
})
|
||||
})
|
||||
29
packages/xrpl/test/utils/hexConversion.ts
Normal file
29
packages/xrpl/test/utils/hexConversion.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { convertHexToString, convertStringToHex } from 'xrpl-local/utils'
|
||||
|
||||
describe('convertHexToString and convertStringToHex', function () {
|
||||
it('converts "example.com"', function () {
|
||||
const str = 'example.com'
|
||||
const hex = convertStringToHex(str)
|
||||
assert.strictEqual(
|
||||
hex,
|
||||
'6578616D706C652E636F6D',
|
||||
'should convert to hex equivalent',
|
||||
)
|
||||
const result = convertHexToString(hex)
|
||||
assert.strictEqual(
|
||||
result,
|
||||
'example.com',
|
||||
'should convert back to example.com',
|
||||
)
|
||||
})
|
||||
|
||||
it('converts "你好"', function () {
|
||||
const str = '你好'
|
||||
const hex = convertStringToHex(str)
|
||||
assert.strictEqual(hex, 'E4BDA0E5A5BD', 'should convert to hex equivalent')
|
||||
const result = convertHexToString(hex)
|
||||
assert.strictEqual(result, '你好', 'should convert back to 你好')
|
||||
})
|
||||
})
|
||||
25
packages/xrpl/test/utils/isValidAddress.ts
Normal file
25
packages/xrpl/test/utils/isValidAddress.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { isValidAddress } from 'xrpl-local'
|
||||
|
||||
describe('isValidAddress', function () {
|
||||
it('Validates valid classic address', function () {
|
||||
const classic = 'r3rhWeE31Jt5sWmi4QiGLMZnY3ENgqw96W'
|
||||
assert(isValidAddress(classic))
|
||||
})
|
||||
|
||||
it('Does not validate invalid classic address', function () {
|
||||
const classic = 'r3rhWeE31Jt5sWmi4QiGLMZnY3ENhqw96W'
|
||||
assert(!isValidAddress(classic))
|
||||
})
|
||||
|
||||
it('Validates valid X-Address', function () {
|
||||
const xAddress = 'XV5sbjUmgPpvXv4ixFWZ5ptAYZ6PD28Sq49uo34VyjnmK5H'
|
||||
assert(isValidAddress(xAddress))
|
||||
})
|
||||
|
||||
it('Does not validate invalid X-Address', function () {
|
||||
const xAddress = 'XV5sbjUmgPpvXv4ixFWZ5pfAYZ6PD28Sq49uo34VyjnmK5H'
|
||||
assert(!isValidAddress(xAddress))
|
||||
})
|
||||
})
|
||||
72
packages/xrpl/test/utils/quality.ts
Normal file
72
packages/xrpl/test/utils/quality.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { ValidationError } from 'xrpl-local'
|
||||
|
||||
import { decimalToQuality, percentToQuality, qualityToDecimal } from '../../src'
|
||||
|
||||
describe('Quality utils', function () {
|
||||
it('converts 101 percent to valid Quality', function () {
|
||||
const billionths = percentToQuality('101%')
|
||||
|
||||
assert.equal(billionths, 1010000000)
|
||||
})
|
||||
|
||||
it('converts 1.01 to valid Quality', function () {
|
||||
assert.equal(decimalToQuality('1.01'), 1010000000)
|
||||
assert.equal(qualityToDecimal(1010000000), '1.01')
|
||||
})
|
||||
|
||||
it('converts 99 percent to valid Quality', function () {
|
||||
const billionths = percentToQuality('99%')
|
||||
|
||||
assert.equal(billionths, 990000000)
|
||||
})
|
||||
|
||||
it('converts .99 to valid Quality', function () {
|
||||
assert.equal(decimalToQuality('.99'), 990000000)
|
||||
assert.equal(qualityToDecimal(990000000), '0.99')
|
||||
})
|
||||
|
||||
it('converts 100 percent to 0', function () {
|
||||
const billionths = percentToQuality('100%')
|
||||
|
||||
assert.equal(billionths, 0)
|
||||
})
|
||||
|
||||
it('converts 1.00 percent to 0', function () {
|
||||
assert.equal(decimalToQuality('1.00'), 0)
|
||||
assert.equal(qualityToDecimal(0), '1')
|
||||
})
|
||||
|
||||
it('Throws when percent Quality greater than maximum precision', function () {
|
||||
assert.throws(
|
||||
() => percentToQuality('.0000000000000011221%'),
|
||||
ValidationError,
|
||||
'Decimal exceeds maximum precision.',
|
||||
)
|
||||
})
|
||||
|
||||
it('Throws when decimal Quality greater than maximum precision', function () {
|
||||
assert.throws(
|
||||
() => decimalToQuality('.000000000000000011221'),
|
||||
ValidationError,
|
||||
'Decimal exceeds maximum precision.',
|
||||
)
|
||||
})
|
||||
|
||||
it('percentToQuality throws with gibberish', function () {
|
||||
assert.throws(
|
||||
() => percentToQuality('3dsadflk%'),
|
||||
ValidationError,
|
||||
'Value is not a number',
|
||||
)
|
||||
})
|
||||
|
||||
it('decimalToQuality throws with gibberish', function () {
|
||||
assert.throws(
|
||||
() => decimalToQuality('3dsadflk%'),
|
||||
ValidationError,
|
||||
'Value is not a number',
|
||||
)
|
||||
})
|
||||
})
|
||||
22
packages/xrpl/test/utils/signPaymentChannelClaim.ts
Normal file
22
packages/xrpl/test/utils/signPaymentChannelClaim.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import signPaymentChannelClaim from 'xrpl-local/utils/signPaymentChannelClaim'
|
||||
|
||||
import responses from '../fixtures/responses'
|
||||
import { assertResultMatch } from '../testUtils'
|
||||
|
||||
describe('signPaymentChannelClaim', function () {
|
||||
it('basic signature matches', function () {
|
||||
const channel =
|
||||
'3E18C05AD40319B809520F1A136370C4075321B285217323396D6FD9EE1E9037'
|
||||
const amount = '.00001'
|
||||
const privateKey =
|
||||
'ACCD3309DB14D1A4FC9B1DAE608031F4408C85C73EE05E035B7DC8B25840107A'
|
||||
|
||||
const result = signPaymentChannelClaim(channel, amount, privateKey)
|
||||
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.signPaymentChannelClaim,
|
||||
'signPaymentChannelClaim',
|
||||
)
|
||||
})
|
||||
})
|
||||
48
packages/xrpl/test/utils/timeConversion.ts
Normal file
48
packages/xrpl/test/utils/timeConversion.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import {
|
||||
rippleTimeToISOTime,
|
||||
isoTimeToRippleTime,
|
||||
unixTimeToRippleTime,
|
||||
rippleTimeToUnixTime,
|
||||
} from '../../src'
|
||||
|
||||
describe('time conversion', function () {
|
||||
describe('rippleTimeToISOTime', function () {
|
||||
it('converts ripple time to ISO time', function () {
|
||||
const rippleTime = 0
|
||||
const isoTime = '2000-01-01T00:00:00.000Z'
|
||||
assert.equal(rippleTimeToISOTime(rippleTime), isoTime)
|
||||
})
|
||||
})
|
||||
|
||||
describe('isoTimeToRippleTime', function () {
|
||||
it('converts ISO time to ripple time', function () {
|
||||
const rippleTime = 0
|
||||
const isoTime = '2000-01-01T00:00:00.000Z'
|
||||
assert.equal(isoTimeToRippleTime(isoTime), rippleTime)
|
||||
})
|
||||
|
||||
it('converts from Date', function () {
|
||||
const rippleTime = 0
|
||||
const isoTime = '2000-01-01T00:00:00.000Z'
|
||||
assert.equal(isoTimeToRippleTime(new Date(isoTime)), rippleTime)
|
||||
})
|
||||
})
|
||||
|
||||
describe('unixTimeToRippleTime', function () {
|
||||
it('converts unix time to ripple time', function () {
|
||||
const unixTime = 946684801000
|
||||
const rippleTime = 1
|
||||
assert.equal(unixTimeToRippleTime(unixTime), rippleTime)
|
||||
})
|
||||
})
|
||||
|
||||
describe('rippleTimeToUnixTime', function () {
|
||||
it('converts ripple time to unix time', function () {
|
||||
const unixTime = 946684801000
|
||||
const rippleTime = 1
|
||||
assert.equal(rippleTimeToUnixTime(rippleTime), unixTime)
|
||||
})
|
||||
})
|
||||
})
|
||||
81
packages/xrpl/test/utils/transferRate.ts
Normal file
81
packages/xrpl/test/utils/transferRate.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { ValidationError } from 'xrpl-local'
|
||||
|
||||
import {
|
||||
percentToTransferRate,
|
||||
decimalToTransferRate,
|
||||
transferRateToDecimal,
|
||||
} from '../../src'
|
||||
|
||||
describe('TransferRate utils', function () {
|
||||
it('converts 1 percent to valid TransferRate', function () {
|
||||
const billionths = percentToTransferRate('1%')
|
||||
|
||||
assert.equal(billionths, 1010000000)
|
||||
})
|
||||
|
||||
it('converts .01 percent to valid TransferRate', function () {
|
||||
assert.equal(decimalToTransferRate('.01'), 1010000000)
|
||||
assert.equal(transferRateToDecimal(1010000000), '0.01')
|
||||
})
|
||||
|
||||
it('Throws when TransferRate < 0%', function () {
|
||||
assert.throws(
|
||||
() => percentToTransferRate('-1%'),
|
||||
ValidationError,
|
||||
'Decimal value must be between 0 and 1.00.',
|
||||
)
|
||||
})
|
||||
|
||||
it('Throws when TransferRate < 0', function () {
|
||||
assert.throws(
|
||||
() => decimalToTransferRate('-.01'),
|
||||
ValidationError,
|
||||
'Decimal value must be between 0 and 1.00.',
|
||||
)
|
||||
})
|
||||
|
||||
it('Throws when TransferRate >100%', function () {
|
||||
assert.throws(
|
||||
() => percentToTransferRate('101%'),
|
||||
ValidationError,
|
||||
'Decimal value must be between 0 and 1.00.',
|
||||
)
|
||||
})
|
||||
|
||||
it('Throws when TransferRate >1.00', function () {
|
||||
assert.throws(
|
||||
() => decimalToTransferRate('1.01'),
|
||||
ValidationError,
|
||||
'Decimal value must be between 0 and 1.00.',
|
||||
)
|
||||
})
|
||||
|
||||
it('percentToTransferRate greater than maximum precision', function () {
|
||||
assert.throws(
|
||||
() => percentToTransferRate('.0000000000000011221%'),
|
||||
ValidationError,
|
||||
'Decimal exceeds maximum precision.',
|
||||
)
|
||||
})
|
||||
|
||||
it('decimalToTransferRate greater than maximum precision', function () {
|
||||
assert.throws(
|
||||
() => decimalToTransferRate('.000000000000000011221'),
|
||||
ValidationError,
|
||||
'Decimal exceeds maximum precision.',
|
||||
)
|
||||
})
|
||||
|
||||
it('converts 0 percent to valid 0', function () {
|
||||
const billionths = percentToTransferRate('0%')
|
||||
|
||||
assert.equal(billionths, 0)
|
||||
})
|
||||
|
||||
it('converts 0 to valid 0', function () {
|
||||
assert.equal(decimalToTransferRate('0'), 0)
|
||||
assert.equal(transferRateToDecimal(0), '0')
|
||||
})
|
||||
})
|
||||
31
packages/xrpl/test/utils/verifyPaymentChannelClaim.ts
Normal file
31
packages/xrpl/test/utils/verifyPaymentChannelClaim.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { verifyPaymentChannelClaim } from 'xrpl-local'
|
||||
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import { assertResultMatch } from '../testUtils'
|
||||
|
||||
describe('verifyPaymentChannelClaim', function () {
|
||||
it('basic verification works', function () {
|
||||
const publicKey =
|
||||
'02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8'
|
||||
const result = verifyPaymentChannelClaim(
|
||||
requests.signPaymentChannelClaim.channel,
|
||||
requests.signPaymentChannelClaim.amount,
|
||||
responses.signPaymentChannelClaim,
|
||||
publicKey,
|
||||
)
|
||||
assertResultMatch(result, true, 'verifyPaymentChannelClaim')
|
||||
})
|
||||
|
||||
it('invalid payment channel claim fails', function () {
|
||||
const publicKey =
|
||||
'03A6523FE4281DA48A6FD77FAF3CB77F5C7001ABA0B32BCEDE0369AC009758D7D9'
|
||||
const result = verifyPaymentChannelClaim(
|
||||
requests.signPaymentChannelClaim.channel,
|
||||
requests.signPaymentChannelClaim.amount,
|
||||
responses.signPaymentChannelClaim,
|
||||
publicKey,
|
||||
)
|
||||
assertResultMatch(result, false, 'verifyPaymentChannelClaim')
|
||||
})
|
||||
})
|
||||
119
packages/xrpl/test/utils/xrpToDrops.ts
Normal file
119
packages/xrpl/test/utils/xrpToDrops.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { xrpToDrops } from 'xrpl-local/utils'
|
||||
|
||||
describe('xrpToDrops', function () {
|
||||
it('works with a typical amount', function () {
|
||||
const drops = xrpToDrops('2')
|
||||
assert.strictEqual(drops, '2000000', '2 XRP equals 2 million drops')
|
||||
})
|
||||
|
||||
it('works with fractions', function () {
|
||||
let drops = xrpToDrops('3.456789')
|
||||
assert.strictEqual(drops, '3456789', '3.456789 XRP equals 3,456,789 drops')
|
||||
drops = xrpToDrops('3.400000')
|
||||
assert.strictEqual(drops, '3400000', '3.400000 XRP equals 3,400,000 drops')
|
||||
drops = xrpToDrops('0.000001')
|
||||
assert.strictEqual(drops, '1', '0.000001 XRP equals 1 drop')
|
||||
drops = xrpToDrops('0.0000010')
|
||||
assert.strictEqual(drops, '1', '0.0000010 XRP equals 1 drop')
|
||||
})
|
||||
|
||||
it('works with zero', function () {
|
||||
let drops = xrpToDrops('0')
|
||||
assert.strictEqual(drops, '0', '0 XRP equals 0 drops')
|
||||
// negative zero is equivalent to zero
|
||||
drops = xrpToDrops('-0')
|
||||
assert.strictEqual(drops, '0', '-0 XRP equals 0 drops')
|
||||
drops = xrpToDrops('0.000000')
|
||||
assert.strictEqual(drops, '0', '0.000000 XRP equals 0 drops')
|
||||
drops = xrpToDrops('0.0000000')
|
||||
assert.strictEqual(drops, '0', '0.0000000 XRP equals 0 drops')
|
||||
})
|
||||
|
||||
it('works with a negative value', function () {
|
||||
const drops = xrpToDrops('-2')
|
||||
assert.strictEqual(drops, '-2000000', '-2 XRP equals -2 million drops')
|
||||
})
|
||||
|
||||
it('works with a value ending with a decimal point', function () {
|
||||
let drops = xrpToDrops('2.')
|
||||
assert.strictEqual(drops, '2000000', '2. XRP equals 2000000 drops')
|
||||
drops = xrpToDrops('-2.')
|
||||
assert.strictEqual(drops, '-2000000', '-2. XRP equals -2000000 drops')
|
||||
})
|
||||
|
||||
it('works with BigNumber objects', function () {
|
||||
let drops = xrpToDrops(new BigNumber(2))
|
||||
assert.strictEqual(
|
||||
drops,
|
||||
'2000000',
|
||||
'(BigNumber) 2 XRP equals 2 million drops',
|
||||
)
|
||||
drops = xrpToDrops(new BigNumber(-2))
|
||||
assert.strictEqual(
|
||||
drops,
|
||||
'-2000000',
|
||||
'(BigNumber) -2 XRP equals -2 million drops',
|
||||
)
|
||||
})
|
||||
|
||||
it('works with a number', function () {
|
||||
// This is not recommended. Use strings or BigNumber objects to avoid precision errors.
|
||||
const drops = xrpToDrops(2)
|
||||
assert.strictEqual(
|
||||
drops,
|
||||
'2000000',
|
||||
'(number) 2 XRP equals 2 million drops',
|
||||
)
|
||||
const drops2 = xrpToDrops(-2)
|
||||
assert.strictEqual(
|
||||
drops2,
|
||||
'-2000000',
|
||||
'(number) -2 XRP equals -2 million drops',
|
||||
)
|
||||
})
|
||||
|
||||
it('works with scientific notation', function () {
|
||||
const drops = xrpToDrops('1e-6')
|
||||
assert.strictEqual(
|
||||
drops,
|
||||
'1',
|
||||
'(scientific notation string) 1e-6 XRP equals 1 drop',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws with an amount with too many decimal places', function () {
|
||||
assert.throws(() => {
|
||||
xrpToDrops('1.1234567')
|
||||
}, /has too many decimal places/u)
|
||||
assert.throws(() => {
|
||||
xrpToDrops('0.0000001')
|
||||
}, /has too many decimal places/u)
|
||||
})
|
||||
|
||||
it('throws with an invalid value', function () {
|
||||
assert.throws(() => {
|
||||
xrpToDrops('FOO')
|
||||
}, /invalid value/u)
|
||||
assert.throws(() => {
|
||||
xrpToDrops('1e-7')
|
||||
}, /decimal place/u)
|
||||
assert.throws(() => {
|
||||
xrpToDrops('2,0')
|
||||
}, /invalid value/u)
|
||||
assert.throws(() => {
|
||||
xrpToDrops('.')
|
||||
}, /xrpToDrops: invalid value '\.', should be a BigNumber or string-encoded number\./u)
|
||||
})
|
||||
|
||||
it('throws with an amount more than one decimal point', function () {
|
||||
assert.throws(() => {
|
||||
xrpToDrops('1.0.0')
|
||||
}, /xrpToDrops: invalid value '1\.0\.0'/u)
|
||||
assert.throws(() => {
|
||||
xrpToDrops('...')
|
||||
}, /xrpToDrops: invalid value '\.\.\.'/u)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user