|
| 1 | +// SPDX-License-Identifier: MIT |
| 2 | +pragma solidity ^0.8.20; |
| 3 | + |
| 4 | +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol"; |
| 5 | +import "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; |
| 6 | + |
| 7 | +/// @title C0LD Token (CD) – DAO-governed capped supply token for COLↁAO |
| 8 | +/// @notice Max supply 20 * 10^12 units (decimals = 12). Mintable only by authorised minter contracts. |
| 9 | +contract ColdToken is ERC20Capped, AccessControlEnumerable { |
| 10 | + /// @dev 12-decimals version of 1 token. |
| 11 | + uint256 private constant ONE = 10 ** 12; |
| 12 | + |
| 13 | + /// @dev Max supply: 20 COLD (20 * 10^12). |
| 14 | + uint256 private constant MAX_SUPPLY = 20 * ONE; |
| 15 | + |
| 16 | + // --- Roles --- |
| 17 | + bytes32 public constant DAO_ADMIN_ROLE = keccak256("DAO_ADMIN_ROLE"); |
| 18 | + bytes32 public constant YIELD_MINTER_ROLE = keccak256("YIELD_MINTER_ROLE"); |
| 19 | + bytes32 public constant LP_MINTER_ROLE = keccak256("LP_MINTER_ROLE"); |
| 20 | + bytes32 public constant STAKE_MINTER_ROLE = keccak256("STAKE_MINTER_ROLE"); |
| 21 | + |
| 22 | + constructor(address daoTreasury) |
| 23 | + ERC20("C0LD Token", "COLD") |
| 24 | + ERC20Capped(MAX_SUPPLY) |
| 25 | + { |
| 26 | + require(daoTreasury != address(0), "dao zero"); |
| 27 | + _setupRole(DAO_ADMIN_ROLE, daoTreasury); |
| 28 | + _setRoleAdmin(YIELD_MINTER_ROLE, DAO_ADMIN_ROLE); |
| 29 | + _setRoleAdmin(LP_MINTER_ROLE, DAO_ADMIN_ROLE); |
| 30 | + _setRoleAdmin(STAKE_MINTER_ROLE, DAO_ADMIN_ROLE); |
| 31 | + } |
| 32 | + |
| 33 | + /// @dev Override decimals to 12. |
| 34 | + function decimals() public pure override returns (uint8) { |
| 35 | + return 12; |
| 36 | + } |
| 37 | + |
| 38 | + // --------- Mint functions (only authorised contracts) --------- |
| 39 | + |
| 40 | + function mintYield(address to, uint256 amount) external onlyRole(YIELD_MINTER_ROLE) { |
| 41 | + _mintChecked(to, amount); |
| 42 | + } |
| 43 | + |
| 44 | + function mintLpRewards(address to, uint256 amount) external onlyRole(LP_MINTER_ROLE) { |
| 45 | + _mintChecked(to, amount); |
| 46 | + } |
| 47 | + |
| 48 | + function mintStakingRewards(address to, uint256 amount) external onlyRole(STAKE_MINTER_ROLE) { |
| 49 | + _mintChecked(to, amount); |
| 50 | + } |
| 51 | + |
| 52 | + // Internal mint with cap enforcement |
| 53 | + function _mintChecked(address to, uint256 amount) internal { |
| 54 | + require(totalSupply() + amount <= cap(), "cap exceeded"); |
| 55 | + _mint(to, amount); |
| 56 | + } |
| 57 | + |
| 58 | + // Disallow transfers before any supply exists (optional) |
| 59 | + function _beforeTokenTransfer(address from, address to, uint256 amount) internal override(ERC20) { |
| 60 | + super._beforeTokenTransfer(from, to, amount); |
| 61 | + } |
| 62 | +} |
0 commit comments