mirror of
https://github.com/vacp2p/minime.git
synced 2026-01-07 22:34:03 -05:00
remove minimetokenfactory
This commit is contained in:
30
.gas-report
30
.gas-report
@@ -1,32 +1,32 @@
|
|||||||
| contracts/MiniMeToken.sol:MiniMeToken contract | | | | | |
|
| contracts/MiniMeToken.sol:MiniMeToken contract | | | | | |
|
||||||
|------------------------------------------------|-----------------|-------|--------|-------|---------|
|
|------------------------------------------------|-----------------|-------|--------|-------|---------|
|
||||||
| Deployment Cost | Deployment Size | | | | |
|
| Deployment Cost | Deployment Size | | | | |
|
||||||
| 2149485 | 12251 | | | | |
|
| 2136695 | 12097 | | | | |
|
||||||
| Function Name | min | avg | median | max | # calls |
|
| Function Name | min | avg | median | max | # calls |
|
||||||
| DOMAIN_SEPARATOR | 365 | 365 | 365 | 365 | 10 |
|
| DOMAIN_SEPARATOR | 387 | 387 | 387 | 387 | 10 |
|
||||||
| allowance | 0 | 202 | 0 | 808 | 16 |
|
| allowance | 0 | 190 | 0 | 763 | 16 |
|
||||||
| approve | 0 | 15064 | 14767 | 31771 | 10 |
|
| approve | 0 | 15064 | 14767 | 31771 | 10 |
|
||||||
| approveAndCall | 0 | 31232 | 0 | 93698 | 3 |
|
| approveAndCall | 0 | 31210 | 0 | 93632 | 3 |
|
||||||
| balanceOf | 0 | 657 | 0 | 2731 | 67 |
|
| balanceOf | 0 | 663 | 0 | 2753 | 67 |
|
||||||
| balanceOfAt | 0 | 905 | 0 | 4027 | 78 |
|
| balanceOfAt | 0 | 890 | 0 | 3982 | 78 |
|
||||||
| changeController | 0 | 593 | 0 | 3558 | 6 |
|
| changeController | 0 | 596 | 0 | 3580 | 6 |
|
||||||
| claimTokens | 9537 | 41267 | 57132 | 57132 | 3 |
|
| claimTokens | 9559 | 41318 | 57198 | 57198 | 3 |
|
||||||
| controller | 0 | 0 | 0 | 0 | 10 |
|
| controller | 0 | 0 | 0 | 0 | 10 |
|
||||||
| decimals | 0 | 0 | 0 | 0 | 10 |
|
| decimals | 0 | 0 | 0 | 0 | 10 |
|
||||||
| destroyTokens | 2286 | 5185 | 4288 | 8983 | 3 |
|
| destroyTokens | 2308 | 5207 | 4310 | 9005 | 3 |
|
||||||
| enableTransfers | 0 | 0 | 0 | 0 | 3 |
|
| enableTransfers | 0 | 0 | 0 | 0 | 3 |
|
||||||
| generateTokens | 0 | 16532 | 0 | 95885 | 64 |
|
| generateTokens | 0 | 16512 | 0 | 95730 | 64 |
|
||||||
| name | 0 | 0 | 0 | 0 | 10 |
|
| name | 0 | 0 | 0 | 0 | 10 |
|
||||||
| nonces | 632 | 1832 | 2632 | 2632 | 5 |
|
| nonces | 654 | 1854 | 2654 | 2654 | 5 |
|
||||||
| parentSnapShotBlock | 0 | 0 | 0 | 0 | 11 |
|
| parentSnapShotBlock | 0 | 0 | 0 | 0 | 11 |
|
||||||
| parentToken | 0 | 0 | 0 | 0 | 11 |
|
| parentToken | 0 | 0 | 0 | 0 | 11 |
|
||||||
| permit | 689 | 39800 | 53934 | 58434 | 10 |
|
| permit | 711 | 39822 | 53956 | 58456 | 10 |
|
||||||
| receive | 7960 | 7979 | 7979 | 7998 | 2 |
|
| receive | 7960 | 7979 | 7979 | 7998 | 2 |
|
||||||
| symbol | 0 | 0 | 0 | 0 | 10 |
|
| symbol | 0 | 0 | 0 | 0 | 10 |
|
||||||
| totalSupply | 0 | 274 | 0 | 2480 | 23 |
|
| totalSupply | 0 | 274 | 0 | 2480 | 23 |
|
||||||
| totalSupplyAt | 0 | 873 | 0 | 3659 | 17 |
|
| totalSupplyAt | 0 | 859 | 0 | 3614 | 17 |
|
||||||
| transfer | 526 | 39283 | 50395 | 93092 | 20 |
|
| transfer | 548 | 39300 | 50417 | 93024 | 20 |
|
||||||
| transferFrom | 0 | 19678 | 3495 | 66574 | 11 |
|
| transferFrom | 0 | 19676 | 3495 | 66551 | 11 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,55 +1,55 @@
|
|||||||
AllowanceTest:testAllowance() (gas: 42775)
|
AllowanceTest:testAllowance() (gas: 42775)
|
||||||
AllowanceTest:testAllowanceAlreadySet() (gas: 36905)
|
AllowanceTest:testAllowanceAlreadySet() (gas: 36905)
|
||||||
AllowanceTest:testAllowanceReset() (gas: 46071)
|
AllowanceTest:testAllowanceReset() (gas: 46071)
|
||||||
AllowanceTest:testApproveAndCall() (gas: 98617)
|
AllowanceTest:testApproveAndCall() (gas: 98551)
|
||||||
AllowanceTest:testApproveTransferDisabled() (gas: 7994)
|
AllowanceTest:testApproveTransferDisabled() (gas: 7994)
|
||||||
AllowanceTest:testDeployment() (gas: 26711)
|
AllowanceTest:testDeployment() (gas: 26711)
|
||||||
AllowanceTest:testNoAllowance() (gas: 9462)
|
AllowanceTest:testNoAllowance() (gas: 9462)
|
||||||
AllowanceTest:testRejectedApproval() (gas: 13683)
|
AllowanceTest:testRejectedApproval() (gas: 13683)
|
||||||
ClaimTokensTest:testClaimERC20() (gas: 63718)
|
ClaimTokensTest:testClaimERC20() (gas: 63784)
|
||||||
ClaimTokensTest:testClaimETH() (gas: 13637)
|
ClaimTokensTest:testClaimETH() (gas: 13659)
|
||||||
ClaimTokensTest:testClaimSelf() (gas: 61200)
|
ClaimTokensTest:testClaimSelf() (gas: 61266)
|
||||||
ClaimTokensTest:testDeployment() (gas: 26595)
|
ClaimTokensTest:testDeployment() (gas: 26595)
|
||||||
CreateCloneTokenTest:testCloneFutureSnapshot() (gas: 101288)
|
CreateCloneTokenTest:testCloneFutureSnapshot() (gas: 101242)
|
||||||
CreateCloneTokenTest:testCreateCloneToken() (gas: 2190766)
|
CreateCloneTokenTest:testCreateCloneToken() (gas: 2175810)
|
||||||
CreateCloneTokenTest:testDeployment() (gas: 26550)
|
CreateCloneTokenTest:testDeployment() (gas: 26550)
|
||||||
CreateCloneTokenTest:testGenerateTokens() (gas: 102171)
|
CreateCloneTokenTest:testGenerateTokens() (gas: 102016)
|
||||||
DestroyTokensTest:testDeployment() (gas: 26595)
|
DestroyTokensTest:testDeployment() (gas: 26595)
|
||||||
DestroyTokensTest:testDestroyTokens() (gas: 13483)
|
DestroyTokensTest:testDestroyTokens() (gas: 13505)
|
||||||
DestroyTokensTest:testDestroyTokensNotEnoughBalance() (gas: 9644)
|
DestroyTokensTest:testDestroyTokensNotEnoughBalance() (gas: 9666)
|
||||||
DestroyTokensTest:testDestroyTokensNotEnoughSupply() (gas: 7975)
|
DestroyTokensTest:testDestroyTokensNotEnoughSupply() (gas: 7997)
|
||||||
GenerateTokensTest:testDeployment() (gas: 26550)
|
GenerateTokensTest:testDeployment() (gas: 26550)
|
||||||
GenerateTokensTest:testGenerateTokens() (gas: 109587)
|
GenerateTokensTest:testGenerateTokens() (gas: 109522)
|
||||||
GenerateTokensTest:testGenerateTokensSupplyOverflow() (gas: 3126)
|
GenerateTokensTest:testGenerateTokensSupplyOverflow() (gas: 3126)
|
||||||
GenerateTokensTest:test_RevertWhen_SenderIsNotController() (gas: 15016)
|
GenerateTokensTest:test_RevertWhen_SenderIsNotController() (gas: 14951)
|
||||||
MiniMeTokenTest:testDeployment() (gas: 26535)
|
MiniMeTokenTest:testDeployment() (gas: 26535)
|
||||||
ReceiveTest:testAcceptingEther() (gas: 18628)
|
ReceiveTest:testAcceptingEther() (gas: 18628)
|
||||||
ReceiveTest:testDeployment() (gas: 26595)
|
ReceiveTest:testDeployment() (gas: 26595)
|
||||||
ReceiveTest:testRejectingEther() (gas: 18691)
|
ReceiveTest:testRejectingEther() (gas: 18691)
|
||||||
ReentrancyTest:testAttack() (gas: 229445)
|
ReentrancyTest:testAttack() (gas: 229445)
|
||||||
TestPermit:testDeployment() (gas: 26573)
|
TestPermit:testDeployment() (gas: 26573)
|
||||||
TestPermit:testInvalidAllowance() (gas: 84292)
|
TestPermit:testInvalidAllowance() (gas: 84299)
|
||||||
TestPermit:testInvalidBalance() (gas: 67373)
|
TestPermit:testInvalidBalance() (gas: 67380)
|
||||||
TestPermit:testPermit() (gas: 84495)
|
TestPermit:testPermit() (gas: 84479)
|
||||||
TestPermit:testRevertExpiredPermit() (gas: 27826)
|
TestPermit:testRevertExpiredPermit() (gas: 27867)
|
||||||
TestPermit:testRevertInvalidNonce() (gas: 57205)
|
TestPermit:testRevertInvalidNonce() (gas: 57221)
|
||||||
TestPermit:testRevertInvalidSigner() (gas: 56018)
|
TestPermit:testRevertInvalidSigner() (gas: 56059)
|
||||||
TestPermit:testRevertSignatureReplay() (gas: 96492)
|
TestPermit:testRevertSignatureReplay() (gas: 96568)
|
||||||
TestPermit:testTransferFromLimitedPermit() (gas: 216206)
|
TestPermit:testTransferFromLimitedPermit() (gas: 216135)
|
||||||
TestPermit:testTransferFromMaxPermit() (gas: 236145)
|
TestPermit:testTransferFromMaxPermit() (gas: 236074)
|
||||||
TestSnapshotReads:testDeployment() (gas: 26550)
|
TestSnapshotReads:testDeployment() (gas: 26550)
|
||||||
TestSnapshotReads:testSnapshotReads() (gas: 756322)
|
TestSnapshotReads:testSnapshotReads() (gas: 754393)
|
||||||
TransferTest:testDeployment() (gas: 26617)
|
TransferTest:testDeployment() (gas: 26617)
|
||||||
TransferTest:testDoubleTransfer() (gas: 92425)
|
TransferTest:testDoubleTransfer() (gas: 92469)
|
||||||
TransferTest:testDoubleTransfer2() (gas: 70578)
|
TransferTest:testDoubleTransfer2() (gas: 70622)
|
||||||
TransferTest:testInvalidDestinationTransfer() (gas: 6402)
|
TransferTest:testInvalidDestinationTransfer() (gas: 6424)
|
||||||
TransferTest:testInvalidDestinationTransfer2() (gas: 6399)
|
TransferTest:testInvalidDestinationTransfer2() (gas: 6421)
|
||||||
TransferTest:testMultipleTransferToSame() (gas: 114655)
|
TransferTest:testMultipleTransferToSame() (gas: 114699)
|
||||||
TransferTest:testMultipleTransferToSame2() (gas: 92852)
|
TransferTest:testMultipleTransferToSame2() (gas: 92896)
|
||||||
TransferTest:testRejectedTransfer() (gas: 59921)
|
TransferTest:testRejectedTransfer() (gas: 59943)
|
||||||
TransferTest:testTransfer() (gas: 81718)
|
TransferTest:testTransfer() (gas: 81740)
|
||||||
TransferTest:testTransfer2() (gas: 59894)
|
TransferTest:testTransfer2() (gas: 59916)
|
||||||
TransferTest:testTransferControllerZero() (gas: 59841)
|
TransferTest:testTransferControllerZero() (gas: 59863)
|
||||||
TransferTest:testTransferDisabled() (gas: 7968)
|
TransferTest:testTransferDisabled() (gas: 7990)
|
||||||
TransferTest:testTransferFromDisabled() (gas: 6526)
|
TransferTest:testTransferFromDisabled() (gas: 6526)
|
||||||
TransferTest:testTransferNoBalance() (gas: 16927)
|
TransferTest:testTransferNoBalance() (gas: 16949)
|
||||||
@@ -2,20 +2,13 @@
|
|||||||
pragma solidity ^0.8.0;
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
import { MiniMeBase } from "./MiniMeBase.sol";
|
import { MiniMeBase } from "./MiniMeBase.sol";
|
||||||
import { MiniMeTokenFactory } from "./MiniMeTokenFactory.sol";
|
|
||||||
|
|
||||||
contract MiniMeToken is MiniMeBase {
|
contract MiniMeToken is MiniMeBase {
|
||||||
// The factory used to create new clone tokens
|
|
||||||
MiniMeTokenFactory public immutable tokenFactory;
|
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// Constructor
|
// Constructor
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
/// @notice Constructor to create a MiniMeToken
|
/// @notice Constructor to create a MiniMeToken
|
||||||
/// @param _tokenFactory The address of the MiniMeTokenFactory contract that
|
|
||||||
/// will create the Clone token contracts, the token factory needs to be
|
|
||||||
/// deployed first
|
|
||||||
/// @param _parentToken Address of the parent token, set to 0x0 if it is a
|
/// @param _parentToken Address of the parent token, set to 0x0 if it is a
|
||||||
/// new token
|
/// new token
|
||||||
/// @param _parentSnapShotBlock Block of the parent token that will
|
/// @param _parentSnapShotBlock Block of the parent token that will
|
||||||
@@ -26,7 +19,6 @@ contract MiniMeToken is MiniMeBase {
|
|||||||
/// @param _tokenSymbol Token Symbol for the new token
|
/// @param _tokenSymbol Token Symbol for the new token
|
||||||
/// @param _transfersEnabled If true, tokens will be able to be transferred
|
/// @param _transfersEnabled If true, tokens will be able to be transferred
|
||||||
constructor(
|
constructor(
|
||||||
MiniMeTokenFactory _tokenFactory,
|
|
||||||
MiniMeToken _parentToken,
|
MiniMeToken _parentToken,
|
||||||
uint256 _parentSnapShotBlock,
|
uint256 _parentSnapShotBlock,
|
||||||
string memory _tokenName,
|
string memory _tokenName,
|
||||||
@@ -35,9 +27,7 @@ contract MiniMeToken is MiniMeBase {
|
|||||||
bool _transfersEnabled
|
bool _transfersEnabled
|
||||||
)
|
)
|
||||||
MiniMeBase(_parentToken, _parentSnapShotBlock, _tokenName, _decimalUnits, _tokenSymbol, _transfersEnabled)
|
MiniMeBase(_parentToken, _parentSnapShotBlock, _tokenName, _decimalUnits, _tokenSymbol, _transfersEnabled)
|
||||||
{
|
{ }
|
||||||
tokenFactory = _tokenFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// Generate and destroy tokens
|
// Generate and destroy tokens
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
pragma solidity ^0.8.0;
|
|
||||||
|
|
||||||
import { MiniMeToken } from "./MiniMeToken.sol";
|
|
||||||
|
|
||||||
/// @title MiniMeToken Factory Contract
|
|
||||||
/// @dev This contract is used to generate clone contracts from a contract.
|
|
||||||
/// In solidity this is the way to create a contract from a contract of the
|
|
||||||
/// same class
|
|
||||||
contract MiniMeTokenFactory {
|
|
||||||
/// @notice Update the DApp by creating a new token with new functionalities
|
|
||||||
/// the msg.sender becomes the controller of this clone token
|
|
||||||
/// @param _parentToken Address of the token being cloned
|
|
||||||
/// @param _snapshotBlock Block of the parent token that will
|
|
||||||
/// determine the initial distribution of the clone token
|
|
||||||
/// @param _tokenName Name of the new token
|
|
||||||
/// @param _decimalUnits Number of decimals of the new token
|
|
||||||
/// @param _tokenSymbol Token Symbol for the new token
|
|
||||||
/// @param _transfersEnabled If true, tokens will be able to be transferred
|
|
||||||
/// @return The address of the new token contract
|
|
||||||
function createCloneToken(
|
|
||||||
MiniMeToken _parentToken,
|
|
||||||
uint256 _snapshotBlock,
|
|
||||||
string memory _tokenName,
|
|
||||||
uint8 _decimalUnits,
|
|
||||||
string memory _tokenSymbol,
|
|
||||||
bool _transfersEnabled
|
|
||||||
)
|
|
||||||
public
|
|
||||||
returns (MiniMeToken)
|
|
||||||
{
|
|
||||||
MiniMeToken newToken = new MiniMeToken(
|
|
||||||
this,
|
|
||||||
_parentToken,
|
|
||||||
_snapshotBlock,
|
|
||||||
_tokenName,
|
|
||||||
_decimalUnits,
|
|
||||||
_tokenSymbol,
|
|
||||||
_transfersEnabled
|
|
||||||
);
|
|
||||||
|
|
||||||
newToken.changeController(payable(msg.sender));
|
|
||||||
return newToken;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,13 +5,9 @@ import { BaseScript } from "./Base.s.sol";
|
|||||||
import { DeploymentConfig } from "./DeploymentConfig.s.sol";
|
import { DeploymentConfig } from "./DeploymentConfig.s.sol";
|
||||||
|
|
||||||
import { MiniMeToken } from "../contracts/MiniMeToken.sol";
|
import { MiniMeToken } from "../contracts/MiniMeToken.sol";
|
||||||
import { MiniMeTokenFactory } from "../contracts/MiniMeToken.sol";
|
|
||||||
|
|
||||||
contract Deploy is BaseScript {
|
contract Deploy is BaseScript {
|
||||||
function run()
|
function run() public returns (DeploymentConfig deploymentConfig, MiniMeToken minimeToken) {
|
||||||
public
|
|
||||||
returns (DeploymentConfig deploymentConfig, MiniMeTokenFactory minimeFactory, MiniMeToken minimeToken)
|
|
||||||
{
|
|
||||||
deploymentConfig = new DeploymentConfig(broadcaster);
|
deploymentConfig = new DeploymentConfig(broadcaster);
|
||||||
(
|
(
|
||||||
,
|
,
|
||||||
@@ -24,9 +20,7 @@ contract Deploy is BaseScript {
|
|||||||
) = deploymentConfig.activeNetworkConfig();
|
) = deploymentConfig.activeNetworkConfig();
|
||||||
|
|
||||||
vm.startBroadcast(broadcaster);
|
vm.startBroadcast(broadcaster);
|
||||||
minimeFactory = new MiniMeTokenFactory();
|
|
||||||
minimeToken = new MiniMeToken(
|
minimeToken = new MiniMeToken(
|
||||||
minimeFactory,
|
|
||||||
MiniMeToken(payable(parentToken)),
|
MiniMeToken(payable(parentToken)),
|
||||||
parentSnapShotBlock,
|
parentSnapShotBlock,
|
||||||
name,
|
name,
|
||||||
|
|||||||
@@ -20,12 +20,10 @@ import {
|
|||||||
IERC20
|
IERC20
|
||||||
} from "../contracts/MiniMeBase.sol";
|
} from "../contracts/MiniMeBase.sol";
|
||||||
import { MiniMeToken } from "../contracts/MiniMeToken.sol";
|
import { MiniMeToken } from "../contracts/MiniMeToken.sol";
|
||||||
import { MiniMeTokenFactory } from "../contracts/MiniMeTokenFactory.sol";
|
|
||||||
import { ApproveAndCallFallBack } from "../contracts/ApproveAndCallFallBack.sol";
|
import { ApproveAndCallFallBack } from "../contracts/ApproveAndCallFallBack.sol";
|
||||||
|
|
||||||
contract MiniMeTokenTest is Test {
|
contract MiniMeTokenTest is Test {
|
||||||
DeploymentConfig internal deploymentConfig;
|
DeploymentConfig internal deploymentConfig;
|
||||||
MiniMeTokenFactory internal minimeTokenFactory;
|
|
||||||
MiniMeToken internal minimeToken;
|
MiniMeToken internal minimeToken;
|
||||||
|
|
||||||
address internal deployer;
|
address internal deployer;
|
||||||
@@ -34,7 +32,7 @@ contract MiniMeTokenTest is Test {
|
|||||||
|
|
||||||
function setUp() public virtual {
|
function setUp() public virtual {
|
||||||
Deploy deployment = new Deploy();
|
Deploy deployment = new Deploy();
|
||||||
(deploymentConfig, minimeTokenFactory, minimeToken) = deployment.run();
|
(deploymentConfig, minimeToken) = deployment.run();
|
||||||
(deployer,,,,,,) = deploymentConfig.activeNetworkConfig();
|
(deployer,,,,,,) = deploymentConfig.activeNetworkConfig();
|
||||||
|
|
||||||
accounts = new address[](4);
|
accounts = new address[](4);
|
||||||
@@ -739,7 +737,6 @@ contract CreateCloneTokenTest is MiniMeTokenTest {
|
|||||||
|
|
||||||
function _createClone() internal returns (MiniMeToken clone) {
|
function _createClone() internal returns (MiniMeToken clone) {
|
||||||
return new MiniMeToken(
|
return new MiniMeToken(
|
||||||
minimeTokenFactory,
|
|
||||||
minimeToken,
|
minimeToken,
|
||||||
block.number,
|
block.number,
|
||||||
"Clone Token 1",
|
"Clone Token 1",
|
||||||
@@ -899,8 +896,7 @@ contract CreateCloneTokenTest is MiniMeTokenTest {
|
|||||||
_generateTokens(accounts[0], 10);
|
_generateTokens(accounts[0], 10);
|
||||||
|
|
||||||
vm.prank(accounts[3]);
|
vm.prank(accounts[3]);
|
||||||
MiniMeToken clone = new MiniMeToken(
|
MiniMeToken clone = new MiniMeToken(
|
||||||
minimeTokenFactory,
|
|
||||||
minimeToken,
|
minimeToken,
|
||||||
block.number+1,
|
block.number+1,
|
||||||
"TestFutureSnapshot",
|
"TestFutureSnapshot",
|
||||||
@@ -936,7 +932,6 @@ contract ClaimTokensTest is MiniMeTokenTest {
|
|||||||
vm.pauseGasMetering();
|
vm.pauseGasMetering();
|
||||||
vm.startPrank(deployer);
|
vm.startPrank(deployer);
|
||||||
MiniMeToken claimTest = new MiniMeToken(
|
MiniMeToken claimTest = new MiniMeToken(
|
||||||
minimeTokenFactory,
|
|
||||||
MiniMeToken(payable(address(0))),
|
MiniMeToken(payable(address(0))),
|
||||||
0,
|
0,
|
||||||
"TestClaim",
|
"TestClaim",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ contract ReentrancyTest is Test {
|
|||||||
|
|
||||||
function setUp() public {
|
function setUp() public {
|
||||||
Deploy deployment = new Deploy();
|
Deploy deployment = new Deploy();
|
||||||
(deploymentConfig,, minimeToken) = deployment.run();
|
(deploymentConfig, minimeToken) = deployment.run();
|
||||||
(deployer,,,,,,) = deploymentConfig.activeNetworkConfig();
|
(deployer,,,,,,) = deploymentConfig.activeNetworkConfig();
|
||||||
|
|
||||||
vm.prank(attackerEOA);
|
vm.prank(attackerEOA);
|
||||||
|
|||||||
Reference in New Issue
Block a user