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
11 changes: 3 additions & 8 deletions contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import type { HardhatUserConfig } from "hardhat/config";

import hardhatEthers from "@nomicfoundation/hardhat-ethers";
import hardhatNetworkHelpers from "@nomicfoundation/hardhat-network-helpers";
import hardhatToolboxMochaEthersPlugin from "@nomicfoundation/hardhat-toolbox-mocha-ethers";

const config: HardhatUserConfig = {
/*
* In Hardhat 3, plugins are defined as part of the Hardhat config instead of
* being based on the side-effect of imports.
*
* Note: A `hardhat-toolbox` like plugin for Hardhat 3 hasn't been defined yet,
* so this list is larger than what you would normally have.
*/
plugins: [hardhatToolboxMochaEthersPlugin],
plugins: [hardhatEthers, hardhatNetworkHelpers, hardhatToolboxMochaEthersPlugin],
solidity: {
profiles: {
default: {
Expand Down
17 changes: 9 additions & 8 deletions contracts/package.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
{
"name": "neox-governance",
"type": "module",
"version": "1.0.0",
"type": "module",
"devDependencies": {
"@nomicfoundation/hardhat-ethers": "^4.0.0-next.21",
"@nomicfoundation/hardhat-ignition": "^3.0.0-next.21",
"@nomicfoundation/hardhat-toolbox-mocha-ethers": "^3.0.0-next.21",
"@nomicfoundation/hardhat-ethers": "^4.0.2",
"@nomicfoundation/hardhat-ignition": "^3.0.3",
"@nomicfoundation/hardhat-network-helpers": "^3.0.1",
"@nomicfoundation/hardhat-toolbox-mocha-ethers": "^3.0.0",
"@types/chai": "^4.3.20",
"@types/chai-as-promised": "^8.0.2",
"@types/mocha": "^10.0.10",
"@types/node": "^22.16.0",
"chai": "^5.2.0",
"@types/node": "^22.18.10",
"chai": "^5.3.3",
"ethers": "^6.15.0",
"forge-std": "github:foundry-rs/forge-std#v1.9.4",
"hardhat": "^3.0.0-next.21",
"mocha": "^11.7.1",
"hardhat": "^3.0.7",
"mocha": "^11.7.4",
"typescript": "~5.8.0"
},
"dependencies": {
Expand Down
24 changes: 1 addition & 23 deletions contracts/solidity/CommitteeMultiSig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,10 @@
pragma solidity ^0.8.25;

import {GovernanceVote} from "./base/GovernanceVote.sol";
import {ERC1967Utils, GovProxyUpgradeable} from "./base/GovProxyUpgradeable.sol";
import {GovProxyUpgradeable} from "./base/GovProxyUpgradeable.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

contract CommitteeMultiSig is GovernanceVote, GovProxyUpgradeable {
address public constant SELF = 0x1212100000000000000000000000000000000007;

// Only for precompiled uups implementation in genesis file, need to be removed when upgrading the contract.
// This override is added because "immutable __self" in UUPSUpgradeable is not avaliable in precompiled contract.
function _checkProxy() internal view virtual override {
if (
address(this) == SELF || // Must be called through delegatecall
ERC1967Utils.getImplementation() != SELF // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}

// Only for precompiled uups implementation in genesis file, need to be removed when upgrading the contract.
// This override is added because "immutable __self" in UUPSUpgradeable is not avaliable in precompiled contract.
function _checkNotDelegated() internal view virtual override {
if (address(this) != SELF) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}

// Execute an operation that calls a function on the `target` contract
function execute(
address target,
Expand Down
23 changes: 1 addition & 22 deletions contracts/solidity/GovReward.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import {Errors} from "./libraries/Errors.sol";
import {Bytes} from "./libraries/Bytes.sol";
import {IGovReward} from "./interfaces/IGovReward.sol";
import {IGovernance} from "./interfaces/IGovernance.sol";
import {ERC1967Utils, GovProxyUpgradeable} from "./base/GovProxyUpgradeable.sol";
import {GovProxyUpgradeable} from "./base/GovProxyUpgradeable.sol";

contract GovReward is IGovReward, GovProxyUpgradeable {
address public constant SELF = 0x1212100000000000000000000000000000000003;
// governance contact
address public constant GOV = 0x1212000000000000000000000000000000000001;

Expand Down Expand Up @@ -36,26 +35,6 @@ contract GovReward is IGovReward, GovProxyUpgradeable {
_;
}

// Only for precompiled uups implementation in genesis file, need to be removed when upgrading the contract.
// This override is added because "immutable __self" in UUPSUpgradeable is not avaliable in precompiled contract.
function _checkProxy() internal view virtual override {
if (
address(this) == SELF || // Must be called through delegatecall
ERC1967Utils.getImplementation() != SELF // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}

// Only for precompiled uups implementation in genesis file, need to be removed when upgrading the contract.
// This override is added because "immutable __self" in UUPSUpgradeable is not avaliable in precompiled contract.
function _checkNotDelegated() internal view virtual override {
if (address(this) != SELF) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}

function getMiners() external view override returns (address[] memory) {
return IGovernance(GOV).getCurrentConsensus();
}
Expand Down
23 changes: 1 addition & 22 deletions contracts/solidity/Governance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ import {IGovReward} from "./interfaces/IGovReward.sol";
import {IKeyManagement} from "./interfaces/IKeyManagement.sol";
import {IGovernance} from "./interfaces/IGovernance.sol";
import {IPolicy} from "./interfaces/IPolicy.sol";
import {ERC1967Utils, GovProxyUpgradeable} from "./base/GovProxyUpgradeable.sol";
import {GovProxyUpgradeable} from "./base/GovProxyUpgradeable.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract Governance is IGovernance, ReentrancyGuard, GovProxyUpgradeable {
using EnumerableSet for EnumerableSet.AddressSet;

address public constant SELF = 0x1212100000000000000000000000000000000001;
// Policy contract
address public constant POLICY = 0x1212000000000000000000000000000000000002;
// GovReward contract
Expand Down Expand Up @@ -76,26 +75,6 @@ contract Governance is IGovernance, ReentrancyGuard, GovProxyUpgradeable {
// the pending group of block validators
address[] public pendingConsensus;

// Only for precompiled uups implementation in genesis file, need to be removed when upgrading the contract.
// This override is added because "immutable __self" in UUPSUpgradeable is not avaliable in precompiled contract.
function _checkProxy() internal view virtual override {
if (
address(this) == SELF || // Must be called through delegatecall
ERC1967Utils.getImplementation() != SELF // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}

// Only for precompiled uups implementation in genesis file, need to be removed when upgrading the contract.
// This override is added because "immutable __self" in UUPSUpgradeable is not avaliable in precompiled contract.
function _checkNotDelegated() internal view virtual override {
if (address(this) != SELF) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}

receive() external payable nonReentrant {
if (msg.sender != GOV_REWARD) revert Errors.SideCallNotAllowed();
address[] memory validators = currentConsensus;
Expand Down
23 changes: 1 addition & 22 deletions contracts/solidity/KeyManagementV0.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import {BLS12381} from "./libraries/BLS12381.sol";
import {IGovernance} from "./interfaces/IGovernance.sol";
import {IKeyManagement} from "./interfaces/IKeyManagement.sol";
import {IZKDKGV0} from "./interfaces/IZKDKGV0.sol";
import {ERC1967Utils, GovProxyUpgradeable} from "./base/GovProxyUpgradeable.sol";
import {GovProxyUpgradeable} from "./base/GovProxyUpgradeable.sol";

contract KeyManagementV0 is GovProxyUpgradeable, IKeyManagement, IZKDKGV0 {
address public constant SELF = 0x1212100000000000000000000000000000000008;
// governance contact
address public constant GOV = 0x1212000000000000000000000000000000000001;
address public constant SYS_CALL =
Expand Down Expand Up @@ -43,26 +42,6 @@ contract KeyManagementV0 is GovProxyUpgradeable, IKeyManagement, IZKDKGV0 {
// ref https://github.com/bane-labs/go-ethereum/blob/a07310bd9a3a117ae0876ad69bbe8b6ed624aaa5/core/antimev/util.go#L27
mapping(uint => bytes) public aggregatedCommitments;

// Only for precompiled uups implementation in genesis file, need to be removed when upgrading the contract.
// This override is added because "immutable __self" in UUPSUpgradeable is not avaliable in precompiled contract.
function _checkProxy() internal view virtual override {
if (
address(this) == SELF || // Must be called through delegatecall
ERC1967Utils.getImplementation() != SELF // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}

// Only for precompiled uups implementation in genesis file, need to be removed when upgrading the contract.
// This override is added because "immutable __self" in UUPSUpgradeable is not avaliable in precompiled contract.
function _checkNotDelegated() internal view virtual override {
if (address(this) != SELF) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}

function registerMessageKey(
address candidate,
bytes calldata pubkey
Expand Down
23 changes: 1 addition & 22 deletions contracts/solidity/KeyManagementV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ import {SevenMessageVerifier} from "./libraries/SevenMessageVerifier.sol";
import {IGovernance} from "./interfaces/IGovernance.sol";
import {IKeyManagement} from "./interfaces/IKeyManagement.sol";
import {IZKDKGV1} from "./interfaces/IZKDKGV1.sol";
import {ERC1967Utils, GovProxyUpgradeable} from "./base/GovProxyUpgradeable.sol";
import {GovProxyUpgradeable} from "./base/GovProxyUpgradeable.sol";

contract KeyManagementV1 is GovProxyUpgradeable, IKeyManagement, IZKDKGV1 {
address public constant SELF = 0x1212100000000000000000000000000000000008;
// governance contact
address public constant GOV = 0x1212000000000000000000000000000000000001;
address public constant SYS_CALL =
Expand Down Expand Up @@ -48,26 +47,6 @@ contract KeyManagementV1 is GovProxyUpgradeable, IKeyManagement, IZKDKGV1 {
// hash=>used, this is used to prevent reusing and uploading the same public input
mapping(bytes32 => bool) public isPubHashUsed;

// Only for precompiled uups implementation in genesis file, need to be removed when upgrading the contract.
// This override is added because "immutable __self" in UUPSUpgradeable is not avaliable in precompiled contract.
function _checkProxy() internal view virtual override {
if (
address(this) == SELF || // Must be called through delegatecall
ERC1967Utils.getImplementation() != SELF // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}

// Only for precompiled uups implementation in genesis file, need to be removed when upgrading the contract.
// This override is added because "immutable __self" in UUPSUpgradeable is not avaliable in precompiled contract.
function _checkNotDelegated() internal view virtual override {
if (address(this) != SELF) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}

function registerMessageKey(
address candidate,
bytes calldata pubkey
Expand Down
23 changes: 1 addition & 22 deletions contracts/solidity/Policy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import {Errors} from "./libraries/Errors.sol";
import {IGovernance} from "./interfaces/IGovernance.sol";
import {IPolicy} from "./interfaces/IPolicy.sol";
import {GovernanceVote} from "./base/GovernanceVote.sol";
import {ERC1967Utils, GovProxyUpgradeable} from "./base/GovProxyUpgradeable.sol";
import {GovProxyUpgradeable} from "./base/GovProxyUpgradeable.sol";

contract Policy is IPolicy, GovernanceVote, GovProxyUpgradeable {
address public constant SELF = 0x1212100000000000000000000000000000000002;
// governance contact
address public constant GOV = 0x1212000000000000000000000000000000000001;
uint256 public constant DEFAULT_CANDIDATE_LIMIT = 2000;
Expand All @@ -21,26 +20,6 @@ contract Policy is IPolicy, GovernanceVote, GovProxyUpgradeable {
uint256 public maxEnvelopesPerBlock;
uint256 public maxEnvelopeGasLimit;

// Only for precompiled uups implementation in genesis file, need to be removed when upgrading the contract.
// This override is added because "immutable __self" in UUPSUpgradeable is not avaliable in precompiled contract.
function _checkProxy() internal view virtual override {
if (
address(this) == SELF || // Must be called through delegatecall
ERC1967Utils.getImplementation() != SELF // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}

// Only for precompiled uups implementation in genesis file, need to be removed when upgrading the contract.
// This override is added because "immutable __self" in UUPSUpgradeable is not avaliable in precompiled contract.
function _checkNotDelegated() internal view virtual override {
if (address(this) != SELF) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}

function addBlackList(
address _addr
)
Expand Down
43 changes: 22 additions & 21 deletions contracts/test/CommitteeMultiSig.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,51 @@
import { expect } from "chai";
import { ERRORS } from "./helpers/errors.js";
import { ethers, allocGenesis } from "./helpers/setup.js";
import { ethers, networkHelpers, allocGenesis } from "./helpers/setup.js";

describe("CommitteeMultiSig", function () {

let signers: any;
let MultiSig: any, MockCaller: any;
let signers: any, snapshot: any;

beforeEach(async function () {
before(async function () {
signers = await ethers.getSigners();
await allocGenesis();
MultiSig = await ethers.deployContract("CommitteeMultiSig");
MockCaller = await ethers.deployContract("MockMultiSig");
snapshot = await networkHelpers.takeSnapshot();
});

describe("execute", function () {
let MultiSig: any, Mock: any;

beforeEach(async function () {
MultiSig = await ethers.deployContract("CommitteeMultiSig");
Mock = await ethers.deployContract("MockMultiSig");
});
afterEach(async function () {
await snapshot.restore();
});

describe("execute", function () {
it("Should revert if the sender is not a miner", async function () {
await expect(
MultiSig.connect(signers[7]).execute(Mock.target, "0xa1b2ca7d0000000000000000000000000000000000000000000000000000000000000001")
MultiSig.connect(signers[7]).execute(MockCaller.target, "0xa1b2ca7d0000000000000000000000000000000000000000000000000000000000000001")
).to.be.revertedWithCustomError(MultiSig, ERRORS.NOT_MINER);
});

it("Should not execute method when threshold is not met", async function () {
await expect(
MultiSig.connect(signers[0]).execute(Mock.target, "0xa1b2ca7d0000000000000000000000000000000000000000000000000000000000000001")
).not.to.be.reverted(ethers);
MultiSig.connect(signers[0]).execute(MockCaller.target, "0xa1b2ca7d0000000000000000000000000000000000000000000000000000000000000001")
).not.to.be.revert(ethers);

expect(await Mock.v()).to.eq(0);
expect(await MockCaller.v()).to.eq(0);
});

it("Should execute method when threshold is met", async function () {
for (let i = 0; i < 3; i++) {
await expect(
MultiSig.connect(signers[i]).execute(Mock.target, "0xa1b2ca7d0000000000000000000000000000000000000000000000000000000000000001")
).not.to.be.reverted(ethers);
MultiSig.connect(signers[i]).execute(MockCaller.target, "0xa1b2ca7d0000000000000000000000000000000000000000000000000000000000000001")
).not.to.be.revert(ethers);
}
expect(await Mock.v()).to.eq(0);
expect(await MockCaller.v()).to.eq(0);

await expect(
MultiSig.connect(signers[3]).execute(Mock.target, "0xa1b2ca7d0000000000000000000000000000000000000000000000000000000000000001")
).not.to.be.reverted(ethers);
expect(await Mock.v()).to.eq(1);
MultiSig.connect(signers[3]).execute(MockCaller.target, "0xa1b2ca7d0000000000000000000000000000000000000000000000000000000000000001")
).not.to.be.revert(ethers);
expect(await MockCaller.v()).to.eq(1);
});
});
});
});
19 changes: 12 additions & 7 deletions contracts/test/GovProxyUpgradeable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,32 @@ import { expect } from "chai";
const { ethers } = await network.connect();

describe("GovProxyUpgradeable", function () {

let Mock: any;

before(async function () {
Mock = await ethers.deployContract("MockGovProxyUpgradeable");
});

it("Should prevent implementation contract from initialization", async function () {
const mockGovProxyUpgradeable = await ethers.deployContract("MockGovProxyUpgradeable");
await expect(mockGovProxyUpgradeable.initialize()).to.be.reverted(ethers);
await expect(Mock.initialize()).to.be.revert(ethers);
expect(
await ethers.provider.send("eth_getStorageAt", [
await mockGovProxyUpgradeable.getAddress(),
await Mock.getAddress(),
"0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00",
"latest"]
)
).to.eq("0x000000000000000000000000000000000000000000000000ffffffffffffffff");
});

it("Should prevent implementation contract from reinitialization", async function () {
const mockGovProxyUpgradeable = await ethers.deployContract("MockGovProxyUpgradeable");
await expect(mockGovProxyUpgradeable.reinitialize()).to.be.reverted(ethers);
await expect(Mock.reinitialize()).to.be.revert(ethers);
expect(
await ethers.provider.send("eth_getStorageAt", [
await mockGovProxyUpgradeable.getAddress(),
await Mock.getAddress(),
"0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00",
"latest"]
)
).to.eq("0x000000000000000000000000000000000000000000000000ffffffffffffffff");
});
});
});
Loading
Loading