// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; /** * @title MycoToken * @notice $MYCO token for the MycoFi ecosystem * @dev Mintable/burnable only by the bonding curve contract */ contract MycoToken is ERC20, ERC20Burnable, Ownable { /// @notice Address of the bonding curve contract (only minter/burner) address public bondingCurve; /// @notice Emitted when bonding curve address is updated event BondingCurveUpdated(address indexed oldCurve, address indexed newCurve); error OnlyBondingCurve(); error ZeroAddress(); constructor() ERC20("MycoFi", "MYCO") Ownable(msg.sender) {} /** * @notice Set the bonding curve contract address * @param _bondingCurve Address of the bonding curve contract */ function setBondingCurve(address _bondingCurve) external onlyOwner { if (_bondingCurve == address(0)) revert ZeroAddress(); address oldCurve = bondingCurve; bondingCurve = _bondingCurve; emit BondingCurveUpdated(oldCurve, _bondingCurve); } /** * @notice Mint tokens (only callable by bonding curve) * @param to Recipient address * @param amount Amount to mint */ function mint(address to, uint256 amount) external { if (msg.sender != bondingCurve) revert OnlyBondingCurve(); _mint(to, amount); } /** * @notice Burn tokens from sender (only callable by bonding curve) * @param from Address to burn from * @param amount Amount to burn */ function burnFrom(address from, uint256 amount) public override { if (msg.sender != bondingCurve) { // Standard burnFrom with allowance check super.burnFrom(from, amount); } else { // Bonding curve can burn without allowance _burn(from, amount); } } }