mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-09 23:35:48 +00:00
Compare commits
2 Commits
1.0.0-beta
...
1.0.0-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d1132b7fa | ||
|
|
e07fa11923 |
31
HISTORY.md
31
HISTORY.md
@@ -1,5 +1,36 @@
|
||||
# ripple-lib Release History
|
||||
|
||||
## 1.0.0-beta.2 (2018-06-08)
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
+ During transaction preparation, there is now a maximum fee. Also, when a transaction is signed, its fee is checked and an error is thrown if the fee exceeds the maximum. The default `maxFeeXRP` is `'2'` (2 XRP). Override this value in the RippleAPI constructor.
|
||||
+ Attempting to prepare a transaction with an exact `fee` higher than `maxFeeXRP` causes a `ValidationError` to be thrown.
|
||||
+ Attempting to sign a transaction with a fee higher than `maxFeeXRP` causes a `ValidationError` to be thrown.
|
||||
+ The value returned by `getFee()` is capped at `maxFeeXRP`.
|
||||
|
||||
### Other Changes
|
||||
|
||||
+ In Transaction Instructions, the `maxFee` parameter is deprecated. Use the `maxFeeXRP` parameter in the RippleAPI constructor.
|
||||
|
||||
#### Overview of new fee limit
|
||||
|
||||
Most users of ripple-lib do not need to make any code changes to accommodate the new soft limit on fees. The limit is designed to protect against the most severe cases where an unintentionally high fee may be used.
|
||||
|
||||
+ When having ripple-lib provide the fee with a `prepare*` method, a maximum fee of `maxFeeXRP` (default 2 XRP) applies. You can prepare more economical transactions by setting a lower `maxFeeXRP`, or support high-priority transactions by setting a higher `maxFeeXRP` in the RippleAPI constructor.
|
||||
+ When using `sign` with a Fee higher than `maxFeeXRP`, a `ValidationError` is thrown.
|
||||
|
||||
If you have any questions or concerns, please open an issue on GitHub.
|
||||
|
||||
The SHA-256 checksums for the browser version of this release can be found
|
||||
below.
|
||||
```
|
||||
% shasum -a 256 *
|
||||
ef348a2805098e61395b689b410cbf4bfd35e4d72e38c89f4ab74ec5e19793f5 ripple-1.0.0-beta.2-debug.js
|
||||
ea33fd53df8c7176d5fbf52dae0b64aade7180860f26449062cdbefaf8bd4d9b ripple-1.0.0-beta.2-min.js
|
||||
fe5cc6e97c9b8a1470dacb34f16a64255cd639a25381abe9db1ba79e102456f2 ripple-1.0.0-beta.2.js
|
||||
```
|
||||
|
||||
## 1.0.0-beta.1 (2018-05-24)
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
@@ -152,6 +152,7 @@ authorization | string | *Optional* Username and password for HTTP basic authent
|
||||
certificate | string | *Optional* A string containing the certificate key of the client in PEM format. (Can be an array of certificates).
|
||||
feeCushion | number | *Optional* Factor to multiply estimated fee by to provide a cushion in case the required fee rises during submission of a transaction. Defaults to `1.2`.
|
||||
key | string | *Optional* A string containing the private key of the client in PEM format. (Can be an array of keys).
|
||||
maxFeeXRP | string | *Optional* Maximum fee to use with transactions, in XRP. Must be a string-encoded number. Defaults to `'2'`.
|
||||
passphrase | string | *Optional* The passphrase for the private key of the client.
|
||||
proxy | uri string | *Optional* URI for HTTP/HTTPS proxy to use to connect to the rippled server.
|
||||
proxyAuthorization | string | *Optional* Username and password for HTTP basic authentication to the proxy in the format **username:password**.
|
||||
@@ -316,7 +317,7 @@ Transaction instructions indicate how to execute a transaction, complementary wi
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
fee | [value](#value) | *Optional* An exact fee to pay for the transaction. See [Transaction Fees](#transaction-fees) for more information.
|
||||
maxFee | [value](#value) | *Optional* The maximum fee to pay for the transaction. See [Transaction Fees](#transaction-fees) for more information.
|
||||
maxFee | [value](#value) | *Optional* Deprecated: Use `maxFeeXRP` in the RippleAPI constructor instead. The maximum fee to pay for this transaction. If this exceeds `maxFeeXRP`, `maxFeeXRP` will be used instead. See [Transaction Fees](#transaction-fees) for more information.
|
||||
maxLedgerVersion | integer,null | *Optional* The highest ledger version that the transaction can be included in. If this option and `maxLedgerVersionOffset` are both omitted, the `maxLedgerVersion` option will default to 3 greater than the current validated ledger version (equivalent to `maxLedgerVersionOffset=3`). Use `null` to not set a maximum ledger version.
|
||||
maxLedgerVersion | string,null | *Optional* The highest ledger version that the transaction can be included in. If this option and `maxLedgerVersionOffset` are both omitted, the `maxLedgerVersion` option will default to 3 greater than the current validated ledger version (equivalent to `maxLedgerVersionOffset=3`). Use `null` to not set a maximum ledger version.
|
||||
maxLedgerVersionOffset | integer | *Optional* Offset from current validated ledger version to highest ledger version that the transaction can be included in.
|
||||
@@ -1076,7 +1077,9 @@ Returns the estimated transaction fee for the rippled server the RippleAPI insta
|
||||
|
||||
### Parameters
|
||||
|
||||
This method has no parameters.
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
cushion | number | *Optional* The fee is the product of the base fee, the `load_factor`, and this cushion. Default is provided by the `RippleAPI` constructor's `feeCushion`.
|
||||
|
||||
### Return Value
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Returns the estimated transaction fee for the rippled server the RippleAPI insta
|
||||
|
||||
### Parameters
|
||||
|
||||
This method has no parameters.
|
||||
<%- renderSchema('input/get-fee.json') %>
|
||||
|
||||
### Return Value
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "1.0.0-beta.1",
|
||||
"version": "1.0.0-beta.2",
|
||||
"license": "ISC",
|
||||
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
||||
"files": [
|
||||
|
||||
@@ -64,6 +64,7 @@ import {clamp} from './ledger/utils'
|
||||
export type APIOptions = {
|
||||
server?: string,
|
||||
feeCushion?: number,
|
||||
maxFeeXRP?: string,
|
||||
trace?: boolean,
|
||||
proxy?: string,
|
||||
timeout?: number
|
||||
@@ -88,6 +89,7 @@ function getCollectKeyFromCommand(command: string): string|undefined {
|
||||
|
||||
class RippleAPI extends EventEmitter {
|
||||
_feeCushion: number
|
||||
_maxFeeXRP: string
|
||||
|
||||
// New in > 0.21.0
|
||||
// non-validated ledger versions are allowed, and passed to rippled as-is.
|
||||
@@ -105,6 +107,7 @@ class RippleAPI extends EventEmitter {
|
||||
super()
|
||||
validate.apiOptions(options)
|
||||
this._feeCushion = options.feeCushion || 1.2
|
||||
this._maxFeeXRP = options.maxFeeXRP || '2'
|
||||
const serverURL = options.server
|
||||
if (serverURL !== undefined) {
|
||||
this.connection = new Connection(serverURL, options)
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
"minimum": 1,
|
||||
"description": "Factor to multiply estimated fee by to provide a cushion in case the required fee rises during submission of a transaction. Defaults to `1.2`."
|
||||
},
|
||||
"maxFeeXRP": {
|
||||
"type": "string",
|
||||
"description": "Maximum fee to use with transactions, in XRP. Must be a string-encoded number. Defaults to `'2'`."
|
||||
},
|
||||
"server": {
|
||||
"type": "string",
|
||||
"description": "URI for rippled websocket port to connect to. Must start with `wss://` or `ws://`.",
|
||||
|
||||
13
src/common/schemas/input/get-fee.json
Normal file
13
src/common/schemas/input/get-fee.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "getFeeParameters",
|
||||
"description": "Parameters for getFee",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cushion": {
|
||||
"type": "number",
|
||||
"description": "The fee is the product of the base fee, the `load_factor`, and this cushion. Default is provided by the `RippleAPI` constructor's `feeCushion`."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
"$ref": "value"
|
||||
},
|
||||
"maxFee": {
|
||||
"description": "The maximum fee to pay for the transaction. See [Transaction Fees](#transaction-fees) for more information.",
|
||||
"description": "Deprecated: Use `maxFeeXRP` in the RippleAPI constructor instead. The maximum fee to pay for this transaction. If this exceeds `maxFeeXRP`, `maxFeeXRP` will be used instead. See [Transaction Fees](#transaction-fees) for more information.",
|
||||
"$ref": "value"
|
||||
},
|
||||
"maxLedgerVersion": {
|
||||
|
||||
@@ -2,7 +2,6 @@ import * as _ from 'lodash'
|
||||
import {convertKeysFromSnakeCaseToCamelCase} from './utils'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import {RippleAPI} from '../index'
|
||||
import {ServerInfoResponse} from './types/commands'
|
||||
|
||||
export type GetServerInfoResponse = {
|
||||
buildVersion: string,
|
||||
@@ -40,14 +39,6 @@ function renameKeys(object, mapping) {
|
||||
})
|
||||
}
|
||||
|
||||
function computeFeeFromServerInfo(
|
||||
cushion: number, serverInfo: ServerInfoResponse
|
||||
): string {
|
||||
return (new BigNumber(serverInfo.info.validated_ledger.base_fee_xrp)).
|
||||
times(serverInfo.info.load_factor).
|
||||
times(cushion).toString()
|
||||
}
|
||||
|
||||
function getServerInfo(this: RippleAPI): Promise<GetServerInfoResponse> {
|
||||
return this.request('server_info').then(response => {
|
||||
const info = convertKeysFromSnakeCaseToCamelCase(response.info)
|
||||
@@ -70,15 +61,23 @@ function getServerInfo(this: RippleAPI): Promise<GetServerInfoResponse> {
|
||||
})
|
||||
}
|
||||
|
||||
async function getFee(this: RippleAPI, cushion?: number): Promise<string> {
|
||||
async function getFee(
|
||||
this: RippleAPI,
|
||||
cushion?: number
|
||||
): Promise<string> {
|
||||
if (cushion === undefined) {
|
||||
cushion = this._feeCushion
|
||||
}
|
||||
if (cushion === undefined) {
|
||||
cushion = 1.2
|
||||
}
|
||||
const response = await this.request('server_info')
|
||||
return computeFeeFromServerInfo(cushion, response)
|
||||
|
||||
const serverInfo = (await this.request('server_info')).info
|
||||
const baseFeeXrp = new BigNumber(serverInfo.validated_ledger.base_fee_xrp)
|
||||
const fee = baseFeeXrp.times(serverInfo.load_factor).times(cushion)
|
||||
|
||||
// Cap fee to `this._maxFeeXRP`
|
||||
return BigNumber.min(fee, this._maxFeeXRP).toString(10)
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
@@ -3,6 +3,9 @@ import keypairs = require('ripple-keypairs')
|
||||
import binary = require('ripple-binary-codec')
|
||||
import {computeBinaryTransactionHash} from 'ripple-hashes'
|
||||
import {SignOptions, KeyPair} from './types'
|
||||
import {BigNumber} from 'bignumber.js'
|
||||
import {xrpToDrops} from '../common'
|
||||
import {RippleAPI} from '../api'
|
||||
const validate = utils.common.validate
|
||||
|
||||
function computeSignature(tx: Object, privateKey: string, signAs?: string) {
|
||||
@@ -13,6 +16,7 @@ function computeSignature(tx: Object, privateKey: string, signAs?: string) {
|
||||
}
|
||||
|
||||
function signWithKeypair(
|
||||
api: RippleAPI,
|
||||
txJSON: string,
|
||||
keypair: KeyPair,
|
||||
options: SignOptions = {
|
||||
@@ -28,6 +32,15 @@ function signWithKeypair(
|
||||
)
|
||||
}
|
||||
|
||||
const fee = new BigNumber(tx.Fee)
|
||||
const maxFeeDrops = xrpToDrops(api._maxFeeXRP)
|
||||
if (fee.greaterThan(maxFeeDrops)) {
|
||||
throw new utils.common.errors.ValidationError(
|
||||
`"Fee" should not exceed "${maxFeeDrops}". ` +
|
||||
'To use a higher fee, set `maxFeeXRP` in the RippleAPI constructor.'
|
||||
)
|
||||
}
|
||||
|
||||
tx.SigningPubKey = options.signAs ? '' : keypair.publicKey
|
||||
|
||||
if (options.signAs) {
|
||||
@@ -49,6 +62,7 @@ function signWithKeypair(
|
||||
}
|
||||
|
||||
function sign(
|
||||
this: RippleAPI,
|
||||
txJSON: string,
|
||||
secret?: any,
|
||||
options?: SignOptions,
|
||||
@@ -58,9 +72,18 @@ function sign(
|
||||
// we can't validate that the secret matches the account because
|
||||
// the secret could correspond to the regular key
|
||||
validate.sign({txJSON, secret})
|
||||
return signWithKeypair(txJSON, keypairs.deriveKeypair(secret), options)
|
||||
return signWithKeypair(
|
||||
this,
|
||||
txJSON,
|
||||
keypairs.deriveKeypair(secret),
|
||||
options
|
||||
)
|
||||
} else {
|
||||
return signWithKeypair(txJSON, keypair ? keypair : secret, options)
|
||||
return signWithKeypair(
|
||||
this,
|
||||
txJSON,
|
||||
keypair ? keypair : secret,
|
||||
options)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import {ApiMemo} from './utils'
|
||||
export type Instructions = {
|
||||
sequence?: number,
|
||||
fee?: string,
|
||||
// @deprecated
|
||||
maxFee?: string,
|
||||
maxLedgerVersion?: number,
|
||||
maxLedgerVersionOffset?: number,
|
||||
|
||||
@@ -4,6 +4,7 @@ import {Memo} from '../common/types/objects'
|
||||
const txFlags = common.txFlags
|
||||
import {Instructions, Prepare} from './types'
|
||||
import {RippleAPI} from '../api'
|
||||
import {ValidationError} from '../common/errors'
|
||||
|
||||
export type ApiMemo = {
|
||||
MemoData?: string,
|
||||
@@ -63,6 +64,13 @@ function prepareTransaction(txJSON: any, api: RippleAPI,
|
||||
const multiplier = instructions.signersCount === undefined ? 1 :
|
||||
instructions.signersCount + 1
|
||||
if (instructions.fee !== undefined) {
|
||||
const fee = new BigNumber(instructions.fee)
|
||||
if (fee.greaterThan(api._maxFeeXRP)) {
|
||||
const errorMessage = `Fee of ${fee.toString(10)} XRP exceeds ` +
|
||||
`max of ${api._maxFeeXRP} XRP. To use this fee, increase ` +
|
||||
'`maxFeeXRP` in the RippleAPI constructor.'
|
||||
throw new ValidationError(errorMessage)
|
||||
}
|
||||
txJSON.Fee = scaleValue(common.xrpToDrops(instructions.fee), multiplier)
|
||||
return Promise.resolve(txJSON)
|
||||
}
|
||||
@@ -75,13 +83,12 @@ function prepareTransaction(txJSON: any, api: RippleAPI,
|
||||
(cushion * feeRef * (32 + Math.floor(
|
||||
new Buffer(txJSON.Fulfillment, 'hex').length / 16)))
|
||||
const feeDrops = common.xrpToDrops(fee)
|
||||
if (instructions.maxFee !== undefined) {
|
||||
const maxFeeDrops = common.xrpToDrops(instructions.maxFee)
|
||||
const normalFee = scaleValue(feeDrops, multiplier, extraFee)
|
||||
txJSON.Fee = BigNumber.min(normalFee, maxFeeDrops).toString()
|
||||
} else {
|
||||
txJSON.Fee = scaleValue(feeDrops, multiplier, extraFee)
|
||||
}
|
||||
const maxFeeXRP = instructions.maxFee ?
|
||||
BigNumber.min(api._maxFeeXRP, instructions.maxFee) : api._maxFeeXRP
|
||||
const maxFeeDrops = common.xrpToDrops(maxFeeXRP)
|
||||
const normalFee = scaleValue(feeDrops, multiplier, extraFee)
|
||||
txJSON.Fee = BigNumber.min(normalFee, maxFeeDrops).toString(10)
|
||||
|
||||
return txJSON
|
||||
})
|
||||
})
|
||||
|
||||
157
test/api-test.js
157
test/api-test.js
@@ -392,6 +392,37 @@ describe('RippleAPI', function () {
|
||||
instructions).then(_.partial(checkResult,
|
||||
responses.preparePayment.minAmount, 'prepare'));
|
||||
});
|
||||
|
||||
it('preparePayment - throws when fee exceeds 2 XRP', function () {
|
||||
const localInstructions = _.defaults({
|
||||
fee: '2.1'
|
||||
}, instructions);
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.preparePayment(
|
||||
address, requests.preparePayment.normal, localInstructions)
|
||||
}, /Fee of 2\.1 XRP exceeds max of 2 XRP\. To use this fee, increase `maxFeeXRP` in the RippleAPI constructor\./)
|
||||
});
|
||||
|
||||
it('preparePayment - allows fee exceeding 2 XRP when maxFeeXRP is higher', function () {
|
||||
this.api._maxFeeXRP = '2.2'
|
||||
const localInstructions = _.defaults({
|
||||
fee: '2.1'
|
||||
}, instructions);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
return this.api.preparePayment(
|
||||
address, requests.preparePayment.normal, localInstructions).then(
|
||||
_.partial(checkResult, expectedResponse, 'prepare'));
|
||||
});
|
||||
});
|
||||
|
||||
it('prepareOrder - buy order', function () {
|
||||
@@ -823,6 +854,62 @@ describe('RippleAPI', function () {
|
||||
assert.deepEqual(signature, responses.sign.signAs);
|
||||
});
|
||||
|
||||
it('sign - throws when Fee exceeds maxFeeXRP (in drops)', function () {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
const request = {
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"2010000\",\"Sequence\":23,\"SigningPubKey\":\"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8\"}",
|
||||
"instructions": {
|
||||
"fee": "2.01",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.sign(request.txJSON, secret)
|
||||
}, /Fee" should not exceed "2000000"\. To use a higher fee, set `maxFeeXRP` in the RippleAPI constructor\./)
|
||||
});
|
||||
|
||||
it('sign - throws when Fee exceeds maxFeeXRP (in drops) - custom maxFeeXRP', function () {
|
||||
this.api._maxFeeXRP = '1.9'
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
const request = {
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"2010000\",\"Sequence\":23,\"SigningPubKey\":\"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8\"}",
|
||||
"instructions": {
|
||||
"fee": "2.01",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.sign(request.txJSON, secret)
|
||||
}, /Fee" should not exceed "1900000"\. To use a higher fee, set `maxFeeXRP` in the RippleAPI constructor\./)
|
||||
});
|
||||
|
||||
it('sign - permits fee exceeding 2000000 drops when maxFeeXRP is higher than 2 XRP', function () {
|
||||
this.api._maxFeeXRP = '2.1'
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
const request = {
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"2010000\",\"Sequence\":23,\"SigningPubKey\":\"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8\"}",
|
||||
"instructions": {
|
||||
"fee": "2.01",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
const result = this.api.sign(request.txJSON, secret)
|
||||
|
||||
const expectedResponse = {
|
||||
signedTransaction: "12000322800000002400000017201B008695536840000000001EAB90732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8744630440220384FBB48EEE7B0E58BD89294A609F9407C51FBE8FA08A4B305B22E9A7489D66602200152315EFE752DA381E74493419871550D206AC6503841DA5F8C30E35D9E3892770A726970706C652E636F6D81145E7B112523F68D2F5E879DB4EAC51C6698A69304",
|
||||
id: "A1586D6AF7B0821E7075E12A0132D9EB50BC1874A0749441201497F7561795FB"
|
||||
}
|
||||
|
||||
assert.deepEqual(result, expectedResponse)
|
||||
schemaValidator.schemaValidate('sign', result)
|
||||
});
|
||||
|
||||
it('submit', function () {
|
||||
return this.api.submit(responses.sign.normal.signedTransaction).then(
|
||||
_.partial(checkResult, responses.submit, 'submit'));
|
||||
@@ -1663,6 +1750,76 @@ describe('RippleAPI', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('getFee - high load_factor', function () {
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'config',
|
||||
data: { highLoadFactor: true }
|
||||
}));
|
||||
|
||||
return this.api.getFee().then(fee => {
|
||||
assert.strictEqual(fee, '2');
|
||||
});
|
||||
});
|
||||
|
||||
it('fee - default maxFee of 2 XRP', function () {
|
||||
this.api._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
|
||||
}
|
||||
}
|
||||
|
||||
return this.api.preparePayment(
|
||||
address, requests.preparePayment.normal, instructions).then(
|
||||
_.partial(checkResult, expectedResponse, 'prepare'));
|
||||
});
|
||||
|
||||
it('fee - capped to maxFeeXRP when maxFee exceeds maxFeeXRP', function () {
|
||||
this.api._feeCushion = 1000000
|
||||
this.api._maxFeeXRP = '3'
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '4'
|
||||
}, instructions);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
return this.api.preparePayment(
|
||||
address, requests.preparePayment.normal, localInstructions).then(
|
||||
_.partial(checkResult, expectedResponse, 'prepare'));
|
||||
});
|
||||
|
||||
it('fee - capped to maxFee', function () {
|
||||
this.api._feeCushion = 1000000
|
||||
this.api._maxFeeXRP = '5'
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '4'
|
||||
}, instructions);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
return this.api.preparePayment(
|
||||
address, requests.preparePayment.normal, localInstructions).then(
|
||||
_.partial(checkResult, expectedResponse, 'prepare'));
|
||||
});
|
||||
|
||||
it('disconnect & isConnected', function () {
|
||||
assert.strictEqual(this.api.isConnected(), true);
|
||||
return this.api.disconnect().then(() => {
|
||||
|
||||
@@ -152,7 +152,39 @@ module.exports = function createMockRippled(port) {
|
||||
|
||||
mock.on('request_server_info', function (request, conn) {
|
||||
assert.strictEqual(request.command, 'server_info');
|
||||
if (conn.config.returnErrorOnServerInfo) {
|
||||
if (conn.config.highLoadFactor) {
|
||||
const response = {
|
||||
"id": 0,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"info": {
|
||||
"build_version": "0.24.0-rc1",
|
||||
"complete_ledgers": "32570-6595042",
|
||||
"hostid": "ARTS",
|
||||
"io_latency_ms": 1,
|
||||
"last_close": {
|
||||
"converge_time_s": 2.007,
|
||||
"proposers": 4
|
||||
},
|
||||
"load_factor": 4294967296,
|
||||
"peers": 53,
|
||||
"pubkey_node": "n94wWvFUmaKGYrKUGgpv1DyYgDeXRGdACkNQaSe7zJiy5Znio7UC",
|
||||
"server_state": "full",
|
||||
"validated_ledger": {
|
||||
"age": 5,
|
||||
"base_fee_xrp": 0.00001,
|
||||
"hash": "4482DEE5362332F54A4036ED57EE1767C9F33CF7CE5A6670355C16CECE381D46",
|
||||
"reserve_base_xrp": 20,
|
||||
"reserve_inc_xrp": 5,
|
||||
"seq": 6595042
|
||||
},
|
||||
"validation_quorum": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
conn.send(createResponse(request, response));
|
||||
} else if (conn.config.returnErrorOnServerInfo) {
|
||||
conn.send(createResponse(request, fixtures.server_info.error));
|
||||
} else if (conn.config.disconnectOnServerInfo) {
|
||||
conn.close();
|
||||
|
||||
Reference in New Issue
Block a user