q9f / eth.rb

a straightforward library to build, sign, and broadcast ethereum transactions anywhere you can run ruby.
https://q9f.github.io/eth.rb
Apache License 2.0
204 stars 88 forks source link

encode bytes error #98

Closed lonnv closed 2 years ago

lonnv commented 2 years ago

When executing a method with arguments of data-type bytes4, a method encode_bytes(value, subtype) in abi.rb:356 throws an Eth::Abi::ValueOutOfBounds

in the Abi I have:

 {
    "constant": true,
    "inputs": [
      { "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" }
    ],
    "name": "supportsInterface",
    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  }

When I call with name supportsInterface and value 0x80ac58cd it throws that error. I can't pass an array of bytes or anything because anything other than a String throws an Eth::Abi::EncodingError on line 348.

Am I missing something or is it impossible to use bytes4 as an input type with the current implementation?

q9f commented 2 years ago

Do you mind posting a script or command you are running so I can try to reproduce it?

lonnv commented 2 years ago
client = Eth::Client.create("https://eth-rinkeby.alchemyapi.io/v2/#{ALCHEMY_KEY}")
contract_address = '0x1935899bfb630aed1fa54f2a943f0b0841724007'
erc721_abi = [{"constant"=>true,
"inputs"=>[{"internalType"=>"bytes4", "name"=>"interfaceId", "type"=>"bytes4"}],
"name"=>"supportsInterface",
"outputs"=>[{"internalType"=>"bool", "name"=>"", "type"=>"bool"}],
"payable"=>false,
"stateMutability"=>"view",
"type"=>"function"}]

erc_721_contract = Eth::Contract.from_abi(abi: erc721_abi, name: 'ERC721', address: contract_address)
client.call(erc_721_contract, 'supportsInterface', '0x80ac58cd')
q9f commented 2 years ago

I identified the issue. I'll try to have a patch by tomorrow.

q9f commented 2 years ago

It needs to be binary not hex. But I can have a patch tomorrow.

infura = Client.create "https://rinkeby.infura.io/v3/#{key}"
# => #<Eth::Client::Http:0x0000558c3bd406d0
# @gas_limit=21000,
# @host="rinkeby.infura.io",
# @id=0,
# @max_fee_per_gas=0.2e11,
# @max_priority_fee_per_gas=0,
# @port=443,
# @ssl=true,
# @uri=#<URI::HTTPS https://rinkeby.infura.io/v3/#{key}>>

contract_address = '0x1935899bfb630aed1fa54f2a943f0b0841724007'
# => "0x1935899bfb630aed1fa54f2a943f0b0841724007"

erc721_abi = [{"constant"=>true,
    "inputs"=>[{"internalType"=>"bytes4", "name"=>"interfaceId", "type"=>"bytes4"}],
    "name"=>"supportsInterface",
    "outputs"=>[{"internalType"=>"bool", "name"=>"", "type"=>"bool"}],
    "payable"=>false,
    "stateMutability"=>"view",}]
# => [{"constant"=>true,
#  "inputs"=>[{"internalType"=>"bytes4", "name"=>"interfaceId", "type"=>"bytes4"}],
#  "name"=>"supportsInterface",
#  "outputs"=>[{"internalType"=>"bool", "name"=>"", "type"=>"bool"}],
#  "payable"=>false,
#  "stateMutability"=>"view",
#  "type"=>"function"}]

erc_721_contract = Eth::Contract.from_abi(abi: erc721_abi, name: 'ERC721', address: contract_address)
# => #<Eth::Contract::ERC721:0x0000558c3bcf5860>

infura.call(erc_721_contract, "supportsInterface", "\x80\xACX\xCD")
# => true

Or:

infura.call(erc_721_contract, "supportsInterface", Util.hex_to_bin("0x80ac58cd"))
# => true
lonnv commented 2 years ago

Great, thank you