feat: use owner&master token addresses when deploying assets

Issue #12364
This commit is contained in:
Michal Iskierko 2023-10-09 12:01:44 +02:00 committed by Michał Iskierko
parent 3326362b90
commit 8ac26f8810
17 changed files with 823 additions and 251 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,70 +0,0 @@
// SPDX-License-Identifier: Mozilla Public License 2.0
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/utils/Context.sol";
contract CommunityERC20 is Context, Ownable, ERC20 {
error CommunityERC20_MaxSupplyLowerThanTotalSupply();
error CommunityERC20_MaxSupplyReached();
error CommunityERC20_MismatchingAddressesAndAmountsLengths();
/**
* If we want unlimited total supply we should set maxSupply to 2^256-1.
*/
uint256 public maxSupply;
uint8 private immutable customDecimals;
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals,
uint256 _maxSupply
)
ERC20(_name, _symbol)
{
maxSupply = _maxSupply;
customDecimals = _decimals;
}
// Events
// External functions
function setMaxSupply(uint256 newMaxSupply) external onlyOwner {
if (newMaxSupply < totalSupply()) {
revert CommunityERC20_MaxSupplyLowerThanTotalSupply();
}
maxSupply = newMaxSupply;
}
/**
* @dev Mint tokens for each address in `addresses` each one with
* an amount specified in `amounts`.
*
*/
function mintTo(address[] memory addresses, uint256[] memory amounts) external onlyOwner {
if (addresses.length != amounts.length) {
revert CommunityERC20_MismatchingAddressesAndAmountsLengths();
}
for (uint256 i = 0; i < addresses.length; i++) {
uint256 amount = amounts[i];
if (totalSupply() + amount > maxSupply) {
revert CommunityERC20_MaxSupplyReached();
}
_mint(addresses[i], amount);
}
}
// Public functions
function decimals() public view virtual override returns (uint8) {
return customDecimals;
}
// Internal functions
// Private functions
}

View File

@ -1,19 +0,0 @@
// SPDX-License-Identifier: Mozilla Public License 2.0
pragma solidity ^0.8.17;
import "./BaseToken.sol";
contract CollectibleV1 is BaseToken {
constructor(
string memory _name,
string memory _symbol,
uint256 _maxSupply,
bool _remoteBurnable,
bool _transferable,
string memory _baseTokenURI,
address _ownerToken,
address _masterToken
)
BaseToken(_name, _symbol, _maxSupply, _remoteBurnable, _transferable, _baseTokenURI, _ownerToken, _masterToken)
{ }
}

File diff suppressed because one or more lines are too long

View File

