stellar / soroban-example-dapp

End-to-End Example Soroban Dapp
Apache License 2.0
1.03k stars 835 forks source link

bigNumberToI128 not working for large numbers #101

Closed lmorgan824 closed 11 months ago

lmorgan824 commented 1 year ago

What version are you using?

What did you do?

using convert.ts for large numbers

// A ten digital number works //const b1 = new BigNumber("1234567890");

// A twenty digital number does not work, pos or neg // FIXME: Not working const b1 = new BigNumber("12345678901234567890"); console.log("b1", util.inspect(b1, false, 5), b1.toString()); const scv1 = bigNumberToI128(b1); console.log("scv1", util.inspect(scv1, false, 5), scvalToBigNumber(scv1)); const b2 = scvalToBigNumber(scv1); console.log("b2", util.inspect(b2, false, 5), b2.toString());

What did you expect to see?

12345678901234567890

What did you see instead?

b2 BigNumber { s: -1, e: 6, c: [ 4223278 ] } -4223278

lmorgan824 commented 1 year ago

Sorry, the FIXME: seems rude on my part; that was a note for me. I am poking about on this, too, I'll post here if I find anything.

lmorgan824 commented 1 year ago

I found the problem: It's in scvalToBigNumber. All the cases for scv > 32 are not passing in bytes buffers to the function bigNumberFromBytes, they're passing in 32 bit numbers. This is causing problems because the param ...bytes don't expand a 32bit value into a buffer. (At least not in my version of node 16.13.1)

I thought hacked a fix by doing this in the scvToBigNumber(scval) function, which should work for the 64 and 256 cases too. There's probably a more elegant solution but it doesn't work for super large number, still working on it...

case xdr.ScValType.scvI128(): {
  const parts = scval.i128();
      const a = parts.hi();
      const b = parts.lo();

      let aHighPadded = Buffer.alloc(4);
      let aHigh = bigintToBuf(a.high);
      aHigh.copy(aHighPadded, aHighPadded.length - aHigh.length);
      let aLowPadded = Buffer.alloc(4);
      let aLow = bigintToBuf(a.low);
      aLow.copy(aLowPadded, aLowPadded.length - aLow.length);
      let bHighPadded = Buffer.alloc(4);
      let bHigh = bigintToBuf(b.high);
      bHigh.copy(bHighPadded, bHighPadded.length - bHigh.length);
      let bLowPadded = Buffer.alloc(4);
      let bLow = bigintToBuf(b.low);
      bLow.copy(bLowPadded, bLowPadded.length - bLow.length);
      let bigBuf = Buffer.concat(
        [aHighPadded, aLowPadded, bHighPadded, bLowPadded],
        16
      );

      return bigNumberFromBytes(true, ...bigBuf);
}
lmorgan824 commented 1 year ago

Something is still wrong as it looks like numbers > 64bits are breaking it and it might be in the encoding xdr.Uint64 overflowing ??

paulbellamy commented 1 year ago

PRs to fix this are welcome, but I don't want to spend too much energy on convert.ts right now. We are working on better conversion functions which will live in js-stellar-base as part of the bigger typescript-contract-bindings effort.

cc @willemneal for visibility.

lmorgan824 commented 1 year ago

If I wind up with a good solution, I'll do a PR but I have what I need now for my current Soroban contracts so, NP just leaving it. I was going to ask about putting these conversions in js-stellar-base, perfect spot. I'll dust off some of my code from the '90s I did for IBM-PC to Sun Micro with RPC and XDR, blast from the past..LOL

esteblock commented 1 year ago

Hello @lmorgan824 this should be fixed in https://github.com/stellar/soroban-example-dapp/pull/121