Love the new PuzzleWallet Ethernaut level

Love the new PuzzleWallet Ethernaut level @andresbach, @jcarpanelli, @vicente, and thank @xaler for merging the code and continually improving Ethernaut!

I especially enjoyed all the obstacles I ran into while trying to drain the ETH balance on the proxy contract. Felt great when I finally came up with the same solution as the one used in the unit test :slight_smile:

One suggestion: mention msg.value in the hint given for the level https://github.com/OpenZeppelin/ethernaut/pull/282

2 Likes

Thanks @scottt !

We just fixed an issue regarding the impossibility of submitting the last level (Motorbike, it's a new one have you seen it ?). Find the details here https://github.com/OpenZeppelin/ethernaut/pull/287

And also thanks for submitting that PR I will be reviewing it as next task

1 Like

Is it possible to get a hint to this level? I am assuming that there is some sort of nested multicall to drain the contract but not sure how msg.value plays a role in that.

Hi @xaler, sorry for the late reply!

I indeed ran into the "impossible to submit a solution to last problem" bug back in October, but I saw your then in-progress fixes in the fix-last-level-submission branch when I went to Github to file a bug.

I used your branch and the React fixes to submit a solution to Motorbike around two days after I solved PuzzleWallet.

@gypto_currency, here's a spoiler adjacent hint to PuzzleWallet:

See the check against calling deposit() more than once in multicall? It's fallible.

    function multicall(bytes[] calldata data) external payable onlyWhitelisted {
        bool depositCalled = false;
        for (uint256 i = 0; i < data.length; i++) {
            bytes memory _data = data[i];
            bytes4 selector;
            assembly {
                selector := mload(add(_data, 32))
            }
            if (selector == this.deposit.selector) {
                require(!depositCalled, "Deposit can only be called once");
                // Protect against reusing msg.value
                depositCalled = true;
            }
            (bool success, ) = address(this).delegatecall(data[i]);
            require(success, "Error while delegating call");
        }
    }
1 Like

I also enjoyed this puzzle very much. However, i have one concern. Using the remix IDE, when i try to multicall with the following param:
deposit func selector --> 1
nested multicall data --> 2
execute func data --> 3
My tx fails, however, when i do it seperately like so:
multicall with param 1 and 2
then execution separately, my tx works, i checked the testing script and it uses method number one, i wonder why it doesnt work on remix?

@scottt thank you for your message and help. I had identified this issue but I am dumb and didn't realize the implication that it would have on the balance mapping versus the actual balance of the contract! Woohoo!

1 Like