web3j icon indicating copy to clipboard operation
web3j copied to clipboard

`Unsupported type encountered: tuple` when trying to create contract wrapper

Open kalekale opened this issue 4 years ago • 22 comments

Tuple types don't seem to be supported

When trying to create a contract wrapper with web3j generate solidity generate --abiFile=myJson.json --outputDir=src/java/ --package=my.package, i run into this error: Unsupported type encountered: tuple

What is the status regarding this, is supporting tuples on the roadmap?

Example snippet from the abi:

...
{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order[]","name":"orders","type":"tuple[]"}],"name":"batchCancelOrders","outputs":[],"payable":true,"stateMutability":"payable","type":"function"}
...

kalekale avatar Jan 30 '21 23:01 kalekale

I also have this problem. How can I solve it?

katoyi120 avatar Feb 03 '21 09:02 katoyi120

Same here. I read that it was fixed and merged in new versions but even if I'm using v4.8.4 of web3j, it still doesn't support tuples. I don't think that's the case but for your information, I'm trying to generate wrappers via Gradle and my development environment is on WSL. How can we solve this problem?

I tried to simplify the contract I wrote here:

pragma solidity >=0.6.0;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/math/SafeMath.sol";

contract Wallet {
    using SafeMath for uint;
    
    struct Consumer {
        string id;
        Item[] itemStructs;
    }

    struct Item {
        string itemId;
        uint quantity;
    }
    mapping (address => Consumer) public consumers;
    mapping (address => mapping(string => bool)) public containsItem;

    function addItemToWallet(address _address, Item memory _item) public {
        Consumer storage consumer = consumers[_address];
        bool isAdded = false;
        
        for (uint i = 0; i<consumer.itemStructs.length; i++) {
            if (keccak256(bytes(consumer.itemStructs[i].itemId)) == keccak256(bytes(_item.itemId))) { 
                require(containsItem[_address][_item.itemId] = true);
                consumer.itemStructs[i].quantity = consumer.itemStructs[i].quantity.add(_item.quantity);
                isAdded = true;
            }
        }
        
        if (isAdded == false) {
         consumer.itemStructs.push(_item);
         containsItem[_address][_item.itemId] = true;
        }
    }
}

It also gives this error when I run ./gradlew generateContractWrappers:

Starting a Gradle Daemon (subsequent builds will be faster)

> Task :compileSolidity
Compiler run successful. Artifact(s) can be found in directory build/resources/main/solidity.
The message received from the daemon indicates that the daemon has disappeared.
Build request sent: Build{id=7484af22-3964-481c-874c-272d0ec2aabb, currentDir=/home/kay/ethereum-projects/loyalty-solidity-smart-contracts}
Attempting to read last messages from the daemon log...
Daemon pid: 19295
  log file: /home/kay/.gradle/daemon/6.8.2/daemon-19295.out.log
----- Last  20 lines from daemon log file - daemon-19295.out.log -----
2021-02-19T16:01:08.687+0300 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Starting executing command: Build{id=7484af22-3964-481c-874c-272d0ec2aabb, currentDir=/home/kay/ethereum-projects/loyalty-solidity-smart-contracts} with connection: socket connection from /127.0.0.1:41293 to /127.0.0.1:56444.
2021-02-19T16:01:08.691+0300 [ERROR] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: started DaemonCommandExecution[command = Build{id=7484af22-3964-481c-874c-272d0ec2aabb, currentDir=/home/kay/ethereum-projects/loyalty-solidity-smart-contracts}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:41293 to /127.0.0.1:56444] after 0.0 minutes of idle
2021-02-19T16:01:08.691+0300 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Marking the daemon as busy, address: [3311916f-d332-4e8d-8b27-bbbb224fb970 port:41293, addresses:[localhost/127.0.0.1]]
2021-02-19T16:01:08.692+0300 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Marking busy by address: [3311916f-d332-4e8d-8b27-bbbb224fb970 port:41293, addresses:[localhost/127.0.0.1]]
2021-02-19T16:01:08.696+0300 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry.
2021-02-19T16:01:08.700+0300 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry.
2021-02-19T16:01:08.701+0300 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry.
2021-02-19T16:01:08.702+0300 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer
2021-02-19T16:01:08.702+0300 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes.
2021-02-19T16:01:08.704+0300 [INFO] [org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy] Daemon is about to start building Build{id=7484af22-3964-481c-874c-272d0ec2aabb, currentDir=/home/kay/ethereum-projects/loyalty-solidity-smart-contracts}. Dispatching build started information...
2021-02-19T16:01:08.705+0300 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 19: dispatching org.gradle.launcher.daemon.protocol.BuildStarted@1870be57
2021-02-19T16:01:08.708+0300 [DEBUG] [org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment] Configuring env variables: [PATH, LESSCLOSE, BROWSER, XDG_DATA_DIRS, TERM, LANG, VSCODE_GIT_IPC_HANDLE, PIPE_LOGGING, VSCODE_GIT_ASKPASS_MAIN, NVM_INC, COLORTERM, VSCODE_IPC_HOOK_CLI, LOGNAME, VSCODE_GIT_ASKPASS_NODE, PWD, TERM_PROGRAM_VERSION, GIT_ASKPASS, USES_VSCODE_SERVER_SPAWN, AMD_ENTRYPOINT, _, NVM_CD_FLAGS, SHELL, NVM_DIR, LESSOPEN, WSL_INTEROP, WSL_DISTRO_NAME, TERM_PROGRAM, HOSTTYPE, GOPATH, OLDPWD, USER, GOROOT, NAME, WSLENV, VERBOSE_LOGGING, LS_COLORS, NVM_BIN, HOME, SHLVL]
2021-02-19T16:01:08.719+0300 [DEBUG] [org.gradle.launcher.daemon.server.exec.LogToClient] About to start relaying all logs to the client via the connection.
2021-02-19T16:01:08.719+0300 [INFO] [org.gradle.launcher.daemon.server.exec.LogToClient] The client will now receive all logging from the daemon (pid: 19295). The daemon log file: /home/kay/.gradle/daemon/6.8.2/daemon-19295.out.log
2021-02-19T16:01:08.721+0300 [INFO] [org.gradle.launcher.daemon.server.exec.LogAndCheckHealth] Starting build in new daemon [memory: 512 MiB]
2021-02-19T16:01:08.734+0300 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has started executing the build.
2021-02-19T16:01:08.734+0300 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] Executing build with daemon context: DefaultDaemonContext[uid=5dacd15e-f5c8-45a5-a2ea-e83282cbe123,javaHome=/usr/lib/jvm/java-11-openjdk-amd64,daemonRegistryDir=/home/kay/.gradle/daemon,pid=19295,idleTimeout=10800000,priority=NORMAL,daemonOpts=--add-opens,java.base/java.util=ALL-UNNAMED,--add-opens,java.base/java.lang=ALL-UNNAMED,--add-opens,java.base/java.lang.invoke=ALL-UNNAMED,--add-opens,java.prefs/java.util.prefs=ALL-UNNAMED,-XX:MaxMetaspaceSize=256m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant]
Compiler run successful. Artifact(s) can be found in directory build/resources/main/solidity.
Unsupported type encountered: tuple
Daemon vm is shutting down... The daemon has exited normally or was terminated in response to a user interrupt.
----- End of the daemon log -----


