Fix preparePayment when using source.amount/destination.minAmount (#1295)

See: https://github.com/ripple/ripple-lib/issues/1237#issuecomment-631670946

Fix #1237

Thanks to @leobel
This commit is contained in:
Elliot Lee
2020-05-26 15:48:50 -07:00
committed by GitHub
parent e6c9617e01
commit 83b5c7f678
4 changed files with 83 additions and 2 deletions

View File

@@ -87,7 +87,12 @@ function applyAnyCounterpartyEncoding(payment: Payment): void {
function createMaximalAmount(amount: Amount): Amount { function createMaximalAmount(amount: Amount): Amount {
const maxXRPValue = '100000000000' const maxXRPValue = '100000000000'
const maxIOUValue = '9999999999999999e80'
// 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 let maxValue
if (amount.currency === 'XRP') { if (amount.currency === 'XRP') {
maxValue = maxXRPValue maxValue = maxXRPValue

View File

@@ -2,6 +2,11 @@ import {assertResultMatch, TestSuite, assertRejects} from '../../utils'
import responses from '../../fixtures/responses' import responses from '../../fixtures/responses'
import requests from '../../fixtures/requests' import requests from '../../fixtures/requests'
import {ValidationError} from 'ripple-api/common/errors' import {ValidationError} from 'ripple-api/common/errors'
import binary from 'ripple-binary-codec'
import assert from 'assert-diff'
import {RippleAPI} from 'ripple-api'
const {schemaValidator} = RippleAPI._PRIVATE
const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100} const instructionsWithMaxLedgerVersionOffset = {maxLedgerVersionOffset: 100}
const {preparePayment: REQUEST_FIXTURES} = requests const {preparePayment: REQUEST_FIXTURES} = requests
const {preparePayment: RESPONSE_FIXTURES} = responses const {preparePayment: RESPONSE_FIXTURES} = responses
@@ -288,6 +293,55 @@ export default <TestSuite>{
assertResultMatch(response, RESPONSE_FIXTURES.noCounterparty, 'prepare') assertResultMatch(response, RESPONSE_FIXTURES.noCounterparty, 'prepare')
}, },
'preparePayment with source.amount/destination.minAmount can be signed': async (api, address) => {
// See also: 'sign succeeds with source.amount/destination.minAmount'
const localInstructions = {
...instructionsWithMaxLedgerVersionOffset,
sequence: 23
}
const response = await api.preparePayment(
address,
{
"source": {
address,
"amount": {
"currency": "GBP",
"value": "0.1",
"counterparty": "rpat5TmYjDsnFSStmgTumFgXCM9eqsWPro"
}
},
"destination": {
"address": "rEX4LtGJubaUcMWCJULcy4NVxGT9ZEMVRq",
"minAmount": {
"currency": "USD",
"value": "0.1248548562296331",
"counterparty": "rMaa8VLBTjwTJWA2kSme4Sqgphhr6Lr6FH"
}
}
},
localInstructions
)
// Important: check that the prepared transaction can actually be signed
// https://github.com/ripple/ripple-lib/issues/1237#issuecomment-631670946
const secret = 'shotKgaEotpcYsshSE39vmSnBDRim'
const result = api.sign(response.txJSON, secret)
const expectedResult = {
signedTransaction:
'12000022800200002400000017201B0086955361EC6386F26FC0FFFF0000000000000000000000005553440000000000DC596C88BCDE4E818D416FCDEEBF2C8656BADC9A68400000000000000C69D4438D7EA4C6800000000000000000000000000047425000000000000C155FFE99C8C91F67083CEFFDB69EBFE76348CA6AD4446F8C5D8A5E0B0000000000000000000000005553440000000000DC596C88BCDE4E818D416FCDEEBF2C8656BADC9A7321022B05847086686F9D0499B13136B94AD4323EE1B67D4C429ECC987AB35ACFA34574473045022100D9634523D8E232D4A7807A71856023D82AC928FA29848571B820867898413B5F022041AC00EC1F81A26A6504EBF844A38CC3204694EF2CC1A97A87632721631F93DA81145E7B112523F68D2F5E879DB4EAC51C6698A6930483149F500E50C2F016CA01945E5A1E5846B61EF2D376',
id: '1C558AA9B926C24FB6BBD6950B2DB1350A83F9F12E4385208867907019761A2D'
}
const decoded = binary.decode(result.signedTransaction)
assert(
decoded.Flags === 2147614720,
`Flags = ${decoded.Flags}, should be 2147614720`
)
assert.deepEqual(result, expectedResult)
schemaValidator.schemaValidate('sign', result)
},
'destination.minAmount': async (api, address) => { 'destination.minAmount': async (api, address) => {
const response = await api.preparePayment( const response = await api.preparePayment(
address, address,

View File

@@ -4,6 +4,7 @@ import binary from 'ripple-binary-codec'
import requests from '../../fixtures/requests' import requests from '../../fixtures/requests'
import responses from '../../fixtures/responses' import responses from '../../fixtures/responses'
import {TestSuite} from '../../utils' import {TestSuite} from '../../utils'
const {schemaValidator} = RippleAPI._PRIVATE const {schemaValidator} = RippleAPI._PRIVATE
const {sign: REQUEST_FIXTURES} = requests const {sign: REQUEST_FIXTURES} = requests
const {sign: RESPONSE_FIXTURES} = responses const {sign: RESPONSE_FIXTURES} = responses
@@ -145,6 +146,27 @@ export default <TestSuite>{
schemaValidator.schemaValidate('sign', result) schemaValidator.schemaValidate('sign', result)
}, },
'sign succeeds with source.amount/destination.minAmount': async (api, address) => {
// See also: 'preparePayment with source.amount/destination.minAmount'
const txJSON =
'{"TransactionType":"Payment","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Destination":"rEX4LtGJubaUcMWCJULcy4NVxGT9ZEMVRq","Amount":{"currency":"USD","issuer":"rMaa8VLBTjwTJWA2kSme4Sqgphhr6Lr6FH","value":"999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000"},"Flags":2147614720,"SendMax":{"currency":"GBP","issuer":"rpat5TmYjDsnFSStmgTumFgXCM9eqsWPro","value":"0.1"},"DeliverMin":{"currency":"USD","issuer":"rMaa8VLBTjwTJWA2kSme4Sqgphhr6Lr6FH","value":"0.1248548562296331"},"Sequence":23,"LastLedgerSequence":8820051,"Fee":"12"}'
const secret = 'shotKgaEotpcYsshSE39vmSnBDRim'
const result = api.sign(txJSON, secret)
const expectedResult = {
signedTransaction:
'12000022800200002400000017201B0086955361EC6386F26FC0FFFF0000000000000000000000005553440000000000DC596C88BCDE4E818D416FCDEEBF2C8656BADC9A68400000000000000C69D4438D7EA4C6800000000000000000000000000047425000000000000C155FFE99C8C91F67083CEFFDB69EBFE76348CA6AD4446F8C5D8A5E0B0000000000000000000000005553440000000000DC596C88BCDE4E818D416FCDEEBF2C8656BADC9A7321022B05847086686F9D0499B13136B94AD4323EE1B67D4C429ECC987AB35ACFA34574473045022100D9634523D8E232D4A7807A71856023D82AC928FA29848571B820867898413B5F022041AC00EC1F81A26A6504EBF844A38CC3204694EF2CC1A97A87632721631F93DA81145E7B112523F68D2F5E879DB4EAC51C6698A6930483149F500E50C2F016CA01945E5A1E5846B61EF2D376',
id: '1C558AA9B926C24FB6BBD6950B2DB1350A83F9F12E4385208867907019761A2D'
}
const decoded = binary.decode(result.signedTransaction)
assert(
decoded.Flags === 2147614720,
`Flags = ${decoded.Flags}, should be 2147614720`
)
assert.deepEqual(result, expectedResult)
schemaValidator.schemaValidate('sign', result)
},
'throws when encoded tx does not match decoded tx - prepared payment': async ( 'throws when encoded tx does not match decoded tx - prepared payment': async (
api, api,
address address

View File

@@ -1,5 +1,5 @@
{ {
"txJSON": "{\"Flags\":2147614720,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"ra5nK24KXen9AHvsdFTKHSANinZseWnPcX\",\"Amount\":{\"value\":\"9999999999999999e80\",\"currency\":\"USD\",\"issuer\":\"ra5nK24KXen9AHvsdFTKHSANinZseWnPcX\"},\"SendMax\":{\"value\":\"5\",\"currency\":\"USD\",\"issuer\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\"},\"DeliverMin\":{\"value\":\"4.93463759481038\",\"currency\":\"USD\",\"issuer\":\"ra5nK24KXen9AHvsdFTKHSANinZseWnPcX\"},\"Paths\":[[{\"account\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\"},{\"currency\":\"XRP\"},{\"issuer\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"currency\":\"USD\"},{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\"},{\"account\":\"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn\"}],[{\"account\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\"},{\"currency\":\"XRP\"},{\"issuer\":\"rfsEoNBUBbvkf4jPcFe2u9CyaQagLVHGfP\",\"currency\":\"USD\"},{\"account\":\"rfsEoNBUBbvkf4jPcFe2u9CyaQagLVHGfP\"},{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\"}]],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147614720,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"ra5nK24KXen9AHvsdFTKHSANinZseWnPcX\",\"Amount\":{\"value\":\"999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"currency\":\"USD\",\"issuer\":\"ra5nK24KXen9AHvsdFTKHSANinZseWnPcX\"},\"SendMax\":{\"value\":\"5\",\"currency\":\"USD\",\"issuer\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\"},\"DeliverMin\":{\"value\":\"4.93463759481038\",\"currency\":\"USD\",\"issuer\":\"ra5nK24KXen9AHvsdFTKHSANinZseWnPcX\"},\"Paths\":[[{\"account\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\"},{\"currency\":\"XRP\"},{\"issuer\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"currency\":\"USD\"},{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\"},{\"account\":\"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn\"}],[{\"account\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\"},{\"currency\":\"XRP\"},{\"issuer\":\"rfsEoNBUBbvkf4jPcFe2u9CyaQagLVHGfP\",\"currency\":\"USD\"},{\"account\":\"rfsEoNBUBbvkf4jPcFe2u9CyaQagLVHGfP\"},{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\"}]],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "0.000012", "fee": "0.000012",
"sequence": 23, "sequence": 23,