Skip to content

Commit

Permalink
refactor: use custom error for onlyOwner and address(0) check (#236)
Browse files Browse the repository at this point in the history
* refactor: use custom error for `address(0)` check

* test: update tests for custom error

* refactor: use custom error for `onlyOwner` check

* ci: add different solc compiler versions to test in CI

* build!: increase min pragma to `0.8.4` for contracts using custom `error`

* fix!: set min pragma to `0.8.5` because of `bytes -> bytesN` conversion feature

* test: add tests for new custom error
  • Loading branch information
CJ42 committed Sep 27, 2023
1 parent 71db6b4 commit d551e90
Show file tree
Hide file tree
Showing 19 changed files with 131 additions and 67 deletions.
18 changes: 13 additions & 5 deletions .github/workflows/solc_version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,23 @@ jobs:
strategy:
matrix:
solc: [
"0.8.5",
"0.8.6",
"0.8.7",
"0.8.8",
"0.8.9",
# "0.8.10" skipped as default in hardhat.config.ts
"0.8.10",
"0.8.11",
"0.8.12",
"0.8.13",
"0.8.14",
"0.8.15",
"0.8.16",
"0.8.17",
# "0.8.17", # skipped as default in hardhat.config.ts
"0.8.18",
"0.8.19",
"0.8.20",
"0.8.21"
]
steps:
- uses: actions/checkout@v3
Expand All @@ -51,6 +58,7 @@ jobs:
- name: Compile Smart Contracts
run: |
solc contracts/**/*.sol \
@openzeppelin/=node_modules/@openzeppelin/ \
solidity-bytes-utils/=node_modules/solidity-bytes-utils/
solc contracts/**/*.sol --allow-paths $(pwd)/node_modules/ \
@openzeppelin/=$(pwd)/node_modules/@openzeppelin/ \
solidity-bytes-utils/=$(pwd)/node_modules/solidity-bytes-utils/ \
../=$(pwd)/contracts/
12 changes: 7 additions & 5 deletions implementations/contracts/ERC725.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
pragma solidity ^0.8.5;

// modules
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
Expand All @@ -10,6 +10,9 @@ import {ERC725YCore} from "./ERC725YCore.sol";
// constants
import {_INTERFACEID_ERC725X, _INTERFACEID_ERC725Y} from "./constants.sol";

// errors
import {OwnableCannotSetZeroAddressAsOwner} from "./errors.sol";

/**
* @title ERC725 bundle.
* @author Fabian Vogelsteller <fabian@lukso.network>
Expand All @@ -27,10 +30,9 @@ contract ERC725 is ERC725XCore, ERC725YCore {
* - `initialOwner` CANNOT be the zero address.
*/
constructor(address initialOwner) payable {
require(
initialOwner != address(0),
"Ownable: new owner is the zero address"
);
if (initialOwner == address(0)) {
revert OwnableCannotSetZeroAddressAsOwner();
}
OwnableUnset._setOwner(initialOwner);
}

Expand Down
2 changes: 1 addition & 1 deletion implementations/contracts/ERC725Init.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
pragma solidity ^0.8.5;

// modules
import {ERC725InitAbstract} from "./ERC725InitAbstract.sol";
Expand Down
12 changes: 7 additions & 5 deletions implementations/contracts/ERC725InitAbstract.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
pragma solidity ^0.8.5;

// modules
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
Expand All @@ -13,6 +13,9 @@ import {ERC725YCore} from "./ERC725YCore.sol";
// constants
import {_INTERFACEID_ERC725X, _INTERFACEID_ERC725Y} from "./constants.sol";

// errors
import {OwnableCannotSetZeroAddressAsOwner} from "./errors.sol";

/**
* @title Inheritable Proxy Implementation of ERC725 bundle
* @author Fabian Vogelsteller <fabian@lukso.network>
Expand All @@ -35,10 +38,9 @@ abstract contract ERC725InitAbstract is
function _initialize(
address initialOwner
) internal virtual onlyInitializing {
require(
initialOwner != address(0),
"Ownable: new owner is the zero address"
);
if (initialOwner == address(0)) {
revert OwnableCannotSetZeroAddressAsOwner();
}
OwnableUnset._setOwner(initialOwner);
}

Expand Down
12 changes: 7 additions & 5 deletions implementations/contracts/ERC725X.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
pragma solidity ^0.8.5;

// modules
import {OwnableUnset} from "./custom/OwnableUnset.sol";
import {ERC725XCore} from "./ERC725XCore.sol";

// errors
import {OwnableCannotSetZeroAddressAsOwner} from "./errors.sol";

/**
* @title Deployable implementation with `constructor` of ERC725X, a generic executor.
* @author Fabian Vogelsteller <fabian@lukso.network>
Expand All @@ -23,10 +26,9 @@ contract ERC725X is ERC725XCore {
* - `initialOwner` CANNOT be the zero address.
*/
constructor(address initialOwner) payable {
require(
initialOwner != address(0),
"Ownable: new owner is the zero address"
);
if (initialOwner == address(0)) {
revert OwnableCannotSetZeroAddressAsOwner();
}
OwnableUnset._setOwner(initialOwner);
}
}
2 changes: 1 addition & 1 deletion implementations/contracts/ERC725XCore.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
pragma solidity ^0.8.5;

