136 lines
5.7 KiB
Solidity
136 lines
5.7 KiB
Solidity
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
pragma solidity ^0.8.19;
|
|
|
|
import {ERC20} from "@openzeppelin/token/ERC20/ERC20.sol";
|
|
import {ERC20Permit} from "@openzeppelin/token/ERC20/extensions/ERC20Permit.sol";
|
|
import {Math} from "@openzeppelin/utils/math/Math.sol";
|
|
|
|
/**
|
|
* @title stakeable ERC20 Token
|
|
* @notice This contract implements an ERC20 token with mechanisms for minting and burning in which a single account (staking Pool) is proportionally receiving a share. Only the liquidity manager has permission to manage token supply.
|
|
*/
|
|
contract Harberg is ERC20, ERC20Permit {
|
|
using Math for uint256;
|
|
// Minimum fraction of the total supply required for staking to prevent fragmentation of staking positions
|
|
|
|
uint256 private constant MIN_STAKE_FRACTION = 3000;
|
|
// Address of the liquidity manager
|
|
address private liquidityManager;
|
|
// Address of the staking pool
|
|
address private stakingPool;
|
|
|
|
// Previous total supply for staking calculations
|
|
uint256 public previousTotalSupply;
|
|
|
|
// Custom errors
|
|
error ZeroAddressInSetter();
|
|
error AddressAlreadySet();
|
|
|
|
// Modifier to restrict access to the liquidity manager
|
|
modifier onlyLiquidityManager() {
|
|
require(msg.sender == address(liquidityManager), "only liquidity manager");
|
|
_;
|
|
}
|
|
|
|
/**
|
|
* @notice Constructor for the Harberg token
|
|
* @param name_ The name of the token
|
|
* @param symbol_ The symbol of the token
|
|
*/
|
|
constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) ERC20Permit(name_) {}
|
|
|
|
/**
|
|
* @notice Sets the address for the liquidityManager. Used once post-deployment to initialize the contract.
|
|
* @dev Should be called only once right after the contract deployment to set the liquidity manager address.
|
|
* Throws AddressAlreadySet if called more than once.
|
|
* @param liquidityManager_ The address of the liquidity manager.
|
|
*/
|
|
function setLiquidityManager(address liquidityManager_) external {
|
|
if (address(0) == liquidityManager_) revert ZeroAddressInSetter();
|
|
if (liquidityManager != address(0)) revert AddressAlreadySet();
|
|
liquidityManager = liquidityManager_;
|
|
}
|
|
|
|
/**
|
|
* @notice Sets the address for the stakingPool. Used once post-deployment to initialize the contract.
|
|
* @dev Should be called only once right after the contract deployment to set the staking pool address.
|
|
* Throws AddressAlreadySet if called more than once.
|
|
* @param stakingPool_ The address of the staking pool.
|
|
*/
|
|
function setStakingPool(address stakingPool_) external {
|
|
if (address(0) == stakingPool_) revert ZeroAddressInSetter();
|
|
if (stakingPool != address(0)) revert AddressAlreadySet();
|
|
stakingPool = stakingPool_;
|
|
}
|
|
|
|
/**
|
|
* @notice Returns the addresses of the periphery contracts
|
|
* @return The addresses of the TWAB controller, liquidity manager, staking pool, and liquidity pool
|
|
*/
|
|
function peripheryContracts() external view returns (address, address) {
|
|
return (liquidityManager, stakingPool);
|
|
}
|
|
|
|
/**
|
|
* @notice Calculates the minimum stake based on the previous total supply
|
|
* @return The minimum stake amount
|
|
*/
|
|
function minStake() external view returns (uint256) {
|
|
return previousTotalSupply / MIN_STAKE_FRACTION;
|
|
}
|
|
|
|
/**
|
|
* @notice Allows the liquidity manager to mint tokens for itself.
|
|
* @dev Tokens minted are managed as community liquidity in the Uniswap pool to stabilize HARB prices.
|
|
* Only callable by the Liquidity Manager. Minting rules and limits are defined externally.
|
|
* @param _amount The number of tokens to mint.
|
|
*/
|
|
function mint(uint256 _amount) external onlyLiquidityManager {
|
|
if (_amount > 0) {
|
|
// make sure staking pool grows proportional to economy
|
|
uint256 stakingPoolBalance = balanceOf(stakingPool);
|
|
if (stakingPoolBalance > 0) {
|
|
uint256 newStake = stakingPoolBalance * _amount / (totalSupply() - stakingPoolBalance);
|
|
_mint(stakingPool, newStake);
|
|
}
|
|
_mint(address(liquidityManager), _amount);
|
|
}
|
|
if (previousTotalSupply == 0) {
|
|
previousTotalSupply = totalSupply();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @notice Allows the liquidity manager to burn tokens from its account, adjusting the staking pool accordingly.
|
|
* @dev When tokens are burned, the total supply shrinks, making excess tokens in the staking pool unnecessary.
|
|
* These excess tokens are burned to maintain the guaranteed fixed percentage of the total supply for stakers.
|
|
* @param _amount The number of tokens to burn.
|
|
*/
|
|
function burn(uint256 _amount) external onlyLiquidityManager {
|
|
if (_amount > 0) {
|
|
// shrink staking pool proportional to economy
|
|
uint256 stakingPoolBalance = balanceOf(stakingPool);
|
|
if (stakingPoolBalance > 0) {
|
|
uint256 excessStake = stakingPoolBalance * _amount / (totalSupply() - stakingPoolBalance);
|
|
_burn(stakingPool, excessStake);
|
|
}
|
|
_burn(address(liquidityManager), _amount);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @notice Sets the previous total supply
|
|
* @param _ts The previous total supply value
|
|
*/
|
|
function setPreviousTotalSupply(uint256 _ts) external onlyLiquidityManager {
|
|
previousTotalSupply = _ts;
|
|
}
|
|
|
|
/**
|
|
* @notice Returns the outstanding supply, excluding the balances of the liquidity pool and liquidity manager
|
|
* @return The outstanding supply
|
|
*/
|
|
function outstandingSupply() public view returns (uint256) {
|
|
return totalSupply() - balanceOf(liquidityManager);
|
|
}
|
|
}
|