From e83ab62373e42b688017a5d5a6853b222f7876d1 Mon Sep 17 00:00:00 2001 From: Martin Kysel Date: Mon, 20 Oct 2025 19:49:46 -0400 Subject: [PATCH 1/5] something --- script/upgrades/GenericEIP1967Migrator.sol | 65 ++++++++++++++++ .../SettlementChainGatewayUpgrade.fork.t.sol | 74 +++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 script/upgrades/GenericEIP1967Migrator.sol create mode 100644 test/upgrades/SettlementChainGatewayUpgrade.fork.t.sol diff --git a/script/upgrades/GenericEIP1967Migrator.sol b/script/upgrades/GenericEIP1967Migrator.sol new file mode 100644 index 0000000..170e79a --- /dev/null +++ b/script/upgrades/GenericEIP1967Migrator.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {IERC1967} from "../../src/abstract/interfaces/IERC1967.sol"; + +/** + * @title GenericEIP1967Migrator + * @notice Minimal migrator that upgrades an EIP-1967 proxy to a new implementation. + * + * @dev HOW IT WORKS + * - This contract is deployed as a *standalone* “migrator”. + * - Your proxied contract implements the XMTP `Migratable` pattern. When governance + * sets this migrator’s address in the ParameterRegistry and calls `proxy.migrate()`, + * the proxy will `delegatecall("")` into this contract (empty calldata). + * - Because it’s a `delegatecall`, *this fallback executes in the proxy’s storage + * context*, so it can write the EIP-1967 implementation slot on the proxy. + * + * WHAT IT DOES + * - Writes `NEW_IMPL` into the EIP-1967 implementation slot. + * - Emits the standard `IERC1967.Upgraded(newImpl)` event. + * + * WHAT IT DOES NOT DO + * - Does not run any initialization or data migration on the new implementation. + * If you need state transforms or an `initialize(...)` call, use a purpose-built + * migrator that (after setting the slot) `delegatecall`s the new impl with the + * desired calldata. + * + * SAFETY NOTES + * - This migrator is intentionally tiny: fewer moving parts, easier to audit. + * - Make sure `NEW_IMPL` preserves storage layout and initializer semantics. + * - Only allow `migrate()` to be reachable via your governed parameter (`migrator` key). + */ +contract GenericEIP1967Migrator { + error InvalidImplementation(); + + /// @notice The implementation that the proxy will be upgraded to. + address public immutable NEW_IMPL; + + /// @dev bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1) + bytes32 private constant _IMPLEMENTATION_SLOT = + 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + + /** + * @param newImpl_ The address of the new implementation (must be non-zero). + */ + constructor(address newImpl_) { + if (newImpl_ == address(0)) revert InvalidImplementation(); + NEW_IMPL = newImpl_; + } + + /** + * @notice Entry point when the proxy `delegatecall`s this contract with empty calldata. + * @dev Runs in the *proxy’s* context (storage is the proxy’s), so we can sstore the slot. + * Emits the standard ERC-1967 `Upgraded` event via the imported interface. + */ + fallback() external payable { + address impl = NEW_IMPL; + + assembly { + sstore(_IMPLEMENTATION_SLOT, impl) + } + + emit IERC1967.Upgraded(impl); + } +} diff --git a/test/upgrades/SettlementChainGatewayUpgrade.fork.t.sol b/test/upgrades/SettlementChainGatewayUpgrade.fork.t.sol new file mode 100644 index 0000000..633d447 --- /dev/null +++ b/test/upgrades/SettlementChainGatewayUpgrade.fork.t.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import "forge-std/Test.sol"; + +import {IERC1967} from "../../src/abstract/interfaces/IERC1967.sol"; +import {IParameterRegistry} from "../../src/abstract/interfaces/IParameterRegistry.sol"; +import {SettlementChainGateway} from "../../src/settlement-chain/SettlementChainGateway.sol"; + +import {SettlementChainGatewayDeployer} from "../../script/deployers/SettlementChainGatewayDeployer.sol"; +import {GenericEIP1967Migrator} from "../../script/upgrades/GenericEIP1967Migrator.sol"; +import {Utils} from "../../script/utils/Utils.sol"; + +interface ISettlementChainGateway { + function parameterRegistry() external view returns (address); + function appChainGateway() external view returns (address); + function feeToken() external view returns (address); + function migrate() external; + function migratorParameterKey() external pure returns (string memory); +} + +contract SettlementChainGatewayUpgradeForkTest is Test { + address constant admin = 0x560469CBb7D1E29c7d56EfE765B21FbBaC639dC7; + + Utils.DeploymentData internal deployment; + + function setUp() external { + // Hardcoded environment and RPC + string memory rpc = "https://sepolia.base.org"; + vm.createSelectFork(rpc); + + string memory environment = "testnet-staging"; + deployment = Utils.parseDeploymentData( + string.concat("config/", environment, ".json") + ); + } + + function test_upgrade_settlement_gateway() external { + address factory = deployment.factory; + address paramRegistry = deployment.parameterRegistryProxy; + address appChainGateway = deployment.gatewayProxy; + address feeToken = deployment.feeTokenProxy; + address proxy = deployment.gatewayProxy; + + address oldImpl = IERC1967(proxy).implementation(); + + (address newImpl, ) = SettlementChainGatewayDeployer.deployImplementation( + factory, + paramRegistry, + appChainGateway, + feeToken + ); + + // Deploy migrator + GenericEIP1967Migrator migrator = + new GenericEIP1967Migrator(newImpl); + + // Set the migrator in ParameterRegistry (impersonate admin) + vm.startPrank(admin); + string memory key = ISettlementChainGateway(proxy).migratorParameterKey(); + IParameterRegistry(paramRegistry).set( + key, + bytes32(uint256(uint160(address(migrator)))) + ); + vm.stopPrank(); + + // Execute migration + ISettlementChainGateway(proxy).migrate(); + + // Confirm the implementation changed + address afterImpl = IERC1967(proxy).implementation(); + assertEq(afterImpl, newImpl, "Implementation did not update"); + } +} From 20a72952ca75bb80b183a6f990792b435ca97d03 Mon Sep 17 00:00:00 2001 From: Martin Kysel Date: Mon, 20 Oct 2025 19:52:26 -0400 Subject: [PATCH 2/5] preettier --- script/upgrades/GenericEIP1967Migrator.sol | 5 ++-- .../SettlementChainGatewayUpgrade.fork.t.sol | 28 ++++++++----------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/script/upgrades/GenericEIP1967Migrator.sol b/script/upgrades/GenericEIP1967Migrator.sol index 170e79a..379d5ba 100644 --- a/script/upgrades/GenericEIP1967Migrator.sol +++ b/script/upgrades/GenericEIP1967Migrator.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; -import {IERC1967} from "../../src/abstract/interfaces/IERC1967.sol"; +import { IERC1967 } from "../../src/abstract/interfaces/IERC1967.sol"; /** * @title GenericEIP1967Migrator @@ -37,8 +37,7 @@ contract GenericEIP1967Migrator { address public immutable NEW_IMPL; /// @dev bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1) - bytes32 private constant _IMPLEMENTATION_SLOT = - 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + bytes32 private constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @param newImpl_ The address of the new implementation (must be non-zero). diff --git a/test/upgrades/SettlementChainGatewayUpgrade.fork.t.sol b/test/upgrades/SettlementChainGatewayUpgrade.fork.t.sol index 633d447..23df2a9 100644 --- a/test/upgrades/SettlementChainGatewayUpgrade.fork.t.sol +++ b/test/upgrades/SettlementChainGatewayUpgrade.fork.t.sol @@ -3,13 +3,13 @@ pragma solidity 0.8.28; import "forge-std/Test.sol"; -import {IERC1967} from "../../src/abstract/interfaces/IERC1967.sol"; -import {IParameterRegistry} from "../../src/abstract/interfaces/IParameterRegistry.sol"; -import {SettlementChainGateway} from "../../src/settlement-chain/SettlementChainGateway.sol"; +import { IERC1967 } from "../../src/abstract/interfaces/IERC1967.sol"; +import { IParameterRegistry } from "../../src/abstract/interfaces/IParameterRegistry.sol"; +import { SettlementChainGateway } from "../../src/settlement-chain/SettlementChainGateway.sol"; -import {SettlementChainGatewayDeployer} from "../../script/deployers/SettlementChainGatewayDeployer.sol"; -import {GenericEIP1967Migrator} from "../../script/upgrades/GenericEIP1967Migrator.sol"; -import {Utils} from "../../script/utils/Utils.sol"; +import { SettlementChainGatewayDeployer } from "../../script/deployers/SettlementChainGatewayDeployer.sol"; +import { GenericEIP1967Migrator } from "../../script/upgrades/GenericEIP1967Migrator.sol"; +import { Utils } from "../../script/utils/Utils.sol"; interface ISettlementChainGateway { function parameterRegistry() external view returns (address); @@ -30,15 +30,13 @@ contract SettlementChainGatewayUpgradeForkTest is Test { vm.createSelectFork(rpc); string memory environment = "testnet-staging"; - deployment = Utils.parseDeploymentData( - string.concat("config/", environment, ".json") - ); + deployment = Utils.parseDeploymentData(string.concat("config/", environment, ".json")); } function test_upgrade_settlement_gateway() external { address factory = deployment.factory; address paramRegistry = deployment.parameterRegistryProxy; - address appChainGateway = deployment.gatewayProxy; + address settlementChainGateway = deployment.gatewayProxy; address feeToken = deployment.feeTokenProxy; address proxy = deployment.gatewayProxy; @@ -47,21 +45,17 @@ contract SettlementChainGatewayUpgradeForkTest is Test { (address newImpl, ) = SettlementChainGatewayDeployer.deployImplementation( factory, paramRegistry, - appChainGateway, + settlementChainGateway, feeToken ); // Deploy migrator - GenericEIP1967Migrator migrator = - new GenericEIP1967Migrator(newImpl); + GenericEIP1967Migrator migrator = new GenericEIP1967Migrator(newImpl); // Set the migrator in ParameterRegistry (impersonate admin) vm.startPrank(admin); string memory key = ISettlementChainGateway(proxy).migratorParameterKey(); - IParameterRegistry(paramRegistry).set( - key, - bytes32(uint256(uint160(address(migrator)))) - ); + IParameterRegistry(paramRegistry).set(key, bytes32(uint256(uint160(address(migrator))))); vm.stopPrank(); // Execute migration From f62b8379987712ccbc09a7489c90528e0b84adac Mon Sep 17 00:00:00 2001 From: Martin Kysel Date: Tue, 28 Oct 2025 11:14:40 -0700 Subject: [PATCH 3/5] upgrader --- .../SettlementChainGatewayUpgrader.s.sol | 73 +++++++++++++++++++ .../any-chain}/GenericEIP1967Migrator.sol | 0 .../SettlementChainGatewayUpgrade.fork.t.sol | 2 +- 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 script/upgrades/SettlementChainGatewayUpgrader.s.sol rename {script/upgrades => src/any-chain}/GenericEIP1967Migrator.sol (100%) diff --git a/script/upgrades/SettlementChainGatewayUpgrader.s.sol b/script/upgrades/SettlementChainGatewayUpgrader.s.sol new file mode 100644 index 0000000..5c63320 --- /dev/null +++ b/script/upgrades/SettlementChainGatewayUpgrader.s.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import { Script, console } from "../../lib/forge-std/src/Script.sol"; + +import { GenericEIP1967Migrator } from "../../../src/any-chain/GenericEIP1967Migrator.sol"; +import { IERC1967 } from "../../../src/abstract/interfaces/IERC1967.sol"; + +import { IParameterRegistry } from "../../../src/abstract/interfaces/IParameterRegistry.sol"; +import { SettlementChainGateway } from "../../../src/settlement-chain/SettlementChainGateway.sol"; +import { SettlementChainGatewayDeployer } from "../../../script/deployers/SettlementChainGatewayDeployer.sol"; +import { Utils } from "../../script/utils/Utils.sol"; + +interface ISettlementChainGateway { + function parameterRegistry() external view returns (address); + function appChainGateway() external view returns (address); + function feeToken() external view returns (address); + function migrate() external; + function migratorParameterKey() external pure returns (string memory); +} + +contract SettlementChainGatewayUpgrader is Script { + error PrivateKeyNotSet(); + + uint256 internal _privateKey; + address internal _admin; + + Utils.DeploymentData internal deployment; + + function setUp() external { + string memory environment = "anvil"; + deployment = Utils.parseDeploymentData(string.concat("config/", environment, ".json")); + + _privateKey = uint256(vm.envBytes32("ADMIN_PRIVATE_KEY")); + + if (_privateKey == 0) revert PrivateKeyNotSet(); + + _admin = vm.addr(_privateKey); + + console.log("Admin: %s", _admin); + } + + function UpgradeSettlementChainGateway() external { + address factory = deployment.factory; + console.log("factory" , factory); + address paramRegistry = deployment.parameterRegistryProxy; + console.log("paramRegistry" , paramRegistry); + address settlementChainGateway = deployment.gatewayProxy; + console.log("settlementChainGateway" , settlementChainGateway); + address feeToken = deployment.feeTokenProxy; + console.log("feeToken" , feeToken); + address proxy = deployment.gatewayProxy; + console.log("proxy" , proxy); + + vm.startBroadcast(_privateKey); + (address newImpl, ) = SettlementChainGatewayDeployer.deployImplementation( + factory, + paramRegistry, + settlementChainGateway, + feeToken + ); + console.log("newImpl", newImpl); + + GenericEIP1967Migrator migrator = new GenericEIP1967Migrator(newImpl); + console.log("migrator", address(migrator)); + string memory key = ISettlementChainGateway(proxy).migratorParameterKey(); + IParameterRegistry(paramRegistry).set(key, bytes32(uint256(uint160(address(migrator))))); + + SettlementChainGateway(settlementChainGateway).migrate(); + + vm.stopBroadcast(); + } +} diff --git a/script/upgrades/GenericEIP1967Migrator.sol b/src/any-chain/GenericEIP1967Migrator.sol similarity index 100% rename from script/upgrades/GenericEIP1967Migrator.sol rename to src/any-chain/GenericEIP1967Migrator.sol diff --git a/test/upgrades/SettlementChainGatewayUpgrade.fork.t.sol b/test/upgrades/SettlementChainGatewayUpgrade.fork.t.sol index 23df2a9..250c2b1 100644 --- a/test/upgrades/SettlementChainGatewayUpgrade.fork.t.sol +++ b/test/upgrades/SettlementChainGatewayUpgrade.fork.t.sol @@ -8,7 +8,7 @@ import { IParameterRegistry } from "../../src/abstract/interfaces/IParameterRegi import { SettlementChainGateway } from "../../src/settlement-chain/SettlementChainGateway.sol"; import { SettlementChainGatewayDeployer } from "../../script/deployers/SettlementChainGatewayDeployer.sol"; -import { GenericEIP1967Migrator } from "../../script/upgrades/GenericEIP1967Migrator.sol"; +import { GenericEIP1967Migrator } from "../../src/any-chain/GenericEIP1967Migrator.sol"; import { Utils } from "../../script/utils/Utils.sol"; interface ISettlementChainGateway { From a480cc4569341028a046b8de4086d4976d2f303d Mon Sep 17 00:00:00 2001 From: Martin Kysel Date: Tue, 28 Oct 2025 11:42:05 -0700 Subject: [PATCH 4/5] upgrades --- .../SettlementChainGatewayUpgrader.s.sol | 12 +++- ...lementChainParameterRegistryUpgrader.s.sol | 63 +++++++++++++++++++ ...ntChainParameterRegistryUpgrade.fork.t.sol | 53 ++++++++++++++++ 3 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 script/upgrades/SettlementChainParameterRegistryUpgrader.s.sol create mode 100644 test/upgrades/SettlementChainParameterRegistryUpgrade.fork.t.sol diff --git a/script/upgrades/SettlementChainGatewayUpgrader.s.sol b/script/upgrades/SettlementChainGatewayUpgrader.s.sol index 5c63320..5dd6be1 100644 --- a/script/upgrades/SettlementChainGatewayUpgrader.s.sol +++ b/script/upgrades/SettlementChainGatewayUpgrader.s.sol @@ -21,6 +21,9 @@ interface ISettlementChainGateway { contract SettlementChainGatewayUpgrader is Script { error PrivateKeyNotSet(); + error EnvironmentNotSet(); + + string internal _environment; uint256 internal _privateKey; address internal _admin; @@ -28,8 +31,13 @@ contract SettlementChainGatewayUpgrader is Script { Utils.DeploymentData internal deployment; function setUp() external { - string memory environment = "anvil"; - deployment = Utils.parseDeploymentData(string.concat("config/", environment, ".json")); + _environment = vm.envString("ENVIRONMENT"); + + if (bytes(_environment).length == 0) revert EnvironmentNotSet(); + + console.log("Environment: %s", _environment); + + deployment = Utils.parseDeploymentData(string.concat("config/", _environment, ".json")); _privateKey = uint256(vm.envBytes32("ADMIN_PRIVATE_KEY")); diff --git a/script/upgrades/SettlementChainParameterRegistryUpgrader.s.sol b/script/upgrades/SettlementChainParameterRegistryUpgrader.s.sol new file mode 100644 index 0000000..6acedb5 --- /dev/null +++ b/script/upgrades/SettlementChainParameterRegistryUpgrader.s.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import { Script, console } from "../../lib/forge-std/src/Script.sol"; + +import { GenericEIP1967Migrator } from "../../../src/any-chain/GenericEIP1967Migrator.sol"; +import { IERC1967 } from "../../../src/abstract/interfaces/IERC1967.sol"; + +import { IParameterRegistry } from "../../../src/abstract/interfaces/IParameterRegistry.sol"; +import { Utils } from "../../script/utils/Utils.sol"; +import {SettlementChainParameterRegistryDeployer} from "../deployers/SettlementChainParameterRegistryDeployer.sol"; + +contract SettlementChainParameterRegistryUpgrader is Script { + error PrivateKeyNotSet(); + error EnvironmentNotSet(); + + string internal _environment; + + uint256 internal _privateKey; + address internal _admin; + + Utils.DeploymentData internal deployment; + + function setUp() external { + _environment = vm.envString("ENVIRONMENT"); + + if (bytes(_environment).length == 0) revert EnvironmentNotSet(); + + console.log("Environment: %s", _environment); + + deployment = Utils.parseDeploymentData(string.concat("config/", _environment, ".json")); + + _privateKey = uint256(vm.envBytes32("ADMIN_PRIVATE_KEY")); + + if (_privateKey == 0) revert PrivateKeyNotSet(); + + _admin = vm.addr(_privateKey); + + console.log("Admin: %s", _admin); + } + + function UpgradeSettlementParameterRegistry() external { + address factory = deployment.factory; + console.log("factory" , factory); + address paramRegistry = deployment.parameterRegistryProxy; + console.log("paramRegistry" , paramRegistry); + + vm.startBroadcast(_privateKey); + (address newImpl, ) = SettlementChainParameterRegistryDeployer.deployImplementation( + factory + ); + console.log("newImpl", newImpl); + + GenericEIP1967Migrator migrator = new GenericEIP1967Migrator(newImpl); + console.log("migrator", address(migrator)); + string memory key = IParameterRegistry(paramRegistry).migratorParameterKey(); + IParameterRegistry(paramRegistry).set(key, bytes32(uint256(uint160(address(migrator))))); + + IParameterRegistry(paramRegistry).migrate(); + + vm.stopBroadcast(); + } +} diff --git a/test/upgrades/SettlementChainParameterRegistryUpgrade.fork.t.sol b/test/upgrades/SettlementChainParameterRegistryUpgrade.fork.t.sol new file mode 100644 index 0000000..17bfbe0 --- /dev/null +++ b/test/upgrades/SettlementChainParameterRegistryUpgrade.fork.t.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import "forge-std/Test.sol"; + +import { IERC1967 } from "../../src/abstract/interfaces/IERC1967.sol"; +import { IParameterRegistry } from "../../src/abstract/interfaces/IParameterRegistry.sol"; + +import { GenericEIP1967Migrator } from "../../src/any-chain/GenericEIP1967Migrator.sol"; +import { Utils } from "../../script/utils/Utils.sol"; +import {SettlementChainParameterRegistryDeployer} from "../../script/deployers/SettlementChainParameterRegistryDeployer.sol"; + + +contract SettlementChainParameterRegistryUpgradeForkTest is Test { + address constant admin = 0x560469CBb7D1E29c7d56EfE765B21FbBaC639dC7; + + Utils.DeploymentData internal deployment; + + function setUp() external { + // Hardcoded environment and RPC + string memory rpc = "https://sepolia.base.org"; + vm.createSelectFork(rpc); + + string memory environment = "testnet-staging"; + deployment = Utils.parseDeploymentData(string.concat("config/", environment, ".json")); + } + + function test_upgrade_settlement_parameter_registry() external { + address factory = deployment.factory; + address paramRegistry = deployment.parameterRegistryProxy; + address oldImpl = IERC1967(paramRegistry).implementation(); + + (address newImpl, ) = SettlementChainParameterRegistryDeployer.deployImplementation( + factory + ); + + // Deploy migrator + GenericEIP1967Migrator migrator = new GenericEIP1967Migrator(newImpl); + + // Set the migrator in ParameterRegistry (impersonate admin) + vm.startPrank(admin); + string memory key = IParameterRegistry(paramRegistry).migratorParameterKey(); + IParameterRegistry(paramRegistry).set(key, bytes32(uint256(uint160(address(migrator))))); + vm.stopPrank(); + + // Execute migration + IParameterRegistry(paramRegistry).migrate(); + + // Confirm the implementation changed + address afterImpl = IERC1967(paramRegistry).implementation(); + assertEq(afterImpl, newImpl, "Implementation did not update"); + } +} From 1d1cfc42a2c73780f39f11b89d384006ff4bb50e Mon Sep 17 00:00:00 2001 From: Martin Kysel Date: Tue, 28 Oct 2025 12:16:44 -0700 Subject: [PATCH 5/5] upgrades --- script/upgrades/PayerRegistryUpgrader.s.sol | 71 ++++++++++++++++++ script/upgrades/PayerReportManager.s.sol | 74 +++++++++++++++++++ test/upgrades/PayerRegistryUpgrade.fork.t.sol | 59 +++++++++++++++ .../PayerReportManagerUpgrade.fork.t.sol | 61 +++++++++++++++ 4 files changed, 265 insertions(+) create mode 100644 script/upgrades/PayerRegistryUpgrader.s.sol create mode 100644 script/upgrades/PayerReportManager.s.sol create mode 100644 test/upgrades/PayerRegistryUpgrade.fork.t.sol create mode 100644 test/upgrades/PayerReportManagerUpgrade.fork.t.sol diff --git a/script/upgrades/PayerRegistryUpgrader.s.sol b/script/upgrades/PayerRegistryUpgrader.s.sol new file mode 100644 index 0000000..7dbfee5 --- /dev/null +++ b/script/upgrades/PayerRegistryUpgrader.s.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import { Script, console } from "../../lib/forge-std/src/Script.sol"; + +import { GenericEIP1967Migrator } from "../../../src/any-chain/GenericEIP1967Migrator.sol"; +import { IERC1967 } from "../../../src/abstract/interfaces/IERC1967.sol"; +import { PayerRegistry } from "../../../src/settlement-chain/PayerRegistry.sol"; + +import { IParameterRegistry } from "../../../src/abstract/interfaces/IParameterRegistry.sol"; +import { Utils } from "../../script/utils/Utils.sol"; +import {PayerRegistryDeployer} from "../deployers/PayerRegistryDeployer.sol"; + + +contract PayerRegistryUpgrader is Script { + error PrivateKeyNotSet(); + error EnvironmentNotSet(); + + string internal _environment; + + uint256 internal _privateKey; + address internal _admin; + + Utils.DeploymentData internal deployment; + + function setUp() external { + _environment = vm.envString("ENVIRONMENT"); + + if (bytes(_environment).length == 0) revert EnvironmentNotSet(); + + console.log("Environment: %s", _environment); + + deployment = Utils.parseDeploymentData(string.concat("config/", _environment, ".json")); + + _privateKey = uint256(vm.envBytes32("ADMIN_PRIVATE_KEY")); + + if (_privateKey == 0) revert PrivateKeyNotSet(); + + _admin = vm.addr(_privateKey); + + console.log("Admin: %s", _admin); + } + + function UpgradePayerRegistry() external { + address factory = deployment.factory; + console.log("factory" , factory); + address paramRegistry = deployment.parameterRegistryProxy; + console.log("paramRegistry" , paramRegistry); + address feeToken = deployment.feeTokenProxy; + console.log("feeToken" , feeToken); + address proxy = deployment.payerRegistryProxy; + console.log("proxy" , proxy); + + vm.startBroadcast(_privateKey); + (address newImpl, ) = PayerRegistryDeployer.deployImplementation( + factory, + paramRegistry, + feeToken + ); + console.log("newImpl", newImpl); + + GenericEIP1967Migrator migrator = new GenericEIP1967Migrator(newImpl); + console.log("migrator", address(migrator)); + string memory key = PayerRegistry(proxy).migratorParameterKey(); + IParameterRegistry(paramRegistry).set(key, bytes32(uint256(uint160(address(migrator))))); + + PayerRegistry(proxy).migrate(); + + vm.stopBroadcast(); + } +} diff --git a/script/upgrades/PayerReportManager.s.sol b/script/upgrades/PayerReportManager.s.sol new file mode 100644 index 0000000..6757090 --- /dev/null +++ b/script/upgrades/PayerReportManager.s.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import { Script, console } from "../../lib/forge-std/src/Script.sol"; + +import { GenericEIP1967Migrator } from "../../../src/any-chain/GenericEIP1967Migrator.sol"; +import { IERC1967 } from "../../../src/abstract/interfaces/IERC1967.sol"; + +import { IParameterRegistry } from "../../../src/abstract/interfaces/IParameterRegistry.sol"; +import { Utils } from "../../script/utils/Utils.sol"; +import {PayerReportManager} from "../../src/settlement-chain/PayerReportManager.sol"; +import {PayerReportManagerDeployer} from "../deployers/PayerReportManagerDeployer.sol"; + + +contract PayerReportManagerUpgrader is Script { + error PrivateKeyNotSet(); + error EnvironmentNotSet(); + + string internal _environment; + + uint256 internal _privateKey; + address internal _admin; + + Utils.DeploymentData internal deployment; + + function setUp() external { + _environment = vm.envString("ENVIRONMENT"); + + if (bytes(_environment).length == 0) revert EnvironmentNotSet(); + + console.log("Environment: %s", _environment); + + deployment = Utils.parseDeploymentData(string.concat("config/", _environment, ".json")); + + _privateKey = uint256(vm.envBytes32("ADMIN_PRIVATE_KEY")); + + if (_privateKey == 0) revert PrivateKeyNotSet(); + + _admin = vm.addr(_privateKey); + + console.log("Admin: %s", _admin); + } + + function UpgradePayerReportManager() external { + address factory = deployment.factory; + console.log("factory" , factory); + address paramRegistry = deployment.parameterRegistryProxy; + console.log("paramRegistry" , paramRegistry); + address proxy = deployment.payerReportManagerProxy; + console.log("proxy" , proxy); + address nodeRegistry = deployment.nodeRegistryProxy; + console.log("nodeRegistry" , nodeRegistry); + address payerRegistry = deployment.payerRegistryProxy; + console.log("payerRegistry" , payerRegistry); + + vm.startBroadcast(_privateKey); + (address newImpl, ) = PayerReportManagerDeployer.deployImplementation( + factory, + paramRegistry, + nodeRegistry, + payerRegistry + ); + console.log("newImpl", newImpl); + + GenericEIP1967Migrator migrator = new GenericEIP1967Migrator(newImpl); + console.log("migrator", address(migrator)); + string memory key = PayerReportManager(proxy).migratorParameterKey(); + IParameterRegistry(paramRegistry).set(key, bytes32(uint256(uint160(address(migrator))))); + + PayerReportManager(proxy).migrate(); + + vm.stopBroadcast(); + } +} diff --git a/test/upgrades/PayerRegistryUpgrade.fork.t.sol b/test/upgrades/PayerRegistryUpgrade.fork.t.sol new file mode 100644 index 0000000..a84d22a --- /dev/null +++ b/test/upgrades/PayerRegistryUpgrade.fork.t.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import "forge-std/Test.sol"; + +import { IERC1967 } from "../../src/abstract/interfaces/IERC1967.sol"; +import { IParameterRegistry } from "../../src/abstract/interfaces/IParameterRegistry.sol"; +import { PayerRegistry } from "../../src/settlement-chain/PayerRegistry.sol"; + +import { GenericEIP1967Migrator } from "../../src/any-chain/GenericEIP1967Migrator.sol"; +import { Utils } from "../../script/utils/Utils.sol"; +import {PayerRegistryDeployer} from "../../script/deployers/PayerRegistryDeployer.sol"; + +contract PayerRegistryUpgradeForkTest is Test { + address constant admin = 0x560469CBb7D1E29c7d56EfE765B21FbBaC639dC7; + + Utils.DeploymentData internal deployment; + + function setUp() external { + // Hardcoded environment and RPC + string memory rpc = "https://sepolia.base.org"; + vm.createSelectFork(rpc); + + string memory environment = "testnet-staging"; + deployment = Utils.parseDeploymentData(string.concat("config/", environment, ".json")); + } + + function test_payer_registry() external { + address factory = deployment.factory; + address paramRegistry = deployment.parameterRegistryProxy; + address settlementChainGateway = deployment.gatewayProxy; + address feeToken = deployment.feeTokenProxy; + address proxy = deployment.payerRegistryProxy; + + address oldImpl = IERC1967(proxy).implementation(); + + (address newImpl, ) = PayerRegistryDeployer.deployImplementation( + factory, + paramRegistry, + feeToken + ); + + // Deploy migrator + GenericEIP1967Migrator migrator = new GenericEIP1967Migrator(newImpl); + + // Set the migrator in ParameterRegistry (impersonate admin) + vm.startPrank(admin); + string memory key = PayerRegistry(proxy).migratorParameterKey(); + IParameterRegistry(paramRegistry).set(key, bytes32(uint256(uint160(address(migrator))))); + vm.stopPrank(); + + // Execute migration + PayerRegistry(proxy).migrate(); + + // Confirm the implementation changed + address afterImpl = IERC1967(proxy).implementation(); + assertEq(afterImpl, newImpl, "Implementation did not update"); + } +} diff --git a/test/upgrades/PayerReportManagerUpgrade.fork.t.sol b/test/upgrades/PayerReportManagerUpgrade.fork.t.sol new file mode 100644 index 0000000..1e7fb1c --- /dev/null +++ b/test/upgrades/PayerReportManagerUpgrade.fork.t.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import "forge-std/Test.sol"; + +import { IERC1967 } from "../../src/abstract/interfaces/IERC1967.sol"; +import { IParameterRegistry } from "../../src/abstract/interfaces/IParameterRegistry.sol"; +import { PayerReportManager } from "../../src/settlement-chain/PayerReportManager.sol"; + +import { GenericEIP1967Migrator } from "../../src/any-chain/GenericEIP1967Migrator.sol"; +import { Utils } from "../../script/utils/Utils.sol"; +import {PayerRegistryDeployer} from "../../script/deployers/PayerRegistryDeployer.sol"; +import {PayerReportManagerDeployer} from "../../script/deployers/PayerReportManagerDeployer.sol"; + +contract PayerReportManagerUpgradeForkTest is Test { + address constant admin = 0x560469CBb7D1E29c7d56EfE765B21FbBaC639dC7; + + Utils.DeploymentData internal deployment; + + function setUp() external { + // Hardcoded environment and RPC + string memory rpc = "https://sepolia.base.org"; + vm.createSelectFork(rpc); + + string memory environment = "testnet-staging"; + deployment = Utils.parseDeploymentData(string.concat("config/", environment, ".json")); + } + + function test_payer_report_manager() external { + address factory = deployment.factory; + address paramRegistry = deployment.parameterRegistryProxy; + address proxy = deployment.payerReportManagerProxy; + address nodeRegistry = deployment.nodeRegistryProxy; + address payerRegistry = deployment.payerRegistryProxy; + + address oldImpl = IERC1967(proxy).implementation(); + + (address newImpl, ) = PayerReportManagerDeployer.deployImplementation( + factory, + paramRegistry, + nodeRegistry, + payerRegistry + ); + + // Deploy migrator + GenericEIP1967Migrator migrator = new GenericEIP1967Migrator(newImpl); + + // Set the migrator in ParameterRegistry (impersonate admin) + vm.startPrank(admin); + string memory key = PayerReportManager(proxy).migratorParameterKey(); + IParameterRegistry(paramRegistry).set(key, bytes32(uint256(uint160(address(migrator))))); + vm.stopPrank(); + + // Execute migration + PayerReportManager(proxy).migrate(); + + // Confirm the implementation changed + address afterImpl = IERC1967(proxy).implementation(); + assertEq(afterImpl, newImpl, "Implementation did not update"); + } +}