Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decoding logs with bytes data fields broken in 1.2.8 for solc 0.4.x / external #3544

Closed
bingen opened this issue May 27, 2020 · 30 comments
Closed
Labels
1.x 1.0 related issues Investigate Stale Has not received enough activity

Comments

@bingen
Copy link

bingen commented May 27, 2020

Expected behavior

Using decodeLogs should parse logs correctly, see here an example

Actual behavior

Throws with an error like this if there’s a bytes field in the log:

     Error: data out-of-bounds (length=36, offset=64, code=BUFFER_OVERRUN, version=abi/5.0.0-beta.153)
      at Logger.makeError (node_modules/@ethersproject/logger/lib/index.js:178:21)
      at Logger.throwError (node_modules/@ethersproject/logger/lib/index.js:187:20)
      at Reader._peekBytes (node_modules/@ethersproject/abi/lib/coders/abstract-coder.js:135:20)
      at Reader.readBytes (node_modules/@ethersproject/abi/lib/coders/abstract-coder.js:146:26)
      at BytesCoder.DynamicBytesCoder.decode (node_modules/@ethersproject/abi/lib/coders/bytes.js:30:23)
      at BytesCoder.decode (node_modules/@ethersproject/abi/lib/coders/bytes.js:41:81)
      at node_modules/@ethersproject/abi/lib/coders/array.js:77:31
      at Array.forEach (<anonymous>)
      at Object.unpack (node_modules/@ethersproject/abi/lib/coders/array.js:71:12)
      at TupleCoder.decode (node_modules/@ethersproject/abi/lib/coders/tuple.js:39:49)
      at AbiCoder.decode (node_modules/@ethersproject/abi/lib/abi-coder.js:93:22)
      at ABICoder.decodeParameters (node_modules/web3-eth-abi/src/index.js:322:30)
      at ABICoder.decodeLog (node_modules/web3-eth-abi/src/index.js:376:52)
      at eventLogs.map.log (node_modules/@aragon/contract-helpers-test/events.js:18:20)
      at Array.map (<anonymous>)
      at decodeEvents (node_modules/@aragon/contract-helpers-test/events.js:16:20)
      at getDeepEventLogs (test/lock_and_call.js:9:10)
      at getDeepEventArgument (test/lock_and_call.js:12:16)
      at checkCallbackLog (test/lock_and_call.js:50:18)
      at Context.it (test/lock_and_call.js:59:7)
      at process._tickCallback (internal/process/next_tick.js:68:7)

Steps to reproduce the behavior

Call that function mentioned above with a log like this one:

event LogLockCallback(uint256 amount, uint256 allowance, bytes data);

Logs

Copied above.

Environment

npm: 6.13.4
Node: v10.15.0
web3: 1.2.8
OS: PureOS 9.0

Reference

Related issue: aragon/contract-helpers#32

@ryanio
Copy link
Collaborator

ryanio commented May 27, 2020

Hey @bingen thanks for reporting, I will take a closer look this afternoon to see if we have tests for decoding logs with bytes data and if it’s working properly.

Meanwhile, could you share what the raw data is for the bytes field in your example above? It seems the ethers abi package is erroring out on “data out-of-bounds”.

@bingen
Copy link
Author

bingen commented May 27, 2020

Yes, it was:

0x00000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000040cbd8c2f

Thanks!

@ryanio
Copy link
Collaborator

ryanio commented May 27, 2020

hey @bingen, it does look like we have tests for decodeLog that include bytes examples and they are passing ok: https://github.com/ethereum/web3.js/blob/1.x/test/eth.abi.decodeLog.js

When I try to add a test with your example data:

{
    params: [[{
        type: 'bytes',
        name: 'data'
    }], '0x00000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000040cbd8c2f'],
    result: {
        'data': '0x00000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000040cbd8c2f',
        "__length__": 1
    }
}

I get:

  1) decodeLog
       should convert correctly:
     data: overflow (fault="overflow", operation="toNumber", value="2213609288845146193920", code=NUMERIC_FAULT, version=bignumber/5.0.0-beta.138)

@bingen
Copy link
Author

bingen commented May 28, 2020

