0

I'm doing a test and trying to send bytes data to a contract so it can parse, store in variables, and return a value.

Solidity code

pragma solidity 0.6.12;


contract testbyte {

    function sendBytes(bytes calldata _data) external pure returns (address) {
        (uint amountIn, uint amountOut, address pool) = abi.decode(_data, (uint, uint, address));

        return pool;


    }
}

I was looking at this answer here but passing the bytes data was done in Javascript. Parsing solidity bytes to params

Python code

w3 = Web3(Web3.HTTPProvider(node_provider))

# I collect all data, abi, etc in between.

data = {
    'amountIn': 1, 
    'amountOut': 2,
    'pool': 'pool address here'
}

# I usually do w3.toBytes(text='') to pass nothing on mainnet contracts.
bytes_data = w3.toBytes(text=str(data))

pool = contract.functions.sendBytes(bytes_data).call()
print(pool)

I get the bytes output

b"{'amountIn': 1, 'amountOut': 2, 'pool': 'pool address here'}"

If I try to pass that the contract reverts and if I try via remix I get

transact to testbyte.sendBytes errored: Error encoding arguments: Error: invalid arrayify value (argument="value", value="{'amountIn': 1, 'amountOut': 2, 'pool': 'pool address here'}", code=INVALID_ARGUMENT, version=bytes/5.5.0)

From researching I can only guess that my byte input is incorrect, or something in my contract is wrong, but I'm unsure.

UPDATE 1:

After looking at example in comment I ended up here: web3py encode method call parameters

I tried using the second method but I get contract reverted.

test_encode = encode_abi(['uint', 'uint', 'address'], [1, 2, '0xAD5ce863aE3E4E9394Ab43d4ba0D80f419F61789'])

contract.functions.sendBytes(test_encode).call()

When I try the first method mixed with the second

contract.encodeABI(fn_name='sendBytes', args=[test_encode])

It returns

0x4c93893a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000ad5ce863ae3e4e9394ab43d4ba0d80f419f61789

Randomly I input that into remix it return values, but all wrong values.

So I am still confused, the js portion seemed easier. Recovering data from Bytes using Assembly

UPDATE 2:

This code works when I take the output and input it into remix

test_encode = encode_abi(['uint', 'uint', 'address'], [1, 2, '0xAD5ce863aE3E4E9394Ab43d4ba0D80f419F61789'],)

contract.encodeABI(fn_name='sendBytes', args=[test_encode], data=test_encode)

output:

0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000ad5ce863ae3e4e9394ab43d4ba0d80f419f617890000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000ad5ce863ae3e4e9394ab43d4ba0d80f419f61789

When entered into remix it returns the right values! But now I don't know how to pass the data in a web3.py call. I keep getting execution reverted.

5
  • The input data is encoded as json. Search for a json decoder in solidity. I'd recommend to change how the input data is encoded. Decoding a json string in solidity will be expensive since it is string manipulation. If possible I'd recommend to use a struct as input data that way the compiler will generate the decoder.
    – Ismael
    Feb 16, 2022 at 3:48
  • @Ismael When you say change input data do you mean the data I'm sending to the function or the bytes parameter itself? I'd prefer to send input via bytes. I can send an array like [1,2,pool] but I'm not sure how I would send a struct via web3 py to the contract to decode.
    – dekubaka
    Feb 16, 2022 at 14:05
  • If you want to send byte see the example in the answer ethereum.stackexchange.com/questions/119342/…
    – Ismael
    Feb 16, 2022 at 15:19
  • @Ismael Updated post. I looked into this but it's in JavaScript. I am still having trouble passing the bytes data. Not sure where I'm going wrong.
    – dekubaka
    Feb 16, 2022 at 21:47
  • @Ismael went down a rabbit hole after your link and I got it now!
    – dekubaka
    Feb 16, 2022 at 23:53

1 Answer 1

0

Found the answer. It seems that my contract address was wrong in my .env file (whoops). After I corrected that I used the code below.

from eth_abi import encode_abi

test_encode = encode_abi(['uint', 'uint', 'address'], [1, 2, '0xAD5ce863aE3E4E9394Ab43d4ba0D80f419F61789'],) # Basically map the types to the values

pool = contract.functions.sendBytes(test_encode).call()
print(pool)

outputs

['0xAD5ce863aE3E4E9394Ab43d4ba0D80f419F61789']

If you want to use arrays you can do

test_encode = encode_abi(['uint[]', 'uint[]', 'address'], [[1,2], [3,4], '0xAD5ce863aE3E4E9394Ab43d4ba0D80f419F61789'],)

I could not use

contract.encodeABI(fn_name='sendBytes', args=[test_encode], data=test_encode)

I believe I was using it wrong, and the data it outputs is a string. When you input the value into remix it works. I can only assume remix handles things differently. Maybe someone can explain how to use this properly in the comments.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.