FAILURE: Build failed with an exception.

* What went wrong:
Gradle build daemon disappeared unexpectedly (it may have been killed or may have crashed)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

> Task :generateContractWrappers
Unsupported type encountered: tuple

Hope you guys can help us with it, thanks in advance!

kerimay avatar Feb 19 '21 13:02 kerimay

@kalekale hi, from the commands you used to generate the wrappers I can see you are using an older version of the CLI. I would recommend you delete the .web3j directory and download web3j once more the new command is web3j generate solidity .....

@kerimay hi, I used the contract that you provided and I was able to generate the wrappers fine I will dig deeper into the Gradle logs you provided to check what exactly the issue might be.

AlexandrouR avatar Feb 19 '21 13:02 AlexandrouR

@kalekale hi, from the commands you used to generate the wrappers I can see you are using an older version of the CLI. I would recommend you delete the .web3j directory and download web3j once more the new command is web3j generate solidity .....

@kerimay hi, I used the contract that you provided and I was able to generate the wrappers fine I will dig deeper into the Gradle logs you provided to check what exactly the issue might be.

I figured out that my general Gradle version on WSL wasn't updated and also, I had a special case with my contract. Except the method I provided here, I also had a function like this:

function getConsumerData(address _address) public view returns (Consumer memory) {
        return consumers[_address];
}

It was working on Remix IDE but maybe it was a bad practice I don't know, this caused the main issue on my case. Other functions with tuples worked well. Thank you for your attention @AlexandrouR

kerimay avatar Feb 21 '21 06:02 kerimay

@kerimay I do get the same issue when I try to generate the wrappers after adding the function, however, I can't compile this in Remix as I get this Invalid input source specified.

AlexandrouR avatar Feb 22 '21 11:02 AlexandrouR

Interesting, because I can compile and deploy it in Remix with no issue. Is it maybe because of compiler version? Mine was 0.7.4

kerimay avatar Feb 22 '21 18:02 kerimay

Just encountered the same problem while trying to build a wrapper.