// interfaces
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
Expand Down
2 changes: 1 addition & 1 deletion implementations/contracts/ERC725XInit.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
pragma solidity ^0.8.5;

// modules
import {ERC725XInitAbstract} from "./ERC725XInitAbstract.sol";
Expand Down
12 changes: 7 additions & 5 deletions implementations/contracts/ERC725XInitAbstract.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
pragma solidity ^0.8.5;

// modules
import {
Expand All @@ -8,6 +8,9 @@ import {
import {OwnableUnset} from "./custom/OwnableUnset.sol";
import {ERC725XCore} from "./ERC725XCore.sol";

// errors
import {OwnableCannotSetZeroAddressAsOwner} from "./errors.sol";

/**
* @title Inheritable Proxy Implementation of ERC725X, a generic executor.
* @author Fabian Vogelsteller <fabian@lukso.network>
Expand All @@ -27,10 +30,9 @@ abstract contract ERC725XInitAbstract is Initializable, ERC725XCore {
function _initialize(
address initialOwner
) internal virtual onlyInitializing {
require(
initialOwner != address(0),
"Ownable: new owner is the zero address"
);
if (initialOwner == address(0)) {
revert OwnableCannotSetZeroAddressAsOwner();
}
OwnableUnset._setOwner(initialOwner);
}
}
12 changes: 7 additions & 5 deletions implementations/contracts/ERC725Y.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

// modules
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {OwnableUnset} from "./custom/OwnableUnset.sol";
import {ERC725YCore} from "./ERC725YCore.sol";

// errors
import {OwnableCannotSetZeroAddressAsOwner} from "./errors.sol";

/**
* @title Deployable implementation with `constructor` of ERC725Y, a generic data key/value store.
* @author Fabian Vogelsteller <fabian@lukso.network>
Expand All @@ -22,10 +25,9 @@ contract ERC725Y is ERC725YCore {
* - `initialOwner` CANNOT be the zero address.
*/
constructor(address initialOwner) payable {
require(
initialOwner != address(0),
"Ownable: new owner is the zero address"
);
if (initialOwner == address(0)) {
revert OwnableCannotSetZeroAddressAsOwner();
}
OwnableUnset._setOwner(initialOwner);
}
}
2 changes: 1 addition & 1 deletion implementations/contracts/ERC725YCore.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

// interfaces
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
Expand Down
2 changes: 1 addition & 1 deletion implementations/contracts/ERC725YInit.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

// modules
import {ERC725YInitAbstract} from "./ERC725YInitAbstract.sol";
Expand Down
12 changes: 7 additions & 5 deletions implementations/contracts/ERC725YInitAbstract.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

// modules
import {
Expand All @@ -8,6 +8,9 @@ import {
import {OwnableUnset} from "./custom/OwnableUnset.sol";
import {ERC725YCore} from "./ERC725YCore.sol";

// errors
import {OwnableCannotSetZeroAddressAsOwner} from "./errors.sol";

/**
* @title Inheritable Proxy Implementation of ERC725Y, a generic data key/value store
* @author Fabian Vogelsteller <fabian@lukso.network>
Expand All @@ -25,10 +28,9 @@ abstract contract ERC725YInitAbstract is Initializable, ERC725YCore {
function _initialize(
address initialOwner
) internal virtual onlyInitializing {
require(
initialOwner != address(0),
"Ownable: new owner is the zero address"
);
if (initialOwner == address(0)) {
revert OwnableCannotSetZeroAddressAsOwner();
}
OwnableUnset._setOwner(initialOwner);
}
}
19 changes: 13 additions & 6 deletions implementations/contracts/custom/OwnableUnset.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

// errors
import {
OwnableCannotSetZeroAddressAsOwner,
OwnableCallerNotTheOwner
} from "../errors.sol";

/**
* @title OwnableUnset
Expand Down Expand Up @@ -47,18 +53,19 @@ abstract contract OwnableUnset {
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(
newOwner != address(0),
"Ownable: new owner is the zero address"
);
if (newOwner == address(0)) {
revert OwnableCannotSetZeroAddressAsOwner();
}
_setOwner(newOwner);
}

/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == msg.sender, "Ownable: caller is not the owner");
if (owner() != msg.sender) {
revert OwnableCallerNotTheOwner(msg.sender);
}
}

/**
Expand Down
14 changes: 13 additions & 1 deletion implementations/contracts/errors.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

/**
* @dev Reverts when trying to set `address(0)` as the contract owner when deploying the contract,
* initializing it or transferring ownership of the contract.
*/
error OwnableCannotSetZeroAddressAsOwner();

/**
* @dev Reverts when only the owner is allowed to call the function.
* @param callerAddress The address that tried to make the call.
*/
error OwnableCallerNotTheOwner(address callerAddress);

/**
* @dev Reverts when trying to send more native tokens `value` than available in current `balance`.
Expand Down
11 changes: 7 additions & 4 deletions implementations/test/ERC725.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ describe('ERC725', () => {
newOwner: ethers.constants.AddressZero,
};

await expect(
new ERC725__factory(accounts[0]).deploy(deployParams.newOwner),
).to.be.revertedWith('Ownable: new owner is the zero address');
const contractToDeploy = new ERC725__factory(accounts[0]);

await expect(contractToDeploy.deploy(deployParams.newOwner)).to.be.revertedWithCustomError(
contractToDeploy,
'OwnableCannotSetZeroAddressAsOwner',
);
});

it("should deploy the contract with the owner's address", async () => {
Expand Down Expand Up @@ -108,7 +111,7 @@ describe('ERC725', () => {
it('should revert when initializing with address(0) as owner', async () => {
await expect(
context.erc725['initialize(address)'](ethers.constants.AddressZero),
).to.be.revertedWith('Ownable: new owner is the zero address');
).to.be.revertedWithCustomError(context.erc725, 'OwnableCannotSetZeroAddressAsOwner');
});

it("should initialize the contract with the owner's address", async () => {
Expand Down
16 changes: 12 additions & 4 deletions implementations/test/ERC725X.behaviour.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,14 @@ export const shouldBehaveLikeERC725X = (buildContext: () => Promise<ERC725XTestC

expect(accountOwner).to.equal(context.accounts.anyone.address);
});

it('should revert when transferring ownership to `address(0)`', async () => {
await expect(
context.erc725X
.connect(context.accounts.owner)
.transferOwnership(ethers.constants.AddressZero),
).to.be.revertedWithCustomError(context.erc725X, 'OwnableCannotSetZeroAddressAsOwner');
});
});

describe('When non-owner is transferring ownership', () => {
Expand All @@ -126,7 +134,7 @@ export const shouldBehaveLikeERC725X = (buildContext: () => Promise<ERC725XTestC
context.erc725X
.connect(context.accounts.anyone)
.transferOwnership(context.accounts.anyone.address),
).to.be.revertedWith('Ownable: caller is not the owner');
).to.be.revertedWithCustomError(context.erc725X, 'OwnableCallerNotTheOwner');
});
});

Expand All @@ -146,7 +154,7 @@ export const shouldBehaveLikeERC725X = (buildContext: () => Promise<ERC725XTestC
it('should revert', async () => {
await expect(
context.erc725X.connect(context.accounts.anyone).renounceOwnership(),
).to.be.revertedWith('Ownable: caller is not the owner');
).to.be.revertedWithCustomError(context.erc725X, 'OwnableCallerNotTheOwner');
});
});
});
Expand Down Expand Up @@ -196,7 +204,7 @@ export const shouldBehaveLikeERC725X = (buildContext: () => Promise<ERC725XTestC
context.erc725X
.connect(context.accounts.anyone)
.execute(txParams.Operation, txParams.to, txParams.value, txParams.data),
).to.be.revertedWith('Ownable: caller is not the owner');
).to.be.revertedWithCustomError(context.erc725X, 'OwnableCallerNotTheOwner');
});
});
});
Expand Down Expand Up @@ -1624,7 +1632,7 @@ export const shouldBehaveLikeERC725X = (buildContext: () => Promise<ERC725XTestC
context.erc725X
.connect(context.accounts.anyone)
.executeBatch(txParams.Operations, txParams.to, txParams.values, txParams.data),
).to.be.revertedWith('Ownable: caller is not the owner');
).to.be.revertedWithCustomError(context.erc725X, 'OwnableCallerNotTheOwner');
});
});
});
Expand Down
Loading

0 comments on commit d551e90

Please sign in to comment.