XRPLF / xrpl.js

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

TypeError: amount.writeBigUInt64BE is not a function #1319

Closed mrosendin closed 3 years ago

mrosendin commented 3 years ago

I'm getting this error when signing a transaction. I'm using v1.8.1

App.tsx:138 TypeError: amount.writeBigUInt64BE is not a function
    at Function.Amount.from (amount.ts:77)
    at st-object.ts:127
    at Array.forEach (<anonymous>)
    at Function.STObject.from (st-object.ts:126)
    at serializeObject (binary.ts:67)
    at signingData (binary.ts:87)
    at Object.encodeForSigning (index.ts:47)
    at computeSignature (sign.ts:13)
    at signWithKeypair (sign.ts:54)
    at RippleAPI.sign (sign.ts:212)
    at App.tsx:120

txJSON (submitted as a raw string):

{
  "TransactionType": "Payment",
  "Account": "r9GsepoFoKKoafxWK8xY5qTp8NRa1XJBiN",
  "Destination": "rsNMwVA7bZny8bBqUYDNf2wC6VjXvEQEvs",
  "Amount": "500000000",
  "Flags": 2147483648,
  "Memos": [
    {
      "Memo": {
        "MemoData": "307834423243306164656237393833323641633839433630333438663732433734313746373837343065"
      }
    }
  ],
  "LastLedgerSequence": 11600009,
  "Fee": "12",
  "Sequence": 11600007
}
natenichols commented 3 years ago

Looks to me like this is occurring while encoding the transaction. I can successfully encode that txJSON using by calling encodeForSigning()

const api = require('ripple-binary-codec')

const txJSON = {
  "TransactionType": "Payment",
   .....
  "Fee": "12",
  "Sequence": 11600007
}

console.log(api.encodeForSigning(txJSON))

Gives me:

5354580012000022800000002400B10087201B00B1008961400000001DCD650068400000000000000C81145A9972BBE3BFC41EE1E7F6FAF5B4EB06EE851A3B831418767DAE699668062BB24382DF93BE6A5096B22DF9EA7D2A307834423243306164656237393833323641633839433630333438663732433734313746373837343065E1F1

Using node v12.18.0

Do you have more info about how you're using ripple-lib so that we can reproduce the issue?

intelliot commented 3 years ago

@mrosendin I think you'll get the writeBigUInt64BE is not a function error if you use a version of Node.js older than 10.22. We currently recommend Node.js v12 (LTS). Can you confirm which version you're using?

mrosendin commented 3 years ago

Hey @intelliot, I was using v10.22.0.

I upgraded to v12.18.3 and still encountering the issue.

@natenichols the use case is I'm making a faucet payment to mint FXRP on Flare's Coston test network. I'm using ripple-lib in a React SPA.

Still running into the issue with code as follows:

const faucetPayment = { ... }

return xrplAPI.preparePayment(xrpFundAddr, faucetPayment)
.then(preparedPayment => {
  console.log(api.encodeForSigning(JSON.parse(preparedPayment['txJSON']))); // error
  ...
})
intelliot commented 3 years ago

@mrosendin I'm not able to reproduce the issue. Here is a full example that I put together based on your snippet. I'm using node v12.18.3 and TypeScript 3.8.3.

import { RippleAPI } from 'ripple-lib'
import * as rbc from 'ripple-binary-codec'

const xrplAPI = new RippleAPI({server: 'wss://s.altnet.rippletest.net:51233'})

const faucetPayment = {
  source: {
    address: 'r9GsepoFoKKoafxWK8xY5qTp8NRa1XJBiN',
    amount: {
      currency: 'drops',
      value: '500000000'
    }
  },
  destination: {
    address: 'rsNMwVA7bZny8bBqUYDNf2wC6VjXvEQEvs',
    minAmount: {
      currency: 'drops',
      value: '500000000'
    }
  },
  memos: [{
    data: '307834423243306164656237393833323641633839433630333438663732433734313746373837343065'
  }]
}

xrplAPI.connect()
.then(() => xrplAPI.preparePayment('r9GsepoFoKKoafxWK8xY5qTp8NRa1XJBiN', faucetPayment))
.then(preparedPayment => {
  console.dir(JSON.parse(preparedPayment['txJSON']), { depth: null })
  console.log(rbc.encodeForSigning(JSON.parse(preparedPayment['txJSON']))); // error
})
.then(() => xrplAPI.disconnect())

Output:

{
  TransactionType: 'Payment',
  Account: 'r9GsepoFoKKoafxWK8xY5qTp8NRa1XJBiN',
  Destination: 'rsNMwVA7bZny8bBqUYDNf2wC6VjXvEQEvs',
  Amount: '500000000',
  Flags: 2147483648,
  Memos: [
    {
      Memo: {
        MemoData: '333037383334343233323433333036313634363536323337333933383333333233363431363333383339343333363330333333343338363633373332343333373334333133373436333733383337333433303635'
      }
    }
  ],
  LastLedgerSequence: 11620704,
  Fee: '12',
  Sequence: 11600007
}
5354580012000022800000002400B10087201B00B1516061400000001DCD650068400000000000000C81145A9972BBE3BFC41EE1E7F6FAF5B4EB06EE851A3B831418767DAE699668062BB24382DF93BE6A5096B22DF9EA7D54333037383334343233323433333036313634363536323337333933383333333233363431363333383339343333363330333333343338363633373332343333373334333133373436333733383337333433303635E1F1

