Skip to content

Commit d725737

Browse files
committed
chore: update openzeppelin-contracts-upgradeable to release-v5.2
1 parent 07d9dd5 commit d725737

14 files changed

+135
-58
lines changed

.vscode/settings.json

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,29 @@
1010
"[solidity]": {
1111
"editor.defaultFormatter": "JuanBlanco.solidity",
1212
"editor.codeActionsOnSave": {
13-
"source.fixAll": "always"
13+
"source.fixAll": "always",
14+
"source.fixAll.solhint": "always"
15+
},
16+
"editor.formatOnSave": true,
17+
"editor.formatOnPaste": true
18+
},
19+
"solidity.solhintRules": {
20+
"extends": "solhint:recommended",
21+
"rules": {
22+
"compiler-version": ["error", "^0.8.0"],
23+
"func-visibility": ["error", { "ignoreConstructors": true }],
24+
"not-rely-on-time": "off",
25+
"no-empty-blocks": "warn",
26+
"max-line-length": ["warn", 145],
27+
"reason-string": ["warn", { "maxLength": 145 }],
28+
"state-visibility": "error",
29+
"var-name-mixedcase": "warn",
30+
"func-name-mixedcase": "warn",
31+
"private-vars-leading-underscore": ["warn", { "strict": false }],
32+
"ordering": "warn",
33+
"reentrancy": "error",
34+
"avoid-low-level-calls": "warn",
35+
"operator-whitespace": "off"
1436
}
1537
}
1638
}

chain/lib/openzeppelin-contracts

chain/src/facets/AccessControlFacet.sol

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ contract AccessControlFacet is AccessControlUpgradeable, IAccessControlFacet {
103103
}
104104

105105
/// @dev Override _grantRole to use diamond storage
106-
function _grantRole(bytes32 role, address account) internal virtual override {
106+
function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {
107107
Storage storage ds = StorageLib.get();
108108
if (!ds.roles[role][account]) {
109109
ds.roles[role][account] = true;
@@ -120,16 +120,20 @@ contract AccessControlFacet is AccessControlUpgradeable, IAccessControlFacet {
120120
emit RoleGranted(INVESTOR_ROLE, account, msg.sender);
121121
}
122122
}
123+
return true;
123124
}
125+
return false;
124126
}
125127

