Skip to content

Commit

Permalink
Soloseng/revert-celo-total-supply-changes (#11093)
Browse files Browse the repository at this point in the history
* initial work

* accounting debug

* disable CELO transfers to celoDistribution schedule

* removed debug logs

* ++ celoDistributionSchedule to `usingRegistry` contract.

* Moved setting registry address to initialize function

* ∆ execution order

* updated release data

* updated variable name in test

* test fix

* ++ native transfer test
  • Loading branch information
soloseng authored and arthurgousset committed Jul 2, 2024
1 parent 71a9462 commit e886bb1
Show file tree
Hide file tree
Showing 12 changed files with 305 additions and 319 deletions.
56 changes: 26 additions & 30 deletions packages/protocol/contracts-0.8/common/CeloDistributionSchedule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@ contract CeloDistributionSchedule is UsingRegistry, ReentrancyGuard, Initializab
using FixidityLib for FixidityLib.Fraction;

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;

bool public areDependenciesSet;
uint256 constant GENESIS_START_TIME = 1587587214; // Copied over from `EpochRewards().startTime()`.
uint256 public l2StartTime;
uint256 public totalSupplyAtL2Start;
uint256 public totalAllocatedAtL2Start;

uint256 public totalDistributedBySchedule;
address public communityRewardFund;
Expand All @@ -50,9 +49,11 @@ contract CeloDistributionSchedule is UsingRegistry, ReentrancyGuard, Initializab

/**
* @notice A constructor for initialising a new instance of a CeloDistributionSchedule contract.
* @param registryAddress The address of the registry core smart contract.
*/
function initialize() external initializer {
function initialize(address registryAddress) external initializer {
_transferOwnership(msg.sender);
setRegistry(registryAddress);
}

/**
Expand All @@ -61,25 +62,21 @@ contract CeloDistributionSchedule is UsingRegistry, ReentrancyGuard, Initializab
* @param _communityRewardFraction The percentage of rewards that go the community funds.
* @param _carbonOffsettingPartner The address of the carbon offsetting partner.
* @param _carbonOffsettingFraction The percentage of rewards going to carbon offsetting partner.
* @param registryAddress Address of the deployed contracts registry.
*/
function activate(
uint256 _l2StartTime,
uint256 _communityRewardFraction,
address _carbonOffsettingPartner,
uint256 _carbonOffsettingFraction,
address registryAddress
uint256 _carbonOffsettingFraction
) 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.");
areDependenciesSet = true;
l2StartTime = _l2StartTime;
setRegistry(registryAddress);
communityRewardFund = address(getGovernance());
ICeloToken celoToken = ICeloToken(address(getCeloToken()));
totalSupplyAtL2Start = celoToken.allocatedSupply();
totalAllocatedAtL2Start = celoToken.allocatedSupply();
setCommunityRewardFraction(_communityRewardFraction);
setCarbonOffsettingFund(_carbonOffsettingPartner, _carbonOffsettingFraction);
}
Expand All @@ -89,21 +86,21 @@ contract CeloDistributionSchedule is UsingRegistry, ReentrancyGuard, Initializab
*/
function distributeAccordingToSchedule() external nonReentrant onlyL2 returns (bool) {
(
uint256 targetCeloTotalSupply,
uint256 targetCeloDistribution,
uint256 communityRewardFundDistributionAmount,
uint256 carbonOffsettingPartnerDistributionAmount
) = getTargetCeloTotalSupply();
) = getTargetCeloDistribution();

ICeloToken celoToken = ICeloToken(address(getCeloToken()));

require(
targetCeloTotalSupply >= celoToken.allocatedSupply(),
targetCeloDistribution >= celoToken.allocatedSupply(),
"Contract balance is insufficient."
);

uint256 distributableAmount = Math.min(
getRemainingBalanceToDistribute(),
targetCeloTotalSupply - celoToken.allocatedSupply()
targetCeloDistribution - celoToken.allocatedSupply()
);

require(distributableAmount > 0, "Distributable amount must be greater than zero.");
Expand Down Expand Up @@ -216,35 +213,33 @@ contract CeloDistributionSchedule is UsingRegistry, ReentrancyGuard, Initializab
}