Hm, but that data is for the whole log, which has 2 uints and 1 bytes fields, so it’s:

0x
uint  -> 0000000000000000000000000000000000000000000000000000000000000028
uint  -> 0000000000000000000000000000000000000000000000000000000000000078
bytes -> 000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000040cbd8c2f

@ryanio
Copy link
Collaborator

ryanio commented May 28, 2020

@bingen ah ok thanks that makes more sense. Ok I can reproduce the same error now with data out-of-bounds for the bytes data. Do you know what your bytes data is supposed to represent or convert to?

@bingen
Copy link
Author

bingen commented May 28, 2020

It’s supposed to be a function signature: https://github.com/aragon/staking/blob/master/test/lock_and_call.js#L27

@ryanio
Copy link
Collaborator

ryanio commented May 28, 2020

@bingen great thanks, ok looks like there may be some issue in the transport of the event because the function signature for receiveLock(uint256,uint256,bytes) is 0xabe985cb which doesn't seem to line up with the bytes data above, I am seeing it encode as:

{
    params: ['bytes', '0xabe985cb'],
    result: '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004abe985cb00000000000000000000000000000000000000000000000000000000'
}

It could be an encoding/decoding issue in the middle, will have to keep digging deeper on this one. We upgraded our abi coder dependency in 1.2.8 from ethers v4 to v5 so we are especially sensitive to any issues.

@bingen
Copy link
Author

bingen commented May 28, 2020

Oh, yes, sorry, that’s because I changed its name, it used to be lockCallback(uint256,uint256,bytes)
😬

@cgewecke
Copy link
Collaborator

cgewecke commented May 28, 2020

@bingen It's possible this is a compatibility issue with Truffle which remains on Web3 1.2.1 (and Ethers V4).

In your example CALLBACK_DATA is passed to a truffle-contract method (and encoded there) but decoded using 1.2.8 in the test helpers. No this is fine.

@cgewecke
Copy link
Collaborator

@bingen

Have tried to make a reproduction case for this using code from aragon contract-helpers, Truffle and Web3 1.2.8 and was not able to trigger the error.

Could you look at https://github.com/cgewecke/web3-issue-3544 and see if it models the bug correctly?

One notable difference from what's reported here is that when I have a solidity event like

event lockCallback(uint256 amount, uint256 allowance, bytes data);

...and inspect the receipt from a transaction that fires it, the raw log data looks like this:

0x0000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004abe985cb00000000000000000000000000000000000000000000000000000000

It's right padded. Is it possible your data was getting mangled somewhere after you got the receipt?

@cgewecke cgewecke added 1.x 1.0 related issues Investigate labels May 29, 2020
@cgewecke
Copy link
Collaborator

cgewecke commented Jun 1, 2020

@bingen Apologies, did you have a chance to look at this again? We'd really like to fix this ASAP if it's happening but at the moment are having difficulty reproducing it from a real example.

@bingen
Copy link
Author

bingen commented Jun 1, 2020

Hey, sorry, I didn’t have time to look at this, I’ll try tomorrow.

@bingen
Copy link
Author

bingen commented Jun 2, 2020

Hm, this is weird, I tired a fresh clone of the repo using this new branch where I just upgrade to web3 1.2.8 and it worked:

git clone git@github.com:aragon/staking.git
cd staking 
git checkout web3_issue
npm i
npm t test/lock_and_call.js

Besides, your example above looks good to me.
Maybe it’s some other package that I had in my local node_modules that was causing the issue, so I guess we can close this issue.
Sorry for the distraction!

@cgewecke
Copy link
Collaborator

cgewecke commented Jun 2, 2020

Sweet! Thanks @bingen.

@bingen
Copy link
Author

bingen commented Jun 9, 2020

Hey, sorry to bother with this again, but there was a problem in the branch I linked above: @aragon/contract-helpers-test was still using 1.2.5:

$ npm ls web3-utils
@aragon/staking@0.1.0 /tmp/staking
├─┬ @aragon/contract-helpers-test@0.0.3 invalid
│ └── web3-utils@1.2.5  extraneous
├─┬ web3-eth-abi@1.2.8
│ └── web3-utils@1.2.8  deduped
└── web3-utils@1.2.8 

