ETH Price: $2,782.05 (+5.39%)

Contract

0x79A5EEc2C87Cd2116195E71af7A38647f89C8Ffa
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
198602562024-05-13 9:39:47277 days ago1715593187  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
DirectGrantsLiteStrategy

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 400 runs

Other Settings:
default evmVersion
File 1 of 12 : DirectGrantsLite.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;

// External Libraries
import {Multicall} from "lib/openzeppelin-contracts/contracts/utils/Multicall.sol";
// Interfaces
import {IRegistry} from "../../core/interfaces/IRegistry.sol";
// Core Contracts
import {BaseStrategy} from "../BaseStrategy.sol";
// Internal Libraries
import {Metadata} from "../../core/libraries/Metadata.sol";
import {Native} from "../../core/libraries/Native.sol";

// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
//                    allo.gitcoin.co

/// @title Direct Grants Lite Strategy
/// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>
/// @notice Strategy for direct grants
contract DirectGrantsLiteStrategy is Native, BaseStrategy, Multicall {
    /// ================================
    /// ========== Struct ==============
    /// ================================

    /// @notice Struct to hold details of the application status
    /// @dev Application status is stored in a bitmap. Each 4 bits represents the status of a recipient,
    /// defined as 'index' here. The first 4 bits of the 256 bits represent the status of the first recipient,
    /// the second 4 bits represent the status of the second recipient, and so on.
    ///
    /// The 'rowIndex' is the index of the row in the bitmap, and the 'statusRow' is the value of the row.
    /// The 'statusRow' is updated when the status of a recipient changes.
    ///
    /// Note: Since we need 4 bits to store a status, one row of the bitmap can hold the status information of 256/4 recipients.
    ///
    /// For example, if we have 5 recipients, the bitmap will look like this:
    /// | recipient1 | recipient2 | recipient3 | recipient4 | recipient5 | 'rowIndex'
    /// |     0000   |    0001    |    0010    |    0011    |    0100    | 'statusRow'
    /// |     none   |   pending  |  accepted  |  rejected  |  appealed  | converted status (0, 1, 2, 3, 4)
    ///
    struct ApplicationStatus {
        uint256 index;
        uint256 statusRow;
    }

    /// @notice Stores the details of the recipients.
    struct Recipient {
        // If false, the recipientAddress is the anchor of the profile
        bool useRegistryAnchor;
        address recipientAddress;
        Metadata metadata;
    }

    /// @notice Stores the details of the allocation.
    struct Allocation {
        address token;
        address recipientId;
        uint256 amount;
    }

    /// @notice Stores the initialize data for the strategy
    struct InitializeData {
        bool useRegistryAnchor;
        bool metadataRequired;
        uint64 registrationStartTime;
        uint64 registrationEndTime;
    }

    /// ===============================
    /// ========== Events =============
    /// ===============================

    /// @notice Emitted when a recipient updates their registration
    /// @param recipientId Id of the recipient
    /// @param data The encoded data - (address recipientId, address recipientAddress, Metadata metadata)
    /// @param sender The sender of the transaction
    /// @param status The updated status of the recipient
    event UpdatedRegistration(address indexed recipientId, bytes data, address sender, uint8 status);

    /// @notice Emitted when a recipient is registered and the status is updated
    /// @param rowIndex The index of the row in the bitmap
    /// @param fullRow The value of the row
    /// @param sender The sender of the transaction
    event RecipientStatusUpdated(uint256 indexed rowIndex, uint256 fullRow, address sender);

    /// @notice Emitted when the timestamps are updated
    /// @param registrationStartTime The start time for the registration
    /// @param registrationEndTime The end time for the registration
    /// @param sender The sender of the transaction
    event TimestampsUpdated(uint64 registrationStartTime, uint64 registrationEndTime, address sender);

    /// ================================
    /// ========== Storage =============
    /// ================================

    /// @notice Flag to indicate whether to use the registry anchor or not.
    bool public useRegistryAnchor;

    /// @notice Flag to indicate whether metadata is required or not.
    bool public metadataRequired;

    /// @notice The timestamps in seconds for the start and end times.
    uint64 public registrationStartTime;
    uint64 public registrationEndTime;

    /// @notice The total number of recipients.
    uint256 public recipientsCounter;

    /// @notice The registry contract interface.
    IRegistry private _registry;

    /// @notice This is a packed array of booleans, 'statuses[0]' is the first row of the bitmap and allows to
    /// store 256 bits to describe the status of 256 projects. 'statuses[1]' is the second row, and so on
    /// Instead of using 1 bit for each recipient status, we will use 4 bits for each status
    /// to allow 7 statuses:
    /// 0: none
    /// 1: pending
    /// 2: accepted
    /// 3: rejected
    /// 4: appealed
    /// 5: in review
    /// 6: canceled
    /// Since it's a mapping the storage it's pre-allocated with zero values, so if we check the
    /// status of an existing recipient, the value is by default 0 (none).
    /// If we want to check the status of a recipient, we take its index from the `recipients` array
    /// and convert it to the 2-bits position in the bitmap.
    mapping(uint256 => uint256) public statusesBitMap;

    /// @notice 'recipientId' => 'statusIndex'
    /// @dev 'statusIndex' is the index of the recipient in the 'statusesBitMap' bitmap.
    mapping(address => uint256) public recipientToStatusIndexes;

    /// @notice 'recipientId' => 'Recipient' struct.
    mapping(address => Recipient) internal _recipients;

    /// ================================
    /// ========== Modifier ============
    /// ================================

    /// @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() {
        _checkOnlyActiveRegistration();
        _;
    }

    /// ===============================
    /// ======== Constructor ==========
    /// ===============================

    /// @notice Constructor for the Direct Grants Lite Strategy
    /// @param _allo The 'Allo' contract
    /// @param _name The name of the strategy
    constructor(address _allo, string memory _name) BaseStrategy(_allo, _name) {}

    /// ===============================
    /// ========= Initialize ==========
    /// ===============================

    /// @notice Initializes the strategy
    /// @dev This will revert if the strategy is already initialized and 'msg.sender' is not the 'Allo' contract.
    /// @param _poolId The 'poolId' to initialize
    /// @param _data The data to be decoded to initialize the strategy
    /// @custom:data InitializeData(bool _useRegistryAnchor, bool _metadataRequired, uint64 _registrationStartTime,
    ///               uint64 _registrationEndTime)
    function initialize(uint256 _poolId, bytes memory _data) external virtual override onlyAllo {
        InitializeData memory initializeData = abi.decode(_data, (InitializeData));
        __DirectGrantsLiteStrategy_init(_poolId, initializeData);
        emit Initialized(_poolId, _data);
    }

    /// @notice Initializes this strategy as well as the BaseStrategy.
    /// @dev This will revert if the strategy is already initialized. Emits a 'TimestampsUpdated()' event.
    /// @param _poolId The 'poolId' to initialize
    /// @param _initializeData The data to be decoded to initialize the strategy
    function __DirectGrantsLiteStrategy_init(uint256 _poolId, InitializeData memory _initializeData) internal {
        // Initialize the BaseStrategy with the '_poolId'
        __BaseStrategy_init(_poolId);

        // Initialize required values
        useRegistryAnchor = _initializeData.useRegistryAnchor;
        metadataRequired = _initializeData.metadataRequired;
        _registry = allo.getRegistry();

        // Set the updated timestamps
        registrationStartTime = _initializeData.registrationStartTime;
        registrationEndTime = _initializeData.registrationEndTime;

        recipientsCounter = 1;

        // If the timestamps are invalid this will revert - See details in '_isPoolTimestampValid'
        _isPoolTimestampValid(_initializeData.registrationStartTime, _initializeData.registrationEndTime);

        // Emit that the timestamps have been updated with the updated values
        emit TimestampsUpdated(_initializeData.registrationStartTime, _initializeData.registrationEndTime, msg.sender);
    }

    /// ===============================
    /// ============ Views ============
    /// ===============================

    /// @notice Get a recipient with a '_recipientId'
    /// @param _recipientId ID of the recipient
    /// @return recipient The recipient details
    function getRecipient(address _recipientId) external view returns (Recipient memory recipient) {
        return _getRecipient(_recipientId);
    }

    /// @notice Get recipient status
    /// @dev This will return the 'Status' of the recipient, the 'Status' is used at the strategy
    ///      level and is different from the 'Status' which is used at the protocol level
    /// @param _recipientId ID of the recipient
    /// @return Status of the recipient
    function _getRecipientStatus(address _recipientId) internal view override returns (Status) {
        return Status(_getUintRecipientStatus(_recipientId));
    }

    /// ===============================
    /// ======= External/Custom =======
    /// ===============================

    /// @notice Sets recipient statuses.
    /// @dev The statuses are stored in a bitmap of 4 bits for each recipient. The first 4 bits of the 256 bits represent
    ///      the status of the first recipient, the second 4 bits represent the status of the second recipient, and so on.
    ///      'msg.sender' must be a pool manager.
    /// Statuses:
    /// - 0: none
    /// - 1: pending
    /// - 2: accepted
    /// - 3: rejected
    /// - 4: appealed
    /// - 5: in review
    /// - 6: canceled
    /// Emits the RecipientStatusUpdated() event.
    /// @param statuses new statuses
    /// @param refRecipientsCounter the recipientCounter the transaction is based on
    function reviewRecipients(ApplicationStatus[] memory statuses, uint256 refRecipientsCounter)
        external
        onlyPoolManager(msg.sender)
    {
        if (refRecipientsCounter != recipientsCounter) revert INVALID();
        // Loop through the statuses and set the status
        uint256 length = statuses.length;
        for (uint256 i; i < length;) {
            uint256 rowIndex = statuses[i].index;
            uint256 fullRow = statuses[i].statusRow;

            statusesBitMap[rowIndex] = fullRow;

            // Emit that the recipient status has been updated with the values
            emit RecipientStatusUpdated(rowIndex, fullRow, msg.sender);

            unchecked {
                i++;
            }
        }
    }

    /// @notice Sets the start and end dates.
    /// @dev The timestamps are in seconds for the start and end times. The 'msg.sender' must be a pool manager.
    ///      Emits a 'TimestampsUpdated()' event.
    /// @param _registrationStartTime The start time for the registration
    /// @param _registrationEndTime The end time for the registration
    function updatePoolTimestamps(uint64 _registrationStartTime, uint64 _registrationEndTime)
        external
        onlyPoolManager(msg.sender)
    {
        // If the timestamps are invalid this will revert - See details in '_isPoolTimestampValid'
        _isPoolTimestampValid(_registrationStartTime, _registrationEndTime);

        // Set the updated timestamps
        registrationStartTime = _registrationStartTime;
        registrationEndTime = _registrationEndTime;

        // Emit that the timestamps have been updated with the updated values
        emit TimestampsUpdated(registrationStartTime, registrationEndTime, msg.sender);
    }

    /// @notice Withdraw funds from pool
    /// @param _token The token to be withdrawn
    function withdraw(address _token) external onlyPoolManager(msg.sender) {
        // get the actual balance hold by the pool
        uint256 amount = _getBalance(_token, address(this));

        // calculate the amount which is accessible
        uint256 accessibleAmount = amount;

        // transfer the amount to the pool manager
        _transferAmount(_token, msg.sender, accessibleAmount);
    }

    /// ====================================
    /// ============ Internal ==============
    /// ====================================

    /// @notice Checks if the registration is active and reverts if not.
    /// @dev This will revert if the registration has not started or if the registration has ended.
    function _checkOnlyActiveRegistration() internal view {
        if (registrationStartTime > block.timestamp || block.timestamp > registrationEndTime) {
            revert REGISTRATION_NOT_ACTIVE();
        }
    }

    /// @notice Checks if address is eligible allocator.
    /// @return True, if address is pool manager, otherwise false.
    function _isValidAllocator(address allocator) internal view override returns (bool) {
        return allo.isPoolManager(poolId, allocator);
    }

    /// @notice Checks if the timestamps are valid.
    /// @dev This will revert if any of the timestamps are invalid. This is determined by the strategy
    /// and may vary from strategy to strategy. Checks if '_registrationStartTime' is greater than the '_registrationEndTime'
    /// @param _registrationStartTime The start time for the registration
    /// @param _registrationEndTime The end time for the registration
    function _isPoolTimestampValid(uint64 _registrationStartTime, uint64 _registrationEndTime) internal pure {
        if (_registrationStartTime > _registrationEndTime) {
            revert INVALID();
        }
    }

    /// @notice Checks whether a pool is active or not.
    /// @dev This will return true if the current 'block timestamp' is greater than or equal to the
    /// 'registrationStartTime' and less than or equal to the 'registrationEndTime'.
    /// @return 'true' if pool is active, otherwise 'false'
    function _isPoolActive() internal view override returns (bool) {
        if (registrationStartTime <= block.timestamp && block.timestamp <= registrationEndTime) {
            return true;
        }
        return false;
    }

    /// @notice Submit recipient to pool and set their status.
    /// @param _data The data to be decoded.
    /// @custom:data if 'useRegistryAnchor' is 'true' (address recipientId, address recipientAddress, Metadata metadata)
    /// @custom:data if 'useRegistryAnchor' is 'false' (address registryAnchor, address recipientAddress, Metadata metadata)
    /// @param _sender The sender of the transaction
    /// @return recipientId The ID of the recipient
    function _registerRecipient(bytes memory _data, address _sender)
        internal
        override
        onlyActiveRegistration
        returns (address recipientId)
    {
        if (msg.value != 0) revert NON_ZERO_VALUE();

        bool isUsingRegistryAnchor;
        address recipientAddress;
        address registryAnchor;
        Metadata memory metadata;

        // decode data custom to this strategy
        if (useRegistryAnchor) {
            (recipientId, recipientAddress, metadata) = abi.decode(_data, (address, address, Metadata));

            // If the sender is not a profile member this will revert
            if (!_isProfileMember(recipientId, _sender)) {
                revert UNAUTHORIZED();
            }
        } else {
            (registryAnchor, recipientAddress, metadata) = abi.decode(_data, (address, address, Metadata));

            // Set this to 'true' if the registry anchor is not the zero address
            isUsingRegistryAnchor = registryAnchor != address(0);

            // If using the 'registryAnchor' we set the 'recipientId' to the 'registryAnchor', otherwise we set it to the 'msg.sender'
            recipientId = isUsingRegistryAnchor ? registryAnchor : _sender;

            // Checks if the '_sender' is a member of the profile 'anchor' being used and reverts if not
            if (isUsingRegistryAnchor && !_isProfileMember(recipientId, _sender)) {
                revert UNAUTHORIZED();
            }
        }

        // If the metadata is required and the metadata is invalid this will revert
        if (metadataRequired && (bytes(metadata.pointer).length == 0 || metadata.protocol == 0)) {
            revert INVALID_METADATA();
        }

        // If the recipient address is the zero address this will revert
        if (recipientAddress == address(0)) {
            revert RECIPIENT_ERROR(recipientId);
        }

        // Get the recipient
        Recipient storage recipient = _recipients[recipientId];

        // update the recipients data
        recipient.recipientAddress = recipientAddress;
        recipient.metadata = metadata;
        recipient.useRegistryAnchor = useRegistryAnchor ? true : isUsingRegistryAnchor;

        if (recipientToStatusIndexes[recipientId] == 0) {
            // recipient registering new application
            recipientToStatusIndexes[recipientId] = recipientsCounter;
            _setRecipientStatus(recipientId, uint8(Status.Pending));

            bytes memory extendedData = abi.encode(_data, recipientsCounter);
            emit Registered(recipientId, extendedData, _sender);

            recipientsCounter++;
        } else {
            uint8 currentStatus = _getUintRecipientStatus(recipientId);
            if (currentStatus == uint8(Status.Accepted) || currentStatus == uint8(Status.InReview)) {
                // recipient updating accepted application
                _setRecipientStatus(recipientId, uint8(Status.Pending));
            } else if (currentStatus == uint8(Status.Rejected)) {
                // recipient updating rejected application
                _setRecipientStatus(recipientId, uint8(Status.Appealed));
            }
            emit UpdatedRegistration(recipientId, _data, _sender, _getUintRecipientStatus(recipientId));
        }
    }

    /// @notice Distribute funds to recipients.
    /// @dev This function reverts by default
    function _distribute(address[] memory, bytes memory, address) internal virtual override {
        revert NOT_IMPLEMENTED();
    }

    /// @notice Allocate. Required by the 'BaseStrategy'.
    /// @param _data The data to be decoded
    /// @custom:data '(Allocation[] allocations)'
    /// @param _sender The sender of the transaction
    function _allocate(bytes memory _data, address _sender) internal virtual override onlyPoolManager(_sender) {
        uint256 nativeAmount = msg.value;

        // Decode the allocation data
        (Allocation[] memory allocations) = abi.decode(_data, (Allocation[]));

        uint256 length = allocations.length;

        if (length == 0) revert INVALID(); // nothing to allocate

        for (uint256 i = 0; i < length;) {
            Allocation memory allocation = allocations[i];
            address recipientId = allocation.recipientId;
            Recipient memory recipient = _getRecipient(recipientId);
            address recipientAddress = recipient.recipientAddress;

            address token = allocations[i].token;
            uint256 amount = allocations[i].amount;

            // This will revert if the sender tries to spend more than the msg.value
            if (token == NATIVE) nativeAmount -= amount;

            if (recipient.recipientAddress == address(0)) {
                revert RECIPIENT_ERROR(recipientId);
            }

            if (_getUintRecipientStatus(recipientId) != uint8(Status.Accepted)) {
                revert RECIPIENT_NOT_ACCEPTED();
            }

            _transferAmountFrom(token, TransferData({from: _sender, to: recipientAddress, amount: amount}));

            emit Allocated(recipientId, amount, token, _sender);

            unchecked {
                ++i;
            }
        }

        if (nativeAmount > 0) _transferAmount(NATIVE, _sender, nativeAmount);
    }

    /// @notice Check if sender is profile owner or member.
    /// @param _anchor Anchor of the profile
    /// @param _sender The sender of the transaction
    /// @return 'true' if the '_sender' is a profile member, otherwise 'false'
    function _isProfileMember(address _anchor, address _sender) internal view virtual returns (bool) {
        IRegistry.Profile memory profile = _registry.getProfileByAnchor(_anchor);
        return _registry.isOwnerOrMemberOfProfile(profile.id, _sender);
    }

    /// @notice Get the recipient details.
    /// @param _recipientId Id of the recipient
    /// @return Recipient details
    function _getRecipient(address _recipientId) internal view returns (Recipient memory) {
        return _recipients[_recipientId];
    }

    /// @notice Returns the payout summary for the accepted recipient.
    /// @dev This will revert by default.
    function _getPayout(address, bytes memory) internal pure override returns (PayoutSummary memory) {
        revert NOT_IMPLEMENTED();
    }

    /// @notice Set the recipient status.
    /// @param _recipientId ID of the recipient
    /// @param _status Status of the recipient
    function _setRecipientStatus(address _recipientId, uint256 _status) internal {
        // Get the row index, column index and current row
        (uint256 rowIndex, uint256 colIndex, uint256 currentRow) = _getStatusRowColumn(_recipientId);

        // Calculate the 'newRow'
        uint256 newRow = currentRow & ~(15 << colIndex);

        // Add the status to the mapping
        statusesBitMap[rowIndex] = newRow | (_status << colIndex);
    }

    /// @notice Get recipient status
    /// @param _recipientId ID of the recipient
    /// @return status The status of the recipient
    function _getUintRecipientStatus(address _recipientId) internal view returns (uint8 status) {
        if (recipientToStatusIndexes[_recipientId] == 0) return 0;
        // Get the column index and current row
        (, uint256 colIndex, uint256 currentRow) = _getStatusRowColumn(_recipientId);

        // Get the status from the 'currentRow' shifting by the 'colIndex'
        status = uint8((currentRow >> colIndex) & 15);

        // Return the status
        return status;
    }

    /// @notice Get recipient status 'rowIndex', 'colIndex' and 'currentRow'.
    /// @param _recipientId ID of the recipient
    /// @return (rowIndex, colIndex, currentRow)
    function _getStatusRowColumn(address _recipientId) internal view returns (uint256, uint256, uint256) {
        uint256 recipientIndex = recipientToStatusIndexes[_recipientId] - 1;

        uint256 rowIndex = recipientIndex / 64; // 256 / 4
        uint256 colIndex = (recipientIndex % 64) * 4;

        return (rowIndex, colIndex, statusesBitMap[rowIndex]);
    }

    /// @notice Contract should be able to receive NATIVE
    receive() external payable {
        _checkOnlyAllo();
    }
}

