XRPLF / xrpl.js

A JavaScript/TypeScript API for interacting with the XRP Ledger in Node.js and the browser
https://xrpl.org/
1.21k stars 512 forks source link

Signing fails when decimal amount contains trailing zeroes #1553

Closed mDuo13 closed 1 year ago

mDuo13 commented 3 years ago

Signing fails (Serialized transaction does not match original txJSON) when decimal amount contains trailing zeroes

When attempting to sign a transaction with an issued currency amount including insignificant trailing zeroes (such as "123.40") the sign function raises a mismatch error because the transaction deserializes the amount without trailing zeroes (such as "123.4").

Tested against ripple-lib 1.10.0.

Steps to reproduce

See this test case: https://gist.github.com/mDuo13/e0ccff15aedd2a0d216e067eb10605b1

Expected result

Successfully signed transaction blob

Actual result

This error:

ValidationError: Serialized transaction does not match original txJSON. See `error.data`
    at checkTxSerialization (/another/devel/rippleapi_workspace/node_modules/ripple-lib/dist/npm/transaction/sign.js:143:23)
    at signWithKeypair (/another/devel/rippleapi_workspace/node_modules/ripple-lib/dist/npm/transaction/sign.js:62:5)
    at RippleAPI.sign (/another/devel/rippleapi_workspace/node_modules/ripple-lib/dist/npm/transaction/sign.js:163:16)
    at Object.<anonymous> (/another/devel/rippleapi_workspace/test-trailingzeroes.js:21:17)
    at Module._compile (node:internal/modules/cjs/loader:1095:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:816:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:79:12)
    at node:internal/main/run_main_module:17:47 {
  data: {
    decoded: {
      TransactionType: 'Payment',
      Flags: 2147483648,
      Sequence: 20292260,
      DestinationTag: 0,
      Amount: {
        value: '123.4',
        currency: 'FOO',
        issuer: 'rnURbz5HLbvqEq69b1B4TX6cUTNMmcrBqi'
      },
      Fee: '12',
      Account: 'rnURbz5HLbvqEq69b1B4TX6cUTNMmcrBqi',
      Destination: 'rf9XceKtJ1Pt1bbARgBo9KXsgNebhSWwuU'
    },
    tx: {
      TransactionType: 'Payment',
      Account: 'rnURbz5HLbvqEq69b1B4TX6cUTNMmcrBqi',
      Amount: {
        currency: 'FOO',
        issuer: 'rnURbz5HLbvqEq69b1B4TX6cUTNMmcrBqi',
        value: '123.40'
      },
      Destination: 'rf9XceKtJ1Pt1bbARgBo9KXsgNebhSWwuU',
      DestinationTag: 0,
      Flags: 2147483648,
      Fee: '12',
      Sequence: 20292260
    },
    diff: { Amount: { value: '123.4' } }
  }
}

Related issues

mvadari commented 3 years ago

Proposed solution: in ripple-binary-codec, add a new exported function that does this sort of checking for you, and can do padStart on all the numbers on both encode/decode.

shortthefomo commented 2 years ago
Screen Shot 2021-10-24 at 13 22 09

hit same bug here today as well

here is my current work around for others

                const offer_create_tx = {
                    TransactionType: 'OfferCreate',
                    Account: wallet.classicAddress,
                    TakerGets: (Math.trunc(amount)).toString(),
                    TakerPays: {
                        currency: currency,
                        issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
                        value: ((price * amount) / 1000000).toFixed(2).toString().replace(/(\.0+|0+)$/, '')
                    }
                }
intelliot commented 2 years ago

I think something like @lathanbritz 's approach is ideal -- it's best to specify values without trailing zeros, as the error simply reflects the fact that trailing zeros are "dropped" and not encoded/signed - I don't think the signed data has any indication of whether there were trailing zeros.

JST5000 commented 1 year ago

This no longer appears to be an issue in xrpl.js v2.6.0.

When trying to reproduce this issue by running the following code, it successfully submits a transaction for 123.4 FOO without throwing an error when given 123.40 FOO as an input.