I have fixed it, so it’s all 1.2.8 now:

$ npm ls web3-utils
@aragon/staking@0.1.0 /tmp/staking
├─┬ @aragon/contract-helpers-test@0.0.2
│ └── web3-utils@1.2.8  deduped
├─┬ web3-eth-abi@1.2.8
│ └── web3-utils@1.2.8  deduped
└── web3-utils@1.2.8 

And I see those errors again. You should see them too if you follow the steps mentioned above:

git clone git@github.com:aragon/staking.git
cd staking 
git checkout web3_issue
npm i
npm t test/lock_and_call.js

The errors are:

  1) Contract: Staking app, Locking and calling
       allows lock manager and locks
         and calls lock manager, with just the signature:
     Error: data out-of-bounds (length=36, offset=64, code=BUFFER_OVERRUN, version=abi/5.0.0-beta.153)
      at Logger.makeError (node_modules/@ethersproject/logger/lib/index.js:178:21)
      at Logger.throwError (node_modules/@ethersproject/logger/lib/index.js:187:20)
      at Reader._peekBytes (node_modules/@ethersproject/abi/lib/coders/abstract-coder.js:135:20)
      at Reader.readBytes (node_modules/@ethersproject/abi/lib/coders/abstract-coder.js:146:26)
      at BytesCoder.DynamicBytesCoder.decode (node_modules/@ethersproject/abi/lib/coders/bytes.js:30:23)
      at BytesCoder.decode (node_modules/@ethersproject/abi/lib/coders/bytes.js:41:81)
      at node_modules/@ethersproject/abi/lib/coders/array.js:77:31
      at Array.forEach (<anonymous>)
      at Object.unpack (node_modules/@ethersproject/abi/lib/coders/array.js:71:12)
      at TupleCoder.decode (node_modules/@ethersproject/abi/lib/coders/tuple.js:39:49)
      at AbiCoder.decode (node_modules/@ethersproject/abi/lib/abi-coder.js:93:22)
      at ABICoder.decodeParameters (node_modules/web3-eth-abi/src/index.js:322:30)
      at ABICoder.decodeLog (node_modules/web3-eth-abi/src/index.js:376:52)
      at eventLogs.map.log (node_modules/@aragon/contract-helpers-test/events.js:18:20)
      at Array.map (<anonymous>)
      at decodeEvents (node_modules/@aragon/contract-helpers-test/events.js:16:20)
      at getDeepEventLogs (test/lock_and_call.js:9:10)
      at getDeepEventArgument (test/lock_and_call.js:12:16)
      at checkCallbackLog (test/lock_and_call.js:50:18)
      at Context.it (test/lock_and_call.js:59:7)
      at process._tickCallback (internal/process/next_tick.js:68:7)

  2) Contract: Staking app, Locking and calling
       allows lock manager and locks
         and calls lock manager, with added data:
     Error: data out-of-bounds (length=68, offset=96, code=BUFFER_OVERRUN, version=abi/5.0.0-beta.153)
      at Logger.makeError (node_modules/@ethersproject/logger/lib/index.js:178:21)
      at Logger.throwError (node_modules/@ethersproject/logger/lib/index.js:187:20)
      at Reader._peekBytes (node_modules/@ethersproject/abi/lib/coders/abstract-coder.js:135:20)
      at Reader.readBytes (node_modules/@ethersproject/abi/lib/coders/abstract-coder.js:146:26)
      at BytesCoder.DynamicBytesCoder.decode (node_modules/@ethersproject/abi/lib/coders/bytes.js:30:23)
      at BytesCoder.decode (node_modules/@ethersproject/abi/lib/coders/bytes.js:41:81)
      at node_modules/@ethersproject/abi/lib/coders/array.js:77:31
      at Array.forEach (<anonymous>)
      at Object.unpack (node_modules/@ethersproject/abi/lib/coders/array.js:71:12)
      at TupleCoder.decode (node_modules/@ethersproject/abi/lib/coders/tuple.js:39:49)
      at AbiCoder.decode (node_modules/@ethersproject/abi/lib/abi-coder.js:93:22)
      at ABICoder.decodeParameters (node_modules/web3-eth-abi/src/index.js:322:30)
      at ABICoder.decodeLog (node_modules/web3-eth-abi/src/index.js:376:52)
      at eventLogs.map.log (node_modules/@aragon/contract-helpers-test/events.js:18:20)
      at Array.map (<anonymous>)
      at decodeEvents (node_modules/@aragon/contract-helpers-test/events.js:16:20)
      at getDeepEventLogs (test/lock_and_call.js:9:10)
      at getDeepEventArgument (test/lock_and_call.js:12:16)
      at checkCallbackLog (test/lock_and_call.js:50:18)
      at Context.it (test/lock_and_call.js:65:7)
      at process._tickCallback (internal/process/next_tick.js:68:7)

  3) Contract: Staking app, Locking and calling
       allows lock manager without locking
         and calls lock manager, with just the signature:
     Error: data out-of-bounds (length=36, offset=64, code=BUFFER_OVERRUN, version=abi/5.0.0-beta.153)
      at Logger.makeError (node_modules/@ethersproject/logger/lib/index.js:178:21)
      at Logger.throwError (node_modules/@ethersproject/logger/lib/index.js:187:20)
      at Reader._peekBytes (node_modules/@ethersproject/abi/lib/coders/abstract-coder.js:135:20)
      at Reader.readBytes (node_modules/@ethersproject/abi/lib/coders/abstract-coder.js:146:26)
      at BytesCoder.DynamicBytesCoder.decode (node_modules/@ethersproject/abi/lib/coders/bytes.js:30:23)
      at BytesCoder.decode (node_modules/@ethersproject/abi/lib/coders/bytes.js:41:81)
      at node_modules/@ethersproject/abi/lib/coders/array.js:77:31
      at Array.forEach (<anonymous>)
      at Object.unpack (node_modules/@ethersproject/abi/lib/coders/array.js:71:12)
      at TupleCoder.decode (node_modules/@ethersproject/abi/lib/coders/tuple.js:39:49)
      at AbiCoder.decode (node_modules/@ethersproject/abi/lib/abi-coder.js:93:22)
      at ABICoder.decodeParameters (node_modules/web3-eth-abi/src/index.js:322:30)
      at ABICoder.decodeLog (node_modules/web3-eth-abi/src/index.js:376:52)
      at eventLogs.map.log (node_modules/@aragon/contract-helpers-test/events.js:18:20)
      at Array.map (<anonymous>)
      at decodeEvents (node_modules/@aragon/contract-helpers-test/events.js:16:20)
      at getDeepEventLogs (test/lock_and_call.js:9:10)
      at getDeepEventArgument (test/lock_and_call.js:12:16)
      at checkCallbackLog (test/lock_and_call.js:50:18)
      at Context.it (test/lock_and_call.js:87:7)
      at process._tickCallback (internal/process/next_tick.js:68:7)

  4) Contract: Staking app, Locking and calling
       allows lock manager without locking
         and calls lock manager, with added data:
     Error: data out-of-bounds (length=68, offset=96, code=BUFFER_OVERRUN, version=abi/5.0.0-beta.153)
      at Logger.makeError (node_modules/@ethersproject/logger/lib/index.js:178:21)
      at Logger.throwError (node_modules/@ethersproject/logger/lib/index.js:187:20)
      at Reader._peekBytes (node_modules/@ethersproject/abi/lib/coders/abstract-coder.js:135:20)
      at Reader.readBytes (node_modules/@ethersproject/abi/lib/coders/abstract-coder.js:146:26)
      at BytesCoder.DynamicBytesCoder.decode (node_modules/@ethersproject/abi/lib/coders/bytes.js:30:23)
      at BytesCoder.decode (node_modules/@ethersproject/abi/lib/coders/bytes.js:41:81)
      at node_modules/@ethersproject/abi/lib/coders/array.js:77:31
      at Array.forEach (<anonymous>)
      at Object.unpack (node_modules/@ethersproject/abi/lib/coders/array.js:71:12)
      at TupleCoder.decode (node_modules/@ethersproject/abi/lib/coders/tuple.js:39:49)
      at AbiCoder.decode (node_modules/@ethersproject/abi/lib/abi-coder.js:93:22)
      at ABICoder.decodeParameters (node_modules/web3-eth-abi/src/index.js:322:30)
      at ABICoder.decodeLog (node_modules/web3-eth-abi/src/index.js:376:52)
      at eventLogs.map.log (node_modules/@aragon/contract-helpers-test/events.js:18:20)
      at Array.map (<anonymous>)
      at decodeEvents (node_modules/@aragon/contract-helpers-test/events.js:16:20)
      at getDeepEventLogs (test/lock_and_call.js:9:10)
      at getDeepEventArgument (test/lock_and_call.js:12:16)
      at checkCallbackLog (test/lock_and_call.js:50:18)
      at Context.it (test/lock_and_call.js:93:7)
      at process._tickCallback (internal/process/next_tick.js:68:7)

