add master/owner tokens to erc20 token (#19)
This commit is contained in:
parent
ff7de4a819
commit
ff01f8e818
|
@ -3,10 +3,10 @@ AddEntryTest:test_RevertWhen_EntryAlreadyExists() (gas: 42644)
|
|||
AddEntryTest:test_RevertWhen_InvalidAddress() (gas: 25133)
|
||||
AddEntryTest:test_RevertWhen_SenderIsNotTokenDeployer() (gas: 14827)
|
||||
CollectibleV1Test:test_Deployment() (gas: 36386)
|
||||
CommunityERC20Test:test_Deployment() (gas: 27614)
|
||||
CommunityERC20Test:test_Deployment() (gas: 27659)
|
||||
CommunityTokenDeployerTest:test_Deployment() (gas: 14805)
|
||||
CreateTest:test_Create() (gas: 2251262)
|
||||
CreateTest:test_Create() (gas: 2548166)
|
||||
CreateTest:test_Create() (gas: 2251272)
|
||||
CreateTest:test_Create() (gas: 2548179)
|
||||
CreateTest:test_RevertWhen_InvalidOwnerTokenAddress() (gas: 15523)
|
||||
CreateTest:test_RevertWhen_InvalidReceiverAddress() (gas: 15656)
|
||||
CreateTest:test_RevertWhen_InvalidSignerPublicKey() (gas: 17057)
|
||||
|
@ -16,26 +16,26 @@ CreateTest:test_RevertWhen_SenderIsNotTokenDeployer() (gas: 16421)
|
|||
CreateTest:test_RevertWhen_SenderIsNotTokenDeployer() (gas: 16524)
|
||||
DeployContracts:test() (gas: 120)
|
||||
DeployOwnerAndMasterToken:test() (gas: 120)
|
||||
DeployTest:test_Deploy() (gas: 4872082)
|
||||
DeployTest:test_Deploy() (gas: 4872105)
|
||||
DeployTest:test_Deployment() (gas: 14947)
|
||||
DeployTest:test_RevertWhen_AlreadyDeployed() (gas: 4868312)
|
||||
DeployTest:test_RevertWhen_AlreadyDeployed() (gas: 4868335)
|
||||
DeployTest:test_RevertWhen_InvalidCommunityAddress() (gas: 51385)
|
||||
DeployTest:test_RevertWhen_InvalidDeployerAddress() (gas: 55272)
|
||||
DeployTest:test_RevertWhen_InvalidDeploymentSignature() (gas: 65617)
|
||||
DeployTest:test_RevertWhen_InvalidSignerPublicKey() (gas: 53433)
|
||||
DeployTest:test_RevertWhen_InvalidTokenMetadata() (gas: 2671682)
|
||||
DeployTest:test_RevertWhen_InvalidTokenMetadata() (gas: 2671695)
|
||||
DeploymentTest:test_Deployment() (gas: 14671)
|
||||
DeploymentTest:test_Deployment() (gas: 14671)
|
||||
DeploymentTest:test_Deployment() (gas: 17295)
|
||||
GetEntryTest:test_ReturnZeroAddressIfEntryDoesNotExist() (gas: 11906)
|
||||
MintToTest:test_Deployment() (gas: 27636)
|
||||
MintToTest:test_Deployment() (gas: 27681)
|
||||
MintToTest:test_Deployment() (gas: 36386)
|
||||
MintToTest:test_Deployment() (gas: 83220)
|
||||
MintToTest:test_MintTo() (gas: 506888)
|
||||
MintToTest:test_RevertWhen_AddressesAndAmountsAreNotEqualLength() (gas: 23778)
|
||||
MintToTest:test_RevertWhen_AddressesAndAmountsAreNotEqualLength() (gas: 29695)
|
||||
MintToTest:test_RevertWhen_MaxSupplyIsReached() (gas: 20653)
|
||||
MintToTest:test_RevertWhen_MaxSupplyIsReached() (gas: 502655)
|
||||
MintToTest:test_RevertWhen_MaxSupplyReached() (gas: 122988)
|
||||
MintToTest:test_RevertWhen_MaxSupplyReached() (gas: 128905)
|
||||
MintToTest:test_RevertWhen_SenderIsNotOwner() (gas: 31544)
|
||||
OwnerTokenTest:test_Deployment() (gas: 83220)
|
||||
RemoteBurnTest:test_Deployment() (gas: 36386)
|
||||
|
@ -54,13 +54,13 @@ SetMasterTokenFactoryAddressTest:test_Deployment() (gas: 14805)
|
|||
SetMasterTokenFactoryAddressTest:test_RevertWhen_InvalidTokenFactoryAddress() (gas: 12992)
|
||||
SetMasterTokenFactoryAddressTest:test_RevertWhen_SenderIsNotOwner() (gas: 12465)
|
||||
SetMasterTokenFactoryAddressTest:test_SetOwnerTokenFactoryAddress() (gas: 22861)
|
||||
SetMaxSupplyTest:test_Deployment() (gas: 27614)
|
||||
SetMaxSupplyTest:test_Deployment() (gas: 27659)
|
||||
SetMaxSupplyTest:test_Deployment() (gas: 83242)
|
||||
SetMaxSupplyTest:test_RevertWhen_CalledBecauseMaxSupplyIsLocked() (gas: 14327)
|
||||
SetMaxSupplyTest:test_RevertWhen_MaxSupplyLowerThanTotalSupply() (gas: 148572)
|
||||
SetMaxSupplyTest:test_RevertWhen_MaxSupplyLowerThanTotalSupply() (gas: 155732)
|
||||
SetMaxSupplyTest:test_RevertWhen_SenderIsNotOwner() (gas: 12527)
|
||||
SetMaxSupplyTest:test_RevertWhen_SenderIsNotOwner() (gas: 12817)
|
||||
SetMaxSupplyTest:test_SetMaxSupply() (gas: 15597)
|
||||
SetMaxSupplyTest:test_RevertWhen_SenderIsNotOwner() (gas: 21402)
|
||||
SetMaxSupplyTest:test_SetMaxSupply() (gas: 23955)
|
||||
SetOwnerTokenFactoryAddressTest:test_Deployment() (gas: 14805)
|
||||
SetOwnerTokenFactoryAddressTest:test_RevertWhen_InvalidTokenFactoryAddress() (gas: 12970)
|
||||
SetOwnerTokenFactoryAddressTest:test_RevertWhen_SenderIsNotOwner() (gas: 12443)
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// SPDX-License-Identifier: Mozilla Public License 2.0
|
||||
|
||||
pragma solidity ^0.8.17;
|
||||
|
||||
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
||||
|
||||
contract CommunityOwnable {
|
||||
error CommunityOwnable_InvalidTokenAddress();
|
||||
error CommunityOwnable_NotAuthorized();
|
||||
|
||||
address public immutable ownerToken;
|
||||
address public immutable masterToken;
|
||||
|
||||
constructor(address _ownerToken, address _masterToken) {
|
||||
ownerToken = _ownerToken;
|
||||
masterToken = _masterToken;
|
||||
|
||||
if (ownerToken == address(0) && masterToken == address(0)) {
|
||||
revert CommunityOwnable_InvalidTokenAddress();
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Reverts if the msg.sender does not possess either an OwnerToken or a MasterToken.
|
||||
modifier onlyCommunityOwnerOrTokenMaster() {
|
||||
if (
|
||||
(ownerToken != address(0) && IERC721(ownerToken).balanceOf(msg.sender) == 0)
|
||||
&& (masterToken != address(0) && IERC721(masterToken).balanceOf(msg.sender) == 0)
|
||||
) {
|
||||
revert CommunityOwnable_NotAuthorized();
|
||||
}
|
||||
_;
|
||||
}
|
||||
}
|
|
@ -6,12 +6,11 @@ import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
|||
import { ERC721Enumerable } from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
|
||||
import { Context } from "@openzeppelin/contracts/utils/Context.sol";
|
||||
import { Counters } from "@openzeppelin/contracts/utils/Counters.sol";
|
||||
import { CommunityOwnable } from "../CommunityOwnable.sol";
|
||||
|
||||
abstract contract BaseToken is Context, ERC721Enumerable {
|
||||
abstract contract BaseToken is Context, ERC721Enumerable, CommunityOwnable {
|
||||
using Counters for Counters.Counter;
|
||||
|
||||
error BaseToken_InvalidTokenAddress();
|
||||
error BaseToken_NotAuthorized();
|
||||
error BaseToken_MaxSupplyLowerThanTotalSupply();
|
||||
error BaseToken_MaxSupplyReached();
|
||||
error BaseToken_NotRemoteBurnable();
|
||||
|
@ -25,10 +24,6 @@ abstract contract BaseToken is Context, ERC721Enumerable {
|
|||
* If we want unlimited total supply we should set maxSupply to 2^256-1.
|
||||
*/
|
||||
uint256 public maxSupply;
|
||||
|
||||
address public immutable ownerToken;
|
||||
address public immutable masterToken;
|
||||
|
||||
/**
|
||||
* If set to true, the contract owner can burn any token.
|
||||
*/
|
||||
|
@ -52,34 +47,19 @@ abstract contract BaseToken is Context, ERC721Enumerable {
|
|||
address _masterToken
|
||||
)
|
||||
ERC721(_name, _symbol)
|
||||
CommunityOwnable(_ownerToken, _masterToken)
|
||||
{
|
||||
maxSupply = _maxSupply;
|
||||
remoteBurnable = _remoteBurnable;
|
||||
transferable = _transferable;
|
||||
baseTokenURI = _baseTokenURI;
|
||||
ownerToken = _ownerToken;
|
||||
masterToken = _masterToken;
|
||||
|
||||
if (ownerToken == address(0) && masterToken == address(0)) {
|
||||
revert BaseToken_InvalidTokenAddress();
|
||||
}
|
||||
}
|
||||
|
||||
modifier onlyOwner() {
|
||||
if (
|
||||
(ownerToken != address(0) && IERC721(ownerToken).balanceOf(msg.sender) == 0)
|
||||
&& (masterToken != address(0) && IERC721(masterToken).balanceOf(msg.sender) == 0)
|
||||
) {
|
||||
revert BaseToken_NotAuthorized();
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
// Events
|
||||
|
||||
// External functions
|
||||
|
||||
function setMaxSupply(uint256 newMaxSupply) external virtual onlyOwner {
|
||||
function setMaxSupply(uint256 newMaxSupply) external virtual onlyCommunityOwnerOrTokenMaster {
|
||||
if (newMaxSupply < totalSupply()) {
|
||||
revert BaseToken_MaxSupplyLowerThanTotalSupply();
|
||||
}
|
||||
|
@ -92,7 +72,7 @@ abstract contract BaseToken is Context, ERC721Enumerable {
|
|||
* URI autogenerated based on the base URI passed at construction.
|
||||
*
|
||||
*/
|
||||
function mintTo(address[] memory addresses) public onlyOwner {
|
||||
function mintTo(address[] memory addresses) public onlyCommunityOwnerOrTokenMaster {
|
||||
if (_tokenIdTracker.current() + addresses.length > maxSupply) {
|
||||
revert BaseToken_MaxSupplyReached();
|
||||
}
|
||||
|
@ -109,7 +89,7 @@ abstract contract BaseToken is Context, ERC721Enumerable {
|
|||
* @notice remoteBurn allows the owner to burn a token
|
||||
* @param tokenIds The list of token IDs to be burned
|
||||
*/
|
||||
function remoteBurn(uint256[] memory tokenIds) public onlyOwner {
|
||||
function remoteBurn(uint256[] memory tokenIds) public onlyCommunityOwnerOrTokenMaster {
|
||||
if (!remoteBurnable) revert BaseToken_NotRemoteBurnable();
|
||||
|
||||
for (uint256 i = 0; i < tokenIds.length; i++) {
|
||||
|
|
|
@ -4,8 +4,9 @@ pragma solidity ^0.8.17;
|
|||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
||||
import { Context } from "@openzeppelin/contracts/utils/Context.sol";
|
||||
import { CommunityOwnable } from "../CommunityOwnable.sol";
|
||||
|
||||
contract CommunityERC20 is Context, Ownable, ERC20 {
|
||||
contract CommunityERC20 is Context, Ownable, ERC20, CommunityOwnable {
|
||||
error CommunityERC20_MaxSupplyLowerThanTotalSupply();
|
||||
error CommunityERC20_MaxSupplyReached();
|
||||
error CommunityERC20_MismatchingAddressesAndAmountsLengths();
|
||||
|
@ -21,9 +22,12 @@ contract CommunityERC20 is Context, Ownable, ERC20 {
|
|||
string memory _name,
|
||||
string memory _symbol,
|
||||
uint8 _decimals,
|
||||
uint256 _maxSupply
|
||||
uint256 _maxSupply,
|
||||
address _ownerToken,
|
||||
address _masterToken
|
||||
)
|
||||
ERC20(_name, _symbol)
|
||||
CommunityOwnable(_ownerToken, _masterToken)
|
||||
{
|
||||
maxSupply = _maxSupply;
|
||||
customDecimals = _decimals;
|
||||
|
@ -33,7 +37,7 @@ contract CommunityERC20 is Context, Ownable, ERC20 {
|
|||
|
||||
// External functions
|
||||
|
||||
function setMaxSupply(uint256 newMaxSupply) external onlyOwner {
|
||||
function setMaxSupply(uint256 newMaxSupply) external onlyCommunityOwnerOrTokenMaster {
|
||||
if (newMaxSupply < totalSupply()) {
|
||||
revert CommunityERC20_MaxSupplyLowerThanTotalSupply();
|
||||
}
|
||||
|
@ -45,7 +49,7 @@ contract CommunityERC20 is Context, Ownable, ERC20 {
|
|||
* an amount specified in `amounts`.
|
||||
*
|
||||
*/
|
||||
function mintTo(address[] memory addresses, uint256[] memory amounts) external onlyOwner {
|
||||
function mintTo(address[] memory addresses, uint256[] memory amounts) external onlyCommunityOwnerOrTokenMaster {
|
||||
if (addresses.length != amounts.length) {
|
||||
revert CommunityERC20_MismatchingAddressesAndAmountsLengths();
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
pragma solidity ^0.8.17;
|
||||
|
||||
import { BaseToken } from "./BaseToken.sol";
|
||||
import { CommunityOwnable } from "../CommunityOwnable.sol";
|
||||
|
||||
contract OwnerToken is BaseToken {
|
||||
bytes public signerPublicKey;
|
||||
|
@ -21,11 +22,11 @@ contract OwnerToken is BaseToken {
|
|||
_mintTo(addresses);
|
||||
}
|
||||
|
||||
function setMaxSupply(uint256 _newMaxSupply) external override onlyOwner {
|
||||
function setMaxSupply(uint256 _newMaxSupply) external override onlyCommunityOwnerOrTokenMaster {
|
||||
revert("max supply locked");
|
||||
}
|
||||
|
||||
function setSignerPublicKey(bytes memory _newSignerPublicKey) external onlyOwner {
|
||||
function setSignerPublicKey(bytes memory _newSignerPublicKey) external onlyCommunityOwnerOrTokenMaster {
|
||||
signerPublicKey = _newSignerPublicKey;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,18 +15,18 @@ contract DeployOwnerAndMasterToken is BaseScript {
|
|||
|
||||
vm.startBroadcast(broadcaster);
|
||||
OwnerToken ownerToken = new OwnerToken(
|
||||
ownerTokenConfig.name,
|
||||
ownerTokenConfig.symbol,
|
||||
ownerTokenConfig.baseURI,
|
||||
broadcaster,
|
||||
ownerTokenConfig.signerPublicKey
|
||||
ownerTokenConfig.name,
|
||||
ownerTokenConfig.symbol,
|
||||
ownerTokenConfig.baseURI,
|
||||
broadcaster,
|
||||
ownerTokenConfig.signerPublicKey
|
||||
);
|
||||
|
||||
MasterToken masterToken = new MasterToken(
|
||||
masterTokenConfig.name,
|
||||
masterTokenConfig.symbol,
|
||||
masterTokenConfig.baseURI,
|
||||
address(ownerToken)
|
||||
masterTokenConfig.name,
|
||||
masterTokenConfig.symbol,
|
||||
masterTokenConfig.baseURI,
|
||||
address(ownerToken)
|
||||
);
|
||||
vm.stopBroadcast();
|
||||
|
||||
|
|
|
@ -20,7 +20,9 @@ contract DeploymentConfig is Script {
|
|||
address public immutable deployer;
|
||||
|
||||
constructor(address _broadcaster) {
|
||||
if (_broadcaster == address(0)) revert DeploymentConfig_InvalidDeployerAddress();
|
||||
if (_broadcaster == address(0)) {
|
||||
revert DeploymentConfig_InvalidDeployerAddress();
|
||||
}
|
||||
deployer = _broadcaster;
|
||||
if (block.chainid == 31_337) {
|
||||
(ownerTokenConfig, masterTokenConfig) = getOrCreateAnvilEthConfig();
|
||||
|
|
|
@ -4,6 +4,7 @@ pragma solidity ^0.8.17;
|
|||
import { Test } from "forge-std/Test.sol";
|
||||
import { DeployOwnerAndMasterToken } from "../script/DeployOwnerAndMasterToken.s.sol";
|
||||
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
|
||||
import { CommunityOwnable } from "../contracts/CommunityOwnable.sol";
|
||||
import { BaseToken } from "../contracts/tokens/BaseToken.sol";
|
||||
import { OwnerToken } from "../contracts/tokens/OwnerToken.sol";
|
||||
import { MasterToken } from "../contracts/tokens/MasterToken.sol";
|
||||
|
@ -60,7 +61,7 @@ contract MintToTest is CollectibleV1Test {
|
|||
}
|
||||
|
||||
function test_RevertWhen_SenderIsNotOwner() public {
|
||||
vm.expectRevert(BaseToken.BaseToken_NotAuthorized.selector);
|
||||
vm.expectRevert(CommunityOwnable.CommunityOwnable_NotAuthorized.selector);
|
||||
collectibleV1.mintTo(accounts);
|
||||
}
|
||||
|
||||
|
@ -98,7 +99,7 @@ contract RemoteBurnTest is CollectibleV1Test {
|
|||
function test_RevertWhen_SenderIsNotOwner() public {
|
||||
uint256[] memory ids = new uint256[](1);
|
||||
ids[0] = 0;
|
||||
vm.expectRevert(BaseToken.BaseToken_NotAuthorized.selector);
|
||||
vm.expectRevert(CommunityOwnable.CommunityOwnable_NotAuthorized.selector);
|
||||
collectibleV1.remoteBurn(ids);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,17 @@ pragma solidity ^0.8.17;
|
|||
|
||||
import { Test } from "forge-std/Test.sol";
|
||||
import { CommunityERC20 } from "../contracts/tokens/CommunityERC20.sol";
|
||||
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
|
||||
import { DeployOwnerAndMasterToken } from "../script/DeployOwnerAndMasterToken.s.sol";
|
||||
import { OwnerToken } from "../contracts/tokens/OwnerToken.sol";
|
||||
import { MasterToken } from "../contracts/tokens/MasterToken.sol";
|
||||
import { CommunityOwnable } from "../contracts/CommunityOwnable.sol";
|
||||
|
||||
contract CommunityERC20Test is Test {
|
||||
CommunityERC20 internal communityToken;
|
||||
|
||||
address[] internal accounts = new address[](4);
|
||||
address internal deployer;
|
||||
|
||||
string internal name = "Test";
|
||||
string internal symbol = "TEST";
|
||||
|
@ -15,7 +21,19 @@ contract CommunityERC20Test is Test {
|
|||
uint8 internal decimals = 18;
|
||||
|
||||
function setUp() public virtual {
|
||||
communityToken = new CommunityERC20(name, symbol, decimals, maxSupply);
|
||||
DeployOwnerAndMasterToken deployment = new DeployOwnerAndMasterToken();
|
||||
(OwnerToken ownerToken, MasterToken masterToken, DeploymentConfig deploymentConfig) = deployment.run();
|
||||
|
||||
deployer = deploymentConfig.deployer();
|
||||
|
||||
communityToken = new CommunityERC20(
|
||||
name,
|
||||
symbol,
|
||||
decimals,
|
||||
maxSupply,
|
||||
address(ownerToken),
|
||||
address(masterToken)
|
||||
);
|
||||
|
||||
accounts[0] = makeAddr("one");
|
||||
accounts[1] = makeAddr("two");
|
||||
|
@ -38,7 +56,7 @@ contract SetMaxSupplyTest is CommunityERC20Test {
|
|||
|
||||
function test_RevertWhen_SenderIsNotOwner() public {
|
||||
vm.prank(makeAddr("notOwner"));
|
||||
vm.expectRevert(bytes("Ownable: caller is not the owner"));
|
||||
vm.expectRevert(CommunityOwnable.CommunityOwnable_NotAuthorized.selector);
|
||||
communityToken.setMaxSupply(1000);
|
||||
}
|
||||
|
||||
|
@ -48,12 +66,18 @@ contract SetMaxSupplyTest is CommunityERC20Test {
|
|||
amounts[1] = 15;
|
||||
amounts[2] = 5;
|
||||
amounts[3] = 20;
|
||||
|
||||
vm.startPrank(deployer);
|
||||
|
||||
communityToken.mintTo(accounts, amounts); // totalSupply is now 50
|
||||
vm.expectRevert(CommunityERC20.CommunityERC20_MaxSupplyLowerThanTotalSupply.selector);
|
||||
communityToken.setMaxSupply(40);
|
||||
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function test_SetMaxSupply() public {
|
||||
vm.prank(deployer);
|
||||
communityToken.setMaxSupply(1000);
|
||||
assertEq(communityToken.maxSupply(), 1000);
|
||||
}
|
||||
|
@ -71,6 +95,7 @@ contract MintToTest is CommunityERC20Test {
|
|||
amounts[2] = 5;
|
||||
|
||||
vm.expectRevert(CommunityERC20.CommunityERC20_MismatchingAddressesAndAmountsLengths.selector);
|
||||
vm.prank(deployer);
|
||||
communityToken.mintTo(accounts, amounts);
|
||||
}
|
||||
|
||||
|
@ -82,6 +107,7 @@ contract MintToTest is CommunityERC20Test {
|
|||
amounts[3] = 1; // this should exceed max supply
|
||||
|
||||
vm.expectRevert(CommunityERC20.CommunityERC20_MaxSupplyReached.selector);
|
||||
vm.prank(deployer);
|
||||
communityToken.mintTo(accounts, amounts);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ pragma solidity ^0.8.17;
|
|||
import { Test } from "forge-std/Test.sol";
|
||||
import { DeployOwnerAndMasterToken } from "../script/DeployOwnerAndMasterToken.s.sol";
|
||||
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
|
||||
import { CommunityOwnable } from "../contracts/CommunityOwnable.sol";
|
||||
import { BaseToken } from "../contracts/tokens/BaseToken.sol";
|
||||
import { OwnerToken } from "../contracts/tokens/OwnerToken.sol";
|
||||
import { MasterToken } from "../contracts/tokens/MasterToken.sol";
|
||||
|
@ -43,7 +44,7 @@ contract SetMaxSupplyTest is OwnerTokenTest {
|
|||
}
|
||||
|
||||
function test_RevertWhen_SenderIsNotOwner() public {
|
||||
vm.expectRevert(BaseToken.BaseToken_NotAuthorized.selector);
|
||||
vm.expectRevert(CommunityOwnable.CommunityOwnable_NotAuthorized.selector);
|
||||
ownerToken.setMaxSupply(1000);
|
||||
}
|
||||
|
||||
|
@ -60,7 +61,7 @@ contract SetSignerPublicKeyTest is OwnerTokenTest {
|
|||
}
|
||||
|
||||
function test_RevertWhen_SenderIsNotOwner() public {
|
||||
vm.expectRevert(BaseToken.BaseToken_NotAuthorized.selector);
|
||||
vm.expectRevert(CommunityOwnable.CommunityOwnable_NotAuthorized.selector);
|
||||
ownerToken.setSignerPublicKey(bytes("some key"));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue