Skip to content

Commit

Permalink
Add SuspendedPayment{Create,Finish,Cancel}
Browse files Browse the repository at this point in the history
* Add SusPay core tests
* Rename SusPay -> SuspendedPayment (code review)
* Rename cancelAfter -> allowCancelAfter
* Rename suspendedPayment{Finish,Execution}
  • Loading branch information
sentientwaffle committed Sep 18, 2015
1 parent 6e98629 commit b134081
Show file tree
Hide file tree
Showing 29 changed files with 733 additions and 31 deletions.
3 changes: 3 additions & 0 deletions src/api/common/schema-validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down
17 changes: 17 additions & 0 deletions src/api/common/schemas/suspended-payment-cancellation.json
Original file line number Diff line number Diff line change
@@ -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
}
28 changes: 28 additions & 0 deletions src/api/common/schemas/suspended-payment-creation.json
Original file line number Diff line number Diff line change
@@ -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
}
20 changes: 20 additions & 0 deletions src/api/common/schemas/suspended-payment-execution.json
Original file line number Diff line number Diff line change
@@ -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
}
6 changes: 6 additions & 0 deletions src/api/common/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down
9 changes: 9 additions & 0 deletions src/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -61,6 +67,9 @@ RippleAPI.prototype = {
prepareTrustline,
prepareOrder,
prepareOrderCancellation,
prepareSuspendedPaymentCreation,
prepareSuspendedPaymentExecution,
prepareSuspendedPaymentCancellation,
prepareSettings,
sign,
submit,
Expand Down
15 changes: 1 addition & 14 deletions src/api/ledger/parse/payment.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand Down
16 changes: 16 additions & 0 deletions src/api/ledger/parse/suspended-payment-cancellation.js
Original file line number Diff line number Diff line change
@@ -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;
39 changes: 39 additions & 0 deletions src/api/ledger/parse/suspended-payment-creation.js
Original file line number Diff line number Diff line change
@@ -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;
25 changes: 25 additions & 0 deletions src/api/ledger/parse/suspended-payment-execution.js
Original file line number Diff line number Diff line change
@@ -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;
14 changes: 12 additions & 2 deletions src/api/ledger/parse/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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;
}
Expand All @@ -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');
Expand Down
14 changes: 14 additions & 0 deletions src/api/ledger/parse/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,22 @@ function parseOutcome(tx: Object): ?Object {
};
}

function parseMemos(tx: Object): ?Array<Object> {
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,
Expand Down
40 changes: 40 additions & 0 deletions src/api/transaction/suspended-payment-cancellation.js
Original file line number Diff line number Diff line change
@@ -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;
57 changes: 57 additions & 0 deletions src/api/transaction/suspended-payment-creation.js
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit b134081

Please sign in to comment.