Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup of Ownership directory #2120

Merged
merged 11 commits into from
Mar 16, 2020
Merged
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

## 3.0.0 (unreleased)

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

## 2.5.0 (2020-02-04)
Expand Down
34 changes: 17 additions & 17 deletions contracts/GSN/GSNRecipientERC20Fee.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pragma solidity ^0.6.0;

import "./GSNRecipient.sol";
import "../math/SafeMath.sol";
import "../ownership/Secondary.sol";
import "../access/Ownable.sol";
import "../token/ERC20/SafeERC20.sol";
import "../token/ERC20/ERC20.sol";
import "../token/ERC20/ERC20Detailed.sol";
Expand All @@ -17,20 +17,20 @@ import "../token/ERC20/ERC20Detailed.sol";
* internal {_mint} function.
*/
contract GSNRecipientERC20Fee is GSNRecipient {
using SafeERC20 for __unstable__ERC20PrimaryAdmin;
using SafeERC20 for __unstable__ERC20Owned;
using SafeMath for uint256;

enum GSNRecipientERC20FeeErrorCodes {
INSUFFICIENT_BALANCE
}

__unstable__ERC20PrimaryAdmin private _token;
__unstable__ERC20Owned private _token;

/**
* @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.
*/
constructor(string memory name, string memory symbol) public {
_token = new __unstable__ERC20PrimaryAdmin(name, symbol, 18);
_token = new __unstable__ERC20Owned(name, symbol, 18);
}

/**
Expand Down Expand Up @@ -106,42 +106,42 @@ contract GSNRecipientERC20Fee is GSNRecipient {
}

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

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

// The primary account (GSNRecipientERC20Fee) can mint tokens
function mint(address account, uint256 amount) public onlyPrimary {
// The owner (GSNRecipientERC20Fee) can mint tokens
function mint(address account, uint256 amount) public onlyOwner {
_mint(account, amount);
}

// The primary account has 'infinite' allowance for all token holders
function allowance(address owner, address spender) public view override(ERC20, IERC20) returns (uint256) {
if (spender == primary()) {
// The owner has 'infinite' allowance for all token holders
function allowance(address tokenOwner, address spender) public view override(ERC20, IERC20) returns (uint256) {
if (spender == owner()) {
return UINT256_MAX;
} else {
return super.allowance(owner, spender);
return super.allowance(tokenOwner, spender);
}
}

// Allowance for the primary account cannot be changed (it is always 'infinite')
function _approve(address owner, address spender, uint256 value) internal override {
if (spender == primary()) {
// Allowance for the owner cannot be changed (it is always 'infinite')
function _approve(address tokenOwner, address spender, uint256 value) internal override {
if (spender == owner()) {
return;
} else {
super._approve(owner, spender, value);
super._approve(tokenOwner, spender, value);
}
}

function transferFrom(address sender, address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
if (recipient == primary()) {
if (recipient == owner()) {
_transfer(sender, recipient, amount);
return true;
} else {
Expand Down
12 changes: 4 additions & 8 deletions contracts/ownership/Ownable.sol → contracts/access/Ownable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import "../GSN/Context.sol";
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
Expand Down Expand Up @@ -35,17 +38,10 @@ contract Ownable is Context {
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(isOwner(), "Ownable: caller is not the owner");
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}

/**
* @dev Returns true if the caller is the current owner.
*/
function isOwner() public view returns (bool) {
return _msgSender() == _owner;
}

/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
Expand Down
6 changes: 4 additions & 2 deletions contracts/access/README.adoc
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
= Access

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

== Library
== Contracts

{{Ownable}}

{{Roles}}
2 changes: 1 addition & 1 deletion contracts/drafts/TokenVesting.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pragma solidity ^0.6.0;

import "../token/ERC20/SafeERC20.sol";
import "../ownership/Ownable.sol";
import "../access/Ownable.sol";
import "../math/SafeMath.sol";

/**
Expand Down
15 changes: 0 additions & 15 deletions contracts/mocks/OwnableInterfaceId.sol

This file was deleted.

2 changes: 1 addition & 1 deletion contracts/mocks/OwnableMock.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pragma solidity ^0.6.0;

import "../ownership/Ownable.sol";
import "../access/Ownable.sol";

contract OwnableMock is Ownable { }
7 changes: 0 additions & 7 deletions contracts/mocks/SecondaryMock.sol

This file was deleted.

11 changes: 0 additions & 11 deletions contracts/ownership/README.adoc

This file was deleted.

50 changes: 0 additions & 50 deletions contracts/ownership/Secondary.sol

This file was deleted.

12 changes: 6 additions & 6 deletions contracts/payment/escrow/Escrow.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pragma solidity ^0.6.0;

import "../../math/SafeMath.sol";
import "../../ownership/Secondary.sol";
import "../../access/Ownable.sol";
import "../../utils/Address.sol";

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

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

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

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

_deposits[payee] = 0;
Expand Down
8 changes: 4 additions & 4 deletions contracts/payment/escrow/RefundEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import "./ConditionalEscrow.sol";
* @dev Escrow that holds funds for a beneficiary, deposited from multiple
* parties.
* @dev Intended usage: See {Escrow}. Same usage guidelines apply here.
* @dev The primary account (that is, the contract that instantiates this
* @dev The owner account (that is, the contract that instantiates this
* contract) may deposit, close the deposit period, and allow for either
* withdrawal by the beneficiary, or refunds to the depositors. All interactions
* with `RefundEscrow` will be made through the primary contract.
* with `RefundEscrow` will be made through the owner contract.
*/
contract RefundEscrow is ConditionalEscrow {
enum State { Active, Refunding, Closed }
Expand Down Expand Up @@ -58,7 +58,7 @@ contract RefundEscrow is ConditionalEscrow {
* @dev Allows for the beneficiary to withdraw their funds, rejecting
* further deposits.
*/
function close() public onlyPrimary virtual {
function close() public onlyOwner virtual {
require(_state == State.Active, "RefundEscrow: can only close while active");
_state = State.Closed;
emit RefundsClosed();
Expand All @@ -67,7 +67,7 @@ contract RefundEscrow is ConditionalEscrow {
/**
* @dev Allows for refunds to take place, rejecting further deposits.
*/
function enableRefunds() public onlyPrimary virtual {
function enableRefunds() public onlyOwner virtual {
require(_state == State.Active, "RefundEscrow: can only enable refunds while active");
_state = State.Refunding;
emit RefundsEnabled();
Expand Down
17 changes: 5 additions & 12 deletions docs/modules/ROOT/pages/access-control.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ Access control—that is, "who is allowed to do this thing"—is incredibly impo

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.

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

[source,solidity]
----
pragma solidity ^0.5.0;

import "@openzeppelin/contracts/ownership/Ownable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyContract is Ownable {
function normalThing() public {
Expand All @@ -26,12 +26,12 @@ contract MyContract is Ownable {
}
----

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.
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.

Ownable also lets you:

* xref:api:ownership.adoc#Ownable-transferOwnership-address-[`transferOwnership`] from the owner account to a new one, and
* 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.
* xref:api:access.adoc#Ownable-transferOwnership-address-[`transferOwnership`] from the owner account to a new one, and
* 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.

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

Expand Down Expand Up @@ -103,10 +103,3 @@ So clean! By splitting concerns this way, much more granular levels of permissio
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.

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.

[[usage-in-openzeppelin]]
== Usage in OpenZeppelin

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.

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.
Loading