### Internal Hackathon: Bounty Strategy Development The goal was to build a flow similar to real-world project and attempt to use the extensions and write our own. Our focus was to replicate what Buidlbox offers and see how long it would take for us to get the contract running #### What We Did : Can we use an extension + build out own ? We began our hackathon project by creating a simple bounty strategy using the RecipientsExtension where a profile deploys the We explored the code and discovered the `_processRecipient` hook, which we utilized to add extra logic to the `registerRecipient` process. Once we completed the simple bounty contract, we decided to develop our own bounty extension that could be used by different strategies. This led to several challenges: - **Documentation**: There was a lack of information about the `_processRecipient` hook, so we had to learn through reading the code. _**Note**: @Henry it might be worth detailing all the hooks in every extension and offering examples on what can be done with it_ - **Extension Compatibility**: Our extension relied on the `_processRecipient` hook, which requires `bytes` data for decoding. This could pose difficulties for other contracts using the same hook without breaking our implementation. We realized the importance of having templates or standards for extension categories to ensure consistent implementations. This consistency is crucial for maintaining interoperability between contracts and extensions, particularly in areas like storage, hooks, and function signatures. For example, different RecipientExtensions would need to implement the `_processRecipient` hook in a similar manner to ensure that they work seamlessly across various extensions. Having this template would be more appealing for those who don't want to figure out all the details on how the extension works #### Moving Forward : Can we use our own extension to build diff flavours ? Next, we aimed to use our extension in a new strategy contract designed for multiple payouts per bounty, such as hackathon prizes. We wanted to avoid rewriting everything from scratch. Our initial extension was too static, making it challenging to implement minor changes. To address this, we refactored our function logic into smaller, internal virtual functions. This approach allowed us to override specific parts without changing the entire logic. For example, we modified the `distribute` function: ```solidity function _distribute(address[] memory _recipientIds, bytes memory _data, address _sender) internal virtual override onlyPoolManager(msg.sender) { uint256[] memory _bountyIds = _getBountyIdsFromDistributeData(_data); bytes[] memory _datas = abi.decode(_data, (bytes[])); uint256 _bountiesLength = _bountyIds.length; uint256 _datasLength = _datas.length; if (_recipientIds.length != _bountiesLength || _bountiesLength != _datasLength) { revert ProfileBounties_InvalidData(); } for (uint256 i = 0; i < _bountiesLength; i++) { uint256 bountyId = _bountyIds[i]; address recipientId = _recipientIds[i]; _revertInvalidBounty(bountyId, _datas[i]); _checkRecipientValidity(recipientId, bountyId, _datas[i]); _handleDistributedBountyState(recipientId, bountyId, _datas[i]); _transferDistribution(recipientId, bountyId, _datas[i]); } } function _revertInvalidBounty(uint256 _bountyId, bytes memory _data) internal virtual { Bounty memory bounty = bounties[_bountyId]; if (bounty.token == address(0) || bounty.status != Status.Pending) { revert ProfileBounties_InvalidData(); } } function _checkRecipientValidity(address _recipientId, uint256 _bountyId, bytes memory _data) internal virtual { if (bountyApplications[_bountyId][_recipientId].bountyId != _bountyId) { revert ProfileBounties_InvalidData(); } } function _handleDistributedBountyState(address _recipientId, uint256 _bountyId, bytes memory _data) internal virtual { Bounty storage _bounty = bounties[_bountyId]; _bounty.status = Status.Paid; } function _transferDistribution(address _recipientId, uint256 _bountyId, bytes memory _data) internal virtual { // todo: _bounty.token.transfer(_recipientId, _getAmountFromBountyData(bounties[_bountyId].data)); } ``` By structuring the code this way, we can tweak the function by just overriding the parts we need to change. For example, if we want to introduce new transfer logic, like a vault or streamed payments, we can simply override the `_transferDistribution` function. #### Key Learnings 1. **Modularization and Flexibility**: Breaking functions into smaller parts makes the code more flexible and easier to manage. We should document folks to have this line of thinking as they look to build extensions 2. **Data Handling**: Always passing additional data that can be encoded/decoded as needed is effective. This was done well in the extensions and we should document on why this important while building extensions. We also added an extra data field in our structs for this purpose: ```solidity struct Bounty { address token; Status status; Metadata metadata; bytes data; } ``` An example of a function that uses this `data` parameter is `_handleDistributedBountyState`, where if wanted custom behaviour for another strategy based on the data, they could choose to just override this: ```solidity function _handleDistributedBountyState(address _recipientId, uint256 _bountyId, bytes memory _data) internal virtual { Bounty storage _bounty = bounties[bountyId]; _bounty.status = Status.Paid; } ``` 3. **Creating Guides**: We should create guidelines on writing extensions to help other developers. These guides will cover best practices, common pitfalls, and examples to ensure consistent and interoperable extensions. However, writing good extensions is not straightforward. We need to learn and think about the different implementations and how they could be used in combination with other extensions. By providing clear documentation and templates, we can help developers create extensions that work seamlessly with existing contracts and extensions. 4. **Potential Improvements**: While working through the code, we identified potential improvements and documented them to share with the Wonderland team. https://hackmd.io/pns_c_WpSkmHY9eJIs1cXA?view