109 lines
4.8 KiB
Solidity
109 lines
4.8 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.20;
|
|
|
|
import "forge-std/Script.sol";
|
|
import "../src/eMoneyToken.sol";
|
|
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
|
|
import "./helpers/EnvValidation.sol";
|
|
|
|
/**
|
|
* @title UpgradeScript
|
|
* @notice Script for upgrading eMoneyToken implementation
|
|
* @dev Deploys new implementation and optionally authorizes upgrade.
|
|
* IMPORTANT: In production, upgrade authorization should be done via multisig, not this script.
|
|
*/
|
|
contract UpgradeScript is Script {
|
|
using EnvValidation for string;
|
|
|
|
function run() external {
|
|
// Validate environment variables
|
|
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
|
address tokenProxyAddr = vm.envAddress("TOKEN_PROXY_ADDRESS");
|
|
EnvValidation.validateAddress(tokenProxyAddr, "TOKEN_PROXY_ADDRESS");
|
|
|
|
vm.startBroadcast(deployerPrivateKey);
|
|
|
|
address deployer = vm.addr(deployerPrivateKey);
|
|
console.log("Deployer address:", deployer);
|
|
console.log("Token Proxy Address:", vm.toString(tokenProxyAddr));
|
|
console.log("");
|
|
|
|
// Get current implementation address
|
|
eMoneyToken tokenProxy = eMoneyToken(tokenProxyAddr);
|
|
address currentImplementation = _getImplementation(tokenProxyAddr);
|
|
console.log("Current Implementation:", vm.toString(currentImplementation));
|
|
console.log("");
|
|
|
|
// Deploy new implementation
|
|
console.log("Deploying new eMoneyToken implementation...");
|
|
eMoneyToken newImplementation = new eMoneyToken();
|
|
address newImplementationAddr = address(newImplementation);
|
|
console.log("New Implementation deployed at:", vm.toString(newImplementationAddr));
|
|
console.log("");
|
|
|
|
// Verify new implementation has code
|
|
require(newImplementationAddr.code.length > 0, "UpgradeScript: new implementation has no code");
|
|
console.log(" [OK] New implementation has code");
|
|
console.log("");
|
|
|
|
// Check if deployer has DEFAULT_ADMIN_ROLE (required for upgrade)
|
|
bytes32 adminRole = tokenProxy.DEFAULT_ADMIN_ROLE();
|
|
bool hasAdminRole = tokenProxy.hasRole(adminRole, deployer);
|
|
|
|
if (!hasAdminRole) {
|
|
console.log("⚠️ WARNING: Deployer does not have DEFAULT_ADMIN_ROLE");
|
|
console.log(" Upgrade authorization must be done via multisig with DEFAULT_ADMIN_ROLE");
|
|
console.log("");
|
|
console.log("=== Manual Upgrade Required ===");
|
|
console.log("Call the following function from a multisig with DEFAULT_ADMIN_ROLE:");
|
|
console.log(" tokenProxy.upgradeTo(", vm.toString(newImplementationAddr), ")");
|
|
console.log("");
|
|
} else {
|
|
console.log(" [OK] Deployer has DEFAULT_ADMIN_ROLE");
|
|
console.log("");
|
|
|
|
// Ask for confirmation before upgrading
|
|
console.log("⚠️ WARNING: This will upgrade the token implementation!");
|
|
console.log(" Current Implementation:", vm.toString(currentImplementation));
|
|
console.log(" New Implementation:", vm.toString(newImplementationAddr));
|
|
console.log("");
|
|
console.log("To proceed with upgrade, uncomment the following line:");
|
|
console.log(" // tokenProxy.upgradeTo(newImplementationAddr);");
|
|
console.log("");
|
|
|
|
// Uncomment the following line to actually perform the upgrade
|
|
// tokenProxy.upgradeTo(newImplementationAddr);
|
|
|
|
console.log(" [SKIP] Upgrade not executed (commented out for safety)");
|
|
console.log(" [INFO] To execute upgrade, uncomment the upgradeTo() call above");
|
|
}
|
|
|
|
console.log("");
|
|
console.log("=== Upgrade Preparation Complete ===");
|
|
console.log("New Implementation:", vm.toString(newImplementationAddr));
|
|
console.log("");
|
|
console.log("=== Next Steps ===");
|
|
console.log("1. Verify storage layout compatibility (run tools/validate-storage-layout.sh)");
|
|
console.log("2. Test upgrade on testnet");
|
|
console.log("3. Get multisig approval");
|
|
console.log("4. Execute upgrade via multisig:");
|
|
console.log(" tokenProxy.upgradeTo(", vm.toString(newImplementationAddr), ")");
|
|
console.log("5. Run VerifyUpgrade.s.sol to verify the upgrade");
|
|
|
|
vm.stopBroadcast();
|
|
}
|
|
|
|
/**
|
|
* @notice Gets the implementation address from a UUPS proxy
|
|
* @param proxyAddr The proxy address
|
|
* @return implementation The implementation address
|
|
*/
|
|
function _getImplementation(address proxyAddr) internal view returns (address implementation) {
|
|
// ERC1967 implementation slot: keccak256("eip1967.proxy.implementation") - 1
|
|
bytes32 slot = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
|
|
assembly {
|
|
implementation := sload(slot)
|
|
}
|
|
}
|
|
}
|