Skip to content
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
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"solidity.packageDefaultDependenciesContractsDirectory": "src",
"solidity.packageDefaultDependenciesDirectory": "lib",
"solidity.monoRepoSupport": false
"solidity.monoRepoSupport": false,
}
7 changes: 4 additions & 3 deletions deployment.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@ staking-rewards-deployer = "0xb13573c6ceb505a7bdd4fa3ad7b473c5c5d36b19"
povw-minter = "0xbfce7c2d5e7eddeab71b3eeed770713c8b755397"
staking-minter = "0x459d87d54808fac136ddcf439fcc1d8a238311c7"
supply-calculator = "0x15eB8cA378E33381c867573EF2f25Ca1010f866d"
supply-calculator-impl = "0x1ff6f81ea7f5e6feafaafb0fc5983576096ded1d"
supply-calculator-impl = "0xddac1f7395815a8afd6673a98f5eddd31b99acd2"
supply-calculator-admin = "0xb13573c6ceb505a7bdd4fa3ad7b473c5c5d36b19"
supply-calculator-commit = "537c077"
supply-calculator-admin-2 = "0xb04d1a222789a76e74168a919b43b20f66e24f0b"
supply-calculator-commit = "2458b44"
zkc-commit = "5b8310b"
vezkc-commit = "caa29df"
staking-rewards-commit = "bac0f29"
supply-calculator-admin-2 = "0xb04d1a222789a76e74168a919b43b20f66e24f0b"
supply-calculator-impl-prev = "0x1ff6f81ea7f5e6feafaafb0fc5983576096ded1d"

[deployment.ethereum-sepolia]
name = "Ethereum Sepolia"
Expand Down
2 changes: 1 addition & 1 deletion script/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ZKC Scripts Guide
# ZKC Scripts

## Prerequisites

Expand Down
58 changes: 35 additions & 23 deletions script/Update.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {ZKC} from "../src/ZKC.sol";
import {SupplyCalculator} from "../src/calculators/SupplyCalculator.sol";
import {veZKC} from "../src/veZKC.sol";
import {StakingRewards} from "../src/rewards/StakingRewards.sol";
import {Supply} from "../src/libraries/Supply.sol";

