Ecosystem
Inherits:IECOSYSTEM, Initializable, PausableUpgradeable, AccessControlUpgradeable, ReentrancyGuardUpgradeable, UUPSUpgradeable
Ecosystem contract handles airdrops, rewards, burning, and partnerships
Implements a secure and upgradeable DAO ecosystem
Notes:
security-contact: security@nebula-labs.xyz
copyright: Copyright (c) 2025 Nebula Holding Inc. All rights reserved.
State Variables
BURNER_ROLE
AccessControl Burner Role
bytes32 internal constant BURNER_ROLE = keccak256("BURNER_ROLE");
PAUSER_ROLE
AccessControl Pauser Role
bytes32 internal constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
UPGRADER_ROLE
AccessControl Upgrader Role
bytes32 internal constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
REWARDER_ROLE
AccessControl Rewarder Role
bytes32 internal constant REWARDER_ROLE = keccak256("REWARDER_ROLE");
MANAGER_ROLE
AccessControl Manager Role
bytes32 internal constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
MIN_VESTING_DURATION
Minimum required vesting duration (30 days)
uint256 internal constant MIN_VESTING_DURATION = 30 days;
MAX_VESTING_DURATION
Maximum allowed vesting duration (10 years)
uint256 internal constant MAX_VESTING_DURATION = 3650 days;
UPGRADE_TIMELOCK_DURATION
Upgrade timelock duration (3 days)
uint256 private constant UPGRADE_TIMELOCK_DURATION = 3 days;
tokenInstance
governance token instance
ILENDEFI internal tokenInstance;
rewardSupply
starting reward supply
uint256 public rewardSupply;
maxReward
maximal one time reward amount
uint256 public maxReward;
issuedReward
issued reward
uint256 public issuedReward;
burnedAmount
burned reward amount (tracked separately for transparency)
uint256 public burnedAmount;
maxBurn
maximum one time burn amount
uint256 public maxBurn;
airdropSupply
starting airdrop supply
uint256 public airdropSupply;
issuedAirDrop
total amount airdropped so far
uint256 public issuedAirDrop;
partnershipSupply
starting partnership supply
uint256 public partnershipSupply;
issuedPartnership
partnership tokens issued so far
uint256 public issuedPartnership;
version
number of UUPS upgrades - packed with other variables to save gas
uint32 public version;
timelock
timelock address for partner vesting cancellations
address public timelock;
vestingContracts
Addresses of vesting contracts issued to partners
mapping(address partner => address vesting) public vestingContracts;
pendingUpgrade
Pending upgrade information
UpgradeRequest public pendingUpgrade;
__gap
uint256[16] private __gap;
Functions
nonZeroAmount
Modifier to check for non-zero amounts
modifier nonZeroAmount(uint256 amount);
Parameters
amount
uint256
The amount to validate
nonZeroAddress
Modifier to check for non-zero addresses
modifier nonZeroAddress(address addr);
Parameters
addr
address
The address to validate
constructor
Note: oz-upgrades-unsafe-allow: constructor
constructor();
receive
Prevents receiving Ether. This contract doesn't handle ETH.
receive() external payable;
initialize
Initializes the Ecosystem contract with core dependencies and configurations
Sets up the contract with initial token allocations, roles, and limits
Notes:
security: Uses initializer modifier to prevent multiple initializations
security-roles: Grants the following roles:
DEFAULT_ADMIN_ROLE to timelock
MANAGER_ROLE to timelock
PAUSER_ROLE to timelock
UPGRADER_ROLE to both timelock and multisig
allocation: Configures token allocations as follows:
26% for rewards
10% for airdrops
8% for partnerships
limits: Sets initial limits:
maxReward: 0.1% of reward supply
maxBurn: 2% of reward supply
events-emits: {Initialized} when initialization is complete
throws: ZeroAddressDetected if any input address is zero
function initialize(address token, address timelockAddr, address multisig) external initializer;
Parameters
token
address
Address of the LENDEFI token contract
timelockAddr
address
Address of the timelock contract that will have admin control
multisig
address
Address of the multisig wallet that will have upgrade rights
pause
Pauses all contract operations.
Pause contract.
Notes:
requires-role: PAUSER_ROLE
events-emits: {Paused} event from PausableUpgradeable
function pause() external onlyRole(PAUSER_ROLE);
unpause
Resumes all contract operations.
Unpause contract.
Notes:
requires-role: PAUSER_ROLE
events-emits: {Unpaused} event from PausableUpgradeable
function unpause() external onlyRole(PAUSER_ROLE);
scheduleUpgrade
Only callable by an address with UPGRADER_ROLE
Schedules an upgrade to a new implementation
function scheduleUpgrade(address newImplementation)
external
onlyRole(UPGRADER_ROLE)
nonZeroAddress(newImplementation);
Parameters
newImplementation
address
Address of the new implementation
emergencyWithdrawToken
Only callable by addresses with MANAGER_ROLE
Always sends all available tokens to the timelock controller
Emergency function to withdraw all tokens to the timelock
Notes:
throws: ZeroAddress if token address is zero
throws: ZeroBalance if contract has no token balance
function emergencyWithdrawToken(address token) external nonReentrant onlyRole(MANAGER_ROLE) nonZeroAddress(token);
Parameters
token
address
The ERC20 token to withdraw
airdrop
Distributes a specified amount of tokens to each address in the recipients array.
Performs an airdrop to a list of recipients.
Notes:
requires-role: MANAGER_ROLE
requires: Contract must not be paused
requires: Amount must be at least 1 ether
requires: Total airdropped amount must not exceed the airdrop supply
requires: Number of recipients must not exceed 4000 to avoid gas limit issues
events-emits: {AirDrop} event
throws: InvalidAmount if the amount is less than 1 ether
throws: AirdropSupplyLimit if the total airdropped amount exceeds the airdrop supply
throws: GasLimit if the number of recipients exceeds 4000
function airdrop(address[] calldata recipients, uint256 amount)
external
nonReentrant
whenNotPaused
onlyRole(MANAGER_ROLE);
Parameters
recipients
address[]
An array of addresses to receive the airdrop.
amount
uint256
The amount of tokens to be airdropped to each address.
reward
Distributes a specified amount of tokens to a beneficiary address.
Reward functionality for the Nebula Protocol.
Notes:
requires-role: REWARDER_ROLE
requires: Contract must not be paused
requires: Amount must be greater than 0
requires: Amount must not exceed the maximum reward limit
requires: Total rewarded amount must not exceed the reward supply
events-emits: {Reward} event
throws: InvalidAmount if the amount is 0
throws: InvalidAddress if the recipient address is 0
throws: RewardLimit if the amount exceeds the maximum reward limit
throws: RewardSupplyLimit if the total rewarded amount exceeds the reward supply
function reward(address to, uint256 amount)
external
nonReentrant
whenNotPaused
onlyRole(REWARDER_ROLE)
nonZeroAmount(amount)
nonZeroAddress(to);
Parameters
to
address
The address that will receive the reward.
amount
uint256
The amount of tokens to be rewarded.
burn
Burns a specified amount of tokens from the reward supply.
Enables burn functionality for the DAO.
Notes:
requires-role: BURNER_ROLE
requires: Contract must not be paused
requires: Amount must be greater than 0
requires: Amount must not exceed the maximum burn limit
requires: Total burned amount must not exceed the reward supply
events-emits: {Burn} event
throws: InvalidAmount if the amount is 0
throws: MaxBurnLimit if the amount exceeds the maximum burn limit
throws: BurnSupplyLimit if the amount exceeds available supply
function burn(uint256 amount) external nonReentrant whenNotPaused nonZeroAmount(amount) onlyRole(BURNER_ROLE);
Parameters
amount
uint256
The amount of tokens to be burned.
addPartner
Adds a new partner by creating a cancellable vesting contract and transferring the specified amount of tokens.
Creates and funds a new vesting contract for a new partner.
Notes:
requires-role: MANAGER_ROLE
requires: Contract must not be paused
requires: Partner address must not be zero and must be a valid contract or EOA
requires: Amount must be between 100 ether and half of the partnership supply
requires: Duration must be within reasonable bounds
requires: Total issued partnership tokens must not exceed the partnership supply
events-emits: {AddPartner} event
throws: InvalidAddress if the partner address is zero
throws: PartnerExists if the partner already has a vesting contract
throws: InvalidAmount if the amount is not within the valid range
throws: InvalidVestingSchedule if duration is not within reasonable bounds
throws: AmountExceedsSupply if the total issued partnership tokens exceed the partnership supply
function addPartner(address partner, uint256 amount, uint256 cliff, uint256 duration)
external
nonReentrant
whenNotPaused
onlyRole(MANAGER_ROLE)
nonZeroAddress(partner);
Parameters
partner
address
The address of the partner to receive the vesting contract.
amount
uint256
The amount of tokens to be vested.
cliff
uint256
The duration in seconds of the cliff period.
duration
uint256
The duration in seconds of the vesting period.
cancelPartnership
This can only be called by the timelock (governance)
Cancels a partner vesting contract
Notes:
requires: The caller must be the timelock
requires: The partner must have a valid vesting contract
emits: CancelPartnership event on successful cancellation
throws: CallerNotAllowed if the caller is not the timelock
throws: InvalidAddress if the partner has no vesting contract
function cancelPartnership(address partner) external nonZeroAddress(partner) onlyRole(MANAGER_ROLE);
Parameters
partner
address
The address of the partner whose vesting should be cancelled
cancelUpgrade
Cancels a previously scheduled upgrade
Only callable by addresses with UPGRADER_ROLE
function cancelUpgrade() external onlyRole(UPGRADER_ROLE);
updateMaxReward
Allows updating the maximum reward that can be issued in a single transaction.
Updates the maximum one-time reward amount.
Notes:
requires-role: MANAGER_ROLE
requires: Contract must not be paused
requires: New max reward must be greater than 0
requires: New max reward must not exceed 5% of remaining reward supply
events-emits: {MaxRewardUpdated} event
throws: InvalidAmount if the amount is 0
throws: ExcessiveMaxValue if the amount exceeds 5% of remaining reward supply
function updateMaxReward(uint256 newMaxReward)
external
whenNotPaused
onlyRole(MANAGER_ROLE)
nonZeroAmount(newMaxReward);
Parameters
newMaxReward
uint256
The new maximum reward amount.
updateMaxBurn
Allows updating the maximum amount that can be burned in a single transaction.
Updates the maximum one-time burn amount.
Notes:
requires-role: MANAGER_ROLE
requires: Contract must not be paused
requires: New max burn must be greater than 0
requires: New max burn must not exceed 10% of remaining reward supply
events-emits: {MaxBurnUpdated} event
throws: InvalidAmount if the amount is 0
throws: ExcessiveMaxValue if the amount exceeds 10% of remaining reward supply
function updateMaxBurn(uint256 newMaxBurn) external whenNotPaused onlyRole(MANAGER_ROLE) nonZeroAmount(newMaxBurn);
Parameters
newMaxBurn
uint256
The new maximum burn amount.
upgradeTimelockRemaining
Returns the remaining time before a scheduled upgrade can be executed
function upgradeTimelockRemaining() external view returns (uint256);
Returns
<none>
uint256
The time remaining in seconds, or 0 if no upgrade is scheduled or timelock has passed
availableRewardSupply
Returns the effective available reward supply considering burns.
function availableRewardSupply() external view returns (uint256);
Returns
<none>
uint256
The current available reward supply.
availableAirdropSupply
Returns the effective available airdrop supply.
function availableAirdropSupply() external view returns (uint256);
Returns
<none>
uint256
The current available airdrop supply.
availablePartnershipSupply
Returns the effective available partnership supply.
function availablePartnershipSupply() external view returns (uint256);
Returns
<none>
uint256
The current available partnership supply.
_authorizeUpgrade
Authorizes an upgrade to a new implementation with timelock enforcement
function _authorizeUpgrade(address newImplementation) internal override onlyRole(UPGRADER_ROLE);
Parameters
newImplementation
address
The address of the new implementation contract
Last updated