File 2 of 12 : IAllo.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;

// Interfaces
import {IRegistry} from "./IRegistry.sol";
import {IStrategy} from "./IStrategy.sol";
// Internal Libraries
import {Metadata} from "../libraries/Metadata.sol";

// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
//                    allo.gitcoin.co

/// @title Allo Interface
/// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]>
/// @notice Interface for the Allo contract. It exposes all functions needed to use the Allo protocol.
interface IAllo {
    /// ======================
    /// ======= Structs ======
    /// ======================

    /// @notice the Pool struct that all strategy pools are based from
    struct Pool {
        bytes32 profileId;
        IStrategy strategy;
        address token;
        Metadata metadata;
        bytes32 managerRole;
        bytes32 adminRole;
    }

    /// ======================
    /// ======= Events =======
    /// ======================

    /// @notice Event emitted when a new pool is created
    /// @param poolId ID of the pool created
    /// @param profileId ID of the profile the pool is associated with
    /// @param strategy Address of the strategy contract
    /// @param token Address of the token pool was funded with when created
    /// @param amount Amount pool was funded with when created
    /// @param metadata Pool metadata
    event PoolCreated(
        uint256 indexed poolId,
        bytes32 indexed profileId,
        IStrategy strategy,
        address token,
        uint256 amount,
        Metadata metadata
    );

    /// @notice Emitted when a pools metadata is updated
    /// @param poolId ID of the pool updated
    /// @param metadata Pool metadata that was updated
    event PoolMetadataUpdated(uint256 indexed poolId, Metadata metadata);

    /// @notice Emitted when a pool is funded
    /// @param poolId ID of the pool funded
    /// @param amount Amount funded to the pool
    /// @param fee Amount of the fee paid to the treasury
    event PoolFunded(uint256 indexed poolId, uint256 amount, uint256 fee);

    /// @notice Emitted when the base fee is paid
    /// @param poolId ID of the pool the base fee was paid for
    /// @param amount Amount of the base fee paid
    event BaseFeePaid(uint256 indexed poolId, uint256 amount);

    /// @notice Emitted when the treasury address is updated
    /// @param treasury Address of the new treasury
    event TreasuryUpdated(address treasury);

    /// @notice Emitted when the percent fee is updated
    /// @param percentFee New percentage for the fee
    event PercentFeeUpdated(uint256 percentFee);

    /// @notice Emitted when the base fee is updated
    /// @param baseFee New base fee amount
    event BaseFeeUpdated(uint256 baseFee);

    /// @notice Emitted when the registry address is updated
    /// @param registry Address of the new registry
    event RegistryUpdated(address registry);

    /// @notice Emitted when a strategy is approved and added to the cloneable strategies
    /// @param strategy Address of the strategy approved
    event StrategyApproved(address strategy);

    /// @notice Emitted when a strategy is removed from the cloneable strategies
    /// @param strategy Address of the strategy removed
    event StrategyRemoved(address strategy);

    /// ====================================
    /// ==== External/Public Functions =====
    /// ====================================

    /// @notice Initialize the Allo contract
    /// @param _owner Address of the owner
    /// @param _registry Address of the registry contract
    /// @param _treasury Address of the treasury
    /// @param _percentFee Percentage for the fee
    /// @param _baseFee Base fee amount
    function initialize(
        address _owner,
        address _registry,
        address payable _treasury,
        uint256 _percentFee,
        uint256 _baseFee
    ) external;

    /// @notice Creates a new pool (with a custom strategy)
    /// @dev 'msg.sender' must be a member or owner of a profile to create a pool with or without a custom strategy, The encoded data
    ///      will be specific to a given strategy requirements, reference the strategy implementation of 'initialize()'. The strategy
    ///      address passed must not be a cloneable strategy. The strategy address passed must not be the zero address. 'msg.sender' must
    ///      be a member or owner of the profile id passed as '_profileId'.
    /// @param _profileId The 'profileId' of the registry profile, used to check if 'msg.sender' is a member or owner of the profile
    /// @param _strategy The address of the deployed custom strategy
    /// @param _initStrategyData The data to initialize the strategy
    /// @param _token The address of the token you want to use in your pool
    /// @param _amount The amount of the token you want to deposit into the pool on initialization
    /// @param _metadata The 'Metadata' of the pool, this uses our 'Meatdata.sol' struct (consistent throughout the protocol)
    /// @param _managers The managers of the pool, and can be added/removed later by the pool admin
    /// @return poolId The ID of the pool
    function createPoolWithCustomStrategy(
        bytes32 _profileId,
        address _strategy,
        bytes memory _initStrategyData,
        address _token,
        uint256 _amount,
        Metadata memory _metadata,
        address[] memory _managers
    ) external payable returns (uint256 poolId);

    /// @notice Creates a new pool (by cloning a cloneable strategies).
    /// @dev 'msg.sender' must be owner or member of the profile id passed as '_profileId'.
    /// @param _profileId The ID of the registry profile, used to check if 'msg.sender' is a member or owner of the profile
    /// @param _strategy The address of the strategy contract the pool will use.
    /// @param _initStrategyData The data to initialize the strategy
    /// @param _token The address of the token
    /// @param _amount The amount of the token
    /// @param _metadata The metadata of the pool
    /// @param _managers The managers of the pool
    /// @custom:initstrategydata The encoded data will be specific to a given strategy requirements,
    ///    reference the strategy implementation of 'initialize()'
    function createPool(
        bytes32 _profileId,
        address _strategy,
        bytes memory _initStrategyData,
        address _token,
        uint256 _amount,
        Metadata memory _metadata,
        address[] memory _managers
    ) external payable returns (uint256 poolId);

    /// @notice Updates a pools metadata.
    /// @dev 'msg.sender' must be a pool admin.
    /// @param _poolId The ID of the pool to update
    /// @param _metadata The new metadata to set
    function updatePoolMetadata(uint256 _poolId, Metadata memory _metadata) external;

    /// @notice Update the registry address.
    /// @dev 'msg.sender' must be the Allo contract owner.
    /// @param _registry The new registry address
    function updateRegistry(address _registry) external;

    /// @notice Updates the treasury address.
    /// @dev 'msg.sender' must be the Allo contract owner.
    /// @param _treasury The new treasury address
    function updateTreasury(address payable _treasury) external;

    /// @notice Updates the percentage for the fee.
    /// @dev 'msg.sender' must be the Allo contract owner.
    /// @param _percentFee The new percentage for the fee
    function updatePercentFee(uint256 _percentFee) external;

    /// @notice Updates the base fee.
    /// @dev 'msg.sender' must be the Allo contract owner.
    /// @param _baseFee The new base fee
    function updateBaseFee(uint256 _baseFee) external;

    /// @notice Adds a strategy to the cloneable strategies.
    /// @dev 'msg.sender' must be the Allo contract owner.
    /// @param _strategy The address of the strategy to add
    function addToCloneableStrategies(address _strategy) external;

    /// @notice Removes a strategy from the cloneable strategies.
    /// @dev 'msg.sender' must be the Allo contract owner.
    /// @param _strategy The address of the strategy to remove
    function removeFromCloneableStrategies(address _strategy) external;

    /// @notice Adds a pool manager to the pool.
    /// @dev 'msg.sender' must be a pool admin.
    /// @param _poolId The ID of the pool to add the manager to
    /// @param _manager The address of the manager to add
    function addPoolManager(uint256 _poolId, address _manager) external;

    /// @notice Removes a pool manager from the pool.
    /// @dev 'msg.sender' must be a pool admin.
    /// @param _poolId The ID of the pool to remove the manager from
    /// @param _manager The address of the manager to remove
    function removePoolManager(uint256 _poolId, address _manager) external;

    /// @notice Recovers funds from a pool.
    /// @dev 'msg.sender' must be a pool admin.
    /// @param _token The token to recover
    /// @param _recipient The address to send the recovered funds to
    function recoverFunds(address _token, address _recipient) external;

    /// @notice Registers a recipient and emits {Registered} event if successful and may be handled differently by each strategy.
    /// @param _poolId The ID of the pool to register the recipient for
    function registerRecipient(uint256 _poolId, bytes memory _data) external payable returns (address);

    /// @notice Registers a batch of recipients.
    /// @param _poolIds The pool ID's to register the recipients for
    /// @param _data The data to pass to the strategy and may be handled differently by each strategy
    function batchRegisterRecipient(uint256[] memory _poolIds, bytes[] memory _data)
        external
        returns (address[] memory);

    /// @notice Funds a pool.
    /// @dev 'msg.value' must be greater than 0 if the token is the native token
    ///       or '_amount' must be greater than 0 if the token is not the native token.
    /// @param _poolId The ID of the pool to fund
    /// @param _amount The amount to fund the pool with
    function fundPool(uint256 _poolId, uint256 _amount) external payable;

    /// @notice Allocates funds to a recipient.
    /// @dev Each strategy will handle the allocation of funds differently.
    /// @param _poolId The ID of the pool to allocate funds from
    /// @param _data The data to pass to the strategy and may be handled differently by each strategy.
    function allocate(uint256 _poolId, bytes memory _data) external payable;