126128
/// @dev Override _revokeRole to use diamond storage
127-
function _revokeRole(bytes32 role, address account) internal virtual override {
129+
function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {
128130
Storage storage ds = StorageLib.get();
129131
if (ds.roles[role][account]) {
130132
ds.roles[role][account] = false;
131133
emit RoleRevoked(role, account, msg.sender);
134+
return true;
132135
}
136+
return false;
133137
}
134138

135139
/// @dev Override _setRoleAdmin to use diamond storage

chain/src/facets/StakeholderFacet.sol

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,9 @@ import {
1010
StakeholderPositions
1111
} from "@libraries/Structs.sol";
1212
import { AccessControl } from "@libraries/AccessControl.sol";
13+
import { IStakeholderFacet } from "@interfaces/IStakeholderFacet.sol";
1314

14-
contract StakeholderFacet {
15-
event StakeholderCreated(bytes16 indexed id);
16-
event StakeholderAddressLinked(bytes16 indexed stakeholder_id, address indexed wallet_address);
17-
18-
error StakeholderAlreadyExists(bytes16 stakeholder_id);
19-
error AddressAlreadyLinked(address wallet_address);
20-
15+
contract StakeholderFacet is IStakeholderFacet {
2116
/// @notice Create a new stakeholder
2217
/// @dev Only OPERATOR_ROLE can create stakeholders
2318
function createStakeholder(bytes16 _id) external {
@@ -56,6 +51,23 @@ contract StakeholderFacet {
5651

5752
emit StakeholderAddressLinked(stakeholder_id, wallet_address);
5853
}
54+
/// @notice Get stakeholder id for a given address
55+
56+
function getStakeholderId(address wallet_address, bool ensure_exists) external view returns (bytes16) {
57+
Storage storage ds = StorageLib.get();
58+
59+
// Check if address is linked to a stakeholder
60+
bytes16 stakeholder_id = ds.addressToStakeholderId[wallet_address];
61+
if (ensure_exists && stakeholder_id == bytes16(0)) {
62+
revert NoStakeholder();
63+
}
64+
return stakeholder_id;
65+
}
66+
67+
/// @notice Get stakeholder idx for a stakeholder id
68+
function getStakeholderIndex(bytes16 stakeholder_id) external view returns (uint256) {
69+
return StorageLib.get().stakeholderIndex[stakeholder_id];
70+
}
5971

6072
/// @notice Get all positions for a stakeholder
6173
/// @dev INVESTOR_ROLE can only view their own positions, OPERATOR_ROLE and above can view any

chain/src/facets/StakeholderNFTFacet.sol

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// SPDX-License-Identifier: MIT
22
pragma solidity ^0.8.0;
33

4-
import "openzeppelin-contracts/contracts/token/ERC721/ERC721.sol";
5-
import "openzeppelin-contracts/contracts/utils/Base64.sol";
4+
import { ERC721 } from "openzeppelin-contracts/contracts/token/ERC721/ERC721.sol";
5+
import { Base64 } from "openzeppelin-contracts/contracts/utils/Base64.sol";
66
import { StorageLib, Storage } from "@core/Storage.sol";
77
import {
88
StakeholderPositions,
@@ -14,14 +14,18 @@ import {
1414
import { ValidationLib } from "@libraries/ValidationLib.sol";
1515
import { StakeholderFacet } from "@facets/StakeholderFacet.sol";
1616
import { AccessControl } from "@libraries/AccessControl.sol";
17+
import { IStakeholderNFTFacet } from "@interfaces/IStakeholderNFTFacet.sol";
1718

18-
contract StakeholderNFTFacet is ERC721 {
19-
error NotStakeholder();
20-
error AlreadyMinted();
21-
error URIQueryForNonexistentToken();
22-
19+
contract StakeholderNFTFacet is ERC721, IStakeholderNFTFacet {
2320
constructor() ERC721("Stakeholder Position", "STKPOS") { }
2421

22+
// Internal function to check if a token exists by checking if the stakeholder ID exists
23+
function _exists(uint256 tokenId) internal view override returns (bool) {
24+
Storage storage ds = StorageLib.get();
25+
bytes16 stakeholderId = bytes16(uint128(tokenId));
26+
return ds.stakeholderIndex[stakeholderId] != 0;
27+
}
28+
2529
/// @notice Mint an NFT representing a stakeholder's position
2630
/// @dev Only stakeholders with INVESTOR_ROLE can mint their own NFT
2731
function mint() external {
@@ -45,12 +49,18 @@ contract StakeholderNFTFacet is ERC721 {
4549
revert AlreadyMinted();
4650
}
4751

48-
_mint(msg.sender, tokenId);
52+
_safeMint(msg.sender, tokenId);
4953
}
5054

5155
/// @notice Get the URI for a token, containing metadata about stakeholder positions
5256
/// @dev Only OPERATOR_ROLE or the token owner can view the token URI
53-
function tokenURI(uint256 tokenId) public view override returns (string memory) {
57+
function tokenURI(uint256 tokenId)
58+
public
59+
view
60+
virtual
61+
override(ERC721, IStakeholderNFTFacet)
62+
returns (string memory)
63+
{
5464
if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
5565

5666
// Allow operators and admins to view any token URI
@@ -71,7 +81,7 @@ contract StakeholderNFTFacet is ERC721 {
7181
bytes(
7282
abi.encodePacked(
7383
'{"name":"Stakeholder Position #',
74-
toString(tokenId),
84+
_toString(tokenId),
7585
'","description":"This NFT represents all active positions for this stakeholder.",',
7686
'"attributes":',
7787
_getAttributesJson(positions),
@@ -105,14 +115,15 @@ contract StakeholderNFTFacet is ERC721 {
105115
if (positions.length == 0) return '{"trait_type": "Stock Positions", "value": "0"}';
106116

107117
return
108-
string(abi.encodePacked('{"trait_type": "Stock Positions", "value": "', toString(positions.length), '"}'));
118+
string(abi.encodePacked('{"trait_type": "Stock Positions", "value": "', _toString(positions.length), '"}'));
109119
}
110120

111121
function _getWarrantPositionsJson(WarrantActivePosition[] memory positions) internal pure returns (string memory) {
112122
if (positions.length == 0) return '{"trait_type": "Warrant Positions", "value": "0"}';
113123

114-
return
115-
string(abi.encodePacked('{"trait_type": "Warrant Positions", "value": "', toString(positions.length), '"}'));
124+
return string(
125+
abi.encodePacked('{"trait_type": "Warrant Positions", "value": "', _toString(positions.length), '"}')
126+
);
116127
}
117128

118129
function _getConvertiblePositionsJson(ConvertibleActivePosition[] memory positions)
@@ -123,7 +134,7 @@ contract StakeholderNFTFacet is ERC721 {
123134
if (positions.length == 0) return '{"trait_type": "Convertible Positions", "value": "0"}';
124135

125136
return string(
126-
abi.encodePacked('{"trait_type": "Convertible Positions", "value": "', toString(positions.length), '"}')
137+
abi.encodePacked('{"trait_type": "Convertible Positions", "value": "', _toString(positions.length), '"}')
127138
);
128139
}
129140

@@ -136,12 +147,12 @@ contract StakeholderNFTFacet is ERC721 {
136147

137148
return string(
138149
abi.encodePacked(
139-
'{"trait_type": "Equity Compensation Positions", "value": "', toString(positions.length), '"}'
150+
'{"trait_type": "Equity Compensation Positions", "value": "', _toString(positions.length), '"}'
140151
)
141152
);
142153
}
143154

144-
function toString(uint256 value) internal pure returns (string memory) {
155+
function _toString(uint256 value) internal pure returns (string memory) {
145156
// Convert uint to string
146157
if (value == 0) {
147158
return "0";

chain/src/facets/StockClassFacet.sol

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,9 @@ import { StockClass } from "@libraries/Structs.sol";
66
import { TxHelper, TxType } from "@libraries/TxHelper.sol";
77
import { LibDiamond } from "diamond-3-hardhat/libraries/LibDiamond.sol";
88
import { AccessControl } from "@libraries/AccessControl.sol";
9+
import { IStockClassFacet } from "@interfaces/IStockClassFacet.sol";
910

10-
contract StockClassFacet {
11-
event StockClassCreated(
12-
bytes16 indexed id, string indexed classType, uint256 indexed pricePerShare, uint256 initialSharesAuthorized
13-
);
14-
event StockClassAuthorizedSharesAdjusted(bytes16 indexed stockClassId, uint256 newSharesAuthorized);
15-
16-
error StockClassAlreadyExists(bytes16 stock_class_id);
17-
error StockClassNotFound(bytes16 stock_class_id);
18-
error InvalidSharesAuthorized();
19-
11+
contract StockClassFacet is IStockClassFacet {
2012
/// @notice Create a new stock class
2113
/// @dev Only DEFAULT_ADMIN_ROLE can create stock classes
2214
function createStockClass(

chain/src/facets/StockFacet.sol

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,9 @@ import {
1414
import { TxHelper, TxType } from "@libraries/TxHelper.sol";
1515
import { ValidationLib } from "@libraries/ValidationLib.sol";
1616
import { AccessControl } from "@libraries/AccessControl.sol";
17+
import { IStockFacet } from "@interfaces/IStockFacet.sol";
1718

18-
contract StockFacet {
19-
/// @notice Issue new stock to a stakeholder
20-
/// @dev Only OPERATOR_ROLE can issue stock
21-
error InvalidSecurityId(bytes16 security_id);
22-
23-
/// @dev Add these custom errors at the contract level
24-
error NoPositionsToConsolidate();
25-
error StockClassMismatch(bytes16 expected, bytes16 actual);
26-
error ZeroQuantityPosition(bytes16 security_id);
27-
error InsufficientSharesForCancellation(bytes16 security_id, uint256 requested, uint256 available);
28-
error InvalidCancellationQuantity(bytes16 security_id, uint256 quantity);
29-
19+
contract StockFacet is IStockFacet {
3020
function issueStock(IssueStockParams calldata params) external {
3121
Storage storage ds = StorageLib.get();
3222

chain/src/interfaces/IAccessControlFacet.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ interface IAccessControlFacet is IAccessControl {
3232

3333
/// @notice Role definitions
3434
/// @return The OPERATOR_ROLE hash
35+
// solhint-disable func-name-mixedcase
3536
function OPERATOR_ROLE() external view returns (bytes32);
3637

3738
/// @notice Role definitions
3839
/// @return The INVESTOR_ROLE hash
40+
// solhint-disable func-name-mixedcase
3941
function INVESTOR_ROLE() external view returns (bytes32);
4042

4143
/// @notice Returns whether an account has a role

chain/src/interfaces/IStakeholderFacet.sol

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ interface IStakeholderFacet {
2222
/// @notice Thrown when attempting to link an address that's already linked
2323
error AddressAlreadyLinked(address wallet_address);
2424

25+
/// @notice Thrown when no stakeholder exists
26+
error NoStakeholder();
27+
2528
/// @notice Create a new stakeholder
2629
/// @dev Only OPERATOR_ROLE can create stakeholders
2730
/// @param _id The unique identifier for the stakeholder
@@ -33,6 +36,14 @@ interface IStakeholderFacet {
3336
/// @param wallet_address The address to link
3437
function linkStakeholderAddress(bytes16 stakeholder_id, address wallet_address) external;
3538

39+
/// @notice Get the stakeholder ID for a given address
40+
/// @param wallet_address The address to get the stakeholder ID for
41+
/// @param ensure_exists If true, will revert if the address is not linked to a stakeholder
42+
function getStakeholderId(address wallet_address, bool ensure_exists) external view returns (bytes16);
43+
44+
/// @notice Get stakeholder idx for a stakeholder id
45+
function getStakeholderIndex(bytes16 stakeholder_id) external view returns (uint256);
46+
3647
/// @notice Get all positions for a stakeholder
3748
/// @dev INVESTOR_ROLE can only view their own positions, OPERATOR_ROLE and above can view any
3849
/// @param stakeholder_id The stakeholder to get positions for

0 commit comments

Comments
 (0)