q9f / eth.rb

a straightforward library to build, sign, and broadcast ethereum transactions anywhere you can run ruby.
https://q9f.github.io/eth.rb
Apache License 2.0
196 stars 85 forks source link

Invalid value for negative int from eth_call #236

Closed wafcio closed 1 month ago

wafcio commented 1 year ago

I am trying to call uniswap NFT for LP position where min tick is -887220 instead of this I received very big positive number (115792089237316195423570985008687907853269984665640564039457584007913111975500). I am using this code:

require "eth"
require "forwardable"

client = Eth::Client.create("https://arb-mainnet.g.alchemy.com/v2/...")

client.call(
  Eth::Contract.from_abi(
    abi: File.read("data/uniswap/abi/nft_manager.json"),
    address: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
    name: "UniswapV3NonfungiblePositionManagerContract"
  ),
  'positions',  323850
)

for positions call I receive [0, "0x0000000000000000000000000000000000000000", "0x82af49447d8a07e3bd95bd0d56f35241523fbab1", "0xfc5a1a6eb076a2c7ad06ed22c90d7e710e35ad0a", 3000, 115792089237316195423570985008687907853269984665640564039457584007913111975500, 887220, 640820570603451914, 10541955816772571196803185866364767643, 641569016979010078464019001567004597581, 0, 0]

Btw, it will be great to add parser for response, something likeabi["outputs"].map.with_index { |func_el, index| [func_el["name"].to_sym, result[index]] }.to_h

Low level investigation params: {:data=>"0x99fbab88000000000000000000000000000000000000000000000000000000000004f10a", :to=>"0xC36442b4a4522E871399CD717aBDD847Ab11FE88"}

rpc response: {"jsonrpc"=>"2.0", "id"=>2, "result"=>"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000fc5a1a6eb076a2c7ad06ed22c90d7e710e35ad0a0000000000000000000000000000000000000000000000000000000000000bb8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2764c00000000000000000000000000000000000000000000000000000000000d89b400000000000000000000000000000000000000000000000008e4a6e9eb94f60a0000000000000000000000000000000007ee4e8cef48e37cb007d989b8b94d9b00000000000000000000000000000001e2a9b2b7eedd5e9d48db82ddcf7c1d4d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}

Everywhere else, like etherscan value is displayed as -887220

After some investigation it looks that there is issue with parsing int format especially for negative .

I believe issue is in line https://github.com/q9f/eth.rb/blob/main/lib/eth/abi/decoder.rb#L109

wafcio commented 1 year ago

Bug found, solution:

In line https://github.com/q9f/eth.rb/blob/main/lib/eth/abi/decoder.rb#L109

i = u >= 2 ** (type.sub_type.to_i - 1) ? (u - 2 ** type.sub_type.to_i) : u

gem removes 111..111 mask of datatype size. Unfortunately from RPC each value is saved on 256 bits, so it should look like this:

i = u >= 2 ** (type.sub_type.to_i - 1) ? (u - 2 ** 256) : u
q9f commented 1 year ago

Thanks for reporting. Unfortunately, the ABI submodule is 8 years old, and I'm currently in the process of rewriting this completely.

I might be able to publish a test case and a patch for this bug meanwhile. Stay tuned.

there is also another test case failing currently in https://github.com/q9f/eth.rb/blob/main/spec/eth/abi_spec.rb#L354

q9f commented 1 month ago

Thank you! This bug is at least 7 years old in this code base.

🙏🏼