From fb035bc7ec195df773ff51b18c0616840c5c802f Mon Sep 17 00:00:00 2001 From: mejango Date: Fri, 8 Sep 2023 13:56:51 -0400 Subject: [PATCH 1/2] added means for finding the project from a token --- contracts/JBTokenStore.sol | 43 ++++++++++++++++++++++++++ contracts/interfaces/IJBTokenStore.sol | 4 +++ 2 files changed, 47 insertions(+) diff --git a/contracts/JBTokenStore.sol b/contracts/JBTokenStore.sol index 7b0f40d9f..9c170ac2d 100644 --- a/contracts/JBTokenStore.sol +++ b/contracts/JBTokenStore.sol @@ -38,6 +38,15 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { error TRANSFERS_PAUSED(); error OVERFLOW_ALERT(); + + //*********************************************************************// + // --------------------- private stored properties ------------------- // + //*********************************************************************// + + /// @notice Each token's project. + /// @custom:param _token The address of the token to which the project belongs. + mapping(IJBToken => uint256[]) private _projectIdsOf; + //*********************************************************************// // ---------------- public immutable stored properties --------------- // //*********************************************************************// @@ -89,6 +98,34 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { if (_token != IJBToken(address(0))) balance = balance + _token.balanceOf(_holder, _projectId); } + /// @notice Each token's project. + /// @param _token The address of the token to which the project belongs. + /// @return The ID of the projects to which the token apply + function projectIdsOf(IJBToken _token) external view returns (uint256[] memory) { + return _projectIdsOf[_token]; + } + + /// @notice Each token's project. + /// @param _token The address of the token to which the project belongs. + /// @return _projectId The ID of the projects to which the token apply + function isProjectIdOfToken(IJBToken _token, uint256 _projectId) external view returns (bool) { + // Get a reference to the project IDs for the token. + uint256[] memory _projectIds = _projectIdsOf[_token]; + + // Keep a reference to the number of project IDs belong to the token. + uint256 _numberOfProjectIds = _projectIds.length; + + // Check to see if the provided project ID is in the set. + for (uint256 _i; _i < _numberOfProjectIds;) { + if (_projectIds[_i] == _projectId) return true; + unchecked { + ++_i; + } + } + + return false; + } + //*********************************************************************// // --------------------------- public views -------------------------- // //*********************************************************************// @@ -161,6 +198,9 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { // Store the token contract. tokenOf[_projectId] = token; + // Store the project for the token. + _projectIdsOf[token].push(_projectId); + emit Issue(_projectId, token, _name, _symbol, msg.sender); } @@ -185,6 +225,9 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { // Store the new token. tokenOf[_projectId] = _token; + // Store the project for the token. + _projectIdsOf[_token].push(_projectId); + emit Set(_projectId, _token, msg.sender); } diff --git a/contracts/interfaces/IJBTokenStore.sol b/contracts/interfaces/IJBTokenStore.sol index 11ffbe247..b178a92cd 100644 --- a/contracts/interfaces/IJBTokenStore.sol +++ b/contracts/interfaces/IJBTokenStore.sol @@ -54,6 +54,10 @@ interface IJBTokenStore { function tokenOf(uint256 projectId) external view returns (IJBToken); + function projectIdsOf(IJBToken token) external view returns (uint256[] memory); + + function isProjectIdOfToken(IJBToken token, uint256 projectId) external view returns (bool); + function projects() external view returns (IJBProjects); function fundingCycleStore() external view returns (IJBFundingCycleStore); From d4a05d84165fcebcc290539ba572e3aa32a9a116 Mon Sep 17 00:00:00 2001 From: mejango Date: Fri, 8 Sep 2023 14:06:39 -0400 Subject: [PATCH 2/2] one project per token --- contracts/JBToken.sol | 10 +++--- contracts/JBTokenStore.sol | 50 ++++++-------------------- contracts/interfaces/IJBTokenStore.sol | 4 +-- 3 files changed, 16 insertions(+), 48 deletions(-) diff --git a/contracts/JBToken.sol b/contracts/JBToken.sol index 59320f933..0e44bcb12 100644 --- a/contracts/JBToken.sol +++ b/contracts/JBToken.sol @@ -82,7 +82,7 @@ contract JBToken is ERC20Votes, Ownable, IJBToken { /// @param _amount The amount of tokens to mint, as a fixed point number with 18 decimals. function mint(uint256 _projectId, address _account, uint256 _amount) external override onlyOwner { // Can't mint for a wrong project. - if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT(); + if (_projectId != projectId) revert BAD_PROJECT(); return _mint(_account, _amount); } @@ -94,7 +94,7 @@ contract JBToken is ERC20Votes, Ownable, IJBToken { /// @param _amount The amount of tokens to burn, as a fixed point number with 18 decimals. function burn(uint256 _projectId, address _account, uint256 _amount) external override onlyOwner { // Can't burn for a wrong project. - if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT(); + if (_projectId != projectId) revert BAD_PROJECT(); return _burn(_account, _amount); } @@ -105,7 +105,7 @@ contract JBToken is ERC20Votes, Ownable, IJBToken { /// @param _amount The amount the `_spender` is allowed to spend. function approve(uint256 _projectId, address _spender, uint256 _amount) external override { // Can't approve for a wrong project. - if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT(); + if (_projectId != projectId) revert BAD_PROJECT(); approve(_spender, _amount); } @@ -116,7 +116,7 @@ contract JBToken is ERC20Votes, Ownable, IJBToken { /// @param _amount The amount of the transfer, as a fixed point number with 18 decimals. function transfer(uint256 _projectId, address _to, uint256 _amount) external override { // Can't transfer for a wrong project. - if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT(); + if (_projectId != projectId) revert BAD_PROJECT(); transfer(_to, _amount); } @@ -133,7 +133,7 @@ contract JBToken is ERC20Votes, Ownable, IJBToken { uint256 _amount ) external override { // Can't transfer for a wrong project. - if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT(); + if (_projectId != projectId) revert BAD_PROJECT(); transferFrom(_from, _to, _amount); } diff --git a/contracts/JBTokenStore.sol b/contracts/JBTokenStore.sol index 9c170ac2d..a16e447dc 100644 --- a/contracts/JBTokenStore.sol +++ b/contracts/JBTokenStore.sol @@ -38,15 +38,6 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { error TRANSFERS_PAUSED(); error OVERFLOW_ALERT(); - - //*********************************************************************// - // --------------------- private stored properties ------------------- // - //*********************************************************************// - - /// @notice Each token's project. - /// @custom:param _token The address of the token to which the project belongs. - mapping(IJBToken => uint256[]) private _projectIdsOf; - //*********************************************************************// // ---------------- public immutable stored properties --------------- // //*********************************************************************// @@ -65,6 +56,10 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { /// @custom:param _projectId The ID of the project to which the token belongs. mapping(uint256 => IJBToken) public override tokenOf; + /// @notice Each token's project. + /// @custom:param _token The address of the token to which the project belongs. + mapping(IJBToken => uint256) public override projectIdOf; + /// @notice The total supply of unclaimed tokens for each project. /// @custom:param _projectId The ID of the project to which the token belongs. mapping(uint256 => uint256) public override unclaimedTotalSupplyOf; @@ -98,34 +93,6 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { if (_token != IJBToken(address(0))) balance = balance + _token.balanceOf(_holder, _projectId); } - /// @notice Each token's project. - /// @param _token The address of the token to which the project belongs. - /// @return The ID of the projects to which the token apply - function projectIdsOf(IJBToken _token) external view returns (uint256[] memory) { - return _projectIdsOf[_token]; - } - - /// @notice Each token's project. - /// @param _token The address of the token to which the project belongs. - /// @return _projectId The ID of the projects to which the token apply - function isProjectIdOfToken(IJBToken _token, uint256 _projectId) external view returns (bool) { - // Get a reference to the project IDs for the token. - uint256[] memory _projectIds = _projectIdsOf[_token]; - - // Keep a reference to the number of project IDs belong to the token. - uint256 _numberOfProjectIds = _projectIds.length; - - // Check to see if the provided project ID is in the set. - for (uint256 _i; _i < _numberOfProjectIds;) { - if (_projectIds[_i] == _projectId) return true; - unchecked { - ++_i; - } - } - - return false; - } - //*********************************************************************// // --------------------------- public views -------------------------- // //*********************************************************************// @@ -199,7 +166,7 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { tokenOf[_projectId] = token; // Store the project for the token. - _projectIdsOf[token].push(_projectId); + projectIdOf[token] = _projectId; emit Issue(_projectId, token, _name, _symbol, msg.sender); } @@ -216,9 +183,12 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { // Can't set to the zero address. if (_token == IJBToken(address(0))) revert EMPTY_TOKEN(); - // Can't set token if already set. + // Can't set token if the project is already associated with another token. if (tokenOf[_projectId] != IJBToken(address(0))) revert ALREADY_SET(); + // Can't set token if its already associated with another project. + if (projectIdOf[_token] != 0) revert ALREADY_SET(); + // Can't change to a token that doesn't use 18 decimals. if (_token.decimals() != 18) revert TOKENS_MUST_HAVE_18_DECIMALS(); @@ -226,7 +196,7 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { tokenOf[_projectId] = _token; // Store the project for the token. - _projectIdsOf[_token].push(_projectId); + projectIdOf[_token] = _projectId; emit Set(_projectId, _token, msg.sender); } diff --git a/contracts/interfaces/IJBTokenStore.sol b/contracts/interfaces/IJBTokenStore.sol index b178a92cd..7e4071ffb 100644 --- a/contracts/interfaces/IJBTokenStore.sol +++ b/contracts/interfaces/IJBTokenStore.sol @@ -54,9 +54,7 @@ interface IJBTokenStore { function tokenOf(uint256 projectId) external view returns (IJBToken); - function projectIdsOf(IJBToken token) external view returns (uint256[] memory); - - function isProjectIdOfToken(IJBToken token, uint256 projectId) external view returns (bool); + function projectIdOf(IJBToken token) external view returns (uint256); function projects() external view returns (IJBProjects);