beautified

This commit is contained in:
giteadmin 2025-07-08 10:33:10 +02:00
parent 8de3865c6f
commit 77af20dcee
14 changed files with 496 additions and 335 deletions

View file

@ -12,6 +12,7 @@ import {Math} from "@openzeppelin/utils/math/Math.sol";
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;
@ -36,9 +37,7 @@ contract Harberg is ERC20, ERC20Permit {
* @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_){}
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.
@ -91,7 +90,7 @@ contract Harberg is ERC20, ERC20Permit {
// make sure staking pool grows proportional to economy
uint256 stakingPoolBalance = balanceOf(stakingPool);
if (stakingPoolBalance > 0) {
uint256 newStake = stakingPoolBalance * _amount / (totalSupply() - stakingPoolBalance);
uint256 newStake = stakingPoolBalance * _amount / (totalSupply() - stakingPoolBalance);
_mint(stakingPool, newStake);
}
_mint(address(liquidityManager), _amount);
@ -134,5 +133,4 @@ contract Harberg is ERC20, ERC20Permit {
function outstandingSupply() public view returns (uint256) {
return totalSupply() - balanceOf(liquidityManager);
}
}

View file

@ -24,7 +24,7 @@ contract Optimizer is Initializable, UUPSUpgradeable {
* @param _harberg The address of the Harberg token.
* @param _stake The address of the Stake contract.
*/
function initialize(address _harberg, address _stake) initializer public {
function initialize(address _harberg, address _stake) public initializer {
// Set the admin for upgradeability (using ERC1967Upgrade _changeAdmin)
_changeAdmin(msg.sender);
harberg = Harberg(_harberg);
@ -50,10 +50,11 @@ contract Optimizer is Initializable, UUPSUpgradeable {
* @param percentageStaked The percentage (in 1e18 precision) of the authorized stake that is currently staked.
* @return sentimentValue A value in the range 0 to 1e18 where 1e18 represents the worst sentiment.
*/
function calculateSentiment(
uint256 averageTaxRate,
uint256 percentageStaked
) public pure returns (uint256 sentimentValue) {
function calculateSentiment(uint256 averageTaxRate, uint256 percentageStaked)
public
pure
returns (uint256 sentimentValue)
{
// deltaS is the slack available below full staking
uint256 deltaS = 1e18 - percentageStaked;
@ -99,12 +100,7 @@ contract Optimizer is Initializable, UUPSUpgradeable {
function getLiquidityParams()
external
view
returns (
uint256 capitalInefficiency,
uint256 anchorShare,
uint24 anchorWidth,
uint256 discoveryDepth
)
returns (uint256 capitalInefficiency, uint256 anchorShare, uint24 anchorWidth, uint256 discoveryDepth)
{
uint256 percentageStaked = stake.getPercentageStaked();
uint256 averageTaxRate = stake.getAverageTaxRate();
@ -116,4 +112,3 @@ contract Optimizer is Initializable, UUPSUpgradeable {
discoveryDepth = sentiment;
}
}

View file

@ -3,7 +3,7 @@ pragma solidity ^0.8.19;
import {IERC20} from "@openzeppelin/token/ERC20/ERC20.sol";
import {IERC20Metadata} from "@openzeppelin/token/ERC20/extensions/IERC20Metadata.sol";
import {ERC20Permit} from"@openzeppelin/token/ERC20/extensions/ERC20Permit.sol";
import {ERC20Permit} from "@openzeppelin/token/ERC20/extensions/ERC20Permit.sol";
import {SafeERC20} from "@openzeppelin/token/ERC20/utils/SafeERC20.sol";
import {Math} from "@openzeppelin/utils/math/Math.sol";
import {Harberg} from "./Harberg.sol";
@ -16,14 +16,14 @@ error TooMuchSnatch(address receiver, uint256 stakeWanted, uint256 availableStak
* @notice This contract manages the staking positions for the Harberg token, allowing users to stake tokens
* in exchange for a share of the total supply. Stakers can set and adjust tax rates on their stakes,
* which affect the Universal Basic Income (UBI) paid from the tax pool.
*
*
* The contract handles:
* - Creation of staking positions with specific tax rates.
* - Snatching of existing positions under certain conditions to consolidate stakes.
* - Calculation and payment of taxes based on stake duration and tax rate.
* - Adjustment of tax rates with protections against griefing through rapid changes.
* - Exiting of positions, either partially or fully, returning the staked assets to the owner.
*
*
* Tax rates and staking positions are adjustable, with a mechanism to prevent snatch-grieving by
* enforcing a minimum tax payment duration.
*/
@ -37,7 +37,38 @@ contract Stake {
uint256 internal constant MAX_STAKE = 20; // 20% of HARB supply
uint256 internal constant TAX_FLOOR_DURATION = 60 * 60 * 24 * 3; //this duration is the minimum basis for fee calculation, regardless of actual holding time.
// the tax rates are discrete to prevent users from snatching by micro incroments of tax
uint256[] public TAX_RATES = [1, 3, 5, 8, 12, 18, 24, 30, 40, 50, 60, 80, 100, 130, 180, 250, 320, 420, 540, 700, 920, 1200, 1600, 2000, 2600, 3400, 4400, 5700, 7500, 9700];
uint256[] public TAX_RATES = [
1,
3,
5,
8,
12,
18,
24,
30,
40,
50,
60,
80,
100,
130,
180,
250,
320,
420,
540,
700,
920,
1200,
1600,
2000,
2600,
3400,
4400,
5700,
7500,
9700
];
// this is the base for the values in the array above: e.g. 1/100 = 1%
uint256 internal constant TAX_RATE_BASE = 100;
/**
@ -49,8 +80,12 @@ contract Stake {
error NoPermission(address requester, address owner);
error PositionNotFound(uint256 positionId, address requester);
event PositionCreated(uint256 indexed positionId, address indexed owner, uint256 harbergDeposit, uint256 share, uint32 taxRate);
event PositionTaxPaid(uint256 indexed positionId, address indexed owner, uint256 taxPaid, uint256 newShares, uint256 taxRate);
event PositionCreated(
uint256 indexed positionId, address indexed owner, uint256 harbergDeposit, uint256 share, uint32 taxRate
);
event PositionTaxPaid(
uint256 indexed positionId, address indexed owner, uint256 taxPaid, uint256 newShares, uint256 taxRate
);
event PositionRateHiked(uint256 indexed positionId, address indexed owner, uint256 newTaxRate);
event PositionShrunk(uint256 indexed positionId, address indexed owner, uint256 newShares, uint256 harbergPayout);
event PositionRemoved(uint256 indexed positionId, address indexed owner, uint256 harbergPayout);
@ -101,7 +136,8 @@ contract Stake {
: block.timestamp;
uint256 elapsedTime = ihet - pos.lastTaxTime;
uint256 assetsBefore = sharesToAssets(pos.share);
uint256 taxAmountDue = assetsBefore * TAX_RATES[pos.taxRate] * elapsedTime / (365 * 24 * 60 * 60) / TAX_RATE_BASE;
uint256 taxAmountDue =
assetsBefore * TAX_RATES[pos.taxRate] * elapsedTime / (365 * 24 * 60 * 60) / TAX_RATE_BASE;
if (taxAmountDue >= assetsBefore) {
// can not pay more tax than value of position
taxAmountDue = assetsBefore;
@ -143,7 +179,7 @@ contract Stake {
/// @dev Internal function to reduce the size of a staking position by a specified number of shares, transferring the corresponding Harberg tokens to the owner.
function _shrinkPosition(uint256 positionId, StakingPosition storage pos, uint256 sharesToTake) private {
require (sharesToTake < pos.share, "position too small");
require(sharesToTake < pos.share, "position too small");
uint256 assets = sharesToAssets(sharesToTake);
pos.share -= sharesToTake;
totalSharesAtTaxRate[pos.taxRate] -= sharesToTake;
@ -287,9 +323,7 @@ contract Stake {
uint8 v,
bytes32 r,
bytes32 s
) external
returns (uint256 positionId)
{
) external returns (uint256 positionId) {
ERC20Permit(address(harberg)).permit(receiver, address(this), assets, deadline, v, r, s);
return snatch(assets, receiver, taxRate, positionsToSnatch);
}
@ -360,17 +394,16 @@ contract Stake {
/// @return averageTaxRate A number between 0 and 1e18 indicating the average tax rate.
function getAverageTaxRate() external view returns (uint256 averageTaxRate) {
// Compute average tax rate weighted by shares
averageTaxRate = 0;
if (outstandingStake > 0) {
for (uint256 i = 0; i < TAX_RATES.length; i++) {
averageTaxRate += TAX_RATES[i] * totalSharesAtTaxRate[i];
}
averageTaxRate = averageTaxRate / outstandingStake;
// normalize tax rate
averageTaxRate = averageTaxRate * 1e18 / TAX_RATES[TAX_RATES.length - 1];
}
if (outstandingStake > 0) {
for (uint256 i = 0; i < TAX_RATES.length; i++) {
averageTaxRate += TAX_RATES[i] * totalSharesAtTaxRate[i];
}
averageTaxRate = averageTaxRate / outstandingStake;
// normalize tax rate
averageTaxRate = averageTaxRate * 1e18 / TAX_RATES[TAX_RATES.length - 1];
}
}
/// @notice Computes the percentage of Harberg staked from outstanding Stake and authorized Stake.
@ -378,5 +411,4 @@ contract Stake {
function getPercentageStaked() external view returns (uint256 percentageStaked) {
percentageStaked = (outstandingStake * 1e18) / authorizedStake();
}
}

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.13;
import '@openzeppelin/token/ERC20/IERC20.sol';
import "@openzeppelin/token/ERC20/IERC20.sol";
/// @title Interface for WETH9
interface IWETH9 is IERC20 {