Treasury
1. Overview
The Treasury contract implements a secure, upgradeable vesting mechanism for managing and distributing both ETH and ERC20 tokens to beneficiaries according to a linear vesting schedule. The contract serves as the financial backbone for the Lendefi DAO, controlling the release of funds over time with appropriate governance controls.
2. Contract Architecture
The contract inherits from multiple OpenZeppelin upgradeable contracts to provide a robust foundation:
AccessControlUpgradeable: Role-based permission system
PausableUpgradeable: Emergency pause functionality
UUPSUpgradeable: Secure upgrade pattern
ReentrancyGuardUpgradeable: Protection against reentrancy attacks
Key components include:
Vesting System: Linear vesting over 3 years (1095 days)
Role-Based Access Control: Different roles for different responsibilities
Pausable Functionality: Emergency pause/unpause capabilities
Upgrade Mechanism: Controlled contract upgrades with version tracking
3. Role-Based Access Control
The contract implements four main roles:
DEFAULT_ADMIN_ROLE: Assigned to "guardian", manages other roles
MANAGER_ROLE: Assigned to "timelock", controls fund releases
PAUSER_ROLE: Can pause/unpause contract operations
UPGRADER_ROLE: Can authorize contract upgrades
This separation of concerns is a security best practice, limiting the power of any single entity.
4. Detailed Feature Analysis
4.1 Vesting Schedule
The vesting schedule is initialized with:
Start time: 180 days before contract initialization
Duration: 1095 days (3 years)
Vesting formula: Linear vesting based on elapsed time
This creates an immediate partial vesting at contract initialization (180 days worth), followed by continuous vesting over the remaining period.
4.2 Fund Release Mechanism
Two separate methods handle fund releases:
ETH release: Protected with
nonReentrant
modifierERC20 release: Uses SafeERC20 for secure transfers
Both functions:
Verify the caller has the MANAGER_ROLE
Check the contract is not paused
Validate the recipient address is not zero
Ensure the requested amount is within vested limits
Update release accounting
Transfer funds and emit events
4.3 Upgrade Mechanism
The contract uses the UUPS (Universal Upgradeable Proxy Standard) pattern:
Restricted to UPGRADER_ROLE
Version tracking with automatic incrementation
Storage gap for future upgrades
Events emitted on upgrades
5. Security Assessment
5.1 Strengths
Comprehensive Access Control: Well-implemented role-based permissions
Reentrancy Protection: For ETH transfers
Pausability: Emergency controls for unforeseen issues
SafeERC20: Protection against malicious tokens
Storage Gap: Future-proofing for upgrades
Input Validation: Checks for zero addresses and vested amounts
Accurate Vesting Calculations: Correctly implements linear vesting
5.2 Concerns and Recommendations
High Severity
No high severity issues identified.
Inherits: ITREASURY, Initializable, PausableUpgradeable, AccessControlUpgradeable, ReentrancyGuardUpgradeable, UUPSUpgradeable
Vesting contract: initialRelease + (36 month duration)
Offers flexible withdrawal schedule (gas efficient)
Implements secure and upgradeable DAO treasury with linear vesting
Notes:
security-contact: security@nebula-labs.xysz
oz-upgrades:
State Variables
PAUSER_ROLE
AccessControl Pauser Role
MANAGER_ROLE
AccessControl Manager Role
UPGRADER_ROLE
AccessControl Upgrader Role
_released
ETH amount released so far
_start
start timestamp
_duration
duration seconds
version
UUPS version
_erc20Released
token amounts released so far
__gap
upgrade gap
Functions
constructor
Note: oz-upgrades-unsafe-allow: constructor
receive
solidity receive function
initialize
Initializes the UUPS contract
Parameters
guardian
address
admin address
timelock
address
address of timelock contract
pause
Emergency function to pause contract operations
Pauses all token transfers and releases.
Notes:
requires-role: PAUSER_ROLE
events-emits: {Paused} from PausableUpgradeable
unpause
Resumes normal contract operations after pause
Unpauses token transfers and releases.
Notes:
requires-role: PAUSER_ROLE
events-emits: {Unpaused} from PausableUpgradeable
release
Allows the manager to release vested ETH to a beneficiary
Release the native token (ether) that have already vested.
Notes:
requires-role: MANAGER_ROLE
requires: Contract must not be paused
requires: Amount must not exceed vested amount
requires: Beneficiary address must not be zero
security: non-reentrant
access: restricted to MANAGER_ROLE
events-emits: {EtherReleased}
Parameters
to
address
The address that will receive the vested ETH
amount
uint256
The amount of ETH to release
release
Allows the manager to release vested tokens to a beneficiary
Release the ERC20 tokens that have already vested.
Notes:
requires-role: MANAGER_ROLE
requires: Contract must not be paused
requires: Amount must not exceed vested amount
requires: Token address must not be zero
requires: Beneficiary address must not be zero
access: restricted to MANAGER_ROLE
events-emits: {ERC20Released}
Parameters
token
address
The address of the ERC20 token to release
to
address
The address that will receive the vested tokens
amount
uint256
The amount of tokens to release
start
Getter for the start timestamp.
Returns
<none>
uint256
start timestamp
duration
Getter for the vesting duration.
Returns
<none>
uint256
duration seconds
end
Getter for the end timestamp.
Returns
<none>
uint256
end timnestamp
released
Getter for the amount of eth already released
Returns
<none>
uint256
amount of ETH released so far
released
Getter for the amount of token already released
Parameters
token
address
address
Returns
<none>
uint256
amount of tokens released so far
releasable
Getter for the amount of releasable eth.
Returns
<none>
uint256
amount of vested ETH
releasable
Getter for the amount of vested ERC20
tokens.
Parameters
token
address
address
Returns
<none>
uint256
amount of vested tokens
_authorizeUpgrade
vestedAmount
Calculates the amount of ETH that has already vested. Default implementation is a linear vesting curve.
Parameters
timestamp
uint64
current timestamp
Returns
<none>
uint256
amount ETH vested
vestedAmount
Calculates the amount of tokens that has already vested. Default implementation is a linear vesting curve.
Parameters
token
address
address of token
timestamp
uint64
current timestamp
Returns
<none>
uint256
amount vested
_vestingSchedule
Virtual implementation of the vesting formula. This returns the amount vested, as a function of time, for an asset given its total historical allocation.
Parameters
totalAllocation
uint256
initial amount
timestamp
uint64
current timestamp
Returns
<none>
uint256
amount vested
Last updated