diff --git a/solidity/contracts/factory.sol b/solidity/contracts/factory.sol index 26b4172..5f93795 100644 --- a/solidity/contracts/factory.sol +++ b/solidity/contracts/factory.sol @@ -16,10 +16,11 @@ pragma solidity ^0.8.20; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {IZetoFungibleInitializable} from "./lib/interfaces/zeto_fungible_initializable.sol"; import {IZetoNonFungibleInitializable} from "./lib/interfaces/zeto_nf_initializable.sol"; -contract ZetoTokenFactory { +contract ZetoTokenFactory is Ownable { // all the addresses needed by the factory to // clone a Zeto token and initialize it. The // "implementation" is used to clone the token, @@ -35,12 +36,12 @@ contract ZetoTokenFactory { mapping(string => ImplementationInfo) internal implementations; - constructor() {} + constructor() Ownable(msg.sender) {} function registerImplementation( string memory name, ImplementationInfo memory implementation - ) public { + ) public onlyOwner { require( implementation.implementation != address(0), "Factory: implementation address is required" diff --git a/solidity/test/factory.ts b/solidity/test/factory.ts index 981c901..6f14d30 100644 --- a/solidity/test/factory.ts +++ b/solidity/test/factory.ts @@ -20,13 +20,28 @@ import { expect } from 'chai'; describe("Zeto based fungible token with anonymity without encryption or nullifier", function () { let deployer: Signer; + let nonOwner: Signer; before(async function () { if (network.name !== 'hardhat') { // accommodate for longer block times on public networks this.timeout(120000); } - [deployer] = await ethers.getSigners(); + [deployer, nonOwner] = await ethers.getSigners(); + }); + + it("attempting to register an implementation as a non-owner should fail", async function () { + const Factory = await ethers.getContractFactory("ZetoTokenFactory"); + const factory = await Factory.deploy(); + await factory.waitForDeployment(); + + const implInfo = { + implementation: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1", + verifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1", + depositVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1", + withdrawVerifier: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1", + }; + await expect(factory.connect(nonOwner).registerImplementation("test", implInfo as any)).rejectedWith(`reverted with custom error 'OwnableUnauthorizedAccount(`); }); it("attempting to register an implementation without the required implementation value should fail", async function () {