Is the code running on your server side, or is it running in the client's browser?

mrosendin commented 3 years ago

Thanks, @natenichols. FTR I'm using TypeScript v3.7.2 and React v16.14.0. I created a Node.js project and ran the snippet with success...

5354580012000022800000002400B10087201B00B1596661400000001DCD650068400000000000000C81145A9972BBE3BFC41EE1E7F6FAF5B4EB06EE851A3B831418767DAE699668062BB24382DF93BE6A5096B22DF9EA7D54333037383334343233323433333036313634363536323337333933383333333233363431363333383339343333363330333333343338363633373332343333373334333133373436333733383337333433303635E1F1

So it seems that the problem is running this code in the client's browser.

intelliot commented 3 years ago

How are you including ripple-lib?

We build a version of ripple-lib for web browsers. On the Releases page, the ripple-latest-min.js and ripple-latest.js files are browser builds. These files are also available via third party CDNs like UNPKG.

I think Buffer and its methods like writeBigUInt64BE are not directly available in browsers, but we use webpack which changes everything to be browser-compatible. So alternatively, if you want to include the JS files intended for Node.js, you'll need to run webpack (or similar) before the code gets served to the browser.

Taking a step back -- why do you want to run ripple-lib in the client's browser? Depending on your use case, it may or may not make sense to do so.

mrosendin commented 3 years ago

@intelliot:

I've tried various different ways to include ripple-latest-min.js. It seems to require lodash so I've included that too. However, it can't read the library from window:

index.html

  ...
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>
  <script type="text/javascript" src="https://unpkg.com/ripple-lib@1.8.1/build/ripple-latest-min.js"></script>
</html>

App.tsx

TypeError: Cannot read property 'RippleAPI' of undefined
Module.<anonymous>
src/App.tsx:10
   7 | 
   8 | console.log(window)
   9 | // @ts-ignore
> 10 | const RippleAPI = window.ripple.RippleAPI;

The console.log(window) does show the library is loaded...I don't think React handles these cases very well.

To make sure I address the use case question, it'd be ideal to run the library in the browser as many other front-ends to blockchain applications (e.g., Ethereum Dapps) do. Even though it's only the test network, my use case requires generating testnet credentials or may involve inputting a set of XRPL testnet credentials in the browser to sign the faucet payment. I'm open to suggestions.

natenichols commented 3 years ago

@mrosendin Glad to hear you have a workaround.

After looking into it a little more:

The buffer library used by webpack to enable code to run in the browser doesn't have methods readBigUInt64BE()/writeBigUInt64BE(). To remedy this, until the buffer library is updated, I refactored ripple-binary-codec to not use those functions.

We should have a fix ready to go shortly. Here's the PR for ripple-binary-codec

mrosendin commented 3 years ago

@natenichols the workaround turned out to just be logging that made it look like it worked. Still having the same issue, so I do appreciate the support!

intelliot commented 3 years ago

@mrosendin As a quick fix, can you try using ripple-lib 1.8.0?

(1.8.0 uses an older version of ripple-binary-codec, which doesn't use writeBigUInt64BE)

mrosendin commented 3 years ago

@intelliot that worked!

natenichols commented 3 years ago

@mrosendin Got a new version of ripple-binary-codec up and working with react. With yarn:

yarn add ripple-binary-codec@beta

Let me know if that fixes your issues using ripple-lib v1.8.1

intelliot commented 3 years ago

Also, I just included the ripple-binary-codec fix in ripple-lib 1.8.2-beta.1. ~It's tagged as beta on npm so you should be able to get it with yarn add ripple-lib@beta or yarn add ripple-lib@1.8.2-beta.1 (same thing)~

mrosendin commented 3 years ago

@intelliot, I tried that, and I'm getting this error:

RangeError: offset is not uint
    at checkOffset (index.js:1097)
    at Uint8Array.readUInt32BE (index.js:1157)
    at UInt32.valueOf (uint-32.ts:53)
    at UInt32.UInt.toJSON (uint.ts:44)
    at STObject.toJSON (st-object.ts:154)
    at readJSON (binary.ts:29)
    at binaryToJSON (binary.ts:37)
    at Object.decode (index.ts:22)
    at checkTxSerialization (sign.ts:147)
    at signWithKeypair (sign.ts:62)
    at RippleAPI.sign (sign.ts:212)
    at App.tsx:110
mrosendin commented 3 years ago

@natenichols I did as you said, but I'm still getting the TypeError. I have "ripple-binary-codec": "^1.0.3" and "ripple-lib": "^1.8.1" in my package.json and freshly installed

intelliot commented 3 years ago

Thank you for finding that the beta failed to fix the issue. We're going to quickly fix this with #1321 (revert/rollback of ripple-binary-codec version)

intelliot commented 3 years ago

@mrosendin We just released 1.8.2 which should fix this issue. Thanks for catching this! Please confirm and/or close this issue :)

mrosendin commented 3 years ago

Great! Thanks, it works.