mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-16 18:35:50 +00:00
Compare commits
11 Commits
1.0.0-beta
...
1.0.0-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc623cd049 | ||
|
|
7cd517268b | ||
|
|
2438295e70 | ||
|
|
f5e1a4a588 | ||
|
|
9e9a0a7d9b | ||
|
|
1c68283d1e | ||
|
|
28796d37cb | ||
|
|
067bc48d4e | ||
|
|
b94698df0b | ||
|
|
4f40b5cb6d | ||
|
|
14704eee6b |
@@ -1,5 +1,14 @@
|
||||
# ripple-lib Release History
|
||||
|
||||
## 1.0.0-beta.5 (2018-08-11)
|
||||
|
||||
+ [Fix a TypeScript error by importing the `Prepare` type](https://github.com/ripple/ripple-lib/commit/7cd517268bda5fe74b91dad02fedf8b51b7eae9b)
|
||||
|
||||
## 1.0.0-beta.4 (2018-08-10)
|
||||
|
||||
+ [Add `prepareTransaction()`](https://github.com/ripple/ripple-lib/pull/898)
|
||||
+ Internal improvements and cleanup
|
||||
|
||||
## 1.0.0-beta.3 (2018-07-17)
|
||||
|
||||
+ For payment channel transactions, `getTransaction` includes a new
|
||||
|
||||
18
README.md
18
README.md
@@ -38,6 +38,24 @@ If you're using the XRP Ledger in production, you should run a [rippled server](
|
||||
|
||||
+ [Subscribe to ripple-server](https://groups.google.com/forum/#!forum/ripple-server)
|
||||
|
||||
## Development
|
||||
|
||||
To build the library for Node.js:
|
||||
```
|
||||
$ yarn compile
|
||||
```
|
||||
|
||||
The TypeScript compiler will [output](./tsconfig.json#L7) the resulting JS files in `./dist/npm/`.
|
||||
|
||||
To build the library for the browser:
|
||||
```
|
||||
$ yarn build
|
||||
```
|
||||
|
||||
Gulp will [output](./Gulpfile.js) the resulting JS files in `./build/`.
|
||||
|
||||
For more details, see the `scripts` in `package.json`.
|
||||
|
||||
## Running tests
|
||||
|
||||
1. Clone the repository
|
||||
|
||||
@@ -1075,6 +1075,8 @@ return api.getServerInfo().then(info => {/* ... */});
|
||||
|
||||
Returns the estimated transaction fee for the rippled server the RippleAPI instance is connected to.
|
||||
|
||||
This will use the [feeCushion parameter](#parameters) provided to the RippleAPI constructor, or the default value of `1.2`.
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description
|
||||
@@ -1083,7 +1085,7 @@ cushion | number | *Optional* The fee is the product of the base fee, the `load_
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with a string encoded floating point value representing the estimated fee to submit a transaction, expressed in XRP.
|
||||
This method returns a promise that resolves with a string-encoded floating point value representing the estimated fee to submit a transaction, expressed in XRP.
|
||||
|
||||
### Example
|
||||
|
||||
@@ -1092,7 +1094,7 @@ return api.getFee().then(fee => {/* ... */});
|
||||
```
|
||||
|
||||
```json
|
||||
"0.012"
|
||||
"0.000012"
|
||||
```
|
||||
|
||||
## getLedgerVersion
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
|
||||
Returns the estimated transaction fee for the rippled server the RippleAPI instance is connected to.
|
||||
|
||||
This will use the [feeCushion parameter](#parameters) provided to the RippleAPI constructor, or the default value of `1.2`.
|
||||
|
||||
### Parameters
|
||||
|
||||
<%- renderSchema('input/get-fee.json') %>
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with a string encoded floating point value representing the estimated fee to submit a transaction, expressed in XRP.
|
||||
This method returns a promise that resolves with a string-encoded floating point value representing the estimated fee to submit a transaction, expressed in XRP.
|
||||
|
||||
### Example
|
||||
|
||||
@@ -19,5 +21,5 @@ return api.getFee().then(fee => {/* ... */});
|
||||
```
|
||||
|
||||
```json
|
||||
"0.012"
|
||||
"0.000012"
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "1.0.0-beta.3",
|
||||
"version": "1.0.0-beta.5",
|
||||
"license": "ISC",
|
||||
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
||||
"files": [
|
||||
@@ -53,7 +53,7 @@
|
||||
"ts-node": "^3.3.0",
|
||||
"tslint": "^5.8.0",
|
||||
"tslint-eslint-rules": "^4.1.1",
|
||||
"typescript": "^2.6.1",
|
||||
"typescript": "2.9.2",
|
||||
"uglifyjs-webpack-plugin": "^1.1.4",
|
||||
"webpack": "^3.10.0",
|
||||
"yargs": "^8.0.2"
|
||||
|
||||
60
src/api.ts
60
src/api.ts
@@ -1,5 +1,13 @@
|
||||
import {EventEmitter} from 'events'
|
||||
import {Connection, errors, validate, xrpToDrops, dropsToXrp} from './common'
|
||||
import {
|
||||
Connection,
|
||||
errors,
|
||||
validate,
|
||||
xrpToDrops,
|
||||
dropsToXrp,
|
||||
iso8601ToRippleTime,
|
||||
txFlags
|
||||
} from './common'
|
||||
import {
|
||||
connect,
|
||||
disconnect,
|
||||
@@ -57,9 +65,11 @@ import {
|
||||
|
||||
import RangeSet from './common/rangeset'
|
||||
import * as ledgerUtils from './ledger/utils'
|
||||
import * as transactionUtils from './transaction/utils'
|
||||
import * as schemaValidator from './common/schema-validator'
|
||||
import {getServerInfo, getFee} from './common/serverinfo'
|
||||
import {clamp} from './ledger/utils'
|
||||
import {Instructions, Prepare} from './transaction/types'
|
||||
|
||||
export type APIOptions = {
|
||||
server?: string,
|
||||
@@ -97,7 +107,7 @@ class RippleAPI extends EventEmitter {
|
||||
|
||||
// these are exposed only for use by unit tests; they are not part of the API.
|
||||
static _PRIVATE = {
|
||||
validate: validate,
|
||||
validate,
|
||||
RangeSet,
|
||||
ledgerUtils,
|
||||
schemaValidator
|
||||
@@ -131,19 +141,16 @@ class RippleAPI extends EventEmitter {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Makes a request to the API with the given command and
|
||||
* additional request body parameters.
|
||||
*/
|
||||
async request(command: 'account_info', params: AccountInfoRequest):
|
||||
Promise<AccountInfoResponse>
|
||||
async request(command: 'account_lines', params: AccountLinesRequest):
|
||||
Promise<AccountLinesResponse>
|
||||
|
||||
/**
|
||||
* Returns objects owned by an account.
|
||||
* For an account's trust lines and balances,
|
||||
* see `getTrustlines` and `getBalances`.
|
||||
*/
|
||||
async request(command: 'account_objects', params: AccountObjectsRequest):
|
||||
Promise<AccountObjectsResponse>
|
||||
|
||||
async request(command: 'account_offers', params: AccountOffersRequest):
|
||||
Promise<AccountOffersResponse>
|
||||
async request(command: 'book_offers', params: BookOffersRequest):
|
||||
@@ -156,15 +163,9 @@ class RippleAPI extends EventEmitter {
|
||||
Promise<LedgerEntryResponse>
|
||||
async request(command: 'server_info', params?: ServerInfoRequest):
|
||||
Promise<ServerInfoResponse>
|
||||
|
||||
async request(command: string, params: object):
|
||||
Promise<object>
|
||||
|
||||
/**
|
||||
* Makes a request to the API with the given command and
|
||||
* additional request body parameters.
|
||||
*/
|
||||
async request(command: string, params: object = {}): Promise<object> {
|
||||
async request(command: string, params: any):
|
||||
Promise<any>
|
||||
async request(command: string, params: any = {}): Promise<any> {
|
||||
return this.connection.request({
|
||||
...params,
|
||||
command
|
||||
@@ -199,6 +200,27 @@ class RippleAPI extends EventEmitter {
|
||||
return this.request(command, nextPageParams)
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a transaction.
|
||||
*
|
||||
* You can later submit the transaction with `submit()`.
|
||||
*/
|
||||
async prepareTransaction(txJSON: object, instructions: Instructions = {}):
|
||||
Promise<Prepare> {
|
||||
return transactionUtils.prepareTransaction(txJSON, this, instructions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string to hex.
|
||||
*
|
||||
* This can be used to generate `MemoData`, `MemoType`, and `MemoFormat`.
|
||||
*
|
||||
* @param string string to convert to hex
|
||||
*/
|
||||
convertStringToHex(string: string): string {
|
||||
return transactionUtils.convertStringToHex(string)
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes multiple paged requests to the API to return a given number of
|
||||
* resources. _requestAll() will make multiple requests until the `limit`
|
||||
@@ -306,6 +328,8 @@ class RippleAPI extends EventEmitter {
|
||||
|
||||
xrpToDrops = xrpToDrops
|
||||
dropsToXrp = dropsToXrp
|
||||
iso8601ToRippleTime = iso8601ToRippleTime
|
||||
txFlags = txFlags
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
@@ -61,6 +61,8 @@ function getServerInfo(this: RippleAPI): Promise<GetServerInfoResponse> {
|
||||
})
|
||||
}
|
||||
|
||||
// This is a public API that can be called directly.
|
||||
// This is not used by the `prepare*` methods. See `src/transaction/utils.ts`
|
||||
async function getFee(
|
||||
this: RippleAPI,
|
||||
cushion?: number
|
||||
@@ -79,7 +81,7 @@ async function getFee(
|
||||
// Cap fee to `this._maxFeeXRP`
|
||||
fee = BigNumber.min(fee, this._maxFeeXRP)
|
||||
// Round fee to 6 decimal places
|
||||
return (new BigNumber(fee.toFormat(6))).toString(10)
|
||||
return (new BigNumber(fee.toFixed(6))).toString(10)
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
@@ -18,7 +18,7 @@ type TransactionResponse = FormattedTransactionType & {
|
||||
|
||||
|
||||
function attachTransactionDate(connection: Connection, tx: any
|
||||
): Promise<FormattedTransactionType> {
|
||||
): Promise<TransactionResponse> {
|
||||
if (tx.date) {
|
||||
return Promise.resolve(tx)
|
||||
}
|
||||
@@ -88,26 +88,20 @@ function formatResponse(options: TransactionOptions, tx: TransactionResponse
|
||||
return parseTransaction(tx)
|
||||
}
|
||||
|
||||
function getTransaction(id: string, options: TransactionOptions = {}
|
||||
async function getTransaction(id: string, options: TransactionOptions = {}
|
||||
): Promise<FormattedTransactionType> {
|
||||
validate.getTransaction({id, options})
|
||||
|
||||
const request = {
|
||||
command: 'tx',
|
||||
transaction: id,
|
||||
binary: false
|
||||
const _options = await utils.ensureLedgerVersion.call(this, options)
|
||||
try {
|
||||
const tx = await this.request('tx', {
|
||||
transaction: id,
|
||||
binary: false
|
||||
})
|
||||
const txWithDate = await attachTransactionDate(this.connection, tx)
|
||||
return formatResponse(_options, txWithDate)
|
||||
} catch (error) {
|
||||
throw (await convertError(this.connection, _options, error))
|
||||
}
|
||||
|
||||
return utils.ensureLedgerVersion.call(this, options).then(_options => {
|
||||
return this.connection.request(request).then((tx: TransactionResponse) =>
|
||||
attachTransactionDate(this.connection, tx)
|
||||
).then(_.partial(formatResponse, _options))
|
||||
.catch(error => {
|
||||
return convertError(this.connection, _options, error).then(_error => {
|
||||
throw _error
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default getTransaction
|
||||
|
||||
@@ -7,6 +7,7 @@ const ValidationError = utils.common.errors.ValidationError
|
||||
import {Instructions, Prepare} from './types'
|
||||
import {Amount, Adjustment, MaxAdjustment,
|
||||
MinAdjustment, Memo} from '../common/types/objects'
|
||||
import {xrpToDrops} from '../common'
|
||||
|
||||
|
||||
export interface Payment {
|
||||
@@ -32,12 +33,12 @@ export interface Payment {
|
||||
|
||||
function isMaxAdjustment(
|
||||
source: Adjustment | MaxAdjustment): source is MaxAdjustment {
|
||||
return (source as MaxAdjustment).maxAmount !== undefined
|
||||
return (source as MaxAdjustment).maxAmount !== undefined
|
||||
}
|
||||
|
||||
function isMinAdjustment(
|
||||
destination: Adjustment | MinAdjustment): destination is MinAdjustment {
|
||||
return (destination as MinAdjustment).minAmount !== undefined
|
||||
return (destination as MinAdjustment).minAmount !== undefined
|
||||
}
|
||||
|
||||
function isXRPToXRPPayment(payment: Payment): boolean {
|
||||
@@ -50,7 +51,7 @@ function isXRPToXRPPayment(payment: Payment): boolean {
|
||||
}
|
||||
|
||||
function isIOUWithoutCounterparty(amount: Amount): boolean {
|
||||
return amount && amount.currency !== 'XRP'
|
||||
return amount && amount.currency !== 'XRP' && amount.currency !== 'drops'
|
||||
&& amount.counterparty === undefined
|
||||
}
|
||||
|
||||
@@ -72,7 +73,14 @@ function applyAnyCounterpartyEncoding(payment: Payment): void {
|
||||
function createMaximalAmount(amount: Amount): Amount {
|
||||
const maxXRPValue = '100000000000'
|
||||
const maxIOUValue = '9999999999999999e80'
|
||||
const maxValue = amount.currency === 'XRP' ? maxXRPValue : maxIOUValue
|
||||
let maxValue
|
||||
if (amount.currency === 'XRP') {
|
||||
maxValue = maxXRPValue
|
||||
} else if (amount.currency === 'drops') {
|
||||
maxValue = xrpToDrops(maxXRPValue)
|
||||
} else {
|
||||
maxValue = maxIOUValue
|
||||
}
|
||||
return _.assign({}, amount, {value: maxValue})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import * as _ from 'lodash'
|
||||
import * as utils from './utils'
|
||||
import {validate} from '../common'
|
||||
import {Submit} from './types'
|
||||
import {RippleAPI} from '..'
|
||||
|
||||
export interface FormattedSubmitResponse {
|
||||
resultCode: string,
|
||||
resultMessage: string
|
||||
}
|
||||
|
||||
function isImmediateRejection(engineResult: string): boolean {
|
||||
// note: "tel" errors mean the local server refused to process the
|
||||
@@ -13,7 +18,7 @@ function isImmediateRejection(engineResult: string): boolean {
|
||||
return _.startsWith(engineResult, 'tem')
|
||||
}
|
||||
|
||||
function formatSubmitResponse(response) {
|
||||
function formatSubmitResponse(response): FormattedSubmitResponse {
|
||||
const data = {
|
||||
resultCode: response.engine_result,
|
||||
resultMessage: response.engine_result_message
|
||||
@@ -24,14 +29,15 @@ function formatSubmitResponse(response) {
|
||||
return data
|
||||
}
|
||||
|
||||
function submit(signedTransaction: string): Promise<Submit> {
|
||||
async function submit(
|
||||
this: RippleAPI, signedTransaction: string
|
||||
): Promise<FormattedSubmitResponse> {
|
||||
// 1. Validate
|
||||
validate.submit({signedTransaction})
|
||||
|
||||
const request = {
|
||||
command: 'submit',
|
||||
tx_blob: signedTransaction
|
||||
}
|
||||
return this.connection.request(request).then(formatSubmitResponse)
|
||||
// 2. Make Request
|
||||
const response = await this.request('submit', {tx_blob: signedTransaction})
|
||||
// 3. Return Formatted Response
|
||||
return formatSubmitResponse(response)
|
||||
}
|
||||
|
||||
export default submit
|
||||
|
||||
@@ -22,10 +22,10 @@ export type Instructions = {
|
||||
export type Prepare = {
|
||||
txJSON: string,
|
||||
instructions: {
|
||||
fee: string,
|
||||
sequence: number,
|
||||
maxLedgerVersion?: number
|
||||
}
|
||||
fee: string,
|
||||
sequence: number,
|
||||
maxLedgerVersion?: number
|
||||
}
|
||||
}
|
||||
|
||||
export type Submit = {
|
||||
|
||||
@@ -94,19 +94,16 @@ function prepareTransaction(txJSON: any, api: RippleAPI,
|
||||
})
|
||||
}
|
||||
|
||||
function prepareSequence(): Promise<Object> {
|
||||
async function prepareSequence(): Promise<Object> {
|
||||
if (instructions.sequence !== undefined) {
|
||||
txJSON.Sequence = instructions.sequence
|
||||
return Promise.resolve(txJSON)
|
||||
}
|
||||
const request = {
|
||||
command: 'account_info',
|
||||
account: account
|
||||
}
|
||||
return api.connection.request(request).then(response => {
|
||||
txJSON.Sequence = response.account_data.Sequence
|
||||
return txJSON
|
||||
const response = await api.request('account_info', {
|
||||
account: account as string
|
||||
})
|
||||
txJSON.Sequence = response.account_data.Sequence
|
||||
return txJSON
|
||||
}
|
||||
|
||||
return Promise.all([
|
||||
|
||||
428
test/api-test.js
428
test/api-test.js
@@ -404,6 +404,23 @@ describe('RippleAPI', function () {
|
||||
}, /Fee of 2\.1 XRP exceeds max of 2 XRP\. To use this fee, increase `maxFeeXRP` in the RippleAPI constructor\./)
|
||||
});
|
||||
|
||||
it('preparePayment - caps fee at 2 XRP by default', 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('preparePayment - allows fee exceeding 2 XRP when maxFeeXRP is higher', function () {
|
||||
this.api._maxFeeXRP = '2.2'
|
||||
const localInstructions = _.defaults({
|
||||
@@ -698,6 +715,384 @@ describe('RippleAPI', function () {
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
describe('prepareTransaction - Payment', function () {
|
||||
|
||||
it('normal', function () {
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '0.000012'
|
||||
}, instructions);
|
||||
|
||||
const txJSON = {
|
||||
TransactionType: 'Payment',
|
||||
Account: address,
|
||||
Destination: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
|
||||
Amount: {
|
||||
currency: 'USD',
|
||||
issuer: 'rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM',
|
||||
value: '0.01'
|
||||
},
|
||||
SendMax: {
|
||||
currency: 'USD',
|
||||
issuer: 'rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM',
|
||||
value: '0.01'
|
||||
},
|
||||
Flags: 0
|
||||
}
|
||||
|
||||
return this.api.prepareTransaction(txJSON, localInstructions).then(
|
||||
_.partial(checkResult, responses.preparePayment.normal, 'prepare'));
|
||||
});
|
||||
|
||||
// prepareTransaction - Payment
|
||||
it('min amount xrp', function () {
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '0.000012'
|
||||
}, instructions);
|
||||
|
||||
const txJSON = {
|
||||
TransactionType: 'Payment',
|
||||
Account: address,
|
||||
Destination: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
|
||||
|
||||
// Max amount to send. Use 100 billion XRP to
|
||||
// ensure that we send the full SendMax amount.
|
||||
Amount: '100000000000000000',
|
||||
|
||||
SendMax: {
|
||||
currency: 'USD',
|
||||
issuer: 'rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM',
|
||||
value: '0.01'
|
||||
},
|
||||
DeliverMin: '10000',
|
||||
Flags: this.api.txFlags.Payment.PartialPayment
|
||||
}
|
||||
|
||||
return this.api.prepareTransaction(txJSON, localInstructions).then(
|
||||
_.partial(checkResult,
|
||||
responses.preparePayment.minAmountXRP, 'prepare'));
|
||||
});
|
||||
|
||||
// prepareTransaction - Payment
|
||||
it('min amount xrp2xrp', function () {
|
||||
const txJSON = {
|
||||
TransactionType: 'Payment',
|
||||
Account: address,
|
||||
Destination: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
|
||||
Amount: '10000',
|
||||
Flags: 0
|
||||
}
|
||||
return this.api.prepareTransaction(txJSON, instructions).then(
|
||||
_.partial(checkResult,
|
||||
responses.preparePayment.minAmountXRPXRP, 'prepare'));
|
||||
});
|
||||
|
||||
// prepareTransaction - Payment
|
||||
it('with all options specified', function () {
|
||||
return this.api.getLedgerVersion().then(ver => {
|
||||
const localInstructions = {
|
||||
maxLedgerVersion: ver + 100,
|
||||
fee: '0.000012'
|
||||
};
|
||||
const txJSON = {
|
||||
TransactionType: 'Payment',
|
||||
Account: address,
|
||||
Destination: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
|
||||
Amount: '10000',
|
||||
InvoiceID: 'A98FD36C17BE2B8511AD36DC335478E7E89F06262949F36EB88E2D683BBCC50A',
|
||||
SourceTag: 14,
|
||||
DestinationTag: 58,
|
||||
Memos: [
|
||||
{
|
||||
Memo: {
|
||||
MemoType: this.api.convertStringToHex('test'),
|
||||
MemoFormat: this.api.convertStringToHex('text/plain'),
|
||||
MemoData: this.api.convertStringToHex('texted data')
|
||||
}
|
||||
}
|
||||
],
|
||||
Flags: 0 | this.api.txFlags.Payment.NoRippleDirect | this.api.txFlags.Payment.LimitQuality
|
||||
}
|
||||
return this.api.prepareTransaction(txJSON, localInstructions).then(
|
||||
_.partial(checkResult,
|
||||
responses.preparePayment.allOptions, 'prepare'));
|
||||
});
|
||||
});
|
||||
|
||||
// prepareTransaction - Payment
|
||||
it('fee is capped at default maxFee of 2 XRP', function () {
|
||||
this.api._feeCushion = 1000000;
|
||||
|
||||
const 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
|
||||
}
|
||||
|
||||
const localInstructions = {
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
|
||||
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.prepareTransaction(txJSON, localInstructions).then(
|
||||
_.partial(checkResult,
|
||||
expectedResponse, 'prepare'));
|
||||
});
|
||||
|
||||
// prepareTransaction - Payment
|
||||
it('fee is capped to custom maxFeeXRP when maxFee exceeds maxFeeXRP', function () {
|
||||
this.api._feeCushion = 1000000
|
||||
this.api._maxFeeXRP = '3'
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '4' // We are testing that this does not matter; fee is still capped to maxFeeXRP
|
||||
}, instructions);
|
||||
|
||||
const 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
|
||||
}
|
||||
|
||||
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.prepareTransaction(txJSON, localInstructions).then(
|
||||
_.partial(checkResult,
|
||||
expectedResponse, 'prepare'));
|
||||
});
|
||||
|
||||
// prepareTransaction - Payment
|
||||
it('fee is capped to maxFee', function () {
|
||||
this.api._feeCushion = 1000000
|
||||
this.api._maxFeeXRP = '5'
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '4' // maxFeeXRP does not matter if maxFee is lower than maxFeeXRP
|
||||
}, instructions);
|
||||
|
||||
const 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,
|
||||
}
|
||||
|
||||
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.prepareTransaction(txJSON, localInstructions).then(
|
||||
_.partial(checkResult,
|
||||
expectedResponse, 'prepare'));
|
||||
});
|
||||
|
||||
it('fee - calculated fee does not use more than 6 decimal places', function () {
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'config',
|
||||
data: { loadFactor: 5407.96875 }
|
||||
}));
|
||||
|
||||
const expectedResponse = {
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"SendMax\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8820051,\"Fee\":\"64896\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.064896",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
return this.api.preparePayment(
|
||||
address, requests.preparePayment.normal, instructions).then(
|
||||
_.partial(checkResult, expectedResponse, 'prepare'));
|
||||
});
|
||||
});
|
||||
|
||||
it('prepareTransaction - PaymentChannelCreate', function () {
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '0.000012'
|
||||
}, instructions);
|
||||
return this.api.prepareTransaction({
|
||||
Account: address,
|
||||
TransactionType: 'PaymentChannelCreate',
|
||||
Amount: '1000000', // 1 XRP in drops. Use a string-encoded integer.
|
||||
Destination: 'rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW',
|
||||
SettleDelay: 86400,
|
||||
PublicKey: '32D2471DB72B27E3310F355BB33E339BF26F8392D5A93D3BC0FC3B566612DA0F0A'
|
||||
// If cancelAfter is used, you must use RippleTime.
|
||||
// You can use `iso8601ToRippleTime()` to convert to RippleTime.
|
||||
|
||||
// Other fields are available (but not used in this test),
|
||||
// including `sourceTag` and `destinationTag`.
|
||||
}, localInstructions).then(
|
||||
_.partial(checkResult, responses.preparePaymentChannelCreate.normal,
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareTransaction - PaymentChannelCreate full', function () {
|
||||
const txJSON = {
|
||||
Account: address,
|
||||
TransactionType: 'PaymentChannelCreate',
|
||||
Amount: this.api.xrpToDrops('1'), // or '1000000'
|
||||
Destination: 'rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW',
|
||||
SettleDelay: 86400,
|
||||
|
||||
// Ensure this is in upper case if it is not already
|
||||
PublicKey: '32D2471DB72B27E3310F355BB33E339BF26F8392D5A93D3BC0FC3B566612DA0F0A'.toUpperCase(),
|
||||
|
||||
CancelAfter: this.api.iso8601ToRippleTime('2017-02-17T15:04:57Z'),
|
||||
SourceTag: 11747,
|
||||
DestinationTag: 23480
|
||||
}
|
||||
|
||||
return this.api.prepareTransaction(txJSON).then(
|
||||
_.partial(checkResult, responses.preparePaymentChannelCreate.full,
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareTransaction - PaymentChannelFund', function () {
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '0.000012'
|
||||
}, instructions);
|
||||
|
||||
const txJSON = {
|
||||
Account: address,
|
||||
TransactionType: 'PaymentChannelFund',
|
||||
Channel: 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198',
|
||||
Amount: this.api.xrpToDrops('1') // or '1000000'
|
||||
}
|
||||
|
||||
return this.api.prepareTransaction(txJSON, localInstructions).then(
|
||||
_.partial(checkResult, responses.preparePaymentChannelFund.normal,
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareTransaction - PaymentChannelFund full', function () {
|
||||
const txJSON = {
|
||||
Account: address,
|
||||
TransactionType: 'PaymentChannelFund',
|
||||
Channel: 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198',
|
||||
Amount: this.api.xrpToDrops('1'), // or '1000000'
|
||||
Expiration: this.api.iso8601ToRippleTime('2017-02-17T15:04:57Z')
|
||||
}
|
||||
|
||||
return this.api.prepareTransaction(txJSON).then(
|
||||
_.partial(checkResult, responses.preparePaymentChannelFund.full,
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareTransaction - PaymentChannelClaim', function () {
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '0.000012'
|
||||
}, instructions);
|
||||
|
||||
const txJSON = {
|
||||
Account: address,
|
||||
TransactionType: 'PaymentChannelClaim',
|
||||
Channel: 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198',
|
||||
Flags: 0
|
||||
}
|
||||
|
||||
return this.api.prepareTransaction(txJSON, localInstructions).then(
|
||||
_.partial(checkResult, responses.preparePaymentChannelClaim.normal,
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareTransaction - PaymentChannelClaim with renew', function () {
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '0.000012'
|
||||
}, instructions);
|
||||
|
||||
const txJSON = {
|
||||
Account: address,
|
||||
TransactionType: 'PaymentChannelClaim',
|
||||
Channel: 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198',
|
||||
Balance: this.api.xrpToDrops('1'), // or '1000000'
|
||||
Amount: this.api.xrpToDrops('1'), // or '1000000'
|
||||
Signature: '30440220718D264EF05CAED7C781FF6DE298DCAC68D002562C9BF3A07C1E721B420C0DAB02203A5A4779EF4D2CCC7BC3EF886676D803A9981B928D3B8ACA483B80ECA3CD7B9B',
|
||||
PublicKey: '32D2471DB72B27E3310F355BB33E339BF26F8392D5A93D3BC0FC3B566612DA0F0A',
|
||||
Flags: 0
|
||||
}
|
||||
txJSON.Flags |= this.api.txFlags.PaymentChannelClaim.Renew
|
||||
|
||||
return this.api.prepareTransaction(txJSON, localInstructions).then(
|
||||
_.partial(checkResult, responses.preparePaymentChannelClaim.renew,
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareTransaction - PaymentChannelClaim with close', function () {
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '0.000012'
|
||||
}, instructions);
|
||||
|
||||
const txJSON = {
|
||||
Account: address,
|
||||
TransactionType: 'PaymentChannelClaim',
|
||||
Channel: 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198',
|
||||
Balance: this.api.xrpToDrops('1'), // or 1000000
|
||||
Amount: this.api.xrpToDrops('1'), // or 1000000
|
||||
Signature: '30440220718D264EF05CAED7C781FF6DE298DCAC68D002562C9BF3A07C1E721B420C0DAB02203A5A4779EF4D2CCC7BC3EF886676D803A9981B928D3B8ACA483B80ECA3CD7B9B',
|
||||
PublicKey: '32D2471DB72B27E3310F355BB33E339BF26F8392D5A93D3BC0FC3B566612DA0F0A',
|
||||
Flags: 0
|
||||
}
|
||||
txJSON.Flags |= this.api.txFlags.PaymentChannelClaim.Close
|
||||
|
||||
return this.api.prepareTransaction(txJSON, localInstructions).then(
|
||||
_.partial(checkResult, responses.preparePaymentChannelClaim.close,
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('preparePaymentChannelCreate', function () {
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '0.000012'
|
||||
@@ -1774,7 +2169,21 @@ describe('RippleAPI', function () {
|
||||
assert.strictEqual(fee, '2');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('getFee - high load_factor with custom maxFeeXRP', function () {
|
||||
// Ensure that overriding with high maxFeeXRP of '51540' causes no errors.
|
||||
// (fee will actually be 51539.607552)
|
||||
this.api._maxFeeXRP = '51540'
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'config',
|
||||
data: { highLoadFactor: true }
|
||||
}));
|
||||
|
||||
return this.api.getFee().then(fee => {
|
||||
assert.strictEqual(fee, '51539.607552');
|
||||
});
|
||||
});
|
||||
|
||||
it('fee - default maxFee of 2 XRP', function () {
|
||||
this.api._feeCushion = 1000000;
|
||||
|
||||
@@ -1853,6 +2262,23 @@ describe('RippleAPI', function () {
|
||||
address, requests.preparePayment.normal, instructions).then(
|
||||
_.partial(checkResult, expectedResponse, 'prepare'));
|
||||
});
|
||||
|
||||
it('getFee custom cushion', function () {
|
||||
this.api._feeCushion = 1.4;
|
||||
return this.api.getFee().then(fee => {
|
||||
assert.strictEqual(fee, '0.000014');
|
||||
});
|
||||
});
|
||||
|
||||
// This is not recommended since it may result in attempting to pay
|
||||
// less than the base fee. However, this test verifies
|
||||
// the existing behavior.
|
||||
it('getFee cushion less than 1.0', function () {
|
||||
this.api._feeCushion = 0.9;
|
||||
return this.api.getFee().then(fee => {
|
||||
assert.strictEqual(fee, '0.000009');
|
||||
});
|
||||
});
|
||||
|
||||
it('disconnect & isConnected', function () {
|
||||
assert.strictEqual(this.api.isConnected(), true);
|
||||
|
||||
@@ -24,6 +24,5 @@
|
||||
],
|
||||
"invoiceID": "A98FD36C17BE2B8511AD36DC335478E7E89F06262949F36EB88E2D683BBCC50A",
|
||||
"noDirectRipple": true,
|
||||
"limitQuality": true,
|
||||
"paths": "[[{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"currency\":\"USD\",\"issuer\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"type\":49,\"type_hex\":\"0000000000000031\"},{\"currency\":\"LTC\",\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"type\":48,\"type_hex\":\"0000000000000030\"},{\"account\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"currency\":\"LTC\",\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"type\":49,\"type_hex\":\"0000000000000031\"}]]"
|
||||
"limitQuality": true
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"amount": {
|
||||
"value": "0.01",
|
||||
"currency": "XRP",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
"currency": "XRP"
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
|
||||
@@ -4803,9 +4803,9 @@ typedarray@^0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
|
||||
typescript@^2.6.1:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.1.tgz#6160e4f8f195d5ba81d4876f9c0cc1fbc0820624"
|
||||
typescript@2.9.2:
|
||||
version "2.9.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
|
||||
|
||||
uglify-es@^3.3.4:
|
||||
version "3.3.9"
|
||||
|
||||
Reference in New Issue
Block a user