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

Soloseng/update-celo-L2-distribution-logic #11045

Merged
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
4 changes: 2 additions & 2 deletions packages/protocol/contractPackages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ export const SOLIDITY_08_PACKAGE = {
proxiesPath: '/', // Proxies are still with 0.5 contracts
// Proxies shouldn't have to be added to a list manually
// https://github.com/celo-org/celo-monorepo/issues/10555
contracts: ['GasPriceMinimum', 'FeeCurrencyDirectory', 'MintGoldSchedule'],
contracts: ['GasPriceMinimum', 'FeeCurrencyDirectory', 'CeloDistributionSchedule'],
proxyContracts: [
'GasPriceMinimumProxy',
'FeeCurrencyDirectoryProxy',
'MentoFeeCurrencyAdapterV1',
'MintGoldScheduleProxy',
'CeloDistributionScheduleProxy',
],
truffleConfig: 'truffle-config0.8.js',
} satisfies ContractPackage
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import "../../contracts/common/Initializable.sol";
import "../../contracts-0.8/common/interfaces/IGoldToken.sol";

/**
* @title Contract for minting new CELO token based on a schedule.
* @title Contract for distributing CELO token based on a schedule.
*/
contract MintGoldSchedule is UsingRegistry, ReentrancyGuard, Initializable, IsL2Check {
contract CeloDistributionSchedule is UsingRegistry, ReentrancyGuard, Initializable, IsL2Check {
using FixidityLib for FixidityLib.Fraction;

uint256 constant GENESIS_GOLD_SUPPLY = 600000000 ether; // 600 million Gold
uint256 constant GOLD_SUPPLY_CAP = 1000000000 ether; // 1 billion Gold
uint256 constant GENESIS_CELO_SUPPLY = 600000000 ether; // 600 million Celo
uint256 constant CELO_SUPPLY_CAP = 1000000000 ether; // 1 billion Celo
uint256 constant YEARS_LINEAR = 15;
uint256 constant SECONDS_LINEAR = YEARS_LINEAR * 365 * 1 days;

Expand All @@ -27,7 +27,7 @@ contract MintGoldSchedule is UsingRegistry, ReentrancyGuard, Initializable, IsL2
uint256 public l2StartTime;
uint256 public totalSupplyAtL2Start;

uint256 public totalMintedBySchedule;
uint256 public totalDistributedBySchedule;
address public communityRewardFund;
address public carbonOffsettingPartner;

Expand All @@ -38,7 +38,7 @@ contract MintGoldSchedule is UsingRegistry, ReentrancyGuard, Initializable, IsL2
event CarbonOffsettingFundSet(address indexed partner, uint256 fraction);

modifier whenActivated() {
require(areDependenciesSet, "Minting schedule has not been activated.");
require(areDependenciesSet, "Distribution schedule has not been activated.");
_;
}

Expand All @@ -49,14 +49,14 @@ contract MintGoldSchedule is UsingRegistry, ReentrancyGuard, Initializable, IsL2
constructor(bool test) public Initializable(test) {}

/**
* @notice A constructor for initialising a new instance of a MintGoldSchedule contract.
* @notice A constructor for initialising a new instance of a CeloDistributionSchedule contract.
*/
function initialize() external initializer {
_transferOwnership(msg.sender);
}

/**
* @notice Sets the minting schedule dependencies during L2 transition.
* @notice Sets the distribution schedule dependencies during L2 transition.
* @param _l2StartTime The timestamp of L1 to L2 transition.
* @param _communityRewardFraction The percentage of rewards that go the community funds.
* @param _carbonOffsettingPartner The address of the carbon offsetting partner.
Expand All @@ -70,6 +70,7 @@ contract MintGoldSchedule is UsingRegistry, ReentrancyGuard, Initializable, IsL2
uint256 _carbonOffsettingFraction,
address registryAddress
) external onlyOwner onlyL2 {
require(address(this).balance > 0, "Contract does not have CELO balance.");
require(!areDependenciesSet, "Contract has already been activated.");
require(registryAddress != address(0), "The registry address cannot be the zero address");
require(block.timestamp > _l2StartTime, "L2 start time cannot be set to a future date.");
Expand All @@ -83,32 +84,38 @@ contract MintGoldSchedule is UsingRegistry, ReentrancyGuard, Initializable, IsL2
}

/**
* @notice Mints CELO to the community and carbon offsetting funds according to the predefined schedule.
* @notice Distributes CELO to the community and carbon offsetting funds according to the predefined schedule.
*/
function mintAccordingToSchedule() external nonReentrant onlyL2 returns (bool) {
function distributeAccordingToSchedule() external nonReentrant onlyL2 returns (bool) {
(
uint256 targetGoldTotalSupply,
uint256 communityRewardFundMintAmount,
uint256 carbonOffsettingPartnerMintAmount
) = getTargetGoldTotalSupply();

uint256 mintableAmount = Math.min(
getRemainingBalanceToMint(),
targetGoldTotalSupply - getGoldToken().totalSupply()
uint256 targetCeloTotalSupply,
uint256 communityRewardFundDistributionAmount,
uint256 carbonOffsettingPartnerDistributionAmount
) = getTargetCeloTotalSupply();

uint256 distributableAmount = Math.min(
getRemainingBalanceToDistribute(),
targetCeloTotalSupply - getGoldToken().totalSupply()
);

require(mintableAmount > 0, "Mintable amount must be greater than zero");
totalMintedBySchedule += mintableAmount;
require(distributableAmount > 0, "Distributable amount must be greater than zero.");
require(address(this).balance > distributableAmount, "Contract balance is insufficient.");

IGoldToken goldToken = IGoldToken(address(getGoldToken()));
totalDistributedBySchedule += distributableAmount;

IGoldToken celoToken = IGoldToken(address(getGoldToken()));

celoToken.increaseSupply(
communityRewardFundDistributionAmount + carbonOffsettingPartnerDistributionAmount
);
require(
goldToken.mint(communityRewardFund, communityRewardFundMintAmount),
"Failed to mint to community partner."
celoToken.transfer(communityRewardFund, communityRewardFundDistributionAmount),
"Failed to transfer to community partner."
);

require(
goldToken.mint(carbonOffsettingPartner, carbonOffsettingPartnerMintAmount),
"Failed to mint to carbon offsetting partner."
celoToken.transfer(carbonOffsettingPartner, carbonOffsettingPartnerDistributionAmount),
"Failed to transfer to carbon offsetting partner."
);
return true;
}
Expand All @@ -129,6 +136,13 @@ contract MintGoldSchedule is UsingRegistry, ReentrancyGuard, Initializable, IsL2
return carbonOffsettingFraction.unwrap();
}

/**
* @return The total balance distributed by the CeloDistributionSchedule contract.
*/
function getTotalDistributedBySchedule() external view returns (uint256) {
return totalDistributedBySchedule;
}

/**
* @notice Returns the storage, major, minor, and patch version of the contract.
* @return Storage version of the contract.
Expand Down Expand Up @@ -200,40 +214,33 @@ contract MintGoldSchedule is UsingRegistry, ReentrancyGuard, Initializable, IsL2
}

/**
* @notice Calculates remaining CELO balance to mint.
* @return The remaining CELO balance to mint.
*/
function getRemainingBalanceToMint() public view returns (uint256) {
return GOLD_SUPPLY_CAP - getGoldToken().totalSupply();
}

/**
* @return The total balance minted by the MintGoldSchedule contract.
* @notice Calculates remaining CELO balance to distribute.
* @return The remaining CELO balance to distribute.
*/
function getTotalMintedBySchedule() public view returns (uint256) {
return totalMintedBySchedule;
function getRemainingBalanceToDistribute() public view returns (uint256) {
return CELO_SUPPLY_CAP - getGoldToken().totalSupply();
}

/**
* @return The currently mintable amount.
* @return The currently distributable amount.
*/
function getMintableAmount() public view returns (uint256) {
(uint256 targetGoldTotalSupply, , ) = getTargetGoldTotalSupply();
return targetGoldTotalSupply - getGoldToken().totalSupply();
function getDistributableAmount() public view returns (uint256) {
(uint256 targetCeloTotalSupply, , ) = getTargetCeloTotalSupply();
return targetCeloTotalSupply - getGoldToken().totalSupply();
}

/**
* @notice Returns the target CELO supply according to the target schedule.
* @return targetGoldTotalSupply The target total CELO supply according to the target schedule.
* @return communityTargetRewards The community reward that can be minted according to the target schedule.
* @return carbonFundTargetRewards The carbon offsetting reward that can be minted according to the target schedule.
* @return targetCeloTotalSupply The target total CELO supply according to the target schedule.
* @return communityTargetRewards The community reward that can be distributed according to the target schedule.
* @return carbonFundTargetRewards The carbon offsetting reward that can be distributed according to the target schedule.
*/
function getTargetGoldTotalSupply()
function getTargetCeloTotalSupply()
public
view
whenActivated
returns (
uint256 targetGoldTotalSupply,
uint256 targetCeloTotalSupply,
uint256 communityTargetRewards,
uint256 carbonFundTargetRewards
)
Expand All @@ -243,20 +250,20 @@ contract MintGoldSchedule is UsingRegistry, ReentrancyGuard, Initializable, IsL2

uint256 timeSinceL2Start = block.timestamp - l2StartTime;
uint256 totalL2LinearSecondsAvailable = SECONDS_LINEAR - (l2StartTime - GENESIS_START_TIME);
uint256 mintedOnL1 = totalSupplyAtL2Start - GENESIS_GOLD_SUPPLY;
uint256 mintedOnL1 = totalSupplyAtL2Start - GENESIS_CELO_SUPPLY;

bool isLinearDistribution = timeSinceL2Start < totalL2LinearSecondsAvailable;
if (isLinearDistribution) {
(
targetGoldTotalSupply,
targetCeloTotalSupply,
communityTargetRewards,
carbonFundTargetRewards
) = _calculateTargetReward(timeSinceL2Start, totalL2LinearSecondsAvailable, mintedOnL1);

return (targetGoldTotalSupply, communityTargetRewards, carbonFundTargetRewards);
return (targetCeloTotalSupply, communityTargetRewards, carbonFundTargetRewards);
} else {
(
targetGoldTotalSupply,
targetCeloTotalSupply,
communityTargetRewards,
carbonFundTargetRewards
) = _calculateTargetReward(
Expand All @@ -265,13 +272,13 @@ contract MintGoldSchedule is UsingRegistry, ReentrancyGuard, Initializable, IsL2
mintedOnL1
);

bool hasNotYetMintedAllLinearRewards = totalMintedBySchedule +
GENESIS_GOLD_SUPPLY +
bool hasNotYetDistributedAllLinearRewards = totalDistributedBySchedule +
GENESIS_CELO_SUPPLY +
mintedOnL1 <
targetGoldTotalSupply;
targetCeloTotalSupply;

if (hasNotYetMintedAllLinearRewards) {
return (targetGoldTotalSupply, communityTargetRewards, carbonFundTargetRewards);
if (hasNotYetDistributedAllLinearRewards) {
return (targetCeloTotalSupply, communityTargetRewards, carbonFundTargetRewards);
}
revert("Block reward calculation for years 15-30 unimplemented");
return (0, 0, 0);
Expand All @@ -286,7 +293,7 @@ contract MintGoldSchedule is UsingRegistry, ReentrancyGuard, Initializable, IsL2
internal
view
returns (
uint256 targetGoldTotalSupply,
uint256 targetCeloTotalSupply,
uint256 communityTargetRewards,
uint256 carbonFundTargetRewards
)
Expand All @@ -296,7 +303,7 @@ contract MintGoldSchedule is UsingRegistry, ReentrancyGuard, Initializable, IsL2
_totalL2LinearSecondsAvailable
);
// Pay out half of all block rewards linearly.
uint256 totalLinearRewards = (GOLD_SUPPLY_CAP - GENESIS_GOLD_SUPPLY) / 2; //(200 million) includes validator rewards.
uint256 totalLinearRewards = (CELO_SUPPLY_CAP - GENESIS_CELO_SUPPLY) / 2; //(200 million) includes validator rewards.

FixidityLib.Fraction memory l2LinearRewards = FixidityLib.newFixed(
totalLinearRewards - _mintedOnL1
Expand All @@ -321,10 +328,10 @@ contract MintGoldSchedule is UsingRegistry, ReentrancyGuard, Initializable, IsL2
.divide(totalL2LinearSecondsAvailableFraction)
.fromFixed();

targetGoldTotalSupply =
targetCeloTotalSupply =
communityTargetRewards +
carbonFundTargetRewards +
GENESIS_GOLD_SUPPLY +
GENESIS_CELO_SUPPLY +
_mintedOnL1;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.5.13 <0.9.0;

interface IMintGoldScheduleInitializer {
interface ICeloDistributionScheduleInitializer {
function initialize() external;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,23 @@ interface IGoldToken is IERC20 {
function setRegistry(address registryAddress) external;

/**
* @notice Used set the address of the MintGoldSchedule contract.
* @param goldTokenMintingScheduleAddress The address of the MintGoldSchedule contract.
* @notice Used set the address of the CeloDistributionSchedule contract.
* @param celoTokenDistributionScheduleAddress The address of the CeloDistributionSchedule contract.
*/
function setGoldTokenMintingScheduleAddress(address goldTokenMintingScheduleAddress) external;
function setCeloTokenDistributionScheduleAddress(
address celoTokenDistributionScheduleAddress
) external;

/**
* @dev Mints a new token.
* @param to The address that will own the minted token.
* @param value The amount of token to be minted.
*/
function mint(address to, uint256 value) external returns (bool);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait can we still mint too?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

answer is not on l2. but there is a test to ensure that so keep the interface


/**
* @notice Increases the variable for total amount of CELO in existence.
* @param amount The amount to increase counter by.
*/
function increaseSupply(uint256 amount) external;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
function increaseSupply(uint256 amount) external;
- function increaseSupply(uint256 amount) external
+ function moneyPrinterGoBrbrbrbrbrbrrrrrrr(uint256 amount) external;

}
32 changes: 18 additions & 14 deletions packages/protocol/contracts/common/GoldToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import "./CalledByVm.sol";
import "./Initializable.sol";
import "./interfaces/ICeloToken.sol";
import "./interfaces/ICeloVersionedContract.sol";
import "./interfaces/IMintGoldSchedule.sol";
import "./interfaces/ICeloDistributionSchedule.sol";
import "../../contracts-0.8/common/IsL2Check.sol";

contract GoldToken is
Expand Down Expand Up @@ -37,19 +37,22 @@ contract GoldToken is
// Burn address is 0xdEaD because truffle is having buggy behaviour with the zero address
address constant BURN_ADDRESS = address(0x000000000000000000000000000000000000dEaD);

IMintGoldSchedule public goldTokenMintingSchedule;
ICeloDistributionSchedule public celoTokenDistributionSchedule;

event Transfer(address indexed from, address indexed to, uint256 value);

event TransferComment(string comment);

event Approval(address indexed owner, address indexed spender, uint256 value);

event SetGoldTokenMintingScheduleAddress(address indexed newScheduleAddress);
event SetCeloTokenDistributionScheduleAddress(address indexed newScheduleAddress);

modifier onlySchedule() {
if (isL2()) {
require(msg.sender == address(goldTokenMintingSchedule), "Only MintGoldSchedule can call.");
require(
msg.sender == address(celoTokenDistributionSchedule),
"Only CeloDistributionSchedule can call."
);
} else {
require(msg.sender == address(0), "Only VM can call.");
}
Expand All @@ -73,20 +76,20 @@ contract GoldToken is
}

/**
* @notice Used set the address of the MintGoldSchedule contract.
* @param goldTokenMintingScheduleAddress The address of the MintGoldSchedule contract.
* @notice Used set the address of the CeloDistributionSchedule contract.
* @param celoTokenDistributionScheduleAddress The address of the CeloDistributionSchedule contract.
*/
function setGoldTokenMintingScheduleAddress(
address goldTokenMintingScheduleAddress
function setCeloTokenDistributionScheduleAddress(
address celoTokenDistributionScheduleAddress
) external onlyOwner {
require(
goldTokenMintingScheduleAddress != address(0) ||
goldTokenMintingScheduleAddress != address(goldTokenMintingSchedule),
celoTokenDistributionScheduleAddress != address(0) ||
celoTokenDistributionScheduleAddress != address(celoTokenDistributionSchedule),
"Invalid address."
);
goldTokenMintingSchedule = IMintGoldSchedule(goldTokenMintingScheduleAddress);
celoTokenDistributionSchedule = ICeloDistributionSchedule(celoTokenDistributionScheduleAddress);

emit SetGoldTokenMintingScheduleAddress(goldTokenMintingScheduleAddress);
emit SetCeloTokenDistributionScheduleAddress(celoTokenDistributionScheduleAddress);
}

/**
Expand Down Expand Up @@ -198,8 +201,9 @@ contract GoldToken is
* @notice Mints new CELO and gives it to 'to'.
* @param to The account for which to mint tokens.
* @param value The amount of CELO to mint.
* @dev This function will be deprecated in L2.
*/
function mint(address to, uint256 value) external onlySchedule returns (bool) {
function mint(address to, uint256 value) external onlyL1 onlyVm returns (bool) {
if (value == 0) {
return true;
}
Expand All @@ -221,7 +225,7 @@ contract GoldToken is
* @dev This function will be deprecated in L2. The onlyway to increase
* the supply is with the mint function.
*/
function increaseSupply(uint256 amount) external onlyL1 onlyVm {
function increaseSupply(uint256 amount) external onlySchedule {
totalSupply_ = totalSupply_.add(amount);
}

Expand Down
Loading
Loading