Here is minimal example in solidity that fails.

pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

contract Hello {

struct Input {
    FooInput[] some;
}

struct FooInput {
    address someAddr;
    BarInput[] barInputs;
}

struct BarInput {
    uint8 xyz;
}

function foo(Input memory output) public pure returns (bool){
    return true;
}

}

Then I used solcjs and web3j to build a wrapper:

$ solcjs -V                                                                                                                                       
0.6.0+commit.26b70077.Emscripten.clang
$ web3j -v                                                                                                                               
 ...
by Web3Labs
Version: 1.4.1
Build timestamp: 2021-02-16 20:28:33.742 UTC
$ solcjs --bin --abi --optimize  hello.sol -o bb
hello.sol:19:14: Warning: Unused function parameter. Remove or comment out the variable name to silence this warning.
function foo(Input memory output) public pure returns (bool){
             ^-----------------^
$ web3j generate solidity --abiFile=bb/hello_sol_Hello.abi -o java -p foo.bar
by Web3Labs
Generating foo.bar.Hello_sol_Hello ... Unsupported type encountered: tuple

Please advise how to tackle this problem?

lukoyanov avatar Mar 02 '21 15:03 lukoyanov

Have the same problem: solc 0.8.2, web3j-cli 1.4.1

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.2;
contract Multicall {
struct Call {
    address target;
    bytes callData;
}
function aggregate(Call[] memory calls) public returns (uint256 blockNumber, bytes[] memory returnData) {
    blockNumber = block.number;
    returnData = new bytes[](calls.length);
    for(uint256 i = 0; i < calls.length; i++) {
        (bool success, bytes memory ret) = calls[i].target.call(calls[i].callData);
        require(success);
        returnData[i] = ret;
    }
}
}

$ solcjs Multicall.sol --optimize --bin --abi -o ./ $ web3j solidity generate -b Multicall_sol_Multicall.bin -a Multicall_sol_Multicall.abi -p cc -o ./ .. Generating cc.Multicall_sol_Multicall ... Unsupported type encountered: tuple

MajdT51 avatar Mar 12 '21 09:03 MajdT51

using maven plugin with web3j 5.0.0 - same issue with tuples when trying to compile an interface with a struct as param.

Whats the solution here? Provider is 3rd party. How can i provide structs manually?

BarBozz avatar May 08 '21 23:05 BarBozz

referencing also https://github.com/web3j/web3j/issues/653 i stumbled upon - sadly web3j doesnt support more recent solidity versions like 0.8 - how to use another solc with web3j?

pragma solidity >=0.7.0;
pragma experimental ABIEncoderV2;

interface SomeInterface {
    struct SomeStruct {
        address addressA;
        address addressB;
    }

    function someFunction(SomeStruct calldata params) external payable returns (uint256 result);
}

Code to produce the error

BarBozz avatar May 08 '21 23:05 BarBozz

@BarBozz web3j:5.0.0 was a mistake release. The latest version of web3j currently is 4.8.4 where tuples are supported to some extent. @MajdT51 and @lukoyanov The current generator still don't support structs containing addresses and list of structs. Will be added in the next release.

rach-id avatar May 09 '21 09:05 rach-id

Hello @SweeXordious, is this feature still under development or already released?

kristianstoinov avatar Jan 22 '22 13:01 kristianstoinov

@kristianstoinov try the latest release please and see. If it's still not working, then nobody picked it up so far.

rach-id avatar Jan 22 '22 14:01 rach-id

I tried the latest version and it still has this issue.

njovy avatar Mar 08 '22 06:03 njovy

@njovy Which version did you try exactly ?

rach-id avatar Mar 08 '22 09:03 rach-id

@SweeXordious I used the latest web3j-cli which is 1.4.1 and this version uses 4.8.4

              _      _____ _ 
             | |    |____ (_)
__      _____| |__      / /_ 
\ \ /\ / / _ \ '_ \     \ \ |
 \ V  V /  __/ |_) |.___/ / |
  \_/\_/ \___|_.__/ \____/| |
                         _/ |
                        |__/ 
by Web3Labs
Version: 1.4.1
Build timestamp: 2021-02-16 20:28:33.742 UTC

The error message says Unsupported type encountered: tuple. I believe this is misleading because it does generate a simple tuple type. This error occurred because of an array of tuple type, tuple[].

njovy avatar Mar 09 '22 02:03 njovy

I am checking the history of commits. There are multiple commits which touch on tuples. Howverr, we need a new web3j-cli release using latest master to see if this is covered or not. Maybe you can try creating a web3j-cli binary locally targeting latest master manually and see if the problem persists. Thanks.

rach-id avatar Mar 09 '22 08:03 rach-id

I just built the latest master branch of the web3j-cli it's not able to generate structs just yet...