I’m going to try to see if I can provide any more info about it.

PS: I don’t see the option to reopen the issue, maybe you can do it if you think it’s a web3.js problem.

@cgewecke cgewecke reopened this Jun 9, 2020
@bingen
Copy link
Author

bingen commented Jun 9, 2020

I see some difference between the logged data in your test and what I get adding the same console.log’s:

  • Yours:
0x0000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004abe985cb00000000000000000000000000000000000000000000000000000000
  • Mine:
0x0000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000007800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004abe985cb

Let’s break it down:

0x
0000000000000000000000000000000000000000000000000000000000000005
0000000000000000000000000000000000000000000000000000000000000005
0000000000000000000000000000000000000000000000000000000000000060
0000000000000000000000000000000000000000000000000000000000000004
abe985cb00000000000000000000000000000000000000000000000000000000

vs

0x
0000000000000000000000000000000000000000000000000000000000000028
0000000000000000000000000000000000000000000000000000000000000078
0000000000000000000000000000000000000000000000000000000000000060
0000000000000000000000000000000000000000000000000000000000000004
abe985cb

So it seems the problem is I’m missing those trailing zeroes, and hence the buffer overrun.

@cgewecke
Copy link
Collaborator

cgewecke commented Jun 9, 2020

@bingen Was able to trigger the error in the minimal reproduction at https://github.com/cgewecke/web3-issue-3544 with this commit by

  • using solc 0.4.24
  • changing the visibility of the method which fires the event from public to external.

