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 543 forks source link

Contract call returnig different values from web3.php and web3.js #287

Closed navigatrum closed 2 years ago

navigatrum commented 2 years ago

I'm calling isValidSignature method from wallet contract implementing EIP1271 (sort of, returning bool, for Argent [and Loopring] wallets, taken from spruceid/siwe/test/eip1271.json).

Problem is that the web3.php call is returning false; while the web3.js call is returning true as expected.

All the params are taken from the same json file, so they are exactly the same for both the implementations.

Here a test repo.

Code

In php I'm doing this (in a class extending PHPUnit\Framework\TestCase):

function testEip1271FromJson()
{
  $data = json_decode(file_get_contents("path/to/below.json"), true);
  extract($data);

  $web3 = new Web3(new HttpProvider(new HttpRequestManager($rpc, "2000")));
  $wallet_contract = new Contract($web3->provider, $abi);

  $wallet_contract->at($address)->call(
    'isValidSignature',
    $hashedMessage,
    $signature,
    function ($err, $result) {
      var_dump($err);     // NULL
      var_dump($result);  // array(1) { [0] => false(bool) }
      if($err != null) {
        return $this->fail($err->getMessage());
      }
      $this->assertTrue($result[0]); // line 272
    }
  );
}

resulting in:

 ✘ Eip 1771 from json
   │
   │ Failed asserting that false is true.
   │
   │ tests/MessageTest.php:272
   │ vendor/web3p/web3.php/src/Contract.php:667
   │ vendor/web3p/web3.php/src/Providers/HttpProvider.php:56
   │ vendor/web3p/web3.php/src/RequestManagers/HttpRequestManager.php:100
   │ vendor/web3p/web3.php/src/Providers/HttpProvider.php:62
   │ vendor/web3p/web3.php/src/Eth.php:105
   │ vendor/web3p/web3.php/src/Contract.php:668
   │ tests/MessageTest.php:273
   │
NULL
array(1) {
  [0]=>
  bool(false)
}

This is the (working) js:

import Web3 from "web3";

async function testValidSignature() {
  const data = require("path/to/below.json");
  const { rpc, abi, address, hashedMessage, signature } = data;

  const web3 = new Web3();
  web3.setProvider(rpc);
  const walletContract = new web3.eth.Contract(abi, address);

  const isValidSignature = await walletContract.methods.isValidSignature(
      hashedMessage,
      signature
  ).call();

  console.log(isValidSignature); // true
}

This is the json:

{
  "rpc": "https://main-rpc.linkpool.io/",
  "signature": "0x00193f8bb87a8bd4a8367a47ee477c62aec984830ec59e730b28d1ec54669eab450b9f3108a5c435648691c5766b35e2f13b8fb29f46298bb378ac34597d7e271c",
  "hashedMessage": "0x13f64d354be469f23cf911231c7acf0b0faf781fbdef0eb1c463bdec229faf0b",
  "address": "0xa5b3A53800cD49669F34DE80f2C569c6D4Ca3009",
  "abi": [
    {
      "inputs": [
        {
          "internalType": "bytes32",
          "name": "_message",
          "type": "bytes32"
        },
        {
          "internalType": "bytes",
          "name": "_signature",
          "type": "bytes"
        }
      ],
      "name": "isValidSignature",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    }

}
navigatrum commented 2 years ago

My fault. Problem was that the contract isn't a sort-of EIP1271 returning bool. But it's exaclty a EIP1271 returning bytes4. And while web3.js (and ethers.js) decoding implementation 'trasforms' the resulting transaction string to true (maybe casting it to bool), web3.php transforms it to false (for some reasons depending on how Ethabi::decodeParameters is implemented).