diff --git a/.gitignore b/.gitignore index 101374a..9c739de 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ /coverage lcov.info .DS_Store -.vscode broadcast/ .env diff --git a/src/DefaultEmissionManager.sol b/src/DefaultEmissionManager.sol index c28b555..a93f7a9 100644 --- a/src/DefaultEmissionManager.sol +++ b/src/DefaultEmissionManager.sol @@ -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, @simonDos) +/// @author Polygon Labs (@DhairyaSethi, @gretzke, @qedk) /// @notice A default emission manager implementation for the Polygon ERC20 token contract on Ethereum L1 -/// @dev The contract allows for a 3% mint per year (compounded). 2% stakeManager(Hub) and 1% treasury +/// @dev The contract allows for a 1% mint *each* per year (compounded every year) to the stakeManager and treasury contracts /// @custom:security-contact security@polygon.technology contract DefaultEmissionManager is Ownable2StepUpgradeable, IDefaultEmissionManager { using SafeERC20 for IPolygonEcosystemToken; - // log2(3%pa continuously compounded emission per year) in 18 decimals, see _inflatedSupplyAfter - uint256 public constant INTEREST_PER_YEAR_LOG2 = 0.04264433740849372e18; + // log2(2%pa continuously compounded emission per year) in 18 decimals, see _inflatedSupplyAfter + uint256 public constant INTEREST_PER_YEAR_LOG2 = 0.028569152196770894e18; uint256 public constant START_SUPPLY = 10_000_000_000e18; address private immutable DEPLOYER; @@ -65,7 +65,7 @@ contract DefaultEmissionManager is Ownable2StepUpgradeable, IDefaultEmissionMana uint256 amountToMint = newSupply - currentSupply; if (amountToMint == 0) return; // no minting required - uint256 treasuryAmt = amountToMint / 3; + uint256 treasuryAmt = amountToMint / 2; uint256 stakeManagerAmt = amountToMint - treasuryAmt; emit TokenMint(amountToMint, msg.sender); @@ -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.03; 3% per year + /// @dev interestRatePerYear = 1.02; 2% 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.04264433740849372 with 18 decimals, as the interest rate does not change, hard code the value + /// log2(interestRatePerYear) = 0.028569152196770894 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); @@ -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.1.0"; + return "1.0.0"; } /** diff --git a/src/PolygonEcosystemToken.sol b/src/PolygonEcosystemToken.sol index d06b996..8a31dad 100644 --- a/src/PolygonEcosystemToken.sol +++ b/src/PolygonEcosystemToken.sol @@ -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, @simonDos) +/// @author Polygon Labs (@DhairyaSethi, @gretzke, @qedk) /// @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 security@polygon.technology @@ -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 = 13.37e18; // 13.37 POL tokens per second. will limit emission in ~23 years + uint256 public mintPerSecondCap = 10e18; // 10 POL tokens per second uint256 public lastMint; bool public permit2Enabled; @@ -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.1.0"; + return "1.0.0"; } function _updatePermit2Allowance(bool enabled) private { diff --git a/test/DefaultEmissionManager.t.sol b/test/DefaultEmissionManager.t.sol index 7e07ee7..6523b36 100644 --- a/test/DefaultEmissionManager.t.sol +++ b/test/DefaultEmissionManager.t.sol @@ -143,12 +143,9 @@ contract DefaultEmissionManagerTest is Test { uint256 newSupply = abi.decode(vm.ffi(inputs), (uint256)); assertApproxEqAbs(newSupply, polygon.totalSupply(), _MAX_PRECISION_DELTA); - uint256 totalAmtMinted = polygon.totalSupply() - initialTotalSupply; - uint256 totalAmtMintedOneThird = totalAmtMinted / 3; - assertEq(matic.balanceOf(stakeManager), totalAmtMinted - totalAmtMintedOneThird); - assertEq(matic.balanceOf(treasury), 0); + assertEq(matic.balanceOf(stakeManager), (polygon.totalSupply() - initialTotalSupply) / 2); assertEq(polygon.balanceOf(stakeManager), 0); - assertEq(polygon.balanceOf(treasury), totalAmtMintedOneThird); + assertEq(polygon.balanceOf(treasury), (polygon.totalSupply() - initialTotalSupply) / 2); } function test_MintDelayTwice(uint128 delay) external { @@ -164,9 +161,8 @@ contract DefaultEmissionManagerTest is Test { uint256 newSupply = abi.decode(vm.ffi(inputs), (uint256)); assertApproxEqAbs(newSupply, polygon.totalSupply(), _MAX_PRECISION_DELTA); - uint256 balance = (polygon.totalSupply() - initialTotalSupply) / 3; - uint256 stakeManagerBalance = (polygon.totalSupply() - initialTotalSupply) - balance; - assertEq(matic.balanceOf(stakeManager), stakeManagerBalance); + uint256 balance = (polygon.totalSupply() - initialTotalSupply) / 2; + assertEq(matic.balanceOf(stakeManager), balance); assertEq(polygon.balanceOf(stakeManager), 0); assertEq(polygon.balanceOf(treasury), balance); @@ -179,13 +175,8 @@ contract DefaultEmissionManagerTest is Test { newSupply = abi.decode(vm.ffi(inputs), (uint256)); assertApproxEqAbs(newSupply, polygon.totalSupply(), _MAX_PRECISION_DELTA); - uint256 totalAmtMinted = polygon.totalSupply() - initialTotalSupply; - uint256 totalAmtMintedOneThird = totalAmtMinted / 3; - - balance += totalAmtMintedOneThird; - stakeManagerBalance += totalAmtMinted - totalAmtMintedOneThird; - - assertEq(matic.balanceOf(stakeManager), stakeManagerBalance); + balance += (polygon.totalSupply() - initialTotalSupply) / 2; + assertEq(matic.balanceOf(stakeManager), balance); assertEq(polygon.balanceOf(stakeManager), 0); assertEq(polygon.balanceOf(treasury), balance); } @@ -194,7 +185,6 @@ 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(); @@ -207,13 +197,8 @@ contract DefaultEmissionManagerTest is Test { uint256 newSupply = abi.decode(vm.ffi(inputs), (uint256)); assertApproxEqAbs(newSupply, polygon.totalSupply(), _MAX_PRECISION_DELTA); - uint256 totalAmtMinted = polygon.totalSupply() - initialTotalSupply; - uint256 totalAmtMintedOneThird = totalAmtMinted / 3; - - balance += totalAmtMintedOneThird; - stakeManagerBalance += totalAmtMinted - totalAmtMintedOneThird; - - assertEq(matic.balanceOf(stakeManager), stakeManagerBalance); + balance += (polygon.totalSupply() - initialTotalSupply) / 2; + assertEq(matic.balanceOf(stakeManager), balance); assertEq(polygon.balanceOf(stakeManager), 0); assertEq(polygon.balanceOf(treasury), balance); } @@ -224,6 +209,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), 1e20); + assertApproxEqAbs(newSupply, emissionManager.inflatedSupplyAfter(block.timestamp + delay), 1e19); } } diff --git a/test/PolygonEcosystemToken.t.sol b/test/PolygonEcosystemToken.t.sol index 4d0044a..9e1096f 100644 --- a/test/PolygonEcosystemToken.t.sol +++ b/test/PolygonEcosystemToken.t.sol @@ -18,7 +18,7 @@ contract PolygonTest is Test { address public governance; address public permit2revoker; DefaultEmissionManager public emissionManager; - uint256 public mintPerSecondCap = 13.37e18; // 13.37 POL tokens per second + uint256 public mintPerSecondCap = 10e18; // 10 POL tokens per second function setUp() external { migration = makeAddr("migration"); diff --git a/test/util/calc.js b/test/util/calc.js index 7b96dbd..b5c2f19 100644 --- a/test/util/calc.js +++ b/test/util/calc.js @@ -1,4 +1,4 @@ -const interestRatePerYear = 1.03; +const interestRatePerYear = 1.02; const startSupply = 10_000_000_000e18; function main() { const [timeElapsedInSeconds] = process.argv.slice(2);