web3p / web3.php

A php interface for interacting with the Ethereum blockchain and ecosystem. Native ABI parsing and smart contract interactions.
MIT License
1.16k stars 542 forks source link

BigInteger object returned from contract function call can't be negative? #172

Open Nanolucas opened 4 years ago

Nanolucas commented 4 years ago

Firstly, thank you for creating this library!

The problem I am having: my contract function call returns an int256 array. If the return value is a positive integer e.g. [0, 1] then it works correctly:

 [_coordinates] => Array
    (
    [0] => phpseclib\Math\BigInteger Object
        (
            [value] => 0x
            [engine] => gmp
        )
    [1] => phpseclib\Math\BigInteger Object
        (
            [value] => 0x01
            [engine] => gmp
        )
)

However, if the values returned are negative e.g. [-1, -2], it seems to treat them as unsigned ints and then underflows them?

[_coordinates] => Array
(
    [0] => phpseclib\Math\BigInteger Object
        (
            [value] => 0x00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
            [engine] => gmp
        )
    [1] => phpseclib\Math\BigInteger Object
        (
            [value] => 0x00fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
            [engine] => gmp
        )
)

If it makes a difference, the specific return type definition is: int256[2] memory _coordinates

Is there some special way I need to handle signed ints?

Nanolucas commented 4 years ago

After looking into this further it seems it isn't necessarily related to being part of an array. I've changed the function so it returns each of the coordinates separately e.g. [0, 0] would be returned as two separate integers instead of one array.

Making this contract call from the web3.js equivalent gets the correct values, however, the problem with negative integers still remains in web3.php.

Return values which should be int(0) and int(-1) are instead being returned as 0 and 115792089237316195423570985008687907853269984665640564039457584007913129639935.

Doing a stacktrace I can see that the Contract object has loaded the following output types for my method from the Abi:

["outputs"]=>
array(5) {
  [0]=>
  array(3) {
    ["internalType"]=>
    string(5) "int32"
    ["name"]=>
    string(0) ""
    ["type"]=>
    string(5) "int32"
  }
  [1]=>
  array(3) {
    ["internalType"]=>
    string(5) "int32"
    ["name"]=>
    string(0) ""
    ["type"]=>
    string(5) "int32"
  }
  [2]=>
  array(3) {
    ["internalType"]=>
    string(5) "uint8"
    ["name"]=>
    string(0) ""
    ["type"]=>
    string(5) "uint8"
  }
  [3]=>
  array(3) {
    ["internalType"]=>
    string(6) "uint16"
    ["name"]=>
    string(0) ""
    ["type"]=>
    string(6) "uint16"
  }
  [4]=>
  array(3) {
    ["internalType"]=>
    string(6) "uint16"
    ["name"]=>
    string(0) ""
    ["type"]=>
    string(6) "uint16"
  }
}

When the contract function call runs (via HttpRequestManager) it returns the following output:

string(322) "0x0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000006700000000000000000000000000000000000000000000000000000000000017000000000000000000000000000000000000000000000000000000000000000000"

which is then being split by the output formatters into:

array(5) {
    [0]=>
    object(phpseclib\Math\BigInteger)#260 (2) {
      ["value"]=>
      string(2) "0x"
      ["engine"]=>
      string(3) "gmp"
    }
    [1]=>
    object(phpseclib\Math\BigInteger)#299 (2) {
      ["value"]=>
      string(68) "0x00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
      ["engine"]=>
      string(3) "gmp"
    }
    [2]=>
    object(phpseclib\Math\BigInteger)#278 (2) {
      ["value"]=>
      string(4) "0x67"
      ["engine"]=>
      string(3) "gmp"
    }
    [3]=>
    object(phpseclib\Math\BigInteger)#263 (2) {
      ["value"]=>
      string(6) "0x1700"
      ["engine"]=>
      string(3) "gmp"
    }
    [4]=>
    object(phpseclib\Math\BigInteger)#280 (2) {
      ["value"]=>
      string(2) "0x"
      ["engine"]=>
      string(3) "gmp"
    }
}

Can anyone help me figure out how the int32 value is somehow underflowing?

xxbtc commented 2 years ago

running into this issue as well... any solution out there?