    /// @notice Allocates funds to multiple recipients.
    /// @dev Each strategy will handle the allocation of funds differently
    function batchAllocate(uint256[] calldata _poolIds, bytes[] memory _datas) external;

    /// @notice Distributes funds to recipients and emits {Distributed} event if successful
    /// @dev Each strategy will handle the distribution of funds differently
    /// @param _poolId The ID of the pool to distribute from
    /// @param _recipientIds The recipient ids to distribute to
    /// @param _data The data to pass to the strategy and may be handled differently by each strategy
    function distribute(uint256 _poolId, address[] memory _recipientIds, bytes memory _data) external;

    /// =========================
    /// ==== View Functions =====
    /// =========================

    /// @notice Checks if an address is a pool admin.
    /// @param _poolId The ID of the pool to check
    /// @param _address The address to check
    /// @return 'true' if the '_address' is a pool admin, otherwise 'false'
    function isPoolAdmin(uint256 _poolId, address _address) external view returns (bool);

    /// @notice Checks if an address is a pool manager.
    /// @param _poolId The ID of the pool to check
    /// @param _address The address to check
    /// @return 'true' if the '_address' is a pool manager, otherwise 'false'
    function isPoolManager(uint256 _poolId, address _address) external view returns (bool);

    /// @notice Checks if a strategy is cloneable (is in the cloneableStrategies mapping).
    /// @param _strategy The address of the strategy to check
    /// @return 'true' if the '_strategy' is cloneable, otherwise 'false'
    function isCloneableStrategy(address _strategy) external view returns (bool);

    /// @notice Returns the address of the strategy for a given 'poolId'
    /// @param _poolId The ID of the pool to check
    /// @return strategy The address of the strategy for the ID of the pool passed in
    function getStrategy(uint256 _poolId) external view returns (address);

    /// @notice Returns the current percent fee
    /// @return percentFee The current percentage for the fee
    function getPercentFee() external view returns (uint256);

    /// @notice Returns the current base fee
    /// @return baseFee The current base fee
    function getBaseFee() external view returns (uint256);

    /// @notice Returns the current treasury address
    /// @return treasury The current treasury address
    function getTreasury() external view returns (address payable);

    /// @notice Returns the current registry address
    /// @return registry The current registry address
    function getRegistry() external view returns (IRegistry);

    /// @notice Returns the 'Pool' struct for a given 'poolId'
    /// @param _poolId The ID of the pool to check
    /// @return pool The 'Pool' struct for the ID of the pool passed in
    function getPool(uint256 _poolId) external view returns (Pool memory);

    /// @notice Returns the current fee denominator
    /// @dev 1e18 represents 100%
    /// @return feeDenominator The current fee denominator
    function getFeeDenominator() external view returns (uint256);
}

File 3 of 12 : IRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

// Internal Libraries
import {Metadata} from "../libraries/Metadata.sol";

// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
//                    allo.gitcoin.co

/// @title IRegistry Interface
/// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]>
/// @notice Interface for the Registry contract and exposes all functions needed to use the Registry
///         within the Allo protocol.
/// @dev The Registry Interface is used to interact with the Allo protocol and create profiles
///      that can be used to interact with the Allo protocol. The Registry is the main contract
///      that all other contracts interact with to get the 'Profile' information needed to
///      interact with the Allo protocol. The Registry is also used to create new profiles
///      and update existing profiles. The Registry is also used to add and remove members
///      from a profile. The Registry will not always be used in a strategy and will depend on
///      the strategy being used.
interface IRegistry {
    /// ======================
    /// ======= Structs ======
    /// ======================

    /// @dev The Profile struct that all profiles are based from
    struct Profile {
        bytes32 id;
        uint256 nonce;
        string name;
        Metadata metadata;
        address owner;
        address anchor;
    }

    /// ======================
    /// ======= Events =======
    /// ======================

    /// @dev Emitted when a profile is created. This will return your anchor address.
    event ProfileCreated(
        bytes32 indexed profileId, uint256 nonce, string name, Metadata metadata, address owner, address anchor
    );

    /// @dev Emitted when a profile name is updated. This will update the anchor when the name is updated and return it.
    event ProfileNameUpdated(bytes32 indexed profileId, string name, address anchor);

    /// @dev Emitted when a profile's metadata is updated.
    event ProfileMetadataUpdated(bytes32 indexed profileId, Metadata metadata);

    /// @dev Emitted when a profile owner is updated.
    event ProfileOwnerUpdated(bytes32 indexed profileId, address owner);

    /// @dev Emitted when a profile pending owner is updated.
    event ProfilePendingOwnerUpdated(bytes32 indexed profileId, address pendingOwner);

    /// =========================
    /// ==== View Functions =====
    /// =========================

    /// @dev Returns the 'Profile' for a '_profileId' passed
    /// @param _profileId The 'profileId' to return the 'Profile' for
    /// @return profile The 'Profile' for the '_profileId' passed
    function getProfileById(bytes32 _profileId) external view returns (Profile memory profile);

    /// @dev Returns the 'Profile' for an '_anchor' passed
    /// @param _anchor The 'anchor' to return the 'Profile' for
    /// @return profile The 'Profile' for the '_anchor' passed
    function getProfileByAnchor(address _anchor) external view returns (Profile memory profile);

    /// @dev Returns a boolean if the '_account' is a member or owner of the '_profileId' passed in
    /// @param _profileId The 'profileId' to check if the '_account' is a member or owner of
    /// @param _account The 'account' to check if they are a member or owner of the '_profileId' passed in
    /// @return isOwnerOrMemberOfProfile A boolean if the '_account' is a member or owner of the '_profileId' passed in
    function isOwnerOrMemberOfProfile(bytes32 _profileId, address _account)
        external
        view
        returns (bool isOwnerOrMemberOfProfile);

    /// @dev Returns a boolean if the '_account' is an owner of the '_profileId' passed in
    /// @param _profileId The 'profileId' to check if the '_account' is an owner of
    /// @param _owner The 'owner' to check if they are an owner of the '_profileId' passed in
    /// @return isOwnerOfProfile A boolean if the '_account' is an owner of the '_profileId' passed in
    function isOwnerOfProfile(bytes32 _profileId, address _owner) external view returns (bool isOwnerOfProfile);

    /// @dev Returns a boolean if the '_account' is a member of the '_profileId' passed in
    /// @param _profileId The 'profileId' to check if the '_account' is a member of
    /// @param _member The 'member' to check if they are a member of the '_profileId' passed in
    /// @return isMemberOfProfile A boolean if the '_account' is a member of the '_profileId' passed in
    function isMemberOfProfile(bytes32 _profileId, address _member) external view returns (bool isMemberOfProfile);

    /// ====================================
    /// ==== External/Public Functions =====
    /// ====================================

    /// @dev Creates a new 'Profile' and returns the 'profileId' of the new profile
    ///
    /// Note: The 'name' and 'nonce' are used to generate the 'anchor' address
    ///
    /// Requirements: None, anyone can create a new profile
    ///
    /// @param _nonce The nonce to use to generate the 'anchor' address
    /// @param _name The name to use to generate the 'anchor' address
    /// @param _metadata The 'Metadata' to use to generate the 'anchor' address
    /// @param _owner The 'owner' to use to generate the 'anchor' address
    /// @param _members The 'members' to use to generate the 'anchor' address
    /// @return profileId The 'profileId' of the new profile
    function createProfile(
        uint256 _nonce,
        string memory _name,
        Metadata memory _metadata,
        address _owner,
        address[] memory _members
    ) external returns (bytes32 profileId);

    /// @dev Updates the 'name' of the '_profileId' passed in and returns the new 'anchor' address
    ///
    /// Requirements: Only the 'Profile' owner can update the name
    ///
    /// Note: The 'name' and 'nonce' are used to generate the 'anchor' address and this will update the 'anchor'
    ///       so please use caution. You can always recreate your 'anchor' address by updating the name back
    ///       to the original name used to create the profile.
    ///
    /// @param _profileId The 'profileId' to update the name for
    /// @param _name The new 'name' value
    /// @return anchor The new 'anchor' address
    function updateProfileName(bytes32 _profileId, string memory _name) external returns (address anchor);

    /// @dev Updates the 'Metadata' of the '_profileId' passed in
    ///
    /// Requirements: Only the 'Profile' owner can update the metadata
    ///
    /// @param _profileId The 'profileId' to update the metadata for
    /// @param _metadata The new 'Metadata' value
    function updateProfileMetadata(bytes32 _profileId, Metadata memory _metadata) external;

    /// @dev Updates the pending 'owner' of the '_profileId' passed in
    ///
    /// Requirements: Only the 'Profile' owner can update the pending owner
    ///
    /// @param _profileId The 'profileId' to update the pending owner for
    /// @param _pendingOwner The new pending 'owner' value
    function updateProfilePendingOwner(bytes32 _profileId, address _pendingOwner) external;

    /// @dev Accepts the pending 'owner' of the '_profileId' passed in
    ///
    /// Requirements: Only the pending owner can accept the ownership
    ///
    /// @param _profileId The 'profileId' to accept the ownership for
    function acceptProfileOwnership(bytes32 _profileId) external;

    /// @dev Adds members to the '_profileId' passed in
    ///
    /// Requirements: Only the 'Profile' owner can add members
    ///
    /// @param _profileId The 'profileId' to add members to
    /// @param _members The members to add to the '_profileId' passed in
    function addMembers(bytes32 _profileId, address[] memory _members) external;

    /// @dev Removes members from the '_profileId' passed in
    ///
    /// Requirements: Only the 'Profile' owner can remove members
    ///
    /// @param _profileId The 'profileId' to remove members from
    /// @param _members The members to remove from the '_profileId' passed in
    function removeMembers(bytes32 _profileId, address[] memory _members) external;

    /// @dev Recovers funds from the contract
    ///
    /// Requirements: Must be the Allo owner
    ///
    /// @param _token The token you want to use to recover funds
    /// @param _recipient The recipient of the recovered funds
    function recoverFunds(address _token, address _recipient) external;
}

File 4 of 12 : IStrategy.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;

// Interfaces
import {IAllo} from "./IAllo.sol";

// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
//                    allo.gitcoin.co

/// @title IStrategy Interface
/// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]> @0xZakk <[email protected]>, @nfrgosselin <[email protected]>
/// @notice BaseStrategy is the base contract that all strategies should inherit from and uses this interface.

interface IStrategy {
    /// ======================
    /// ======= Storage ======
    /// ======================

    /// @notice The Status enum that all recipients are based from
    enum Status {
        None,
        Pending,
        Accepted,
        Rejected,
        Appealed,
        InReview,
        Canceled
    }

    /// @notice Payout summary struct to hold the payout data
    struct PayoutSummary {
        address recipientAddress;
        uint256 amount;
    }

    /// ======================
    /// ======= Events =======
    /// ======================

    /// @notice Emitted when strategy is initialized.
    /// @param poolId The ID of the pool
    /// @param data The data passed to the 'initialize' function
    event Initialized(uint256 poolId, bytes data);

    /// @notice Emitted when a recipient is registered.
    /// @param recipientId The ID of the recipient
    /// @param data The data passed to the 'registerRecipient' function
    /// @param sender The sender
    event Registered(address indexed recipientId, bytes data, address sender);

    /// @notice Emitted when a recipient is allocated to.
    /// @param recipientId The ID of the recipient
    /// @param amount The amount allocated
    /// @param token The token allocated
    event Allocated(address indexed recipientId, uint256 amount, address token, address sender);

    /// @notice Emitted when tokens are distributed.
    /// @param recipientId The ID of the recipient
    /// @param recipientAddress The recipient
    /// @param amount The amount distributed
    /// @param sender The sender
    event Distributed(address indexed recipientId, address recipientAddress, uint256 amount, address sender);

    /// @notice Emitted when pool is set to active status.
    /// @param active The status of the pool
    event PoolActive(bool active);

    /// ======================
    /// ======= Views ========
    /// ======================

    /// @notice Getter for the address of the Allo contract.
    /// @return The 'Allo' contract
    function getAllo() external view returns (IAllo);

    /// @notice Getter for the 'poolId' for this strategy.
    /// @return The ID of the pool
    function getPoolId() external view returns (uint256);

    /// @notice Getter for the 'id' of the strategy.
    /// @return The ID of the strategy
    function getStrategyId() external view returns (bytes32);

    /// @notice Checks whether a allocator is valid or not, will usually be true for all strategies
    ///      and will depend on the strategy implementation.
    /// @param _allocator The allocator to check
    /// @return Whether the allocator is valid or not
    function isValidAllocator(address _allocator) external view returns (bool);

    /// @notice whether pool is active.
    /// @return Whether the pool is active or not
    function isPoolActive() external returns (bool);

    /// @notice Checks the amount of tokens in the pool.
    /// @return The balance of the pool
    function getPoolAmount() external view returns (uint256);

    /// @notice Increases the balance of the pool.
    /// @param _amount The amount to increase the pool by
    function increasePoolAmount(uint256 _amount) external;

    /// @notice Checks the status of a recipient probably tracked in a mapping, but will depend on the implementation
    ///      for example, the OpenSelfRegistration only maps users to bool, and then assumes Accepted for those
    ///      since there is no need for Pending or Rejected.
    /// @param _recipientId The ID of the recipient
    /// @return The status of the recipient
    function getRecipientStatus(address _recipientId) external view returns (Status);

    /// @notice Checks the amount allocated to a recipient for distribution.
    /// @dev Input the values you would send to distribute(), get the amounts each recipient in the array would receive.
    ///      The encoded '_data' will be determined by the strategy, and will be used to determine the payout.
    /// @param _recipientIds The IDs of the recipients
    /// @param _data The encoded data
    function getPayouts(address[] memory _recipientIds, bytes[] memory _data)
        external
        view
        returns (PayoutSummary[] memory);

    /// ======================
    /// ===== Functions ======
    /// ======================

    /// @notice
    /// @dev The default BaseStrategy version will not use the data  if a strategy wants to use it, they will overwrite it,
    ///      use it, and then call super.initialize().
    /// @param _poolId The ID of the pool
    /// @param _data The encoded data
    function initialize(uint256 _poolId, bytes memory _data) external;

    /// @notice This will register a recipient, set their status (and any other strategy specific values), and
    ///         return the ID of the recipient.
    /// @dev Able to change status all the way up to 'Accepted', or to 'Pending' and if there are more steps, additional
    ///      functions should be added to allow the owner to check this. The owner could also check attestations directly
    ///      and then accept for instance. The '_data' will be determined by the strategy implementation.
    /// @param _data The data to use to register the recipient
    /// @param _sender The address of the sender
    /// @return The ID of the recipient
    function registerRecipient(bytes memory _data, address _sender) external payable returns (address);

