-
Notifications
You must be signed in to change notification settings - Fork 3
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
bounty -> hackathon #46
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// SPDX-License-Identifier: AGPL-3.0-only | ||
pragma solidity ^0.8.19; | ||
|
||
// Core Contracts | ||
import {BaseStrategy} from "strategies/BaseStrategy.sol"; | ||
import {BountyExtension} from "strategies/extensions/bounties/BountyExtension.sol"; | ||
import {RecipientExtension} from "strategies/extensions/recipients/RecipientsExtension.sol"; | ||
|
||
// NOTE: Singleton contracts will require different extensions | ||
// NOTE: Why do the extensions have constructors ? | ||
|
||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀ | ||
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀ | ||
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀ | ||
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀ | ||
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀ | ||
// allo.gitcoin.co | ||
|
||
/// @title ProfileBounties Strategy | ||
/// @notice Strategy that allows allo profiles to create and manage bounties under one instance | ||
// Every profile on the registry would deploy their own instance of this strategy | ||
// and then manage all the bounties for that profile. | ||
contract MultipleBountyDistributions is BaseStrategy, RecipientExtension, BountyExtension { | ||
/// =============================== | ||
/// ======== Constructor ========== | ||
/// =============================== | ||
constructor(address _allo, string memory _strategyName) BaseStrategy(_allo, _strategyName) {} | ||
|
||
mapping(uint256 => uint256) public distributedAmounts; | ||
/// =============================== | ||
/// ========= Initialize ========== | ||
/// =============================== | ||
|
||
function initialize(uint256 _poolId, bytes memory _data) external override { | ||
__BaseStrategy_init(_poolId); | ||
// NOTE: can this entire function be moved to the BaseStrategy ? | ||
// and have another internal function which strategies can override | ||
emit Initialized(_poolId, _data); | ||
} | ||
|
||
function _getBountyIdFromExtraData(bytes memory _extraData) internal view virtual returns (uint256) { | ||
return abi.decode(_extraData, (uint256)); | ||
} | ||
|
||
function _handleDistributedBountyState(address _recipientId, uint256 _bountyId, bytes memory _data) | ||
internal | ||
override | ||
{ | ||
// nothing to do | ||
} | ||
|
||
function _transferDistribution(address _recipientId, uint256 _bountyId, bytes memory _data) internal override { | ||
uint256 distributedAmount = distributedAmounts[_bountyId]; | ||
uint256 amount = _getAmountFromBountyData(bounties[_bountyId].data); | ||
|
||
uint256 amountToDistribute = abi.decode(_data, (uint256)); | ||
uint256 newDistributedAmount = distributedAmount + amountToDistribute; | ||
if (newDistributedAmount <= amount) { | ||
distributedAmounts[_bountyId] = newDistributedAmount; | ||
// todo: _bounty.token.transfer(_recipientId, amountToDistribute); | ||
} | ||
if (newDistributedAmount == amount) { | ||
Bounty storage _bounty = bounties[bountyId]; | ||
_bounty.status = Status.Paid; | ||
} | ||
} | ||
|
||
// returns totalAmount and distribution amounts | ||
function _decodeData(bytes memory _data) internal view virtual returns (uint256, uint256) { | ||
return abi.decode(_data, (uint256, uint256)); | ||
} | ||
|
||
function _getAmountFromBountyData(bytes memory _data) internal view virtual returns (uint256) { | ||
(uint256 amount, _) = _decodeData(_data); | ||
return amount; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// SPDX-License-Identifier: AGPL-3.0-only | ||
pragma solidity ^0.8.19; | ||
|
||
// Core Contracts | ||
import {BaseStrategy} from "strategies/BaseStrategy.sol"; | ||
import {BountyExtension} from "strategies/extensions/bounties/BountyExtension.sol"; | ||
import {RecipientExtension} from "strategies/extensions/recipients/RecipientsExtension.sol"; | ||
// NOTE: Singleton contracts will require different extensions | ||
// NOTE: Why do the extensions have constructors ? | ||
|
||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀ | ||
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀ | ||
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀ | ||
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀ | ||
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀ | ||
// allo.gitcoin.co | ||
|
||
/// @title ProfileBounties Strategy | ||
/// @notice Strategy that allows allo profiles to create and manage bounties under one instance | ||
// Every profile on the registry would deploy their own instance of this strategy | ||
// and then manage all the bounties for that profile. | ||
contract ProfileBounties is BaseStrategy, RecipientExtension, BountyExtension { | ||
/// =============================== | ||
/// ======== Constructor ========== | ||
/// =============================== | ||
constructor(address _allo, string memory _strategyName) BaseStrategy(_allo, _strategyName) {} | ||
|
||
/// =============================== | ||
/// ========= Initialize ========== | ||
/// =============================== | ||
function initialize(uint256 _poolId, bytes memory _data) external override { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dont forget to also initialize the |
||
__BaseStrategy_init(_poolId); | ||
// NOTE: can this entire function be moved to the BaseStrategy ? | ||
// and have another internal function which strategies can override | ||
emit Initialized(_poolId, _data); | ||
} | ||
|
||
function _getBountyIdFromExtraData(bytes memory _data) internal view override returns (uint256) { | ||
return abi.decode(_data, (uint256)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
// SPDX-License-Identifier: AGPL-3.0-only | ||
pragma solidity ^0.8.19; | ||
|
||
// Internal Imports | ||
// Core Contracts | ||
import {BaseStrategy} from "strategies/BaseStrategy.sol"; | ||
import {Transfer} from "contracts/core/libraries/Transfer.sol"; | ||
import {Metadata} from "contracts/core/libraries/Metadata.sol"; | ||
|
||
/// @title NFT Gating Extension | ||
/// @notice This contract is providing nft gating options for a strategy's calls | ||
/// @dev This contract is inheriting BaseStrategy | ||
abstract contract BountyExtension is BaseStrategy { | ||
using Transfer for address; | ||
|
||
enum Status { | ||
None, | ||
Pending, | ||
Paid | ||
} | ||
|
||
struct Bounty { | ||
address token; | ||
Status status; | ||
Metadata metadata; | ||
bytes data; | ||
} | ||
|
||
// if we don't add any fields to application, | ||
// we can remove this struct and save only the metadata | ||
struct BountyApplication { | ||
uint256 bountyId; | ||
address recipientId; | ||
Metadata metadata; | ||
bytes data; | ||
} | ||
// maybe recipientAddress? | ||
|
||
/// =============================== | ||
/// ========== Storage ============ | ||
/// =============================== | ||
|
||
/// @notice Counter for the number of bounties created | ||
uint256 public bountyIdCounter; | ||
|
||
/// @notice Mapping of bounty id to bounty | ||
mapping(uint256 => Bounty) public bounties; | ||
|
||
/// @notice Mapping of bounty id to recipientAddress to bounty application | ||
mapping(uint256 => mapping(address => BountyApplication)) public bountyApplications; | ||
|
||
/// ================================ | ||
/// ========== Events ============== | ||
/// ================================ | ||
event BountyCreated(uint256 indexed bountyId, Bounty bounty); | ||
|
||
/// ================================ | ||
/// ========== Errors ============== | ||
/// ================================ | ||
|
||
error ProfileBounties_InvalidData(); | ||
error ProfileBounties_NotImplemented(); | ||
error ProfileBounties_AlreadyDistributed(); | ||
|
||
/// ============================== | ||
/// ========= Modifiers ========== | ||
/// ============================== | ||
|
||
/// =============================== | ||
/// ======= Internal Functions ==== | ||
/// =============================== | ||
|
||
function __BountyExtension_init() internal { | ||
// todo: no code? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes! in this case if you dont have to initialize anything you can leave it |
||
} | ||
|
||
function _getBountyIdFromExtraData(bytes memory _data) internal view virtual returns (uint256); | ||
|
||
function _processRecipient( | ||
address _recipientId, | ||
bool _isUsingRegistryAnchor, | ||
Metadata memory _metadata, | ||
bytes memory _extraData | ||
) internal { | ||
uint256 bountyId = _getBountyIdFromExtraData(_extraData); | ||
_revertInvalidBounty(bountyId); | ||
|
||
BountyApplication memory _bountyApplication = | ||
BountyApplication({bountyId: bountyId, recipientId: _recipientId, metadata: _metadata}); | ||
// add additional fields here | ||
|
||
bountyApplications[bountyId][_recipientId] = _bountyApplication; | ||
// should we emit an event here or can we rely on the Registered Event? | ||
} | ||
|
||
/// @inheritdoc BaseStrategy | ||
function _allocate(address[] memory, uint256[] memory, bytes memory, address) internal virtual override { | ||
revert ProfileBounties_NotImplemented(); | ||
} | ||
|
||
function _createBounty(address _token, Metadata memory _metadata, bytes _data) | ||
internal | ||
onlyPoolManager(msg.sender) | ||
{ | ||
Bounty memory _bounty = Bounty({token: _token, status: Status.Pending, metadata: _metadata, data: _data}); | ||
|
||
bountyIdCounter++; | ||
bounties[bountyIdCounter] = _bounty; | ||
|
||
emit BountyCreated(bountyIdCounter, _bounty); | ||
} | ||
|
||
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]); | ||
} | ||
|
||
// emit Distribute(_recipientIds, _data, _sender); | ||
} | ||
|
||
function _getBountyIdsFromDistributeData(bytes memory _data) internal view virtual returns (uint256[] memory) { | ||
uint256[] memory _bountyIds = abi.decode(_data, (uint256[])); | ||
return _bountyIds; | ||
} | ||
|
||
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 _getAmountFromBountyData(bytes memory _data) internal view virtual returns (uint256) { | ||
return abi.decode(_data, (uint256)); | ||
} | ||
|
||
function _transferDistribution(address _recipientId, uint256 _bountyId, bytes memory _data) internal virtual { | ||
// todo: _bounty.token.transfer(_recipientId, _getAmountFromBountyData(bounties[_bountyId].data)); | ||
} | ||
|
||
/// ==================================== | ||
/// ============ External ============== | ||
/// ==================================== | ||
|
||
function createBounties(address[] memory _tokens, bytes[] memory _data, Metadata[] memory _metadata) external { | ||
uint256 _tokensLength = _tokens.length; | ||
if (_tokensLength != _data.length || _tokensLength != _metadata.length) { | ||
revert ProfileBounties_InvalidData(); | ||
} | ||
|
||
for (uint256 i = 0; i < _tokensLength; i++) { | ||
_createBounty(_tokens[i], _data[i], _metadata[i]); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,16 +53,6 @@ abstract contract RecipientsExtension is BaseStrategy, IRecipientsExtension, Err | |
/// ========== Constructor ============= | ||
/// ==================================== | ||
|
||
/// @notice Constructor to set the Allo contract | ||
/// @param _allo Address of the Allo contract. | ||
/// @param _strategyName Name of the strategy. | ||
/// @param _reviewEachStatus true if custom review logic was added. | ||
constructor(address _allo, string memory _strategyName, bool _reviewEachStatus) | ||
BaseStrategy(_allo, _strategyName) | ||
{ | ||
REVIEW_EACH_STATUS = _reviewEachStatus; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
/// @notice Modifier to check if the registration is active | ||
/// @dev This will revert if the registration has not started or if the registration has ended. | ||
modifier onlyActiveRegistration() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dont forget to also initialize the
RecipientExtension