mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-12-06 17:27:59 +00:00
Removes all prepare methods (#1605)
* deprecate and alias prepareTransaction * delete prepareTransaction and replace methods in check-cancel * WIP update check-cash * remove all prepares * remove prepares from client * fix ts issues * remove tests * fix tests * additional cleanup * fix integration tests * remove console statement * re-add helper function * fix imports * fix more issues with integration tests Co-authored-by: Omar Khan <khancodegt@gmail.com>
This commit is contained in:
@@ -107,25 +107,8 @@ import {
|
||||
UnsubscribeResponse,
|
||||
} from '../models/methods'
|
||||
import { BaseRequest, BaseResponse } from '../models/methods/baseMethod'
|
||||
import prepareCheckCancel from '../transaction/check-cancel'
|
||||
import prepareCheckCash from '../transaction/check-cash'
|
||||
import prepareCheckCreate from '../transaction/check-create'
|
||||
import combine from '../transaction/combine'
|
||||
import prepareEscrowCancellation from '../transaction/escrow-cancellation'
|
||||
import prepareEscrowCreation from '../transaction/escrow-creation'
|
||||
import prepareEscrowExecution from '../transaction/escrow-execution'
|
||||
import prepareOrder from '../transaction/order'
|
||||
import prepareOrderCancellation from '../transaction/ordercancellation'
|
||||
import preparePayment from '../transaction/payment'
|
||||
import preparePaymentChannelClaim from '../transaction/payment-channel-claim'
|
||||
import preparePaymentChannelCreate from '../transaction/payment-channel-create'
|
||||
import preparePaymentChannelFund from '../transaction/payment-channel-fund'
|
||||
import prepareSettings from '../transaction/settings'
|
||||
import { sign } from '../transaction/sign'
|
||||
import prepareTicketCreate from '../transaction/ticket'
|
||||
import prepareTrustline from '../transaction/trustline'
|
||||
import { TransactionJSON, Instructions, Prepare } from '../transaction/types'
|
||||
import * as transactionUtils from '../transaction/utils'
|
||||
import { deriveAddress, deriveXAddress } from '../utils/derive'
|
||||
import generateFaucetWallet from '../wallet/generateFaucetWallet'
|
||||
|
||||
@@ -213,9 +196,6 @@ class Client extends EventEmitter {
|
||||
// number. Defaults to '2'.
|
||||
public readonly maxFeeXRP: string
|
||||
|
||||
// TODO: Use partial for other instance methods as well.
|
||||
public autofill = prepend(autofill, this)
|
||||
|
||||
/**
|
||||
* Creates a new Client with a websocket connection to a rippled server.
|
||||
*
|
||||
@@ -426,22 +406,6 @@ class Client extends EventEmitter {
|
||||
return super.on(eventName, listener)
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a transaction.
|
||||
*
|
||||
* You can later submit the transaction with a `submit` request.
|
||||
*
|
||||
* @param txJSON - TODO: will be deleted.
|
||||
* @param instructions - TODO: will be deleted.
|
||||
* @returns TODO: will be deleted.
|
||||
*/
|
||||
public async prepareTransaction(
|
||||
txJSON: TransactionJSON,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
return transactionUtils.prepareTransaction(txJSON, this, instructions)
|
||||
}
|
||||
|
||||
public async requestAll(
|
||||
req: AccountChannelsRequest,
|
||||
): Promise<AccountChannelsResponse[]>
|
||||
@@ -551,6 +515,12 @@ class Client extends EventEmitter {
|
||||
return this.connection.isConnected()
|
||||
}
|
||||
|
||||
// TODO: Use prepend for other instance methods as well.
|
||||
public autofill = prepend(autofill, this)
|
||||
|
||||
// @deprecated Use autofill instead
|
||||
public prepareTransaction = prepend(autofill, this)
|
||||
|
||||
public getFee = getFee
|
||||
|
||||
public getTrustlines = getTrustlines
|
||||
@@ -558,25 +528,10 @@ class Client extends EventEmitter {
|
||||
public getPaths = getPaths
|
||||
public getOrderbook = getOrderbook
|
||||
|
||||
public preparePayment = preparePayment
|
||||
public prepareTrustline = prepareTrustline
|
||||
public prepareOrder = prepareOrder
|
||||
public prepareOrderCancellation = prepareOrderCancellation
|
||||
public prepareEscrowCreation = prepareEscrowCreation
|
||||
public prepareEscrowExecution = prepareEscrowExecution
|
||||
public prepareEscrowCancellation = prepareEscrowCancellation
|
||||
public preparePaymentChannelCreate = preparePaymentChannelCreate
|
||||
public preparePaymentChannelFund = preparePaymentChannelFund
|
||||
public preparePaymentChannelClaim = preparePaymentChannelClaim
|
||||
public prepareCheckCreate = prepareCheckCreate
|
||||
public prepareCheckCash = prepareCheckCash
|
||||
public prepareCheckCancel = prepareCheckCancel
|
||||
public prepareTicketCreate = prepareTicketCreate
|
||||
public prepareSettings = prepareSettings
|
||||
public sign = sign
|
||||
public combine = combine
|
||||
|
||||
public generateFaucetWallet = generateFaucetWallet
|
||||
public generateFaucetWallet = prepend(generateFaucetWallet, this)
|
||||
|
||||
public errors = errors
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ function validateAccountAddress(
|
||||
// eslint-disable-next-line no-param-reassign -- param reassign is safe
|
||||
tx[accountField] = classicAccount
|
||||
|
||||
if (tag != null) {
|
||||
if (tag != null && tag !== false) {
|
||||
if (tx[tagField] && tx[tagField] !== tag) {
|
||||
throw new ValidationError(
|
||||
`The ${tagField}, if present, must match the tag of the ${accountField} X-address`,
|
||||
|
||||
@@ -7,7 +7,6 @@ import type { Connection } from '../client'
|
||||
import * as common from '../common'
|
||||
import { Issue } from '../common/types/objects'
|
||||
import { AccountInfoRequest } from '../models/methods'
|
||||
import { FormattedTransactionType } from '../transaction/types'
|
||||
import { dropsToXrp } from '../utils'
|
||||
|
||||
export interface RecursiveData {
|
||||
@@ -82,32 +81,6 @@ function renameCounterpartyToIssuerInOrder(order: RequestBookOffersArgs) {
|
||||
return { ...order, ..._.omitBy(changes, (value) => value == null) }
|
||||
}
|
||||
|
||||
function signum(num) {
|
||||
return num === 0 ? 0 : num > 0 ? 1 : -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Order two rippled transactions based on their ledger_index.
|
||||
* If two transactions took place in the same ledger, sort
|
||||
* them based on TransactionIndex
|
||||
* See: https://developers.ripple.com/transaction-metadata.html.
|
||||
*
|
||||
* @param first
|
||||
* @param second
|
||||
*/
|
||||
function compareTransactions(
|
||||
first: FormattedTransactionType,
|
||||
second: FormattedTransactionType,
|
||||
): number {
|
||||
if (!first.outcome || !second.outcome) {
|
||||
return 0
|
||||
}
|
||||
if (first.outcome.ledgerVersion === second.outcome.ledgerVersion) {
|
||||
return signum(first.outcome.indexInLedger - second.outcome.indexInLedger)
|
||||
}
|
||||
return first.outcome.ledgerVersion < second.outcome.ledgerVersion ? -1 : 1
|
||||
}
|
||||
|
||||
async function isPendingLedgerVersion(
|
||||
client: Client,
|
||||
maxLedgerVersion?: number,
|
||||
@@ -142,7 +115,6 @@ async function ensureLedgerVersion(
|
||||
export {
|
||||
getXRPBalance,
|
||||
ensureLedgerVersion,
|
||||
compareTransactions,
|
||||
renameCounterpartyToIssuer,
|
||||
renameCounterpartyToIssuerInOrder,
|
||||
getRecursive,
|
||||
|
||||
@@ -58,6 +58,8 @@ interface PathStep {
|
||||
export type Path = PathStep[]
|
||||
|
||||
export interface SignerEntry {
|
||||
Account: string
|
||||
SignerWeight: number
|
||||
SignerEntry: {
|
||||
Account: string
|
||||
SignerWeight: number
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,10 +59,8 @@ export function verifyPayment(tx: Record<string, unknown>): void {
|
||||
throw new ValidationError('PaymentTransaction: invalid Destination')
|
||||
}
|
||||
|
||||
if (
|
||||
tx.DestinationTag !== undefined &&
|
||||
typeof tx.DestinationTag !== 'number'
|
||||
) {
|
||||
if (tx.DestinationTag != null && typeof tx.DestinationTag !== 'number') {
|
||||
console.log(tx.DestinationTag)
|
||||
throw new ValidationError(
|
||||
'PaymentTransaction: DestinationTag must be a number',
|
||||
)
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import type { Client } from '..'
|
||||
|
||||
import { Instructions, Prepare, TransactionJSON } from './types'
|
||||
import { prepareTransaction } from './utils'
|
||||
|
||||
export interface CheckCancelParameters {
|
||||
checkID: string
|
||||
}
|
||||
|
||||
function createCheckCancelTransaction(
|
||||
account: string,
|
||||
cancel: CheckCancelParameters,
|
||||
): TransactionJSON {
|
||||
const txJSON = {
|
||||
Account: account,
|
||||
TransactionType: 'CheckCancel',
|
||||
CheckID: cancel.checkID,
|
||||
}
|
||||
|
||||
return txJSON
|
||||
}
|
||||
|
||||
async function prepareCheckCancel(
|
||||
this: Client,
|
||||
address: string,
|
||||
checkCancel: CheckCancelParameters,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
const txJSON = createCheckCancelTransaction(address, checkCancel)
|
||||
return await prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default prepareCheckCancel
|
||||
@@ -1,57 +0,0 @@
|
||||
import type { Client } from '..'
|
||||
import { ValidationError } from '../common/errors'
|
||||
import { Amount } from '../common/types/objects'
|
||||
import { toRippledAmount } from '../utils'
|
||||
|
||||
import { Instructions, Prepare, TransactionJSON } from './types'
|
||||
import * as utils from './utils'
|
||||
|
||||
export interface CheckCashParameters {
|
||||
checkID: string
|
||||
amount?: Amount
|
||||
deliverMin?: Amount
|
||||
}
|
||||
|
||||
function createCheckCashTransaction(
|
||||
account: string,
|
||||
checkCash: CheckCashParameters,
|
||||
): TransactionJSON {
|
||||
if (checkCash.amount && checkCash.deliverMin) {
|
||||
throw new ValidationError(
|
||||
'"amount" and "deliverMin" properties on ' +
|
||||
'CheckCash are mutually exclusive',
|
||||
)
|
||||
}
|
||||
|
||||
const txJSON: any = {
|
||||
Account: account,
|
||||
TransactionType: 'CheckCash',
|
||||
CheckID: checkCash.checkID,
|
||||
}
|
||||
|
||||
if (checkCash.amount != null) {
|
||||
txJSON.Amount = toRippledAmount(checkCash.amount)
|
||||
}
|
||||
|
||||
if (checkCash.deliverMin != null) {
|
||||
txJSON.DeliverMin = toRippledAmount(checkCash.deliverMin)
|
||||
}
|
||||
|
||||
return txJSON
|
||||
}
|
||||
|
||||
async function prepareCheckCash(
|
||||
this: Client,
|
||||
address: string,
|
||||
checkCash: CheckCashParameters,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
const txJSON = createCheckCashTransaction(address, checkCash)
|
||||
return await utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default prepareCheckCash
|
||||
@@ -1,56 +0,0 @@
|
||||
import type { Client } from '..'
|
||||
import { Amount } from '../common/types/objects'
|
||||
import { ISOTimeToRippleTime, toRippledAmount } from '../utils'
|
||||
|
||||
import { Instructions, Prepare, TransactionJSON } from './types'
|
||||
import * as utils from './utils'
|
||||
|
||||
export interface CheckCreateParameters {
|
||||
destination: string
|
||||
sendMax: Amount
|
||||
destinationTag?: number
|
||||
expiration?: string
|
||||
invoiceID?: string
|
||||
}
|
||||
|
||||
function createCheckCreateTransaction(
|
||||
account: string,
|
||||
check: CheckCreateParameters,
|
||||
): TransactionJSON {
|
||||
const txJSON: any = {
|
||||
Account: account,
|
||||
TransactionType: 'CheckCreate',
|
||||
Destination: check.destination,
|
||||
SendMax: toRippledAmount(check.sendMax),
|
||||
}
|
||||
|
||||
if (check.destinationTag != null) {
|
||||
txJSON.DestinationTag = check.destinationTag
|
||||
}
|
||||
|
||||
if (check.expiration != null) {
|
||||
txJSON.Expiration = ISOTimeToRippleTime(check.expiration)
|
||||
}
|
||||
|
||||
if (check.invoiceID != null) {
|
||||
txJSON.InvoiceID = check.invoiceID
|
||||
}
|
||||
|
||||
return txJSON
|
||||
}
|
||||
|
||||
async function prepareCheckCreate(
|
||||
this: Client,
|
||||
address: string,
|
||||
checkCreate: CheckCreateParameters,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
const txJSON = createCheckCreateTransaction(address, checkCreate)
|
||||
return await utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default prepareCheckCreate
|
||||
@@ -1,45 +0,0 @@
|
||||
import type { Client } from '..'
|
||||
import { Memo } from '../common/types/objects'
|
||||
|
||||
import { Instructions, Prepare, TransactionJSON } from './types'
|
||||
import * as utils from './utils'
|
||||
|
||||
export interface EscrowCancellation {
|
||||
owner: string
|
||||
escrowSequence: number
|
||||
|
||||
// TODO: This ripple-lib memo format should be deprecated in favor of rippled's format.
|
||||
// If necessary, expose a public method for converting between the two formats.
|
||||
memos?: Memo[]
|
||||
}
|
||||
|
||||
function createEscrowCancellationTransaction(
|
||||
account: string,
|
||||
payment: EscrowCancellation,
|
||||
): TransactionJSON {
|
||||
const txJSON: any = {
|
||||
TransactionType: 'EscrowCancel',
|
||||
Account: account,
|
||||
Owner: payment.owner,
|
||||
OfferSequence: payment.escrowSequence,
|
||||
}
|
||||
if (payment.memos != null) {
|
||||
txJSON.Memos = payment.memos.map(utils.convertMemo)
|
||||
}
|
||||
return txJSON
|
||||
}
|
||||
|
||||
async function prepareEscrowCancellation(
|
||||
this: Client,
|
||||
address: string,
|
||||
escrowCancellation: EscrowCancellation,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
const txJSON = createEscrowCancellationTransaction(
|
||||
address,
|
||||
escrowCancellation,
|
||||
)
|
||||
return utils.prepareTransaction(txJSON, this, instructions)
|
||||
}
|
||||
|
||||
export default prepareEscrowCancellation
|
||||
@@ -1,77 +0,0 @@
|
||||
import type { Client } from '..'
|
||||
import { Memo } from '../common/types/objects'
|
||||
import { ISOTimeToRippleTime, xrpToDrops } from '../utils'
|
||||
|
||||
import { Instructions, Prepare, TransactionJSON } from './types'
|
||||
import * as utils from './utils'
|
||||
|
||||
const ValidationError = utils.common.errors.ValidationError
|
||||
|
||||
export interface EscrowCreation {
|
||||
amount: string
|
||||
destination: string
|
||||
memos?: Memo[]
|
||||
condition?: string
|
||||
allowCancelAfter?: string
|
||||
allowExecuteAfter?: string
|
||||
sourceTag?: number
|
||||
destinationTag?: number
|
||||
}
|
||||
|
||||
function createEscrowCreationTransaction(
|
||||
account: string,
|
||||
payment: EscrowCreation,
|
||||
): TransactionJSON {
|
||||
const txJSON: any = {
|
||||
TransactionType: 'EscrowCreate',
|
||||
Account: account,
|
||||
Destination: payment.destination,
|
||||
Amount: xrpToDrops(payment.amount),
|
||||
}
|
||||
|
||||
if (payment.condition != null) {
|
||||
txJSON.Condition = payment.condition
|
||||
}
|
||||
if (payment.allowCancelAfter != null) {
|
||||
txJSON.CancelAfter = ISOTimeToRippleTime(payment.allowCancelAfter)
|
||||
}
|
||||
if (payment.allowExecuteAfter != null) {
|
||||
txJSON.FinishAfter = ISOTimeToRippleTime(payment.allowExecuteAfter)
|
||||
}
|
||||
if (payment.sourceTag != null) {
|
||||
txJSON.SourceTag = payment.sourceTag
|
||||
}
|
||||
if (payment.destinationTag != null) {
|
||||
txJSON.DestinationTag = payment.destinationTag
|
||||
}
|
||||
if (payment.memos != null) {
|
||||
txJSON.Memos = payment.memos.map(utils.convertMemo)
|
||||
}
|
||||
if (
|
||||
Boolean(payment.allowCancelAfter) &&
|
||||
Boolean(payment.allowExecuteAfter) &&
|
||||
txJSON.CancelAfter <= txJSON.FinishAfter
|
||||
) {
|
||||
throw new ValidationError(
|
||||
'prepareEscrowCreation: ' +
|
||||
'"allowCancelAfter" must be after "allowExecuteAfter"',
|
||||
)
|
||||
}
|
||||
return txJSON
|
||||
}
|
||||
|
||||
async function prepareEscrowCreation(
|
||||
this: Client,
|
||||
address: string,
|
||||
escrowCreation: EscrowCreation,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
const txJSON = createEscrowCreationTransaction(address, escrowCreation)
|
||||
return await utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default prepareEscrowCreation
|
||||
@@ -1,61 +0,0 @@
|
||||
import type { Client } from '..'
|
||||
import { Memo } from '../common/types/objects'
|
||||
|
||||
import { Instructions, Prepare, TransactionJSON } from './types'
|
||||
import * as utils from './utils'
|
||||
|
||||
const ValidationError = utils.common.errors.ValidationError
|
||||
|
||||
export interface EscrowExecution {
|
||||
owner: string
|
||||
escrowSequence: number
|
||||
memos?: Memo[]
|
||||
condition?: string
|
||||
fulfillment?: string
|
||||
}
|
||||
|
||||
function createEscrowExecutionTransaction(
|
||||
account: string,
|
||||
payment: EscrowExecution,
|
||||
): TransactionJSON {
|
||||
const txJSON: any = {
|
||||
TransactionType: 'EscrowFinish',
|
||||
Account: account,
|
||||
Owner: payment.owner,
|
||||
OfferSequence: payment.escrowSequence,
|
||||
}
|
||||
|
||||
if (Boolean(payment.condition) !== Boolean(payment.fulfillment)) {
|
||||
throw new ValidationError(
|
||||
'"condition" and "fulfillment" fields on' +
|
||||
' EscrowFinish must only be specified together.',
|
||||
)
|
||||
}
|
||||
|
||||
if (payment.condition != null) {
|
||||
txJSON.Condition = payment.condition
|
||||
}
|
||||
if (payment.fulfillment != null) {
|
||||
txJSON.Fulfillment = payment.fulfillment
|
||||
}
|
||||
if (payment.memos != null) {
|
||||
txJSON.Memos = payment.memos.map(utils.convertMemo)
|
||||
}
|
||||
return txJSON
|
||||
}
|
||||
|
||||
async function prepareEscrowExecution(
|
||||
this: Client,
|
||||
address: string,
|
||||
escrowExecution: EscrowExecution,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
const txJSON = createEscrowExecutionTransaction(address, escrowExecution)
|
||||
return await utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default prepareEscrowExecution
|
||||
@@ -1,67 +0,0 @@
|
||||
import type { Client } from '..'
|
||||
import { FormattedOrderSpecification } from '../common/types/objects/index'
|
||||
import { ISOTimeToRippleTime, toRippledAmount } from '../utils'
|
||||
|
||||
import { Instructions, Prepare, OfferCreateTransaction } from './types'
|
||||
import * as utils from './utils'
|
||||
|
||||
const offerFlags = utils.common.txFlags.OfferCreate
|
||||
|
||||
function createOrderTransaction(
|
||||
account: string,
|
||||
order: FormattedOrderSpecification,
|
||||
): OfferCreateTransaction {
|
||||
const takerPays = toRippledAmount(
|
||||
order.direction === 'buy' ? order.quantity : order.totalPrice,
|
||||
)
|
||||
const takerGets = toRippledAmount(
|
||||
order.direction === 'buy' ? order.totalPrice : order.quantity,
|
||||
)
|
||||
|
||||
const txJSON: Partial<OfferCreateTransaction> = {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: account,
|
||||
TakerGets: takerGets,
|
||||
TakerPays: takerPays,
|
||||
}
|
||||
|
||||
txJSON.Flags = 0
|
||||
if (order.direction === 'sell') {
|
||||
txJSON.Flags |= offerFlags.Sell
|
||||
}
|
||||
if (order.passive) {
|
||||
txJSON.Flags |= offerFlags.Passive
|
||||
}
|
||||
if (order.immediateOrCancel) {
|
||||
txJSON.Flags |= offerFlags.ImmediateOrCancel
|
||||
}
|
||||
if (order.fillOrKill) {
|
||||
txJSON.Flags |= offerFlags.FillOrKill
|
||||
}
|
||||
if (order.expirationTime != null) {
|
||||
txJSON.Expiration = ISOTimeToRippleTime(order.expirationTime)
|
||||
}
|
||||
if (order.orderToReplace != null) {
|
||||
txJSON.OfferSequence = order.orderToReplace
|
||||
}
|
||||
if (order.memos != null) {
|
||||
txJSON.Memos = order.memos.map(utils.convertMemo)
|
||||
}
|
||||
return txJSON as OfferCreateTransaction
|
||||
}
|
||||
|
||||
async function prepareOrder(
|
||||
this: Client,
|
||||
address: string,
|
||||
order: FormattedOrderSpecification,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
const txJSON = createOrderTransaction(address, order)
|
||||
return await utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default prepareOrder
|
||||
@@ -1,38 +0,0 @@
|
||||
import type { Client } from '..'
|
||||
|
||||
import { Instructions, Prepare, TransactionJSON } from './types'
|
||||
import * as utils from './utils'
|
||||
|
||||
function createOrderCancellationTransaction(
|
||||
account: string,
|
||||
orderCancellation: any,
|
||||
): TransactionJSON {
|
||||
const txJSON: any = {
|
||||
TransactionType: 'OfferCancel',
|
||||
Account: account,
|
||||
OfferSequence: orderCancellation.orderSequence,
|
||||
}
|
||||
if (orderCancellation.memos != null) {
|
||||
txJSON.Memos = orderCancellation.memos.map(utils.convertMemo)
|
||||
}
|
||||
return txJSON
|
||||
}
|
||||
|
||||
async function prepareOrderCancellation(
|
||||
this: Client,
|
||||
address: string,
|
||||
orderCancellation: object,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
const txJSON = createOrderCancellationTransaction(
|
||||
address,
|
||||
orderCancellation,
|
||||
)
|
||||
return await utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default prepareOrderCancellation
|
||||
@@ -1,87 +0,0 @@
|
||||
import type { Client } from '..'
|
||||
import { xrpToDrops } from '../utils'
|
||||
|
||||
import { Instructions, Prepare, TransactionJSON } from './types'
|
||||
import * as utils from './utils'
|
||||
|
||||
const ValidationError = utils.common.errors.ValidationError
|
||||
const claimFlags = utils.common.txFlags.PaymentChannelClaim
|
||||
|
||||
export interface PaymentChannelClaim {
|
||||
channel: string
|
||||
balance?: string
|
||||
amount?: string
|
||||
signature?: string
|
||||
publicKey?: string
|
||||
renew?: boolean
|
||||
close?: boolean
|
||||
}
|
||||
|
||||
function createPaymentChannelClaimTransaction(
|
||||
account: string,
|
||||
claim: PaymentChannelClaim,
|
||||
): TransactionJSON {
|
||||
const txJSON: TransactionJSON = {
|
||||
Account: account,
|
||||
TransactionType: 'PaymentChannelClaim',
|
||||
Channel: claim.channel,
|
||||
Flags: 0,
|
||||
}
|
||||
|
||||
if (claim.balance != null) {
|
||||
txJSON.Balance = xrpToDrops(claim.balance)
|
||||
}
|
||||
if (claim.amount != null) {
|
||||
txJSON.Amount = xrpToDrops(claim.amount)
|
||||
}
|
||||
|
||||
if (Boolean(claim.signature) !== Boolean(claim.publicKey)) {
|
||||
throw new ValidationError(
|
||||
'"signature" and "publicKey" fields on' +
|
||||
' PaymentChannelClaim must only be specified together.',
|
||||
)
|
||||
}
|
||||
|
||||
if (claim.signature != null) {
|
||||
txJSON.Signature = claim.signature
|
||||
}
|
||||
if (claim.publicKey != null) {
|
||||
txJSON.PublicKey = claim.publicKey
|
||||
}
|
||||
|
||||
if (claim.renew && claim.close) {
|
||||
throw new ValidationError(
|
||||
'"renew" and "close" flags on PaymentChannelClaim' +
|
||||
' are mutually exclusive',
|
||||
)
|
||||
}
|
||||
|
||||
txJSON.Flags = 0
|
||||
if (claim.renew) {
|
||||
txJSON.Flags |= claimFlags.Renew
|
||||
}
|
||||
if (claim.close) {
|
||||
txJSON.Flags |= claimFlags.Close
|
||||
}
|
||||
|
||||
return txJSON
|
||||
}
|
||||
|
||||
async function preparePaymentChannelClaim(
|
||||
this: Client,
|
||||
address: string,
|
||||
paymentChannelClaim: PaymentChannelClaim,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
const txJSON = createPaymentChannelClaimTransaction(
|
||||
address,
|
||||
paymentChannelClaim,
|
||||
)
|
||||
return await utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default preparePaymentChannelClaim
|
||||
@@ -1,60 +0,0 @@
|
||||
import type { Client } from '..'
|
||||
import { ISOTimeToRippleTime, xrpToDrops } from '../utils'
|
||||
|
||||
import { Instructions, Prepare, TransactionJSON } from './types'
|
||||
import * as utils from './utils'
|
||||
|
||||
export interface PaymentChannelCreate {
|
||||
amount: string
|
||||
destination: string
|
||||
settleDelay: number
|
||||
publicKey: string
|
||||
cancelAfter?: string
|
||||
sourceTag?: number
|
||||
destinationTag?: number
|
||||
}
|
||||
|
||||
function createPaymentChannelCreateTransaction(
|
||||
account: string,
|
||||
paymentChannel: PaymentChannelCreate,
|
||||
): TransactionJSON {
|
||||
const txJSON: any = {
|
||||
Account: account,
|
||||
TransactionType: 'PaymentChannelCreate',
|
||||
Amount: xrpToDrops(paymentChannel.amount),
|
||||
Destination: paymentChannel.destination,
|
||||
SettleDelay: paymentChannel.settleDelay,
|
||||
PublicKey: paymentChannel.publicKey.toUpperCase(),
|
||||
}
|
||||
|
||||
if (paymentChannel.cancelAfter != null) {
|
||||
txJSON.CancelAfter = ISOTimeToRippleTime(paymentChannel.cancelAfter)
|
||||
}
|
||||
if (paymentChannel.sourceTag != null) {
|
||||
txJSON.SourceTag = paymentChannel.sourceTag
|
||||
}
|
||||
if (paymentChannel.destinationTag != null) {
|
||||
txJSON.DestinationTag = paymentChannel.destinationTag
|
||||
}
|
||||
|
||||
return txJSON
|
||||
}
|
||||
|
||||
async function preparePaymentChannelCreate(
|
||||
this: Client,
|
||||
address: string,
|
||||
paymentChannelCreate: PaymentChannelCreate,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
const txJSON = createPaymentChannelCreateTransaction(
|
||||
address,
|
||||
paymentChannelCreate,
|
||||
)
|
||||
return await utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default preparePaymentChannelCreate
|
||||
@@ -1,48 +0,0 @@
|
||||
import type { Client } from '..'
|
||||
import { ISOTimeToRippleTime, xrpToDrops } from '../utils'
|
||||
|
||||
import { Instructions, Prepare, TransactionJSON } from './types'
|
||||
import * as utils from './utils'
|
||||
|
||||
export interface PaymentChannelFund {
|
||||
channel: string
|
||||
amount: string
|
||||
expiration?: string
|
||||
}
|
||||
|
||||
function createPaymentChannelFundTransaction(
|
||||
account: string,
|
||||
fund: PaymentChannelFund,
|
||||
): TransactionJSON {
|
||||
const txJSON: TransactionJSON = {
|
||||
Account: account,
|
||||
TransactionType: 'PaymentChannelFund',
|
||||
Channel: fund.channel,
|
||||
Amount: xrpToDrops(fund.amount),
|
||||
}
|
||||
|
||||
if (fund.expiration != null) {
|
||||
txJSON.Expiration = ISOTimeToRippleTime(fund.expiration)
|
||||
}
|
||||
|
||||
return txJSON
|
||||
}
|
||||
|
||||
async function preparePaymentChannelFund(
|
||||
this: Client,
|
||||
address: string,
|
||||
paymentChannelFund: PaymentChannelFund,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
const txJSON = createPaymentChannelFundTransaction(
|
||||
address,
|
||||
paymentChannelFund,
|
||||
)
|
||||
return await utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default preparePaymentChannelFund
|
||||
@@ -1,261 +0,0 @@
|
||||
import _ from 'lodash'
|
||||
|
||||
import type { Client } from '../client'
|
||||
import {
|
||||
Amount,
|
||||
Adjustment,
|
||||
MaxAdjustment,
|
||||
MinAdjustment,
|
||||
Memo,
|
||||
} from '../common/types/objects'
|
||||
import { toRippledAmount, xrpToDrops } from '../utils'
|
||||
|
||||
import { Instructions, Prepare, TransactionJSON } from './types'
|
||||
import * as utils from './utils'
|
||||
import { getClassicAccountAndTag, ClassicAccountAndTag } from './utils'
|
||||
|
||||
const paymentFlags = utils.common.txFlags.Payment
|
||||
const ValidationError = utils.common.errors.ValidationError
|
||||
|
||||
export interface Payment {
|
||||
source: Adjustment | MaxAdjustment
|
||||
destination: Adjustment | MinAdjustment
|
||||
paths?: string
|
||||
memos?: Memo[]
|
||||
// A 256-bit hash that can be used to identify a particular payment
|
||||
invoiceID?: string
|
||||
// A boolean that, if set to true, indicates that this payment should go
|
||||
// through even if the whole amount cannot be delivered because of a lack of
|
||||
// liquidity or funds in the source_account account
|
||||
allowPartialPayment?: boolean
|
||||
// A boolean that can be set to true if paths are specified and the sender
|
||||
// would like the Ripple Network to disregard any direct paths from
|
||||
// the source_account to the destination_account. This may be used to take
|
||||
// advantage of an arbitrage opportunity or by gateways wishing to issue
|
||||
// balances from a hot wallet to a user who has mistakenly set a trustline
|
||||
// directly to the hot wallet
|
||||
noDirectRipple?: boolean
|
||||
limitQuality?: boolean
|
||||
}
|
||||
|
||||
function isMaxAdjustment(
|
||||
source: Adjustment | MaxAdjustment,
|
||||
): source is MaxAdjustment {
|
||||
return (source as MaxAdjustment).maxAmount != null
|
||||
}
|
||||
|
||||
function isMinAdjustment(
|
||||
destination: Adjustment | MinAdjustment,
|
||||
): destination is MinAdjustment {
|
||||
return (destination as MinAdjustment).minAmount != null
|
||||
}
|
||||
|
||||
function isXRPToXRPPayment(payment: Payment): boolean {
|
||||
const { source, destination } = payment
|
||||
const sourceCurrency = isMaxAdjustment(source)
|
||||
? source.maxAmount.currency
|
||||
: source.amount.currency
|
||||
const destinationCurrency = isMinAdjustment(destination)
|
||||
? destination.minAmount.currency
|
||||
: destination.amount.currency
|
||||
return (
|
||||
(sourceCurrency === 'XRP' || sourceCurrency === 'drops') &&
|
||||
(destinationCurrency === 'XRP' || destinationCurrency === 'drops')
|
||||
)
|
||||
}
|
||||
|
||||
function isIOUWithoutCounterparty(amount: Amount): boolean {
|
||||
return (
|
||||
amount &&
|
||||
amount.currency !== 'XRP' &&
|
||||
amount.currency !== 'drops' &&
|
||||
amount.counterparty == null
|
||||
)
|
||||
}
|
||||
|
||||
function applyAnyCounterpartyEncoding(payment: Payment): void {
|
||||
// Convert blank counterparty to sender or receiver's address
|
||||
// (Ripple convention for 'any counterparty')
|
||||
// https://developers.ripple.com/payment.html#special-issuer-values-for-sendmax-and-amount
|
||||
;[payment.source, payment.destination].forEach((adjustment) => {
|
||||
;['amount', 'minAmount', 'maxAmount'].forEach((key) => {
|
||||
if (isIOUWithoutCounterparty(adjustment[key])) {
|
||||
adjustment[key].counterparty = adjustment.address
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function createMaximalAmount(amount: Amount): Amount {
|
||||
const maxXRPValue = '100000000000'
|
||||
|
||||
// Equivalent to '9999999999999999e80' but we cannot use that because sign()
|
||||
// now checks that the encoded representation exactly matches the transaction
|
||||
// as it was originally provided.
|
||||
const maxIOUValue =
|
||||
'999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000'
|
||||
|
||||
let maxValue
|
||||
if (amount.currency === 'XRP') {
|
||||
maxValue = maxXRPValue
|
||||
} else if (amount.currency === 'drops') {
|
||||
maxValue = xrpToDrops(maxXRPValue)
|
||||
} else {
|
||||
maxValue = maxIOUValue
|
||||
}
|
||||
return { ...amount, value: maxValue }
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an address and tag:
|
||||
* 1. Get the classic account and tag;
|
||||
* 2. If a tag is provided:
|
||||
* 2a. If the address was an X-address, validate that the X-address has the expected tag;
|
||||
* 2b. If the address was a classic address, return `expectedTag` as the tag.
|
||||
* 3. If we do not want to use a tag in this case,
|
||||
* set the tag in the return value to `undefined`.
|
||||
*
|
||||
* @param address - The address to parse.
|
||||
* @param expectedTag - If provided, and the `Account` is an X-address,
|
||||
* this method throws an error if `expectedTag`
|
||||
* does not match the tag of the X-address.
|
||||
* @returns
|
||||
* The classic account and tag.
|
||||
*/
|
||||
function validateAndNormalizeAddress(
|
||||
address: string,
|
||||
expectedTag: number | undefined,
|
||||
): ClassicAccountAndTag {
|
||||
const classicAddress = getClassicAccountAndTag(address, expectedTag)
|
||||
classicAddress.tag =
|
||||
classicAddress.tag === false ? undefined : classicAddress.tag
|
||||
return classicAddress
|
||||
}
|
||||
|
||||
function createPaymentTransaction(
|
||||
address: string,
|
||||
paymentArgument: Payment,
|
||||
): TransactionJSON {
|
||||
const payment = _.cloneDeep(paymentArgument)
|
||||
applyAnyCounterpartyEncoding(payment)
|
||||
|
||||
const sourceAddressAndTag = validateAndNormalizeAddress(
|
||||
payment.source.address,
|
||||
payment.source.tag,
|
||||
)
|
||||
const addressToVerifyAgainst = validateAndNormalizeAddress(address, undefined)
|
||||
if (
|
||||
addressToVerifyAgainst.classicAccount !== sourceAddressAndTag.classicAccount
|
||||
) {
|
||||
throw new ValidationError('address must match payment.source.address')
|
||||
}
|
||||
|
||||
if (
|
||||
addressToVerifyAgainst.tag != null &&
|
||||
sourceAddressAndTag.tag != null &&
|
||||
addressToVerifyAgainst.tag !== sourceAddressAndTag.tag
|
||||
) {
|
||||
throw new ValidationError(
|
||||
'address includes a tag that does not match payment.source.tag',
|
||||
)
|
||||
}
|
||||
|
||||
const destinationAddressAndTag = validateAndNormalizeAddress(
|
||||
payment.destination.address,
|
||||
payment.destination.tag,
|
||||
)
|
||||
|
||||
if (
|
||||
(isMaxAdjustment(payment.source) && isMinAdjustment(payment.destination)) ||
|
||||
(!isMaxAdjustment(payment.source) && !isMinAdjustment(payment.destination))
|
||||
) {
|
||||
throw new ValidationError(
|
||||
'payment must specify either (source.maxAmount ' +
|
||||
'and destination.amount) or (source.amount and destination.minAmount)',
|
||||
)
|
||||
}
|
||||
|
||||
const destinationAmount = isMinAdjustment(payment.destination)
|
||||
? payment.destination.minAmount
|
||||
: payment.destination.amount
|
||||
const sourceAmount = isMaxAdjustment(payment.source)
|
||||
? payment.source.maxAmount
|
||||
: payment.source.amount
|
||||
|
||||
// when using destination.minAmount, rippled still requires that we set
|
||||
// a destination amount in addition to DeliverMin. the destination amount
|
||||
// is interpreted as the maximum amount to send. we want to be sure to
|
||||
// send the whole source amount, so we set the destination amount to the
|
||||
// maximum possible amount. otherwise it's possible that the destination
|
||||
// cap could be hit before the source cap.
|
||||
const amount =
|
||||
isMinAdjustment(payment.destination) && !isXRPToXRPPayment(payment)
|
||||
? createMaximalAmount(destinationAmount)
|
||||
: destinationAmount
|
||||
|
||||
const txJSON: any = {
|
||||
TransactionType: 'Payment',
|
||||
Account: sourceAddressAndTag.classicAccount,
|
||||
Destination: destinationAddressAndTag.classicAccount,
|
||||
Amount: toRippledAmount(amount),
|
||||
Flags: 0,
|
||||
}
|
||||
|
||||
if (payment.invoiceID != null) {
|
||||
txJSON.InvoiceID = payment.invoiceID
|
||||
}
|
||||
if (sourceAddressAndTag.tag != null) {
|
||||
txJSON.SourceTag = sourceAddressAndTag.tag
|
||||
}
|
||||
if (destinationAddressAndTag.tag != null) {
|
||||
txJSON.DestinationTag = destinationAddressAndTag.tag
|
||||
}
|
||||
if (payment.memos != null) {
|
||||
txJSON.Memos = payment.memos.map(utils.convertMemo)
|
||||
}
|
||||
if (payment.noDirectRipple) {
|
||||
txJSON.Flags |= paymentFlags.NoRippleDirect
|
||||
}
|
||||
if (payment.limitQuality) {
|
||||
txJSON.Flags |= paymentFlags.LimitQuality
|
||||
}
|
||||
if (!isXRPToXRPPayment(payment)) {
|
||||
// Don't set SendMax for XRP->XRP payment
|
||||
// temREDUNDANT_SEND_MAX removed in:
|
||||
// https://github.com/ripple/rippled/commit/
|
||||
// c522ffa6db2648f1d8a987843e7feabf1a0b7de8/
|
||||
if (payment.allowPartialPayment || isMinAdjustment(payment.destination)) {
|
||||
txJSON.Flags |= paymentFlags.PartialPayment
|
||||
}
|
||||
|
||||
txJSON.SendMax = toRippledAmount(sourceAmount)
|
||||
|
||||
if (isMinAdjustment(payment.destination)) {
|
||||
txJSON.DeliverMin = toRippledAmount(destinationAmount)
|
||||
}
|
||||
|
||||
if (payment.paths != null) {
|
||||
txJSON.Paths = JSON.parse(payment.paths)
|
||||
}
|
||||
} else if (payment.allowPartialPayment) {
|
||||
throw new ValidationError('XRP to XRP payments cannot be partial payments')
|
||||
}
|
||||
|
||||
return txJSON
|
||||
}
|
||||
|
||||
async function preparePayment(
|
||||
this: Client,
|
||||
address: string,
|
||||
payment: Payment,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
const txJSON = createPaymentTransaction(address, payment)
|
||||
return await utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default preparePayment
|
||||
@@ -1,163 +0,0 @@
|
||||
import * as assert from 'assert'
|
||||
|
||||
import BigNumber from 'bignumber.js'
|
||||
|
||||
import type { Client } from '..'
|
||||
import { FormattedSettings, WeightedSigner } from '../common/types/objects'
|
||||
|
||||
import {
|
||||
Instructions,
|
||||
Prepare,
|
||||
SettingsTransaction,
|
||||
TransactionJSON,
|
||||
} from './types'
|
||||
import * as utils from './utils'
|
||||
|
||||
const AccountSetFlags = utils.common.constants.AccountSetFlags
|
||||
const AccountFields = utils.common.constants.AccountFields
|
||||
|
||||
function setTransactionFlags(
|
||||
txJSON: TransactionJSON,
|
||||
values: FormattedSettings,
|
||||
) {
|
||||
const keys = Object.keys(values).filter((key) => AccountSetFlags[key] != null)
|
||||
assert.ok(keys.length <= 1, 'ERROR: can only set one setting per transaction')
|
||||
const flagName = keys[0]
|
||||
const value = values[flagName]
|
||||
const index = AccountSetFlags[flagName]
|
||||
if (index != null) {
|
||||
if (value) {
|
||||
txJSON.SetFlag = index
|
||||
} else {
|
||||
txJSON.ClearFlag = index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sets `null` fields to their `default`.
|
||||
function setTransactionFields(
|
||||
txJSON: TransactionJSON,
|
||||
input: FormattedSettings,
|
||||
) {
|
||||
const fieldSchema = AccountFields
|
||||
for (const fieldName in fieldSchema) {
|
||||
const field = fieldSchema[fieldName]
|
||||
let value = input[field.name]
|
||||
|
||||
if (value === undefined) {
|
||||
continue
|
||||
}
|
||||
|
||||
// The value required to clear an account root field varies
|
||||
if (value === null && field.hasOwnProperty('defaults')) {
|
||||
value = field.defaults
|
||||
}
|
||||
|
||||
if (field.encoding === 'hex' && !field.length) {
|
||||
// This is currently only used for Domain field
|
||||
value = Buffer.from(value, 'ascii').toString('hex').toUpperCase()
|
||||
}
|
||||
|
||||
txJSON[fieldName] = value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: A fee of 1% requires 101% of the destination to be sent for the
|
||||
* destination to receive 100%.
|
||||
* The transfer rate is specified as the input amount as fraction of 1.
|
||||
* To specify the default rate of 0%, a 100% input amount, specify 1.
|
||||
* To specify a rate of 1%, a 101% input amount, specify 1.01.
|
||||
*
|
||||
* @param {Number|String} transferRate
|
||||
*
|
||||
* @returns {Number|String} Numbers will be converted while strings
|
||||
* are returned.
|
||||
*/
|
||||
|
||||
function convertTransferRate(transferRate: number): number {
|
||||
return new BigNumber(transferRate).shiftedBy(9).toNumber()
|
||||
}
|
||||
|
||||
function formatSignerEntry(signer: WeightedSigner): object {
|
||||
return {
|
||||
SignerEntry: {
|
||||
Account: signer.address,
|
||||
SignerWeight: signer.weight,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function createSettingsTransactionWithoutMemos(
|
||||
account: string,
|
||||
settings: FormattedSettings,
|
||||
): SettingsTransaction {
|
||||
if (settings.regularKey !== undefined) {
|
||||
const removeRegularKey = {
|
||||
TransactionType: 'SetRegularKey',
|
||||
Account: account,
|
||||
}
|
||||
if (settings.regularKey === null) {
|
||||
return removeRegularKey
|
||||
}
|
||||
return { ...removeRegularKey, RegularKey: settings.regularKey }
|
||||
}
|
||||
|
||||
if (settings.signers != null) {
|
||||
const setSignerList: SettingsTransaction = {
|
||||
TransactionType: 'SignerListSet',
|
||||
Account: account,
|
||||
SignerEntries: [],
|
||||
SignerQuorum: settings.signers.threshold,
|
||||
}
|
||||
|
||||
if (settings.signers.weights != null) {
|
||||
setSignerList.SignerEntries =
|
||||
settings.signers.weights.map(formatSignerEntry)
|
||||
}
|
||||
return setSignerList
|
||||
}
|
||||
|
||||
const txJSON: SettingsTransaction = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: account,
|
||||
}
|
||||
|
||||
const settingsWithoutMemos = { ...settings }
|
||||
delete settingsWithoutMemos.memos
|
||||
setTransactionFlags(txJSON, settingsWithoutMemos)
|
||||
setTransactionFields(txJSON, settings) // Sets `null` fields to their `default`.
|
||||
|
||||
if (txJSON.TransferRate != null) {
|
||||
txJSON.TransferRate = convertTransferRate(txJSON.TransferRate)
|
||||
}
|
||||
return txJSON
|
||||
}
|
||||
|
||||
function createSettingsTransaction(
|
||||
account: string,
|
||||
settings: FormattedSettings,
|
||||
): SettingsTransaction {
|
||||
const txJSON = createSettingsTransactionWithoutMemos(account, settings)
|
||||
if (settings.memos != null) {
|
||||
txJSON.Memos = settings.memos.map(utils.convertMemo)
|
||||
}
|
||||
return txJSON
|
||||
}
|
||||
|
||||
async function prepareSettings(
|
||||
this: Client,
|
||||
address: string,
|
||||
settings: FormattedSettings,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
const txJSON = createSettingsTransaction(address, settings)
|
||||
|
||||
return await utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default prepareSettings
|
||||
@@ -5,10 +5,11 @@ import keypairs from 'ripple-keypairs'
|
||||
|
||||
import type { Client, Wallet } from '..'
|
||||
import { ValidationError } from '../common/errors'
|
||||
import { Transaction } from '../models/transactions'
|
||||
import { xrpToDrops } from '../utils'
|
||||
import { computeSignedTransactionHash } from '../utils/hashes'
|
||||
|
||||
import { SignOptions, KeyPair, TransactionJSON } from './types'
|
||||
import { SignOptions, KeyPair } from './types'
|
||||
|
||||
function computeSignature(tx: object, privateKey: string, signAs?: string) {
|
||||
const signingData = signAs
|
||||
@@ -140,7 +141,7 @@ function objectDiff(a: object, b: object): object {
|
||||
*
|
||||
* @returns This method does not return a value, but throws an error if the check fails.
|
||||
*/
|
||||
function checkTxSerialization(serialized: string, tx: TransactionJSON): void {
|
||||
function checkTxSerialization(serialized: string, tx: Transaction): void {
|
||||
// Decode the serialized transaction:
|
||||
const decoded = binaryCodec.decode(serialized)
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import _ from 'lodash'
|
||||
|
||||
import type { Client } from '..'
|
||||
|
||||
import { Prepare, TransactionJSON, Instructions } from './types'
|
||||
import * as utils from './utils'
|
||||
|
||||
const ValidationError = utils.common.errors.ValidationError
|
||||
|
||||
export interface Ticket {
|
||||
account: string
|
||||
sequence: number
|
||||
}
|
||||
|
||||
function createTicketTransaction(
|
||||
account: string,
|
||||
ticketCount: number,
|
||||
): TransactionJSON {
|
||||
if (!ticketCount || ticketCount === 0) {
|
||||
throw new ValidationError('Ticket count must be greater than 0.')
|
||||
}
|
||||
|
||||
const txJSON: any = {
|
||||
TransactionType: 'TicketCreate',
|
||||
Account: account,
|
||||
TicketCount: ticketCount,
|
||||
}
|
||||
|
||||
return txJSON
|
||||
}
|
||||
|
||||
async function prepareTicketCreate(
|
||||
this: Client,
|
||||
address: string,
|
||||
ticketCount: number,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
const txJSON = createTicketTransaction(address, ticketCount)
|
||||
return await utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default prepareTicketCreate
|
||||
@@ -1,73 +0,0 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
|
||||
import type { Client } from '..'
|
||||
import { FormattedTrustlineSpecification } from '../common/types/objects/trustlines'
|
||||
|
||||
import { Instructions, Prepare, TransactionJSON } from './types'
|
||||
import * as utils from './utils'
|
||||
|
||||
const trustlineFlags = utils.common.txFlags.TrustSet
|
||||
|
||||
function convertQuality(quality) {
|
||||
return new BigNumber(quality)
|
||||
.shiftedBy(9)
|
||||
.integerValue(BigNumber.ROUND_DOWN)
|
||||
.toNumber()
|
||||
}
|
||||
|
||||
function createTrustlineTransaction(
|
||||
account: string,
|
||||
trustline: FormattedTrustlineSpecification,
|
||||
): TransactionJSON {
|
||||
const limit = {
|
||||
currency: trustline.currency,
|
||||
issuer: trustline.counterparty,
|
||||
value: trustline.limit,
|
||||
}
|
||||
|
||||
const txJSON: any = {
|
||||
TransactionType: 'TrustSet',
|
||||
Account: account,
|
||||
LimitAmount: limit,
|
||||
Flags: 0,
|
||||
}
|
||||
if (trustline.qualityIn != null) {
|
||||
txJSON.QualityIn = convertQuality(trustline.qualityIn)
|
||||
}
|
||||
if (trustline.qualityOut != null) {
|
||||
txJSON.QualityOut = convertQuality(trustline.qualityOut)
|
||||
}
|
||||
if (trustline.authorized) {
|
||||
txJSON.Flags |= trustlineFlags.SetAuth
|
||||
}
|
||||
if (trustline.ripplingDisabled != null) {
|
||||
txJSON.Flags |= trustline.ripplingDisabled
|
||||
? trustlineFlags.NoRipple
|
||||
: trustlineFlags.ClearNoRipple
|
||||
}
|
||||
if (trustline.frozen != null) {
|
||||
txJSON.Flags |= trustline.frozen
|
||||
? trustlineFlags.SetFreeze
|
||||
: trustlineFlags.ClearFreeze
|
||||
}
|
||||
if (trustline.memos != null) {
|
||||
txJSON.Memos = trustline.memos.map(utils.convertMemo)
|
||||
}
|
||||
return txJSON
|
||||
}
|
||||
|
||||
async function prepareTrustline(
|
||||
this: Client,
|
||||
address: string,
|
||||
trustline: FormattedTrustlineSpecification,
|
||||
instructions: Instructions = {},
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
const txJSON = createTrustlineTransaction(address, trustline)
|
||||
return await utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default prepareTrustline
|
||||
@@ -1,44 +1,3 @@
|
||||
import {
|
||||
FormattedOrderSpecification,
|
||||
FormattedTrustlineSpecification,
|
||||
Adjustment,
|
||||
RippledAmount,
|
||||
Memo,
|
||||
FormattedSettings,
|
||||
} from '../common/types/objects'
|
||||
|
||||
import { ApiMemo } from './utils'
|
||||
|
||||
export interface TransactionJSON {
|
||||
Account: string
|
||||
TransactionType: string
|
||||
Memos?: Array<{ Memo: ApiMemo }>
|
||||
Flags?: number
|
||||
Fulfillment?: string
|
||||
[Field: string]: string | number | any[] | RippledAmount | undefined
|
||||
}
|
||||
|
||||
export interface Instructions {
|
||||
sequence?: number
|
||||
ticketSequence?: number
|
||||
fee?: string
|
||||
// @deprecated
|
||||
maxFee?: string
|
||||
maxLedgerVersion?: number
|
||||
maxLedgerVersionOffset?: number
|
||||
signersCount?: number
|
||||
}
|
||||
|
||||
export interface Prepare {
|
||||
txJSON: string
|
||||
instructions: {
|
||||
fee: string
|
||||
sequence?: number
|
||||
ticketSequence?: number
|
||||
maxLedgerVersion?: number
|
||||
}
|
||||
}
|
||||
|
||||
export interface Submit {
|
||||
success: boolean
|
||||
engineResult: string
|
||||
@@ -48,24 +7,6 @@ export interface Submit {
|
||||
txJson?: object
|
||||
}
|
||||
|
||||
export interface OfferCreateTransaction extends TransactionJSON {
|
||||
TransactionType: 'OfferCreate'
|
||||
Account: string
|
||||
Fee: string
|
||||
Flags: number
|
||||
LastLedgerSequence: number
|
||||
Sequence: number
|
||||
TakerGets: RippledAmount
|
||||
TakerPays: RippledAmount
|
||||
Expiration?: number
|
||||
OfferSequence?: number
|
||||
Memos?: Array<{ Memo: ApiMemo }>
|
||||
}
|
||||
|
||||
export interface SettingsTransaction extends TransactionJSON {
|
||||
TransferRate?: number
|
||||
}
|
||||
|
||||
export interface KeyPair {
|
||||
publicKey: string
|
||||
privateKey: string
|
||||
@@ -95,70 +36,3 @@ export interface Outcome {
|
||||
}
|
||||
timestamp?: string
|
||||
}
|
||||
|
||||
export interface FormattedOrderCancellation {
|
||||
orderSequence: number
|
||||
}
|
||||
|
||||
export interface FormattedPayment {
|
||||
source: Adjustment
|
||||
destination: Adjustment
|
||||
paths?: string
|
||||
memos?: Memo[]
|
||||
invoiceID?: string
|
||||
allowPartialPayment?: boolean
|
||||
noDirectRipple?: boolean
|
||||
limitQuality?: boolean
|
||||
}
|
||||
|
||||
export interface FormattedPaymentTransaction {
|
||||
type: string
|
||||
specification: FormattedPayment
|
||||
outcome: Outcome
|
||||
id: string
|
||||
address: string
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export interface FormattedOrderTransaction {
|
||||
type: string
|
||||
specification: FormattedOrderSpecification
|
||||
outcome: Outcome
|
||||
id: string
|
||||
address: string
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export interface FormattedOrderCancellationTransaction {
|
||||
type: string
|
||||
specification: FormattedOrderCancellation
|
||||
outcome: Outcome
|
||||
id: string
|
||||
address: string
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export interface FormattedTrustlineTransaction {
|
||||
type: string
|
||||
specification: FormattedTrustlineSpecification
|
||||
outcome: Outcome
|
||||
id: string
|
||||
address: string
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export interface FormattedSettingsTransaction {
|
||||
type: string
|
||||
specification: FormattedSettings
|
||||
outcome: Outcome
|
||||
id: string
|
||||
address: string
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type FormattedTransactionType =
|
||||
| FormattedPaymentTransaction
|
||||
| FormattedOrderTransaction
|
||||
| FormattedOrderCancellationTransaction
|
||||
| FormattedTrustlineTransaction
|
||||
| FormattedSettingsTransaction
|
||||
|
||||
@@ -1,418 +0,0 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { xAddressToClassicAddress, isValidXAddress } from 'ripple-address-codec'
|
||||
|
||||
import type { Client } from '..'
|
||||
import * as common from '../common'
|
||||
import { ValidationError } from '../common/errors'
|
||||
import { Memo } from '../common/types/objects'
|
||||
import {
|
||||
toRippledAmount,
|
||||
dropsToXrp,
|
||||
removeUndefined,
|
||||
xrpToDrops,
|
||||
} from '../utils'
|
||||
|
||||
import { Instructions, Prepare, TransactionJSON } from './types'
|
||||
|
||||
const txFlags = common.txFlags
|
||||
const TRANSACTION_TYPES_WITH_DESTINATION_TAG_FIELD = [
|
||||
'Payment',
|
||||
'CheckCreate',
|
||||
'EscrowCreate',
|
||||
'PaymentChannelCreate',
|
||||
]
|
||||
|
||||
export interface ApiMemo {
|
||||
MemoData?: string
|
||||
MemoType?: string
|
||||
MemoFormat?: string
|
||||
}
|
||||
|
||||
// TODO: move relevant methods from here to `src/utils` (such as `convertStringToHex`?)
|
||||
|
||||
function formatPrepareResponse(txJSON: any): Prepare {
|
||||
const instructions: any = {
|
||||
fee: dropsToXrp(txJSON.Fee),
|
||||
maxLedgerVersion:
|
||||
txJSON.LastLedgerSequence == null ? null : txJSON.LastLedgerSequence,
|
||||
}
|
||||
if (txJSON.TicketSequence != null) {
|
||||
instructions.ticketSequence = txJSON.TicketSequence
|
||||
} else {
|
||||
instructions.sequence = txJSON.Sequence
|
||||
}
|
||||
return {
|
||||
txJSON: JSON.stringify(txJSON),
|
||||
instructions,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the `tfFullyCanonicalSig` flag on a transaction.
|
||||
*
|
||||
* See https://xrpl.org/transaction-malleability.html.
|
||||
*
|
||||
* @param txJSON - The transaction object to modify.
|
||||
* This method will modify object's `Flags` property, or add it if it does not exist.
|
||||
*
|
||||
* @returns This method mutates the original txJSON and does not return a value.
|
||||
*/
|
||||
function setCanonicalFlag(txJSON: TransactionJSON): void {
|
||||
if (txJSON.Flags == null) {
|
||||
txJSON.Flags = 0
|
||||
}
|
||||
|
||||
txJSON.Flags |= txFlags.Universal.FullyCanonicalSig
|
||||
|
||||
// JavaScript converts operands to 32-bit signed ints before doing bitwise
|
||||
// operations. We need to convert it back to an unsigned int.
|
||||
txJSON.Flags >>>= 0
|
||||
}
|
||||
|
||||
function scaleValue(value, multiplier, extra = 0) {
|
||||
return new BigNumber(value).times(multiplier).plus(extra).toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} ClassicAccountAndTag
|
||||
* @property {string} classicAccount - The classic account address.
|
||||
* @property {number | false | undefined } tag - The destination tag;
|
||||
* `false` if no tag should be used;
|
||||
* `undefined` if the input could not specify whether a tag should be used.
|
||||
*/
|
||||
export interface ClassicAccountAndTag {
|
||||
classicAccount: string
|
||||
tag: number | false | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an address (account), get the classic account and tag.
|
||||
* If an `expectedTag` is provided:
|
||||
* 1. If the `Account` is an X-address, validate that the tags match.
|
||||
* 2. If the `Account` is a classic address, return `expectedTag` as the tag.
|
||||
*
|
||||
* @param Account - The address to parse.
|
||||
* @param expectedTag - If provided, and the `Account` is an X-address,
|
||||
* this method throws an error if `expectedTag`
|
||||
* does not match the tag of the X-address.
|
||||
* @returns
|
||||
* The classic account and tag.
|
||||
*/
|
||||
function getClassicAccountAndTag(
|
||||
Account: string,
|
||||
expectedTag?: number,
|
||||
): ClassicAccountAndTag {
|
||||
if (isValidXAddress(Account)) {
|
||||
const classic = xAddressToClassicAddress(Account)
|
||||
if (expectedTag != null && classic.tag !== expectedTag) {
|
||||
throw new ValidationError(
|
||||
'address includes a tag that does not match the tag specified in the transaction',
|
||||
)
|
||||
}
|
||||
return {
|
||||
classicAccount: classic.classicAddress,
|
||||
tag: classic.tag,
|
||||
}
|
||||
}
|
||||
return {
|
||||
classicAccount: Account,
|
||||
tag: expectedTag,
|
||||
}
|
||||
}
|
||||
|
||||
async function prepareTransaction(
|
||||
txJSON: TransactionJSON,
|
||||
client: Client,
|
||||
instructions: Instructions,
|
||||
): Promise<Prepare> {
|
||||
// We allow 0 values in the Sequence schema to support the Tickets feature
|
||||
// When a ticketSequence is used, sequence has to be 0
|
||||
// We validate that a sequence with value 0 is not passed even if the json schema allows it
|
||||
if (instructions.sequence != null && instructions.sequence === 0) {
|
||||
return Promise.reject(new ValidationError('`sequence` cannot be 0'))
|
||||
}
|
||||
|
||||
const disallowedFieldsInTxJSON = [
|
||||
'maxLedgerVersion',
|
||||
'maxLedgerVersionOffset',
|
||||
'fee',
|
||||
'sequence',
|
||||
'ticketSequence',
|
||||
]
|
||||
const badFields = disallowedFieldsInTxJSON.filter((field) => txJSON[field])
|
||||
if (badFields.length) {
|
||||
return Promise.reject(
|
||||
new ValidationError(
|
||||
`txJSON additionalProperty "${badFields[0]}" exists in instance when not allowed`,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
const newTxJSON = { ...txJSON }
|
||||
|
||||
// To remove the signer list, `SignerEntries` field should be omitted.
|
||||
if (txJSON.SignerQuorum === 0) {
|
||||
delete newTxJSON.SignerEntries
|
||||
}
|
||||
|
||||
// Sender:
|
||||
const { classicAccount, tag: sourceTag } = getClassicAccountAndTag(
|
||||
txJSON.Account,
|
||||
)
|
||||
newTxJSON.Account = classicAccount
|
||||
if (sourceTag != null) {
|
||||
if (txJSON.SourceTag && txJSON.SourceTag !== sourceTag) {
|
||||
return Promise.reject(
|
||||
new ValidationError(
|
||||
'The `SourceTag`, if present, must match the tag of the `Account` X-address',
|
||||
),
|
||||
)
|
||||
}
|
||||
if (sourceTag) {
|
||||
newTxJSON.SourceTag = sourceTag
|
||||
}
|
||||
}
|
||||
|
||||
// Destination:
|
||||
if (typeof txJSON.Destination === 'string') {
|
||||
const { classicAccount: destinationAccount, tag: destinationTag } =
|
||||
getClassicAccountAndTag(txJSON.Destination)
|
||||
newTxJSON.Destination = destinationAccount
|
||||
if (destinationTag != null) {
|
||||
if (
|
||||
TRANSACTION_TYPES_WITH_DESTINATION_TAG_FIELD.includes(
|
||||
txJSON.TransactionType,
|
||||
)
|
||||
) {
|
||||
if (txJSON.DestinationTag && txJSON.DestinationTag !== destinationTag) {
|
||||
return Promise.reject(
|
||||
new ValidationError(
|
||||
'The Payment `DestinationTag`, if present, must match the tag of the `Destination` X-address',
|
||||
),
|
||||
)
|
||||
}
|
||||
if (destinationTag) {
|
||||
newTxJSON.DestinationTag = destinationTag
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function convertToClassicAccountIfPresent(fieldName: string): void {
|
||||
const account = txJSON[fieldName]
|
||||
if (typeof account === 'string') {
|
||||
const { classicAccount: ca } = getClassicAccountAndTag(account)
|
||||
newTxJSON[fieldName] = ca
|
||||
}
|
||||
}
|
||||
|
||||
function convertIssuedCurrencyToAccountIfPresent(fieldName: string): void {
|
||||
const amount = txJSON[fieldName]
|
||||
if (
|
||||
typeof amount === 'number' ||
|
||||
amount instanceof Array ||
|
||||
amount == null
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
newTxJSON[fieldName] = toRippledAmount(amount)
|
||||
}
|
||||
|
||||
// DepositPreauth:
|
||||
convertToClassicAccountIfPresent('Authorize')
|
||||
convertToClassicAccountIfPresent('Unauthorize')
|
||||
|
||||
// EscrowCancel, EscrowFinish:
|
||||
convertToClassicAccountIfPresent('Owner')
|
||||
|
||||
// SetRegularKey:
|
||||
convertToClassicAccountIfPresent('RegularKey')
|
||||
|
||||
// Payment
|
||||
convertIssuedCurrencyToAccountIfPresent('Amount')
|
||||
convertIssuedCurrencyToAccountIfPresent('SendMax')
|
||||
convertIssuedCurrencyToAccountIfPresent('DeliverMin')
|
||||
|
||||
// OfferCreate
|
||||
convertIssuedCurrencyToAccountIfPresent('TakerPays')
|
||||
convertIssuedCurrencyToAccountIfPresent('TakerGets')
|
||||
|
||||
// TrustSet
|
||||
convertIssuedCurrencyToAccountIfPresent('LimitAmount')
|
||||
|
||||
setCanonicalFlag(newTxJSON)
|
||||
|
||||
async function prepareMaxLedgerVersion(): Promise<void> {
|
||||
// Up to one of the following is allowed:
|
||||
// txJSON.LastLedgerSequence
|
||||
// instructions.maxLedgerVersion
|
||||
// instructions.maxLedgerVersionOffset
|
||||
if (newTxJSON.LastLedgerSequence && instructions.maxLedgerVersion) {
|
||||
return Promise.reject(
|
||||
new ValidationError(
|
||||
'`LastLedgerSequence` in txJSON and `maxLedgerVersion`' +
|
||||
' in `instructions` cannot both be set',
|
||||
),
|
||||
)
|
||||
}
|
||||
if (newTxJSON.LastLedgerSequence && instructions.maxLedgerVersionOffset) {
|
||||
return Promise.reject(
|
||||
new ValidationError(
|
||||
'`LastLedgerSequence` in txJSON and `maxLedgerVersionOffset`' +
|
||||
' in `instructions` cannot both be set',
|
||||
),
|
||||
)
|
||||
}
|
||||
if (newTxJSON.LastLedgerSequence) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
if (instructions.maxLedgerVersion !== undefined) {
|
||||
if (instructions.maxLedgerVersion !== null) {
|
||||
newTxJSON.LastLedgerSequence = instructions.maxLedgerVersion
|
||||
}
|
||||
return Promise.resolve()
|
||||
}
|
||||
const offset =
|
||||
instructions.maxLedgerVersionOffset != null
|
||||
? instructions.maxLedgerVersionOffset
|
||||
: 3
|
||||
return client
|
||||
.request({ command: 'ledger_current' })
|
||||
.then((response) => response.result.ledger_current_index)
|
||||
.then((ledgerVersion) => {
|
||||
newTxJSON.LastLedgerSequence = ledgerVersion + offset
|
||||
})
|
||||
}
|
||||
|
||||
async function prepareFee(): Promise<void> {
|
||||
// instructions.fee is scaled (for multi-signed transactions) while txJSON.Fee is not.
|
||||
// Due to this difference, we do NOT allow both to be set, as the behavior would be complex and
|
||||
// potentially ambiguous.
|
||||
// Furthermore, txJSON.Fee is in drops while instructions.fee is in XRP, which would just add to
|
||||
// the confusion. It is simpler to require that only one is used.
|
||||
if (newTxJSON.Fee && instructions.fee) {
|
||||
return Promise.reject(
|
||||
new ValidationError(
|
||||
'`Fee` in txJSON and `fee` in `instructions` cannot both be set',
|
||||
),
|
||||
)
|
||||
}
|
||||
if (newTxJSON.Fee) {
|
||||
// txJSON.Fee is set. Use this value and do not scale it.
|
||||
return Promise.resolve()
|
||||
}
|
||||
const multiplier =
|
||||
instructions.signersCount == null ? 1 : instructions.signersCount + 1
|
||||
if (instructions.fee != null) {
|
||||
const fee = new BigNumber(instructions.fee)
|
||||
if (fee.isGreaterThan(client.maxFeeXRP)) {
|
||||
return Promise.reject(
|
||||
new ValidationError(
|
||||
`Fee of ${fee.toString(10)} XRP exceeds ` +
|
||||
`max of ${client.maxFeeXRP} XRP. To use this fee, increase ` +
|
||||
'`maxFeeXRP` in the Client constructor.',
|
||||
),
|
||||
)
|
||||
}
|
||||
newTxJSON.Fee = scaleValue(xrpToDrops(instructions.fee), multiplier)
|
||||
return Promise.resolve()
|
||||
}
|
||||
const cushion = client.feeCushion
|
||||
return client.getFee(cushion).then(async (fee) => {
|
||||
return client
|
||||
.request({ command: 'fee' })
|
||||
.then((response) => Number(response.result.drops.minimum_fee))
|
||||
.then((feeRef) => {
|
||||
// feeRef is the reference transaction cost in "fee units"
|
||||
const extraFee =
|
||||
newTxJSON.TransactionType !== 'EscrowFinish' ||
|
||||
newTxJSON.Fulfillment == null
|
||||
? 0
|
||||
: cushion *
|
||||
feeRef *
|
||||
(32 +
|
||||
Math.floor(
|
||||
Buffer.from(newTxJSON.Fulfillment, 'hex').length / 16,
|
||||
))
|
||||
const feeDrops = xrpToDrops(fee)
|
||||
const maxFeeXRP = instructions.maxFee
|
||||
? BigNumber.min(client.maxFeeXRP, instructions.maxFee)
|
||||
: client.maxFeeXRP
|
||||
const maxFeeDrops = xrpToDrops(maxFeeXRP)
|
||||
const normalFee = scaleValue(feeDrops, multiplier, extraFee)
|
||||
newTxJSON.Fee = BigNumber.min(normalFee, maxFeeDrops).toString(10)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function prepareSequence(): Promise<void> {
|
||||
if (instructions.sequence != null) {
|
||||
if (
|
||||
newTxJSON.Sequence == null ||
|
||||
instructions.sequence === newTxJSON.Sequence
|
||||
) {
|
||||
newTxJSON.Sequence = instructions.sequence
|
||||
return Promise.resolve()
|
||||
}
|
||||
// Both txJSON.Sequence and instructions.sequence are defined, and they are NOT equal
|
||||
return Promise.reject(
|
||||
new ValidationError(
|
||||
'`Sequence` in txJSON must match `sequence` in `instructions`',
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (newTxJSON.Sequence != null) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
// Ticket Sequence
|
||||
if (instructions.ticketSequence != null) {
|
||||
newTxJSON.Sequence = 0
|
||||
newTxJSON.TicketSequence = instructions.ticketSequence
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await client.request({
|
||||
command: 'account_info',
|
||||
account: classicAccount,
|
||||
ledger_index: 'current', // Fix #999
|
||||
})
|
||||
newTxJSON.Sequence = response.result.account_data.Sequence
|
||||
return await Promise.resolve()
|
||||
} catch (e) {
|
||||
return await Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all([
|
||||
prepareMaxLedgerVersion(),
|
||||
prepareFee(),
|
||||
prepareSequence(),
|
||||
]).then(() => formatPrepareResponse(newTxJSON))
|
||||
}
|
||||
|
||||
function convertStringToHex(string: string): string {
|
||||
return Buffer.from(string, 'utf8').toString('hex').toUpperCase()
|
||||
}
|
||||
|
||||
function convertMemo(memo: Memo): { Memo: ApiMemo } {
|
||||
return {
|
||||
Memo: removeUndefined({
|
||||
MemoData: memo.data ? convertStringToHex(memo.data) : undefined,
|
||||
MemoType: memo.type ? convertStringToHex(memo.type) : undefined,
|
||||
MemoFormat: memo.format ? convertStringToHex(memo.format) : undefined,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
convertStringToHex,
|
||||
convertMemo,
|
||||
prepareTransaction,
|
||||
common,
|
||||
setCanonicalFlag,
|
||||
getClassicAccountAndTag,
|
||||
}
|
||||
@@ -213,6 +213,10 @@ function ISOTimeToRippleTime(iso8601: string): number {
|
||||
return unixToRippleTimestamp(Date.parse(iso8601))
|
||||
}
|
||||
|
||||
function convertStringToHex(string: string): string {
|
||||
return Buffer.from(string, 'utf8').toString('hex').toUpperCase()
|
||||
}
|
||||
|
||||
export {
|
||||
computeLedgerHeaderHash,
|
||||
dropsToXrp,
|
||||
@@ -240,4 +244,5 @@ export {
|
||||
deriveXAddress,
|
||||
signPaymentChannelClaim,
|
||||
verifyPaymentChannelClaim,
|
||||
convertStringToHex,
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ class Wallet {
|
||||
* @param test - A boolean to indicate if X-address should be in Testnet (true) or Mainnet (false) format.
|
||||
* @returns An X-address.
|
||||
*/
|
||||
getXAddress(tag: number, test = false): string {
|
||||
getXAddress(tag: number | false = false, test = false): string {
|
||||
return classicAddressToXAddress(this.classicAddress, tag, test)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertResultMatch, addressTests } from '../testUtils'
|
||||
|
||||
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
|
||||
|
||||
describe('client.prepareCheckCancel', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
addressTests.forEach(function (test) {
|
||||
describe(test.type, function () {
|
||||
it('prepareCheckCancel', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const result = await this.client.prepareCheckCancel(
|
||||
test.address,
|
||||
requests.prepareCheckCancel.normal,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareCheckCancel.normal,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('with ticket', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23,
|
||||
}
|
||||
const result = await this.client.prepareCheckCancel(
|
||||
test.address,
|
||||
requests.prepareCheckCancel.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareCheckCancel.ticket,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,71 +0,0 @@
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertResultMatch, addressTests } from '../testUtils'
|
||||
|
||||
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
|
||||
|
||||
describe('client.prepareCheckCash', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
addressTests.forEach(function (test) {
|
||||
describe(test.type, function () {
|
||||
it('prepareCheckCash amount', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const result = await this.client.prepareCheckCash(
|
||||
test.address,
|
||||
requests.prepareCheckCash.amount,
|
||||
)
|
||||
assertResultMatch(result, responses.prepareCheckCash.amount, 'prepare')
|
||||
})
|
||||
|
||||
it('prepareCheckCash deliverMin', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const result = await this.client.prepareCheckCash(
|
||||
test.address,
|
||||
requests.prepareCheckCash.deliverMin,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareCheckCash.deliverMin,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('with ticket', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23,
|
||||
}
|
||||
const result = await this.client.prepareCheckCash(
|
||||
test.address,
|
||||
requests.prepareCheckCash.amount,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(result, responses.prepareCheckCash.ticket, 'prepare')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,80 +0,0 @@
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertResultMatch, addressTests } from '../testUtils'
|
||||
|
||||
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
|
||||
|
||||
describe('client.prepareCheckCreate', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
addressTests.forEach(function (test) {
|
||||
describe(test.type, function () {
|
||||
it('prepareCheckCreate', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
}
|
||||
const result = await this.client.prepareCheckCreate(
|
||||
test.address,
|
||||
requests.prepareCheckCreate.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareCheckCreate.normal,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('prepareCheckCreate full', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const result = await this.client.prepareCheckCreate(
|
||||
test.address,
|
||||
requests.prepareCheckCreate.full,
|
||||
)
|
||||
assertResultMatch(result, responses.prepareCheckCreate.full, 'prepare')
|
||||
})
|
||||
|
||||
it('prepareCheckCreate with ticket', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23,
|
||||
}
|
||||
const result = await this.client.prepareCheckCreate(
|
||||
test.address,
|
||||
requests.prepareCheckCreate.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareCheckCreate.ticket,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,80 +0,0 @@
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertResultMatch, addressTests } from '../testUtils'
|
||||
|
||||
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
|
||||
|
||||
describe('client.prepareEscrowCancellation', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
addressTests.forEach(function (test) {
|
||||
describe(test.type, function () {
|
||||
it('prepareEscrowCancellation', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const result = await this.client.prepareEscrowCancellation(
|
||||
test.address,
|
||||
requests.prepareEscrowCancellation.normal,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareEscrowCancellation.normal,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('prepareEscrowCancellation with memos', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const result = await this.client.prepareEscrowCancellation(
|
||||
test.address,
|
||||
requests.prepareEscrowCancellation.memos,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareEscrowCancellation.memos,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('with ticket', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23,
|
||||
}
|
||||
const result = await this.client.prepareEscrowCancellation(
|
||||
test.address,
|
||||
requests.prepareEscrowCancellation.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareEscrowCancellation.ticket,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,74 +0,0 @@
|
||||
import addresses from '../fixtures/addresses.json'
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertResultMatch } from '../testUtils'
|
||||
|
||||
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
|
||||
|
||||
describe('client.prepareEscrowCreation', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('prepareEscrowCreation', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
}
|
||||
const result = await this.client.prepareEscrowCreation(
|
||||
addresses.ACCOUNT,
|
||||
requests.prepareEscrowCreation.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(result, responses.prepareEscrowCreation.normal, 'prepare')
|
||||
})
|
||||
|
||||
it('prepareEscrowCreation full', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
const result = await this.client.prepareEscrowCreation(
|
||||
addresses.ACCOUNT,
|
||||
requests.prepareEscrowCreation.full,
|
||||
)
|
||||
assertResultMatch(result, responses.prepareEscrowCreation.full, 'prepare')
|
||||
})
|
||||
|
||||
// it("prepareEscrowCreation - invalid", async function () {
|
||||
// this.mockRippled.addResponse("server_info", rippled.server_info.normal);
|
||||
// this.mockRippled.addResponse("fee", rippled.fee);
|
||||
// this.mockRippled.addResponse("ledger_current", rippled.ledger_current);
|
||||
// this.mockRippled.addResponse("account_info", rippled.account_info.normal);
|
||||
// const escrow = { ...requests.prepareEscrowCreation.full };
|
||||
// delete escrow.amount; // Make invalid
|
||||
// await assertRejects(
|
||||
// this.client.prepareEscrowCreation(addresses.ACCOUNT, escrow),
|
||||
// this.client.errors.ValidationError,
|
||||
// 'instance.escrowCreation requires property "amount"'
|
||||
// );
|
||||
// });
|
||||
|
||||
it('with ticket', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000396',
|
||||
ticketSequence: 23,
|
||||
}
|
||||
const result = await this.client.prepareEscrowCreation(
|
||||
addresses.ACCOUNT,
|
||||
requests.prepareEscrowCreation.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(result, responses.prepareEscrowCreation.ticket, 'prepare')
|
||||
})
|
||||
})
|
||||
@@ -1,118 +0,0 @@
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { addressTests, assertRejects, assertResultMatch } from '../testUtils'
|
||||
|
||||
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
|
||||
|
||||
describe('client.prepareEscrowExecution', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
addressTests.forEach(function (test) {
|
||||
describe(test.type, function () {
|
||||
it('prepareEscrowExecution', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const result = await this.client.prepareEscrowExecution(
|
||||
test.address,
|
||||
requests.prepareEscrowExecution.normal,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareEscrowExecution.normal,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('prepareEscrowExecution - simple', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const result = await this.client.prepareEscrowExecution(
|
||||
test.address,
|
||||
requests.prepareEscrowExecution.simple,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareEscrowExecution.simple,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('prepareEscrowExecution - no condition', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
await assertRejects(
|
||||
this.client.prepareEscrowExecution(
|
||||
test.address,
|
||||
requests.prepareEscrowExecution.noCondition,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
),
|
||||
this.client.errors.ValidationError,
|
||||
'"condition" and "fulfillment" fields on EscrowFinish must only be specified together.',
|
||||
)
|
||||
})
|
||||
|
||||
it('prepareEscrowExecution - no fulfillment', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
await assertRejects(
|
||||
this.client.prepareEscrowExecution(
|
||||
test.address,
|
||||
requests.prepareEscrowExecution.noFulfillment,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
),
|
||||
this.client.errors.ValidationError,
|
||||
'"condition" and "fulfillment" fields on EscrowFinish must only be specified together.',
|
||||
)
|
||||
})
|
||||
|
||||
it('with ticket', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000396',
|
||||
ticketSequence: 23,
|
||||
}
|
||||
const result = await this.client.prepareEscrowExecution(
|
||||
test.address,
|
||||
requests.prepareEscrowExecution.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareEscrowExecution.ticket,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,107 +0,0 @@
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertResultMatch, addressTests } from '../testUtils'
|
||||
|
||||
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
|
||||
|
||||
describe('client.prepareOrder', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
addressTests.forEach(function (test) {
|
||||
describe(test.type, function () {
|
||||
it('buy order', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const request = requests.prepareOrder.buy
|
||||
const result = await this.client.prepareOrder(test.address, request)
|
||||
assertResultMatch(result, responses.prepareOrder.buy, 'prepare')
|
||||
})
|
||||
|
||||
it('buy order with expiration', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const request = requests.prepareOrder.expiration
|
||||
const response = responses.prepareOrder.expiration
|
||||
const result = await this.client.prepareOrder(
|
||||
test.address,
|
||||
request,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(result, response, 'prepare')
|
||||
})
|
||||
|
||||
it('sell order', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const request = requests.prepareOrder.sell
|
||||
const result = await this.client.prepareOrder(
|
||||
test.address,
|
||||
request,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(result, responses.prepareOrder.sell, 'prepare')
|
||||
})
|
||||
|
||||
// it("invalid", async function () {
|
||||
// this.mockRippled.addResponse("server_info", rippled.server_info.normal);
|
||||
// this.mockRippled.addResponse("fee", rippled.fee);
|
||||
// this.mockRippled.addResponse("ledger_current", rippled.ledger_current);
|
||||
// this.mockRippled.addResponse(
|
||||
// "account_info",
|
||||
// rippled.account_info.normal
|
||||
// );
|
||||
// const request = { ...requests.prepareOrder.sell };
|
||||
// delete request.direction; // Make invalid
|
||||
// await assertRejects(
|
||||
// this.client.prepareOrder(
|
||||
// test.address,
|
||||
// request,
|
||||
// instructionsWithMaxLedgerVersionOffset
|
||||
// ),
|
||||
// this.client.errors.ValidationError,
|
||||
// 'instance.order requires property "direction"'
|
||||
// );
|
||||
// });
|
||||
|
||||
it('with ticket', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const request = requests.prepareOrder.sell
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23,
|
||||
}
|
||||
const result = await this.client.prepareOrder(
|
||||
test.address,
|
||||
request,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(result, responses.prepareOrder.ticket, 'prepare')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,123 +0,0 @@
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertResultMatch, addressTests } from '../testUtils'
|
||||
|
||||
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
|
||||
|
||||
describe('client.prepareOrderCancellation', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
addressTests.forEach(function (test) {
|
||||
describe(test.type, function () {
|
||||
it('prepareOrderCancellation', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const request = requests.prepareOrderCancellation.simple
|
||||
const result = await this.client.prepareOrderCancellation(
|
||||
test.address,
|
||||
request,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareOrderCancellation.normal,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('no instructions', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const request = requests.prepareOrderCancellation.simple
|
||||
const result = await this.client.prepareOrderCancellation(
|
||||
test.address,
|
||||
request,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareOrderCancellation.noInstructions,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('with memos', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const request = requests.prepareOrderCancellation.withMemos
|
||||
const result = await this.client.prepareOrderCancellation(
|
||||
test.address,
|
||||
request,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareOrderCancellation.withMemos,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
// it("invalid", async function () {
|
||||
// this.mockRippled.addResponse("server_info", rippled.server_info.normal);
|
||||
// this.mockRippled.addResponse("fee", rippled.fee);
|
||||
// this.mockRippled.addResponse("ledger_current", rippled.ledger_current);
|
||||
// this.mockRippled.addResponse(
|
||||
// "account_info",
|
||||
// rippled.account_info.normal
|
||||
// );
|
||||
// const request = {
|
||||
// ...requests.prepareOrderCancellation.withMemos,
|
||||
// };
|
||||
// delete request.orderSequence; // Make invalid
|
||||
|
||||
// await assertRejects(
|
||||
// this.client.prepareOrderCancellation(test.address, request),
|
||||
// this.client.errors.ValidationError,
|
||||
// 'instance.orderCancellation requires property "orderSequence"'
|
||||
// );
|
||||
// });
|
||||
|
||||
it('with ticket', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const request = requests.prepareOrderCancellation.simple
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23,
|
||||
}
|
||||
const result = await this.client.prepareOrderCancellation(
|
||||
test.address,
|
||||
request,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareOrderCancellation.ticket,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,663 +0,0 @@
|
||||
import { ValidationError } from 'xrpl-local/common/errors'
|
||||
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertResultMatch, addressTests, assertRejects } from '../testUtils'
|
||||
|
||||
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
|
||||
const { preparePayment: REQUEST_FIXTURES } = requests
|
||||
const { preparePayment: RESPONSE_FIXTURES } = responses
|
||||
const RECIPIENT_ADDRESS = 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo'
|
||||
|
||||
describe('client.preparePayment', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
addressTests.forEach(function (test) {
|
||||
describe(test.type, function () {
|
||||
it('normal', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
}
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.normal, 'prepare')
|
||||
})
|
||||
|
||||
it('min amount xrp', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
}
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.minAmountXRP,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.minAmountXRP, 'prepare')
|
||||
})
|
||||
|
||||
it('min amount xrp2xrp', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.minAmount,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
RESPONSE_FIXTURES.minAmountXRPXRP,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('XRP to XRP', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const payment = {
|
||||
source: {
|
||||
address: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||
maxAmount: { value: '1', currency: 'XRP' },
|
||||
},
|
||||
destination: {
|
||||
address: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
|
||||
amount: { value: '1', currency: 'XRP' },
|
||||
},
|
||||
}
|
||||
const expected = {
|
||||
txJSON:
|
||||
'{"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":"1000000","Flags":2147483648,"LastLedgerSequence":8820051,"Sequence":23,"Fee":"12"}',
|
||||
instructions: {
|
||||
fee: '0.000012',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
},
|
||||
}
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
payment,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(response, expected, 'prepare')
|
||||
})
|
||||
|
||||
it('XRP drops to XRP drops', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const payment = {
|
||||
source: {
|
||||
address: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||
maxAmount: { value: '1000000', currency: 'drops' },
|
||||
},
|
||||
destination: {
|
||||
address: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
|
||||
amount: { value: '1000000', currency: 'drops' },
|
||||
},
|
||||
}
|
||||
const expected = {
|
||||
txJSON:
|
||||
'{"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":"1000000","Flags":2147483648,"LastLedgerSequence":8820051,"Sequence":23,"Fee":"12"}',
|
||||
instructions: {
|
||||
fee: '0.000012',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
},
|
||||
}
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
payment,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(response, expected, 'prepare')
|
||||
})
|
||||
|
||||
it('XRP drops to XRP', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const payment = {
|
||||
source: {
|
||||
address: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||
maxAmount: { value: '1000000', currency: 'drops' },
|
||||
},
|
||||
destination: {
|
||||
address: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
|
||||
amount: { value: '1', currency: 'XRP' },
|
||||
},
|
||||
}
|
||||
const expected = {
|
||||
txJSON:
|
||||
'{"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":"1000000","Flags":2147483648,"LastLedgerSequence":8820051,"Sequence":23,"Fee":"12"}',
|
||||
instructions: {
|
||||
fee: '0.000012',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
},
|
||||
}
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
payment,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(response, expected, 'prepare')
|
||||
})
|
||||
|
||||
it('XRP to XRP drops', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const payment = {
|
||||
source: {
|
||||
address: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||
maxAmount: { value: '1', currency: 'XRP' },
|
||||
},
|
||||
destination: {
|
||||
address: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
|
||||
amount: { value: '1000000', currency: 'drops' },
|
||||
},
|
||||
}
|
||||
const expected = {
|
||||
txJSON:
|
||||
'{"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":"1000000","Flags":2147483648,"LastLedgerSequence":8820051,"Sequence":23,"Fee":"12"}',
|
||||
instructions: {
|
||||
fee: '0.000012',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
},
|
||||
}
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
payment,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(response, expected, 'prepare')
|
||||
})
|
||||
|
||||
// Errors
|
||||
it('rejects promise and does not throw when payment object is invalid', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const payment = {
|
||||
source: {
|
||||
address: test.address,
|
||||
// instead of `maxAmount`
|
||||
amount: { value: '1000', currency: 'drops' },
|
||||
},
|
||||
destination: {
|
||||
address: RECIPIENT_ADDRESS,
|
||||
amount: { value: '1000', currency: 'drops' },
|
||||
},
|
||||
}
|
||||
|
||||
return assertRejects(
|
||||
this.client.preparePayment(test.address, payment),
|
||||
ValidationError,
|
||||
'payment must specify either (source.maxAmount and destination.amount) or (source.amount and destination.minAmount)',
|
||||
)
|
||||
})
|
||||
|
||||
// it("rejects promise and does not throw when field is missing", async function () {
|
||||
// this.mockRippled.addResponse("server_info", rippled.server_info.normal);
|
||||
// this.mockRippled.addResponse("fee", rippled.fee);
|
||||
// this.mockRippled.addResponse("ledger_current", rippled.ledger_current);
|
||||
// this.mockRippled.addResponse(
|
||||
// "account_info",
|
||||
// rippled.account_info.normal
|
||||
// );
|
||||
// // Marking as "any" to get around the fact that TS won't allow this.
|
||||
// const payment: any = {
|
||||
// source: { address: test.address },
|
||||
// destination: {
|
||||
// address: RECIPIENT_ADDRESS,
|
||||
// amount: { value: "1000", currency: "drops" },
|
||||
// },
|
||||
// };
|
||||
|
||||
// return assertRejects(
|
||||
// this.client.preparePayment(test.address, payment),
|
||||
// ValidationError,
|
||||
// "instance.payment.source is not exactly one from <sourceExactAdjustment>,<maxAdjustment>"
|
||||
// );
|
||||
// });
|
||||
|
||||
it('rejects promise and does not throw when fee exceeds maxFeeXRP', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const payment = {
|
||||
source: {
|
||||
address: test.address,
|
||||
maxAmount: { value: '1000', currency: 'drops' },
|
||||
},
|
||||
destination: {
|
||||
address: RECIPIENT_ADDRESS,
|
||||
amount: { value: '1000', currency: 'drops' },
|
||||
},
|
||||
}
|
||||
return assertRejects(
|
||||
this.client.preparePayment(test.address, payment, { fee: '3' }),
|
||||
ValidationError,
|
||||
'Fee of 3 XRP exceeds max of 2 XRP. To use this fee, increase `maxFeeXRP` in the Client constructor.',
|
||||
)
|
||||
})
|
||||
|
||||
it('XRP to XRP no partial', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
return assertRejects(
|
||||
this.client.preparePayment(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.wrongPartial,
|
||||
),
|
||||
ValidationError,
|
||||
'XRP to XRP payments cannot be partial payments',
|
||||
)
|
||||
})
|
||||
|
||||
it('address must match payment.source.address', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
return assertRejects(
|
||||
this.client.preparePayment(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.wrongAddress,
|
||||
),
|
||||
ValidationError,
|
||||
'address must match payment.source.address',
|
||||
)
|
||||
})
|
||||
|
||||
it('wrong amount', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
return assertRejects(
|
||||
this.client.preparePayment(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.wrongAmount,
|
||||
),
|
||||
ValidationError,
|
||||
'payment must specify either (source.maxAmount and destination.amount) or (source.amount and destination.minAmount)',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws when fee exceeds 2 XRP', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
fee: '2.1',
|
||||
}
|
||||
return assertRejects(
|
||||
this.client.preparePayment(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.normal,
|
||||
localInstructions,
|
||||
),
|
||||
ValidationError,
|
||||
'Fee of 2.1 XRP exceeds max of 2 XRP. To use this fee, increase `maxFeeXRP` in the Client constructor.',
|
||||
)
|
||||
})
|
||||
|
||||
// 'preparePayment with all options specified': async (client, test.address) => {
|
||||
// const ledgerResponse = await this.client.request({command: 'ledger', ledger_index: 'validated'})
|
||||
// const version = ledgerResponse.result.ledger_index
|
||||
// const localInstructions = {
|
||||
// maxLedgerVersion: version + 100,
|
||||
// fee: '0.000012'
|
||||
// }
|
||||
// const response = await this.client.preparePayment(
|
||||
// test.address,
|
||||
// REQUEST_FIXTURES.allOptions,
|
||||
// localInstructions
|
||||
// )
|
||||
// assertResultMatch(response, RESPONSE_FIXTURES.allOptions, 'prepare')
|
||||
// },
|
||||
|
||||
it('preparePayment without counterparty set', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
sequence: 23,
|
||||
}
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.noCounterparty,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.noCounterparty, 'prepare')
|
||||
})
|
||||
|
||||
it('preparePayment with source.amount/destination.minAmount can be signed', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
// See also: 'sign succeeds with source.amount/destination.minAmount'
|
||||
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
sequence: 23,
|
||||
}
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.noCounterparty,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.noCounterparty, 'prepare')
|
||||
})
|
||||
|
||||
it('destination.minAmount', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
responses.getPaths.sendAll[0],
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.minAmount, 'prepare')
|
||||
})
|
||||
|
||||
it('caps fee at 2 XRP by default', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
this.client.feeCushion = 1000000
|
||||
const expectedResponse = {
|
||||
txJSON:
|
||||
'{"Flags":2147483648,"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"SendMax":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"LastLedgerSequence":8820051,"Fee":"2000000","Sequence":23}',
|
||||
instructions: {
|
||||
fee: '2',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
},
|
||||
}
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.normal,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(response, expectedResponse, 'prepare')
|
||||
})
|
||||
|
||||
it('allows fee exceeding 2 XRP when maxFeeXRP is higher', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
this.client.maxFeeXRP = '2.2'
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
fee: '2.1',
|
||||
}
|
||||
const expectedResponse = {
|
||||
txJSON:
|
||||
'{"Flags":2147483648,"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"SendMax":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"LastLedgerSequence":8820051,"Fee":"2100000","Sequence":23}',
|
||||
instructions: {
|
||||
fee: '2.1',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
},
|
||||
}
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(response, expectedResponse, 'prepare')
|
||||
})
|
||||
|
||||
it('fee - default maxFee of 2 XRP', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
this.client.feeCushion = 1000000
|
||||
const expectedResponse = {
|
||||
txJSON:
|
||||
'{"Flags":2147483648,"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"SendMax":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"LastLedgerSequence":8820051,"Fee":"2000000","Sequence":23}',
|
||||
instructions: {
|
||||
fee: '2',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
},
|
||||
}
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
requests.preparePayment.normal,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(response, expectedResponse, 'prepare')
|
||||
})
|
||||
|
||||
it('fee - capped to maxFeeXRP when maxFee exceeds maxFeeXRP', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
this.client.feeCushion = 1000000
|
||||
this.client.maxFeeXRP = '3'
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '4',
|
||||
}
|
||||
const expectedResponse = {
|
||||
txJSON:
|
||||
'{"Flags":2147483648,"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"SendMax":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"LastLedgerSequence":8820051,"Fee":"3000000","Sequence":23}',
|
||||
instructions: {
|
||||
fee: '3',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
},
|
||||
}
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
requests.preparePayment.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(response, expectedResponse, 'prepare')
|
||||
})
|
||||
|
||||
it('fee - capped to maxFee', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
this.client.feeCushion = 1000000
|
||||
this.client.maxFeeXRP = '5'
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '4',
|
||||
}
|
||||
const expectedResponse = {
|
||||
txJSON:
|
||||
'{"Flags":2147483648,"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"SendMax":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"LastLedgerSequence":8820051,"Fee":"4000000","Sequence":23}',
|
||||
instructions: {
|
||||
fee: '4',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
},
|
||||
}
|
||||
const response = await this.client.preparePayment(
|
||||
test.address,
|
||||
requests.preparePayment.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(response, expectedResponse, 'prepare')
|
||||
})
|
||||
|
||||
// 'fee - calculated fee does not use more than 6 decimal places': async (
|
||||
// client,
|
||||
// test.address
|
||||
// ) => {
|
||||
// this.client.connection.request({
|
||||
// command: 'config',
|
||||
// data: {loadFactor: 5407.96875}
|
||||
// })
|
||||
// const expectedResponse = {
|
||||
// txJSON:
|
||||
// '{"Flags":2147483648,"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo","Amount":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"SendMax":{"value":"0.01","currency":"USD","issuer":"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"},"LastLedgerSequence":8820051,"Fee":"64896","Sequence":23}',
|
||||
// instructions: {
|
||||
// fee: '0.064896',
|
||||
// sequence: 23,
|
||||
// maxLedgerVersion: 8820051
|
||||
// }
|
||||
// }
|
||||
// const response = await this.client.preparePayment(
|
||||
// test.address,
|
||||
// requests.preparePayment.normal,
|
||||
// instructionsWithMaxLedgerVersionOffset
|
||||
// )
|
||||
// assertResultMatch(response, expectedResponse, 'prepare')
|
||||
// },
|
||||
|
||||
// Tickets
|
||||
// 'preparePayment with ticketSequence': async (client, test.address) => {
|
||||
// const ledgerResponse = await this.client.request({
|
||||
// command: 'ledger',
|
||||
// ledger_index: 'validated'
|
||||
// })
|
||||
// const version = ledgerResponse.result.ledger_index
|
||||
// const localInstructions = {
|
||||
// maxLedgerVersion: version + 100,
|
||||
// fee: '0.000012',
|
||||
// ticketSequence: 23
|
||||
// }
|
||||
// const response = await this.client.preparePayment(
|
||||
// test.address,
|
||||
// REQUEST_FIXTURES.allOptions,
|
||||
// localInstructions
|
||||
// )
|
||||
// assertResultMatch(response, RESPONSE_FIXTURES.ticketSequence, 'prepare')
|
||||
// },
|
||||
|
||||
// 'throws when both sequence and ticketSequence are set': async (
|
||||
// client,
|
||||
// test.address
|
||||
// ) => {
|
||||
// const ledgerResponse = await this.client.request({
|
||||
// command: 'ledger',
|
||||
// ledger_index: 'validated'
|
||||
// })
|
||||
// const version = ledgerResponse.result.ledger_index
|
||||
// const localInstructions = {
|
||||
// maxLedgerVersion: version + 100,
|
||||
// fee: '0.000012',
|
||||
// ticketSequence: 23,
|
||||
// sequence: 12
|
||||
// }
|
||||
// return assertRejects(
|
||||
// this.client.preparePayment(
|
||||
// test.address,
|
||||
// REQUEST_FIXTURES.allOptions,
|
||||
// localInstructions
|
||||
// ),
|
||||
// ValidationError,
|
||||
// 'instance.instructions is of prohibited type [object Object]'
|
||||
// )
|
||||
// }
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,155 +0,0 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertResultMatch, addressTests } from '../testUtils'
|
||||
|
||||
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
|
||||
const { preparePaymentChannelClaim: REQUEST_FIXTURES } = requests
|
||||
const { preparePaymentChannelClaim: RESPONSE_FIXTURES } = responses
|
||||
|
||||
describe('client.preparePaymentChannelClaim', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
addressTests.forEach(function (test) {
|
||||
describe(test.type, function () {
|
||||
it('default', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
}
|
||||
const response = await this.client.preparePaymentChannelClaim(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.normal, 'prepare')
|
||||
})
|
||||
|
||||
it('with renew', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
}
|
||||
const response = await this.client.preparePaymentChannelClaim(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.renew,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.renew, 'prepare')
|
||||
})
|
||||
|
||||
it('with close', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
}
|
||||
const response = await this.client.preparePaymentChannelClaim(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.close,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.close, 'prepare')
|
||||
})
|
||||
|
||||
it('with ticket', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23,
|
||||
}
|
||||
const response = await this.client.preparePaymentChannelClaim(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(response, RESPONSE_FIXTURES.ticket, 'prepare')
|
||||
})
|
||||
|
||||
it('rejects Promise on preparePaymentChannelClaim with renew and close', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
try {
|
||||
const prepared = await this.client.preparePaymentChannelClaim(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.full,
|
||||
)
|
||||
throw new Error(
|
||||
`Expected method to reject. Prepared transaction: ${JSON.stringify(
|
||||
prepared,
|
||||
)}`,
|
||||
)
|
||||
} catch (err) {
|
||||
assert.strictEqual(err.name, 'ValidationError')
|
||||
assert.strictEqual(
|
||||
err.message,
|
||||
'"renew" and "close" flags on PaymentChannelClaim are mutually exclusive',
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('rejects Promise on preparePaymentChannelClaim with no signature', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
try {
|
||||
const prepared = await this.client.preparePaymentChannelClaim(
|
||||
test.address,
|
||||
REQUEST_FIXTURES.noSignature,
|
||||
)
|
||||
throw new Error(
|
||||
`Expected method to reject. Prepared transaction: ${JSON.stringify(
|
||||
prepared,
|
||||
)}`,
|
||||
)
|
||||
} catch (err) {
|
||||
assert.strictEqual(err.name, 'ValidationError')
|
||||
assert.strictEqual(
|
||||
err.message,
|
||||
'"signature" and "publicKey" fields on PaymentChannelClaim must only be specified together.',
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,72 +0,0 @@
|
||||
import addresses from '../fixtures/addresses.json'
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertResultMatch } from '../testUtils'
|
||||
|
||||
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
|
||||
|
||||
describe('client.preparePaymentChannelCreate', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('preparePaymentChannelCreate', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
}
|
||||
const result = await this.client.preparePaymentChannelCreate(
|
||||
addresses.ACCOUNT,
|
||||
requests.preparePaymentChannelCreate.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.preparePaymentChannelCreate.normal,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('preparePaymentChannelCreate full', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
const result = await this.client.preparePaymentChannelCreate(
|
||||
addresses.ACCOUNT,
|
||||
requests.preparePaymentChannelCreate.full,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.preparePaymentChannelCreate.full,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('preparePaymentChannelCreate with ticket', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23,
|
||||
}
|
||||
const result = await this.client.preparePaymentChannelCreate(
|
||||
addresses.ACCOUNT,
|
||||
requests.preparePaymentChannelCreate.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.preparePaymentChannelCreate.ticket,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -1,84 +0,0 @@
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertResultMatch, addressTests } from '../testUtils'
|
||||
|
||||
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
|
||||
|
||||
describe('client.preparePaymentChannelFund', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
addressTests.forEach(function (test) {
|
||||
describe(test.type, function () {
|
||||
it('preparePaymentChannelFund', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
}
|
||||
const result = await this.client.preparePaymentChannelFund(
|
||||
test.address,
|
||||
requests.preparePaymentChannelFund.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.preparePaymentChannelFund.normal,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('preparePaymentChannelFund full', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const result = await this.client.preparePaymentChannelFund(
|
||||
test.address,
|
||||
requests.preparePaymentChannelFund.full,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.preparePaymentChannelFund.full,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('with ticket', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23,
|
||||
}
|
||||
const result = await this.client.preparePaymentChannelFund(
|
||||
test.address,
|
||||
requests.preparePaymentChannelFund.normal,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.preparePaymentChannelFund.ticket,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,431 +0,0 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { FormattedSettings } from '../../src/common/types/objects'
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertResultMatch, addressTests } from '../testUtils'
|
||||
|
||||
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
|
||||
|
||||
describe('client.prepareSettings', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
addressTests.forEach(function (test) {
|
||||
describe(test.type, function () {
|
||||
it('simple test', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
requests.prepareSettings.domain,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(response, responses.prepareSettings.flags, 'prepare')
|
||||
})
|
||||
it('no maxLedgerVersion', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
requests.prepareSettings.domain,
|
||||
{
|
||||
maxLedgerVersion: null as unknown as undefined,
|
||||
},
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.noMaxLedgerVersion,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
it('no instructions', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
requests.prepareSettings.domain,
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.noInstructions,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
it('regularKey', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const regularKey = { regularKey: 'rAR8rR8sUkBoCZFawhkWzY4Y5YoyuznwD' }
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
regularKey,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.regularKey,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
it('remove regularKey', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const regularKey = { regularKey: null }
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
regularKey as unknown as FormattedSettings,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.removeRegularKey,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
it('flag set', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const settings = { requireDestinationTag: true }
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.flagSet,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
it('flag clear', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const settings = { requireDestinationTag: false }
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.flagClear,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
it('set depositAuth flag', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const settings = { depositAuth: true }
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.flagSetDepositAuth,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
it('clear depositAuth flag', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const settings = { depositAuth: false }
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.flagClearDepositAuth,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
it('integer field clear', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const settings = { transferRate: null }
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assert(response)
|
||||
assert.strictEqual(JSON.parse(response.txJSON).TransferRate, 0)
|
||||
})
|
||||
it('set transferRate', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const settings = { transferRate: 1 }
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.setTransferRate,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
it('set signers', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const settings = requests.prepareSettings.signers.normal
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
settings,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.signers,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
// it("signers no threshold", async function () {
|
||||
// this.mockRippled.addResponse("server_info", rippled.server_info.normal);
|
||||
// this.mockRippled.addResponse("fee", rippled.fee);
|
||||
// this.mockRippled.addResponse("ledger_current", rippled.ledger_current);
|
||||
// this.mockRippled.addResponse(
|
||||
// "account_info",
|
||||
// rippled.account_info.normal
|
||||
// );
|
||||
// const settings = requests.prepareSettings.signers.noThreshold;
|
||||
// try {
|
||||
// const response = await this.client.prepareSettings(
|
||||
// test.address,
|
||||
// settings,
|
||||
// instructionsWithMaxLedgerVersionOffset
|
||||
// );
|
||||
// throw new Error(
|
||||
// `Expected method to reject. Prepared transaction: ${JSON.stringify(
|
||||
// response
|
||||
// )}`
|
||||
// );
|
||||
// } catch (err) {
|
||||
// assert.strictEqual(
|
||||
// err.message,
|
||||
// 'instance.settings.signers requires property "threshold"'
|
||||
// );
|
||||
// assert.strictEqual(err.name, "ValidationError");
|
||||
// }
|
||||
// });
|
||||
it('signers no weights', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const settings = requests.prepareSettings.signers.noWeights
|
||||
const localInstructions = {
|
||||
signersCount: 1,
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
}
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
settings,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.noWeights,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
it('fee for multisign', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
signersCount: 4,
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
}
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
requests.prepareSettings.domain,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.flagsMultisign,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
it('no signer list', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const settings = requests.prepareSettings.noSignerEntries
|
||||
const localInstructions = {
|
||||
signersCount: 1,
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
}
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
settings,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(
|
||||
response,
|
||||
responses.prepareSettings.noSignerList,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
// it("invalid", async function () {
|
||||
// this.mockRippled.addResponse("server_info", rippled.server_info.normal);
|
||||
// this.mockRippled.addResponse("fee", rippled.fee);
|
||||
// this.mockRippled.addResponse("ledger_current", rippled.ledger_current);
|
||||
// this.mockRippled.addResponse(
|
||||
// "account_info",
|
||||
// rippled.account_info.normal
|
||||
// );
|
||||
// // domain must be a string
|
||||
// const settings = { ...requests.prepareSettings.domain, domain: 123 };
|
||||
// const localInstructions = {
|
||||
// signersCount: 4,
|
||||
// ...instructionsWithMaxLedgerVersionOffset,
|
||||
// };
|
||||
|
||||
// try {
|
||||
// const response = await this.client.prepareSettings(
|
||||
// test.address,
|
||||
// settings,
|
||||
// localInstructions
|
||||
// );
|
||||
// throw new Error(
|
||||
// `Expected method to reject. Prepared transaction: ${JSON.stringify(
|
||||
// response
|
||||
// )}`
|
||||
// );
|
||||
// } catch (err) {
|
||||
// assert.strictEqual(
|
||||
// err.message,
|
||||
// "instance.settings.domain is not of a type(s) string"
|
||||
// );
|
||||
// assert.strictEqual(err.name, "ValidationError");
|
||||
// }
|
||||
// });
|
||||
it('offline', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
|
||||
const settings = requests.prepareSettings.domain
|
||||
const instructions = {
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
fee: '0.000012',
|
||||
}
|
||||
const result = await this.client.prepareSettings(
|
||||
test.address,
|
||||
settings,
|
||||
instructions,
|
||||
)
|
||||
assertResultMatch(result, responses.prepareSettings.flags, 'prepare')
|
||||
assert.deepEqual(
|
||||
this.client.sign(result.txJSON, secret),
|
||||
responses.prepareSettings.signed,
|
||||
)
|
||||
})
|
||||
it('prepare settings with ticket', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const instructions = {
|
||||
ticketSequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
fee: '0.000012',
|
||||
}
|
||||
const response = await this.client.prepareSettings(
|
||||
test.address,
|
||||
requests.prepareSettings.domain,
|
||||
instructions,
|
||||
)
|
||||
assertResultMatch(response, responses.prepareSettings.ticket, 'prepare')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,75 +0,0 @@
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertResultMatch, addressTests } from '../testUtils'
|
||||
// import responses from '../fixtures/responses'
|
||||
// import requests from '../fixtures/requests'
|
||||
// import {ValidationError} from 'xrpl-local/common/errors'
|
||||
// import binary from 'ripple-binary-codec'
|
||||
// import {assert} from 'chai'
|
||||
// import {Client} from 'xrpl-local'
|
||||
// import * as schemaValidator from 'xrpl-local/common/schema-validator'
|
||||
|
||||
// const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
|
||||
// const {preparePayment: REQUEST_FIXTURES} = requests
|
||||
// const {preparePayment: RESPONSE_FIXTURES} = responses
|
||||
// const ADDRESS = 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo'
|
||||
|
||||
describe('client.prepareTicket', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
addressTests.forEach(function (test) {
|
||||
describe(test.type, function () {
|
||||
it('creates a ticket successfully with a sequence number', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const expected = {
|
||||
txJSON:
|
||||
'{"TransactionType":"TicketCreate", "TicketCount": 2, "Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Flags":2147483648,"LastLedgerSequence":8819954,"Sequence":23,"Fee":"12"}',
|
||||
instructions: {
|
||||
maxLedgerVersion: 8819954,
|
||||
sequence: 23,
|
||||
fee: '0.000012',
|
||||
},
|
||||
}
|
||||
const response = await this.client.prepareTicketCreate(test.address, 2)
|
||||
assertResultMatch(response, expected, 'prepare')
|
||||
})
|
||||
|
||||
it('creates a ticket successfully with another ticket', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const expected = {
|
||||
txJSON:
|
||||
'{"TransactionType":"TicketCreate", "TicketCount": 1, "Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Flags":2147483648,"LastLedgerSequence":8819954,"Sequence": 0,"TicketSequence":23,"Fee":"12"}',
|
||||
instructions: {
|
||||
maxLedgerVersion: 8819954,
|
||||
ticketSequence: 23,
|
||||
fee: '0.000012',
|
||||
},
|
||||
}
|
||||
const instructions = {
|
||||
maxLedgerVersion: 8819954,
|
||||
ticketSequence: 23,
|
||||
fee: '0.000012',
|
||||
}
|
||||
const response = await this.client.prepareTicketCreate(
|
||||
test.address,
|
||||
1,
|
||||
instructions,
|
||||
)
|
||||
assertResultMatch(response, expected, 'prepare')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,126 +0,0 @@
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { assertResultMatch, addressTests } from '../testUtils'
|
||||
|
||||
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
|
||||
|
||||
describe('client.prepareTrustline', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
addressTests.forEach(function (test) {
|
||||
describe(test.type, function () {
|
||||
it('simple', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const result = await this.client.prepareTrustline(
|
||||
test.address,
|
||||
requests.prepareTrustline.simple,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(result, responses.prepareTrustline.simple, 'prepare')
|
||||
})
|
||||
|
||||
it('frozen', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const result = await this.client.prepareTrustline(
|
||||
test.address,
|
||||
requests.prepareTrustline.frozen,
|
||||
)
|
||||
assertResultMatch(result, responses.prepareTrustline.frozen, 'prepare')
|
||||
})
|
||||
|
||||
it('complex', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const result = await this.client.prepareTrustline(
|
||||
test.address,
|
||||
requests.prepareTrustline.complex,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(result, responses.prepareTrustline.complex, 'prepare')
|
||||
})
|
||||
|
||||
// it("invalid", async function () {
|
||||
// this.mockRippled.addResponse("server_info", rippled.server_info.normal);
|
||||
// this.mockRippled.addResponse("fee", rippled.fee);
|
||||
// this.mockRippled.addResponse("ledger_current", rippled.ledger_current);
|
||||
// this.mockRippled.addResponse(
|
||||
// "account_info",
|
||||
// rippled.account_info.normal
|
||||
// );
|
||||
// const trustline = { ...requests.prepareTrustline.complex };
|
||||
// delete trustline.limit; // Make invalid
|
||||
|
||||
// await assertRejects(
|
||||
// this.client.prepareTrustline(
|
||||
// test.address,
|
||||
// trustline,
|
||||
// instructionsWithMaxLedgerVersionOffset
|
||||
// ),
|
||||
// this.client.errors.ValidationError,
|
||||
// 'instance.trustline requires property "limit"'
|
||||
// );
|
||||
// });
|
||||
|
||||
it('xtest.address-issuer', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const result = await this.client.prepareTrustline(
|
||||
test.address,
|
||||
requests.prepareTrustline.issuedXAddress,
|
||||
instructionsWithMaxLedgerVersionOffset,
|
||||
)
|
||||
assertResultMatch(
|
||||
result,
|
||||
responses.prepareTrustline.issuedXAddress,
|
||||
'prepare',
|
||||
)
|
||||
})
|
||||
|
||||
it('with ticket', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const localInstructions = {
|
||||
...instructionsWithMaxLedgerVersionOffset,
|
||||
maxFee: '0.000012',
|
||||
ticketSequence: 23,
|
||||
}
|
||||
const result = await this.client.prepareTrustline(
|
||||
test.address,
|
||||
requests.prepareTrustline.simple,
|
||||
localInstructions,
|
||||
)
|
||||
assertResultMatch(result, responses.prepareTrustline.ticket, 'prepare')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -3,9 +3,7 @@ import binary from 'ripple-binary-codec'
|
||||
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { addressTests } from '../testUtils'
|
||||
|
||||
const { sign: REQUEST_FIXTURES } = requests
|
||||
const { sign: RESPONSE_FIXTURES } = responses
|
||||
@@ -228,188 +226,143 @@ describe('client.sign', function () {
|
||||
assert.deepEqual(result, RESPONSE_FIXTURES.ticket)
|
||||
})
|
||||
|
||||
addressTests.forEach(function (test) {
|
||||
describe(test.type, function () {
|
||||
it('throws when Fee exceeds maxFeeXRP (in drops)', async function () {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const request = {
|
||||
txJSON: `{"Flags":2147483648,"TransactionType":"AccountSet","Account":"${test.address}","Domain":"6578616D706C652E636F6D","LastLedgerSequence":8820051,"Fee":"2010000","Sequence":23,"SigningPubKey":"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8"}`,
|
||||
instructions: {
|
||||
fee: '2.01',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
},
|
||||
}
|
||||
it('throws when Fee exceeds maxFeeXRP (in drops)', async function () {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const request = {
|
||||
txJSON: `{"Flags":2147483648,"TransactionType":"AccountSet","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Domain":"6578616D706C652E636F6D","LastLedgerSequence":8820051,"Fee":"2010000","Sequence":23,"SigningPubKey":"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8"}`,
|
||||
instructions: {
|
||||
fee: '2.01',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
},
|
||||
}
|
||||
|
||||
assert.throws(() => {
|
||||
this.client.sign(request.txJSON, secret)
|
||||
}, /Fee" should not exceed "2000000"\. To use a higher fee, set `maxFeeXRP` in the Client constructor\./)
|
||||
})
|
||||
assert.throws(() => {
|
||||
this.client.sign(request.txJSON, secret)
|
||||
}, /Fee" should not exceed "2000000"\. To use a higher fee, set `maxFeeXRP` in the Client constructor\./)
|
||||
})
|
||||
|
||||
it('throws when Fee exceeds maxFeeXRP (in drops) - custom maxFeeXRP', async function () {
|
||||
this.client.maxFeeXRP = '1.9'
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const request = {
|
||||
txJSON: `{"Flags":2147483648,"TransactionType":"AccountSet","Account":"${test.address}","Domain":"6578616D706C652E636F6D","LastLedgerSequence":8820051,"Fee":"2010000","Sequence":23,"SigningPubKey":"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8"}`,
|
||||
instructions: {
|
||||
fee: '2.01',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
},
|
||||
}
|
||||
it('throws when Fee exceeds maxFeeXRP (in drops) - custom maxFeeXRP', async function () {
|
||||
this.client.maxFeeXRP = '1.9'
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const request = {
|
||||
txJSON: `{"Flags":2147483648,"TransactionType":"AccountSet","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Domain":"6578616D706C652E636F6D","LastLedgerSequence":8820051,"Fee":"2010000","Sequence":23,"SigningPubKey":"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8"}`,
|
||||
instructions: {
|
||||
fee: '2.01',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
},
|
||||
}
|
||||
|
||||
assert.throws(() => {
|
||||
this.client.sign(request.txJSON, secret)
|
||||
}, /Fee" should not exceed "1900000"\. To use a higher fee, set `maxFeeXRP` in the Client constructor\./)
|
||||
})
|
||||
assert.throws(() => {
|
||||
this.client.sign(request.txJSON, secret)
|
||||
}, /Fee" should not exceed "1900000"\. To use a higher fee, set `maxFeeXRP` in the Client constructor\./)
|
||||
})
|
||||
|
||||
it('sign with paths', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const payment = {
|
||||
source: {
|
||||
address: test.address,
|
||||
amount: {
|
||||
currency: 'drops',
|
||||
value: '100',
|
||||
},
|
||||
},
|
||||
destination: {
|
||||
address: 'rKT4JX4cCof6LcDYRz8o3rGRu7qxzZ2Zwj',
|
||||
minAmount: {
|
||||
currency: 'USD',
|
||||
value: '0.00004579644712312366',
|
||||
counterparty: 'rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc',
|
||||
},
|
||||
},
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
paths:
|
||||
'[[{"currency":"USD","issuer":"rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc"}]]',
|
||||
}
|
||||
const ret = await this.client.preparePayment(test.address, payment, {
|
||||
sequence: 1,
|
||||
maxLedgerVersion: 15696358,
|
||||
})
|
||||
const result = this.client.sign(ret.txJSON, secret)
|
||||
assert.deepEqual(result, {
|
||||
signedTransaction:
|
||||
'12000022800200002400000001201B00EF81E661EC6386F26FC0FFFF0000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D166461968400000000000000C6940000000000000646AD3504529A0465E2E0000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D1664619732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402200A693FB5CA6B21250EBDFD8CFF526EE0DF7C9E4E31EB0660692E75E6A93BF5F802203CC39463DDA21386898CA31E18AD1A6828647D65741DD637BAD71BC83E29DB9481145E7B112523F68D2F5E879DB4EAC51C6698A693048314CA6EDC7A28252DAEA6F2045B24F4D7C333E146170112300000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D166461900',
|
||||
id: '78874FE5F5299FEE3EA85D3CF6C1FB1F1D46BB08F716662A3E3D1F0ADE4EF796',
|
||||
})
|
||||
})
|
||||
|
||||
it('succeeds - prepared payment', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const payment = await this.client.preparePayment(test.address, {
|
||||
source: {
|
||||
address: test.address,
|
||||
maxAmount: {
|
||||
value: '1',
|
||||
currency: 'drops',
|
||||
},
|
||||
},
|
||||
destination: {
|
||||
address: 'rQ3PTWGLCbPz8ZCicV5tCX3xuymojTng5r',
|
||||
amount: {
|
||||
value: '1',
|
||||
currency: 'drops',
|
||||
},
|
||||
},
|
||||
})
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const result = this.client.sign(payment.txJSON, secret)
|
||||
const expectedResult = {
|
||||
signedTransaction:
|
||||
'12000022800000002400000017201B008694F261400000000000000168400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D874473045022100A9C91D4CFAE45686146EE0B56D4C53A2E7C2D672FB834D43E0BE2D2E9106519A022075DDA2F92DE552B0C45D83D4E6D35889B3FBF51BFBBD9B25EBF70DE3C96D0D6681145E7B112523F68D2F5E879DB4EAC51C6698A693048314FDB08D07AAA0EB711793A3027304D688E10C3648',
|
||||
id: '88D6B913C66279EA31ADC25C5806C48B2D4E5680261666790A736E1961217700',
|
||||
}
|
||||
assert.deepEqual(result, expectedResult)
|
||||
})
|
||||
|
||||
it('throws when encoded tx does not match decoded tx - prepared payment', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const payment = await this.client.preparePayment(test.address, {
|
||||
source: {
|
||||
address: test.address,
|
||||
maxAmount: {
|
||||
value: '1.1234567',
|
||||
currency: 'drops',
|
||||
},
|
||||
},
|
||||
destination: {
|
||||
address: 'rQ3PTWGLCbPz8ZCicV5tCX3xuymojTng5r',
|
||||
amount: {
|
||||
value: '1.1234567',
|
||||
currency: 'drops',
|
||||
},
|
||||
},
|
||||
})
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
assert.throws(() => {
|
||||
this.client.sign(payment.txJSON, secret)
|
||||
}, /^1.1234567 is an illegal amount/)
|
||||
})
|
||||
|
||||
it('throws when encoded tx does not match decoded tx - prepared order', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('fee', rippled.fee)
|
||||
this.mockRippled.addResponse('ledger_current', rippled.ledger_current)
|
||||
this.mockRippled.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
const order = {
|
||||
direction: 'sell',
|
||||
quantity: {
|
||||
currency: 'USD',
|
||||
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '3.140000',
|
||||
},
|
||||
totalPrice: {
|
||||
currency: 'XRP',
|
||||
value: '31415',
|
||||
},
|
||||
}
|
||||
const prepared = await this.client.prepareOrder(test.address, order, {
|
||||
sequence: 123,
|
||||
})
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
try {
|
||||
this.client.sign(prepared.txJSON, secret)
|
||||
return await Promise.reject(
|
||||
new Error('this.client.sign should have thrown'),
|
||||
)
|
||||
} catch (error) {
|
||||
assert.equal(error.name, 'ValidationError')
|
||||
assert.equal(
|
||||
error.message,
|
||||
'Serialized transaction does not match original txJSON. See `error.data`',
|
||||
)
|
||||
assert.deepEqual(error.data.diff, {
|
||||
TakerGets: {
|
||||
value: '3.14',
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
it('sign with paths', async function () {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const payment = {
|
||||
TransactionType: 'Payment',
|
||||
Account: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||
Destination: 'rKT4JX4cCof6LcDYRz8o3rGRu7qxzZ2Zwj',
|
||||
Amount: {
|
||||
currency: 'USD',
|
||||
issuer: 'rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc',
|
||||
value:
|
||||
'999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||
},
|
||||
Flags: 2147614720,
|
||||
SendMax: '100',
|
||||
DeliverMin: {
|
||||
currency: 'USD',
|
||||
issuer: 'rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc',
|
||||
value: '0.00004579644712312366',
|
||||
},
|
||||
Paths: [
|
||||
[{ currency: 'USD', issuer: 'rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc' }],
|
||||
],
|
||||
LastLedgerSequence: 15696358,
|
||||
Sequence: 1,
|
||||
Fee: '12',
|
||||
}
|
||||
const result = this.client.sign(JSON.stringify(payment), secret)
|
||||
assert.deepEqual(result, {
|
||||
signedTransaction:
|
||||
'12000022800200002400000001201B00EF81E661EC6386F26FC0FFFF0000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D166461968400000000000000C6940000000000000646AD3504529A0465E2E0000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D1664619732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402200A693FB5CA6B21250EBDFD8CFF526EE0DF7C9E4E31EB0660692E75E6A93BF5F802203CC39463DDA21386898CA31E18AD1A6828647D65741DD637BAD71BC83E29DB9481145E7B112523F68D2F5E879DB4EAC51C6698A693048314CA6EDC7A28252DAEA6F2045B24F4D7C333E146170112300000000000000000000000005553440000000000054F6F784A58F9EFB0A9EB90B83464F9D166461900',
|
||||
id: '78874FE5F5299FEE3EA85D3CF6C1FB1F1D46BB08F716662A3E3D1F0ADE4EF796',
|
||||
})
|
||||
})
|
||||
|
||||
it('succeeds - prepared payment', async function () {
|
||||
const payment = {
|
||||
TransactionType: 'Payment',
|
||||
Account: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||
Destination: 'rQ3PTWGLCbPz8ZCicV5tCX3xuymojTng5r',
|
||||
Amount: '1',
|
||||
Flags: 2147483648,
|
||||
Sequence: 23,
|
||||
LastLedgerSequence: 8819954,
|
||||
Fee: '12',
|
||||
}
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
const result = this.client.sign(JSON.stringify(payment), secret)
|
||||
const expectedResult = {
|
||||
signedTransaction:
|
||||
'12000022800000002400000017201B008694F261400000000000000168400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D874473045022100A9C91D4CFAE45686146EE0B56D4C53A2E7C2D672FB834D43E0BE2D2E9106519A022075DDA2F92DE552B0C45D83D4E6D35889B3FBF51BFBBD9B25EBF70DE3C96D0D6681145E7B112523F68D2F5E879DB4EAC51C6698A693048314FDB08D07AAA0EB711793A3027304D688E10C3648',
|
||||
id: '88D6B913C66279EA31ADC25C5806C48B2D4E5680261666790A736E1961217700',
|
||||
}
|
||||
assert.deepEqual(result, expectedResult)
|
||||
})
|
||||
|
||||
it('throws when encoded tx does not match decoded tx - prepared payment', async function () {
|
||||
const payment = {
|
||||
TransactionType: 'Payment',
|
||||
Account: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||
Destination: 'rQ3PTWGLCbPz8ZCicV5tCX3xuymojTng5r',
|
||||
Amount: '1.1234567',
|
||||
Flags: 2147483648,
|
||||
Sequence: 23,
|
||||
LastLedgerSequence: 8819954,
|
||||
Fee: '12',
|
||||
}
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
assert.throws(() => {
|
||||
this.client.sign(JSON.stringify(payment), secret)
|
||||
}, /^1.1234567 is an illegal amount/)
|
||||
})
|
||||
|
||||
it('throws when encoded tx does not match decoded tx - prepared order', async function () {
|
||||
const offerCreate = {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '3.140000',
|
||||
},
|
||||
TakerPays: '31415000000',
|
||||
Flags: 2148007936,
|
||||
Sequence: 123,
|
||||
LastLedgerSequence: 8819954,
|
||||
Fee: '12',
|
||||
}
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
try {
|
||||
this.client.sign(JSON.stringify(offerCreate), secret)
|
||||
return await Promise.reject(
|
||||
new Error('this.client.sign should have thrown'),
|
||||
)
|
||||
} catch (error) {
|
||||
assert.equal(error.name, 'ValidationError')
|
||||
assert.equal(
|
||||
error.message,
|
||||
'Serialized transaction does not match original txJSON. See `error.data`',
|
||||
)
|
||||
assert.deepEqual(error.data.diff, {
|
||||
TakerGets: {
|
||||
value: '3.14',
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,10 +4,20 @@ import _ from 'lodash'
|
||||
import { isValidXAddress } from 'ripple-address-codec'
|
||||
|
||||
import { Client } from 'xrpl-local'
|
||||
import { isValidSecret } from 'xrpl-local/utils'
|
||||
import {
|
||||
AccountSet,
|
||||
OfferCreate,
|
||||
SignerListSet,
|
||||
TrustSet,
|
||||
} from 'xrpl-local/models/transactions'
|
||||
import {
|
||||
isValidSecret,
|
||||
generateXAddress,
|
||||
xrpToDrops,
|
||||
convertStringToHex,
|
||||
} from 'xrpl-local/utils'
|
||||
|
||||
import { generateXAddress } from '../../src/utils/generateAddress'
|
||||
import requests from '../fixtures/requests'
|
||||
// import requests from '../fixtures/requests'
|
||||
|
||||
import { payTo, ledgerAccept } from './utils'
|
||||
import wallet from './wallet'
|
||||
@@ -116,16 +126,20 @@ const masterSecret = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb'
|
||||
|
||||
function makeTrustLine(testcase, address, secret) {
|
||||
const client = testcase.client
|
||||
const specification = {
|
||||
currency: 'USD',
|
||||
counterparty: masterAccount,
|
||||
limit: '1341.1',
|
||||
ripplingDisabled: true,
|
||||
const trustSet: TrustSet = {
|
||||
TransactionType: 'TrustSet',
|
||||
Account: address,
|
||||
LimitAmount: {
|
||||
value: '1341.1',
|
||||
issuer: masterAccount,
|
||||
currency: 'USD',
|
||||
},
|
||||
Flags: 0x00020000,
|
||||
}
|
||||
const trust = client
|
||||
.prepareTrustline(address, specification, {})
|
||||
.then((data) => {
|
||||
const signed = client.sign(data.txJSON, secret)
|
||||
.autofill(trustSet)
|
||||
.then(async (tx) => {
|
||||
const signed = client.sign(JSON.stringify(tx), secret)
|
||||
if (address === wallet.getAddress()) {
|
||||
testcase.transactions.push(signed.id)
|
||||
}
|
||||
@@ -134,32 +148,65 @@ function makeTrustLine(testcase, address, secret) {
|
||||
tx_blob: signed.signedTransaction,
|
||||
})
|
||||
})
|
||||
.then(() => ledgerAccept(client))
|
||||
.then((response) => {
|
||||
if (
|
||||
response.result.engine_result !== 'tesSUCCESS' &&
|
||||
response.result.engine_result !== 'tecPATH_PARTIAL'
|
||||
) {
|
||||
console.log(response)
|
||||
assert.fail(`Response not successful, ${response.result.engine_result}`)
|
||||
}
|
||||
ledgerAccept(client)
|
||||
})
|
||||
return trust
|
||||
}
|
||||
|
||||
function makeOrder(client, address, specification, secret) {
|
||||
function makeOrder(client, offerCreate, secret) {
|
||||
return client
|
||||
.prepareOrder(address, specification)
|
||||
.then((data) => client.sign(data.txJSON, secret))
|
||||
.autofill(offerCreate)
|
||||
.then((tx) => client.sign(JSON.stringify(tx), secret))
|
||||
.then((signed) =>
|
||||
client.request({ command: 'submit', tx_blob: signed.signedTransaction }),
|
||||
)
|
||||
.then(() => ledgerAccept(client))
|
||||
.then((response) => {
|
||||
if (
|
||||
response.result.engine_result !== 'tesSUCCESS' &&
|
||||
response.result.engine_result !== 'tecPATH_PARTIAL'
|
||||
) {
|
||||
console.log(response)
|
||||
assert.fail(`Response not successful, ${response.result.engine_result}`)
|
||||
}
|
||||
ledgerAccept(client)
|
||||
})
|
||||
}
|
||||
|
||||
function setupAccounts(testcase) {
|
||||
const client = testcase.client
|
||||
let fundAmount = '20'
|
||||
|
||||
const promise = payTo(client, 'rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM')
|
||||
.then(() => payTo(client, wallet.getAddress()))
|
||||
.then(() => payTo(client, testcase.newWallet.xAddress))
|
||||
.then(() => payTo(client, 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc'))
|
||||
.then(() => payTo(client, 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q'))
|
||||
const promise = client
|
||||
.request({ command: 'server_info' })
|
||||
.then(
|
||||
(response) =>
|
||||
(fundAmount = xrpToDrops(
|
||||
Number(response.result.info.validated_ledger.reserve_base_xrp) * 2,
|
||||
)),
|
||||
)
|
||||
.then(() => payTo(client, 'rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM', fundAmount))
|
||||
.then(() => payTo(client, wallet.getAddress(), fundAmount))
|
||||
.then(() => payTo(client, testcase.newWallet.classicAddress, fundAmount))
|
||||
.then(() => payTo(client, 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc', fundAmount))
|
||||
.then(() => payTo(client, 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q', fundAmount))
|
||||
.then(() => {
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: masterAccount,
|
||||
// default ripple
|
||||
SetFlag: 8,
|
||||
}
|
||||
return client
|
||||
.prepareSettings(masterAccount, { defaultRipple: true })
|
||||
.then((data) => client.sign(data.txJSON, masterSecret))
|
||||
.autofill(accountSet)
|
||||
.then((tx) => client.sign(JSON.stringify(tx), masterSecret))
|
||||
.then((signed) =>
|
||||
client.request({
|
||||
command: 'submit',
|
||||
@@ -181,44 +228,30 @@ function setupAccounts(testcase) {
|
||||
.then(() => payTo(client, wallet.getAddress(), '123', 'USD', masterAccount))
|
||||
.then(() => payTo(client, 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q'))
|
||||
.then(() => {
|
||||
const orderSpecification = {
|
||||
direction: 'buy',
|
||||
quantity: {
|
||||
const offerCreate: OfferCreate = {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: testcase.newWallet.xAddress,
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
value: '432',
|
||||
counterparty: masterAccount,
|
||||
},
|
||||
totalPrice: {
|
||||
currency: 'XRP',
|
||||
value: '432',
|
||||
issuer: masterAccount,
|
||||
},
|
||||
TakerGets: xrpToDrops('432'),
|
||||
}
|
||||
return makeOrder(
|
||||
testcase.client,
|
||||
testcase.newWallet.xAddress,
|
||||
orderSpecification,
|
||||
testcase.newWallet.secret,
|
||||
)
|
||||
return makeOrder(testcase.client, offerCreate, testcase.newWallet.secret)
|
||||
})
|
||||
.then(() => {
|
||||
const orderSpecification = {
|
||||
direction: 'buy',
|
||||
quantity: {
|
||||
currency: 'XRP',
|
||||
value: '1741',
|
||||
},
|
||||
totalPrice: {
|
||||
const offerCreate: OfferCreate = {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: masterAccount,
|
||||
TakerPays: xrpToDrops('1741'),
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
value: '171',
|
||||
counterparty: masterAccount,
|
||||
issuer: masterAccount,
|
||||
},
|
||||
}
|
||||
return makeOrder(
|
||||
testcase.client,
|
||||
masterAccount,
|
||||
orderSpecification,
|
||||
masterSecret,
|
||||
)
|
||||
return makeOrder(testcase.client, offerCreate, masterSecret)
|
||||
})
|
||||
return promise
|
||||
}
|
||||
@@ -234,7 +267,10 @@ function suiteSetup(this: any) {
|
||||
setup
|
||||
.bind(this)(serverUrl)
|
||||
.then(() => ledgerAccept(this.client))
|
||||
.then(() => (this.newWallet = generateXAddress()))
|
||||
.then(
|
||||
() =>
|
||||
(this.newWallet = generateXAddress({ includeClassicAddress: true })),
|
||||
)
|
||||
// two times to give time to server to send `ledgerClosed` event
|
||||
// so getLedgerVersion will return right value
|
||||
.then(() => ledgerAccept(this.client))
|
||||
@@ -256,128 +292,12 @@ function suiteSetup(this: any) {
|
||||
|
||||
describe('integration tests', function () {
|
||||
const address = wallet.getAddress()
|
||||
const instructions = { maxLedgerVersionOffset: 10 }
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteSetup)
|
||||
beforeEach(_.partial(setup, serverUrl))
|
||||
afterEach(teardown)
|
||||
|
||||
it('trustline', function () {
|
||||
return this.client
|
||||
.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
.then((response) => response.result.ledger_index)
|
||||
.then((ledgerVersion) => {
|
||||
return this.client
|
||||
.prepareTrustline(
|
||||
address,
|
||||
requests.prepareTrustline.simple,
|
||||
instructions,
|
||||
)
|
||||
.then((prepared) =>
|
||||
testTransaction(this, 'TrustSet', ledgerVersion, prepared),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('payment', function () {
|
||||
const amount = { currency: 'XRP', value: '0.000001' }
|
||||
const paymentSpecification = {
|
||||
source: {
|
||||
address,
|
||||
maxAmount: amount,
|
||||
},
|
||||
destination: {
|
||||
address: 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc',
|
||||
amount,
|
||||
},
|
||||
}
|
||||
return this.client
|
||||
.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
.then((response) => response.result.ledger_index)
|
||||
.then((ledgerVersion) => {
|
||||
return this.client
|
||||
.preparePayment(address, paymentSpecification, instructions)
|
||||
.then((prepared) =>
|
||||
testTransaction(this, 'Payment', ledgerVersion, prepared),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('order', function () {
|
||||
const orderSpecification = {
|
||||
direction: 'buy',
|
||||
quantity: {
|
||||
currency: 'USD',
|
||||
value: '237',
|
||||
counterparty: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
},
|
||||
totalPrice: {
|
||||
currency: 'XRP',
|
||||
value: '0.0002',
|
||||
},
|
||||
}
|
||||
const expectedOrder = {
|
||||
flags: 0,
|
||||
quality: '1.185',
|
||||
taker_gets: '200',
|
||||
taker_pays: {
|
||||
currency: 'USD',
|
||||
value: '237',
|
||||
issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
},
|
||||
}
|
||||
return this.client
|
||||
.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
.then((response) => response.result.ledger_index)
|
||||
.then((ledgerVersion) => {
|
||||
return this.client
|
||||
.prepareOrder(address, orderSpecification, instructions)
|
||||
.then((prepared) =>
|
||||
testTransaction(this, 'OfferCreate', ledgerVersion, prepared),
|
||||
)
|
||||
.then((result) => {
|
||||
const txData = JSON.parse(result.txJSON)
|
||||
return this.client
|
||||
.request({
|
||||
command: 'account_offers',
|
||||
account: address,
|
||||
})
|
||||
.then((response) => response.result.offers)
|
||||
.then((orders) => {
|
||||
assert(orders && orders.length > 0)
|
||||
const createdOrder = orders.filter((order) => {
|
||||
return order.seq === txData.Sequence
|
||||
})[0]
|
||||
assert(createdOrder)
|
||||
delete createdOrder.seq
|
||||
assert.deepEqual(createdOrder, expectedOrder)
|
||||
return txData
|
||||
})
|
||||
})
|
||||
.then((txData) =>
|
||||
this.client
|
||||
.prepareOrderCancellation(
|
||||
address,
|
||||
{ orderSequence: txData.Sequence },
|
||||
instructions,
|
||||
)
|
||||
.then((prepared) =>
|
||||
testTransaction(this, 'OfferCancel', ledgerVersion, prepared),
|
||||
),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('isConnected', function () {
|
||||
assert(this.client.isConnected())
|
||||
})
|
||||
@@ -390,29 +310,29 @@ describe('integration tests', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('getTrustlines', function () {
|
||||
const fixture = requests.prepareTrustline.simple
|
||||
const { currency, counterparty } = fixture
|
||||
const options = { currency, counterparty }
|
||||
return this.client.getTrustlines(address, options).then((data) => {
|
||||
assert(data && data.length > 0 && data[0] && data[0].specification)
|
||||
const specification = data[0].specification
|
||||
assert.strictEqual(Number(specification.limit), Number(fixture.limit))
|
||||
assert.strictEqual(specification.currency, fixture.currency)
|
||||
assert.strictEqual(specification.counterparty, fixture.counterparty)
|
||||
})
|
||||
})
|
||||
// it('getTrustlines', function () {
|
||||
// const fixture = requests.prepareTrustline.simple
|
||||
// const { currency, counterparty } = fixture
|
||||
// const options = { currency, counterparty }
|
||||
// return this.client.getTrustlines(address, options).then((data) => {
|
||||
// assert(data && data.length > 0 && data[0] && data[0].specification)
|
||||
// const specification = data[0].specification
|
||||
// assert.strictEqual(Number(specification.limit), Number(fixture.limit))
|
||||
// assert.strictEqual(specification.currency, fixture.currency)
|
||||
// assert.strictEqual(specification.counterparty, fixture.counterparty)
|
||||
// })
|
||||
// })
|
||||
|
||||
it('getBalances', function () {
|
||||
const fixture = requests.prepareTrustline.simple
|
||||
const { currency, counterparty } = fixture
|
||||
const options = { currency, counterparty }
|
||||
return this.client.getBalances(address, options).then((data) => {
|
||||
assert(data && data.length > 0 && data[0])
|
||||
assert.strictEqual(data[0].currency, fixture.currency)
|
||||
assert.strictEqual(data[0].counterparty, fixture.counterparty)
|
||||
})
|
||||
})
|
||||
// it('getBalances', function () {
|
||||
// const fixture = requests.prepareTrustline.simple
|
||||
// const { currency, counterparty } = fixture
|
||||
// const options = { currency, counterparty }
|
||||
// return this.client.getBalances(address, options).then((data) => {
|
||||
// assert(data && data.length > 0 && data[0])
|
||||
// assert.strictEqual(data[0].currency, fixture.currency)
|
||||
// assert.strictEqual(data[0].counterparty, fixture.counterparty)
|
||||
// })
|
||||
// })
|
||||
|
||||
it('getOrderbook', function () {
|
||||
const orderbook = {
|
||||
@@ -505,98 +425,122 @@ describe('integration tests', function () {
|
||||
assert(isValidXAddress(newWallet.xAddress))
|
||||
assert(isValidSecret(newWallet.secret))
|
||||
})
|
||||
})
|
||||
|
||||
describe('integration tests - standalone rippled', function () {
|
||||
const instructions = { maxLedgerVersionOffset: 10 }
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
beforeEach(_.partial(setup, serverUrl))
|
||||
afterEach(teardown)
|
||||
const address = 'r5nx8ZkwEbFztnc8Qyi22DE9JYjRzNmvs'
|
||||
const secret = 'ss6F8381Br6wwpy9p582H8sBt19J3'
|
||||
const multisignAccount = 'r5nx8ZkwEbFztnc8Qyi22DE9JYjRzNmvs'
|
||||
const multisignSecret = 'ss6F8381Br6wwpy9p582H8sBt19J3'
|
||||
const signer1address = 'rQDhz2ZNXmhxzCYwxU6qAbdxsHA4HV45Y2'
|
||||
const signer1secret = 'shK6YXzwYfnFVn3YZSaMh5zuAddKx'
|
||||
const signer2address = 'r3RtUvGw9nMoJ5FuHxuoVJvcENhKtuF9ud'
|
||||
const signer2secret = 'shUHQnL4EH27V4EiBrj6EfhWvZngF'
|
||||
|
||||
it('submit multisigned transaction', function () {
|
||||
const signers = {
|
||||
threshold: 2,
|
||||
weights: [
|
||||
{ address: signer1address, weight: 1 },
|
||||
{ address: signer2address, weight: 1 },
|
||||
const signerListSet: SignerListSet = {
|
||||
TransactionType: 'SignerListSet',
|
||||
Account: multisignAccount,
|
||||
SignerEntries: [
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signer1address,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signer2address,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
SignerQuorum: 2,
|
||||
}
|
||||
let minLedgerVersion = null
|
||||
return payTo(this.client, address)
|
||||
.then(() => {
|
||||
return this.client
|
||||
.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
.then((response) => response.result.ledger_index)
|
||||
.then((ledgerVersion) => {
|
||||
minLedgerVersion = ledgerVersion
|
||||
let fundAmount = '20'
|
||||
return this.client
|
||||
.request({ command: 'server_info' })
|
||||
.then(
|
||||
(response) =>
|
||||
(fundAmount = xrpToDrops(
|
||||
Number(response.result.info.validated_ledger.reserve_base_xrp) * 2,
|
||||
)),
|
||||
)
|
||||
.then(() =>
|
||||
payTo(this.client, multisignAccount, fundAmount)
|
||||
.then(() => {
|
||||
return this.client
|
||||
.prepareSettings(address, { signers }, instructions)
|
||||
.then((prepared) => {
|
||||
.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
.then((response) => response.result.ledger_index)
|
||||
.then((ledgerVersion) => {
|
||||
minLedgerVersion = ledgerVersion
|
||||
})
|
||||
.then(() => this.client.autofill(signerListSet, 2))
|
||||
.then((tx) => {
|
||||
return testTransaction(
|
||||
this,
|
||||
'SignerListSet',
|
||||
ledgerVersion,
|
||||
prepared,
|
||||
address,
|
||||
secret,
|
||||
minLedgerVersion,
|
||||
{ txJSON: JSON.stringify(tx) },
|
||||
multisignAccount,
|
||||
multisignSecret,
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
const multisignInstructions = { ...instructions, signersCount: 2 }
|
||||
return this.client
|
||||
.prepareSettings(
|
||||
address,
|
||||
{ domain: 'example.com' },
|
||||
multisignInstructions,
|
||||
)
|
||||
.then((prepared) => {
|
||||
const signed1 = this.client.sign(prepared.txJSON, signer1secret, {
|
||||
signAs: signer1address,
|
||||
})
|
||||
const signed2 = this.client.sign(prepared.txJSON, signer2secret, {
|
||||
signAs: signer2address,
|
||||
})
|
||||
const combined = this.client.combine([
|
||||
signed1.signedTransaction,
|
||||
signed2.signedTransaction,
|
||||
])
|
||||
return this.client
|
||||
.request({
|
||||
command: 'submit',
|
||||
tx_blob: combined.signedTransaction,
|
||||
})
|
||||
.then((response) =>
|
||||
acceptLedger(this.client).then(() => response),
|
||||
.then(() => {
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: multisignAccount,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
return this.client.autofill(accountSet, 2).then((tx) => {
|
||||
const signed1 = this.client.sign(
|
||||
JSON.stringify(tx),
|
||||
signer1secret,
|
||||
{
|
||||
signAs: signer1address,
|
||||
},
|
||||
)
|
||||
.then((response) => {
|
||||
assert.strictEqual(response.result.engine_result, 'tesSUCCESS')
|
||||
const options = { minLedgerVersion }
|
||||
return verifyTransaction(
|
||||
this,
|
||||
combined.id,
|
||||
'AccountSet',
|
||||
options,
|
||||
{},
|
||||
address,
|
||||
const signed2 = this.client.sign(
|
||||
JSON.stringify(tx),
|
||||
signer2secret,
|
||||
{
|
||||
signAs: signer2address,
|
||||
},
|
||||
)
|
||||
const combined = this.client.combine([
|
||||
signed1.signedTransaction,
|
||||
signed2.signedTransaction,
|
||||
])
|
||||
return this.client
|
||||
.request({
|
||||
command: 'submit',
|
||||
tx_blob: combined.signedTransaction,
|
||||
})
|
||||
.then((response) =>
|
||||
acceptLedger(this.client).then(() => response),
|
||||
)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error.message)
|
||||
throw error
|
||||
})
|
||||
})
|
||||
})
|
||||
.then((response) => {
|
||||
assert.strictEqual(
|
||||
response.result.engine_result,
|
||||
'tesSUCCESS',
|
||||
)
|
||||
const options = { minLedgerVersion }
|
||||
return verifyTransaction(
|
||||
this,
|
||||
combined.id,
|
||||
'AccountSet',
|
||||
options,
|
||||
{},
|
||||
multisignAccount,
|
||||
)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error.message)
|
||||
throw error
|
||||
})
|
||||
})
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,57 +1,80 @@
|
||||
'use strict';
|
||||
const assert = require('chai').assert
|
||||
|
||||
const masterAccount = 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh';
|
||||
const masterSecret = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb';
|
||||
const models = require('xrpl-local/models/transactions')
|
||||
const utils = require('xrpl-local/utils')
|
||||
|
||||
const masterAccount = 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'
|
||||
const masterSecret = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb'
|
||||
|
||||
function ledgerAccept(client) {
|
||||
const request = {command: 'ledger_accept'};
|
||||
return client.connection.request(request);
|
||||
const request = { command: 'ledger_accept' }
|
||||
return client.connection.request(request)
|
||||
}
|
||||
|
||||
function pay(client, from, to, amount, secret, currency = 'XRP', counterparty) {
|
||||
const paymentSpecification = {
|
||||
source: {
|
||||
address: from,
|
||||
maxAmount: {
|
||||
value: amount,
|
||||
currency: currency
|
||||
}
|
||||
},
|
||||
destination: {
|
||||
address: to,
|
||||
amount: {
|
||||
value: amount,
|
||||
currency: currency
|
||||
}
|
||||
}
|
||||
};
|
||||
function pay(client, from, to, amount, secret, currency = 'XRP', issuer) {
|
||||
const paymentAmount =
|
||||
currency === 'XRP' ? amount : { value: amount, currency, issuer }
|
||||
|
||||
if (counterparty != null) {
|
||||
paymentSpecification.source.maxAmount.counterparty = counterparty;
|
||||
paymentSpecification.destination.amount.counterparty = counterparty;
|
||||
const payment = {
|
||||
TransactionType: 'Payment',
|
||||
Account: from,
|
||||
Destination: to,
|
||||
Amount: paymentAmount,
|
||||
}
|
||||
|
||||
let id = null;
|
||||
return client.preparePayment(from, paymentSpecification, {})
|
||||
.then(data => client.sign(data.txJSON, secret))
|
||||
.then(signed => {
|
||||
id = signed.id;
|
||||
return client.request({command: 'submit', tx_blob: signed.signedTransaction});
|
||||
})
|
||||
// TODO: add better error handling here
|
||||
.then(() => ledgerAccept(client))
|
||||
.then(() => id);
|
||||
let id = null
|
||||
return (
|
||||
client
|
||||
.autofill(payment, 1)
|
||||
.then((tx) => {
|
||||
models.verifyPayment(payment)
|
||||
return client.sign(JSON.stringify(tx), secret)
|
||||
})
|
||||
.then((signed) => {
|
||||
id = signed.id
|
||||
return client.request({
|
||||
command: 'submit',
|
||||
tx_blob: signed.signedTransaction,
|
||||
})
|
||||
})
|
||||
// TODO: add better error handling here
|
||||
// TODO: fix path issues
|
||||
.then((response) => {
|
||||
if (
|
||||
response.result.engine_result !== 'tesSUCCESS' &&
|
||||
response.result.engine_result !== 'tecPATH_PARTIAL'
|
||||
) {
|
||||
console.log(response)
|
||||
assert.fail(
|
||||
`Response not successful, ${response.result.engine_result}`,
|
||||
)
|
||||
}
|
||||
ledgerAccept(client)
|
||||
})
|
||||
.then(() => id)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
function payTo(client, to, amount = '4003218', currency = 'XRP', counterparty) {
|
||||
return pay(client, masterAccount, to, amount, masterSecret, currency,
|
||||
counterparty);
|
||||
function payTo(
|
||||
client,
|
||||
to,
|
||||
amount = '40000000',
|
||||
currency = 'XRP',
|
||||
counterparty,
|
||||
) {
|
||||
return pay(
|
||||
client,
|
||||
masterAccount,
|
||||
to,
|
||||
amount,
|
||||
masterSecret,
|
||||
currency,
|
||||
counterparty,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
pay,
|
||||
payTo,
|
||||
ledgerAccept
|
||||
};
|
||||
ledgerAccept,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user