-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement
CommunityTokenDeployer
contract
This commit introduces the `CommunityTokenDeployer` contract discussed in status-im/status-desktop#11954. The idea is that, instead of having accounts deploy `OwnerToken` and `MasterToken` directly, they'd use a deployer contract instead, which maintains a registry of known `OwnerToken` addresses, mapped to Status community addresses. The following changes have been made: It was, and still is, a requirement that both, `OwnerToken` and `MasterToken` are deployed within a single transaction, so that when something goes wrong, we don't end up in an inconsistent state. That's why `OwnerToken` used to instantiated `MasterToken` and required all of its constructor arguments as well. Unfortunately, this resulted in compilation issues in the context of the newly introduce deployer contract, where there are too many function arguments. Because we now delegate deployment to a dedicated contract, we can instantiate both `OwnerToken` and `MasterToken` in a single transaction, without having `OwnerToken` being responsible to instantiate `MasterToken`. This fixes the compilation issues and simplifies the constructor of `OwnerToken`. The new `CommunityTokenDeployer` contract is now responsble for deploying the aforementioned tokens and ensures that they are deployed within a single transaction. To deploy an `OwnerToken` and `MasterToken` accounts can now call `CommunityDeloyerToken.deploy(TokenConfig, TokenConfig, DeploymentSignature)`. The `DeploymentSignature` uses `EIP712` structured type hash data to let the contract verify that the deployer is allowed to deploy the contracts on behalf of a community account.
- Loading branch information
Showing
25 changed files
with
1,357 additions
and
74 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,77 @@ | ||
AddEntryTest:test_AddEntry() (gas: 44369) | ||
AddEntryTest:test_RevertWhen_EntryAlreadyExists() (gas: 42598) | ||
AddEntryTest:test_RevertWhen_InvalidAddress() (gas: 25087) | ||
AddEntryTest:test_RevertWhen_SenderIsNotTokenDeployer() (gas: 14804) | ||
CollectibleV1Test:test_Deployment() (gas: 38626) | ||
CommunityERC20Test:test_Deployment() (gas: 29720) | ||
CommunityTokenDeployerTest:test_Deployment() (gas: 14805) | ||
CreateTest:test_Create() (gas: 2252539) | ||
CreateTest:test_Create() (gas: 2517349) | ||
CreateTest:test_RevertWhen_InvalidOwnerTokenAddress() (gas: 15523) | ||
CreateTest:test_RevertWhen_InvalidReceiverAddress() (gas: 15656) | ||
CreateTest:test_RevertWhen_InvalidSignerPublicKey() (gas: 17057) | ||
CreateTest:test_RevertWhen_InvalidTokenMetadata() (gas: 27936) | ||
CreateTest:test_RevertWhen_InvalidTokenMetadata() (gas: 28173) | ||
CreateTest:test_RevertWhen_SenderIsNotTokenDeployer() (gas: 16421) | ||
CreateTest:test_RevertWhen_SenderIsNotTokenDeployer() (gas: 16524) | ||
DeployContracts:test() (gas: 120) | ||
DeployOwnerAndMasterToken:test() (gas: 120) | ||
DeployTest:test_Deploy() (gas: 4840232) | ||
DeployTest:test_Deployment() (gas: 14925) | ||
DeployTest:test_RevertWhen_AlreadyDeployed() (gas: 4836115) | ||
DeployTest:test_RevertWhen_DeploymentSignatureExpired() (gas: 53642) | ||
DeployTest:test_RevertWhen_InvalidCommunityAddress() (gas: 51341) | ||
DeployTest:test_RevertWhen_InvalidDeployerAddress() (gas: 55329) | ||
DeployTest:test_RevertWhen_InvalidDeploymentSignature() (gas: 65663) | ||
DeployTest:test_RevertWhen_InvalidSignerPublicKey() (gas: 53435) | ||
DeployTest:test_RevertWhen_InvalidTokenMetadata() (gas: 2639807) | ||
DeploymentTest:test_Deployment() (gas: 14671) | ||
DeploymentTest:test_Deployment() (gas: 14671) | ||
DeploymentTest:test_Deployment() (gas: 17250) | ||
GetEntryTest:test_ReturnZeroAddressIfEntryDoesNotExist() (gas: 11906) | ||
MintToTest:test_Deployment() (gas: 29742) | ||
MintToTest:test_Deployment() (gas: 38626) | ||
MintToTest:test_Deployment() (gas: 85415) | ||
MintToTest:test_MintTo() (gas: 509977) | ||
MintToTest:test_Deployment() (gas: 85460) | ||
MintToTest:test_MintTo() (gas: 509082) | ||
MintToTest:test_RevertWhen_AddressesAndAmountsAreNotEqualLength() (gas: 24193) | ||
MintToTest:test_RevertWhen_MaxSupplyIsReached() (gas: 23267) | ||
MintToTest:test_RevertWhen_MaxSupplyIsReached() (gas: 505463) | ||
MintToTest:test_RevertWhen_MaxSupplyReached() (gas: 123426) | ||
MintToTest:test_RevertWhen_SenderIsNotOwner() (gas: 36358) | ||
OwnerTokenTest:test_Deployment() (gas: 85415) | ||
OwnerTokenTest:test_Deployment() (gas: 85460) | ||
RemoteBurnTest:test_Deployment() (gas: 38626) | ||
RemoteBurnTest:test_Deployment() (gas: 85437) | ||
RemoteBurnTest:test_Deployment() (gas: 85482) | ||
RemoteBurnTest:test_RemoteBurn() (gas: 455285) | ||
RemoteBurnTest:test_RevertWhen_RemoteBurn() (gas: 19499) | ||
RemoteBurnTest:test_RevertWhen_SenderIsNotOwner() (gas: 25211) | ||
SetCommunityTokenDeployerAddressTest:test_RevertWhen_InvalidTokenDeployerAddress() (gas: 12963) | ||
SetCommunityTokenDeployerAddressTest:test_RevertWhen_SenderIsNotOwner() (gas: 12504) | ||
SetCommunityTokenDeployerAddressTest:test_SetCommunityTokenDeployerAddress() (gas: 22807) | ||
SetDeploymentRegistryAddressTest:test_Deployment() (gas: 14827) | ||
SetDeploymentRegistryAddressTest:test_RevertWhen_InvalidDeploymentRegistryAddress() (gas: 13014) | ||
SetDeploymentRegistryAddressTest:test_RevertWhen_SenderIsNotOwner() (gas: 12508) | ||
SetDeploymentRegistryAddressTest:test_SetDeploymentRegistryAddress() (gas: 22903) | ||
SetMasterTokenFactoryAddressTest:test_Deployment() (gas: 14805) | ||
SetMasterTokenFactoryAddressTest:test_RevertWhen_InvalidTokenFactoryAddress() (gas: 13014) | ||
SetMasterTokenFactoryAddressTest:test_RevertWhen_SenderIsNotOwner() (gas: 12487) | ||
SetMasterTokenFactoryAddressTest:test_SetOwnerTokenFactoryAddress() (gas: 22861) | ||
SetMaxSupplyTest:test_Deployment() (gas: 29720) | ||
SetMaxSupplyTest:test_Deployment() (gas: 85437) | ||
SetMaxSupplyTest:test_Deployment() (gas: 85482) | ||
SetMaxSupplyTest:test_RevertWhen_CalledBecauseMaxSupplyIsLocked() (gas: 16521) | ||
SetMaxSupplyTest:test_RevertWhen_MaxSupplyLowerThanTotalSupply() (gas: 149095) | ||
SetMaxSupplyTest:test_RevertWhen_SenderIsNotOwner() (gas: 12852) | ||
SetMaxSupplyTest:test_RevertWhen_SenderIsNotOwner() (gas: 12823) | ||
SetMaxSupplyTest:test_RevertWhen_SenderIsNotOwner() (gas: 17335) | ||
SetMaxSupplyTest:test_SetMaxSupply() (gas: 15597) | ||
SetSignerPublicKeyTest:test_Deployment() (gas: 85415) | ||
SetOwnerTokenFactoryAddressTest:test_Deployment() (gas: 14805) | ||
SetOwnerTokenFactoryAddressTest:test_RevertWhen_InvalidTokenFactoryAddress() (gas: 12992) | ||
SetOwnerTokenFactoryAddressTest:test_RevertWhen_SenderIsNotOwner() (gas: 12465) | ||
SetOwnerTokenFactoryAddressTest:test_SetOwnerTokenFactoryAddress() (gas: 22862) | ||
SetSignerPublicKeyTest:test_Deployment() (gas: 85460) | ||
SetSignerPublicKeyTest:test_RevertWhen_SenderIsNotOwner() (gas: 18036) | ||
SetSignerPublicKeyTest:test_SetSignerPublicKey() (gas: 26357) | ||
SetSignerPublicKeyTest:test_SetSignerPublicKey() (gas: 26357) | ||
SetTokenDeployerAddressTest:test_RevertWhen_InvalidTokenDeployerAddress() (gas: 12964) | ||
SetTokenDeployerAddressTest:test_RevertWhen_InvalidTokenDeployerAddress() (gas: 12964) | ||
SetTokenDeployerAddressTest:test_RevertWhen_SenderIsNotOwner() (gas: 12438) | ||
SetTokenDeployerAddressTest:test_RevertWhen_SenderIsNotOwner() (gas: 12438) | ||
SetTokenDeployerAddressTest:test_SetTokenDeployerAddress() (gas: 22768) | ||
SetTokenDeployerAddressTest:test_SetTokenDeployerAddress() (gas: 22768) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
|
||
pragma solidity ^0.8.17; | ||
|
||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; | ||
import { IAddressRegistry } from "./interfaces/IAddressRegistry.sol"; | ||
import { OwnerToken } from "./tokens/OwnerToken.sol"; | ||
|
||
/** | ||
* @title CommunityOwnerTokenRegistry contract | ||
* @author 0x-r4bbit | ||
* | ||
* This contract serves as a simple registry to map Status community addresses | ||
* to Status community `OwnerToken` addresses. | ||
* The `CommunityTokenDeployer` contract uses this registry contract to maintain | ||
* a list of community address and their token addresses. | ||
* @notice This contract will be deployed by Status similar to the `CommunityTokenDeployer` | ||
* contract. | ||
* @notice This contract maps community addresses to `OwnerToken` addresses. | ||
* @notice Only one entry per community address can exist in the registry. | ||
* @dev This registry has been extracted into its own contract so that it's possible | ||
* to introduce different version of a `CommunityDeployerContract` without needing to | ||
* migrate existing registry data, as the deployer contract would simply point at this | ||
* registry contract. | ||
* @dev Only `tokenDeployer` can add entries to the registry. | ||
*/ | ||
contract CommunityOwnerTokenRegistry is IAddressRegistry, Ownable { | ||
error CommunityOwnerTokenRegistry_NotAuthorized(); | ||
error CommunityOwnerTokenRegistry_EntryAlreadyExists(); | ||
error CommunityOwnerTokenRegistry_InvalidAddress(); | ||
|
||
event TokenDeployerAddressChange(address indexed); | ||
event AddEntry(address indexed, address indexed); | ||
|
||
/// @dev The address of the token deployer contract. | ||
address public tokenDeployer; | ||
|
||
mapping(address => address) public communityAddressToTokenAddress; | ||
|
||
modifier onlyTokenDeployer() { | ||
if (msg.sender != tokenDeployer) { | ||
revert CommunityOwnerTokenRegistry_NotAuthorized(); | ||
} | ||
_; | ||
} | ||
|
||
/** | ||
* @notice Sets the address of the community token deployer contract. This is needed to | ||
* ensure only the known token deployer contract can add new entries to the registry. | ||
* @dev Only the owner of this contract can call this function. | ||
* @dev Emits a {TokenDeployerAddressChange} event. | ||
* | ||
* @param _tokenDeployer The address of the community token deployer contract | ||
*/ | ||
function setCommunityTokenDeployerAddress(address _tokenDeployer) external onlyOwner { | ||
if (_tokenDeployer == address(0)) { | ||
revert CommunityOwnerTokenRegistry_InvalidAddress(); | ||
} | ||
tokenDeployer = _tokenDeployer; | ||
emit TokenDeployerAddressChange(tokenDeployer); | ||
} | ||
|
||
/** | ||
* @notice Adds an entry to the registry. Only one entry per community address can exist. | ||
* @dev Only the token deployer contract can call this function. | ||
* @dev Reverts when the entry already exists. | ||
* @dev Reverts when either `_communityAddress` or `_tokenAddress` are zero addresses. | ||
* @dev Emits a {AddEntry} event. | ||
*/ | ||
function addEntry(address _communityAddress, address _tokenAddress) external onlyTokenDeployer { | ||
if (getEntry(_communityAddress) != address(0)) { | ||
revert CommunityOwnerTokenRegistry_EntryAlreadyExists(); | ||
} | ||
|
||
if (_communityAddress == address(0) || _tokenAddress == address(0)) { | ||
revert CommunityOwnerTokenRegistry_InvalidAddress(); | ||
} | ||
|
||
communityAddressToTokenAddress[_communityAddress] = _tokenAddress; | ||
emit AddEntry(_communityAddress, _tokenAddress); | ||
} | ||
|
||
/** | ||
* @notice Returns the owner token address for a given community address. | ||
* @param _communityAddress The community address to look up an owner token address. | ||
* @return address The owner token address for the community addres, or zero address . | ||
*/ | ||
function getEntry(address _communityAddress) public view returns (address) { | ||
return communityAddressToTokenAddress[_communityAddress]; | ||
} | ||
} |
Oops, something went wrong.