davida5 avatar Apr 27 '22 15:04 davida5

@davida5 did you change the following line: https://github.com/web3j/web3j-cli/blob/45c2e095c6fed724b7ab32d97bbd03b6cfea91ae/build.gradle#L22 to:

web3jVersion = '4.9.1'

?

rach-id avatar Apr 27 '22 15:04 rach-id

@SweeXordious thanks, after changing the version as suggested it worked, the struct was generated as : MyClass extends StaticStruct . Also I had to change the the generated web3j script --- the "lib" in the classpath is now called "libs" ----

davida5 avatar Apr 27 '22 15:04 davida5

Awesome. I will open an issue under web3j-cli to create a new release.

rach-id avatar Apr 27 '22 16:04 rach-id

I am checking the history of commits. There are multiple commits which touch on tuples. Howverr, we need a new web3j-cli release using latest master to see if this is covered or not. Maybe you can try creating a web3j-cli binary locally targeting latest master manually and see if the problem persists. Thanks.

Can you write step by step? @SweeXordious

tonghoang196 avatar Aug 04 '22 08:08 tonghoang196

<build>
    <plugins>
        <plugin>
            <groupId>org.web3j</groupId>
            <artifactId>web3j-maven-plugin</artifactId>
            <version>4.9.4</version>
            <configuration>
                <soliditySourceFiles/>
            </configuration>
        </plugin>
    </plugins>
</build>

@SweeXordious still cannot deal with turple, need help @conor10 @snazha-blkio @antonydenyer

struct A {
    B[] b;
}

struct B {
    uint256 b1;
    address b2;
}

run with mvn web3j:generate-sources

error show: Unsupported type encountered: tuple

leiiiooo avatar Oct 09 '22 05:10 leiiiooo

Just checked, Web3J doesn't currently support structs of array of structs. That's why it's failing

rach-id avatar Oct 09 '22 11:10 rach-id

Just checked, Web3J doesn't currently support structs of array of structs. That's why it's failing

sad, bro. if like that, i need try to create bytes with another lib.

leiiiooo avatar Oct 09 '22 11:10 leiiiooo

Yes. I might work on this by the end of the year. But nothing promised.

rach-id avatar Oct 09 '22 14:10 rach-id

Yes. I might work on this by the end of the year. But nothing promised.

I would also like to contribute. Which library do I need to look at regarding this part of the modification?

leiiiooo avatar Oct 09 '22 23:10 leiiiooo

That would be really awesome if you could work on this.

The concerned modules are:

  • abi: contains the encoder/decoder for all types. This is where the encoding logic should be.
  • codegen: contains the Java wrapper code generator for the smart contracts.

The implementation should start at the abi module and have tests for different cases, mainly structs containing array of structs. And, after all of this is working, the codegen should be updated accordingly.

The abi part is hardest and might require some refactors.

You can be inspired from the following PRs as they touch on this:

rach-id avatar Oct 10 '22 10:10 rach-id

When web3J support structs of array of structs @SweeXordious?

tonghoang196 avatar Nov 04 '22 10:11 tonghoang196

I really need generate wrapper this abi, currently still error on web3j-cli version: 1.4.2

[
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "_expectedState",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "_settlePrice",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "_referralAddr",
        "type": "address"
      },
      {
        "internalType": "bytes",
        "name": "_signature",
        "type": "bytes"
      },
      {
        "components": [
          {
            "internalType": "address",
            "name": "maker",
            "type": "address"
          },
          {
            "internalType": "enum MarketOrder.OrderKind",
            "name": "kind",
            "type": "uint8"
          },
          {
            "components": [
              {
                "internalType": "enum MarketAsset.TokenStandard",
                "name": "erc",
                "type": "uint8"
              },
              {
                "internalType": "address",
                "name": "addr",
                "type": "address"
              },
              {
                "internalType": "uint256",
                "name": "id",
                "type": "uint256"
              },
              {
                "internalType": "uint256",
                "name": "quantity",
                "type": "uint256"
              }
            ],
            "internalType": "struct MarketAsset.Asset[]",
            "name": "assets",
            "type": "tuple[]"
          },
          {
            "internalType": "uint256",
            "name": "expiredAt",
            "type": "uint256"
          },
          {
            "internalType": "address",
            "name": "paymentToken",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "startedAt",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "basePrice",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "endedAt",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "endedPrice",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "expectedState",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "nonce",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "marketFeePercentage",
            "type": "uint256"
          }
        ],
        "internalType": "struct MarketOrder.Order",
        "name": "_order",
        "type": "tuple"
      }
    ],
    "name": "settleOrder",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

tonghoang196 avatar Nov 04 '22 10:11 tonghoang196