How to encode tuple as input parameter to function using web3j

9.5k Views Asked by At

I am attempting to call a solidity function that looks something like the following:

function fillOrder(
    Order memory order,
    uint256 takerAssetFillAmount,
    bytes memory signature
)

Using web3j I would create the function similar to below, however I'm not quite sure how to represent the order which is represented as a struct in Solidity.

List<Type> inputParams = Arrays.asList(???, new 
Uint256(takerAssetFillAmount), new Bytes32(signture));
new Function("fillOrder", inputParams, Collections.emptyList());

Any pointers on how I should represent the struct?

Thanks.

3

There are 3 best solutions below

0
On

You can wrap parameters with square brackets.

For example, let's say I have a contract:

contract Test {
    struct Foo {
        uint a;
        string b;
        address c;
    }

    function bar (Foo memory foo) public {
        c = foo.c;
    }
}

I can call bar function with web3.js like this:

contract.methods.foo([123, "123", "0xABC...."]).send({ from: '0x...' })
0
On

Web3j offers such classes as StaticStruct and DynamicStruct where you define your struct object via primitives. Here is the sample from my project:

class Value: DynamicStruct {

    private lateinit var offer: String
    private lateinit var availableSince: BigInteger
    private lateinit var availabilityEnd: BigInteger
    private var isConsumed: Boolean = false
    private lateinit var lockedUntil: BigInteger

    constructor(
        offer: String,
        availableSince: BigInteger,
        availabilityEnd: BigInteger,
        isConsumed: Boolean,
        lockedUntil: BigInteger
    ) : super(
        Utf8String(offer), Uint256(availableSince),
        Uint256(availabilityEnd), Bool(isConsumed),
        Uint256(lockedUntil)
    ) {
        this.offer = offer
        this.availableSince = availableSince
        this.availabilityEnd = availabilityEnd
        this.isConsumed = isConsumed
        this.lockedUntil = lockedUntil
    }

    constructor(
        offer: Utf8String,
        availableSince: Uint256,
        availabilityEnd: Uint256,
        isConsumed: Bool,
        lockedUntil: Uint256
    ) : super(offer, availableSince, availabilityEnd, isConsumed, lockedUntil) {
        this.offer = offer.value
        this.availableSince = availableSince.value
        this.availabilityEnd = availabilityEnd.value
        this.isConsumed = isConsumed.value
        this.lockedUntil = lockedUntil.value
    }

}

Ideally you just need to pass this struct instance to you contract method as a parameter where contract is autogenerated over $web3j solidity generate -b /path/to/<smart-contract>.bin -a /path/to/<smart-contract>.abi -o /path/to/src/main/java -p com.your.organisation.name command.

However personally I faced with issue to make this console command working and have to implement required logic by my own. This is in the progress now.

0
On

here is the contract address https://goerli.etherscan.io/address/0xd5999bf0ce31a1d9d6a6de2bf03feaff1913cee5#writeContract

in the write function , createSwapOrder is asking nested Tuple . here is the solidity code to show the structure of tuple :

struct Side {
    address user;
    bytes signedRequiredOutput;
    ERC20Component[] erc20s;
    ERC721Component[] erc721s;
    ERC1155Component[] erc1155s;
}

struct ERC20Component {
    uint256 amount;
    address underlying;

    // A signed approval transaction giving `amount` transfer rights
    // of token `underlying` to address(this).
    // bytes signedApproval;
}

struct ERC721Component {
    uint256 tokenId;
    address collection;

    // A signed approval transaction giving `tokenId` tranfer rights
    // of token `collection` to address(this).
    // bytes signedApproval;
}

struct ERC1155Component {
    uint256 tokenId;
    uint256 amount;
    address collection;

    // A signed approval transaction giving `tokenId` tranfer rights
    // of token `collection` to address(this).
    // bytes signedApproval;
}

struct Order {
    Side side0;
    Side side1;
    uint256 expiry;
    bytes32 hashlock;
    bytes32 preimage;
    bool completed;
}

event OrderCreated(address indexed user, bytes32 orderId);

uint256 public totalOrders;
mapping(bytes32 => Order) public orders;

function createSwapOrder(
    Side calldata side0,
    bytes32 hashlock,
    uint256 timelock
) public {

... }

and in first args side0 is asking a nested tuple and this tuple formet should be like this ["0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","0x00",[["32","0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"]],[["32","0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"]],[["32","32","0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"]]],

i hope you can understand the structure how its provided !! and sure it working