Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change staking emission from 1 to 2 percent #39

Merged
merged 2 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/coverage
lcov.info
.DS_Store
.vscode
.env

broadcast/*/31337
Expand Down
16 changes: 8 additions & 8 deletions src/DefaultEmissionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/Safe
import {PowUtil} from "./lib/PowUtil.sol";

/// @title Default Emission Manager
/// @author Polygon Labs (@DhairyaSethi, @gretzke, @qedk)
/// @author Polygon Labs (@DhairyaSethi, @gretzke, @qedk, @simonDos)
/// @notice A default emission manager implementation for the Polygon ERC20 token contract on Ethereum L1
/// @dev The contract allows for a 1% mint *each* per year (compounded every year) to the stakeManager and treasury contracts
/// @dev The contract allows for a 3% mint per year (compounded). 2% stakeManager(Hub) and 1% treasury
/// @custom:security-contact [email protected]
contract DefaultEmissionManager is Ownable2StepUpgradeable, IDefaultEmissionManager {
using SafeERC20 for IPolygonEcosystemToken;

// log2(2%pa continuously compounded emission per year) in 18 decimals, see _inflatedSupplyAfter
uint256 public constant INTEREST_PER_YEAR_LOG2 = 0.028569152196770894e18;
// log2(3%pa continuously compounded emission per year) in 18 decimals, see _inflatedSupplyAfter
uint256 public constant INTEREST_PER_YEAR_LOG2 = 0.04264433740849372e18;
uint256 public constant START_SUPPLY = 10_000_000_000e18;
address private immutable DEPLOYER;

Expand Down Expand Up @@ -65,7 +65,7 @@ contract DefaultEmissionManager is Ownable2StepUpgradeable, IDefaultEmissionMana
uint256 amountToMint = newSupply - currentSupply;
if (amountToMint == 0) return; // no minting required

uint256 treasuryAmt = amountToMint / 2;
uint256 treasuryAmt = amountToMint / 3;
uint256 stakeManagerAmt = amountToMint - treasuryAmt;

emit TokenMint(amountToMint, msg.sender);
Expand All @@ -79,10 +79,10 @@ contract DefaultEmissionManager is Ownable2StepUpgradeable, IDefaultEmissionMana

/// @notice Returns total supply from compounded emission after timeElapsed from startTimestamp (deployment)
/// @param timeElapsed The time elapsed since startTimestamp
/// @dev interestRatePerYear = 1.02; 2% per year
/// @dev interestRatePerYear = 1.03; 3% per year
/// approximate the compounded interest rate using x^y = 2^(log2(x)*y)
/// where x is the interest rate per year and y is the number of seconds elapsed since deployment divided by 365 days in seconds
/// log2(interestRatePerYear) = 0.028569152196770894 with 18 decimals, as the interest rate does not change, hard code the value
/// log2(interestRatePerYear) = 0.04264433740849372 with 18 decimals, as the interest rate does not change, hard code the value
/// @return supply total supply from compounded emission after timeElapsed
function inflatedSupplyAfter(uint256 timeElapsed) public pure returns (uint256 supply) {
uint256 supplyFactor = PowUtil.exp2((INTEREST_PER_YEAR_LOG2 * timeElapsed) / 365 days);
Expand All @@ -92,7 +92,7 @@ contract DefaultEmissionManager is Ownable2StepUpgradeable, IDefaultEmissionMana
/// @notice Returns the implementation version
/// @return Version string
function getVersion() external pure returns (string memory) {
return "1.0.0";
return "1.1.0";
}

/**
Expand Down
6 changes: 3 additions & 3 deletions src/PolygonEcosystemToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {AccessControlEnumerable} from "openzeppelin-contracts/contracts/access/A
import {IPolygonEcosystemToken} from "./interfaces/IPolygonEcosystemToken.sol";

/// @title Polygon ERC20 token
/// @author Polygon Labs (@DhairyaSethi, @gretzke, @qedk)
/// @author Polygon Labs (@DhairyaSethi, @gretzke, @qedk, @simonDos)
/// @notice This is the Polygon ERC20 token contract on Ethereum L1
/// @dev The contract allows for a 1-to-1 representation between $POL and $MATIC and allows for additional emission based on hub and treasury requirements
/// @custom:security-contact [email protected]
Expand All @@ -15,7 +15,7 @@ contract PolygonEcosystemToken is ERC20Permit, AccessControlEnumerable, IPolygon
bytes32 public constant CAP_MANAGER_ROLE = keccak256("CAP_MANAGER_ROLE");
bytes32 public constant PERMIT2_REVOKER_ROLE = keccak256("PERMIT2_REVOKER_ROLE");
address public constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
uint256 public mintPerSecondCap = 10e18; // 10 POL tokens per second
uint256 public mintPerSecondCap = 13.37e18; // 13.37 POL tokens per second. will limit emission in ~23 years
uint256 public lastMint;
bool public permit2Enabled;

Expand Down Expand Up @@ -78,7 +78,7 @@ contract PolygonEcosystemToken is ERC20Permit, AccessControlEnumerable, IPolygon
/// this contract not being behind a proxy
/// @return Version string
function getVersion() external pure returns (string memory) {
return "1.0.0";
return "1.1.0";
}

function _updatePermit2Allowance(bool enabled) private {
Expand Down
33 changes: 24 additions & 9 deletions test/DefaultEmissionManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,12 @@ contract DefaultEmissionManagerTest is Test {
uint256 newSupply = abi.decode(vm.ffi(inputs), (uint256));

assertApproxEqAbs(newSupply, polygon.totalSupply(), _MAX_PRECISION_DELTA);
assertEq(matic.balanceOf(stakeManager), (polygon.totalSupply() - initialTotalSupply) / 2);
uint256 totalAmtMinted = polygon.totalSupply() - initialTotalSupply;
uint256 totalAmtMintedOneThird = totalAmtMinted / 3;
assertEq(matic.balanceOf(stakeManager), totalAmtMinted - totalAmtMintedOneThird);
assertEq(matic.balanceOf(treasury), 0);
assertEq(polygon.balanceOf(stakeManager), 0);
assertEq(polygon.balanceOf(treasury), (polygon.totalSupply() - initialTotalSupply) / 2);
assertEq(polygon.balanceOf(treasury), totalAmtMintedOneThird);
}

function test_MintDelayTwice(uint128 delay) external {
Expand All @@ -161,8 +164,9 @@ contract DefaultEmissionManagerTest is Test {
uint256 newSupply = abi.decode(vm.ffi(inputs), (uint256));

assertApproxEqAbs(newSupply, polygon.totalSupply(), _MAX_PRECISION_DELTA);
uint256 balance = (polygon.totalSupply() - initialTotalSupply) / 2;
assertEq(matic.balanceOf(stakeManager), balance);
uint256 balance = (polygon.totalSupply() - initialTotalSupply) / 3;
uint256 stakeManagerBalance = (polygon.totalSupply() - initialTotalSupply) - balance;
assertEq(matic.balanceOf(stakeManager), stakeManagerBalance);
assertEq(polygon.balanceOf(stakeManager), 0);
assertEq(polygon.balanceOf(treasury), balance);

Expand All @@ -175,8 +179,13 @@ contract DefaultEmissionManagerTest is Test {
newSupply = abi.decode(vm.ffi(inputs), (uint256));

assertApproxEqAbs(newSupply, polygon.totalSupply(), _MAX_PRECISION_DELTA);
balance += (polygon.totalSupply() - initialTotalSupply) / 2;
assertEq(matic.balanceOf(stakeManager), balance);
uint256 totalAmtMinted = polygon.totalSupply() - initialTotalSupply;
uint256 totalAmtMintedOneThird = totalAmtMinted / 3;

balance += totalAmtMintedOneThird;
stakeManagerBalance += totalAmtMinted - totalAmtMintedOneThird;

assertEq(matic.balanceOf(stakeManager), stakeManagerBalance);
assertEq(polygon.balanceOf(stakeManager), 0);
assertEq(polygon.balanceOf(treasury), balance);
}
Expand All @@ -185,6 +194,7 @@ contract DefaultEmissionManagerTest is Test {
vm.assume(delay * uint256(cycles) <= 10 * 365 days && delay > 0 && cycles < 30);

uint256 balance;
uint256 stakeManagerBalance;

for (uint256 cycle; cycle < cycles; cycle++) {
uint256 initialTotalSupply = polygon.totalSupply();
Expand All @@ -197,8 +207,13 @@ contract DefaultEmissionManagerTest is Test {
uint256 newSupply = abi.decode(vm.ffi(inputs), (uint256));

assertApproxEqAbs(newSupply, polygon.totalSupply(), _MAX_PRECISION_DELTA);
balance += (polygon.totalSupply() - initialTotalSupply) / 2;
assertEq(matic.balanceOf(stakeManager), balance);
uint256 totalAmtMinted = polygon.totalSupply() - initialTotalSupply;
uint256 totalAmtMintedOneThird = totalAmtMinted / 3;

balance += totalAmtMintedOneThird;
stakeManagerBalance += totalAmtMinted - totalAmtMintedOneThird;

assertEq(matic.balanceOf(stakeManager), stakeManagerBalance);
assertEq(polygon.balanceOf(stakeManager), 0);
assertEq(polygon.balanceOf(treasury), balance);
}
Expand All @@ -209,6 +224,6 @@ contract DefaultEmissionManagerTest is Test {
inputs[2] = vm.toString(delay);
inputs[3] = vm.toString(polygon.totalSupply());
uint256 newSupply = abi.decode(vm.ffi(inputs), (uint256));
assertApproxEqAbs(newSupply, emissionManager.inflatedSupplyAfter(block.timestamp + delay), 1e19);
assertApproxEqAbs(newSupply, emissionManager.inflatedSupplyAfter(block.timestamp + delay), 1e20);
}
}
2 changes: 1 addition & 1 deletion test/PolygonEcosystemToken.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ contract PolygonTest is Test {
address public governance;
address public permit2revoker;
DefaultEmissionManager public emissionManager;
uint256 public mintPerSecondCap = 10e18; // 10 POL tokens per second
uint256 public mintPerSecondCap = 13.37e18; // 13.37 POL tokens per second

function setUp() external {
migration = makeAddr("migration");
Expand Down
2 changes: 1 addition & 1 deletion test/util/calc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const interestRatePerYear = 1.02;
const interestRatePerYear = 1.03;
const startSupply = 10_000_000_000e18;
function main() {
const [timeElapsedInSeconds] = process.argv.slice(2);
Expand Down