Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00Multichain Info
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 191633165 | 599 days ago | Contract Creation | 0 ETH |
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:
DonationVotingMerkleDistributionDirectTransferStrategy
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;
import {ISignatureTransfer} from "lib/permit2/src/interfaces/ISignatureTransfer.sol";
import {DonationVotingMerkleDistributionBaseStrategy} from
"../donation-voting-merkle-base/DonationVotingMerkleDistributionBaseStrategy.sol";
import {SafeTransferLib} from "lib/solady/src/utils/SafeTransferLib.sol";
import {IERC20Permit} from "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol";
import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IDAI} from "../donation-voting-merkle-base/IDAI.sol";
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
// allo.gitcoin.co
/// @title Donation Voting Merkle Distribution Strategy
/// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]>
/// @notice Strategy for donation voting allocation with a merkle distribution
contract DonationVotingMerkleDistributionDirectTransferStrategy is DonationVotingMerkleDistributionBaseStrategy {
/// ===============================
/// ======== Constructor ==========
/// ===============================
/// @notice Constructor for the Donation Voting Merkle Distribution Strategy
/// @param _allo The 'Allo' contract
/// @param _name The name of the strategy
constructor(address _allo, string memory _name, ISignatureTransfer _permit2)
DonationVotingMerkleDistributionBaseStrategy(_allo, _name, _permit2)
{}
/// ================================
/// ============ Hooks =============
/// ================================
/// @notice After allocation hook to transfer the allocated tokens to the recipients
/// @param _data The encoded recipientId, amount and token
/// @param _sender The sender of the allocation
function _afterAllocate(bytes memory _data, address _sender) internal override {
// Decode the '_data' to get the recipientId, amount and token
(address recipientId, PermitType permitType, Permit2Data memory p2Data) =
abi.decode(_data, (address, PermitType, Permit2Data));
// Get the token address
address token = p2Data.permit.permitted.token;
uint256 amount = p2Data.permit.permitted.amount;
address recipientAddress = _recipients[recipientId].recipientAddress;
// Native or already approved
if (permitType == PermitType.None) {
_transferAmountFrom(token, TransferData(_sender, recipientAddress, amount));
} else if (permitType == PermitType.Permit2) {
PERMIT2.permitTransferFrom( // The permit message.
p2Data.permit,
// The transfer recipient and amount.
ISignatureTransfer.SignatureTransferDetails({to: recipientAddress, requestedAmount: amount}),
// Owner of the tokens and signer of the message.
_sender,
// The packed signature that was the result of signing
// the EIP712 hash of `_permit`.
p2Data.signature
);
} else if (permitType == PermitType.Permit) {
(bytes32 r, bytes32 s, uint8 v) = splitSignature(p2Data.signature);
// The tx can be front-run, and another user can use the permit message and signature to invalidate the nonce.
// In this case the permit call will fail, but it means that the contract already has allowance for the token.
try IERC20Permit(token).permit(_sender, address(this), amount, p2Data.permit.deadline, v, r, s) {}
catch Error(string memory reason) {
if (IERC20(token).allowance(_sender, address(this)) < amount) {
revert(reason);
}
} catch (bytes memory reason) {
if (IERC20(token).allowance(_sender, address(this)) < amount) {
revert(string(reason));
}
}
IERC20(token).transferFrom(_sender, recipientAddress, amount);
} else if (permitType == PermitType.PermitDAI) {
(bytes32 r, bytes32 s, uint8 v) = splitSignature(p2Data.signature);
// The tx can be front-run, and another user can use the permit message and signature to invalidate the nonce.
// In this case the permit call will fail, but it means that the contract already has allowance for the token.
try IDAI(token).permit(_sender, address(this), p2Data.permit.nonce, p2Data.permit.deadline, true, v, r, s) {}
catch Error(string memory reason) {
if (IERC20(token).allowance(_sender, address(this)) < amount) {
revert(reason);
}
} catch (bytes memory reason) {
if (IERC20(token).allowance(_sender, address(this)) < amount) {
revert(string(reason));
}
}
IERC20(token).transferFrom(_sender, recipientAddress, amount);
}
}
function splitSignature(bytes memory sig) public pure returns (bytes32 r, bytes32 s, uint8 v) {
if (sig.length == 65) {
(r, s) = abi.decode(sig, (bytes32, bytes32));
v = uint8(sig[64]);
} else if (sig.length == 64) {
// EIP-2098
bytes32 vs;
(r, vs) = abi.decode(sig, (bytes32, bytes32));
s = vs & (0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
v = uint8(uint256(vs >> 255)) + 27;
} else {
revert INVALID();
}
}
/// @notice Internal function to return the token amount locked in vault
/// @dev This function will return 0 since all funds are transferred directly to the recipient
function _tokenAmountInVault(address) internal pure override returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;
// Interfaces
import {IRegistry} from "./IRegistry.sol";
import {IStrategy} from "./IStrategy.sol";
// Internal Libraries
import {Metadata} from "../libraries/Metadata.sol";
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
// allo.gitcoin.co
/// @title Allo Interface
/// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]>
/// @notice Interface for the Allo contract. It exposes all functions needed to use the Allo protocol.
interface IAllo {
/// ======================
/// ======= Structs ======
/// ======================
/// @notice the Pool struct that all strategy pools are based from
struct Pool {
bytes32 profileId;
IStrategy strategy;
address token;
Metadata metadata;
bytes32 managerRole;
bytes32 adminRole;
}
/// ======================
/// ======= Events =======
/// ======================
/// @notice Event emitted when a new pool is created
/// @param poolId ID of the pool created
/// @param profileId ID of the profile the pool is associated with
/// @param strategy Address of the strategy contract
/// @param token Address of the token pool was funded with when created
/// @param amount Amount pool was funded with when created
/// @param metadata Pool metadata
event PoolCreated(
uint256 indexed poolId,
bytes32 indexed profileId,
IStrategy strategy,
address token,
uint256 amount,
Metadata metadata
);
/// @notice Emitted when a pools metadata is updated
/// @param poolId ID of the pool updated
/// @param metadata Pool metadata that was updated
event PoolMetadataUpdated(uint256 indexed poolId, Metadata metadata);
/// @notice Emitted when a pool is funded
/// @param poolId ID of the pool funded
/// @param amount Amount funded to the pool
/// @param fee Amount of the fee paid to the treasury
event PoolFunded(uint256 indexed poolId, uint256 amount, uint256 fee);
/// @notice Emitted when the base fee is paid
/// @param poolId ID of the pool the base fee was paid for
/// @param amount Amount of the base fee paid
event BaseFeePaid(uint256 indexed poolId, uint256 amount);
/// @notice Emitted when the treasury address is updated
/// @param treasury Address of the new treasury
event TreasuryUpdated(address treasury);
/// @notice Emitted when the percent fee is updated
/// @param percentFee New percentage for the fee
event PercentFeeUpdated(uint256 percentFee);
/// @notice Emitted when the base fee is updated
/// @param baseFee New base fee amount
event BaseFeeUpdated(uint256 baseFee);
/// @notice Emitted when the registry address is updated
/// @param registry Address of the new registry
event RegistryUpdated(address registry);
/// @notice Emitted when a strategy is approved and added to the cloneable strategies
/// @param strategy Address of the strategy approved
event StrategyApproved(address strategy);
/// @notice Emitted when a strategy is removed from the cloneable strategies
/// @param strategy Address of the strategy removed
event StrategyRemoved(address strategy);
/// ====================================
/// ==== External/Public Functions =====
/// ====================================
/// @notice Initialize the Allo contract
/// @param _owner Address of the owner
/// @param _registry Address of the registry contract
/// @param _treasury Address of the treasury
/// @param _percentFee Percentage for the fee
/// @param _baseFee Base fee amount
function initialize(
address _owner,
address _registry,
address payable _treasury,
uint256 _percentFee,
uint256 _baseFee
) external;
/// @notice Creates a new pool (with a custom strategy)
/// @dev 'msg.sender' must be a member or owner of a profile to create a pool with or without a custom strategy, The encoded data
/// will be specific to a given strategy requirements, reference the strategy implementation of 'initialize()'. The strategy
/// address passed must not be a cloneable strategy. The strategy address passed must not be the zero address. 'msg.sender' must
/// be a member or owner of the profile id passed as '_profileId'.
/// @param _profileId The 'profileId' of the registry profile, used to check if 'msg.sender' is a member or owner of the profile
/// @param _strategy The address of the deployed custom strategy
/// @param _initStrategyData The data to initialize the strategy
/// @param _token The address of the token you want to use in your pool
/// @param _amount The amount of the token you want to deposit into the pool on initialization
/// @param _metadata The 'Metadata' of the pool, this uses our 'Meatdata.sol' struct (consistent throughout the protocol)
/// @param _managers The managers of the pool, and can be added/removed later by the pool admin
/// @return poolId The ID of the pool
function createPoolWithCustomStrategy(
bytes32 _profileId,
address _strategy,
bytes memory _initStrategyData,
address _token,
uint256 _amount,
Metadata memory _metadata,
address[] memory _managers
) external payable returns (uint256 poolId);
/// @notice Creates a new pool (by cloning a cloneable strategies).
/// @dev 'msg.sender' must be owner or member of the profile id passed as '_profileId'.
/// @param _profileId The ID of the registry profile, used to check if 'msg.sender' is a member or owner of the profile
/// @param _strategy The address of the strategy contract the pool will use.
/// @param _initStrategyData The data to initialize the strategy
/// @param _token The address of the token
/// @param _amount The amount of the token
/// @param _metadata The metadata of the pool
/// @param _managers The managers of the pool
/// @custom:initstrategydata The encoded data will be specific to a given strategy requirements,
/// reference the strategy implementation of 'initialize()'
function createPool(
bytes32 _profileId,
address _strategy,
bytes memory _initStrategyData,
address _token,
uint256 _amount,
Metadata memory _metadata,
address[] memory _managers
) external payable returns (uint256 poolId);
/// @notice Updates a pools metadata.
/// @dev 'msg.sender' must be a pool admin.
/// @param _poolId The ID of the pool to update
/// @param _metadata The new metadata to set
function updatePoolMetadata(uint256 _poolId, Metadata memory _metadata) external;
/// @notice Update the registry address.
/// @dev 'msg.sender' must be the Allo contract owner.
/// @param _registry The new registry address
function updateRegistry(address _registry) external;
/// @notice Updates the treasury address.
/// @dev 'msg.sender' must be the Allo contract owner.
/// @param _treasury The new treasury address
function updateTreasury(address payable _treasury) external;
/// @notice Updates the percentage for the fee.
/// @dev 'msg.sender' must be the Allo contract owner.
/// @param _percentFee The new percentage for the fee
function updatePercentFee(uint256 _percentFee) external;
/// @notice Updates the base fee.
/// @dev 'msg.sender' must be the Allo contract owner.
/// @param _baseFee The new base fee
function updateBaseFee(uint256 _baseFee) external;
/// @notice Adds a strategy to the cloneable strategies.
/// @dev 'msg.sender' must be the Allo contract owner.
/// @param _strategy The address of the strategy to add
function addToCloneableStrategies(address _strategy) external;
/// @notice Removes a strategy from the cloneable strategies.
/// @dev 'msg.sender' must be the Allo contract owner.
/// @param _strategy The address of the strategy to remove
function removeFromCloneableStrategies(address _strategy) external;
/// @notice Adds a pool manager to the pool.
/// @dev 'msg.sender' must be a pool admin.
/// @param _poolId The ID of the pool to add the manager to
/// @param _manager The address of the manager to add
function addPoolManager(uint256 _poolId, address _manager) external;
/// @notice Removes a pool manager from the pool.
/// @dev 'msg.sender' must be a pool admin.
/// @param _poolId The ID of the pool to remove the manager from
/// @param _manager The address of the manager to remove
function removePoolManager(uint256 _poolId, address _manager) external;
/// @notice Recovers funds from a pool.
/// @dev 'msg.sender' must be a pool admin.
/// @param _token The token to recover
/// @param _recipient The address to send the recovered funds to
function recoverFunds(address _token, address _recipient) external;
/// @notice Registers a recipient and emits {Registered} event if successful and may be handled differently by each strategy.
/// @param _poolId The ID of the pool to register the recipient for
function registerRecipient(uint256 _poolId, bytes memory _data) external payable returns (address);
/// @notice Registers a batch of recipients.
/// @param _poolIds The pool ID's to register the recipients for
/// @param _data The data to pass to the strategy and may be handled differently by each strategy
function batchRegisterRecipient(uint256[] memory _poolIds, bytes[] memory _data)
external
returns (address[] memory);
/// @notice Funds a pool.
/// @dev 'msg.value' must be greater than 0 if the token is the native token
/// or '_amount' must be greater than 0 if the token is not the native token.
/// @param _poolId The ID of the pool to fund
/// @param _amount The amount to fund the pool with
function fundPool(uint256 _poolId, uint256 _amount) external payable;
/// @notice Allocates funds to a recipient.
/// @dev Each strategy will handle the allocation of funds differently.
/// @param _poolId The ID of the pool to allocate funds from
/// @param _data The data to pass to the strategy and may be handled differently by each strategy.
function allocate(uint256 _poolId, bytes memory _data) external payable;
/// @notice Allocates funds to multiple recipients.
/// @dev Each strategy will handle the allocation of funds differently
function batchAllocate(uint256[] calldata _poolIds, bytes[] memory _datas) external;
/// @notice Distributes funds to recipients and emits {Distributed} event if successful
/// @dev Each strategy will handle the distribution of funds differently
/// @param _poolId The ID of the pool to distribute from
/// @param _recipientIds The recipient ids to distribute to
/// @param _data The data to pass to the strategy and may be handled differently by each strategy
function distribute(uint256 _poolId, address[] memory _recipientIds, bytes memory _data) external;
/// =========================
/// ==== View Functions =====
/// =========================
/// @notice Checks if an address is a pool admin.
/// @param _poolId The ID of the pool to check
/// @param _address The address to check
/// @return 'true' if the '_address' is a pool admin, otherwise 'false'
function isPoolAdmin(uint256 _poolId, address _address) external view returns (bool);
/// @notice Checks if an address is a pool manager.
/// @param _poolId The ID of the pool to check
/// @param _address The address to check
/// @return 'true' if the '_address' is a pool manager, otherwise 'false'
function isPoolManager(uint256 _poolId, address _address) external view returns (bool);
/// @notice Checks if a strategy is cloneable (is in the cloneableStrategies mapping).
/// @param _strategy The address of the strategy to check
/// @return 'true' if the '_strategy' is cloneable, otherwise 'false'
function isCloneableStrategy(address _strategy) external view returns (bool);
/// @notice Returns the address of the strategy for a given 'poolId'
/// @param _poolId The ID of the pool to check
/// @return strategy The address of the strategy for the ID of the pool passed in
function getStrategy(uint256 _poolId) external view returns (address);
/// @notice Returns the current percent fee
/// @return percentFee The current percentage for the fee
function getPercentFee() external view returns (uint256);
/// @notice Returns the current base fee
/// @return baseFee The current base fee
function getBaseFee() external view returns (uint256);
/// @notice Returns the current treasury address
/// @return treasury The current treasury address
function getTreasury() external view returns (address payable);
/// @notice Returns the current registry address
/// @return registry The current registry address
function getRegistry() external view returns (IRegistry);
/// @notice Returns the 'Pool' struct for a given 'poolId'
/// @param _poolId The ID of the pool to check
/// @return pool The 'Pool' struct for the ID of the pool passed in
function getPool(uint256 _poolId) external view returns (Pool memory);
/// @notice Returns the current fee denominator
/// @dev 1e18 represents 100%
/// @return feeDenominator The current fee denominator
function getFeeDenominator() external view returns (uint256);
}// 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; // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀ // ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀ // ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀ // ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀ // ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀ // allo.gitcoin.co /// @title Errors /// @author @thelostone-mc <[email protected]>, @KurtMerbeth <[email protected]>, @codenamejason <[email protected]> /// @notice Library containing all custom errors the protocol may revert with. contract Errors { /// ====================== /// ====== Generic ======= /// ====================== /// @notice Thrown as a general error when input / data is invalid error INVALID(); /// @notice Thrown when mismatch in decoding data error MISMATCH(); /// @notice Thrown when not enough funds are available error NOT_ENOUGH_FUNDS(); /// @notice Thrown when user is not authorized error UNAUTHORIZED(); /// @notice Thrown when address is the zero address error ZERO_ADDRESS(); /// @notice Thrown when the function is not implemented error NOT_IMPLEMENTED(); /// @notice Thrown when the value is non-zero error NON_ZERO_VALUE(); /// ====================== /// ====== Registry ====== /// ====================== /// @dev Thrown when the nonce passed has been used or not available error NONCE_NOT_AVAILABLE(); /// @dev Thrown when the 'msg.sender' is not the pending owner on ownership transfer error NOT_PENDING_OWNER(); /// @dev Thrown if the anchor creation fails error ANCHOR_ERROR(); /// ====================== /// ======== Allo ======== /// ====================== /// @notice Thrown when the strategy is not approved error NOT_APPROVED_STRATEGY(); /// @notice Thrown when the strategy is approved and should be cloned error IS_APPROVED_STRATEGY(); /// @notice Thrown when the fee is below 1e18 which is the fee percentage denominator error INVALID_FEE(); /// ====================== /// ===== IStrategy ====== /// ====================== /// @notice Thrown when data is already intialized error ALREADY_INITIALIZED(); /// @notice Thrown when data is yet to be initialized error NOT_INITIALIZED(); /// @notice Thrown when an invalid address is used error INVALID_ADDRESS(); /// @notice Thrown when a pool is inactive error POOL_INACTIVE(); /// @notice Thrown when a pool is already active error POOL_ACTIVE(); /// @notice Thrown when two arrays length are not equal error ARRAY_MISMATCH(); /// @notice Thrown when the registration is invalid. error INVALID_REGISTRATION(); /// @notice Thrown when the metadata is invalid. error INVALID_METADATA(); /// @notice Thrown when the recipient is not accepted. error RECIPIENT_NOT_ACCEPTED(); /// @notice Thrown when recipient is already accepted. error RECIPIENT_ALREADY_ACCEPTED(); /// @notice Thrown when registration is not active. error REGISTRATION_NOT_ACTIVE(); /// @notice Thrown when registration is active. error REGISTRATION_ACTIVE(); /// @notice Thrown when there is an error in recipient. error RECIPIENT_ERROR(address recipientId); /// @notice Thrown when the allocation is not active. error ALLOCATION_NOT_ACTIVE(); /// @notice Thrown when the allocation is not ended. error ALLOCATION_NOT_ENDED(); /// @notice Thrown when the allocation is active. error ALLOCATION_ACTIVE(); }
// 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 "lib/solady/src/utils/SafeTransferLib.sol";
// Internal Libraries
import "./Native.sol";
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
// allo.gitcoin.co
/// @title Transfer contract
/// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]>
/// @notice A helper contract to transfer tokens within Allo protocol
/// @dev Handles the transfer of tokens to an address
contract Transfer is Native {
/// @notice Thrown when the amount of tokens sent does not match the amount of tokens expected
error AMOUNT_MISMATCH();
/// @notice This holds the details for a transfer
struct TransferData {
address from;
address to;
uint256 amount;
}
/// @notice Transfer an amount of a token to an array of addresses
/// @param _token The address of the token
/// @param _transferData TransferData[]
/// @return Whether the transfer was successful or not
function _transferAmountsFrom(address _token, TransferData[] memory _transferData)
internal
virtual
returns (bool)
{
uint256 msgValue = msg.value;
for (uint256 i; i < _transferData.length;) {
TransferData memory transferData = _transferData[i];
if (_token == NATIVE) {
msgValue -= transferData.amount;
SafeTransferLib.safeTransferETH(transferData.to, transferData.amount);
} else {
SafeTransferLib.safeTransferFrom(_token, transferData.from, transferData.to, transferData.amount);
}
unchecked {
i++;
}
}
if (msgValue != 0) revert AMOUNT_MISMATCH();
return true;
}
/// @notice Transfer an amount of a token to an address
/// @param _token The address of the token
/// @param _transferData Individual TransferData
/// @return Whether the transfer was successful or not
function _transferAmountFrom(address _token, TransferData memory _transferData) internal virtual returns (bool) {
uint256 amount = _transferData.amount;
if (_token == NATIVE) {
// Native Token
if (msg.value < amount) revert AMOUNT_MISMATCH();
SafeTransferLib.safeTransferETH(_transferData.to, amount);
} else {
SafeTransferLib.safeTransferFrom(_token, _transferData.from, _transferData.to, amount);
}
return true;
}
/// @notice Transfer an amount of a token to an address
/// @param _token The token to transfer
/// @param _to The address to transfer to
/// @param _amount The amount to transfer
function _transferAmount(address _token, address _to, uint256 _amount) internal virtual {
if (_token == NATIVE) {
SafeTransferLib.safeTransferETH(_to, _amount);
} else {
SafeTransferLib.safeTransfer(_token, _to, _amount);
}
}
/// @notice Get the balance of a token for an account
/// @param _token The token to get the balance of
/// @param _account The account to get the balance for
/// @return The balance of the token for the account
function _getBalance(address _token, address _account) internal view returns (uint256) {
if (_token == NATIVE) {
return payable(_account).balance;
} else {
return SafeTransferLib.balanceOf(_token, _account);
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;
// Interfaces
import "../core/interfaces/IStrategy.sol";
// Libraries
import {Transfer} from "../core/libraries/Transfer.sol";
import {Errors} from "../core/libraries/Errors.sol";
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
// allo.gitcoin.co
/// @title BaseStrategy Contract
/// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]>
/// @notice This contract is the base contract for all strategies
/// @dev This contract is implemented by all strategies.
abstract contract BaseStrategy is IStrategy, Transfer, Errors {
/// ==========================
/// === Storage Variables ====
/// ==========================
IAllo internal immutable allo;
bytes32 internal immutable strategyId;
bool internal poolActive;
uint256 internal poolId;
uint256 internal poolAmount;
/// ====================================
/// ========== Constructor =============
/// ====================================
/// @notice Constructor to set the Allo contract and "strategyId'.
/// @param _allo Address of the Allo contract.
/// @param _name Name of the strategy
constructor(address _allo, string memory _name) {
allo = IAllo(_allo);
strategyId = keccak256(abi.encode(_name));
}
/// ====================================
/// =========== Modifiers ==============
/// ====================================
/// @notice Modifier to check if the 'msg.sender' is the Allo contract.
/// @dev Reverts if the 'msg.sender' is not the Allo contract.
modifier onlyAllo() {
_checkOnlyAllo();
_;
}
/// @notice Modifier to check if the '_sender' is a pool manager.
/// @dev Reverts if the '_sender' is not a pool manager.
/// @param _sender The address to check if they are a pool manager
modifier onlyPoolManager(address _sender) {
_checkOnlyPoolManager(_sender);
_;
}
/// @notice Modifier to check if the pool is active.
/// @dev Reverts if the pool is not active.
modifier onlyActivePool() {
_checkOnlyActivePool();
_;
}
/// @notice Modifier to check if the pool is inactive.
/// @dev Reverts if the pool is active.
modifier onlyInactivePool() {
_checkInactivePool();
_;
}
/// @notice Modifier to check if the pool is initialized.
/// @dev Reverts if the pool is not initialized.
modifier onlyInitialized() {
_checkOnlyInitialized();
_;
}
/// ================================
/// =========== Views ==============
/// ================================
/// @notice Getter for the 'Allo' contract.
/// @return The Allo contract
function getAllo() external view override returns (IAllo) {
return allo;
}
/// @notice Getter for the 'poolId'.
/// @return The ID of the pool
function getPoolId() external view override returns (uint256) {
return poolId;
}
/// @notice Getter for the 'strategyId'.
/// @return The ID of the strategy
function getStrategyId() external view override returns (bytes32) {
return strategyId;
}
/// @notice Getter for the 'poolAmount'.
/// @return The balance of the pool
function getPoolAmount() external view virtual override returns (uint256) {
return poolAmount;
}
/// @notice Getter for whether or not the pool is active.
/// @return 'true' if the pool is active, otherwise 'false'
function isPoolActive() external view override returns (bool) {
return _isPoolActive();
}
/// @notice Getter for the status of a recipient.
/// @param _recipientId The ID of the recipient
/// @return The status of the recipient
function getRecipientStatus(address _recipientId) external view virtual returns (Status) {
return _getRecipientStatus(_recipientId);
}
/// ====================================
/// =========== Functions ==============
/// ====================================
/// @notice Initializes the 'Basetrategy'.
/// @dev Will revert if the poolId is invalid or already initialized
/// @param _poolId ID of the pool
function __BaseStrategy_init(uint256 _poolId) internal virtual onlyAllo {
// check if pool ID is not initialized already, if it is, revert
if (poolId != 0) revert ALREADY_INITIALIZED();
// check if pool ID is valid and not zero (0), if it is, revert
if (_poolId == 0) revert INVALID();
poolId = _poolId;
}
/// @notice Increases the pool amount.
/// @dev Increases the 'poolAmount' by '_amount'. Only 'Allo' contract can call this.
/// @param _amount The amount to increase the pool by
function increasePoolAmount(uint256 _amount) external override onlyAllo {
_beforeIncreasePoolAmount(_amount);
poolAmount += _amount;
_afterIncreasePoolAmount(_amount);
}
/// @notice Registers a recipient.
/// @dev Registers a recipient and returns the ID of the recipient. The encoded '_data' will be determined by the
/// strategy implementation. Only 'Allo' contract can call this when it is initialized.
/// @param _data The data to use to register the recipient
/// @param _sender The address of the sender
/// @return recipientId The recipientId
function registerRecipient(bytes memory _data, address _sender)
external
payable
onlyAllo
onlyInitialized
returns (address recipientId)
{
_beforeRegisterRecipient(_data, _sender);
recipientId = _registerRecipient(_data, _sender);
_afterRegisterRecipient(_data, _sender);
}
/// @notice Allocates to a recipient.
/// @dev The encoded '_data' will be determined by the strategy implementation. Only 'Allo' contract can
/// call this when it is initialized.
/// @param _data The data to use to allocate to the recipient
/// @param _sender The address of the sender
function allocate(bytes memory _data, address _sender) external payable onlyAllo onlyInitialized {
_beforeAllocate(_data, _sender);
_allocate(_data, _sender);
_afterAllocate(_data, _sender);
}
/// @notice Distributes funds (tokens) to recipients.
/// @dev The encoded '_data' will be determined by the strategy implementation. Only 'Allo' contract can
/// call this when it is initialized.
/// @param _recipientIds The IDs of the recipients
/// @param _data The data to use to distribute to the recipients
/// @param _sender The address of the sender
function distribute(address[] memory _recipientIds, bytes memory _data, address _sender)
external
onlyAllo
onlyInitialized
{
_beforeDistribute(_recipientIds, _data, _sender);
_distribute(_recipientIds, _data, _sender);
_afterDistribute(_recipientIds, _data, _sender);
}
/// @notice Gets the payout summary for recipients.
/// @dev The encoded '_data' will be determined by the strategy implementation.
/// @param _recipientIds The IDs of the recipients
/// @param _data The data to use to get the payout summary for the recipients
/// @return The payout summary for the recipients
function getPayouts(address[] memory _recipientIds, bytes[] memory _data)
external
view
virtual
override
returns (PayoutSummary[] memory)
{
uint256 recipientLength = _recipientIds.length;
// check if the length of the recipient IDs and data arrays are equal, if they are not, revert
if (recipientLength != _data.length) revert ARRAY_MISMATCH();
PayoutSummary[] memory payouts = new PayoutSummary[](recipientLength);
for (uint256 i; i < recipientLength;) {
payouts[i] = _getPayout(_recipientIds[i], _data[i]);
unchecked {
i++;
}
}
return payouts;
}
/// @notice Checks if the '_allocator' is a valid allocator.
/// @dev How the allocator is determined is up to the strategy implementation.
/// @param _allocator The address to check if it is a valid allocator for the strategy.
/// @return 'true' if the address is a valid allocator, 'false' otherwise
function isValidAllocator(address _allocator) external view virtual override returns (bool) {
return _isValidAllocator(_allocator);
}
/// ====================================
/// ============ Internal ==============
/// ====================================
/// @notice Checks if the 'msg.sender' is the Allo contract.
/// @dev Reverts if the 'msg.sender' is not the Allo contract.
function _checkOnlyAllo() internal view {
if (msg.sender != address(allo)) revert UNAUTHORIZED();
}
/// @notice Checks if the '_sender' is a pool manager.
/// @dev Reverts if the '_sender' is not a pool manager.
/// @param _sender The address to check if they are a pool manager
function _checkOnlyPoolManager(address _sender) internal view {
if (!allo.isPoolManager(poolId, _sender)) revert UNAUTHORIZED();
}
/// @notice Checks if the pool is active.
/// @dev Reverts if the pool is not active.
function _checkOnlyActivePool() internal view {
if (!poolActive) revert POOL_INACTIVE();
}
/// @notice Checks if the pool is inactive.
/// @dev Reverts if the pool is active.
function _checkInactivePool() internal view {
if (poolActive) revert POOL_ACTIVE();
}
/// @notice Checks if the pool is initialized.
/// @dev Reverts if the pool is not initialized.
function _checkOnlyInitialized() internal view {
if (poolId == 0) revert NOT_INITIALIZED();
}
/// @notice Set the pool to active or inactive status.
/// @dev This will emit a 'PoolActive()' event. Used by the strategy implementation.
/// @param _active The status to set, 'true' means active, 'false' means inactive
function _setPoolActive(bool _active) internal {
poolActive = _active;
emit PoolActive(_active);
}
/// @notice Checks if the pool is active.
/// @dev Used by the strategy implementation.
/// @return 'true' if the pool is active, otherwise 'false'
function _isPoolActive() internal view virtual returns (bool) {
return poolActive;
}
/// @notice Checks if the allocator is valid
/// @param _allocator The allocator address
/// @return 'true' if the allocator is valid, otherwise 'false'
function _isValidAllocator(address _allocator) internal view virtual returns (bool);
/// @notice This will register a recipient, set their status (and any other strategy specific values), and
/// return the ID of the recipient.
/// @dev Able to change status all the way up to Accepted, or to Pending and if there are more steps, additional
/// functions should be added to allow the owner to check this. The owner could also check attestations directly
/// and then Accept for instance.
/// @param _data The data to use to register the recipient
/// @param _sender The address of the sender
/// @return The ID of the recipient
function _registerRecipient(bytes memory _data, address _sender) internal virtual returns (address);
/// @notice This will allocate to a recipient.
/// @dev The encoded '_data' will be determined by the strategy implementation.
/// @param _data The data to use to allocate to the recipient
/// @param _sender The address of the sender
function _allocate(bytes memory _data, address _sender) internal virtual;
/// @notice This will distribute funds (tokens) to recipients.
/// @dev most strategies will track a TOTAL amount per recipient, and a PAID amount, and pay the difference
/// this contract will need to track the amount paid already, so that it doesn't double pay.
/// @param _recipientIds The ids of the recipients to distribute to
/// @param _data Data required will depend on the strategy implementation
/// @param _sender The address of the sender
function _distribute(address[] memory _recipientIds, bytes memory _data, address _sender) internal virtual;
/// @notice This will get the payout summary for a recipient.
/// @dev The encoded '_data' will be determined by the strategy implementation.
/// @param _recipientId The ID of the recipient
/// @param _data The data to use to get the payout summary for the recipient
/// @return The payout summary for the recipient
function _getPayout(address _recipientId, bytes memory _data)
internal
view
virtual
returns (PayoutSummary memory);
/// @notice This will get the status of a recipient.
/// @param _recipientId The ID of the recipient
/// @return The status of the recipient
function _getRecipientStatus(address _recipientId) internal view virtual returns (Status);
/// ===================================
/// ============== Hooks ==============
/// ===================================
/// @notice Hook called before increasing the pool amount.
/// @param _amount The amount to increase the pool by
function _beforeIncreasePoolAmount(uint256 _amount) internal virtual {}
/// @notice Hook called after increasing the pool amount.
/// @param _amount The amount to increase the pool by
function _afterIncreasePoolAmount(uint256 _amount) internal virtual {}
/// @notice Hook called before registering a recipient.
/// @param _data The data to use to register the recipient
/// @param _sender The address of the sender
function _beforeRegisterRecipient(bytes memory _data, address _sender) internal virtual {}
/// @notice Hook called after registering a recipient.
/// @param _data The data to use to register the recipient
/// @param _sender The address of the sender
function _afterRegisterRecipient(bytes memory _data, address _sender) internal virtual {}
/// @notice Hook called before allocating to a recipient.
/// @param _data The data to use to allocate to the recipient
/// @param _sender The address of the sender
function _beforeAllocate(bytes memory _data, address _sender) internal virtual {}
/// @notice Hook called after allocating to a recipient.
/// @param _data The data to use to allocate to the recipient
/// @param _sender The address of the sender
function _afterAllocate(bytes memory _data, address _sender) internal virtual {}
/// @notice Hook called before distributing funds (tokens) to recipients.
/// @param _recipientIds The IDs of the recipients
/// @param _data The data to use to distribute to the recipients
/// @param _sender The address of the sender
function _beforeDistribute(address[] memory _recipientIds, bytes memory _data, address _sender) internal virtual {}
/// @notice Hook called after distributing funds (tokens) to recipients.
/// @param _recipientIds The IDs of the recipients
/// @param _data The data to use to distribute to the recipients
/// @param _sender The address of the sender
function _afterDistribute(address[] memory _recipientIds, bytes memory _data, address _sender) internal virtual {}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
// External Libraries
import {ISignatureTransfer} from "lib/permit2/src/interfaces/ISignatureTransfer.sol";
import {MerkleProof} from "lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol";
import {Multicall} from "lib/openzeppelin-contracts/contracts/utils/Multicall.sol";
// Interfaces
import {IAllo} from "../../core/interfaces/IAllo.sol";
import {IRegistry} from "../../core/interfaces/IRegistry.sol";
// Core Contracts
import {BaseStrategy} from "../BaseStrategy.sol";
// Internal Libraries
import {Metadata} from "../../core/libraries/Metadata.sol";
import {Native} from "../../core/libraries/Native.sol";
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀
// ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀
// ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀
// ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀
// ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀
// allo.gitcoin.co
/// @title Donation Voting Merkle Distribution Strategy
/// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]>
/// @notice Strategy for donation voting allocation with a merkle distribution
abstract contract DonationVotingMerkleDistributionBaseStrategy is Native, BaseStrategy, Multicall {
/// ================================
/// ========== Struct ==============
/// ================================
/// @notice Struct to hold details of the application status
/// @dev Application status is stored in a bitmap. Each 4 bits represents the status of a recipient,
/// defined as 'index' here. The first 4 bits of the 256 bits represent the status of the first recipient,
/// the second 4 bits represent the status of the second recipient, and so on.
///
/// The 'rowIndex' is the index of the row in the bitmap, and the 'statusRow' is the value of the row.
/// The 'statusRow' is updated when the status of a recipient changes.
///
/// Note: Since we need 4 bits to store a status, one row of the bitmap can hold the status information of 256/4 recipients.
///
/// For example, if we have 5 recipients, the bitmap will look like this:
/// | recipient1 | recipient2 | recipient3 | recipient4 | recipient5 | 'rowIndex'
/// | 0000 | 0001 | 0010 | 0011 | 0100 | 'statusRow'
/// | none | pending | accepted | rejected | appealed | converted status (0, 1, 2, 3, 4)
///
struct ApplicationStatus {
uint256 index;
uint256 statusRow;
}
/// @notice Stores the details of the recipients.
struct Recipient {
// If false, the recipientAddress is the anchor of the profile
bool useRegistryAnchor;
address recipientAddress;
Metadata metadata;
}
/// @notice Stores the details of the distribution.
struct Distribution {
uint256 index;
address recipientId;
uint256 amount;
bytes32[] merkleProof;
}
/// @notice Stores the initialize data for the strategy
struct InitializeData {
bool useRegistryAnchor;
bool metadataRequired;
uint64 registrationStartTime;
uint64 registrationEndTime;
uint64 allocationStartTime;
uint64 allocationEndTime;
address[] allowedTokens;
}
enum PermitType {
None,
Permit,
PermitDAI,
Permit2
}
/// @notice Stores the permit2 data for the allocation
struct Permit2Data {
ISignatureTransfer.PermitTransferFrom permit;
bytes signature;
}
/// ===============================
/// ========== Events =============
/// ===============================
/// @notice Emitted when a recipient updates their registration
/// @param recipientId Id of the recipient
/// @param data The encoded data - (address recipientId, address recipientAddress, Metadata metadata)
/// @param sender The sender of the transaction
/// @param status The updated status of the recipient
event UpdatedRegistration(address indexed recipientId, bytes data, address sender, uint8 status);
/// @notice Emitted when a recipient is registered and the status is updated
/// @param rowIndex The index of the row in the bitmap
/// @param fullRow The value of the row
/// @param sender The sender of the transaction
event RecipientStatusUpdated(uint256 indexed rowIndex, uint256 fullRow, address sender);
/// @notice Emitted when the timestamps are updated
/// @param registrationStartTime The start time for the registration
/// @param registrationEndTime The end time for the registration
/// @param allocationStartTime The start time for the allocation
/// @param allocationEndTime The end time for the allocation
/// @param sender The sender of the transaction
event TimestampsUpdated(
uint64 registrationStartTime,
uint64 registrationEndTime,
uint64 allocationStartTime,
uint64 allocationEndTime,
address sender
);
/// @notice Emitted when the distribution has been updated with a new merkle root or metadata
/// @param merkleRoot The merkle root of the distribution
/// @param metadata The metadata of the distribution
event DistributionUpdated(bytes32 merkleRoot, Metadata metadata);
/// @notice Emitted when funds are distributed to a recipient
/// @param amount The amount of tokens distributed
/// @param grantee The address of the recipient
/// @param token The address of the token
/// @param recipientId The id of the recipient
event FundsDistributed(uint256 amount, address grantee, address indexed token, address indexed recipientId);
/// @notice Emitted when a batch payout is successful
/// @param sender The sender of the transaction
event BatchPayoutSuccessful(address indexed sender);
/// @notice Emitted when a recipient is allocated funds
/// @param recipientId The id of the recipient
/// @param amount The amount of tokens allocated
/// @param token The address of the token
/// @param sender The sender of the transaction
/// @param origin The original sender of the transaction
event Allocated(address indexed recipientId, uint256 amount, address token, address sender, address origin);
/// ================================
/// ========== Storage =============
/// ================================
/// @notice Metadata containing the distribution data.
Metadata public distributionMetadata;
/// @notice Flag to indicate whether to use the registry anchor or not.
bool public useRegistryAnchor;
/// @notice Flag to indicate whether metadata is required or not.
bool public metadataRequired;
/// @notice Flag to indicate whether the distribution has started or not.
bool public distributionStarted;
/// @notice The timestamps in seconds for the start and end times.
uint64 public registrationStartTime;
uint64 public registrationEndTime;
uint64 public allocationStartTime;
uint64 public allocationEndTime;
/// @notice The total amount of tokens allocated to the payout.
uint256 public totalPayoutAmount;
/// @notice The total number of recipients.
uint256 public recipientsCounter;
/// @notice The registry contract interface.
IRegistry private _registry;
/// @notice the permit2 interface
ISignatureTransfer public immutable PERMIT2;
/// @notice The merkle root of the distribution will be set by the pool manager.
bytes32 public merkleRoot;
/// @notice This is a packed array of booleans, 'statuses[0]' is the first row of the bitmap and allows to
/// store 256 bits to describe the status of 256 projects. 'statuses[1]' is the second row, and so on
/// Instead of using 1 bit for each recipient status, we will use 4 bits for each status
/// to allow 5 statuses:
/// 0: none
/// 1: pending
/// 2: accepted
/// 3: rejected
/// 4: appealed
/// Since it's a mapping the storage it's pre-allocated with zero values, so if we check the
/// status of an existing recipient, the value is by default 0 (none).
/// If we want to check the status of an recipient, we take its index from the `recipients` array
/// and convert it to the 2-bits position in the bitmap.
mapping(uint256 => uint256) public statusesBitMap;
/// @notice 'recipientId' => 'statusIndex'
/// @dev 'statusIndex' is the index of the recipient in the 'statusesBitMap' bitmap.
mapping(address => uint256) public recipientToStatusIndexes;
/// @notice This is a packed array of booleans to keep track of claims distributed.
/// @dev distributedBitMap[0] is the first row of the bitmap and allows to store 256 bits to describe
/// the status of 256 claims
mapping(uint256 => uint256) private distributedBitMap;
/// @notice 'token' address => boolean (allowed = true).
/// @dev This can be updated by the pool manager.
mapping(address => bool) public allowedTokens;
/// @notice 'recipientId' => 'Recipient' struct.
mapping(address => Recipient) internal _recipients;
/// ================================
/// ========== Modifier ============
/// ================================
/// @notice Modifier to check if the registration is active
/// @dev This will revert if the registration has not started or if the registration has ended.
modifier onlyActiveRegistration() {
_checkOnlyActiveRegistration();
_;
}
/// @notice Modifier to check if the allocation is active
/// @dev This will revert if the allocation has not started or if the allocation has ended.
modifier onlyActiveAllocation() {
_checkOnlyActiveAllocation();
_;
}
/// @notice Modifier to check if the allocation has ended
/// @dev This will revert if the allocation has not ended.
modifier onlyAfterAllocation() {
_checkOnlyAfterAllocation();
_;
}
/// @notice Modifier to check if the allocation has ended
/// @dev This will revert if the allocation has ended.
modifier onlyBeforeAllocationEnds() {
_checkOnlyBeforeAllocationEnds();
_;
}
/// ===============================
/// ======== Constructor ==========
/// ===============================
/// @notice Constructor for the Donation Voting Merkle Distribution Strategy
/// @param _allo The 'Allo' contract
/// @param _name The name of the strategy
constructor(address _allo, string memory _name, ISignatureTransfer _permit2) BaseStrategy(_allo, _name) {
if (address(_permit2) == address(0)) revert ZERO_ADDRESS();
PERMIT2 = _permit2;
}
/// ===============================
/// ========= Initialize ==========
/// ===============================
/// @notice Initializes the strategy
/// @dev This will revert if the strategy is already initialized and 'msg.sender' is not the 'Allo' contract.
/// @param _poolId The 'poolId' to initialize
/// @param _data The data to be decoded to initialize the strategy
/// @custom:data InitializeData(bool _useRegistryAnchor, bool _metadataRequired, uint64 _registrationStartTime,
/// uint64 _registrationEndTime, uint64 _allocationStartTime, uint64 _allocationEndTime,
/// address[] memory _allowedTokens)
function initialize(uint256 _poolId, bytes memory _data) external virtual override onlyAllo {
InitializeData memory initializeData = abi.decode(_data, (InitializeData));
__DonationVotingStrategy_init(_poolId, initializeData);
emit Initialized(_poolId, _data);
}
/// @notice Initializes this strategy as well as the BaseStrategy.
/// @dev This will revert if the strategy is already initialized. Emits a 'TimestampsUpdated()' event.
/// @param _poolId The 'poolId' to initialize
/// @param _initializeData The data to be decoded to initialize the strategy
function __DonationVotingStrategy_init(uint256 _poolId, InitializeData memory _initializeData) internal {
// Initialize the BaseStrategy with the '_poolId'
__BaseStrategy_init(_poolId);
// Initialize required values
useRegistryAnchor = _initializeData.useRegistryAnchor;
metadataRequired = _initializeData.metadataRequired;
_registry = allo.getRegistry();
// Set the updated timestamps
registrationStartTime = _initializeData.registrationStartTime;
registrationEndTime = _initializeData.registrationEndTime;
allocationStartTime = _initializeData.allocationStartTime;
allocationEndTime = _initializeData.allocationEndTime;
recipientsCounter = 1;
// If the timestamps are invalid this will revert - See details in '_isPoolTimestampValid'
_isPoolTimestampValid(registrationStartTime, registrationEndTime, allocationStartTime, allocationEndTime);
// Emit that the timestamps have been updated with the updated values
emit TimestampsUpdated(
registrationStartTime, registrationEndTime, allocationStartTime, allocationEndTime, msg.sender
);
uint256 allowedTokensLength = _initializeData.allowedTokens.length;
// If the length of the allowed tokens is zero, we will allow all tokens
if (allowedTokensLength == 0) {
// all tokens
allowedTokens[address(0)] = true;
}
// Loop through the allowed tokens and set them to true
for (uint256 i; i < allowedTokensLength;) {
allowedTokens[_initializeData.allowedTokens[i]] = true;
unchecked {
i++;
}
}
}
/// ===============================
/// ============ Views ============
/// ===============================
/// @notice Get a recipient with a '_recipientId'
/// @param _recipientId ID of the recipient
/// @return recipient The recipient details
function getRecipient(address _recipientId) external view returns (Recipient memory recipient) {
return _getRecipient(_recipientId);
}
/// @notice Get recipient status
/// @dev This will return the 'Status' of the recipient, the 'Status' is used at the strategy
/// level and is different from the 'Status' which is used at the protocol level
/// @param _recipientId ID of the recipient
/// @return Status of the recipient
function _getRecipientStatus(address _recipientId) internal view override returns (Status) {
return Status(_getUintRecipientStatus(_recipientId));
}
/// ===============================
/// ======= External/Custom =======
/// ===============================
/// @notice Sets recipient statuses.
/// @dev The statuses are stored in a bitmap of 4 bits for each recipient. The first 4 bits of the 256 bits represent
/// the status of the first recipient, the second 4 bits represent the status of the second recipient, and so on.
/// 'msg.sender' must be a pool manager and the registration must be active.
/// Statuses:
/// - 0: none
/// - 1: pending
/// - 2: accepted
/// - 3: rejected
/// - 4: appealed
/// Emits the RecipientStatusUpdated() event.
/// @param statuses new statuses
/// @param refRecipientsCounter the recipientCounter the transaction is based on
function reviewRecipients(ApplicationStatus[] memory statuses, uint256 refRecipientsCounter)
external
onlyBeforeAllocationEnds
onlyPoolManager(msg.sender)
{
if (refRecipientsCounter != recipientsCounter) revert INVALID();
// Loop through the statuses and set the status
for (uint256 i; i < statuses.length;) {
uint256 rowIndex = statuses[i].index;
uint256 fullRow = statuses[i].statusRow;
statusesBitMap[rowIndex] = fullRow;
// Emit that the recipient status has been updated with the values
emit RecipientStatusUpdated(rowIndex, fullRow, msg.sender);
unchecked {
i++;
}
}
}
/// @notice Sets the start and end dates.
/// @dev The timestamps are in seconds for the start and end times. The 'msg.sender' must be a pool manager.
/// Emits a 'TimestampsUpdated()' event.
/// @param _registrationStartTime The start time for the registration
/// @param _registrationEndTime The end time for the registration
/// @param _allocationStartTime The start time for the allocation
/// @param _allocationEndTime The end time for the allocation
function updatePoolTimestamps(
uint64 _registrationStartTime,
uint64 _registrationEndTime,
uint64 _allocationStartTime,
uint64 _allocationEndTime
) external onlyPoolManager(msg.sender) {
// If the timestamps are invalid this will revert - See details in '_isPoolTimestampValid'
_isPoolTimestampValid(_registrationStartTime, _registrationEndTime, _allocationStartTime, _allocationEndTime);
// Set the updated timestamps
registrationStartTime = _registrationStartTime;
registrationEndTime = _registrationEndTime;
allocationStartTime = _allocationStartTime;
allocationEndTime = _allocationEndTime;
// Emit that the timestamps have been updated with the updated values
emit TimestampsUpdated(
registrationStartTime, registrationEndTime, allocationStartTime, allocationEndTime, msg.sender
);
}
/// @notice Withdraw funds from pool
/// @dev This can only be called after the allocation has ended and 30 days have passed.
/// @param _token The token to be withdrawn
function withdraw(address _token) external onlyPoolManager(msg.sender) {
if (block.timestamp <= allocationEndTime + 30 days) {
revert INVALID();
}
// get the actual balance hold by the pool
uint256 amount = _getBalance(_token, address(this));
// get the token amount in vault which belong to the recipients
uint256 tokenInVault = _tokenAmountInVault(_token);
// calculate the amount which is accessible
uint256 accessableAmount = amount - tokenInVault;
// transfer the amount to the pool manager
_transferAmount(_token, msg.sender, accessableAmount);
}
/// @notice Internal function to return the token amount locked in vault
/// @dev This function will return 0 if all funds are accessible
/// @param _token The address of the token
function _tokenAmountInVault(address _token) internal view virtual returns (uint256);
/// ==================================
/// ============ Merkle ==============
/// ==================================
/// @notice Invoked by round operator to update the merkle root and distribution Metadata.
/// @dev This can only be called after the allocation has ended and 'msg.sender' must be a pool manager and allocation must have ended.
/// Emits a 'DistributionUpdated()' event.
/// @param _merkleRoot The merkle root of the distribution
/// @param _distributionMetadata The metadata of the distribution
function updateDistribution(bytes32 _merkleRoot, Metadata memory _distributionMetadata)
external
onlyAfterAllocation
onlyPoolManager(msg.sender)
{
// If the distribution has already started this will revert, you can only
// update the distribution before it has started
if (distributionStarted) {
revert INVALID();
}
merkleRoot = _merkleRoot;
distributionMetadata = _distributionMetadata;
// Emit that the distribution has been updated
emit DistributionUpdated(merkleRoot, distributionMetadata);
}
/// @notice Checks if distribution is set.
/// @return 'true' if distribution is set, otherwise 'false'
function isDistributionSet() external view returns (bool) {
return merkleRoot != "";
}
/// @notice Utility function to check if distribution is done.
/// @param _index index of the distribution
/// @return 'true' if distribution is completed, otherwise 'false'
function hasBeenDistributed(uint256 _index) external view returns (bool) {
return _hasBeenDistributed(_index);
}
/// ====================================
/// ============ Internal ==============
/// ====================================
/// @notice Checks if the registration is active and reverts if not.
/// @dev This will revert if the registration has not started or if the registration has ended.
function _checkOnlyActiveRegistration() internal view {
if (registrationStartTime > block.timestamp || block.timestamp > registrationEndTime) {
revert REGISTRATION_NOT_ACTIVE();
}
}
/// @notice Checks if the allocation is active and reverts if not.
/// @dev This will revert if the allocation has not started or if the allocation has ended.
function _checkOnlyActiveAllocation() internal view {
if (allocationStartTime > block.timestamp || block.timestamp > allocationEndTime) {
revert ALLOCATION_NOT_ACTIVE();
}
}
/// @notice Checks if the allocation has ended and reverts if not.
/// @dev This will revert if the allocation has not ended.
function _checkOnlyAfterAllocation() internal view {
if (block.timestamp <= allocationEndTime) {
revert ALLOCATION_NOT_ENDED();
}
}
/// @notice Checks if the allocation has not ended and reverts if it has.
/// @dev This will revert if the allocation has ended.
function _checkOnlyBeforeAllocationEnds() internal view {
if (block.timestamp > allocationEndTime) {
revert ALLOCATION_NOT_ACTIVE();
}
}
/// @notice Checks if address is eligible allocator.
/// @return Always returns true for this strategy
function _isValidAllocator(address) internal pure override returns (bool) {
return true;
}
/// @notice Checks if the timestamps are valid.
/// @dev This will revert if any of the timestamps are invalid. This is determined by the strategy
/// and may vary from strategy to strategy. Checks if '_registrationStartTime' is greater than the '_registrationEndTime'
/// or if '_registrationStartTime' is greater than the '_allocationStartTime' or if '_registrationEndTime'
/// is greater than the '_allocationEndTime' or if '_allocationStartTime' is greater than the '_allocationEndTime'.
/// If any of these conditions are true, this will revert.
/// @param _registrationStartTime The start time for the registration
/// @param _registrationEndTime The end time for the registration
/// @param _allocationStartTime The start time for the allocation
/// @param _allocationEndTime The end time for the allocation
function _isPoolTimestampValid(
uint64 _registrationStartTime,
uint64 _registrationEndTime,
uint64 _allocationStartTime,
uint64 _allocationEndTime
) internal pure {
if (
_registrationStartTime > _registrationEndTime || _registrationStartTime > _allocationStartTime
|| _allocationStartTime > _allocationEndTime || _registrationEndTime > _allocationEndTime
) {
revert INVALID();
}
}
/// @notice Checks whether a pool is active or not.
/// @dev This will return true if the current 'block timestamp' is greater than or equal to the
/// 'registrationStartTime' and less than or equal to the 'registrationEndTime'.
/// @return 'true' if pool is active, otherwise 'false'
function _isPoolActive() internal view override returns (bool) {
if (registrationStartTime <= block.timestamp && block.timestamp <= registrationEndTime) {
return true;
}
return false;
}
/// @notice Submit recipient to pool and set their status.
/// @param _data The data to be decoded.
/// @custom:data if 'useRegistryAnchor' is 'true' (address recipientId, address recipientAddress, Metadata metadata)
/// @custom:data if 'useRegistryAnchor' is 'false' (address registryAnchor, address recipientAddress, Metadata metadata)
/// @param _sender The sender of the transaction
/// @return recipientId The ID of the recipient
function _registerRecipient(bytes memory _data, address _sender)
internal
override
onlyActiveRegistration
returns (address recipientId)
{
bool isUsingRegistryAnchor;
address recipientAddress;
address registryAnchor;
Metadata memory metadata;
// decode data custom to this strategy
if (useRegistryAnchor) {
(recipientId, recipientAddress, metadata) = abi.decode(_data, (address, address, Metadata));
// If the sender is not a profile member this will revert
if (!_isProfileMember(recipientId, _sender)) {
revert UNAUTHORIZED();
}
} else {
(registryAnchor, recipientAddress, metadata) = abi.decode(_data, (address, address, Metadata));
// Set this to 'true' if the registry anchor is not the zero address
isUsingRegistryAnchor = registryAnchor != address(0);
// If using the 'registryAnchor' we set the 'recipientId' to the 'registryAnchor', otherwise we set it to the 'msg.sender'
recipientId = isUsingRegistryAnchor ? registryAnchor : _sender;
// Checks if the '_sender' is a member of the profile 'anchor' being used and reverts if not
if (isUsingRegistryAnchor && !_isProfileMember(recipientId, _sender)) {
revert UNAUTHORIZED();
}
}
// If the metadata is required and the metadata is invalid this will revert
if (metadataRequired && (bytes(metadata.pointer).length == 0 || metadata.protocol == 0)) {
revert INVALID_METADATA();
}
// If the recipient address is the zero address this will revert
if (recipientAddress == address(0)) {
revert RECIPIENT_ERROR(recipientId);
}
// Get the recipient
Recipient storage recipient = _recipients[recipientId];
// update the recipients data
recipient.recipientAddress = recipientAddress;
recipient.metadata = metadata;
recipient.useRegistryAnchor = useRegistryAnchor ? true : isUsingRegistryAnchor;
if (recipientToStatusIndexes[recipientId] == 0) {
// recipient registering new application
recipientToStatusIndexes[recipientId] = recipientsCounter;
_setRecipientStatus(recipientId, uint8(Status.Pending));
bytes memory extendedData = abi.encode(_data, recipientsCounter);
emit Registered(recipientId, extendedData, _sender);
recipientsCounter++;
} else {
uint8 currentStatus = _getUintRecipientStatus(recipientId);
if (currentStatus == uint8(Status.Accepted)) {
// recipient updating accepted application
_setRecipientStatus(recipientId, uint8(Status.Pending));
} else if (currentStatus == uint8(Status.Rejected)) {
// recipient updating rejected application
_setRecipientStatus(recipientId, uint8(Status.Appealed));
}
emit UpdatedRegistration(recipientId, _data, _sender, _getUintRecipientStatus(recipientId));
}
}
/// @notice Distribute funds to recipients.
/// @dev 'distributionStarted' will be set to 'true' when called. Only the pool manager can call.
/// Emits a 'BatchPayoutSuccessful()' event.
/// @param _data The data to be decoded
/// @custom:data '(Distribution[] distributions)'
/// @param _sender The sender of the transaction
function _distribute(address[] memory, bytes memory _data, address _sender)
internal
virtual
override
onlyPoolManager(_sender)
{
if (merkleRoot == "") revert INVALID();
if (!distributionStarted) {
distributionStarted = true;
}
// Decode the '_data' to get the distributions
Distribution[] memory distributions = abi.decode(_data, (Distribution[]));
uint256 length = distributions.length;
// Loop through the distributions and distribute the funds
for (uint256 i; i < length;) {
_distributeSingle(distributions[i]);
unchecked {
i++;
}
}
// Emit that the batch payout was successful
emit BatchPayoutSuccessful(_sender);
}
/// @notice Allocate tokens to recipient.
/// @dev This can only be called during the allocation period. Emts an 'Allocated()' event.
/// @param _data The data to be decoded
/// @custom:data (address recipientId, uint256 amount, address token)
/// @param _sender The sender of the transaction
function _allocate(bytes memory _data, address _sender) internal virtual override onlyActiveAllocation {
// Decode the '_data' to get the recipientId, amount and token
(address recipientId,, Permit2Data memory p2Data) = abi.decode(_data, (address, PermitType, Permit2Data));
uint256 amount = p2Data.permit.permitted.amount;
address token = p2Data.permit.permitted.token;
// If the recipient status is not 'Accepted' this will revert, the recipient must be accepted through registration
if (Status(_getUintRecipientStatus(recipientId)) != Status.Accepted) {
revert RECIPIENT_ERROR(recipientId);
}
// The token must be in the allowed token list and not be native token or zero address
if (!allowedTokens[token] && !allowedTokens[address(0)]) {
revert INVALID();
}
// If the token is native, the amount must be equal to the value sent, otherwise it reverts
if ((msg.value > 0 && token != NATIVE) || (token == NATIVE && msg.value != amount)) {
revert INVALID();
}
// Emit that the amount has been allocated to the recipient by the sender
emit Allocated(recipientId, amount, token, _sender, tx.origin);
}
/// @notice Check if sender is profile owner or member.
/// @param _anchor Anchor of the profile
/// @param _sender The sender of the transaction
/// @return 'true' if the '_sender' is a profile member, otherwise 'false'
function _isProfileMember(address _anchor, address _sender) internal view virtual returns (bool) {
IRegistry.Profile memory profile = _registry.getProfileByAnchor(_anchor);
return _registry.isOwnerOrMemberOfProfile(profile.id, _sender);
}
/// @notice Get the recipient details.
/// @param _recipientId Id of the recipient
/// @return Recipient details
function _getRecipient(address _recipientId) internal view returns (Recipient memory) {
return _recipients[_recipientId];
}
/// @notice Returns the payout summary for the accepted recipient.
/// @param _data The data to be decoded
/// @custom:data '(Distribution)'
/// @return 'PayoutSummary' for a recipient
function _getPayout(address, bytes memory _data) internal view override returns (PayoutSummary memory) {
// Decode the '_data' to get the distribution
Distribution memory distribution = abi.decode(_data, (Distribution));
uint256 index = distribution.index;
address recipientId = distribution.recipientId;
uint256 amount = distribution.amount;
bytes32[] memory merkleProof = distribution.merkleProof;
address recipientAddress = _getRecipient(recipientId).recipientAddress;
// Validate the distribution
if (_validateDistribution(index, recipientId, recipientAddress, amount, merkleProof)) {
// Return a 'PayoutSummary' with the 'recipientAddress' and 'amount'
return PayoutSummary(recipientAddress, amount);
}
// If the distribution is not valid, return a payout summary with the amount set to zero
return PayoutSummary(recipientAddress, 0);
}
/// @notice Validate the distribution for the payout.
/// @param _index index of the distribution
/// @param _recipientId Id of the recipient
/// @param _recipientAddress Address of the recipient
/// @param _amount Amount of tokens to be distributed
/// @param _merkleProof Merkle proof of the distribution
/// @return 'true' if the distribution is valid, otherwise 'false'
function _validateDistribution(
uint256 _index,
address _recipientId,
address _recipientAddress,
uint256 _amount,
bytes32[] memory _merkleProof
) internal view returns (bool) {
// If the '_index' has been distributed this will return 'false'
if (_hasBeenDistributed(_index)) {
return false;
}
// Generate the node that will be verified in the 'merkleRoot'
bytes32 node = keccak256(bytes.concat(keccak256(abi.encode(_index, _recipientId, _recipientAddress, _amount))));
// If the node is not verified in the 'merkleRoot' this will return 'false'
if (!MerkleProof.verify(_merkleProof, merkleRoot, node)) {
return false;
}
// Return 'true', the distribution is valid at this point
return true;
}
/// @notice Check if the distribution has been distributed.
/// @param _index index of the distribution
/// @return 'true' if the distribution has been distributed, otherwise 'false'
function _hasBeenDistributed(uint256 _index) internal view returns (bool) {
// Get the word index by dividing the '_index' by 256
uint256 distributedWordIndex = _index / 256;
// Get the bit index by getting the remainder of the '_index' divided by 256
uint256 distributedBitIndex = _index % 256;
// Get the word from the 'distributedBitMap' using the 'distributedWordIndex'
uint256 distributedWord = distributedBitMap[distributedWordIndex];
// Get the mask by shifting 1 to the left of the 'distributedBitIndex'
uint256 mask = (1 << distributedBitIndex);
// Return 'true' if the 'distributedWord' and 'mask' are equal to the 'mask'
return distributedWord & mask == mask;
}
/// @notice Mark distribution as done.
/// @param _index index of the distribution
function _setDistributed(uint256 _index) private {
// Get the word index by dividing the '_index' by 256
uint256 distributedWordIndex = _index / 256;
// Get the bit index by getting the remainder of the '_index' divided by 256
uint256 distributedBitIndex = _index % 256;
// Set the bit in the 'distributedBitMap' shifting 1 to the left of the 'distributedBitIndex'
distributedBitMap[distributedWordIndex] |= (1 << distributedBitIndex);
}
/// @notice Distribute funds to recipient.
/// @dev Emits a 'FundsDistributed()' event
/// @param _distribution Distribution to be distributed
function _distributeSingle(Distribution memory _distribution) private {
uint256 index = _distribution.index;
address recipientId = _distribution.recipientId;
uint256 amount = _distribution.amount;
bytes32[] memory merkleProof = _distribution.merkleProof;
address recipientAddress = _recipients[recipientId].recipientAddress;
// Validate the distribution and transfer the funds to the recipient, otherwise revert if not valid
if (_validateDistribution(index, recipientId, recipientAddress, amount, merkleProof)) {
IAllo.Pool memory pool = allo.getPool(poolId);
// Set the distribution as distributed
_setDistributed(index);
// Update the pool amount
poolAmount -= amount;
// Transfer the amount to the recipient
_transferAmount(pool.token, payable(recipientAddress), amount);
// Emit that the funds have been distributed to the recipient
emit FundsDistributed(amount, recipientAddress, pool.token, recipientId);
} else {
revert RECIPIENT_ERROR(recipientId);
}
}
/// @notice Set the recipient status.
/// @param _recipientId ID of the recipient
/// @param _status Status of the recipient
function _setRecipientStatus(address _recipientId, uint256 _status) internal {
// Get the row index, column index and current row
(uint256 rowIndex, uint256 colIndex, uint256 currentRow) = _getStatusRowColumn(_recipientId);
// Calculate the 'newRow'
uint256 newRow = currentRow & ~(15 << colIndex);
// Add the status to the mapping
statusesBitMap[rowIndex] = newRow | (_status << colIndex);
}
/// @notice Get recipient status
/// @param _recipientId ID of the recipient
/// @return status The status of the recipient
function _getUintRecipientStatus(address _recipientId) internal view returns (uint8 status) {
if (recipientToStatusIndexes[_recipientId] == 0) return 0;
// Get the column index and current row
(, uint256 colIndex, uint256 currentRow) = _getStatusRowColumn(_recipientId);
// Get the status from the 'currentRow' shifting by the 'colIndex'
status = uint8((currentRow >> colIndex) & 15);
// Return the status
return status;
}
/// @notice Get recipient status 'rowIndex', 'colIndex' and 'currentRow'.
/// @param _recipientId ID of the recipient
/// @return (rowIndex, colIndex, currentRow)
function _getStatusRowColumn(address _recipientId) internal view returns (uint256, uint256, uint256) {
uint256 recipientIndex = recipientToStatusIndexes[_recipientId] - 1;
uint256 rowIndex = recipientIndex / 64; // 256 / 4
uint256 colIndex = (recipientIndex % 64) * 4;
return (rowIndex, colIndex, statusesBitMap[rowIndex]);
}
/// @notice Contract should be able to receive NATIVE
receive() external payable {}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;
interface IDAI {
function permit(
address holder,
address spender,
uint256 nonce,
uint256 expiry,
bool allowed,
uint8 v,
bytes32 r,
bytes32 s
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// 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 IERC20 {
/**
* @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 Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.2) (utils/cryptography/MerkleProof.sol)
pragma solidity ^0.8.0;
/**
* @dev These functions deal with verification of Merkle Tree proofs.
*
* The tree and the proofs can be generated using our
* https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
* You will find a quickstart guide in the readme.
*
* WARNING: You should avoid using leaf values that are 64 bytes long prior to
* hashing, or use a hash function other than keccak256 for hashing leaves.
* This is because the concatenation of a sorted pair of internal nodes in
* the merkle tree could be reinterpreted as a leaf value.
* OpenZeppelin's JavaScript library generates merkle trees that are safe
* against this attack out of the box.
*/
library MerkleProof {
/**
* @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
* defined by `root`. For this, a `proof` must be provided, containing
* sibling hashes on the branch from the leaf to the root of the tree. Each
* pair of leaves and each pair of pre-images are assumed to be sorted.
*/
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
/**
* @dev Calldata version of {verify}
*
* _Available since v4.7._
*/
function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
/**
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. When processing the proof, the pairs
* of leafs & pre-images are assumed to be sorted.
*
* _Available since v4.4._
*/
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Calldata version of {processProof}
*
* _Available since v4.7._
*/
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by
* `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
/**
* @dev Calldata version of {multiProofVerify}
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
/**
* @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
* proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
* leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
* respectively.
*
* CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
* is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
* tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
*
* _Available since v4.7._
*/
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the merkle tree.
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proofLen - 1 == totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
require(proofPos == proofLen, "MerkleProof: invalid multiproof");
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
/**
* @dev Calldata version of {processMultiProof}.
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the merkle tree.
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proofLen - 1 == totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
require(proofPos == proofLen, "MerkleProof: invalid multiproof");
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Multicall.sol)
pragma solidity ^0.8.0;
import "./Address.sol";
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* _Available since v4.1._
*/
abstract contract Multicall {
/**
* @dev Receives and executes a batch of function calls on this contract.
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = Address.functionDelegateCall(address(this), data[i]);
}
return results;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface IEIP712 {
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import {IEIP712} from "./IEIP712.sol";
/// @title SignatureTransfer
/// @notice Handles ERC20 token transfers through signature based actions
/// @dev Requires user's token approval on the Permit2 contract
interface ISignatureTransfer is IEIP712 {
/// @notice Thrown when the requested amount for a transfer is larger than the permissioned amount
/// @param maxAmount The maximum amount a spender can request to transfer
error InvalidAmount(uint256 maxAmount);
/// @notice Thrown when the number of tokens permissioned to a spender does not match the number of tokens being transferred
/// @dev If the spender does not need to transfer the number of tokens permitted, the spender can request amount 0 to be transferred
error LengthMismatch();
/// @notice Emits an event when the owner successfully invalidates an unordered nonce.
event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);
/// @notice The token and amount details for a transfer signed in the permit transfer signature
struct TokenPermissions {
// ERC20 token address
address token;
// the maximum amount that can be spent
uint256 amount;
}
/// @notice The signed permit message for a single token transfer
struct PermitTransferFrom {
TokenPermissions permitted;
// a unique value for every token owner's signature to prevent signature replays
uint256 nonce;
// deadline on the permit signature
uint256 deadline;
}
/// @notice Specifies the recipient address and amount for batched transfers.
/// @dev Recipients and amounts correspond to the index of the signed token permissions array.
/// @dev Reverts if the requested amount is greater than the permitted signed amount.
struct SignatureTransferDetails {
// recipient address
address to;
// spender requested amount
uint256 requestedAmount;
}
/// @notice Used to reconstruct the signed permit message for multiple token transfers
/// @dev Do not need to pass in spender address as it is required that it is msg.sender
/// @dev Note that a user still signs over a spender address
struct PermitBatchTransferFrom {
// the tokens and corresponding amounts permitted for a transfer
TokenPermissions[] permitted;
// a unique value for every token owner's signature to prevent signature replays
uint256 nonce;
// deadline on the permit signature
uint256 deadline;
}
/// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection
/// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order
/// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce
/// @dev It returns a uint256 bitmap
/// @dev The index, or wordPosition is capped at type(uint248).max
function nonceBitmap(address, uint256) external view returns (uint256);
/// @notice Transfers a token using a signed permit message
/// @dev Reverts if the requested amount is greater than the permitted signed amount
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails The spender's requested transfer details for the permitted token
/// @param signature The signature to verify
function permitTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external;
/// @notice Transfers a token using a signed permit message
/// @notice Includes extra data provided by the caller to verify signature over
/// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition
/// @dev Reverts if the requested amount is greater than the permitted signed amount
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails The spender's requested transfer details for the permitted token
/// @param witness Extra data to include when checking the user signature
/// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash
/// @param signature The signature to verify
function permitWitnessTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes32 witness,
string calldata witnessTypeString,
bytes calldata signature
) external;
/// @notice Transfers multiple tokens using a signed permit message
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails Specifies the recipient and requested amount for the token transfer
/// @param signature The signature to verify
function permitTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes calldata signature
) external;
/// @notice Transfers multiple tokens using a signed permit message
/// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition
/// @notice Includes extra data provided by the caller to verify signature over
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails Specifies the recipient and requested amount for the token transfer
/// @param witness Extra data to include when checking the user signature
/// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash
/// @param signature The signature to verify
function permitWitnessTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes32 witness,
string calldata witnessTypeString,
bytes calldata signature
) external;
/// @notice Invalidates the bits specified in mask for the bitmap at the word position
/// @dev The wordPos is maxed at type(uint248).max
/// @param wordPos A number to index the nonceBitmap at
/// @param mask A bitmap masked against msg.sender's current bitmap at the word position
function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for gas griefing protection.
/// - For ERC20s, this implementation won't check that a token has code,
/// responsibility is delegated to the caller.
library SafeTransferLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ETH transfer has failed.
error ETHTransferFailed();
/// @dev The ERC20 `transferFrom` has failed.
error TransferFromFailed();
/// @dev The ERC20 `transfer` has failed.
error TransferFailed();
/// @dev The ERC20 `approve` has failed.
error ApproveFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Suggested gas stipend for contract receiving ETH
/// that disallows any storage writes.
uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;
/// @dev Suggested gas stipend for contract receiving ETH to perform a few
/// storage reads and writes, but low enough to prevent griefing.
/// Multiply by a small constant (e.g. 2), if needed.
uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ETH OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sends `amount` (in wei) ETH to `to`.
/// Reverts upon failure.
///
/// Note: This implementation does NOT protect against gas griefing.
/// Please use `forceSafeTransferETH` for gas griefing protection.
function safeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
// Transfer the ETH and check if it succeeded or not.
if iszero(call(gas(), to, amount, 0x00, 0x00, 0x00, 0x00)) {
// Store the function selector of `ETHTransferFailed()`.
mstore(0x00, 0xb12d13eb)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
/// The `gasStipend` can be set to a low enough value to prevent
/// storage writes or gas griefing.
///
/// If sending via the normal procedure fails, force sends the ETH by
/// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH.
///
/// Reverts if the current contract has insufficient balance.
function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
// If insufficient balance, revert.
if lt(selfbalance(), amount) {
// Store the function selector of `ETHTransferFailed()`.
mstore(0x00, 0xb12d13eb)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Transfer the ETH and check if it succeeded or not.
if iszero(call(gasStipend, to, amount, 0x00, 0x00, 0x00, 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
// We can directly use `SELFDESTRUCT` in the contract creation.
// Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758
if iszero(create(amount, 0x0b, 0x16)) {
// To coerce gas estimation to provide enough gas for the `create` above.
if iszero(gt(gas(), 1000000)) { revert(0x00, 0x00) }
}
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with a gas stipend
/// equal to `GAS_STIPEND_NO_GRIEF`. This gas stipend is a reasonable default
/// for 99% of cases and can be overridden with the three-argument version of this
/// function if necessary.
///
/// If sending via the normal procedure fails, force sends the ETH by
/// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH.
///
/// Reverts if the current contract has insufficient balance.
function forceSafeTransferETH(address to, uint256 amount) internal {
// Manually inlined because the compiler doesn't inline functions with branches.
/// @solidity memory-safe-assembly
assembly {
// If insufficient balance, revert.
if lt(selfbalance(), amount) {
// Store the function selector of `ETHTransferFailed()`.
mstore(0x00, 0xb12d13eb)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Transfer the ETH and check if it succeeded or not.
if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, 0x00, 0x00, 0x00, 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
// We can directly use `SELFDESTRUCT` in the contract creation.
// Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758
if iszero(create(amount, 0x0b, 0x16)) {
// To coerce gas estimation to provide enough gas for the `create` above.
if iszero(gt(gas(), 1000000)) { revert(0x00, 0x00) }
}
}
}
}
/// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
/// The `gasStipend` can be set to a low enough value to prevent
/// storage writes or gas griefing.
///
/// Simply use `gasleft()` for `gasStipend` if you don't need a gas stipend.
///
/// Note: Does NOT revert upon failure.
/// Returns whether the transfer of ETH is successful instead.
function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
// Transfer the ETH and check if it succeeded or not.
success := call(gasStipend, to, amount, 0x00, 0x00, 0x00, 0x00)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have at least `amount` approved for
/// the current contract to manage.
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, amount) // Store the `amount` argument.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
// Store the function selector of `transferFrom(address,address,uint256)`.
mstore(0x0c, 0x23b872dd000000000000000000000000)
if iszero(
and( // The arguments of `and` are evaluated from right to left.
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
// Store the function selector of `TransferFromFailed()`.
mstore(0x00, 0x7939f424)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends all of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have their entire balance approved for
/// the current contract to manage.
function safeTransferAllFrom(address token, address from, address to)
internal
returns (uint256 amount)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
// Store the function selector of `balanceOf(address)`.
mstore(0x0c, 0x70a08231000000000000000000000000)
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
)
) {
// Store the function selector of `TransferFromFailed()`.
mstore(0x00, 0x7939f424)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Store the function selector of `transferFrom(address,address,uint256)`.
mstore(0x00, 0x23b872dd)
// The `amount` is already at 0x60. Load it for the function's return value.
amount := mload(0x60)
if iszero(
and( // The arguments of `and` are evaluated from right to left.
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
// Store the function selector of `TransferFromFailed()`.
mstore(0x00, 0x7939f424)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransfer(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
// Store the function selector of `transfer(address,uint256)`.
mstore(0x00, 0xa9059cbb000000000000000000000000)
if iszero(
and( // The arguments of `and` are evaluated from right to left.
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
// Store the function selector of `TransferFailed()`.
mstore(0x00, 0x90b8ec18)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Restore the part of the free memory pointer that was overwritten.
mstore(0x34, 0)
}
}
/// @dev Sends all of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransferAll(address token, address to) internal returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
mstore(0x20, address()) // Store the address of the current contract.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
)
) {
// Store the function selector of `TransferFailed()`.
mstore(0x00, 0x90b8ec18)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
mstore(0x14, to) // Store the `to` argument.
// The `amount` is already at 0x34. Load it for the function's return value.
amount := mload(0x34)
// Store the function selector of `transfer(address,uint256)`.
mstore(0x00, 0xa9059cbb000000000000000000000000)
if iszero(
and( // The arguments of `and` are evaluated from right to left.
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
// Store the function selector of `TransferFailed()`.
mstore(0x00, 0x90b8ec18)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Restore the part of the free memory pointer that was overwritten.
mstore(0x34, 0)
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// Reverts upon failure.
function safeApprove(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
// Store the function selector of `approve(address,uint256)`.
mstore(0x00, 0x095ea7b3000000000000000000000000)
if iszero(
and( // The arguments of `and` are evaluated from right to left.
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
// Store the function selector of `ApproveFailed()`.
mstore(0x00, 0x3e3f8f73)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Restore the part of the free memory pointer that was overwritten.
mstore(0x34, 0)
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
/// then retries the approval again (some tokens, e.g. USDT, requires this).
/// Reverts upon failure.
function safeApproveWithRetry(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
// Store the function selector of `approve(address,uint256)`.
mstore(0x00, 0x095ea7b3000000000000000000000000)
if iszero(
and( // The arguments of `and` are evaluated from right to left.
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x34, 0) // Store 0 for the `amount`.
mstore(0x00, 0x095ea7b3000000000000000000000000) // Store the function selector.
// We can ignore the result of this call. Just need to check the next call.
pop(call(gas(), token, 0, 0x10, 0x44, 0x00, 0x00))
mstore(0x34, amount) // Store back the original `amount`.
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
// Store the function selector of `ApproveFailed()`.
mstore(0x00, 0x3e3f8f73)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
}
// Restore the part of the free memory pointer that was overwritten.
mstore(0x34, 0)
}
}
/// @dev Returns the amount of ERC20 `token` owned by `account`.
/// Returns zero if the `token` does not exist.
function balanceOf(address token, address account) internal view returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, account) // Store the `account` argument.
// Store the function selector of `balanceOf(address)`.
mstore(0x00, 0x70a08231000000000000000000000000)
amount :=
mul(
mload(0x20),
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
)
)
}
}
}{
"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":[{"internalType":"address","name":"_allo","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"contract ISignatureTransfer","name":"_permit2","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ALLOCATION_ACTIVE","type":"error"},{"inputs":[],"name":"ALLOCATION_NOT_ACTIVE","type":"error"},{"inputs":[],"name":"ALLOCATION_NOT_ENDED","type":"error"},{"inputs":[],"name":"ALREADY_INITIALIZED","type":"error"},{"inputs":[],"name":"AMOUNT_MISMATCH","type":"error"},{"inputs":[],"name":"ANCHOR_ERROR","type":"error"},{"inputs":[],"name":"ARRAY_MISMATCH","type":"error"},{"inputs":[],"name":"INVALID","type":"error"},{"inputs":[],"name":"INVALID_ADDRESS","type":"error"},{"inputs":[],"name":"INVALID_FEE","type":"error"},{"inputs":[],"name":"INVALID_METADATA","type":"error"},{"inputs":[],"name":"INVALID_REGISTRATION","type":"error"},{"inputs":[],"name":"IS_APPROVED_STRATEGY","type":"error"},{"inputs":[],"name":"MISMATCH","type":"error"},{"inputs":[],"name":"NONCE_NOT_AVAILABLE","type":"error"},{"inputs":[],"name":"NON_ZERO_VALUE","type":"error"},{"inputs":[],"name":"NOT_APPROVED_STRATEGY","type":"error"},{"inputs":[],"name":"NOT_ENOUGH_FUNDS","type":"error"},{"inputs":[],"name":"NOT_IMPLEMENTED","type":"error"},{"inputs":[],"name":"NOT_INITIALIZED","type":"error"},{"inputs":[],"name":"NOT_PENDING_OWNER","type":"error"},{"inputs":[],"name":"POOL_ACTIVE","type":"error"},{"inputs":[],"name":"POOL_INACTIVE","type":"error"},{"inputs":[],"name":"RECIPIENT_ALREADY_ACCEPTED","type":"error"},{"inputs":[{"internalType":"address","name":"recipientId","type":"address"}],"name":"RECIPIENT_ERROR","type":"error"},{"inputs":[],"name":"RECIPIENT_NOT_ACCEPTED","type":"error"},{"inputs":[],"name":"REGISTRATION_ACTIVE","type":"error"},{"inputs":[],"name":"REGISTRATION_NOT_ACTIVE","type":"error"},{"inputs":[],"name":"UNAUTHORIZED","type":"error"},{"inputs":[],"name":"ZERO_ADDRESS","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipientId","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"origin","type":"address"}],"name":"Allocated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipientId","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"Allocated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"BatchPayoutSuccessful","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipientId","type":"address"},{"indexed":false,"internalType":"address","name":"recipientAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"Distributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"indexed":false,"internalType":"struct Metadata","name":"metadata","type":"tuple"}],"name":"DistributionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"grantee","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"recipientId","type":"address"}],"name":"FundsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"PoolActive","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fullRow","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"RecipientStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipientId","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"Registered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"registrationStartTime","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"registrationEndTime","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"allocationStartTime","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"allocationEndTime","type":"uint64"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"TimestampsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipientId","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint8","name":"status","type":"uint8"}],"name":"UpdatedRegistration","type":"event"},{"inputs":[],"name":"NATIVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT2","outputs":[{"internalType":"contract ISignatureTransfer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"address","name":"_sender","type":"address"}],"name":"allocate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"allocationEndTime","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allocationStartTime","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowedTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_recipientIds","type":"address[]"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"address","name":"_sender","type":"address"}],"name":"distribute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"distributionMetadata","outputs":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"distributionStarted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllo","outputs":[{"internalType":"contract IAllo","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_recipientIds","type":"address[]"},{"internalType":"bytes[]","name":"_data","type":"bytes[]"}],"name":"getPayouts","outputs":[{"components":[{"internalType":"address","name":"recipientAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IStrategy.PayoutSummary[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPoolAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPoolId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipientId","type":"address"}],"name":"getRecipient","outputs":[{"components":[{"internalType":"bool","name":"useRegistryAnchor","type":"bool"},{"internalType":"address","name":"recipientAddress","type":"address"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"internalType":"struct Metadata","name":"metadata","type":"tuple"}],"internalType":"struct DonationVotingMerkleDistributionBaseStrategy.Recipient","name":"recipient","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipientId","type":"address"}],"name":"getRecipientStatus","outputs":[{"internalType":"enum IStrategy.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStrategyId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"hasBeenDistributed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"increasePoolAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isDistributionSet","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPoolActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_allocator","type":"address"}],"name":"isValidAllocator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataRequired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"recipientToStatusIndexes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"recipientsCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"address","name":"_sender","type":"address"}],"name":"registerRecipient","outputs":[{"internalType":"address","name":"recipientId","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"registrationEndTime","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registrationStartTime","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"statusRow","type":"uint256"}],"internalType":"struct DonationVotingMerkleDistributionBaseStrategy.ApplicationStatus[]","name":"statuses","type":"tuple[]"},{"internalType":"uint256","name":"refRecipientsCounter","type":"uint256"}],"name":"reviewRecipients","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"splitSignature","outputs":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"statusesBitMap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPayoutAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"internalType":"struct Metadata","name":"_distributionMetadata","type":"tuple"}],"name":"updateDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_registrationStartTime","type":"uint64"},{"internalType":"uint64","name":"_registrationEndTime","type":"uint64"},{"internalType":"uint64","name":"_allocationStartTime","type":"uint64"},{"internalType":"uint64","name":"_allocationEndTime","type":"uint64"}],"name":"updatePoolTimestamps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"useRegistryAnchor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60e06040523480156200001157600080fd5b50604051620043a5380380620043a5833981016040819052620000349162000122565b6001600160a01b038316608052604051839083908390839083906200005e90829060200162000204565b60408051601f19818403018152919052805160209091012060a05250506001600160a01b038116620000a35760405163538ba4f960e01b815260040160405180910390fd5b6001600160a01b031660c05250620002399350505050565b6001600160a01b0381168114620000d157600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000107578181015183820152602001620000ed565b50506000910152565b80516200011d81620000bb565b919050565b6000806000606084860312156200013857600080fd5b83516200014581620000bb565b60208501519093506001600160401b03808211156200016357600080fd5b818601915086601f8301126200017857600080fd5b8151818111156200018d576200018d620000d4565b604051601f8201601f19908116603f01168101908382118183101715620001b857620001b8620000d4565b81604052828152896020848701011115620001d257600080fd5b620001e5836020830160208801620000ea565b8096505050505050620001fb6040850162000110565b90509250925092565b602081526000825180602084015262000225816040850160208701620000ea565b601f01601f19169190910160400192915050565b60805160a05160c0516141196200028c600039600081816104df0152611d9b015260006103920152600081816102a601528181610f27015281816110900152818161186801526123a301526141196000f3fe6080604052600436106102295760003560e01c806373af345311610123578063df868ed3116100ab578063edd146cc1161006f578063edd146cc14610713578063ef2920fc14610733578063f31db3d114610746578063f5b0dfb714610766578063f6f258911461078657600080fd5b8063df868ed314610664578063dff7d2c714610679578063e744092e146106a0578063e7efcfc2146106d0578063eb11af93146106e657600080fd5b8063a7bb5803116100f2578063a7bb580314610586578063ac9650d8146105c4578063b2b878d0146105f1578063cb0e85a61461061e578063d2e17f591461063d57600080fd5b806373af34531461050157806395355b3b146105215780639af5c09d14610537578063a0cf0aea1461055e57600080fd5b806342fda9c7116101b15780635708973911610175578063570897391461044357806359a3977b1461045d5780635f1b55f31461048057806362812a39146104a05780636afdd850146104cd57600080fd5b806342fda9c7146103835780634533d678146103b65780634ab4ba42146103ee5780634d31d0871461040357806351cff8d91461042357600080fd5b806321755088116101f857806321755088146102fe5780632bbe0cae1461032e5780632d52eff2146103415780632eb4a7ab1461035857806338fff2d01461036e57600080fd5b806301fc1c64146102355780630a6f0ee91461027557806315cc481e146102975780632143e92f146102de57600080fd5b3661023057005b600080fd5b34801561024157600080fd5b50610262610250366004612c01565b600c6020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561028157600080fd5b50610295610290366004612e4a565b6107b3565b005b3480156102a357600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b03909116815260200161026c565b3480156102ea57600080fd5b506102956102f9366004612ed6565b6107d3565b34801561030a57600080fd5b5060055461031e9062010000900460ff1681565b604051901515815260200161026c565b6102c661033c366004612f32565b6108d0565b34801561034d57600080fd5b50600a54151561031e565b34801561036457600080fd5b50610262600a5481565b34801561037a57600080fd5b50600154610262565b34801561038f57600080fd5b507f0000000000000000000000000000000000000000000000000000000000000000610262565b3480156103c257600080fd5b506006546103d6906001600160401b031681565b6040516001600160401b03909116815260200161026c565b3480156103fa57600080fd5b50600254610262565b34801561040f57600080fd5b5061031e61041e366004612c01565b6108f5565b34801561042f57600080fd5b5061029561043e366004612c01565b6108fe565b34801561044f57600080fd5b5060055461031e9060ff1681565b34801561046957600080fd5b50610472610978565b60405161026c929190612fd3565b34801561048c57600080fd5b5061031e61049b366004612fec565b610a0f565b3480156104ac57600080fd5b506104c06104bb366004612c01565b610a1a565b60405161026c9190613005565b3480156104d957600080fd5b506102c67f000000000000000000000000000000000000000000000000000000000000000081565b34801561050d57600080fd5b5061029561051c366004613054565b610a2b565b34801561052d57600080fd5b5061026260085481565b34801561054357600080fd5b506005546103d690630100000090046001600160401b031681565b34801561056a57600080fd5b506102c673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b34801561059257600080fd5b506105a66105a13660046130f1565b610acd565b60408051938452602084019290925260ff169082015260600161026c565b3480156105d057600080fd5b506105e46105df366004613125565b610b7f565b60405161026c9190613199565b3480156105fd57600080fd5b5061061161060c3660046131fb565b610c73565b60405161026c91906132da565b34801561062a57600080fd5b5060055461031e90610100900460ff1681565b34801561064957600080fd5b506005546103d690600160981b90046001600160401b031681565b34801561067057600080fd5b5061031e610d71565b34801561068557600080fd5b506005546103d690600160581b90046001600160401b031681565b3480156106ac57600080fd5b5061031e6106bb366004612c01565b600e6020526000908152604090205460ff1681565b3480156106dc57600080fd5b5061026260075481565b3480156106f257600080fd5b50610706610701366004612c01565b610d80565b60405161026c9190613350565b34801561071f57600080fd5b5061029561072e366004613378565b610d8b565b610295610741366004612f32565b610de6565b34801561075257600080fd5b506102956107613660046133be565b610e0e565b34801561077257600080fd5b50610295610781366004612fec565b610ef2565b34801561079257600080fd5b506102626107a1366004612fec565b600b6020526000908152604090205481565b6107bb610f1c565b6107c3610f67565b6107ce838383610f8a565b505050565b336107dd81611066565b6107e985858585611118565b6005805472ffffffffffffffffffffffffffffffff000000191663010000006001600160401b03888116820267ffffffffffffffff60581b191692909217600160581b88841681029190911767ffffffffffffffff60981b1916600160981b888516810291909117948590556006805467ffffffffffffffff191688861690811790915560408051948704861685529286048516602085015294049092169181019190915260608101919091523360808201527fcb0fb7a7b87db2f472ee8977444cfdbc51993ce660aca27a5969a724fae6dcf39060a00160405180910390a15050505050565b60006108da610f1c565b6108e2610f67565b6108ec838361119f565b90505b92915050565b600060016108ef565b3361090881611066565b600654610921906001600160401b031662278d0061349b565b6001600160401b0316421161094957604051637fcce2a960e01b815260040160405180910390fd5b600061095583306114f1565b905060008061096482846134bb565b905061097185338361153a565b5050505050565b600380546004805491929161098c906134ce565b80601f01602080910402602001604051908101604052809291908181526020018280546109b8906134ce565b8015610a055780601f106109da57610100808354040283529160200191610a05565b820191906000526020600020905b8154815290600101906020018083116109e857829003601f168201915b5050505050905082565b60006108ef82611574565b610a22612ba6565b6108ef826115b5565b610a336116ae565b33610a3d81611066565b60055462010000900460ff1615610a6757604051637fcce2a960e01b815260040160405180910390fd5b600a839055815160039081556020830151839190600490610a88908261354e565b509050507fdc7180ca4affc84269428ed20ef950e745126f11691b010c4a7d49458421008f600a546003604051610ac092919061360d565b60405180910390a1505050565b60008060008351604103610b185783806020019051810190610aef91906136b2565b8551919450925084906040908110610b0957610b096136d6565b016020015160f81c9050610b78565b8351604003610b5f57600084806020019051810190610b3791906136b2565b9094506001600160ff1b03811693509050610b5760ff82901c601b6136ec565b915050610b78565b604051637fcce2a960e01b815260040160405180910390fd5b9193909250565b6060816001600160401b03811115610b9957610b99612c25565b604051908082528060200260200182016040528015610bcc57816020015b6060815260200190600190039081610bb75790505b50905060005b82811015610c6c57610c3c30858584818110610bf057610bf06136d6565b9050602002810190610c029190613705565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506116d992505050565b828281518110610c4e57610c4e6136d6565b60200260200101819052508080610c6490613752565b915050610bd2565b5092915050565b81518151606091908114610c9a57604051633da4c02b60e11b815260040160405180910390fd5b6000816001600160401b03811115610cb457610cb4612c25565b604051908082528060200260200182016040528015610cf957816020015b6040805180820190915260008082526020820152815260200190600190039081610cd25790505b50905060005b82811015610d6857610d43868281518110610d1c57610d1c6136d6565b6020026020010151868381518110610d3657610d366136d6565b60200260200101516116fe565b828281518110610d5557610d556136d6565b6020908102919091010152600101610cff565b50949350505050565b6000610d7b6117b9565b905090565b60006108ef82611802565b610d93610f1c565b600081806020019051810190610da99190613805565b9050610db58382611821565b7f91efa3d50feccde0d0d202f8ae5c41ca0b2be614cebcb2bd2f4b019396e6568a8383604051610ac0929190612fd3565b610dee610f1c565b610df6610f67565b610e008282611ad4565b610e0a8282611caa565b5050565b610e1661230f565b33610e2081611066565b6008548214610e4257604051637fcce2a960e01b815260040160405180910390fd5b60005b8351811015610eec576000848281518110610e6257610e626136d6565b60200260200101516000015190506000858381518110610e8457610e846136d6565b6020908102919091018101518101516000848152600b83526040908190208290558051828152339381019390935290925083917f941884a9a55191a7401466aaf8a0d2b7c8b082055a5a2b345b83c73940172ac4910160405180910390a25050600101610e45565b50505050565b610efa610f1c565b8060026000828254610f0c91906138d7565b90915550610f1990508181565b50565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f655760405163075fd2b160e01b815260040160405180910390fd5b565b600154600003610f6557604051630f68fe6360e21b815260040160405180910390fd5b80610f9481611066565b600a54600003610fb757604051637fcce2a960e01b815260040160405180910390fd5b60055462010000900460ff16610fd9576005805462ff00001916620100001790555b600083806020019051810190610fef91906139be565b805190915060005b8181101561102957611021838281518110611014576110146136d6565b602002602001015161233a565b600101610ff7565b506040516001600160a01b038516907f7ec3272052827f7b50d9e84f98172cbb80c112df1e377c5b97ea77f1812db8d990600090a2505050505050565b6001546040516329e40d4b60e01b815260048101919091526001600160a01b0382811660248301527f000000000000000000000000000000000000000000000000000000000000000016906329e40d4b90604401602060405180830381865afa1580156110d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110fb9190613a79565b610f195760405163075fd2b160e01b815260040160405180910390fd5b826001600160401b0316846001600160401b031611806111495750816001600160401b0316846001600160401b0316115b806111655750806001600160401b0316826001600160401b0316115b806111815750806001600160401b0316836001600160401b0316115b15610eec57604051637fcce2a960e01b815260040160405180910390fd5b60006111a96124d0565b60008060006111cb604051806040016040528060008152602001606081525090565b60055460ff161561121d57868060200190518101906111ea9190613b3a565b919650935090506111fb8587612520565b6112185760405163075fd2b160e01b815260040160405180910390fd5b611288565b868060200190518101906112319190613b3a565b6001600160a01b038316151596509094509092509050836112525785611254565b815b945083801561126a57506112688587612520565b155b156112885760405163075fd2b160e01b815260040160405180910390fd5b600554610100900460ff1680156112ab575060208101515115806112ab57508051155b156112c95760405163c19e07c560e01b815260040160405180910390fd5b6001600160a01b0383166113005760405163f4a513b960e01b81526001600160a01b03861660048201526024015b60405180910390fd5b6001600160a01b038086166000908152600f6020908152604090912080549286166101000274ffffffffffffffffffffffffffffffffffffffff0019909316929092178255825160018301908155908301518391906002840190611364908261354e565b505060055460ff169050611378578461137b565b60015b815460ff19169015151781556001600160a01b0386166000908152600c60205260408120549003611457576008546001600160a01b0387166000908152600c60205260409020556113d18660015b60ff16612618565b6000886008546040516020016113e8929190613b9d565b6040516020818303038152906040529050866001600160a01b03167fa197306e3dd5494a61a695381aa809a53b8e377a685e84e404a85d5a8da6cc62828a604051611434929190613bbf565b60405180910390a26008805490600061144c83613752565b9190505550506114e6565b60006114628761264b565b905060011960ff8216016114805761147b8760016113c9565b611497565b60021960ff821601611497576114978760046113c9565b866001600160a01b03167fcec1da3f7f0b8a344dd1025d06e2ddd48b14880395997ad97cbdb439acc761d48a8a6114cd8b61264b565b6040516114dc93929190613bea565b60405180910390a2505b505050505092915050565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0384160161152957506001600160a01b038116316108ef565b611533838361268c565b90506108ef565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601611569576107ce82826126c1565b6107ce8383836126dd565b60008061158361010084613c35565b9050600061159361010085613c49565b6000928352600d602052604090922054600190921b9182169091149392505050565b6115bd612ba6565b6001600160a01b038083166000908152600f60209081526040918290208251606081018452815460ff811615158252610100900490941684830152825180840184526001820180548252600283018054939587019492939192840191611622906134ce565b80601f016020809104026020016040519081016040528092919081815260200182805461164e906134ce565b801561169b5780601f106116705761010080835404028352916020019161169b565b820191906000526020600020905b81548152906001019060200180831161167e57829003601f168201915b5050509190925250505090525092915050565b6006546001600160401b03164211610f6557604051634543ced160e11b815260040160405180910390fd5b60606108ec83836040518060600160405280602781526020016140bd6027913961272c565b60408051808201909152600080825260208201526000828060200190518101906117289190613c5d565b80516020820151604083015160608401519394509192909190600061174c846115b5565b60200151905061175f85858386866127a4565b1561178f576040518060400160405280826001600160a01b031681526020018481525096505050505050506108ef565b604080518082019091526001600160a01b0390911681526000602082015298975050505050505050565b6005546000904263010000009091046001600160401b0316118015906117f15750600554600160581b90046001600160401b03164211155b156117fc5750600190565b50600090565b600061180d8261264b565b60ff1660068111156108ef576108ef61333a565b61182a8261284d565b80516005805460208085015161ffff1990921693151561ff001916939093176101009115159190910217905560408051635ab1bd5360e01b815290517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692635ab1bd5392600480820193918290030181865afa1580156118b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118db9190613c91565b6009805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03929092169190911790556040810151600580546060840151608085015172ffffffffffffffffffffffffffffffff0000001990921663010000006001600160401b03958616810267ffffffffffffffff60581b191691909117600160581b92861683021767ffffffffffffffff60981b1916600160981b9386168402179384905560a08601516006805467ffffffffffffffff1916918716918217905560016008556119ba959185048216949283048216939092041690611118565b60055460065460408051630100000084046001600160401b039081168252600160581b850481166020830152600160981b909404841681830152929091166060830152336080830152517fcb0fb7a7b87db2f472ee8977444cfdbc51993ce660aca27a5969a724fae6dcf39181900360a00190a160c0810151516000819003611a735760008052600e6020527fe710864318d4a32f37d6ce54cb3fadbef648dd12d8dbdf53973564d56b7f881c805460ff191660011790555b60005b81811015610eec576001600e60008560c001518481518110611a9a57611a9a6136d6565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055600101611a76565b611adc61289c565b60008083806020019051810190611af39190613cae565b805151602081015190519395509093509190506002611b118561264b565b60ff166006811115611b2557611b2561333a565b6006811115611b3657611b3661333a565b14611b5f5760405163f4a513b960e01b81526001600160a01b03851660048201526024016112f7565b6001600160a01b0381166000908152600e602052604090205460ff16158015611bb3575060008052600e6020527fe710864318d4a32f37d6ce54cb3fadbef648dd12d8dbdf53973564d56b7f881c5460ff16155b15611bd157604051637fcce2a960e01b815260040160405180910390fd5b600034118015611bfe57506001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14155b80611c3057506001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015611c305750813414155b15611c4e57604051637fcce2a960e01b815260040160405180910390fd5b604080518381526001600160a01b038381166020830152878116828401523260608301529151918616917fdc9d40760308557d1377c2fe7c984ace9eb02d23b60a5f6f26be62c52431bc389181900360800190a2505050505050565b600080600084806020019051810190611cc39190613cae565b80515180516020918201516001600160a01b038087166000908152600f909452604084205496995094975092955093919261010090920490911690856003811115611d1057611d1061333a565b03611d5157611d4b8360405180606001604052808a6001600160a01b03168152602001846001600160a01b03168152602001858152506128e4565b50612305565b6003856003811115611d6557611d6561333a565b03611e0c5783516040805180820182526001600160a01b0384811682526020808301879052880151925163187945bd60e11b81527f0000000000000000000000000000000000000000000000000000000000000000909116936330f28b7a93611dd59391928d9190600401613dbb565b600060405180830381600087803b158015611def57600080fd5b505af1158015611e03573d6000803e3d6000fd5b50505050612305565b6001856003811115611e2057611e2061333a565b0361206f576000806000611e378760200151610acd565b8951604090810151905163d505accf60e01b81526001600160a01b038f81166004830152306024830152604482018b9052606482019290925260ff8316608482015260a4810185905260c48101849052939650919450925087169063d505accf9060e401600060405180830381600087803b158015611eb557600080fd5b505af1925050508015611ec6575060015b611ff457611ed2613e3e565b806308c379a003611f8b5750611ee6613e59565b80611ef15750611f8d565b604051636eb1769f60e11b81526001600160a01b038c8116600483015230602483015287919089169063dd62ed3e906044015b602060405180830381865afa158015611f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f659190613ee2565b1015611f85578060405162461bcd60e51b81526004016112f79190613efb565b50611ff4565b505b3d808015611fb7576040519150601f19603f3d011682016040523d82523d6000602084013e611fbc565b606091505b50604051636eb1769f60e11b81526001600160a01b038c8116600483015230602483015287919089169063dd62ed3e90604401611f24565b6040516323b872dd60e01b81526001600160a01b038b811660048301528581166024830152604482018790528716906323b872dd906064016020604051808303816000875af115801561204b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e039190613a79565b60028560038111156120835761208361333a565b0361230557600080600061209a8760200151610acd565b8951602081015160409182015191516323f2ebc360e21b81529497509295509093506001600160a01b03891692638fcbaf0c9261212c928f923092919060019089908c908c906004016001600160a01b039889168152969097166020870152604086019490945260608501929092521515608084015260ff1660a083015260c082015260e08101919091526101000190565b600060405180830381600087803b15801561214657600080fd5b505af1925050508015612157575060015b61228557612163613e3e565b806308c379a00361221c5750612177613e59565b80612182575061221e565b604051636eb1769f60e11b81526001600160a01b038c8116600483015230602483015287919089169063dd62ed3e906044015b602060405180830381865afa1580156121d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f69190613ee2565b1015612216578060405162461bcd60e51b81526004016112f79190613efb565b50612285565b505b3d808015612248576040519150601f19603f3d011682016040523d82523d6000602084013e61224d565b606091505b50604051636eb1769f60e11b81526001600160a01b038c8116600483015230602483015287919089169063dd62ed3e906044016121b5565b6040516323b872dd60e01b81526001600160a01b038b811660048301528581166024830152604482018790528716906323b872dd906064016020604051808303816000875af11580156122dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123009190613a79565b505050505b5050505050505050565b6006546001600160401b0316421115610f655760405162b828c960e81b815260040160405180910390fd5b805160208083015160408085015160608601516001600160a01b038085166000908152600f90965292909420549293909290916101009091041661238185858386866127a4565b156124a45760015460405163068bcd8d60e01b81526000916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163068bcd8d916123da9160040190815260200190565b600060405180830381865afa1580156123f7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261241f9190810190613f0e565b905061242a86612963565b836002600082825461243c91906134bb565b9091555050604081015161245190838661153a565b60408082015181518681526001600160a01b038581166020830152808916939216917fa6b66f665010d2f7435f110111aaa34b56564074f66081bef606d996fc8caa6f910160405180910390a3506124c8565b60405163f4a513b960e01b81526001600160a01b03851660048201526024016112f7565b505050505050565b6005544263010000009091046001600160401b031611806125025750600554600160581b90046001600160401b031642115b15610f6557604051635b04f6ad60e11b815260040160405180910390fd5b60095460405163dd93da4360e01b81526001600160a01b038481166004830152600092839291169063dd93da4390602401600060405180830381865afa15801561256e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125969190810190613fc3565b6009548151604051635e8a791560e01b815260048101919091526001600160a01b038681166024830152929350911690635e8a791590604401602060405180830381865afa1580156125ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126109190613a79565b949350505050565b6000806000612626856129a1565b6000928352600b602052604090922095811b600f90911b199091161790935550505050565b6001600160a01b0381166000908152600c6020526040812054810361267257506000919050565b60008061267e846129a1565b600f911c1695945050505050565b6000816014526f70a0823100000000000000000000000060005260208060246010865afa601f3d111660205102905092915050565b60008060008084865af1610e0a5763b12d13eb6000526004601cfd5b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d156001600051141716612722576390b8ec186000526004601cfd5b6000603452505050565b6060600080856001600160a01b0316856040516127499190614089565b600060405180830381855af49150503d8060008114612784576040519150601f19603f3d011682016040523d82523d6000602084013e612789565b606091505b509150915061279a86838387612a14565b9695505050505050565b60006127af86611574565b156127bc57506000612844565b60408051602081018890526001600160a01b038088169282019290925290851660608201526080810184905260009060a00160408051601f198184030181528282528051602091820120908301520160405160208183030381529060405280519060200120905061283083600a5483612a8d565b61283e576000915050612844565b60019150505b95945050505050565b612855610f1c565b600154156128765760405163439a74c960e01b815260040160405180910390fd5b8060000361289757604051637fcce2a960e01b815260040160405180910390fd5b600155565b60055442600160981b9091046001600160401b031611806128c757506006546001600160401b031642115b15610f655760405162b828c960e81b815260040160405180910390fd5b604081015160009073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038516016129455780341015612932576040516374c5672b60e01b815260040160405180910390fd5b6129408360200151826126c1565b612959565b612959848460000151856020015184612aa3565b5060019392505050565b600061297161010083613c35565b9050600061298161010084613c49565b6000928352600d60205260409092208054600190931b9092179091555050565b6001600160a01b0381166000908152600c60205260408120548190819081906129cc906001906134bb565b905060006129db604083613c35565b905060006129ea604084613c49565b6129f59060046140a5565b6000838152600b60205260409020549298909750919550909350505050565b60608315612a83578251600003612a7c576001600160a01b0385163b612a7c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016112f7565b5081612610565b6126108383612b00565b600082612a9a8584612b2a565b14949350505050565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c52602060006064601c6000895af13d156001600051141716612af257637939f4246000526004601cfd5b600060605260405250505050565b815115612b105781518083602001fd5b8060405162461bcd60e51b81526004016112f79190613efb565b600081815b8451811015612b6f57612b5b82868381518110612b4e57612b4e6136d6565b6020026020010151612b77565b915080612b6781613752565b915050612b2f565b509392505050565b6000818310612b935760008281526020849052604090206108ec565b60008381526020839052604090206108ec565b604051806060016040528060001515815260200160006001600160a01b03168152602001612be7604051806040016040528060008152602001606081525090565b905290565b6001600160a01b0381168114610f1957600080fd5b600060208284031215612c1357600080fd5b8135612c1e81612bec565b9392505050565b634e487b7160e01b600052604160045260246000fd5b604081018181106001600160401b0382111715612c5a57612c5a612c25565b60405250565b608081018181106001600160401b0382111715612c5a57612c5a612c25565b606081018181106001600160401b0382111715612c5a57612c5a612c25565b60c081018181106001600160401b0382111715612c5a57612c5a612c25565b601f8201601f191681016001600160401b0381118282101715612ce257612ce2612c25565b6040525050565b60405160e081016001600160401b0381118282101715612d0b57612d0b612c25565b60405290565b604051612d1d81612c9e565b90565b60006001600160401b03821115612d3957612d39612c25565b5060051b60200190565b600082601f830112612d5457600080fd5b81356020612d6182612d20565b604051612d6e8282612cbd565b83815260059390931b8501820192828101915086841115612d8e57600080fd5b8286015b84811015612db2578035612da581612bec565b8352918301918301612d92565b509695505050505050565b60006001600160401b03821115612dd657612dd6612c25565b50601f01601f191660200190565b6000612def83612dbd565b604051612dfc8282612cbd565b809250848152858585011115612e1157600080fd5b8484602083013760006020868301015250509392505050565b600082601f830112612e3b57600080fd5b6108ec83833560208501612de4565b600080600060608486031215612e5f57600080fd5b83356001600160401b0380821115612e7657600080fd5b612e8287838801612d43565b94506020860135915080821115612e9857600080fd5b50612ea586828701612e2a565b9250506040840135612eb681612bec565b809150509250925092565b6001600160401b0381168114610f1957600080fd5b60008060008060808587031215612eec57600080fd5b8435612ef781612ec1565b93506020850135612f0781612ec1565b92506040850135612f1781612ec1565b91506060850135612f2781612ec1565b939692955090935050565b60008060408385031215612f4557600080fd5b82356001600160401b03811115612f5b57600080fd5b612f6785828601612e2a565b9250506020830135612f7881612bec565b809150509250929050565b60005b83811015612f9e578181015183820152602001612f86565b50506000910152565b60008151808452612fbf816020860160208601612f83565b601f01601f19169290920160200192915050565b8281526040602082015260006126106040830184612fa7565b600060208284031215612ffe57600080fd5b5035919050565b602081528151151560208201526001600160a01b036020830151166040820152600060408301516060808401528051608084015260208101519050604060a084015261261060c0840182612fa7565b6000806040838503121561306757600080fd5b8235915060208301356001600160401b038082111561308557600080fd5b908401906040828703121561309957600080fd5b6040516130a581612c3b565b823581526020830135828111156130bb57600080fd5b80840193505086601f8401126130d057600080fd5b6130df87843560208601612de4565b60208201528093505050509250929050565b60006020828403121561310357600080fd5b81356001600160401b0381111561311957600080fd5b61261084828501612e2a565b6000806020838503121561313857600080fd5b82356001600160401b038082111561314f57600080fd5b818501915085601f83011261316357600080fd5b81358181111561317257600080fd5b8660208260051b850101111561318757600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156131ee57603f198886030184526131dc858351612fa7565b945092850192908501906001016131c0565b5092979650505050505050565b6000806040838503121561320e57600080fd5b82356001600160401b038082111561322557600080fd5b61323186838701612d43565b935060209150818501358181111561324857600080fd5b8501601f8101871361325957600080fd5b803561326481612d20565b6040516132718282612cbd565b82815260059290921b830185019185810191508983111561329157600080fd5b8584015b838110156132c9578035868111156132ad5760008081fd5b6132bb8c8983890101612e2a565b845250918601918601613295565b508096505050505050509250929050565b602080825282518282018190526000919060409081850190868401855b8281101561332d5761331d84835180516001600160a01b03168252602090810151910152565b92840192908501906001016132f7565b5091979650505050505050565b634e487b7160e01b600052602160045260246000fd5b602081016007831061337257634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561338b57600080fd5b8235915060208301356001600160401b038111156133a857600080fd5b6133b485828601612e2a565b9150509250929050565b60008060408084860312156133d257600080fd5b83356001600160401b038111156133e857600080fd5b8401601f810186136133f957600080fd5b8035602061340682612d20565b84516134128282612cbd565b83815260069390931b840182019282810191508984111561343257600080fd5b938201935b838510156134755785858b03121561344f5760008081fd5b855161345a81612c3b565b85358152838601358482015282529385019390820190613437565b9997909101359750505050505050565b634e487b7160e01b600052601160045260246000fd5b6001600160401b03818116838216019080821115610c6c57610c6c613485565b818103818111156108ef576108ef613485565b600181811c908216806134e257607f821691505b60208210810361350257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156107ce57600081815260208120601f850160051c8101602086101561352f5750805b601f850160051c820191505b818110156124c85782815560010161353b565b81516001600160401b0381111561356757613567612c25565b61357b8161357584546134ce565b84613508565b602080601f8311600181146135b057600084156135985750858301515b600019600386901b1c1916600185901b1785556124c8565b600085815260208120601f198616915b828110156135df578886015182559484019460019091019084016135c0565b50858210156135fd5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b82815260006020604081840152835460408401526001808501604060608601526000815461363a816134ce565b80608089015260a08583166000811461365a5760018114613674576136a2565b60ff1984168a83015282151560051b8a01820194506136a2565b856000528760002060005b8481101561369a5781548c820185015290880190890161367f565b8b0183019550505b50929a9950505050505050505050565b600080604083850312156136c557600080fd5b505080516020909101519092909150565b634e487b7160e01b600052603260045260246000fd5b60ff81811683821601908111156108ef576108ef613485565b6000808335601e1984360301811261371c57600080fd5b8301803591506001600160401b0382111561373657600080fd5b60200191503681900382131561374b57600080fd5b9250929050565b60006001820161376457613764613485565b5060010190565b8051801515811461377b57600080fd5b919050565b805161377b81612ec1565b805161377b81612bec565b600082601f8301126137a757600080fd5b815160206137b482612d20565b6040516137c18282612cbd565b83815260059390931b85018201928281019150868411156137e157600080fd5b8286015b84811015612db25780516137f881612bec565b83529183019183016137e5565b60006020828403121561381757600080fd5b81516001600160401b038082111561382e57600080fd5b9083019060e0828603121561384257600080fd5b61384a612ce9565b6138538361376b565b81526138616020840161376b565b602082015261387260408401613780565b604082015261388360608401613780565b606082015261389460808401613780565b60808201526138a560a08401613780565b60a082015260c0830151828111156138bc57600080fd5b6138c887828601613796565b60c08301525095945050505050565b808201808211156108ef576108ef613485565b6000608082840312156138fc57600080fd5b60405161390881612c60565b8091508251815260208084015161391e81612bec565b828201526040848101519083015260608401516001600160401b0381111561394557600080fd5b8401601f8101861361395657600080fd5b805161396181612d20565b60405161396e8282612cbd565b82815260059290921b830184019184810191508883111561398e57600080fd5b928401925b828410156139ac57835182529284019290840190613993565b80606087015250505050505092915050565b600060208083850312156139d157600080fd5b82516001600160401b03808211156139e857600080fd5b818501915085601f8301126139fc57600080fd5b8151613a0781612d20565b604051613a148282612cbd565b82815260059290921b8401850191858101915088831115613a3457600080fd5b8585015b83811015613a6c57805185811115613a505760008081fd5b613a5e8b89838a01016138ea565b845250918601918601613a38565b5098975050505050505050565b600060208284031215613a8b57600080fd5b6108ec8261376b565b600082601f830112613aa557600080fd5b8151613ab081612dbd565b604051613abd8282612cbd565b828152856020848701011115613ad257600080fd5b612844836020830160208801612f83565b600060408284031215613af557600080fd5b604051613b0181612c3b565b8091508251815260208301516001600160401b03811115613b2157600080fd5b613b2d85828601613a94565b6020830152505092915050565b600080600060608486031215613b4f57600080fd5b8351613b5a81612bec565b6020850151909350613b6b81612bec565b60408501519092506001600160401b03811115613b8757600080fd5b613b9386828701613ae3565b9150509250925092565b604081526000613bb06040830185612fa7565b90508260208301529392505050565b604081526000613bd26040830185612fa7565b90506001600160a01b03831660208301529392505050565b606081526000613bfd6060830186612fa7565b90506001600160a01b038416602083015260ff83166040830152949350505050565b634e487b7160e01b600052601260045260246000fd5b600082613c4457613c44613c1f565b500490565b600082613c5857613c58613c1f565b500690565b600060208284031215613c6f57600080fd5b81516001600160401b03811115613c8557600080fd5b612610848285016138ea565b600060208284031215613ca357600080fd5b8151612c1e81612bec565b600080600060608486031215613cc357600080fd5b8351613cce81612bec565b602085015190935060048110613ce357600080fd5b809250506040808501516001600160401b0380821115613d0257600080fd5b9086019081880360a0811215613d1757600080fd5b8351613d2281612c3b565b6080821215613d3057600080fd5b8451613d3b81612c7f565b85831215613d4857600080fd5b85519250613d5583612c3b565b8451613d6081612bec565b8084525060208501516020840152828152858501516020820152606085015186820152808252506080840151945082851115613d9b57600080fd5b613da78a868601613a94565b602082015280955050505050509250925092565b6000610100613dde83885180516001600160a01b03168252602090810151910152565b6020870151604084015260408701516060840152613e12608084018780516001600160a01b03168252602090810151910152565b6001600160a01b03851660c08401528060e0840152613e3381840185612fa7565b979650505050505050565b600060033d1115612d1d5760046000803e5060005160e01c90565b600060443d1015613e675790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715613e9657505050505090565b8285019150815181811115613eae5750505050505090565b843d8701016020828501011115613ec85750505050505090565b613ed760208286010187612cbd565b509095945050505050565b600060208284031215613ef457600080fd5b5051919050565b6020815260006108ec6020830184612fa7565b600060208284031215613f2057600080fd5b81516001600160401b0380821115613f3757600080fd5b9083019060c08286031215613f4b57600080fd5b604051613f5781612c9e565b825181526020830151613f6981612bec565b6020820152613f7a6040840161378b565b6040820152606083015182811115613f9157600080fd5b613f9d87828601613ae3565b6060830152506080830151608082015260a083015160a082015280935050505092915050565b600060208284031215613fd557600080fd5b81516001600160401b0380821115613fec57600080fd5b9083019060c0828603121561400057600080fd5b614008612d11565b825181526020830151602082015260408301518281111561402857600080fd5b61403487828601613a94565b60408301525060608301518281111561404c57600080fd5b61405887828601613ae3565b60608301525061406a6080840161378b565b608082015261407b60a0840161378b565b60a082015295945050505050565b6000825161409b818460208701612f83565b9190910192915050565b80820281158282048414176108ef576108ef61348556fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122090a027d5c30b677b89be58109c6a3efc07cbe35e974459c9b30ee5c37c08a8a964736f6c634300081300330000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a10000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000000000000000000000000000000000000000003a446f6e6174696f6e566f74696e674d65726b6c65446973747269627574696f6e4469726563745472616e73666572537472617465677976322e31000000000000
Deployed Bytecode
0x6080604052600436106102295760003560e01c806373af345311610123578063df868ed3116100ab578063edd146cc1161006f578063edd146cc14610713578063ef2920fc14610733578063f31db3d114610746578063f5b0dfb714610766578063f6f258911461078657600080fd5b8063df868ed314610664578063dff7d2c714610679578063e744092e146106a0578063e7efcfc2146106d0578063eb11af93146106e657600080fd5b8063a7bb5803116100f2578063a7bb580314610586578063ac9650d8146105c4578063b2b878d0146105f1578063cb0e85a61461061e578063d2e17f591461063d57600080fd5b806373af34531461050157806395355b3b146105215780639af5c09d14610537578063a0cf0aea1461055e57600080fd5b806342fda9c7116101b15780635708973911610175578063570897391461044357806359a3977b1461045d5780635f1b55f31461048057806362812a39146104a05780636afdd850146104cd57600080fd5b806342fda9c7146103835780634533d678146103b65780634ab4ba42146103ee5780634d31d0871461040357806351cff8d91461042357600080fd5b806321755088116101f857806321755088146102fe5780632bbe0cae1461032e5780632d52eff2146103415780632eb4a7ab1461035857806338fff2d01461036e57600080fd5b806301fc1c64146102355780630a6f0ee91461027557806315cc481e146102975780632143e92f146102de57600080fd5b3661023057005b600080fd5b34801561024157600080fd5b50610262610250366004612c01565b600c6020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561028157600080fd5b50610295610290366004612e4a565b6107b3565b005b3480156102a357600080fd5b507f0000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a15b6040516001600160a01b03909116815260200161026c565b3480156102ea57600080fd5b506102956102f9366004612ed6565b6107d3565b34801561030a57600080fd5b5060055461031e9062010000900460ff1681565b604051901515815260200161026c565b6102c661033c366004612f32565b6108d0565b34801561034d57600080fd5b50600a54151561031e565b34801561036457600080fd5b50610262600a5481565b34801561037a57600080fd5b50600154610262565b34801561038f57600080fd5b507f9fa6890423649187b1f0e8bf4265f0305ce99523c3d11aa36b35a54617bb0ec0610262565b3480156103c257600080fd5b506006546103d6906001600160401b031681565b6040516001600160401b03909116815260200161026c565b3480156103fa57600080fd5b50600254610262565b34801561040f57600080fd5b5061031e61041e366004612c01565b6108f5565b34801561042f57600080fd5b5061029561043e366004612c01565b6108fe565b34801561044f57600080fd5b5060055461031e9060ff1681565b34801561046957600080fd5b50610472610978565b60405161026c929190612fd3565b34801561048c57600080fd5b5061031e61049b366004612fec565b610a0f565b3480156104ac57600080fd5b506104c06104bb366004612c01565b610a1a565b60405161026c9190613005565b3480156104d957600080fd5b506102c67f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba381565b34801561050d57600080fd5b5061029561051c366004613054565b610a2b565b34801561052d57600080fd5b5061026260085481565b34801561054357600080fd5b506005546103d690630100000090046001600160401b031681565b34801561056a57600080fd5b506102c673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b34801561059257600080fd5b506105a66105a13660046130f1565b610acd565b60408051938452602084019290925260ff169082015260600161026c565b3480156105d057600080fd5b506105e46105df366004613125565b610b7f565b60405161026c9190613199565b3480156105fd57600080fd5b5061061161060c3660046131fb565b610c73565b60405161026c91906132da565b34801561062a57600080fd5b5060055461031e90610100900460ff1681565b34801561064957600080fd5b506005546103d690600160981b90046001600160401b031681565b34801561067057600080fd5b5061031e610d71565b34801561068557600080fd5b506005546103d690600160581b90046001600160401b031681565b3480156106ac57600080fd5b5061031e6106bb366004612c01565b600e6020526000908152604090205460ff1681565b3480156106dc57600080fd5b5061026260075481565b3480156106f257600080fd5b50610706610701366004612c01565b610d80565b60405161026c9190613350565b34801561071f57600080fd5b5061029561072e366004613378565b610d8b565b610295610741366004612f32565b610de6565b34801561075257600080fd5b506102956107613660046133be565b610e0e565b34801561077257600080fd5b50610295610781366004612fec565b610ef2565b34801561079257600080fd5b506102626107a1366004612fec565b600b6020526000908152604090205481565b6107bb610f1c565b6107c3610f67565b6107ce838383610f8a565b505050565b336107dd81611066565b6107e985858585611118565b6005805472ffffffffffffffffffffffffffffffff000000191663010000006001600160401b03888116820267ffffffffffffffff60581b191692909217600160581b88841681029190911767ffffffffffffffff60981b1916600160981b888516810291909117948590556006805467ffffffffffffffff191688861690811790915560408051948704861685529286048516602085015294049092169181019190915260608101919091523360808201527fcb0fb7a7b87db2f472ee8977444cfdbc51993ce660aca27a5969a724fae6dcf39060a00160405180910390a15050505050565b60006108da610f1c565b6108e2610f67565b6108ec838361119f565b90505b92915050565b600060016108ef565b3361090881611066565b600654610921906001600160401b031662278d0061349b565b6001600160401b0316421161094957604051637fcce2a960e01b815260040160405180910390fd5b600061095583306114f1565b905060008061096482846134bb565b905061097185338361153a565b5050505050565b600380546004805491929161098c906134ce565b80601f01602080910402602001604051908101604052809291908181526020018280546109b8906134ce565b8015610a055780601f106109da57610100808354040283529160200191610a05565b820191906000526020600020905b8154815290600101906020018083116109e857829003601f168201915b5050505050905082565b60006108ef82611574565b610a22612ba6565b6108ef826115b5565b610a336116ae565b33610a3d81611066565b60055462010000900460ff1615610a6757604051637fcce2a960e01b815260040160405180910390fd5b600a839055815160039081556020830151839190600490610a88908261354e565b509050507fdc7180ca4affc84269428ed20ef950e745126f11691b010c4a7d49458421008f600a546003604051610ac092919061360d565b60405180910390a1505050565b60008060008351604103610b185783806020019051810190610aef91906136b2565b8551919450925084906040908110610b0957610b096136d6565b016020015160f81c9050610b78565b8351604003610b5f57600084806020019051810190610b3791906136b2565b9094506001600160ff1b03811693509050610b5760ff82901c601b6136ec565b915050610b78565b604051637fcce2a960e01b815260040160405180910390fd5b9193909250565b6060816001600160401b03811115610b9957610b99612c25565b604051908082528060200260200182016040528015610bcc57816020015b6060815260200190600190039081610bb75790505b50905060005b82811015610c6c57610c3c30858584818110610bf057610bf06136d6565b9050602002810190610c029190613705565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506116d992505050565b828281518110610c4e57610c4e6136d6565b60200260200101819052508080610c6490613752565b915050610bd2565b5092915050565b81518151606091908114610c9a57604051633da4c02b60e11b815260040160405180910390fd5b6000816001600160401b03811115610cb457610cb4612c25565b604051908082528060200260200182016040528015610cf957816020015b6040805180820190915260008082526020820152815260200190600190039081610cd25790505b50905060005b82811015610d6857610d43868281518110610d1c57610d1c6136d6565b6020026020010151868381518110610d3657610d366136d6565b60200260200101516116fe565b828281518110610d5557610d556136d6565b6020908102919091010152600101610cff565b50949350505050565b6000610d7b6117b9565b905090565b60006108ef82611802565b610d93610f1c565b600081806020019051810190610da99190613805565b9050610db58382611821565b7f91efa3d50feccde0d0d202f8ae5c41ca0b2be614cebcb2bd2f4b019396e6568a8383604051610ac0929190612fd3565b610dee610f1c565b610df6610f67565b610e008282611ad4565b610e0a8282611caa565b5050565b610e1661230f565b33610e2081611066565b6008548214610e4257604051637fcce2a960e01b815260040160405180910390fd5b60005b8351811015610eec576000848281518110610e6257610e626136d6565b60200260200101516000015190506000858381518110610e8457610e846136d6565b6020908102919091018101518101516000848152600b83526040908190208290558051828152339381019390935290925083917f941884a9a55191a7401466aaf8a0d2b7c8b082055a5a2b345b83c73940172ac4910160405180910390a25050600101610e45565b50505050565b610efa610f1c565b8060026000828254610f0c91906138d7565b90915550610f1990508181565b50565b336001600160a01b037f0000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a11614610f655760405163075fd2b160e01b815260040160405180910390fd5b565b600154600003610f6557604051630f68fe6360e21b815260040160405180910390fd5b80610f9481611066565b600a54600003610fb757604051637fcce2a960e01b815260040160405180910390fd5b60055462010000900460ff16610fd9576005805462ff00001916620100001790555b600083806020019051810190610fef91906139be565b805190915060005b8181101561102957611021838281518110611014576110146136d6565b602002602001015161233a565b600101610ff7565b506040516001600160a01b038516907f7ec3272052827f7b50d9e84f98172cbb80c112df1e377c5b97ea77f1812db8d990600090a2505050505050565b6001546040516329e40d4b60e01b815260048101919091526001600160a01b0382811660248301527f0000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a116906329e40d4b90604401602060405180830381865afa1580156110d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110fb9190613a79565b610f195760405163075fd2b160e01b815260040160405180910390fd5b826001600160401b0316846001600160401b031611806111495750816001600160401b0316846001600160401b0316115b806111655750806001600160401b0316826001600160401b0316115b806111815750806001600160401b0316836001600160401b0316115b15610eec57604051637fcce2a960e01b815260040160405180910390fd5b60006111a96124d0565b60008060006111cb604051806040016040528060008152602001606081525090565b60055460ff161561121d57868060200190518101906111ea9190613b3a565b919650935090506111fb8587612520565b6112185760405163075fd2b160e01b815260040160405180910390fd5b611288565b868060200190518101906112319190613b3a565b6001600160a01b038316151596509094509092509050836112525785611254565b815b945083801561126a57506112688587612520565b155b156112885760405163075fd2b160e01b815260040160405180910390fd5b600554610100900460ff1680156112ab575060208101515115806112ab57508051155b156112c95760405163c19e07c560e01b815260040160405180910390fd5b6001600160a01b0383166113005760405163f4a513b960e01b81526001600160a01b03861660048201526024015b60405180910390fd5b6001600160a01b038086166000908152600f6020908152604090912080549286166101000274ffffffffffffffffffffffffffffffffffffffff0019909316929092178255825160018301908155908301518391906002840190611364908261354e565b505060055460ff169050611378578461137b565b60015b815460ff19169015151781556001600160a01b0386166000908152600c60205260408120549003611457576008546001600160a01b0387166000908152600c60205260409020556113d18660015b60ff16612618565b6000886008546040516020016113e8929190613b9d565b6040516020818303038152906040529050866001600160a01b03167fa197306e3dd5494a61a695381aa809a53b8e377a685e84e404a85d5a8da6cc62828a604051611434929190613bbf565b60405180910390a26008805490600061144c83613752565b9190505550506114e6565b60006114628761264b565b905060011960ff8216016114805761147b8760016113c9565b611497565b60021960ff821601611497576114978760046113c9565b866001600160a01b03167fcec1da3f7f0b8a344dd1025d06e2ddd48b14880395997ad97cbdb439acc761d48a8a6114cd8b61264b565b6040516114dc93929190613bea565b60405180910390a2505b505050505092915050565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0384160161152957506001600160a01b038116316108ef565b611533838361268c565b90506108ef565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601611569576107ce82826126c1565b6107ce8383836126dd565b60008061158361010084613c35565b9050600061159361010085613c49565b6000928352600d602052604090922054600190921b9182169091149392505050565b6115bd612ba6565b6001600160a01b038083166000908152600f60209081526040918290208251606081018452815460ff811615158252610100900490941684830152825180840184526001820180548252600283018054939587019492939192840191611622906134ce565b80601f016020809104026020016040519081016040528092919081815260200182805461164e906134ce565b801561169b5780601f106116705761010080835404028352916020019161169b565b820191906000526020600020905b81548152906001019060200180831161167e57829003601f168201915b5050509190925250505090525092915050565b6006546001600160401b03164211610f6557604051634543ced160e11b815260040160405180910390fd5b60606108ec83836040518060600160405280602781526020016140bd6027913961272c565b60408051808201909152600080825260208201526000828060200190518101906117289190613c5d565b80516020820151604083015160608401519394509192909190600061174c846115b5565b60200151905061175f85858386866127a4565b1561178f576040518060400160405280826001600160a01b031681526020018481525096505050505050506108ef565b604080518082019091526001600160a01b0390911681526000602082015298975050505050505050565b6005546000904263010000009091046001600160401b0316118015906117f15750600554600160581b90046001600160401b03164211155b156117fc5750600190565b50600090565b600061180d8261264b565b60ff1660068111156108ef576108ef61333a565b61182a8261284d565b80516005805460208085015161ffff1990921693151561ff001916939093176101009115159190910217905560408051635ab1bd5360e01b815290517f0000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a16001600160a01b031692635ab1bd5392600480820193918290030181865afa1580156118b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118db9190613c91565b6009805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03929092169190911790556040810151600580546060840151608085015172ffffffffffffffffffffffffffffffff0000001990921663010000006001600160401b03958616810267ffffffffffffffff60581b191691909117600160581b92861683021767ffffffffffffffff60981b1916600160981b9386168402179384905560a08601516006805467ffffffffffffffff1916918716918217905560016008556119ba959185048216949283048216939092041690611118565b60055460065460408051630100000084046001600160401b039081168252600160581b850481166020830152600160981b909404841681830152929091166060830152336080830152517fcb0fb7a7b87db2f472ee8977444cfdbc51993ce660aca27a5969a724fae6dcf39181900360a00190a160c0810151516000819003611a735760008052600e6020527fe710864318d4a32f37d6ce54cb3fadbef648dd12d8dbdf53973564d56b7f881c805460ff191660011790555b60005b81811015610eec576001600e60008560c001518481518110611a9a57611a9a6136d6565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055600101611a76565b611adc61289c565b60008083806020019051810190611af39190613cae565b805151602081015190519395509093509190506002611b118561264b565b60ff166006811115611b2557611b2561333a565b6006811115611b3657611b3661333a565b14611b5f5760405163f4a513b960e01b81526001600160a01b03851660048201526024016112f7565b6001600160a01b0381166000908152600e602052604090205460ff16158015611bb3575060008052600e6020527fe710864318d4a32f37d6ce54cb3fadbef648dd12d8dbdf53973564d56b7f881c5460ff16155b15611bd157604051637fcce2a960e01b815260040160405180910390fd5b600034118015611bfe57506001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14155b80611c3057506001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015611c305750813414155b15611c4e57604051637fcce2a960e01b815260040160405180910390fd5b604080518381526001600160a01b038381166020830152878116828401523260608301529151918616917fdc9d40760308557d1377c2fe7c984ace9eb02d23b60a5f6f26be62c52431bc389181900360800190a2505050505050565b600080600084806020019051810190611cc39190613cae565b80515180516020918201516001600160a01b038087166000908152600f909452604084205496995094975092955093919261010090920490911690856003811115611d1057611d1061333a565b03611d5157611d4b8360405180606001604052808a6001600160a01b03168152602001846001600160a01b03168152602001858152506128e4565b50612305565b6003856003811115611d6557611d6561333a565b03611e0c5783516040805180820182526001600160a01b0384811682526020808301879052880151925163187945bd60e11b81527f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3909116936330f28b7a93611dd59391928d9190600401613dbb565b600060405180830381600087803b158015611def57600080fd5b505af1158015611e03573d6000803e3d6000fd5b50505050612305565b6001856003811115611e2057611e2061333a565b0361206f576000806000611e378760200151610acd565b8951604090810151905163d505accf60e01b81526001600160a01b038f81166004830152306024830152604482018b9052606482019290925260ff8316608482015260a4810185905260c48101849052939650919450925087169063d505accf9060e401600060405180830381600087803b158015611eb557600080fd5b505af1925050508015611ec6575060015b611ff457611ed2613e3e565b806308c379a003611f8b5750611ee6613e59565b80611ef15750611f8d565b604051636eb1769f60e11b81526001600160a01b038c8116600483015230602483015287919089169063dd62ed3e906044015b602060405180830381865afa158015611f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f659190613ee2565b1015611f85578060405162461bcd60e51b81526004016112f79190613efb565b50611ff4565b505b3d808015611fb7576040519150601f19603f3d011682016040523d82523d6000602084013e611fbc565b606091505b50604051636eb1769f60e11b81526001600160a01b038c8116600483015230602483015287919089169063dd62ed3e90604401611f24565b6040516323b872dd60e01b81526001600160a01b038b811660048301528581166024830152604482018790528716906323b872dd906064016020604051808303816000875af115801561204b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e039190613a79565b60028560038111156120835761208361333a565b0361230557600080600061209a8760200151610acd565b8951602081015160409182015191516323f2ebc360e21b81529497509295509093506001600160a01b03891692638fcbaf0c9261212c928f923092919060019089908c908c906004016001600160a01b039889168152969097166020870152604086019490945260608501929092521515608084015260ff1660a083015260c082015260e08101919091526101000190565b600060405180830381600087803b15801561214657600080fd5b505af1925050508015612157575060015b61228557612163613e3e565b806308c379a00361221c5750612177613e59565b80612182575061221e565b604051636eb1769f60e11b81526001600160a01b038c8116600483015230602483015287919089169063dd62ed3e906044015b602060405180830381865afa1580156121d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f69190613ee2565b1015612216578060405162461bcd60e51b81526004016112f79190613efb565b50612285565b505b3d808015612248576040519150601f19603f3d011682016040523d82523d6000602084013e61224d565b606091505b50604051636eb1769f60e11b81526001600160a01b038c8116600483015230602483015287919089169063dd62ed3e906044016121b5565b6040516323b872dd60e01b81526001600160a01b038b811660048301528581166024830152604482018790528716906323b872dd906064016020604051808303816000875af11580156122dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123009190613a79565b505050505b5050505050505050565b6006546001600160401b0316421115610f655760405162b828c960e81b815260040160405180910390fd5b805160208083015160408085015160608601516001600160a01b038085166000908152600f90965292909420549293909290916101009091041661238185858386866127a4565b156124a45760015460405163068bcd8d60e01b81526000916001600160a01b037f0000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a1169163068bcd8d916123da9160040190815260200190565b600060405180830381865afa1580156123f7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261241f9190810190613f0e565b905061242a86612963565b836002600082825461243c91906134bb565b9091555050604081015161245190838661153a565b60408082015181518681526001600160a01b038581166020830152808916939216917fa6b66f665010d2f7435f110111aaa34b56564074f66081bef606d996fc8caa6f910160405180910390a3506124c8565b60405163f4a513b960e01b81526001600160a01b03851660048201526024016112f7565b505050505050565b6005544263010000009091046001600160401b031611806125025750600554600160581b90046001600160401b031642115b15610f6557604051635b04f6ad60e11b815260040160405180910390fd5b60095460405163dd93da4360e01b81526001600160a01b038481166004830152600092839291169063dd93da4390602401600060405180830381865afa15801561256e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125969190810190613fc3565b6009548151604051635e8a791560e01b815260048101919091526001600160a01b038681166024830152929350911690635e8a791590604401602060405180830381865afa1580156125ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126109190613a79565b949350505050565b6000806000612626856129a1565b6000928352600b602052604090922095811b600f90911b199091161790935550505050565b6001600160a01b0381166000908152600c6020526040812054810361267257506000919050565b60008061267e846129a1565b600f911c1695945050505050565b6000816014526f70a0823100000000000000000000000060005260208060246010865afa601f3d111660205102905092915050565b60008060008084865af1610e0a5763b12d13eb6000526004601cfd5b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d156001600051141716612722576390b8ec186000526004601cfd5b6000603452505050565b6060600080856001600160a01b0316856040516127499190614089565b600060405180830381855af49150503d8060008114612784576040519150601f19603f3d011682016040523d82523d6000602084013e612789565b606091505b509150915061279a86838387612a14565b9695505050505050565b60006127af86611574565b156127bc57506000612844565b60408051602081018890526001600160a01b038088169282019290925290851660608201526080810184905260009060a00160408051601f198184030181528282528051602091820120908301520160405160208183030381529060405280519060200120905061283083600a5483612a8d565b61283e576000915050612844565b60019150505b95945050505050565b612855610f1c565b600154156128765760405163439a74c960e01b815260040160405180910390fd5b8060000361289757604051637fcce2a960e01b815260040160405180910390fd5b600155565b60055442600160981b9091046001600160401b031611806128c757506006546001600160401b031642115b15610f655760405162b828c960e81b815260040160405180910390fd5b604081015160009073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038516016129455780341015612932576040516374c5672b60e01b815260040160405180910390fd5b6129408360200151826126c1565b612959565b612959848460000151856020015184612aa3565b5060019392505050565b600061297161010083613c35565b9050600061298161010084613c49565b6000928352600d60205260409092208054600190931b9092179091555050565b6001600160a01b0381166000908152600c60205260408120548190819081906129cc906001906134bb565b905060006129db604083613c35565b905060006129ea604084613c49565b6129f59060046140a5565b6000838152600b60205260409020549298909750919550909350505050565b60608315612a83578251600003612a7c576001600160a01b0385163b612a7c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016112f7565b5081612610565b6126108383612b00565b600082612a9a8584612b2a565b14949350505050565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c52602060006064601c6000895af13d156001600051141716612af257637939f4246000526004601cfd5b600060605260405250505050565b815115612b105781518083602001fd5b8060405162461bcd60e51b81526004016112f79190613efb565b600081815b8451811015612b6f57612b5b82868381518110612b4e57612b4e6136d6565b6020026020010151612b77565b915080612b6781613752565b915050612b2f565b509392505050565b6000818310612b935760008281526020849052604090206108ec565b60008381526020839052604090206108ec565b604051806060016040528060001515815260200160006001600160a01b03168152602001612be7604051806040016040528060008152602001606081525090565b905290565b6001600160a01b0381168114610f1957600080fd5b600060208284031215612c1357600080fd5b8135612c1e81612bec565b9392505050565b634e487b7160e01b600052604160045260246000fd5b604081018181106001600160401b0382111715612c5a57612c5a612c25565b60405250565b608081018181106001600160401b0382111715612c5a57612c5a612c25565b606081018181106001600160401b0382111715612c5a57612c5a612c25565b60c081018181106001600160401b0382111715612c5a57612c5a612c25565b601f8201601f191681016001600160401b0381118282101715612ce257612ce2612c25565b6040525050565b60405160e081016001600160401b0381118282101715612d0b57612d0b612c25565b60405290565b604051612d1d81612c9e565b90565b60006001600160401b03821115612d3957612d39612c25565b5060051b60200190565b600082601f830112612d5457600080fd5b81356020612d6182612d20565b604051612d6e8282612cbd565b83815260059390931b8501820192828101915086841115612d8e57600080fd5b8286015b84811015612db2578035612da581612bec565b8352918301918301612d92565b509695505050505050565b60006001600160401b03821115612dd657612dd6612c25565b50601f01601f191660200190565b6000612def83612dbd565b604051612dfc8282612cbd565b809250848152858585011115612e1157600080fd5b8484602083013760006020868301015250509392505050565b600082601f830112612e3b57600080fd5b6108ec83833560208501612de4565b600080600060608486031215612e5f57600080fd5b83356001600160401b0380821115612e7657600080fd5b612e8287838801612d43565b94506020860135915080821115612e9857600080fd5b50612ea586828701612e2a565b9250506040840135612eb681612bec565b809150509250925092565b6001600160401b0381168114610f1957600080fd5b60008060008060808587031215612eec57600080fd5b8435612ef781612ec1565b93506020850135612f0781612ec1565b92506040850135612f1781612ec1565b91506060850135612f2781612ec1565b939692955090935050565b60008060408385031215612f4557600080fd5b82356001600160401b03811115612f5b57600080fd5b612f6785828601612e2a565b9250506020830135612f7881612bec565b809150509250929050565b60005b83811015612f9e578181015183820152602001612f86565b50506000910152565b60008151808452612fbf816020860160208601612f83565b601f01601f19169290920160200192915050565b8281526040602082015260006126106040830184612fa7565b600060208284031215612ffe57600080fd5b5035919050565b602081528151151560208201526001600160a01b036020830151166040820152600060408301516060808401528051608084015260208101519050604060a084015261261060c0840182612fa7565b6000806040838503121561306757600080fd5b8235915060208301356001600160401b038082111561308557600080fd5b908401906040828703121561309957600080fd5b6040516130a581612c3b565b823581526020830135828111156130bb57600080fd5b80840193505086601f8401126130d057600080fd5b6130df87843560208601612de4565b60208201528093505050509250929050565b60006020828403121561310357600080fd5b81356001600160401b0381111561311957600080fd5b61261084828501612e2a565b6000806020838503121561313857600080fd5b82356001600160401b038082111561314f57600080fd5b818501915085601f83011261316357600080fd5b81358181111561317257600080fd5b8660208260051b850101111561318757600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156131ee57603f198886030184526131dc858351612fa7565b945092850192908501906001016131c0565b5092979650505050505050565b6000806040838503121561320e57600080fd5b82356001600160401b038082111561322557600080fd5b61323186838701612d43565b935060209150818501358181111561324857600080fd5b8501601f8101871361325957600080fd5b803561326481612d20565b6040516132718282612cbd565b82815260059290921b830185019185810191508983111561329157600080fd5b8584015b838110156132c9578035868111156132ad5760008081fd5b6132bb8c8983890101612e2a565b845250918601918601613295565b508096505050505050509250929050565b602080825282518282018190526000919060409081850190868401855b8281101561332d5761331d84835180516001600160a01b03168252602090810151910152565b92840192908501906001016132f7565b5091979650505050505050565b634e487b7160e01b600052602160045260246000fd5b602081016007831061337257634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561338b57600080fd5b8235915060208301356001600160401b038111156133a857600080fd5b6133b485828601612e2a565b9150509250929050565b60008060408084860312156133d257600080fd5b83356001600160401b038111156133e857600080fd5b8401601f810186136133f957600080fd5b8035602061340682612d20565b84516134128282612cbd565b83815260069390931b840182019282810191508984111561343257600080fd5b938201935b838510156134755785858b03121561344f5760008081fd5b855161345a81612c3b565b85358152838601358482015282529385019390820190613437565b9997909101359750505050505050565b634e487b7160e01b600052601160045260246000fd5b6001600160401b03818116838216019080821115610c6c57610c6c613485565b818103818111156108ef576108ef613485565b600181811c908216806134e257607f821691505b60208210810361350257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156107ce57600081815260208120601f850160051c8101602086101561352f5750805b601f850160051c820191505b818110156124c85782815560010161353b565b81516001600160401b0381111561356757613567612c25565b61357b8161357584546134ce565b84613508565b602080601f8311600181146135b057600084156135985750858301515b600019600386901b1c1916600185901b1785556124c8565b600085815260208120601f198616915b828110156135df578886015182559484019460019091019084016135c0565b50858210156135fd5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b82815260006020604081840152835460408401526001808501604060608601526000815461363a816134ce565b80608089015260a08583166000811461365a5760018114613674576136a2565b60ff1984168a83015282151560051b8a01820194506136a2565b856000528760002060005b8481101561369a5781548c820185015290880190890161367f565b8b0183019550505b50929a9950505050505050505050565b600080604083850312156136c557600080fd5b505080516020909101519092909150565b634e487b7160e01b600052603260045260246000fd5b60ff81811683821601908111156108ef576108ef613485565b6000808335601e1984360301811261371c57600080fd5b8301803591506001600160401b0382111561373657600080fd5b60200191503681900382131561374b57600080fd5b9250929050565b60006001820161376457613764613485565b5060010190565b8051801515811461377b57600080fd5b919050565b805161377b81612ec1565b805161377b81612bec565b600082601f8301126137a757600080fd5b815160206137b482612d20565b6040516137c18282612cbd565b83815260059390931b85018201928281019150868411156137e157600080fd5b8286015b84811015612db25780516137f881612bec565b83529183019183016137e5565b60006020828403121561381757600080fd5b81516001600160401b038082111561382e57600080fd5b9083019060e0828603121561384257600080fd5b61384a612ce9565b6138538361376b565b81526138616020840161376b565b602082015261387260408401613780565b604082015261388360608401613780565b606082015261389460808401613780565b60808201526138a560a08401613780565b60a082015260c0830151828111156138bc57600080fd5b6138c887828601613796565b60c08301525095945050505050565b808201808211156108ef576108ef613485565b6000608082840312156138fc57600080fd5b60405161390881612c60565b8091508251815260208084015161391e81612bec565b828201526040848101519083015260608401516001600160401b0381111561394557600080fd5b8401601f8101861361395657600080fd5b805161396181612d20565b60405161396e8282612cbd565b82815260059290921b830184019184810191508883111561398e57600080fd5b928401925b828410156139ac57835182529284019290840190613993565b80606087015250505050505092915050565b600060208083850312156139d157600080fd5b82516001600160401b03808211156139e857600080fd5b818501915085601f8301126139fc57600080fd5b8151613a0781612d20565b604051613a148282612cbd565b82815260059290921b8401850191858101915088831115613a3457600080fd5b8585015b83811015613a6c57805185811115613a505760008081fd5b613a5e8b89838a01016138ea565b845250918601918601613a38565b5098975050505050505050565b600060208284031215613a8b57600080fd5b6108ec8261376b565b600082601f830112613aa557600080fd5b8151613ab081612dbd565b604051613abd8282612cbd565b828152856020848701011115613ad257600080fd5b612844836020830160208801612f83565b600060408284031215613af557600080fd5b604051613b0181612c3b565b8091508251815260208301516001600160401b03811115613b2157600080fd5b613b2d85828601613a94565b6020830152505092915050565b600080600060608486031215613b4f57600080fd5b8351613b5a81612bec565b6020850151909350613b6b81612bec565b60408501519092506001600160401b03811115613b8757600080fd5b613b9386828701613ae3565b9150509250925092565b604081526000613bb06040830185612fa7565b90508260208301529392505050565b604081526000613bd26040830185612fa7565b90506001600160a01b03831660208301529392505050565b606081526000613bfd6060830186612fa7565b90506001600160a01b038416602083015260ff83166040830152949350505050565b634e487b7160e01b600052601260045260246000fd5b600082613c4457613c44613c1f565b500490565b600082613c5857613c58613c1f565b500690565b600060208284031215613c6f57600080fd5b81516001600160401b03811115613c8557600080fd5b612610848285016138ea565b600060208284031215613ca357600080fd5b8151612c1e81612bec565b600080600060608486031215613cc357600080fd5b8351613cce81612bec565b602085015190935060048110613ce357600080fd5b809250506040808501516001600160401b0380821115613d0257600080fd5b9086019081880360a0811215613d1757600080fd5b8351613d2281612c3b565b6080821215613d3057600080fd5b8451613d3b81612c7f565b85831215613d4857600080fd5b85519250613d5583612c3b565b8451613d6081612bec565b8084525060208501516020840152828152858501516020820152606085015186820152808252506080840151945082851115613d9b57600080fd5b613da78a868601613a94565b602082015280955050505050509250925092565b6000610100613dde83885180516001600160a01b03168252602090810151910152565b6020870151604084015260408701516060840152613e12608084018780516001600160a01b03168252602090810151910152565b6001600160a01b03851660c08401528060e0840152613e3381840185612fa7565b979650505050505050565b600060033d1115612d1d5760046000803e5060005160e01c90565b600060443d1015613e675790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715613e9657505050505090565b8285019150815181811115613eae5750505050505090565b843d8701016020828501011115613ec85750505050505090565b613ed760208286010187612cbd565b509095945050505050565b600060208284031215613ef457600080fd5b5051919050565b6020815260006108ec6020830184612fa7565b600060208284031215613f2057600080fd5b81516001600160401b0380821115613f3757600080fd5b9083019060c08286031215613f4b57600080fd5b604051613f5781612c9e565b825181526020830151613f6981612bec565b6020820152613f7a6040840161378b565b6040820152606083015182811115613f9157600080fd5b613f9d87828601613ae3565b6060830152506080830151608082015260a083015160a082015280935050505092915050565b600060208284031215613fd557600080fd5b81516001600160401b0380821115613fec57600080fd5b9083019060c0828603121561400057600080fd5b614008612d11565b825181526020830151602082015260408301518281111561402857600080fd5b61403487828601613a94565b60408301525060608301518281111561404c57600080fd5b61405887828601613ae3565b60608301525061406a6080840161378b565b608082015261407b60a0840161378b565b60a082015295945050505050565b6000825161409b818460208701612f83565b9190910192915050565b80820281158282048414176108ef576108ef61348556fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122090a027d5c30b677b89be58109c6a3efc07cbe35e974459c9b30ee5c37c08a8a964736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a10000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000000000000000000000000000000000000000003a446f6e6174696f6e566f74696e674d65726b6c65446973747269627574696f6e4469726563745472616e73666572537472617465677976322e31000000000000
-----Decoded View---------------
Arg [0] : _allo (address): 0x1133eA7Af70876e64665ecD07C0A0476d09465a1
Arg [1] : _name (string): DonationVotingMerkleDistributionDirectTransferStrategyv2.1
Arg [2] : _permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000001133ea7af70876e64665ecd07c0a0476d09465a1
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [2] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Arg [3] : 000000000000000000000000000000000000000000000000000000000000003a
Arg [4] : 446f6e6174696f6e566f74696e674d65726b6c65446973747269627574696f6e
Arg [5] : 4469726563745472616e73666572537472617465677976322e31000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.