Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Allo
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 400 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
// External Libraries
import "solady/src/auth/Ownable.sol";
import "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
import "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/IERC20Upgradeable.sol";
import "lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol";
import "lib/openzeppelin-contracts-upgradeable/contracts/security/ReentrancyGuardUpgradeable.sol";
// Interfaces
import "./interfaces/IAllo.sol";
// Internal Libraries
import {Clone} from "./libraries/Clone.sol";
import {Errors} from "./libraries/Errors.sol";
import "./libraries/Native.sol";
import {Transfer} from "./libraries/Transfer.sol";
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
// allo.gitcoin.co
/// @title Allo
/// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]>
/// @notice This contract is used to create & manage pools as well as manage the protocol.
/// @dev The contract must be initialized with the 'initialize()' function.
contract Allo is
IAllo,
Native,
Transfer,
Initializable,
Ownable,
AccessControlUpgradeable,
ReentrancyGuardUpgradeable,
Errors
{
// ==========================
// === Storage Variables ====
// ==========================
/// @notice Percentage that is used to calculate the fee Allo takes from each pool when funded
/// and is deducted when a pool is funded. So if you want to fund a round with 1000 DAI and the fee
/// percentage is 1e17 (10%), then 100 DAI will be deducted from the 1000 DAI and the pool will be
/// funded with 900 DAI. The fee is then sent to the treasury address.
/// @dev How the percentage is represented in our contracts: 1e18 = 100%, 1e17 = 10%, 1e16 = 1%, 1e15 = 0.1%
uint256 private percentFee;
/// @notice Fee Allo charges for all pools on creation
/// @dev This is different from the 'percentFee' in that this is a flat fee and not a percentage. So if you want to create a pool
/// with a base fee of 100 DAI, then you would pass 100 DAI to the 'createPool()' function and the pool would be created
/// with 100 DAI less than the amount you passed to the function. The base fee is sent to the treasury address.
uint256 internal baseFee;
/// @notice Incremental index to track the pools created
uint256 private _poolIndex;
/// @notice Allo treasury
address payable private treasury;
/// @notice Registry contract
IRegistry private registry;
/// @notice Maps the `msg.sender` to a `nonce` to prevent duplicates
/// @dev 'msg.sender' -> 'nonce' for cloning strategies
mapping(address => uint256) private _nonces;
/// @notice Maps the pool ID to the pool details
/// @dev 'Pool.id' -> 'Pool'
mapping(uint256 => Pool) private pools;
/// @notice Returns a bool for whether a strategy is cloneable or not using the strategy address as the key
/// @dev Strategy.address -> bool
mapping(address => bool) private cloneableStrategies;
// ====================================
// =========== Initializer =============
// ====================================
/// @notice Initializes the contract after an upgrade
/// @dev During upgrade -> a higher version should be passed to reinitializer
/// @param _owner The owner of allo
/// @param _registry The address of the registry
/// @param _treasury The address of the treasury
/// @param _percentFee The percentage fee
/// @param _baseFee The base fee
function initialize(
address _owner,
address _registry,
address payable _treasury,
uint256 _percentFee,
uint256 _baseFee
) external reinitializer(1) {
// Initialize the owner using Solady ownable library
_initializeOwner(_owner);
// Set the address of the registry
_updateRegistry(_registry);
// Set the address of the treasury
_updateTreasury(_treasury);
// Set the fee percentage
_updatePercentFee(_percentFee);
// Set the base fee
_updateBaseFee(_baseFee);
}
// ====================================
// =========== Modifier ===============
// ====================================
// Both modifiers below are using OpenZeppelin's AccessControl.sol with custom roles under the hood
/// @notice Reverts UNAUTHORIZED() if the caller is not a pool manager
/// @param _poolId The pool id
modifier onlyPoolManager(uint256 _poolId) {
_checkOnlyPoolManager(_poolId);
_;
}
/// @notice Reverts UNAUTHORIZED() if the caller is not a pool admin
/// @param _poolId The pool id
modifier onlyPoolAdmin(uint256 _poolId) {
_checkOnlyPoolAdmin(_poolId);
_;
}
// ====================================
// ==== External/Public Functions =====
// ====================================
/// @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) {
// Revert if the strategy address passed is the zero address with 'ZERO_ADDRESS()'
if (_strategy == address(0)) revert ZERO_ADDRESS();
// Revert if we already have this strategy in our cloneable mapping with 'IS_APPROVED_STRATEGY()' (only non-cloneable strategies can be used)
if (_isCloneableStrategy(_strategy)) revert IS_APPROVED_STRATEGY();
// Call the internal '_createPool()' function and return the pool ID
return _createPool(_profileId, IStrategy(_strategy), _initStrategyData, _token, _amount, _metadata, _managers);
}
/// @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 nonReentrant returns (uint256 poolId) {
if (!_isCloneableStrategy(_strategy)) {
revert NOT_APPROVED_STRATEGY();
}
// Returns the created pool ID
return _createPool(
_profileId,
IStrategy(Clone.createClone(_strategy, _nonces[msg.sender]++)),
_initStrategyData,
_token,
_amount,
_metadata,
_managers
);
}
/// @notice Update pool metadata
/// @dev 'msg.sender' must be a pool manager. Emits 'PoolMetadataUpdated()' event.
/// @param _poolId ID of the pool
/// @param _metadata The new metadata of the pool
function updatePoolMetadata(uint256 _poolId, Metadata memory _metadata) external onlyPoolManager(_poolId) {
Pool storage pool = pools[_poolId];
pool.metadata = _metadata;
emit PoolMetadataUpdated(_poolId, _metadata);
}
/// @notice Updates the registry address.
/// @dev Use this to update the registry address. 'msg.sender' must be Allo owner.
/// @param _registry The new registry address
function updateRegistry(address _registry) external onlyOwner {
_updateRegistry(_registry);
}
/// @notice Updates the treasury address.
/// @dev Use this to update the treasury address. 'msg.sender' must be Allo owner.
/// @param _treasury The new treasury address
function updateTreasury(address payable _treasury) external onlyOwner {
_updateTreasury(_treasury);
}
/// @notice Updates the fee percentage.
/// @dev Use this to update the fee percentage. 'msg.sender' must be Allo owner.
/// @param _percentFee The new fee
function updatePercentFee(uint256 _percentFee) external onlyOwner {
_updatePercentFee(_percentFee);
}
/// @notice Updates the base fee.
/// @dev Use this to update the base fee. 'msg.sender' must be Allo owner.
/// @param _baseFee The new base fee
function updateBaseFee(uint256 _baseFee) external onlyOwner {
_updateBaseFee(_baseFee);
}
/// @notice Add a strategy to the allowlist.
/// @dev Emits the 'StrategyApproved()' event. 'msg.sender' must be Allo owner.
/// @param _strategy The address of the strategy
function addToCloneableStrategies(address _strategy) external onlyOwner {
if (_strategy == address(0)) revert ZERO_ADDRESS();
cloneableStrategies[_strategy] = true;
emit StrategyApproved(_strategy);
}
/// @notice Remove a strategy from the allowlist
/// @dev Emits 'StrategyRemoved()' event. 'msg.sender must be Allo owner.
/// @param _strategy The address of the strategy
function removeFromCloneableStrategies(address _strategy) external onlyOwner {
// Set the strategy to false in the cloneableStrategies mapping
cloneableStrategies[_strategy] = false;
// Emit the StrategyRemoved event
emit StrategyRemoved(_strategy);
}
/// @notice Add a pool manager
/// @dev Emits 'RoleGranted()' event. 'msg.sender' must be a pool admin.
/// @param _poolId ID of the pool
/// @param _manager The address to add
function addPoolManager(uint256 _poolId, address _manager) external onlyPoolAdmin(_poolId) {
// Reverts if the address is the zero address with 'ZERO_ADDRESS()'
if (_manager == address(0)) revert ZERO_ADDRESS();
// Grants the pool manager role to the '_manager' address
_grantRole(pools[_poolId].managerRole, _manager);
}
/// @notice Remove a pool manager
/// @dev Emits 'RoleRevoked()' event. 'msg.sender' must be a pool admin.
/// @param _poolId ID of the pool
/// @param _manager The address to remove
function removePoolManager(uint256 _poolId, address _manager) external onlyPoolAdmin(_poolId) {
_revokeRole(pools[_poolId].managerRole, _manager);
}
/// @notice Transfer the funds recovered to the recipient
/// @dev 'msg.sender' must be Allo owner
/// @param _token The token to transfer
/// @param _recipient The recipient
function recoverFunds(address _token, address _recipient) external onlyOwner {
// Get the amount of the token to transfer, which is always the entire balance of the contract address
uint256 amount = _token == NATIVE ? address(this).balance : IERC20Upgradeable(_token).balanceOf(address(this));
// Transfer the amount to the recipient (pool owner)
_transferAmount(_token, _recipient, amount);
}
// ====================================
// ======= Strategy Functions =========
// ====================================
/// @notice Passes _data through to the strategy for that pool.
/// @dev The encoded data will be specific to a given strategy requirements, reference the strategy
/// implementation of registerRecipient().
/// @param _poolId ID of the pool
/// @param _data Encoded data unique to a strategy that registerRecipient() requires
/// @return recipientId The recipient ID that has been registered
function registerRecipient(uint256 _poolId, bytes memory _data) external payable nonReentrant returns (address) {
// Return the recipientId (address) from the strategy
return pools[_poolId].strategy.registerRecipient{value: msg.value}(_data, msg.sender);
}
/// @notice Register multiple recipients to multiple pools.
/// @dev Returns the 'recipientIds' from the strategy that have been registered from calling this function.
/// Encoded data unique to a strategy that registerRecipient() requires. Encoded '_data' length must match
/// '_poolIds' length or this will revert with MISMATCH(). Other requirements will be determined by the strategy.
/// @param _poolIds ID's of the pools
/// @param _data An array of encoded data unique to a strategy that registerRecipient() requires.
/// @return recipientIds The recipient IDs that have been registered
function batchRegisterRecipient(uint256[] memory _poolIds, bytes[] memory _data)
external
nonReentrant
returns (address[] memory recipientIds)
{
uint256 poolIdLength = _poolIds.length;
recipientIds = new address[](poolIdLength);
if (poolIdLength != _data.length) revert MISMATCH();
// Loop through the '_poolIds' & '_data' and call the 'strategy.registerRecipient()' function
for (uint256 i; i < poolIdLength;) {
recipientIds[i] = pools[_poolIds[i]].strategy.registerRecipient(_data[i], msg.sender);
unchecked {
++i;
}
}
// Return the recipientIds that have been registered
return recipientIds;
}
/// @notice Fund a pool.
/// @dev Anyone can fund a pool and call this function.
/// @param _poolId ID of the pool
/// @param _amount The amount to be deposited into the pool
function fundPool(uint256 _poolId, uint256 _amount) external payable nonReentrant {
// if amount is 0, revert with 'NOT_ENOUGH_FUNDS()' error
if (_amount == 0) revert NOT_ENOUGH_FUNDS();
Pool memory pool = pools[_poolId];
if (pool.token == NATIVE && _amount != msg.value) revert NOT_ENOUGH_FUNDS();
// Call the internal fundPool() function
_fundPool(_amount, _poolId, pool.strategy);
}
/// @notice Allocate to a recipient or multiple recipients.
/// @dev The encoded data will be specific to a given strategy requirements, reference the strategy
/// implementation of allocate().
/// @param _poolId ID of the pool
/// @param _data Encoded data unique to the strategy for that pool
function allocate(uint256 _poolId, bytes memory _data) external payable nonReentrant {
_allocate(_poolId, _data);
}
/// @notice Allocate to multiple pools
/// @dev The encoded data will be specific to a given strategy requirements, reference the strategy
/// implementation of allocate(). Please note that this is not a 'payable' function, so if you
/// want to send funds to the strategy, you must send the funds using 'fundPool()'.
/// @param _poolIds IDs of the pools
/// @param _datas encoded data unique to the strategy for that pool
function batchAllocate(uint256[] calldata _poolIds, bytes[] memory _datas) external nonReentrant {
uint256 numPools = _poolIds.length;
// Reverts if the length of _poolIds does not match the length of _datas with 'MISMATCH()' error
if (numPools != _datas.length) revert MISMATCH();
// Loop through the _poolIds & _datas and call the internal _allocate() function
for (uint256 i; i < numPools;) {
_allocate(_poolIds[i], _datas[i]);
unchecked {
++i;
}
}
}
/// @notice Distribute to a recipient or multiple recipients.
/// @dev The encoded data will be specific to a given strategy requirements, reference the strategy
/// implementation of 'strategy.distribute()'.
/// @param _poolId ID of the pool
/// @param _recipientIds Ids of the recipients of the distribution
/// @param _data Encoded data unique to the strategy
function distribute(uint256 _poolId, address[] memory _recipientIds, bytes memory _data) external nonReentrant {
pools[_poolId].strategy.distribute(_recipientIds, _data, msg.sender);
}
/// ====================================
/// ======= Internal Functions =========
/// ====================================
/// @notice Internal function to check is caller is pool manager
/// @param _poolId The pool id
function _checkOnlyPoolManager(uint256 _poolId) internal view {
if (!_isPoolManager(_poolId, msg.sender)) revert UNAUTHORIZED();
}
/// @notice Internal function to check is caller is pool admin
/// @param _poolId The pool id
function _checkOnlyPoolAdmin(uint256 _poolId) internal view {
if (!_isPoolAdmin(_poolId, msg.sender)) revert UNAUTHORIZED();
}
/// @notice Creates a new pool.
/// @dev This is an internal function that is called by the 'createPool()' & 'createPoolWithCustomStrategy()' functions
/// It is used to create a new pool and is called by both functions. The 'msg.sender' must be a member or owner of
/// a profile to create a pool.
/// @param _profileId The ID of the profile of for pool creator in the registry
/// @param _strategy The address of strategy
/// @param _initStrategyData The data to initialize the strategy
/// @param _token The address of the token that the pool is denominated in
/// @param _amount The amount of the token to be deposited into the pool
/// @param _metadata The 'Metadata' of the pool
/// @param _managers The managers of the pool
/// @return poolId The ID of the pool
function _createPool(
bytes32 _profileId,
IStrategy _strategy,
bytes memory _initStrategyData,
address _token,
uint256 _amount,
Metadata memory _metadata,
address[] memory _managers
) internal returns (uint256 poolId) {
if (!registry.isOwnerOrMemberOfProfile(_profileId, msg.sender)) revert UNAUTHORIZED();
poolId = ++_poolIndex;
// Generate the manager & admin roles for the pool (this is the way we do this throughout the protocol for consistency)
bytes32 POOL_MANAGER_ROLE = bytes32(poolId);
bytes32 POOL_ADMIN_ROLE = keccak256(abi.encodePacked(poolId, "admin"));
// Create the Pool instance
Pool memory pool = Pool({
profileId: _profileId,
strategy: _strategy,
metadata: _metadata,
token: _token,
managerRole: POOL_MANAGER_ROLE,
adminRole: POOL_ADMIN_ROLE
});
// Add the pool to the mapping of created pools
pools[poolId] = pool;
// Grant admin roles to the pool creator
_grantRole(POOL_ADMIN_ROLE, msg.sender);
// Set admin role for POOL_MANAGER_ROLE
_setRoleAdmin(POOL_MANAGER_ROLE, POOL_ADMIN_ROLE);
// initialize strategies
// Initialization is expected to revert when invoked more than once with 'ALREADY_INITIALIZED()' error
_strategy.initialize(poolId, _initStrategyData);
if (_strategy.getPoolId() != poolId || address(_strategy.getAllo()) != address(this)) revert MISMATCH();
// grant pool managers roles
uint256 managersLength = _managers.length;
for (uint256 i; i < managersLength;) {
address manager = _managers[i];
if (manager == address(0)) revert ZERO_ADDRESS();
_grantRole(POOL_MANAGER_ROLE, manager);
unchecked {
++i;
}
}
if (baseFee > 0) {
// To prevent paying the baseFee from the Allo contract's balance
// If _token is NATIVE, then baseFee + _amount should be > than msg.value.
// If _token is not NATIVE, then baseFee should be > than msg.value.
if ((_token == NATIVE && (baseFee + _amount != msg.value)) || (_token != NATIVE && baseFee != msg.value)) {
revert NOT_ENOUGH_FUNDS();
}
_transferAmount(NATIVE, treasury, baseFee);
emit BaseFeePaid(poolId, baseFee);
}
if (_amount > 0) {
_fundPool(_amount, poolId, _strategy);
}
emit PoolCreated(poolId, _profileId, _strategy, _token, _amount, _metadata);
}
/// @notice Allocate to recipient(s).
/// @dev Passes '_data' & 'msg.sender' through to the strategy for that pool.
/// This is an internal function that is called by the 'allocate()' & 'batchAllocate()' functions.
/// @param _poolId ID of the pool
/// @param _data Encoded data unique to the strategy for that pool
function _allocate(uint256 _poolId, bytes memory _data) internal {
pools[_poolId].strategy.allocate{value: msg.value}(_data, msg.sender);
}
/// @notice Fund a pool.
/// @dev Deducts the fee and transfers the amount to the distribution strategy.
/// Emits a 'PoolFunded' event.
/// @param _amount The amount to transfer
/// @param _poolId The 'poolId' for the pool you are funding
/// @param _strategy The address of the strategy
function _fundPool(uint256 _amount, uint256 _poolId, IStrategy _strategy) internal {
uint256 feeAmount;
uint256 amountAfterFee = _amount;
Pool storage pool = pools[_poolId];
address _token = pool.token;
if (percentFee > 0) {
feeAmount = (_amount * percentFee) / getFeeDenominator();
amountAfterFee -= feeAmount;
if (feeAmount + amountAfterFee != _amount) revert INVALID();
if (_token == NATIVE) {
_transferAmountFrom(_token, TransferData({from: msg.sender, to: treasury, amount: feeAmount}));
} else {
uint256 balanceBeforeFee = _getBalance(_token, treasury);
_transferAmountFrom(_token, TransferData({from: msg.sender, to: treasury, amount: feeAmount}));
uint256 balanceAfterFee = _getBalance(_token, treasury);
// Track actual fee paid to account for fee on ERC20 token transfers
feeAmount = balanceAfterFee - balanceBeforeFee;
}
}
if (_token == NATIVE) {
_transferAmountFrom(
_token, TransferData({from: msg.sender, to: address(_strategy), amount: amountAfterFee})
);
} else {
uint256 balanceBeforeFundingPool = _getBalance(_token, address(_strategy));
_transferAmountFrom(
_token, TransferData({from: msg.sender, to: address(_strategy), amount: amountAfterFee})
);
uint256 balanceAfterFundingPool = _getBalance(_token, address(_strategy));
// Track actual fee paid to account for fee on ERC20 token transfers
amountAfterFee = balanceAfterFundingPool - balanceBeforeFundingPool;
}
_strategy.increasePoolAmount(amountAfterFee);
emit PoolFunded(_poolId, amountAfterFee, feeAmount);
}
/// @notice Checks if the strategy is an approved cloneable strategy.
/// @dev Internal function used by createPoolwithCustomStrategy and createPool to
/// determine if a strategy is in the cloneable strategy allow list.
/// @param _strategy The address of the strategy
/// @return This will return 'true' if the strategy is cloneable, otherwise 'false'
function _isCloneableStrategy(address _strategy) internal view returns (bool) {
return cloneableStrategies[_strategy];
}
/// @notice Checks if the address is a pool admin
/// @dev Internal function used to determine if an address is a pool admin
/// @param _poolId The ID of the pool
/// @param _address The address to check
/// @return This will return 'true' if the address is a pool admin, otherwise 'false'
function _isPoolAdmin(uint256 _poolId, address _address) internal view returns (bool) {
return hasRole(pools[_poolId].adminRole, _address);
}
/// @notice Checks if the address is a pool manager
/// @dev Internal function used to determine if an address is a pool manager
/// @param _poolId The ID of the pool
/// @param _address The address to check
/// @return This will return 'true' if the address is a pool manager, otherwise 'false'
function _isPoolManager(uint256 _poolId, address _address) internal view returns (bool) {
return hasRole(pools[_poolId].managerRole, _address) || _isPoolAdmin(_poolId, _address);
}
/// @notice Updates the registry address
/// @dev Internal function used to update the registry address.
/// Emits a RegistryUpdated event.
/// @param _registry The new registry address
function _updateRegistry(address _registry) internal {
if (_registry == address(0)) revert ZERO_ADDRESS();
registry = IRegistry(_registry);
emit RegistryUpdated(_registry);
}
/// @notice Updates the treasury address
/// @dev Internal function used to update the treasury address.
/// Emits a TreasuryUpdated event.
/// @param _treasury The new treasury address
function _updateTreasury(address payable _treasury) internal {
if (_treasury == address(0)) revert ZERO_ADDRESS();
treasury = _treasury;
emit TreasuryUpdated(treasury);
}
/// @notice Updates the fee percentage
/// @dev Internal function used to update the percentage fee.
/// Emits a PercentFeeUpdated event.
/// @param _percentFee The new fee
function _updatePercentFee(uint256 _percentFee) internal {
if (_percentFee > 1e18) revert INVALID_FEE();
percentFee = _percentFee;
emit PercentFeeUpdated(percentFee);
}
/// @notice Updates the base fee
/// @dev Internal function used to update the base fee.
/// Emits a BaseFeeUpdated event.
/// @param _baseFee The new base fee
function _updateBaseFee(uint256 _baseFee) internal {
baseFee = _baseFee;
emit BaseFeeUpdated(baseFee);
}
// =========================
// ==== View Functions =====
// =========================
/// @notice Getter for the fee denominator
/// @return FEE_DENOMINATOR The fee denominator is (1e18) which represents 100%
function getFeeDenominator() public pure returns (uint256 FEE_DENOMINATOR) {
return 1e18;
}
/// @notice Checks if the address is a pool admin.
/// @param _poolId The ID of the pool
/// @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) {
return _isPoolAdmin(_poolId, _address);
}
/// @notice Checks if the address is a pool manager
/// @param _poolId The ID of the pool
/// @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) {
return _isPoolManager(_poolId, _address);
}
/// @notice Getter for the strategy.
/// @param _poolId The ID of the pool
/// @return The address of the strategy
function getStrategy(uint256 _poolId) external view returns (address) {
return address(pools[_poolId].strategy);
}
/// @notice Getter for fee percentage.
/// @return The fee percentage (1e18 = 100%)
function getPercentFee() external view returns (uint256) {
return percentFee;
}
/// @notice Getter for base fee.
/// @return The base fee
function getBaseFee() external view returns (uint256) {
return baseFee;
}
/// @notice Getter for treasury address.
/// @return The treasury address
function getTreasury() external view returns (address payable) {
return treasury;
}
/// @notice Getter for registry.
/// @return The registry address
function getRegistry() external view returns (IRegistry) {
return registry;
}
/// @notice Getter for if strategy is cloneable.
/// @param _strategy The address of the strategy
/// @return 'true' if the strategy is cloneable, otherwise 'false'
function isCloneableStrategy(address _strategy) external view returns (bool) {
return _isCloneableStrategy(_strategy);
}
/// @notice Getter for the 'Pool'.
/// @param _poolId The ID of the pool
/// @return The 'Pool' struct
function getPool(uint256 _poolId) external view returns (Pool memory) {
return pools[_poolId];
}
}// 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 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);
}// 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;
}// 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;
}// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.19; // External Libraries import "lib/openzeppelin-contracts-upgradeable/contracts/proxy/ClonesUpgradeable.sol"; // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀ // ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀ // ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀ // ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀ // ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀ // allo.gitcoin.co /// @title Clone library /// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]> /// @notice A helper library to create deterministic clones of the strategy contracts when a pool is created /// @dev Handles the creation of clones for the strategy contracts and returns the address of the clone library Clone { /// @dev Create a clone of the contract /// @param _contract The address of the contract to clone /// @param _nonce The nonce to use for the clone function createClone(address _contract, uint256 _nonce) internal returns (address) { bytes32 salt = keccak256(abi.encodePacked(msg.sender, _nonce)); // Return the address of the contract return ClonesUpgradeable.cloneDeterministic(_contract, salt); } }
// 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(); /// ====================== /// ====== 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 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(); }
// 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; }
// 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; }
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
// External Libraries
import {SafeTransferLib} from "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 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 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 {
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);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControlUpgradeable.sol";
import "../utils/ContextUpgradeable.sol";
import "../utils/StringsUpgradeable.sol";
import "../utils/introspection/ERC165Upgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
StringsUpgradeable.toHexString(account),
" is missing role ",
StringsUpgradeable.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControlUpgradeable {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/Clones.sol)
pragma solidity ^0.8.0;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*
* _Available since v3.4._
*/
library ClonesUpgradeable {
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(0, 0x09, 0x37)
}
require(instance != address(0), "ERC1167: create failed");
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(0, 0x09, 0x37, salt)
}
require(instance != address(0), "ERC1167: create2 failed");
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := keccak256(add(ptr, 0x43), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// 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 AddressUpgradeable {
/**
* @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);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165Upgradeable).interfaceId;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMathUpgradeable {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/MathUpgradeable.sol";
import "./math/SignedMathUpgradeable.sol";
/**
* @dev String operations.
*/
library StringsUpgradeable {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = MathUpgradeable.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, MathUpgradeable.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
/// @dev While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The caller is not authorized to call the function.
error Unauthorized();
/// @dev The `newOwner` cannot be the zero address.
error NewOwnerIsZeroAddress();
/// @dev The `pendingOwner` does not have a valid handover request.
error NoHandoverRequest();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ownership is transferred from `oldOwner` to `newOwner`.
/// This event is intentionally kept the same as OpenZeppelin's Ownable to be
/// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
/// despite it not being as lightweight as a single argument event.
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
/// @dev An ownership handover to `pendingOwner` has been requested.
event OwnershipHandoverRequested(address indexed pendingOwner);
/// @dev The ownership handover to `pendingOwner` has been canceled.
event OwnershipHandoverCanceled(address indexed pendingOwner);
/// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
/// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
/// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`.
/// It is intentionally chosen to be a high value
/// to avoid collision with lower slots.
/// The choice of manual storage layout is to enable compatibility
/// with both regular and upgradeable contracts.
uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8;
/// The ownership handover slot of `newOwner` is given by:
/// ```
/// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
/// let handoverSlot := keccak256(0x00, 0x20)
/// ```
/// It stores the expiry timestamp of the two-step ownership handover.
uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Initializes the owner directly without authorization guard.
/// This function must be called upon initialization,
/// regardless of whether the contract is upgradeable or not.
/// This is to enable generalization to both regular and upgradeable contracts,
/// and to save gas in case the initial owner is not the caller.
/// For performance reasons, this function will not check if there
/// is an existing owner.
function _initializeOwner(address newOwner) internal virtual {
/// @solidity memory-safe-assembly
assembly {
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(not(_OWNER_SLOT_NOT), newOwner)
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
}
/// @dev Sets the owner directly without authorization guard.
function _setOwner(address newOwner) internal virtual {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := not(_OWNER_SLOT_NOT)
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, newOwner)
}
}
/// @dev Throws if the sender is not the owner.
function _checkOwner() internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// If the caller is not the stored owner, revert.
if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Returns how long a two-step ownership handover is valid for in seconds.
/// Override to return a different value if needed.
/// Made internal to conserve bytecode. Wrap it in a public function if needed.
function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
return 48 * 3600;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC UPDATE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Allows the owner to transfer the ownership to `newOwner`.
function transferOwnership(address newOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
if iszero(shl(96, newOwner)) {
mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
revert(0x1c, 0x04)
}
}
_setOwner(newOwner);
}
/// @dev Allows the owner to renounce their ownership.
function renounceOwnership() public payable virtual onlyOwner {
_setOwner(address(0));
}
/// @dev Request a two-step ownership handover to the caller.
/// The request will automatically expire in 48 hours (172800 seconds) by default.
function requestOwnershipHandover() public payable virtual {
unchecked {
uint256 expires = block.timestamp + _ownershipHandoverValidFor();
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to `expires`.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), expires)
// Emit the {OwnershipHandoverRequested} event.
log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
}
}
}
/// @dev Cancels the two-step ownership handover to the caller, if any.
function cancelOwnershipHandover() public payable virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), 0)
// Emit the {OwnershipHandoverCanceled} event.
log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
}
}
/// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
/// Reverts if there is no existing ownership handover requested by `pendingOwner`.
function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
let handoverSlot := keccak256(0x0c, 0x20)
// If the handover does not exist, or has expired.
if gt(timestamp(), sload(handoverSlot)) {
mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
revert(0x1c, 0x04)
}
// Set the handover slot to 0.
sstore(handoverSlot, 0)
}
_setOwner(pendingOwner);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC READ FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the owner of the contract.
function owner() public view virtual returns (address result) {
/// @solidity memory-safe-assembly
assembly {
result := sload(not(_OWNER_SLOT_NOT))
}
}
/// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
function ownershipHandoverExpiresAt(address pendingOwner)
public
view
virtual
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
// Compute the handover slot.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
// Load the handover slot.
result := sload(keccak256(0x0c, 0x20))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MODIFIERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Marks a function as only callable by the owner.
modifier onlyOwner() virtual {
_checkOwner();
_;
}
}// 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, 0, 0, 0, 0)) {
// 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, 0, 0, 0, 0)) {
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(0, 0) }
}
}
}
}
/// @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, 0, 0, 0, 0)) {
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(0, 0) }
}
}
}
}
/// @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, 0, 0, 0, 0)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* 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` argument is already written to the memory word at 0x60.
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` argument is already written to the memory word at 0x34.
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 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)
)
)
}
}
}{
"optimizer": {
"enabled": true,
"runs": 400
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"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":"NOT_APPROVED_STRATEGY","type":"error"},{"inputs":[],"name":"NOT_ENOUGH_FUNDS","type":"error"},{"inputs":[],"name":"NOT_INITIALIZED","type":"error"},{"inputs":[],"name":"NOT_PENDING_OWNER","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","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_NOT_ACTIVE","type":"error"},{"inputs":[],"name":"UNAUTHORIZED","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZERO_ADDRESS","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BaseFeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"baseFee","type":"uint256"}],"name":"BaseFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"percentFee","type":"uint256"}],"name":"PercentFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"profileId","type":"bytes32"},{"indexed":false,"internalType":"contract IStrategy","name":"strategy","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"indexed":false,"internalType":"struct Metadata","name":"metadata","type":"tuple"}],"name":"PoolCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"PoolFunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolId","type":"uint256"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"indexed":false,"internalType":"struct Metadata","name":"metadata","type":"tuple"}],"name":"PoolMetadataUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"registry","type":"address"}],"name":"RegistryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"treasury","type":"address"}],"name":"TreasuryUpdated","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"address","name":"_manager","type":"address"}],"name":"addPoolManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"addToCloneableStrategies","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"allocate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_poolIds","type":"uint256[]"},{"internalType":"bytes[]","name":"_datas","type":"bytes[]"}],"name":"batchAllocate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_poolIds","type":"uint256[]"},{"internalType":"bytes[]","name":"_data","type":"bytes[]"}],"name":"batchRegisterRecipient","outputs":[{"internalType":"address[]","name":"recipientIds","type":"address[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_profileId","type":"bytes32"},{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"bytes","name":"_initStrategyData","type":"bytes"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"internalType":"struct Metadata","name":"_metadata","type":"tuple"},{"internalType":"address[]","name":"_managers","type":"address[]"}],"name":"createPool","outputs":[{"internalType":"uint256","name":"poolId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_profileId","type":"bytes32"},{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"bytes","name":"_initStrategyData","type":"bytes"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"internalType":"struct Metadata","name":"_metadata","type":"tuple"},{"internalType":"address[]","name":"_managers","type":"address[]"}],"name":"createPoolWithCustomStrategy","outputs":[{"internalType":"uint256","name":"poolId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"address[]","name":"_recipientIds","type":"address[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"distribute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"fundPool","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getBaseFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeeDenominator","outputs":[{"internalType":"uint256","name":"FEE_DENOMINATOR","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getPercentFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"}],"name":"getPool","outputs":[{"components":[{"internalType":"bytes32","name":"profileId","type":"bytes32"},{"internalType":"contract IStrategy","name":"strategy","type":"address"},{"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"internalType":"struct Metadata","name":"metadata","type":"tuple"},{"internalType":"bytes32","name":"managerRole","type":"bytes32"},{"internalType":"bytes32","name":"adminRole","type":"bytes32"}],"internalType":"struct IAllo.Pool","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRegistry","outputs":[{"internalType":"contract IRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"}],"name":"getStrategy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTreasury","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_registry","type":"address"},{"internalType":"address payable","name":"_treasury","type":"address"},{"internalType":"uint256","name":"_percentFee","type":"uint256"},{"internalType":"uint256","name":"_baseFee","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"isCloneableStrategy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"address","name":"_address","type":"address"}],"name":"isPoolAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"address","name":"_address","type":"address"}],"name":"isPoolManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"recoverFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"registerRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"removeFromCloneableStrategies","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"address","name":"_manager","type":"address"}],"name":"removePoolManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_baseFee","type":"uint256"}],"name":"updateBaseFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_percentFee","type":"uint256"}],"name":"updatePercentFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"internalType":"struct Metadata","name":"_metadata","type":"tuple"}],"name":"updatePoolMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_registry","type":"address"}],"name":"updateRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_treasury","type":"address"}],"name":"updateTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b5061331a806100206000396000f3fe6080604052600436106102a75760003560e01c80635f9ca13811610164578063ab2ec589116100c6578063e1007d4a1161008a578063f4e1fc4111610064578063f4e1fc41146107a7578063f54fc4a0146107c2578063fee81cf4146107e257600080fd5b8063e1007d4a1461076e578063f04e283e14610781578063f2fde38b1461079457600080fd5b8063ab2ec589146106b5578063ab3febc6146106d5578063c6dff1cf146106f5578063cfc0cc3414610715578063d547741f1461074e57600080fd5b80638da5cb5b11610128578063a0cf0aea11610102578063a0cf0aea14610658578063a217fddf14610680578063a6b63eb81461069557600080fd5b80638da5cb5b146105d95780638e690186146105f257806391d148541461061257600080fd5b80635f9ca1381461055e578063715018a61461057e57806377da8caf146105865780637f51bb1f146105995780637f5a70bd146105b957600080fd5b80632cf682b01161020d5780633b19e84a116101d157806354d1f13d116101ab57806354d1f13d146105255780635ab1bd531461052d5780635acd6fac1461054b57600080fd5b80633b19e84a146104d257806341bba0b4146104f05780634edbaadc1461051057600080fd5b80632cf682b01461043f5780632ec381881461045f5780632f2ff15d1461047257806336568abe146104925780633a5fbd92146104b257600080fd5b80631a20bd881161026f57806324ae6a271161024957806324ae6a27146103f7578063256929621461041757806329e40d4b1461041f57600080fd5b80631a20bd881461037a5780631a5da6c8146103a7578063248a9ca3146103c757600080fd5b806301ffc9a7146102ac578063031e2fa1146102e1578063068bcd8d14610303578063075c0e9c1461033057806315e812ad1461035b575b600080fd5b3480156102b857600080fd5b506102cc6102c736600461275a565b610815565b60405190151581526020015b60405180910390f35b3480156102ed57600080fd5b506103016102fc366004612799565b61084c565b005b34801561030f57600080fd5b5061032361031e3660046127b6565b6108ac565b6040516102d8919061283e565b61034361033e366004612966565b6109bf565b6040516001600160a01b0390911681526020016102d8565b34801561036757600080fd5b5060ca545b6040519081526020016102d8565b34801561038657600080fd5b5061039a610395366004612a61565b610a5c565b6040516102d89190612b54565b3480156103b357600080fd5b506103016103c2366004612799565b610be3565b3480156103d357600080fd5b5061036c6103e23660046127b6565b60009081526065602052604090206001015490565b34801561040357600080fd5b50610301610412366004612b67565b610bf7565b610301610ca6565b34801561042b57600080fd5b506102cc61043a366004612ba0565b610cf6565b34801561044b57600080fd5b5061030161045a366004612ba0565b610d09565b61030161046d366004612966565b610d56565b34801561047e57600080fd5b5061030161048d366004612ba0565b610d76565b34801561049e57600080fd5b506103016104ad366004612ba0565b610d9b565b3480156104be57600080fd5b506103016104cd366004612c29565b610e1a565b3480156104de57600080fd5b5060cc546001600160a01b0316610343565b3480156104fc57600080fd5b5061030161050b366004612799565b610ea2565b34801561051c57600080fd5b5060c95461036c565b610301610f25565b34801561053957600080fd5b5060cd546001600160a01b0316610343565b610301610559366004612c96565b610f61565b34801561056a57600080fd5b50610301610579366004612d3b565b6110f8565b610301611175565b61036c610594366004612d78565b611189565b3480156105a557600080fd5b506103016105b4366004612799565b61121f565b3480156105c557600080fd5b506103016105d4366004612ba0565b611230565b3480156105e557600080fd5b50638b78c6d81954610343565b3480156105fe57600080fd5b5061030161060d3660046127b6565b611256565b34801561061e57600080fd5b506102cc61062d366004612ba0565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561066457600080fd5b5061034373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b34801561068c57600080fd5b5061036c600081565b3480156106a157600080fd5b506103016106b0366004612e3b565b611267565b3480156106c157600080fd5b506102cc6106d0366004612799565b611376565b3480156106e157600080fd5b506102cc6106f0366004612ba0565b611397565b34801561070157600080fd5b50610301610710366004612e96565b6113a3565b34801561072157600080fd5b506103436107303660046127b6565b600090815260cf60205260409020600101546001600160a01b031690565b34801561075a57600080fd5b50610301610769366004612ba0565b611428565b61036c61077c366004612d78565b61144d565b61030161078f366004612799565b6114cb565b6103016107a2366004612799565b611508565b3480156107b357600080fd5b50670de0b6b3a764000061036c565b3480156107ce57600080fd5b506103016107dd3660046127b6565b61152f565b3480156107ee57600080fd5b5061036c6107fd366004612799565b63389a75e1600c908152600091909152602090205490565b60006001600160e01b03198216637965db0b60e01b148061084657506301ffc9a760e01b6001600160e01b03198316145b92915050565b610854611540565b6001600160a01b038116600081815260d06020908152604091829020805460ff1916905590519182527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea491015b60405180910390a150565b6108b46126f4565b600082815260cf6020908152604091829020825160c0810184528154815260018201546001600160a01b0390811682850152600283015416818501528351808501909452600382018054855260048301805492959394606087019493908401919061091e90612f23565b80601f016020809104026020016040519081016040528092919081815260200182805461094a90612f23565b80156109975780601f1061096c57610100808354040283529160200191610997565b820191906000526020600020905b81548152906001019060200180831161097a57829003601f168201915b5050505050815250508152602001600582015481526020016006820154815250509050919050565b60006109c961155b565b600083815260cf6020526040908190206001015490516315df065760e11b81526001600160a01b0390911690632bbe0cae903490610a0d9086903390600401612f5d565b60206040518083038185885af1158015610a2b573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610a509190612f88565b90506108466001609755565b6060610a6661155b565b82518067ffffffffffffffff811115610a8157610a816128a7565b604051908082528060200260200182016040528015610aaa578160200160208202803683370190505b50915082518114610ace5760405163636e39bb60e01b815260040160405180910390fd5b60005b81811015610bd75760cf6000868381518110610aef57610aef612fa5565b6020026020010151815260200190815260200160002060010160009054906101000a90046001600160a01b03166001600160a01b0316632bbe0cae858381518110610b3c57610b3c612fa5565b6020026020010151336040518363ffffffff1660e01b8152600401610b62929190612f5d565b6020604051808303816000875af1158015610b81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba59190612f88565b838281518110610bb757610bb7612fa5565b6001600160a01b0390921660209283029190910190910152600101610ad1565b50506108466001609755565b610beb611540565b610bf4816115b4565b50565b610bff611540565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610c92576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610c69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c8d9190612fbb565b610c94565b475b9050610ca1838383611629565b505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b6000610d028383611663565b9392505050565b81610d13816116a6565b6001600160a01b038216610d3a5760405163538ba4f960e01b815260040160405180910390fd5b600083815260cf6020526040902060050154610ca190836116cd565b610d5e61155b565b610d68828261176f565b610d726001609755565b5050565b600082815260656020526040902060010154610d91816117e9565b610ca183836116cd565b6001600160a01b0381163314610e105760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610d7282826117f3565b610e2261155b565b600083815260cf602052604090819020600101549051630a6f0ee960e01b81526001600160a01b0390911690630a6f0ee990610e6690859085903390600401612fd4565b600060405180830381600087803b158015610e8057600080fd5b505af1158015610e94573d6000803e3d6000fd5b50505050610ca16001609755565b610eaa611540565b6001600160a01b038116610ed15760405163538ba4f960e01b815260040160405180910390fd5b6001600160a01b038116600081815260d06020908152604091829020805460ff1916600117905590519182527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d191016108a1565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610f6961155b565b80600003610f8a576040516303e09bb960e31b815260040160405180910390fd5b600082815260cf60209081526040808320815160c0810183528154815260018201546001600160a01b0390811682860152600283015416818401528251808401909352600382018054845260048301805492959394606087019490939084019190610ff490612f23565b80601f016020809104026020016040519081016040528092919081815260200182805461102090612f23565b801561106d5780601f106110425761010080835404028352916020019161106d565b820191906000526020600020905b81548152906001019060200180831161105057829003601f168201915b505050919092525050508152600582015460208201526006909101546040918201528101519091506001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480156110c05750348214155b156110de576040516303e09bb960e31b815260040160405180910390fd5b6110ed82848360200151611876565b50610d726001609755565b8161110281611b28565b600083815260cf60209081526040909120835160038201908155918401519091849160048401906111339082613061565b50905050837f14f52b76bda9e4c482842cefda2968d332933577988f224e80aae18fba10edf0846040516111679190613121565b60405180910390a250505050565b61117d611540565b6111876000611b32565b565b600061119361155b565b6001600160a01b038716600090815260d0602052604090205460ff166111cc5760405163126d324760e31b815260040160405180910390fd5b33600090815260ce602052604081208054611208928b926111fe928c929091906111f58361314a565b91905055611b70565b8888888888611bc4565b90506112146001609755565b979650505050505050565b611227611540565b610bf4816120a8565b8161123a816116a6565b600083815260cf6020526040902060050154610ca190836117f3565b61125e611540565b610bf48161211d565b600054600190610100900460ff16158015611289575060005460ff8083169116105b6112ec5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610e07565b6000805461ffff191660ff83161761010017905561130986612152565b611312856115b4565b61131b846120a8565b6113248361218e565b61132d8261211d565b6000805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6001600160a01b038116600090815260d0602052604081205460ff16610846565b6000610d0283836121ec565b6113ab61155b565b8051829081146113ce5760405163636e39bb60e01b815260040160405180910390fd5b60005b8181101561141c576114148585838181106113ee576113ee612fa5565b9050602002013584838151811061140757611407612fa5565b602002602001015161176f565b6001016113d1565b5050610ca16001609755565b600082815260656020526040902060010154611443816117e9565b610ca183836117f3565b60006001600160a01b0387166114765760405163538ba4f960e01b815260040160405180910390fd5b6001600160a01b038716600090815260d0602052604090205460ff16156114b05760405163eeffa72160e01b815260040160405180910390fd5b6114bf88888888888888611bc4565b98975050505050505050565b6114d3611540565b63389a75e1600c52806000526020600c2080544211156114fb57636f5e88186000526004601cfd5b60009055610bf481611b32565b611510611540565b8060601b61152657637448fbae6000526004601cfd5b610bf481611b32565b611537611540565b610bf48161218e565b638b78c6d819543314611187576382b429006000526004601cfd5b6002609754036115ad5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e07565b6002609755565b6001600160a01b0381166115db5760405163538ba4f960e01b815260040160405180910390fd5b60cd80546001600160a01b0319166001600160a01b0383169081179091556040519081527fd6ceddf6d2a22f21c7c81675c518004eff43bc5c8a6fc32a0b748e69d58671cd906020016108a1565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0384160161165857610ca18282612224565b610ca1838383612240565b600082815260cf60209081526040808320600501548352606582528083206001600160a01b038516845290915281205460ff1680610d025750610d0283836121ec565b6116b081336121ec565b610bf45760405163075fd2b160e01b815260040160405180910390fd5b60008281526065602090815260408083206001600160a01b038516845290915290205460ff16610d725760008281526065602090815260408083206001600160a01b03851684529091529020805460ff1916600117905561172b3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600082815260cf602052604090819020600101549051633bca483f60e21b81526001600160a01b039091169063ef2920fc9034906117b39085903390600401612f5d565b6000604051808303818588803b1580156117cc57600080fd5b505af11580156117e0573d6000803e3d6000fd5b50505050505050565b610bf4813361228f565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff1615610d725760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600082815260cf60205260408120600281015460c9548692916001600160a01b031690156119c757670de0b6b3a764000060c9546118b49089613163565b6118be919061317a565b93506118ca848461319c565b9250866118d784866131af565b146118f557604051637fcce2a960e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0382160161194f576040805160608101825233815260cc546001600160a01b03166020820152908101859052611949908290612304565b506119c7565b60cc546000906119699083906001600160a01b0316612383565b6040805160608101825233815260cc546001600160a01b0316602082015290810187905290915061199b908390612304565b5060cc546000906119b69084906001600160a01b0316612383565b90506119c2828261319c565b955050505b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601611a2857611a22816040518060600160405280336001600160a01b03168152602001886001600160a01b0316815260200186815250612304565b50611a8a565b6000611a348287612383565b9050611a6c826040518060600160405280336001600160a01b03168152602001896001600160a01b0316815260200187815250612304565b506000611a798388612383565b9050611a85828261319c565b945050505b60405163f5b0dfb760e01b8152600481018490526001600160a01b0386169063f5b0dfb790602401600060405180830381600087803b158015611acc57600080fd5b505af1158015611ae0573d6000803e3d6000fd5b505060408051868152602081018890528993507fbf59838198f4ea92f663f5c1fc697f151a1b746b7dff86d564f250a55cbb485192500160405180910390a250505050505050565b6116b08133611663565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b6040516bffffffffffffffffffffffff193360601b166020820152603481018290526000908190605401604051602081830303815290604052805190602001209050611bbc84826123cc565b949350505050565b60cd54604051635e8a791560e01b8152600481018990523360248201526000916001600160a01b031690635e8a791590604401602060405180830381865afa158015611c14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3891906131c2565b611c555760405163075fd2b160e01b815260040160405180910390fd5b60cb60008154611c649061314a565b91829055506040519091508190600090611c949083906020019081526430b236b4b760d91b602082015260250190565b60408051601f19818403018152828252805160209182012060c0840183528d84526001600160a01b03808e168584019081528c8216868601908152606087018c8152608088018a905260a0880185905260008b815260cf8752969096208751815591516001830180549185166001600160a01b031992831617905590516002830180549190941691161790915592518051600385019081559281015191955084939290916004840190611d479082613061565b5050506080820151600582015560a090910151600690910155611d6a82336116cd565b611d748383612469565b604051633b7451b360e21b81526001600160a01b038b169063edd146cc90611da29087908d906004016131e4565b600060405180830381600087803b158015611dbc57600080fd5b505af1158015611dd0573d6000803e3d6000fd5b50505050838a6001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e379190612fbb565b141580611eb75750306001600160a01b03168a6001600160a01b03166315cc481e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eab9190612f88565b6001600160a01b031614155b15611ed55760405163636e39bb60e01b815260040160405180910390fd5b845160005b81811015611f46576000878281518110611ef657611ef6612fa5565b6020026020010151905060006001600160a01b0316816001600160a01b031603611f335760405163538ba4f960e01b815260040160405180910390fd5b611f3d86826116cd565b50600101611eda565b5060ca5415612049576001600160a01b03891673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015611f885750348860ca54611f8591906131af565b14155b80611fbd57506001600160a01b03891673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14801590611fbd57503460ca5414155b15611fdb576040516303e09bb960e31b815260040160405180910390fd5b60cc5460ca5461200c9173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee916001600160a01b0390911690611629565b847f02e340b51c6ae66fd22509c9b016f224c47a54063d4259fe3d860958e9eaac7260ca5460405161204091815260200190565b60405180910390a25b871561205a5761205a88868d611876565b8b857f69bcb5a6cf6a3c95185cbb451e77787240c866dd2e8332597e3013ff18a1aba18d8c8c8c60405161209194939291906131fd565b60405180910390a350505050979650505050505050565b6001600160a01b0381166120cf5760405163538ba4f960e01b815260040160405180910390fd5b60cc80546001600160a01b0319166001600160a01b0383169081179091556040519081527f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d1906020016108a1565b60ca8190556040518181527f803bee7e92bbc6ae7a1551f9f4ed3e31a8ea8df32e93332f41b0028f1091f9c3906020016108a1565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b670de0b6b3a76400008111156121b757604051632fb15b8760e01b815260040160405180910390fd5b60c98190556040518181527f9e826789de2de708fd9f09edea1182545e543893caa8ff71f8eb3aab50a4b065906020016108a1565b600082815260cf60209081526040808320600601548352606582528083206001600160a01b038516845290915281205460ff16610d02565b60008060008084865af1610d725763b12d13eb6000526004601cfd5b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d156001600051141716612285576390b8ec186000526004601cfd5b6000603452505050565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff16610d72576122c2816124b4565b6122cd8360206124c6565b6040516020016122de929190613239565b60408051601f198184030181529082905262461bcd60e51b8252610e07916004016132ba565b604081015160009073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038516016123655780341015612352576040516374c5672b60e01b815260040160405180910390fd5b612360836020015182612224565b612379565b612379848460000151856020015184612662565b5060019392505050565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038416016123bb57506001600160a01b03811631610846565b6123c583836126bf565b9050610846565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b0381166108465760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401610e07565b600082815260656020526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b60606108466001600160a01b03831660145b606060006124d5836002613163565b6124e09060026131af565b67ffffffffffffffff8111156124f8576124f86128a7565b6040519080825280601f01601f191660200182016040528015612522576020820181803683370190505b509050600360fc1b8160008151811061253d5761253d612fa5565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061256c5761256c612fa5565b60200101906001600160f81b031916908160001a9053506000612590846002613163565b61259b9060016131af565b90505b6001811115612613576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106125cf576125cf612fa5565b1a60f81b8282815181106125e5576125e5612fa5565b60200101906001600160f81b031916908160001a90535060049490941c9361260c816132cd565b905061259e565b508315610d025760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610e07565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c52602060006064601c6000895af13d1560016000511417166126b157637939f4246000526004601cfd5b600060605260405250505050565b6000816014526f70a0823100000000000000000000000060005260208060246010865afa601f3d111660205102905092915050565b6040518060c001604052806000801916815260200160006001600160a01b0316815260200160006001600160a01b03168152602001612746604051806040016040528060008152602001606081525090565b815260006020820181905260409091015290565b60006020828403121561276c57600080fd5b81356001600160e01b031981168114610d0257600080fd5b6001600160a01b0381168114610bf457600080fd5b6000602082840312156127ab57600080fd5b8135610d0281612784565b6000602082840312156127c857600080fd5b5035919050565b60005b838110156127ea5781810151838201526020016127d2565b50506000910152565b6000815180845261280b8160208601602086016127cf565b601f01601f19169290920160200192915050565b805182526000602082015160406020850152611bbc60408501826127f3565b6020815281516020820152600060208301516001600160a01b0380821660408501528060408601511660608501525050606083015160c0608084015261288760e084018261281f565b9050608084015160a084015260a084015160c08401528091505092915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156128e6576128e66128a7565b604052919050565b600067ffffffffffffffff831115612908576129086128a7565b61291b601f8401601f19166020016128bd565b905082815283838301111561292f57600080fd5b828260208301376000602084830101529392505050565b600082601f83011261295757600080fd5b610d02838335602085016128ee565b6000806040838503121561297957600080fd5b82359150602083013567ffffffffffffffff81111561299757600080fd5b6129a385828601612946565b9150509250929050565b600067ffffffffffffffff8211156129c7576129c76128a7565b5060051b60200190565b600082601f8301126129e257600080fd5b813560206129f76129f2836129ad565b6128bd565b82815260059290921b84018101918181019086841115612a1657600080fd5b8286015b84811015612a5657803567ffffffffffffffff811115612a3a5760008081fd5b612a488986838b0101612946565b845250918301918301612a1a565b509695505050505050565b60008060408385031215612a7457600080fd5b823567ffffffffffffffff80821115612a8c57600080fd5b818501915085601f830112612aa057600080fd5b81356020612ab06129f2836129ad565b82815260059290921b84018101918181019089841115612acf57600080fd5b948201945b83861015612aed57853582529482019490820190612ad4565b96505086013592505080821115612b0357600080fd5b506129a3858286016129d1565b600081518084526020808501945080840160005b83811015612b495781516001600160a01b031687529582019590820190600101612b24565b509495945050505050565b602081526000610d026020830184612b10565b60008060408385031215612b7a57600080fd5b8235612b8581612784565b91506020830135612b9581612784565b809150509250929050565b60008060408385031215612bb357600080fd5b823591506020830135612b9581612784565b600082601f830112612bd657600080fd5b81356020612be66129f2836129ad565b82815260059290921b84018101918181019086841115612c0557600080fd5b8286015b84811015612a56578035612c1c81612784565b8352918301918301612c09565b600080600060608486031215612c3e57600080fd5b83359250602084013567ffffffffffffffff80821115612c5d57600080fd5b612c6987838801612bc5565b93506040860135915080821115612c7f57600080fd5b50612c8c86828701612946565b9150509250925092565b60008060408385031215612ca957600080fd5b50508035926020909101359150565b600060408284031215612cca57600080fd5b6040516040810167ffffffffffffffff8282108183111715612cee57612cee6128a7565b81604052829350843583526020850135915080821115612d0d57600080fd5b508301601f81018513612d1f57600080fd5b612d2e858235602084016128ee565b6020830152505092915050565b60008060408385031215612d4e57600080fd5b82359150602083013567ffffffffffffffff811115612d6c57600080fd5b6129a385828601612cb8565b600080600080600080600060e0888a031215612d9357600080fd5b873596506020880135612da581612784565b9550604088013567ffffffffffffffff80821115612dc257600080fd5b612dce8b838c01612946565b965060608a01359150612de082612784565b9094506080890135935060a08901359080821115612dfd57600080fd5b612e098b838c01612cb8565b935060c08a0135915080821115612e1f57600080fd5b50612e2c8a828b01612bc5565b91505092959891949750929550565b600080600080600060a08688031215612e5357600080fd5b8535612e5e81612784565b94506020860135612e6e81612784565b93506040860135612e7e81612784565b94979396509394606081013594506080013592915050565b600080600060408486031215612eab57600080fd5b833567ffffffffffffffff80821115612ec357600080fd5b818601915086601f830112612ed757600080fd5b813581811115612ee657600080fd5b8760208260051b8501011115612efb57600080fd5b602092830195509350908501359080821115612f1657600080fd5b50612c8c868287016129d1565b600181811c90821680612f3757607f821691505b602082108103612f5757634e487b7160e01b600052602260045260246000fd5b50919050565b604081526000612f7060408301856127f3565b90506001600160a01b03831660208301529392505050565b600060208284031215612f9a57600080fd5b8151610d0281612784565b634e487b7160e01b600052603260045260246000fd5b600060208284031215612fcd57600080fd5b5051919050565b606081526000612fe76060830186612b10565b8281036020840152612ff981866127f3565b9150506001600160a01b0383166040830152949350505050565b601f821115610ca157600081815260208120601f850160051c8101602086101561303a5750805b601f850160051c820191505b8181101561305957828155600101613046565b505050505050565b815167ffffffffffffffff81111561307b5761307b6128a7565b61308f816130898454612f23565b84613013565b602080601f8311600181146130c457600084156130ac5750858301515b600019600386901b1c1916600185901b178555613059565b600085815260208120601f198616915b828110156130f3578886015182559484019460019091019084016130d4565b50858210156131115787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b602081526000610d02602083018461281f565b634e487b7160e01b600052601160045260246000fd5b60006001820161315c5761315c613134565b5060010190565b808202811582820484141761084657610846613134565b60008261319757634e487b7160e01b600052601260045260246000fd5b500490565b8181038181111561084657610846613134565b8082018082111561084657610846613134565b6000602082840312156131d457600080fd5b81518015158114610d0257600080fd5b828152604060208201526000611bbc60408301846127f3565b60006001600160a01b0380871683528086166020840152508360408301526080606083015261322f608083018461281f565b9695505050505050565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516132718160178501602088016127cf565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516132ae8160288401602088016127cf565b01602801949350505050565b602081526000610d0260208301846127f3565b6000816132dc576132dc613134565b50600019019056fea2646970667358221220c524dca189879d6356e6617edf44bf49f1a7582c373aeecaaf9075174ab0fe1c64736f6c63430008130033
Deployed Bytecode
0x6080604052600436106102a75760003560e01c80635f9ca13811610164578063ab2ec589116100c6578063e1007d4a1161008a578063f4e1fc4111610064578063f4e1fc41146107a7578063f54fc4a0146107c2578063fee81cf4146107e257600080fd5b8063e1007d4a1461076e578063f04e283e14610781578063f2fde38b1461079457600080fd5b8063ab2ec589146106b5578063ab3febc6146106d5578063c6dff1cf146106f5578063cfc0cc3414610715578063d547741f1461074e57600080fd5b80638da5cb5b11610128578063a0cf0aea11610102578063a0cf0aea14610658578063a217fddf14610680578063a6b63eb81461069557600080fd5b80638da5cb5b146105d95780638e690186146105f257806391d148541461061257600080fd5b80635f9ca1381461055e578063715018a61461057e57806377da8caf146105865780637f51bb1f146105995780637f5a70bd146105b957600080fd5b80632cf682b01161020d5780633b19e84a116101d157806354d1f13d116101ab57806354d1f13d146105255780635ab1bd531461052d5780635acd6fac1461054b57600080fd5b80633b19e84a146104d257806341bba0b4146104f05780634edbaadc1461051057600080fd5b80632cf682b01461043f5780632ec381881461045f5780632f2ff15d1461047257806336568abe146104925780633a5fbd92146104b257600080fd5b80631a20bd881161026f57806324ae6a271161024957806324ae6a27146103f7578063256929621461041757806329e40d4b1461041f57600080fd5b80631a20bd881461037a5780631a5da6c8146103a7578063248a9ca3146103c757600080fd5b806301ffc9a7146102ac578063031e2fa1146102e1578063068bcd8d14610303578063075c0e9c1461033057806315e812ad1461035b575b600080fd5b3480156102b857600080fd5b506102cc6102c736600461275a565b610815565b60405190151581526020015b60405180910390f35b3480156102ed57600080fd5b506103016102fc366004612799565b61084c565b005b34801561030f57600080fd5b5061032361031e3660046127b6565b6108ac565b6040516102d8919061283e565b61034361033e366004612966565b6109bf565b6040516001600160a01b0390911681526020016102d8565b34801561036757600080fd5b5060ca545b6040519081526020016102d8565b34801561038657600080fd5b5061039a610395366004612a61565b610a5c565b6040516102d89190612b54565b3480156103b357600080fd5b506103016103c2366004612799565b610be3565b3480156103d357600080fd5b5061036c6103e23660046127b6565b60009081526065602052604090206001015490565b34801561040357600080fd5b50610301610412366004612b67565b610bf7565b610301610ca6565b34801561042b57600080fd5b506102cc61043a366004612ba0565b610cf6565b34801561044b57600080fd5b5061030161045a366004612ba0565b610d09565b61030161046d366004612966565b610d56565b34801561047e57600080fd5b5061030161048d366004612ba0565b610d76565b34801561049e57600080fd5b506103016104ad366004612ba0565b610d9b565b3480156104be57600080fd5b506103016104cd366004612c29565b610e1a565b3480156104de57600080fd5b5060cc546001600160a01b0316610343565b3480156104fc57600080fd5b5061030161050b366004612799565b610ea2565b34801561051c57600080fd5b5060c95461036c565b610301610f25565b34801561053957600080fd5b5060cd546001600160a01b0316610343565b610301610559366004612c96565b610f61565b34801561056a57600080fd5b50610301610579366004612d3b565b6110f8565b610301611175565b61036c610594366004612d78565b611189565b3480156105a557600080fd5b506103016105b4366004612799565b61121f565b3480156105c557600080fd5b506103016105d4366004612ba0565b611230565b3480156105e557600080fd5b50638b78c6d81954610343565b3480156105fe57600080fd5b5061030161060d3660046127b6565b611256565b34801561061e57600080fd5b506102cc61062d366004612ba0565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561066457600080fd5b5061034373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b34801561068c57600080fd5b5061036c600081565b3480156106a157600080fd5b506103016106b0366004612e3b565b611267565b3480156106c157600080fd5b506102cc6106d0366004612799565b611376565b3480156106e157600080fd5b506102cc6106f0366004612ba0565b611397565b34801561070157600080fd5b50610301610710366004612e96565b6113a3565b34801561072157600080fd5b506103436107303660046127b6565b600090815260cf60205260409020600101546001600160a01b031690565b34801561075a57600080fd5b50610301610769366004612ba0565b611428565b61036c61077c366004612d78565b61144d565b61030161078f366004612799565b6114cb565b6103016107a2366004612799565b611508565b3480156107b357600080fd5b50670de0b6b3a764000061036c565b3480156107ce57600080fd5b506103016107dd3660046127b6565b61152f565b3480156107ee57600080fd5b5061036c6107fd366004612799565b63389a75e1600c908152600091909152602090205490565b60006001600160e01b03198216637965db0b60e01b148061084657506301ffc9a760e01b6001600160e01b03198316145b92915050565b610854611540565b6001600160a01b038116600081815260d06020908152604091829020805460ff1916905590519182527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea491015b60405180910390a150565b6108b46126f4565b600082815260cf6020908152604091829020825160c0810184528154815260018201546001600160a01b0390811682850152600283015416818501528351808501909452600382018054855260048301805492959394606087019493908401919061091e90612f23565b80601f016020809104026020016040519081016040528092919081815260200182805461094a90612f23565b80156109975780601f1061096c57610100808354040283529160200191610997565b820191906000526020600020905b81548152906001019060200180831161097a57829003601f168201915b5050505050815250508152602001600582015481526020016006820154815250509050919050565b60006109c961155b565b600083815260cf6020526040908190206001015490516315df065760e11b81526001600160a01b0390911690632bbe0cae903490610a0d9086903390600401612f5d565b60206040518083038185885af1158015610a2b573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610a509190612f88565b90506108466001609755565b6060610a6661155b565b82518067ffffffffffffffff811115610a8157610a816128a7565b604051908082528060200260200182016040528015610aaa578160200160208202803683370190505b50915082518114610ace5760405163636e39bb60e01b815260040160405180910390fd5b60005b81811015610bd75760cf6000868381518110610aef57610aef612fa5565b6020026020010151815260200190815260200160002060010160009054906101000a90046001600160a01b03166001600160a01b0316632bbe0cae858381518110610b3c57610b3c612fa5565b6020026020010151336040518363ffffffff1660e01b8152600401610b62929190612f5d565b6020604051808303816000875af1158015610b81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba59190612f88565b838281518110610bb757610bb7612fa5565b6001600160a01b0390921660209283029190910190910152600101610ad1565b50506108466001609755565b610beb611540565b610bf4816115b4565b50565b610bff611540565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610c92576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610c69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c8d9190612fbb565b610c94565b475b9050610ca1838383611629565b505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b6000610d028383611663565b9392505050565b81610d13816116a6565b6001600160a01b038216610d3a5760405163538ba4f960e01b815260040160405180910390fd5b600083815260cf6020526040902060050154610ca190836116cd565b610d5e61155b565b610d68828261176f565b610d726001609755565b5050565b600082815260656020526040902060010154610d91816117e9565b610ca183836116cd565b6001600160a01b0381163314610e105760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610d7282826117f3565b610e2261155b565b600083815260cf602052604090819020600101549051630a6f0ee960e01b81526001600160a01b0390911690630a6f0ee990610e6690859085903390600401612fd4565b600060405180830381600087803b158015610e8057600080fd5b505af1158015610e94573d6000803e3d6000fd5b50505050610ca16001609755565b610eaa611540565b6001600160a01b038116610ed15760405163538ba4f960e01b815260040160405180910390fd5b6001600160a01b038116600081815260d06020908152604091829020805460ff1916600117905590519182527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d191016108a1565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610f6961155b565b80600003610f8a576040516303e09bb960e31b815260040160405180910390fd5b600082815260cf60209081526040808320815160c0810183528154815260018201546001600160a01b0390811682860152600283015416818401528251808401909352600382018054845260048301805492959394606087019490939084019190610ff490612f23565b80601f016020809104026020016040519081016040528092919081815260200182805461102090612f23565b801561106d5780601f106110425761010080835404028352916020019161106d565b820191906000526020600020905b81548152906001019060200180831161105057829003601f168201915b505050919092525050508152600582015460208201526006909101546040918201528101519091506001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480156110c05750348214155b156110de576040516303e09bb960e31b815260040160405180910390fd5b6110ed82848360200151611876565b50610d726001609755565b8161110281611b28565b600083815260cf60209081526040909120835160038201908155918401519091849160048401906111339082613061565b50905050837f14f52b76bda9e4c482842cefda2968d332933577988f224e80aae18fba10edf0846040516111679190613121565b60405180910390a250505050565b61117d611540565b6111876000611b32565b565b600061119361155b565b6001600160a01b038716600090815260d0602052604090205460ff166111cc5760405163126d324760e31b815260040160405180910390fd5b33600090815260ce602052604081208054611208928b926111fe928c929091906111f58361314a565b91905055611b70565b8888888888611bc4565b90506112146001609755565b979650505050505050565b611227611540565b610bf4816120a8565b8161123a816116a6565b600083815260cf6020526040902060050154610ca190836117f3565b61125e611540565b610bf48161211d565b600054600190610100900460ff16158015611289575060005460ff8083169116105b6112ec5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610e07565b6000805461ffff191660ff83161761010017905561130986612152565b611312856115b4565b61131b846120a8565b6113248361218e565b61132d8261211d565b6000805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6001600160a01b038116600090815260d0602052604081205460ff16610846565b6000610d0283836121ec565b6113ab61155b565b8051829081146113ce5760405163636e39bb60e01b815260040160405180910390fd5b60005b8181101561141c576114148585838181106113ee576113ee612fa5565b9050602002013584838151811061140757611407612fa5565b602002602001015161176f565b6001016113d1565b5050610ca16001609755565b600082815260656020526040902060010154611443816117e9565b610ca183836117f3565b60006001600160a01b0387166114765760405163538ba4f960e01b815260040160405180910390fd5b6001600160a01b038716600090815260d0602052604090205460ff16156114b05760405163eeffa72160e01b815260040160405180910390fd5b6114bf88888888888888611bc4565b98975050505050505050565b6114d3611540565b63389a75e1600c52806000526020600c2080544211156114fb57636f5e88186000526004601cfd5b60009055610bf481611b32565b611510611540565b8060601b61152657637448fbae6000526004601cfd5b610bf481611b32565b611537611540565b610bf48161218e565b638b78c6d819543314611187576382b429006000526004601cfd5b6002609754036115ad5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e07565b6002609755565b6001600160a01b0381166115db5760405163538ba4f960e01b815260040160405180910390fd5b60cd80546001600160a01b0319166001600160a01b0383169081179091556040519081527fd6ceddf6d2a22f21c7c81675c518004eff43bc5c8a6fc32a0b748e69d58671cd906020016108a1565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0384160161165857610ca18282612224565b610ca1838383612240565b600082815260cf60209081526040808320600501548352606582528083206001600160a01b038516845290915281205460ff1680610d025750610d0283836121ec565b6116b081336121ec565b610bf45760405163075fd2b160e01b815260040160405180910390fd5b60008281526065602090815260408083206001600160a01b038516845290915290205460ff16610d725760008281526065602090815260408083206001600160a01b03851684529091529020805460ff1916600117905561172b3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600082815260cf602052604090819020600101549051633bca483f60e21b81526001600160a01b039091169063ef2920fc9034906117b39085903390600401612f5d565b6000604051808303818588803b1580156117cc57600080fd5b505af11580156117e0573d6000803e3d6000fd5b50505050505050565b610bf4813361228f565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff1615610d725760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600082815260cf60205260408120600281015460c9548692916001600160a01b031690156119c757670de0b6b3a764000060c9546118b49089613163565b6118be919061317a565b93506118ca848461319c565b9250866118d784866131af565b146118f557604051637fcce2a960e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0382160161194f576040805160608101825233815260cc546001600160a01b03166020820152908101859052611949908290612304565b506119c7565b60cc546000906119699083906001600160a01b0316612383565b6040805160608101825233815260cc546001600160a01b0316602082015290810187905290915061199b908390612304565b5060cc546000906119b69084906001600160a01b0316612383565b90506119c2828261319c565b955050505b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601611a2857611a22816040518060600160405280336001600160a01b03168152602001886001600160a01b0316815260200186815250612304565b50611a8a565b6000611a348287612383565b9050611a6c826040518060600160405280336001600160a01b03168152602001896001600160a01b0316815260200187815250612304565b506000611a798388612383565b9050611a85828261319c565b945050505b60405163f5b0dfb760e01b8152600481018490526001600160a01b0386169063f5b0dfb790602401600060405180830381600087803b158015611acc57600080fd5b505af1158015611ae0573d6000803e3d6000fd5b505060408051868152602081018890528993507fbf59838198f4ea92f663f5c1fc697f151a1b746b7dff86d564f250a55cbb485192500160405180910390a250505050505050565b6116b08133611663565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b6040516bffffffffffffffffffffffff193360601b166020820152603481018290526000908190605401604051602081830303815290604052805190602001209050611bbc84826123cc565b949350505050565b60cd54604051635e8a791560e01b8152600481018990523360248201526000916001600160a01b031690635e8a791590604401602060405180830381865afa158015611c14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3891906131c2565b611c555760405163075fd2b160e01b815260040160405180910390fd5b60cb60008154611c649061314a565b91829055506040519091508190600090611c949083906020019081526430b236b4b760d91b602082015260250190565b60408051601f19818403018152828252805160209182012060c0840183528d84526001600160a01b03808e168584019081528c8216868601908152606087018c8152608088018a905260a0880185905260008b815260cf8752969096208751815591516001830180549185166001600160a01b031992831617905590516002830180549190941691161790915592518051600385019081559281015191955084939290916004840190611d479082613061565b5050506080820151600582015560a090910151600690910155611d6a82336116cd565b611d748383612469565b604051633b7451b360e21b81526001600160a01b038b169063edd146cc90611da29087908d906004016131e4565b600060405180830381600087803b158015611dbc57600080fd5b505af1158015611dd0573d6000803e3d6000fd5b50505050838a6001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e379190612fbb565b141580611eb75750306001600160a01b03168a6001600160a01b03166315cc481e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eab9190612f88565b6001600160a01b031614155b15611ed55760405163636e39bb60e01b815260040160405180910390fd5b845160005b81811015611f46576000878281518110611ef657611ef6612fa5565b6020026020010151905060006001600160a01b0316816001600160a01b031603611f335760405163538ba4f960e01b815260040160405180910390fd5b611f3d86826116cd565b50600101611eda565b5060ca5415612049576001600160a01b03891673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015611f885750348860ca54611f8591906131af565b14155b80611fbd57506001600160a01b03891673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14801590611fbd57503460ca5414155b15611fdb576040516303e09bb960e31b815260040160405180910390fd5b60cc5460ca5461200c9173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee916001600160a01b0390911690611629565b847f02e340b51c6ae66fd22509c9b016f224c47a54063d4259fe3d860958e9eaac7260ca5460405161204091815260200190565b60405180910390a25b871561205a5761205a88868d611876565b8b857f69bcb5a6cf6a3c95185cbb451e77787240c866dd2e8332597e3013ff18a1aba18d8c8c8c60405161209194939291906131fd565b60405180910390a350505050979650505050505050565b6001600160a01b0381166120cf5760405163538ba4f960e01b815260040160405180910390fd5b60cc80546001600160a01b0319166001600160a01b0383169081179091556040519081527f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d1906020016108a1565b60ca8190556040518181527f803bee7e92bbc6ae7a1551f9f4ed3e31a8ea8df32e93332f41b0028f1091f9c3906020016108a1565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b670de0b6b3a76400008111156121b757604051632fb15b8760e01b815260040160405180910390fd5b60c98190556040518181527f9e826789de2de708fd9f09edea1182545e543893caa8ff71f8eb3aab50a4b065906020016108a1565b600082815260cf60209081526040808320600601548352606582528083206001600160a01b038516845290915281205460ff16610d02565b60008060008084865af1610d725763b12d13eb6000526004601cfd5b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d156001600051141716612285576390b8ec186000526004601cfd5b6000603452505050565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff16610d72576122c2816124b4565b6122cd8360206124c6565b6040516020016122de929190613239565b60408051601f198184030181529082905262461bcd60e51b8252610e07916004016132ba565b604081015160009073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038516016123655780341015612352576040516374c5672b60e01b815260040160405180910390fd5b612360836020015182612224565b612379565b612379848460000151856020015184612662565b5060019392505050565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038416016123bb57506001600160a01b03811631610846565b6123c583836126bf565b9050610846565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b0381166108465760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401610e07565b600082815260656020526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b60606108466001600160a01b03831660145b606060006124d5836002613163565b6124e09060026131af565b67ffffffffffffffff8111156124f8576124f86128a7565b6040519080825280601f01601f191660200182016040528015612522576020820181803683370190505b509050600360fc1b8160008151811061253d5761253d612fa5565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061256c5761256c612fa5565b60200101906001600160f81b031916908160001a9053506000612590846002613163565b61259b9060016131af565b90505b6001811115612613576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106125cf576125cf612fa5565b1a60f81b8282815181106125e5576125e5612fa5565b60200101906001600160f81b031916908160001a90535060049490941c9361260c816132cd565b905061259e565b508315610d025760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610e07565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c52602060006064601c6000895af13d1560016000511417166126b157637939f4246000526004601cfd5b600060605260405250505050565b6000816014526f70a0823100000000000000000000000060005260208060246010865afa601f3d111660205102905092915050565b6040518060c001604052806000801916815260200160006001600160a01b0316815260200160006001600160a01b03168152602001612746604051806040016040528060008152602001606081525090565b815260006020820181905260409091015290565b60006020828403121561276c57600080fd5b81356001600160e01b031981168114610d0257600080fd5b6001600160a01b0381168114610bf457600080fd5b6000602082840312156127ab57600080fd5b8135610d0281612784565b6000602082840312156127c857600080fd5b5035919050565b60005b838110156127ea5781810151838201526020016127d2565b50506000910152565b6000815180845261280b8160208601602086016127cf565b601f01601f19169290920160200192915050565b805182526000602082015160406020850152611bbc60408501826127f3565b6020815281516020820152600060208301516001600160a01b0380821660408501528060408601511660608501525050606083015160c0608084015261288760e084018261281f565b9050608084015160a084015260a084015160c08401528091505092915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156128e6576128e66128a7565b604052919050565b600067ffffffffffffffff831115612908576129086128a7565b61291b601f8401601f19166020016128bd565b905082815283838301111561292f57600080fd5b828260208301376000602084830101529392505050565b600082601f83011261295757600080fd5b610d02838335602085016128ee565b6000806040838503121561297957600080fd5b82359150602083013567ffffffffffffffff81111561299757600080fd5b6129a385828601612946565b9150509250929050565b600067ffffffffffffffff8211156129c7576129c76128a7565b5060051b60200190565b600082601f8301126129e257600080fd5b813560206129f76129f2836129ad565b6128bd565b82815260059290921b84018101918181019086841115612a1657600080fd5b8286015b84811015612a5657803567ffffffffffffffff811115612a3a5760008081fd5b612a488986838b0101612946565b845250918301918301612a1a565b509695505050505050565b60008060408385031215612a7457600080fd5b823567ffffffffffffffff80821115612a8c57600080fd5b818501915085601f830112612aa057600080fd5b81356020612ab06129f2836129ad565b82815260059290921b84018101918181019089841115612acf57600080fd5b948201945b83861015612aed57853582529482019490820190612ad4565b96505086013592505080821115612b0357600080fd5b506129a3858286016129d1565b600081518084526020808501945080840160005b83811015612b495781516001600160a01b031687529582019590820190600101612b24565b509495945050505050565b602081526000610d026020830184612b10565b60008060408385031215612b7a57600080fd5b8235612b8581612784565b91506020830135612b9581612784565b809150509250929050565b60008060408385031215612bb357600080fd5b823591506020830135612b9581612784565b600082601f830112612bd657600080fd5b81356020612be66129f2836129ad565b82815260059290921b84018101918181019086841115612c0557600080fd5b8286015b84811015612a56578035612c1c81612784565b8352918301918301612c09565b600080600060608486031215612c3e57600080fd5b83359250602084013567ffffffffffffffff80821115612c5d57600080fd5b612c6987838801612bc5565b93506040860135915080821115612c7f57600080fd5b50612c8c86828701612946565b9150509250925092565b60008060408385031215612ca957600080fd5b50508035926020909101359150565b600060408284031215612cca57600080fd5b6040516040810167ffffffffffffffff8282108183111715612cee57612cee6128a7565b81604052829350843583526020850135915080821115612d0d57600080fd5b508301601f81018513612d1f57600080fd5b612d2e858235602084016128ee565b6020830152505092915050565b60008060408385031215612d4e57600080fd5b82359150602083013567ffffffffffffffff811115612d6c57600080fd5b6129a385828601612cb8565b600080600080600080600060e0888a031215612d9357600080fd5b873596506020880135612da581612784565b9550604088013567ffffffffffffffff80821115612dc257600080fd5b612dce8b838c01612946565b965060608a01359150612de082612784565b9094506080890135935060a08901359080821115612dfd57600080fd5b612e098b838c01612cb8565b935060c08a0135915080821115612e1f57600080fd5b50612e2c8a828b01612bc5565b91505092959891949750929550565b600080600080600060a08688031215612e5357600080fd5b8535612e5e81612784565b94506020860135612e6e81612784565b93506040860135612e7e81612784565b94979396509394606081013594506080013592915050565b600080600060408486031215612eab57600080fd5b833567ffffffffffffffff80821115612ec357600080fd5b818601915086601f830112612ed757600080fd5b813581811115612ee657600080fd5b8760208260051b8501011115612efb57600080fd5b602092830195509350908501359080821115612f1657600080fd5b50612c8c868287016129d1565b600181811c90821680612f3757607f821691505b602082108103612f5757634e487b7160e01b600052602260045260246000fd5b50919050565b604081526000612f7060408301856127f3565b90506001600160a01b03831660208301529392505050565b600060208284031215612f9a57600080fd5b8151610d0281612784565b634e487b7160e01b600052603260045260246000fd5b600060208284031215612fcd57600080fd5b5051919050565b606081526000612fe76060830186612b10565b8281036020840152612ff981866127f3565b9150506001600160a01b0383166040830152949350505050565b601f821115610ca157600081815260208120601f850160051c8101602086101561303a5750805b601f850160051c820191505b8181101561305957828155600101613046565b505050505050565b815167ffffffffffffffff81111561307b5761307b6128a7565b61308f816130898454612f23565b84613013565b602080601f8311600181146130c457600084156130ac5750858301515b600019600386901b1c1916600185901b178555613059565b600085815260208120601f198616915b828110156130f3578886015182559484019460019091019084016130d4565b50858210156131115787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b602081526000610d02602083018461281f565b634e487b7160e01b600052601160045260246000fd5b60006001820161315c5761315c613134565b5060010190565b808202811582820484141761084657610846613134565b60008261319757634e487b7160e01b600052601260045260246000fd5b500490565b8181038181111561084657610846613134565b8082018082111561084657610846613134565b6000602082840312156131d457600080fd5b81518015158114610d0257600080fd5b828152604060208201526000611bbc60408301846127f3565b60006001600160a01b0380871683528086166020840152508360408301526080606083015261322f608083018461281f565b9695505050505050565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516132718160178501602088016127cf565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516132ae8160288401602088016127cf565b01602801949350505050565b602081526000610d0260208301846127f3565b6000816132dc576132dc613134565b50600019019056fea2646970667358221220c524dca189879d6356e6617edf44bf49f1a7582c373aeecaaf9075174ab0fe1c64736f6c63430008130033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.