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

Improve revert reason when assuming interface compliance #1727

Closed
nventuro opened this issue Apr 24, 2019 · 7 comments · Fixed by #2018
Closed

Improve revert reason when assuming interface compliance #1727

nventuro opened this issue Apr 24, 2019 · 7 comments · Fixed by #2018
Labels
contracts Smart contract code. good first issue Low hanging fruit for new contributors to get involved!

Comments

@nventuro
Copy link
Contributor

As discussed in this review comment, it'd be interesting to wrap calls to unknown contracts for which an interface is assumed in a low-level call that returns a custom revert reason on error, to better describe what went wrong.

@nventuro nventuro added the contracts Smart contract code. label Apr 24, 2019
@frangio
Copy link
Contributor

frangio commented Apr 25, 2019

A concrete example where whoever works on this should begin is this line in ERC721:

https://github.com/OpenZeppelin/openzeppelin-solidity/blob/af55a843e3e2d9c941712788a3e0318988f2bd06/contracts/token/ERC721/ERC721.sol#L284

This line can revert if the receiver doesn't implement the onERC721Received function. It can also revert if it does implement it but something in the implementation like a require causes a revert.

This issue is about ensuring there is a nice error message in those cases.

The way in we can achieve it is by performing a low-level call which allows us to revert with a custom revert reason.

(bool success, bytes returndata) = to.call( ... );
if (!success) {
    // revert with custom reason (or use `returndata` if non-empty)
} else ...

@nventuro nventuro added the good first issue Low hanging fruit for new contributors to get involved! label Apr 25, 2019
@balajipachai
Copy link
Contributor

@nventuro I have started to look into it

@balajipachai
Copy link
Contributor

Hi @nventuro @frangio,
I have added below piece of code in ERC721.sol:

bytes memory payload = abi.encodeWithSignature(
          "onERC721Received(address,address,uint256,bytes)",
          msg.sender,
          from,
          tokenId,
          _data
        );

(bool success, bytes memory returndata) = to.call(payload);

if (!success) {
    revert("ERC721: to address does not implement ERC721Received interface");
} else {
          return true;
   }

While running the test cases it fails:
Issue1727

Any help on this will be much appreciated.

@NoopurShinde
Copy link

Hi Team,

I went through the specified issue. I have added the following code in ERC721.sol.

bytes memory payload = abi.encodeWithSignature(
        "onERC721Received(address,address,uint256,bytes)",
        msg.sender,
        from,
        tokenId,
        _data
        );

        (bool success, ) = to.call(payload);

        if (!success) {
            revert("ERC721: to address does not implement ERC721Received interface");
        } else {
                return true;
        }

I have created a dummy contract which does not implement the IERC721Receiver interface and have updated test cases for the same in ERC721.behavior.js

Please do let me know if this is the correct approach used or do I need to think of some other way to solve the issue.

@frangio
Copy link
Contributor

frangio commented Oct 9, 2019

That's pretty good @NoopurShinde!

It's also a possibility that the recipient does implement ERC721Received and has reverted to reject the transaction. In that case, we should bubble the revert reason up. We can account for this case by checking in the case of success == false whether the length of the returndata is greater than zero, and if so, bubbling that instead up of reverting with our own revert reason.

@NoopurShinde
Copy link

I have updated the code in ERC721.sol and ERC721Behavior.test.js as suggested by @frangio to solve the specified issues.
Whenever I run the test cases for ERC721, all the test cases are passed. But when I try to run the test suite, test cases result in failure. Is GSN causing the testcases to fail? I tried running test suite using truffle test and npm test. Please do let me know if this scenario is normal or is there something I am missing on.

@frangio
Copy link
Contributor

frangio commented Dec 6, 2019

Does someone want to pick up #1943 and continue the work?

nventuro added a commit that referenced this issue Jan 23, 2020
* adding mock contacts, test code

* adding changes to ERC721.sol per @frangio's comments on original PR #1943

* fix solhint warnings

* Update contracts/token/ERC721/ERC721.sol

Co-Authored-By: Francisco Giordano <[email protected]>

* same revert wording per @frangio's review suggestion

* per @frangio's feedback, changing the inline assembly to accomplish: we want to ignore the first 4 bytes of content, so we should read the length and decrease it by 4, then take the memory location and add 4 to it, then store the new length at the new memory location, then that is the new byte array that we want.

* change revert msg assembly per PR comment by @frangio

* unify revert msg in test code

* fix some failed tests, wording change

* Update contracts/token/ERC721/ERC721.sol

Co-Authored-By: Francisco Giordano <[email protected]>

* Update contracts/token/ERC721/ERC721.sol

Co-Authored-By: Francisco Giordano <[email protected]>

* fix test case, revert without reason

* fix 'ERC721ReceiverRevertsMock: Transaction rejected by receiver'

* style change per review by @frangio

* fix revert reason forwarding

* remove duplicate contracts/mocks/ERC721ReceiverRevertsMock.sol per review https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2018\#issuecomment-574381034

* Add changelog entry

* Fix tests

* Make tests more clear

Co-authored-by: Francisco Giordano <[email protected]>
Co-authored-by: Nicolás Venturo <[email protected]>
KaiRo-at pushed a commit to KaiRo-at/openzeppelin-contracts that referenced this issue Mar 16, 2020
* adding mock contacts, test code

* adding changes to ERC721.sol per @frangio's comments on original PR OpenZeppelin#1943

* fix solhint warnings

* Update contracts/token/ERC721/ERC721.sol

Co-Authored-By: Francisco Giordano <[email protected]>

* same revert wording per @frangio's review suggestion

* per @frangio's feedback, changing the inline assembly to accomplish: we want to ignore the first 4 bytes of content, so we should read the length and decrease it by 4, then take the memory location and add 4 to it, then store the new length at the new memory location, then that is the new byte array that we want.

* change revert msg assembly per PR comment by @frangio

* unify revert msg in test code

* fix some failed tests, wording change

* Update contracts/token/ERC721/ERC721.sol

Co-Authored-By: Francisco Giordano <[email protected]>

* Update contracts/token/ERC721/ERC721.sol

Co-Authored-By: Francisco Giordano <[email protected]>

* fix test case, revert without reason

* fix 'ERC721ReceiverRevertsMock: Transaction rejected by receiver'

* style change per review by @frangio

* fix revert reason forwarding

* remove duplicate contracts/mocks/ERC721ReceiverRevertsMock.sol per review https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2018\#issuecomment-574381034

* Add changelog entry

* Fix tests

* Make tests more clear

Co-authored-by: Francisco Giordano <[email protected]>
Co-authored-by: Nicolás Venturo <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contracts Smart contract code. good first issue Low hanging fruit for new contributors to get involved!
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants