diff --git a/api/balances.js b/api/balances.js index 0076fbfa..5b843421 100644 --- a/api/balances.js +++ b/api/balances.js @@ -33,9 +33,7 @@ function getBalances(account, options, callback) { validate.address(account); validate.currency(options.currency, true); validate.counterparty(options.counterparty, true); - validate.ledger(options.ledger, true); - validate.limit(options.limit, true); - validate.paging(options, true); + validate.options(options); var self = this; diff --git a/api/lib/validate.js b/api/lib/validate.js index e8e69bed..f4bd04a4 100644 --- a/api/lib/validate.js +++ b/api/lib/validate.js @@ -50,6 +50,14 @@ function validateAddressAndSecret(obj) { } } +function validateAddressAndMaybeSecret(obj) { + if (obj.secret === undefined) { + validateAddress(obj.address); + } else { + validateAddressAndSecret(obj); + } +} + function validateCurrency(currency) { if (!validator.isValid(currency, 'Currency')) { throw error('Parameter is not a valid currency: currency'); @@ -451,12 +459,6 @@ function validateTrustline(trustline) { // TODO: validateSchema(trustline, 'Trustline'); } -function validateValidated(validated) { - if (!isBoolean(validated)) { - throw error('validated must be boolean, not: ' + validated); - } -} - function validateTxJSON(txJSON) { if (typeof txJSON !== 'object') { throw error('tx_json must be an object, not: ' + typeof txJSON); @@ -479,6 +481,62 @@ function validateBlob(blob) { } } +function isNumeric(value) { + return !isNaN(parseFloat(value)) && isFinite(value); +} + +function validateNonNegativeStringFloat(value, name) { + if (typeof value !== 'string') { + throw error(name + ' must be a string, not: ' + typeof value); + } + if (!isNumeric(value)) { + throw error(name + ' must be a numeric string, not: ' + value); + } + if (parseFloat(value) < 0) { + throw error(name + ' must be non-negative, got: ' + parseFloat(value)); + } +} + +function validateNonNegativeStringInteger(value, name) { + validateNonNegativeStringFloat(value, name); + if (value.indexOf('.') !== -1) { + throw error(name + ' must be an integer, got: ' + value); + } +} + +function validateOptions(options) { + if (options.max_fee !== undefined) { + validateNonNegativeStringFloat(options.max_fee, 'max_fee'); + } + if (options.fixed_fee !== undefined) { + validateNonNegativeStringFloat(options.fixed_fee, 'fixed_fee'); + } + if (options.last_ledger_sequence !== undefined) { + validateNonNegativeStringInteger(options.last_ledger_sequence, + 'last_ledger_sequence'); + } + if (options.last_ledger_offset !== undefined) { + validateNonNegativeStringInteger(options.last_ledger_offset, + 'last_ledger_offset'); + } + if (options.sequence !== undefined) { + validateNonNegativeStringInteger(options.sequence, 'sequence'); + } + if (options.limit !== undefined) { + validateLimit(options.limit); + } + if (options.ledger !== undefined) { + validateLedger(options.ledger); + } + if (options.validated !== undefined && !isBoolean(options.validated)) { + throw error('validated must be boolean, not: ' + options.validated); + } + if (options.submit !== undefined && !isBoolean(options.submit)) { + throw error('submit must be boolean, not: ' + options.submit); + } + validatePaging(options); +} + function createValidators(validatorMap) { var result = {}; _.forEach(validatorMap, function(validateFunction, key) { @@ -498,12 +556,10 @@ function createValidators(validatorMap) { module.exports = createValidators({ address: validateAddress, addressAndSecret: validateAddressAndSecret, + addressAndMaybeSecret: validateAddressAndMaybeSecret, currency: validateCurrency, counterparty: validateCounterparty, issue: validateIssue, - ledger: validateLedger, - limit: validateLimit, - paging: validatePaging, identifier: validateIdentifier, paymentIdentifier: validatePaymentIdentifier, sequence: validateSequence, @@ -515,7 +571,7 @@ module.exports = createValidators({ pathfind: validatePathFind, settings: validateSettings, trustline: validateTrustline, - validated: validateValidated, txJSON: validateTxJSON, - blob: validateBlob + blob: validateBlob, + options: validateOptions }); diff --git a/api/orders.js b/api/orders.js index 69b2d6a3..6043781a 100644 --- a/api/orders.js +++ b/api/orders.js @@ -2,10 +2,8 @@ /* eslint-disable valid-jsdoc */ 'use strict'; var _ = require('lodash'); -var async = require('async'); var Promise = require('bluebird'); var ripple = require('ripple-lib'); -var transactions = require('./transactions'); var utils = require('./lib/utils'); var errors = require('./lib/errors.js'); var TxToRestConverter = require('./lib/tx-to-rest-converter.js'); @@ -15,6 +13,7 @@ var validate = require('./lib/validate'); var createOrderTransaction = require('./transaction').createOrderTransaction; var createOrderCancellationTransaction = require('./transaction').createOrderCancellationTransaction; +var transact = require('./transact'); var InvalidRequestError = errors.InvalidRequestError; @@ -41,9 +40,7 @@ function getOrders(account, options, callback) { var self = this; validate.address(account); - validate.ledger(options.ledger, true); - validate.limit(options.limit, true); - validate.paging(options, true); + validate.options(options); function getAccountOrders(prevResult) { var isAggregate = options.limit === 'all'; @@ -162,15 +159,9 @@ function getOrders(account, options, callback) { * - validating the submitted transaction */ function placeOrder(account, order, secret, options, callback) { - validate.addressAndSecret({address: account, secret: secret}); - validate.order(order); - validate.validated(options.validated, true); - var transaction = createOrderTransaction(account, order); - async.waterfall([ - _.partial(transactions.submit, this, transaction, secret, options), - TxToRestConverter.parseSubmitOrderFromTx - ], callback); + var converter = TxToRestConverter.parseSubmitOrderFromTx; + transact(transaction, this, secret, options, converter, callback); } /** @@ -186,14 +177,9 @@ function placeOrder(account, order, secret, options, callback) { * validating the submitted transaction */ function cancelOrder(account, sequence, secret, options, callback) { - validate.sequence(sequence); - validate.address(account); - var transaction = createOrderCancellationTransaction(account, sequence); - async.waterfall([ - _.partial(transactions.submit, this, transaction, secret, options), - TxToRestConverter.parseCancelOrderFromTx - ], callback); + var converter = TxToRestConverter.parseCancelOrderFromTx; + transact(transaction, this, secret, options, converter, callback); } /** @@ -225,7 +211,7 @@ function getOrderBook(account, base, counter, options, callback) { }); validate.address(account); validate.orderbook(params); - validate.validated(options.validated, true); + validate.options(options); function getLastValidatedLedger(parameters) { var promise = new Promise(function(resolve, reject) { diff --git a/api/payments.js b/api/payments.js index 1414f289..15ace54f 100644 --- a/api/payments.js +++ b/api/payments.js @@ -17,6 +17,7 @@ var createPaymentTransaction = var renameCounterpartyToIssuer = require('./transaction/utils').renameCounterpartyToIssuer; var xrpToDrops = require('./transaction/utils').xrpToDrops; +var transact = require('./transact'); var errors = require('./lib/errors'); var InvalidRequestError = errors.InvalidRequestError; @@ -122,19 +123,19 @@ function formatPaymentHelper(account, transaction, callback) { * submitted transaction */ function submitPayment(account, payment, clientResourceID, secret, - lastLedgerSequence, urlBase, options, callback) { + urlBase, options, callback) { var self = this; var max_fee = Number(options.max_fee) > 0 ? xrpToDrops(options.max_fee) : undefined; var fixed_fee = Number(options.fixed_fee) > 0 ? xrpToDrops(options.fixed_fee) : undefined; - validate.client_resource_id(clientResourceID); - // TODO: validate.addressAndSecret({address: account, secret: secret}); - validate.address(account); + // these checks are done at the top of the function because we cannot + // raise exceptions inside callbacks + validate.addressAndMaybeSecret({address: account, secret: secret}); validate.payment(payment); - validate.last_ledger_sequence(lastLedgerSequence, true); - validate.validated(options.validated, true); + validate.client_resource_id(clientResourceID); + validate.options(options); function formatTransactionResponse(message, meta, _callback) { if (meta.state === 'validated') { @@ -155,14 +156,20 @@ function submitPayment(account, payment, clientResourceID, secret, } function _createPaymentTransaction(remote, _callback) { - var transaction = createPaymentTransaction(payment); + var transaction; + try { + transaction = createPaymentTransaction(account, payment); + } catch (err) { + _callback(err); + return; + } var ledgerIndex; var maxFee = Number(max_fee); var fixedFee = Number(fixed_fee); - if (Number(lastLedgerSequence) > 0) { - ledgerIndex = Number(lastLedgerSequence); + if (Number(options.last_ledger_sequence) > 0) { + ledgerIndex = Number(options.last_ledger_sequence); } else { ledgerIndex = Number(remote._ledger_current_index) + transactions.DEFAULT_LEDGER_BUFFER; @@ -189,12 +196,16 @@ function submitPayment(account, payment, clientResourceID, secret, saveTransaction: true }; + var converter = formatTransactionResponse; async.waterfall([ _.partial(_createPaymentTransaction, self.remote), function(transaction, _callback) { - transactions.submit(self, transaction, secret, _options, _callback); - }, - formatTransactionResponse + try { // for case of missing secret and submit=false not set + transact(transaction, self, secret, _options, converter, _callback); + } catch (err) { + _callback(err); + } + } ], callback); } diff --git a/api/settings.js b/api/settings.js index 161f4bc4..b49fb7df 100644 --- a/api/settings.js +++ b/api/settings.js @@ -1,14 +1,13 @@ /* eslint-disable valid-jsdoc */ 'use strict'; var _ = require('lodash'); -var async = require('async'); var utils = require('./lib/utils'); -var transactions = require('./transactions.js'); var TxToRestConverter = require('./lib/tx-to-rest-converter.js'); var validate = require('./lib/validate'); var createSettingsTransaction = require('./transaction').createSettingsTransaction; var constants = require('./lib/constants'); +var transact = require('./transact'); function parseFieldsFromResponse(responseBody, fields) { var parsedBody = {}; @@ -73,14 +72,10 @@ function getSettings(account, callback) { * */ function changeSettings(account, settings, secret, options, callback) { - validate.address(account); - validate.settings(settings); - var transaction = createSettingsTransaction(account, settings); - async.waterfall([ - _.partial(transactions.submit, this, transaction, secret, options), - _.partial(TxToRestConverter.parseSettingsResponseFromTx, settings) - ], callback); + var converter = _.partial(TxToRestConverter.parseSettingsResponseFromTx, + settings); + transact(transaction, this, secret, options, converter, callback); } module.exports = { diff --git a/api/transact.js b/api/transact.js new file mode 100644 index 00000000..ea424faa --- /dev/null +++ b/api/transact.js @@ -0,0 +1,56 @@ +'use strict'; +var _ = require('lodash'); +var async = require('async'); +var sign = require('./transaction/sign'); +var createTxJSON = require('./transaction/utils').createTxJSON; +var transactions = require('./transactions'); +var validate = require('./lib/validate'); + +function signIfSecretExists(secret, prepared, callback) { + var signResponse = secret ? sign(prepared.tx_json, secret) : {}; + callback(null, _.assign(prepared, signResponse)); +} + +function formatResponse(converter, prepared, callback) { + async.waterfall([ + _.partial(converter, prepared, {}), + function(formatted, _callback) { + _callback(null, _.assign(formatted, prepared)); + } + ], callback); +} + +function prepareAndOptionallySign(transaction, api, secret, options, + converter, callback) { + var address = transaction.tx_json.Account; + validate.addressAndMaybeSecret({address: address, secret: secret}); + validate.options(options); + async.waterfall([ + _.partial(createTxJSON, transaction, api.remote, options), + _.partial(signIfSecretExists, secret), + _.partial(formatResponse, converter) + ], callback); +} + +function prepareAndSignAndSubmit(transaction, api, secret, options, converter, + callback) { + var address = transaction.tx_json.Account; + validate.addressAndSecret({address: address, secret: secret}); + validate.options(options); + async.waterfall([ + _.partial(transactions.submit, api, transaction, secret, options), + converter + ], callback); +} + +/* eslint-disable no-unused-vars */ +function transact(transaction, api, secret, options, converter, callback) { + if (options.submit === false) { + prepareAndOptionallySign.apply(this, arguments); + } else { + prepareAndSignAndSubmit.apply(this, arguments); + } +} +/* eslint-enable no-unused-vars */ + +module.exports = transact; diff --git a/api/transaction/order.js b/api/transaction/order.js index e4e64a13..21e6bbc6 100644 --- a/api/transaction/order.js +++ b/api/transaction/order.js @@ -11,10 +11,11 @@ var OfferCreateFlags = { }; function createOrderTransaction(account, order) { - if (order) { - utils.renameCounterpartyToIssuer(order.taker_gets); - utils.renameCounterpartyToIssuer(order.taker_pays); - } + validate.address(account); + validate.order(order); + + utils.renameCounterpartyToIssuer(order.taker_gets); + utils.renameCounterpartyToIssuer(order.taker_pays); var transaction = new ripple.Transaction(); var takerPays = order.taker_pays.currency !== 'XRP' ? order.taker_pays : utils.xrpToDrops(order.taker_pays.value); @@ -36,10 +37,6 @@ function createOrderTransaction(account, order) { } function prepareOrder(account, order, instructions, callback) { - instructions = instructions || {}; - validate.address(account); - validate.order(order); - var transaction = createOrderTransaction(account, order); utils.createTxJSON(transaction, this.remote, instructions, callback); } diff --git a/api/transaction/ordercancellation.js b/api/transaction/ordercancellation.js index 9704cec4..7326871a 100644 --- a/api/transaction/ordercancellation.js +++ b/api/transaction/ordercancellation.js @@ -5,16 +5,15 @@ var validate = require('../lib/validate'); var wrapCatch = require('../lib/utils').wrapCatch; function createOrderCancellationTransaction(account, sequence) { + validate.address(account); + validate.sequence(sequence); + var transaction = new ripple.Transaction(); transaction.offerCancel(account, sequence); return transaction; } function prepareOrderCancellation(account, sequence, instructions, callback) { - instructions = instructions || {}; - validate.sequence(sequence); - validate.address(account); - var transaction = createOrderCancellationTransaction(account, sequence); utils.createTxJSON(transaction, this.remote, instructions, callback); } diff --git a/api/transaction/payment.js b/api/transaction/payment.js index e4dcd7d3..64c14ae2 100644 --- a/api/transaction/payment.js +++ b/api/transaction/payment.js @@ -30,7 +30,10 @@ function isSendMaxRequired(payment) { return false; } -function createPaymentTransaction(payment) { +function createPaymentTransaction(account, payment) { + validate.address(account); + validate.payment(payment); + // Convert blank issuer to sender's address // (Ripple convention for 'any issuer') // https://ripple.com/build/transactions/ @@ -128,11 +131,7 @@ function createPaymentTransaction(payment) { } function preparePayment(account, payment, instructions, callback) { - instructions = instructions || {}; - validate.address(account); - validate.payment(payment); - - var transaction = createPaymentTransaction(payment); + var transaction = createPaymentTransaction(account, payment); utils.createTxJSON(transaction, this.remote, instructions, callback); } diff --git a/api/transaction/settings.js b/api/transaction/settings.js index 96aa71d2..0e30031c 100644 --- a/api/transaction/settings.js +++ b/api/transaction/settings.js @@ -134,6 +134,9 @@ function convertTransferRate(transferRate) { } function createSettingsTransaction(account, settings) { + validate.address(account); + validate.settings(settings); + var transaction = new ripple.Transaction(); transaction.accountSet(account); @@ -151,10 +154,6 @@ function createSettingsTransaction(account, settings) { } function prepareSettings(account, settings, instructions, callback) { - instructions = instructions || {}; - validate.address(account); - validate.settings(settings); - var transaction = createSettingsTransaction(account, settings); utils.createTxJSON(transaction, this.remote, instructions, callback); } diff --git a/api/transaction/trustline.js b/api/transaction/trustline.js index 44882b8e..9831c953 100644 --- a/api/transaction/trustline.js +++ b/api/transaction/trustline.js @@ -13,6 +13,9 @@ var TrustSetFlags = { }; function createTrustLineTransaction(account, trustline) { + validate.address(account); + validate.trustline(trustline); + if (trustline && trustline.limit) { trustline.limit = String(trustline.limit); } @@ -42,10 +45,6 @@ function createTrustLineTransaction(account, trustline) { } function prepareTrustLine(account, trustline, instructions, callback) { - instructions = instructions || {}; - validate.address(account); - validate.trustline(trustline); - var transaction = createTrustLineTransaction(account, trustline); utils.createTxJSON(transaction, this.remote, instructions, callback); } diff --git a/api/transaction/utils.js b/api/transaction/utils.js index 3e43d568..40e20d37 100644 --- a/api/transaction/utils.js +++ b/api/transaction/utils.js @@ -1,6 +1,7 @@ /* eslint-disable valid-jsdoc */ 'use strict'; var BigNumber = require('bignumber.js'); +var validate = require('../lib/validate'); function renameCounterpartyToIssuer(amount) { if (amount && amount.counterparty) { @@ -69,24 +70,28 @@ function getFeeDrops(remote) { } function createTxJSON(transaction, remote, instructions, callback) { + instructions = instructions || {}; + validate.options(instructions); + transaction.complete(); var account = transaction.getAccount(); var tx_json = transaction.tx_json; - if (instructions.lastLedgerSequence !== undefined) { - tx_json.LastLedgerSequence = instructions.lastLedgerSequence; + if (instructions.last_ledger_sequence !== undefined) { + tx_json.LastLedgerSequence = + parseInt(instructions.last_ledger_sequence, 10); } else { - var offset = instructions.lastLedgerOffset !== undefined ? - instructions.lastLedgerOffset : 3; + var offset = instructions.last_ledger_offset !== undefined ? + parseInt(instructions.last_ledger_offset, 10) : 3; tx_json.LastLedgerSequence = remote.getLedgerSequence() + offset; } - if (instructions.fixedFee !== undefined) { - tx_json.Fee = xrpToDrops(instructions.fixedFee); + if (instructions.fixed_fee !== undefined) { + tx_json.Fee = xrpToDrops(instructions.fixed_fee); } else { var serverFeeDrops = getFeeDrops(remote); - if (instructions.maxFee !== undefined) { - var maxFeeDrops = xrpToDrops(instructions.maxFee); + if (instructions.max_fee !== undefined) { + var maxFeeDrops = xrpToDrops(instructions.max_fee); tx_json.Fee = BigNumber.min(serverFeeDrops, maxFeeDrops).toString(); } else { tx_json.Fee = serverFeeDrops; @@ -94,7 +99,7 @@ function createTxJSON(transaction, remote, instructions, callback) { } if (instructions.sequence !== undefined) { - tx_json.Sequence = instructions.sequence; + tx_json.Sequence = parseInt(instructions.sequence, 10); callback(null, {tx_json: tx_json}); } else { remote.findAccount(account).getNextSequence(function(error, sequence) { diff --git a/api/transactions.js b/api/transactions.js index 239ba6af..cee419f5 100644 --- a/api/transactions.js +++ b/api/transactions.js @@ -8,7 +8,6 @@ var utils = require('./lib/utils'); var validator = require('./lib/schema-validator'); var validate = require('./lib/validate'); var errors = require('./lib/errors.js'); -var utils = require('./lib/utils'); var DEFAULT_RESULTS_PER_PAGE = 10; @@ -194,7 +193,7 @@ function getTransaction(api, account, identifier, requestOptions, callback) { validate.address(account, true); validate.paymentIdentifier(identifier); - validate.ledger(requestOptions.ledger, true); + validate.options(requestOptions); } catch(err) { return callback(err); } diff --git a/api/trustlines.js b/api/trustlines.js index df1c2d9c..ab3425be 100644 --- a/api/trustlines.js +++ b/api/trustlines.js @@ -1,16 +1,14 @@ /* globals Promise: true */ /* eslint-disable valid-jsdoc */ 'use strict'; -var _ = require('lodash'); -var async = require('async'); var Promise = require('bluebird'); -var transactions = require('./transactions.js'); var utils = require('./lib/utils'); var validator = require('./lib/schema-validator'); var TxToRestConverter = require('./lib/tx-to-rest-converter.js'); var validate = require('./lib/validate'); var createTrustLineTransaction = require('./transaction').createTrustLineTransaction; +var transact = require('./transact'); var DefaultPageLimit = 200; @@ -38,9 +36,7 @@ function getTrustLines(account, options, callback) { validate.address(account); validate.currency(options.currency, true); validate.counterparty(options.counterparty, true); - validate.ledger(options.ledger, true); - validate.limit(options.limit, true); - validate.paging(options, true); + validate.options(options); var self = this; @@ -151,15 +147,9 @@ function getTrustLines(account, options, callback) { */ function addTrustLine(account, trustline, secret, options, callback) { - validate.address(account); - validate.trustline(trustline); - validate.validated(options.validated, true); - var transaction = createTrustLineTransaction(account, trustline); - async.waterfall([ - _.partial(transactions.submit, this, transaction, secret, options), - TxToRestConverter.parseTrustResponseFromTx - ], callback); + var converter = TxToRestConverter.parseTrustResponseFromTx; + transact(transaction, this, secret, options, converter, callback); } module.exports = { diff --git a/server/routes.js b/server/routes.js index f037351c..33c0def6 100644 --- a/server/routes.js +++ b/server/routes.js @@ -1,9 +1,24 @@ 'use strict'; - +var _ = require('lodash'); var api = require('./api'); var respond = require('./response-handler'); var config = require('./config'); +function invalid(message) { + return new api.errors.InvalidRequestError(message); +} + +function validateRequest(request) { + if (request.query.submit === 'false') { + if (request.query.validated === 'true') { + throw invalid('validated=true cannot be set with submit=false'); + } + if (request.body.client_resource_id) { + throw invalid('client_resource_id cannot be set with submit=false'); + } + } +} + function getUrlBase(request) { if (config.get('url_base')) { return config.get('url_base'); @@ -33,6 +48,27 @@ function makeMiddleware(handler, type) { }; } +function removeUndefinedValues(object) { + return _.omit(object, _.isUndefined); +} + +function loadInstructions(body) { + return removeUndefinedValues({ + max_fee: body.max_fee, + fixed_fee: body.fixed_fee, + last_ledger_sequence: body.last_ledger_sequence, + last_ledger_offset: body.last_ledger_offset, + sequence: body.sequence + }); +} + +function loadOptions(request) { + return _.assign(loadInstructions(request.body), { + validated: request.query.validated === 'true', + submit: request.query.submit !== 'false' + }); +} + function getUUID(request, callback) { api.getUUID(callback); } @@ -164,50 +200,50 @@ function getTrustLines(request, callback) { } function submitPayment(request, callback) { + validateRequest(request); var account = request.params.account; var payment = request.body.payment; var clientResourceID = request.body.client_resource_id; - var lastLedgerSequence = request.body.last_ledger_sequence; var secret = request.body.secret; var urlBase = getUrlBase(request); - var options = { - max_fee: request.body.max_fee, - fixed_fee: request.body.fixed_fee, - validated: request.query.validated === 'true' - }; + var options = loadOptions(request); api.submitPayment(account, payment, clientResourceID, secret, - lastLedgerSequence, urlBase, options, callback); + urlBase, options, callback); } function submitOrder(request, callback) { + validateRequest(request); var account = request.params.account; var order = request.body.order; var secret = request.body.secret; - var options = {validated: request.query.validated === 'true'}; + var options = loadOptions(request); api.submitOrder(account, order, secret, options, callback); } function changeSettings(request, callback) { + validateRequest(request); var account = request.params.account; var settings = request.body.settings; var secret = request.body.secret; - var options = {validated: request.query.validated === 'true'}; + var options = loadOptions(request); api.changeSettings(account, settings, secret, options, callback); } function addTrustLine(request, callback) { + validateRequest(request); var account = request.params.account; var trustline = request.body.trustline; var secret = request.body.secret; - var options = {validated: request.query.validated === 'true'}; + var options = loadOptions(request); api.addTrustLine(account, trustline, secret, options, callback); } function cancelOrder(request, callback) { + validateRequest(request); var account = request.params.account; var sequence = request.params.sequence; var secret = request.body.secret; - var options = {validated: request.query.validated === 'true'}; + var options = loadOptions(request); api.cancelOrder(account, sequence, secret, options, callback); } diff --git a/test/_payments-test.js b/test/_payments-test.js index 5e39b6c7..c4b0de07 100644 --- a/test/_payments-test.js +++ b/test/_payments-test.js @@ -950,7 +950,7 @@ suite('payments', function() { test('Posting XRP from genesis to dan with missing client resource id', function(done) { - app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') + app.post('/v1/accounts/' + fixtures.accounts.genesis.address + '/payments') .send(store.paymentGenesisToDan) .end(function(err, resp) { if (err) { @@ -969,7 +969,7 @@ suite('payments', function() { test('Posting XRP from genesis to dan with empty client resource id', function(done) { store.paymentGenesisToDan.client_resource_id = ''; - app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') + app.post('/v1/accounts/' + fixtures.accounts.genesis.address + '/payments') .send(store.paymentGenesisToDan) .end(function(err, resp) { if (err) { @@ -991,7 +991,7 @@ suite('payments', function() { test('Posting XRP from genesis to dan with valid client resource id', function(done) { store.paymentGenesisToDan.client_resource_id = 'qwerty'; - app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') + app.post('/v1/accounts/' + fixtures.accounts.genesis.address + '/payments') .send(store.paymentGenesisToDan) .end(function(err, resp) { if (err) { @@ -1010,7 +1010,7 @@ suite('payments', function() { test('Double posting XRP from genesis to dan with valid client resource id', function(done) { store.paymentGenesisToDan.client_resource_id = 'qwerty'; - app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') + app.post('/v1/accounts/' + fixtures.accounts.genesis.address + '/payments') .send(store.paymentGenesisToDan) .expect(function(resp) { assert.equal(resp.status, 500); @@ -1189,7 +1189,7 @@ suite('payments', function() { test.skip('Posting 10USD from carol to dan with valid client resource id ' + 'but incorrect secret', function(done) { - app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') + app.post('/v1/accounts/' + fixtures.accounts.carol.address + '/payments') .send(store.paymentCarolToDan) .expect(function(resp) { assert.deepEqual(resp.body, @@ -1207,7 +1207,7 @@ suite('payments', function() { store.paymentCarolToDan.secret = fixtures.accounts.carol.secret; store.value = store.paymentCarolToDan.payment.destination_amount.value; delete store.paymentCarolToDan.payment.destination_amount.value; - app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') + app.post('/v1/accounts/' + fixtures.accounts.carol.address + '/payments') .send(store.paymentCarolToDan) .expect(function(resp) { assert.equal(resp.status, 400); @@ -1227,7 +1227,7 @@ suite('payments', function() { store.paymentCarolToDan.payment.destination_amount.value = store.value; store.paymentCarolToDan.secret = fixtures.accounts.carol.secret; store.paymentCarolToDan.client_resource_id = 'abc'; - app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') + app.post('/v1/accounts/' + fixtures.accounts.carol.address + '/payments') .send(store.paymentCarolToDan) .expect(function(resp) { assert.equal(resp.status, 200); diff --git a/test/fixtures/errors.js b/test/fixtures/errors.js index 81321684..4e3319e5 100644 --- a/test/fixtures/errors.js +++ b/test/fixtures/errors.js @@ -19,20 +19,13 @@ module.exports.RESTMissingSecret = JSON.stringify({ message: 'Parameter missing: secret' }); -module.exports.RESTRequestInvalidSecret = JSON.stringify({ +module.exports.RESTInvalidSecret = JSON.stringify({ success: false, error_type: 'invalid_request', error: 'restINVALID_PARAMETER', message: 'Invalid secret' }); -module.exports.RESTInvalidSecret = JSON.stringify({ - success: false, - error_type: 'transaction', - error: 'tejSecretInvalid', - message: 'Invalid secret' -}); - module.exports.RESTInvalidAccount = JSON.stringify({ success: false, error_type: 'invalid_request', diff --git a/test/fixtures/orders.js b/test/fixtures/orders.js index 4d53a468..1cce067d 100644 --- a/test/fixtures/orders.js +++ b/test/fixtures/orders.js @@ -4748,7 +4748,7 @@ module.exports.prepareOrderResponse = JSON.stringify({ currency: 'USD', issuer: 'r3PDtZSa5LiYp1Ysn1vMuMzB59RzV3W9QH' }, - LastLedgerSequence: 8820085, + LastLedgerSequence: 8819988, Fee: '12', Sequence: 23 } diff --git a/test/fixtures/payments.js b/test/fixtures/payments.js index 8677e9f4..3af68552 100644 --- a/test/fixtures/payments.js +++ b/test/fixtures/payments.js @@ -1522,7 +1522,7 @@ module.exports.preparePaymentResponse = JSON.stringify({ } ] ], - LastLedgerSequence: 8820183, + LastLedgerSequence: 8820086, Fee: '12', Sequence: 23 } diff --git a/test/fixtures/settings.js b/test/fixtures/settings.js index 3fcfff1f..a0ec2674 100644 --- a/test/fixtures/settings.js +++ b/test/fixtures/settings.js @@ -234,24 +234,32 @@ module.exports.RESTAccountSettingsSubmitResponse = function(options) { }; module.exports.prepareSettingsRequest = { - address: addresses.VALID, + secret: addresses.SECRET, settings: { domain: 'ripple.com' }, - instructions: { - lastLedgerOffset: 100 - } + last_ledger_offset: '100' }; module.exports.prepareSettingsResponse = JSON.stringify({ success: true, + settings: { + domain: 'ripple.com', + require_destination_tag: false, + require_authorization: false, + disallow_xrp: false + }, tx_json: { - Flags: 0, - TransactionType: 'AccountSet', - Account: addresses.VALID, - Domain: '726970706C652E636F6D', - LastLedgerSequence: 8820244, - Fee: '12', - Sequence: 2938 - } + Flags: 0, + TransactionType: 'AccountSet', + Account: 'r3GgMwvgvP8h4yVWvjH1dPZNvC37TjzBBE', + Domain: '726970706C652E636F6D', + LastLedgerSequence: 8820244, + Fee: '12', + Sequence: 2938, + SigningPubKey: '02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8', + TxnSignature: '304402207660BDEF67105CE1EBA9AD35DC7156BAB43FF1D47633199EE257D70B6B9AAFBF02206934A3A39EB713051BB0278F3190FEFD2029A090FEF96F24A00D3A81C3D9F288' + }, + tx_blob: '12000322000000002400000B7A201B0086961468400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402207660BDEF67105CE1EBA9AD35DC7156BAB43FF1D47633199EE257D70B6B9AAFBF02206934A3A39EB713051BB0278F3190FEFD2029A090FEF96F24A00D3A81C3D9F288770A726970706C652E636F6D81144FBFF73DA4ECF9B701940F27341FA8020C313443', + hash: '7817010688A9D4151E63D8AD84893DDA48C3EA73D452A1B4E417A32A8BEDFEA5' }); diff --git a/test/fixtures/sign.js b/test/fixtures/sign.js index 9788c3a2..8de7c749 100644 --- a/test/fixtures/sign.js +++ b/test/fixtures/sign.js @@ -10,6 +10,6 @@ module.exports.signRequest = { module.exports.signResponse = JSON.stringify({ success: true, - tx_blob: '12000322000000002400000B7A201B0086961468400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402207660BDEF67105CE1EBA9AD35DC7156BAB43FF1D47633199EE257D70B6B9AAFBF02206934A3A39EB713051BB0278F3190FEFD2029A090FEF96F24A00D3A81C3D9F288770A726970706C652E636F6D81144FBFF73DA4ECF9B701940F27341FA8020C313443', - hash: '7817010688A9D4151E63D8AD84893DDA48C3EA73D452A1B4E417A32A8BEDFEA5' + tx_blob: '12000322000000002400000B7A201B0086961468400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402207660BDEF67105CE1EBA9AD35DC7156BAB43FF1D47633199EE257D70B6B9AAFBF02204A91292D4D46454F846E1B3F4DC6A158D290AE0FC5D38835AD8DEA826899CA47770A726970706C652E636F6D81144FBFF73DA4ECF9B701940F27341FA8020C313443', + hash: 'D2727C9FD5A53CBB9418956D82A3E72DA5284C2E1E44052290EA56778D8AA45B' }); diff --git a/test/fixtures/trustlines.js b/test/fixtures/trustlines.js index eb759685..5f2bd9b2 100644 --- a/test/fixtures/trustlines.js +++ b/test/fixtures/trustlines.js @@ -780,7 +780,7 @@ module.exports.prepareTrustLineResponse = JSON.stringify({ currency: 'USD', issuer: addresses.COUNTERPARTY }, - LastLedgerSequence: 8820289, + LastLedgerSequence: 8820192, Fee: '12', Sequence: 2938 } diff --git a/test/orders-test.js b/test/orders-test.js index db94d458..f0902be1 100644 --- a/test/orders-test.js +++ b/test/orders-test.js @@ -2,6 +2,7 @@ /* eslint-disable max-len */ 'use strict'; +var _ = require('lodash'); var assert = require('assert'); var ripple = require('ripple-lib'); var testutils = require('./testutils'); @@ -635,7 +636,7 @@ suite('post orders', function() { })) .expect(testutils.checkStatus(400)) .expect(testutils.checkHeaders) - .expect(testutils.checkBody(errors.RESTRequestInvalidSecret)) + .expect(testutils.checkBody(errors.RESTInvalidSecret)) .end(done); }); @@ -1087,7 +1088,7 @@ suite('post orders', function() { self.app .post('/v1/accounts/' + addresses.VALID + '/orders') - .send({}) + .send(_.omit(fixtures.order(), 'secret')) .expect(testutils.checkStatus(400)) .expect(testutils.checkHeaders) .expect(testutils.checkBody(errors.RESTMissingSecret)) @@ -1112,7 +1113,7 @@ suite('post orders', function() { })) .expect(testutils.checkStatus(400)) .expect(testutils.checkHeaders) - .expect(testutils.checkBody(errors.RESTRequestInvalidSecret)) + .expect(testutils.checkBody(errors.RESTInvalidSecret)) .end(done); }); @@ -1372,7 +1373,7 @@ suite('delete orders', function() { .send(fixtures.order({ secret: 'foo' })) - .expect(testutils.checkStatus(500)) + .expect(testutils.checkStatus(400)) .expect(testutils.checkHeaders) .expect(testutils.checkBody(errors.RESTInvalidSecret)) .end(done); @@ -1507,7 +1508,7 @@ suite('delete orders', function() { .send({ secret: 'foo' }) - .expect(testutils.checkStatus(500)) + .expect(testutils.checkStatus(400)) .expect(testutils.checkHeaders) .expect(testutils.checkBody(errors.RESTInvalidSecret)) .end(done); diff --git a/test/payments-test.js b/test/payments-test.js index 1417d46a..3175ea35 100644 --- a/test/payments-test.js +++ b/test/payments-test.js @@ -733,7 +733,7 @@ suite('post payments', function() { .send(fixtures.payment({ secret: 'foo' })) - .expect(testutils.checkStatus(500)) + .expect(testutils.checkStatus(400)) .expect(testutils.checkHeaders) .expect(testutils.checkBody(errors.RESTInvalidSecret)) .end(done); @@ -759,7 +759,7 @@ suite('post payments', function() { value: '0.001', currency: 'USD', issuer: addresses.issuer, - lastLedgerSequence: 9036185 + lastLedgerSequence: '9036185' })) .expect(testutils.checkStatus(200)) .expect(testutils.checkHeaders) diff --git a/test/settings-test.js b/test/settings-test.js index 956f4854..4bfafa7d 100644 --- a/test/settings-test.js +++ b/test/settings-test.js @@ -7,25 +7,27 @@ var fixtures = require('./fixtures').settings; var errors = require('./fixtures').errors; var addresses = require('./fixtures').addresses; -suite('prepareSettings', function() { +suite('prepare settings', function() { var self = this; setup(testutils.setup.bind(self)); teardown(testutils.teardown.bind(self)); - test('/transaction/prepare/settings', function(done) { + test('/accounts/:account/settings?submit=false', function(done) { self.wss.on('request_account_info', function(message, conn) { assert.strictEqual(message.command, 'account_info'); assert.strictEqual(message.account, addresses.VALID); conn.send(fixtures.accountInfoResponse(message)); }); - self.app - .post(testutils.getPrepareURL('settings')) - .send(fixtures.prepareSettingsRequest) - .expect(testutils.checkStatus(200)) - .expect(testutils.checkHeaders) - .expect(testutils.checkBody(fixtures.prepareSettingsResponse)) - .end(done); + testutils.withDeterministicPRNG(function(_done) { + self.app + .post(fixtures.requestPath(addresses.VALID, '?submit=false')) + .send(fixtures.prepareSettingsRequest) + .expect(testutils.checkStatus(200)) + .expect(testutils.checkHeaders) + .expect(testutils.checkBody(fixtures.prepareSettingsResponse)) + .end(_done); + }, done); }); }); @@ -235,7 +237,7 @@ suite('post settings', function() { wallet_size: 1, transfer_rate: 2 }}) - .expect(testutils.checkStatus(500)) + .expect(testutils.checkStatus(400)) .expect(testutils.checkHeaders) .expect(testutils.checkBody(errors.RESTInvalidSecret)) .end(done); @@ -928,7 +930,7 @@ suite('post settings', function() { settings: fixtures.settings() }) .expect(testutils.checkBody(errors.RESTInvalidSecret)) - .expect(testutils.checkStatus(500)) + .expect(testutils.checkStatus(400)) .expect(testutils.checkHeaders) .end(done); }); diff --git a/test/testutils.js b/test/testutils.js index 6cfa1736..27fe2c7c 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -110,6 +110,10 @@ function checkHeaders(res) { 'X-Requested-With, Content-Type'); } +function dumpBody(res) { + console.log(JSON.stringify(res.body)); +} + function checkBody(expected) { return function(res, err) { // console.log(require('util').inspect(res.body,false,null)); @@ -165,7 +169,8 @@ module.exports = { getPrepareURL: getPrepareURL, getSignURL: getSignURL, getSubmitURL: getSubmitURL, - withDeterministicPRNG: withDeterministicPRNG + withDeterministicPRNG: withDeterministicPRNG, + dumpBody: dumpBody }; module.exports.closeLedgers = closeLedgers; diff --git a/test/trustlines-test.js b/test/trustlines-test.js index 134b9c0d..82bb986e 100644 --- a/test/trustlines-test.js +++ b/test/trustlines-test.js @@ -662,7 +662,7 @@ suite('post trustlines', function() { testPostRequest({ account: addresses.VALID, data: data, - expectedStatus: 500, + expectedStatus: 400, expectedBody: errors.RESTInvalidSecret }, done); }); diff --git a/test/unit/create-payment-tx-test.js b/test/unit/create-payment-tx-test.js index 5c7b7763..da18da73 100644 --- a/test/unit/create-payment-tx-test.js +++ b/test/unit/create-payment-tx-test.js @@ -7,27 +7,31 @@ var fixtures = require('./fixtures').restConverter; var addresses = require('./../fixtures').addresses; var createPaymentTransaction = require('./../../api/transaction/payment').createPaymentTransaction; +var ACCOUNT = addresses.VALID; suite('unit - createPaymentTransaction', function() { test('payment with IOU and issuer', function() { - var transaction = createPaymentTransaction(fixtures.paymentRest); + var transaction = createPaymentTransaction(ACCOUNT, fixtures.paymentRest); assert.deepEqual(transaction.summary(), fixtures.paymentTx); }); test('payment with XRP and no source amount', function() { - var transaction = createPaymentTransaction(fixtures.paymentRestXRP); + var transaction = createPaymentTransaction(ACCOUNT, + fixtures.paymentRestXRP); assert.deepEqual(transaction.summary(), fixtures.paymentTxXRP); assert.strictEqual(transaction.tx_json.SendMax, undefined); }); test(' payment XRP to XRP', function() { - var transaction = createPaymentTransaction(fixtures.paymentRestXRPtoXRP); + var transaction = createPaymentTransaction(ACCOUNT, + fixtures.paymentRestXRPtoXRP); assert.strictEqual(transaction.tx_json.SendMax, undefined); }); test('payment with additional flags', function() { - var transaction = createPaymentTransaction(fixtures.paymentRestComplex); + var transaction = createPaymentTransaction(ACCOUNT, + fixtures.paymentRestComplex); assert.deepEqual(transaction.summary(), fixtures.paymentTxComplex); }); @@ -38,7 +42,7 @@ suite('unit - createPaymentTransaction', function() { sourceIssuer: addresses.ISSUER, destinationIssuer: addresses.ISSUER }); - var transaction = createPaymentTransaction(payment); + var transaction = createPaymentTransaction(ACCOUNT, payment); assert.strictEqual(transaction.tx_json.SendMax, undefined); }); @@ -49,7 +53,7 @@ suite('unit - createPaymentTransaction', function() { sourceIssuer: addresses.VALID2, destinationIssuer: addresses.ISSUER2 }); - var transaction = createPaymentTransaction(payment); + var transaction = createPaymentTransaction(ACCOUNT, payment); assert.deepEqual(transaction.tx_json.SendMax, { value: '10', currency: 'USD', @@ -66,7 +70,7 @@ suite('unit - createPaymentTransaction', function() { sourceSlippage: '0.1', sourceAmount: '10' }); - var transaction = createPaymentTransaction(payment); + var transaction = createPaymentTransaction(ACCOUNT, payment); assert.deepEqual(transaction.tx_json.SendMax, { value: '10.1', currency: 'USD', @@ -80,7 +84,7 @@ suite('unit - createPaymentTransaction', function() { destinationAccount: addresses.COUNTERPARTY, sourceIssuer: '' }); - var transaction = createPaymentTransaction(payment); + var transaction = createPaymentTransaction(ACCOUNT, payment); assert.strictEqual(transaction.tx_json.SendMax, undefined); }); @@ -91,7 +95,7 @@ suite('unit - createPaymentTransaction', function() { destinationAccount: addresses.COUNTERPARTY, destinationIssuer: '' }); - var transaction = createPaymentTransaction(payment); + var transaction = createPaymentTransaction(ACCOUNT, payment); assert.strictEqual(transaction.tx_json.SendMax, undefined); }); @@ -102,7 +106,7 @@ suite('unit - createPaymentTransaction', function() { destinationAccount: addresses.COUNTERPARTY, destinationIssuer: '' }); - var transaction = createPaymentTransaction(payment); + var transaction = createPaymentTransaction(ACCOUNT, payment); assert.strictEqual(transaction.tx_json.SendMax, undefined); }); @@ -113,7 +117,7 @@ suite('unit - createPaymentTransaction', function() { destinationAccount: addresses.COUNTERPARTY, destinationIssuer: addresses.COUNTERPARTY // destination account is destination issuer }); - var transaction = createPaymentTransaction(payment); + var transaction = createPaymentTransaction(ACCOUNT, payment); assert.strictEqual(transaction.tx_json.SendMax, undefined); }); });