Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make upgradable #3

Merged
merged 4 commits into from
Jun 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions contracts/community/Administration.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
pragma solidity ^0.8.17;

abstract contract Administration {
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

abstract contract Administration is Initializable {
mapping(address => bool) private _admins;

constructor() {
function _initializeAdministration() internal virtual initializer {
_admins[msg.sender] = true;
}

Expand Down Expand Up @@ -35,4 +37,4 @@ abstract contract Administration {
function deleteAdmin(address _deleteAdmin) external onlyAdmins {
_admins[_deleteAdmin] = false;
}
}
}
47 changes: 47 additions & 0 deletions contracts/community/InteractCommunityToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "./Administration.sol";
import "./MintManager.sol";
import "./interfaces/IHenkakuToken.sol";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IHenkakuToken.solICommunityToken.sol に変更するのはいかがでしょうか?


abstract contract InteractCommunityToken is Administration, MintManager {
address public communityToken;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

address public communityToken; の値をAdminが変更できる関数を追加するのはいかがでしょうか?


function _initializeInteractCommunityToken(address _communityToken) internal virtual initializer {
communityToken = _communityToken;
}

function setCommunityToken(address _communityToken) external onlyAdmins {
communityToken = _communityToken;
}

function _batchTransferCommunityToken(
uint256 totalAmount,
uint256[] memory _amounts,
address[] memory _to
) internal {
_checkCommunityTokenBalance(totalAmount);

uint256[] memory amounts = _amounts;
uint256 amountsLength = amounts.length;
require(amountsLength == _to.length, "amounts and to length mismatch");

for (uint256 i = 0; i < amountsLength; ) {
bool sent = IHenkakuToken(communityToken).transferFrom(msg.sender, _to[i], amounts[i]);
require(sent, "Ticket: ERC20 Token transfer failed");

unchecked {
++i;
}
}
}

function _checkCommunityTokenBalance(uint256 _requiredAmount) internal view {
require(
IHenkakuToken(communityToken).balanceOf(msg.sender) >= _requiredAmount,
"Ticket: Insufficient ERC20 token"
);
}
}
41 changes: 0 additions & 41 deletions contracts/community/InteractHenkakuToken.sol

This file was deleted.

4 changes: 1 addition & 3 deletions contracts/community/MintManager.sol
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
pragma solidity ^0.8.17;

import "./Administration.sol";

abstract contract MintManager is Administration {
bool public mintable;

constructor() {}

function switchMintable() external onlyAdmins {
mintable = !mintable;
}
Expand Down
65 changes: 39 additions & 26 deletions contracts/community/Ticket.sol
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

今回のアップデートとは関係のないところで、Ticket.sol の32~34行目について相談させてください!
以前とにかくガス代を下げたかったため私が uint64 を設定したのですが、他コミュニティに使用してもらうことを考えると、念のため3つとも uint256 に戻した方が良いかもと思いました。
いかがでしょうか?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

64でもかなりでかいのでこれで良さそうです

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちらも今回のアプデとは関係なく、45~49行目の関数へのコメントは削除するのはいかがでしょうか?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

26~27行目の

mapping(address => uint256[]) private ownerOfRegisteredIds;
mapping(address => uint256[]) private ownerOfMintedIds;

ですが、private のためアンダースコアを追加するのはいかがでしょうか?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

関数内で_つかっている同じ名前の変数があるのでこのままにしておきます

Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
pragma solidity ^0.8.17;

import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155SupplyUpgradeable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "./Administration.sol";
import "./InteractHenkakuToken.sol";
import "./InteractCommunityToken.sol";
import "./MintManager.sol";

contract Ticket is ERC1155, ERC1155Supply, Administration, MintManager, InteractHenakuToken {
contract Ticket is
Initializable,
ERC1155Upgradeable,
ERC1155SupplyUpgradeable,
Administration,
MintManager,
InteractCommunityToken
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

アップグレーダブルのパターンとしてUUPSを採用するのはいかがでしょうか?
ロジック内に誰がアップグレードできるかを決定する関数( _authorizeUpgrade() )を置くアブストラクトで、そちらを override することで modifier などで簡単にアップグレード権限を設定でき、 _authorizeUpgrade() 自体もアップグレードできるらしいと聞きました!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ちょっと時間が...ww

//@dev count up tokenId from 0
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
Expand Down Expand Up @@ -35,9 +43,15 @@ contract Ticket is ERC1155, ERC1155Supply, Administration, MintManager, Interact
error InvalidParams(string);

/**
* @param uri: metadata uri
* @param creator: creator's wallet address
* @param open_blockTimestamp: open block timestamp for sales period
* @param close_blockTimestamp: close block timestamp for sales period
* @param maxSupply: max supply number of token
* @param id: event id
* @param price: price of ticket
* @param uri: metadata uri
* @param sharesAmounts: shares amount of shareholders
* @param shareholdersAddresses: shareholders' wallet addresses
*/
struct TicketInfo {
address creator;
Expand All @@ -51,22 +65,21 @@ contract Ticket is ERC1155, ERC1155Supply, Administration, MintManager, Interact
address[] shareholdersAddresses;
}

TicketInfo[] private registeredTickets;
TicketInfo[] private _registeredTickets;

constructor(
string memory _name,
string memory _symbol,
address _communityToken
) ERC1155("") MintManager() InteractHenakuToken(_communityToken) {
function initialize(string memory _name, string memory _symbol, address _communityToken) public initializer {
name = _name;
symbol = _symbol;

registeredTickets.push(TicketInfo(address(0), 0, 0, 0, 0, 0, "", new uint256[](0), new address[](0)));
_registeredTickets.push(TicketInfo(address(0), 0, 0, 0, 0, 0, "", new uint256[](0), new address[](0)));
_tokenIds.increment();

super._initializeAdministration();
super._initializeInteractCommunityToken(_communityToken);
}

modifier onlyHenkakuHolders() {
_checkHenkakuV2Balance(1);
modifier onlyCommunityTokenHolders() {
_checkCommunityTokenBalance(1);
_;
}

Expand All @@ -91,7 +104,7 @@ contract Ticket is ERC1155, ERC1155Supply, Administration, MintManager, Interact
uint64 _close_blockTimestamp,
address[] memory _shareholdersAddresses,
uint256[] memory _sharesAmounts
) external onlyHenkakuHolders {
) external onlyCommunityTokenHolders {
if (
_maxSupply == 0 ||
keccak256(bytes(_metaDataURL)) == keccak256(bytes("")) ||
Expand All @@ -100,7 +113,7 @@ contract Ticket is ERC1155, ERC1155Supply, Administration, MintManager, Interact

uint256 tokenId = _tokenIds.current();
ownerOfRegisteredIds[msg.sender].push(tokenId);
registeredTickets.push(
_registeredTickets.push(
TicketInfo(
msg.sender,
_open_blockTimestamp,
Expand Down Expand Up @@ -132,13 +145,13 @@ contract Ticket is ERC1155, ERC1155Supply, Administration, MintManager, Interact

// @return all registered TicketInfo
function retrieveAllTickets() public view returns (TicketInfo[] memory) {
return registeredTickets;
return _registeredTickets;
}

// @return registered TicketInfo by tokenId
function retrieveRegisteredTicket(uint256 _tokenId) public view returns (TicketInfo memory) {
require(registeredTickets.length > _tokenId, "Ticket: not available");
return registeredTickets[_tokenId];
require(_registeredTickets.length > _tokenId, "Ticket: not available");
return _registeredTickets[_tokenId];
}

// @return registered TicketInfo by address
Expand All @@ -148,7 +161,7 @@ contract Ticket is ERC1155, ERC1155Supply, Administration, MintManager, Interact
TicketInfo[] memory _ownerOfRegisteredTickets = new TicketInfo[](_ownerOfRegisteredIdsLength);

for (uint256 i = 0; i < _ownerOfRegisteredIdsLength; ) {
TicketInfo memory _registeredTicket = registeredTickets[_ownerOfRegisteredIds[i]];
TicketInfo memory _registeredTicket = _registeredTickets[_ownerOfRegisteredIds[i]];
_ownerOfRegisteredTickets[i] = _registeredTicket;
unchecked {
++i;
Expand All @@ -158,7 +171,7 @@ contract Ticket is ERC1155, ERC1155Supply, Administration, MintManager, Interact
}

// @dev mint function
function mint(uint256 _tokenId) external onlyHenkakuHolders {
function mint(uint256 _tokenId) external onlyCommunityTokenHolders {
require(mintable, "Ticket: Not mintable");
require(balanceOf(msg.sender, _tokenId) == 0, "Ticket: You already have this ticket");

Expand All @@ -169,7 +182,7 @@ contract Ticket is ERC1155, ERC1155Supply, Administration, MintManager, Interact

ownerOfMintedIds[msg.sender].push(_tokenId);

batchTransferHenkakuV2(ticket.price, ticket.sharesAmounts, ticket.shareholdersAddresses);
_batchTransferCommunityToken(ticket.price, ticket.sharesAmounts, ticket.shareholdersAddresses);

_mint(msg.sender, _tokenId, 1, "");

Expand All @@ -185,7 +198,7 @@ contract Ticket is ERC1155, ERC1155Supply, Administration, MintManager, Interact
TicketInfo[] memory _ownerOfMintedTickets = new TicketInfo[](_ownerOfMintedIdsLength);

for (uint256 i = 0; i < _ownerOfMintedIdsLength; ) {
_ownerOfMintedTickets[i] = registeredTickets[_ownerOfMintedIds[i]];
_ownerOfMintedTickets[i] = _registeredTickets[_ownerOfMintedIds[i]];
unchecked {
++i;
}
Expand All @@ -195,7 +208,7 @@ contract Ticket is ERC1155, ERC1155Supply, Administration, MintManager, Interact
}

// @return token metadata uri
function uri(uint256 _tokenId) public view override(ERC1155) returns (string memory) {
function uri(uint256 _tokenId) public view override(ERC1155Upgradeable) returns (string memory) {
return retrieveRegisteredTicket(_tokenId).uri;
}

Expand All @@ -211,7 +224,7 @@ contract Ticket is ERC1155, ERC1155Supply, Administration, MintManager, Interact
uint256[] memory _ids,
uint256[] memory _amounts,
bytes memory _data
) internal virtual override(ERC1155, ERC1155Supply) {
ERC1155Supply._beforeTokenTransfer(_operator, _from, _to, _ids, _amounts, _data);
) internal virtual override(ERC1155Upgradeable, ERC1155SupplyUpgradeable) {
ERC1155SupplyUpgradeable._beforeTokenTransfer(_operator, _from, _to, _ids, _amounts, _data);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import "hardhat/console.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract HenkakuToken is ERC20, Ownable {
uint256 private maxSupply = 1_000_000_000e18; // 1 billion henkaku
contract CommunityToken is ERC20, Ownable {
uint256 private maxSupply = 1_000_000_000e18; // 1 billion Community
mapping(address => bool) private whitelist;
address public gateKeeper; // multisig contract address managed by henkaku community
address public gateKeeper; // multisig contract address managed by Community community
address public dev; // EOA which updates whitelist systematically like using crontab.
bool unlock;

constructor() ERC20("HENKAKU", "HENKAKU") {
constructor() ERC20("Community", "Community") {
unlock = false;
}

Expand Down
77 changes: 51 additions & 26 deletions contracts/community/interfaces/IHenkakuToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,55 @@
pragma solidity ^0.8.9;

interface IHenkakuToken {
function addWhitelistUser ( address user ) external;
function addWhitelistUsers ( address[] memory users ) external;
function allowance ( address owner, address spender ) external view returns ( uint256 );
function approve ( address spender, uint256 amount ) external returns ( bool );
function balanceOf ( address account ) external view returns ( uint256 );
function burn ( address _of, uint256 amount ) external;
function decimals ( ) external view returns ( uint8 );
function decreaseAllowance ( address spender, uint256 subtractedValue ) external returns ( bool );
function dev ( ) external view returns ( address );
function gateKeeper ( ) external view returns ( address );
function increaseAllowance ( address spender, uint256 addedValue ) external returns ( bool );
function isAllowed ( address user ) external view returns ( bool );
function mint ( address _to, uint256 amount ) external;
function name ( ) external view returns ( string memory );
function owner ( ) external view returns ( address );
function removeWhitelistUser ( address user ) external;
function removeWhitelistUsers ( address[] memory users ) external;
function renounceOwnership ( ) external;
function setDevAddress ( address user ) external;
function setGateKeeper ( address user ) external;
function symbol ( ) external view returns ( string memory );
function totalSupply ( ) external view returns ( uint256 );
function transfer ( address to, uint256 amount ) external returns ( bool );
function transferFrom ( address from, address to, uint256 amount ) external returns ( bool );
function transferOwnership ( address newOwner ) external;
function unLock ( ) external;
function addWhitelistUser(address user) external;

function addWhitelistUsers(address[] memory users) external;

function allowance(address owner, address spender) external view returns (uint256);

function approve(address spender, uint256 amount) external returns (bool);

function balanceOf(address account) external view returns (uint256);

function burn(address _of, uint256 amount) external;

function decimals() external view returns (uint8);

function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);

function dev() external view returns (address);

function gateKeeper() external view returns (address);

function increaseAllowance(address spender, uint256 addedValue) external returns (bool);

function isAllowed(address user) external view returns (bool);

function mint(address _to, uint256 amount) external;

function name() external view returns (string memory);

function owner() external view returns (address);

function removeWhitelistUser(address user) external;

function removeWhitelistUsers(address[] memory users) external;

function renounceOwnership() external;

function setDevAddress(address user) external;

function setGateKeeper(address user) external;

function symbol() external view returns (string memory);

function totalSupply() external view returns (uint256);

function transfer(address to, uint256 amount) external returns (bool);

function transferFrom(address from, address to, uint256 amount) external returns (bool);

function transferOwnership(address newOwner) external;

function unLock() external;
}
Loading