TokenizedAllocationMechanism
Inherits: IERC20
Title: TokenizedAllocationMechanism
Author: Golem Foundation
Shared implementation for allocation/voting mechanisms (Yearn V3 pattern)
Handles all standard voting logic via delegatecall from mechanism proxies
PROPOSAL STATE MACHINE:
Pending -> Active -> Tallying -> Defeated/Succeeded -> Queued -> Redeemable -> Expired
Canceled proposals leave the normal lifecycle as a terminal state.
STATE DESCRIPTIONS:
- Pending: Proposal created, waiting for votingDelay
- Active: Voting period active, users can cast votes
- Tallying: Voting ended, waiting for finalization
- Defeated: Voting ended, failed quorum
- Succeeded: Voting ended, passed quorum
- Queued: Shares minted, waiting for timelock
- Redeemable: Timelock passed, within grace period
- Expired: Grace period passed, redemptions closed
- Canceled: Proposer canceled (terminal state)
LIFECYCLE TIMELINE:
- T0: Proposal created (Pending)
- T0 + votingDelay: Voting opens (Active)
- T0 + votingDelay + votingPeriod: Voting closes (Tallying)
- Anyone calls finalizeVoteTally(): Defeated or Succeeded
- If Succeeded, anyone calls queue(): Queued (shares minted)
- Queued + timelockDelay: Redeemable (redemptions allowed)
- Redeemable + gracePeriod: Expired (redemptions closed)
VOTING MECHANICS:
- Users signup (deposit assets, get voting power)
- Proposals created during registration period
- Users cast votes (Against/For/Abstain)
- Votes finalized after votingPeriod
- Successful proposals get shares minted
- Recipients redeem shares for assets
SECURITY FEATURES:
- Timelock: Delay before redemptions (security buffer)
- Grace Period: Limited redemption window
- Quorum: Minimum votes required
- EIP-712: Gasless signups and votes
- Reentrancy protection
- Pausability
Notes:
-
security-contact: [email protected]
-
security: State machine enforces proper proposal progression
-
security: Timelock provides security delay before fund distribution
Quick Start — What Matters Most
This is the shared lifecycle implementation for all allocation mechanisms. It manages the round lifecycle from registration through redemption.
Key functions to understand:
signup— Users register and deposit assetspropose— Create funding proposalscastVote— Cast votes on proposalsfinalizeVoteTally— Tally votes and determine winners (onlyOwner)queueProposal— Mint shares for successful proposals
State Variables
MAX_SAFE_VALUE
Maximum safe value for internal math to avoid overflows
Capped at uint128.max to keep intermediate operations within safe bounds
uint256 public constant MAX_SAFE_VALUE = type(uint128).max
ALLOCATION_STORAGE_SLOT
Storage slot for allocation mechanism data (EIP-1967-like deterministic slot)
Calculated as keccak256("tokenized.allocation.storage") - 1 to minimize collision risk
bytes32 private constant ALLOCATION_STORAGE_SLOT = bytes32(uint256(keccak256("tokenized.allocation.storage")) - 1)
TYPE_HASH
EIP-712 Domain separator typehash
Used to compute domain separator for structured data signing
bytes32 private constant TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
SIGNUP_TYPEHASH
Signup typehash for EIP-712 structured data
Typed data: Signup(user, payer, deposit, nonce, deadline)
bytes32 private constant SIGNUP_TYPEHASH =
keccak256("Signup(address user,address payer,uint256 deposit,uint256 nonce,uint256 deadline)")
CAST_VOTE_TYPEHASH
CastVote typehash for EIP-712 structured data
Typed data: CastVote(voter, proposalId, choice, weight, expectedRecipient, nonce, deadline)
bytes32 private constant CAST_VOTE_TYPEHASH = keccak256(
"CastVote(address voter,uint256 proposalId,uint8 choice,uint256 weight,address expectedRecipient,uint256 nonce,uint256 deadline)"
)
EIP712_VERSION
EIP-712 version string used in domain separator
Update only with extreme caution; changing breaks signature domain
string private constant EIP712_VERSION = "1"
Functions
_getStorage
Get the storage struct from the predefined slot
function _getStorage() internal pure returns (AllocationStorage storage s);
Returns
| Name | Type | Description |
|---|---|---|
s | AllocationStorage | Storage struct containing all mutable state |
constructor
Constructor to prevent initialization of the library implementation
constructor() ;
DOMAIN_SEPARATOR
Returns the domain separator, updating it if chain ID changed (fork protection)
function DOMAIN_SEPARATOR() public returns (bytes32);
_computeDomainSeparator
Computes the domain separator
function _computeDomainSeparator(AllocationStorage storage s) private view returns (bytes32);
onlyOwner
modifier onlyOwner() ;
whenNotPaused
modifier whenNotPaused() ;
nonReentrant
modifier nonReentrant() ;
initialize
Initialize the allocation mechanism with configuration
Can only be called once by the strategy/clone proxy; subsequent calls revert
Note:
security: Initialization guarded by AlreadyInitialized check
function initialize(
address _owner,
IERC20 _asset,
string memory _name,
string memory _symbol,
uint256 _votingDelay,
uint256 _votingPeriod,
uint256 _quorumShares,
uint256 _timelockDelay,
uint256 _gracePeriod
) external;
Parameters
| Name | Type | Description |
|---|---|---|
_owner | address | Address that will become the owner and management |
_asset | IERC20 | Underlying ERC20 asset used for deposits/redemptions |
_name | string | ERC20 name for the shares token |
_symbol | string | ERC20 symbol for the shares token |
_votingDelay | uint256 | Delay before voting opens (seconds) |
_votingPeriod | uint256 | Duration of the voting phase (seconds) |
_quorumShares | uint256 | Quorum threshold (shares, 18 decimals) |
_timelockDelay | uint256 | Delay after queueing before redemptions (seconds) |
_gracePeriod | uint256 | Duration of redemption window (seconds) |
_initializeAllocation
Internal allocation mechanism initialization
Shared initializer used by initialize
function _initializeAllocation(
address _owner,
IERC20 _asset,
string memory _name,
string memory _symbol,
uint256 _votingDelay,
uint256 _votingPeriod,
uint256 _quorumShares,
uint256 _timelockDelay,
uint256 _gracePeriod
) internal;
Parameters
| Name | Type | Description |
|---|---|---|
_owner | address | Address that will become the owner and management |
_asset | IERC20 | Underlying ERC20 asset used for deposits/redemptions |
_name | string | ERC20 name for the shares token |
_symbol | string | ERC20 symbol for the shares token |
_votingDelay | uint256 | Delay before voting opens (seconds) |
_votingPeriod | uint256 | Duration of the voting phase (seconds) |
_quorumShares | uint256 | Quorum threshold (shares, 18 decimals) |
_timelockDelay | uint256 | Delay after queueing before redemptions (seconds) |
_gracePeriod | uint256 | Duration of redemption window (seconds) |
signup
Register to gain voting power by depositing underlying tokens
Note: security: Reentrancy protected; callable only when not paused
function signup(uint256 deposit) external nonReentrant whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
deposit | uint256 | Amount of underlying to deposit (asset base units, may be zero) |
signupOnBehalfWithSignature
Register on behalf of another user using EIP-712 signature
The deposit will be taken from msg.sender, not the user. Increments nonces[user].
Note: security: Reentrancy protected; callable only when not paused
function signupOnBehalfWithSignature(address user, uint256 deposit, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
external
nonReentrant
whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
user | address | Address of the user signing up |
deposit | uint256 | Amount of underlying to deposit (asset base units) |
deadline | uint256 | Expiration timestamp for the signature (seconds) |
v | uint8 | Signature parameter |
r | bytes32 | Signature parameter |
s | bytes32 | Signature parameter |
signupWithSignature
Register with voting power using EIP-712 signature
The deposit will be taken from the user themselves. Increments nonces[user].
Note: security: Reentrancy protected; callable only when not paused
function signupWithSignature(address user, uint256 deposit, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
external
nonReentrant
whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
user | address | Address of the user signing up |
deposit | uint256 | Amount of underlying to deposit (asset base units) |
deadline | uint256 | Expiration timestamp for the signature (seconds) |
v | uint8 | Signature parameter |
r | bytes32 | Signature parameter |
s | bytes32 | Signature parameter |
_validateSignature
Validates signature parameters with ERC1271 support for contract signers
function _validateSignature(
address expectedSigner,
bytes32 structHash,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) private;
_executeSignup
Internal signup execution logic
function _executeSignup(address user, uint256 deposit, address payer) private;
propose
Create a new proposal targeting recipient
Note: security: Reentrancy protected; callable only when not paused; subject to strategy hook
function propose(address recipient, string calldata description)
external
whenNotPaused
nonReentrant
returns (uint256 pid);
Parameters
| Name | Type | Description |
|---|---|---|
recipient | address | Address to receive allocated vault shares upon queue |
description | string | Human-readable description or rationale for the proposal |
Returns
| Name | Type | Description |
|---|---|---|
pid | uint256 | Unique identifier for the new proposal |
castVote
Cast a vote on a proposal
Note: security: Reentrancy protected; callable only when not paused; only during voting window
function castVote(uint256 pid, VoteType choice, uint256 weight, address expectedRecipient)
external
nonReentrant
whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Proposal ID |
choice | VoteType | VoteType (Against, For, Abstain) |
weight | uint256 | Amount of voting power to apply (shares, 18 decimals) |
expectedRecipient | address | Expected recipient address to prevent reorganization attacks |
castVoteWithSignature
Cast vote using EIP-712 signature
Note: security: Reentrancy protected; callable only when not paused; only during voting window
function castVoteWithSignature(
address voter,
uint256 pid,
VoteType choice,
uint256 weight,
address expectedRecipient,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external nonReentrant whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
voter | address | Address of the voter |
pid | uint256 | Proposal ID |
choice | VoteType | Vote choice (Against, For, Abstain) |
weight | uint256 | Voting weight to use (shares, 18 decimals) |
expectedRecipient | address | Expected recipient address for the proposal |
deadline | uint256 | Expiration timestamp for the signature (seconds) |
v | uint8 | Signature parameter |
r | bytes32 | Signature parameter |
s | bytes32 | Signature parameter |
_executeCastVote
Internal vote execution logic
function _executeCastVote(address voter, uint256 pid, VoteType choice, uint256 weight, address expectedRecipient)
private;
finalizeVoteTally
Finalize vote tally once voting period has ended
Note: security: Only owner; reentrancy protected
function finalizeVoteTally() external onlyOwner nonReentrant;
queueProposal
Queue proposal and trigger share distribution
Note: security: Reentrancy protected; callable only after tally finalized and before redemption
function queueProposal(uint256 pid) external nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Proposal ID to queue |
state
Get the current state of a proposal
function state(uint256 pid) external view returns (ProposalState);
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Proposal ID |
Returns
| Name | Type | Description |
|---|---|---|
<none> | ProposalState | Current state of the proposal |
_state
Internal state computation for a proposal with direct time range checks
function _state(uint256 pid) internal view returns (ProposalState);
cancelProposal
Cancel a proposal
Can only be called before vote tally is finalized. After finalization, all proposals are immutable.
This prevents race conditions and ensures coordinators can verify all proposals before committing.
function cancelProposal(uint256 pid) external nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Proposal ID to cancel |
getProposalCount
Get total number of proposals created
function getProposalCount() external view returns (uint256);
name
Returns the mechanism name
function name() external view returns (string memory);
symbol
Returns the mechanism symbol
function symbol() external view returns (string memory);
asset
Returns the underlying asset
function asset() external view returns (IERC20);
owner
Returns the current owner
function owner() external view returns (address);
pendingOwner
Returns the pending owner awaiting acceptance
function pendingOwner() external view returns (address);
tallyFinalized
Returns whether vote tally has been finalized
function tallyFinalized() external view returns (bool);
proposals
Returns proposal data for a given proposal ID
function proposals(uint256 pid) external view returns (Proposal memory);
votingPower
Returns the voting power for a user
function votingPower(address user) external view returns (uint256);
proposalShares
Returns allocated shares for a proposal
function proposalShares(uint256 pid) external view returns (uint256);
startBlock
Returns the block number when mechanism was initialized
function startBlock() external view returns (uint256);
votingDelay
Returns the voting delay period in blocks
function votingDelay() external view returns (uint256);
votingPeriod
Returns the voting period duration in blocks
function votingPeriod() external view returns (uint256);
quorumShares
Returns the minimum shares required for quorum
function quorumShares() external view returns (uint256);
timelockDelay
Returns the timelock delay in seconds
function timelockDelay() external view returns (uint256);
gracePeriod
Returns the grace period duration in seconds
function gracePeriod() external view returns (uint256);
globalRedemptionStart
Returns the global redemption start timestamp
function globalRedemptionStart() external view returns (uint256);
votingStartTime
Returns the voting start timestamp
function votingStartTime() external view returns (uint256);
votingEndTime
Returns the voting end timestamp
function votingEndTime() external view returns (uint256);
startTime
Returns the mechanism start timestamp
function startTime() external view returns (uint256);
nonces
Returns the current nonce for an address
function nonces(address account) external view returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
account | address | Address to check nonce for |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Current nonce for permit operations |
transferOwnership
Initiate ownership transfer to a new address (step 1 of 2)
function transferOwnership(address newOwner) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
newOwner | address | Address to transfer ownership to |
acceptOwnership
Accept ownership transfer (step 2 of 2)
Must be called by the pending owner to complete the transfer
function acceptOwnership() external;
cancelOwnershipTransfer
Cancel pending ownership transfer
Can only be called by current owner
function cancelOwnershipTransfer() external onlyOwner;
setKeeper
Update keeper address
function setKeeper(address newKeeper) external onlyOwner;
setManagement
Update management address
function setManagement(address newManagement) external onlyOwner;
pause
Emergency pause all operations
function pause() external onlyOwner;
unpause
Resume operations after pause
function unpause() external onlyOwner;
paused
Check if contract is paused
function paused() external view returns (bool);
sweep
Sweep remaining tokens after grace period expires
Can only be called by owner after global grace period ends
function sweep(address token, address receiver) external onlyOwner nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
token | address | Token to sweep (use address(0) for ETH) |
receiver | address | Address to receive swept tokens |
redeem
Redeems exactly shares from shareOwner and
sends assets of underlying tokens to receiver.
Reverts with "ZERO_ASSETS" if shares amount rounds to 0 assets
Reverts with "redeem more than max" if shares > maxRedeem(shareOwner)
function redeem(uint256 shares, address receiver, address shareOwner) external nonReentrant returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
shares | uint256 | Amount of shares to burn |
receiver | address | Address to receive withdrawn assets |
shareOwner | address | Address whose shares are burned |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | assetsWithdrawn Actual amount of underlying withdrawn in asset base units |
totalAssets
Get the total amount of assets this strategy holds
as of the last report.
We manually track totalAssets to avoid any PPS manipulation.
function totalAssets() external view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | totalAssets_ Total assets the strategy holds. |
totalSupply
Get the current supply of the strategies shares. Locked shares issued to the strategy from profits are not counted towards the full supply until they are unlocked. As more shares slowly unlock the totalSupply will decrease causing the PPS of the strategy to increase.
function totalSupply() external view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | totalSupply_ Total amount of shares outstanding. |
convertToShares
The amount of shares that the strategy would exchange for the amount of assets provided, in an ideal scenario where all the conditions are met.
function convertToShares(uint256 assets) external view returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
assets | uint256 | Amount of underlying assets |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | shares_ Expected shares that assets represent |
convertToAssets
The amount of assets that the strategy would exchange for the amount of shares provided, in an ideal scenario where all the conditions are met.
function convertToAssets(uint256 shares) external view returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
shares | uint256 | Amount of strategy shares |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | assets_ Expected assets the shares represent in asset base units |
previewRedeem
Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block, given current on-chain conditions.
This will round down.
function previewRedeem(uint256 shares) external view returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
shares | uint256 | Amount of shares to redeem |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | assets_ Amount of assets that would be returned in asset base units |
maxRedeem
Total number of strategy shares that can be
redeemed from the strategy by shareOwner, where shareOwner
corresponds to the msg.sender of a redeem call.
function maxRedeem(address shareOwner) external view returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
shareOwner | address | Address that owns the shares |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | _maxRedeem Maximum shares that can be redeemed |
management
Returns the management address
function management() external view returns (address);
keeper
Returns the keeper address
function keeper() external view returns (address);
decimals
Returns the decimals used for the token (always 18)
function decimals() external pure returns (uint8);
balanceOf
Returns the balance of an account
function balanceOf(address account) external view returns (uint256);
allowance
Returns the allowance of a spender for a token owner
function allowance(address tokenOwner, address spender) external view returns (uint256);
_totalAssets
Internal implementation of totalAssets.
function _totalAssets(AllocationStorage storage S) internal view returns (uint256);
_totalSupply
Internal implementation of totalSupply.
function _totalSupply(AllocationStorage storage S) internal view returns (uint256);
_convertToShares
Internal implementation of convertToShares.
function _convertToShares(AllocationStorage storage S, uint256 assets, Math.Rounding _rounding)
internal
view
returns (uint256);
_convertToAssets
Internal implementation of convertToAssets.
function _convertToAssets(AllocationStorage storage S, uint256 shares, Math.Rounding _rounding)
internal
view
returns (uint256);
_maxRedeem
Internal implementation of maxRedeem.
function _maxRedeem(AllocationStorage storage S, address shareOwner) internal view returns (uint256 maxRedeem_);
_balanceOf
Internal implementation of balanceOf.
function _balanceOf(AllocationStorage storage S, address account) internal view returns (uint256);
_allowance
Internal implementation of allowance.
function _allowance(AllocationStorage storage S, address tokenOwner, address spender)
internal
view
returns (uint256);
_withdraw
To be called during redeem and withdraw.
This will handle all logic, transfers and accounting
in order to service the withdraw request.
function _withdraw(
AllocationStorage storage S,
address receiver,
address shareOwner,
uint256 assets,
uint256 shares
) internal returns (uint256);
transfer
Transfer '_amountof shares frommsg.sendertoto`.
Requirements:
tocannot be the zero address.tocannot be the address of the strategy.- the caller must have a balance of at least
_amount.
function transfer(address to, uint256 amount) external returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
to | address | Address receiving the shares |
amount | uint256 | Amount of shares to transfer |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | success True if operation succeeded |
approve
Sets amount as the allowance of spender over the caller's tokens.
NOTE: If amount is the maximum uint256, the allowance is not updated on
transferFrom. This is semantically equivalent to an infinite approval.
Requirements:
spendercannot be the zero address. 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 anApprovalevent.
function approve(address spender, uint256 amount) external returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
spender | address | the address to allow the shares to be moved by. |
amount | uint256 | the amount of shares to allow spender to move. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | success True if the operation succeeded. |
transferFrom
amount tokens from from to to using the
allowance mechanism. amount is then deducted from the caller's
allowance.
Emits an Approval event indicating the updated allowance. This is not
required by the EIP.
NOTE: Does not update the allowance if the current allowance
is the maximum uint256.
Requirements:
fromandtocannot be the zero address.tocannot be the address of the strategy.frommust have a balance of at leastamount.- the caller must have allowance for
from's tokens of at leastamount. Emits aTransferevent.
function transferFrom(address from, address to, uint256 amount) external returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
from | address | the address to be moving shares from. |
to | address | the address to be moving shares to. |
amount | uint256 | the quantity of shares to move. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | success True if the operation succeeded. |
_transfer
Moves amount of tokens from from to to.
This internal function is equivalent to transfer, and can be used to
e.g. implement automatic token fees, slashing mechanisms, etc.
Emits a Transfer event.
Requirements:
fromcannot be the zero address.tocannot be the zero address.tocannot be the strategies addressfrommust have a balance of at leastamount.
function _transfer(AllocationStorage storage S, address from, address to, uint256 amount) internal;
_mint
Creates amount tokens and assigns them to account, increasing
the total supply.
Emits a Transfer event with from set to the zero address.
Requirements:
accountcannot be the zero address.
function _mint(AllocationStorage storage S, address account, uint256 amount) internal;
_burn
Destroys amount tokens from account, reducing the
total supply.
Emits a Transfer event with to set to the zero address.
Requirements:
accountcannot be the zero address.accountmust have at leastamounttokens.
function _burn(AllocationStorage storage S, address account, uint256 amount) internal;
_approve
Sets amount as the allowance of spender over the owner s tokens.
This internal function is equivalent to approve, and can be used to
e.g. set automatic allowances for certain subsystems, etc.
Emits an Approval event.
Requirements:
ownercannot be the zero address.spendercannot be the zero address.
function _approve(AllocationStorage storage S, address tokenOwner, address spender, uint256 amount) internal;
_spendAllowance
Updates owner s allowance for spender based on spent amount.
Does not update the allowance amount in case of infinite allowance.
Revert if not enough allowance is available.
Might emit an Approval event.
function _spendAllowance(AllocationStorage storage S, address tokenOwner, address spender, uint256 amount)
internal;
Events
UserRegistered
Emitted when a user completes registration
event UserRegistered(address indexed user, uint256 votingPower);
Parameters
| Name | Type | Description |
|---|---|---|
user | address | Address of the registered user |
votingPower | uint256 | Voting power granted (shares, 18 decimals) |
ProposalCreated
Emitted when a new proposal is created
event ProposalCreated(uint256 indexed pid, address indexed proposer, address indexed recipient, string description);
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Newly assigned proposal id |
proposer | address | Address that created the proposal |
recipient | address | Intended recipient of minted shares upon queue |
description | string | Human-readable proposal description |
VotesCast
Emitted when a vote is cast
event VotesCast(address indexed voter, uint256 indexed pid, uint256 weight);
Parameters
| Name | Type | Description |
|---|---|---|
voter | address | Address casting the vote |
pid | uint256 | Proposal id being voted on |
weight | uint256 | Vote weight used (shares, 18 decimals) |
VoteTallyFinalized
Emitted when vote tally is finalized
event VoteTallyFinalized();
ProposalQueued
Emitted when a proposal is queued and shares minted
event ProposalQueued(uint256 indexed pid, uint256 eta, uint256 shareAmount);
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Proposal id being queued |
eta | uint256 | Timestamp when timelock elapses and redemptions can begin (seconds) |
shareAmount | uint256 | Number of shares minted/allocated in share base units |
ProposalCanceled
Emitted when a proposal is canceled
event ProposalCanceled(uint256 indexed pid, address indexed proposer);
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Proposal id that was canceled |
proposer | address | Address of the canceling proposer |
OwnershipTransferInitiated
Emitted when ownership transfer is initiated
event OwnershipTransferInitiated(address indexed currentOwner, address indexed pendingOwner);
Parameters
| Name | Type | Description |
|---|---|---|
currentOwner | address | Current owner address |
pendingOwner | address | Address nominated to become the new owner |
OwnershipTransferCanceled
Emitted when ownership transfer is canceled
event OwnershipTransferCanceled(address indexed currentOwner, address indexed canceledPendingOwner);
Parameters
| Name | Type | Description |
|---|---|---|
currentOwner | address | Current owner address |
canceledPendingOwner | address | Previously pending owner whose transfer was canceled |
OwnershipTransferred
Emitted when ownership is transferred
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
Parameters
| Name | Type | Description |
|---|---|---|
previousOwner | address | Address of the previous owner |
newOwner | address | Address of the new owner |
KeeperUpdated
Emitted when keeper is updated
event KeeperUpdated(address indexed previousKeeper, address indexed newKeeper);
Parameters
| Name | Type | Description |
|---|---|---|
previousKeeper | address | Old keeper address |
newKeeper | address | New keeper address |
ManagementUpdated
Emitted when management is updated
event ManagementUpdated(address indexed previousManagement, address indexed newManagement);
Parameters
| Name | Type | Description |
|---|---|---|
previousManagement | address | Old management address |
newManagement | address | New management address |
PausedStatusChanged
Emitted when contract is paused/unpaused
event PausedStatusChanged(bool paused);
Parameters
| Name | Type | Description |
|---|---|---|
paused | bool | True if paused, false if unpaused |
GlobalRedemptionPeriodSet
Emitted when global redemption period is set
event GlobalRedemptionPeriodSet(uint256 redemptionStart, uint256 redemptionEnd);
Parameters
| Name | Type | Description |
|---|---|---|
redemptionStart | uint256 | Timestamp when global redemptions can begin (seconds) |
redemptionEnd | uint256 | Timestamp when global redemptions end (seconds) |
Swept
Emitted when tokens are swept after grace period
event Swept(address indexed token, address indexed receiver, uint256 amount);
Parameters
| Name | Type | Description |
|---|---|---|
token | address | Token address that was swept |
receiver | address | Recipient of swept tokens |
amount | uint256 | Amount swept in token base units |
Withdraw
event Withdraw(
address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares
);
Parameters
| Name | Type | Description |
|---|---|---|
caller | address | Address initiating the redemption |
receiver | address | Address receiving the underlying assets |
owner | address | Owner of the shares being redeemed |
assets | uint256 | Amount of underlying assets transferred (asset base units) |
shares | uint256 | Amount of shares burned in share base units |
Errors
ZeroAssetAddress
error ZeroAssetAddress();
ZeroVotingDelay
error ZeroVotingDelay();
ZeroVotingPeriod
error ZeroVotingPeriod();
ZeroQuorumShares
error ZeroQuorumShares();
ZeroTimelockDelay
error ZeroTimelockDelay();
ZeroGracePeriod
error ZeroGracePeriod();
ZeroStartBlock
error ZeroStartBlock();
InvalidStartTime
error InvalidStartTime(uint256 startTime, uint256 currentTime);
Parameters
| Name | Type | Description |
|---|---|---|
startTime | uint256 | Proposed start timestamp in seconds |
currentTime | uint256 | Current block timestamp in seconds |
EmptyName
error EmptyName();
EmptySymbol
error EmptySymbol();
RegistrationBlocked
error RegistrationBlocked(address user);
Parameters
| Name | Type | Description |
|---|---|---|
user | address | Address attempting to register |
VotingEnded
error VotingEnded(uint256 currentTime, uint256 endTime);
Parameters
| Name | Type | Description |
|---|---|---|
currentTime | uint256 | Current block timestamp in seconds |
endTime | uint256 | Voting end timestamp in seconds |
AlreadyRegistered
error AlreadyRegistered(address user);
Parameters
| Name | Type | Description |
|---|---|---|
user | address | Address that is already registered |
DepositTooLarge
error DepositTooLarge(uint256 deposit, uint256 maxAllowed);
Parameters
| Name | Type | Description |
|---|---|---|
deposit | uint256 | Deposit amount in asset base units (token decimals) |
maxAllowed | uint256 | Maximum allowed deposit in asset base units |
VotingPowerTooLarge
error VotingPowerTooLarge(uint256 votingPower, uint256 maxAllowed);
Parameters
| Name | Type | Description |
|---|---|---|
votingPower | uint256 | Voting power in shares units in share base units |
maxAllowed | uint256 | Maximum allowed voting power in share base units |
InsufficientDeposit
error InsufficientDeposit(uint256 deposit);
Parameters
| Name | Type | Description |
|---|---|---|
deposit | uint256 | Deposit amount in asset base units (token decimals) |
ProposeNotAllowed
error ProposeNotAllowed(address proposer);
Parameters
| Name | Type | Description |
|---|---|---|
proposer | address | Address attempting to propose |
InvalidRecipient
error InvalidRecipient(address recipient);
Parameters
| Name | Type | Description |
|---|---|---|
recipient | address | Invalid recipient address |
InvalidUser
error InvalidUser(address user);
Parameters
| Name | Type | Description |
|---|---|---|
user | address | Invalid user address |
RecipientUsed
error RecipientUsed(address recipient);
Parameters
| Name | Type | Description |
|---|---|---|
recipient | address | Recipient with an active proposal |
RecipientMismatch
error RecipientMismatch(uint256 pid, address expected, address actual);
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Proposal id |
expected | address | Expected recipient address |
actual | address | Provided recipient address |
DescriptionMismatch
error DescriptionMismatch(uint256 pid);
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Proposal id |
EmptyDescription
error EmptyDescription();
DescriptionTooLong
error DescriptionTooLong(uint256 length, uint256 maxLength);
Parameters
| Name | Type | Description |
|---|---|---|
length | uint256 | Provided description length in bytes |
maxLength | uint256 | Maximum allowed length in bytes |
VotingNotEnded
error VotingNotEnded(uint256 currentTime, uint256 endTime);
Parameters
| Name | Type | Description |
|---|---|---|
currentTime | uint256 | Current block timestamp in seconds |
endTime | uint256 | Voting end timestamp in seconds |
TallyAlreadyFinalized
error TallyAlreadyFinalized();
FinalizationBlocked
error FinalizationBlocked();
TallyNotFinalized
error TallyNotFinalized();
InvalidProposal
error InvalidProposal(uint256 pid);
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Invalid proposal id |
ProposalCanceledError
error ProposalCanceledError(uint256 pid);
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Canceled proposal id |
NoQuorum
error NoQuorum(uint256 pid, uint256 forVotes, uint256 againstVotes, uint256 required);
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Proposal id |
forVotes | uint256 | Total for votes in share base units |
againstVotes | uint256 | Total against votes in share base units |
required | uint256 | Quorum threshold in shares in share base units |
AlreadyQueued
error AlreadyQueued(uint256 pid);
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Proposal id |
QueueingClosedAfterRedemption
error QueueingClosedAfterRedemption();
NoAllocation
error NoAllocation(uint256 pid, uint256 sharesToMint);
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Proposal id |
sharesToMint | uint256 | Calculated shares to mint in share base units |
InsufficientAssets
error InsufficientAssets(uint256 requested, uint256 available);
Parameters
| Name | Type | Description |
|---|---|---|
requested | uint256 | Assets requested in base units (token decimals) |
available | uint256 | Available assets in base units (token decimals) |
VotingClosed
error VotingClosed(uint256 currentTime, uint256 startTime, uint256 endTime);
Parameters
| Name | Type | Description |
|---|---|---|
currentTime | uint256 | Current block timestamp in seconds |
startTime | uint256 | Voting start timestamp in seconds |
endTime | uint256 | Voting end timestamp in seconds |
InvalidWeight
error InvalidWeight(uint256 weight, uint256 votingPower);
Parameters
| Name | Type | Description |
|---|---|---|
weight | uint256 | Vote weight in shares in share base units |
votingPower | uint256 | Voter's voting power in shares in share base units |
WeightTooLarge
error WeightTooLarge(uint256 weight, uint256 maxAllowed);
Parameters
| Name | Type | Description |
|---|---|---|
weight | uint256 | Vote weight in shares in share base units |
maxAllowed | uint256 | Maximum allowed weight in shares in share base units |
PowerIncreased
error PowerIncreased(uint256 oldPower, uint256 newPower);
Parameters
| Name | Type | Description |
|---|---|---|
oldPower | uint256 | Previous voting power in shares in share base units |
newPower | uint256 | New voting power in shares in share base units |
NotProposer
error NotProposer(address caller, address proposer);
Parameters
| Name | Type | Description |
|---|---|---|
caller | address | Caller address |
proposer | address | Expected proposer address |
AlreadyCanceled
error AlreadyCanceled(uint256 pid);
Parameters
| Name | Type | Description |
|---|---|---|
pid | uint256 | Proposal id |
Unauthorized
error Unauthorized();
AlreadyInitialized
error AlreadyInitialized();
PausedError
error PausedError();
ReentrantCall
error ReentrantCall();
ExpiredSignature
error ExpiredSignature(uint256 deadline, uint256 currentTime);
Parameters
| Name | Type | Description |
|---|---|---|
deadline | uint256 | Signature deadline timestamp in seconds |
currentTime | uint256 | Current block timestamp in seconds |
InvalidSignature
error InvalidSignature();
InvalidSigner
error InvalidSigner(address recovered, address expected);
Parameters
| Name | Type | Description |
|---|---|---|
recovered | address | Address recovered from signature |
expected | address | Expected signer address |
Structs
Proposal
Core proposal data used throughout the allocation mechanism
Stores immutable metadata for a proposal; dynamic tallies are kept elsewhere
struct Proposal {
/// @notice Number of shares requested if proposal succeeds in share base units
uint256 sharesRequested;
/// @notice Address that created the proposal
address proposer;
/// @notice Intended recipient of minted shares upon queue
address recipient;
/// @notice Human-readable description or rationale for the proposal
string description;
/// @notice True if the proposer canceled the proposal (terminal state)
bool canceled;
}
AllocationStorage
Main storage struct containing all allocation mechanism state
Stored at a deterministic slot; see ALLOCATION_STORAGE_SLOT
struct AllocationStorage {
// Basic information
/// @notice ERC20 name for the shares token
string name;
/// @notice ERC20 symbol for the shares token
string symbol;
/// @notice Underlying ERC20 asset used for deposits and redemptions
IERC20 asset;
// Configuration (immutable after initialization)
/// @notice Block number at initialization for legacy compatibility (blocks)
uint256 startBlock;
/// @notice Voting delay after start before voting opens (seconds)
uint256 votingDelay;
/// @notice Voting duration once opened (seconds)
uint256 votingPeriod;
/// @notice Timelock duration after queue before redemptions (seconds)
uint256 timelockDelay;
/// @notice Grace period during which redemptions are allowed (seconds)
uint256 gracePeriod;
/// @notice Quorum threshold in shares required for success in share base units
uint256 quorumShares;
/// @notice Mechanism start timestamp (seconds)
uint256 startTime;
/// @notice Timestamp when voting opens (startTime + votingDelay) (seconds)
uint256 votingStartTime;
/// @notice Timestamp when voting ends (startTime + votingDelay + votingPeriod) (seconds)
uint256 votingEndTime;
/// @notice Timestamp when {finalizeVoteTally} was called (seconds)
uint256 tallyFinalizedTime;
// Access control
/// @notice Current contract owner authorized to manage configuration
address owner;
/// @notice Pending owner waiting to accept ownership
address pendingOwner;
/// @notice Global pause flag to disable mutating actions
bool paused;
/// @notice True once {initialize} has been successfully called
bool initialized;
// Reentrancy protection
/// @notice Reentrancy guard flag (1 = NOT_ENTERED, 2 = ENTERED)
uint8 reentrancyStatus;
// Voting state
/// @notice True if vote tally is finalized (post-voting)
bool tallyFinalized;
/// @notice Monotonic counter used to assign new proposal ids
uint256 proposalIdCounter;
/// @notice Global timestamp when all redemptions and transfers can begin (seconds)
uint256 globalRedemptionStart;
/// @notice Global timestamp when the redemption period ends (seconds)
uint256 globalRedemptionEndTime;
// Allocation Mechanism Vault Storage (merged from DistributionMechanism)
/// @notice Per-address sequential nonces for EIP-712 signatures
mapping(address => uint256) nonces;
/// @notice Share balances per account in share base units
mapping(address => uint256) balances;
/// @notice Allowances mapping for share spenders in share base units
mapping(address => mapping(address => uint256)) allowances;
/// @notice Total number of shares in circulation in share base units
uint256 totalSupply;
/// @notice Total assets under management in underlying base units
/// @dev Manually tracked to prevent PPS manipulation through airdrops
uint256 totalAssets;
// Strategy Management
/// @notice Address permitted to perform keeper operations
address keeper;
/// @notice Management address authorized to update configuration
address management;
/// @notice Decimals used by asset and this shares token
uint8 decimals;
// Mappings
/// @notice Mapping from proposal id to stored {Proposal}
mapping(uint256 => Proposal) proposals;
/// @notice Tracks active proposal id for a given recipient (if any)
mapping(address => uint256) activeProposalByRecipient;
/// @notice Voting power per user in shares in share base units
mapping(address => uint256) votingPower;
/// @notice Shares allocated to each proposal in share base units
mapping(uint256 => uint256) proposalShares;
// EIP712 storage
/// @notice Cached EIP-712 domain separator for signatures
bytes32 domainSeparator; // Cached domain separator
/// @notice Chain id used in domain separator to provide fork protection
uint256 initialChainId; // Chain ID at deployment for fork protection
}
Enums
VoteType
Vote types for proposal voting
Used in castVote() to indicate vote direction
enum VoteType {
/// @notice Vote against the proposal
Against,
/// @notice Vote in favor of the proposal
For,
/// @notice Abstain from voting (recorded but doesn't affect outcome)
Abstain
}
ProposalState
Proposal lifecycle states
State machine progression enforced by contract logic
enum ProposalState {
/// @notice Created, waiting for votingDelay to pass
Pending,
/// @notice Voting period active, can cast votes
Active,
/// @notice Proposer canceled, terminal state
Canceled,
/// @notice Voting ended, awaiting finalization
Tallying,
/// @notice Finalized, failed quorum (terminal)
Defeated,
/// @notice Finalized, passed quorum, ready to queue
Succeeded,
/// @notice Shares minted, waiting for timelock
Queued,
/// @notice Timelock passed, in grace period (can redeem)
Redeemable,
/// @notice Grace period ended (redemptions closed)
Expired
}