Code to reproduce:

import { Client, Payment, TrustSet } from 'xrpl'

const client = new Client('wss://s.altnet.rippletest.net:51233')

void sendTx()

// The snippet walks us through creating and finishing escrows.
async function sendTx(): Promise<void> {
  await client.connect()

  // creating wallets as prerequisite
  const { wallet: wallet1 } = await client.fundWallet()
  const { wallet: wallet2 } = await client.fundWallet()

  const trustset: TrustSet = {
    TransactionType: 'TrustSet',
    Account: wallet2.address,
    LimitAmount: {
      currency: 'FOO',
      issuer: wallet1.address,
      value: '10000',
    },
  }

  const trustset_response = await client.submitAndWait(trustset, {
    wallet: wallet2,
  })

  console.log(trustset_response)

  const payment: Payment = {
    TransactionType: 'Payment',
    Account: wallet1.address,
    Amount: {
      currency: 'FOO',
      issuer: wallet1.address,
      value: '123.40',
    },
    Destination: wallet2.address,
    DestinationTag: 0,
    Flags: 2147483648,
  }

  const payment_response = await client.submitAndWait(payment, {
    wallet: wallet1,
  })

  console.log(payment_response)

  await client.disconnect()
}

Output:

{
  id: 23,
  result: {
    Account: 'rU5bBf617FKGmrtuZG3VPUSPdGkSyQJN7H',
    Fee: '12',
    Flags: 0,
    LastLedgerSequence: 34792562,
    LimitAmount: {
      currency: 'FOO',
      issuer: 'rwHDRrQjkELmn8Zez7N3H5kC6dUk8pmjUa',
      value: '10000'
    },
    Sequence: 34792542,
    SigningPubKey: 'EDDED52DFA03FB85FE84C0D66C177AABD3633307148BDE67016B5CD10C86EE1F49',
    TransactionType: 'TrustSet',
    TxnSignature: 'A42309D5D81FB617E8106778E9E62EFF0587A5976BB6C44D23559E5657BA93FB2D7FDB268C306C66E09587DBB2593927637EB61B534B67541936E819EC2F6000',
    date: 727824371,
    hash: 'C54315BB135435803CF218AD95D8BAC7F3447CCE1D3EE8E32DCB8974F20502B7',
    inLedger: 34792544,
    ledger_index: 34792544,
    meta: {
      AffectedNodes: [Array],
      TransactionIndex: 8,
      TransactionResult: 'tesSUCCESS'
    },
    validated: true
  },
  type: 'response'
}
{
  id: 36,
  result: {
    Account: 'rwHDRrQjkELmn8Zez7N3H5kC6dUk8pmjUa',
    Amount: {
      currency: 'FOO',
      issuer: 'rwHDRrQjkELmn8Zez7N3H5kC6dUk8pmjUa',
      value: '123.4'
    },
    Destination: 'rU5bBf617FKGmrtuZG3VPUSPdGkSyQJN7H',
    DestinationTag: 0,
    Fee: '12',
    Flags: 2147483648,
    LastLedgerSequence: 34792564,
    Sequence: 34792540,
    SigningPubKey: 'EDA0D2F749A0DB43C7609E8C0EA86EFA66BA32314D61B02A5D5D243F78111516C0',
    TransactionType: 'Payment',
    TxnSignature: '1A96EEC6C6A5D93502D7B77DB69C19C8142C1491C060262C2FCA7040B94D32F693A25A58976FF55B11613E8F53B2765BEFDFEF9AA85BCC737A10D9F1665F1702',
    date: 727824373,
    hash: '4BF8A1FA4B16308F091719656E763799A1F1EE86F4436D046E9AD9493410A4AB',
    inLedger: 34792546,
    ledger_index: 34792546,
    meta: {
      AffectedNodes: [Array],
      TransactionIndex: 1,
      TransactionResult: 'tesSUCCESS',
      delivered_amount: [Object]
    },
    validated: true
  },
  type: 'response'
}