The DonationVotingMerkleDistributionVaultStrategy
contract presents an advanced fund distribution approach within the Allo ecosystem, combining Merkle trees, recipient statuses, and precise timestamps for secure and equitable allocation. This contract builds upon the BaseStrategy
while integrating OpenZeppelin's ReentrancyGuard
and Multicall
libraries, ensuring heightened security, prevention of reentrancy attacks, and optimized batch operations.
- DonationVotingMerkleDistributionVaultStrategy.sol
- Table of Contents
- Sequence Diagram
- Smart Contract Overview
- User Flows
- Registering a Recipient
- Reviewing Recipients
- Updating Pool Timestamps
- Withdrawing Funds from Pool
- Claiming Allocated Tokens
- Updating Distribution
- Distributing Funds
- Checking Distribution Status
- Checking Distribution Set Status
- Updating Recipient Registration
- Checking Recipient Status
- Getting Recipient Details
- Getting Payout Summary
- Receiving Ether (Fallback Function)
sequenceDiagram
participant Alice
participant Bob
participant PoolManager
participant Allo
participant DonationVotingMerkle
participant Permit2
PoolManager->>Allo: createPool with DonationVotingMerkle
Allo-->>PoolManager: poolId
Alice->>+Allo: registerRecipient
Allo->>DonationVotingMerkle: registerRecipient
DonationVotingMerkle-->>Allo: recipient1
Allo-->>-Alice: recipientId 1
PoolManager-->DonationVotingMerkle: reviewRecipients()
Bob-->>+Allo: allocate()
Allo-->>-DonationVotingMerkle: allocate()
DonationVotingMerkle-->>Permit2: permitTransferFrom()
Permit2-->>DonationVotingMerkle: Funds transferred
PoolManager->>DonationVotingMerkle: setPayouts() to upload root
PoolManager->>+Allo: distribute()
Allo-->>-DonationVotingMerkle: distribute()
Alice->>DonationVotingMerkle: claim() funds from allocation
- License: The
DonationVotingMerkleDistributionVaultStrategy
contract adheres to the AGPL-3.0-only License, promoting open-source usage with specific terms. - Solidity Version: Developed using Solidity version 0.8.19, leveraging the latest Ethereum smart contract advancements.
- External Libraries: Utilizes the
MerkleProof
,ReentrancyGuard
,Multicall
libraries from OpenZeppelin for enhanced security, efficiency, and reentrancy protection,SafeTransferLib
from Solady andISignatureTransfer
from Uniswap permit2. - Interfaces: Interfaces with the
IAllo
andIRegistry
components for external communication. - Inheritance: Inherits from the
BaseStrategy
contract, inheriting and expanding core strategy functionalities.
ApplicationStatus
: Contains the recipient application's index and status row.Recipient
: Captures recipient-specific attributes, such as using a registry anchor, recipient address, and metadata.Claim
: Describes a claim for allocated tokens.Distribution
: Represents fund distribution, encompassing an index, recipient ID, allocation amount, and Merkle proof.Permit2Data
: Represents the permit data and the signature.
onlyActiveRegistration
: Restricts actions to the active registration period.onlyActiveAllocation
: Permits actions only during the active allocation phase.onlyAfterAllocation
: Allows actions after the allocation period concludes.
The constructor initializes the strategy with essential parameters and configurations.
getRecipient
: Retrieves recipient details using their ID.isDistributionSet
: Checks if the distribution is configured.hasBeenDistributed
: Verifies if a distribution has occurred.
reviewRecipients
: Enables pool managers to update recipient application statuses.updatePoolTimestamps
: Allows pool managers to adjust pool phase timestamps.withdraw
: Permits pool managers to withdraw funds post-allocation.claim
: Enables recipients to claim their allocated tokens after allocation.updateDistribution
: Enables pool managers to update distribution metadata and Merkle root.isDistributionSet
: Checks if the distribution is configured.getRecipient
: Retrieves recipient details using their ID.
_isValidAllocator
: Validates an address as an eligible allocator._isPoolTimestampValid
: Validates the pool's timestamp configuration._isPoolActive
: Checks if the pool is active._registerRecipient
: Registers a recipient with validation and status updates._allocate
: Allocates tokens to recipients using provided data._distribute
: Distributes funds to recipients based on data._isProfileMember
: Checks if the sender is a profile member (when using registry anchors)._getRecipient
: Retrieves recipient details using their ID._getRecipientStatus
: Retrieves a recipient's status (pending, accepted, rejected, appealed)._getUintRecipientStatus
: Retrieves recipient status as a uint8 value._getStatusRowColumn
: Retrieves a recipient's status row index, column index, and current row._setRecipientStatus
: Sets a recipient's status._setDistributed
: Marks a distribution as complete._validateDistribution
: Validates a distribution with a provided Merkle proof._hasBeenDistributed
: Checks if a distribution has occurred.
The contract employs a bitmap to efficiently store recipient statuses. Each bit in the bitmap represents a specific recipient's status (pending, accepted, rejected, appealed). By using 4 bits per recipient, the bitmap optimally accommodates five status levels.
The contract implements a Merkle tree structure for fund distribution. The Merkle tree is stored in the distributionMetadata
and the Merkle root is stored in merkleRoot
. To distribute funds, a pool manager submits the proofs, and the contract verifies it against the Merkle root, ensuring the validity of distributions.
In summary, the DonationVotingMerkleDistributionVaultStrategy
contract introduces a sophisticated fund distribution mechanism within the Allo ecosystem. By integrating Merkle trees, precise timestamps, and recipient status management, the contract guarantees secure and fair fund allocation. With the integration of external libraries and meticulous contract design, the strategy fosters efficient and secure fund distribution.
- Recipient initiates a registration request.
- If
useRegistryAnchor
is enabled:- Decodes recipient ID, recipient address, and metadata from provided data.
- Verifies sender's authorization as a profile member.
- Validates the provided data.
- If recipient ID is not a profile member, reverts.
- Registers recipient as "Pending" with provided details.
- Emits
Registered
event.
- If
useRegistryAnchor
is disabled:- Decodes recipient address, registry anchor (optional), and metadata from provided data.
- Determines if registry anchor is being used.
- Verifies sender's authorization as a profile member if using registry anchor.
- Validates the provided data.
- If registry anchor is used and recipient ID is not a profile member, reverts.
- Registers recipient as "Pending" with provided details.
- Emits
Registered
event.
- Pool Manager initiates a recipient status review request.
- Verifies if sender is a pool manager.
- Loops through provided application statuses and
- Updates recipient's status based on the application status.
- Emits
RecipientStatusUpdated
event.
- Pool Manager initiates a pool timestamp update request.
- Verifies if sender is a pool manager.
- Updates registration and allocation timestamps.
- Emits
TimestampsUpdated
event.
- Pool Manager initiates a withdrawal request.
- Verifies if sender is a pool manager.
- Deducts the specified amount from the pool amount.
- Transfers the specified amount to the sender's address.
- Recipient initiates a claim request.
- Verifies if claim amount is greater than zero.
- Transfers the claim amount of tokens from the contract to the recipient's address.
- Emits
Claimed
event.
- Pool Manager initiates a distribution update request.
- Verifies if sender is a pool manager.
- Checks if distribution has started, reverts if it has.
- Updates merkle root and distribution metadata.
- Emits
DistributionUpdated
event.
- Pool Manager initiates a batch payout request.
- Verifies if sender is a pool manager.
- Checks if distribution has started.
- Decodes distribution data and loops through distributions and
- Validates the distribution using merkle proof.
- Deducts the distributed amount from the pool amount.
- Transfers the distributed amount to the recipient's address.
- Marks the distribution as done. e. Emits
FundsDistributed
event.
- User initiates a distribution status check request.
- Checks if the specified distribution index has been marked as distributed.
- User initiates a distribution set status check request.
- Checks if the merkle root for distribution has been set.
- Updates recipient metadata via
registerRecipient
- Checks if the recipient's status is "Rejected.", then update status to "Appealed."
- Checks if the recipient's status is "Accepted.", then update status to "Pending."
- Checks if the recipient's status is "Pending"/"Appealed", no change in status.
- Emits
UpdatedRegistration
event.
- User initiates a recipient status check request.
- Retrieves and returns the recipient status.
- User initiates a recipient details request.
- Retrieves and returns recipient details, including recipient address and metadata.
- Pool Manager initiates a payout summary request.
- Decodes distribution data and retrieves recipient address and payout amount for a distribution.
- The contract receives Ether from external transactions.
- Ether is added to the contract's balance.