@ -1,19 +1,30 @@
// SPDX-License-Identifier: Mozilla Public License 2.0
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
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_MaxSupplyLowerThanTotalSupply();
error BaseToken_MaxSupplyReached();
error BaseToken_NotRemoteBurnable();
error BaseToken_NotTransferable();
/// @notice Emits a custom mint event for Status applications to listen to
/// @dev This is doubling the {Transfer} event from ERC721 but we need to emit this
/// so Status applications have a way to easily distinguish between transactions that have
/// a similar event footprint but are semantically different.
/// @param from The address that minted the token
/// @param to The address that received the token
/// @param tokenId The token ID that was minted
event StatusMint(address indexed from, address indexed to, uint256 indexed tokenId);
// State variables
Counters.Counter private _tokenIdTracker;
@ -22,19 +33,15 @@ abstract contract BaseToken is
* If we want unlimited total supply we should set maxSupply to 2^256-1.
*/
uint256 public maxSupply;
address public ownerToken;
address public masterToken;
/**
* If set to true, the contract owner can burn any token.
*/
bool public remoteBurnable;
bool public immutable remoteBurnable;
/**
* If set to false it acts as a soulbound token.
*/
bool public transferable;
bool public immutable transferable;
string public baseTokenURI;
@ -47,33 +54,24 @@ abstract contract BaseToken is
string memory _baseTokenURI,
address _ownerToken,
address _masterToken
) ERC721(_name, _symbol) {
)
ERC721(_name, _symbol)
CommunityOwnable(_ownerToken, _masterToken)
{
maxSupply = _maxSupply;
remoteBurnable = _remoteBurnable;
transferable = _transferable;
baseTokenURI = _baseTokenURI;
ownerToken = _ownerToken;
masterToken = _masterToken;
require(ownerToken != address(0x0) || masterToken != address(0x0), "owner or master tokens required");
}
modifier onlyOwner() {
require(
(ownerToken == address(0) || IERC721(ownerToken).balanceOf(msg.sender) > 0) ||
(masterToken == address(0) || IERC721(masterToken).balanceOf(msg.sender) > 0),
"Not authorized"
);
_;
}
// Events
// External functions
function setMaxSupply(uint256 newMaxSupply) virtual external onlyOwner {
require(newMaxSupply >= totalSupply(), "MAX_SUPPLY_LOWER_THAN_TOTAL_SUPPLY");
function setMaxSupply(uint256 newMaxSupply) external virtual onlyCommunityOwnerOrTokenMaster {
if (newMaxSupply < totalSupply()) {
revert BaseToken_MaxSupplyLowerThanTotalSupply();
}
maxSupply = newMaxSupply;
}
@ -83,8 +81,10 @@ abstract contract BaseToken is
* URI autogenerated based on the base URI passed at construction.
*
*/
function mintTo(address[] memory addresses) public onlyOwner {
require(_tokenIdTracker.current() + addresses.length <= maxSupply, "MAX_SUPPLY_REACHED");
function mintTo(address[] memory addresses) public onlyCommunityOwnerOrTokenMaster {
if (_tokenIdTracker.current() + addresses.length > maxSupply) {
revert BaseToken_MaxSupplyReached();
}
_mintTo(addresses);
}
@ -98,8 +98,8 @@ abstract contract BaseToken is
* @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 {
require(remoteBurnable, "NOT_REMOTE_BURNABLE");
function remoteBurn(uint256[] memory tokenIds) public onlyCommunityOwnerOrTokenMaster {
if (!remoteBurnable) revert BaseToken_NotRemoteBurnable();
for (uint256 i = 0; i < tokenIds.length; i++) {
_burn(tokenIds[i]);
@ -109,13 +109,7 @@ abstract contract BaseToken is
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC721Enumerable)
returns (bool)
{
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Enumerable) returns (bool) {
return super.supportsInterface(interfaceId);
}
@ -134,6 +128,7 @@ abstract contract BaseToken is
// can be burned so we use a separate counter.
for (uint256 i = 0; i < addresses.length; i++) {
_safeMint(addresses[i], _tokenIdTracker.current(), "");
emit StatusMint(address(0), addresses[i], _tokenIdTracker.current());
_tokenIdTracker.increment();
}
}
@ -147,9 +142,13 @@ abstract contract BaseToken is
address to,
uint256 firstTokenId,
uint256 batchSize
) internal virtual override(ERC721Enumerable) {
)
internal
virtual
override(ERC721Enumerable)
{
if (from != address(0) && to != address(0) && !transferable) {
revert("not transferable");
revert BaseToken_NotTransferable();
}
super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
}

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: Mozilla Public License 2.0
pragma solidity ^0.8.17;
import "./BaseToken.sol";
import { BaseToken } from "./BaseToken.sol";
contract CollectibleV1 is BaseToken {
constructor(
@ -13,14 +13,7 @@ contract CollectibleV1 is BaseToken {
string memory _baseTokenURI,
address _ownerToken,
address _masterToken
) BaseToken(
_name,
_symbol,
_maxSupply,
_remoteBurnable,
_transferable,
_baseTokenURI,
_ownerToken,
_masterToken) {
}
)
BaseToken(_name, _symbol, _maxSupply, _remoteBurnable, _transferable, _baseTokenURI, _ownerToken, _masterToken)
{ }
}

View File

@ -1,28 +1,43 @@
// SPDX-License-Identifier: Mozilla Public License 2.0
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/utils/Context.sol";
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, CommunityOwnable {
error CommunityERC20_MaxSupplyLowerThanTotalSupply();
error CommunityERC20_MaxSupplyReached();
error CommunityERC20_MismatchingAddressesAndAmountsLengths();
/// @notice Emits a custom mint event for Status applications to listen to
/// @dev This is doubling the {Transfer} event from ERC20 but we need to emit this
/// so Status applications have a way to easily distinguish between transactions that have
/// a similar event footprint but are semantically different.
/// @param from The address that minted the token
/// @param to The address that received the token
/// @param amount The amount that was minted
event StatusMint(address indexed from, address indexed to, uint256 indexed amount);
contract CommunityERC20 is
Context,
Ownable,
ERC20
{
/**
* If we want unlimited total supply we should set maxSupply to 2^256-1.
*/
uint256 public maxSupply;
uint8 private customDecimals;
uint8 private immutable customDecimals;
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals,
uint256 _maxSupply
) ERC20(_name, _symbol) {
uint256 _maxSupply,
address _ownerToken,
address _masterToken
)
ERC20(_name, _symbol)
CommunityOwnable(_ownerToken, _masterToken)
{
maxSupply = _maxSupply;
customDecimals = _decimals;
}
@ -31,8 +46,10 @@ contract CommunityERC20 is
// External functions
function setMaxSupply(uint256 newMaxSupply) external onlyOwner {
require(newMaxSupply >= totalSupply(), "MAX_SUPPLY_LOWER_THAN_TOTAL_SUPPLY");
function setMaxSupply(uint256 newMaxSupply) external onlyCommunityOwnerOrTokenMaster {
if (newMaxSupply < totalSupply()) {
revert CommunityERC20_MaxSupplyLowerThanTotalSupply();
}
maxSupply = newMaxSupply;
}
@ -41,13 +58,18 @@ contract CommunityERC20 is
* an amount specified in `amounts`.
*
*/
function mintTo(address[] memory addresses, uint256[] memory amounts) external onlyOwner {
require(addresses.length == amounts.length, "WRONG_LENGTHS");
function mintTo(address[] memory addresses, uint256[] memory amounts) external onlyCommunityOwnerOrTokenMaster {
if (addresses.length != amounts.length) {
revert CommunityERC20_MismatchingAddressesAndAmountsLengths();
}
for (uint256 i = 0; i < addresses.length; i++) {
uint256 amount = amounts[i];
require(totalSupply() + amount <= maxSupply, "MAX_SUPPLY_REACHED");
if (totalSupply() + amount > maxSupply) {
revert CommunityERC20_MaxSupplyReached();
}
_mint(addresses[i], amount);
emit StatusMint(address(0), addresses[i], amount);
}
}

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: Mozilla Public License 2.0
pragma solidity ^0.8.17;
import "./BaseToken.sol";
import { BaseToken } from "./BaseToken.sol";
contract MasterToken is BaseToken {
constructor(
@ -9,14 +9,7 @@ contract MasterToken is BaseToken {
string memory _symbol,
string memory _baseTokenURI,
address _ownerToken
) BaseToken(
_name,
_symbol,
type(uint256).max,
true,
false,
_baseTokenURI,
_ownerToken,
address(0x0)) {
}
)
BaseToken(_name, _symbol, type(uint256).max, true, false, _baseTokenURI, _ownerToken, address(0x0))
{ }
}

View File

@ -1,45 +1,32 @@
// SPDX-License-Identifier: Mozilla Public License 2.0
pragma solidity ^0.8.17;
import "./BaseToken.sol";
import "./MasterToken.sol";
import { BaseToken } from "./BaseToken.sol";
import { CommunityOwnable } from "../CommunityOwnable.sol";
contract OwnerToken is BaseToken {
event MasterTokenCreated(address masterToken);
bytes public signerPublicKey;
constructor(
string memory _name,
string memory _symbol,
string memory _baseTokenURI,
string memory _masterName,
string memory _masterSymbol,
string memory _masterBaseTokenURI,
address _receiver,
bytes memory _signerPublicKey
) BaseToken(
_name,
_symbol,
1,
false,
true,
_baseTokenURI,
address(this),
address(this))
)
BaseToken(_name, _symbol, 1, false, true, _baseTokenURI, address(this), address(this))
{
signerPublicKey = _signerPublicKey;
MasterToken masterToken = new MasterToken(_masterName, _masterSymbol, _masterBaseTokenURI, address(this));
emit MasterTokenCreated(address(masterToken));
address[] memory addresses = new address[](1);
addresses[0] = msg.sender;
addresses[0] = _receiver;
_mintTo(addresses);
}
function setMaxSupply(uint256 _newMaxSupply) override external 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;
}
}

View File

@ -0,0 +1 @@
See https://github.com/status-im/communities-contracts/tree/main/contracts

File diff suppressed because one or more lines are too long

View File

@ -1,15 +0,0 @@
// SPDX-License-Identifier: Mozilla Public License 2.0
pragma solidity ^0.8.17;
import "./BaseToken.sol";
contract MasterToken is BaseToken {
constructor(
string memory _name,
string memory _symbol,
string memory _baseTokenURI,
address _ownerToken
)
BaseToken(_name, _symbol, type(uint256).max, true, false, _baseTokenURI, _ownerToken, address(0x0))
{ }
}

File diff suppressed because one or more lines are too long

View File

@ -1,31 +0,0 @@
// SPDX-License-Identifier: Mozilla Public License 2.0
pragma solidity ^0.8.17;
import "./BaseToken.sol";
contract OwnerToken is BaseToken {
bytes public signerPublicKey;
constructor(
string memory _name,
string memory _symbol,
string memory _baseTokenURI,
address _receiver,
bytes memory _signerPublicKey
)
BaseToken(_name, _symbol, 1, false, true, _baseTokenURI, address(this), address(this))
{
signerPublicKey = _signerPublicKey;
address[] memory addresses = new address[](1);
addresses[0] = _receiver;
_mintTo(addresses);
}
function setMaxSupply(uint256 _newMaxSupply) external override onlyOwner {
revert("max supply locked");
}
function setSignerPublicKey(bytes memory _newSignerPublicKey) external onlyOwner {
signerPublicKey = _newSignerPublicKey;
}
}

View File

@ -305,7 +305,9 @@ func (api *API) DeployAssets(ctx context.Context, chainID uint64, deploymentPara
const decimals = 18
address, tx, _, err := assets.DeployAssets(transactOpts, ethClient, deploymentParameters.Name,
deploymentParameters.Symbol, decimals, deploymentParameters.GetSupply())
deploymentParameters.Symbol, decimals, deploymentParameters.GetSupply(),
common.HexToAddress(deploymentParameters.OwnerTokenAddress),
common.HexToAddress(deploymentParameters.MasterTokenAddress))
if err != nil {
log.Error(err.Error())
return DeploymentDetails{}, err