From 30314ecc5148262a4af3a5ac1cee3bb7403bc806 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Fri, 25 Oct 2024 11:09:57 +0100 Subject: [PATCH] feat: ownable sysstia (#9398) Fixes #9351 --- l1-contracts/src/governance/Sysstia.sol | 16 ++++--- .../src/governance/interfaces/ISysstia.sol | 5 +++ l1-contracts/test/Rollup.t.sol | 2 +- .../fee_portal/depositToAztecPublic.t.sol | 2 +- .../test/fee_portal/distributeFees.t.sol | 2 +- .../governance/scenario/UpgradeGerousia.t.sol | 2 +- .../test/governance/sysstia/Base.t.sol | 2 +- .../governance/sysstia/updateRegistry.t.sol | 43 +++++++++++++++++++ .../governance/sysstia/updateRegistry.tree | 6 +++ l1-contracts/test/portals/TokenPortal.t.sol | 2 +- l1-contracts/test/portals/UniswapPortal.t.sol | 2 +- l1-contracts/test/sparta/Sparta.t.sol | 2 +- .../ethereum/src/deploy_l1_contracts.ts | 27 ++++++------ 13 files changed, 87 insertions(+), 26 deletions(-) create mode 100644 l1-contracts/test/governance/sysstia/updateRegistry.t.sol create mode 100644 l1-contracts/test/governance/sysstia/updateRegistry.tree diff --git a/l1-contracts/src/governance/Sysstia.sol b/l1-contracts/src/governance/Sysstia.sol index dabf9ba8c78..15aa341e8e7 100644 --- a/l1-contracts/src/governance/Sysstia.sol +++ b/l1-contracts/src/governance/Sysstia.sol @@ -9,19 +9,25 @@ import {IRegistry} from "@aztec/governance/interfaces/IRegistry.sol"; import {ISysstia} from "@aztec/governance/interfaces/ISysstia.sol"; import {Errors} from "@aztec/governance/libraries/Errors.sol"; +import {Ownable} from "@oz/access/Ownable.sol"; -contract Sysstia is ISysstia { +contract Sysstia is ISysstia, Ownable { using SafeERC20 for IERC20; // This value is pulled out my ass. Don't take it seriously uint256 public constant BLOCK_REWARD = 50e18; IERC20 public immutable ASSET; - IRegistry public immutable REGISTRY; + IRegistry public registry; - constructor(IERC20 _asset, IRegistry _registry) { + constructor(IERC20 _asset, IRegistry _registry, address _owner) Ownable(_owner) { ASSET = _asset; - REGISTRY = _registry; + registry = _registry; + } + + function updateRegistry(IRegistry _registry) external onlyOwner { + registry = _registry; + emit RegistryUpdated(_registry); } /** @@ -48,6 +54,6 @@ contract Sysstia is ISysstia { } function canonicalRollup() public view returns (address) { - return REGISTRY.getRollup(); + return registry.getRollup(); } } diff --git a/l1-contracts/src/governance/interfaces/ISysstia.sol b/l1-contracts/src/governance/interfaces/ISysstia.sol index dbf6c1b6aab..baaa3ad721b 100644 --- a/l1-contracts/src/governance/interfaces/ISysstia.sol +++ b/l1-contracts/src/governance/interfaces/ISysstia.sol @@ -1,7 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity >=0.8.27; +import {IRegistry} from "./IRegistry.sol"; + interface ISysstia { + event RegistryUpdated(IRegistry indexed registry); + + function updateRegistry(IRegistry _registry) external; function claim(address _to) external returns (uint256); function canonicalRollup() external view returns (address); } diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index 2a55cce83f1..6677ac68f06 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -76,7 +76,7 @@ contract RollupTest is DecoderBase { ); testERC20.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); feeJuicePortal.initialize(); - sysstia = new Sysstia(testERC20, registry); + sysstia = new Sysstia(testERC20, registry, address(this)); testERC20.mint(address(sysstia), 1e6 ether); rollup = diff --git a/l1-contracts/test/fee_portal/depositToAztecPublic.t.sol b/l1-contracts/test/fee_portal/depositToAztecPublic.t.sol index d4d6031a942..21294aababc 100644 --- a/l1-contracts/test/fee_portal/depositToAztecPublic.t.sol +++ b/l1-contracts/test/fee_portal/depositToAztecPublic.t.sol @@ -33,7 +33,7 @@ contract DepositToAztecPublic is Test { token.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); feeJuicePortal.initialize(); - sysstia = new Sysstia(token, registry); + sysstia = new Sysstia(token, registry, address(this)); rollup = new Rollup(feeJuicePortal, sysstia, bytes32(0), bytes32(0), address(this), new address[](0)); diff --git a/l1-contracts/test/fee_portal/distributeFees.t.sol b/l1-contracts/test/fee_portal/distributeFees.t.sol index daf14dc8080..103b890cdf4 100644 --- a/l1-contracts/test/fee_portal/distributeFees.t.sol +++ b/l1-contracts/test/fee_portal/distributeFees.t.sol @@ -32,7 +32,7 @@ contract DistributeFees is Test { token.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); feeJuicePortal.initialize(); - sysstia = new Sysstia(token, registry); + sysstia = new Sysstia(token, registry, address(this)); rollup = new Rollup(feeJuicePortal, sysstia, bytes32(0), bytes32(0), address(this), new address[](0)); diff --git a/l1-contracts/test/governance/scenario/UpgradeGerousia.t.sol b/l1-contracts/test/governance/scenario/UpgradeGerousia.t.sol index 6ccb368ff13..b9f44593168 100644 --- a/l1-contracts/test/governance/scenario/UpgradeGerousia.t.sol +++ b/l1-contracts/test/governance/scenario/UpgradeGerousia.t.sol @@ -60,7 +60,7 @@ contract UpgradeGerousiaTest is TestBase { initialValidators[i - 1] = validator; } - Sysstia sysstia = new Sysstia(token, registry); + Sysstia sysstia = new Sysstia(token, registry, address(this)); rollup = new Rollup( new MockFeeJuicePortal(), sysstia, bytes32(0), bytes32(0), address(this), initialValidators ); diff --git a/l1-contracts/test/governance/sysstia/Base.t.sol b/l1-contracts/test/governance/sysstia/Base.t.sol index 3a6a41b1dd8..64798c056eb 100644 --- a/l1-contracts/test/governance/sysstia/Base.t.sol +++ b/l1-contracts/test/governance/sysstia/Base.t.sol @@ -18,6 +18,6 @@ contract SysstiaBase is Test { function setUp() public { token = IMintableERC20(address(new TestERC20())); registry = new Registry(address(this)); - sysstia = new Sysstia(token, registry); + sysstia = new Sysstia(token, registry, address(this)); } } diff --git a/l1-contracts/test/governance/sysstia/updateRegistry.t.sol b/l1-contracts/test/governance/sysstia/updateRegistry.t.sol new file mode 100644 index 00000000000..e5d8e402c92 --- /dev/null +++ b/l1-contracts/test/governance/sysstia/updateRegistry.t.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.27; + +import {SysstiaBase} from "./Base.t.sol"; +import {Ownable} from "@oz/access/Ownable.sol"; + +import {Registry} from "@aztec/governance/Registry.sol"; +import {IRegistry} from "@aztec/governance/interfaces/IRegistry.sol"; +import {ISysstia} from "@aztec/governance/interfaces/ISysstia.sol"; + +contract UpdateRegistryTest is SysstiaBase { + address internal caller; + + function test_WhenCallerIsNotOwner(address _caller) external { + // it reverts + vm.assume(_caller != sysstia.owner()); + + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, _caller)); + vm.prank(_caller); + sysstia.updateRegistry(IRegistry(address(0xdead))); + } + + function test_WhenCallerIsOwner() external { + // it updates the registry + // it emits a {RegistryUpdated} event + + Registry registry = new Registry(address(this)); + registry.upgrade(address(0xbeef)); + + IRegistry oldRegistry = sysstia.registry(); + address oldCanonical = sysstia.canonicalRollup(); + + vm.prank(sysstia.owner()); + vm.expectEmit(true, true, false, true, address(sysstia)); + emit ISysstia.RegistryUpdated(registry); + sysstia.updateRegistry(registry); + + assertEq(address(sysstia.registry()), address(registry)); + assertNotEq(address(oldRegistry), address(registry)); + assertEq(sysstia.canonicalRollup(), address(0xbeef)); + assertNotEq(oldCanonical, address(0xbeef)); + } +} diff --git a/l1-contracts/test/governance/sysstia/updateRegistry.tree b/l1-contracts/test/governance/sysstia/updateRegistry.tree new file mode 100644 index 00000000000..596aea57c19 --- /dev/null +++ b/l1-contracts/test/governance/sysstia/updateRegistry.tree @@ -0,0 +1,6 @@ +UpdateRegistryTest +├── when caller is not owner +│ └── it reverts +└── when caller is owner + ├── it updates the registry + └── it emits a {RegistryUpdated} event \ No newline at end of file diff --git a/l1-contracts/test/portals/TokenPortal.t.sol b/l1-contracts/test/portals/TokenPortal.t.sol index 83a81731522..60672b8e081 100644 --- a/l1-contracts/test/portals/TokenPortal.t.sol +++ b/l1-contracts/test/portals/TokenPortal.t.sol @@ -62,7 +62,7 @@ contract TokenPortalTest is Test { function setUp() public { registry = new Registry(address(this)); testERC20 = new TestERC20(); - sysstia = new Sysstia(testERC20, registry); + sysstia = new Sysstia(testERC20, registry, address(this)); rollup = new Rollup( new MockFeeJuicePortal(), sysstia, bytes32(0), bytes32(0), address(this), new address[](0) ); diff --git a/l1-contracts/test/portals/UniswapPortal.t.sol b/l1-contracts/test/portals/UniswapPortal.t.sol index 7fdc3b0950d..b96c59ff8c8 100644 --- a/l1-contracts/test/portals/UniswapPortal.t.sol +++ b/l1-contracts/test/portals/UniswapPortal.t.sol @@ -54,7 +54,7 @@ contract UniswapPortalTest is Test { vm.selectFork(forkId); registry = new Registry(address(this)); - Sysstia sysstia = new Sysstia(DAI, registry); + Sysstia sysstia = new Sysstia(DAI, registry, address(this)); rollup = new Rollup( new MockFeeJuicePortal(), sysstia, bytes32(0), bytes32(0), address(this), new address[](0) ); diff --git a/l1-contracts/test/sparta/Sparta.t.sol b/l1-contracts/test/sparta/Sparta.t.sol index a560b81c946..4df558471fe 100644 --- a/l1-contracts/test/sparta/Sparta.t.sol +++ b/l1-contracts/test/sparta/Sparta.t.sol @@ -76,7 +76,7 @@ contract SpartaTest is DecoderBase { testERC20 = new TestERC20(); Registry registry = new Registry(address(this)); - sysstia = new Sysstia(testERC20, registry); + sysstia = new Sysstia(testERC20, registry, address(this)); rollup = new Rollup( new MockFeeJuicePortal(), sysstia, bytes32(0), bytes32(0), address(this), initialValidators ); diff --git a/yarn-project/ethereum/src/deploy_l1_contracts.ts b/yarn-project/ethereum/src/deploy_l1_contracts.ts index 43fc2c2923b..7cb33ec0b13 100644 --- a/yarn-project/ethereum/src/deploy_l1_contracts.ts +++ b/yarn-project/ethereum/src/deploy_l1_contracts.ts @@ -315,19 +315,6 @@ export const deployL1Contracts = async ( const feeJuiceAddress = await govDeployer.deploy(l1Artifacts.feeJuice); logger.info(`Deployed Fee Juice at ${feeJuiceAddress}`); - const nomismatokopioAddress = await govDeployer.deploy(l1Artifacts.nomismatokopio, [ - feeJuiceAddress.toString(), - 1n * 10n ** 18n, // @todo #8084 - account.address.toString(), - ]); - logger.info(`Deployed Nomismatokopio at ${nomismatokopioAddress}`); - - const sysstiaAddress = await govDeployer.deploy(l1Artifacts.sysstia, [ - feeJuiceAddress.toString(), - registryAddress.toString(), - ]); - logger.info(`Deployed Sysstia at ${sysstiaAddress}`); - // @todo #8084 // @note These numbers are just chosen to make testing simple. const quorumSize = 6n; @@ -345,6 +332,20 @@ export const deployL1Contracts = async ( ]); logger.info(`Deployed Apella at ${apellaAddress}`); + const nomismatokopioAddress = await govDeployer.deploy(l1Artifacts.nomismatokopio, [ + feeJuiceAddress.toString(), + 1n * 10n ** 18n, // @todo #8084 + apellaAddress.toString(), + ]); + logger.info(`Deployed Nomismatokopio at ${nomismatokopioAddress}`); + + const sysstiaAddress = await govDeployer.deploy(l1Artifacts.sysstia, [ + feeJuiceAddress.toString(), + registryAddress.toString(), + apellaAddress.toString(), + ]); + logger.info(`Deployed Sysstia at ${sysstiaAddress}`); + await govDeployer.waitForDeployments(); logger.info(`All governance contracts deployed`);