diff --git a/contracts/GovernanceToken/GovernanceToken.sol b/contracts/GovernanceToken/GovernanceToken.sol index 33a69ff..b6fe00e 100644 --- a/contracts/GovernanceToken/GovernanceToken.sol +++ b/contracts/GovernanceToken/GovernanceToken.sol @@ -4,9 +4,6 @@ pragma solidity 0.8.16; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import "./GovernanceTokenSnapshot.sol"; -import { Roles } from "../extensions/Roles.sol"; -import "../extensions/DAORoles.sol"; -import "../extensions/HasRole.sol"; /** * @title GovernanceToken @@ -16,7 +13,7 @@ import "../extensions/HasRole.sol"; * functionality for voting, minting, burning, wrapping/unwrapping, and settling tokens. Only authorized * roles (as defined in DAORoles contract) can call certain functions such as mint, burn, wrap, unwrap, and others. */ -contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { +contract GovernanceToken is Initializable, GovernanceTokenSnapshot { IShareholderRegistry internal _shareholderRegistry; event DepositStarted( @@ -37,21 +34,17 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { /** * @notice Initializes a new GovernanceToken instance with the provided roles, name, and symbol. * @dev Sets the roles, ERC20 name and symbol using provided args and calls the internal `_initialize` function. - * @param roles DAORoles instance that controls roles within the token contract. + * @param daoRegistry DAORegistry instance that controls roles within the token contract. * @param name string for the ERC20 token name of GovernanceToken. * @param symbol string for the ERC20 token symbol of GovernanceToken. */ function initialize( - DAORoles roles, + DAORegistry daoRegistry, string memory name, string memory symbol ) public initializer { - require( - address(roles) != address(0), - "GovernanceToken: 0x0 not allowed" - ); + _setDAORegistry(daoRegistry); _initialize(name, symbol); - _setRoles(roles); } /// @custom:oz-upgrades-unsafe-allow constructor @@ -71,39 +64,12 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { public virtual override - onlyRole(Roles.RESOLUTION_ROLE) + onlyResolutionManager returns (uint256) { return _snapshot(); } - /** - * @notice Set address of the Voting logic for the contract. - * @dev Can be called only by the operator role. - * @param voting IVoting instance that controls the voting logic. - */ - function setVoting( - IVoting voting - ) - external - virtual - onlyRole(Roles.OPERATOR_ROLE) - zeroCheck(address(voting)) - { - _setVoting(voting); - } - - /** - * @notice Set the shareholder registry contract address. - * @dev Can be called only by the operator role. - * @param shareholderRegistry IShareholderRegistry instance that maintains the shareholder data. - */ - function setShareholderRegistry( - IShareholderRegistry shareholderRegistry - ) external virtual onlyRole(Roles.OPERATOR_ROLE) { - _shareholderRegistry = shareholderRegistry; - } - /** * @notice Set the settlement period for token deposits. * @dev Can be called only by the operator role. @@ -111,42 +77,10 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { */ function setSettlementPeriod( uint256 settlementPeriod_ - ) external virtual onlyRole(Roles.OPERATOR_ROLE) { + ) external virtual onlyResolutionManager { settlementPeriod = settlementPeriod_; } - /** - * @notice Set the external token reference for wrapping into the GovernanceToken. - * @dev Can be called only by the operator role. - * @param tokenExternalAddress Address of the external token to wrap into GovernanceToken. - */ - function setTokenExternal( - address tokenExternalAddress - ) - external - virtual - onlyRole(Roles.OPERATOR_ROLE) - zeroCheck(tokenExternalAddress) - { - _setTokenExternal(tokenExternalAddress); - } - - /** - * @notice Set redemption controller. - * @dev Can be called only by the operator role. - * @param redemption IRedemptionController instance that controls token redemption. - */ - function setRedemptionController( - IRedemptionController redemption - ) - external - virtual - onlyRole(Roles.OPERATOR_ROLE) - zeroCheck(address(redemption)) - { - _setRedemptionController(redemption); - } - /** * @notice Mint new governance tokens for the given address. * @dev Can be called only by the resolution role. @@ -156,7 +90,7 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { function mint( address to, uint256 amount - ) public virtual onlyRole(Roles.RESOLUTION_ROLE) { + ) public virtual onlyResolutionManager { _mint(to, amount); if ( @@ -165,7 +99,7 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { to ) ) { - _redemptionController.afterMint(to, amount); + getRedemptionController().afterMint(to, amount); } } @@ -178,7 +112,7 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { function burn( address from, uint256 amount - ) public virtual onlyRole(Roles.MARKET_ROLE) { + ) public virtual onlyInternalMarket { _burn(from, amount); } @@ -191,7 +125,7 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { function wrap( address from, uint256 amount - ) public virtual onlyRole(Roles.MARKET_ROLE) { + ) public virtual onlyInternalMarket { _wrap(from, amount); } @@ -206,7 +140,7 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { address from, address to, uint256 amount - ) public virtual onlyRole(Roles.MARKET_ROLE) { + ) public virtual onlyInternalMarket { _unwrap(from, to, amount); } @@ -228,7 +162,7 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { function mintVesting( address to, uint256 amount - ) public virtual onlyRole(Roles.RESOLUTION_ROLE) { + ) public virtual onlyResolutionManager { _mintVesting(to, amount); } @@ -241,7 +175,7 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { function setVesting( address to, uint256 amount - ) public virtual onlyRole(Roles.OPERATOR_ROLE) { + ) public virtual onlyResolutionManager { _setVesting(to, amount); } @@ -259,7 +193,7 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { public virtual override(ERC20Upgradeable, IERC20Upgradeable) - onlyRole(Roles.MARKET_ROLE) + onlyInternalMarket returns (bool) { return super.transfer(to, amount); @@ -281,7 +215,7 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { public virtual override(ERC20Upgradeable, IERC20Upgradeable) - onlyRole(Roles.MARKET_ROLE) + onlyInternalMarket returns (bool) { return super.transferFrom(from, to, amount); @@ -303,7 +237,7 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { uint256 amount ) internal virtual override { super._afterTokenTransfer(from, to, amount); - _voting.afterTokenTransfer(from, to, amount); + getVoting().afterTokenTransfer(from, to, amount); // Invariants require( @@ -346,7 +280,7 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { */ function _wrap(address from, uint amount) internal virtual { require( - tokenExternal.transferFrom(from, address(this), amount), + getNeokingdomToken().transferFrom(from, address(this), amount), "GovernanceToken: transfer failed" ); require(amount > 0, "GovernanceToken: attempt to wrap 0 tokens"); diff --git a/contracts/GovernanceToken/GovernanceTokenBase.sol b/contracts/GovernanceToken/GovernanceTokenBase.sol index fe33fcc..ad6db68 100644 --- a/contracts/GovernanceToken/GovernanceTokenBase.sol +++ b/contracts/GovernanceToken/GovernanceTokenBase.sol @@ -5,16 +5,16 @@ import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import "../RedemptionController/IRedemptionController.sol"; import "../Voting/IVoting.sol"; import "../InternalMarket/InternalMarket.sol"; -import "../extensions/DAORoles.sol"; +import "../extensions/DAORegistryProxy.sol"; import "./IGovernanceToken.sol"; -abstract contract GovernanceTokenBase is ERC20Upgradeable, IGovernanceToken { +abstract contract GovernanceTokenBase is + ERC20Upgradeable, + IGovernanceToken, + DAORegistryProxy +{ event VestingSet(address to, uint256 amount); - IVoting internal _voting; - IRedemptionController internal _redemptionController; - INeokingdomToken public tokenExternal; - function _initialize( string memory name, string memory symbol @@ -26,21 +26,6 @@ abstract contract GovernanceTokenBase is ERC20Upgradeable, IGovernanceToken { // In theory they should be burned or added to a pool mapping(address => uint256) internal _vestingBalance; - // mapping(address => uint256) internal _unlockedBalance; - function _setVoting(IVoting voting) internal { - _voting = voting; - } - - function _setRedemptionController( - IRedemptionController redemptionController - ) internal virtual { - _redemptionController = redemptionController; - } - - function _setTokenExternal(address tokenExternalAddress) internal { - tokenExternal = INeokingdomToken(tokenExternalAddress); - } - function _beforeTokenTransfer( address from, address to, @@ -57,7 +42,7 @@ abstract contract GovernanceTokenBase is ERC20Upgradeable, IGovernanceToken { } function _mint(address to, uint256 amount) internal virtual override { - tokenExternal.mint(address(this), amount); + getNeokingdomToken().mint(address(this), amount); super._mint(to, amount); } @@ -69,14 +54,14 @@ abstract contract GovernanceTokenBase is ERC20Upgradeable, IGovernanceToken { function _unwrap(address from, address to, uint amount) internal virtual { require( - tokenExternal.transfer(to, amount), + getNeokingdomToken().transfer(to, amount), "GovernanceToken: transfer failed" ); super._burn(from, amount); } function _burn(address from, uint amount) internal virtual override { - tokenExternal.burn(amount); + getNeokingdomToken().burn(amount); super._burn(from, amount); } diff --git a/contracts/InternalMarket/InternalMarket.sol b/contracts/InternalMarket/InternalMarket.sol index 8ecff95..975c8f2 100644 --- a/contracts/InternalMarket/InternalMarket.sol +++ b/contracts/InternalMarket/InternalMarket.sol @@ -6,9 +6,6 @@ import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "../ShareholderRegistry/IShareholderRegistry.sol"; import "./InternalMarketBase.sol"; -import { Roles } from "../extensions/Roles.sol"; -import "../extensions/DAORoles.sol"; -import "../extensions/HasRole.sol"; import "./IDIAOracleV2.sol"; /** @@ -16,25 +13,16 @@ import "./IDIAOracleV2.sol"; * @dev A smart contract that handles trading of governance tokens between users, * allowing them to make an offer, match existing offers, deposit, withdraw, and redeem locked tokens. */ -contract InternalMarket is Initializable, HasRole, InternalMarketBase { +contract InternalMarket is Initializable, InternalMarketBase { IDIAOracleV2 internal _diaPriceOracle; /** * @dev Initializes the contract with the given roles and internal token. - * @param roles DAORoles instance containing custom access control roles. - * @param governanceToken Reference to governance token. + * @param daoRegistry DAORegistry instance containing custom access control roles. */ - function initialize( - DAORoles roles, - IGovernanceToken governanceToken - ) public initializer { - require( - address(roles) != address(0) && - address(governanceToken) != address(0), - "InternalMarket: 0x0 not allowed" - ); - _initialize(governanceToken, 7 days); - _setRoles(roles); + function initialize(DAORegistry daoRegistry) public initializer { + _setDAORegistry(daoRegistry); + _initialize(7 days); } /// @custom:oz-upgrades-unsafe-allow constructor @@ -51,8 +39,8 @@ contract InternalMarket is Initializable, HasRole, InternalMarketBase { */ function makeOffer(uint256 amount) public virtual { require( - _shareholderRegistry.isAtLeast( - _shareholderRegistry.CONTRIBUTOR_STATUS(), + getShareholderRegistry().isAtLeast( + getShareholderRegistry().CONTRIBUTOR_STATUS(), msg.sender ), "InternalMarket: only contributors can make offers" @@ -101,30 +89,6 @@ contract InternalMarket is Initializable, HasRole, InternalMarketBase { _redeem(_msgSender(), amount); } - /** - * @dev Set internal token reference. - * @param token The address of the internal governance token. - */ - function setTokenInternal( - IGovernanceToken token - ) public onlyRole(Roles.RESOLUTION_ROLE) zeroCheck(address(token)) { - _setTokenInternal(token); - } - - /** - * @dev Set shareholder registry reference. - * @param shareholderRegistry The address of the shareholder registry contract. - */ - function setShareholderRegistry( - IShareholderRegistry shareholderRegistry - ) - public - onlyRole(Roles.RESOLUTION_ROLE) - zeroCheck(address(shareholderRegistry)) - { - _setShareholderRegistry(shareholderRegistry); - } - /** * @dev Set the exchange pair and Oracle reference. * @param token The address of the ERC20 token to set as the exchange pair. @@ -135,7 +99,7 @@ contract InternalMarket is Initializable, HasRole, InternalMarketBase { IDIAOracleV2 oracle ) public - onlyRole(Roles.RESOLUTION_ROLE) + onlyResolutionManager zeroCheck(address(token)) zeroCheck(address(oracle)) { @@ -148,31 +112,15 @@ contract InternalMarket is Initializable, HasRole, InternalMarketBase { */ function setReserve( address reserve_ - ) public onlyRole(Roles.RESOLUTION_ROLE) zeroCheck(address(reserve_)) { + ) public onlyResolutionManager zeroCheck(address(reserve_)) { _setReserve(reserve_); } - /** - * @dev Set redemption controller address. - * @param redemptionController_ The address of the redemption controller. - */ - function setRedemptionController( - IRedemptionController redemptionController_ - ) - public - onlyRole(Roles.RESOLUTION_ROLE) - zeroCheck(address(redemptionController_)) - { - _setRedemptionController(redemptionController_); - } - /** * @dev Set offer duration. * @param duration The duration of the offer in seconds. */ - function setOfferDuration( - uint duration - ) public onlyRole(Roles.RESOLUTION_ROLE) { + function setOfferDuration(uint duration) public onlyResolutionManager { _setOfferDuration(duration); } } diff --git a/contracts/InternalMarket/InternalMarketBase.sol b/contracts/InternalMarket/InternalMarketBase.sol index c50d73d..7faaa2d 100644 --- a/contracts/InternalMarket/InternalMarketBase.sol +++ b/contracts/InternalMarket/InternalMarketBase.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; +import "../extensions/DAORegistryProxy.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "../ShareholderRegistry/IShareholderRegistry.sol"; import "../RedemptionController/IRedemptionController.sol"; @@ -8,7 +9,7 @@ import "./IDIAOracleV2.sol"; import "../NeokingdomToken/INeokingdomToken.sol"; import "../GovernanceToken/IGovernanceToken.sol"; -contract InternalMarketBase { +contract InternalMarketBase is DAORegistryProxy { event OfferCreated( uint128 id, address from, @@ -30,14 +31,10 @@ contract InternalMarketBase { mapping(uint128 => Offer) offer; } - IGovernanceToken public tokenInternal; - // Cannot use IERC20 here because it lacks `decimals` ERC20 public exchangeToken; - IRedemptionController public redemptionController; IDIAOracleV2 public priceOracle; - IShareholderRegistry internal _shareholderRegistry; address public reserve; uint256 public offerDuration; @@ -46,11 +43,7 @@ contract InternalMarketBase { mapping(address => uint256) internal _vaultContributors; - function _initialize( - IGovernanceToken _governanceToken, - uint256 _offerDuration - ) internal virtual { - tokenInternal = _governanceToken; + function _initialize(uint256 _offerDuration) internal virtual { offerDuration = _offerDuration; } @@ -62,16 +55,6 @@ contract InternalMarketBase { return offers.end++; } - function _setTokenInternal(IGovernanceToken token) internal virtual { - tokenInternal = token; - } - - function _setShareholderRegistry( - IShareholderRegistry shareholderRegistry - ) internal virtual { - _shareholderRegistry = shareholderRegistry; - } - function _setExchangePair( ERC20 token, IDIAOracleV2 oracle @@ -84,12 +67,6 @@ contract InternalMarketBase { reserve = reserve_; } - function _setRedemptionController( - IRedemptionController redemptionController_ - ) internal virtual { - redemptionController = redemptionController_; - } - function _setOfferDuration(uint duration) internal virtual { offerDuration = duration; } @@ -103,10 +80,10 @@ contract InternalMarketBase { emit OfferCreated(id, from, amount, expiredAt); require( - tokenInternal.transferFrom(from, address(this), amount), + getGovernanceToken().transferFrom(from, address(this), amount), "InternalMarketBase: transfer failed" ); - redemptionController.afterOffer(from, amount); + getRedemptionController().afterOffer(from, amount); } function _beforeWithdraw(address from, uint256 amount) internal virtual { @@ -179,7 +156,7 @@ contract InternalMarketBase { ) internal virtual { _beforeMatchOffer(from, to, amount); require( - tokenInternal.transfer(to, amount), + getGovernanceToken().transfer(to, amount), "InternalMarketBase: transfer failed" ); require( @@ -194,15 +171,15 @@ contract InternalMarketBase { uint256 amount ) internal virtual { if ( - _shareholderRegistry.isAtLeast( - _shareholderRegistry.CONTRIBUTOR_STATUS(), + getShareholderRegistry().isAtLeast( + getShareholderRegistry().CONTRIBUTOR_STATUS(), from ) ) { _beforeWithdraw(from, amount); - tokenInternal.unwrap(address(this), to, amount); + getGovernanceToken().unwrap(address(this), to, amount); } else { - tokenInternal.unwrap(from, to, amount); + getGovernanceToken().unwrap(from, to, amount); } emit Withdrawn(from, to, amount); @@ -210,21 +187,21 @@ contract InternalMarketBase { function _burn(address from, uint256 amount) internal virtual { assert( - _shareholderRegistry.isAtLeast( - _shareholderRegistry.CONTRIBUTOR_STATUS(), + getShareholderRegistry().isAtLeast( + getShareholderRegistry().CONTRIBUTOR_STATUS(), from ) ); _beforeWithdraw(from, amount); - tokenInternal.burn(address(this), amount); + getGovernanceToken().burn(address(this), amount); } function _deposit(address to, uint256 amount) internal virtual { - tokenInternal.wrap(to, amount); + getGovernanceToken().wrap(to, amount); } function _finalizeDeposit(address to) internal virtual { - tokenInternal.settleTokens(to); + getGovernanceToken().settleTokens(to); } function _redeem(address from, uint256 amount) internal virtual { @@ -233,7 +210,7 @@ contract InternalMarketBase { uint256 difference = amount - withdrawableBalance; // governanceToken is an address set by the operators of the DAO, hence trustworthy // slither-disable-start reentrancy-no-eth - tokenInternal.burn(from, difference); + getGovernanceToken().burn(from, difference); _burn(from, withdrawableBalance); // slither-disable-end reentrancy-no-eth } else { @@ -246,7 +223,7 @@ contract InternalMarketBase { exchangeToken.transferFrom(reserve, from, _convertToUSDC(amount)), "InternalMarketBase: transfer failed" ); - redemptionController.afterRedeem(from, amount); + getRedemptionController().afterRedeem(from, amount); } function _convertToUSDC( diff --git a/contracts/RedemptionController/RedemptionController.sol b/contracts/RedemptionController/RedemptionController.sol index 155c6cc..152d88a 100644 --- a/contracts/RedemptionController/RedemptionController.sol +++ b/contracts/RedemptionController/RedemptionController.sol @@ -3,9 +3,6 @@ pragma solidity 0.8.16; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "./RedemptionControllerBase.sol"; -import { Roles } from "../extensions/Roles.sol"; -import "../extensions/DAORoles.sol"; -import "../extensions/HasRole.sol"; /** * @title RedemptionController @@ -25,21 +22,13 @@ import "../extensions/HasRole.sol"; * redeemable. They can only be moved outside the vault (contributor or * secondary). */ -contract RedemptionController is - Initializable, - HasRole, - RedemptionControllerBase -{ +contract RedemptionController is Initializable, RedemptionControllerBase { /** * @dev Initializes the smart contract. - * @param roles The addresses of DAORoles for this contract. + * @param daoRegistry The addresses of DAORoles for this contract. */ - function initialize(DAORoles roles) public initializer { - require( - address(roles) != address(0), - "RedemptionController: 0x0 not allowed" - ); - _setRoles(roles); + function initialize(DAORegistry daoRegistry) public initializer { + _setDAORegistry(daoRegistry); _initialize(); } @@ -58,7 +47,7 @@ contract RedemptionController is function afterMint( address to, uint256 amount - ) external override onlyRole(Roles.TOKEN_MANAGER_ROLE) { + ) external override onlyGovernanceToken { _afterMint(to, amount); } @@ -71,7 +60,7 @@ contract RedemptionController is function afterOffer( address account, uint256 amount - ) external override onlyRole(Roles.TOKEN_MANAGER_ROLE) { + ) external override onlyInternalMarket { _afterOffer(account, amount); } @@ -84,7 +73,7 @@ contract RedemptionController is function afterRedeem( address account, uint256 amount - ) external override onlyRole(Roles.TOKEN_MANAGER_ROLE) { + ) external override onlyInternalMarket { _afterRedeem(account, amount); } } diff --git a/contracts/RedemptionController/RedemptionControllerBase.sol b/contracts/RedemptionController/RedemptionControllerBase.sol index 4d019b3..c68d0a2 100644 --- a/contracts/RedemptionController/RedemptionControllerBase.sol +++ b/contracts/RedemptionController/RedemptionControllerBase.sol @@ -2,10 +2,13 @@ pragma solidity 0.8.16; import "./IRedemptionController.sol"; -import "hardhat/console.sol"; +import "../extensions/DAORegistryProxy.sol"; // The contract tells how many tokens are redeemable by Contributors -abstract contract RedemptionControllerBase is IRedemptionController { +abstract contract RedemptionControllerBase is + IRedemptionController, + DAORegistryProxy +{ struct Redeemable { uint256 amount; uint256 mintTimestamp; diff --git a/contracts/ResolutionManager/ResolutionManager.sol b/contracts/ResolutionManager/ResolutionManager.sol index 0ef7e19..0453f57 100644 --- a/contracts/ResolutionManager/ResolutionManager.sol +++ b/contracts/ResolutionManager/ResolutionManager.sol @@ -1,50 +1,27 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; +import "../extensions/DAORegistryProxy.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -import { Roles } from "../extensions/Roles.sol"; import "./ResolutionManagerBase.sol"; -import "../extensions/DAORoles.sol"; -import "../extensions/HasRole.sol"; /** * @title ResolutionManager * @dev This contract manages the creation, approval, rejection, updating and * execution of resolutions. It also allows shareholders to vote on resolutions. */ -contract ResolutionManager is Initializable, ResolutionManagerBase, HasRole { +contract ResolutionManager is Initializable, ResolutionManagerBase { /** * @dev Initializes the contract with the required dependencies. - * @param roles The roles extension of the DAO. - * @param shareholderRegistry The registry of shareholders of the DAO. - * @param governanceToken The governance token of the DAO. - * @param voting The voting extension of the DAO. + * @param daoRegistry The roles extension of the DAO. */ - function initialize( - DAORoles roles, - IShareholderRegistry shareholderRegistry, - IGovernanceToken governanceToken, - IVoting voting - ) public initializer { - require( - address(roles) != address(0) && - address(shareholderRegistry) != address(0) && - address(governanceToken) != address(0) && - address(voting) != address(0), - "ResolutionManager: 0x0 not allowed" - ); - _setRoles(roles); - _initialize(shareholderRegistry, governanceToken, voting); + function initialize(DAORegistry daoRegistry) public initializer { + _setDAORegistry(daoRegistry); } /// @custom:oz-upgrades-unsafe-allow constructor constructor() initializer {} - modifier zeroCheck(address address_) { - require(address_ != address(0), "ResolutionManager: 0x0 not allowed"); - _; - } - /** * @dev Adds a new resolution type. * @param name The name of the new resolution type. @@ -59,7 +36,7 @@ contract ResolutionManager is Initializable, ResolutionManagerBase, HasRole { uint256 noticePeriod, uint256 votingPeriod, bool canBeNegative - ) public virtual onlyRole(Roles.RESOLUTION_ROLE) { + ) public virtual onlyResolutionManager { _addResolutionType( name, quorum, @@ -69,51 +46,6 @@ contract ResolutionManager is Initializable, ResolutionManagerBase, HasRole { ); } - /** - * @dev Sets the shareholder registry. - * @param shareholderRegistry The new shareholder registry. - */ - function setShareholderRegistry( - IShareholderRegistry shareholderRegistry - ) - external - virtual - onlyRole(Roles.OPERATOR_ROLE) - zeroCheck(address(shareholderRegistry)) - { - _setShareholderRegistry(shareholderRegistry); - } - - /** - * @dev Sets the governance token. - * @param governanceToken The new governance token. - */ - function setGovernanceToken( - IGovernanceToken governanceToken - ) - external - virtual - onlyRole(Roles.OPERATOR_ROLE) - zeroCheck(address(governanceToken)) - { - _setGovernanceToken(governanceToken); - } - - /** - * @dev Sets the voting extension. - * @param voting The new voting extension. - */ - function setVoting( - IVoting voting - ) - external - virtual - onlyRole(Roles.OPERATOR_ROLE) - zeroCheck(address(voting)) - { - _setVoting(voting); - } - /** * @dev Creates a new resolution. * @param dataURI The data URI of the resolution. diff --git a/contracts/ResolutionManager/ResolutionManagerBase.sol b/contracts/ResolutionManager/ResolutionManagerBase.sol index 819e139..5449f69 100644 --- a/contracts/ResolutionManager/ResolutionManagerBase.sol +++ b/contracts/ResolutionManager/ResolutionManagerBase.sol @@ -1,11 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import "../ShareholderRegistry/IShareholderRegistry.sol"; -import "../GovernanceToken/IGovernanceToken.sol"; -import "../Voting/IVoting.sol"; +import "../extensions/DAORegistryProxy.sol"; -abstract contract ResolutionManagerBase { +contract ResolutionManagerBase is DAORegistryProxy { event ResolutionCreated(address indexed from, uint256 indexed resolutionId); event ResolutionUpdated(address indexed from, uint256 indexed resolutionId); @@ -71,23 +69,11 @@ abstract contract ResolutionManagerBase { uint256 internal _currentResolutionId; - IShareholderRegistry internal _shareholderRegistry; - IGovernanceToken internal _governanceToken; - IVoting internal _voting; - ResolutionType[] public resolutionTypes; mapping(uint256 => Resolution) public resolutions; - function _initialize( - IShareholderRegistry shareholderRegistry, - IGovernanceToken governanceToken, - IVoting voting - ) internal { - _shareholderRegistry = shareholderRegistry; - _governanceToken = governanceToken; - _voting = voting; - + function _initialize() internal { // TODO: check if there are any rounding errors _addResolutionType("amendment", 66, 14 days, 6 days, false); _addResolutionType("capitalChange", 66, 14 days, 6 days, false); @@ -124,27 +110,11 @@ abstract contract ResolutionManagerBase { _; } - function _setShareholderRegistry( - IShareholderRegistry shareholderRegistry - ) internal virtual { - _shareholderRegistry = shareholderRegistry; - } - - function _setGovernanceToken( - IGovernanceToken governanceToken - ) internal virtual { - _governanceToken = governanceToken; - } - - function _setVoting(IVoting voting) internal virtual { - _voting = voting; - } - function _snapshotAll() internal virtual returns (uint256) { - uint256 snapshotId = _shareholderRegistry.snapshot(); + uint256 snapshotId = getShareholderRegistry().snapshot(); require( - _governanceToken.snapshot() == snapshotId && - _voting.snapshot() == snapshotId, + getGovernanceToken().snapshot() == snapshotId && + getVoting().snapshot() == snapshotId, "ResolutionManager: snapshot ids are inconsistent" ); @@ -163,8 +133,8 @@ abstract contract ResolutionManagerBase { resolutionTypeId ]; require( - _shareholderRegistry.isAtLeast( - _shareholderRegistry.CONTRIBUTOR_STATUS(), + getShareholderRegistry().isAtLeast( + getShareholderRegistry().CONTRIBUTOR_STATUS(), msg.sender ), "Resolution: only contributor can create" @@ -197,8 +167,8 @@ abstract contract ResolutionManagerBase { ) internal virtual onlyPending(resolutionId) exists(resolutionId) { emit ResolutionApproved(msg.sender, resolutionId); require( - _shareholderRegistry.isAtLeast( - _shareholderRegistry.MANAGING_BOARD_STATUS(), + getShareholderRegistry().isAtLeast( + getShareholderRegistry().MANAGING_BOARD_STATUS(), msg.sender ), "Resolution: only managing board can approve" @@ -217,13 +187,13 @@ abstract contract ResolutionManagerBase { bytes32 originalStatus; if (addressedContributor != address(0)) { - originalDelegate = _voting.getDelegate(addressedContributor); - originalStatus = _shareholderRegistry.getStatus( + originalDelegate = getVoting().getDelegate(addressedContributor); + originalStatus = getShareholderRegistry().getStatus( addressedContributor ); // Downgrading to investor removes delegation - _shareholderRegistry.setStatus( - _shareholderRegistry.INVESTOR_STATUS(), + getShareholderRegistry().setStatus( + getShareholderRegistry().INVESTOR_STATUS(), addressedContributor ); } @@ -231,12 +201,15 @@ abstract contract ResolutionManagerBase { resolution.snapshotId = _snapshotAll(); if (addressedContributor != address(0)) { - _shareholderRegistry.setStatus( + getShareholderRegistry().setStatus( originalStatus, addressedContributor ); if (addressedContributor != originalDelegate) { - _voting.delegateFrom(addressedContributor, originalDelegate); + getVoting().delegateFrom( + addressedContributor, + originalDelegate + ); } } } @@ -247,8 +220,8 @@ abstract contract ResolutionManagerBase { emit ResolutionRejected(msg.sender, resolutionId); require( - _shareholderRegistry.isAtLeast( - _shareholderRegistry.MANAGING_BOARD_STATUS(), + getShareholderRegistry().isAtLeast( + getShareholderRegistry().MANAGING_BOARD_STATUS(), msg.sender ), "Resolution: only managing board can reject" @@ -276,8 +249,8 @@ abstract contract ResolutionManagerBase { ); require( - _shareholderRegistry.isAtLeast( - _shareholderRegistry.MANAGING_BOARD_STATUS(), + getShareholderRegistry().isAtLeast( + getShareholderRegistry().MANAGING_BOARD_STATUS(), msg.sender ), "Resolution: only managing board can update" @@ -342,7 +315,7 @@ abstract contract ResolutionManagerBase { ); require( - _voting.canVoteAt(msg.sender, resolution.snapshotId), + getVoting().canVoteAt(msg.sender, resolution.snapshotId), "Resolution: account cannot vote" ); @@ -359,11 +332,11 @@ abstract contract ResolutionManagerBase { "Resolution: not votable" ); - uint256 votingPower = _voting.getVotingPowerAt( + uint256 votingPower = getVoting().getVotingPowerAt( msg.sender, resolution.snapshotId ); - address delegate = _voting.getDelegateAt( + address delegate = getVoting().getDelegateAt( msg.sender, resolution.snapshotId ); @@ -371,11 +344,11 @@ abstract contract ResolutionManagerBase { // If sender has a delegate, load voting power from GovernanceToken if (delegate != msg.sender) { votingPower = - _governanceToken.balanceOfAt( + getGovernanceToken().balanceOfAt( msg.sender, resolution.snapshotId ) + - _shareholderRegistry.balanceOfAt( + getShareholderRegistry().balanceOfAt( msg.sender, resolution.snapshotId ); @@ -466,7 +439,7 @@ abstract contract ResolutionManagerBase { Resolution storage resolution = resolutions[resolutionId]; require( voter != resolution.addressedContributor && - _voting.canVoteAt(voter, resolution.snapshotId), + getVoting().canVoteAt(voter, resolution.snapshotId), "Resolution: account cannot vote" ); @@ -474,15 +447,18 @@ abstract contract ResolutionManagerBase { hasVoted = resolution.hasVoted[voter]; if ( - _voting.getDelegateAt(voter, resolution.snapshotId) != voter && + getVoting().getDelegateAt(voter, resolution.snapshotId) != voter && hasVoted ) { votingPower = - _governanceToken.balanceOfAt(voter, resolution.snapshotId) + - _shareholderRegistry.balanceOfAt(voter, resolution.snapshotId); + getGovernanceToken().balanceOfAt(voter, resolution.snapshotId) + + getShareholderRegistry().balanceOfAt( + voter, + resolution.snapshotId + ); } else { votingPower = - _voting.getVotingPowerAt(voter, resolution.snapshotId) - + getVoting().getVotingPowerAt(voter, resolution.snapshotId) - resolution.lostVotingPower[voter]; } } @@ -494,7 +470,7 @@ abstract contract ResolutionManagerBase { ResolutionType storage resolutionType = resolutionTypes[ resolution.resolutionTypeId ]; - uint256 totalVotingPower = _voting.getTotalVotingPowerAt( + uint256 totalVotingPower = getVoting().getTotalVotingPowerAt( resolution.snapshotId ); diff --git a/contracts/ShareholderRegistry/ShareholderRegistry.sol b/contracts/ShareholderRegistry/ShareholderRegistry.sol index 42265d2..9831853 100644 --- a/contracts/ShareholderRegistry/ShareholderRegistry.sol +++ b/contracts/ShareholderRegistry/ShareholderRegistry.sol @@ -3,37 +3,25 @@ pragma solidity 0.8.16; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "./ShareholderRegistrySnapshot.sol"; -import { Roles } from "../extensions/Roles.sol"; -import "../extensions/DAORoles.sol"; -import "../extensions/HasRole.sol"; /** * @title ShareholderRegistry * @notice ShareholderRegistry provides an implementation of a registry system for * a) holding and distributing shares; and b) set the status of the holders. */ -contract ShareholderRegistry is - Initializable, - ShareholderRegistrySnapshot, - HasRole -{ +contract ShareholderRegistry is Initializable, ShareholderRegistrySnapshot { /** * @notice Initializes the ShareholderRegistry contract with the given token name, symbol, and DAO roles. - * @param roles DAORoles struct containing DAO-specific roles. + * @param daoRegistry DAORegistry struct containing DAO-specific roles. * @param name string value representing the name of the token. * @param symbol string value representing the symbol of the token. */ function initialize( - DAORoles roles, + DAORegistry daoRegistry, string memory name, string memory symbol ) public initializer { - require( - address(roles) != address(0), - "ShareholderRegistry: 0x0 not allowed" - ); - _initialize(name, symbol); - _setRoles(roles); + _initialize(daoRegistry, name, symbol); } /// @custom:oz-upgrades-unsafe-allow constructor @@ -72,22 +60,6 @@ contract ShareholderRegistry is _setStatus(status, account); } - /** - * @notice Sets the voting implementation for the registry. - * @dev Requires the sender to have the OPERATOR_ROLE. - * @param voting contract instance to set as the current voting contract. - */ - function setVoting( - IVoting voting - ) - external - virtual - onlyRole(Roles.OPERATOR_ROLE) - zeroCheck(address(voting)) - { - _setVoting(voting); - } - /** * @notice Mints new shares and assigns them to the specified shareholder address. * @dev Requires the sender to have the RESOLUTION_ROLE. diff --git a/contracts/ShareholderRegistry/ShareholderRegistryBase.sol b/contracts/ShareholderRegistry/ShareholderRegistryBase.sol index 9df6737..4254178 100644 --- a/contracts/ShareholderRegistry/ShareholderRegistryBase.sol +++ b/contracts/ShareholderRegistry/ShareholderRegistryBase.sol @@ -1,18 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; +import "../extensions/DAORegistryProxy.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "../Voting/IVoting.sol"; -contract ShareholderRegistryBase is ERC20Upgradeable { +contract ShareholderRegistryBase is ERC20Upgradeable, DAORegistryProxy { bytes32 public SHAREHOLDER_STATUS; bytes32 public INVESTOR_STATUS; bytes32 public CONTRIBUTOR_STATUS; bytes32 public MANAGING_BOARD_STATUS; - IVoting internal _voting; - event StatusChanged( address indexed account, bytes32 previous, @@ -22,9 +21,11 @@ contract ShareholderRegistryBase is ERC20Upgradeable { mapping(address => bytes32) internal _statuses; function _initialize( + DAORegistry daoRegistry, string memory name, string memory symbol ) internal virtual { + _setDAORegistry(daoRegistry); __ERC20_init(name, symbol); SHAREHOLDER_STATUS = keccak256("SHAREHOLDER_STATUS"); INVESTOR_STATUS = keccak256("INVESTOR_STATUS"); @@ -32,10 +33,6 @@ contract ShareholderRegistryBase is ERC20Upgradeable { MANAGING_BOARD_STATUS = keccak256("MANAGING_BOARD_STATUS"); } - function _setVoting(IVoting voting) internal virtual { - _voting = voting; - } - function _setStatus(bytes32 status, address account) internal virtual { require( !Address.isContract(account), @@ -104,7 +101,7 @@ contract ShareholderRegistryBase is ERC20Upgradeable { _isAtLeast(1, statusBefore, CONTRIBUTOR_STATUS) && !_isAtLeast(1, statusAfter, CONTRIBUTOR_STATUS) ) { - _voting.beforeRemoveContributor(account); + getVoting().beforeRemoveContributor(account); } } @@ -117,7 +114,7 @@ contract ShareholderRegistryBase is ERC20Upgradeable { !_isAtLeast(1, statusBefore, CONTRIBUTOR_STATUS) && _isAtLeast(1, statusAfter, CONTRIBUTOR_STATUS) ) { - _voting.afterAddContributor(account); + getVoting().afterAddContributor(account); } } @@ -142,6 +139,6 @@ contract ShareholderRegistryBase is ERC20Upgradeable { if (balanceOf(from) == 0) { _setStatus(0, from); } - _voting.afterTokenTransfer(from, to, amount); + getVoting().afterTokenTransfer(from, to, amount); } } diff --git a/contracts/extensions/DAORegistry.sol b/contracts/extensions/DAORegistry.sol new file mode 100644 index 0000000..cacb736 --- /dev/null +++ b/contracts/extensions/DAORegistry.sol @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.16; + +import "@openzeppelin/contracts/access/AccessControl.sol"; +import "../NeokingdomToken/INeokingdomToken.sol"; +import "../GovernanceToken/IGovernanceToken.sol"; +import "../ShareholderRegistry/IShareholderRegistry.sol"; +import "../Voting/IVoting.sol"; +import "../RedemptionController/IRedemptionController.sol"; +import "../ResolutionManager/ResolutionManager.sol"; +import "../InternalMarket/InternalMarket.sol"; + +contract DAORegistry is AccessControl { + INeokingdomToken internal _neokingdomToken; + IGovernanceToken internal _governanceToken; + IShareholderRegistry internal _shareholderRegistry; + IVoting internal _voting; + IRedemptionController internal _redemptionController; + ResolutionManager internal _resolutionManager; + InternalMarket internal _internalMarket; + + constructor() { + _grantRole(DEFAULT_ADMIN_ROLE, _msgSender()); + } + + /* + function initialize() { + + } + */ + + function setNeokingdomToken( + INeokingdomToken neokingdomToken + ) public onlyRole(Roles.OPERATOR_ROLE) { + _neokingdomToken = neokingdomToken; + } + + function getNeokingdomToken() public view returns (INeokingdomToken) { + return _neokingdomToken; + } + + function requireMsgSenderToBeNeokingdomToken() public view { + address account = _msgSender(); + require( + account == address(_neokingdomToken), + "DAORoles: sender is not NeokingdomToken" + ); + } + + function setGovernanceToken( + IGovernanceToken governanceToken + ) public onlyRole(Roles.OPERATOR_ROLE) { + _governanceToken = governanceToken; + } + + function getGovernanceToken() public view returns (IGovernanceToken) { + return _governanceToken; + } + + function requireMsgSenderToBeGovernanceToken() public view { + address account = _msgSender(); + require( + account == address(_governanceToken), + "DAORoles: sender is not GovernanceToken" + ); + } + + function setShareholderRegistry( + IShareholderRegistry shareholderRegistry + ) public onlyRole(Roles.OPERATOR_ROLE) { + _shareholderRegistry = shareholderRegistry; + } + + function getShareholderRegistry() + public + view + returns (IShareholderRegistry) + { + return _shareholderRegistry; + } + + function requireMsgSenderToBeShareholderRegistry() public view { + address account = _msgSender(); + require( + account == address(_shareholderRegistry), + "DAORoles: sender is not ShareholderRegistry" + ); + } + + function setVoting(IVoting voting) public onlyRole(Roles.OPERATOR_ROLE) { + _voting = voting; + } + + function getVoting() public view returns (IVoting) { + return _voting; + } + + function requireMsgSenderToBeVoting() public view { + address account = _msgSender(); + require(account == address(_voting), "DAORoles: sender is not Voting"); + } + + function setRedemptionController( + IRedemptionController redemptionController + ) public onlyRole(Roles.OPERATOR_ROLE) { + _redemptionController = redemptionController; + } + + function getRedemptionController() + public + view + returns (IRedemptionController) + { + return _redemptionController; + } + + function requireMsgSenderToBeRedemptionController() public view { + address account = _msgSender(); + require( + account == address(_redemptionController), + "DAORoles: sender is not RedemptionController" + ); + } + + function setResolutionManager( + ResolutionManager resolutionManager + ) public onlyRole(Roles.OPERATOR_ROLE) { + _resolutionManager = resolutionManager; + } + + function getResolutionManager() public view returns (ResolutionManager) { + return _resolutionManager; + } + + function requireMsgSenderToBeResolutionManager() public view { + address account = _msgSender(); + require( + account == address(_resolutionManager), + "DAORoles: sender is not ResolutionManager" + ); + } + + function setInternalMarket( + InternalMarket internalMarket + ) public onlyRole(Roles.OPERATOR_ROLE) { + _internalMarket = internalMarket; + } + + function getInternalMarket() public view returns (InternalMarket) { + return _internalMarket; + } + + function requireMsgSenderToBeInternalMarket() public view { + address account = _msgSender(); + require( + account == address(_internalMarket), + "DAORoles: sender is not InternalMarket" + ); + } +} diff --git a/contracts/extensions/DAORegistryProxy.sol b/contracts/extensions/DAORegistryProxy.sol new file mode 100644 index 0000000..da089f1 --- /dev/null +++ b/contracts/extensions/DAORegistryProxy.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.16; + +import "./DAORegistry.sol"; +import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; + +contract DAORegistryProxy is ContextUpgradeable { + DAORegistry internal _daoRegistry; + + function _setDAORegistry(DAORegistry daoRegistry) internal { + require( + address(daoRegistry) != address(0), + "DAORegistryProxy: 0x0 not allowed" + ); + _daoRegistry = daoRegistry; + } + + function getDAORegistry() public view returns (DAORegistry) { + return _daoRegistry; + } + + // Neokingdom Token contract + + function getNeokingdomToken() public view returns (INeokingdomToken) { + return _daoRegistry.getNeokingdomToken(); + } + + modifier onlyNeokingdomToken() { + _daoRegistry.requireMsgSenderToBeNeokingdomToken(); + _; + } + + // Governance Token contract + + function getGovernanceToken() public view returns (IGovernanceToken) { + return _daoRegistry.getGovernanceToken(); + } + + modifier onlyGovernanceToken() { + _daoRegistry.requireMsgSenderToBeGovernanceToken(); + _; + } + + // Shareholders' Registry contract + + function getShareholderRegistry() + public + view + returns (IShareholderRegistry) + { + return _daoRegistry.getShareholderRegistry(); + } + + modifier onlyShareholderRegistry() { + _daoRegistry.requireMsgSenderToBeShareholderRegistry(); + _; + } + + // Voting contract + + function getVoting() public view returns (IVoting) { + return _daoRegistry.getVoting(); + } + + modifier onlyVoting() { + _daoRegistry.requireMsgSenderToBeVoting(); + _; + } + + // Redemption Controller contract + + function getRedemptionController() + public + view + returns (IRedemptionController) + { + return _daoRegistry.getRedemptionController(); + } + + modifier onlyRedemptionController() { + _daoRegistry.requireMsgSenderToBeRedemptionController(); + _; + } + + // Resolution Manager contract + + function getResolutionManager() public view returns (ResolutionManager) { + return _daoRegistry.getResolutionManager(); + } + + modifier onlyResolutionManager() { + _daoRegistry.requireMsgSenderToBeResolutionManager(); + _; + } + + // Internal Market contract + + function getInternalMarket() public view returns (InternalMarket) { + return _daoRegistry.getInternalMarket(); + } + + modifier onlyInternalMarket() { + _daoRegistry.requireMsgSenderToBeInternalMarket(); + _; + } +} diff --git a/contracts/extensions/DAORoles.sol b/contracts/extensions/DAORoles.sol deleted file mode 100644 index 7d2d9c8..0000000 --- a/contracts/extensions/DAORoles.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.16; - -import "@openzeppelin/contracts/access/AccessControl.sol"; - -contract DAORoles is AccessControl { - constructor() { - _grantRole(DEFAULT_ADMIN_ROLE, _msgSender()); - } -} diff --git a/contracts/extensions/HasRole.sol b/contracts/extensions/HasRole.sol deleted file mode 100644 index 2c760d6..0000000 --- a/contracts/extensions/HasRole.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.16; - -import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; -import "@openzeppelin/contracts/utils/Strings.sol"; -import "./DAORoles.sol"; -import { Roles } from "./Roles.sol"; - -abstract contract HasRole is ContextUpgradeable { - DAORoles internal _roles; - - function _setRoles(DAORoles roles) internal { - _roles = roles; - } - - function setRoles(DAORoles roles) public onlyRole(Roles.OPERATOR_ROLE) { - _setRoles(roles); - } - - function getRoles() public view returns (DAORoles) { - return _roles; - } - - modifier onlyRole(bytes32 role) { - address account = _msgSender(); - if (!_roles.hasRole(role, account)) { - revert( - string( - abi.encodePacked( - "AccessControl: account ", - Strings.toHexString(account), - " is missing role ", - Strings.toHexString(uint256(role), 32) - ) - ) - ); - } - _; - } -} diff --git a/contracts/extensions/Roles.sol b/contracts/extensions/Roles.sol deleted file mode 100644 index 5ca5b28..0000000 --- a/contracts/extensions/Roles.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.16; - -library Roles { - bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); - bytes32 public constant RESOLUTION_ROLE = keccak256("RESOLUTION_ROLE"); - bytes32 public constant ESCROW_ROLE = keccak256("ESCROW_ROLE"); - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - bytes32 public constant MARKET_ROLE = keccak256("MARKET_ROLE"); - bytes32 public constant SHAREHOLDER_REGISTRY_ROLE = - keccak256("SHAREHOLDER_REGISTRY_ROLE"); - bytes32 public constant TOKEN_MANAGER_ROLE = - keccak256("TOKEN_MANAGER_ROLE"); -}