From 3f95a3bcf9689f998008149afc61b7f07b0a8a2a Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Fri, 22 Sep 2023 16:08:59 -0300 Subject: [PATCH] make abstract and concrete versions add gas reports move event from abstract to concrete lint --- .gas-report | 14 ++--- .gas-snapshot | 14 ++--- contracts/MiniMeBase.sol | 79 ++++--------------------- contracts/MiniMeToken.sol | 99 ++++++++++++++++++++++++++++++++ contracts/MiniMeTokenFactory.sol | 2 +- 5 files changed, 126 insertions(+), 82 deletions(-) create mode 100644 contracts/MiniMeToken.sol diff --git a/.gas-report b/.gas-report index e539892..cb457e3 100644 --- a/.gas-report +++ b/.gas-report @@ -1,7 +1,7 @@ | contracts/MiniMeToken.sol:MiniMeToken contract | | | | | | |------------------------------------------------|-----------------|---------|---------|---------|---------| | Deployment Cost | Deployment Size | | | | | -| 1788057 | 9919 | | | | | +| 1793495 | 9955 | | | | | | Function Name | min | avg | median | max | # calls | | allowance | 808 | 808 | 808 | 808 | 3 | | approve | 30781 | 31244 | 31244 | 31708 | 2 | @@ -9,16 +9,16 @@ | balanceOfAt | 1142 | 2585 | 2363 | 3603 | 26 | | changeController | 758 | 1318 | 758 | 3558 | 5 | | controller | 2447 | 2447 | 2447 | 2447 | 6 | -| createCloneToken | 1832796 | 1832796 | 1832796 | 1832796 | 2 | +| createCloneToken | 1838245 | 1838245 | 1838245 | 1838245 | 2 | | decimals | 294 | 294 | 294 | 294 | 6 | -| destroyTokens | 8956 | 8956 | 8956 | 8956 | 1 | -| generateTokens | 2541 | 82036 | 94453 | 95751 | 11 | +| destroyTokens | 9001 | 9001 | 9001 | 9001 | 1 | +| generateTokens | 2541 | 82077 | 94498 | 95796 | 11 | | name | 3253 | 3253 | 3253 | 3253 | 6 | | parentSnapShotBlock | 284 | 284 | 284 | 284 | 7 | | parentToken | 305 | 305 | 305 | 305 | 7 | | symbol | 3274 | 3274 | 3274 | 3274 | 6 | | totalSupply | 1911 | 2917 | 1911 | 4930 | 6 | -| totalSupplyAt | 1995 | 3029 | 3003 | 4606 | 7 | +| totalSupplyAt | 1995 | 3028 | 3003 | 4603 | 7 | | transfer | 75187 | 75187 | 75187 | 75187 | 1 | | transferFrom | 3495 | 48093 | 66590 | 74194 | 3 | @@ -26,9 +26,9 @@ | contracts/MiniMeTokenFactory.sol:MiniMeTokenFactory contract | | | | | | |--------------------------------------------------------------|-----------------|---------|---------|---------|---------| | Deployment Cost | Deployment Size | | | | | -| 2111243 | 10577 | | | | | +| 2118450 | 10613 | | | | | | Function Name | min | avg | median | max | # calls | -| createCloneToken | 1825218 | 1825218 | 1825218 | 1825218 | 2 | +| createCloneToken | 1830667 | 1830667 | 1830667 | 1830667 | 2 | diff --git a/.gas-snapshot b/.gas-snapshot index f25e9ad..f362669 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,14 +1,14 @@ -AllowanceTest:testAllowance() (gas: 244240) +AllowanceTest:testAllowance() (gas: 244285) AllowanceTest:testDeployment() (gas: 45814) -CreateCloneTokenTest:testCreateCloneToken() (gas: 2165972) +CreateCloneTokenTest:testCreateCloneToken() (gas: 2171532) CreateCloneTokenTest:testDeployment() (gas: 45769) -CreateCloneTokenTest:testGenerateTokens() (gas: 2045315) +CreateCloneTokenTest:testGenerateTokens() (gas: 2050854) DestroyTokensTest:testDeployment() (gas: 45598) -DestroyTokensTest:testDestroyTokens() (gas: 124840) +DestroyTokensTest:testDestroyTokens() (gas: 124930) GenerateTokensTest:testDeployment() (gas: 45553) -GenerateTokensTest:testGenerateTokens() (gas: 114564) +GenerateTokensTest:testGenerateTokens() (gas: 114609) GenerateTokensTest:test_RevertWhen_SenderIsNotController() (gas: 14930) MiniMeTokenTest:testDeployment() (gas: 45598) -ReentrancyTest:testAttack() (gas: 229331) +ReentrancyTest:testAttack() (gas: 229376) TransferTest:testDeployment() (gas: 45814) -TransferTest:testTransfer() (gas: 201218) \ No newline at end of file +TransferTest:testTransfer() (gas: 201263) \ No newline at end of file diff --git a/contracts/MiniMeBase.sol b/contracts/MiniMeBase.sol index b490654..7a7cfd4 100644 --- a/contracts/MiniMeBase.sol +++ b/contracts/MiniMeBase.sol @@ -29,24 +29,18 @@ error ControllerNotSet(); along with this program. If not, see . */ -/// @title MiniMeToken Contract +import { Controlled } from "./Controlled.sol"; +import { TokenController } from "./TokenController.sol"; +import { ApproveAndCallFallBack } from "./ApproveAndCallFallBack.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +/// @title MiniMeBase Contract /// @author Jordi Baylina /// @dev This token contract's goal is to make it easy for anyone to clone this /// token using the token distribution at a given block, this will allow DAO's /// and DApps to upgrade their features in a decentralized manner without /// affecting the original token -/// @dev It is ERC20 compliant, but still needs to under go further testing. - -import { Controlled } from "./Controlled.sol"; -import { TokenController } from "./TokenController.sol"; -import { ApproveAndCallFallBack } from "./ApproveAndCallFallBack.sol"; -import { MiniMeTokenFactory } from "./MiniMeTokenFactory.sol"; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -/// @dev The actual token contract, the default controller is the msg.sender -/// that deploys the contract, so usually this token will be deployed by a -/// token controller contract, which Giveth will call a "Campaign" -contract MiniMeToken is Controlled, IERC20 { +abstract contract MiniMeBase is Controlled, IERC20 { string public name; //The Token's name: e.g. DigixDAO Tokens uint8 public immutable decimals; //Number of decimals of the smallest unit string public symbol; //An identifier: e.g. REP @@ -64,7 +58,7 @@ contract MiniMeToken is Controlled, IERC20 { // `parentToken` is the Token address that was cloned to produce this token; // it will be 0x0 for a token that was not cloned - MiniMeToken public immutable parentToken; + MiniMeBase public immutable parentToken; // `parentSnapShotBlock` is the block number from the Parent Token that was // used to determine the initial distribution of the Clone Token @@ -87,17 +81,7 @@ contract MiniMeToken is Controlled, IERC20 { // Flag that determines if the token is transferable or not. bool public transfersEnabled; - // The factory used to create new clone tokens - MiniMeTokenFactory public immutable tokenFactory; - - //////////////// - // Constructor - //////////////// - - /// @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 + /// @notice Constructor to create a MiniMeBase /// @param _parentToken Address of the parent token, set to 0x0 if it is a /// new token /// @param _parentSnapShotBlock Block of the parent token that will @@ -108,15 +92,13 @@ contract MiniMeToken is Controlled, IERC20 { /// @param _tokenSymbol Token Symbol for the new token /// @param _transfersEnabled If true, tokens will be able to be transferred constructor( - MiniMeTokenFactory _tokenFactory, - MiniMeToken _parentToken, + MiniMeBase _parentToken, uint256 _parentSnapShotBlock, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol, bool _transfersEnabled ) { - tokenFactory = _tokenFactory; name = _tokenName; // Set the name decimals = _decimalUnits; // Set the decimals symbol = _tokenSymbol; // Set the symbol @@ -318,42 +300,6 @@ contract MiniMeToken is Controlled, IERC20 { } } - //////////////// - // Clone Token Method - //////////////// - - /// @notice Creates a new clone token with the initial distribution being - /// this token at `_snapshotBlock` - /// @param _cloneTokenName Name of the clone token - /// @param _cloneDecimalUnits Number of decimals of the smallest unit - /// @param _cloneTokenSymbol Symbol of the clone token - /// @param _snapshotBlock Block when the distribution of the parent token is - /// copied to set the initial distribution of the new clone token; - /// if the block is zero than the actual block, the current block is used - /// @param _transfersEnabled True if transfers are allowed in the clone - /// @return The address of the new MiniMeToken Contract - function createCloneToken( - string memory _cloneTokenName, - uint8 _cloneDecimalUnits, - string memory _cloneTokenSymbol, - uint256 _snapshotBlock, - bool _transfersEnabled - ) - public - returns (address) - { - if (_snapshotBlock == 0) _snapshotBlock = block.number; - MiniMeToken cloneToken = tokenFactory.createCloneToken( - this, _snapshotBlock, _cloneTokenName, _cloneDecimalUnits, _cloneTokenSymbol, _transfersEnabled - ); - - cloneToken.changeController(payable(msg.sender)); - - // An event to make the token easy to find on the blockchain - emit NewCloneToken(address(cloneToken), _snapshotBlock); - return address(cloneToken); - } - //////////////// // Generate and destroy tokens //////////////// @@ -362,7 +308,7 @@ contract MiniMeToken is Controlled, IERC20 { /// @param _owner The address that will be assigned the new tokens /// @param _amount The quantity of tokens generated /// @return True if the tokens are generated correctly - function generateTokens(address _owner, uint256 _amount) public onlyController returns (bool) { + function mint(address _owner, uint256 _amount) internal returns (bool) { uint256 curTotalSupply = totalSupply(); if (curTotalSupply + _amount < curTotalSupply) revert Overflow(); // Check for overflow uint256 previousBalanceTo = balanceOf(_owner); @@ -377,7 +323,7 @@ contract MiniMeToken is Controlled, IERC20 { /// @param _owner The address that will lose the tokens /// @param _amount The quantity of tokens to burn /// @return True if the tokens are burned correctly - function destroyTokens(address _owner, uint256 _amount) public onlyController returns (bool) { + function burn(address _owner, uint256 _amount) internal returns (bool) { uint256 curTotalSupply = totalSupply(); if (curTotalSupply < _amount) revert NotEnoughSupply(); uint256 previousBalanceFrom = balanceOf(_owner); @@ -496,5 +442,4 @@ contract MiniMeToken is Controlled, IERC20 { // Events //////////////// event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount); - event NewCloneToken(address indexed _cloneToken, uint256 _snapshotBlock); } diff --git a/contracts/MiniMeToken.sol b/contracts/MiniMeToken.sol new file mode 100644 index 0000000..8023053 --- /dev/null +++ b/contracts/MiniMeToken.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.0; + +import { MiniMeBase } from "./MiniMeBase.sol"; +import { MiniMeTokenFactory } from "./MiniMeTokenFactory.sol"; + +contract MiniMeToken is MiniMeBase { + // The factory used to create new clone tokens + MiniMeTokenFactory public immutable tokenFactory; + + //////////////// + // Constructor + //////////////// + + /// @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 + /// new token + /// @param _parentSnapShotBlock Block of the parent token that will + /// determine the initial distribution of the clone token, set to 0 if it + /// is a new 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 + constructor( + MiniMeTokenFactory _tokenFactory, + MiniMeToken _parentToken, + uint256 _parentSnapShotBlock, + string memory _tokenName, + uint8 _decimalUnits, + string memory _tokenSymbol, + bool _transfersEnabled + ) + MiniMeBase(_parentToken, _parentSnapShotBlock, _tokenName, _decimalUnits, _tokenSymbol, _transfersEnabled) + { + tokenFactory = _tokenFactory; + } + + //////////////// + // Generate and destroy tokens + //////////////// + + /// @notice Generates `_amount` tokens that are assigned to `_owner` + /// @param _owner The address that will be assigned the new tokens + /// @param _amount The quantity of tokens generated + /// @return True if the tokens are generated correctly + function generateTokens(address _owner, uint256 _amount) public onlyController returns (bool) { + return mint(_owner, _amount); + } + + /// @notice Burns `_amount` tokens from `_owner` + /// @param _owner The address that will lose the tokens + /// @param _amount The quantity of tokens to burn + /// @return True if the tokens are burned correctly + function destroyTokens(address _owner, uint256 _amount) public onlyController returns (bool) { + return burn(_owner, _amount); + } + + //////////////// + // Clone Token Method + //////////////// + + /// @notice Creates a new clone token with the initial distribution being + /// this token at `_snapshotBlock` + /// @param _cloneTokenName Name of the clone token + /// @param _cloneDecimalUnits Number of decimals of the smallest unit + /// @param _cloneTokenSymbol Symbol of the clone token + /// @param _snapshotBlock Block when the distribution of the parent token is + /// copied to set the initial distribution of the new clone token; + /// if the block is zero than the actual block, the current block is used + /// @param _transfersEnabled True if transfers are allowed in the clone + /// @return The address of the new MiniMeToken Contract + function createCloneToken( + string memory _cloneTokenName, + uint8 _cloneDecimalUnits, + string memory _cloneTokenSymbol, + uint256 _snapshotBlock, + bool _transfersEnabled + ) + public + returns (address) + { + if (_snapshotBlock == 0) _snapshotBlock = block.number; + MiniMeToken cloneToken = tokenFactory.createCloneToken( + this, _snapshotBlock, _cloneTokenName, _cloneDecimalUnits, _cloneTokenSymbol, _transfersEnabled + ); + + cloneToken.changeController(payable(msg.sender)); + + // An event to make the token easy to find on the blockchain + emit NewCloneToken(address(cloneToken), _snapshotBlock); + return address(cloneToken); + } + + event NewCloneToken(address indexed _cloneToken, uint256 _snapshotBlock); +} diff --git a/contracts/MiniMeTokenFactory.sol b/contracts/MiniMeTokenFactory.sol index 7461fc9..dc5162f 100644 --- a/contracts/MiniMeTokenFactory.sol +++ b/contracts/MiniMeTokenFactory.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; -import "./MiniMeToken.sol"; +import { MiniMeToken } from "./MiniMeToken.sol"; /// @title MiniMeToken Factory Contract /// @dev This contract is used to generate clone contracts from a contract.