diff --git a/src/transaction/payment.ts b/src/transaction/payment.ts index e3a7582dee..53a8b01728 100644 --- a/src/transaction/payment.ts +++ b/src/transaction/payment.ts @@ -9,7 +9,7 @@ import {Amount, Adjustment, MaxAdjustment, MinAdjustment, Memo} from '../common/types/objects' - export type Payment = { +export interface Payment { source: Adjustment | MaxAdjustment, destination: Adjustment | MinAdjustment, paths?: string, @@ -30,11 +30,22 @@ import {Amount, Adjustment, MaxAdjustment, limitQuality?: boolean } +function isMaxAdjustment( + source: Adjustment | MaxAdjustment): source is MaxAdjustment { +return (source as MaxAdjustment).maxAmount !== undefined +} + +function isMinAdjustment( + destination: Adjustment | MinAdjustment): destination is MinAdjustment { +return (destination as MinAdjustment).minAmount !== undefined +} + function isXRPToXRPPayment(payment: Payment): boolean { - const sourceCurrency = _.get(payment, 'source.maxAmount.currency', - _.get(payment, 'source.amount.currency')) - const destinationCurrency = _.get(payment, 'destination.amount.currency', - _.get(payment, 'destination.minAmount.currency')) + 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' && destinationCurrency === 'XRP' } @@ -74,21 +85,29 @@ function createPaymentTransaction(address: string, paymentArgument: Payment throw new ValidationError('address must match payment.source.address') } - if (((payment.source).maxAmount && (payment.destination).minAmount) || - ((payment.source).amount && (payment.destination).amount)) { + 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 = (payment.destination).minAmount && !isXRPToXRPPayment(payment) ? - createMaximalAmount((payment.destination).minAmount) : - ((payment.destination).amount || (payment.destination).minAmount) + const amount = + (isMinAdjustment(payment.destination) && !isXRPToXRPPayment(payment)) + ? createMaximalAmount(destinationAmount) : destinationAmount const txJSON: any = { TransactionType: 'Payment', @@ -121,16 +140,14 @@ function createPaymentTransaction(address: string, paymentArgument: Payment // temREDUNDANT_SEND_MAX removed in: // https://github.com/ripple/rippled/commit/ // c522ffa6db2648f1d8a987843e7feabf1a0b7de8/ - if (payment.allowPartialPayment === true - || (payment.destination).minAmount !== undefined) { + if (payment.allowPartialPayment || isMinAdjustment(payment.destination)) { txJSON.Flags |= paymentFlags.PartialPayment } - txJSON.SendMax = toRippledAmount( - (payment.source).maxAmount || (payment.source).amount) + txJSON.SendMax = toRippledAmount(sourceAmount) - if ((payment.destination).minAmount !== undefined) { - txJSON.DeliverMin = toRippledAmount((payment.destination).minAmount) + if (isMinAdjustment(payment.destination)) { + txJSON.DeliverMin = toRippledAmount(destinationAmount) } if (payment.paths !== undefined) {