Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DepositPreauth #958

Merged
merged 12 commits into from
Oct 31, 2018
4 changes: 4 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# ripple-lib Release History

## UNRELEASED

+ Add [DepositPreauth](https://developers.ripple.com/depositauth.html) ([#958](https://github.com/ripple/ripple-lib/pull/958))

## 1.0.2 (2018-10-16)

+ Fix #954: Exclude SendMax from all XRP to XRP payments (thanks @jefftrudeau)
Expand Down
109 changes: 109 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
- [getAccountObjects](#getaccountobjects)
- [getPaymentChannel](#getpaymentchannel)
- [getLedger](#getledger)
- [parseAccountFlags](#parseaccountflags)
- [prepareTransaction](#preparetransaction)
- [preparePayment](#preparepayment)
- [prepareTrustline](#preparetrustline)
- [prepareOrder](#prepareorder)
Expand Down Expand Up @@ -4103,6 +4105,109 @@ return api.getLedger()
```


## parseAccountFlags

`parseAccountFlags(Flags: number): object`

Parse an `AccountRoot` object's [`Flags`](https://developers.ripple.com/accountroot.html#accountroot-flags).

### Parameters

This method takes one parameter, the `Flags` number to parse.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe worth a note that this only works for AccountRoot Flags since the flags have different mappings on other types of objects or in transactions like AccountSet.


### Return Value

This method returns an object with containing a key for each parsed flag. Each flag has a boolean value of `true` or `false`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example implies that flags that are false are omitted from the return value, or at least that flags whose value is their default value are omitted. That should be explicit. Alternatively, it would be OK (maybe more useful?) if all known flags were included (even if most of them are false).


### Example

```javascript
const account_info = await api.request('account_info', {account: 'rKsdkGhyZH6b2Zzd5hNnEqSv2wpznn4n6N'})
const flags = api.parseAccountFlags(account_info.account_data.Flags)
console.log(JSON.stringify([account_info, flags], null, 2))
```

```json
[
{
"account_data": {
"Account": "rKsdkGhyZH6b2Zzd5hNnEqSv2wpznn4n6N",
"Balance": "9997999496",
"Flags": 16777216,
"LedgerEntryType": "AccountRoot",
"OwnerCount": 2,
"PreviousTxnID": "22C2B172891F92470E37D8E3AA9A9C950751C13EB059B21DADF3A5A0B120C147",
"PreviousTxnLgrSeq": 13558089,
"Sequence": 9,
"index": "8D40979208F658354384E9D069C0EC56814997807378651E39575CFE8A483EB9"
},
"ledger_current_index": 13752642,
"validated": false
},
{
"depositAuth": true
}
]
```

## prepareTransaction

`prepareTransaction(address: string, transaction: object, instructions: object): Promise<object>`

Prepare a transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).

This method works with any of [the transaction types supported by rippled](https://developers.ripple.com/transaction-types.html).

Notably, this is the preferred method for preparing a `DepositPreauth` transaction (added in rippled 1.1.0).

### Parameters

Name | Type | Description
---- | ---- | -----------
transaction | [transaction](https://developers.ripple.com/transaction-formats.html) | The specification (JSON) of the transaction to prepare. Set `Account` to the address of the account that is creating the transaction. Common fields like `Fee`, `Flags`, and `Sequence` may be omitted; `prepareTransaction` will set them automatically.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the rippled API documentation, we use the term "Auto-fillable fields" for fields whose values can be automatically provided, and "Common fields" for fields that apply to all transactions (but whose values cannot be automatically provided, such as Account). Let's try to match that usage here.

instructions | [instructions](#transaction-instructions) | *Optional* Instructions for executing the transaction

### Return Value

This method returns a promise that resolves with an object with the following structure:

<aside class="notice">
All "prepare*" methods have the same return type.
</aside>

Name | Type | Description
---- | ---- | -----------
txJSON | string | The prepared transaction in rippled JSON format.
instructions | object | The instructions for how to execute the transaction after adding automatic defaults.
*instructions.* fee | [value](#value) | An exact fee to pay for the transaction. See [Transaction Fees](#transaction-fees) for more information.
*instructions.* sequence | [sequence](#account-sequence-number) | The initiating account's sequence number for this transaction.
*instructions.* maxLedgerVersion | integer,null | The highest ledger version that the transaction can be included in. Set to `null` if there is no maximum.
*instructions.* maxLedgerVersion | string,null | The highest ledger version that the transaction can be included in. Set to `null` if there is no maximum.

### Example

```javascript
async function preparedPreauth() {
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
return api.prepareTransaction({
TransactionType: 'DepositPreauth',
Account: address,
Authorize: 'rMyVso4p83khNyHdV1m1PggV9QNadCj8wM'
});
}
```

```javascript
{
txJSON: '{"TransactionType":"DepositPreauth","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Authorize":"rMyVso4p83khNyHdV1m1PggV9QNadCj8wM","Flags":2147483648,"LastLedgerSequence":13561714,"Fee":"12","Sequence":1}',
instructions: {
fee: '0.000012',
sequence: 1,
maxLedgerVersion: 13561714
}
}
```

## preparePayment

`preparePayment(address: string, payment: object, instructions: object): Promise<object>`
Expand Down Expand Up @@ -4955,6 +5060,10 @@ sign(txJSON: string, keypair: object, options: object): {signedTransaction: stri

Sign a prepared transaction. The signed transaction must subsequently be [submitted](#submit).

This method can sign any of [the transaction types supported by ripple-binary-codec](https://github.com/ripple/ripple-binary-codec/blob/cfcde79c19c359e9a0466d7bc3dc9a3aef47bb99/src/enums/definitions.json#L1637). When a new transaction type is added, it will be unrecognized until ripple-binary-codec is updated. An error will be thrown:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For style reasons, avoid future tense and passive voice except when talking about future events. (In this paragraph, there are two instances of future tense, one of which is appropriate and one of which isn't.) Here's a suggested rephrase:

When a new transaction type is added to the XRP Ledger, it will be unrecognized until ripple-binary-codec is updated. If you try to sign an unrecognized transaction type, this method throws an error similar to the following:


`Error: [TRANSACTION_TYPE] is not a valid name or ordinal for TransactionType`

### Parameters

Name | Type | Description
Expand Down
2 changes: 2 additions & 0 deletions docs/src/index.md.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
<% include getAccountObjects.md.ejs %>
<% include getPaymentChannel.md.ejs %>
<% include getLedger.md.ejs %>
<% include parseAccountFlags.md.ejs %>
<% include prepareTransaction.md.ejs %>
<% include preparePayment.md.ejs %>
<% include prepareTrustline.md.ejs %>
<% include prepareOrder.md.ejs %>
Expand Down
44 changes: 44 additions & 0 deletions docs/src/parseAccountFlags.md.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
## parseAccountFlags

`parseAccountFlags(Flags: number): object`

Parse an `AccountRoot` object's [`Flags`](https://developers.ripple.com/accountroot.html#accountroot-flags).

### Parameters

This method takes one parameter, the `Flags` number to parse.

### Return Value

This method returns an object with containing a key for each parsed flag. Each flag has a boolean value of `true` or `false`.

### Example

```javascript
const account_info = await api.request('account_info', {account: 'rKsdkGhyZH6b2Zzd5hNnEqSv2wpznn4n6N'})
const flags = api.parseAccountFlags(account_info.account_data.Flags)
console.log(JSON.stringify([account_info, flags], null, 2))
```

```json
[
{
"account_data": {
"Account": "rKsdkGhyZH6b2Zzd5hNnEqSv2wpznn4n6N",
"Balance": "9997999496",
"Flags": 16777216,
"LedgerEntryType": "AccountRoot",
"OwnerCount": 2,
"PreviousTxnID": "22C2B172891F92470E37D8E3AA9A9C950751C13EB059B21DADF3A5A0B120C147",
"PreviousTxnLgrSeq": 13558089,
"Sequence": 9,
"index": "8D40979208F658354384E9D069C0EC56814997807378651E39575CFE8A483EB9"
},
"ledger_current_index": 13752642,
"validated": false
},
{
"depositAuth": true
}
]
```
50 changes: 50 additions & 0 deletions docs/src/prepareTransaction.md.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
## prepareTransaction

`prepareTransaction(address: string, transaction: object, instructions: object): Promise<object>`

Prepare a transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).

This method works with any of [the transaction types supported by rippled](https://developers.ripple.com/transaction-types.html).

Notably, this is the preferred method for preparing a `DepositPreauth` transaction (added in rippled 1.1.0).

### Parameters

Name | Type | Description
---- | ---- | -----------
transaction | [transaction](https://developers.ripple.com/transaction-formats.html) | The specification (JSON) of the transaction to prepare. Set `Account` to the address of the account that is creating the transaction. Common fields like `Fee`, `Flags`, and `Sequence` may be omitted; `prepareTransaction` will set them automatically.
instructions | [instructions](#transaction-instructions) | *Optional* Instructions for executing the transaction

### Return Value

This method returns a promise that resolves with an object with the following structure:

<aside class="notice">
All "prepare*" methods have the same return type.
</aside>

<%- renderSchema("output/prepare.json") %>

### Example

```javascript
async function preparedPreauth() {
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
return api.prepareTransaction({
TransactionType: 'DepositPreauth',
Account: address,
Authorize: 'rMyVso4p83khNyHdV1m1PggV9QNadCj8wM'
});
}
```

```javascript
{
txJSON: '{"TransactionType":"DepositPreauth","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Authorize":"rMyVso4p83khNyHdV1m1PggV9QNadCj8wM","Flags":2147483648,"LastLedgerSequence":13561714,"Fee":"12","Sequence":1}',
instructions: {
fee: '0.000012',
sequence: 1,
maxLedgerVersion: 13561714
}
}
```
4 changes: 4 additions & 0 deletions docs/src/sign.md.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ sign(txJSON: string, keypair: object, options: object): {signedTransaction: stri

Sign a prepared transaction. The signed transaction must subsequently be [submitted](#submit).

This method can sign any of [the transaction types supported by ripple-binary-codec](https://github.com/ripple/ripple-binary-codec/blob/cfcde79c19c359e9a0466d7bc3dc9a3aef47bb99/src/enums/definitions.json#L1637). When a new transaction type is added, it will be unrecognized until ripple-binary-codec is updated. An error will be thrown:

`Error: [TRANSACTION_TYPE] is not a valid name or ordinal for TransactionType`

### Parameters

<%- renderSchema("input/sign.json") %>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"jsonschema": "1.2.2",
"lodash": "^4.17.4",
"ripple-address-codec": "^2.0.1",
"ripple-binary-codec": "^0.1.13",
"ripple-binary-codec": "0.2.0",
"ripple-hashes": "^0.3.1",
"ripple-keypairs": "^0.10.1",
"ripple-lib-transactionparser": "0.7.1",
Expand Down
3 changes: 2 additions & 1 deletion src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import getBalanceSheet from './ledger/balance-sheet'
import getPaths from './ledger/pathfind'
import getOrders from './ledger/orders'
import getOrderbook from './ledger/orderbook'
import getSettings from './ledger/settings'
import {getSettings, parseAccountFlags} from './ledger/settings'
import getAccountInfo from './ledger/accountinfo'
import getAccountObjects from './ledger/accountobjects'
import getPaymentChannel from './ledger/payment-channel'
Expand Down Expand Up @@ -302,6 +302,7 @@ class RippleAPI extends EventEmitter {
getAccountObjects = getAccountObjects
getPaymentChannel = getPaymentChannel
getLedger = getLedger
parseAccountFlags = parseAccountFlags

preparePayment = preparePayment
prepareTrustline = prepareTrustline
Expand Down
21 changes: 21 additions & 0 deletions src/ledger/parse/deposit-preauth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as assert from 'assert'
import {removeUndefined} from '../../common'

export type FormattedDepositPreauth = {
// account (address) of the sender to preauthorize
authorize: string,

// account (address) of the sender whose preauthorization should be revoked
unauthorize: string
}

function parseDepositPreauth(tx: any): FormattedDepositPreauth {
assert(tx.TransactionType === 'DepositPreauth')

return removeUndefined({
authorize: tx.Authorize,
unauthorize: tx.Unauthorize
})
}

export default parseDepositPreauth
42 changes: 27 additions & 15 deletions src/ledger/parse/transaction.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as assert from 'assert'
import {parseOutcome} from './utils'
import {removeUndefined} from '../../common'
import parsePayment from './payment'
Expand All @@ -12,36 +11,41 @@ import parseEscrowCancellation from './escrow-cancellation'
import parseCheckCreate from './check-create'
import parseCheckCash from './check-cash'
import parseCheckCancel from './check-cancel'
import parseDepositPreauth from './deposit-preauth'
import parsePaymentChannelCreate from './payment-channel-create'
import parsePaymentChannelFund from './payment-channel-fund'
import parsePaymentChannelClaim from './payment-channel-claim'
import parseFeeUpdate from './fee-update'
import parseAmendment from './amendment'

function parseTransactionType(type) {
// Ordering matches https://developers.ripple.com/transaction-types.html
const mapping = {
Payment: 'payment',
TrustSet: 'trustline',
OfferCreate: 'order',
OfferCancel: 'orderCancellation',
AccountSet: 'settings',
SetRegularKey: 'settings',
CheckCancel: 'checkCancel',
CheckCash: 'checkCash',
CheckCreate: 'checkCreate',
DepositPreauth: 'depositPreauth',
EscrowCancel: 'escrowCancellation',
EscrowCreate: 'escrowCreation',
EscrowFinish: 'escrowExecution',
EscrowCancel: 'escrowCancellation',
CheckCreate: 'checkCreate',
CheckCash: 'checkCash',
CheckCancel: 'checkCancel',
OfferCancel: 'orderCancellation',
OfferCreate: 'order',
Payment: 'payment',
PaymentChannelClaim: 'paymentChannelClaim',
PaymentChannelCreate: 'paymentChannelCreate',
PaymentChannelFund: 'paymentChannelFund',
PaymentChannelClaim: 'paymentChannelClaim',
SetRegularKey: 'settings',
SignerListSet: 'settings',
SetFee: 'feeUpdate', // pseudo-transaction
EnableAmendment: 'amendment' // pseudo-transaction
TrustSet: 'trustline',

EnableAmendment: 'amendment', // pseudo-transaction
SetFee: 'feeUpdate' // pseudo-transaction
}
return mapping[type] || null
}

// includeRawTransaction: undefined by default (getTransaction)
function parseTransaction(tx: any, includeRawTransaction: boolean): any {
const type = parseTransactionType(tx.TransactionType)
const mapping = {
Expand All @@ -56,15 +60,23 @@ function parseTransaction(tx: any, includeRawTransaction: boolean): any {
'checkCreate': parseCheckCreate,
'checkCash': parseCheckCash,
'checkCancel': parseCheckCancel,
'depositPreauth': parseDepositPreauth,
'paymentChannelCreate': parsePaymentChannelCreate,
'paymentChannelFund': parsePaymentChannelFund,
'paymentChannelClaim': parsePaymentChannelClaim,
'feeUpdate': parseFeeUpdate,
'amendment': parseAmendment
}
const parser: Function = mapping[type]
assert(parser !== undefined, 'Unrecognized transaction type')
const specification = parser(tx)

const specification = parser ? parser(tx) : {
UNAVAILABLE: 'Unrecognized transaction type.',
SEE_RAW_TRANSACTION: 'Since this type is unrecognized, `rawTransaction` is included in this response.'
}
if (!parser) {
includeRawTransaction = true
}

const outcome = parseOutcome(tx)
return removeUndefined({
type: type,
Expand Down
Loading