It's not reproducible in solc 0.5.x and the underlying issue was documented here: ethereum/solidity#3493.

So...on one hand the Ethers ABICoder upgrade has broken what used to work, on the other hand this discrepancy in the way solc encodes based on function visibility is weird.

What is your view of this?

@bingen
Copy link
Author

bingen commented Jun 10, 2020

Oops, yes, what a bug. I wonder why it was working with previous versions if the logs were coming different. Do you know how that difference was being handled?
On our side, we can keep on pinning v1.2.5, but I guess it would be useful to document it somewhere, as I expect this may hit some other projects still using solc 0.4.x
Thanks for the update!

@geomad
Copy link

geomad commented Jun 13, 2020

Hi! I'm having the same issue when trying to decode uniswap 2 pair contracts swap logs (solidity 0.5.16)

with web3.eth.abi.decodeLog on 1.2.8 or 1.2.9 I get the error:
UnhandledPromiseRejectionWarning: null: value out of range (argument="value", value=20, code=INVALID_ARGUMENT, version=bytes/5.0.0-beta.138)
This is working fine on version 1.2.7

Data field:
0x00000000000000000000000000000000000000000000003635c9adc5dea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d437ab7505b8492

Full Error Log:

(node:16552) UnhandledPromiseRejectionWarning: null: value out of range (argument="value", value=20, code=INVALID_ARGUMENT, version=bytes/5.0.0-beta.138)
    at Logger.makeError (C:\dev\logs\node_modules\@ethersproject\logger\lib\index.js:178:21)
    at Logger.throwError (C:\dev\logs\node_modules\@ethersproject\logger\lib\index.js:187:20)
    at Logger.throwArgumentError (C:\dev\logs\node_modules\@ethersproject\logger\lib\index.js:190:21)
    at Object.hexZeroPad (C:\dev\logs\node_modules\@ethersproject\bytes\lib\index.js:263:16)
    at AddressCoder.decode (C:\dev\logs\node_modules\web3-eth-abi\node_modules\@ethersproject\abi\lib\coders\address.js:34:45)
    at C:\dev\logs\node_modules\web3-eth-abi\node_modules\@ethersproject\abi\lib\coders\array.js:93:31
    at Array.forEach (<anonymous>)
    at Object.unpack (C:\dev\logs\node_modules\web3-eth-abi\node_modules\@ethersproject\abi\lib\coders\array.js:71:12)
    at TupleCoder.decode (C:\dev\logs\node_modules\web3-eth-abi\node_modules\@ethersproject\abi\lib\coders\tuple.js:39:49)
    at AbiCoder.decode (C:\dev\logs\node_modules\web3-eth-abi\node_modules\@ethersproject\abi\lib\abi-coder.js:93:22)
    at ABICoder.decodeParameters (C:\dev\logs\node_modules\web3-eth-abi\src\index.js:341:30)
    at ABICoder.decodeParameter (C:\dev\logs\node_modules\web3-eth-abi\src\index.js:319:17)
    at C:\dev\logs\node_modules\web3-eth-abi\src\index.js:386:25
    at Array.forEach (<anonymous>)
    at ABICoder.decodeLog (C:\dev\logs\node_modules\web3-eth-abi\src\index.js:382:12)
    at txlogs (C:\dev\logs\tests.js:681:36)
