Comment by @definn • Hey
Nice, thank you for publishing this!
A few things that are kind of bugging me still:
👉 1. In the Strategy/Relayed contract (0x097...), there is a `isRou
Comments
- Great questions @DeFinn!
👉 1+2. They didn’t get past this, they simply called the round. The vote function was called on the round contract by the attacker and then the round contract called the function on the voting implementation. So the is round contract modifier didn't actually help in this case. To your second point: the relayer address is automatically set as the `msg.sender` in the round implementation. This way, when the function was called from the lens module we had originally designed to use/be the relayer which would have to be an approved address. You can inspect the vote method in the round contract on our GitHub.
Voting in round contract: [https://github.com/bitbeckers/grants-round/blob/16b786db1367b1248e83b732cfcce5676ee54846/packages/contracts/contracts/round/RoundImplementation.sol#L384C6-L384C6](https://github.com/bitbeckers/grants-round/blob/16b786db1367b1248e83b732cfcce5676ee54846/packages/contracts/contracts/round/RoundImplementation.sol#L384C6-L384C6)
👉 3. Let’s dive a little deeper in the code.
For the vote we expect the decoded data `(address _voterAddress, address _token, uint256 _amount, address _grantAddress, bytes32 _projectId)` . It’s not the project ID but the grantAddress that set’s the tip recipient. The project ID is the encoded Lens publication ID. Admittedly, this could also be something else.
In our app, the encoding happens client side as you can see in Tipping component. (LINK). The attacker(s) mimicked the functionality of the frontend but with parameters that allowed the exploit.
Data encoding: [https://github.com/psparacino/qf-lenster/blob/3bc857cd2462fd6c6d953017c4ea28e61b7c327f/apps/web/src/components/Publication/Actions/Tip/Tipping.tsx#L211](https://github.com/psparacino/qf-lenster/blob/3bc857cd2462fd6c6d953017c4ea28e61b7c327f/apps/web/src/components/Publication/Actions/Tip/Tipping.tsx#L211)
Data decoding: [https://github.com/bitbeckers/grants-round/blob/16b786db1367b1248e83b732cfcce5676ee54846/packages/contracts/contracts/votingStrategy/QuadraticFundingRelayStrategy/QuadraticFundingRelayStrategyImplementation.sol#L72](https://github.com/bitbeckers/grants-round/blob/16b786db1367b1248e83b732cfcce5676ee54846/packages/contracts/contracts/votingStrategy/QuadraticFundingRelayStrategy/QuadraticFundingRelayStrategyImplementation.sol#L72)
👉 4. Yes! Lens did a very good job at establishing that pattern and this is probably also why they’ve been pretty restrictive in allowing new modules into their production environment. A powerful property of the protocol is to have Modules with specific functionalities that are controlled by Lens users/application via the LensHub. At the risk of cutting some corners: If you create a post as a user you configure the module with specific parameters that will be used when the Module is called. Additionally, if you’re not a user or the post doesn’t have the module enabled, you can’t execute the module.
And this brings us back to the Relayer setup. The Module would be the Relayer and should have the allowance set.