Skip to content

Commit 8176a90

Browse files
authored
Cleanup of Ownership directory (#2120)
* Remove Ownable.isOwner. * Remove ownable behavior from tests * Make Escrow use Ownable instead of Secondary * Migrate GSNRecipientERC20Fee to Ownable * Remove Secondary * Move Ownable to access directory * Remove mentions of Secondary * Add changelog entry * Move Ownable tests to access * Remove unused mock
1 parent baaadde commit 8176a90

20 files changed

+144
-315
lines changed

CHANGELOG.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
## 3.0.0 (unreleased)
44

5-
### Breaking Changes
5+
### Breaking changes
66
* `ECDSA`: when receiving an invalid signature, `recover` now reverts instead of returning the zero address. ([#2114](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2114))
7+
* `Ownable`: moved to the `access` directory. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120))
8+
* `Ownable`: removed `isOwner`. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120))
9+
* `Secondary`: removed from the library, use `Ownable` instead. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120))
10+
* `Escrow`, `ConditionalEscrow`, `RefundEscrow`: these now use `Ownable` instead of `Secondary`, their external API changed accordingly. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120))
711
* `ERC20`: removed `_burnFrom`. ([#2119](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2119))
812

913
## 2.5.0 (2020-02-04)

contracts/GSN/GSNRecipientERC20Fee.sol

+17-17
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pragma solidity ^0.6.0;
22

33
import "./GSNRecipient.sol";
44
import "../math/SafeMath.sol";
5-
import "../ownership/Secondary.sol";
5+
import "../access/Ownable.sol";
66
import "../token/ERC20/SafeERC20.sol";
77
import "../token/ERC20/ERC20.sol";
88
import "../token/ERC20/ERC20Detailed.sol";
@@ -17,20 +17,20 @@ import "../token/ERC20/ERC20Detailed.sol";
1717
* internal {_mint} function.
1818
*/
1919
contract GSNRecipientERC20Fee is GSNRecipient {
20-
using SafeERC20 for __unstable__ERC20PrimaryAdmin;
20+
using SafeERC20 for __unstable__ERC20Owned;
2121
using SafeMath for uint256;
2222

2323
enum GSNRecipientERC20FeeErrorCodes {
2424
INSUFFICIENT_BALANCE
2525
}
2626

27-
__unstable__ERC20PrimaryAdmin private _token;
27+
__unstable__ERC20Owned private _token;
2828

2929
/**
3030
* @dev The arguments to the constructor are the details that the gas payment token will have: `name` and `symbol`. `decimals` is hard-coded to 18.
3131
*/
3232
constructor(string memory name, string memory symbol) public {
33-
_token = new __unstable__ERC20PrimaryAdmin(name, symbol, 18);
33+
_token = new __unstable__ERC20Owned(name, symbol, 18);
3434
}
3535

3636
/**
@@ -106,42 +106,42 @@ contract GSNRecipientERC20Fee is GSNRecipient {
106106
}
107107

108108
/**
109-
* @title __unstable__ERC20PrimaryAdmin
109+
* @title __unstable__ERC20Owned
110110
* @dev An ERC20 token owned by another contract, which has minting permissions and can use transferFrom to receive
111111
* anyone's tokens. This contract is an internal helper for GSNRecipientERC20Fee, and should not be used
112112
* outside of this context.
113113
*/
114114
// solhint-disable-next-line contract-name-camelcase
115-
contract __unstable__ERC20PrimaryAdmin is ERC20, ERC20Detailed, Secondary {
115+
contract __unstable__ERC20Owned is ERC20, ERC20Detailed, Ownable {
116116
uint256 private constant UINT256_MAX = 2**256 - 1;
117117

118118
constructor(string memory name, string memory symbol, uint8 decimals) public ERC20Detailed(name, symbol, decimals) { }
119119

120-
// The primary account (GSNRecipientERC20Fee) can mint tokens
121-
function mint(address account, uint256 amount) public onlyPrimary {
120+
// The owner (GSNRecipientERC20Fee) can mint tokens
121+
function mint(address account, uint256 amount) public onlyOwner {
122122
_mint(account, amount);
123123
}
124124

125-
// The primary account has 'infinite' allowance for all token holders
126-
function allowance(address owner, address spender) public view override(ERC20, IERC20) returns (uint256) {
127-
if (spender == primary()) {
125+
// The owner has 'infinite' allowance for all token holders
126+
function allowance(address tokenOwner, address spender) public view override(ERC20, IERC20) returns (uint256) {
127+
if (spender == owner()) {
128128
return UINT256_MAX;
129129
} else {
130-
return super.allowance(owner, spender);
130+
return super.allowance(tokenOwner, spender);
131131
}
132132
}
133133

134-
// Allowance for the primary account cannot be changed (it is always 'infinite')
135-
function _approve(address owner, address spender, uint256 value) internal override {
136-
if (spender == primary()) {
134+
// Allowance for the owner cannot be changed (it is always 'infinite')
135+
function _approve(address tokenOwner, address spender, uint256 value) internal override {
136+
if (spender == owner()) {
137137
return;
138138
} else {
139-
super._approve(owner, spender, value);
139+
super._approve(tokenOwner, spender, value);
140140
}
141141
}
142142

143143
function transferFrom(address sender, address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
144-
if (recipient == primary()) {
144+
if (recipient == owner()) {
145145
_transfer(sender, recipient, amount);
146146
return true;
147147
} else {

contracts/ownership/Ownable.sol contracts/access/Ownable.sol

+4-8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import "../GSN/Context.sol";
66
* there is an account (an owner) that can be granted exclusive access to
77
* specific functions.
88
*
9+
* By default, the owner account will be the one that deploys the contract. This
10+
* can later be changed with {transferOwnership}.
11+
*
912
* This module is used through inheritance. It will make available the modifier
1013
* `onlyOwner`, which can be applied to your functions to restrict their use to
1114
* the owner.
@@ -35,17 +38,10 @@ contract Ownable is Context {
3538
* @dev Throws if called by any account other than the owner.
3639
*/
3740
modifier onlyOwner() {
38-
require(isOwner(), "Ownable: caller is not the owner");
41+
require(_owner == _msgSender(), "Ownable: caller is not the owner");
3942
_;
4043
}
4144

42-
/**
43-
* @dev Returns true if the caller is the current owner.
44-
*/
45-
function isOwner() public view returns (bool) {
46-
return _msgSender() == _owner;
47-
}
48-
4945
/**
5046
* @dev Leaves the contract without owner. It will not be possible to call
5147
* `onlyOwner` functions anymore. Can only be called by the current owner.

contracts/access/README.adoc

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
= Access
22

3-
NOTE: This page is incomplete. We're working to improve it for the next release. Stay tuned!
3+
Contract modules for authorization and access control mechanisms.
44

5-
== Library
5+
== Contracts
6+
7+
{{Ownable}}
68

79
{{Roles}}

contracts/drafts/TokenVesting.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pragma solidity ^0.6.0;
22

33
import "../token/ERC20/SafeERC20.sol";
4-
import "../ownership/Ownable.sol";
4+
import "../access/Ownable.sol";
55
import "../math/SafeMath.sol";
66

77
/**

contracts/mocks/OwnableInterfaceId.sol

-15
This file was deleted.

contracts/mocks/OwnableMock.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
pragma solidity ^0.6.0;
22

3-
import "../ownership/Ownable.sol";
3+
import "../access/Ownable.sol";
44

55
contract OwnableMock is Ownable { }

contracts/mocks/SecondaryMock.sol

-7
This file was deleted.

contracts/ownership/README.adoc

-11
This file was deleted.

contracts/ownership/Secondary.sol

-50
This file was deleted.

contracts/payment/escrow/Escrow.sol

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pragma solidity ^0.6.0;
22

33
import "../../math/SafeMath.sol";
4-
import "../../ownership/Secondary.sol";
4+
import "../../access/Ownable.sol";
55
import "../../utils/Address.sol";
66

77
/**
@@ -14,10 +14,10 @@ import "../../utils/Address.sol";
1414
* it. That way, it is guaranteed that all Ether will be handled according to
1515
* the `Escrow` rules, and there is no need to check for payable functions or
1616
* transfers in the inheritance tree. The contract that uses the escrow as its
17-
* payment method should be its primary, and provide public methods redirecting
17+
* payment method should be its owner, and provide public methods redirecting
1818
* to the escrow's deposit and withdraw.
1919
*/
20-
contract Escrow is Secondary {
20+
contract Escrow is Ownable {
2121
using SafeMath for uint256;
2222
using Address for address payable;
2323

@@ -34,7 +34,7 @@ contract Escrow is Secondary {
3434
* @dev Stores the sent amount as credit to be withdrawn.
3535
* @param payee The destination address of the funds.
3636
*/
37-
function deposit(address payee) public virtual payable onlyPrimary {
37+
function deposit(address payee) public virtual payable onlyOwner {
3838
uint256 amount = msg.value;
3939
_deposits[payee] = _deposits[payee].add(amount);
4040

@@ -52,7 +52,7 @@ contract Escrow is Secondary {
5252
*
5353
* @param payee The address whose funds will be withdrawn and transferred to.
5454
*/
55-
function withdraw(address payable payee) public virtual onlyPrimary {
55+
function withdraw(address payable payee) public virtual onlyOwner {
5656
uint256 payment = _deposits[payee];
5757

5858
_deposits[payee] = 0;
@@ -71,7 +71,7 @@ contract Escrow is Secondary {
7171
*
7272
* _Available since v2.4.0._
7373
*/
74-
function withdrawWithGas(address payable payee) public virtual onlyPrimary {
74+
function withdrawWithGas(address payable payee) public virtual onlyOwner {
7575
uint256 payment = _deposits[payee];
7676

7777
_deposits[payee] = 0;

contracts/payment/escrow/RefundEscrow.sol

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import "./ConditionalEscrow.sol";
77
* @dev Escrow that holds funds for a beneficiary, deposited from multiple
88
* parties.
99
* @dev Intended usage: See {Escrow}. Same usage guidelines apply here.
10-
* @dev The primary account (that is, the contract that instantiates this
10+
* @dev The owner account (that is, the contract that instantiates this
1111
* contract) may deposit, close the deposit period, and allow for either
1212
* withdrawal by the beneficiary, or refunds to the depositors. All interactions
13-
* with `RefundEscrow` will be made through the primary contract.
13+
* with `RefundEscrow` will be made through the owner contract.
1414
*/
1515
contract RefundEscrow is ConditionalEscrow {
1616
enum State { Active, Refunding, Closed }
@@ -58,7 +58,7 @@ contract RefundEscrow is ConditionalEscrow {
5858
* @dev Allows for the beneficiary to withdraw their funds, rejecting
5959
* further deposits.
6060
*/
61-
function close() public onlyPrimary virtual {
61+
function close() public onlyOwner virtual {
6262
require(_state == State.Active, "RefundEscrow: can only close while active");
6363
_state = State.Closed;
6464
emit RefundsClosed();
@@ -67,7 +67,7 @@ contract RefundEscrow is ConditionalEscrow {
6767
/**
6868
* @dev Allows for refunds to take place, rejecting further deposits.
6969
*/
70-
function enableRefunds() public onlyPrimary virtual {
70+
function enableRefunds() public onlyOwner virtual {
7171
require(_state == State.Active, "RefundEscrow: can only enable refunds while active");
7272
_state = State.Refunding;
7373
emit RefundsEnabled();

docs/modules/ROOT/pages/access-control.adoc

+5-12
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ Access control—that is, "who is allowed to do this thing"—is incredibly impo
77

88
The most common and basic form of access control is the concept of _ownership_: there's an account that is the `owner` of a contract and can do administrative tasks on it. This approach is perfectly reasonable for contracts that have a single administrative user.
99

10-
OpenZeppelin provides xref:api:ownership.adoc#Ownable[`Ownable`] for implementing ownership in your contracts.
10+
OpenZeppelin provides xref:api:access.adoc#Ownable[`Ownable`] for implementing ownership in your contracts.
1111

1212
[source,solidity]
1313
----
1414
pragma solidity ^0.5.0;
1515
16-
import "@openzeppelin/contracts/ownership/Ownable.sol";
16+
import "@openzeppelin/contracts/access/Ownable.sol";
1717
1818
contract MyContract is Ownable {
1919
function normalThing() public {
@@ -26,12 +26,12 @@ contract MyContract is Ownable {
2626
}
2727
----
2828

29-
By default, the xref:api:ownership.adoc#Ownable-owner--[`owner`] of an `Ownable` contract is the account that deployed it, which is usually exactly what you want.
29+
By default, the xref:api:access.adoc#Ownable-owner--[`owner`] of an `Ownable` contract is the account that deployed it, which is usually exactly what you want.
3030

3131
Ownable also lets you:
3232

33-
* xref:api:ownership.adoc#Ownable-transferOwnership-address-[`transferOwnership`] from the owner account to a new one, and
34-
* xref:api:ownership.adoc#Ownable-renounceOwnership--[`renounceOwnership`] for the owner to relinquish this administrative privilege, a common pattern after an initial stage with centralized administration is over.
33+
* xref:api:access.adoc#Ownable-transferOwnership-address-[`transferOwnership`] from the owner account to a new one, and
34+
* xref:api:access.adoc#Ownable-renounceOwnership--[`renounceOwnership`] for the owner to relinquish this administrative privilege, a common pattern after an initial stage with centralized administration is over.
3535

3636
WARNING: Removing the owner altogether will mean that administrative tasks that are protected by `onlyOwner` will no longer be callable!
3737

@@ -103,10 +103,3 @@ So clean! By splitting concerns this way, much more granular levels of permissio
103103
OpenZeppelin uses `Roles` extensively with predefined contracts that encode rules for each specific role. A few examples are: xref:api:token/ERC20.adoc#ERC20Mintable[`ERC20Mintable`] which uses the xref:api:access.adoc#MinterRole[`MinterRole`] to determine who can mint tokens, and xref:api:crowdsale.adoc#WhitelistCrowdsale[`WhitelistCrowdsale`] which uses both xref:api:access.adoc#WhitelistAdminRole[`WhitelistAdminRole`] and xref:api:access.adoc#WhitelistedRole[`WhitelistedRole`] to create a set of accounts that can purchase tokens.
104104

105105
This flexibility allows for interesting setups: for example, a xref:api:crowdsale.adoc#MintedCrowdsale[`MintedCrowdsale`] expects to be given the `MinterRole` of an `ERC20Mintable` in order to work, but the token contract could also extend xref:api:token/ERC20.adoc#ERC20Pausable[`ERC20Pausable`] and assign the xref:api:access.adoc#PauserRole[`PauserRole`] to a DAO that serves as a contingency mechanism in case a vulnerability is discovered in the contract code. Limiting what each component of a system is able to do is known as the https://en.wikipedia.org/wiki/Principle_of_least_privilege[principle of least privilege], and is a good security practice.
106-
107-
[[usage-in-openzeppelin]]
108-
== Usage in OpenZeppelin
109-
110-
You'll notice that none of the OpenZeppelin contracts use `Ownable`. `Roles` is a prefferred solution, because it provides the user of the library with enough flexibility to adapt the provided contracts to their needs.
111-
112-
There are some cases, however, where there's a direct relationship between contracts. For example, xref:api:crowdsale.adoc#RefundableCrowdsale[`RefundableCrowdsale`] deploys a xref:api:payment.adoc#RefundEscrow[`RefundEscrow`] on construction, to hold its funds. For those cases, we'll use xref:api:ownership.adoc#Secondary[`Secondary`] to create a _secondary_ contract that allows a _primary_ contract to manage it. You could also think of these as _auxiliary_ contracts.

0 commit comments

Comments
 (0)