(node:16552) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:16552) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

@cgewecke
Copy link
Collaborator

@geomad Thanks for reporting.

Could you provide more specific info about:

  • which uniswap contracts
  • which method call
  • which event(s) fired

Are you using this?

Event signatures in the etherscan contract referenced above:

    event Mint(address indexed sender, uint amount0, uint amount1);
    event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint amount0In,
        uint amount1In,
        uint amount0Out,
        uint amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

Solidity version is 0.5.16

@geomad
Copy link

geomad commented Jun 13, 2020

@cgewecke Exactly. I'm trying to decode the Swap event Log above.

@cgewecke
Copy link
Collaborator

@geomad

Was unable to reproduce your error while interacting with the deployed Uniswap contracts. For example, decoding the Swap event for mainnet tx:

"0x4f19e76573f363956e9e356fdce0b65b6610f6c6663f22b1c21171f05363698c"

const abi = [
  {
    "indexed": true,
    "internalType": "address",
    "name": "sender",
    "type": "address"
  },
  {
    "indexed": false,
    "internalType": "uint256",
    "name": "amount0In",
    "type": "uint256"
  },
  {
    "indexed": false,
    "internalType": "uint256",
    "name": "amount1In",
    "type": "uint256"
  },
  {
    "indexed": false,
    "internalType": "uint256",
    "name": "amount0Out",
    "type": "uint256"
  },
  {
    "indexed": false,
    "internalType": "uint256",
    "name": "amount1Out",
    "type": "uint256"
  },
  {
    "indexed": true,
    "internalType": "address",
    "name": "to",
    "type": "address"
  }
];

const tx = "0x4f19e76573f363956e9e356fdce0b65b6610f6c6663f22b1c21171f05363698c";
const web3 = new Web3('https://mainnet.infura.io/v3/<INFURA_ID>');
const receipt = await web3.eth.getTransactionReceipt(tx);
const result = web3.eth.abi.decodeLog(
  abi, 
  receipt.logs[4].data, 
  receipt.logs[4].topics.slice(1)
);

> Result {
  '0': '0xf164fC0Ec4E93095b804a4795bBe1e041497b92a',
  '1': '0',
  '2': '1040000000000000000',
  '3': '801266216497835763803',
  '4': '0',
  '5': '0xaaa2e80AB7D7b3C216af30Fc8165E7823e74cc62',
  __length__: 6,
  sender: '0xf164fC0Ec4E93095b804a4795bBe1e041497b92a',
  amount0In: '0',
  amount1In: '1040000000000000000',
  amount0Out: '801266216497835763803',
  amount1Out: '0',
  to: '0xaaa2e80AB7D7b3C216af30Fc8165E7823e74cc62' 
}

