communities-contracts/test/CommunityMasterTokenFactory...

137 lines
5.5 KiB
Solidity
Raw Normal View History

feat: implement `CommunityTokenDeployer` contract This commit introduces the `CommunityTokenDeployer` contract discussed in https://github.com/status-im/status-desktop/issues/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.
2023-08-30 09:27:44 +00:00
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
import { Test } from "forge-std/Test.sol";
import { DeployContracts } from "../script/DeployContracts.s.sol";
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
import { BaseTokenFactory } from "../contracts/factories/BaseTokenFactory.sol";
import { CommunityMasterTokenFactory } from "../contracts/factories/CommunityMasterTokenFactory.sol";
import { MasterToken } from "../contracts/tokens/MasterToken.sol";
import { CommunityTokenDeployer } from "../contracts/CommunityTokenDeployer.sol";
contract CommunityMasterTokenFactoryTest is Test {
DeploymentConfig internal deploymentConfig;
address internal deployer;
CommunityTokenDeployer internal tokenDeployer;
CommunityMasterTokenFactory internal masterTokenFactory;
function setUp() public virtual {
DeployContracts deployment = new DeployContracts();
(tokenDeployer,,, masterTokenFactory, deploymentConfig) = deployment.run();
deployer = deploymentConfig.deployer();
}
}
contract DeploymentTest is CommunityMasterTokenFactoryTest {
function setUp() public virtual override {
CommunityMasterTokenFactoryTest.setUp();
}
function test_Deployment() public {
assertEq(masterTokenFactory.owner(), deployer);
assertEq(masterTokenFactory.tokenDeployer(), address(tokenDeployer));
}
}
contract SetTokenDeployerAddressTest is CommunityMasterTokenFactoryTest {
event TokenDeployerAddressChange(address indexed);
function setUp() public virtual override {
CommunityMasterTokenFactoryTest.setUp();
}
function test_RevertWhen_SenderIsNotOwner() public {
vm.expectRevert(bytes("Ownable: caller is not the owner"));
masterTokenFactory.setTokenDeployerAddress(makeAddr("something"));
}
function test_RevertWhen_InvalidTokenDeployerAddress() public {
vm.prank(deployer);
vm.expectRevert(BaseTokenFactory.BaseTokenFactory_InvalidTokenDeployerAddress.selector);
masterTokenFactory.setTokenDeployerAddress(address(0));
}
function test_SetTokenDeployerAddress() public {
address someAddress = makeAddr("someAddress");
vm.prank(deployer);
vm.expectEmit(true, true, true, true);
emit TokenDeployerAddressChange(someAddress);
masterTokenFactory.setTokenDeployerAddress(someAddress);
assertEq(masterTokenFactory.tokenDeployer(), someAddress);
}
}
contract CreateTest is CommunityMasterTokenFactoryTest {
event CreateToken(address indexed);
function setUp() public virtual override {
CommunityMasterTokenFactoryTest.setUp();
}
function test_RevertWhen_SenderIsNotTokenDeployer() public {
string memory name = "TestToken";
string memory symbol = "TEST";
string memory baseURI = "http://test.dev";
address ownerToken = makeAddr("ownerToken");
bytes memory signerPublicKey = bytes("");
vm.prank(makeAddr("notTokenDeployer"));
vm.expectRevert(BaseTokenFactory.BaseTokenFactory_NotAuthorized.selector);
masterTokenFactory.create(name, symbol, baseURI, ownerToken, signerPublicKey);
}
function test_RevertWhen_InvalidTokenMetadata() public {
string memory name = "";
string memory symbol = "";
string memory baseURI = "";
address ownerToken = makeAddr("ownerToken");
bytes memory signerPublicKey = bytes("");
vm.startPrank(address(tokenDeployer));
vm.expectRevert(BaseTokenFactory.BaseTokenFactory_InvalidTokenMetadata.selector);
masterTokenFactory.create(name, symbol, baseURI, ownerToken, signerPublicKey);
baseURI = "http://test.dev";
vm.expectRevert(BaseTokenFactory.BaseTokenFactory_InvalidTokenMetadata.selector);
masterTokenFactory.create(name, symbol, baseURI, ownerToken, signerPublicKey);
symbol = "TEST";
vm.expectRevert(BaseTokenFactory.BaseTokenFactory_InvalidTokenMetadata.selector);
masterTokenFactory.create(name, symbol, baseURI, ownerToken, signerPublicKey);
}
function test_RevertWhen_InvalidOwnerTokenAddress() public {
string memory name = "TestToken";
string memory symbol = "TEST";
string memory baseURI = "http://test.dev";
address ownerToken = address(0);
bytes memory signerPublicKey = bytes("");
vm.prank(address(tokenDeployer));
vm.expectRevert(CommunityMasterTokenFactory.CommunityMasterTokenFactory_InvalidOwnerTokenAddress.selector);
masterTokenFactory.create(name, symbol, baseURI, ownerToken, signerPublicKey);
}
function test_Create() public {
string memory name = "TestToken";
string memory symbol = "TEST";
string memory baseURI = "http://test.dev";
address ownerToken = makeAddr("ownerToken");
bytes memory signerPublicKey = bytes("some public key");
vm.prank(address(tokenDeployer));
vm.expectEmit(false, false, false, false);
emit CreateToken(makeAddr("some address"));
address masterTokenAddress = masterTokenFactory.create(name, symbol, baseURI, ownerToken, signerPublicKey);
assertEq(MasterToken(masterTokenAddress).totalSupply(), 0);
assertEq(MasterToken(masterTokenAddress).maxSupply(), type(uint256).max);
assertEq(MasterToken(masterTokenAddress).transferable(), false);
assertEq(MasterToken(masterTokenAddress).remoteBurnable(), true);
assertEq(MasterToken(masterTokenAddress).ownerToken(), ownerToken);
}
}