Core Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // Specify the Solidity compiler version
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; // Import standard ERC20 implementation
import "@openzeppelin/contracts/access/AccessControl.sol"; // Import AccessControl for role-based permissions
import "@openzeppelin/contracts/utils/Pausable.sol"; // Import Pausable for emergency stop mechanism
contract UnaxiGold is ERC20, AccessControl, Pausable {
// Define role identifiers using keccak256 hashes
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
bytes32 public constant SALE_MANAGER_ROLE = keccak256("SALE_MANAGER_ROLE");
// Track total circulating supply manually
uint256 private _circulatingSupply;
// Mappings for locked token amounts and their release block numbers
mapping(address => uint256) private _lockedTokens;
mapping(address => uint256) private _releaseBlock;
// Event declarations for transparency and external tracking
event TokensLocked(address indexed account, uint256 amount, uint256 releaseBlock);
event TokensReleased(address indexed account, uint256 amount);
event TokensSold(address indexed buyer, uint256 amount, uint256 price);
event TokensBought(address indexed seller, uint256 amount, uint256 price);
// Contract constructor, sets token name and symbol, and assigns roles to deployer
constructor() ERC20("UnaxiGold", "UXG") {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(MINTER_ROLE, msg.sender);
_grantRole(BURNER_ROLE, msg.sender);
_grantRole(SALE_MANAGER_ROLE, msg.sender);
}
// Modifier to restrict function access to admin only
modifier onlyAdmin() {
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Not admin");
_;
}
// Modifier to restrict function access to minters
modifier onlyMinter() {
require(hasRole(MINTER_ROLE, msg.sender), "Not minter");
_;
}
// Modifier to restrict function access to burners
modifier onlyBurner() {
require(hasRole(BURNER_ROLE, msg.sender), "Not burner");
_;
}
// Modifier to restrict function access to sale managers
modifier onlySaleManager() {
require(hasRole(SALE_MANAGER_ROLE, msg.sender), "Not sale manager");
_;
}
// Admin-only function to pause all transfers and sensitive actions
function pause() public onlyAdmin {
_pause();
}
// Admin-only function to resume operations
function unpause() public onlyAdmin {
_unpause();
}
// Minter-only function to mint new tokens to a specific address
function mint(address to, uint256 amount) public onlyMinter whenNotPaused {
_mint(to, amount);
_circulatingSupply += amount;
}
// Burner-only function to destroy tokens from caller's balance
function burn(uint256 amount) public onlyBurner whenNotPaused {
require(balanceOf(msg.sender) >= amount, "Insufficient balance");
require(getUnlockedBalance(msg.sender) >= amount, "Insufficient unlocked");
_burn(msg.sender, amount);
_circulatingSupply -= amount;
}
// Override ERC20 transfer to restrict based on locked balance
function transfer(address recipient, uint256 amount) public override whenNotPaused returns (bool) {
require(getUnlockedBalance(msg.sender) >= amount, "Locked balance");
return super.transfer(recipient, amount);
}
// Override ERC20 transferFrom with locked balance check
function transferFrom(address sender, address recipient, uint256 amount) public override whenNotPaused returns (bool) {
require(getUnlockedBalance(sender) >= amount, "Locked balance");
return super.transferFrom(sender, recipient, amount);
}
// Sale manager-only function to sell tokens (mint to buyer)
function sellToPublic(address buyer, uint256 amount, uint256 price) public onlySaleManager whenNotPaused {
require(amount > 0, "Amount zero");
_mint(buyer, amount);
_circulatingSupply += amount;
emit TokensSold(buyer, amount, price);
}
// Sale manager-only function to buy tokens (burn from seller)
function buyFromPublic(address seller, uint256 amount, uint256 price) public onlySaleManager whenNotPaused {
require(amount > 0, "Amount zero");
require(balanceOf(seller) >= amount, "Insufficient balance");
require(getUnlockedBalance(seller) >= amount, "Locked tokens");
_burn(seller, amount);
_circulatingSupply -= amount;
emit TokensBought(seller, amount, price);
}
// Admin-only function to lock tokens of a specific account until a future block
function lockTokens(address account, uint256 amount, uint256 releaseBlock) public onlyAdmin whenNotPaused {
require(amount > 0, "Amount zero");
require(balanceOf(account) >= amount, "Not enough tokens");
require(releaseBlock > block.number, "Release in future");
require(_lockedTokens[account] == 0, "Already locked");
_lockedTokens[account] = amount;
_releaseBlock[account] = releaseBlock;
emit TokensLocked(account, amount, releaseBlock);
}
// Admin-only batch version of lockTokens for multiple accounts
function batchLockTokens(address[] calldata accounts, uint256[] calldata amounts, uint256 releaseBlock) public onlyAdmin whenNotPaused {
require(accounts.length == amounts.length, "Mismatched arrays");
require(releaseBlock > block.number, "Release in future");
for (uint256 i = 0; i < accounts.length; i++) {
require(amounts[i] > 0, "Amount zero");
require(balanceOf(accounts[i]) >= amounts[i], "Insufficient");
require(_lockedTokens[accounts[i]] == 0, "Already locked");
_lockedTokens[accounts[i]] = amounts[i];
_releaseBlock[accounts[i]] = releaseBlock;
emit TokensLocked(accounts[i], amounts[i], releaseBlock);
}
}
// Function to release locked tokens manually after release block has passed
function releaseTokens(address account) public whenNotPaused {
require(_lockedTokens[account] > 0, "No locked tokens");
require(block.number >= _releaseBlock[account], "Not yet");
uint256 amount = _lockedTokens[account];
_lockedTokens[account] = 0;
_releaseBlock[account] = 0;
emit TokensReleased(account, amount);
}
// View function to check how many tokens are locked for an account
function getLockedTokens(address account) public view returns (uint256) {
return _lockedTokens[account];
}
// View function to check the release block of locked tokens for an account
function getReleaseBlock(address account) public view returns (uint256) {
return _releaseBlock[account];
}
// View function to get the available (unlocked) balance of an account
function getUnlockedBalance(address account) public view returns (uint256) {
return balanceOf(account) - _lockedTokens[account];
}
// View function to get current circulating supply
function circulatingSupply() public view returns (uint256) {
return _circulatingSupply;
}
// Admin-only override to grant roles
function grantRole(bytes32 role, address account) public override onlyAdmin {
_grantRole(role, account);
}
// Admin-only override to revoke roles
function revokeRole(bytes32 role, address account) public override onlyAdmin {
_revokeRole(role, account);
}
}
Last updated