Skip to content

Commit 5f7b2b6

Browse files
authored
Implemented PermanentOwnable contract with the test coverage (#82)
* Implemented PermanentOwnable contract with the test coverage * Refactored the code * Integrated PermanentOwnable into ProxyBeacon and TransparentProxyUpgrader contracts * Updated the patch version and refactored imports
1 parent 4eea4dc commit 5f7b2b6

File tree

10 files changed

+123
-28
lines changed

10 files changed

+123
-28
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.4;
3+
4+
/**
5+
* @notice The PermanentOwnable module
6+
*
7+
* Contract module which provides a basic access control mechanism, where there is
8+
* an account (an owner) that can be granted exclusive access to specific functions.
9+
*
10+
* The owner is set to the address provided by the deployer. The ownership cannot be further changed.
11+
*
12+
* This module will make available the modifier `onlyOwner`, which can be applied
13+
* to your functions to restrict their use to the owners.
14+
*/
15+
abstract contract PermanentOwnable {
16+
address private immutable _OWNER;
17+
18+
/**
19+
* @dev Throws if called by any account other than the owner.
20+
*/
21+
modifier onlyOwner() {
22+
_onlyOwner();
23+
_;
24+
}
25+
26+
/**
27+
* @notice Initializes the contract setting the address provided by the deployer as the owner.
28+
* @param owner_ the address of the permanent owner.
29+
*/
30+
constructor(address owner_) {
31+
require(owner_ != address(0), "PermanentOwnable: zero address can not be the owner");
32+
33+
_OWNER = owner_;
34+
}
35+
36+
/**
37+
* @notice Returns the address of the owner.
38+
* @return the permanent owner.
39+
*/
40+
function owner() public view virtual returns (address) {
41+
return _OWNER;
42+
}
43+
44+
function _onlyOwner() internal view virtual {
45+
require(_OWNER == msg.sender, "PermanentOwnable: caller is not the owner");
46+
}
47+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.4;
3+
4+
import {PermanentOwnable} from "../../access-control/PermanentOwnable.sol";
5+
6+
contract PermanentOwnableMock is PermanentOwnable {
7+
event ValidOwner();
8+
9+
constructor(address _owner) PermanentOwnable(_owner) {}
10+
11+
function onlyOwnerMethod() external onlyOwner {
12+
emit ValidOwner();
13+
}
14+
}

contracts/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@solarity/solidity-lib",
3-
"version": "2.6.12",
3+
"version": "2.6.13",
44
"license": "MIT",
55
"author": "Distributed Lab",
66
"readme": "README.md",

contracts/proxy/beacon/ProxyBeacon.sol

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,22 @@ pragma solidity ^0.8.4;
44
import {IBeacon} from "@openzeppelin/contracts/proxy/beacon/IBeacon.sol";
55
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
66

7+
import {PermanentOwnable} from "../../access-control/PermanentOwnable.sol";
8+
79
/**
810
* @notice The proxies module
911
*
1012
* This is a lightweight utility ProxyBeacon contract that may be used as a beacon that BeaconProxies point to.
1113
*/
12-
contract ProxyBeacon is IBeacon {
14+
contract ProxyBeacon is IBeacon, PermanentOwnable {
1315
using Address for address;
1416

15-
address private immutable _OWNER;
17+
constructor() PermanentOwnable(msg.sender) {}
1618

1719
address private _implementation;
1820

1921
event Upgraded(address implementation);
2022

21-
modifier onlyOwner() {
22-
require(_OWNER == msg.sender, "ProxyBeacon: not an owner");
23-
_;
24-
}
25-
26-
constructor() {
27-
_OWNER = msg.sender;
28-
}
29-
3023
/**
3124
* @notice The function to upgrade to implementation contract
3225
* @param newImplementation_ the new implementation

contracts/proxy/transparent/TransparentProxyUpgrader.sol

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,17 @@ pragma solidity ^0.8.4;
44
import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
55
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
66

7+
import {PermanentOwnable} from "../../access-control/PermanentOwnable.sol";
8+
79
/**
810
* @notice The proxies module
911
*
1012
* This is the lightweight helper contract that may be used as a TransparentProxy admin.
1113
*/
12-
contract TransparentProxyUpgrader {
14+
contract TransparentProxyUpgrader is PermanentOwnable {
1315
using Address for address;
1416

15-
address private immutable _OWNER;
16-
17-
modifier onlyOwner() {
18-
require(_OWNER == msg.sender, "TransparentProxyUpgrader: not an owner");
19-
_;
20-
}
21-
22-
constructor() {
23-
_OWNER = msg.sender;
24-
}
17+
constructor() PermanentOwnable(msg.sender) {}
2518

2619
/**
2720
* @notice The function to upgrade the implementation contract

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@solarity/solidity-lib",
3-
"version": "2.6.12",
3+
"version": "2.6.13",
44
"license": "MIT",
55
"author": "Distributed Lab",
66
"description": "Solidity Library by Distributed Lab",
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { ethers } from "hardhat";
2+
import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers";
3+
import { expect } from "chai";
4+
import { Reverter } from "@/test/helpers/reverter";
5+
import { ZERO_ADDR } from "@/scripts/utils/constants";
6+
7+
import { PermanentOwnableMock } from "@ethers-v6";
8+
9+
describe("PermanentOwnable", () => {
10+
const reverter = new Reverter();
11+
12+
let OWNER: SignerWithAddress;
13+
let OTHER: SignerWithAddress;
14+
15+
let permanentOwnable: PermanentOwnableMock;
16+
17+
before("setup", async () => {
18+
[OWNER, OTHER] = await ethers.getSigners();
19+
20+
const permanentOwnableMock = await ethers.getContractFactory("PermanentOwnableMock");
21+
permanentOwnable = await permanentOwnableMock.deploy(OWNER);
22+
23+
await reverter.snapshot();
24+
});
25+
26+
afterEach(reverter.revert);
27+
28+
describe("PermanentOwnable", () => {
29+
it("should set the correct owner", async () => {
30+
expect(await permanentOwnable.owner()).to.equal(OWNER.address);
31+
});
32+
33+
it("should reject zero address during the owner initialization", async () => {
34+
const permanentOwnableMock = await ethers.getContractFactory("PermanentOwnableMock");
35+
36+
await expect(permanentOwnableMock.deploy(ZERO_ADDR)).to.be.revertedWith(
37+
"PermanentOwnable: zero address can not be the owner",
38+
);
39+
});
40+
41+
it("only owner should call this function", async () => {
42+
expect(await permanentOwnable.connect(OWNER).onlyOwnerMethod()).to.emit(permanentOwnable, "ValidOwner");
43+
await expect(permanentOwnable.connect(OTHER).onlyOwnerMethod()).to.be.revertedWith(
44+
"PermanentOwnable: caller is not the owner",
45+
);
46+
});
47+
});
48+
});

test/proxy/beacon/ProxyBeacon.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ describe("ProxyBeacon", () => {
4444

4545
it("only owner should upgrade", async () => {
4646
await expect(proxyBeacon.connect(SECOND).upgradeTo(await token.getAddress())).to.be.revertedWith(
47-
"ProxyBeacon: not an owner",
47+
"PermanentOwnable: caller is not the owner",
4848
);
4949
});
5050
});

test/proxy/transparent/TransparentProxyUpgrader.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ describe("TransparentProxyUpgrader", () => {
4040
it("only owner should upgrade", async () => {
4141
await expect(
4242
transparentProxyUpgrader.connect(SECOND).upgrade(await proxy.getAddress(), await proxy.getAddress(), "0x"),
43-
).to.be.revertedWith("TransparentProxyUpgrader: not an owner");
43+
).to.be.revertedWith("PermanentOwnable: caller is not the owner");
4444
});
4545
});
4646

0 commit comments

Comments
 (0)