@bananapus/ownable-v6 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,67 @@
1
+ # IJBOwnable
2
+ [Git Source](https://github.com/Bananapus/nana-ownable/blob/a74b3181e75adaf0ee0c93cb00bcc5709ca8f314/src/interfaces/IJBOwnable.sol)
3
+
4
+
5
+ ## Functions
6
+ ### PROJECTS
7
+
8
+
9
+ ```solidity
10
+ function PROJECTS() external view returns (IJBProjects);
11
+ ```
12
+
13
+ ### jbOwner
14
+
15
+
16
+ ```solidity
17
+ function jbOwner() external view returns (address owner, uint88 projectOwner, uint8 permissionId);
18
+ ```
19
+
20
+ ### owner
21
+
22
+
23
+ ```solidity
24
+ function owner() external view returns (address);
25
+ ```
26
+
27
+ ### renounceOwnership
28
+
29
+
30
+ ```solidity
31
+ function renounceOwnership() external;
32
+ ```
33
+
34
+ ### setPermissionId
35
+
36
+
37
+ ```solidity
38
+ function setPermissionId(uint8 permissionId) external;
39
+ ```
40
+
41
+ ### transferOwnership
42
+
43
+
44
+ ```solidity
45
+ function transferOwnership(address newOwner) external;
46
+ ```
47
+
48
+ ### transferOwnershipToProject
49
+
50
+
51
+ ```solidity
52
+ function transferOwnershipToProject(uint256 projectId) external;
53
+ ```
54
+
55
+ ## Events
56
+ ### PermissionIdChanged
57
+
58
+ ```solidity
59
+ event PermissionIdChanged(uint8 newId, address caller);
60
+ ```
61
+
62
+ ### OwnershipTransferred
63
+
64
+ ```solidity
65
+ event OwnershipTransferred(address indexed previousOwner, address indexed newOwner, address caller);
66
+ ```
67
+
@@ -0,0 +1,4 @@
1
+
2
+
3
+ # Contents
4
+ - [IJBOwnable](IJBOwnable.sol/interface.IJBOwnable.md)
@@ -0,0 +1,23 @@
1
+ # JBOwner
2
+ [Git Source](https://github.com/Bananapus/nana-ownable/blob/a74b3181e75adaf0ee0c93cb00bcc5709ca8f314/src/struct/JBOwner.sol)
3
+
4
+ Owner information for a given instance of `JBOwnableOverrides`.
5
+
6
+ **Notes:**
7
+ - member: owner If `projectId` is 0, this address has owner access.
8
+
9
+ - member: projectId The owner of the `JBProjects` ERC-721 with this ID has owner access. If this is 0, the
10
+ `owner` address has owner access.
11
+
12
+ - member: permissionId The permission ID which corresponds to owner access. See `JBPermissions` in `nana-core`
13
+ and `nana-permission-ids`.
14
+
15
+
16
+ ```solidity
17
+ struct JBOwner {
18
+ address owner;
19
+ uint88 projectId;
20
+ uint8 permissionId;
21
+ }
22
+ ```
23
+
@@ -0,0 +1,4 @@
1
+
2
+
3
+ # Contents
4
+ - [JBOwner](JBOwner.sol/struct.JBOwner.md)
package/foundry.toml ADDED
@@ -0,0 +1,12 @@
1
+ [profile.default]
2
+ solc = '0.8.23'
3
+ evm_version = 'paris' # Required for L2s (Optimism, Arbitrum, etc.)
4
+ optimizer_runs = 1000000000
5
+
6
+ [fuzz]
7
+ runs = 4096
8
+
9
+ [fmt]
10
+ number_underscore = "thousands"
11
+ multiline_func_header = "all"
12
+ wrap_comments = true
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@bananapus/ownable-v6",
3
+ "version": "0.0.1",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/Bananapus/nana-ownable-v6"
8
+ },
9
+ "dependencies": {
10
+ "@bananapus/core-v6": "^0.0.1",
11
+ "@openzeppelin/contracts": "^5.0.2"
12
+ },
13
+ "scripts": {
14
+ "test": "forge test",
15
+ "coverage:integration": "forge coverage --match-path \"./src/*.sol\" --report lcov --report summary"
16
+ }
17
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "detectors_to_exclude": "timestamp,uninitialized-local,naming-convention,solc-version,shadowing-local",
3
+ "exclude_informational": true,
4
+ "exclude_low": false,
5
+ "exclude_medium": false,
6
+ "exclude_high": false,
7
+ "disable_color": false,
8
+ "filter_paths": "(mocks/|test/|node_modules/)",
9
+ "legacy_ast": false
10
+ }
@@ -0,0 +1,76 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Juicebox variation on OpenZeppelin Ownable
3
+ pragma solidity ^0.8.23;
4
+
5
+ import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
6
+ import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
7
+
8
+ import {JBOwnableOverrides} from "./JBOwnableOverrides.sol";
9
+
10
+ /// @notice A function restricted by `JBOwnable` can only be called by a Juicebox project's owner, a specified owner
11
+ /// address (if set), or addresses with permission from the owner.
12
+ /// @dev A function with the `onlyOwner` modifier from `JBOwnable` can only be called by addresses with owner access
13
+ /// based on a `JBOwner` struct:
14
+ /// 1. If `JBOwner.projectId` isn't zero, the address holding the `JBProjects` NFT with the `JBOwner.projectId` ID is
15
+ /// the owner.
16
+ /// 2. If `JBOwner.projectId` is set to `0`, the `JBOwner.owner` address is the owner.
17
+ /// 3. The owner can give other addresses access with `JBPermissions.setPermissionsFor(...)`, using the
18
+ /// `JBOwner.permissionId` permission.
19
+ /// @dev To use `onlyOwner`, inherit this contract and apply the modifier to a function.
20
+ contract JBOwnable is JBOwnableOverrides {
21
+ //*********************************************************************//
22
+ // -------------------------- constructor ---------------------------- //
23
+ //*********************************************************************//
24
+
25
+ /// @dev To make a Juicebox project's owner this contract's owner, pass that project's ID as the
26
+ /// `initialProjectIdOwner`.
27
+ /// @dev To make a specific address the owner, pass that address as the `initialOwner` and `0` as the
28
+ /// `initialProjectIdOwner`.
29
+ /// @dev The owner can give other addresses owner access through the `permissions` contract.
30
+ /// @param permissions A contract storing permissions.
31
+ /// @param projects Mints ERC-721s that represent project ownership and transfers.
32
+ /// @param initialOwner An address with owner access (until ownership is transferred).
33
+ /// @param initialProjectIdOwner The ID of the Juicebox project whose owner has owner access (until ownership is
34
+ /// transferred).
35
+ constructor(
36
+ IJBPermissions permissions,
37
+ IJBProjects projects,
38
+ address initialOwner,
39
+ uint88 initialProjectIdOwner
40
+ )
41
+ JBOwnableOverrides(permissions, projects, initialOwner, initialProjectIdOwner)
42
+ {}
43
+
44
+ //*********************************************************************//
45
+ // --------------------------- modifiers ----------------------------- //
46
+ //*********************************************************************//
47
+
48
+ /// @notice Reverts if called by an address without owner access.
49
+ modifier onlyOwner() virtual {
50
+ _checkOwner();
51
+ _;
52
+ }
53
+
54
+ //*********************************************************************//
55
+ // ------------------------ internal functions ----------------------- //
56
+ //*********************************************************************//
57
+
58
+ /// @notice Either `newOwner` or `newProjectId` is non-zero or both are zero. But they can never both be non-zero.
59
+ /// @dev This function exists because some contracts need to deploy contracts for a project before the project's NFT
60
+ /// has been minted, so the transfer event resolves the project's current owner at emission time.
61
+ function _emitTransferEvent(
62
+ address previousOwner,
63
+ address newOwner,
64
+ uint88 newProjectId
65
+ )
66
+ internal
67
+ virtual
68
+ override
69
+ {
70
+ emit OwnershipTransferred({
71
+ previousOwner: previousOwner,
72
+ newOwner: newProjectId == 0 ? newOwner : PROJECTS.ownerOf(newProjectId),
73
+ caller: msg.sender
74
+ });
75
+ }
76
+ }
@@ -0,0 +1,203 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Juicebox variation on OpenZeppelin Ownable
3
+ pragma solidity ^0.8.23;
4
+
5
+ import {JBPermissioned} from "@bananapus/core-v6/src/abstract/JBPermissioned.sol";
6
+ import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
7
+ import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
8
+ import {Context} from "@openzeppelin/contracts/utils/Context.sol";
9
+
10
+ import {IJBOwnable} from "./interfaces/IJBOwnable.sol";
11
+ import {JBOwner} from "./structs/JBOwner.sol";
12
+
13
+ /// @notice An abstract base for `JBOwnable`, which restricts functions so they can only be called by a Juicebox
14
+ /// project's owner or a specific owner address. The owner can give access permission to other addresses with
15
+ /// `JBPermissions`.
16
+ abstract contract JBOwnableOverrides is Context, JBPermissioned, IJBOwnable {
17
+ //*********************************************************************//
18
+ // --------------------------- custom errors --------------------------//
19
+ //*********************************************************************//
20
+
21
+ error JBOwnableOverrides_InvalidNewOwner();
22
+ error JBOwnableOverrides_ProjectDoesNotExist();
23
+
24
+ //*********************************************************************//
25
+ // ---------------- public immutable stored properties --------------- //
26
+ //*********************************************************************//
27
+
28
+ /// @notice Mints ERC-721s that represent project ownership and transfers.
29
+ IJBProjects public immutable override PROJECTS;
30
+
31
+ //*********************************************************************//
32
+ // --------------------- public stored properties -------------------- //
33
+ //*********************************************************************//
34
+
35
+ /// @notice This contract's owner information.
36
+ JBOwner public override jbOwner;
37
+
38
+ //*********************************************************************//
39
+ // -------------------------- constructor ---------------------------- //
40
+ //*********************************************************************//
41
+
42
+ /// @dev To restrict access to a Juicebox project's owner, pass that project's ID as the `initialProjectIdOwner` and
43
+ /// the zero address as the `initialOwner`.
44
+ /// To restrict access to a specific address, pass that address as the `initialOwner` and `0` as the
45
+ /// `initialProjectIdOwner`.
46
+ /// @dev The owner can give owner access to other addresses through the `permissions` contract.
47
+ /// @param permissions A contract storing permissions.
48
+ /// @param projects Mints ERC-721s that represent project ownership and transfers.
49
+ /// @param initialOwner The owner if the `initialProjectIdOwner` is 0 (until ownership is transferred).
50
+ /// @param initialProjectIdOwner The ID of the Juicebox project whose owner is this contract's owner (until
51
+ /// ownership is transferred).
52
+ constructor(
53
+ IJBPermissions permissions,
54
+ IJBProjects projects,
55
+ address initialOwner,
56
+ uint88 initialProjectIdOwner
57
+ )
58
+ JBPermissioned(permissions)
59
+ {
60
+ PROJECTS = projects;
61
+
62
+ // We force the inheriting contract to set an owner, as there is a low chance someone will use `JBOwnable` to
63
+ // create an unowned contract.
64
+ // It's more likely both were accidentally set to `0`. If you really want an unowned contract, set the owner to
65
+ // an address and call `renounceOwnership()` in the constructor body.
66
+ if (initialProjectIdOwner == 0 && initialOwner == address(0)) {
67
+ revert JBOwnableOverrides_InvalidNewOwner();
68
+ }
69
+
70
+ _transferOwnership(initialOwner, initialProjectIdOwner);
71
+ }
72
+
73
+ //*********************************************************************//
74
+ // -------------------------- public views --------------------------- //
75
+ //*********************************************************************//
76
+
77
+ /// @notice Returns the owner's address based on this contract's `JBOwner`.
78
+ function owner() public view virtual returns (address) {
79
+ JBOwner memory ownerInfo = jbOwner;
80
+
81
+ if (ownerInfo.projectId == 0) {
82
+ return ownerInfo.owner;
83
+ }
84
+
85
+ return PROJECTS.ownerOf(ownerInfo.projectId);
86
+ }
87
+
88
+ //*********************************************************************//
89
+ // -------------------------- internal views ------------------------- //
90
+ //*********************************************************************//
91
+
92
+ /// @notice Reverts if the sender is not the owner.
93
+ function _checkOwner() internal view virtual {
94
+ JBOwner memory ownerInfo = jbOwner;
95
+
96
+ _requirePermissionFrom({
97
+ account: ownerInfo.projectId == 0 ? ownerInfo.owner : PROJECTS.ownerOf(ownerInfo.projectId),
98
+ projectId: ownerInfo.projectId,
99
+ permissionId: ownerInfo.permissionId
100
+ });
101
+ }
102
+
103
+ //*********************************************************************//
104
+ // ---------------------- public transactions ------------------------ //
105
+ //*********************************************************************//
106
+
107
+ /// @notice Gives up ownership of this contract, making it impossible to call `onlyOwner` and `_checkOwner`
108
+ /// functions.
109
+ /// @dev This can only be called by the current owner.
110
+ function renounceOwnership() public virtual override {
111
+ _checkOwner();
112
+ _transferOwnership(address(0), 0);
113
+ }
114
+
115
+ /// @notice Sets the permission ID the owner can use to give other addresses owner access.
116
+ /// @dev This can only be called by the current owner.
117
+ /// @param permissionId The permission ID to use for `onlyOwner`.
118
+ function setPermissionId(uint8 permissionId) public virtual override {
119
+ _checkOwner();
120
+ _setPermissionId(permissionId);
121
+ }
122
+
123
+ /// @notice Transfers ownership of this contract to a new address (the `newOwner`). Can only be called by the
124
+ /// current owner.
125
+ /// @dev The `permissionId` is reset to 0 on transfer to prevent permission clashes for the new owner.
126
+ /// The new owner must explicitly call `setPermissionId()` to configure owner-level permission delegation.
127
+ /// @param newOwner The address to transfer ownership to.
128
+ function transferOwnership(address newOwner) public virtual override {
129
+ _checkOwner();
130
+ if (newOwner == address(0)) {
131
+ revert JBOwnableOverrides_InvalidNewOwner();
132
+ }
133
+
134
+ _transferOwnership(newOwner, 0);
135
+ }
136
+
137
+ /// @notice Transfer ownership of this contract to a new Juicebox project.
138
+ /// @dev The `permissionId` is reset to 0 on transfer to prevent permission clashes for the new project owner.
139
+ /// The new owner must explicitly call `setPermissionId()` to configure owner-level permission delegation.
140
+ /// @dev The `projectId` must fit within a `uint88`.
141
+ /// @param projectId The ID of the project to transfer ownership to.
142
+ function transferOwnershipToProject(uint256 projectId) public virtual override {
143
+ _checkOwner();
144
+ if (projectId == 0 || projectId > type(uint88).max) {
145
+ revert JBOwnableOverrides_InvalidNewOwner();
146
+ }
147
+
148
+ // Make sure the project exists to prevent permanent loss of contract control.
149
+ if (projectId > PROJECTS.count()) {
150
+ revert JBOwnableOverrides_ProjectDoesNotExist();
151
+ }
152
+
153
+ _transferOwnership(address(0), uint88(projectId));
154
+ }
155
+
156
+ //*********************************************************************//
157
+ // ------------------------ internal functions ----------------------- //
158
+ //*********************************************************************//
159
+
160
+ /// @notice Either `newOwner` or `newProjectId` is non-zero or both are zero. But they can never both be non-zero.
161
+ /// @dev This function exists because some contracts need to deploy contracts for a project before the project's NFT
162
+ /// has been minted, so the transfer event resolves the project's current owner at emission time.
163
+ /// @param previousOwner The address of the previous owner.
164
+ /// @param newOwner The address of the new owner (zero if transferring to a project).
165
+ /// @param newProjectId The ID of the new owning project (zero if transferring to an address).
166
+ function _emitTransferEvent(address previousOwner, address newOwner, uint88 newProjectId) internal virtual;
167
+
168
+ /// @notice Sets the permission ID the owner can use to give other addresses owner access.
169
+ /// @dev Internal function without access restriction.
170
+ /// @param permissionId The permission ID to use for `onlyOwner`.
171
+ function _setPermissionId(uint8 permissionId) internal virtual {
172
+ jbOwner.permissionId = permissionId;
173
+ emit PermissionIdChanged({newId: permissionId, caller: msg.sender});
174
+ }
175
+
176
+ /// @notice Helper to allow for drop-in replacement of OpenZeppelin `Ownable`.
177
+ /// @param newOwner The address that should receive ownership of this contract.
178
+ function _transferOwnership(address newOwner) internal virtual {
179
+ _transferOwnership(newOwner, 0);
180
+ }
181
+
182
+ /// @notice Transfers this contract's ownership to an address (`newOwner`) OR a Juicebox project (`projectId`).
183
+ /// @dev Updates this contract's `JBOwner` owner information and resets the `JBOwner.permissionId`.
184
+ /// @dev If both `newOwner` and `projectId` are set, this will revert.
185
+ /// @dev Internal function without access restriction.
186
+ /// @param newOwner The address that should become this contract's owner.
187
+ /// @param projectId The ID of the project whose owner should become this contract's owner.
188
+ function _transferOwnership(address newOwner, uint88 projectId) internal virtual {
189
+ // Can't set both a new owner and a new project ID.
190
+ if (projectId != 0 && newOwner != address(0)) {
191
+ revert JBOwnableOverrides_InvalidNewOwner();
192
+ }
193
+ // Load the owner information from storage.
194
+ JBOwner memory ownerInfo = jbOwner;
195
+ // Get the address of the old owner.
196
+ address oldOwner = ownerInfo.projectId == 0 ? ownerInfo.owner : PROJECTS.ownerOf(ownerInfo.projectId);
197
+ // Update the stored owner information to the new owner and reset the `permissionId`.
198
+ // This is to prevent permissions clashes for the new user/owner.
199
+ jbOwner = JBOwner({owner: newOwner, projectId: projectId, permissionId: 0});
200
+ // Emit a transfer event with the new owner's address.
201
+ _emitTransferEvent(oldOwner, newOwner, projectId);
202
+ }
203
+ }
@@ -0,0 +1,38 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
5
+
6
+ interface IJBOwnable {
7
+ event PermissionIdChanged(uint8 newId, address caller);
8
+ event OwnershipTransferred(address indexed previousOwner, address indexed newOwner, address caller);
9
+
10
+ /// @notice The contract that mints ERC-721s representing project ownership.
11
+ /// @return projects The `IJBProjects` contract.
12
+ function PROJECTS() external view returns (IJBProjects projects);
13
+
14
+ /// @notice This contract's owner information.
15
+ /// @return owner The owner address (used when `projectId` is 0).
16
+ /// @return projectId The ID of the Juicebox project whose owner is this contract's owner (0 if not project-owned).
17
+ /// @return permissionId The permission ID the owner can use to grant other addresses owner access.
18
+ function jbOwner() external view returns (address owner, uint88 projectId, uint8 permissionId);
19
+
20
+ /// @notice Returns the current owner's address.
21
+ /// @return owner The address of the current owner.
22
+ function owner() external view returns (address owner);
23
+
24
+ /// @notice Gives up ownership, making it impossible to call `onlyOwner` functions.
25
+ function renounceOwnership() external;
26
+
27
+ /// @notice Sets the permission ID the owner can use to give other addresses owner access.
28
+ /// @param permissionId The permission ID to use for `onlyOwner`.
29
+ function setPermissionId(uint8 permissionId) external;
30
+
31
+ /// @notice Transfers ownership of this contract to a new address.
32
+ /// @param newOwner The address to transfer ownership to.
33
+ function transferOwnership(address newOwner) external;
34
+
35
+ /// @notice Transfers ownership of this contract to a Juicebox project.
36
+ /// @param projectId The ID of the project to transfer ownership to.
37
+ function transferOwnershipToProject(uint256 projectId) external;
38
+ }
@@ -0,0 +1,14 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ /// @notice Owner information for a given instance of `JBOwnableOverrides`.
5
+ /// @custom:member owner If `projectId` is 0, this address has owner access.
6
+ /// @custom:member projectId The owner of the `JBProjects` ERC-721 with this ID has owner access. If this is 0, the
7
+ /// `owner` address has owner access.
8
+ /// @custom:member permissionId The permission ID which corresponds to owner access. See `JBPermissions` in `nana-core`
9
+ /// and `nana-permission-ids`.
10
+ struct JBOwner {
11
+ address owner;
12
+ uint88 projectId;
13
+ uint8 permissionId;
14
+ }