Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Truffle test throws error when specify web3 options on overloaded function #2868

Open
1 task
r0qs opened this issue Mar 2, 2020 · 7 comments
Open
1 task

Comments

@r0qs
Copy link

r0qs commented Mar 2, 2020


Issue

I don't know if this is a bug of Truffle or web3, or if I'm doing something wrong. But when I try to specify some options parameter (e.g. {from: some_address}) on an overloaded function the truffle test throws the following error:

Error: invalid number value (arg="number", coderType="uint256", value="One")
  at PromiEvent (node_modules/truffle/build/webpack:/packages/contract/lib/promievent.js:9:1)
  at TruffleContract.write (node_modules/truffle/build/webpack:/packages/contract/lib/execute.js:169:1)
  at Context.it (test/TestC.js:10:15)
  at processTicksAndRejections (internal/process/task_queues.js:86:5)

If I remove the option parameter (e.g. {from: some_address}) the test works. So it seems that truffle or web3 are getting the wrong function signature. Or I'm declaring it in the wrong way.

const c = await C.deployed();
await c.write("One", { from: account }); // this doesn't work
await c.write("One"); // this work

The code is:

pragma solidity >=0.5.13 <0.7.0;

interface I {
    function write(string calldata str) external;
    function read() external view returns (string memory);
}

abstract contract A is I {

    string _str;
    
    constructor() public {}

    function write(string memory str)
        public
        override
    {
        _str = str;
    }

    function read() public view override returns (string memory){
        return _str;
    }
}

abstract contract B is A {

    uint256 _number;

    constructor() public A() {}

    function write(uint256 number, string memory str)
        public
    {
        _number = number;
        _str = str;
    }
}

contract C is B {
    constructor() public B() {}
}

Steps to Reproduce

I created a repository to test this code and reproduce the problem. Just clone this repo and run "npm install" to install the dependencies, and run the ethereum client in one terminal:

$ npm run ganache-cli

Then, to see the test passing without the options parameter, run in another terminal:

$ npm run test

To see the error when the options parameter is informed, run:

$ npm run test:bug

Expected Behavior

The test should succeed passing the web3 options parameter.

Actual Results

Truffle test throws the error: "invalid number value (arg="number", coderType="uint256", valu e="One")"

Environment

  • Operating System: Arch Linux x86_64 Linux 5.5.7-arch1-1
  • Ethereum client: ganache-cli verison 6.9.1
  • Solc version: solc: 0.6.3+commit.8dda9521
  • Truffle version (truffle version): 5.1.15
  • node version (node --version): v11.15.0
  • npm version (npm --version): 6.14.1

Am I missing something? Even though if I make the "write" function virtual on the A contract and override it on the B contract, like the following:

abstract contract A is I {
...
function write(string memory str)
        public
        override
        virtual
    {
        _str = str;
    }
...
}
abstract contract B is A {
....
function write(string memory str)
        public
        override
    {
        super.write(str);
    }
...
}

I still get the same error.

And if I inspect the contract C abi the two method signatures are there:

abi:
   [...
     { inputs: [Array],
       name: 'write',
       outputs: [],
       stateMutability: 'nonpayable',
       type: 'function',
       constant: undefined,
       payable: undefined,
       signature: '0x216a3382' },
     { inputs: [Array],
       name: 'write',
       outputs: [],
       stateMutability: 'nonpayable',
       type: 'function',
       constant: undefined,
       payable: undefined,
       signature: '0xebaac771' } ],

Also in the contract object:

methods:
      { read: [Function: bound _createTxObject],
        '0x57de26a4': [Function: bound _createTxObject],
        'read()': [Function: bound _createTxObject],
        write: [Function: bound _createTxObject],
        '0x216a3382': [Function: bound _createTxObject],
        'write(uint256,string)': [Function: bound _createTxObject],
        '0xebaac771': [Function: bound _createTxObject],
        'write(string)': [Function: bound _createTxObject] },
@gnidan
Copy link
Contributor

gnidan commented Mar 3, 2020

Ah, thanks for reporting this! Congrats, you've successfully confused Truffle! :)

Sounds like your hunch is correct: because you define more than one write() method (write(string memory) and write(uint256, string memory)), and because your C contract inherits B, which has both of those methods, Truffle sees the second argument in c.write("...", { from: "..." }) and assumes you mean to use write(uint256, string memory). Thus, it tries to interpret "One" as a uint256.

(You had me for a second there with that error message... I thought you were making a joke, saying "One" is supposed to be a uint ;)

Anyway, Truffle provides a way for you to get around this incorrect method discernment... and it's that c.methods object you found! Unfortunately this isn't in our docs, but see the original release notes for this feature. Roughly, you should just do this:

await c.methods["write(uint256,string)"]("One", { from: account });

Hope this helps!

@haltman-at
Copy link
Contributor

haltman-at commented Mar 3, 2020

Btw, I want to pop in here that better overload resolution is planned for the future to make resorting to methods less necessary! (But it's going to take a while and methods is the current way to handle this.)

@r0qs
Copy link
Author

r0qs commented Mar 3, 2020

Hahaha, thanks @gnidan! It works indeed, but the correct method is:

await c.methods["write(string)"]("One", { from: account });

Since is the method with signature "write(string)" that looks to be hidden for truffle, but can be accessed explicitly as you recommended, and not the most derived method write(uint256,string).

@gnidan
Copy link
Contributor

gnidan commented Mar 3, 2020

It works indeed, but the correct method is:

Oh of course; I wrote the wrong one, oops :)

Anyway, glad I could help! Besides the docs change, anything else actionable here? Is this a case where Truffle can error better? Can we feasibly detect the ambiguity here / is it worth it to add this before @haltman-at's teased changes?

Feel free to close if you're satisfied, or I'll follow-up after some team discussion in our weekly ticket processing on Wednesday. Thanks again!

@gnidan gnidan added the bug label Mar 4, 2020
@gnidan
Copy link
Contributor

gnidan commented Mar 4, 2020

@haltman-at brings up a good point that we should be able to detect when the last argument is an options and thus not conformant to one of the overloads. Calling this a bug, then!

@argctl
Copy link

argctl commented Aug 16, 2023

Can an object ever be a useable parameter? The solidity ABI can only accept strings and number types?

@haltman-at
Copy link
Contributor

@Epict33tus No, the Solidity ABI is considerably broader than that; it includes both structs and arrays, for instance. You can read more about it here.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants