mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-20 04:05:52 +00:00
Allow specifying amounts in drops (#892)
* Accept "drops" in lieu of "XRP" * Export xrpToDrops() and dropsToXrp() * Throw our own validation errors instead of BigNumber Errors
This commit is contained in:
12
HISTORY.md
12
HISTORY.md
@@ -2,6 +2,18 @@
|
||||
|
||||
## 1.0.0 (UNRELEASED)
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
+ Amounts in drops (recommended) and XRP are checked for validity. Some
|
||||
methods may now throw a `BigNumber Error` or `ValidationError` if the amount
|
||||
is invalid. This may include methods that previously did not throw.
|
||||
+ Note that 1 drop is equivalent to 0.000001 XRP and 1 XRP is equivalent to 1,000,000 drops.
|
||||
|
||||
### Other Changes
|
||||
|
||||
+ Allow specifying amounts in drops for consistency with the `rippled`
|
||||
APIs.
|
||||
+ Export `xrpToDrops()` and `dropsToXrp()` functions.
|
||||
+ Potentially breaking change: Improve errors. For example, `RippledError` now includes the full response from
|
||||
the `rippled` server ([#687](https://github.com/ripple/ripple-lib/issues/687)). `NotConnectedError`
|
||||
may be thrown with a different message than before.
|
||||
|
||||
@@ -221,14 +221,13 @@ Currencies are represented as either 3-character currency codes or 40-character
|
||||
## Value
|
||||
A *value* is a quantity of a currency represented as a decimal string. Be careful: JavaScript's native number format does not have sufficient precision to represent all values. XRP has different precision from other currencies.
|
||||
|
||||
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). XRP has a maximum value of `100000000000` (1e11).
|
||||
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). This smallest unit is called a "drop". XRP has a maximum value of `100000000000` (1e11). Some RippleAPI methods accept XRP in order to maintain compatibility with older versions of the API. For consistency with the `rippled` APIs, we recommend formally specifying XRP values in *drops* in all API requests, and converting them to XRP for display. This is similar to Bitcoin's *satoshis* and Ethereum's *wei*. 1 XRP = 1,000,000 drops.
|
||||
|
||||
**Non-XRP values** have 16 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
|
||||
|
||||
|
||||
## Amount
|
||||
|
||||
Example amount:
|
||||
Example 100.00 USD amount:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -238,15 +237,16 @@ Example amount:
|
||||
}
|
||||
```
|
||||
|
||||
Example XRP amount:
|
||||
Example 3.0 XRP amount, in drops:
|
||||
```json
|
||||
{
|
||||
"currency": "XRP",
|
||||
"value": "2000"
|
||||
"currency": "drops",
|
||||
"value": "3000000"
|
||||
}
|
||||
```
|
||||
(Requires `ripple-lib` version 1.0.0 or higher.)
|
||||
|
||||
An *amount* is data structure representing a currency, a quantity of that currency, and the counterparty on the trustline that holds the value. For XRP, there is no counterparty.
|
||||
An *amount* is an object specifying a currency, a quantity of that currency, and the counterparty (issuer) on the trustline that holds the value. For XRP, there is no counterparty.
|
||||
|
||||
A *lax amount* allows the counterparty to be omitted for all currencies. If the counterparty is not specified in an amount within a transaction specification, then any counterparty may be used for that amount.
|
||||
|
||||
@@ -256,8 +256,8 @@ A *balance* is an amount than can have a negative value.
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
currency | [currency](#currency) | The three-character code or hexadecimal string used to denote currencies
|
||||
counterparty | [address](#address) | *Optional* The Ripple address of the account that owes or is owed the funds (omitted if `currency` is "XRP")
|
||||
currency | [currency](#currency) | The three-character code or hexadecimal string used to denote currencies, or "drops" for the smallest unit of XRP.
|
||||
counterparty | [address](#address) | *Optional* The Ripple address of the account that owes or is owed the funds (omitted if `currency` is "XRP" or "drops")
|
||||
value | [value](#value) | *Optional* The quantity of the currency, denoted as a string to retain floating point precision
|
||||
|
||||
# Transaction Overview
|
||||
@@ -323,7 +323,7 @@ maxLedgerVersionOffset | integer | *Optional* Offset from current validated ledg
|
||||
sequence | [sequence](#account-sequence-number) | *Optional* The initiating account's sequence number for this transaction.
|
||||
signersCount | integer | *Optional* Number of signers that will be signing this transaction.
|
||||
|
||||
We recommended that you specify a `maxLedgerVersion` so that you can quickly determine that a failed transaction will never succeeed in the future. It is impossible for a transaction to succeed after the XRP Ledger's consensus-validated ledger version exceeds the transaction's `maxLedgerVersion`. If you omit `maxLedgerVersion`, the "prepare*" method automatically supplies a `maxLedgerVersion` equal to the current ledger plus 3, which it includes in the return value from the "prepare*" method.
|
||||
We recommend that you specify a `maxLedgerVersion` so that you can quickly determine that a failed transaction will never succeeed in the future. It is impossible for a transaction to succeed after the XRP Ledger's consensus-validated ledger version exceeds the transaction's `maxLedgerVersion`. If you omit `maxLedgerVersion`, the "prepare\*" method automatically supplies a `maxLedgerVersion` equal to the current ledger plus 3, which it includes in the return value from the "prepare\*" method.
|
||||
|
||||
## Transaction ID
|
||||
|
||||
@@ -465,10 +465,10 @@ passive | boolean | *Optional* If enabled, the offer will not consume offers tha
|
||||
"value": "10.1"
|
||||
},
|
||||
"totalPrice": {
|
||||
"currency": "XRP",
|
||||
"value": "2"
|
||||
"currency": "drops",
|
||||
"value": "2000000"
|
||||
},
|
||||
"passive": true,
|
||||
"passive": false,
|
||||
"fillOrKill": true
|
||||
}
|
||||
```
|
||||
@@ -632,8 +632,8 @@ invoiceID | string | *Optional* 256-bit hash, as a 64-character hexadecimal stri
|
||||
{
|
||||
"destination": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
|
||||
"sendMax": {
|
||||
"currency": "XRP",
|
||||
"value": "1"
|
||||
"currency": "drops",
|
||||
"value": "1000000"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -673,8 +673,8 @@ deliverMin | [laxAmount](#amount) | *Optional* Redeem the Check for at least thi
|
||||
```json
|
||||
{
|
||||
"amount": {
|
||||
"currency": "XRP",
|
||||
"value": "1"
|
||||
"currency": "drops",
|
||||
"value": "1000000"
|
||||
},
|
||||
"checkID": "838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334"
|
||||
}
|
||||
@@ -4271,6 +4271,8 @@ instructions | object | The instructions for how to execute the transaction afte
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
|
||||
// Buy 10.10 USD (of the specified issuer) for 2.0 XRP (2000000 drops), fill or kill.
|
||||
const order = {
|
||||
"direction": "buy",
|
||||
"quantity": {
|
||||
@@ -4279,10 +4281,10 @@ const order = {
|
||||
"value": "10.1"
|
||||
},
|
||||
"totalPrice": {
|
||||
"currency": "XRP",
|
||||
"value": "2"
|
||||
"currency": "drops",
|
||||
"value": "2000000"
|
||||
},
|
||||
"passive": true,
|
||||
"passive": false,
|
||||
"fillOrKill": true
|
||||
};
|
||||
return api.prepareOrder(address, order)
|
||||
@@ -4292,7 +4294,7 @@ return api.prepareOrder(address, order)
|
||||
|
||||
```json
|
||||
{
|
||||
"txJSON": "{\"Flags\":2147811328,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":\"2000000\",\"TakerPays\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"txJSON": "{\"Flags\":2147745792,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":\"2000000\",\"TakerPays\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
@@ -4798,8 +4800,8 @@ const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const checkCreate = {
|
||||
"destination": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
|
||||
"sendMax": {
|
||||
"currency": "XRP",
|
||||
"value": "1"
|
||||
"currency": "drops",
|
||||
"value": "1000000"
|
||||
}
|
||||
};
|
||||
return api.prepareCheckCreate(address, checkCreate).then(prepared =>
|
||||
@@ -4911,8 +4913,8 @@ instructions | object | The instructions for how to execute the transaction afte
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const checkCash = {
|
||||
"amount": {
|
||||
"currency": "XRP",
|
||||
"value": "1"
|
||||
"currency": "drops",
|
||||
"value": "1000000"
|
||||
},
|
||||
"checkID": "838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334"
|
||||
};
|
||||
|
||||
@@ -19,14 +19,13 @@ Currencies are represented as either 3-character currency codes or 40-character
|
||||
## Value
|
||||
A *value* is a quantity of a currency represented as a decimal string. Be careful: JavaScript's native number format does not have sufficient precision to represent all values. XRP has different precision from other currencies.
|
||||
|
||||
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). XRP has a maximum value of `100000000000` (1e11).
|
||||
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). This smallest unit is called a "drop". XRP has a maximum value of `100000000000` (1e11). Some RippleAPI methods accept XRP in order to maintain compatibility with older versions of the API. For consistency with the `rippled` APIs, we recommend formally specifying XRP values in *drops* in all API requests, and converting them to XRP for display. This is similar to Bitcoin's *satoshis* and Ethereum's *wei*. 1 XRP = 1,000,000 drops.
|
||||
|
||||
**Non-XRP values** have 16 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
|
||||
|
||||
|
||||
## Amount
|
||||
|
||||
Example amount:
|
||||
Example 100.00 USD amount:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -36,15 +35,16 @@ Example amount:
|
||||
}
|
||||
```
|
||||
|
||||
Example XRP amount:
|
||||
Example 3.0 XRP amount, in drops:
|
||||
```json
|
||||
{
|
||||
"currency": "XRP",
|
||||
"value": "2000"
|
||||
"currency": "drops",
|
||||
"value": "3000000"
|
||||
}
|
||||
```
|
||||
(Requires `ripple-lib` version 1.0.0 or higher.)
|
||||
|
||||
An *amount* is data structure representing a currency, a quantity of that currency, and the counterparty on the trustline that holds the value. For XRP, there is no counterparty.
|
||||
An *amount* is an object specifying a currency, a quantity of that currency, and the counterparty (issuer) on the trustline that holds the value. For XRP, there is no counterparty.
|
||||
|
||||
A *lax amount* allows the counterparty to be omitted for all currencies. If the counterparty is not specified in an amount within a transaction specification, then any counterparty may be used for that amount.
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ All "prepare*" methods have the same return type.
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
|
||||
// Buy 10.10 USD (of the specified issuer) for 2.0 XRP (2000000 drops), fill or kill.
|
||||
const order = <%- importFile('test/fixtures/requests/prepare-order.json') %>;
|
||||
return api.prepareOrder(address, order)
|
||||
.then(prepared => {/* ... */});
|
||||
|
||||
@@ -53,7 +53,7 @@ Transaction instructions indicate how to execute a transaction, complementary wi
|
||||
|
||||
<%- renderSchema("objects/instructions.json") %>
|
||||
|
||||
We recommended that you specify a `maxLedgerVersion` so that you can quickly determine that a failed transaction will never succeeed in the future. It is impossible for a transaction to succeed after the XRP Ledger's consensus-validated ledger version exceeds the transaction's `maxLedgerVersion`. If you omit `maxLedgerVersion`, the "prepare*" method automatically supplies a `maxLedgerVersion` equal to the current ledger plus 3, which it includes in the return value from the "prepare*" method.
|
||||
We recommend that you specify a `maxLedgerVersion` so that you can quickly determine that a failed transaction will never succeeed in the future. It is impossible for a transaction to succeed after the XRP Ledger's consensus-validated ledger version exceeds the transaction's `maxLedgerVersion`. If you omit `maxLedgerVersion`, the "prepare\*" method automatically supplies a `maxLedgerVersion` equal to the current ledger plus 3, which it includes in the return value from the "prepare\*" method.
|
||||
|
||||
## Transaction ID
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {EventEmitter} from 'events'
|
||||
import {Connection, errors, validate} from './common'
|
||||
import {Connection, errors, validate, xrpToDrops, dropsToXrp} from './common'
|
||||
import {
|
||||
connect,
|
||||
disconnect,
|
||||
@@ -300,6 +300,9 @@ class RippleAPI extends EventEmitter {
|
||||
signPaymentChannelClaim = signPaymentChannelClaim
|
||||
verifyPaymentChannelClaim = verifyPaymentChannelClaim
|
||||
errors = errors
|
||||
|
||||
xrpToDrops = xrpToDrops
|
||||
dropsToXrp = dropsToXrp
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
"$ref": "value"
|
||||
},
|
||||
"currency": {
|
||||
"description": "The three-character code or hexadecimal string used to denote currencies",
|
||||
"description": "The three-character code or hexadecimal string used to denote currencies, or \"drops\" for the smallest unit of XRP.",
|
||||
"$ref": "currency"
|
||||
},
|
||||
"counterparty": {
|
||||
"description": "The Ripple address of the account that owes or is owed the funds (omitted if `currency` is \"XRP\")",
|
||||
"description": "The Ripple address of the account that owes or is owed the funds (omitted if `currency` is \"XRP\" or \"drops\")",
|
||||
"$ref": "address"
|
||||
}
|
||||
},
|
||||
@@ -24,7 +24,7 @@
|
||||
"properties": {
|
||||
"currency": {
|
||||
"not": {
|
||||
"enum": ["XRP"]
|
||||
"enum": ["XRP", "drops"]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -33,7 +33,7 @@
|
||||
{
|
||||
"properties": {
|
||||
"currency": {
|
||||
"enum": ["XRP"]
|
||||
"enum": ["XRP", "drops"]
|
||||
}
|
||||
},
|
||||
"not": {
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
"description": "The three-character code or hexadecimal string used to denote currencies",
|
||||
"type": "string",
|
||||
"link": "currency",
|
||||
"pattern": "^([a-zA-Z0-9<>(){}[\\]|?!@#$%^&*]{3}|[A-F0-9]{40})$"
|
||||
"pattern": "^([a-zA-Z0-9<>(){}[\\]|?!@#$%^&*]{3}|[A-F0-9]{40}|drops)$"
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as _ from 'lodash'
|
||||
import BigNumber from 'bignumber.js'
|
||||
const {deriveKeypair} = require('ripple-keypairs')
|
||||
|
||||
import {deriveKeypair} from 'ripple-keypairs'
|
||||
import {Amount, RippledAmount} from './types/objects'
|
||||
import {ValidationError} from './errors'
|
||||
|
||||
function isValidSecret(secret: string): boolean {
|
||||
try {
|
||||
@@ -13,18 +13,86 @@ function isValidSecret(secret: string): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
function dropsToXrp(drops: string): string {
|
||||
return (new BigNumber(drops)).dividedBy(1000000.0).toString()
|
||||
function dropsToXrp(drops: string | BigNumber): 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: string): string {
|
||||
return (new BigNumber(xrp)).times(1000000.0).floor().toString()
|
||||
function xrpToDrops(xrp: string | BigNumber): 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).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 :
|
||||
|
||||
219
test/api-test.js
219
test/api-test.js
@@ -15,6 +15,7 @@ const utils = RippleAPI._PRIVATE.ledgerUtils;
|
||||
const ledgerClosed = require('./fixtures/rippled/ledger-close-newer');
|
||||
const schemaValidator = RippleAPI._PRIVATE.schemaValidator;
|
||||
const binary = require('ripple-binary-codec');
|
||||
const BigNumber = require('bignumber.js')
|
||||
assert.options.strict = true;
|
||||
|
||||
// how long before each test case times out
|
||||
@@ -51,6 +52,224 @@ describe('RippleAPI', function () {
|
||||
assert.strictEqual(error.inspect(), '[RippleError(mess, { data: 1 })]');
|
||||
});
|
||||
|
||||
describe('xrpToDrops', function () {
|
||||
it('works with a typical amount', function () {
|
||||
const drops = this.api.xrpToDrops('2')
|
||||
assert.strictEqual(drops, '2000000', '2 XRP equals 2 million drops')
|
||||
})
|
||||
|
||||
it('works with fractions', function () {
|
||||
let drops = this.api.xrpToDrops('3.456789')
|
||||
assert.strictEqual(drops, '3456789', '3.456789 XRP equals 3,456,789 drops')
|
||||
|
||||
drops = this.api.xrpToDrops('3.400000')
|
||||
assert.strictEqual(drops, '3400000', '3.400000 XRP equals 3,400,000 drops')
|
||||
|
||||
drops = this.api.xrpToDrops('0.000001')
|
||||
assert.strictEqual(drops, '1', '0.000001 XRP equals 1 drop')
|
||||
|
||||
drops = this.api.xrpToDrops('0.0000010')
|
||||
assert.strictEqual(drops, '1', '0.0000010 XRP equals 1 drop')
|
||||
})
|
||||
|
||||
it('works with zero', function () {
|
||||
let drops = this.api.xrpToDrops('0')
|
||||
assert.strictEqual(drops, '0', '0 XRP equals 0 drops')
|
||||
|
||||
// negative zero is equivalent to zero
|
||||
drops = this.api.xrpToDrops('-0')
|
||||
assert.strictEqual(drops, '0', '-0 XRP equals 0 drops')
|
||||
|
||||
drops = this.api.xrpToDrops('0.000000')
|
||||
assert.strictEqual(drops, '0', '0.000000 XRP equals 0 drops')
|
||||
|
||||
drops = this.api.xrpToDrops('0.0000000')
|
||||
assert.strictEqual(drops, '0', '0.0000000 XRP equals 0 drops')
|
||||
})
|
||||
|
||||
it('works with a negative value', function () {
|
||||
const drops = this.api.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 = this.api.xrpToDrops('2.')
|
||||
assert.strictEqual(drops, '2000000', '2. XRP equals 2000000 drops')
|
||||
|
||||
drops = this.api.xrpToDrops('-2.')
|
||||
assert.strictEqual(drops, '-2000000', '-2. XRP equals -2000000 drops')
|
||||
})
|
||||
|
||||
it('works with BigNumber objects', function () {
|
||||
let drops = this.api.xrpToDrops(new BigNumber(2))
|
||||
assert.strictEqual(drops, '2000000', '(BigNumber) 2 XRP equals 2 million drops')
|
||||
|
||||
drops = this.api.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.
|
||||
|
||||
let drops = this.api.xrpToDrops(2)
|
||||
assert.strictEqual(drops, '2000000', '(number) 2 XRP equals 2 million drops')
|
||||
|
||||
drops = this.api.xrpToDrops(-2)
|
||||
assert.strictEqual(drops, '-2000000', '(number) -2 XRP equals -2 million drops')
|
||||
})
|
||||
|
||||
it('throws with an amount with too many decimal places', function () {
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('1.1234567')
|
||||
}, /has too many decimal places/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('0.0000001')
|
||||
}, /has too many decimal places/)
|
||||
})
|
||||
|
||||
it('throws with an invalid value', function () {
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('FOO')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('1e-7')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('2,0')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('.')
|
||||
}, /xrpToDrops\: invalid value '\.', should be a BigNumber or string-encoded number\./)
|
||||
})
|
||||
|
||||
it('throws with an amount more than one decimal point', function () {
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('1.0.0')
|
||||
}, /xrpToDrops:\ invalid\ value\ '1\.0\.0'\,\ should\ be\ a\ number\ matching\ \(\^\-\?\[0\-9\]\*\.\?\[0\-9\]\*\$\)\./)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('...')
|
||||
}, /xrpToDrops:\ invalid\ value\ '\.\.\.'\,\ should\ be\ a\ number\ matching\ \(\^\-\?\[0\-9\]\*\.\?\[0\-9\]\*\$\)\./)
|
||||
})
|
||||
})
|
||||
|
||||
describe('dropsToXrp', function () {
|
||||
it('works with a typical amount', function () {
|
||||
const xrp = this.api.dropsToXrp('2000000')
|
||||
assert.strictEqual(xrp, '2', '2 million drops equals 2 XRP')
|
||||
})
|
||||
|
||||
it('works with fractions', function () {
|
||||
let xrp = this.api.dropsToXrp('3456789')
|
||||
assert.strictEqual(xrp, '3.456789', '3,456,789 drops equals 3.456789 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp('3400000')
|
||||
assert.strictEqual(xrp, '3.4', '3,400,000 drops equals 3.4 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp('1')
|
||||
assert.strictEqual(xrp, '0.000001', '1 drop equals 0.000001 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp('1.0')
|
||||
assert.strictEqual(xrp, '0.000001', '1.0 drops equals 0.000001 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp('1.00')
|
||||
assert.strictEqual(xrp, '0.000001', '1.00 drops equals 0.000001 XRP')
|
||||
})
|
||||
|
||||
it('works with zero', function () {
|
||||
let xrp = this.api.dropsToXrp('0')
|
||||
assert.strictEqual(xrp, '0', '0 drops equals 0 XRP')
|
||||
|
||||
// negative zero is equivalent to zero
|
||||
xrp = this.api.dropsToXrp('-0')
|
||||
assert.strictEqual(xrp, '0', '-0 drops equals 0 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp('0.00')
|
||||
assert.strictEqual(xrp, '0', '0.00 drops equals 0 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp('000000000')
|
||||
assert.strictEqual(xrp, '0', '000000000 drops equals 0 XRP')
|
||||
})
|
||||
|
||||
it('works with a negative value', function () {
|
||||
const xrp = this.api.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 = this.api.dropsToXrp('2000000.')
|
||||
assert.strictEqual(xrp, '2', '2000000. drops equals 2 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp('-2000000.')
|
||||
assert.strictEqual(xrp, '-2', '-2000000. drops equals -2 XRP')
|
||||
})
|
||||
|
||||
it('works with BigNumber objects', function () {
|
||||
let xrp = this.api.dropsToXrp(new BigNumber(2000000))
|
||||
assert.strictEqual(xrp, '2', '(BigNumber) 2 million drops equals 2 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp(new BigNumber(-2000000))
|
||||
assert.strictEqual(xrp, '-2', '(BigNumber) -2 million drops equals -2 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp(new BigNumber(2345678))
|
||||
assert.strictEqual(xrp, '2.345678', '(BigNumber) 2,345,678 drops equals 2.345678 XRP')
|
||||
|
||||
xrp = this.api.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 = this.api.dropsToXrp(2000000)
|
||||
assert.strictEqual(xrp, '2', '(number) 2 million drops equals 2 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp(-2000000)
|
||||
assert.strictEqual(xrp, '-2', '(number) -2 million drops equals -2 XRP')
|
||||
})
|
||||
|
||||
it('throws with an amount with too many decimal places', function () {
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('1.2')
|
||||
}, /has too many decimal places/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('0.10')
|
||||
}, /has too many decimal places/)
|
||||
})
|
||||
|
||||
it('throws with an invalid value', function () {
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('FOO')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('1e-7')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('2,0')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('.')
|
||||
}, /dropsToXrp\: invalid value '\.', should be a BigNumber or string-encoded number\./)
|
||||
})
|
||||
|
||||
it('throws with an amount more than one decimal point', function () {
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('1.0.0')
|
||||
}, /dropsToXrp:\ invalid\ value\ '1\.0\.0'\,\ should\ be\ a\ number\ matching\ \(\^\-\?\[0\-9\]\*\.\?\[0\-9\]\*\$\)\./)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('...')
|
||||
}, /dropsToXrp:\ invalid\ value\ '\.\.\.'\,\ should\ be\ a\ number\ matching\ \(\^\-\?\[0\-9\]\*\.\?\[0\-9\]\*\$\)\./)
|
||||
})
|
||||
})
|
||||
describe('pagination', function () {
|
||||
|
||||
describe('hasNextPage', function () {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"amount": {
|
||||
"currency": "XRP",
|
||||
"value": "1"
|
||||
"currency": "drops",
|
||||
"value": "1000000"
|
||||
},
|
||||
"checkID": "838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"destination": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
|
||||
"sendMax": {
|
||||
"currency": "XRP",
|
||||
"value": "1"
|
||||
"currency": "drops",
|
||||
"value": "1000000"
|
||||
}
|
||||
}
|
||||
|
||||
6
test/fixtures/requests/prepare-order.json
vendored
6
test/fixtures/requests/prepare-order.json
vendored
@@ -6,9 +6,9 @@
|
||||
"value": "10.1"
|
||||
},
|
||||
"totalPrice": {
|
||||
"currency": "XRP",
|
||||
"value": "2"
|
||||
"currency": "drops",
|
||||
"value": "2000000"
|
||||
},
|
||||
"passive": true,
|
||||
"passive": false,
|
||||
"fillOrKill": true
|
||||
}
|
||||
|
||||
2
test/fixtures/responses/prepare-order.json
vendored
2
test/fixtures/responses/prepare-order.json
vendored
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"txJSON": "{\"Flags\":2147811328,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":\"2000000\",\"TakerPays\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"txJSON": "{\"Flags\":2147745792,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":\"2000000\",\"TakerPays\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
|
||||
Reference in New Issue
Block a user