From b134081293c7f3db01c7c0f658111bef9209beb4 Mon Sep 17 00:00:00 2001 From: sentientwaffle Date: Mon, 31 Aug 2015 07:24:55 -0700 Subject: [PATCH 1/2] Add SuspendedPayment{Create,Finish,Cancel} * Add SusPay core tests * Rename SusPay -> SuspendedPayment (code review) * Rename cancelAfter -> allowCancelAfter * Rename suspendedPayment{Finish,Execution} --- src/api/common/schema-validator.js | 3 + .../suspended-payment-cancellation.json | 17 +++ .../schemas/suspended-payment-creation.json | 28 +++++ .../schemas/suspended-payment-execution.json | 20 +++ src/api/common/validate.js | 6 + src/api/index.js | 9 ++ src/api/ledger/parse/payment.js | 15 +-- .../parse/suspended-payment-cancellation.js | 16 +++ .../parse/suspended-payment-creation.js | 39 ++++++ .../parse/suspended-payment-execution.js | 25 ++++ src/api/ledger/parse/transaction.js | 14 ++- src/api/ledger/parse/utils.js | 14 +++ .../suspended-payment-cancellation.js | 40 ++++++ .../transaction/suspended-payment-creation.js | 57 +++++++++ .../suspended-payment-execution.js | 50 ++++++++ src/core/binformat.js | 35 +++++- src/core/remote.js | 5 +- src/core/transaction.js | 114 +++++++++++++++++- test/api-test.js | 25 ++++ test/fixtures/api/requests/index.js | 6 + ...repare-suspended-payment-cancellation.json | 4 + .../prepare-suspended-payment-creation.json | 19 +++ .../prepare-suspended-payment-execution.json | 7 ++ test/fixtures/api/responses/index.js | 6 + ...repare-suspended-payment-cancellation.json | 8 ++ .../prepare-suspended-payment-creation.json | 8 ++ .../prepare-suspended-payment-execution.json | 8 ++ test/remote-test.js | 52 +++++++- test/transaction-test.js | 114 +++++++++++++++++- 29 files changed, 733 insertions(+), 31 deletions(-) create mode 100644 src/api/common/schemas/suspended-payment-cancellation.json create mode 100644 src/api/common/schemas/suspended-payment-creation.json create mode 100644 src/api/common/schemas/suspended-payment-execution.json create mode 100644 src/api/ledger/parse/suspended-payment-cancellation.js create mode 100644 src/api/ledger/parse/suspended-payment-creation.js create mode 100644 src/api/ledger/parse/suspended-payment-execution.js create mode 100644 src/api/transaction/suspended-payment-cancellation.js create mode 100644 src/api/transaction/suspended-payment-creation.js create mode 100644 src/api/transaction/suspended-payment-execution.js create mode 100644 test/fixtures/api/requests/prepare-suspended-payment-cancellation.json create mode 100644 test/fixtures/api/requests/prepare-suspended-payment-creation.json create mode 100644 test/fixtures/api/requests/prepare-suspended-payment-execution.json create mode 100644 test/fixtures/api/responses/prepare-suspended-payment-cancellation.json create mode 100644 test/fixtures/api/responses/prepare-suspended-payment-creation.json create mode 100644 test/fixtures/api/responses/prepare-suspended-payment-execution.json diff --git a/src/api/common/schema-validator.js b/src/api/common/schema-validator.js index de884c9f..25c43a70 100644 --- a/src/api/common/schema-validator.js +++ b/src/api/common/schema-validator.js @@ -69,6 +69,9 @@ function loadSchemas() { require('./schemas/sign.json'), require('./schemas/signed-value.json'), require('./schemas/submit.json'), + require('./schemas/suspended-payment-cancellation.json'), + require('./schemas/suspended-payment-execution.json'), + require('./schemas/suspended-payment-creation.json'), require('./schemas/timestamp.json'), require('./schemas/transaction-options.json'), require('./schemas/transactions-options.json'), diff --git a/src/api/common/schemas/suspended-payment-cancellation.json b/src/api/common/schemas/suspended-payment-cancellation.json new file mode 100644 index 00000000..30e8e445 --- /dev/null +++ b/src/api/common/schemas/suspended-payment-cancellation.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "suspended-payment-cancellation", + "type": "object", + "properties": { + "memos": { + "type": "array", + "items": { + "$ref": "memo" + } + }, + "owner": {"$ref": "address"}, + "paymentSequence": {"$ref": "uint32"} + }, + "required": ["owner", "paymentSequence"], + "additionalProperties": false +} diff --git a/src/api/common/schemas/suspended-payment-creation.json b/src/api/common/schemas/suspended-payment-creation.json new file mode 100644 index 00000000..2dbf667d --- /dev/null +++ b/src/api/common/schemas/suspended-payment-creation.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "suspended-payment-creation", + "type": "object", + "properties": { + "source": {"$ref": "maxAdjustment"}, + "destination": {"$ref": "adjustment"}, + "memos": { + "type": "array", + "items": { + "$ref": "memo" + } + }, + "digest": {"$ref": "hash256"}, + "allowCancelAfter": { + "type": "integer", + "minimum": 0, + "description": "milliseconds since unix epoch" + }, + "allowExecuteAfter": { + "type": "integer", + "minimum": 0, + "description": "milliseconds since unix epoch" + } + }, + "required": ["source", "destination"], + "additionalProperties": false +} diff --git a/src/api/common/schemas/suspended-payment-execution.json b/src/api/common/schemas/suspended-payment-execution.json new file mode 100644 index 00000000..cde068a5 --- /dev/null +++ b/src/api/common/schemas/suspended-payment-execution.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "suspended-payment-execution", + "type": "object", + "properties": { + "memos": { + "type": "array", + "items": { + "$ref": "memo" + } + }, + "owner": {"$ref": "address"}, + "paymentSequence": {"$ref": "uint32"}, + "method": {"type": "integer", "minimum": 0, "maximum": 255}, + "digest": {"$ref": "hash256"}, + "proof": {"type": "string"} + }, + "required": ["owner", "paymentSequence"], + "additionalProperties": false +} diff --git a/src/api/common/validate.js b/src/api/common/validate.js index 0cb9b7c1..176e3c50 100644 --- a/src/api/common/validate.js +++ b/src/api/common/validate.js @@ -61,6 +61,12 @@ module.exports = { order: _.partial(schemaValidate, 'order'), orderbook: _.partial(schemaValidate, 'orderbook'), payment: _.partial(schemaValidate, 'payment'), + suspendedPaymentCreation: + _.partial(schemaValidate, 'suspended-payment-creation'), + suspendedPaymentExecution: + _.partial(schemaValidate, 'suspended-payment-execution'), + suspendedPaymentCancellation: + _.partial(schemaValidate, 'suspended-payment-cancellation'), pathfind: _.partial(schemaValidate, 'pathfind'), settings: _.partial(schemaValidate, 'settings'), trustline: _.partial(schemaValidate, 'trustline'), diff --git a/src/api/index.js b/src/api/index.js index 68aed81d..ddd489c9 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -23,6 +23,12 @@ const preparePayment = require('./transaction/payment'); const prepareTrustline = require('./transaction/trustline'); const prepareOrder = require('./transaction/order'); const prepareOrderCancellation = require('./transaction/ordercancellation'); +const prepareSuspendedPaymentCreation = + require('./transaction/suspended-payment-creation'); +const prepareSuspendedPaymentExecution = + require('./transaction/suspended-payment-execution'); +const prepareSuspendedPaymentCancellation = + require('./transaction/suspended-payment-cancellation'); const prepareSettings = require('./transaction/settings'); const sign = require('./transaction/sign'); const submit = require('./transaction/submit'); @@ -61,6 +67,9 @@ RippleAPI.prototype = { prepareTrustline, prepareOrder, prepareOrderCancellation, + prepareSuspendedPaymentCreation, + prepareSuspendedPaymentExecution, + prepareSuspendedPaymentCancellation, prepareSettings, sign, submit, diff --git a/src/api/ledger/parse/payment.js b/src/api/ledger/parse/payment.js index 0dfe438b..55f6917d 100644 --- a/src/api/ledger/parse/payment.js +++ b/src/api/ledger/parse/payment.js @@ -18,19 +18,6 @@ function isQualityLimited(tx) { return (tx.Flags & Transaction.flags.Payment.LimitQuality) !== 0; } -function parsePaymentMemos(tx) { - if (!Array.isArray(tx.Memos) || tx.Memos.length === 0) { - return undefined; - } - return tx.Memos.map((m) => { - return utils.removeUndefined({ - type: m.Memo.parsed_memo_type, - format: m.Memo.parsed_memo_format, - data: m.Memo.parsed_memo_data - }); - }); -} - function removeGenericCounterparty(amount, address) { return amount.counterparty === address ? _.omit(amount, 'counterparty') : amount; @@ -55,7 +42,7 @@ function parsePayment(tx: Object): Object { return utils.removeUndefined({ source: utils.removeUndefined(source), destination: utils.removeUndefined(destination), - memos: parsePaymentMemos(tx), + memos: utils.parseMemos(tx), invoiceID: tx.InvoiceID, paths: tx.Paths ? JSON.stringify(tx.Paths) : undefined, allowPartialPayment: isPartialPayment(tx) || undefined, diff --git a/src/api/ledger/parse/suspended-payment-cancellation.js b/src/api/ledger/parse/suspended-payment-cancellation.js new file mode 100644 index 00000000..ea1295f0 --- /dev/null +++ b/src/api/ledger/parse/suspended-payment-cancellation.js @@ -0,0 +1,16 @@ +/* @flow */ +'use strict'; +const assert = require('assert'); +const utils = require('./utils'); + +function parseSuspendedPaymentCancellation(tx: Object): Object { + assert(tx.TransactionType === 'SuspendedPaymentCancel'); + + return utils.removeUndefined({ + memos: utils.parseMemos(tx), + owner: tx.Owner, + paymentSequence: tx.OfferSequence + }); +} + +module.exports = parseSuspendedPaymentCancellation; diff --git a/src/api/ledger/parse/suspended-payment-creation.js b/src/api/ledger/parse/suspended-payment-creation.js new file mode 100644 index 00000000..7b91b265 --- /dev/null +++ b/src/api/ledger/parse/suspended-payment-creation.js @@ -0,0 +1,39 @@ +/* @flow */ +'use strict'; +const _ = require('lodash'); +const assert = require('assert'); +const utils = require('./utils'); +const parseAmount = require('./amount'); + +function removeGenericCounterparty(amount, address) { + return amount.counterparty === address ? + _.omit(amount, 'counterparty') : amount; +} + +function parseSuspendedPaymentCreation(tx: Object): Object { + assert(tx.TransactionType === 'SuspendedPaymentCreate'); + + const source = { + address: tx.Account, + maxAmount: removeGenericCounterparty( + parseAmount(tx.SendMax || tx.Amount), tx.Account), + tag: tx.SourceTag + }; + + const destination = { + address: tx.Destination, + amount: removeGenericCounterparty(parseAmount(tx.Amount), tx.Destination), + tag: tx.DestinationTag + }; + + return utils.removeUndefined({ + source: utils.removeUndefined(source), + destination: utils.removeUndefined(destination), + memos: utils.parseMemos(tx), + digest: tx.Digest, + allowCancelAfter: tx.CancelAfter, + allowExecuteAfter: tx.FinishAfter + }); +} + +module.exports = parseSuspendedPaymentCreation; diff --git a/src/api/ledger/parse/suspended-payment-execution.js b/src/api/ledger/parse/suspended-payment-execution.js new file mode 100644 index 00000000..71159d2c --- /dev/null +++ b/src/api/ledger/parse/suspended-payment-execution.js @@ -0,0 +1,25 @@ +/* @flow */ +'use strict'; +const assert = require('assert'); +const sjclcodec = require('sjcl-codec'); +const utils = require('./utils'); + +function convertHexToString(hexString) { + const bits = sjclcodec.hex.toBits(hexString); + return sjclcodec.utf8String.fromBits(bits); +} + +function parseSuspendedPaymentExecution(tx: Object): Object { + assert(tx.TransactionType === 'SuspendedPaymentFinish'); + + return utils.removeUndefined({ + memos: utils.parseMemos(tx), + owner: tx.Owner, + paymentSequence: tx.OfferSequence, + method: tx.Method, + digest: tx.Digest, + proof: tx.Proof ? convertHexToString(tx.Proof) : undefined + }); +} + +module.exports = parseSuspendedPaymentExecution; diff --git a/src/api/ledger/parse/transaction.js b/src/api/ledger/parse/transaction.js index 17cb2ac6..0043ebd3 100644 --- a/src/api/ledger/parse/transaction.js +++ b/src/api/ledger/parse/transaction.js @@ -7,6 +7,10 @@ const parseTrustline = require('./trustline'); const parseOrder = require('./order'); const parseOrderCancellation = require('./cancellation'); const parseSettings = require('./settings'); +const parseSuspendedPaymentCreation = require('./suspended-payment-creation'); +const parseSuspendedPaymentExecution = require('./suspended-payment-execution'); +const parseSuspendedPaymentCancellation = + require('./suspended-payment-cancellation'); function parseTransactionType(type) { const mapping = { @@ -15,7 +19,10 @@ function parseTransactionType(type) { OfferCreate: 'order', OfferCancel: 'orderCancellation', AccountSet: 'settings', - SetRegularKey: 'settings' + SetRegularKey: 'settings', + SuspendedPaymentCreate: 'suspendedPaymentCreation', + SuspendedPaymentFinish: 'suspendedPaymentExecution', + SuspendedPaymentCancel: 'suspendedPaymentCancellation' }; return mapping[type] || null; } @@ -27,7 +34,10 @@ function parseTransaction(tx: Object): Object { 'trustline': parseTrustline, 'order': parseOrder, 'orderCancellation': parseOrderCancellation, - 'settings': parseSettings + 'settings': parseSettings, + 'suspendedPaymentCreation': parseSuspendedPaymentCreation, + 'suspendedPaymentExecution': parseSuspendedPaymentExecution, + 'suspendedPaymentCancellation': parseSuspendedPaymentCancellation }; const parser = mapping[type]; assert(parser !== undefined, 'Unrecognized transaction type'); diff --git a/src/api/ledger/parse/utils.js b/src/api/ledger/parse/utils.js index 29a761cb..bf5d34c7 100644 --- a/src/api/ledger/parse/utils.js +++ b/src/api/ledger/parse/utils.js @@ -67,8 +67,22 @@ function parseOutcome(tx: Object): ?Object { }; } +function parseMemos(tx: Object): ?Array { + if (!Array.isArray(tx.Memos) || tx.Memos.length === 0) { + return undefined; + } + return tx.Memos.map((m) => { + return removeUndefined({ + type: m.Memo.parsed_memo_type, + format: m.Memo.parsed_memo_format, + data: m.Memo.parsed_memo_data + }); + }); +} + module.exports = { parseOutcome, + parseMemos, removeUndefined, adjustQualityForXRP, dropsToXrp: utils.common.dropsToXrp, diff --git a/src/api/transaction/suspended-payment-cancellation.js b/src/api/transaction/suspended-payment-cancellation.js new file mode 100644 index 00000000..3748a0e5 --- /dev/null +++ b/src/api/transaction/suspended-payment-cancellation.js @@ -0,0 +1,40 @@ +/* @flow */ +'use strict'; +const _ = require('lodash'); +const utils = require('./utils'); +const validate = utils.common.validate; +const Transaction = utils.common.core.Transaction; + +function createSuspendedPaymentCancellationTransaction(account, payment) { + 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) + ); + } + return transaction; +} + +function prepareSuspendedPaymentCancellationAsync(account, payment, +instructions, callback) { + const transaction = + createSuspendedPaymentCancellationTransaction(account, payment); + utils.prepareTransaction(transaction, this.remote, instructions, callback); +} + +function prepareSuspendedPaymentCancellation(account: string, payment: Object, +instructions = {}) { + return utils.promisify(prepareSuspendedPaymentCancellationAsync) + .call(this, account, payment, instructions); +} + +module.exports = prepareSuspendedPaymentCancellation; diff --git a/src/api/transaction/suspended-payment-creation.js b/src/api/transaction/suspended-payment-creation.js new file mode 100644 index 00000000..f9b52659 --- /dev/null +++ b/src/api/transaction/suspended-payment-creation.js @@ -0,0 +1,57 @@ +/* @flow */ +'use strict'; +const _ = require('lodash'); +const utils = require('./utils'); +const validate = utils.common.validate; +const toRippledAmount = utils.common.toRippledAmount; +const Transaction = utils.common.core.Transaction; + +function createSuspendedPaymentCreationTransaction(account, payment) { + validate.address(account); + validate.suspendedPaymentCreation(payment); + + const transaction = new Transaction(); + transaction.suspendedPaymentCreate({ + account: account, + destination: payment.destination.address, + amount: toRippledAmount(payment.destination.amount) + }); + + if (payment.digest) { + transaction.setDigest(payment.digest); + } + if (payment.allowCancelAfter) { + transaction.setAllowCancelAfter(payment.allowCancelAfter); + } + if (payment.allowExecuteAfter) { + transaction.setAllowExecuteAfter(payment.allowExecuteAfter); + } + + if (payment.source.tag) { + transaction.sourceTag(payment.source.tag); + } + if (payment.destination.tag) { + transaction.destinationTag(payment.destination.tag); + } + if (payment.memos) { + _.forEach(payment.memos, memo => + transaction.addMemo(memo.type, memo.format, memo.data) + ); + } + return transaction; +} + +function prepareSuspendedPaymentCreationAsync(account, payment, instructions, +callback) { + const transaction = + createSuspendedPaymentCreationTransaction(account, payment); + utils.prepareTransaction(transaction, this.remote, instructions, callback); +} + +function prepareSuspendedPaymentCreation(account: string, payment: Object, +instructions = {}) { + return utils.promisify(prepareSuspendedPaymentCreationAsync) + .call(this, account, payment, instructions); +} + +module.exports = prepareSuspendedPaymentCreation; diff --git a/src/api/transaction/suspended-payment-execution.js b/src/api/transaction/suspended-payment-execution.js new file mode 100644 index 00000000..c8aab156 --- /dev/null +++ b/src/api/transaction/suspended-payment-execution.js @@ -0,0 +1,50 @@ +/* @flow */ +'use strict'; +const _ = require('lodash'); +const utils = require('./utils'); +const validate = utils.common.validate; +const Transaction = utils.common.core.Transaction; + +function createSuspendedPaymentExecutionTransaction(account, payment) { + validate.address(account); + validate.suspendedPaymentExecution(payment); + + const transaction = new Transaction(); + transaction.suspendedPaymentFinish({ + account: account, + owner: payment.owner, + paymentSequence: payment.paymentSequence + }); + + if (payment.method) { + transaction.setMethod(payment.method); + } + if (payment.digest) { + transaction.setDigest(payment.digest); + } + if (payment.proof) { + transaction.setProof(payment.proof); + } + + if (payment.memos) { + _.forEach(payment.memos, memo => + transaction.addMemo(memo.type, memo.format, memo.data) + ); + } + return transaction; +} + +function prepareSuspendedPaymentExecutionAsync(account, payment, instructions, +callback) { + const transaction = + createSuspendedPaymentExecutionTransaction(account, payment); + utils.prepareTransaction(transaction, this.remote, instructions, callback); +} + +function prepareSuspendedPaymentExecution(account: string, payment: Object, +instructions = {}) { + return utils.promisify(prepareSuspendedPaymentExecutionAsync) + .call(this, account, payment, instructions); +} + +module.exports = prepareSuspendedPaymentExecution; diff --git a/src/core/binformat.js b/src/core/binformat.js index 9211855c..c3e44658 100644 --- a/src/core/binformat.js +++ b/src/core/binformat.js @@ -92,6 +92,8 @@ const FIELDS_MAP = exports.fields = { 33: 'SetFlag', 34: 'ClearFlag', 35: 'SignerQuorum', + 36: 'CancelAfter', + 37: 'FinishAfter', 38: 'SignerListID' }, 3: { // Int64 @@ -121,7 +123,8 @@ const FIELDS_MAP = exports.fields = { 17: 'InvoiceID', 18: 'Nickname', 19: 'Amendment', - 20: 'TicketID' + 20: 'TicketID', + 21: 'Digest' }, 6: { // Amount 1: 'Amount', @@ -151,7 +154,8 @@ const FIELDS_MAP = exports.fields = { 11: 'CreateCode', 12: 'MemoType', 13: 'MemoData', - 14: 'MemoFormat' + 14: 'MemoFormat', + 17: 'Proof' }, 8: { // Account 1: 'Account', @@ -190,7 +194,7 @@ const FIELDS_MAP = exports.fields = { // Uncommon types 16: { // Int8 1: 'CloseResolution', - 2: 'TemplateEntryType', + 2: 'Method', 3: 'TransactionResult' }, 17: { // Hash160 @@ -217,9 +221,9 @@ Object.keys(FIELDS_MAP).forEach(function(k1) { }); }); -const REQUIRED = exports.REQUIRED = 0, - OPTIONAL = exports.OPTIONAL = 1, - DEFAULT = exports.DEFAULT = 2; +const REQUIRED = exports.REQUIRED = 0; +const OPTIONAL = exports.OPTIONAL = 1; +const DEFAULT = exports.DEFAULT = 2; const base = [ [ 'TransactionType' , REQUIRED ], @@ -308,6 +312,25 @@ exports.tx = { SignerListSet: [12].concat(base, [ ['SignerQuorum', REQUIRED], ['SignerEntries', OPTIONAL] + ]), + SuspendedPaymentCreate: [1].concat(base, [ + [ 'Destination' , REQUIRED ], + [ 'Amount' , REQUIRED ], + [ 'Digest' , OPTIONAL ], + [ 'CancelAfter' , OPTIONAL ], + [ 'FinishAfter' , OPTIONAL ], + [ 'DestinationTag' , OPTIONAL ] + ]), + SuspendedPaymentFinish: [2].concat(base, [ + [ 'Owner' , REQUIRED ], + [ 'OfferSequence' , REQUIRED ], + [ 'Method' , OPTIONAL ], + [ 'Digest' , OPTIONAL ], + [ 'Proof' , OPTIONAL ] + ]), + SuspendedPaymentCancel: [4].concat(base, [ + [ 'Owner' , REQUIRED ], + [ 'OfferSequence' , REQUIRED ] ]) }; diff --git a/src/core/remote.js b/src/core/remote.js index 3ed74b42..76fcf4b4 100644 --- a/src/core/remote.js +++ b/src/core/remote.js @@ -2276,7 +2276,10 @@ Remote.prototype.createTransaction = function(type, options = {}) { OfferCreate: transaction.offerCreate, OfferCancel: transaction.offerCancel, SetRegularKey: transaction.setRegularKey, - SignerListSet: transaction.setSignerList + SignerListSet: transaction.setSignerList, + SuspendedPaymentCreate: transaction.suspendedPaymentCreate, + SuspendedPaymentFinish: transaction.suspendedPaymentFinish, + SuspendedPaymentCancel: transaction.suspendedPaymentCancel }; const transactionConstructor = constructorMap[type]; diff --git a/src/core/transaction.js b/src/core/transaction.js index c1d3a5fa..3685c17f 100644 --- a/src/core/transaction.js +++ b/src/core/transaction.js @@ -808,6 +808,11 @@ Transaction.prototype.setFlags = function(flags) { return this; }; +function convertStringToHex(string) { + const utf8String = sjclcodec.utf8String.toBits(string); + return sjclcodec.hex.fromBits(utf8String).toUpperCase(); +} + /** * Add a Memo to transaction. * @@ -834,11 +839,6 @@ Transaction.prototype.addMemo = function(options_) { }; } - function convertStringToHex(string) { - const utf8String = sjclcodec.utf8String.toBits(string); - return sjclcodec.hex.fromBits(utf8String).toUpperCase(); - } - const memo = {}; const memoRegex = Transaction.MEMO_REGEX; let memoType = options.memoType; @@ -1501,6 +1501,110 @@ Transaction.prototype.summary = function() { return txSummary; }; +/** + * Construct a 'SuspendedPaymentCreate' transaction + * + * Relevant setters: + * - setSourceTag() + * - setFlags() + * - setDigest() + * - setAllowCancelAfter() + * - setAllowExecuteAfter() + * + * @param {String} options.account source account + * @param {String} options.destination account + * @param {Amount} options.amount payment amount + */ + +Transaction.prototype.suspendedPaymentCreate = function(options) { + this.setType('SuspendedPaymentCreate'); + this.setAccount(options.account); + this.setDestination(options.destination); + this.setAmount(options.amount); + return this; +}; + +/** + * Construct a 'SuspendedPaymentFinish' transaction + * + * Relevant setters: + * - setSourceTag() + * - setFlags() + * - setOwner() + * - setOfferSequence() + * - setMethod() + * - setDigest() + * - setProof() + * + * @param {String} options.account source account + * @param {String} options.owner SuspendedPaymentCreate's Account + * @param {Integer} options.paymentSequence SuspendedPaymentCreate's Sequence + */ + +Transaction.prototype.suspendedPaymentFinish = function(options) { + this.setType('SuspendedPaymentFinish'); + this.setAccount(options.account); + this.setOwner(options.owner); + this.setOfferSequence(options.paymentSequence); + return this; +}; + +/** + * Construct a 'SuspendedPaymentCancel' transaction + * + * Relevant setters: + * - setSourceTag() + * - setFlags() + * - setOwner() + * - setOfferSequence() + * + * @param {String} options.account source account + * @param {String} options.owner SuspendedPaymentCreate's Account + * @param {Integer} options.paymentSequence SuspendedPaymentCreate's Sequence + */ + +Transaction.prototype.suspendedPaymentCancel = function(options) { + this.setType('SuspendedPaymentCancel'); + this.setAccount(options.account); + this.setOwner(options.owner); + this.setOfferSequence(options.paymentSequence); + return this; +}; + +Transaction.prototype.setDigest = function(digest) { + return this._setHash256('Digest', digest); +}; + +Transaction.prototype.setAllowCancelAfter = function(after) { + return this._setUInt32('CancelAfter', utils.time.toRipple(after)); +}; + +Transaction.prototype.setAllowExecuteAfter = function(after) { + return this._setUInt32('FinishAfter', utils.time.toRipple(after)); +}; + +Transaction.prototype.setOwner = function(owner) { + return this._setAccount('Owner', owner); +}; + +Transaction.prototype.setMethod = function(method) { + return this._setUInt8('Method', method); +}; + +Transaction.prototype.setProof = function(proof) { + this.tx_json.Proof = convertStringToHex(proof); + return this; +}; + +Transaction.prototype._setUInt8 = function(name, value) { + const isValidUInt8 = typeof value === 'number' && value >= 0 && value < 256; + if (!isValidUInt8) { + throw new Error(name + ' must be a valid UInt8'); + } + this.tx_json[name] = value; + return this; +}; + Transaction.prototype.setSigners = function(signers) { if (_.isArray(signers)) { this.tx_json.Signers = signers; diff --git a/test/api-test.js b/test/api-test.js index e0226965..b775529f 100644 --- a/test/api-test.js +++ b/test/api-test.js @@ -143,6 +143,31 @@ describe('RippleAPI', function() { 'prepare')); }); + it('prepareSuspendedPaymentCreation', function() { + const localInstructions = _.defaults({ + maxFee: '0.000012' + }, instructions); + return this.api.prepareSuspendedPaymentCreation( + address, requests.prepareSuspendedPaymentCreation, + localInstructions).then( + _.partial(checkResult, responses.prepareSuspendedPaymentCreation, + 'prepare')); + }); + + it('prepareSuspendedPaymentExecution', function() { + return this.api.prepareSuspendedPaymentExecution( + address, requests.prepareSuspendedPaymentExecution, instructions).then( + _.partial(checkResult, responses.prepareSuspendedPaymentExecution, + 'prepare')); + }); + + it('prepareSuspendedPaymentCancellation', function() { + return this.api.prepareSuspendedPaymentCancellation( + address, requests.prepareSuspendedPaymentCancellation, instructions).then( + _.partial(checkResult, responses.prepareSuspendedPaymentCancellation, + 'prepare')); + }); + it('sign', function() { const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'; const result = this.api.sign(requests.sign.txJSON, secret); diff --git a/test/fixtures/api/requests/index.js b/test/fixtures/api/requests/index.js index dfe28b95..6ef8dc86 100644 --- a/test/fixtures/api/requests/index.js +++ b/test/fixtures/api/requests/index.js @@ -7,6 +7,12 @@ module.exports = { preparePaymentAllOptions: require('./prepare-payment-all-options'), preparePaymentNoCounterparty: require('./prepare-payment-no-counterparty'), prepareSettings: require('./prepare-settings'), + prepareSuspendedPaymentCreation: + require('./prepare-suspended-payment-creation'), + prepareSuspendedPaymentExecution: + require('./prepare-suspended-payment-execution'), + prepareSuspendedPaymentCancellation: + require('./prepare-suspended-payment-cancellation'), prepareTrustline: { simple: require('./prepare-trustline-simple'), complex: require('./prepare-trustline') diff --git a/test/fixtures/api/requests/prepare-suspended-payment-cancellation.json b/test/fixtures/api/requests/prepare-suspended-payment-cancellation.json new file mode 100644 index 00000000..9925c002 --- /dev/null +++ b/test/fixtures/api/requests/prepare-suspended-payment-cancellation.json @@ -0,0 +1,4 @@ +{ + "owner": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "paymentSequence": 1234 +} diff --git a/test/fixtures/api/requests/prepare-suspended-payment-creation.json b/test/fixtures/api/requests/prepare-suspended-payment-creation.json new file mode 100644 index 00000000..7e6985ea --- /dev/null +++ b/test/fixtures/api/requests/prepare-suspended-payment-creation.json @@ -0,0 +1,19 @@ +{ + "source": { + "address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "maxAmount": { + "value": "0.01", + "currency": "USD", + "counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM" + } + }, + "destination": { + "address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo", + "amount": { + "value": "0.01", + "currency": "USD", + "counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM" + } + }, + "allowCancelAfter": 1440694329002 +} diff --git a/test/fixtures/api/requests/prepare-suspended-payment-execution.json b/test/fixtures/api/requests/prepare-suspended-payment-execution.json new file mode 100644 index 00000000..9c1d227f --- /dev/null +++ b/test/fixtures/api/requests/prepare-suspended-payment-execution.json @@ -0,0 +1,7 @@ +{ + "owner": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "paymentSequence": 1234, + "method": 1, + "digest": "8F434346648F6B96DF89DDA901C5176B10A6D83961DD3C1AC88B59B2DC327AA4", + "proof": "whatever" +} diff --git a/test/fixtures/api/responses/index.js b/test/fixtures/api/responses/index.js index 87d87f97..d33a28b0 100644 --- a/test/fixtures/api/responses/index.js +++ b/test/fixtures/api/responses/index.js @@ -47,6 +47,12 @@ module.exports = { setTransferRate: require('./prepare-settings-set-transfer-rate.json'), fieldClear: require('./prepare-settings-field-clear.json') }, + prepareSuspendedPaymentCreation: + require('./prepare-suspended-payment-creation'), + prepareSuspendedPaymentExecution: + require('./prepare-suspended-payment-execution'), + prepareSuspendedPaymentCancellation: + require('./prepare-suspended-payment-cancellation'), prepareTrustline: { simple: require('./prepare-trustline-simple.json'), complex: require('./prepare-trustline.json') diff --git a/test/fixtures/api/responses/prepare-suspended-payment-cancellation.json b/test/fixtures/api/responses/prepare-suspended-payment-cancellation.json new file mode 100644 index 00000000..e20055af --- /dev/null +++ b/test/fixtures/api/responses/prepare-suspended-payment-cancellation.json @@ -0,0 +1,8 @@ +{ + "txJSON": "{\"Flags\":0,\"TransactionType\":\"SuspendedPaymentCancel\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Owner\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":1234,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", + "instructions": { + "fee": "12", + "sequence": 23, + "maxLedgerVersion": 8820051 + } +} diff --git a/test/fixtures/api/responses/prepare-suspended-payment-creation.json b/test/fixtures/api/responses/prepare-suspended-payment-creation.json new file mode 100644 index 00000000..9b1ae3ff --- /dev/null +++ b/test/fixtures/api/responses/prepare-suspended-payment-creation.json @@ -0,0 +1,8 @@ +{ + "txJSON": "{\"Flags\":0,\"TransactionType\":\"SuspendedPaymentCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"CancelAfter\":494009529,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", + "instructions": { + "fee": "12", + "sequence": 23, + "maxLedgerVersion": 8820051 + } +} diff --git a/test/fixtures/api/responses/prepare-suspended-payment-execution.json b/test/fixtures/api/responses/prepare-suspended-payment-execution.json new file mode 100644 index 00000000..5437dd66 --- /dev/null +++ b/test/fixtures/api/responses/prepare-suspended-payment-execution.json @@ -0,0 +1,8 @@ +{ + "txJSON": "{\"Flags\":0,\"TransactionType\":\"SuspendedPaymentFinish\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Owner\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":1234,\"Method\":1,\"Digest\":\"8F434346648F6B96DF89DDA901C5176B10A6D83961DD3C1AC88B59B2DC327AA4\",\"Proof\":\"7768617465766572\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", + "instructions": { + "fee": "12", + "sequence": 23, + "maxLedgerVersion": 8820051 + } +} diff --git a/test/remote-test.js b/test/remote-test.js index 4778bc16..fe659392 100644 --- a/test/remote-test.js +++ b/test/remote-test.js @@ -1,4 +1,4 @@ -/* eslint-disable no-new, max-len, no-comma-dangle, indent */ +/* eslint-disable no-new, max-len, no-comma-dangle, indent, max-nested-callbacks */ 'use strict'; @@ -14,7 +14,9 @@ const Amount = require('ripple-lib').Amount; const PathFind = require('ripple-lib')._test.PathFind; const Log = require('ripple-lib')._test.Log; -let options, remote, callback; +let options; +let remote; +let callback; const ADDRESS = 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS'; const LEDGER_INDEX = 9592219; @@ -2095,4 +2097,50 @@ describe('Remote', function() { ] }); }); + + it('Construct SuspendedPaymentCreate transaction', function() { + const tx = remote.createTransaction('SuspendedPaymentCreate', { + account: TX_JSON.Account, + destination: TX_JSON.Destination, + amount: TX_JSON.Amount + }); + + assert.deepEqual(tx.tx_json, { + Flags: 0, + TransactionType: 'SuspendedPaymentCreate', + Account: TX_JSON.Account, + Destination: TX_JSON.Destination, + Amount: TX_JSON.Amount + }); + }); + it('Construct SuspendedPaymentFinish transaction', function() { + const tx = remote.createTransaction('SuspendedPaymentFinish', { + account: TX_JSON.Account, + owner: TX_JSON.Account, + paymentSequence: 1234 + }); + + assert.deepEqual(tx.tx_json, { + Flags: 0, + TransactionType: 'SuspendedPaymentFinish', + Account: TX_JSON.Account, + Owner: TX_JSON.Account, + OfferSequence: 1234 + }); + }); + it('Construct SuspendedPaymentCancel transaction', function() { + const tx = remote.createTransaction('SuspendedPaymentCancel', { + account: TX_JSON.Account, + owner: TX_JSON.Account, + paymentSequence: 1234 + }); + + assert.deepEqual(tx.tx_json, { + Flags: 0, + TransactionType: 'SuspendedPaymentCancel', + Account: TX_JSON.Account, + Owner: TX_JSON.Account, + OfferSequence: 1234 + }); + }); }); diff --git a/test/transaction-test.js b/test/transaction-test.js index 38654bcf..94b9d65f 100644 --- a/test/transaction-test.js +++ b/test/transaction-test.js @@ -1,4 +1,4 @@ -/* eslint-disable max-len */ +/* eslint-disable max-len, max-nested-callbacks */ 'use strict'; @@ -2182,4 +2182,116 @@ describe('Transaction', function() { {Signer: s1} ]); }); + + it('Construct SuspendedPaymentCreate transaction', function() { + const transaction = new Transaction().suspendedPaymentCreate({ + account: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', + destination: 'r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe', + amount: '1/USD/r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe' + }); + + assert(transaction instanceof Transaction); + assert.deepEqual(transaction.tx_json, { + Flags: 0, + TransactionType: 'SuspendedPaymentCreate', + Account: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', + Destination: 'r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe', + Amount: { + value: '1', + currency: 'USD', + issuer: 'r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe' + } + }); + }); + + it('Set Digest', function() { + const transaction = new Transaction(); + assert.strictEqual(transaction.tx_json.Digest, undefined); + transaction.setType('SuspendedPaymentCreate'); + assert.throws(function() { + transaction.setDigest('foo'); + }, /Error: Digest must be a valid Hash256/); + + const hash = '8F434346648F6B96DF89DDA901C5176B10A6D83961DD3C1AC88B59B2DC327AA4'; + transaction.setDigest(hash); + assert.strictEqual(transaction.tx_json.Digest, hash); + }); + + it('Set CancelAfter', function() { + const transaction = new Transaction(); + assert.strictEqual(transaction.tx_json.CancelAfter, undefined); + transaction.setType('SuspendedPaymentCreate'); + assert.throws(function() { + transaction.setAllowCancelAfter('foo'); + }, /Error: CancelAfter must be a valid UInt32/); + + transaction.setAllowCancelAfter(1441043377523); + assert.strictEqual(transaction.tx_json.CancelAfter, 494358578); + }); + + it('Set FinishAfter', function() { + const transaction = new Transaction(); + assert.strictEqual(transaction.tx_json.FinishAfter, undefined); + transaction.setType('SuspendedPaymentCreate'); + assert.throws(function() { + transaction.setAllowExecuteAfter('foo'); + }, /Error: FinishAfter must be a valid UInt32/); + + transaction.setAllowExecuteAfter(1441043377523); + assert.strictEqual(transaction.tx_json.FinishAfter, 494358578); + }); + + it('Construct SuspendedPaymentFinish transaction', function() { + const transaction = new Transaction().suspendedPaymentFinish({ + account: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', + owner: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', + paymentSequence: 1234 + }); + + assert(transaction instanceof Transaction); + assert.deepEqual(transaction.tx_json, { + Flags: 0, + TransactionType: 'SuspendedPaymentFinish', + Account: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', + Owner: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', + OfferSequence: 1234 + }); + }); + + it('Set Method', function() { + const transaction = new Transaction(); + assert.strictEqual(transaction.tx_json.Method, undefined); + transaction.setType('SuspendedPaymentFinish'); + assert.throws(function() { + transaction.setMethod('foo'); + }, /Error: Method must be a valid UInt8/); + + transaction.setMethod(1); + assert.strictEqual(transaction.tx_json.Method, 1); + }); + + it('Set Proof', function() { + const transaction = new Transaction(); + assert.strictEqual(transaction.tx_json.Proof, undefined); + transaction.setType('SuspendedPaymentFinish'); + transaction.setProof('foo'); + assert.strictEqual(transaction.tx_json.Proof, '666F6F'); + }); + + it('Construct SuspendedPaymentCancel transaction', function() { + const transaction = new Transaction().suspendedPaymentCancel({ + account: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', + owner: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', + paymentSequence: 1234 + }); + + assert(transaction instanceof Transaction); + assert.deepEqual(transaction.tx_json, { + Flags: 0, + TransactionType: 'SuspendedPaymentCancel', + Account: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', + Owner: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', + OfferSequence: 1234 + }); + }); }); From 2f6d25ed01548c440c4e667abe171fb0abcd3e56 Mon Sep 17 00:00:00 2001 From: sentientwaffle Date: Mon, 31 Aug 2015 11:29:07 -0700 Subject: [PATCH 2/2] lint --- src/core/binformat.js | 118 +++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/src/core/binformat.js b/src/core/binformat.js index c3e44658..51929613 100644 --- a/src/core/binformat.js +++ b/src/core/binformat.js @@ -217,7 +217,7 @@ const INVERSE_FIELDS_MAP = exports.fieldsInverseMap = { }; Object.keys(FIELDS_MAP).forEach(function(k1) { Object.keys(FIELDS_MAP[k1]).forEach(function(k2) { - INVERSE_FIELDS_MAP[FIELDS_MAP[k1][k2]] = [ Number(k1), Number(k2) ]; + INVERSE_FIELDS_MAP[FIELDS_MAP[k1][k2]] = [Number(k1), Number(k2)]; }); }); @@ -243,94 +243,94 @@ const base = [ exports.tx = { AccountSet: [3].concat(base, [ - [ 'EmailHash' , OPTIONAL ], - [ 'WalletLocator' , OPTIONAL ], - [ 'WalletSize' , OPTIONAL ], - [ 'MessageKey' , OPTIONAL ], - [ 'Domain' , OPTIONAL ], - [ 'TransferRate' , OPTIONAL ], - [ 'SetFlag' , OPTIONAL ], - [ 'ClearFlag' , OPTIONAL ] + ['EmailHash' , OPTIONAL], + ['WalletLocator' , OPTIONAL], + ['WalletSize' , OPTIONAL], + ['MessageKey' , OPTIONAL], + ['Domain' , OPTIONAL], + ['TransferRate' , OPTIONAL], + ['SetFlag' , OPTIONAL], + ['ClearFlag' , OPTIONAL] ]), TrustSet: [20].concat(base, [ - [ 'LimitAmount' , OPTIONAL ], - [ 'QualityIn' , OPTIONAL ], - [ 'QualityOut' , OPTIONAL ] + ['LimitAmount' , OPTIONAL], + ['QualityIn' , OPTIONAL], + ['QualityOut' , OPTIONAL] ]), OfferCreate: [7].concat(base, [ - [ 'TakerPays' , REQUIRED ], - [ 'TakerGets' , REQUIRED ], - [ 'Expiration' , OPTIONAL ], - [ 'OfferSequence' , OPTIONAL ] + ['TakerPays' , REQUIRED], + ['TakerGets' , REQUIRED], + ['Expiration' , OPTIONAL], + ['OfferSequence' , OPTIONAL] ]), OfferCancel: [8].concat(base, [ - [ 'OfferSequence' , REQUIRED ] + ['OfferSequence' , REQUIRED] ]), SetRegularKey: [5].concat(base, [ - [ 'RegularKey' , OPTIONAL ] + ['RegularKey' , OPTIONAL] ]), Payment: [0].concat(base, [ - [ 'Destination' , REQUIRED ], - [ 'Amount' , REQUIRED ], - [ 'SendMax' , OPTIONAL ], - [ 'Paths' , DEFAULT ], - [ 'InvoiceID' , OPTIONAL ], - [ 'DestinationTag' , OPTIONAL ] + ['Destination' , REQUIRED], + ['Amount' , REQUIRED], + ['SendMax' , OPTIONAL], + ['Paths' , DEFAULT], + ['InvoiceID' , OPTIONAL], + ['DestinationTag' , OPTIONAL] ]), Contract: [9].concat(base, [ - [ 'Expiration' , REQUIRED ], - [ 'BondAmount' , REQUIRED ], - [ 'StampEscrow' , REQUIRED ], - [ 'RippleEscrow' , REQUIRED ], - [ 'CreateCode' , OPTIONAL ], - [ 'FundCode' , OPTIONAL ], - [ 'RemoveCode' , OPTIONAL ], - [ 'ExpireCode' , OPTIONAL ] + ['Expiration' , REQUIRED], + ['BondAmount' , REQUIRED], + ['StampEscrow' , REQUIRED], + ['RippleEscrow' , REQUIRED], + ['CreateCode' , OPTIONAL], + ['FundCode' , OPTIONAL], + ['RemoveCode' , OPTIONAL], + ['ExpireCode' , OPTIONAL] ]), RemoveContract: [10].concat(base, [ - [ 'Target' , REQUIRED ] + ['Target' , REQUIRED] ]), EnableFeature: [100].concat(base, [ - [ 'Feature' , REQUIRED ] + ['Feature' , REQUIRED] ]), EnableAmendment: [100].concat(base, [ - [ 'Amendment' , REQUIRED ] + ['Amendment' , REQUIRED] ]), SetFee: [101].concat(base, [ - [ 'BaseFee' , REQUIRED ], - [ 'ReferenceFeeUnits' , REQUIRED ], - [ 'ReserveBase' , REQUIRED ], - [ 'ReserveIncrement' , REQUIRED ] + ['BaseFee' , REQUIRED], + ['ReferenceFeeUnits' , REQUIRED], + ['ReserveBase' , REQUIRED], + ['ReserveIncrement' , REQUIRED] ]), TicketCreate: [10].concat(base, [ - [ 'Target' , OPTIONAL ], - [ 'Expiration' , OPTIONAL ] + ['Target' , OPTIONAL], + ['Expiration' , OPTIONAL] ]), TicketCancel: [11].concat(base, [ - [ 'TicketID' , REQUIRED ] + ['TicketID' , REQUIRED] ]), SignerListSet: [12].concat(base, [ ['SignerQuorum', REQUIRED], ['SignerEntries', OPTIONAL] ]), SuspendedPaymentCreate: [1].concat(base, [ - [ 'Destination' , REQUIRED ], - [ 'Amount' , REQUIRED ], - [ 'Digest' , OPTIONAL ], - [ 'CancelAfter' , OPTIONAL ], - [ 'FinishAfter' , OPTIONAL ], - [ 'DestinationTag' , OPTIONAL ] + ['Destination' , REQUIRED], + ['Amount' , REQUIRED], + ['Digest' , OPTIONAL], + ['CancelAfter' , OPTIONAL], + ['FinishAfter' , OPTIONAL], + ['DestinationTag' , OPTIONAL] ]), SuspendedPaymentFinish: [2].concat(base, [ - [ 'Owner' , REQUIRED ], - [ 'OfferSequence' , REQUIRED ], - [ 'Method' , OPTIONAL ], - [ 'Digest' , OPTIONAL ], - [ 'Proof' , OPTIONAL ] + ['Owner' , REQUIRED], + ['OfferSequence' , REQUIRED], + ['Method' , OPTIONAL], + ['Digest' , OPTIONAL], + ['Proof' , OPTIONAL] ]), SuspendedPaymentCancel: [4].concat(base, [ - [ 'Owner' , REQUIRED ], - [ 'OfferSequence' , REQUIRED ] + ['Owner' , REQUIRED], + ['OfferSequence' , REQUIRED] ]) }; @@ -443,10 +443,10 @@ exports.ledger = { }; exports.metadata = [ - [ 'DeliveredAmount' , OPTIONAL ], - [ 'TransactionIndex' , REQUIRED ], - [ 'TransactionResult' , REQUIRED ], - [ 'AffectedNodes' , REQUIRED ] + ['DeliveredAmount' , OPTIONAL], + ['TransactionIndex' , REQUIRED], + ['TransactionResult' , REQUIRED], + ['AffectedNodes' , REQUIRED] ]; exports.ter = {