/**
* Sample Usage for setting POVW minter role:
Expand Down Expand Up @@ -201,7 +202,7 @@ contract UpdateStakingMinter is BaseDeployment {
*
* # Direct execution:
* export CHAIN_KEY="anvil"
* export NEW_UNLOCKED="750000000000000000000000000" # 750M tokens
* export NEW_LOCKED="250000000000000000000000000" # 250M tokens
*
* forge script script/Update.s.sol:UpdateSupplyCalculatorUnlocked \
* --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
Expand All @@ -210,23 +211,23 @@ contract UpdateStakingMinter is BaseDeployment {
*
* # Gnosis Safe execution (print call data only):
* export CHAIN_KEY="anvil"
* export NEW_UNLOCKED="750000000000000000000000000" # 750M tokens
* export NEW_LOCKED="250000000000000000000000000" # 250M tokens
* export GNOSIS_EXECUTE=true
*
* forge script script/Update.s.sol:UpdateSupplyCalculatorUnlocked \
* --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
* --rpc-url http://127.0.0.1:8545
*/
contract UpdateSupplyCalculatorUnlocked is BaseDeployment {
contract UpdateSupplyCalculatorLocked is BaseDeployment {
function setUp() public {}

function run() public {
(DeploymentConfig memory config, string memory deploymentKey) = ConfigLoader.loadDeploymentConfig(vm);
require(config.supplyCalculator != address(0), "SupplyCalculator address not set in deployment.toml");

// Get new unlocked value from environment
uint256 newUnlocked = vm.envUint("NEW_UNLOCKED");
require(newUnlocked > 0, "NEW_UNLOCKED must be greater than 0");
// Get new locked value from environment
uint256 newLocked = vm.envUint("NEW_LOCKED");
require(newLocked > 0, "NEW_LOCKED must be greater than 0");

// Check for Gnosis Safe execution mode
bool gnosisExecute = vm.envOr("GNOSIS_EXECUTE", false);
Expand All @@ -236,23 +237,31 @@ contract UpdateSupplyCalculatorUnlocked is BaseDeployment {

// Get current values for logging
uint256 currentUnlocked = supplyCalculator.unlocked();
uint256 currentLocked = supplyCalculator.locked();
uint256 currentCirculatingSupply = supplyCalculator.circulatingSupply();

console2.log("================================================");
console2.log("Current locked amount: ", currentLocked);
console2.log("Current locked amount (in tokens): ", currentLocked / 10 ** 18);
console2.log("Current unlocked amount: ", currentUnlocked);
console2.log("Current unlocked amount (in tokens): ", currentUnlocked / 10 ** 18);
console2.log("Current circulating supply: ", currentCirculatingSupply);
console2.log("Current circulating supply (in tokens): ", currentCirculatingSupply / 10 ** 18);
console2.log("================================================");

// Calculate new unlocked value from new locked value
uint256 newUnlocked = Supply.INITIAL_SUPPLY - newLocked;

if (gnosisExecute) {
// Print Gnosis Safe transaction info for manual execution
_printGnosisSafeInfo(config.supplyCalculator, newUnlocked);
_printGnosisSafeInfo(config.supplyCalculator, newLocked);

// Calculate expected new circulating supply for display
// Calculate expected new values for display
uint256 expectedNewCirculatingSupply = currentCirculatingSupply - currentUnlocked + newUnlocked;

console2.log("Expected after update:");
console2.log("New locked amount: ", newLocked);
console2.log("New locked amount (in tokens): ", newLocked / 10 ** 18);
console2.log("New unlocked amount: ", newUnlocked);
console2.log("New unlocked amount (in tokens): ", newUnlocked / 10 ** 18);
console2.log("New circulating supply: ", expectedNewCirculatingSupply);
Expand All @@ -261,51 +270,54 @@ contract UpdateSupplyCalculatorUnlocked is BaseDeployment {
} else {
vm.startBroadcast();

// Update the unlocked value
supplyCalculator.updateUnlockedValue(newUnlocked);
// Update the locked value (which will also update unlocked)
supplyCalculator.updateLockedValue(newLocked);

// Get updated values
uint256 updatedUnlocked = supplyCalculator.unlocked();
uint256 updatedLocked = supplyCalculator.locked();
uint256 updatedCirculatingSupply = supplyCalculator.circulatingSupply();

vm.stopBroadcast();

console2.log("Updated unlocked value!");
console2.log("Updated locked value!");
console2.log("================================================");
console2.log("New locked amount: ", updatedLocked);
console2.log("New locked amount (in tokens): ", updatedLocked / 10 ** 18);
console2.log("New unlocked amount: ", updatedUnlocked);
console2.log("New unlocked amount (in tokens): ", updatedUnlocked / 10 ** 18);
console2.log("New circulating supply: ", updatedCirculatingSupply);
console2.log("New circulating supply (in tokens): ", updatedCirculatingSupply / 10 ** 18);
console2.log("================================================");
console2.log("Change in unlocked: ", newUnlocked > currentUnlocked ? "+" : "-");
if (newUnlocked > currentUnlocked) {
console2.log(" Amount increased: ", (newUnlocked - currentUnlocked) / 10 ** 18, " tokens");
console2.log("Change in locked: ", newLocked > currentLocked ? "+" : "-");
if (newLocked > currentLocked) {
console2.log(" Amount increased: ", (newLocked - currentLocked) / 10 ** 18, " tokens");
} else {
console2.log(" Amount decreased: ", (currentUnlocked - newUnlocked) / 10 ** 18, " tokens");
console2.log(" Amount decreased: ", (currentLocked - newLocked) / 10 ** 18, " tokens");
}
}
}

/// @notice Print Gnosis Safe transaction information for manual updates
/// @param targetAddress The SupplyCalculator contract address (target for Gnosis Safe)
/// @param newUnlocked The new unlocked value to set
function _printGnosisSafeInfo(address targetAddress, uint256 newUnlocked) internal pure {
/// @param newLocked The new locked value to set
function _printGnosisSafeInfo(address targetAddress, uint256 newLocked) internal pure {
console2.log("================================");
console2.log("================================");
console2.log("=== GNOSIS SAFE UPDATE INFO ===");
console2.log("Target Address (To): ", targetAddress);
console2.log("Function: updateUnlockedValue(uint256)");
console2.log("New Unlocked Value: ", newUnlocked);
console2.log("New Unlocked Value (in tokens): ", newUnlocked / 10 ** 18);
console2.log("Function: updateLockedValue(uint256)");
console2.log("New Locked Value: ", newLocked);
console2.log("New Locked Value (in tokens): ", newLocked / 10 ** 18);

bytes memory callData = abi.encodeWithSignature("updateUnlockedValue(uint256)", newUnlocked);
bytes memory callData = abi.encodeWithSignature("updateLockedValue(uint256)", newLocked);
console2.log("");
console2.log("Calldata:");
console2.logBytes(callData);
console2.log("");
console2.log("Expected Events on Successful Execution:");
console2.log("1. UnlockedValueUpdated(uint256 oldValue, uint256 newValue)");
console2.log(" - newValue: ", newUnlocked);
console2.log("1. LockedValueUpdated(uint256 oldValue, uint256 newValue)");
console2.log(" - newValue: ", newLocked);
console2.log("================================");
}
}
Expand Down
132 changes: 132 additions & 0 deletions script/Upgrade.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -535,8 +535,140 @@ contract UpgradeSupplyCalculator is BaseDeployment {
);
console2.log("Implementation updated: ", newImpl != config.supplyCalculatorImpl);
console2.log("ZKC token still configured: ", address(supplyCalculatorContract.zkc()) == config.zkc);
console2.log("Circulating supply: ", supplyCalculatorContract.circulatingSupply());
console2.log("Circulating supply (in tokens): ", supplyCalculatorContract.circulatingSupply() / 10 ** 18);
console2.log("================================================");
console2.log("SupplyCalculator Upgrade Complete");
console2.log("New Implementation: ", newImpl);
}
}

/**
* Sample Usage for SupplyCalculator upgrade with initializeV2:
*
* # Option 1: Safe upgrade with reference build (recommended)
* # First, create reference build from deployed SupplyCalculator commit:
* export DEPLOYED_COMMIT=$(python3 -c "import tomlkit; print(tomlkit.load(open('deployment.toml'))['deployment']['$CHAIN_KEY']['supply-calculator-commit'])")
* WORKTREE_PATH="../supply-calculator-reference-${DEPLOYED_COMMIT}"
* git worktree add "$WORKTREE_PATH" "$DEPLOYED_COMMIT"
* cd "$WORKTREE_PATH"
* forge build --profile reference
* cp -R out-reference/build-info "$OLDPWD/build-info-reference"
* cd "$OLDPWD"
*
* # Then run upgrade:
* export CHAIN_KEY="anvil"
* export INITIAL_LOCKED=500000000000000000000000000 # 500M ZKC in wei
* forge script script/Upgrade.s.sol:UpgradeSupplyCalculatorInitV2 \
* --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
* --broadcast \
* --rpc-url http://127.0.0.1:8545
*/
contract UpgradeSupplyCalculatorInitV2 is BaseDeployment {
function run() public {
(DeploymentConfig memory config, string memory deploymentKey) = ConfigLoader.loadDeploymentConfig(vm);
require(config.supplyCalculator != address(0), "SupplyCalculator not deployed");

// Read initial locked value from environment variable
uint256 initialLocked = vm.envUint("INITIAL_LOCKED");
console2.log("Initial locked value: ", initialLocked);
console2.log("Initial locked (in tokens): ", initialLocked / 10 ** 18);

vm.startBroadcast();

// Check for skip safety checks flag
bool skipSafetyChecks = vm.envOr("SKIP_SAFETY_CHECKS", false);

// Prepare upgrade options with reference contract
Options memory opts;

if (skipSafetyChecks) {
console2.log("WARNING: Skipping all upgrade safety checks and reference build!");
opts.unsafeSkipAllChecks = true;
} else {
// Get the SupplyCalculator commit hash from deployment config for commit-specific reference build
string memory supplyCalculatorCommit = config.supplyCalculatorCommit;
require(
bytes(supplyCalculatorCommit).length > 0, "SupplyCalculator commit hash not found in deployment config"
);

string memory referenceBuildDir = string.concat("build-info-reference-", supplyCalculatorCommit);
opts.referenceContract = string.concat(referenceBuildDir, ":SupplyCalculator");
opts.referenceBuildInfoDir = referenceBuildDir;
console2.log("Using reference build directory: ", referenceBuildDir);
}

address currentImpl = _getImplementationAddress(config.supplyCalculator);
bytes memory initializerData = abi.encodeCall(SupplyCalculator.initializeV2, (initialLocked));
address newImpl;

// Check for deployment mode flags
bool gnosisExecute = vm.envOr("GNOSIS_EXECUTE", false);

if (gnosisExecute) {
console2.log("GNOSIS_EXECUTE=true: Deploying new implementation for Safe upgrade");
console2.log("Target proxy address: ", config.supplyCalculator);
console2.log("Current implementation: ", currentImpl);

// Use prepareUpgrade for validation + deployment
newImpl = Upgrades.prepareUpgrade("SupplyCalculator.sol:SupplyCalculator", opts);
console2.log("New implementation deployed: ", newImpl);

// Print Gnosis Safe transaction info
_printGnosisSafeInfo(config.supplyCalculator, newImpl, initializerData);
} else {
console2.log("Upgrading SupplyCalculator at: ", config.supplyCalculator);
console2.log("Current implementation: ", currentImpl);

// Perform upgrade with initializeV2 initializer
Upgrades.upgradeProxy(
config.supplyCalculator, "SupplyCalculator.sol:SupplyCalculator", initializerData, opts
);

newImpl = Upgrades.getImplementationAddress(config.supplyCalculator);
console2.log("Upgraded SupplyCalculator implementation to: ", newImpl);
}

vm.stopBroadcast();

// Update deployment.toml with new implementation and store previous
_updateDeploymentConfig(deploymentKey, "supply-calculator-impl-prev", currentImpl);
_updateDeploymentConfig(deploymentKey, "supply-calculator-impl", newImpl);
_updateSupplyCalculatorCommit(deploymentKey);

// Print Gnosis Safe transaction info (only if not in GNOSIS_EXECUTE mode)
if (!gnosisExecute) {
_printGnosisSafeInfo(config.supplyCalculator, newImpl, initializerData);
}

// Verify results
if (gnosisExecute) {
console2.log("================================================");
console2.log("SupplyCalculator Implementation Deployment Complete");
console2.log("New Implementation: ", newImpl);
console2.log("Proxy NOT upgraded - use Gnosis Safe to complete upgrade");
console2.log("Note: initializeV2 will be called when Safe executes upgrade");
} else {
SupplyCalculator supplyCalculatorContract = SupplyCalculator(config.supplyCalculator);
console2.log(
"Proxy still points to SupplyCalculator: ", address(supplyCalculatorContract) == config.supplyCalculator
);
console2.log("Implementation updated: ", newImpl != config.supplyCalculatorImpl);
console2.log("ZKC token still configured: ", address(supplyCalculatorContract.zkc()) == config.zkc);
console2.log("Claimed total supply: ", supplyCalculatorContract.zkc().claimedTotalSupply());
console2.log(
"Claimed total supply (in tokens): ", supplyCalculatorContract.zkc().claimedTotalSupply() / 10 ** 18
);
console2.log("Locked value: ", supplyCalculatorContract.locked());
console2.log("Locked value (in tokens): ", supplyCalculatorContract.locked() / 10 ** 18);
console2.log("Unlocked value: ", supplyCalculatorContract.unlocked());
console2.log("Unlocked value (in tokens): ", supplyCalculatorContract.unlocked() / 10 ** 18);
console2.log("Circulating supply: ", supplyCalculatorContract.circulatingSupply());
console2.log("Circulating supply (in tokens): ", supplyCalculatorContract.circulatingSupply() / 10 ** 18);
console2.log("initializeV2 called during upgrade");
console2.log("================================================");
console2.log("SupplyCalculator Upgrade with InitV2 Complete");
console2.log("New Implementation: ", newImpl);
}
}
}
Loading
Loading