diff --git a/src/api/common/constants.js b/src/api/common/constants.js index 64ee69ee..40427cc2 100644 --- a/src/api/common/constants.js +++ b/src/api/common/constants.js @@ -1,6 +1,6 @@ 'use strict'; const core = require('./utils').core; -const flagIndices = core.Transaction.set_clear_flags.AccountSet; +const flagIndices = require('./txflags').txFlagIndices.AccountSet; const flags = core.Remote.flags.account_root; const AccountFlags = { diff --git a/src/api/common/index.js b/src/api/common/index.js index 5173dd9a..6a4b3586 100644 --- a/src/api/common/index.js +++ b/src/api/common/index.js @@ -7,6 +7,7 @@ module.exports = { constants: require('./constants'), errors: require('./errors'), validate: require('./validate'), + txFlags: require('./txflags').txFlags, dropsToXrp: utils.dropsToXrp, xrpToDrops: utils.xrpToDrops, toRippledAmount: utils.toRippledAmount, diff --git a/src/api/transaction/txflags.js b/src/api/common/txflags.js similarity index 91% rename from src/api/transaction/txflags.js rename to src/api/common/txflags.js index d07d5151..40fa071e 100644 --- a/src/api/transaction/txflags.js +++ b/src/api/common/txflags.js @@ -1,6 +1,6 @@ 'use strict'; -const transactionFlags = { +const txFlags = { // Universal flags can apply to any transaction type Universal: { FullyCanonicalSig: 0x80000000 @@ -41,7 +41,7 @@ const transactionFlags = { // The following are integer (as opposed to bit) flags // that can be set for particular transactions in the // SetFlag or ClearFlag field -const transactionFlagIndices = { +const txFlagIndices = { AccountSet: { asfRequireDest: 1, asfRequireAuth: 2, @@ -55,6 +55,6 @@ const transactionFlagIndices = { }; module.exports = { - transactionFlags, - transactionFlagIndices + txFlags, + txFlagIndices }; diff --git a/src/api/ledger/parse/order.js b/src/api/ledger/parse/order.js index 13060fd7..902d4b89 100644 --- a/src/api/ledger/parse/order.js +++ b/src/api/ledger/parse/order.js @@ -3,7 +3,7 @@ const assert = require('assert'); const utils = require('./utils'); const parseAmount = require('./amount'); -const flags = utils.core.Transaction.flags.OfferCreate; +const flags = utils.txFlags.OfferCreate; function parseOrder(tx: Object): Object { assert(tx.TransactionType === 'OfferCreate'); diff --git a/src/api/ledger/parse/payment.js b/src/api/ledger/parse/payment.js index 55f6917d..d3e221e0 100644 --- a/src/api/ledger/parse/payment.js +++ b/src/api/ledger/parse/payment.js @@ -4,18 +4,18 @@ const _ = require('lodash'); const assert = require('assert'); const utils = require('./utils'); const parseAmount = require('./amount'); -const Transaction = utils.core.Transaction; +const txFlags = utils.txFlags; function isPartialPayment(tx) { - return (tx.Flags & Transaction.flags.Payment.PartialPayment) !== 0; + return (tx.Flags & txFlags.Payment.PartialPayment) !== 0; } function isNoDirectRipple(tx) { - return (tx.Flags & Transaction.flags.Payment.NoRippleDirect) !== 0; + return (tx.Flags & txFlags.Payment.NoRippleDirect) !== 0; } function isQualityLimited(tx) { - return (tx.Flags & Transaction.flags.Payment.LimitQuality) !== 0; + return (tx.Flags & txFlags.Payment.LimitQuality) !== 0; } function removeGenericCounterparty(amount, address) { diff --git a/src/api/ledger/parse/trustline.js b/src/api/ledger/parse/trustline.js index 9a592c90..fbdb1a65 100644 --- a/src/api/ledger/parse/trustline.js +++ b/src/api/ledger/parse/trustline.js @@ -2,7 +2,7 @@ 'use strict'; const assert = require('assert'); const utils = require('./utils'); -const flags = utils.core.Transaction.flags.TrustSet; +const flags = utils.txFlags.TrustSet; const BigNumber = require('bignumber.js'); function parseFlag(flagsValue, trueValue, falseValue) { diff --git a/src/api/ledger/parse/utils.js b/src/api/ledger/parse/utils.js index 9fbac78b..56a6111f 100644 --- a/src/api/ledger/parse/utils.js +++ b/src/api/ledger/parse/utils.js @@ -91,5 +91,6 @@ module.exports = { adjustQualityForXRP, dropsToXrp: utils.common.dropsToXrp, constants: utils.common.constants, + txFlags: utils.common.txFlags, core: utils.common.core }; diff --git a/src/api/transaction/order.js b/src/api/transaction/order.js index 21f0e446..47db05b4 100644 --- a/src/api/transaction/order.js +++ b/src/api/transaction/order.js @@ -2,40 +2,45 @@ 'use strict'; const utils = require('./utils'); const validate = utils.common.validate; -const Transaction = utils.common.core.Transaction; +const offerFlags = utils.common.txFlags.OfferCreate; import type {Instructions, Prepare} from './types.js'; import type {Order} from '../ledger/transaction-types.js'; -const OfferCreateFlags = { - passive: {set: 'Passive'}, - immediateOrCancel: {set: 'ImmediateOrCancel'}, - fillOrKill: {set: 'FillOrKill'} -}; - -function createOrderTransaction(account: string, order: Order): Transaction { +function createOrderTransaction(account: string, order: Order): Object { validate.address(account); validate.order(order); - const transaction = new Transaction(); const takerPays = utils.common.toRippledAmount(order.direction === 'buy' ? order.quantity : order.totalPrice); const takerGets = utils.common.toRippledAmount(order.direction === 'buy' ? order.totalPrice : order.quantity); - transaction.offerCreate(account, takerPays, takerGets); - - utils.setTransactionBitFlags(transaction, order, OfferCreateFlags); + const txJSON: Object = { + TransactionType: 'OfferCreate', + Account: account, + TakerGets: takerGets, + TakerPays: takerPays, + Flags: 0 + }; if (order.direction === 'sell') { - transaction.setFlags('Sell'); + txJSON.Flags |= offerFlags.Sell; } - - return transaction; + if (order.passive === true) { + txJSON.Flags |= offerFlags.Passive; + } + if (order.immediateOrCancel === true) { + txJSON.Flags |= offerFlags.ImmediateOrCancel; + } + if (order.fillOrKill === true) { + txJSON.Flags |= offerFlags.FillOrKill; + } + return txJSON; } function prepareOrderAsync(account: string, order: Order, instructions: Instructions, callback ) { - const txJSON = createOrderTransaction(account, order).tx_json; + const txJSON = createOrderTransaction(account, order); utils.prepareTransaction(txJSON, this.remote, instructions, callback); } diff --git a/src/api/transaction/ordercancellation.js b/src/api/transaction/ordercancellation.js index 0f80a5ad..ec8cd826 100644 --- a/src/api/transaction/ordercancellation.js +++ b/src/api/transaction/ordercancellation.js @@ -2,24 +2,25 @@ 'use strict'; const utils = require('./utils'); const validate = utils.common.validate; -const Transaction = utils.common.core.Transaction; import type {Instructions, Prepare} from './types.js'; function createOrderCancellationTransaction(account: string, sequence: number -): Transaction { +): Object { validate.address(account); validate.sequence(sequence); - const transaction = new Transaction(); - transaction.offerCancel(account, sequence); - return transaction; + return { + TransactionType: 'OfferCancel', + Account: account, + OfferSequence: sequence + }; } function prepareOrderCancellationAsync(account: string, sequence: number, instructions: Instructions, callback ) { - const txJSON = createOrderCancellationTransaction(account, sequence).tx_json; + const txJSON = createOrderCancellationTransaction(account, sequence); utils.prepareTransaction(txJSON, this.remote, instructions, callback); } diff --git a/src/api/transaction/payment.js b/src/api/transaction/payment.js index 4ed74c85..9b9125c6 100644 --- a/src/api/transaction/payment.js +++ b/src/api/transaction/payment.js @@ -4,7 +4,7 @@ const _ = require('lodash'); const utils = require('./utils'); const validate = utils.common.validate; const toRippledAmount = utils.common.toRippledAmount; -const Transaction = utils.common.core.Transaction; +const paymentFlags = utils.common.txFlags.Payment; const ValidationError = utils.common.errors.ValidationError; import type {Instructions, Prepare} from './types.js'; import type {Amount, Adjustment, MaxAdjustment, @@ -66,7 +66,7 @@ function createMaximalAmount(amount: Amount): Amount { } function createPaymentTransaction(account: string, paymentArgument: Payment -): Transaction { +): Object { const payment = _.cloneDeep(paymentArgument); applyAnyCounterpartyEncoding(payment); validate.address(account); @@ -88,63 +88,63 @@ function createPaymentTransaction(account: string, paymentArgument: Payment createMaximalAmount(payment.destination.minAmount) : (payment.destination.amount || payment.destination.minAmount); - const transaction = new Transaction(); - transaction.payment({ - from: payment.source.address, - to: payment.destination.address, - amount: toRippledAmount(amount) - }); + const txJSON: Object = { + TransactionType: 'Payment', + Account: payment.source.address, + Destination: payment.destination.address, + Amount: toRippledAmount(amount), + Flags: 0 + }; - if (payment.invoiceID) { - transaction.invoiceID(payment.invoiceID); + if (payment.invoiceID !== undefined) { + txJSON.InvoiceID = payment.invoiceID; } - if (payment.source.tag) { - transaction.sourceTag(payment.source.tag); + if (payment.source.tag !== undefined) { + txJSON.SourceTag = payment.source.tag; } - if (payment.destination.tag) { - transaction.destinationTag(payment.destination.tag); + if (payment.destination.tag !== undefined) { + txJSON.DestinationTag = payment.destination.tag; } - if (payment.memos) { - _.forEach(payment.memos, memo => - transaction.addMemo(memo.type, memo.format, memo.data) - ); + if (payment.memos !== undefined) { + txJSON.Memos = _.map(payment.memos, utils.convertMemo); } - if (payment.noDirectRipple) { - transaction.setFlags(['NoRippleDirect']); + if (payment.noDirectRipple === true) { + txJSON.Flags |= paymentFlags.NoRippleDirect; } - if (payment.limitQuality) { - transaction.setFlags(['LimitQuality']); + if (payment.limitQuality === true) { + txJSON.Flags |= paymentFlags.LimitQuality; } if (!isXRPToXRPPayment(payment)) { // Don't set SendMax for XRP->XRP payment // temREDUNDANT_SEND_MAX removed in: // https://github.com/ripple/rippled/commit/ // c522ffa6db2648f1d8a987843e7feabf1a0b7de8/ - if (payment.allowPartialPayment || payment.destination.minAmount) { - transaction.setFlags(['PartialPayment']); + if (payment.allowPartialPayment === true + || payment.destination.minAmount !== undefined) { + txJSON.Flags |= paymentFlags.PartialPayment; } - transaction.setSendMax(toRippledAmount( - payment.source.maxAmount || payment.source.amount)); + txJSON.SendMax = toRippledAmount( + payment.source.maxAmount || payment.source.amount); - if (payment.destination.minAmount) { - transaction.setDeliverMin(toRippledAmount(payment.destination.minAmount)); + if (payment.destination.minAmount !== undefined) { + txJSON.DeliverMin = toRippledAmount(payment.destination.minAmount); } - if (payment.paths) { - transaction.paths(JSON.parse(payment.paths)); + if (payment.paths !== undefined) { + txJSON.Paths = JSON.parse(payment.paths); } - } else if (payment.allowPartialPayment) { + } else if (payment.allowPartialPayment === true) { throw new ValidationError('XRP to XRP payments cannot be partial payments'); } - return transaction; + return txJSON; } function preparePaymentAsync(account: string, payment: Payment, instructions: Instructions, callback ) { - const txJSON = createPaymentTransaction(account, payment).tx_json; + const txJSON = createPaymentTransaction(account, payment); utils.prepareTransaction(txJSON, this.remote, instructions, callback); } diff --git a/src/api/transaction/settings.js b/src/api/transaction/settings.js index b194c9a1..b9e71578 100644 --- a/src/api/transaction/settings.js +++ b/src/api/transaction/settings.js @@ -6,7 +6,6 @@ const utils = require('./utils'); const validate = utils.common.validate; const AccountFlagIndices = utils.common.constants.AccountFlagIndices; const AccountFields = utils.common.constants.AccountFields; -const Transaction = utils.common.core.Transaction; import type {Instructions, Prepare} from './types.js'; import type {Settings} from './settings-types.js'; @@ -14,7 +13,7 @@ import type {Settings} from './settings-types.js'; const CLEAR_SETTING = null; -function setTransactionFlags(transaction: Transaction, values: Settings) { +function setTransactionFlags(txJSON: Object, values: Settings) { const keys = Object.keys(values); assert(keys.length === 1, 'ERROR: can only set one setting per transaction'); const flagName = keys[0]; @@ -22,14 +21,14 @@ function setTransactionFlags(transaction: Transaction, values: Settings) { const index = AccountFlagIndices[flagName]; if (index !== undefined) { if (value) { - transaction.tx_json.SetFlag = index; + txJSON.SetFlag = index; } else { - transaction.tx_json.ClearFlag = index; + txJSON.ClearFlag = index; } } } -function setTransactionFields(transaction: Transaction, input: Settings) { +function setTransactionFields(txJSON: Object, input: Settings) { const fieldSchema = AccountFields; for (const fieldName in fieldSchema) { const field = fieldSchema[fieldName]; @@ -49,7 +48,7 @@ function setTransactionFields(transaction: Transaction, input: Settings) { value = new Buffer(value, 'ascii').toString('hex').toUpperCase(); } - transaction.tx_json[fieldName] = value; + txJSON[fieldName] = value; } } @@ -71,33 +70,35 @@ function convertTransferRate(transferRate: number | string): number | string { } function createSettingsTransaction(account: string, settings: Settings -): Transaction { +): Object { validate.address(account); validate.settings(settings); - const transaction = new Transaction(); if (settings.regularKey) { - return transaction.setRegularKey({ - account: account, - regular_key: settings.regularKey - }); + return { + TransactionType: 'SetRegularKey', + Account: account, + RegularKey: settings.regularKey + }; } - transaction.accountSet(account); - setTransactionFlags(transaction, settings); - setTransactionFields(transaction, settings); + const txJSON: Object = { + TransactionType: 'AccountSet', + Account: account + }; + setTransactionFlags(txJSON, settings); + setTransactionFields(txJSON, settings); - if (transaction.tx_json.TransferRate !== undefined) { - transaction.tx_json.TransferRate = convertTransferRate( - transaction.tx_json.TransferRate); + if (txJSON.TransferRate !== undefined) { + txJSON.TransferRate = convertTransferRate(txJSON.TransferRate); } - return transaction; + return txJSON; } function prepareSettingsAsync(account: string, settings: Settings, instructions: Instructions, callback ) { - const txJSON = createSettingsTransaction(account, settings).tx_json; + const txJSON = createSettingsTransaction(account, settings); utils.prepareTransaction(txJSON, this.remote, instructions, callback); } diff --git a/src/api/transaction/suspended-payment-cancellation.js b/src/api/transaction/suspended-payment-cancellation.js index d088dcb8..be9ba6cb 100644 --- a/src/api/transaction/suspended-payment-cancellation.js +++ b/src/api/transaction/suspended-payment-cancellation.js @@ -3,7 +3,6 @@ const _ = require('lodash'); const utils = require('./utils'); const validate = utils.common.validate; -const Transaction = utils.common.core.Transaction; import type {Instructions, Prepare} from './types.js'; import type {Memo} from '../common/types.js'; @@ -15,30 +14,27 @@ type SuspendedPaymentCancellation = { function createSuspendedPaymentCancellationTransaction(account: string, payment: SuspendedPaymentCancellation -): Transaction { +): Object { validate.address(account); validate.suspendedPaymentCancellation(payment); - const transaction = new Transaction(); - transaction.suspendedPaymentCancel({ - account: account, - owner: payment.owner, - paymentSequence: payment.paymentSequence - }); - - if (payment.memos) { - _.forEach(payment.memos, memo => - transaction.addMemo(memo.type, memo.format, memo.data) - ); + const txJSON: Object = { + TransactionType: 'SuspendedPaymentCancel', + Account: account, + Owner: payment.owner, + OfferSequence: payment.paymentSequence + }; + if (payment.memos !== undefined) { + txJSON.Memos = _.map(payment.memos, utils.convertMemo); } - return transaction; + return txJSON; } function prepareSuspendedPaymentCancellationAsync(account: string, payment: SuspendedPaymentCancellation, instructions: Instructions, callback ) { const txJSON = - createSuspendedPaymentCancellationTransaction(account, payment).tx_json; + createSuspendedPaymentCancellationTransaction(account, payment); utils.prepareTransaction(txJSON, this.remote, instructions, callback); } diff --git a/src/api/transaction/suspended-payment-creation.js b/src/api/transaction/suspended-payment-creation.js index 0bcedf6b..7400934e 100644 --- a/src/api/transaction/suspended-payment-creation.js +++ b/src/api/transaction/suspended-payment-creation.js @@ -4,7 +4,6 @@ const _ = require('lodash'); const utils = require('./utils'); const validate = utils.common.validate; const toRippledAmount = utils.common.toRippledAmount; -const Transaction = utils.common.core.Transaction; import type {Instructions, Prepare} from './types.js'; import type {Adjustment, MaxAdjustment, Memo} from '../common/types.js'; @@ -19,46 +18,42 @@ type SuspendedPaymentCreation = { function createSuspendedPaymentCreationTransaction(account: string, payment: SuspendedPaymentCreation -): Transaction { +): Object { validate.address(account); validate.suspendedPaymentCreation(payment); - const transaction = new Transaction(); - transaction.suspendedPaymentCreate({ - account: account, - destination: payment.destination.address, - amount: toRippledAmount(payment.destination.amount) - }); + const txJSON: Object = { + TransactionType: 'SuspendedPaymentCreate', + Account: account, + Destination: payment.destination.address, + Amount: toRippledAmount(payment.destination.amount) + }; - if (payment.digest) { - transaction.setDigest(payment.digest); + if (payment.digest !== undefined) { + txJSON.Digest = payment.digest; } - if (payment.allowCancelAfter) { - transaction.setAllowCancelAfter(payment.allowCancelAfter); + if (payment.allowCancelAfter !== undefined) { + txJSON.CancelAfter = utils.fromTimestamp(payment.allowCancelAfter); } - if (payment.allowExecuteAfter) { - transaction.setAllowExecuteAfter(payment.allowExecuteAfter); + if (payment.allowExecuteAfter !== undefined) { + txJSON.FinishAfter = utils.fromTimestamp(payment.allowExecuteAfter); } - - if (payment.source.tag) { - transaction.sourceTag(payment.source.tag); + if (payment.source.tag !== undefined) { + txJSON.SourceTag = payment.source.tag; } - if (payment.destination.tag) { - transaction.destinationTag(payment.destination.tag); + if (payment.destination.tag !== undefined) { + txJSON.DestinationTag = payment.destination.tag; } - if (payment.memos) { - _.forEach(payment.memos, memo => - transaction.addMemo(memo.type, memo.format, memo.data) - ); + if (payment.memos !== undefined) { + txJSON.Memos = _.map(payment.memos, utils.convertMemo); } - return transaction; + return txJSON; } function prepareSuspendedPaymentCreationAsync(account: string, payment: SuspendedPaymentCreation, instructions: Instructions, callback ) { - const txJSON = - createSuspendedPaymentCreationTransaction(account, payment).tx_json; + const txJSON = createSuspendedPaymentCreationTransaction(account, payment); utils.prepareTransaction(txJSON, this.remote, instructions, callback); } diff --git a/src/api/transaction/suspended-payment-execution.js b/src/api/transaction/suspended-payment-execution.js index 3fb95f69..86245914 100644 --- a/src/api/transaction/suspended-payment-execution.js +++ b/src/api/transaction/suspended-payment-execution.js @@ -3,7 +3,6 @@ const _ = require('lodash'); const utils = require('./utils'); const validate = utils.common.validate; -const Transaction = utils.common.core.Transaction; import type {Instructions, Prepare} from './types.js'; import type {Memo} from '../common/types.js'; @@ -18,40 +17,36 @@ type SuspendedPaymentExecution = { function createSuspendedPaymentExecutionTransaction(account: string, payment: SuspendedPaymentExecution -): Transaction { +): Object { validate.address(account); validate.suspendedPaymentExecution(payment); - const transaction = new Transaction(); - transaction.suspendedPaymentFinish({ - account: account, - owner: payment.owner, - paymentSequence: payment.paymentSequence - }); + const txJSON: Object = { + TransactionType: 'SuspendedPaymentFinish', + Account: account, + Owner: payment.owner, + OfferSequence: payment.paymentSequence + }; - if (payment.method) { - transaction.setMethod(payment.method); + if (payment.method !== undefined) { + txJSON.Method = payment.method; } - if (payment.digest) { - transaction.setDigest(payment.digest); + if (payment.digest !== undefined) { + txJSON.Digest = payment.digest; } - if (payment.proof) { - transaction.setProof(payment.proof); + if (payment.proof !== undefined) { + txJSON.Proof = utils.convertStringToHex(payment.proof); } - - if (payment.memos) { - _.forEach(payment.memos, memo => - transaction.addMemo(memo.type, memo.format, memo.data) - ); + if (payment.memos !== undefined) { + txJSON.Memos = _.map(payment.memos, utils.convertMemo); } - return transaction; + return txJSON; } function prepareSuspendedPaymentExecutionAsync(account: string, payment: SuspendedPaymentExecution, instructions: Instructions, callback ) { - const txJSON = - createSuspendedPaymentExecutionTransaction(account, payment).tx_json; + const txJSON = createSuspendedPaymentExecutionTransaction(account, payment); utils.prepareTransaction(txJSON, this.remote, instructions, callback); } diff --git a/src/api/transaction/trustline.js b/src/api/transaction/trustline.js index ad962733..77ec4d9f 100644 --- a/src/api/transaction/trustline.js +++ b/src/api/transaction/trustline.js @@ -2,17 +2,11 @@ 'use strict'; const utils = require('./utils'); const validate = utils.common.validate; -const Transaction = utils.common.core.Transaction; +const trustlineFlags = utils.common.txFlags.TrustSet; const BigNumber = require('bignumber.js'); import type {Instructions, Prepare} from './types.js'; import type {TrustLineSpecification} from '../ledger/trustlines-types.js'; -const TrustSetFlags = { - authorized: {set: 'SetAuth'}, - ripplingDisabled: {set: 'NoRipple', unset: 'ClearNoRipple'}, - frozen: {set: 'SetFreeze', unset: 'ClearFreeze'} -}; - function convertQuality(quality) { return quality === undefined ? undefined : (new BigNumber(quality)).shift(9).truncated().toNumber(); @@ -20,7 +14,7 @@ function convertQuality(quality) { function createTrustlineTransaction(account: string, trustline: TrustLineSpecification -): Transaction { +): Object { validate.address(account); validate.trustline(trustline); @@ -30,17 +24,36 @@ function createTrustlineTransaction(account: string, value: trustline.limit }; - const transaction = new Transaction(); - transaction.trustSet(account, limit, convertQuality(trustline.qualityIn), - convertQuality(trustline.qualityOut)); - utils.setTransactionBitFlags(transaction, trustline, TrustSetFlags); - return transaction; + const txJSON: Object = { + TransactionType: 'TrustSet', + Account: account, + LimitAmount: limit, + Flags: 0 + }; + if (trustline.qualityIn !== undefined) { + txJSON.QualityIn = convertQuality(trustline.qualityIn); + } + if (trustline.qualityOut !== undefined) { + txJSON.QualityOut = convertQuality(trustline.qualityOut); + } + if (trustline.authorized === true) { + txJSON.Flags |= trustlineFlags.SetAuth; + } + if (trustline.ripplingDisabled !== undefined) { + txJSON.Flags |= trustline.ripplingDisabled ? + trustlineFlags.NoRipple : trustlineFlags.ClearNoRipple; + } + if (trustline.frozen !== undefined) { + txJSON.Flags |= trustline.frozen ? + trustlineFlags.SetFreeze : trustlineFlags.ClearFreeze; + } + return txJSON; } function prepareTrustlineAsync(account: string, trustline: TrustLineSpecification, instructions: Instructions, callback ) { - const txJSON = createTrustlineTransaction(account, trustline).tx_json; + const txJSON = createTrustlineTransaction(account, trustline); utils.prepareTransaction(txJSON, this.remote, instructions, callback); } diff --git a/src/api/transaction/utils.js b/src/api/transaction/utils.js index 934273c5..8c9cf649 100644 --- a/src/api/transaction/utils.js +++ b/src/api/transaction/utils.js @@ -5,25 +5,12 @@ const async = require('async'); const BigNumber = require('bignumber.js'); const common = require('../common'); const composeAsync = common.composeAsync; -const txFlags = require('./txflags'); +const txFlags = common.txFlags; import type {Remote} from '../../core/remote'; -import type {Transaction} from '../../core/transaction'; import type {Instructions} from './types.js'; -function setTransactionBitFlags(transaction: Transaction, values: any, - flags: any -): void { - for (const flagName in flags) { - const flagValue = values[flagName]; - const flagConversions = flags[flagName]; - - if (flagValue === true && flagConversions.set !== undefined) { - transaction.setFlags(flagConversions.set); - } - if (flagValue === false && flagConversions.unset !== undefined) { - transaction.setFlags(flagConversions.unset); - } - } +function removeUndefined(obj: Object): Object { + return _.omit(obj, _.isUndefined); } function getFeeDrops(remote: Remote, callback) { @@ -46,7 +33,7 @@ function formatPrepareResponse(txJSON: Object): Object { } function setCanonicalFlag(txJSON) { - txJSON.Flags |= txFlags.transactionFlags.Universal.FullyCanonicalSig; + txJSON.Flags |= txFlags.Universal.FullyCanonicalSig; // JavaScript converts operands to 32-bit signed ints before doing bitwise // operations. We need to convert it back to an unsigned int. @@ -114,8 +101,47 @@ function prepareTransaction(txJSON: Object, remote: Remote, })); } +function convertStringToHex(string: string) { + return string ? (new Buffer(string, 'utf8')).toString('hex').toUpperCase() : + undefined; +} + +function convertMemo(memo: Object): Object { + return { + Memo: removeUndefined({ + MemoData: convertStringToHex(memo.data), + MemoType: convertStringToHex(memo.type), + MemoFormat: convertStringToHex(memo.format) + }) + }; +} + +/** + * @param {Number} rpepoch (seconds since 1/1/2000 GMT) + * @return {Number} ms since unix epoch + * + */ +function toTimestamp(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 fromTimestamp(timestamp: number | Date): number { + const timestamp_ = timestamp instanceof Date ? + timestamp.getTime() : + timestamp; + return Math.round(timestamp_ / 1000) - 0x386D4380; +} + module.exports = { - setTransactionBitFlags, + removeUndefined, + convertStringToHex, + fromTimestamp, + toTimestamp, + convertMemo, prepareTransaction, common, promisify: common.promisify diff --git a/test/api-test.js b/test/api-test.js index 9eddf337..749ac31a 100644 --- a/test/api-test.js +++ b/test/api-test.js @@ -29,7 +29,11 @@ const orderbook = { }; function checkResult(expected, schemaName, response) { - assert.deepEqual(response, expected); + if (expected.txJSON) { + assert(response.txJSON); + assert.deepEqual(JSON.parse(response.txJSON), JSON.parse(expected.txJSON)); + } + assert.deepEqual(_.omit(response, 'txJSON'), _.omit(expected, 'txJSON')); if (schemaName) { schemaValidator.schemaValidate(schemaName, response); } @@ -908,7 +912,7 @@ describe('RippleAPI - offline', function() { fee: '0.000012' }; return api.prepareSettings(address, settings, instructions).then(data => { - assert.deepEqual(data, responses.prepareSettings.flags); + checkResult(responses.prepareSettings.flags, 'prepare', data); assert.deepEqual(api.sign(data.txJSON, secret), responses.sign); }); }); diff --git a/test/fixtures/api/requests/prepare-payment-no-counterparty.json b/test/fixtures/api/requests/prepare-payment-no-counterparty.json index 6f5782e3..e232363a 100644 --- a/test/fixtures/api/requests/prepare-payment-no-counterparty.json +++ b/test/fixtures/api/requests/prepare-payment-no-counterparty.json @@ -26,5 +26,5 @@ "allowPartialPayment": true, "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\"}]]" + "paths": "[[{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"currency\":\"USD\",\"issuer\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\"},{\"currency\":\"LTC\",\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\"},{\"account\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"currency\":\"LTC\",\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\"}]]" } diff --git a/test/fixtures/api/requests/prepare-trustline-simple.json b/test/fixtures/api/requests/prepare-trustline-simple.json index 572e61cc..b0b48e36 100644 --- a/test/fixtures/api/requests/prepare-trustline-simple.json +++ b/test/fixtures/api/requests/prepare-trustline-simple.json @@ -1,5 +1,5 @@ { "currency": "BTC", "counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM", - "limit": "0.10" + "limit": "0.1" } diff --git a/test/fixtures/api/responses/prepare-payment-no-counterparty.json b/test/fixtures/api/responses/prepare-payment-no-counterparty.json index 3ffa57c8..4fbd7631 100644 --- a/test/fixtures/api/responses/prepare-payment-no-counterparty.json +++ b/test/fixtures/api/responses/prepare-payment-no-counterparty.json @@ -1,5 +1,5 @@ { - "txJSON": "{\"Flags\":2147942400,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"LTC\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\"},\"InvoiceID\":\"A98FD36C17BE2B8511AD36DC335478E7E89F06262949F36EB88E2D683BBCC50A\",\"SourceTag\":14,\"DestinationTag\":58,\"Memos\":[{\"Memo\":{\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\",\"MemoData\":\"7465787465642064617461\"}}],\"SendMax\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\"},\"Paths\":[[{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"issuer\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"currency\":\"USD\",\"type_hex\":\"0000000000000031\"},{\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"currency\":\"LTC\",\"type_hex\":\"0000000000000030\"},{\"account\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"currency\":\"LTC\",\"type_hex\":\"0000000000000031\"}]],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", + "txJSON": "{\"Flags\":2147942400,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"LTC\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\"},\"InvoiceID\":\"A98FD36C17BE2B8511AD36DC335478E7E89F06262949F36EB88E2D683BBCC50A\",\"SourceTag\":14,\"DestinationTag\":58,\"Memos\":[{\"Memo\":{\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\",\"MemoData\":\"7465787465642064617461\"}}],\"SendMax\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\"},\"Paths\":[[{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"issuer\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"currency\":\"USD\"},{\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"currency\":\"LTC\"},{\"account\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"currency\":\"LTC\"}]],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "instructions": { "fee": "12", "sequence": 23,