/**
* @notice Calculates remaining CELO balance to distribute.
* @return The remaining CELO balance to distribute.
*/
function getRemainingBalanceToDistribute() public view returns (uint256) {
ICeloToken celoToken = ICeloToken(address(getCeloToken()));
return CELO_SUPPLY_CAP - celoToken.allocatedSupply();
return address(this).balance;
}

/**
* @return The currently distributable amount.
*/
function getDistributableAmount() public view returns (uint256) {
(uint256 targetCeloTotalSupply, , ) = getTargetCeloTotalSupply();
(uint256 targetCeloDistribution, , ) = getTargetCeloDistribution();
ICeloToken celoToken = ICeloToken(address(getCeloToken()));
return targetCeloTotalSupply - celoToken.allocatedSupply();
return targetCeloDistribution - celoToken.allocatedSupply();
}

/**
* @notice Returns the target CELO supply according to the target schedule.
* @return targetCeloTotalSupply The target total CELO supply according to the target schedule.
* @return targetCeloDistribution 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 getTargetCeloTotalSupply()
function getTargetCeloDistribution()
public
view
whenActivated
returns (
uint256 targetCeloTotalSupply,
uint256 targetCeloDistribution,
uint256 communityTargetRewards,
uint256 carbonFundTargetRewards
)
Expand All @@ -254,20 +249,20 @@ contract CeloDistributionSchedule is UsingRegistry, ReentrancyGuard, Initializab

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

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

return (targetCeloTotalSupply, communityTargetRewards, carbonFundTargetRewards);
return (targetCeloDistribution, communityTargetRewards, carbonFundTargetRewards);
} else {
(
targetCeloTotalSupply,
targetCeloDistribution,
communityTargetRewards,
carbonFundTargetRewards
) = _calculateTargetReward(
Expand All @@ -279,10 +274,10 @@ contract CeloDistributionSchedule is UsingRegistry, ReentrancyGuard, Initializab
bool hasNotYetDistributedAllLinearRewards = totalDistributedBySchedule +
GENESIS_CELO_SUPPLY +
mintedOnL1 <
targetCeloTotalSupply;
targetCeloDistribution;

if (hasNotYetDistributedAllLinearRewards) {
return (targetCeloTotalSupply, communityTargetRewards, carbonFundTargetRewards);
return (targetCeloDistribution, communityTargetRewards, carbonFundTargetRewards);
}
revert("Block reward calculation for years 15-30 unimplemented");
return (0, 0, 0);
Expand All @@ -297,7 +292,7 @@ contract CeloDistributionSchedule is UsingRegistry, ReentrancyGuard, Initializab
internal
view
returns (
uint256 targetCeloTotalSupply,
uint256 targetCeloDistribution,
uint256 communityTargetRewards,
uint256 carbonFundTargetRewards
)
Expand All @@ -307,7 +302,8 @@ contract CeloDistributionSchedule is UsingRegistry, ReentrancyGuard, Initializab
_totalL2LinearSecondsAvailable
);
// Pay out half of all block rewards linearly.
uint256 totalLinearRewards = (CELO_SUPPLY_CAP - GENESIS_CELO_SUPPLY) / 2; //(200 million) includes validator rewards.
ICeloToken celoToken = ICeloToken(address(getCeloToken()));
uint256 totalLinearRewards = (celoToken.totalSupply() - GENESIS_CELO_SUPPLY) / 2; //(200 million) includes validator rewards.

FixidityLib.Fraction memory l2LinearRewards = FixidityLib.newFixed(
totalLinearRewards - _mintedOnL1
Expand All @@ -332,7 +328,7 @@ contract CeloDistributionSchedule is UsingRegistry, ReentrancyGuard, Initializab
.divide(totalL2LinearSecondsAvailableFraction)
.fromFixed();

targetCeloTotalSupply =
targetCeloDistribution =
communityTargetRewards +
carbonFundTargetRewards +
GENESIS_CELO_SUPPLY +
Expand Down
8 changes: 7 additions & 1 deletion packages/protocol/contracts-0.8/common/UsingRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import "@openzeppelin/contracts8/token/ERC20/IERC20.sol";
import "../../contracts/common/interfaces/IRegistry.sol";
import "../../contracts/common/interfaces/IAccounts.sol";
import "../../contracts/common/interfaces/IFreezer.sol";
import "../../contracts/common/interfaces/ICeloDistributionSchedule.sol";
import "../../contracts/governance/interfaces/IGovernance.sol";
import "../../contracts/governance/interfaces/ILockedGold.sol";
import "../../contracts/governance/interfaces/ILockedCelo.sol";
Expand Down Expand Up @@ -44,9 +45,10 @@ contract UsingRegistry is Ownable {
bytes32 constant VALIDATORS_REGISTRY_ID = keccak256(abi.encodePacked("Validators"));
bytes32 constant MENTOFEEHANDLERSELLER_REGISTRY_ID =
keccak256(abi.encodePacked("MentoFeeHandlerSeller"));

bytes32 constant CELO_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("CeloToken"));
bytes32 constant LOCKED_CELO_REGISTRY_ID = keccak256(abi.encodePacked("LockedCelo"));
bytes32 constant CELO_DISTRIBUTION_SCHEDULE_ID =
keccak256(abi.encodePacked("CeloDistributionSchedule"));
// solhint-enable state-visibility

IRegistry public registry;
Expand Down Expand Up @@ -124,4 +126,8 @@ contract UsingRegistry is Ownable {
function getGovernance() internal view returns (IGovernance) {
return IGovernance(registry.getAddressForOrDie(GOVERNANCE_REGISTRY_ID));
}

function getCeloDistributionSchedule() internal view returns (ICeloDistributionSchedule) {
return ICeloDistributionSchedule(registry.getAddressForOrDie(CELO_DISTRIBUTION_SCHEDULE_ID));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
pragma solidity >=0.5.13 <0.9.0;

interface ICeloDistributionScheduleInitializer {
function initialize() external;
function initialize(address registryAddress) external;
}
37 changes: 9 additions & 28 deletions packages/protocol/contracts/common/GoldToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ contract GoldToken is

mapping(address => mapping(address => uint256)) internal allowed;

// Total amount that was withdrawn from L2 (Celo) to L1 (Ethereum)
uint256 public withdrawn;

// Burn address is 0xdEaD because truffle is having buggy behaviour with the zero address
address constant BURN_ADDRESS = address(0x000000000000000000000000000000000000dEaD);

Expand All @@ -53,14 +50,6 @@ contract GoldToken is

event SetCeloTokenDistributionScheduleAddress(address indexed newScheduleAddress);

modifier onlyL2ToL1MessagePasser() {
require(
msg.sender == 0x4200000000000000000000000000000000000016,
"Only L2ToL1MessagePasser can call."
);
_;
}

/**
* @notice Sets initialized == true on implementation contracts
* @param test Set to true to skip implementation initialization
Expand Down Expand Up @@ -184,6 +173,10 @@ contract GoldToken is
*/
function transferFrom(address from, address to, uint256 value) external returns (bool) {
require(to != address(0), "transfer attempted to reserved address 0x0");
require(
to != address(celoTokenDistributionSchedule),
"transfer attempted to reserved celoTokenDistributionSchedule address"
);
require(value <= balanceOf(from), "transfer value exceeded balance of sender");
require(
value <= allowed[from][msg.sender],
Expand Down Expand Up @@ -221,22 +214,6 @@ contract GoldToken is
return true;
}

/**
* @notice Increases the total withdrawn CELO from L2 to L1.
* @param _withdrawAmount The amount to decrease counter by
*/
function withdrawAmount(uint256 _withdrawAmount) external onlyL2 onlyL2ToL1MessagePasser {
withdrawn = withdrawn.add(_withdrawAmount);
}

/**
* @notice Decreases the total withdrawn CELO from L2 to L1.
* @param _depositAmount The amount to decrease counter by
*/
function depositAmount(uint256 _depositAmount) external onlyVm onlyL2 {
withdrawn = withdrawn.sub(_depositAmount);
}

/**
* @notice Increases the variable for total amount of CELO in existence.
* @param amount The amount to increase counter by
Expand Down Expand Up @@ -325,7 +302,7 @@ contract GoldToken is
*/
function totalSupply() public view returns (uint256) {
if (isL2()) {
return CELO_SUPPLY_CAP.sub(withdrawn);
return CELO_SUPPLY_CAP;
} else {
return totalSupply_;
}
Expand All @@ -338,6 +315,10 @@ contract GoldToken is
* @return True if the transaction succeeds.
*/
function _transfer(address to, uint256 value) internal returns (bool) {
require(
to != address(celoTokenDistributionSchedule),
"transfer attempted to reserved celoTokenDistributionSchedule address"
);
require(value <= balanceOf(msg.sender), "transfer value exceeded balance of sender");

bool success;
Expand Down
8 changes: 8 additions & 0 deletions packages/protocol/contracts/common/UsingRegistryV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "./interfaces/IAccounts.sol";
import "./interfaces/IFeeCurrencyWhitelist.sol";
import "./interfaces/IFreezer.sol";
import "./interfaces/IRegistry.sol";
import "./interfaces/ICeloDistributionSchedule.sol";

import "../governance/interfaces/IElection.sol";
import "../governance/interfaces/IGovernance.sol";
Expand Down Expand Up @@ -58,6 +59,8 @@ contract UsingRegistryV2 {
bytes32 internal constant STABLE_REAL_TOKEN_REGISTRY_ID =
keccak256(abi.encodePacked("StableTokenBRL"));
bytes32 internal constant VALIDATORS_REGISTRY_ID = keccak256(abi.encodePacked("Validators"));
bytes32 constant CELO_DISTRIBUTION_SCHEDULE_ID =
keccak256(abi.encodePacked("CeloDistributionSchedule"));

bytes32 internal constant CELO_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("CeloToken"));
bytes32 internal constant LOCKED_CELO_REGISTRY_ID = keccak256(abi.encodePacked("LockedCelo"));
Expand Down Expand Up @@ -172,4 +175,9 @@ contract UsingRegistryV2 {
function getValidators() internal view returns (IValidators) {
return IValidators(registryContract.getAddressForOrDie(VALIDATORS_REGISTRY_ID));
}

function getCeloDistributionSchedule() internal view returns (ICeloDistributionSchedule) {
return
ICeloDistributionSchedule(registryContract.getAddressForOrDie(CELO_DISTRIBUTION_SCHEDULE_ID));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
pragma solidity >=0.5.13 <0.9.0;

interface ICeloDistributionSchedule {
/**
* @notice Sets the distribution schedule dependencies during L2 transition.
*/
function activate(uint256, uint256, address, uint256, address) external;

/**
* @notice Mints CELO to the beneficiaries according to the predefined schedule.
*/
Expand Down
5 changes: 4 additions & 1 deletion packages/protocol/migrations_sol/Migration.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,10 @@ contract Migration is Script, UsingRegistry, Constants {
function migrateCeloDistributionSchedule() public {
deployProxiedContract(
"CeloDistributionSchedule",
abi.encodeWithSelector(ICeloDistributionScheduleInitializer.initialize.selector)
abi.encodeWithSelector(
ICeloDistributionScheduleInitializer.initialize.selector,
registryAddress
)
);
}

Expand Down
14 changes: 11 additions & 3 deletions packages/protocol/migrations_ts/28_celoDistributionSchedule.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { CeloContractName } from '@celo/protocol/lib/registry-utils'
import { deploymentForCoreContract } from '@celo/protocol/lib/web3-utils'
import {
deploymentForCoreContract,
getDeployedProxiedContract,
} from '@celo/protocol/lib/web3-utils'
import { RegistryInstance } from '@celo/protocol/types'
import { CeloDistributionScheduleInstance } from 'types/08'
import { SOLIDITY_08_PACKAGE } from '../contractPackages'

const initializeArgs = async () => {
return []
const initializeArgs = async (): Promise<[string]> => {
const registry: RegistryInstance = await getDeployedProxiedContract<RegistryInstance>(
'Registry',
artifacts
)
return [registry.address]
}

module.exports = deploymentForCoreContract<CeloDistributionScheduleInstance>(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"FeeCurrencyDirectory": [],
"CeloDistributionSchedule": []
"CeloDistributionSchedule": ["0x000000000000000000000000000000000000ce10"]
}
Loading

0 comments on commit e886bb1

Please sign in to comment.