    /// @notice This will allocate to a recipient.
    /// @dev The encoded '_data' will be determined by the strategy implementation.
    /// @param _data The data to use to allocate to the recipient
    /// @param _sender The address of the sender
    function allocate(bytes memory _data, address _sender) external payable;

    /// @notice This will distribute funds (tokens) to recipients.
    /// @dev most strategies will track a TOTAL amount per recipient, and a PAID amount, and pay the difference
    /// this contract will need to track the amount paid already, so that it doesn't double pay.
    function distribute(address[] memory _recipientIds, bytes memory _data, address _sender) external;
}

File 5 of 12 : Errors.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;

// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
//                    allo.gitcoin.co

/// @title Errors
/// @author @thelostone-mc <[email protected]>, @KurtMerbeth <[email protected]>, @codenamejason <[email protected]>
/// @notice Library containing all custom errors the protocol may revert with.
contract Errors {
    /// ======================
    /// ====== Generic =======
    /// ======================

    /// @notice Thrown as a general error when input / data is invalid
    error INVALID();

    /// @notice Thrown when mismatch in decoding data
    error MISMATCH();

    /// @notice Thrown when not enough funds are available
    error NOT_ENOUGH_FUNDS();

    /// @notice Thrown when user is not authorized
    error UNAUTHORIZED();

    /// @notice Thrown when address is the zero address
    error ZERO_ADDRESS();

    /// @notice Thrown when the function is not implemented
    error NOT_IMPLEMENTED();

    /// @notice Thrown when the value is non-zero
    error NON_ZERO_VALUE();

    /// ======================
    /// ====== Registry ======
    /// ======================

    /// @dev Thrown when the nonce passed has been used or not available
    error NONCE_NOT_AVAILABLE();

    /// @dev Thrown when the 'msg.sender' is not the pending owner on ownership transfer
    error NOT_PENDING_OWNER();

    /// @dev Thrown if the anchor creation fails
    error ANCHOR_ERROR();

    /// ======================
    /// ======== Allo ========
    /// ======================

    /// @notice Thrown when the strategy is not approved
    error NOT_APPROVED_STRATEGY();

    /// @notice Thrown when the strategy is approved and should be cloned
    error IS_APPROVED_STRATEGY();

    /// @notice Thrown when the fee is below 1e18 which is the fee percentage denominator
    error INVALID_FEE();

    /// ======================
    /// ===== IStrategy ======
    /// ======================

    /// @notice Thrown when data is already intialized
    error ALREADY_INITIALIZED();

    /// @notice Thrown when data is yet to be initialized
    error NOT_INITIALIZED();

    /// @notice Thrown when an invalid address is used
    error INVALID_ADDRESS();

    /// @notice Thrown when a pool is inactive
    error POOL_INACTIVE();

    /// @notice Thrown when a pool is already active
    error POOL_ACTIVE();

    /// @notice Thrown when two arrays length are not equal
    error ARRAY_MISMATCH();

    /// @notice Thrown when the registration is invalid.
    error INVALID_REGISTRATION();

    /// @notice Thrown when the metadata is invalid.
    error INVALID_METADATA();

    /// @notice Thrown when the recipient is not accepted.
    error RECIPIENT_NOT_ACCEPTED();

    /// @notice Thrown when recipient is already accepted.
    error RECIPIENT_ALREADY_ACCEPTED();

    /// @notice Thrown when registration is not active.
    error REGISTRATION_NOT_ACTIVE();

    /// @notice Thrown when registration is active.
    error REGISTRATION_ACTIVE();

    /// @notice Thrown when there is an error in recipient.
    error RECIPIENT_ERROR(address recipientId);

    /// @notice Thrown when the allocation is not active.
    error ALLOCATION_NOT_ACTIVE();

    /// @notice Thrown when the allocation is not ended.
    error ALLOCATION_NOT_ENDED();

    /// @notice Thrown when the allocation is active.
    error ALLOCATION_ACTIVE();
}

File 6 of 12 : Metadata.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;

// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
//                    allo.gitcoin.co

/// @title Metadata
/// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]>
/// @notice Metadata is used to define the metadata for the protocol that is used throughout the system.
struct Metadata {
    /// @notice Protocol ID corresponding to a specific protocol (currently using IPFS = 1)
    uint256 protocol;
    /// @notice Pointer (hash) to fetch metadata for the specified protocol
    string pointer;
}

File 7 of 12 : Native.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;

// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
//                    allo.gitcoin.co

/// @title Native token information
/// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]>
/// @notice This is used to define the address of the native token for the protocol
contract Native {
    /// @notice Address of the native token
    address public constant NATIVE = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
}

File 8 of 12 : Transfer.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;

// External Libraries
import {SafeTransferLib} from "lib/solady/src/utils/SafeTransferLib.sol";
// Internal Libraries
import "./Native.sol";

// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
//                    allo.gitcoin.co

/// @title Transfer contract
/// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]>
/// @notice A helper contract to transfer tokens within Allo protocol
/// @dev Handles the transfer of tokens to an address
contract Transfer is Native {
    /// @notice Thrown when the amount of tokens sent does not match the amount of tokens expected
    error AMOUNT_MISMATCH();

    /// @notice This holds the details for a transfer
    struct TransferData {
        address from;
        address to;
        uint256 amount;
    }

    /// @notice Transfer an amount of a token to an array of addresses
    /// @param _token The address of the token
    /// @param _transferData TransferData[]
    /// @return Whether the transfer was successful or not
    function _transferAmountsFrom(address _token, TransferData[] memory _transferData)
        internal
        virtual
        returns (bool)
    {
        uint256 msgValue = msg.value;

        for (uint256 i; i < _transferData.length;) {
            TransferData memory transferData = _transferData[i];

            if (_token == NATIVE) {
                msgValue -= transferData.amount;
                SafeTransferLib.safeTransferETH(transferData.to, transferData.amount);
            } else {
                SafeTransferLib.safeTransferFrom(_token, transferData.from, transferData.to, transferData.amount);
            }

            unchecked {
                i++;
            }
        }

        if (msgValue != 0) revert AMOUNT_MISMATCH();

        return true;
    }

    /// @notice Transfer an amount of a token to an address
    /// @param _token The address of the token
    /// @param _transferData Individual TransferData
    /// @return Whether the transfer was successful or not
    function _transferAmountFrom(address _token, TransferData memory _transferData) internal virtual returns (bool) {
        uint256 amount = _transferData.amount;
        if (_token == NATIVE) {
            // Native Token
            if (msg.value < amount) revert AMOUNT_MISMATCH();

            SafeTransferLib.safeTransferETH(_transferData.to, amount);
        } else {
            SafeTransferLib.safeTransferFrom(_token, _transferData.from, _transferData.to, amount);
        }
        return true;
    }

    /// @notice Transfer an amount of a token to an address
    /// @param _token The token to transfer
    /// @param _to The address to transfer to
    /// @param _amount The amount to transfer
    function _transferAmount(address _token, address _to, uint256 _amount) internal virtual {
        if (_token == NATIVE) {
            SafeTransferLib.safeTransferETH(_to, _amount);
        } else {
            SafeTransferLib.safeTransfer(_token, _to, _amount);
        }
    }

    /// @notice Get the balance of a token for an account
    /// @param _token The token to get the balance of
    /// @param _account The account to get the balance for
    /// @return The balance of the token for the account
    function _getBalance(address _token, address _account) internal view returns (uint256) {
        if (_token == NATIVE) {
            return payable(_account).balance;
        } else {
            return SafeTransferLib.balanceOf(_token, _account);
        }
    }
}

File 9 of 12 : BaseStrategy.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;

// Interfaces
import "../core/interfaces/IStrategy.sol";

// Libraries
import {Transfer} from "../core/libraries/Transfer.sol";
import {Errors} from "../core/libraries/Errors.sol";

// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
//                    allo.gitcoin.co

/// @title BaseStrategy Contract
/// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]>
/// @notice This contract is the base contract for all strategies
/// @dev This contract is implemented by all strategies.
abstract contract BaseStrategy is IStrategy, Transfer, Errors {
    /// ==========================
    /// === Storage Variables ====
    /// ==========================

    IAllo internal immutable allo;
    bytes32 internal immutable strategyId;
    bool internal poolActive;
    uint256 internal poolId;
    uint256 internal poolAmount;

    /// ====================================
    /// ========== Constructor =============
    /// ====================================

    /// @notice Constructor to set the Allo contract and "strategyId'.
    /// @param _allo Address of the Allo contract.
    /// @param _name Name of the strategy
    constructor(address _allo, string memory _name) {
        allo = IAllo(_allo);
        strategyId = keccak256(abi.encode(_name));
    }

    /// ====================================
    /// =========== Modifiers ==============
    /// ====================================

    /// @notice Modifier to check if the 'msg.sender' is the Allo contract.
    /// @dev Reverts if the 'msg.sender' is not the Allo contract.
    modifier onlyAllo() {
        _checkOnlyAllo();
        _;
    }

    /// @notice Modifier to check if the '_sender' is a pool manager.
    /// @dev Reverts if the '_sender' is not a pool manager.
    /// @param _sender The address to check if they are a pool manager
    modifier onlyPoolManager(address _sender) {
        _checkOnlyPoolManager(_sender);
        _;
    }

    /// @notice Modifier to check if the pool is active.
    /// @dev Reverts if the pool is not active.
    modifier onlyActivePool() {
        _checkOnlyActivePool();
        _;
    }

    /// @notice Modifier to check if the pool is inactive.
    /// @dev Reverts if the pool is active.
    modifier onlyInactivePool() {
        _checkInactivePool();
        _;
    }

    /// @notice Modifier to check if the pool is initialized.
    /// @dev Reverts if the pool is not initialized.
    modifier onlyInitialized() {
        _checkOnlyInitialized();
        _;
    }

    /// ================================
    /// =========== Views ==============
    /// ================================

    /// @notice Getter for the 'Allo' contract.
    /// @return The Allo contract
    function getAllo() external view override returns (IAllo) {
        return allo;
    }

    /// @notice Getter for the 'poolId'.
    /// @return The ID of the pool
    function getPoolId() external view override returns (uint256) {
        return poolId;
    }

    /// @notice Getter for the 'strategyId'.
    /// @return The ID of the strategy
    function getStrategyId() external view override returns (bytes32) {
        return strategyId;
    }

    /// @notice Getter for the 'poolAmount'.
    /// @return The balance of the pool
    function getPoolAmount() external view virtual override returns (uint256) {
        return poolAmount;
    }

    /// @notice Getter for whether or not the pool is active.
    /// @return 'true' if the pool is active, otherwise 'false'
    function isPoolActive() external view override returns (bool) {
        return _isPoolActive();
    }

    /// @notice Getter for the status of a recipient.
    /// @param _recipientId The ID of the recipient
    /// @return The status of the recipient
    function getRecipientStatus(address _recipientId) external view virtual returns (Status) {
        return _getRecipientStatus(_recipientId);
    }

    /// ====================================
    /// =========== Functions ==============
    /// ====================================

    /// @notice Initializes the 'Basetrategy'.
    /// @dev Will revert if the poolId is invalid or already initialized
    /// @param _poolId ID of the pool
    function __BaseStrategy_init(uint256 _poolId) internal virtual onlyAllo {
        // check if pool ID is not initialized already, if it is, revert
        if (poolId != 0) revert ALREADY_INITIALIZED();

        // check if pool ID is valid and not zero (0), if it is, revert
        if (_poolId == 0) revert INVALID();
        poolId = _poolId;
    }

    /// @notice Increases the pool amount.
    /// @dev Increases the 'poolAmount' by '_amount'. Only 'Allo' contract can call this.
    /// @param _amount The amount to increase the pool by
    function increasePoolAmount(uint256 _amount) external override onlyAllo {
        _beforeIncreasePoolAmount(_amount);
        poolAmount += _amount;
        _afterIncreasePoolAmount(_amount);
    }

    /// @notice Registers a recipient.
    /// @dev Registers a recipient and returns the ID of the recipient. The encoded '_data' will be determined by the
    ///      strategy implementation. Only 'Allo' contract can call this when it is initialized.
    /// @param _data The data to use to register the recipient
    /// @param _sender The address of the sender
    /// @return recipientId The recipientId
    function registerRecipient(bytes memory _data, address _sender)
        external
        payable
        onlyAllo
        onlyInitialized
        returns (address recipientId)
    {
        _beforeRegisterRecipient(_data, _sender);
        recipientId = _registerRecipient(_data, _sender);
        _afterRegisterRecipient(_data, _sender);
    }

    /// @notice Allocates to a recipient.
    /// @dev The encoded '_data' will be determined by the strategy implementation. Only 'Allo' contract can
    ///      call this when it is initialized.
    /// @param _data The data to use to allocate to the recipient
    /// @param _sender The address of the sender
    function allocate(bytes memory _data, address _sender) external payable onlyAllo onlyInitialized {
        _beforeAllocate(_data, _sender);
        _allocate(_data, _sender);
        _afterAllocate(_data, _sender);
    }

    /// @notice Distributes funds (tokens) to recipients.
    /// @dev The encoded '_data' will be determined by the strategy implementation. Only 'Allo' contract can
    ///      call this when it is initialized.
    /// @param _recipientIds The IDs of the recipients
    /// @param _data The data to use to distribute to the recipients
    /// @param _sender The address of the sender
    function distribute(address[] memory _recipientIds, bytes memory _data, address _sender)
        external
        onlyAllo
        onlyInitialized
    {
        _beforeDistribute(_recipientIds, _data, _sender);
        _distribute(_recipientIds, _data, _sender);
        _afterDistribute(_recipientIds, _data, _sender);
    }

    /// @notice Gets the payout summary for recipients.
    /// @dev The encoded '_data' will be determined by the strategy implementation.
    /// @param _recipientIds The IDs of the recipients
    /// @param _data The data to use to get the payout summary for the recipients
    /// @return The payout summary for the recipients
    function getPayouts(address[] memory _recipientIds, bytes[] memory _data)
        external
        view
        virtual
        override
        returns (PayoutSummary[] memory)
    {
        uint256 recipientLength = _recipientIds.length;
        // check if the length of the recipient IDs and data arrays are equal, if they are not, revert
        if (recipientLength != _data.length) revert ARRAY_MISMATCH();

        PayoutSummary[] memory payouts = new PayoutSummary[](recipientLength);
        for (uint256 i; i < recipientLength;) {
            payouts[i] = _getPayout(_recipientIds[i], _data[i]);
            unchecked {
                i++;
            }
        }
        return payouts;
    }

    /// @notice Checks if the '_allocator' is a valid allocator.
    /// @dev How the allocator is determined is up to the strategy implementation.
    /// @param _allocator The address to check if it is a valid allocator for the strategy.
    /// @return 'true' if the address is a valid allocator, 'false' otherwise
    function isValidAllocator(address _allocator) external view virtual override returns (bool) {
        return _isValidAllocator(_allocator);
    }

    /// ====================================
    /// ============ Internal ==============
    /// ====================================

    /// @notice Checks if the 'msg.sender' is the Allo contract.
    /// @dev Reverts if the 'msg.sender' is not the Allo contract.
    function _checkOnlyAllo() internal view {
        if (msg.sender != address(allo)) revert UNAUTHORIZED();
    }

    /// @notice Checks if the '_sender' is a pool manager.
    /// @dev Reverts if the '_sender' is not a pool manager.
    /// @param _sender The address to check if they are a pool manager
    function _checkOnlyPoolManager(address _sender) internal view {
        if (!allo.isPoolManager(poolId, _sender)) revert UNAUTHORIZED();
    }

    /// @notice Checks if the pool is active.
    /// @dev Reverts if the pool is not active.
    function _checkOnlyActivePool() internal view {
        if (!poolActive) revert POOL_INACTIVE();
    }

    /// @notice Checks if the pool is inactive.
    /// @dev Reverts if the pool is active.
    function _checkInactivePool() internal view {
        if (poolActive) revert POOL_ACTIVE();
    }

    /// @notice Checks if the pool is initialized.
    /// @dev Reverts if the pool is not initialized.
    function _checkOnlyInitialized() internal view {
        if (poolId == 0) revert NOT_INITIALIZED();
    }

    /// @notice Set the pool to active or inactive status.
    /// @dev This will emit a 'PoolActive()' event. Used by the strategy implementation.
    /// @param _active The status to set, 'true' means active, 'false' means inactive
    function _setPoolActive(bool _active) internal {
        poolActive = _active;
        emit PoolActive(_active);
    }

    /// @notice Checks if the pool is active.
    /// @dev Used by the strategy implementation.
    /// @return 'true' if the pool is active, otherwise 'false'
    function _isPoolActive() internal view virtual returns (bool) {
        return poolActive;
    }

    /// @notice Checks if the allocator is valid
    /// @param _allocator The allocator address
    /// @return 'true' if the allocator is valid, otherwise 'false'
    function _isValidAllocator(address _allocator) internal view virtual returns (bool);

    /// @notice This will register a recipient, set their status (and any other strategy specific values), and
    ///         return the ID of the recipient.
    /// @dev Able to change status all the way up to Accepted, or to Pending and if there are more steps, additional
    ///      functions should be added to allow the owner to check this. The owner could also check attestations directly
    ///      and then Accept for instance.
    /// @param _data The data to use to register the recipient
    /// @param _sender The address of the sender
    /// @return The ID of the recipient
    function _registerRecipient(bytes memory _data, address _sender) internal virtual returns (address);

    /// @notice This will allocate to a recipient.
    /// @dev The encoded '_data' will be determined by the strategy implementation.
    /// @param _data The data to use to allocate to the recipient
    /// @param _sender The address of the sender
    function _allocate(bytes memory _data, address _sender) internal virtual;

    /// @notice This will distribute funds (tokens) to recipients.
    /// @dev most strategies will track a TOTAL amount per recipient, and a PAID amount, and pay the difference
    /// this contract will need to track the amount paid already, so that it doesn't double pay.
    /// @param _recipientIds The ids of the recipients to distribute to
    /// @param _data Data required will depend on the strategy implementation
    /// @param _sender The address of the sender
    function _distribute(address[] memory _recipientIds, bytes memory _data, address _sender) internal virtual;

    /// @notice This will get the payout summary for a recipient.
    /// @dev The encoded '_data' will be determined by the strategy implementation.
    /// @param _recipientId The ID of the recipient
    /// @param _data The data to use to get the payout summary for the recipient
    /// @return The payout summary for the recipient
    function _getPayout(address _recipientId, bytes memory _data)
        internal
        view
        virtual
        returns (PayoutSummary memory);

    /// @notice This will get the status of a recipient.
    /// @param _recipientId The ID of the recipient
    /// @return The status of the recipient
    function _getRecipientStatus(address _recipientId) internal view virtual returns (Status);

    /// ===================================
    /// ============== Hooks ==============
    /// ===================================

    /// @notice Hook called before increasing the pool amount.
    /// @param _amount The amount to increase the pool by
    function _beforeIncreasePoolAmount(uint256 _amount) internal virtual {}

    /// @notice Hook called after increasing the pool amount.
    /// @param _amount The amount to increase the pool by
    function _afterIncreasePoolAmount(uint256 _amount) internal virtual {}

    /// @notice Hook called before registering a recipient.
    /// @param _data The data to use to register the recipient
    /// @param _sender The address of the sender
    function _beforeRegisterRecipient(bytes memory _data, address _sender) internal virtual {}

    /// @notice Hook called after registering a recipient.
    /// @param _data The data to use to register the recipient
    /// @param _sender The address of the sender
    function _afterRegisterRecipient(bytes memory _data, address _sender) internal virtual {}

    /// @notice Hook called before allocating to a recipient.
    /// @param _data The data to use to allocate to the recipient
    /// @param _sender The address of the sender
    function _beforeAllocate(bytes memory _data, address _sender) internal virtual {}

    /// @notice Hook called after allocating to a recipient.
    /// @param _data The data to use to allocate to the recipient
    /// @param _sender The address of the sender
    function _afterAllocate(bytes memory _data, address _sender) internal virtual {}

    /// @notice Hook called before distributing funds (tokens) to recipients.
    /// @param _recipientIds The IDs of the recipients
    /// @param _data The data to use to distribute to the recipients
    /// @param _sender The address of the sender
    function _beforeDistribute(address[] memory _recipientIds, bytes memory _data, address _sender) internal virtual {}

    /// @notice Hook called after distributing funds (tokens) to recipients.
    /// @param _recipientIds The IDs of the recipients
    /// @param _data The data to use to distribute to the recipients
    /// @param _sender The address of the sender
    function _afterDistribute(address[] memory _recipientIds, bytes memory _data, address _sender) internal virtual {}
}

