-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'v2.1' of github.com:allo-protocol/allo-v2 into feat/imp…
…rove-transfer-library
- Loading branch information
Showing
8 changed files
with
696 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
// SPDX-License-Identifier: AGPL-3.0-only | ||
pragma solidity 0.8.19; | ||
|
||
// External Libraries | ||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
|
||
// Interfaces | ||
import {IAllo} from "../core/interfaces/IAllo.sol"; | ||
// Core Contracts | ||
import {QVSimple} from "./QVSimple.sol"; | ||
|
||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀ | ||
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀ | ||
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀ | ||
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀ | ||
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀ | ||
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀ | ||
// allo.gitcoin.co | ||
contract QVImpactStream is QVSimple { | ||
/// ====================== | ||
/// ======= Events ======= | ||
/// ====================== | ||
|
||
/// @notice Emitted when the payouts are set | ||
/// @param payouts The payouts to distribute | ||
/// @param sender The sender of the transaction | ||
event PayoutSet(Payout[] payouts, address sender); | ||
|
||
/// ====================== | ||
/// ======= Errors ======= | ||
/// ====================== | ||
|
||
/// @notice Thrown when payout is already set | ||
error PAYOUT_ALREADY_SET(); | ||
|
||
/// @notice Thrown when the total set payout is more than the pool balance | ||
error PAYOUT_MORE_THAN_POOL_BALANCE(); | ||
|
||
/// ====================== | ||
/// ======= Storage ====== | ||
/// ====================== | ||
|
||
/// @notice Returns the amount to pay to the recipient | ||
/// @dev recipientId => payouts | ||
mapping(address => uint256) public payouts; | ||
|
||
/// @notice Returns true if the payout is set | ||
bool public payoutSet; | ||
|
||
/// ====================== | ||
/// ======= Struct ======= | ||
/// ====================== | ||
|
||
/// @notice The details of the payout set by the pool managers | ||
struct Payout { | ||
address recipientId; | ||
uint256 amount; | ||
} | ||
|
||
/// ==================================== | ||
/// ========== Constructor ============= | ||
/// ==================================== | ||
|
||
/// @notice Constructor for the QV Impact Stream strategy | ||
/// @param _allo The 'Allo' contract | ||
constructor(address _allo) QVSimple(_allo) {} | ||
|
||
/// ==================================== | ||
/// ==== External/Public Functions ===== | ||
/// ==================================== | ||
|
||
/// @notice Add allocator array | ||
/// @dev Only the pool manager(s) can call this function and emits an `AllocatorAdded` event | ||
/// @param _allocators The allocator address array | ||
function batchAddAllocator(address[] memory _allocators) external onlyPoolManager(msg.sender) { | ||
uint256 length = _allocators.length; | ||
for (uint256 i = 0; i < length;) { | ||
_addAllocator(_allocators[i]); | ||
|
||
unchecked { | ||
++i; | ||
} | ||
} | ||
} | ||
|
||
/// @notice Remove allocator array | ||
/// @dev Only the pool manager(s) can call this function and emits an `AllocatorRemoved` event | ||
/// @param _allocators The allocators address array | ||
function batchRemoveAllocator(address[] memory _allocators) external onlyPoolManager(msg.sender) { | ||
uint256 length = _allocators.length; | ||
for (uint256 i = 0; i < length;) { | ||
_removeAllocator(_allocators[i]); | ||
|
||
unchecked { | ||
++i; | ||
} | ||
} | ||
} | ||
|
||
/// @notice Set the payouts to distribute | ||
/// @dev Only the pool manager(s) can call this function | ||
/// @param _payouts The payouts to distribute | ||
function setPayouts(Payout[] memory _payouts) external onlyPoolManager(msg.sender) onlyAfterAllocation { | ||
if (payoutSet) revert PAYOUT_ALREADY_SET(); | ||
payoutSet = true; | ||
|
||
uint256 totalAmount; | ||
|
||
uint256 length = _payouts.length; | ||
for (uint256 i = 0; i < length;) { | ||
Payout memory payout = _payouts[i]; | ||
uint256 amount = payout.amount; | ||
address recipientId = payout.recipientId; | ||
|
||
if (amount == 0 || _getRecipientStatus(recipientId) != Status.Accepted) { | ||
revert RECIPIENT_ERROR(recipientId); | ||
} | ||
|
||
payouts[recipientId] = amount; | ||
totalAmount += amount; | ||
unchecked { | ||
++i; | ||
} | ||
} | ||
|
||
if (totalAmount > poolAmount) revert PAYOUT_MORE_THAN_POOL_BALANCE(); | ||
|
||
emit PayoutSet(_payouts, msg.sender); | ||
} | ||
|
||
/// ============================= | ||
/// ==== Internal Functions ===== | ||
/// ============================= | ||
|
||
function _distribute(address[] memory _recipientIds, bytes memory, address _sender) | ||
internal | ||
virtual | ||
override | ||
onlyAfterAllocation | ||
{ | ||
IAllo.Pool memory pool = allo.getPool(poolId); | ||
address poolToken = pool.token; | ||
|
||
uint256 length = _recipientIds.length; | ||
for (uint256 i = 0; i < length;) { | ||
address recipientId = _recipientIds[i]; | ||
Recipient storage recipient = _recipients[recipientId]; | ||
|
||
address recipientAddress = recipient.recipientAddress; | ||
uint256 amount = payouts[recipientId]; | ||
|
||
if (amount == 0) revert RECIPIENT_ERROR(recipientId); | ||
|
||
delete payouts[recipientId]; | ||
|
||
_transferAmount(poolToken, recipientAddress, amount); | ||
|
||
bytes memory data = abi.encode(recipientAddress, amount, _sender); | ||
|
||
emit Distributed(recipientId, data); | ||
|
||
unchecked { | ||
++i; | ||
} | ||
} | ||
} | ||
|
||
/// ========================= | ||
/// ==== View Functions ===== | ||
/// ========================= | ||
|
||
/// @notice Get the total votes received for a recipient | ||
/// @param _recipient The address of the recipient | ||
/// @return The total votes received by the recipient | ||
function getTotalVotesForRecipient(address _recipient) external view returns (uint256) { | ||
return _votingState.recipientVotes[_recipient]; | ||
} | ||
|
||
/// @notice Get the payout for a single recipient | ||
/// @param _recipientId The ID of the recipient | ||
/// @return The payout as a 'Payout' struct | ||
function getPayout(address _recipientId) external view returns (Payout memory) { | ||
uint256 amount = payouts[_recipientId]; | ||
return Payout(_recipientId, amount); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.