├── .gitignore ├── README.md ├── contracts ├── ContentNFT.sol ├── CreatorGroup.sol ├── Factory.sol ├── Marketplace.sol ├── USDC.sol └── interfaces │ ├── IContentNFT.sol │ ├── ICreatorGroup.sol │ ├── IFactory.sol │ └── IMarketplace.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── scripts └── deploy_sepolia.ts ├── test ├── InitialTesting.ts ├── contentNFT.json └── creatorGroup.json ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | # Hardhat files 5 | /cache 6 | /artifacts 7 | 8 | # TypeChain files 9 | /typechain 10 | /typechain-types 11 | 12 | # solidity-coverage files 13 | /coverage 14 | /coverage.json 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## SQUAD NFT Marketplace 2 | 3 | ### Welcome to the SQUAD NFT Marketplace project! 4 | 5 | ### Project Overview 6 | 7 | The SQUAD NFT Marketplace project enables users to collaborate and create NFTs within a group setting. The group contract functions as a Multi-sig Wallet, allowing creators to collectively manage and oversee the NFT creation process. 8 | 9 | ### Features 10 | 11 | -Group Formation: Users can come together to form a group for creating NFTs. 12 | 13 | -Multi-sig Wallet: The group contract operates as a Multi-sig Wallet for secure management of funds and transactions. 14 | 15 | -NFT Minting and Listing: Creators can mint their NFTs and list them on the marketplace, choosing from various sale methods such as English auction, Dutch auction, blind auction, fixed price, and offering methods. 16 | 17 | -Revenue Distribution: Upon successful sales, the marketplace distributes 85% of the revenue to the creators and 15% to the development team. 18 | 19 | -Loyalty Fee: A loyalty fee is applied to each NFT sale, ensuring ongoing compensation for the original creators. 20 | 21 | ### Getting Started 22 | 23 | To get started with the SQUAD NFT Marketplace project, follow these steps: 24 | 25 | -Group Formation: Collaborate with others to form a group for NFT creation. 26 | 27 | -NFT Minting: Mint your NFT and list it on the marketplace using your preferred sale method. 28 | 29 | -Explore Sale Options: Choose from various sale methods including English auction, Dutch auction, blind auction, fixed price, and offering methods. 30 | 31 | -Revenue Distribution: Receive 85% of the sales revenue as a creator, with 15% allocated to the development team. 32 | 33 | -Loyalty Fee: Benefit from ongoing compensation through the loyalty fee applied to your NFT sales. 34 | 35 | Thank you for being a part of the SQUAD NFT Marketplace project! Feel free to reach out if you have any questions or feedback. 36 | 37 | ### This README provides an overview of the SQUAD NFT Marketplace project and its key features. For detailed instructions and documentation, please refer to the project's codebase and documentation. -------------------------------------------------------------------------------- /contracts/ContentNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.19; 3 | import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; 4 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {ICreatorGroup} from "./interfaces/ICreatorGroup.sol"; 7 | import {IFactory} from "./interfaces/IFactory.sol"; 8 | 9 | contract ContentNFT is ERC721Upgradeable { 10 | // Struct to store transfer details 11 | struct TransferHistory { 12 | address from; 13 | address to; 14 | uint256 timestamp; 15 | } 16 | // State variables 17 | address public owner; // Address of the contract owner 18 | address public factory; // Address of the factory contract 19 | mapping(uint256 => string) private nftURIPath; // Mapping to store NFT URI paths 20 | string public description; // Description of the NFT contract 21 | uint256 public tokenNumber; // Current token number 22 | uint256 public mintFee; // Fee required for minting 23 | uint256 public burnFee; // Fee required for burning 24 | address public USDC; // USDC address 25 | address public marketplace; // Marketplace address 26 | IERC20 public USDC_token; // USDC token contract 27 | mapping(uint256 => address) public creators; // Mapping to store the creator address for each NFT token ID 28 | mapping(uint256 => uint256) private loyaltyFee; // Mapping to store the loyalty fee percentage for each NFT token ID 29 | mapping(uint256 => TransferHistory[]) private transferHistory; // Mapping to store transfer history 30 | // Events 31 | event minted( 32 | address indexed from, 33 | uint256 indexed tokenId, 34 | string indexed nftURI 35 | ); 36 | event Burned(address indexed from, uint256 indexed tokenId); 37 | event LoyaltyFeeChanged(uint256 indexed tokenId, uint256 indexed newFee); 38 | 39 | /// @notice Function to initialize the NFT contract 40 | /// @param _name Name of the NFT contract 41 | /// @param _symbol Symbol of the NFT contract 42 | /// @param _description Description of the NFT contract 43 | /// @param _nftURI Path to the first NFT URI 44 | /// @param _target Address of the target contract 45 | /// @param _mintFee Fee required for minting 46 | /// @param _burnFee Fee required for burning 47 | /// @param _USDC Address of the USDC token contract 48 | /// @param _marketplace Address of the marketplace contract 49 | function initialize( 50 | string memory _name, 51 | string memory _symbol, 52 | string memory _description, 53 | string memory _nftURI, 54 | address _target, 55 | uint256 _mintFee, 56 | uint256 _burnFee, 57 | address _USDC, 58 | address _marketplace 59 | ) external initializer { 60 | // Initialize ERC721 contract 61 | ERC721Upgradeable.__ERC721_init(_name, _symbol); 62 | factory = msg.sender; 63 | require(_target != address(0), "target address cannot be 0"); 64 | owner = _target; 65 | description = _description; 66 | tokenNumber = 1; 67 | _mint(owner, tokenNumber); 68 | creators[tokenNumber] = owner; 69 | mintFee = _mintFee; 70 | burnFee = _burnFee; 71 | transferHistory[tokenNumber].push( 72 | TransferHistory(address(0), owner, block.timestamp) 73 | ); 74 | _setTokenURI(_nftURI); 75 | require(_USDC != address(0), "USDC address cannot be 0"); 76 | USDC = _USDC; 77 | USDC_token = IERC20(_USDC); 78 | require(_marketplace != address(0), "marketplace address cannot be 0"); 79 | marketplace = _marketplace; 80 | emit minted(owner, 0, _nftURI); 81 | } 82 | 83 | /// @notice Function to mint a new NFT token 84 | /// @param _nftURI URI of the NFT token 85 | /// @return tokenNumber 86 | function mint(string memory _nftURI) external payable returns (uint256) { 87 | require(IFactory(factory).isCreatorGroup(msg.sender) == true, "Invalid Minter"); 88 | // Mint the NFT token 89 | if (mintFee != 0) { 90 | SafeERC20.safeTransferFrom( 91 | USDC_token, 92 | msg.sender, 93 | factory, 94 | mintFee 95 | ); 96 | } 97 | _mint(msg.sender, tokenNumber); 98 | creators[tokenNumber] = msg.sender; 99 | transferHistory[tokenNumber].push( 100 | TransferHistory(address(0), msg.sender, block.timestamp) 101 | ); 102 | _setTokenURI(_nftURI); 103 | emit minted(msg.sender, tokenNumber - 1, _nftURI); 104 | return tokenNumber - 1; 105 | } 106 | 107 | /// @notice Function to burn an NFT token 108 | /// @param _tokenId Token ID of the NFT token 109 | /// @return Burned tokenId 110 | function burn(uint256 _tokenId) external payable returns (uint256) { 111 | require(msg.sender == ownerOf(_tokenId), "only owner can burn"); 112 | // Burn the NFT token 113 | if (burnFee != 0) { 114 | SafeERC20.safeTransferFrom( 115 | USDC_token, 116 | msg.sender, 117 | factory, 118 | burnFee 119 | ); 120 | } 121 | _burn(_tokenId); 122 | emit Burned(msg.sender, _tokenId); 123 | return _tokenId; 124 | } 125 | 126 | /// @notice Function to set the token URI path 127 | /// @param _nftURI URI of the NFT token 128 | function _setTokenURI(string memory _nftURI) private { 129 | nftURIPath[tokenNumber] = _nftURI; 130 | tokenNumber++; 131 | } 132 | 133 | /// @notice Function to set LoyaltyFee to a given token ID 134 | /// @param _tokenId Token ID of the NFT token 135 | /// @param _loyaltyFee Loyalty Fee percentage 136 | function setLoyaltyFee(uint256 _tokenId, uint256 _loyaltyFee) external { 137 | require( 138 | msg.sender == marketplace, 139 | "Invalid caller." 140 | ); 141 | loyaltyFee[_tokenId] = _loyaltyFee; 142 | emit LoyaltyFeeChanged(_tokenId, _loyaltyFee); 143 | } 144 | 145 | /// @notice Function to handle NFT transfers and record transfer history 146 | /// @param _from Previous owner of the NFT 147 | /// @param _to New owner of the NFT 148 | /// @param _tokenId Token ID of the NFT token 149 | function transferFrom( 150 | address _from, 151 | address _to, 152 | uint256 _tokenId 153 | ) public override { 154 | super.transferFrom(_from, _to, _tokenId); 155 | if (transferHistory[_tokenId].length >= 2) { 156 | ICreatorGroup(creators[_tokenId]).alarmLoyaltyFeeReceived( 157 | _tokenId, 158 | loyaltyFee[_tokenId] 159 | ); 160 | if (loyaltyFee[_tokenId] != 0) { 161 | SafeERC20.safeTransferFrom( 162 | USDC_token, 163 | msg.sender, 164 | creators[_tokenId], 165 | loyaltyFee[_tokenId] 166 | ); 167 | } 168 | } 169 | transferHistory[_tokenId].push( 170 | TransferHistory(_from, _to, block.timestamp) 171 | ); 172 | } 173 | 174 | /// @notice Function to get the transfer history for a given token ID 175 | /// @param _tokenId Token ID of the NFT token 176 | /// @return TransferHistory of the given token 177 | function getTransferHistory( 178 | uint256 _tokenId 179 | ) external view returns (TransferHistory[] memory) { 180 | return transferHistory[_tokenId]; 181 | } 182 | 183 | /// @notice Function to get the loyalty fee for a given token ID 184 | /// @param _tokenId Token ID of the NFT token 185 | /// @return Percentage of the loyalty fee for the given token 186 | function getLoyaltyFee(uint256 _tokenId) external view returns (uint256) { 187 | return loyaltyFee[_tokenId]; 188 | } 189 | 190 | /// @notice Function to get the token URI for a given token ID 191 | /// @param _tokenId Token ID of the NFT token 192 | /// @return Token URI 193 | function tokenURI( 194 | uint256 _tokenId 195 | ) public view override returns (string memory) { 196 | return nftURIPath[_tokenId]; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /contracts/CreatorGroup.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.19; 3 | 4 | import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; 5 | import "./interfaces/ICreatorGroup.sol"; 6 | import "./interfaces/IFactory.sol"; 7 | import "./interfaces/IMarketplace.sol"; 8 | import "./interfaces/IContentNFT.sol"; 9 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 10 | import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; 11 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 12 | import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; 13 | 14 | 15 | contract CreatorGroup is Initializable, ICreatorGroup, ReentrancyGuard { 16 | // Struct for transaction candidates 17 | struct transaction_candidate { 18 | address candidate; 19 | bool endState; 20 | } 21 | // Struct for offering transactions 22 | struct transaction_offering { 23 | uint256 marketId; 24 | uint256 id; 25 | uint256 price; 26 | address buyer; 27 | bool endState; 28 | } 29 | // Struct for burn transactions 30 | struct transaction_burn { 31 | uint256 id; 32 | bool endState; 33 | } 34 | // Struct for recording member information in revenue 35 | struct record_member { 36 | address _member; 37 | uint256 _percent; 38 | uint256 _sum; 39 | } 40 | // State variables 41 | address public USDC; // USDC token address 42 | IERC20 public USDC_token; // USDC token contract 43 | string public name; // Name of the CreatorGroup 44 | string public description; // Description of the CreatorGroup 45 | uint256 public mintFee; // Fee for minting NFTs 46 | uint256 public burnFee; // Fee for burning NFTs 47 | uint256 public numberOfMembers; // Number of members in the group 48 | address[] public members; // Array to store member addresses 49 | address public factory; // Address of the factory contract 50 | address public marketplace; // Address of the marketplace contract 51 | mapping(address => uint256) public balance; // Mapping to store balances of members 52 | mapping(address => bool) public isOwner; // Mapping to track ownership status of members' addresses 53 | uint256 public numConfirmationRequired; // Number of confirmations required for transactions 54 | address public director; // Address of the director for certain functions 55 | soldInfor[] public soldInformation; // Array to store sold NFT information 56 | uint256 public currentDistributeNumber; // Current distribution number 57 | uint256 public teamScore; // Team score 58 | uint256 public totalEarning; //Total Earning 59 | uint256 public numberOfNFT; // Number of NFTs in the group 60 | mapping(uint256 => uint256) public nftIdArr; // Mapping of NFT IDs 61 | mapping(uint256 => address) public nftAddressArr; // Mapping of NFT addresses 62 | mapping(uint256 => bool) public listedState; // Mapping to track the listing state of NFTs 63 | mapping(uint256 => bool) public soldOutState; // Mapping to track the sold state of NFTs 64 | mapping(address => mapping(uint256 => uint256)) public revenueDistribution; // Mapping for revenue distribution of NFTs 65 | mapping(address => mapping(uint256 => uint256)) public getNFTId; // Mapping for getting NFT IDs 66 | transaction_candidate[] public transactions_candidate; // Array of transaction candidates 67 | mapping(address => mapping(uint256 => bool)) 68 | public confirmTransaction_Candidate; // Mapping for confirm transaction 69 | transaction_offering[] public transactions_offering; // Array of offering transaction 70 | mapping(address => mapping(uint256 => bool)) 71 | public confirmTransaction_Offering; // Mapping for offering transaction confirmed state 72 | transaction_burn[] public transactions_burn; // Array of burn transaction 73 | mapping(address => mapping(uint256 => bool)) public confirmTransaction_Burn; // Mapping for burn transaction confirmed state 74 | mapping(uint256 => record_member[]) public Recording; // Recording for sold NFT's distribution 75 | // events 76 | event TeamScoreSet(uint256 value); 77 | event NFTMinted(address indexed nftAddress, uint256 indexed nftId); 78 | event UploadNFTFromMember( 79 | address indexed member, 80 | address indexed nftContract, 81 | uint256 indexed nftId 82 | ); 83 | event NFTBurned(uint256 indexed nftId); 84 | event EnglishAuctionListed( 85 | uint256 indexed nftId, 86 | uint256 indexed initialPrice, 87 | uint256 indexed salePeriod 88 | ); 89 | event DutchAuctionListed( 90 | uint256 indexed nftId, 91 | uint256 indexed initialPrice, 92 | uint256 indexed reducingRate, 93 | uint256 salePeriod 94 | ); 95 | event OfferingSaleListed( 96 | uint256 indexed nftId, 97 | uint256 indexed initialPrice 98 | ); 99 | event EnglishAuctionEnded(uint256 indexed nftId); 100 | event WithdrawalFromMarketplace(); 101 | event DirectorSettingProposed(address indexed _candidate); 102 | event DirectorSettingExecuted(address indexed _director); 103 | event DirectorSettingConfirmed( 104 | uint256 indexed index, 105 | address indexed from, 106 | bool indexed state 107 | ); 108 | event OfferingSaleTransactionProposed( 109 | address indexed _tokenContractAddress, 110 | uint256 indexed tokenId, 111 | address indexed _buyer, 112 | uint256 _price 113 | ); 114 | event OfferingSaleTransactionConfirmed( 115 | uint256 indexed index, 116 | address indexed from, 117 | bool indexed state 118 | ); 119 | event OfferingSaleTransactionExecuted(uint256 indexed index); 120 | event ConfirmationRequiredNumberSet(uint256 indexed confirmNumber); 121 | event WithdrawHappened( 122 | address indexed from, 123 | uint256 indexed balanceToWithdraw 124 | ); 125 | event LoyaltyFeeReceived(uint256 indexed id, uint256 indexed price); 126 | event BurnTransactionProposed(uint256 indexed id); 127 | event BurnTransactionConfirmed( 128 | uint256 indexed index, 129 | address indexed from, 130 | bool indexed state 131 | ); 132 | // Modifier to restrict access to only director 133 | modifier onlyDirector() { 134 | require( 135 | msg.sender == director, 136 | "Only delegated member can call this function" 137 | ); 138 | _; 139 | } 140 | // Modifier to restrict access to only members 141 | modifier onlyMembers() { 142 | require( 143 | isOwner[msg.sender] == true, 144 | "Only members can call this function" 145 | ); 146 | _; 147 | } 148 | // Modifier to restrict access to only marketplace contract 149 | modifier onlyMarketplace() { 150 | require( 151 | msg.sender == marketplace, 152 | "only Marketplace can Call this function." 153 | ); 154 | _; 155 | } 156 | modifier onlyFactory() { 157 | require(msg.sender == factory, "Only factory can call this function."); 158 | _; 159 | } 160 | 161 | /// @notice Function to initialize the CreatorGroup contract with member addresses and other parameters 162 | /// @param _name Name of the group 163 | /// @param _description Description of the group 164 | /// @param _members Member addresses 165 | /// @param _numConfirmationRequired Number of confirmations required for a transaction 166 | /// @param _marketplace Marketplace contract address 167 | /// @param _mintFee Mint fee 168 | /// @param _burnFee Burn Fee 169 | /// @param _USDC Address of the USDC token contract 170 | function initialize( 171 | string memory _name, 172 | string memory _description, 173 | address[] memory _members, 174 | uint256 _numConfirmationRequired, 175 | address _marketplace, 176 | uint256 _mintFee, 177 | uint256 _burnFee, 178 | address _USDC 179 | ) external initializer { 180 | name = _name; 181 | description = _description; 182 | for (uint256 i = 0; i < _members.length; ++i) { 183 | if (!isOwner[_members[i]]) { 184 | members.push(_members[i]); 185 | isOwner[_members[i]] = true; 186 | } 187 | } 188 | numberOfMembers = members.length; 189 | require( 190 | _numConfirmationRequired <= numberOfMembers && 191 | _numConfirmationRequired >= 1, 192 | "Invalid Confirmation Number" 193 | ); 194 | numConfirmationRequired = _numConfirmationRequired; 195 | require(_marketplace != address(0), "Invalid Marketplace Address"); 196 | marketplace = _marketplace; 197 | mintFee = _mintFee; 198 | burnFee = _burnFee; 199 | factory = msg.sender; 200 | director = members[0]; 201 | numberOfNFT = 0; 202 | currentDistributeNumber = 0; 203 | teamScore = 80; 204 | require(_USDC != address(0), "Invalid USDC Address"); 205 | USDC = _USDC; 206 | USDC_token = IERC20(USDC); 207 | } 208 | 209 | /// @notice Function to add a new member to the CreatorGroup 210 | /// @param _newMember Address of the new member to be added 211 | function addMember(address _newMember) external onlyDirector { 212 | require(!isOwner[_newMember], "Already existing member!"); 213 | require(_newMember != address(0), "Invalid Address"); 214 | members.push(_newMember); 215 | isOwner[_newMember] = true; 216 | numberOfMembers++; 217 | } 218 | 219 | /// @notice Function to remove a member from the CreatorGroup 220 | /// @param _oldMember Address of the member to be removed 221 | function removeMember(address _oldMember) external onlyMembers { 222 | require(msg.sender == _oldMember, "Remove failed!"); 223 | delete isOwner[_oldMember]; 224 | uint256 id = 0; 225 | for (uint256 i = 0; i < members.length; ++i) { 226 | if (members[i] == _oldMember) id = i; 227 | } 228 | members[id] = members[numberOfMembers - 1]; 229 | delete members[numberOfMembers - 1]; 230 | numberOfMembers--; 231 | } 232 | 233 | /// @notice Function to mint a new NFT 234 | /// @param _nftURI The URI of the NFT 235 | /// @param _name The name of the new Collection 236 | /// @param _symbol The symbol of the new Collection 237 | /// @param _description The description of the new Collection 238 | function mintNew( 239 | string memory _nftURI, 240 | string memory _name, 241 | string memory _symbol, 242 | string memory _description 243 | ) external onlyDirector { 244 | if (mintFee != 0) { 245 | SafeERC20.forceApprove(USDC_token, factory, mintFee); 246 | } 247 | address nftAddress = IFactory(factory).mintNew( 248 | _nftURI, 249 | _name, 250 | _symbol, 251 | _description 252 | ); 253 | nftAddressArr[numberOfNFT] = nftAddress; 254 | nftIdArr[numberOfNFT] = 1; 255 | getNFTId[nftAddress][1] = numberOfNFT; 256 | for (uint256 i = 0; i < members.length; ++i) { 257 | record_member memory tmp = record_member(members[i], 0, 0); 258 | Recording[numberOfNFT].push(tmp); 259 | } 260 | emit NFTMinted(nftAddress, numberOfNFT); 261 | numberOfNFT++; 262 | } 263 | 264 | /// @notice Function to mint an existing NFT Collection 265 | /// @param _nftURI The URI of the NFT 266 | /// @param _targetCollection The address of taret Collection Address 267 | function mint( 268 | string memory _nftURI, 269 | address _targetCollection 270 | ) external onlyDirector { 271 | if (mintFee != 0) { 272 | SafeERC20.forceApprove(USDC_token, _targetCollection, mintFee); 273 | } 274 | nftIdArr[numberOfNFT] = IContentNFT(_targetCollection).mint(_nftURI); 275 | nftAddressArr[numberOfNFT] = _targetCollection; 276 | getNFTId[_targetCollection][nftIdArr[numberOfNFT]] = numberOfNFT; 277 | for (uint256 i = 0; i < members.length; ++i) { 278 | record_member memory tmp = record_member(members[i], 0, 0); 279 | Recording[numberOfNFT].push(tmp); 280 | } 281 | emit NFTMinted(_targetCollection, numberOfNFT); 282 | numberOfNFT++; 283 | } 284 | 285 | /// @notice Function to list an NFT for an English auction 286 | /// @param _id The id of the NFT in the group 287 | /// @param _initialPrice The initial price of the NFT 288 | /// @param _salePeriod The sale period of the NFT 289 | function listToEnglishAuction( 290 | uint256 _id, 291 | uint256 _initialPrice, 292 | uint256 _salePeriod 293 | ) external onlyDirector { 294 | require(_id <= numberOfNFT - 1 && _id >= 0, "NFT does not exist!"); 295 | require(listedState[_id] == false, "Already listed!"); 296 | listedState[_id] = true; 297 | IERC721(nftAddressArr[_id]).approve(marketplace, nftIdArr[_id]); 298 | IMarketplace(marketplace).listToEnglishAuction( 299 | nftAddressArr[_id], 300 | nftIdArr[_id], 301 | _initialPrice, 302 | _salePeriod 303 | ); 304 | emit EnglishAuctionListed(_id, _initialPrice, _salePeriod); 305 | } 306 | 307 | /// @notice Function to list an NFT for a Dutch auction 308 | /// @param _id The id of the NFT in the group 309 | /// @param _initialPrice The initial price of the NFT 310 | /// @param _reducingRate The reducing rate per hour 311 | /// @param _salePeriod The sale period of the NFT 312 | function listToDutchAuction( 313 | uint256 _id, 314 | uint256 _initialPrice, 315 | uint256 _reducingRate, 316 | uint256 _salePeriod 317 | ) external onlyDirector { 318 | require(_id <= numberOfNFT - 1 && _id >= 0, "NFT does not exist!"); 319 | require(listedState[_id] == false, "Already listed!"); 320 | require( 321 | _initialPrice > _reducingRate * (_salePeriod / 3600), 322 | "Invalid Dutch information!" 323 | ); 324 | listedState[_id] = true; 325 | IERC721(nftAddressArr[_id]).approve(marketplace, nftIdArr[_id]); 326 | IMarketplace(marketplace).listToDutchAuction( 327 | nftAddressArr[_id], 328 | nftIdArr[_id], 329 | _initialPrice, 330 | _reducingRate, 331 | _salePeriod 332 | ); 333 | emit DutchAuctionListed(_id, _initialPrice, _reducingRate, _salePeriod); 334 | } 335 | 336 | /// @notice Function to list an NFT for an offering sale 337 | /// @param _id The id of the NFT in the group 338 | /// @param _initialPrice The initial price of the NFT 339 | function listToOfferingSale( 340 | uint256 _id, 341 | uint256 _initialPrice 342 | ) external onlyDirector { 343 | require(_id <= numberOfNFT - 1 && _id >= 0, "NFT does not exist!"); 344 | require(listedState[_id] == false, "Already listed!"); 345 | listedState[_id] = true; 346 | IERC721(nftAddressArr[_id]).approve(marketplace, nftIdArr[_id]); 347 | IMarketplace(marketplace).listToOfferingSale( 348 | nftAddressArr[_id], 349 | nftIdArr[_id], 350 | _initialPrice 351 | ); 352 | emit OfferingSaleListed(_id, _initialPrice); 353 | } 354 | 355 | /// @notice Function to cancel the listing of an NFT 356 | /// @param _id The id of the NFT in the group 357 | function cancelListing(uint256 _id) external onlyDirector { 358 | require(_id <= numberOfNFT - 1 && _id >= 0, "NFT does not exist!"); 359 | require(listedState[_id] == true, "Not Listed!"); 360 | IMarketplace(marketplace).cancelListing( 361 | nftAddressArr[_id], 362 | nftIdArr[_id] 363 | ); 364 | listedState[_id] = false; 365 | } 366 | 367 | /// @notice Function to end an English auction 368 | /// @param _id The id of the NFT in the group 369 | function endEnglishAuction(uint256 _id) external onlyDirector { 370 | require(_id <= numberOfNFT - 1 && _id >= 0, "NFT does not exist!"); 371 | require(listedState[_id] == true, "Not listed!"); 372 | IMarketplace(marketplace).endEnglishAuction( 373 | nftAddressArr[_id], 374 | nftIdArr[_id] 375 | ); 376 | emit EnglishAuctionEnded(_id); 377 | } 378 | 379 | /// @notice Function to submit an offering sale transaction 380 | /// @param _marketId The listed id of the NFT in the marketplace for offering sale 381 | /// @param _tokenContractAddress The address of the NFT contract 382 | /// @param _tokenId The id of the NFT in the NFT contract 383 | /// @param _buyer The buyer of the NFT 384 | /// @param _price The price of the NFT 385 | function submitOfferingSaleTransaction( 386 | uint256 _marketId, 387 | address _tokenContractAddress, 388 | uint256 _tokenId, 389 | address _buyer, 390 | uint256 _price 391 | ) external onlyMarketplace { 392 | uint256 id = getNFTId[_tokenContractAddress][_tokenId]; 393 | require(listedState[id] == true, "Not listed"); 394 | transactions_offering.push( 395 | transaction_offering(_marketId, id, _price, _buyer, false) 396 | ); 397 | emit OfferingSaleTransactionProposed( 398 | _tokenContractAddress, 399 | _tokenId, 400 | _buyer, 401 | _price 402 | ); 403 | } 404 | 405 | /// @notice Function to confirm an offering sale transaction 406 | /// @param _transactionId The index of the transaction to be confirmed 407 | /// @param _state The state of the transaction to be confirmed True/False 408 | function confirmOfferingSaleTransaction( 409 | uint256 _transactionId, 410 | bool _state 411 | ) external onlyMembers { 412 | require( 413 | _transactionId <= transactions_offering.length - 1 && 414 | _transactionId >= 0, 415 | "Invalid transaction id" 416 | ); 417 | confirmTransaction_Offering[msg.sender][_transactionId] = _state; 418 | emit OfferingSaleTransactionConfirmed( 419 | _transactionId, 420 | msg.sender, 421 | _state 422 | ); 423 | } 424 | 425 | /// @notice Function to execute an offering sale transaction 426 | /// @param _transactionId The index of the transaction to be executed 427 | function executeOfferingSaleTransaction( 428 | uint256 _transactionId 429 | ) external onlyMembers { 430 | require( 431 | _transactionId <= transactions_offering.length - 1 && 432 | _transactionId >= 0, 433 | "Invalid transaction id" 434 | ); 435 | uint256 count = getConfirmNumberOfOfferingSaleTransaction( 436 | _transactionId 437 | ); 438 | require(count >= numConfirmationRequired, "Not confirmed enough!!!"); 439 | transactions_offering[_transactionId].endState = true; 440 | for (uint256 i = 0; i < transactions_offering.length; ++i) { 441 | if ( 442 | transactions_offering[i].id == 443 | transactions_offering[_transactionId].id 444 | ) { 445 | transactions_offering[i].endState = true; 446 | } 447 | } 448 | address buyer = transactions_offering[_transactionId].buyer; 449 | IMarketplace(marketplace).endOfferingSale( 450 | transactions_offering[_transactionId].marketId, 451 | buyer 452 | ); 453 | emit OfferingSaleTransactionExecuted(_transactionId); 454 | } 455 | 456 | /// @notice Function to submit a director setting transaction 457 | /// @param _candidate The candidate to be a director 458 | function submitDirectorSettingTransaction( 459 | address _candidate 460 | ) external onlyMembers { 461 | require( 462 | isOwner[_candidate] == true && _candidate != director, 463 | "Select right candidate" 464 | ); 465 | transactions_candidate.push(transaction_candidate(_candidate, false)); 466 | emit DirectorSettingProposed(_candidate); 467 | } 468 | 469 | /// @notice Function to confirm a director setting transaction 470 | /// @param _transactionId The index of the transaction to be confirmed 471 | /// @param _state The state to be confirmed True/False 472 | function confirmDirectorSettingTransaction( 473 | uint256 _transactionId, 474 | bool _state 475 | ) external onlyMembers { 476 | require( 477 | _transactionId <= transactions_candidate.length - 1 && 478 | _transactionId >= 0, 479 | "Invalid transaction id" 480 | ); 481 | confirmTransaction_Candidate[msg.sender][_transactionId] = _state; 482 | emit DirectorSettingConfirmed(_transactionId, msg.sender, _state); 483 | } 484 | 485 | /// @notice Function to execute a director setting transaction 486 | /// @param _transactionId The index of the transaction to be executed 487 | function executeDirectorSettingTransaction( 488 | uint256 _transactionId 489 | ) external onlyMembers { 490 | require( 491 | _transactionId <= transactions_candidate.length - 1 && 492 | _transactionId >= 0, 493 | "Invalid transaction id" 494 | ); 495 | uint256 count = getConfirmNumberOfDirectorSettingTransaction( 496 | _transactionId 497 | ); 498 | require(count >= numConfirmationRequired, "Not confirmed enough!!!"); 499 | director = transactions_candidate[_transactionId].candidate; 500 | transactions_candidate[_transactionId].endState = true; 501 | emit DirectorSettingExecuted(director); 502 | } 503 | 504 | /// @notice Function to submit Burn Transaction 505 | /// @param _id The id of the NFT in the group 506 | function submitBurnTransaction(uint256 _id) external onlyMembers { 507 | require(_id <= numberOfNFT - 1 && _id >= 0, "NFT does not exist!"); 508 | require(listedState[_id] == false, "Already listed"); 509 | transactions_burn.push(transaction_burn(_id, false)); 510 | emit BurnTransactionProposed(_id); 511 | } 512 | 513 | /// @notice Function to confirm an offering sale transaction 514 | /// @param _transactionId The index of the transaction to be confirmed 515 | /// @param _state The state of the transaction to be confirmed True/False 516 | function confirmBurnTransaction( 517 | uint256 _transactionId, 518 | bool _state 519 | ) external onlyMembers { 520 | require( 521 | _transactionId <= transactions_burn.length - 1 && 522 | _transactionId >= 0, 523 | "Invalid transaction id" 524 | ); 525 | confirmTransaction_Burn[msg.sender][_transactionId] = _state; 526 | emit BurnTransactionConfirmed(_transactionId, msg.sender, _state); 527 | } 528 | 529 | /// @notice Function to execute an offering sale transaction 530 | /// @param _transactionId The index of the transaction to be executed 531 | function executeBurnTransaction( 532 | uint256 _transactionId 533 | ) external onlyMembers { 534 | require( 535 | _transactionId <= transactions_burn.length - 1 && 536 | _transactionId >= 0, 537 | "Invalid transaction id" 538 | ); 539 | uint256 count = getConfirmNumberOfBurnTransaction(_transactionId); 540 | require(count >= numConfirmationRequired, "Not confirmed enough!!!"); 541 | transactions_burn[_transactionId].endState = true; 542 | for (uint256 i = 0; i < transactions_burn.length; ++i) { 543 | if ( 544 | transactions_burn[i].id == transactions_burn[_transactionId].id 545 | ) { 546 | transactions_burn[i].endState = true; 547 | } 548 | } 549 | uint256 id = transactions_burn[_transactionId].id; 550 | address nftAddress = nftAddressArr[id]; 551 | uint256 tokenId = nftIdArr[id]; 552 | if (burnFee != 0) { 553 | SafeERC20.forceApprove(USDC_token, nftAddress, burnFee); 554 | } 555 | uint256 burnedId = IContentNFT(nftAddress).burn(tokenId); 556 | require(burnedId == tokenId, "Not match burned ID"); 557 | nftIdArr[id] = nftIdArr[numberOfNFT - 1]; 558 | delete nftIdArr[numberOfNFT - 1]; 559 | nftAddressArr[id] = nftAddressArr[numberOfNFT - 1]; 560 | delete nftAddressArr[numberOfNFT - 1]; 561 | getNFTId[nftAddressArr[id]][nftIdArr[id]] = id; 562 | delete getNFTId[nftAddress][tokenId]; 563 | numberOfNFT--; 564 | emit NFTBurned(id); 565 | } 566 | 567 | /// @notice Function to set the number of confirmations required for transactions 568 | /// @param _confirmNumber The number of confirmations required for transactions 569 | function setConfirmationRequiredNumber( 570 | uint256 _confirmNumber 571 | ) external onlyDirector { 572 | require( 573 | _confirmNumber <= numberOfMembers && _confirmNumber >= 1, 574 | "Invalid Number" 575 | ); 576 | numConfirmationRequired = _confirmNumber; 577 | emit ConfirmationRequiredNumberSet(_confirmNumber); 578 | } 579 | 580 | /// @notice Function to set the team score 581 | /// @param _score Team score 582 | function setTeamScore(uint256 _score) external onlyFactory { 583 | require(_score >= 0 && _score <= 100, "Invalid score"); 584 | teamScore = _score; 585 | emit TeamScoreSet(_score); 586 | } 587 | 588 | /// @notice Function to upload member's NFT to the group 589 | /// @param _nftContractAddress The address of the NFT contract 590 | /// @param _tokenId The id of the NFT in the NFT contract 591 | function uploadMemberNFT( 592 | address _nftContractAddress, 593 | uint256 _tokenId 594 | ) external onlyMembers { 595 | require( 596 | IContentNFT(_nftContractAddress).ownerOf(_tokenId) == msg.sender, 597 | "Not owner" 598 | ); 599 | require( 600 | getNFTId[_nftContractAddress][_tokenId] == 0, 601 | "Already uploaded" 602 | ); 603 | uint256 _loyaltyFee = IContentNFT(_nftContractAddress).getLoyaltyFee( 604 | _tokenId 605 | ); 606 | if (_loyaltyFee != 0) { 607 | SafeERC20.safeTransferFrom( 608 | USDC_token, 609 | msg.sender, 610 | address(this), 611 | _loyaltyFee 612 | ); 613 | SafeERC20.forceApprove(USDC_token, _nftContractAddress, _loyaltyFee); 614 | } 615 | IContentNFT(_nftContractAddress).transferFrom( 616 | msg.sender, 617 | address(this), 618 | _tokenId 619 | ); 620 | nftAddressArr[numberOfNFT] = _nftContractAddress; 621 | nftIdArr[numberOfNFT] = _tokenId; 622 | getNFTId[_nftContractAddress][_tokenId] = numberOfNFT; 623 | record_member memory tmp = record_member(msg.sender, 0, 0); 624 | Recording[numberOfNFT].push(tmp); 625 | numberOfNFT++; 626 | emit UploadNFTFromMember(msg.sender, _nftContractAddress, _tokenId); 627 | } 628 | 629 | /// @notice Function to receive loyalty fee and distribute immediately automatically 630 | /// @param _nftId The id of the NFT 631 | /// @param _price The loyaltyFee for secondary sale 632 | function alarmLoyaltyFeeReceived(uint256 _nftId, uint256 _price) external { 633 | require( 634 | IContentNFT(msg.sender).creators(_nftId) == address(this), 635 | "Invalid Alarm!" 636 | ); 637 | uint256 id = getNFTId[msg.sender][_nftId]; 638 | require(id <= numberOfNFT - 1 && id >= 0, "NFT does not exist!"); 639 | require(listedState[id] == true, "Not listed"); 640 | eachDistribution(id, _price); 641 | emit LoyaltyFeeReceived(id, _price); 642 | } 643 | 644 | /// @notice Function to handle a sold-out event 645 | /// @param _nftContractAddress The address of the contract that sold out NFT 646 | /// @param _nftId The Id of the token contract that sold out NFT 647 | /// @param _price The price of the sold out NFT 648 | function alarmSoldOut( 649 | address _nftContractAddress, 650 | uint256 _nftId, 651 | uint256 _price 652 | ) external onlyMarketplace { 653 | require( 654 | IContentNFT(_nftContractAddress).creators(_nftId) == address(this), 655 | "Invalid Alarm!" 656 | ); 657 | uint256 id = getNFTId[_nftContractAddress][_nftId]; 658 | require(id <= numberOfNFT - 1 && id >= 0, "NFT does not exist!"); 659 | require(listedState[id] == true, "Not listed"); 660 | record_member[] memory temp = Recording[id]; 661 | uint256 sum = 0; 662 | for (uint256 i = 0; i < temp.length; ++i) { 663 | uint256 value = IMarketplace(marketplace).getBalanceOfUser( 664 | temp[i]._member 665 | ); 666 | Recording[id][i]._percent = value; 667 | sum += value; 668 | } 669 | for (uint256 i = 0; i < temp.length; ++i) { 670 | Recording[id][i]._sum = sum; 671 | } 672 | soldOutState[id] = true; 673 | soldInformation.push(soldInfor(id, _price, false)); 674 | } 675 | 676 | /// @notice Function to withdraw funds from the marketplace 677 | function withdrawFromMarketplace() external onlyDirector { 678 | IMarketplace(marketplace).withdrawFromSeller(); 679 | uint256 startNumber = currentDistributeNumber; 680 | for (uint256 i = startNumber; i < soldInformation.length; ++i) { 681 | if (!soldInformation[i].distributeState) 682 | eachDistribution( 683 | soldInformation[i].id, 684 | soldInformation[i].price 685 | ); 686 | soldInformation[i].distributeState = true; 687 | } 688 | currentDistributeNumber = soldInformation.length; 689 | emit WithdrawalFromMarketplace(); 690 | } 691 | 692 | /// @notice Function to withdraw funds from the contract 693 | function withdraw() external onlyMembers nonReentrant { 694 | uint256 balanceToWithdraw = balance[msg.sender]; 695 | require(balanceToWithdraw != 0, "No balance to withdraw"); 696 | balance[msg.sender] = 0; 697 | SafeERC20.safeTransfer(USDC_token, msg.sender, balanceToWithdraw); 698 | emit WithdrawHappened(msg.sender, balanceToWithdraw); 699 | } 700 | 701 | /// @notice Function to distribute revenue from sold NFTs 702 | /// @param _id NFT id in the group 703 | /// @param _value Earning Value 704 | function eachDistribution(uint256 _id, uint256 _value) internal { 705 | totalEarning += _value; 706 | uint256 count = Recording[_id].length; 707 | require(count != 0, "No members to distribute"); 708 | uint256 eachTeamScore = ((_value * teamScore) / 100) / count; 709 | uint256 remainingValue = _value - eachTeamScore * count; 710 | uint256[] memory _revenues = new uint256[](count); 711 | for (uint256 i = 0; i < count; ++i) { 712 | _revenues[i] += eachTeamScore; 713 | if (Recording[_id][i]._sum == 0) { 714 | _revenues[i] += remainingValue / count; 715 | } else { 716 | _revenues[i] += 717 | (remainingValue * Recording[_id][i]._percent) / 718 | Recording[_id][i]._sum; 719 | } 720 | } 721 | address[] memory _members = new address[](count); 722 | for (uint256 i = 0; i < count; ++i) { 723 | address tmp_address = Recording[_id][i]._member; 724 | revenueDistribution[tmp_address][_id] += _revenues[i]; 725 | _members[i] = tmp_address; 726 | balance[tmp_address] += _revenues[i]; 727 | } 728 | IMarketplace(marketplace).addBalanceOfUser( 729 | _members, 730 | _revenues, 731 | nftAddressArr[_id], 732 | nftIdArr[_id] 733 | ); 734 | } 735 | 736 | /// @notice Function to get the number of confirmations of a director setting transaction 737 | /// @param index The index of the transaction to get confirm number 738 | /// @return The number of confirmations of a director setting transaction 739 | function getConfirmNumberOfDirectorSettingTransaction( 740 | uint256 index 741 | ) public view returns (uint256) { 742 | uint256 count = 0; 743 | for (uint256 i = 0; i < numberOfMembers; ++i) { 744 | if (confirmTransaction_Candidate[members[i]][index] == true) { 745 | count++; 746 | } 747 | } 748 | return count; 749 | } 750 | 751 | /// @notice Function to get the number of confirmations of an offering sale transaction 752 | /// @param index The index of the transaction to get confirm number 753 | /// @return The number of confirmations of an offering sale transaction 754 | function getConfirmNumberOfOfferingSaleTransaction( 755 | uint256 index 756 | ) public view returns (uint256) { 757 | uint256 count = 0; 758 | for (uint256 i = 0; i < numberOfMembers; ++i) { 759 | if (confirmTransaction_Offering[members[i]][index] == true) { 760 | count++; 761 | } 762 | } 763 | return count; 764 | } 765 | 766 | /// @notice Function to get the number of confirmations of an offering sale transaction 767 | /// @param index The index of the transaction to get confirm number 768 | /// @return The number of confirmations of a burn transaction 769 | function getConfirmNumberOfBurnTransaction( 770 | uint256 index 771 | ) public view returns (uint256) { 772 | uint256 count = 0; 773 | for (uint256 i = 0; i < numberOfMembers; ++i) { 774 | if (confirmTransaction_Burn[members[i]][index] == true) { 775 | count++; 776 | } 777 | } 778 | return count; 779 | } 780 | 781 | /// @notice Function to get the number of candidate transactions 782 | /// @return The number of candidate transactions 783 | function getNumberOfCandidateTransaction() external view returns (uint256) { 784 | return transactions_candidate.length; 785 | } 786 | 787 | /// @notice Function to get the number of sale offering transactions 788 | /// @return The number of sale offering transactions 789 | function getNumberOfSaleOfferingTransaction() 790 | external 791 | view 792 | returns (uint256) 793 | { 794 | return transactions_offering.length; 795 | } 796 | 797 | /// @notice Function to get the number of burn transactions 798 | /// @return The number of burn transactions 799 | function getNumberOfBurnTransaction() external view returns (uint256) { 800 | return transactions_burn.length; 801 | } 802 | 803 | /// @notice Function to upload member owned NFT to the group 804 | /// @param contractAddress The address of the NFT contract 805 | /// @param tokenId The token Id of the NFT contract 806 | 807 | /// @notice Function to get the NFT ID of a specific index 808 | /// @param index The index of the NFT ID to get 809 | /// @return The NFT ID of a specific index 810 | function getNftOfId(uint256 index) external view returns (uint256) { 811 | return nftIdArr[index]; 812 | } 813 | 814 | /// @notice Function to get the NFT address of a specific index 815 | /// @param index The index of the NFT address to get 816 | /// @return The NFT address of a specific index 817 | function getNftAddress(uint256 index) external view returns (address) { 818 | return nftAddressArr[index]; 819 | } 820 | 821 | /// @notice Function to get the revenue distribution for a member and NFT ID 822 | /// @param _member The address of the member 823 | /// @param id The id of the NFT in the group 824 | /// @return The revenue for a member and NFT ID 825 | function getRevenueDistribution( 826 | address _member, 827 | uint256 id 828 | ) external view returns (uint256) { 829 | return revenueDistribution[_member][id]; 830 | } 831 | 832 | /// @notice Function to get the number of sold NFTs 833 | /// @return The number of sold NFTs 834 | function getSoldNumber() external view returns (uint256) { 835 | return soldInformation.length; 836 | } 837 | 838 | /// @notice Function to get information about a sold NFT at a specific index 839 | /// @param index The index of the sold NFT information to get 840 | /// @return The information about a sold NFT at a specific index 841 | function getSoldInfor( 842 | uint256 index 843 | ) external view returns (soldInfor memory) { 844 | return soldInformation[index]; 845 | } 846 | } 847 | -------------------------------------------------------------------------------- /contracts/Factory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.19; 3 | import "@openzeppelin/contracts/proxy/Clones.sol"; 4 | import "./interfaces/ICreatorGroup.sol"; 5 | import "./interfaces/IContentNFT.sol"; 6 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 7 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 8 | 9 | 10 | contract Factory { 11 | // State variables 12 | address public owner; // Address of the contract owner 13 | address public developmentTeam; // Address of the development team associated with the contract 14 | address public marketplace; // Address of the marketplace contract 15 | uint256 public numberOfCreators; // Number of creators associated with the contract 16 | address[] public Creators; // Array to store addresses of creators 17 | address public implementGroup; // Address of the implementation contract for creating groups 18 | address public implementContent; // Address of the implementation contract for creating content 19 | uint256 public mintFee; // Fee required for minting NFTs 20 | uint256 public burnFee; // Fee required for burning NFTs 21 | address public USDC; // Address of the USDC token contract 22 | IERC20 public immutable USDC_token; // USDC token contract 23 | // Events 24 | event GroupCreated( 25 | address indexed creator, 26 | string indexed name, 27 | string indexed description, 28 | address newDeployedAddress 29 | ); 30 | event NewNFTMinted(address indexed creator, address indexed nftAddress); 31 | event WithdrawalFromDevelopmentTeam(address indexed withdrawer, uint256 indexed amount); 32 | event TeamScoreChanged(address indexed teamMember, uint256 indexed score); 33 | // Modifier to restrict access to only the contract owner 34 | modifier onlyOwner() { 35 | require(msg.sender == owner, "Only owner can call this function"); 36 | _; 37 | } 38 | modifier onlyGroup() { 39 | bool flg = false; 40 | for(uint256 i = 0; i < numberOfCreators; ++i) { 41 | if (msg.sender == Creators[i]) { 42 | flg = true; break; 43 | } 44 | } 45 | require(flg == true, "Only group can call this function"); 46 | _; 47 | } 48 | /// @notice Constructor to initialize contract variables 49 | /// @param _implementGroup Address of the implementation contract for creating groups 50 | /// @param _implementContent Context of the implementation contract for NFT Collection 51 | /// @param _marketplace Address of the marketplace contract 52 | /// @param _developmentTeam Address of the development team 53 | /// @param _mintFee Fee required for minting NFTs 54 | /// @param _burnFee Fee required for burning NFTs 55 | /// @param _USDC Address of the USDC token contract 56 | constructor( 57 | address _implementGroup, 58 | address _implementContent, 59 | address _marketplace, 60 | address _developmentTeam, 61 | uint256 _mintFee, 62 | uint256 _burnFee, 63 | address _USDC 64 | ) payable { 65 | owner = msg.sender; 66 | require(_marketplace!= address(0), "Address cannot be 0"); 67 | marketplace = _marketplace; 68 | require(_developmentTeam!= address(0), "Address cannot be 0"); 69 | developmentTeam = _developmentTeam; 70 | numberOfCreators = 0; 71 | mintFee = _mintFee; 72 | burnFee = _burnFee; 73 | require(_implementGroup != address(0), "Address cannot be 0"); 74 | implementGroup = _implementGroup; 75 | require(_implementContent!= address(0), "Address cannot be 0"); 76 | implementContent = _implementContent; 77 | require(_USDC != address(0), "Address cannot be 0"); 78 | USDC = _USDC; 79 | USDC_token = IERC20(_USDC); 80 | } 81 | 82 | /// @notice Function to create a new group 83 | /// @param _name The name of the group 84 | /// @param _description The description of the group 85 | /// @param _members The members of the group 86 | /// @param _numConfirmationRequired The number of confirmations required for execution of a transaction in the group 87 | 88 | function createGroup( 89 | string memory _name, 90 | string memory _description, 91 | address[] memory _members, 92 | uint256 _numConfirmationRequired 93 | ) external { 94 | require(_members.length != 0, "At least one owner is required"); 95 | address newDeployedAddress = Clones.clone(implementGroup); 96 | ICreatorGroup(newDeployedAddress).initialize( 97 | _name, 98 | _description, 99 | _members, 100 | _numConfirmationRequired, 101 | marketplace, 102 | mintFee, 103 | burnFee, 104 | USDC 105 | ); 106 | Creators.push(newDeployedAddress); 107 | numberOfCreators = Creators.length; 108 | emit GroupCreated(msg.sender, _name, _description, newDeployedAddress); 109 | } 110 | 111 | /// @notice Function to mint a new NFT 112 | /// @param _nftURI The URI of the NFT 113 | /// @param _name The name of the new collection 114 | /// @param _symbol The symbol of the new collection 115 | /// @param _description The description of the new collection 116 | /// @return The address of the new collection 117 | function mintNew( 118 | string memory _nftURI, 119 | string memory _name, 120 | string memory _symbol, 121 | string memory _description 122 | ) external onlyGroup returns (address) { 123 | uint256 beforeBalance = USDC_token.balanceOf(address(this)); 124 | if(mintFee != 0) { 125 | SafeERC20.safeTransferFrom(USDC_token, msg.sender, address(this), mintFee); 126 | } 127 | uint256 afterBalance = USDC_token.balanceOf(address(this)); 128 | require(afterBalance - beforeBalance >= mintFee, "Not enough funds to pay the mint fee"); 129 | address newDeployedAddress = Clones.clone(implementContent); 130 | IContentNFT(newDeployedAddress).initialize( 131 | _name, 132 | _symbol, 133 | _description, 134 | _nftURI, 135 | msg.sender, 136 | mintFee, 137 | burnFee, 138 | USDC, 139 | marketplace 140 | ); 141 | emit NewNFTMinted(msg.sender, newDeployedAddress); 142 | return newDeployedAddress; 143 | } 144 | 145 | /// @notice Function for the development team to withdraw funds 146 | /// @dev Only the development team can call this function 147 | function withdraw() external { 148 | require(msg.sender == developmentTeam, "Invalid withdrawer"); 149 | uint256 amount = IERC20(USDC).balanceOf(address(this)); 150 | if(amount != 0) { 151 | SafeERC20.safeTransfer(USDC_token, msg.sender, amount) ; 152 | } 153 | emit WithdrawalFromDevelopmentTeam(msg.sender, amount); 154 | } 155 | 156 | /// @notice Function for the owner to set the team score for revenue distribution of a creator group 157 | /// @param _id The ID of the creator group 158 | /// @param _score The team score for the creator group 159 | function setTeamScoreForCreatorGroup( 160 | uint256 _id, 161 | uint256 _score 162 | ) external onlyOwner { 163 | require(Creators.length > _id, "Invalid creator group"); 164 | require(_score >= 0 && _score <= 100, "Invalid score"); 165 | ICreatorGroup(Creators[_id]).setTeamScore(_score); 166 | emit TeamScoreChanged(Creators[_id], _score); 167 | } 168 | 169 | /// @notice Function to check if it is a creator group 170 | /// @param _groupAddress The group address 171 | /// @return The bool value if it is a creator group -> true, or not -> false 172 | function isCreatorGroup(address _groupAddress) external view returns(bool){ 173 | bool flg = false; 174 | for(uint256 i = 0; i < numberOfCreators; ++i) { 175 | if (_groupAddress == Creators[i]) { 176 | flg = true; break; 177 | } 178 | } 179 | return flg; 180 | } 181 | 182 | /// @notice Function to get the address of a creator group at a specific index 183 | /// @param _id The ID of the creator group 184 | /// @return The address of the creator group 185 | function getCreatorGroupAddress(uint256 _id) external view returns (address) { 186 | return Creators[_id]; 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /contracts/Marketplace.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.19; 3 | 4 | import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import "./interfaces/ICreatorGroup.sol"; 7 | import "./interfaces/IContentNFT.sol"; 8 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 9 | import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; 10 | 11 | 12 | contract Marketplace is ReentrancyGuard { 13 | // Enum defining different sale types 14 | enum SaleType { 15 | ENGLISH_AUCTION, 16 | DUTCH_AUCTION, 17 | OFFERING_SALE 18 | } 19 | // Struct to represent a listed NFT 20 | struct listedNFT { 21 | SaleType _saleType; 22 | uint256 Id; 23 | address currentOwner; 24 | address nftContractAddress; 25 | uint256 nftId; 26 | uint256 startTime; 27 | uint256 endTime; 28 | bool endState; 29 | } 30 | // Struct to handle English auction details 31 | struct englishAuction { 32 | uint256 initialPrice; 33 | uint256 salePeriod; 34 | address currentWinner; 35 | uint256 currentPrice; 36 | } 37 | // Struct to handle Dutch auction details 38 | struct dutchAuction { 39 | uint256 initialPrice; 40 | uint256 reducingRate; 41 | uint256 salePeriod; 42 | } 43 | // Strcut to handle Offering Sale details 44 | struct offeringSale { 45 | uint256 initialPrice; 46 | uint256 bidNumber; 47 | } 48 | // State variables 49 | address public owner; // Address of the contract owner 50 | address public developmentTeam; // Address of the development team 51 | uint256 public balanceOfDevelopmentTeam; // Balance of the development team 52 | uint256 public percentForSeller; // Percentage of the Seller 53 | uint256 public percentForLoyaltyFee; // Percentage of the loyalty fee 54 | mapping(address => uint256) public balanceOfUser; // Balance of the user 55 | address public USDC; // Address of the USDC 56 | IERC20 public immutable USDC_token; // USDC token contract 57 | mapping(address => uint256) public balanceOfSeller; // Balance of the seller 58 | listedNFT[] public listedNFTs; // Array to store listed NFTs 59 | mapping(uint256 => bool) public cancelListingState; // Array to store state of cancelListing 60 | mapping(uint256 => mapping(address => uint256)) public englishAuction_balancesForWithdraw; // Mapping to store balances available for withdrawal in English auctions 61 | englishAuction[] public englishAuctions; // Array to store instances of English auction contracts 62 | mapping(uint256 => uint256) public englishAuction_listedNumber; // Mapping to track the number of items listed in each English auction 63 | dutchAuction[] public dutchAuctions; // Array to store instances of Dutch auction contracts 64 | mapping(uint256 => uint256) public dutchAuction_listedNumber; // Mapping to track the number of items listed in each Dutch auction 65 | mapping(uint256 => mapping(address => uint256)) public offeringSale_balancesForWithdraw; // Mapping to store balances available for withdrawal in offering sales 66 | mapping(uint256 => mapping(address => uint256)) offeringSale_currentBids; // Mapping to store current bids in offering sales 67 | offeringSale[] public offeringSales; // Array to store instances of offering sale contracts 68 | mapping(uint256 => uint256) public offeringSale_listedNumber; // Mapping to track the number of items listed in each offering sale 69 | //event 70 | event BuyEnglishAuction( 71 | address indexed buyer, 72 | address indexed contractAddress, 73 | uint256 indexed nftId, 74 | uint256 price, 75 | uint256 time 76 | ); 77 | event BuyDutchAuction( 78 | address indexed buyer, 79 | address indexed contractAddress, 80 | uint256 indexed nftId, 81 | uint256 price, 82 | uint256 time 83 | ); 84 | event BuyOfferingSale( 85 | address indexed buyer, 86 | address indexed contractAddress, 87 | uint256 indexed nftId, 88 | uint256 price, 89 | uint256 time 90 | ); 91 | event Withdrawal(address indexed withdrawer, uint256 indexed amount); 92 | event PercentForSellerSet(uint256 indexed _percentForSeller); 93 | event NewEnglishAuctionListing( 94 | address indexed _nftContractAddress, 95 | uint256 indexed _nftId, 96 | uint256 indexed _initialPrice, 97 | uint256 _salePeriod 98 | ); 99 | event NewDutchAuctionListing( 100 | address indexed _nftContractAddress, 101 | uint256 indexed nftId, 102 | uint256 indexed initialPrice, 103 | uint256 reducingRate, 104 | uint256 salePeriod 105 | ); 106 | event NewOfferingSaleListing( 107 | address indexed nftContractAddress, 108 | uint256 indexed nftId, 109 | uint256 indexed initialPrice 110 | ); 111 | event NewBidToEnglishAuction( 112 | uint256 indexed id, 113 | uint256 indexed sendingValue, 114 | address indexed currentWinner 115 | ); 116 | event NewWithdrawFromEnglishAuction( 117 | uint256 indexed id, 118 | address indexed from, 119 | uint256 indexed amount 120 | ); 121 | event NewBidToOfferingSale(uint256 indexed id, address indexed from, uint256 indexed sendingValue); 122 | event NewWithdrawFromOfferingSale(uint256 indexed id, address indexed from, uint256 indexed amount); 123 | event CanceledListing(uint256 indexed id, address indexed from); 124 | event PercentForLoyaltyFeeSet(uint256 indexed value); 125 | // Modifier to restrict access to only the contract owner 126 | modifier onlyOwner() { 127 | require(msg.sender == owner, "Only owner can call this function"); 128 | _; 129 | } 130 | /// @notice Constructor to set the development team address 131 | /// @param _developmentTeam Address of the development team 132 | /// @param _percentForSeller Revenue Percentage for the seller of the sold NFT 133 | /// @param _USDC Address of the USDC token 134 | constructor( 135 | address _developmentTeam, 136 | uint256 _percentForSeller, 137 | address _USDC 138 | ) { 139 | owner = msg.sender; 140 | require(_developmentTeam!= address(0), "Invalid address"); 141 | developmentTeam = _developmentTeam; 142 | require(_percentForSeller <= 100 && _percentForSeller != 0, "Invalid percentage"); 143 | percentForSeller = _percentForSeller; 144 | balanceOfDevelopmentTeam = 0; 145 | require(_USDC!= address(0), "Invalid address"); 146 | USDC = _USDC; 147 | USDC_token = IERC20(USDC) ; 148 | percentForLoyaltyFee = 5; 149 | } 150 | 151 | /// @notice Function to list an NFT to an English auction 152 | /// @param _nftContractAddress Address of the NFT contract 153 | /// @param _nftId TokenId of the NFT contract 154 | /// @param _initialPrice Initial price of the NFT 155 | /// @param _salePeriod Sale period of the NFT 156 | function listToEnglishAuction( 157 | address _nftContractAddress, 158 | uint256 _nftId, 159 | uint256 _initialPrice, 160 | uint256 _salePeriod 161 | ) external { 162 | require( 163 | checkOwnerOfNFT(_nftContractAddress, _nftId) == true, 164 | "Invalid token owner" 165 | ); 166 | uint256 id = englishAuctions.length; 167 | englishAuction memory newAuction = englishAuction( 168 | _initialPrice, 169 | _salePeriod, 170 | address(0), 171 | _initialPrice 172 | ); 173 | englishAuctions.push(newAuction); 174 | listedNFT memory newListing = listedNFT( 175 | SaleType.ENGLISH_AUCTION, 176 | id, 177 | msg.sender, 178 | _nftContractAddress, 179 | _nftId, 180 | block.timestamp, 181 | 0, 182 | false 183 | ); 184 | englishAuction_listedNumber[id] = listedNFTs.length; 185 | listedNFTs.push(newListing); 186 | emit NewEnglishAuctionListing( 187 | _nftContractAddress, 188 | _nftId, 189 | _initialPrice, 190 | _salePeriod 191 | ); 192 | } 193 | 194 | /// @notice Function to list an NFT to a Dutch auction 195 | /// @param _nftContractAddress Address of the NFT contract 196 | /// @param _nftId TokenId of the NFT contract 197 | /// @param _initialPrice Initial price of the NFT 198 | /// @param _reducingRate The reducing rate per hour 199 | /// @param _salePeriod Sale period of the NFT 200 | function listToDutchAuction( 201 | address _nftContractAddress, 202 | uint256 _nftId, 203 | uint256 _initialPrice, 204 | uint256 _reducingRate, 205 | uint256 _salePeriod 206 | ) external { 207 | require( 208 | checkOwnerOfNFT(_nftContractAddress, _nftId) == true, 209 | "Invalid token owner" 210 | ); 211 | require( 212 | _initialPrice > _reducingRate * (_salePeriod / 3600), 213 | "Invalid information for Dutch Auction!" 214 | ); 215 | uint256 id = dutchAuctions.length; 216 | dutchAuction memory newAuction = dutchAuction( 217 | _initialPrice, 218 | _reducingRate, 219 | _salePeriod 220 | ); 221 | dutchAuctions.push(newAuction); 222 | listedNFT memory newListing = listedNFT( 223 | SaleType.DUTCH_AUCTION, 224 | id, 225 | msg.sender, 226 | _nftContractAddress, 227 | _nftId, 228 | block.timestamp, 229 | 0, 230 | false 231 | ); 232 | dutchAuction_listedNumber[id] = listedNFTs.length; 233 | listedNFTs.push(newListing); 234 | emit NewDutchAuctionListing( 235 | _nftContractAddress, 236 | _nftId, 237 | _initialPrice, 238 | _reducingRate, 239 | _salePeriod 240 | ); 241 | } 242 | 243 | /// @notice Function to list an NFT for an offering sale 244 | /// @param _nftContractAddress Address of the NFT contract 245 | /// @param _nftId TokenId of the NFT contract 246 | /// @param _initialPrice Initial price of the NFT 247 | function listToOfferingSale( 248 | address _nftContractAddress, 249 | uint256 _nftId, 250 | uint256 _initialPrice 251 | ) external { 252 | require( 253 | checkOwnerOfNFT(_nftContractAddress, _nftId) == true, 254 | "Invalid token owner" 255 | ); 256 | uint256 id = offeringSales.length; 257 | offeringSale memory newSale = offeringSale(_initialPrice, 0); 258 | offeringSales.push(newSale); 259 | listedNFT memory newListing = listedNFT( 260 | SaleType.OFFERING_SALE, 261 | id, 262 | msg.sender, 263 | _nftContractAddress, 264 | _nftId, 265 | block.timestamp, 266 | 0, 267 | false 268 | ); 269 | offeringSale_listedNumber[id] = listedNFTs.length; 270 | listedNFTs.push(newListing); 271 | emit NewOfferingSaleListing(_nftContractAddress, _nftId, _initialPrice); 272 | } 273 | 274 | /// @notice Function to check the owner of an NFT 275 | /// @param _nftContractAddress Address of the NFT contract 276 | /// @param _nftId Id of the NFT contract 277 | /// @return true if the owner is the sender, false otherwise 278 | function checkOwnerOfNFT( 279 | address _nftContractAddress, 280 | uint256 _nftId 281 | ) public view returns (bool) { 282 | address checkAddress = IERC721(_nftContractAddress).ownerOf(_nftId); 283 | return (checkAddress == msg.sender); 284 | } 285 | 286 | /// @notice Function for a user to bid in an English auction 287 | /// @param _id The list id of the English Auction 288 | /// @param _sendingValue Bid amount 289 | function makeBidToEnglishAuction(uint256 _id, uint256 _sendingValue) external { 290 | require( 291 | englishAuctions.length > _id && _id >= 0, 292 | "Not listed in the english auction list." 293 | ); 294 | uint256 listedId = englishAuction_listedNumber[_id]; 295 | require(cancelListingState[listedId] == false, "Listing Cancelled."); 296 | uint256 expectEndTime = listedNFTs[listedId].startTime + 297 | englishAuctions[_id].salePeriod; 298 | require(expectEndTime > block.timestamp, "Auction ended!"); 299 | require(listedNFTs[listedId].endState == false, "Already sold out."); 300 | uint256 price = englishAuctions[_id].currentPrice; 301 | address currentWinner = englishAuctions[_id].currentWinner; 302 | require( 303 | _sendingValue > price, 304 | "You should send a price that is more than current price." 305 | ); 306 | if(_sendingValue != 0) SafeERC20.safeTransferFrom(USDC_token, msg.sender, address(this), _sendingValue) ; 307 | englishAuction_balancesForWithdraw[_id][currentWinner] += price; 308 | englishAuctions[_id].currentPrice = _sendingValue; 309 | englishAuctions[_id].currentWinner = msg.sender; 310 | emit NewBidToEnglishAuction(_id, _sendingValue, msg.sender); 311 | } 312 | 313 | /// @notice Function to withdraw funds from an English auction 314 | /// @param _id The list id of the English Auction 315 | function withdrawFromEnglishAuction(uint256 _id) external nonReentrant { 316 | require( 317 | englishAuctions.length > _id && _id >= 0, 318 | "Not listed in the english auction list." 319 | ); 320 | uint256 amount = englishAuction_balancesForWithdraw[_id][msg.sender]; 321 | require(amount != 0, "You don't have any balance."); 322 | englishAuction_balancesForWithdraw[_id][msg.sender] = 0; 323 | SafeERC20.safeTransfer(USDC_token, msg.sender, amount); 324 | emit NewWithdrawFromEnglishAuction(_id, msg.sender, amount); 325 | } 326 | 327 | /// @notice Function to end an English auction 328 | /// @param _nftContractAddress Address of the NFT contract 329 | /// @param _nftId Id of the NFT contract 330 | function endEnglishAuction(address _nftContractAddress, uint256 _nftId) external { 331 | uint256 id; 332 | bool flg = false; 333 | for (uint256 i = 0; i < englishAuctions.length; ++i) { 334 | uint256 tmp_Id = englishAuction_listedNumber[i]; 335 | if ( 336 | listedNFTs[tmp_Id].nftContractAddress == _nftContractAddress && 337 | listedNFTs[tmp_Id].nftId == _nftId 338 | ) { 339 | id = i; 340 | flg = true; 341 | break; 342 | } 343 | } 344 | require(flg, "Wrong nft"); 345 | require( 346 | englishAuctions.length > id && id >= 0, 347 | "Not listed in the english auction list." 348 | ); 349 | uint256 listedId = englishAuction_listedNumber[id]; 350 | require(cancelListingState[listedId] == false, "Listing Cancelled."); 351 | uint256 expectEndTime = listedNFTs[listedId].startTime + 352 | englishAuctions[id].salePeriod; 353 | require(expectEndTime < block.timestamp, "Auction is not ended!"); 354 | address contractAddress = _nftContractAddress; 355 | uint256 nftId = _nftId; 356 | uint256 price = englishAuctions[id].currentPrice; 357 | uint256 initialPrice= englishAuctions[id].initialPrice; 358 | address currentOwner = listedNFTs[listedId].currentOwner; 359 | require( 360 | msg.sender == currentOwner, 361 | "Only current Owner is allowed to end the auction." 362 | ); 363 | require( 364 | price > initialPrice, 365 | "No bidder!" 366 | ); 367 | uint256 loyaltyFee; 368 | loyaltyFee = (price * percentForLoyaltyFee) / 100; 369 | IContentNFT(contractAddress).setLoyaltyFee(nftId, loyaltyFee); 370 | if (IContentNFT(contractAddress).creators(nftId) == currentOwner) 371 | loyaltyFee = 0; 372 | if(loyaltyFee != 0) { 373 | SafeERC20.forceApprove(USDC_token, contractAddress, loyaltyFee); 374 | } 375 | IContentNFT(contractAddress).transferFrom( 376 | currentOwner, 377 | englishAuctions[id].currentWinner, 378 | nftId 379 | ); 380 | recordRevenue(currentOwner, price - loyaltyFee, contractAddress, nftId); 381 | listedNFTs[listedId].endState = true; 382 | listedNFTs[listedId].endTime = block.timestamp; 383 | emit BuyEnglishAuction( 384 | englishAuctions[id].currentWinner, 385 | contractAddress, 386 | nftId, 387 | price, 388 | block.timestamp 389 | ); 390 | } 391 | 392 | /// @notice Function to record revenue from a sale 393 | /// @param _seller Address of the seller 394 | /// @param _price Price of the NFT 395 | /// @param _nftContractAddress Address of the NFT contract 396 | /// @param _nftId TokenId of the NFT contract 397 | function recordRevenue( 398 | address _seller, 399 | uint256 _price, 400 | address _nftContractAddress, 401 | uint256 _nftId 402 | ) private { 403 | uint256 value = (_price * percentForSeller) / 100; 404 | balanceOfSeller[_seller] += value; 405 | balanceOfDevelopmentTeam += _price - value; 406 | ICreatorGroup(_seller).alarmSoldOut(_nftContractAddress, _nftId, value); 407 | } 408 | 409 | /// @notice Function for a user to buy in a Dutch auction 410 | /// @param _id The list id of the Dutch Auction 411 | /// @param _sendingValue Bid amount 412 | function buyDutchAuction(uint256 _id, uint256 _sendingValue) external { 413 | require( 414 | dutchAuctions.length > _id && _id >= 0, 415 | "Not listed in the dutch auction list." 416 | ); 417 | uint256 listedId = dutchAuction_listedNumber[_id]; 418 | require(cancelListingState[listedId] == false, "Listing Cancelled."); 419 | require(listedNFTs[listedId].endState == false, "Already sold out."); 420 | uint256 expectEndTime = listedNFTs[listedId].startTime + 421 | dutchAuctions[_id].salePeriod; 422 | require(expectEndTime > block.timestamp, "Auction ended!"); 423 | address contractAddress = listedNFTs[listedId].nftContractAddress; 424 | uint256 nftId = listedNFTs[listedId].nftId; 425 | address currentOwner = listedNFTs[listedId].currentOwner; 426 | uint256 price = getDutchAuctionPrice(_id); 427 | require(_sendingValue == price, "Not exact fee"); 428 | if(_sendingValue != 0) SafeERC20.safeTransferFrom(USDC_token, msg.sender, address(this), _sendingValue); 429 | uint256 loyaltyFee; 430 | loyaltyFee = (price * percentForLoyaltyFee) / 100; 431 | IContentNFT(contractAddress).setLoyaltyFee(nftId, loyaltyFee); 432 | if (IContentNFT(contractAddress).creators(nftId) == currentOwner) 433 | loyaltyFee = 0; 434 | if(loyaltyFee != 0) { 435 | SafeERC20.forceApprove(USDC_token, contractAddress, loyaltyFee); 436 | } 437 | IContentNFT(contractAddress).transferFrom( 438 | currentOwner, 439 | msg.sender, 440 | nftId 441 | ); 442 | recordRevenue(currentOwner, price - loyaltyFee, contractAddress, nftId); 443 | listedNFTs[listedId].endState = true; 444 | listedNFTs[listedId].endTime = block.timestamp; 445 | emit BuyDutchAuction( 446 | msg.sender, 447 | contractAddress, 448 | nftId, 449 | price, 450 | block.timestamp 451 | ); 452 | } 453 | 454 | /// @notice Function for a user to bid in an offering sale 455 | /// @param _id The list id of the Offering Sale 456 | /// @param _sendingValue Bid amount 457 | function makeBidToOfferingSale(uint256 _id, uint256 _sendingValue) external { 458 | require( 459 | offeringSales.length > _id && _id >= 0, 460 | "Not listed in the offering sale list." 461 | ); 462 | uint256 listedId = offeringSale_listedNumber[_id]; 463 | require(cancelListingState[listedId] == false, "Listing Cancelled."); 464 | require(listedNFTs[listedId].endState == false, "Already sold out."); 465 | address contractAddress = listedNFTs[listedId].nftContractAddress; 466 | uint256 nftId = listedNFTs[listedId].nftId; 467 | address currentOwner = listedNFTs[listedId].currentOwner; 468 | uint256 price = offeringSales[_id].initialPrice; 469 | require( 470 | _sendingValue >= price, 471 | "You should send a price that is more than current price." 472 | ); 473 | offeringSales[_id].bidNumber++; 474 | if(_sendingValue != 0) SafeERC20.safeTransferFrom(USDC_token, msg.sender, address(this), _sendingValue); 475 | offeringSale_currentBids[_id][msg.sender] = _sendingValue; 476 | offeringSale_balancesForWithdraw[_id][msg.sender] += _sendingValue; 477 | // call the CreatorGroup's function 478 | ICreatorGroup(currentOwner).submitOfferingSaleTransaction( 479 | _id, 480 | contractAddress, 481 | nftId, 482 | msg.sender, 483 | _sendingValue 484 | ); 485 | emit NewBidToOfferingSale(_id, msg.sender, _sendingValue); 486 | } 487 | 488 | /// @notice Function to withdraw funds from an offering sale 489 | /// @param _id The list id of the Offering Sale 490 | function withdrawFromOfferingSale(uint256 _id) external nonReentrant{ 491 | require( 492 | offeringSales.length > _id && _id >= 0, 493 | "Not listed in the offering sale list." 494 | ); 495 | uint256 listedId = offeringSale_listedNumber[_id]; 496 | require(listedNFTs[listedId].endState == true, "Not finished yet"); 497 | uint256 amount = offeringSale_balancesForWithdraw[_id][msg.sender]; 498 | require(amount != 0, "You don't have any balance."); 499 | offeringSale_balancesForWithdraw[_id][msg.sender] = 0; 500 | if(amount != 0) SafeERC20.safeTransfer(USDC_token, msg.sender, amount) ; 501 | emit NewWithdrawFromOfferingSale(_id, msg.sender, amount); 502 | } 503 | 504 | /// @notice Function to end an offering sale 505 | /// @param _id The list id of the Offering Sale 506 | /// @param _buyer The address of the buyer 507 | function endOfferingSale(uint256 _id, address _buyer) external { 508 | require( 509 | offeringSales.length > _id && _id >= 0, 510 | "Not listed in the offering sale list." 511 | ); 512 | uint256 listedId = offeringSale_listedNumber[_id]; 513 | require(cancelListingState[listedId] == false, "Listing Cancelled."); 514 | require(listedNFTs[listedId].endState == false, "Already sold out!"); 515 | uint256 price = offeringSale_currentBids[_id][_buyer]; 516 | require(price != 0, "Buyer doesn't have any bid."); 517 | address contractAddress = listedNFTs[listedId].nftContractAddress; 518 | uint256 nftId = listedNFTs[listedId].nftId; 519 | require( 520 | checkOwnerOfNFT(contractAddress, nftId) == true, 521 | "only the nft owner can call this function" 522 | ); 523 | uint256 loyaltyFee; 524 | loyaltyFee = (price * percentForLoyaltyFee) / 100; 525 | IContentNFT(contractAddress).setLoyaltyFee(nftId, loyaltyFee); 526 | if (IContentNFT(contractAddress).creators(nftId) == msg.sender) 527 | loyaltyFee = 0; 528 | if(loyaltyFee != 0) { 529 | SafeERC20.forceApprove(USDC_token, contractAddress, loyaltyFee); 530 | } 531 | IContentNFT(contractAddress).transferFrom(msg.sender, _buyer, nftId); 532 | recordRevenue(msg.sender, price - loyaltyFee, contractAddress, nftId); 533 | listedNFTs[listedId].endState = true; 534 | listedNFTs[listedId].endTime = block.timestamp; 535 | offeringSale_balancesForWithdraw[_id][_buyer] -= price; 536 | emit BuyOfferingSale( 537 | _buyer, 538 | contractAddress, 539 | nftId, 540 | price, 541 | block.timestamp 542 | ); 543 | } 544 | 545 | /// @notice Function to cancel a listing 546 | /// @param _nftContractAddress The address of the NFT contract 547 | /// @param _nftId The ID of the NFT 548 | function cancelListing(address _nftContractAddress, uint256 _nftId) external { 549 | require( 550 | checkOwnerOfNFT(_nftContractAddress, _nftId) == true, 551 | "only the nft owner can call this function" 552 | ); 553 | uint256 id; 554 | bool flag = false ; 555 | for (uint256 i = 0; i < listedNFTs.length; ++i) { 556 | if ( 557 | listedNFTs[i].nftContractAddress == _nftContractAddress && 558 | listedNFTs[i].nftId == _nftId 559 | ) { 560 | id = i; 561 | flag = true ; 562 | break; 563 | } 564 | } 565 | require(flag == true, "Not listed yet"); 566 | require(listedNFTs[id].endState == false, "Already sold out!"); 567 | uint256 listId = listedNFTs[id].Id; 568 | require( 569 | !(listedNFTs[id]._saleType == SaleType.ENGLISH_AUCTION && 570 | englishAuctions[listId].currentPrice != 571 | englishAuctions[listId].initialPrice), 572 | "Already english auction started!" 573 | ); 574 | require( 575 | !(listedNFTs[id]._saleType == SaleType.OFFERING_SALE && 576 | offeringSales[listId].bidNumber != 0), 577 | "Already sale offering started!" 578 | ); 579 | cancelListingState[id] = true; 580 | emit CanceledListing(id, msg.sender); 581 | } 582 | 583 | /// @notice Function to add balance to multiple users 584 | /// @param _members Array of addresses to add balance 585 | /// @param _values Array of values to add to the balance of each user 586 | /// @param _nftContractAddress Address of the NFT contract 587 | /// @param _nftId TokenId of the NFT contract 588 | function addBalanceOfUser( 589 | address[] memory _members, 590 | uint256[] memory _values, 591 | address _nftContractAddress, 592 | uint256 _nftId 593 | ) external { 594 | bool flag = false; 595 | for (uint256 i = 0; i < listedNFTs.length; ++i) { 596 | if ( 597 | listedNFTs[i].nftContractAddress == _nftContractAddress && 598 | listedNFTs[i].nftId == _nftId && 599 | listedNFTs[i].currentOwner == msg.sender && 600 | listedNFTs[i].endState == true 601 | ) { 602 | flag = true; 603 | break; 604 | } 605 | } 606 | require(flag == true, "Invalid address for adding revenue"); 607 | for (uint256 i = 0; i < _members.length; ++i) { 608 | balanceOfUser[_members[i]] += _values[i]; 609 | } 610 | } 611 | 612 | /// @notice Function to set the percentage for seller 613 | /// @param _percentForSeller Revenue Percentage for the seller of the sold NFT 614 | /// @dev Only callable by the owner 615 | function setPercentForSeller(uint256 _percentForSeller) external onlyOwner { 616 | percentForSeller = _percentForSeller; 617 | emit PercentForSellerSet(percentForSeller); 618 | } 619 | 620 | /// @notice Function to set the percentage for Loyalty Fee 621 | /// @param _percentForLoyaltyFee Percentage for Loyalty Fee 622 | /// @dev Only callable by the owner 623 | function setPercentForLoyaltyFee( 624 | uint256 _percentForLoyaltyFee 625 | ) external onlyOwner { 626 | percentForLoyaltyFee = _percentForLoyaltyFee; 627 | emit PercentForLoyaltyFeeSet(percentForLoyaltyFee); 628 | } 629 | 630 | /// @notice Function to withdraw funds from the contract 631 | function withdraw() external nonReentrant{ 632 | require(msg.sender == developmentTeam, "Invalid withdrawer"); 633 | uint amount = balanceOfDevelopmentTeam; 634 | balanceOfDevelopmentTeam = 0; 635 | if(amount != 0) SafeERC20.safeTransfer(USDC_token, msg.sender, amount) ; 636 | emit Withdrawal(msg.sender, amount); 637 | } 638 | 639 | /// @notice Function to withdraw funds from a seller's balance 640 | function withdrawFromSeller() external nonReentrant{ 641 | require(balanceOfSeller[msg.sender] != 0, "Invalid withdrawer"); 642 | uint amount = balanceOfSeller[msg.sender]; 643 | balanceOfSeller[msg.sender] = 0; 644 | if(amount != 0) SafeERC20.safeTransfer(USDC_token, msg.sender, amount) ; 645 | emit Withdrawal(msg.sender, amount); 646 | } 647 | /// @notice Function to get the balance of a specific user 648 | /// @param to Address to get the balance of user 649 | /// @return The balance of a specific user 650 | function getBalanceOfUser(address to) external view returns (uint256) { 651 | return balanceOfUser[to]; 652 | } 653 | 654 | /// @notice Function to get the number of Listed NFTs 655 | /// @return The number of Listed NFTs 656 | function getListedNumber() external view returns (uint256) { 657 | return listedNFTs.length; 658 | } 659 | 660 | /// @notice Function to get the number of English Auctions 661 | /// @return The number of English Auctions 662 | function getListedEnglishAuctionNumber() external view returns (uint256) { 663 | return englishAuctions.length; 664 | } 665 | 666 | /// @notice Function to get the number of Dutch Auctions 667 | /// @return The number of Dutch Auctions 668 | function getListedDutchAuctionNumber() external view returns (uint256) { 669 | return dutchAuctions.length; 670 | } 671 | 672 | /// @notice Function to get the number of Offering Sales 673 | /// @return The number of Offering Sales 674 | function getOfferingSaleAuctionNumber() external view returns (uint256) { 675 | return offeringSales.length; 676 | } 677 | 678 | /// @notice Function to get the current price in a Dutch auction 679 | /// @param id The list id of the Dutch Auction 680 | /// @return The current price in a Dutch auction of specified NFT 681 | 682 | function getDutchAuctionPrice(uint256 id) public view returns (uint256) { 683 | uint256 listedId = dutchAuction_listedNumber[id]; 684 | uint256 duration = 3600; 685 | uint256 price = dutchAuctions[id].initialPrice - 686 | ((block.timestamp - listedNFTs[listedId].startTime) / duration) * 687 | dutchAuctions[id].reducingRate; 688 | return price; 689 | } 690 | 691 | /// @notice Function to get withdraw balance for English Auction 692 | /// @param id The id of the listed English Auction 693 | /// @param to The address of the withdrawal account 694 | /// @return The amount of withdraw for English Auction 695 | function withdrawBalanceForEnglishAuction( 696 | uint256 id, 697 | address to 698 | ) external view returns (uint256) { 699 | return englishAuction_balancesForWithdraw[id][to]; 700 | } 701 | 702 | /// @notice Function to get withdraw balance for Offering Sale 703 | /// @param id The id of the listed Offering Sale 704 | /// @param to The address of the withdrawal account 705 | /// @return The amount of withdraw for Offering Sale 706 | function withdrawBalanceForOfferingSale( 707 | uint256 id, 708 | address to 709 | ) external view returns (uint256) { 710 | return offeringSale_balancesForWithdraw[id][to]; 711 | } 712 | } 713 | -------------------------------------------------------------------------------- /contracts/USDC.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.19; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract USDCToken is ERC20 { 7 | /// @notice Constrcutor of Test USDC Token 8 | /// @param initialSupply The initial total supply of USDC Token 9 | constructor(uint256 initialSupply) ERC20("USD Coin", "USDC") payable { 10 | _mint(msg.sender, initialSupply * 10 ** 6); 11 | } 12 | 13 | /// @notice Mint USDC Token 14 | /// @param account The account to mint USDC Token 15 | /// @param amount The amount to mint USDC Token 16 | function mint(address account, uint256 amount) public { 17 | _mint(account, amount); 18 | } 19 | 20 | /// @notice Burn USDC Token 21 | /// @param account The account to burn USDC Token 22 | /// @param amount The amount to burn USDC Token 23 | function burn(address account, uint256 amount) public { 24 | _burn(account, amount); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/interfaces/IContentNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.19; 3 | 4 | interface IContentNFT { 5 | struct TransferHistory { 6 | address from; 7 | address to; 8 | uint256 timestamp; 9 | } 10 | function owner() external view returns (address); 11 | function ownerOf(uint256 tokenId) external view returns (address); 12 | function factory() external view returns (address); 13 | function description() external view returns (string memory); 14 | function tokenNumber() external view returns (uint256); 15 | function mintFee() external view returns (uint256); 16 | function burnFee() external view returns (uint256); 17 | function creators(uint256) external view returns (address); 18 | function initialize(string memory _name, string memory _symbol, string memory _description, string memory _nftURI, 19 | address _target, uint256 _mintFee, uint256 _burnFee, address _USDC, address _marketplace) external; 20 | function mint(string memory _nftURI) external payable returns (uint256); 21 | function burn(uint256 tokenId) external payable returns (uint256); 22 | function tokenURI(uint256 _tokenId) external view returns (string memory); 23 | function transferFrom(address from, address to, uint256 tokenId) external; 24 | function getTransferHistory(uint256 tokenId) external view returns (TransferHistory[] memory); 25 | function getLoyaltyFee(uint256 tokenId) external view returns (uint256); 26 | function setLoyaltyFee(uint256 _tokenId, uint256 _loyaltyFee) external; 27 | } -------------------------------------------------------------------------------- /contracts/interfaces/ICreatorGroup.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.19; 3 | 4 | interface ICreatorGroup { 5 | struct soldInfor { 6 | uint256 id; 7 | uint256 price; 8 | bool distributeState; 9 | } 10 | 11 | function initialize( 12 | string memory _name, 13 | string memory _description, 14 | address[] memory _members, 15 | uint256 _numConfirmationRequired, 16 | address _marketplace, 17 | uint256 _mintFee, 18 | uint256 _burnFee, 19 | address _USDC 20 | ) external; 21 | 22 | function setTeamScore(uint256 value) external; 23 | 24 | function alarmSoldOut( 25 | address contractAddress, 26 | uint256 nftId, 27 | uint256 price 28 | ) external; 29 | 30 | function mintNew( 31 | string memory _nftURI, 32 | string memory _name, 33 | string memory _symbol, 34 | string memory _description 35 | ) external; 36 | 37 | function mint(string memory _nftURI, address _targetNFT) external; 38 | 39 | function listToEnglishAuction( 40 | uint256 id, 41 | uint256 initialPrice, 42 | uint256 salePeriod 43 | ) external; 44 | 45 | function listToDutchAuction( 46 | uint256 id, 47 | uint256 initialPrice, 48 | uint256 reducingRate, 49 | uint256 salePeriod 50 | ) external; 51 | 52 | function listToOfferingSale(uint256 id, uint256 initialPrice) external; 53 | 54 | function endEnglishAuction(uint256 id) external; 55 | 56 | function withdrawFromMarketplace() external; 57 | 58 | function submitDirectorSettingTransaction(address _candidate) external; 59 | 60 | function confirmDirectorSettingTransaction( 61 | uint256 index, 62 | bool state 63 | ) external; 64 | 65 | function executeDirectorSettingTransaction(uint256 index) external; 66 | 67 | function submitOfferingSaleTransaction( 68 | uint256 _marketId, 69 | address _tokenContractAddress, 70 | uint256 tokenId, 71 | address _buyer, 72 | uint256 _price 73 | ) external; 74 | 75 | function confirmOfferingSaleTransaction(uint256 index, bool state) external; 76 | 77 | function executeOfferingSaleTransaction(uint256 index) external; 78 | 79 | function setConfirmationRequiredNumber(uint256 confirmNumber) external; 80 | 81 | function getNftOfId(uint256 index) external view returns (uint256); 82 | 83 | function getNftAddress(uint256 index) external view returns (address); 84 | 85 | function getSoldNumber() external view returns (uint256); 86 | 87 | function getRevenueDistribution( 88 | address one, 89 | uint256 id 90 | ) external view returns (uint256); 91 | 92 | function getSoldInfor( 93 | uint256 index 94 | ) external view returns (soldInfor memory); 95 | 96 | function withdraw() external; 97 | 98 | function addMember(address _newMember) external; 99 | 100 | function removeMember(address _removeMember) external; 101 | 102 | function alarmLoyaltyFeeReceived(uint256 nftId, uint256 price) external; 103 | 104 | function getNumberOfCandidateTransaction() external view returns (uint256); 105 | 106 | function getNumberOfSaleOfferingTransaction() 107 | external 108 | view 109 | returns (uint256); 110 | 111 | function getConfirmNumberOfOfferingSaleTransaction( 112 | uint256 index 113 | ) external view returns (uint256); 114 | 115 | function getConfirmNumberOfDirectorSettingTransaction( 116 | uint256 index 117 | ) external view returns (uint256); 118 | 119 | function submitBurnTransaction(uint256 id) external; 120 | 121 | function confirmBurnTransaction(uint256 index, bool state) external; 122 | 123 | function executeBurnTransaction(uint256 index) external; 124 | 125 | function getConfirmNumberOfBurnTransaction( 126 | uint256 index 127 | ) external view returns (uint256); 128 | 129 | function getNumberOfBurnTransaction() external view returns (uint256); 130 | 131 | function uploadMemberNFT(address contractAddress, uint256 tokenId) external; 132 | } 133 | -------------------------------------------------------------------------------- /contracts/interfaces/IFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.19; 3 | 4 | interface IFactory { 5 | function createGroup( 6 | string memory name, 7 | string memory description, 8 | address[] memory owners, 9 | uint256[] memory roles, 10 | uint256 numConfirmationRequired 11 | ) external; 12 | function mintNew( 13 | string memory _nftURI, 14 | string memory _name, 15 | string memory _symbol, 16 | string memory _description 17 | ) external returns (address); 18 | function withdraw() external; 19 | function setTeamScoreForCreatorGroup(uint256 id, uint256 score) external; 20 | function isCreatorGroup(address _groupAddress) external view returns(bool); 21 | function getCreatorGroupAddress(uint256 id) external view returns(address); 22 | } -------------------------------------------------------------------------------- /contracts/interfaces/IMarketplace.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.19; 3 | 4 | interface IMarketplace { 5 | function getBalanceOfUser(address to) external view returns (uint256); 6 | function addBalanceOfUser( 7 | address[] memory _members, 8 | uint256[] memory _values, 9 | address contractAddress, 10 | uint256 nftId 11 | ) external; 12 | function setPercentForSeller(uint256 _percentForSeller) external; 13 | function withdraw() external; 14 | function withdrawFromSeller() external; 15 | function listToEnglishAuction( 16 | address nftContractAddress, 17 | uint256 nftId, 18 | uint256 initialPrice, 19 | uint256 salePeriod 20 | ) external; 21 | function listToDutchAuction( 22 | address nftContractAddress, 23 | uint256 nftId, 24 | uint256 initialPrice, 25 | uint256 reducingRate, 26 | uint256 salePeriod 27 | ) external; 28 | function listToOfferingSale( 29 | address nftContractAddress, 30 | uint256 nftId, 31 | uint256 initialPrice 32 | ) external; 33 | function makeBidToEnglishAuction(uint256 id, uint256 sendingValue) external; 34 | function withdrawFromEnglishAuction(uint256 id) external; 35 | function endEnglishAuction(address _contractAddress, uint256 _nftId) external; 36 | function buyDutchAuction(uint256 id, uint256 sendingValue) external; 37 | function makeBidToOfferingSale(uint256 id, uint256 sendingValue) external; 38 | function withdrawFromOfferingSale(uint256 id) external; 39 | function endOfferingSale(uint256 id, address buyer) external; 40 | function cancelListing(address _nftContractAddress, uint256 _nftId) external; 41 | function getDutchAuctionPrice(uint256 id) external view returns (uint256); 42 | function setPercentForLoyaltyFee(uint256 _percentForLoyaltyFee) external; 43 | function getOfferingSaleAuctionNumber() external view returns (uint256); 44 | function getListedDutchAuctionNumber() external view returns (uint256); 45 | function getListedEnglishAuctionNumber() external view returns (uint256); 46 | function getListedNumber() external view returns (uint256); 47 | function withdrawBalanceForEnglishAuction(uint256 id, address to) 48 | external 49 | view 50 | returns (uint256); 51 | function withdrawBalanceForOfferingSale(uint256 id, address to) 52 | external 53 | view 54 | returns (uint256); 55 | } -------------------------------------------------------------------------------- /hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { HardhatUserConfig } from "hardhat/config"; 2 | import "dotenv/config"; 3 | 4 | import "@nomicfoundation/hardhat-toolbox"; 5 | 6 | const infuraKey = process.env.INFURA_API_KEY; 7 | const privateKey = process.env.PRIVATE_KEY?process.env.PRIVATE_KEY:""; 8 | const config: HardhatUserConfig = { 9 | solidity: { 10 | version: "0.8.24", 11 | settings: { 12 | optimizer: { 13 | enabled: true, 14 | runs: 100, 15 | }, 16 | viaIR: true, 17 | }, 18 | }, 19 | networks:{ 20 | sepolia:{ 21 | url: `https://sepolia.infura.io/v3/${infuraKey}`, 22 | accounts:[privateKey], 23 | }, 24 | mainnet:{ 25 | url: `https://mainnet.infura.io/v3/${infuraKey}`, 26 | accounts:[privateKey], 27 | } 28 | }, 29 | etherscan: { 30 | apiKey: { 31 | sepolia: 'ED2NED96C214Y891MR98PZZ1Q45VTFYZRV' 32 | }, 33 | }, 34 | gasReporter: {enabled: true}, 35 | sourcify: { 36 | enabled: true 37 | } 38 | }; 39 | 40 | export default config; 41 | 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "squad-project", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "compile": "npx hardhat compile", 8 | "deploy:testnet": "npx hardhat run --network testnet scripts/deploy.ts", 9 | "deploy:mainnet": "npx hardhat run --network mainnet scripts/deploy.ts", 10 | "test": "npx hardhat test", 11 | "test:coverage": "npx hardhat coverage", 12 | "test:size-contracts": "npx hardhat size-contracts" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "devDependencies": { 18 | "@nomicfoundation/hardhat-toolbox": "^4.0.0", 19 | "@openzeppelin/contracts": "^5.0.1", 20 | "@types/jest": "^29.5.12", 21 | "dotenv": "^16.4.5", 22 | "hardhat": "^2.20.1" 23 | }, 24 | "dependencies": { 25 | "@nomicfoundation/hardhat-network-helpers": "^1.0.10", 26 | "@openzeppelin/contracts-upgradeable": "^5.0.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/deploy_sepolia.ts: -------------------------------------------------------------------------------- 1 | 2 | // Importing necessary functionalities from the Hardhat package. 3 | import { ethers } from 'hardhat' 4 | 5 | async function main() { 6 | // Retrieve the first signer, typically the default account in Hardhat, to use as the deployer. 7 | const [deployer] = await ethers.getSigners() 8 | const percentForSeller: number = 85; 9 | console.log('Contract is deploying...') 10 | const instanceUSDC = await ethers.deployContract('USDCToken', [100000000]); 11 | // Waiting for the contract deployment to be confirmed on the blockchain. 12 | await instanceUSDC.waitForDeployment() 13 | 14 | // Logging the address of the deployed My404 contract. 15 | console.log(`USDC contract is deployed. Token address: ${instanceUSDC.target}`) 16 | 17 | const USDC_Address = await instanceUSDC.getAddress(); 18 | const developmentTeam: string = "0x9319Ec01DcB2086dc828C9A23Fa32DFb2FE10143"; 19 | const Marketplace = await ethers.deployContract('Marketplace', [developmentTeam, percentForSeller, USDC_Address]); 20 | await Marketplace.waitForDeployment() 21 | const Marketplace_Address = await Marketplace.getAddress(); 22 | console.log(`Marketplace is deployed. ${Marketplace.target}`); 23 | 24 | const instanceGroup = await ethers.deployContract("CreatorGroup"); 25 | await instanceGroup.waitForDeployment() ; 26 | console.log(`instance Group is deployed. ${instanceGroup.target}`); 27 | const Group_Address = await instanceGroup.getAddress(); 28 | const instanceContent = await ethers.deployContract("ContentNFT"); 29 | await instanceContent.waitForDeployment() 30 | console.log(`instance Content is deployed. ${instanceContent.target}`); 31 | const Content_Address = await instanceContent.getAddress(); 32 | const mintFee:number = 0; 33 | const burnFee:number = 0; 34 | const instanceFactory = await ethers.deployContract("Factory", [Group_Address, Content_Address, Marketplace_Address, developmentTeam, mintFee, burnFee, USDC_Address]); 35 | await instanceFactory.waitForDeployment() 36 | const Factory_Address = await instanceFactory.getAddress(); 37 | console.log(`Factory is deployed. ${instanceFactory.target}`); 38 | } 39 | 40 | // This pattern allows the use of async/await throughout and ensures that errors are caught and handled properly. 41 | main().catch(error => { 42 | console.error(error) 43 | process.exitCode = 1 44 | }) -------------------------------------------------------------------------------- /test/InitialTesting.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "hardhat"; 2 | import { time } from "@nomicfoundation/hardhat-network-helpers"; 3 | import { expect } from "chai"; 4 | import creatorGroupABI from "./creatorGroup.json"; 5 | import contentNFTABI from "./contentNFT.json"; 6 | let USDC_Address: any; 7 | let USDC_Contract: any; 8 | let Marketplace: any; 9 | let Marketplace_Address: any; 10 | let Factory: any; 11 | let Factory_Address: any; 12 | let owner: any; 13 | let user1: any; 14 | let user2: any; 15 | let user3: any; 16 | let developmentTeam: any; 17 | let buyer1: any; 18 | let buyer2: any; 19 | const percentForSeller: number = 85; 20 | const mintFee: number = 0; 21 | const burnFee: number = 0; 22 | describe("Create Initial Contracts of all types", function () { 23 | it("get accounts", async function () { 24 | [owner, user1, user2, developmentTeam, buyer1, buyer2, user3] = 25 | await ethers.getSigners(); 26 | console.log("\tAccount address\t", await owner.getAddress()); 27 | }); 28 | it("should deploy USDC Contract", async function () { 29 | const instanceUSDC = await ethers.getContractFactory("USDCToken"); 30 | USDC_Contract = await instanceUSDC.deploy(1e6); 31 | USDC_Address = await USDC_Contract.getAddress(); 32 | console.log("\tUSDC Contract deployed at:", USDC_Address); 33 | }); 34 | it("should deploy Marketplace Contract", async function () { 35 | const instanceMarketplace = await ethers.getContractFactory("Marketplace"); 36 | Marketplace = await instanceMarketplace.deploy( 37 | developmentTeam, 38 | percentForSeller, 39 | USDC_Address 40 | ); 41 | Marketplace_Address = await Marketplace.getAddress(); 42 | console.log("\tMarketplace Contract deployed at:", Marketplace_Address); 43 | }); 44 | it("should deploy Factory Contract", async function () { 45 | const instanceGroup = await ethers.getContractFactory("CreatorGroup"); 46 | const Group = await instanceGroup.deploy(); 47 | const Group_Address = await Group.getAddress(); 48 | const instanceContent = await ethers.getContractFactory("ContentNFT"); 49 | const Content = await instanceContent.deploy(); 50 | const Content_Address = await Content.getAddress(); 51 | const instanceFactory = await ethers.getContractFactory("Factory"); 52 | Factory = await instanceFactory.deploy( 53 | Group_Address, 54 | Content_Address, 55 | Marketplace_Address, 56 | developmentTeam, 57 | mintFee, 58 | burnFee, 59 | USDC_Address 60 | ); 61 | Factory_Address = await Factory.getAddress(); 62 | console.log("\tFactory Contract deployed at:", Factory_Address); 63 | }); 64 | }); 65 | let group_address: any; 66 | let creatorGroup: any; 67 | const amount: number = 5000; 68 | let firstNFTAddress: any; 69 | describe("test creating CreatorGroup contracts and mint & burn NFTs", async function () { 70 | it("Create first CreatorGroup", async function () { 71 | await Factory.createGroup( 72 | "Top_Artists", 73 | "We are all NFT artists", 74 | [user2, user1], 75 | 2 76 | ); 77 | group_address = await Factory.getCreatorGroupAddress(0); 78 | console.log("\tCreatorGroup address\t", group_address); 79 | creatorGroup = new ethers.Contract( 80 | group_address, 81 | creatorGroupABI, 82 | ethers.provider 83 | ); 84 | }); 85 | 86 | it("sending USDC to the users", async function () { 87 | await USDC_Contract.approve(user1, amount); 88 | await USDC_Contract.approve(user2, amount); 89 | await USDC_Contract.approve(buyer1, amount); 90 | await USDC_Contract.approve(buyer2, amount); 91 | 92 | await USDC_Contract.connect(user1).transferFrom(owner, user1, amount); 93 | await USDC_Contract.connect(user2).transferFrom(owner, user2, amount); 94 | await USDC_Contract.connect(buyer1).transferFrom(owner, buyer1, amount); 95 | await USDC_Contract.connect(buyer2).transferFrom(owner, buyer2, amount); 96 | await USDC_Contract.connect(user1).approve(user1, 200); 97 | await USDC_Contract.connect(user1).transferFrom(user1, group_address, 200); 98 | 99 | console.log("\tUSDC sent to user1\t", await USDC_Contract.balanceOf(user1)); 100 | console.log("\tUSDC sent to user2\t", await USDC_Contract.balanceOf(user2)); 101 | console.log( 102 | "\tUSDC sent to group_address\t", 103 | await USDC_Contract.balanceOf(group_address) 104 | ); 105 | }); 106 | 107 | it("set Director First", async function () { 108 | await creatorGroup.connect(user1).submitDirectorSettingTransaction(user1); 109 | await creatorGroup 110 | .connect(user1) 111 | .confirmDirectorSettingTransaction(0, true); 112 | await creatorGroup 113 | .connect(user2) 114 | .confirmDirectorSettingTransaction(0, true); 115 | await creatorGroup.connect(user2).executeDirectorSettingTransaction(0); 116 | const addresOfDirector = await creatorGroup.director(); 117 | console.log("\taddress of user1\t", await user1.getAddress()); 118 | console.log("\taddress of director\t", addresOfDirector); 119 | }); 120 | 121 | it("mint First NFT in the CreatorGroup", async function () { 122 | await creatorGroup 123 | .connect(user1) 124 | .mintNew( 125 | "ipfs://firstToken", 126 | "Nature", 127 | "DDD", 128 | "Oh my god, it's beautiful" 129 | ); 130 | const nftId = await creatorGroup.getNftOfId(0); 131 | console.log("\tNFT id\t", nftId); 132 | firstNFTAddress = await creatorGroup.getNftAddress(0); 133 | console.log("\tNFT address\t", firstNFTAddress); 134 | }); 135 | 136 | it("check nft values in nft contract", async function () { 137 | const nft = new ethers.Contract( 138 | firstNFTAddress, 139 | contentNFTABI, 140 | ethers.provider 141 | ); 142 | const name = await nft.name(); 143 | console.log("\tNFT name\t", name); 144 | const symbol = await nft.symbol(); 145 | console.log("\tNFT symbol\t", symbol); 146 | const description = await nft.description(); 147 | console.log("\tNFT description\t", description); 148 | const imageURI = await nft.tokenURI(1); 149 | console.log("\t1 NFT imageURI\t", imageURI); 150 | }); 151 | 152 | it("mint second NFT to the Nature NFT Collection", async function () { 153 | await creatorGroup 154 | .connect(user1) 155 | .mint("ipfs://secondToken", firstNFTAddress); 156 | }); 157 | 158 | it("check nft values in nft contract", async function () { 159 | const nft = new ethers.Contract( 160 | firstNFTAddress, 161 | contentNFTABI, 162 | ethers.provider 163 | ); 164 | const imageURI = await nft.tokenURI(2); 165 | console.log("\t2 NFT imageURI\t", imageURI); 166 | }); 167 | 168 | it("mint third NFT to the Nature NFT Collection", async function () { 169 | await creatorGroup 170 | .connect(user1) 171 | .mint("ipfs://thirdToken", firstNFTAddress); 172 | }); 173 | 174 | it("check nft values in nft contract", async function () { 175 | const nft = new ethers.Contract( 176 | firstNFTAddress, 177 | contentNFTABI, 178 | ethers.provider 179 | ); 180 | const imageURI = await nft.tokenURI(3); 181 | console.log("\t3 NFT imageURI\t", imageURI); 182 | }); 183 | 184 | // it("burn second NFT to the Nature NFT Collection", async function(){ 185 | // const before_numberOfNFT = await creatorGroup.numberOfNFT() ; 186 | // console.log("\tBefore Burn -> NFT number\t", before_numberOfNFT); 187 | // await creatorGroup.connect(user1).burn(1) ; 188 | // const after_numberOfNFT = await creatorGroup.numberOfNFT() ; 189 | // console.log("\tfter Burn -> tNFT number\t", after_numberOfNFT); 190 | // }) 191 | 192 | it("check USDC balance of each addresses", async function () { 193 | const user1_balance = await USDC_Contract.balanceOf(user1); 194 | console.log("\tUSDC balance of user1\t", user1_balance); 195 | const user2_balance = await USDC_Contract.balanceOf(user2); 196 | console.log("\tUSDC balance of user2\t", user2_balance); 197 | const group_address_balance = await USDC_Contract.balanceOf(group_address); 198 | console.log("\tUSDC balance of group_address\t", group_address_balance); 199 | const factory_address_balance = await USDC_Contract.balanceOf( 200 | Factory_Address 201 | ); 202 | console.log("\tUSDC balance of factory_address\t", factory_address_balance); 203 | }); 204 | }); 205 | 206 | describe("listing EnglishAuction & biding & endAuction", async function () { 207 | it("list to English Auction", async function () { 208 | await creatorGroup.connect(user1).listToEnglishAuction(0, 200, 300); 209 | }); 210 | it("make a bid to the NFT", async function () { 211 | await USDC_Contract.connect(buyer1).approve(Marketplace_Address, 350); 212 | await Marketplace.connect(buyer1).makeBidToEnglishAuction(0, 350); 213 | await USDC_Contract.connect(buyer2).approve(Marketplace_Address, 400); 214 | await Marketplace.connect(buyer2).makeBidToEnglishAuction(0, 400); 215 | }); 216 | it("end English Auction", async function () { 217 | await time.increaseTo((await time.latest()) + 3600); 218 | await creatorGroup.connect(user1).endEnglishAuction(0); 219 | }); 220 | it("withdraw after english Auctin ended", async function () { 221 | await Marketplace.connect(buyer1).withdrawFromEnglishAuction(0); 222 | await creatorGroup.connect(user1).withdrawFromMarketplace(); 223 | }); 224 | it("check USDC balance of each addresses", async function () { 225 | const buyer1_balance = await USDC_Contract.balanceOf(buyer1); 226 | console.log("\tUSDC balance of buyer1\t", buyer1_balance); 227 | const buyer2_balance = await USDC_Contract.balanceOf(buyer2); 228 | console.log("\tUSDC balance of buyer2\t", buyer2_balance); 229 | const group_address_balance = await USDC_Contract.balanceOf(group_address); 230 | console.log("\tUSDC balance of group_address\t", group_address_balance); 231 | const factory_address_balance = await USDC_Contract.balanceOf( 232 | Factory_Address 233 | ); 234 | console.log("\tUSDC balance of factory_address\t", factory_address_balance); 235 | }); 236 | }); 237 | describe("listing DutchAuction & biding", async function () { 238 | it("list to Dutch Auction", async function () { 239 | await creatorGroup.connect(user1).listToDutchAuction(1, 1000, 100, 5000); 240 | }); 241 | it("buyer1 buy Dutch Auction", async function () { 242 | await time.increaseTo((await time.latest()) + 3650); 243 | const value = await Marketplace.getDutchAuctionPrice(0); 244 | USDC_Contract.connect(buyer1).approve(Marketplace_Address, value); 245 | await Marketplace.connect(buyer1).buyDutchAuction(0, value); 246 | }); 247 | it("check USDC balance of each addresses", async function () { 248 | const buyer1_balance = await USDC_Contract.balanceOf(buyer1); 249 | console.log("\tUSDC balance of buyer1\t", buyer1_balance); 250 | }); 251 | }); 252 | 253 | describe("listing SaleOffering & biding & endAuction", async function () { 254 | it("list to Sale Offering", async function () { 255 | await creatorGroup.connect(user1).listToOfferingSale(2, 1500); 256 | }); 257 | it("buyer1 make a bid to the Offering", async function () { 258 | await USDC_Contract.connect(buyer1).approve(Marketplace_Address, 1600); 259 | await Marketplace.connect(buyer1).makeBidToOfferingSale(0, 1600); 260 | }); 261 | it("buyer2 make a bid to the Offering", async function () { 262 | await USDC_Contract.connect(buyer2).approve(Marketplace_Address, 1700); 263 | await Marketplace.connect(buyer2).makeBidToOfferingSale(0, 1700); 264 | }); 265 | it("confirm transactions", async function () { 266 | await creatorGroup.connect(user1).confirmOfferingSaleTransaction(1, true); 267 | await creatorGroup.connect(user2).confirmOfferingSaleTransaction(1, true); 268 | await creatorGroup.connect(user1).executeOfferingSaleTransaction(1); 269 | }); 270 | it("withdraw after english Auctin ended", async function () { 271 | await Marketplace.connect(buyer1).withdrawFromOfferingSale(0); 272 | }); 273 | it("check USDC balance of each addresses", async function () { 274 | const buyer1_balance = await USDC_Contract.balanceOf(buyer1); 275 | console.log("\tUSDC balance of buyer1\t", buyer1_balance); 276 | const buyer2_balance = await USDC_Contract.balanceOf(buyer2); 277 | console.log("\tUSDC balance of buyer2\t", buyer2_balance); 278 | }); 279 | }); 280 | 281 | describe("Check how to distributed revenues", async function () { 282 | it("withdraw from Marketplace", async function () { 283 | await creatorGroup.connect(user1).withdrawFromMarketplace(); 284 | }); 285 | it("check the balance of each address", async function () { 286 | const user1_balance = await creatorGroup.balance(user1); 287 | console.log("\tuser1_balance: " + user1_balance); 288 | const user2_balance = await creatorGroup.balance(user2); 289 | console.log("\tuser2_balance: " + user2_balance); 290 | }); 291 | it("check sold value and each earning", async function () { 292 | const count = await creatorGroup.getSoldNumber(); 293 | console.log("\tcount: " + count); 294 | let id: number; 295 | for (id = 0; id < count; id++) { 296 | const soldInformation = await creatorGroup.getSoldInfor(id); 297 | console.log("\tid: " + soldInformation.id); 298 | console.log("\tprice: " + soldInformation.price); 299 | console.log("\tdistributeState: " + soldInformation.distributeState); 300 | } 301 | const groupNumber = await creatorGroup.numberOfMembers(); 302 | for (id = 0; id < groupNumber; id++) { 303 | const member = await creatorGroup.members(id); 304 | console.log("\taddress: " + member); 305 | let each: number; 306 | for (each = 0; each < count; each++) { 307 | const value = await creatorGroup.getRevenueDistribution(member, each); 308 | console.log("\tvalue: " + value); 309 | } 310 | } 311 | }); 312 | }); 313 | describe("check cancel listing", async function () { 314 | it("mint fourth NFT to the Nature NFT Collection", async function () { 315 | await creatorGroup 316 | .connect(user1) 317 | .mint("ipfs://fourthToken", firstNFTAddress); 318 | }); 319 | it("list to English Auction", async function () { 320 | await creatorGroup.connect(user1).listToEnglishAuction(3, 200, 300); 321 | }); 322 | it("make a bid to the NFT", async function () { 323 | await USDC_Contract.connect(buyer1).approve(Marketplace_Address, 350); 324 | await Marketplace.connect(buyer1).makeBidToEnglishAuction(1, 350); 325 | await USDC_Contract.connect(buyer2).approve(Marketplace_Address, 400); 326 | await Marketplace.connect(buyer2).makeBidToEnglishAuction(1, 400); 327 | }); 328 | it("cancel listing fourth nft", async function () { 329 | try { 330 | await creatorGroup.connect(user1).cancelListing(3); 331 | } catch (error: any) { 332 | expect(error.message).contain("Already english auction started!"); 333 | } 334 | }); 335 | }); 336 | describe("In creatorGroup contract, withdraw all balances", async function () { 337 | it("check the balance of each address", async function () { 338 | const user1_balance = await creatorGroup.balance(user1); 339 | console.log("\tuser1_balance: " + user1_balance); 340 | const user2_balance = await creatorGroup.balance(user2); 341 | console.log("\tuser2_balance: " + user2_balance); 342 | }); 343 | it("withdraw all balances", async function () { 344 | await creatorGroup.connect(user1).withdraw(); 345 | await creatorGroup.connect(user2).withdraw(); 346 | }); 347 | it("check the balance of each address", async function () { 348 | const user1_balance = await creatorGroup.balance(user1); 349 | console.log("\tuser1_balance: " + user1_balance); 350 | const user2_balance = await creatorGroup.balance(user2); 351 | console.log("\tuser2_balance: " + user2_balance); 352 | }); 353 | it("check balance of CreatorGroup Contract", async function () { 354 | const group_balance = await USDC_Contract.balanceOf(group_address); 355 | console.log("\tUSDC balance of group\t", group_balance); 356 | }); 357 | }); 358 | describe("withdraw all of balances in Factory and Marketplace Contract from Development Team", async function () { 359 | it("check current balance of development Team wallet", async function () { 360 | const developmentTeam_balance = await USDC_Contract.balanceOf( 361 | developmentTeam 362 | ); 363 | console.log("\tUSDC balance of developmentTeam\t", developmentTeam_balance); 364 | }); 365 | it("withdraw from Marketplace", async function () { 366 | await Marketplace.connect(developmentTeam).withdraw(); 367 | const developmentTeam_balance = await USDC_Contract.balanceOf( 368 | developmentTeam 369 | ); 370 | console.log("\tUSDC balance of developmentTeam\t", developmentTeam_balance); 371 | }); 372 | it("withdraw from Factory", async function () { 373 | await Factory.connect(developmentTeam).withdraw(); 374 | const developmentTeam_balance = await USDC_Contract.balanceOf( 375 | developmentTeam 376 | ); 377 | console.log("\tUSDC balance of developmentTeam\t", developmentTeam_balance); 378 | }); 379 | }); 380 | 381 | describe("add member to the group processing happen", async function () { 382 | it("add member to the group", async function () { 383 | await creatorGroup.connect(user1).addMember(user3); 384 | }); 385 | it("end the EnglishAuction of Fourth NFT", async function () { 386 | await time.increaseTo((await time.latest()) + 3600); 387 | await creatorGroup.connect(user1).endEnglishAuction(3); 388 | }); 389 | it("mint fifth nft", async function () { 390 | await creatorGroup 391 | .connect(user1) 392 | .mint("ipfs://fifthToken", firstNFTAddress); 393 | }); 394 | it("lits fifth nft to the Dutch Auction", async function () { 395 | await creatorGroup.connect(user1).listToDutchAuction(4, 1000, 100, 28800); 396 | }); 397 | it("buyer1 buy DutchAuction nft", async function () { 398 | await time.increaseTo((await time.latest()) + 3650); 399 | const value = await Marketplace.getDutchAuctionPrice(1); 400 | USDC_Contract.connect(buyer1).approve(Marketplace_Address, value); 401 | await Marketplace.connect(buyer1).buyDutchAuction(1, value); 402 | }); 403 | it("check the balance of each address", async function () { 404 | const user1_balance = await creatorGroup.balance(user1); 405 | console.log("\tuser1_balance: " + user1_balance); 406 | const user2_balance = await creatorGroup.balance(user2); 407 | console.log("\tuser2_balance: " + user2_balance); 408 | }); 409 | it("withdraw from Marketplace", async function () { 410 | await creatorGroup.connect(user1).withdrawFromMarketplace(); 411 | }); 412 | 413 | it("check sold value and each earning", async function () { 414 | const count = await creatorGroup.getSoldNumber(); 415 | console.log("\tcount: " + count); 416 | let id: number; 417 | for (id = 0; id < count; id++) { 418 | const soldInformation = await creatorGroup.getSoldInfor(id); 419 | console.log("\tid: " + soldInformation.id); 420 | console.log("\tprice: " + soldInformation.price); 421 | console.log("\tdistributeState: " + soldInformation.distributeState); 422 | } 423 | const groupNumber = await creatorGroup.numberOfMembers(); 424 | for (id = 0; id < groupNumber; id++) { 425 | const member = await creatorGroup.members(id); 426 | console.log("\taddress: " + member); 427 | let each: number; 428 | for (each = 0; each < count; each++) { 429 | const value = await creatorGroup.getRevenueDistribution(member, each); 430 | console.log("\tvalue: " + value); 431 | } 432 | } 433 | }); 434 | it("check the balance of each address", async function () { 435 | const user1_balance = await creatorGroup.balance(user1); 436 | console.log("\tuser1_balance: " + user1_balance); 437 | const user2_balance = await creatorGroup.balance(user2); 438 | console.log("\tuser2_balance: " + user2_balance); 439 | const balance_user3 = await creatorGroup.balance(user3); 440 | console.log("\tbalance_user3: " + balance_user3); 441 | }); 442 | }); 443 | -------------------------------------------------------------------------------- /test/contentNFT.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "target", 7 | "type": "address" 8 | } 9 | ], 10 | "name": "AddressEmptyCode", 11 | "type": "error" 12 | }, 13 | { 14 | "inputs": [ 15 | { 16 | "internalType": "address", 17 | "name": "account", 18 | "type": "address" 19 | } 20 | ], 21 | "name": "AddressInsufficientBalance", 22 | "type": "error" 23 | }, 24 | { 25 | "inputs": [ 26 | { 27 | "internalType": "address", 28 | "name": "sender", 29 | "type": "address" 30 | }, 31 | { 32 | "internalType": "uint256", 33 | "name": "tokenId", 34 | "type": "uint256" 35 | }, 36 | { 37 | "internalType": "address", 38 | "name": "owner", 39 | "type": "address" 40 | } 41 | ], 42 | "name": "ERC721IncorrectOwner", 43 | "type": "error" 44 | }, 45 | { 46 | "inputs": [ 47 | { 48 | "internalType": "address", 49 | "name": "operator", 50 | "type": "address" 51 | }, 52 | { 53 | "internalType": "uint256", 54 | "name": "tokenId", 55 | "type": "uint256" 56 | } 57 | ], 58 | "name": "ERC721InsufficientApproval", 59 | "type": "error" 60 | }, 61 | { 62 | "inputs": [ 63 | { 64 | "internalType": "address", 65 | "name": "approver", 66 | "type": "address" 67 | } 68 | ], 69 | "name": "ERC721InvalidApprover", 70 | "type": "error" 71 | }, 72 | { 73 | "inputs": [ 74 | { 75 | "internalType": "address", 76 | "name": "operator", 77 | "type": "address" 78 | } 79 | ], 80 | "name": "ERC721InvalidOperator", 81 | "type": "error" 82 | }, 83 | { 84 | "inputs": [ 85 | { 86 | "internalType": "address", 87 | "name": "owner", 88 | "type": "address" 89 | } 90 | ], 91 | "name": "ERC721InvalidOwner", 92 | "type": "error" 93 | }, 94 | { 95 | "inputs": [ 96 | { 97 | "internalType": "address", 98 | "name": "receiver", 99 | "type": "address" 100 | } 101 | ], 102 | "name": "ERC721InvalidReceiver", 103 | "type": "error" 104 | }, 105 | { 106 | "inputs": [ 107 | { 108 | "internalType": "address", 109 | "name": "sender", 110 | "type": "address" 111 | } 112 | ], 113 | "name": "ERC721InvalidSender", 114 | "type": "error" 115 | }, 116 | { 117 | "inputs": [ 118 | { 119 | "internalType": "uint256", 120 | "name": "tokenId", 121 | "type": "uint256" 122 | } 123 | ], 124 | "name": "ERC721NonexistentToken", 125 | "type": "error" 126 | }, 127 | { 128 | "inputs": [], 129 | "name": "FailedInnerCall", 130 | "type": "error" 131 | }, 132 | { 133 | "inputs": [], 134 | "name": "InvalidInitialization", 135 | "type": "error" 136 | }, 137 | { 138 | "inputs": [], 139 | "name": "NotInitializing", 140 | "type": "error" 141 | }, 142 | { 143 | "inputs": [ 144 | { 145 | "internalType": "address", 146 | "name": "token", 147 | "type": "address" 148 | } 149 | ], 150 | "name": "SafeERC20FailedOperation", 151 | "type": "error" 152 | }, 153 | { 154 | "anonymous": false, 155 | "inputs": [ 156 | { 157 | "indexed": true, 158 | "internalType": "address", 159 | "name": "owner", 160 | "type": "address" 161 | }, 162 | { 163 | "indexed": true, 164 | "internalType": "address", 165 | "name": "approved", 166 | "type": "address" 167 | }, 168 | { 169 | "indexed": true, 170 | "internalType": "uint256", 171 | "name": "tokenId", 172 | "type": "uint256" 173 | } 174 | ], 175 | "name": "Approval", 176 | "type": "event" 177 | }, 178 | { 179 | "anonymous": false, 180 | "inputs": [ 181 | { 182 | "indexed": true, 183 | "internalType": "address", 184 | "name": "owner", 185 | "type": "address" 186 | }, 187 | { 188 | "indexed": true, 189 | "internalType": "address", 190 | "name": "operator", 191 | "type": "address" 192 | }, 193 | { 194 | "indexed": false, 195 | "internalType": "bool", 196 | "name": "approved", 197 | "type": "bool" 198 | } 199 | ], 200 | "name": "ApprovalForAll", 201 | "type": "event" 202 | }, 203 | { 204 | "anonymous": false, 205 | "inputs": [ 206 | { 207 | "indexed": true, 208 | "internalType": "address", 209 | "name": "from", 210 | "type": "address" 211 | }, 212 | { 213 | "indexed": true, 214 | "internalType": "uint256", 215 | "name": "tokenId", 216 | "type": "uint256" 217 | } 218 | ], 219 | "name": "Burned", 220 | "type": "event" 221 | }, 222 | { 223 | "anonymous": false, 224 | "inputs": [ 225 | { 226 | "indexed": false, 227 | "internalType": "uint64", 228 | "name": "version", 229 | "type": "uint64" 230 | } 231 | ], 232 | "name": "Initialized", 233 | "type": "event" 234 | }, 235 | { 236 | "anonymous": false, 237 | "inputs": [ 238 | { 239 | "indexed": true, 240 | "internalType": "uint256", 241 | "name": "tokenId", 242 | "type": "uint256" 243 | }, 244 | { 245 | "indexed": true, 246 | "internalType": "uint256", 247 | "name": "newFee", 248 | "type": "uint256" 249 | } 250 | ], 251 | "name": "LoyaltyFeeChanged", 252 | "type": "event" 253 | }, 254 | { 255 | "anonymous": false, 256 | "inputs": [ 257 | { 258 | "indexed": true, 259 | "internalType": "address", 260 | "name": "from", 261 | "type": "address" 262 | }, 263 | { 264 | "indexed": true, 265 | "internalType": "address", 266 | "name": "to", 267 | "type": "address" 268 | }, 269 | { 270 | "indexed": true, 271 | "internalType": "uint256", 272 | "name": "tokenId", 273 | "type": "uint256" 274 | } 275 | ], 276 | "name": "Transfer", 277 | "type": "event" 278 | }, 279 | { 280 | "anonymous": false, 281 | "inputs": [ 282 | { 283 | "indexed": true, 284 | "internalType": "address", 285 | "name": "from", 286 | "type": "address" 287 | }, 288 | { 289 | "indexed": true, 290 | "internalType": "uint256", 291 | "name": "tokenId", 292 | "type": "uint256" 293 | }, 294 | { 295 | "indexed": true, 296 | "internalType": "string", 297 | "name": "nftURI", 298 | "type": "string" 299 | } 300 | ], 301 | "name": "minted", 302 | "type": "event" 303 | }, 304 | { 305 | "inputs": [], 306 | "name": "USDC", 307 | "outputs": [ 308 | { 309 | "internalType": "address", 310 | "name": "", 311 | "type": "address" 312 | } 313 | ], 314 | "stateMutability": "view", 315 | "type": "function" 316 | }, 317 | { 318 | "inputs": [], 319 | "name": "USDC_token", 320 | "outputs": [ 321 | { 322 | "internalType": "contract IERC20", 323 | "name": "", 324 | "type": "address" 325 | } 326 | ], 327 | "stateMutability": "view", 328 | "type": "function" 329 | }, 330 | { 331 | "inputs": [ 332 | { 333 | "internalType": "address", 334 | "name": "to", 335 | "type": "address" 336 | }, 337 | { 338 | "internalType": "uint256", 339 | "name": "tokenId", 340 | "type": "uint256" 341 | } 342 | ], 343 | "name": "approve", 344 | "outputs": [], 345 | "stateMutability": "nonpayable", 346 | "type": "function" 347 | }, 348 | { 349 | "inputs": [ 350 | { 351 | "internalType": "address", 352 | "name": "owner", 353 | "type": "address" 354 | } 355 | ], 356 | "name": "balanceOf", 357 | "outputs": [ 358 | { 359 | "internalType": "uint256", 360 | "name": "", 361 | "type": "uint256" 362 | } 363 | ], 364 | "stateMutability": "view", 365 | "type": "function" 366 | }, 367 | { 368 | "inputs": [ 369 | { 370 | "internalType": "uint256", 371 | "name": "_tokenId", 372 | "type": "uint256" 373 | } 374 | ], 375 | "name": "burn", 376 | "outputs": [ 377 | { 378 | "internalType": "uint256", 379 | "name": "", 380 | "type": "uint256" 381 | } 382 | ], 383 | "stateMutability": "payable", 384 | "type": "function" 385 | }, 386 | { 387 | "inputs": [], 388 | "name": "burnFee", 389 | "outputs": [ 390 | { 391 | "internalType": "uint256", 392 | "name": "", 393 | "type": "uint256" 394 | } 395 | ], 396 | "stateMutability": "view", 397 | "type": "function" 398 | }, 399 | { 400 | "inputs": [ 401 | { 402 | "internalType": "uint256", 403 | "name": "", 404 | "type": "uint256" 405 | } 406 | ], 407 | "name": "creators", 408 | "outputs": [ 409 | { 410 | "internalType": "address", 411 | "name": "", 412 | "type": "address" 413 | } 414 | ], 415 | "stateMutability": "view", 416 | "type": "function" 417 | }, 418 | { 419 | "inputs": [], 420 | "name": "description", 421 | "outputs": [ 422 | { 423 | "internalType": "string", 424 | "name": "", 425 | "type": "string" 426 | } 427 | ], 428 | "stateMutability": "view", 429 | "type": "function" 430 | }, 431 | { 432 | "inputs": [], 433 | "name": "factory", 434 | "outputs": [ 435 | { 436 | "internalType": "address", 437 | "name": "", 438 | "type": "address" 439 | } 440 | ], 441 | "stateMutability": "view", 442 | "type": "function" 443 | }, 444 | { 445 | "inputs": [ 446 | { 447 | "internalType": "uint256", 448 | "name": "tokenId", 449 | "type": "uint256" 450 | } 451 | ], 452 | "name": "getApproved", 453 | "outputs": [ 454 | { 455 | "internalType": "address", 456 | "name": "", 457 | "type": "address" 458 | } 459 | ], 460 | "stateMutability": "view", 461 | "type": "function" 462 | }, 463 | { 464 | "inputs": [ 465 | { 466 | "internalType": "uint256", 467 | "name": "_tokenId", 468 | "type": "uint256" 469 | } 470 | ], 471 | "name": "getLoyaltyFee", 472 | "outputs": [ 473 | { 474 | "internalType": "uint256", 475 | "name": "", 476 | "type": "uint256" 477 | } 478 | ], 479 | "stateMutability": "view", 480 | "type": "function" 481 | }, 482 | { 483 | "inputs": [ 484 | { 485 | "internalType": "uint256", 486 | "name": "_tokenId", 487 | "type": "uint256" 488 | } 489 | ], 490 | "name": "getTransferHistory", 491 | "outputs": [ 492 | { 493 | "components": [ 494 | { 495 | "internalType": "address", 496 | "name": "from", 497 | "type": "address" 498 | }, 499 | { 500 | "internalType": "address", 501 | "name": "to", 502 | "type": "address" 503 | }, 504 | { 505 | "internalType": "uint256", 506 | "name": "timestamp", 507 | "type": "uint256" 508 | } 509 | ], 510 | "internalType": "struct ContentNFT.TransferHistory[]", 511 | "name": "", 512 | "type": "tuple[]" 513 | } 514 | ], 515 | "stateMutability": "view", 516 | "type": "function" 517 | }, 518 | { 519 | "inputs": [ 520 | { 521 | "internalType": "string", 522 | "name": "_name", 523 | "type": "string" 524 | }, 525 | { 526 | "internalType": "string", 527 | "name": "_symbol", 528 | "type": "string" 529 | }, 530 | { 531 | "internalType": "string", 532 | "name": "_description", 533 | "type": "string" 534 | }, 535 | { 536 | "internalType": "string", 537 | "name": "_nftURI", 538 | "type": "string" 539 | }, 540 | { 541 | "internalType": "address", 542 | "name": "_target", 543 | "type": "address" 544 | }, 545 | { 546 | "internalType": "uint256", 547 | "name": "_mintFee", 548 | "type": "uint256" 549 | }, 550 | { 551 | "internalType": "uint256", 552 | "name": "_burnFee", 553 | "type": "uint256" 554 | }, 555 | { 556 | "internalType": "address", 557 | "name": "_USDC", 558 | "type": "address" 559 | }, 560 | { 561 | "internalType": "address", 562 | "name": "_marketplace", 563 | "type": "address" 564 | } 565 | ], 566 | "name": "initialize", 567 | "outputs": [], 568 | "stateMutability": "nonpayable", 569 | "type": "function" 570 | }, 571 | { 572 | "inputs": [ 573 | { 574 | "internalType": "address", 575 | "name": "owner", 576 | "type": "address" 577 | }, 578 | { 579 | "internalType": "address", 580 | "name": "operator", 581 | "type": "address" 582 | } 583 | ], 584 | "name": "isApprovedForAll", 585 | "outputs": [ 586 | { 587 | "internalType": "bool", 588 | "name": "", 589 | "type": "bool" 590 | } 591 | ], 592 | "stateMutability": "view", 593 | "type": "function" 594 | }, 595 | { 596 | "inputs": [], 597 | "name": "marketplace", 598 | "outputs": [ 599 | { 600 | "internalType": "address", 601 | "name": "", 602 | "type": "address" 603 | } 604 | ], 605 | "stateMutability": "view", 606 | "type": "function" 607 | }, 608 | { 609 | "inputs": [ 610 | { 611 | "internalType": "string", 612 | "name": "_nftURI", 613 | "type": "string" 614 | } 615 | ], 616 | "name": "mint", 617 | "outputs": [ 618 | { 619 | "internalType": "uint256", 620 | "name": "", 621 | "type": "uint256" 622 | } 623 | ], 624 | "stateMutability": "payable", 625 | "type": "function" 626 | }, 627 | { 628 | "inputs": [], 629 | "name": "mintFee", 630 | "outputs": [ 631 | { 632 | "internalType": "uint256", 633 | "name": "", 634 | "type": "uint256" 635 | } 636 | ], 637 | "stateMutability": "view", 638 | "type": "function" 639 | }, 640 | { 641 | "inputs": [], 642 | "name": "name", 643 | "outputs": [ 644 | { 645 | "internalType": "string", 646 | "name": "", 647 | "type": "string" 648 | } 649 | ], 650 | "stateMutability": "view", 651 | "type": "function" 652 | }, 653 | { 654 | "inputs": [], 655 | "name": "owner", 656 | "outputs": [ 657 | { 658 | "internalType": "address", 659 | "name": "", 660 | "type": "address" 661 | } 662 | ], 663 | "stateMutability": "view", 664 | "type": "function" 665 | }, 666 | { 667 | "inputs": [ 668 | { 669 | "internalType": "uint256", 670 | "name": "tokenId", 671 | "type": "uint256" 672 | } 673 | ], 674 | "name": "ownerOf", 675 | "outputs": [ 676 | { 677 | "internalType": "address", 678 | "name": "", 679 | "type": "address" 680 | } 681 | ], 682 | "stateMutability": "view", 683 | "type": "function" 684 | }, 685 | { 686 | "inputs": [ 687 | { 688 | "internalType": "address", 689 | "name": "from", 690 | "type": "address" 691 | }, 692 | { 693 | "internalType": "address", 694 | "name": "to", 695 | "type": "address" 696 | }, 697 | { 698 | "internalType": "uint256", 699 | "name": "tokenId", 700 | "type": "uint256" 701 | } 702 | ], 703 | "name": "safeTransferFrom", 704 | "outputs": [], 705 | "stateMutability": "nonpayable", 706 | "type": "function" 707 | }, 708 | { 709 | "inputs": [ 710 | { 711 | "internalType": "address", 712 | "name": "from", 713 | "type": "address" 714 | }, 715 | { 716 | "internalType": "address", 717 | "name": "to", 718 | "type": "address" 719 | }, 720 | { 721 | "internalType": "uint256", 722 | "name": "tokenId", 723 | "type": "uint256" 724 | }, 725 | { 726 | "internalType": "bytes", 727 | "name": "data", 728 | "type": "bytes" 729 | } 730 | ], 731 | "name": "safeTransferFrom", 732 | "outputs": [], 733 | "stateMutability": "nonpayable", 734 | "type": "function" 735 | }, 736 | { 737 | "inputs": [ 738 | { 739 | "internalType": "address", 740 | "name": "operator", 741 | "type": "address" 742 | }, 743 | { 744 | "internalType": "bool", 745 | "name": "approved", 746 | "type": "bool" 747 | } 748 | ], 749 | "name": "setApprovalForAll", 750 | "outputs": [], 751 | "stateMutability": "nonpayable", 752 | "type": "function" 753 | }, 754 | { 755 | "inputs": [ 756 | { 757 | "internalType": "uint256", 758 | "name": "_tokenId", 759 | "type": "uint256" 760 | }, 761 | { 762 | "internalType": "uint256", 763 | "name": "_loyaltyFee", 764 | "type": "uint256" 765 | } 766 | ], 767 | "name": "setLoyaltyFee", 768 | "outputs": [], 769 | "stateMutability": "nonpayable", 770 | "type": "function" 771 | }, 772 | { 773 | "inputs": [ 774 | { 775 | "internalType": "bytes4", 776 | "name": "interfaceId", 777 | "type": "bytes4" 778 | } 779 | ], 780 | "name": "supportsInterface", 781 | "outputs": [ 782 | { 783 | "internalType": "bool", 784 | "name": "", 785 | "type": "bool" 786 | } 787 | ], 788 | "stateMutability": "view", 789 | "type": "function" 790 | }, 791 | { 792 | "inputs": [], 793 | "name": "symbol", 794 | "outputs": [ 795 | { 796 | "internalType": "string", 797 | "name": "", 798 | "type": "string" 799 | } 800 | ], 801 | "stateMutability": "view", 802 | "type": "function" 803 | }, 804 | { 805 | "inputs": [], 806 | "name": "tokenNumber", 807 | "outputs": [ 808 | { 809 | "internalType": "uint256", 810 | "name": "", 811 | "type": "uint256" 812 | } 813 | ], 814 | "stateMutability": "view", 815 | "type": "function" 816 | }, 817 | { 818 | "inputs": [ 819 | { 820 | "internalType": "uint256", 821 | "name": "_tokenId", 822 | "type": "uint256" 823 | } 824 | ], 825 | "name": "tokenURI", 826 | "outputs": [ 827 | { 828 | "internalType": "string", 829 | "name": "", 830 | "type": "string" 831 | } 832 | ], 833 | "stateMutability": "view", 834 | "type": "function" 835 | }, 836 | { 837 | "inputs": [ 838 | { 839 | "internalType": "address", 840 | "name": "_from", 841 | "type": "address" 842 | }, 843 | { 844 | "internalType": "address", 845 | "name": "_to", 846 | "type": "address" 847 | }, 848 | { 849 | "internalType": "uint256", 850 | "name": "_tokenId", 851 | "type": "uint256" 852 | } 853 | ], 854 | "name": "transferFrom", 855 | "outputs": [], 856 | "stateMutability": "nonpayable", 857 | "type": "function" 858 | } 859 | ] -------------------------------------------------------------------------------- /test/creatorGroup.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "target", 7 | "type": "address" 8 | } 9 | ], 10 | "name": "AddressEmptyCode", 11 | "type": "error" 12 | }, 13 | { 14 | "inputs": [ 15 | { 16 | "internalType": "address", 17 | "name": "account", 18 | "type": "address" 19 | } 20 | ], 21 | "name": "AddressInsufficientBalance", 22 | "type": "error" 23 | }, 24 | { 25 | "inputs": [], 26 | "name": "FailedInnerCall", 27 | "type": "error" 28 | }, 29 | { 30 | "inputs": [], 31 | "name": "InvalidInitialization", 32 | "type": "error" 33 | }, 34 | { 35 | "inputs": [], 36 | "name": "NotInitializing", 37 | "type": "error" 38 | }, 39 | { 40 | "inputs": [ 41 | { 42 | "internalType": "address", 43 | "name": "token", 44 | "type": "address" 45 | } 46 | ], 47 | "name": "SafeERC20FailedOperation", 48 | "type": "error" 49 | }, 50 | { 51 | "anonymous": false, 52 | "inputs": [ 53 | { 54 | "indexed": true, 55 | "internalType": "uint256", 56 | "name": "index", 57 | "type": "uint256" 58 | }, 59 | { 60 | "indexed": true, 61 | "internalType": "address", 62 | "name": "from", 63 | "type": "address" 64 | }, 65 | { 66 | "indexed": true, 67 | "internalType": "bool", 68 | "name": "state", 69 | "type": "bool" 70 | } 71 | ], 72 | "name": "BurnTransactionConfirmed", 73 | "type": "event" 74 | }, 75 | { 76 | "anonymous": false, 77 | "inputs": [ 78 | { 79 | "indexed": true, 80 | "internalType": "uint256", 81 | "name": "id", 82 | "type": "uint256" 83 | } 84 | ], 85 | "name": "BurnTransactionProposed", 86 | "type": "event" 87 | }, 88 | { 89 | "anonymous": false, 90 | "inputs": [ 91 | { 92 | "indexed": true, 93 | "internalType": "uint256", 94 | "name": "confirmNumber", 95 | "type": "uint256" 96 | } 97 | ], 98 | "name": "ConfirmationRequiredNumberSet", 99 | "type": "event" 100 | }, 101 | { 102 | "anonymous": false, 103 | "inputs": [ 104 | { 105 | "indexed": true, 106 | "internalType": "uint256", 107 | "name": "index", 108 | "type": "uint256" 109 | }, 110 | { 111 | "indexed": true, 112 | "internalType": "address", 113 | "name": "from", 114 | "type": "address" 115 | }, 116 | { 117 | "indexed": true, 118 | "internalType": "bool", 119 | "name": "state", 120 | "type": "bool" 121 | } 122 | ], 123 | "name": "DirectorSettingConfirmed", 124 | "type": "event" 125 | }, 126 | { 127 | "anonymous": false, 128 | "inputs": [ 129 | { 130 | "indexed": true, 131 | "internalType": "address", 132 | "name": "_director", 133 | "type": "address" 134 | } 135 | ], 136 | "name": "DirectorSettingExecuted", 137 | "type": "event" 138 | }, 139 | { 140 | "anonymous": false, 141 | "inputs": [ 142 | { 143 | "indexed": true, 144 | "internalType": "address", 145 | "name": "_candidate", 146 | "type": "address" 147 | } 148 | ], 149 | "name": "DirectorSettingProposed", 150 | "type": "event" 151 | }, 152 | { 153 | "anonymous": false, 154 | "inputs": [ 155 | { 156 | "indexed": true, 157 | "internalType": "uint256", 158 | "name": "nftId", 159 | "type": "uint256" 160 | }, 161 | { 162 | "indexed": true, 163 | "internalType": "uint256", 164 | "name": "initialPrice", 165 | "type": "uint256" 166 | }, 167 | { 168 | "indexed": true, 169 | "internalType": "uint256", 170 | "name": "reducingRate", 171 | "type": "uint256" 172 | }, 173 | { 174 | "indexed": false, 175 | "internalType": "uint256", 176 | "name": "salePeriod", 177 | "type": "uint256" 178 | } 179 | ], 180 | "name": "DutchAuctionListed", 181 | "type": "event" 182 | }, 183 | { 184 | "anonymous": false, 185 | "inputs": [ 186 | { 187 | "indexed": true, 188 | "internalType": "uint256", 189 | "name": "nftId", 190 | "type": "uint256" 191 | } 192 | ], 193 | "name": "EnglishAuctionEnded", 194 | "type": "event" 195 | }, 196 | { 197 | "anonymous": false, 198 | "inputs": [ 199 | { 200 | "indexed": true, 201 | "internalType": "uint256", 202 | "name": "nftId", 203 | "type": "uint256" 204 | }, 205 | { 206 | "indexed": true, 207 | "internalType": "uint256", 208 | "name": "initialPrice", 209 | "type": "uint256" 210 | }, 211 | { 212 | "indexed": true, 213 | "internalType": "uint256", 214 | "name": "salePeriod", 215 | "type": "uint256" 216 | } 217 | ], 218 | "name": "EnglishAuctionListed", 219 | "type": "event" 220 | }, 221 | { 222 | "anonymous": false, 223 | "inputs": [ 224 | { 225 | "indexed": false, 226 | "internalType": "uint64", 227 | "name": "version", 228 | "type": "uint64" 229 | } 230 | ], 231 | "name": "Initialized", 232 | "type": "event" 233 | }, 234 | { 235 | "anonymous": false, 236 | "inputs": [ 237 | { 238 | "indexed": true, 239 | "internalType": "uint256", 240 | "name": "id", 241 | "type": "uint256" 242 | }, 243 | { 244 | "indexed": true, 245 | "internalType": "uint256", 246 | "name": "price", 247 | "type": "uint256" 248 | } 249 | ], 250 | "name": "LoyaltyFeeReceived", 251 | "type": "event" 252 | }, 253 | { 254 | "anonymous": false, 255 | "inputs": [ 256 | { 257 | "indexed": true, 258 | "internalType": "uint256", 259 | "name": "nftId", 260 | "type": "uint256" 261 | } 262 | ], 263 | "name": "NFTBurned", 264 | "type": "event" 265 | }, 266 | { 267 | "anonymous": false, 268 | "inputs": [ 269 | { 270 | "indexed": true, 271 | "internalType": "address", 272 | "name": "nftAddress", 273 | "type": "address" 274 | }, 275 | { 276 | "indexed": true, 277 | "internalType": "uint256", 278 | "name": "nftId", 279 | "type": "uint256" 280 | } 281 | ], 282 | "name": "NFTMinted", 283 | "type": "event" 284 | }, 285 | { 286 | "anonymous": false, 287 | "inputs": [ 288 | { 289 | "indexed": true, 290 | "internalType": "uint256", 291 | "name": "nftId", 292 | "type": "uint256" 293 | }, 294 | { 295 | "indexed": true, 296 | "internalType": "uint256", 297 | "name": "initialPrice", 298 | "type": "uint256" 299 | } 300 | ], 301 | "name": "OfferingSaleListed", 302 | "type": "event" 303 | }, 304 | { 305 | "anonymous": false, 306 | "inputs": [ 307 | { 308 | "indexed": true, 309 | "internalType": "uint256", 310 | "name": "index", 311 | "type": "uint256" 312 | }, 313 | { 314 | "indexed": true, 315 | "internalType": "address", 316 | "name": "from", 317 | "type": "address" 318 | }, 319 | { 320 | "indexed": true, 321 | "internalType": "bool", 322 | "name": "state", 323 | "type": "bool" 324 | } 325 | ], 326 | "name": "OfferingSaleTransactionConfirmed", 327 | "type": "event" 328 | }, 329 | { 330 | "anonymous": false, 331 | "inputs": [ 332 | { 333 | "indexed": true, 334 | "internalType": "uint256", 335 | "name": "index", 336 | "type": "uint256" 337 | } 338 | ], 339 | "name": "OfferingSaleTransactionExecuted", 340 | "type": "event" 341 | }, 342 | { 343 | "anonymous": false, 344 | "inputs": [ 345 | { 346 | "indexed": true, 347 | "internalType": "address", 348 | "name": "_tokenContractAddress", 349 | "type": "address" 350 | }, 351 | { 352 | "indexed": true, 353 | "internalType": "uint256", 354 | "name": "tokenId", 355 | "type": "uint256" 356 | }, 357 | { 358 | "indexed": true, 359 | "internalType": "address", 360 | "name": "_buyer", 361 | "type": "address" 362 | }, 363 | { 364 | "indexed": false, 365 | "internalType": "uint256", 366 | "name": "_price", 367 | "type": "uint256" 368 | } 369 | ], 370 | "name": "OfferingSaleTransactionProposed", 371 | "type": "event" 372 | }, 373 | { 374 | "anonymous": false, 375 | "inputs": [ 376 | { 377 | "indexed": false, 378 | "internalType": "uint256", 379 | "name": "value", 380 | "type": "uint256" 381 | } 382 | ], 383 | "name": "TeamScoreSet", 384 | "type": "event" 385 | }, 386 | { 387 | "anonymous": false, 388 | "inputs": [ 389 | { 390 | "indexed": true, 391 | "internalType": "address", 392 | "name": "member", 393 | "type": "address" 394 | }, 395 | { 396 | "indexed": true, 397 | "internalType": "address", 398 | "name": "nftContract", 399 | "type": "address" 400 | }, 401 | { 402 | "indexed": true, 403 | "internalType": "uint256", 404 | "name": "nftId", 405 | "type": "uint256" 406 | } 407 | ], 408 | "name": "UploadNFTFromMember", 409 | "type": "event" 410 | }, 411 | { 412 | "anonymous": false, 413 | "inputs": [ 414 | { 415 | "indexed": true, 416 | "internalType": "address", 417 | "name": "from", 418 | "type": "address" 419 | }, 420 | { 421 | "indexed": true, 422 | "internalType": "uint256", 423 | "name": "balanceToWithdraw", 424 | "type": "uint256" 425 | } 426 | ], 427 | "name": "WithdrawHappened", 428 | "type": "event" 429 | }, 430 | { 431 | "anonymous": false, 432 | "inputs": [], 433 | "name": "WithdrawalFromMarketplace", 434 | "type": "event" 435 | }, 436 | { 437 | "inputs": [ 438 | { 439 | "internalType": "uint256", 440 | "name": "", 441 | "type": "uint256" 442 | }, 443 | { 444 | "internalType": "uint256", 445 | "name": "", 446 | "type": "uint256" 447 | } 448 | ], 449 | "name": "Recording", 450 | "outputs": [ 451 | { 452 | "internalType": "address", 453 | "name": "_member", 454 | "type": "address" 455 | }, 456 | { 457 | "internalType": "uint256", 458 | "name": "_percent", 459 | "type": "uint256" 460 | }, 461 | { 462 | "internalType": "uint256", 463 | "name": "_sum", 464 | "type": "uint256" 465 | } 466 | ], 467 | "stateMutability": "view", 468 | "type": "function" 469 | }, 470 | { 471 | "inputs": [], 472 | "name": "USDC", 473 | "outputs": [ 474 | { 475 | "internalType": "address", 476 | "name": "", 477 | "type": "address" 478 | } 479 | ], 480 | "stateMutability": "view", 481 | "type": "function" 482 | }, 483 | { 484 | "inputs": [], 485 | "name": "USDC_token", 486 | "outputs": [ 487 | { 488 | "internalType": "contract IERC20", 489 | "name": "", 490 | "type": "address" 491 | } 492 | ], 493 | "stateMutability": "view", 494 | "type": "function" 495 | }, 496 | { 497 | "inputs": [ 498 | { 499 | "internalType": "address", 500 | "name": "_newMember", 501 | "type": "address" 502 | } 503 | ], 504 | "name": "addMember", 505 | "outputs": [], 506 | "stateMutability": "nonpayable", 507 | "type": "function" 508 | }, 509 | { 510 | "inputs": [ 511 | { 512 | "internalType": "uint256", 513 | "name": "_nftId", 514 | "type": "uint256" 515 | }, 516 | { 517 | "internalType": "uint256", 518 | "name": "_price", 519 | "type": "uint256" 520 | } 521 | ], 522 | "name": "alarmLoyaltyFeeReceived", 523 | "outputs": [], 524 | "stateMutability": "nonpayable", 525 | "type": "function" 526 | }, 527 | { 528 | "inputs": [ 529 | { 530 | "internalType": "address", 531 | "name": "_nftContractAddress", 532 | "type": "address" 533 | }, 534 | { 535 | "internalType": "uint256", 536 | "name": "_nftId", 537 | "type": "uint256" 538 | }, 539 | { 540 | "internalType": "uint256", 541 | "name": "_price", 542 | "type": "uint256" 543 | } 544 | ], 545 | "name": "alarmSoldOut", 546 | "outputs": [], 547 | "stateMutability": "nonpayable", 548 | "type": "function" 549 | }, 550 | { 551 | "inputs": [ 552 | { 553 | "internalType": "address", 554 | "name": "", 555 | "type": "address" 556 | } 557 | ], 558 | "name": "balance", 559 | "outputs": [ 560 | { 561 | "internalType": "uint256", 562 | "name": "", 563 | "type": "uint256" 564 | } 565 | ], 566 | "stateMutability": "view", 567 | "type": "function" 568 | }, 569 | { 570 | "inputs": [], 571 | "name": "burnFee", 572 | "outputs": [ 573 | { 574 | "internalType": "uint256", 575 | "name": "", 576 | "type": "uint256" 577 | } 578 | ], 579 | "stateMutability": "view", 580 | "type": "function" 581 | }, 582 | { 583 | "inputs": [ 584 | { 585 | "internalType": "uint256", 586 | "name": "_id", 587 | "type": "uint256" 588 | } 589 | ], 590 | "name": "cancelListing", 591 | "outputs": [], 592 | "stateMutability": "nonpayable", 593 | "type": "function" 594 | }, 595 | { 596 | "inputs": [ 597 | { 598 | "internalType": "uint256", 599 | "name": "_transactionId", 600 | "type": "uint256" 601 | }, 602 | { 603 | "internalType": "bool", 604 | "name": "_state", 605 | "type": "bool" 606 | } 607 | ], 608 | "name": "confirmBurnTransaction", 609 | "outputs": [], 610 | "stateMutability": "nonpayable", 611 | "type": "function" 612 | }, 613 | { 614 | "inputs": [ 615 | { 616 | "internalType": "uint256", 617 | "name": "_transactionId", 618 | "type": "uint256" 619 | }, 620 | { 621 | "internalType": "bool", 622 | "name": "_state", 623 | "type": "bool" 624 | } 625 | ], 626 | "name": "confirmDirectorSettingTransaction", 627 | "outputs": [], 628 | "stateMutability": "nonpayable", 629 | "type": "function" 630 | }, 631 | { 632 | "inputs": [ 633 | { 634 | "internalType": "uint256", 635 | "name": "_transactionId", 636 | "type": "uint256" 637 | }, 638 | { 639 | "internalType": "bool", 640 | "name": "_state", 641 | "type": "bool" 642 | } 643 | ], 644 | "name": "confirmOfferingSaleTransaction", 645 | "outputs": [], 646 | "stateMutability": "nonpayable", 647 | "type": "function" 648 | }, 649 | { 650 | "inputs": [ 651 | { 652 | "internalType": "address", 653 | "name": "", 654 | "type": "address" 655 | }, 656 | { 657 | "internalType": "uint256", 658 | "name": "", 659 | "type": "uint256" 660 | } 661 | ], 662 | "name": "confirmTransaction_Burn", 663 | "outputs": [ 664 | { 665 | "internalType": "bool", 666 | "name": "", 667 | "type": "bool" 668 | } 669 | ], 670 | "stateMutability": "view", 671 | "type": "function" 672 | }, 673 | { 674 | "inputs": [ 675 | { 676 | "internalType": "address", 677 | "name": "", 678 | "type": "address" 679 | }, 680 | { 681 | "internalType": "uint256", 682 | "name": "", 683 | "type": "uint256" 684 | } 685 | ], 686 | "name": "confirmTransaction_Candidate", 687 | "outputs": [ 688 | { 689 | "internalType": "bool", 690 | "name": "", 691 | "type": "bool" 692 | } 693 | ], 694 | "stateMutability": "view", 695 | "type": "function" 696 | }, 697 | { 698 | "inputs": [ 699 | { 700 | "internalType": "address", 701 | "name": "", 702 | "type": "address" 703 | }, 704 | { 705 | "internalType": "uint256", 706 | "name": "", 707 | "type": "uint256" 708 | } 709 | ], 710 | "name": "confirmTransaction_Offering", 711 | "outputs": [ 712 | { 713 | "internalType": "bool", 714 | "name": "", 715 | "type": "bool" 716 | } 717 | ], 718 | "stateMutability": "view", 719 | "type": "function" 720 | }, 721 | { 722 | "inputs": [], 723 | "name": "currentDistributeNumber", 724 | "outputs": [ 725 | { 726 | "internalType": "uint256", 727 | "name": "", 728 | "type": "uint256" 729 | } 730 | ], 731 | "stateMutability": "view", 732 | "type": "function" 733 | }, 734 | { 735 | "inputs": [], 736 | "name": "description", 737 | "outputs": [ 738 | { 739 | "internalType": "string", 740 | "name": "", 741 | "type": "string" 742 | } 743 | ], 744 | "stateMutability": "view", 745 | "type": "function" 746 | }, 747 | { 748 | "inputs": [], 749 | "name": "director", 750 | "outputs": [ 751 | { 752 | "internalType": "address", 753 | "name": "", 754 | "type": "address" 755 | } 756 | ], 757 | "stateMutability": "view", 758 | "type": "function" 759 | }, 760 | { 761 | "inputs": [ 762 | { 763 | "internalType": "uint256", 764 | "name": "_id", 765 | "type": "uint256" 766 | } 767 | ], 768 | "name": "endEnglishAuction", 769 | "outputs": [], 770 | "stateMutability": "nonpayable", 771 | "type": "function" 772 | }, 773 | { 774 | "inputs": [ 775 | { 776 | "internalType": "uint256", 777 | "name": "_transactionId", 778 | "type": "uint256" 779 | } 780 | ], 781 | "name": "executeBurnTransaction", 782 | "outputs": [], 783 | "stateMutability": "nonpayable", 784 | "type": "function" 785 | }, 786 | { 787 | "inputs": [ 788 | { 789 | "internalType": "uint256", 790 | "name": "_transactionId", 791 | "type": "uint256" 792 | } 793 | ], 794 | "name": "executeDirectorSettingTransaction", 795 | "outputs": [], 796 | "stateMutability": "nonpayable", 797 | "type": "function" 798 | }, 799 | { 800 | "inputs": [ 801 | { 802 | "internalType": "uint256", 803 | "name": "_transactionId", 804 | "type": "uint256" 805 | } 806 | ], 807 | "name": "executeOfferingSaleTransaction", 808 | "outputs": [], 809 | "stateMutability": "nonpayable", 810 | "type": "function" 811 | }, 812 | { 813 | "inputs": [], 814 | "name": "factory", 815 | "outputs": [ 816 | { 817 | "internalType": "address", 818 | "name": "", 819 | "type": "address" 820 | } 821 | ], 822 | "stateMutability": "view", 823 | "type": "function" 824 | }, 825 | { 826 | "inputs": [ 827 | { 828 | "internalType": "uint256", 829 | "name": "index", 830 | "type": "uint256" 831 | } 832 | ], 833 | "name": "getConfirmNumberOfBurnTransaction", 834 | "outputs": [ 835 | { 836 | "internalType": "uint256", 837 | "name": "", 838 | "type": "uint256" 839 | } 840 | ], 841 | "stateMutability": "view", 842 | "type": "function" 843 | }, 844 | { 845 | "inputs": [ 846 | { 847 | "internalType": "uint256", 848 | "name": "index", 849 | "type": "uint256" 850 | } 851 | ], 852 | "name": "getConfirmNumberOfDirectorSettingTransaction", 853 | "outputs": [ 854 | { 855 | "internalType": "uint256", 856 | "name": "", 857 | "type": "uint256" 858 | } 859 | ], 860 | "stateMutability": "view", 861 | "type": "function" 862 | }, 863 | { 864 | "inputs": [ 865 | { 866 | "internalType": "uint256", 867 | "name": "index", 868 | "type": "uint256" 869 | } 870 | ], 871 | "name": "getConfirmNumberOfOfferingSaleTransaction", 872 | "outputs": [ 873 | { 874 | "internalType": "uint256", 875 | "name": "", 876 | "type": "uint256" 877 | } 878 | ], 879 | "stateMutability": "view", 880 | "type": "function" 881 | }, 882 | { 883 | "inputs": [ 884 | { 885 | "internalType": "address", 886 | "name": "", 887 | "type": "address" 888 | }, 889 | { 890 | "internalType": "uint256", 891 | "name": "", 892 | "type": "uint256" 893 | } 894 | ], 895 | "name": "getNFTId", 896 | "outputs": [ 897 | { 898 | "internalType": "uint256", 899 | "name": "", 900 | "type": "uint256" 901 | } 902 | ], 903 | "stateMutability": "view", 904 | "type": "function" 905 | }, 906 | { 907 | "inputs": [ 908 | { 909 | "internalType": "uint256", 910 | "name": "index", 911 | "type": "uint256" 912 | } 913 | ], 914 | "name": "getNftAddress", 915 | "outputs": [ 916 | { 917 | "internalType": "address", 918 | "name": "", 919 | "type": "address" 920 | } 921 | ], 922 | "stateMutability": "view", 923 | "type": "function" 924 | }, 925 | { 926 | "inputs": [ 927 | { 928 | "internalType": "uint256", 929 | "name": "index", 930 | "type": "uint256" 931 | } 932 | ], 933 | "name": "getNftOfId", 934 | "outputs": [ 935 | { 936 | "internalType": "uint256", 937 | "name": "", 938 | "type": "uint256" 939 | } 940 | ], 941 | "stateMutability": "view", 942 | "type": "function" 943 | }, 944 | { 945 | "inputs": [], 946 | "name": "getNumberOfBurnTransaction", 947 | "outputs": [ 948 | { 949 | "internalType": "uint256", 950 | "name": "", 951 | "type": "uint256" 952 | } 953 | ], 954 | "stateMutability": "view", 955 | "type": "function" 956 | }, 957 | { 958 | "inputs": [], 959 | "name": "getNumberOfCandidateTransaction", 960 | "outputs": [ 961 | { 962 | "internalType": "uint256", 963 | "name": "", 964 | "type": "uint256" 965 | } 966 | ], 967 | "stateMutability": "view", 968 | "type": "function" 969 | }, 970 | { 971 | "inputs": [], 972 | "name": "getNumberOfSaleOfferingTransaction", 973 | "outputs": [ 974 | { 975 | "internalType": "uint256", 976 | "name": "", 977 | "type": "uint256" 978 | } 979 | ], 980 | "stateMutability": "view", 981 | "type": "function" 982 | }, 983 | { 984 | "inputs": [ 985 | { 986 | "internalType": "address", 987 | "name": "_member", 988 | "type": "address" 989 | }, 990 | { 991 | "internalType": "uint256", 992 | "name": "id", 993 | "type": "uint256" 994 | } 995 | ], 996 | "name": "getRevenueDistribution", 997 | "outputs": [ 998 | { 999 | "internalType": "uint256", 1000 | "name": "", 1001 | "type": "uint256" 1002 | } 1003 | ], 1004 | "stateMutability": "view", 1005 | "type": "function" 1006 | }, 1007 | { 1008 | "inputs": [ 1009 | { 1010 | "internalType": "uint256", 1011 | "name": "index", 1012 | "type": "uint256" 1013 | } 1014 | ], 1015 | "name": "getSoldInfor", 1016 | "outputs": [ 1017 | { 1018 | "components": [ 1019 | { 1020 | "internalType": "uint256", 1021 | "name": "id", 1022 | "type": "uint256" 1023 | }, 1024 | { 1025 | "internalType": "uint256", 1026 | "name": "price", 1027 | "type": "uint256" 1028 | }, 1029 | { 1030 | "internalType": "bool", 1031 | "name": "distributeState", 1032 | "type": "bool" 1033 | } 1034 | ], 1035 | "internalType": "struct ICreatorGroup.soldInfor", 1036 | "name": "", 1037 | "type": "tuple" 1038 | } 1039 | ], 1040 | "stateMutability": "view", 1041 | "type": "function" 1042 | }, 1043 | { 1044 | "inputs": [], 1045 | "name": "getSoldNumber", 1046 | "outputs": [ 1047 | { 1048 | "internalType": "uint256", 1049 | "name": "", 1050 | "type": "uint256" 1051 | } 1052 | ], 1053 | "stateMutability": "view", 1054 | "type": "function" 1055 | }, 1056 | { 1057 | "inputs": [ 1058 | { 1059 | "internalType": "string", 1060 | "name": "_name", 1061 | "type": "string" 1062 | }, 1063 | { 1064 | "internalType": "string", 1065 | "name": "_description", 1066 | "type": "string" 1067 | }, 1068 | { 1069 | "internalType": "address[]", 1070 | "name": "_members", 1071 | "type": "address[]" 1072 | }, 1073 | { 1074 | "internalType": "uint256", 1075 | "name": "_numConfirmationRequired", 1076 | "type": "uint256" 1077 | }, 1078 | { 1079 | "internalType": "address", 1080 | "name": "_marketplace", 1081 | "type": "address" 1082 | }, 1083 | { 1084 | "internalType": "uint256", 1085 | "name": "_mintFee", 1086 | "type": "uint256" 1087 | }, 1088 | { 1089 | "internalType": "uint256", 1090 | "name": "_burnFee", 1091 | "type": "uint256" 1092 | }, 1093 | { 1094 | "internalType": "address", 1095 | "name": "_USDC", 1096 | "type": "address" 1097 | } 1098 | ], 1099 | "name": "initialize", 1100 | "outputs": [], 1101 | "stateMutability": "nonpayable", 1102 | "type": "function" 1103 | }, 1104 | { 1105 | "inputs": [ 1106 | { 1107 | "internalType": "address", 1108 | "name": "", 1109 | "type": "address" 1110 | } 1111 | ], 1112 | "name": "isOwner", 1113 | "outputs": [ 1114 | { 1115 | "internalType": "bool", 1116 | "name": "", 1117 | "type": "bool" 1118 | } 1119 | ], 1120 | "stateMutability": "view", 1121 | "type": "function" 1122 | }, 1123 | { 1124 | "inputs": [ 1125 | { 1126 | "internalType": "uint256", 1127 | "name": "_id", 1128 | "type": "uint256" 1129 | }, 1130 | { 1131 | "internalType": "uint256", 1132 | "name": "_initialPrice", 1133 | "type": "uint256" 1134 | }, 1135 | { 1136 | "internalType": "uint256", 1137 | "name": "_reducingRate", 1138 | "type": "uint256" 1139 | }, 1140 | { 1141 | "internalType": "uint256", 1142 | "name": "_salePeriod", 1143 | "type": "uint256" 1144 | } 1145 | ], 1146 | "name": "listToDutchAuction", 1147 | "outputs": [], 1148 | "stateMutability": "nonpayable", 1149 | "type": "function" 1150 | }, 1151 | { 1152 | "inputs": [ 1153 | { 1154 | "internalType": "uint256", 1155 | "name": "_id", 1156 | "type": "uint256" 1157 | }, 1158 | { 1159 | "internalType": "uint256", 1160 | "name": "_initialPrice", 1161 | "type": "uint256" 1162 | }, 1163 | { 1164 | "internalType": "uint256", 1165 | "name": "_salePeriod", 1166 | "type": "uint256" 1167 | } 1168 | ], 1169 | "name": "listToEnglishAuction", 1170 | "outputs": [], 1171 | "stateMutability": "nonpayable", 1172 | "type": "function" 1173 | }, 1174 | { 1175 | "inputs": [ 1176 | { 1177 | "internalType": "uint256", 1178 | "name": "_id", 1179 | "type": "uint256" 1180 | }, 1181 | { 1182 | "internalType": "uint256", 1183 | "name": "_initialPrice", 1184 | "type": "uint256" 1185 | } 1186 | ], 1187 | "name": "listToOfferingSale", 1188 | "outputs": [], 1189 | "stateMutability": "nonpayable", 1190 | "type": "function" 1191 | }, 1192 | { 1193 | "inputs": [ 1194 | { 1195 | "internalType": "uint256", 1196 | "name": "", 1197 | "type": "uint256" 1198 | } 1199 | ], 1200 | "name": "listedState", 1201 | "outputs": [ 1202 | { 1203 | "internalType": "bool", 1204 | "name": "", 1205 | "type": "bool" 1206 | } 1207 | ], 1208 | "stateMutability": "view", 1209 | "type": "function" 1210 | }, 1211 | { 1212 | "inputs": [], 1213 | "name": "marketplace", 1214 | "outputs": [ 1215 | { 1216 | "internalType": "address", 1217 | "name": "", 1218 | "type": "address" 1219 | } 1220 | ], 1221 | "stateMutability": "view", 1222 | "type": "function" 1223 | }, 1224 | { 1225 | "inputs": [ 1226 | { 1227 | "internalType": "uint256", 1228 | "name": "", 1229 | "type": "uint256" 1230 | } 1231 | ], 1232 | "name": "members", 1233 | "outputs": [ 1234 | { 1235 | "internalType": "address", 1236 | "name": "", 1237 | "type": "address" 1238 | } 1239 | ], 1240 | "stateMutability": "view", 1241 | "type": "function" 1242 | }, 1243 | { 1244 | "inputs": [ 1245 | { 1246 | "internalType": "string", 1247 | "name": "_nftURI", 1248 | "type": "string" 1249 | }, 1250 | { 1251 | "internalType": "address", 1252 | "name": "_targetCollection", 1253 | "type": "address" 1254 | } 1255 | ], 1256 | "name": "mint", 1257 | "outputs": [], 1258 | "stateMutability": "nonpayable", 1259 | "type": "function" 1260 | }, 1261 | { 1262 | "inputs": [], 1263 | "name": "mintFee", 1264 | "outputs": [ 1265 | { 1266 | "internalType": "uint256", 1267 | "name": "", 1268 | "type": "uint256" 1269 | } 1270 | ], 1271 | "stateMutability": "view", 1272 | "type": "function" 1273 | }, 1274 | { 1275 | "inputs": [ 1276 | { 1277 | "internalType": "string", 1278 | "name": "_nftURI", 1279 | "type": "string" 1280 | }, 1281 | { 1282 | "internalType": "string", 1283 | "name": "_name", 1284 | "type": "string" 1285 | }, 1286 | { 1287 | "internalType": "string", 1288 | "name": "_symbol", 1289 | "type": "string" 1290 | }, 1291 | { 1292 | "internalType": "string", 1293 | "name": "_description", 1294 | "type": "string" 1295 | } 1296 | ], 1297 | "name": "mintNew", 1298 | "outputs": [], 1299 | "stateMutability": "nonpayable", 1300 | "type": "function" 1301 | }, 1302 | { 1303 | "inputs": [], 1304 | "name": "name", 1305 | "outputs": [ 1306 | { 1307 | "internalType": "string", 1308 | "name": "", 1309 | "type": "string" 1310 | } 1311 | ], 1312 | "stateMutability": "view", 1313 | "type": "function" 1314 | }, 1315 | { 1316 | "inputs": [ 1317 | { 1318 | "internalType": "uint256", 1319 | "name": "", 1320 | "type": "uint256" 1321 | } 1322 | ], 1323 | "name": "nftAddressArr", 1324 | "outputs": [ 1325 | { 1326 | "internalType": "address", 1327 | "name": "", 1328 | "type": "address" 1329 | } 1330 | ], 1331 | "stateMutability": "view", 1332 | "type": "function" 1333 | }, 1334 | { 1335 | "inputs": [ 1336 | { 1337 | "internalType": "uint256", 1338 | "name": "", 1339 | "type": "uint256" 1340 | } 1341 | ], 1342 | "name": "nftIdArr", 1343 | "outputs": [ 1344 | { 1345 | "internalType": "uint256", 1346 | "name": "", 1347 | "type": "uint256" 1348 | } 1349 | ], 1350 | "stateMutability": "view", 1351 | "type": "function" 1352 | }, 1353 | { 1354 | "inputs": [], 1355 | "name": "numConfirmationRequired", 1356 | "outputs": [ 1357 | { 1358 | "internalType": "uint256", 1359 | "name": "", 1360 | "type": "uint256" 1361 | } 1362 | ], 1363 | "stateMutability": "view", 1364 | "type": "function" 1365 | }, 1366 | { 1367 | "inputs": [], 1368 | "name": "numberOfMembers", 1369 | "outputs": [ 1370 | { 1371 | "internalType": "uint256", 1372 | "name": "", 1373 | "type": "uint256" 1374 | } 1375 | ], 1376 | "stateMutability": "view", 1377 | "type": "function" 1378 | }, 1379 | { 1380 | "inputs": [], 1381 | "name": "numberOfNFT", 1382 | "outputs": [ 1383 | { 1384 | "internalType": "uint256", 1385 | "name": "", 1386 | "type": "uint256" 1387 | } 1388 | ], 1389 | "stateMutability": "view", 1390 | "type": "function" 1391 | }, 1392 | { 1393 | "inputs": [ 1394 | { 1395 | "internalType": "address", 1396 | "name": "_oldMember", 1397 | "type": "address" 1398 | } 1399 | ], 1400 | "name": "removeMember", 1401 | "outputs": [], 1402 | "stateMutability": "nonpayable", 1403 | "type": "function" 1404 | }, 1405 | { 1406 | "inputs": [ 1407 | { 1408 | "internalType": "address", 1409 | "name": "", 1410 | "type": "address" 1411 | }, 1412 | { 1413 | "internalType": "uint256", 1414 | "name": "", 1415 | "type": "uint256" 1416 | } 1417 | ], 1418 | "name": "revenueDistribution", 1419 | "outputs": [ 1420 | { 1421 | "internalType": "uint256", 1422 | "name": "", 1423 | "type": "uint256" 1424 | } 1425 | ], 1426 | "stateMutability": "view", 1427 | "type": "function" 1428 | }, 1429 | { 1430 | "inputs": [ 1431 | { 1432 | "internalType": "uint256", 1433 | "name": "_confirmNumber", 1434 | "type": "uint256" 1435 | } 1436 | ], 1437 | "name": "setConfirmationRequiredNumber", 1438 | "outputs": [], 1439 | "stateMutability": "nonpayable", 1440 | "type": "function" 1441 | }, 1442 | { 1443 | "inputs": [ 1444 | { 1445 | "internalType": "uint256", 1446 | "name": "_score", 1447 | "type": "uint256" 1448 | } 1449 | ], 1450 | "name": "setTeamScore", 1451 | "outputs": [], 1452 | "stateMutability": "nonpayable", 1453 | "type": "function" 1454 | }, 1455 | { 1456 | "inputs": [ 1457 | { 1458 | "internalType": "uint256", 1459 | "name": "", 1460 | "type": "uint256" 1461 | } 1462 | ], 1463 | "name": "soldInformation", 1464 | "outputs": [ 1465 | { 1466 | "internalType": "uint256", 1467 | "name": "id", 1468 | "type": "uint256" 1469 | }, 1470 | { 1471 | "internalType": "uint256", 1472 | "name": "price", 1473 | "type": "uint256" 1474 | }, 1475 | { 1476 | "internalType": "bool", 1477 | "name": "distributeState", 1478 | "type": "bool" 1479 | } 1480 | ], 1481 | "stateMutability": "view", 1482 | "type": "function" 1483 | }, 1484 | { 1485 | "inputs": [ 1486 | { 1487 | "internalType": "uint256", 1488 | "name": "", 1489 | "type": "uint256" 1490 | } 1491 | ], 1492 | "name": "soldOutState", 1493 | "outputs": [ 1494 | { 1495 | "internalType": "bool", 1496 | "name": "", 1497 | "type": "bool" 1498 | } 1499 | ], 1500 | "stateMutability": "view", 1501 | "type": "function" 1502 | }, 1503 | { 1504 | "inputs": [ 1505 | { 1506 | "internalType": "uint256", 1507 | "name": "_id", 1508 | "type": "uint256" 1509 | } 1510 | ], 1511 | "name": "submitBurnTransaction", 1512 | "outputs": [], 1513 | "stateMutability": "nonpayable", 1514 | "type": "function" 1515 | }, 1516 | { 1517 | "inputs": [ 1518 | { 1519 | "internalType": "address", 1520 | "name": "_candidate", 1521 | "type": "address" 1522 | } 1523 | ], 1524 | "name": "submitDirectorSettingTransaction", 1525 | "outputs": [], 1526 | "stateMutability": "nonpayable", 1527 | "type": "function" 1528 | }, 1529 | { 1530 | "inputs": [ 1531 | { 1532 | "internalType": "uint256", 1533 | "name": "_marketId", 1534 | "type": "uint256" 1535 | }, 1536 | { 1537 | "internalType": "address", 1538 | "name": "_tokenContractAddress", 1539 | "type": "address" 1540 | }, 1541 | { 1542 | "internalType": "uint256", 1543 | "name": "_tokenId", 1544 | "type": "uint256" 1545 | }, 1546 | { 1547 | "internalType": "address", 1548 | "name": "_buyer", 1549 | "type": "address" 1550 | }, 1551 | { 1552 | "internalType": "uint256", 1553 | "name": "_price", 1554 | "type": "uint256" 1555 | } 1556 | ], 1557 | "name": "submitOfferingSaleTransaction", 1558 | "outputs": [], 1559 | "stateMutability": "nonpayable", 1560 | "type": "function" 1561 | }, 1562 | { 1563 | "inputs": [], 1564 | "name": "teamScore", 1565 | "outputs": [ 1566 | { 1567 | "internalType": "uint256", 1568 | "name": "", 1569 | "type": "uint256" 1570 | } 1571 | ], 1572 | "stateMutability": "view", 1573 | "type": "function" 1574 | }, 1575 | { 1576 | "inputs": [], 1577 | "name": "totalEarning", 1578 | "outputs": [ 1579 | { 1580 | "internalType": "uint256", 1581 | "name": "", 1582 | "type": "uint256" 1583 | } 1584 | ], 1585 | "stateMutability": "view", 1586 | "type": "function" 1587 | }, 1588 | { 1589 | "inputs": [ 1590 | { 1591 | "internalType": "uint256", 1592 | "name": "", 1593 | "type": "uint256" 1594 | } 1595 | ], 1596 | "name": "transactions_burn", 1597 | "outputs": [ 1598 | { 1599 | "internalType": "uint256", 1600 | "name": "id", 1601 | "type": "uint256" 1602 | }, 1603 | { 1604 | "internalType": "bool", 1605 | "name": "endState", 1606 | "type": "bool" 1607 | } 1608 | ], 1609 | "stateMutability": "view", 1610 | "type": "function" 1611 | }, 1612 | { 1613 | "inputs": [ 1614 | { 1615 | "internalType": "uint256", 1616 | "name": "", 1617 | "type": "uint256" 1618 | } 1619 | ], 1620 | "name": "transactions_candidate", 1621 | "outputs": [ 1622 | { 1623 | "internalType": "address", 1624 | "name": "candidate", 1625 | "type": "address" 1626 | }, 1627 | { 1628 | "internalType": "bool", 1629 | "name": "endState", 1630 | "type": "bool" 1631 | } 1632 | ], 1633 | "stateMutability": "view", 1634 | "type": "function" 1635 | }, 1636 | { 1637 | "inputs": [ 1638 | { 1639 | "internalType": "uint256", 1640 | "name": "", 1641 | "type": "uint256" 1642 | } 1643 | ], 1644 | "name": "transactions_offering", 1645 | "outputs": [ 1646 | { 1647 | "internalType": "uint256", 1648 | "name": "marketId", 1649 | "type": "uint256" 1650 | }, 1651 | { 1652 | "internalType": "uint256", 1653 | "name": "id", 1654 | "type": "uint256" 1655 | }, 1656 | { 1657 | "internalType": "address", 1658 | "name": "buyer", 1659 | "type": "address" 1660 | }, 1661 | { 1662 | "internalType": "uint256", 1663 | "name": "price", 1664 | "type": "uint256" 1665 | }, 1666 | { 1667 | "internalType": "bool", 1668 | "name": "endState", 1669 | "type": "bool" 1670 | } 1671 | ], 1672 | "stateMutability": "view", 1673 | "type": "function" 1674 | }, 1675 | { 1676 | "inputs": [ 1677 | { 1678 | "internalType": "address", 1679 | "name": "_nftContractAddress", 1680 | "type": "address" 1681 | }, 1682 | { 1683 | "internalType": "uint256", 1684 | "name": "_tokenId", 1685 | "type": "uint256" 1686 | } 1687 | ], 1688 | "name": "uploadMemberNFT", 1689 | "outputs": [], 1690 | "stateMutability": "nonpayable", 1691 | "type": "function" 1692 | }, 1693 | { 1694 | "inputs": [], 1695 | "name": "withdraw", 1696 | "outputs": [], 1697 | "stateMutability": "nonpayable", 1698 | "type": "function" 1699 | }, 1700 | { 1701 | "inputs": [], 1702 | "name": "withdrawFromMarketplace", 1703 | "outputs": [], 1704 | "stateMutability": "nonpayable", 1705 | "type": "function" 1706 | } 1707 | ] -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "resolveJsonModule": true 10 | }, 11 | "exclude": ["dist", "node_modules"], 12 | "include": ["./test", "./src", "./scripts", "./typechain-types"], 13 | "files": ["./hardhat.config.ts"] 14 | } 15 | --------------------------------------------------------------------------------