File 10 of 12 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 11 of 12 : Multicall.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Multicall.sol)

pragma solidity ^0.8.0;

import "./Address.sol";

/**
 * @dev Provides a function to batch together multiple calls in a single external call.
 *
 * _Available since v4.1._
 */
abstract contract Multicall {
    /**
     * @dev Receives and executes a batch of function calls on this contract.
     * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
     */
    function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            results[i] = Address.functionDelegateCall(address(this), data[i]);
        }
        return results;
    }
}

File 12 of 12 : SafeTransferLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for gas griefing protection.
/// - For ERC20s, this implementation won't check that a token has code,
/// responsibility is delegated to the caller.
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH
    /// that disallows any storage writes.
    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    /// Multiply by a small constant (e.g. 2), if needed.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` (in wei) ETH to `to`.
    /// Reverts upon failure.
    ///
    /// Note: This implementation does NOT protect against gas griefing.
    /// Please use `forceSafeTransferETH` for gas griefing protection.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, amount, 0x00, 0x00, 0x00, 0x00)) {
                // Store the function selector of `ETHTransferFailed()`.
                mstore(0x00, 0xb12d13eb)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    /// The `gasStipend` can be set to a low enough value to prevent
    /// storage writes or gas griefing.
    ///
    /// If sending via the normal procedure fails, force sends the ETH by
    /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH.
    ///
    /// Reverts if the current contract has insufficient balance.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // If insufficient balance, revert.
            if lt(selfbalance(), amount) {
                // Store the function selector of `ETHTransferFailed()`.
                mstore(0x00, 0xb12d13eb)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Transfer the ETH and check if it succeeded or not.
            if iszero(call(gasStipend, to, amount, 0x00, 0x00, 0x00, 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                // We can directly use `SELFDESTRUCT` in the contract creation.
                // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758
                if iszero(create(amount, 0x0b, 0x16)) {
                    // To coerce gas estimation to provide enough gas for the `create` above.
                    if iszero(gt(gas(), 1000000)) { revert(0x00, 0x00) }
                }
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a gas stipend
    /// equal to `GAS_STIPEND_NO_GRIEF`. This gas stipend is a reasonable default
    /// for 99% of cases and can be overridden with the three-argument version of this
    /// function if necessary.
    ///
    /// If sending via the normal procedure fails, force sends the ETH by
    /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH.
    ///
    /// Reverts if the current contract has insufficient balance.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        // Manually inlined because the compiler doesn't inline functions with branches.
        /// @solidity memory-safe-assembly
        assembly {
            // If insufficient balance, revert.
            if lt(selfbalance(), amount) {
                // Store the function selector of `ETHTransferFailed()`.
                mstore(0x00, 0xb12d13eb)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Transfer the ETH and check if it succeeded or not.
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, 0x00, 0x00, 0x00, 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                // We can directly use `SELFDESTRUCT` in the contract creation.
                // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758
                if iszero(create(amount, 0x0b, 0x16)) {
                    // To coerce gas estimation to provide enough gas for the `create` above.
                    if iszero(gt(gas(), 1000000)) { revert(0x00, 0x00) }
                }
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    /// The `gasStipend` can be set to a low enough value to prevent
    /// storage writes or gas griefing.
    ///
    /// Simply use `gasleft()` for `gasStipend` if you don't need a gas stipend.
    ///
    /// Note: Does NOT revert upon failure.
    /// Returns whether the transfer of ETH is successful instead.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and check if it succeeded or not.
            success := call(gasStipend, to, amount, 0x00, 0x00, 0x00, 0x00)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.

            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            // Store the function selector of `transferFrom(address,address,uint256)`.
            mstore(0x0c, 0x23b872dd000000000000000000000000)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `TransferFromFailed()`.
                mstore(0x00, 0x7939f424)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have their entire balance approved for
    /// the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.

            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            // Store the function selector of `balanceOf(address)`.
            mstore(0x0c, 0x70a08231000000000000000000000000)
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                // Store the function selector of `TransferFromFailed()`.
                mstore(0x00, 0x7939f424)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Store the function selector of `transferFrom(address,address,uint256)`.
            mstore(0x00, 0x23b872dd)
            // The `amount` is already at 0x60. Load it for the function's return value.
            amount := mload(0x60)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `TransferFromFailed()`.
                mstore(0x00, 0x7939f424)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            // Store the function selector of `transfer(address,uint256)`.
            mstore(0x00, 0xa9059cbb000000000000000000000000)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `TransferFailed()`.
                mstore(0x00, 0x90b8ec18)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Restore the part of the free memory pointer that was overwritten.
            mstore(0x34, 0)
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                // Store the function selector of `TransferFailed()`.
                mstore(0x00, 0x90b8ec18)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            mstore(0x14, to) // Store the `to` argument.
            // The `amount` is already at 0x34. Load it for the function's return value.
            amount := mload(0x34)
            // Store the function selector of `transfer(address,uint256)`.
            mstore(0x00, 0xa9059cbb000000000000000000000000)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `TransferFailed()`.
                mstore(0x00, 0x90b8ec18)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Restore the part of the free memory pointer that was overwritten.
            mstore(0x34, 0)
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            // Store the function selector of `approve(address,uint256)`.
            mstore(0x00, 0x095ea7b3000000000000000000000000)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `ApproveFailed()`.
                mstore(0x00, 0x3e3f8f73)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Restore the part of the free memory pointer that was overwritten.
            mstore(0x34, 0)
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
    /// then retries the approval again (some tokens, e.g. USDT, requires this).
    /// Reverts upon failure.
    function safeApproveWithRetry(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            // Store the function selector of `approve(address,uint256)`.
            mstore(0x00, 0x095ea7b3000000000000000000000000)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x34, 0) // Store 0 for the `amount`.
                mstore(0x00, 0x095ea7b3000000000000000000000000) // Store the function selector.
                // We can ignore the result of this call. Just need to check the next call.
                pop(call(gas(), token, 0, 0x10, 0x44, 0x00, 0x00))
                mstore(0x34, amount) // Store back the original `amount`.

                if iszero(
                    and(
                        or(eq(mload(0x00), 1), iszero(returndatasize())),
                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    )
                ) {
                    // Store the function selector of `ApproveFailed()`.
                    mstore(0x00, 0x3e3f8f73)
                    // Revert with (offset, size).
                    revert(0x1c, 0x04)
                }
            }
            // Restore the part of the free memory pointer that was overwritten.
            mstore(0x34, 0)
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            // Store the function selector of `balanceOf(address)`.
            mstore(0x00, 0x70a08231000000000000000000000000)
            amount :=
                mul(
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 400
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_allo","type":"address"},{"internalType":"string","name":"_name","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ALLOCATION_ACTIVE","type":"error"},{"inputs":[],"name":"ALLOCATION_NOT_ACTIVE","type":"error"},{"inputs":[],"name":"ALLOCATION_NOT_ENDED","type":"error"},{"inputs":[],"name":"ALREADY_INITIALIZED","type":"error"},{"inputs":[],"name":"AMOUNT_MISMATCH","type":"error"},{"inputs":[],"name":"ANCHOR_ERROR","type":"error"},{"inputs":[],"name":"ARRAY_MISMATCH","type":"error"},{"inputs":[],"name":"INVALID","type":"error"},{"inputs":[],"name":"INVALID_ADDRESS","type":"error"},{"inputs":[],"name":"INVALID_FEE","type":"error"},{"inputs":[],"name":"INVALID_METADATA","type":"error"},{"inputs":[],"name":"INVALID_REGISTRATION","type":"error"},{"inputs":[],"name":"IS_APPROVED_STRATEGY","type":"error"},{"inputs":[],"name":"MISMATCH","type":"error"},{"inputs":[],"name":"NONCE_NOT_AVAILABLE","type":"error"},{"inputs":[],"name":"NON_ZERO_VALUE","type":"error"},{"inputs":[],"name":"NOT_APPROVED_STRATEGY","type":"error"},{"inputs":[],"name":"NOT_ENOUGH_FUNDS","type":"error"},{"inputs":[],"name":"NOT_IMPLEMENTED","type":"error"},{"inputs":[],"name":"NOT_INITIALIZED","type":"error"},{"inputs":[],"name":"NOT_PENDING_OWNER","type":"error"},{"inputs":[],"name":"POOL_ACTIVE","type":"error"},{"inputs":[],"name":"POOL_INACTIVE","type":"error"},{"inputs":[],"name":"RECIPIENT_ALREADY_ACCEPTED","type":"error"},{"inputs":[{"internalType":"address","name":"recipientId","type":"address"}],"name":"RECIPIENT_ERROR","type":"error"},{"inputs":[],"name":"RECIPIENT_NOT_ACCEPTED","type":"error"},{"inputs":[],"name":"REGISTRATION_ACTIVE","type":"error"},{"inputs":[],"name":"REGISTRATION_NOT_ACTIVE","type":"error"},{"inputs":[],"name":"UNAUTHORIZED","type":"error"},{"inputs":[],"name":"ZERO_ADDRESS","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipientId","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"Allocated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipientId","type":"address"},{"indexed":false,"internalType":"address","name":"recipientAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"Distributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"PoolActive","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fullRow","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"RecipientStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipientId","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"Registered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"registrationStartTime","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"registrationEndTime","type":"uint64"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"TimestampsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipientId","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint8","name":"status","type":"uint8"}],"name":"UpdatedRegistration","type":"event"},{"inputs":[],"name":"NATIVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"address","name":"_sender","type":"address"}],"name":"allocate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_recipientIds","type":"address[]"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"address","name":"_sender","type":"address"}],"name":"distribute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllo","outputs":[{"internalType":"contract IAllo","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_recipientIds","type":"address[]"},{"internalType":"bytes[]","name":"_data","type":"bytes[]"}],"name":"getPayouts","outputs":[{"components":[{"internalType":"address","name":"recipientAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IStrategy.PayoutSummary[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPoolAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPoolId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipientId","type":"address"}],"name":"getRecipient","outputs":[{"components":[{"internalType":"bool","name":"useRegistryAnchor","type":"bool"},{"internalType":"address","name":"recipientAddress","type":"address"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"internalType":"struct Metadata","name":"metadata","type":"tuple"}],"internalType":"struct DirectGrantsLiteStrategy.Recipient","name":"recipient","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipientId","type":"address"}],"name":"getRecipientStatus","outputs":[{"internalType":"enum IStrategy.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStrategyId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"increasePoolAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isPoolActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_allocator","type":"address"}],"name":"isValidAllocator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataRequired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"recipientToStatusIndexes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"recipientsCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"address","name":"_sender","type":"address"}],"name":"registerRecipient","outputs":[{"internalType":"address","name":"recipientId","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"registrationEndTime","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registrationStartTime","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"statusRow","type":"uint256"}],"internalType":"struct DirectGrantsLiteStrategy.ApplicationStatus[]","name":"statuses","type":"tuple[]"},{"internalType":"uint256","name":"refRecipientsCounter","type":"uint256"}],"name":"reviewRecipients","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"statusesBitMap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"_registrationStartTime","type":"uint64"},{"internalType":"uint64","name":"_registrationEndTime","type":"uint64"}],"name":"updatePoolTimestamps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"useRegistryAnchor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c06040523480156200001157600080fd5b5060405162002b2e38038062002b2e8339810160408190526200003491620000ba565b6001600160a01b038216608052604051829082906200005890829060200162000195565b60408051601f19818403018152919052805160209091012060a05250620001ca92505050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620000b157818101518382015260200162000097565b50506000910152565b60008060408385031215620000ce57600080fd5b82516001600160a01b0381168114620000e657600080fd5b60208401519092506001600160401b03808211156200010457600080fd5b818501915085601f8301126200011957600080fd5b8151818111156200012e576200012e6200007e565b604051601f8201601f19908116603f011681019083821181831017156200015957620001596200007e565b816040528281528860208487010111156200017357600080fd5b6200018683602083016020880162000094565b80955050505050509250929050565b6020815260008251806020840152620001b681604085016020870162000094565b601f01601f19169190910160400192915050565b60805160a0516129226200020c60003960006102970152600081816102280152818161059001528181610e7201528181610f24015261124701526129226000f3fe6080604052600436106101a55760003560e01c80639af5c09d116100e1578063dff7d2c71161008a578063ef2920fc11610064578063ef2920fc14610505578063f31db3d114610518578063f5b0dfb714610538578063f6f258911461055857600080fd5b8063dff7d2c714610491578063eb11af93146104b8578063edd146cc146104e557600080fd5b8063b2b878d0116100bb578063b2b878d014610430578063cb0e85a61461045d578063df868ed31461047c57600080fd5b80639af5c09d1461039d578063a0cf0aea146103db578063ac9650d81461040357600080fd5b80634ab4ba421161014e5780635708973911610128578063570897391461032057806362812a391461033a57806375777aaa1461036757806395355b3b1461038757600080fd5b80634ab4ba42146102bb5780634d31d087146102d057806351cff8d91461030057600080fd5b80632bbe0cae1161017f5780632bbe0cae1461026057806338fff2d01461027357806342fda9c71461028857600080fd5b806301fc1c64146101b95780630a6f0ee9146101f957806315cc481e1461021957600080fd5b366101b4576101b2610585565b005b600080fd5b3480156101c557600080fd5b506101e66101d4366004611b61565b60076020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561020557600080fd5b506101b2610214366004611d46565b6105d0565b34801561022557600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016101f0565b61024861026e366004611dbd565b6105f0565b34801561027f57600080fd5b506001546101e6565b34801561029457600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006101e6565b3480156102c757600080fd5b506002546101e6565b3480156102dc57600080fd5b506102f06102eb366004611b61565b610615565b60405190151581526020016101f0565b34801561030c57600080fd5b506101b261031b366004611b61565b610620565b34801561032c57600080fd5b506003546102f09060ff1681565b34801561034657600080fd5b5061035a610355366004611b61565b61064a565b6040516101f09190611e5e565b34801561037357600080fd5b506101b2610382366004611ec2565b61065b565b34801561039357600080fd5b506101e660045481565b3480156103a957600080fd5b506003546103c3906201000090046001600160401b031681565b6040516001600160401b0390911681526020016101f0565b3480156103e757600080fd5b5061024873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b34801561040f57600080fd5b5061042361041e366004611ef0565b61070d565b6040516101f09190611f64565b34801561043c57600080fd5b5061045061044b366004611fc6565b610801565b6040516101f0919061209a565b34801561046957600080fd5b506003546102f090610100900460ff1681565b34801561048857600080fd5b506102f06108ff565b34801561049d57600080fd5b506003546103c390600160501b90046001600160401b031681565b3480156104c457600080fd5b506104d86104d3366004611b61565b61090e565b6040516101f09190612108565b3480156104f157600080fd5b506101b2610500366004612130565b610919565b6101b2610513366004611dbd565b610974565b34801561052457600080fd5b506101b2610533366004612176565b610992565b34801561054457600080fd5b506101b2610553366004612230565b610a70565b34801561056457600080fd5b506101e6610573366004612230565b60066020526000908152604090205481565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146105ce5760405163075fd2b160e01b815260040160405180910390fd5b565b6105d8610585565b6105e0610a9a565b6105eb838383610abd565b505050565b60006105fa610585565b610602610a9a565b61060c8383610ad6565b90505b92915050565b600061060f82610e55565b3361062a81610efa565b60006106368330610fac565b905080610644843383610ff5565b50505050565b610652611b06565b61060f8261102f565b3361066581610efa565b61066f8383611128565b6003805471ffffffffffffffffffffffffffffffff00001916620100006001600160401b03868116820267ffffffffffffffff60501b191692909217600160501b8684168102919091179384905560408051928504841683529304909116602082015233918101919091527f70d34c8836b996cffd8970ba5edf940d83ca7c8f30f738ea4fd8566a37d93359906060015b60405180910390a1505050565b6060816001600160401b0381111561072757610727611b85565b60405190808252806020026020018201604052801561075a57816020015b60608152602001906001900390816107455790505b50905060005b828110156107fa576107ca3085858481811061077e5761077e612249565b9050602002810190610790919061225f565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061115b92505050565b8282815181106107dc576107dc612249565b602002602001018190525080806107f2906122c2565b915050610760565b5092915050565b8151815160609190811461082857604051633da4c02b60e11b815260040160405180910390fd5b6000816001600160401b0381111561084257610842611b85565b60405190808252806020026020018201604052801561088757816020015b60408051808201909152600080825260208201528152602001906001900390816108605790505b50905060005b828110156108f6576108d18682815181106108aa576108aa612249565b60200260200101518683815181106108c4576108c4612249565b6020026020010151611180565b8282815181106108e3576108e3612249565b602090810291909101015260010161088d565b50949350505050565b6000610909611199565b905090565b600061060f826111e1565b610921610585565b60008180602001905181019061093791906122f0565b90506109438382611200565b7f91efa3d50feccde0d0d202f8ae5c41ca0b2be614cebcb2bd2f4b019396e6568a8383604051610700929190612370565b61097c610585565b610984610a9a565b61098e82826113a9565b5050565b3361099c81610efa565b60045482146109be57604051637fcce2a960e01b815260040160405180910390fd5b825160005b81811015610a695760008582815181106109df576109df612249565b60200260200101516000015190506000868381518110610a0157610a01612249565b6020908102919091018101518101516000848152600683526040908190208290558051828152339381019390935290925083917f941884a9a55191a7401466aaf8a0d2b7c8b082055a5a2b345b83c73940172ac4910160405180910390a250506001016109c3565b5050505050565b610a78610585565b8060026000828254610a8a9190612389565b90915550610a9790508181565b50565b6001546000036105ce57604051630f68fe6360e21b815260040160405180910390fd5b6040516343f6e4ab60e01b815260040160405180910390fd5b6000610ae06115f2565b3415610aff576040516322d8ddab60e01b815260040160405180910390fd5b6000806000610b21604051806040016040528060008152602001606081525090565b60035460ff1615610b735786806020019051810190610b409190612432565b91965093509050610b518587611641565b610b6e5760405163075fd2b160e01b815260040160405180910390fd5b610bde565b86806020019051810190610b879190612432565b6001600160a01b03831615159650909450909250905083610ba85785610baa565b815b9450838015610bc05750610bbe8587611641565b155b15610bde5760405163075fd2b160e01b815260040160405180910390fd5b600354610100900460ff168015610c0157506020810151511580610c0157508051155b15610c1f5760405163c19e07c560e01b815260040160405180910390fd5b6001600160a01b038316610c565760405163f4a513b960e01b81526001600160a01b03861660048201526024015b60405180910390fd5b6001600160a01b03808616600090815260086020908152604090912080549286166101000274ffffffffffffffffffffffffffffffffffffffff0019909316929092178255825160018301908155908301518391906002840190610cba9082612515565b505060035460ff169050610cce5784610cd1565b60015b815460ff19169015151781556001600160a01b0386166000908152600760205260408120549003610dad576004546001600160a01b038716600090815260076020526040902055610d278660015b60ff16611739565b600088600454604051602001610d3e9291906125d4565b6040516020818303038152906040529050866001600160a01b03167fa197306e3dd5494a61a695381aa809a53b8e377a685e84e404a85d5a8da6cc62828a604051610d8a9291906125f6565b60405180910390a260048054906000610da2836122c2565b919050555050610e4a565b6000610db88761176c565b905060ff811660021480610dcf575060ff81166005145b15610de457610ddf876001610d1f565b610dfb565b60021960ff821601610dfb57610dfb876004610d1f565b866001600160a01b03167fcec1da3f7f0b8a344dd1025d06e2ddd48b14880395997ad97cbdb439acc761d48a8a610e318b61176c565b604051610e4093929190612621565b60405180910390a2505b505050505092915050565b6001546040516329e40d4b60e01b81526000916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916329e40d4b91610eb99186906004019182526001600160a01b0316602082015260400190565b602060405180830381865afa158015610ed6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060f9190612656565b6001546040516329e40d4b60e01b815260048101919091526001600160a01b0382811660248301527f000000000000000000000000000000000000000000000000000000000000000016906329e40d4b90604401602060405180830381865afa158015610f6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8f9190612656565b610a975760405163075fd2b160e01b815260040160405180910390fd5b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601610fe457506001600160a01b0381163161060f565b610fee83836117ad565b905061060f565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601611024576105eb82826117e2565b6105eb8383836117fe565b611037611b06565b6001600160a01b038083166000908152600860209081526040918290208251606081018452815460ff81161515825261010090049094168483015282518084018452600182018054825260028301805493958701949293919284019161109c90612495565b80601f01602080910402602001604051908101604052809291908181526020018280546110c890612495565b80156111155780601f106110ea57610100808354040283529160200191611115565b820191906000526020600020905b8154815290600101906020018083116110f857829003601f168201915b5050509190925250505090525092915050565b806001600160401b0316826001600160401b0316111561098e57604051637fcce2a960e01b815260040160405180910390fd5b606061060c83836040518060600160405280602781526020016128c66027913961184d565b6040805180820190915260008082526020820152610abd565b60035460009042620100009091046001600160401b0316118015906111d05750600354600160501b90046001600160401b03164211155b156111db5750600190565b50600090565b60006111ec8261176c565b60ff16600681111561060f5761060f6120f2565b611209826118c5565b80516003805460208085015161ffff1990921693151561ff001916939093176101009115159190910217905560408051635ab1bd5360e01b815290517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692635ab1bd5392600480820193918290030181865afa158015611296573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ba9190612671565b6005805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055604081015160038054606084015171ffffffffffffffffffffffffffffffff000019909116620100006001600160401b038086169190910267ffffffffffffffff60501b191691909117600160501b918316919091021790915560016004556113509190611128565b60408082015160608084015183516001600160401b0393841681529216602083015233928201929092527f70d34c8836b996cffd8970ba5edf940d83ca7c8f30f738ea4fd8566a37d93359910160405180910390a15050565b806113b381610efa565b60003490506000848060200190518101906113ce9190612699565b805190915060008190036113f557604051637fcce2a960e01b815260040160405180910390fd5b60005b818110156115c457600083828151811061141457611414612249565b6020026020010151905060008160200151905060006114328261102f565b9050600081602001519050600087868151811061145157611451612249565b6020026020010151600001519050600088878151811061147357611473612249565b602002602001015160400151905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0316826001600160a01b0316036114bb576114b8818b612768565b99505b60208401516001600160a01b03166114f15760405163f4a513b960e01b81526001600160a01b0386166004820152602401610c4d565b60026114fc8661176c565b60ff161461151d5760405163392c16fb60e21b815260040160405180910390fd5b6115538260405180606001604052808f6001600160a01b03168152602001866001600160a01b0316815260200184815250611914565b50846001600160a01b03167f463ffc2cf8b1596445c417388ed30e53eb67cf6668cb2be7f0addf8a78c8441b82848f6040516115ab939291909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a28660010196505050505050506113f8565b5082156115ea576115ea73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8685610ff5565b505050505050565b60035442620100009091046001600160401b031611806116235750600354600160501b90046001600160401b031642115b156105ce57604051635b04f6ad60e11b815260040160405180910390fd5b60055460405163dd93da4360e01b81526001600160a01b038481166004830152600092839291169063dd93da4390602401600060405180830381865afa15801561168f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116b7919081019061277b565b6005548151604051635e8a791560e01b815260048101919091526001600160a01b038681166024830152929350911690635e8a791590604401602060405180830381865afa15801561170d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117319190612656565b949350505050565b600080600061174785611993565b60009283526006602052604090922095811b600f90911b199091161790935550505050565b6001600160a01b038116600090815260076020526040812054810361179357506000919050565b60008061179f84611993565b600f911c1695945050505050565b6000816014526f70a0823100000000000000000000000060005260208060246010865afa601f3d111660205102905092915050565b60008060008084865af161098e5763b12d13eb6000526004601cfd5b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d156001600051141716611843576390b8ec186000526004601cfd5b6000603452505050565b6060600080856001600160a01b03168560405161186a9190612841565b600060405180830381855af49150503d80600081146118a5576040519150601f19603f3d011682016040523d82523d6000602084013e6118aa565b606091505b50915091506118bb86838387611a06565b9695505050505050565b6118cd610585565b600154156118ee5760405163439a74c960e01b815260040160405180910390fd5b8060000361190f57604051637fcce2a960e01b815260040160405180910390fd5b600155565b604081015160009073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038516016119755780341015611962576040516374c5672b60e01b815260040160405180910390fd5b6119708360200151826117e2565b611989565b611989848460000151856020015184611a7f565b5060019392505050565b6001600160a01b0381166000908152600760205260408120548190819081906119be90600190612768565b905060006119cd604083612873565b905060006119dc604084612887565b6119e790600461289b565b6000838152600660205260409020549298909750919550909350505050565b60608315611a75578251600003611a6e576001600160a01b0385163b611a6e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c4d565b5081611731565b6117318383611adc565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c52602060006064601c6000895af13d156001600051141716611ace57637939f4246000526004601cfd5b600060605260405250505050565b815115611aec5781518083602001fd5b8060405162461bcd60e51b8152600401610c4d91906128b2565b604051806060016040528060001515815260200160006001600160a01b03168152602001611b47604051806040016040528060008152602001606081525090565b905290565b6001600160a01b0381168114610a9757600080fd5b600060208284031215611b7357600080fd5b8135611b7e81611b4c565b9392505050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715611bbd57611bbd611b85565b60405290565b604051606081016001600160401b0381118282101715611bbd57611bbd611b85565b60405160c081016001600160401b0381118282101715611bbd57611bbd611b85565b604051601f8201601f191681016001600160401b0381118282101715611c2f57611c2f611b85565b604052919050565b60006001600160401b03821115611c5057611c50611b85565b5060051b60200190565b600082601f830112611c6b57600080fd5b81356020611c80611c7b83611c37565b611c07565b82815260059290921b84018101918181019086841115611c9f57600080fd5b8286015b84811015611cc3578035611cb681611b4c565b8352918301918301611ca3565b509695505050505050565b60006001600160401b03821115611ce757611ce7611b85565b50601f01601f191660200190565b600082601f830112611d0657600080fd5b8135611d14611c7b82611cce565b818152846020838601011115611d2957600080fd5b816020850160208301376000918101602001919091529392505050565b600080600060608486031215611d5b57600080fd5b83356001600160401b0380821115611d7257600080fd5b611d7e87838801611c5a565b94506020860135915080821115611d9457600080fd5b50611da186828701611cf5565b9250506040840135611db281611b4c565b809150509250925092565b60008060408385031215611dd057600080fd5b82356001600160401b03811115611de657600080fd5b611df285828601611cf5565b9250506020830135611e0381611b4c565b809150509250929050565b60005b83811015611e29578181015183820152602001611e11565b50506000910152565b60008151808452611e4a816020860160208601611e0e565b601f01601f19169290920160200192915050565b602081528151151560208201526001600160a01b036020830151166040820152600060408301516060808401528051608084015260208101519050604060a084015261173160c0840182611e32565b6001600160401b0381168114610a9757600080fd5b60008060408385031215611ed557600080fd5b8235611ee081611ead565b91506020830135611e0381611ead565b60008060208385031215611f0357600080fd5b82356001600160401b0380821115611f1a57600080fd5b818501915085601f830112611f2e57600080fd5b813581811115611f3d57600080fd5b8660208260051b8501011115611f5257600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015611fb957603f19888603018452611fa7858351611e32565b94509285019290850190600101611f8b565b5092979650505050505050565b60008060408385031215611fd957600080fd5b82356001600160401b0380821115611ff057600080fd5b611ffc86838701611c5a565b935060209150818501358181111561201357600080fd5b8501601f8101871361202457600080fd5b8035612032611c7b82611c37565b81815260059190911b8201840190848101908983111561205157600080fd5b8584015b838110156120895780358681111561206d5760008081fd5b61207b8c8983890101611cf5565b845250918601918601612055565b508096505050505050509250929050565b602080825282518282018190526000919060409081850190868401855b828110156120e557815180516001600160a01b031685528601518685015292840192908501906001016120b7565b5091979650505050505050565b634e487b7160e01b600052602160045260246000fd5b602081016007831061212a57634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561214357600080fd5b8235915060208301356001600160401b0381111561216057600080fd5b61216c85828601611cf5565b9150509250929050565b600080604080848603121561218a57600080fd5b83356001600160401b038111156121a057600080fd5b8401601f810186136121b157600080fd5b803560206121c1611c7b83611c37565b82815260069290921b830181019181810190898411156121e057600080fd5b938201935b838510156122205785858b0312156121fd5760008081fd5b612205611b9b565b853581528386013584820152825293850193908201906121e5565b9997909101359750505050505050565b60006020828403121561224257600080fd5b5035919050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261227657600080fd5b8301803591506001600160401b0382111561229057600080fd5b6020019150368190038213156122a557600080fd5b9250929050565b634e487b7160e01b600052601160045260246000fd5b6000600182016122d4576122d46122ac565b5060010190565b805180151581146122eb57600080fd5b919050565b60006080828403121561230257600080fd5b604051608081018181106001600160401b038211171561232457612324611b85565b604052612330836122db565b815261233e602084016122db565b6020820152604083015161235181611ead565b6040820152606083015161236481611ead565b60608201529392505050565b8281526040602082015260006117316040830184611e32565b8082018082111561060f5761060f6122ac565b600082601f8301126123ad57600080fd5b81516123bb611c7b82611cce565b8181528460208386010111156123d057600080fd5b611731826020830160208701611e0e565b6000604082840312156123f357600080fd5b6123fb611b9b565b90508151815260208201516001600160401b0381111561241a57600080fd5b6124268482850161239c565b60208301525092915050565b60008060006060848603121561244757600080fd5b835161245281611b4c565b602085015190935061246381611b4c565b60408501519092506001600160401b0381111561247f57600080fd5b61248b868287016123e1565b9150509250925092565b600181811c908216806124a957607f821691505b6020821081036124c957634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156105eb57600081815260208120601f850160051c810160208610156124f65750805b601f850160051c820191505b818110156115ea57828155600101612502565b81516001600160401b0381111561252e5761252e611b85565b6125428161253c8454612495565b846124cf565b602080601f831160018114612577576000841561255f5750858301515b600019600386901b1c1916600185901b1785556115ea565b600085815260208120601f198616915b828110156125a657888601518255948401946001909101908401612587565b50858210156125c45787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6040815260006125e76040830185611e32565b90508260208301529392505050565b6040815260006126096040830185611e32565b90506001600160a01b03831660208301529392505050565b6060815260006126346060830186611e32565b90506001600160a01b038416602083015260ff83166040830152949350505050565b60006020828403121561266857600080fd5b61060c826122db565b60006020828403121561268357600080fd5b8151611b7e81611b4c565b80516122eb81611b4c565b600060208083850312156126ac57600080fd5b82516001600160401b038111156126c257600080fd5b8301601f810185136126d357600080fd5b80516126e1611c7b82611c37565b8181526060918202830184019184820191908884111561270057600080fd5b938501935b8385101561275c5780858a03121561271d5760008081fd5b612725611bc3565b855161273081611b4c565b81528587015161273f81611b4c565b818801526040868101519082015283529384019391850191612705565b50979650505050505050565b8181038181111561060f5761060f6122ac565b60006020828403121561278d57600080fd5b81516001600160401b03808211156127a457600080fd5b9083019060c082860312156127b857600080fd5b6127c0611be5565b82518152602083015160208201526040830151828111156127e057600080fd5b6127ec8782860161239c565b60408301525060608301518281111561280457600080fd5b612810878286016123e1565b6060830152506128226080840161268e565b608082015261283360a0840161268e565b60a082015295945050505050565b60008251612853818460208701611e0e565b9190910192915050565b634e487b7160e01b600052601260045260246000fd5b6000826128825761288261285d565b500490565b6000826128965761289661285d565b500690565b808202811582820484141761060f5761060f6122ac565b60208152600061060c6020830184611e3256fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212206eece4c0fef0132b2728a7c3ff64467c881f80749d4c23f80868f1b32717dcab64736f6c634300081300330000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a10000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c4469726563744772616e74734c697465537472617465677976312e3000000000

Deployed Bytecode

0x6080604052600436106101a55760003560e01c80639af5c09d116100e1578063dff7d2c71161008a578063ef2920fc11610064578063ef2920fc14610505578063f31db3d114610518578063f5b0dfb714610538578063f6f258911461055857600080fd5b8063dff7d2c714610491578063eb11af93146104b8578063edd146cc146104e557600080fd5b8063b2b878d0116100bb578063b2b878d014610430578063cb0e85a61461045d578063df868ed31461047c57600080fd5b80639af5c09d1461039d578063a0cf0aea146103db578063ac9650d81461040357600080fd5b80634ab4ba421161014e5780635708973911610128578063570897391461032057806362812a391461033a57806375777aaa1461036757806395355b3b1461038757600080fd5b80634ab4ba42146102bb5780634d31d087146102d057806351cff8d91461030057600080fd5b80632bbe0cae1161017f5780632bbe0cae1461026057806338fff2d01461027357806342fda9c71461028857600080fd5b806301fc1c64146101b95780630a6f0ee9146101f957806315cc481e1461021957600080fd5b366101b4576101b2610585565b005b600080fd5b3480156101c557600080fd5b506101e66101d4366004611b61565b60076020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561020557600080fd5b506101b2610214366004611d46565b6105d0565b34801561022557600080fd5b507f0000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a15b6040516001600160a01b0390911681526020016101f0565b61024861026e366004611dbd565b6105f0565b34801561027f57600080fd5b506001546101e6565b34801561029457600080fd5b507f103732a8e473467a510d4128ee11065262bdd978f0d9dad89ba68f2c56127e276101e6565b3480156102c757600080fd5b506002546101e6565b3480156102dc57600080fd5b506102f06102eb366004611b61565b610615565b60405190151581526020016101f0565b34801561030c57600080fd5b506101b261031b366004611b61565b610620565b34801561032c57600080fd5b506003546102f09060ff1681565b34801561034657600080fd5b5061035a610355366004611b61565b61064a565b6040516101f09190611e5e565b34801561037357600080fd5b506101b2610382366004611ec2565b61065b565b34801561039357600080fd5b506101e660045481565b3480156103a957600080fd5b506003546103c3906201000090046001600160401b031681565b6040516001600160401b0390911681526020016101f0565b3480156103e757600080fd5b5061024873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b34801561040f57600080fd5b5061042361041e366004611ef0565b61070d565b6040516101f09190611f64565b34801561043c57600080fd5b5061045061044b366004611fc6565b610801565b6040516101f0919061209a565b34801561046957600080fd5b506003546102f090610100900460ff1681565b34801561048857600080fd5b506102f06108ff565b34801561049d57600080fd5b506003546103c390600160501b90046001600160401b031681565b3480156104c457600080fd5b506104d86104d3366004611b61565b61090e565b6040516101f09190612108565b3480156104f157600080fd5b506101b2610500366004612130565b610919565b6101b2610513366004611dbd565b610974565b34801561052457600080fd5b506101b2610533366004612176565b610992565b34801561054457600080fd5b506101b2610553366004612230565b610a70565b34801561056457600080fd5b506101e6610573366004612230565b60066020526000908152604090205481565b336001600160a01b037f0000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a116146105ce5760405163075fd2b160e01b815260040160405180910390fd5b565b6105d8610585565b6105e0610a9a565b6105eb838383610abd565b505050565b60006105fa610585565b610602610a9a565b61060c8383610ad6565b90505b92915050565b600061060f82610e55565b3361062a81610efa565b60006106368330610fac565b905080610644843383610ff5565b50505050565b610652611b06565b61060f8261102f565b3361066581610efa565b61066f8383611128565b6003805471ffffffffffffffffffffffffffffffff00001916620100006001600160401b03868116820267ffffffffffffffff60501b191692909217600160501b8684168102919091179384905560408051928504841683529304909116602082015233918101919091527f70d34c8836b996cffd8970ba5edf940d83ca7c8f30f738ea4fd8566a37d93359906060015b60405180910390a1505050565b6060816001600160401b0381111561072757610727611b85565b60405190808252806020026020018201604052801561075a57816020015b60608152602001906001900390816107455790505b50905060005b828110156107fa576107ca3085858481811061077e5761077e612249565b9050602002810190610790919061225f565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061115b92505050565b8282815181106107dc576107dc612249565b602002602001018190525080806107f2906122c2565b915050610760565b5092915050565b8151815160609190811461082857604051633da4c02b60e11b815260040160405180910390fd5b6000816001600160401b0381111561084257610842611b85565b60405190808252806020026020018201604052801561088757816020015b60408051808201909152600080825260208201528152602001906001900390816108605790505b50905060005b828110156108f6576108d18682815181106108aa576108aa612249565b60200260200101518683815181106108c4576108c4612249565b6020026020010151611180565b8282815181106108e3576108e3612249565b602090810291909101015260010161088d565b50949350505050565b6000610909611199565b905090565b600061060f826111e1565b610921610585565b60008180602001905181019061093791906122f0565b90506109438382611200565b7f91efa3d50feccde0d0d202f8ae5c41ca0b2be614cebcb2bd2f4b019396e6568a8383604051610700929190612370565b61097c610585565b610984610a9a565b61098e82826113a9565b5050565b3361099c81610efa565b60045482146109be57604051637fcce2a960e01b815260040160405180910390fd5b825160005b81811015610a695760008582815181106109df576109df612249565b60200260200101516000015190506000868381518110610a0157610a01612249565b6020908102919091018101518101516000848152600683526040908190208290558051828152339381019390935290925083917f941884a9a55191a7401466aaf8a0d2b7c8b082055a5a2b345b83c73940172ac4910160405180910390a250506001016109c3565b5050505050565b610a78610585565b8060026000828254610a8a9190612389565b90915550610a9790508181565b50565b6001546000036105ce57604051630f68fe6360e21b815260040160405180910390fd5b6040516343f6e4ab60e01b815260040160405180910390fd5b6000610ae06115f2565b3415610aff576040516322d8ddab60e01b815260040160405180910390fd5b6000806000610b21604051806040016040528060008152602001606081525090565b60035460ff1615610b735786806020019051810190610b409190612432565b91965093509050610b518587611641565b610b6e5760405163075fd2b160e01b815260040160405180910390fd5b610bde565b86806020019051810190610b879190612432565b6001600160a01b03831615159650909450909250905083610ba85785610baa565b815b9450838015610bc05750610bbe8587611641565b155b15610bde5760405163075fd2b160e01b815260040160405180910390fd5b600354610100900460ff168015610c0157506020810151511580610c0157508051155b15610c1f5760405163c19e07c560e01b815260040160405180910390fd5b6001600160a01b038316610c565760405163f4a513b960e01b81526001600160a01b03861660048201526024015b60405180910390fd5b6001600160a01b03808616600090815260086020908152604090912080549286166101000274ffffffffffffffffffffffffffffffffffffffff0019909316929092178255825160018301908155908301518391906002840190610cba9082612515565b505060035460ff169050610cce5784610cd1565b60015b815460ff19169015151781556001600160a01b0386166000908152600760205260408120549003610dad576004546001600160a01b038716600090815260076020526040902055610d278660015b60ff16611739565b600088600454604051602001610d3e9291906125d4565b6040516020818303038152906040529050866001600160a01b03167fa197306e3dd5494a61a695381aa809a53b8e377a685e84e404a85d5a8da6cc62828a604051610d8a9291906125f6565b60405180910390a260048054906000610da2836122c2565b919050555050610e4a565b6000610db88761176c565b905060ff811660021480610dcf575060ff81166005145b15610de457610ddf876001610d1f565b610dfb565b60021960ff821601610dfb57610dfb876004610d1f565b866001600160a01b03167fcec1da3f7f0b8a344dd1025d06e2ddd48b14880395997ad97cbdb439acc761d48a8a610e318b61176c565b604051610e4093929190612621565b60405180910390a2505b505050505092915050565b6001546040516329e40d4b60e01b81526000916001600160a01b037f0000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a116916329e40d4b91610eb99186906004019182526001600160a01b0316602082015260400190565b602060405180830381865afa158015610ed6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060f9190612656565b6001546040516329e40d4b60e01b815260048101919091526001600160a01b0382811660248301527f0000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a116906329e40d4b90604401602060405180830381865afa158015610f6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8f9190612656565b610a975760405163075fd2b160e01b815260040160405180910390fd5b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601610fe457506001600160a01b0381163161060f565b610fee83836117ad565b905061060f565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601611024576105eb82826117e2565b6105eb8383836117fe565b611037611b06565b6001600160a01b038083166000908152600860209081526040918290208251606081018452815460ff81161515825261010090049094168483015282518084018452600182018054825260028301805493958701949293919284019161109c90612495565b80601f01602080910402602001604051908101604052809291908181526020018280546110c890612495565b80156111155780601f106110ea57610100808354040283529160200191611115565b820191906000526020600020905b8154815290600101906020018083116110f857829003601f168201915b5050509190925250505090525092915050565b806001600160401b0316826001600160401b0316111561098e57604051637fcce2a960e01b815260040160405180910390fd5b606061060c83836040518060600160405280602781526020016128c66027913961184d565b6040805180820190915260008082526020820152610abd565b60035460009042620100009091046001600160401b0316118015906111d05750600354600160501b90046001600160401b03164211155b156111db5750600190565b50600090565b60006111ec8261176c565b60ff16600681111561060f5761060f6120f2565b611209826118c5565b80516003805460208085015161ffff1990921693151561ff001916939093176101009115159190910217905560408051635ab1bd5360e01b815290517f0000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a16001600160a01b031692635ab1bd5392600480820193918290030181865afa158015611296573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ba9190612671565b6005805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055604081015160038054606084015171ffffffffffffffffffffffffffffffff000019909116620100006001600160401b038086169190910267ffffffffffffffff60501b191691909117600160501b918316919091021790915560016004556113509190611128565b60408082015160608084015183516001600160401b0393841681529216602083015233928201929092527f70d34c8836b996cffd8970ba5edf940d83ca7c8f30f738ea4fd8566a37d93359910160405180910390a15050565b806113b381610efa565b60003490506000848060200190518101906113ce9190612699565b805190915060008190036113f557604051637fcce2a960e01b815260040160405180910390fd5b60005b818110156115c457600083828151811061141457611414612249565b6020026020010151905060008160200151905060006114328261102f565b9050600081602001519050600087868151811061145157611451612249565b6020026020010151600001519050600088878151811061147357611473612249565b602002602001015160400151905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0316826001600160a01b0316036114bb576114b8818b612768565b99505b60208401516001600160a01b03166114f15760405163f4a513b960e01b81526001600160a01b0386166004820152602401610c4d565b60026114fc8661176c565b60ff161461151d5760405163392c16fb60e21b815260040160405180910390fd5b6115538260405180606001604052808f6001600160a01b03168152602001866001600160a01b0316815260200184815250611914565b50846001600160a01b03167f463ffc2cf8b1596445c417388ed30e53eb67cf6668cb2be7f0addf8a78c8441b82848f6040516115ab939291909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a28660010196505050505050506113f8565b5082156115ea576115ea73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8685610ff5565b505050505050565b60035442620100009091046001600160401b031611806116235750600354600160501b90046001600160401b031642115b156105ce57604051635b04f6ad60e11b815260040160405180910390fd5b60055460405163dd93da4360e01b81526001600160a01b038481166004830152600092839291169063dd93da4390602401600060405180830381865afa15801561168f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116b7919081019061277b565b6005548151604051635e8a791560e01b815260048101919091526001600160a01b038681166024830152929350911690635e8a791590604401602060405180830381865afa15801561170d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117319190612656565b949350505050565b600080600061174785611993565b60009283526006602052604090922095811b600f90911b199091161790935550505050565b6001600160a01b038116600090815260076020526040812054810361179357506000919050565b60008061179f84611993565b600f911c1695945050505050565b6000816014526f70a0823100000000000000000000000060005260208060246010865afa601f3d111660205102905092915050565b60008060008084865af161098e5763b12d13eb6000526004601cfd5b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d156001600051141716611843576390b8ec186000526004601cfd5b6000603452505050565b6060600080856001600160a01b03168560405161186a9190612841565b600060405180830381855af49150503d80600081146118a5576040519150601f19603f3d011682016040523d82523d6000602084013e6118aa565b606091505b50915091506118bb86838387611a06565b9695505050505050565b6118cd610585565b600154156118ee5760405163439a74c960e01b815260040160405180910390fd5b8060000361190f57604051637fcce2a960e01b815260040160405180910390fd5b600155565b604081015160009073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038516016119755780341015611962576040516374c5672b60e01b815260040160405180910390fd5b6119708360200151826117e2565b611989565b611989848460000151856020015184611a7f565b5060019392505050565b6001600160a01b0381166000908152600760205260408120548190819081906119be90600190612768565b905060006119cd604083612873565b905060006119dc604084612887565b6119e790600461289b565b6000838152600660205260409020549298909750919550909350505050565b60608315611a75578251600003611a6e576001600160a01b0385163b611a6e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c4d565b5081611731565b6117318383611adc565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c52602060006064601c6000895af13d156001600051141716611ace57637939f4246000526004601cfd5b600060605260405250505050565b815115611aec5781518083602001fd5b8060405162461bcd60e51b8152600401610c4d91906128b2565b604051806060016040528060001515815260200160006001600160a01b03168152602001611b47604051806040016040528060008152602001606081525090565b905290565b6001600160a01b0381168114610a9757600080fd5b600060208284031215611b7357600080fd5b8135611b7e81611b4c565b9392505050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715611bbd57611bbd611b85565b60405290565b604051606081016001600160401b0381118282101715611bbd57611bbd611b85565b60405160c081016001600160401b0381118282101715611bbd57611bbd611b85565b604051601f8201601f191681016001600160401b0381118282101715611c2f57611c2f611b85565b604052919050565b60006001600160401b03821115611c5057611c50611b85565b5060051b60200190565b600082601f830112611c6b57600080fd5b81356020611c80611c7b83611c37565b611c07565b82815260059290921b84018101918181019086841115611c9f57600080fd5b8286015b84811015611cc3578035611cb681611b4c565b8352918301918301611ca3565b509695505050505050565b60006001600160401b03821115611ce757611ce7611b85565b50601f01601f191660200190565b600082601f830112611d0657600080fd5b8135611d14611c7b82611cce565b818152846020838601011115611d2957600080fd5b816020850160208301376000918101602001919091529392505050565b600080600060608486031215611d5b57600080fd5b83356001600160401b0380821115611d7257600080fd5b611d7e87838801611c5a565b94506020860135915080821115611d9457600080fd5b50611da186828701611cf5565b9250506040840135611db281611b4c565b809150509250925092565b60008060408385031215611dd057600080fd5b82356001600160401b03811115611de657600080fd5b611df285828601611cf5565b9250506020830135611e0381611b4c565b809150509250929050565b60005b83811015611e29578181015183820152602001611e11565b50506000910152565b60008151808452611e4a816020860160208601611e0e565b601f01601f19169290920160200192915050565b602081528151151560208201526001600160a01b036020830151166040820152600060408301516060808401528051608084015260208101519050604060a084015261173160c0840182611e32565b6001600160401b0381168114610a9757600080fd5b60008060408385031215611ed557600080fd5b8235611ee081611ead565b91506020830135611e0381611ead565b60008060208385031215611f0357600080fd5b82356001600160401b0380821115611f1a57600080fd5b818501915085601f830112611f2e57600080fd5b813581811115611f3d57600080fd5b8660208260051b8501011115611f5257600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015611fb957603f19888603018452611fa7858351611e32565b94509285019290850190600101611f8b565b5092979650505050505050565b60008060408385031215611fd957600080fd5b82356001600160401b0380821115611ff057600080fd5b611ffc86838701611c5a565b935060209150818501358181111561201357600080fd5b8501601f8101871361202457600080fd5b8035612032611c7b82611c37565b81815260059190911b8201840190848101908983111561205157600080fd5b8584015b838110156120895780358681111561206d5760008081fd5b61207b8c8983890101611cf5565b845250918601918601612055565b508096505050505050509250929050565b602080825282518282018190526000919060409081850190868401855b828110156120e557815180516001600160a01b031685528601518685015292840192908501906001016120b7565b5091979650505050505050565b634e487b7160e01b600052602160045260246000fd5b602081016007831061212a57634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561214357600080fd5b8235915060208301356001600160401b0381111561216057600080fd5b61216c85828601611cf5565b9150509250929050565b600080604080848603121561218a57600080fd5b83356001600160401b038111156121a057600080fd5b8401601f810186136121b157600080fd5b803560206121c1611c7b83611c37565b82815260069290921b830181019181810190898411156121e057600080fd5b938201935b838510156122205785858b0312156121fd5760008081fd5b612205611b9b565b853581528386013584820152825293850193908201906121e5565b9997909101359750505050505050565b60006020828403121561224257600080fd5b5035919050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261227657600080fd5b8301803591506001600160401b0382111561229057600080fd5b6020019150368190038213156122a557600080fd5b9250929050565b634e487b7160e01b600052601160045260246000fd5b6000600182016122d4576122d46122ac565b5060010190565b805180151581146122eb57600080fd5b919050565b60006080828403121561230257600080fd5b604051608081018181106001600160401b038211171561232457612324611b85565b604052612330836122db565b815261233e602084016122db565b6020820152604083015161235181611ead565b6040820152606083015161236481611ead565b60608201529392505050565b8281526040602082015260006117316040830184611e32565b8082018082111561060f5761060f6122ac565b600082601f8301126123ad57600080fd5b81516123bb611c7b82611cce565b8181528460208386010111156123d057600080fd5b611731826020830160208701611e0e565b6000604082840312156123f357600080fd5b6123fb611b9b565b90508151815260208201516001600160401b0381111561241a57600080fd5b6124268482850161239c565b60208301525092915050565b60008060006060848603121561244757600080fd5b835161245281611b4c565b602085015190935061246381611b4c565b60408501519092506001600160401b0381111561247f57600080fd5b61248b868287016123e1565b9150509250925092565b600181811c908216806124a957607f821691505b6020821081036124c957634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156105eb57600081815260208120601f850160051c810160208610156124f65750805b601f850160051c820191505b818110156115ea57828155600101612502565b81516001600160401b0381111561252e5761252e611b85565b6125428161253c8454612495565b846124cf565b602080601f831160018114612577576000841561255f5750858301515b600019600386901b1c1916600185901b1785556115ea565b600085815260208120601f198616915b828110156125a657888601518255948401946001909101908401612587565b50858210156125c45787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6040815260006125e76040830185611e32565b90508260208301529392505050565b6040815260006126096040830185611e32565b90506001600160a01b03831660208301529392505050565b6060815260006126346060830186611e32565b90506001600160a01b038416602083015260ff83166040830152949350505050565b60006020828403121561266857600080fd5b61060c826122db565b60006020828403121561268357600080fd5b8151611b7e81611b4c565b80516122eb81611b4c565b600060208083850312156126ac57600080fd5b82516001600160401b038111156126c257600080fd5b8301601f810185136126d357600080fd5b80516126e1611c7b82611c37565b8181526060918202830184019184820191908884111561270057600080fd5b938501935b8385101561275c5780858a03121561271d5760008081fd5b612725611bc3565b855161273081611b4c565b81528587015161273f81611b4c565b818801526040868101519082015283529384019391850191612705565b50979650505050505050565b8181038181111561060f5761060f6122ac565b60006020828403121561278d57600080fd5b81516001600160401b03808211156127a457600080fd5b9083019060c082860312156127b857600080fd5b6127c0611be5565b82518152602083015160208201526040830151828111156127e057600080fd5b6127ec8782860161239c565b60408301525060608301518281111561280457600080fd5b612810878286016123e1565b6060830152506128226080840161268e565b608082015261283360a0840161268e565b60a082015295945050505050565b60008251612853818460208701611e0e565b9190910192915050565b634e487b7160e01b600052601260045260246000fd5b6000826128825761288261285d565b500490565b6000826128965761289661285d565b500690565b808202811582820484141761060f5761060f6122ac565b60208152600061060c6020830184611e3256fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212206eece4c0fef0132b2728a7c3ff64467c881f80749d4c23f80868f1b32717dcab64736f6c63430008130033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a10000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c4469726563744772616e74734c697465537472617465677976312e3000000000

-----Decoded View---------------
Arg [0] : _allo (address): 0x1133eA7Af70876e64665ecD07C0A0476d09465a1
Arg [1] : _name (string): DirectGrantsLiteStrategyv1.0

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a1
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [2] : 000000000000000000000000000000000000000000000000000000000000001c
Arg [3] : 4469726563744772616e74734c697465537472617465677976312e3000000000


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.