Make Ownable's initial owner explicit (#4267)

Co-authored-by: Ernesto García <ernestognw@gmail.com>
This commit is contained in:
Hadrien Croubois
2023-05-23 23:26:43 +02:00
committed by GitHub
parent 11d65442b3
commit 13d5e0466a
10 changed files with 29 additions and 20 deletions

View File

@ -0,0 +1,5 @@
---
'openzeppelin-solidity': major
---
`Ownable`: Add an `initialOwner` parameter to the constructor, making the ownership initialization explicit.

View File

@ -25,8 +25,8 @@ abstract contract Ownable is Context {
/** /**
* @dev Initializes the contract setting the deployer as the initial owner. * @dev Initializes the contract setting the deployer as the initial owner.
*/ */
constructor() { constructor(address initialOwner) {
_transferOwnership(_msgSender()); _transferOwnership(initialOwner);
} }
/** /**

View File

@ -7,9 +7,7 @@ import "../interfaces/IERC1271.sol";
import "../utils/cryptography/ECDSA.sol"; import "../utils/cryptography/ECDSA.sol";
contract ERC1271WalletMock is Ownable, IERC1271 { contract ERC1271WalletMock is Ownable, IERC1271 {
constructor(address originalOwner) { constructor(address originalOwner) Ownable(originalOwner) {}
transferOwnership(originalOwner);
}
function isValidSignature(bytes32 hash, bytes memory signature) public view override returns (bytes4 magicValue) { function isValidSignature(bytes32 hash, bytes memory signature) public view override returns (bytes4 magicValue) {
return ECDSA.recover(hash, signature) == owner() ? this.isValidSignature.selector : bytes4(0); return ECDSA.recover(hash, signature) == owner() ? this.isValidSignature.selector : bytes4(0);

View File

@ -21,10 +21,9 @@ contract UpgradeableBeacon is IBeacon, Ownable {
event Upgraded(address indexed implementation); event Upgraded(address indexed implementation);
/** /**
* @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the * @dev Sets the address of the initial implementation, and the initial owner who can upgrade the beacon.
* beacon.
*/ */
constructor(address implementation_) { constructor(address implementation_, address initialOwner) Ownable(initialOwner) {
_setImplementation(implementation_); _setImplementation(implementation_);
} }

View File

@ -11,6 +11,11 @@ import "../../access/Ownable.sol";
* explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}. * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
*/ */
contract ProxyAdmin is Ownable { contract ProxyAdmin is Ownable {
/**
* @dev Sets the initial owner who can perform upgrades.
*/
constructor(address initialOwner) Ownable(initialOwner) {}
/** /**
* @dev Changes the admin of `proxy` to `newAdmin`. * @dev Changes the admin of `proxy` to `newAdmin`.
* *

View File

@ -9,7 +9,7 @@ contract('Ownable', function (accounts) {
const [owner, other] = accounts; const [owner, other] = accounts;
beforeEach(async function () { beforeEach(async function () {
this.ownable = await Ownable.new({ from: owner }); this.ownable = await Ownable.new(owner);
}); });
it('has an owner', async function () { it('has an owner', async function () {

View File

@ -8,7 +8,7 @@ contract('Ownable2Step', function (accounts) {
const [owner, accountA, accountB] = accounts; const [owner, accountA, accountB] = accounts;
beforeEach(async function () { beforeEach(async function () {
this.ownable2Step = await Ownable2Step.new({ from: owner }); this.ownable2Step = await Ownable2Step.new(owner);
}); });
describe('transfer ownership', function () { describe('transfer ownership', function () {

View File

@ -11,7 +11,7 @@ const BadBeaconNoImpl = artifacts.require('BadBeaconNoImpl');
const BadBeaconNotContract = artifacts.require('BadBeaconNotContract'); const BadBeaconNotContract = artifacts.require('BadBeaconNotContract');
contract('BeaconProxy', function (accounts) { contract('BeaconProxy', function (accounts) {
const [anotherAccount] = accounts; const [upgradeableBeaconAdmin, anotherAccount] = accounts;
describe('bad beacon is not accepted', async function () { describe('bad beacon is not accepted', async function () {
it('non-contract beacon', async function () { it('non-contract beacon', async function () {
@ -49,7 +49,7 @@ contract('BeaconProxy', function (accounts) {
}); });
beforeEach('deploy beacon', async function () { beforeEach('deploy beacon', async function () {
this.beacon = await UpgradeableBeacon.new(this.implementationV0.address); this.beacon = await UpgradeableBeacon.new(this.implementationV0.address, upgradeableBeaconAdmin);
}); });
it('no initialization', async function () { it('no initialization', async function () {
@ -81,7 +81,7 @@ contract('BeaconProxy', function (accounts) {
}); });
it('upgrade a proxy by upgrading its beacon', async function () { it('upgrade a proxy by upgrading its beacon', async function () {
const beacon = await UpgradeableBeacon.new(this.implementationV0.address); const beacon = await UpgradeableBeacon.new(this.implementationV0.address, upgradeableBeaconAdmin);
const value = '10'; const value = '10';
const data = this.implementationV0.contract.methods.initializeNonPayableWithValue(value).encodeABI(); const data = this.implementationV0.contract.methods.initializeNonPayableWithValue(value).encodeABI();
@ -96,7 +96,7 @@ contract('BeaconProxy', function (accounts) {
expect(await dummy.version()).to.eq('V1'); expect(await dummy.version()).to.eq('V1');
// upgrade beacon // upgrade beacon
await beacon.upgradeTo(this.implementationV1.address); await beacon.upgradeTo(this.implementationV1.address, { from: upgradeableBeaconAdmin });
// test upgraded version // test upgraded version
expect(await dummy.version()).to.eq('V2'); expect(await dummy.version()).to.eq('V2');
@ -106,7 +106,7 @@ contract('BeaconProxy', function (accounts) {
const value1 = '10'; const value1 = '10';
const value2 = '42'; const value2 = '42';
const beacon = await UpgradeableBeacon.new(this.implementationV0.address); const beacon = await UpgradeableBeacon.new(this.implementationV0.address, upgradeableBeaconAdmin);
const proxy1InitializeData = this.implementationV0.contract.methods const proxy1InitializeData = this.implementationV0.contract.methods
.initializeNonPayableWithValue(value1) .initializeNonPayableWithValue(value1)
@ -130,7 +130,7 @@ contract('BeaconProxy', function (accounts) {
expect(await dummy2.version()).to.eq('V1'); expect(await dummy2.version()).to.eq('V1');
// upgrade beacon // upgrade beacon
await beacon.upgradeTo(this.implementationV1.address); await beacon.upgradeTo(this.implementationV1.address, { from: upgradeableBeaconAdmin });
// test upgraded version // test upgraded version
expect(await dummy1.version()).to.eq('V2'); expect(await dummy1.version()).to.eq('V2');

View File

@ -9,13 +9,16 @@ contract('UpgradeableBeacon', function (accounts) {
const [owner, other] = accounts; const [owner, other] = accounts;
it('cannot be created with non-contract implementation', async function () { it('cannot be created with non-contract implementation', async function () {
await expectRevert(UpgradeableBeacon.new(accounts[0]), 'UpgradeableBeacon: implementation is not a contract'); await expectRevert(
UpgradeableBeacon.new(accounts[0], owner),
'UpgradeableBeacon: implementation is not a contract',
);
}); });
context('once deployed', async function () { context('once deployed', async function () {
beforeEach('deploying beacon', async function () { beforeEach('deploying beacon', async function () {
this.v1 = await Implementation1.new(); this.v1 = await Implementation1.new();
this.beacon = await UpgradeableBeacon.new(this.v1.address, { from: owner }); this.beacon = await UpgradeableBeacon.new(this.v1.address, owner);
}); });
it('returns implementation', async function () { it('returns implementation', async function () {

View File

@ -17,12 +17,11 @@ contract('ProxyAdmin', function (accounts) {
beforeEach(async function () { beforeEach(async function () {
const initializeData = Buffer.from(''); const initializeData = Buffer.from('');
this.proxyAdmin = await ProxyAdmin.new({ from: proxyAdminOwner }); this.proxyAdmin = await ProxyAdmin.new(proxyAdminOwner);
const proxy = await TransparentUpgradeableProxy.new( const proxy = await TransparentUpgradeableProxy.new(
this.implementationV1.address, this.implementationV1.address,
this.proxyAdmin.address, this.proxyAdmin.address,
initializeData, initializeData,
{ from: proxyAdminOwner },
); );
this.proxy = await ITransparentUpgradeableProxy.at(proxy.address); this.proxy = await ITransparentUpgradeableProxy.at(proxy.address);
}); });