Does this model your case correctly?

@geomad
Copy link

geomad commented Jun 13, 2020

@cgewecke this example works for me aswell. It seems like .slice(1) on the topics array did the trick and solved my issue aswell. While versions before 1.2.8 worked without slicing it, newer don't, so code that is written this way needs to be updated! Thanks for helping me resolving the issue!

@sohkai
Copy link

sohkai commented Jun 16, 2020

So...on one hand the Ethers ABICoder upgrade has broken what used to work, on the other hand this discrepancy in the way solc encodes based on function visibility is weird.

What is your view of this?

To be clear: the old Ethers v4 ABICoder did not have this problem, since it was the one used in <=web3@1.2.7?

I'd love @ricmoo's opinion on this as well, but since it's a somewhat prevalent solidity bug (lots of contracts were compiled with 0.4, especially older proxies), it is one of these weird edge cases to factor in when building and testing an ABI encoder.

@cgewecke
Copy link
Collaborator

To be clear: the old Ethers v4 ABICoder did not have this problem, since it was the one used in <=web3@1.2.7?

@sohkai Yes, that's correct. Web3 switched to @ethersproject/abi@^5.0.0-beta.153 in 1.2.8

@ricmoo
Copy link
Contributor

ricmoo commented Jun 16, 2020

The old coder didn’t have a problem with it because of a bug. :p

For context, that was a very old version of the ABI coder, which was fixed and that fix got brought along into v5. :)

If that fix had been around sooner, the bug would have hopefully been caught before any contract went to production. Alas, my bad. :(

The new error recovery API also cannot handle this, since it is a buffer overrun and not just a data type issue.

One solution would be to sanitize the data before feeding it to the abi coder, but this could also break the revert reason, which is also important.

Can we get an idea of how many contracts and their popularity are impacted? There isn’t really a good/clean/obvious fix, since it is literally wrong data being emitted from the contract.

@sohkai
Copy link

sohkai commented Jun 17, 2020

One solution would be to sanitize the data before feeding it to the abi coder, but this could also break the revert reason, which is also important.

Lacking context, but would it be naive to only do this sanitization when decoding logs (since I believe the bug may only be apparent there)?

Can we get an idea of how many contracts and their popularity are impacted? There isn’t really a good/clean/obvious fix, since it is literally wrong data being emitted from the contract.

I haven't done the homework (not sure if there's a good automated way of detecting this), but not being able to handle historic event data is my main concern.

If I'm correct, it looks like the bug is present only in these conditions:

  • Contract is compiled with solc@0.4.x
  • Contract contains external functions
  • One or more of the external functions log an event with non-indexed data from calldata (that must be a dynamic length data type, e.g. string or bytes? For example, this old OpenZeppelin contract should not be affected?)
    • If so, this may be quite common as a lot of off-chain content links (e.g. IPFS) are encoded as dynamic length bytes or strings and logged directly from calldata

While we (Aragon) are likely in the minority as our users still use 0.4.24 contracts and we haven't migrated them to 0.5+, this problem would still exist when we fetch old event data from contracts that were affected.

@cgewecke
Copy link
Collaborator

Update: discussion about this is proceeding at ethers 891.

For the moment it doesn't look like there's a simple fix (e.g: right padding) we can make here that works for events with more than one dynamically sized data type.

@cgewecke cgewecke changed the title Decoding logs with bytes data fields no longer works in 1.2.8 Decoding logs with bytes data fields broken in 1.2.8 for solc 0.4.x / external Jun 24, 2020
@github-actions
Copy link

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions

@ricmoo
Copy link
Contributor

ricmoo commented Sep 8, 2020

I've added support in ethers 5.0.12 for supporting legacy Solidity 0.4 external event data. I believe web3 depends on the abi package directly, in which case web3 should upgrade to @ethersproject/abi version 5.0.4.

For more details, please see ethers-io/ethers.js#891.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1.x 1.0 related issues Investigate Stale Has not received enough activity
Projects
None yet
Development

No branches or pull requests

6 participants