beautified
This commit is contained in:
parent
8de3865c6f
commit
77af20dcee
14 changed files with 496 additions and 335 deletions
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue