Files
xahau.js/src/common/utils.ts
2019-12-17 10:35:59 -08:00

190 lines
5.1 KiB
TypeScript

import * as _ from 'lodash'
import BigNumber from 'bignumber.js'
import {deriveKeypair} from 'ripple-keypairs'
import {Amount, RippledAmount} from './types/objects'
import {ValidationError} from './errors'
function isValidSecret(secret: string): boolean {
try {
deriveKeypair(secret)
return true
} catch (err) {
return false
}
}
function dropsToXrp(drops: BigNumber.Value): string {
if (typeof drops === 'string') {
if (!drops.match(/^-?[0-9]*\.?[0-9]*$/)) {
throw new ValidationError(
`dropsToXrp: invalid value '${drops}',` +
` should be a number matching (^-?[0-9]*\\.?[0-9]*$).`
)
} else if (drops === '.') {
throw new ValidationError(
`dropsToXrp: invalid value '${drops}',` +
` should be a BigNumber or string-encoded number.`
)
}
}
// Converting to BigNumber and then back to string should remove any
// decimal point followed by zeros, e.g. '1.00'.
// Important: specify base 10 to avoid exponential notation, e.g. '1e-7'.
drops = new BigNumber(drops).toString(10)
// drops are only whole units
if (drops.includes('.')) {
throw new ValidationError(
`dropsToXrp: value '${drops}' has` + ` too many decimal places.`
)
}
// This should never happen; the value has already been
// validated above. This just ensures BigNumber did not do
// something unexpected.
if (!drops.match(/^-?[0-9]+$/)) {
throw new ValidationError(
`dropsToXrp: failed sanity check -` +
` value '${drops}',` +
` does not match (^-?[0-9]+$).`
)
}
return new BigNumber(drops).dividedBy(1000000.0).toString(10)
}
function xrpToDrops(xrp: BigNumber.Value): string {
if (typeof xrp === 'string') {
if (!xrp.match(/^-?[0-9]*\.?[0-9]*$/)) {
throw new ValidationError(
`xrpToDrops: invalid value '${xrp}',` +
` should be a number matching (^-?[0-9]*\\.?[0-9]*$).`
)
} else if (xrp === '.') {
throw new ValidationError(
`xrpToDrops: invalid value '${xrp}',` +
` should be a BigNumber or string-encoded number.`
)
}
}
// Important: specify base 10 to avoid exponential notation, e.g. '1e-7'.
xrp = new BigNumber(xrp).toString(10)
// This should never happen; the value has already been
// validated above. This just ensures BigNumber did not do
// something unexpected.
if (!xrp.match(/^-?[0-9.]+$/)) {
throw new ValidationError(
`xrpToDrops: failed sanity check -` +
` value '${xrp}',` +
` does not match (^-?[0-9.]+$).`
)
}
const components = xrp.split('.')
if (components.length > 2) {
throw new ValidationError(
`xrpToDrops: failed sanity check -` +
` value '${xrp}' has` +
` too many decimal points.`
)
}
const fraction = components[1] || '0'
if (fraction.length > 6) {
throw new ValidationError(
`xrpToDrops: value '${xrp}' has` + ` too many decimal places.`
)
}
return new BigNumber(xrp)
.times(1000000.0)
.integerValue(BigNumber.ROUND_FLOOR)
.toString(10)
}
function toRippledAmount(amount: Amount): RippledAmount {
if (amount.currency === 'XRP') {
return xrpToDrops(amount.value)
}
if (amount.currency === 'drops') {
return amount.value
}
return {
currency: amount.currency,
issuer: amount.counterparty
? amount.counterparty
: amount.issuer
? amount.issuer
: undefined,
value: amount.value
}
}
function convertKeysFromSnakeCaseToCamelCase(obj: any): any {
if (typeof obj === 'object') {
const accumulator = Array.isArray(obj) ? [] : {}
let newKey
return _.reduce(
obj,
(result, value, key) => {
newKey = key
// taking this out of function leads to error in PhantomJS
const FINDSNAKE = /([a-zA-Z]_[a-zA-Z])/g
if (FINDSNAKE.test(key)) {
newKey = key.replace(FINDSNAKE, r => r[0] + r[2].toUpperCase())
}
result[newKey] = convertKeysFromSnakeCaseToCamelCase(value)
return result
},
accumulator
)
}
return obj
}
function removeUndefined<T extends object>(obj: T): T {
return _.omitBy(obj, _.isUndefined) as T
}
/**
* @param {Number} rpepoch (seconds since 1/1/2000 GMT)
* @return {Number} ms since unix epoch
*/
function rippleToUnixTimestamp(rpepoch: number): number {
return (rpepoch + 0x386d4380) * 1000
}
/**
* @param {Number|Date} timestamp (ms since unix epoch)
* @return {Number} seconds since ripple epoch (1/1/2000 GMT)
*/
function unixToRippleTimestamp(timestamp: number): number {
return Math.round(timestamp / 1000) - 0x386d4380
}
function rippleTimeToISO8601(rippleTime: number): string {
return new Date(rippleToUnixTimestamp(rippleTime)).toISOString()
}
/**
* @param {string} iso8601 international standard date format
* @return {number} seconds since ripple epoch (1/1/2000 GMT)
*/
function iso8601ToRippleTime(iso8601: string): number {
return unixToRippleTimestamp(Date.parse(iso8601))
}
export {
dropsToXrp,
xrpToDrops,
toRippledAmount,
convertKeysFromSnakeCaseToCamelCase,
removeUndefined,
rippleTimeToISO8601,
iso8601ToRippleTime,
isValidSecret
}