diff --git a/contract b/contract new file mode 160000 index 0000000..328f751 --- /dev/null +++ b/contract @@ -0,0 +1 @@ +Subproject commit 328f751cfdfbc487a62b46d8e579dfdbd463bb56 diff --git a/contract/.editorconfig b/contract/.editorconfig deleted file mode 100644 index 10edce2..0000000 --- a/contract/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -root = true - -[*] -end_of_line = lf -insert_final_newline = true -charset = utf-8 -indent_size = 2 -indent_style = space - -[*.sol] -indent_size = 4 -indent_style = space - -[Makefile] -indent_style = tab -indent_size = 8 diff --git a/contract/.gitignore b/contract/.gitignore deleted file mode 100644 index 3297e19..0000000 --- a/contract/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules/ -artifacts/ -cache/ -.log/ -chain.ts diff --git a/contract/LICENSE b/contract/LICENSE deleted file mode 100644 index df62036..0000000 --- a/contract/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 SparkLink - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/contract/Makefile b/contract/Makefile deleted file mode 100644 index 5a98a1d..0000000 --- a/contract/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -.PHONY: build test prepare clean - -prepare: - yarn - if [ ! -f chain.ts ]; then cp chain.sample.ts chain.ts; fi; - -build: - yarn hardhat compile - -test: build - yarn hardhat test - -clean: - yarn hardhat clean - -check: - yarn hardhat check - -rinkeby: - yarn hardhat run scripts/deploy.ts --network rinkeby - -matic: - yarn hardhat run scripts/deploy.ts --network matic - -BSC: - yarn hardhat run scripts/deploy.ts --network BSC - -ETH: - yarn hardhat run scripts/deploy.ts --network ETH - -hh: - yarn hardhat run scripts/deploy.ts -flatten: - yarn hardhat flatten ./contracts/SparkLink.sol > publish.sol \ No newline at end of file diff --git a/contract/README.md b/contract/README.md deleted file mode 100644 index 508b473..0000000 --- a/contract/README.md +++ /dev/null @@ -1,85 +0,0 @@ -# SparkLink Smart Contract - -## Brief introduction - -SparkLink Smart Contract is an Ethereum smart contract. - -Authors can publish their virtual products (such as a book) on the blockchain and generate a `root NFT`. - -Others can buy a child `NFT3` from any existing father `NFT2`, holder of `NFT2` will get income. - -At the same time, holders of `NFT2`'s father `NFT3` will extract the amount corresponding to the proportion of royalties from the profit of the child `NFT2`. - -SparkLink Smart Contract can support these features: - -- Authors can create virtual products (such as a book) with attributes (such as: royalty percent, maximum number of child NFTs). -- Accept shill from an existing NFT and will get an child NFT. -- Claim the profit generated by the NFT you own. - -For design details, please see [API document](doc/SparkLink_API.md). - -## Getting Started - -To install required node.js modules: - -```bash -npm ci -``` - -To compile the solidity source code - -```bash -make build -``` - -To run unit test: - -```bash -make test -``` - -To deploy the smart contract on Ethereum rinkeby testnet: - -```bash -make rinkeby -``` - -Note: - -- This project is powered by [hardhat](https://hardhat.org/). - You can change your network configuration in `hardhat.config.ts` file. -- Before you deploy a smart contract or interact with a smart contract, - you need to set up your wallet private key and [`infura`](https://infura.io/) key in `config.json`. - - `config.json` is a template, which contains dummy configurations. - - Please handle your private key carefully. In this project, - `config.json` has already been added into `.gitignore`, as foolproof. - -## Deployed Contract Address - -| Contract | Address | -| ---------------------- | ---------------------- | -| [Mainnet][mainnet] | [0x71872117][71872117] | -| [BSC][bscscan] | [0xDc891065][Dc891065] | -| [Matic][matic] | [0x166BCdc5][166BCdc5] | - -[mainnet]: https://etherscan.io/ -[ropsten]: https://ropsten.etherscan.io -[bscscan]: https://bscscan.com -[bsctest]: https://testnet.bscscan.com -[matic]: https://polygonscan.com -[mumbai]: https://explorer-mumbai.maticvigil.com -[166BCdc5]: https://polygonscan.com/address/0x166BCdc53BC8573448F37C66EF409f1Cb31450a2 -[Dc891065]: https://www.bscscan.com/address/0xDc89106504f82642801dc43C8B545Ef7DA95ff2b -[71872117]: https://etherscan.io/address/0x7187211744c67F8cE89fEAc63b85D8D17417bDfE - -## Contribute - -Any contribution is welcomed to make it better. - -Had you any questions, please do not hesitate to create an [issue](https://github.com/andy-at-mask/AirPod/issues). - -## License - -[MIT LICENSE](LICENSE) diff --git a/contract/abi/SparkLink.json b/contract/abi/SparkLink.json deleted file mode 100644 index b4d4325..0000000 --- a/contract/abi/SparkLink.json +++ /dev/null @@ -1,1359 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "SparkLink", - "sourceName": "contracts/SparkLink.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "DAO_router_address01", - "type": "address" - }, - { - "internalType": "address", - "name": "DAO_router_address02", - "type": "address" - }, - { - "internalType": "address", - "name": "uniswapRouterAddress", - "type": "address" - }, - { - "internalType": "address", - "name": "factoryAddress", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "approved", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "ApprovalForAll", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "NFT_id", - "type": "uint64" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint128", - "name": "amount", - "type": "uint128" - } - ], - "name": "Claim", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "NFT_id", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "uint128", - "name": "transfer_price", - "type": "uint128" - } - ], - "name": "DeterminePrice", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "NFT_id", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "uint128", - "name": "transfer_price", - "type": "uint128" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "DeterminePriceAndApprove", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "NFT_id", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "string", - "name": "content", - "type": "string" - } - ], - "name": "Label", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "publisher", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint64", - "name": "rootNFTId", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "address", - "name": "token_addr", - "type": "address" - } - ], - "name": "Publish", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "old_DAO_fee", - "type": "uint8" - }, - { - "indexed": false, - "internalType": "uint8", - "name": "new_DAO_fee", - "type": "uint8" - } - ], - "name": "SetDAOFee", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "old_router_address", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "new_router_address", - "type": "address" - } - ], - "name": "SetDAORouter01", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "old_router_address", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "new_router_address", - "type": "address" - } - ], - "name": "SetDAORouter02", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "old_loss_ratio", - "type": "uint8" - }, - { - "indexed": false, - "internalType": "uint8", - "name": "new_loss_ratio", - "type": "uint8" - } - ], - "name": "SetLoosRatio", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "NFT_id", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "old_URI", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "new_URI", - "type": "bytes32" - } - ], - "name": "SetURI", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [], - "name": "DAO_fee", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "DAO_router01", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "DAO_router02", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "MAX_DAO_FEE", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "MAX_LOSS_RATIO", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "acceptShill", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "claimProfit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - }, - { - "internalType": "uint128", - "name": "_price", - "type": "uint128" - } - ], - "name": "determinePrice", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - }, - { - "internalType": "uint128", - "name": "_price", - "type": "uint128" - }, - { - "internalType": "address", - "name": "_to", - "type": "address" - } - ], - "name": "determinePriceAndApprove", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "getApproved", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getDepthByNFTId", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getEditionIdByNFTId", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getFatherByNFTId", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getIsFreeByNFTId", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getIsNCByNFTId", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getIsNDByNFTId", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getLossRatio", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getNFTInfoByNFTID", - "outputs": [ - { - "internalType": "uint64", - "name": "issue_information", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "father_id", - "type": "uint64" - }, - { - "internalType": "uint128", - "name": "shill_price", - "type": "uint128" - }, - { - "internalType": "uint16", - "name": "remain_shill_times", - "type": "uint16" - }, - { - "internalType": "uint128", - "name": "profit", - "type": "uint128" - }, - { - "internalType": "string", - "name": "metadata", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getProfitByNFTId", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getRemainShillTimesByNFTId", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getRootNFTIdByNFTId", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getRoyaltyFeeByNFTId", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getShillPriceByNFTId", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getShillTimesByNFTId", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getTokenAddrByNFTId", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getTotalAmountByNFTId", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "getTransferPriceByNFTId", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "isApprovedForAll", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "isEditionExisting", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "isRootNFT", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - }, - { - "internalType": "string", - "name": "content", - "type": "string" - } - ], - "name": "label", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "loss_ratio", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "ownerOf", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "_first_sell_price", - "type": "uint128" - }, - { - "internalType": "uint8", - "name": "_royalty_fee", - "type": "uint8" - }, - { - "internalType": "uint16", - "name": "_shill_times", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "_ipfs_hash", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "_token_addr", - "type": "address" - }, - { - "internalType": "bool", - "name": "_is_free", - "type": "bool" - }, - { - "internalType": "bool", - "name": "_is_NC", - "type": "bool" - }, - { - "internalType": "bool", - "name": "_is_ND", - "type": "bool" - } - ], - "name": "publish", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "setApprovalForAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "_DAO_fee", - "type": "uint8" - } - ], - "name": "setDAOFee", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_DAO_router01", - "type": "address" - } - ], - "name": "setDAORouter01", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_DAO_router02", - "type": "address" - } - ], - "name": "setDAORouter02", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "_loss_ratio", - "type": "uint8" - } - ], - "name": "setLoosRatio", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "ipfs_hash", - "type": "bytes32" - } - ], - "name": "setURI", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_uniswapV2Factory", - "type": "address" - } - ], - "name": "setUniswapV2Factory", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_uniswapV2Router", - "type": "address" - } - ], - "name": "setUniswapV2Router", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "tokenURI", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "uniswapV2Factory", - "outputs": [ - { - "internalType": "contract IUniswapV2Factory", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "uniswapV2Router", - "outputs": [ - { - "internalType": "contract IUniswapV2Router02", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_NFT_id", - "type": "uint64" - } - ], - "name": "updateURI", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x60806040526004805461ffff191661023e1790553480156200002057600080fd5b5060405162004f2538038062004f25833981016040819052620000439162000222565b6200004e336200010f565b600680546001600160a01b03199081166001600160a01b03858116919091179092556007805482168484161790556004805462010000600160b01b03191662010000888516021790556005805490911691851691909117905560408051808201909152600980825268537061726b4c696e6b60b81b6020909201918252620000d9916002916200015f565b506040805180820190915260038082526214d41360ea1b60209092019182526200010491816200015f565b5050505050620002bb565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b8280546200016d906200027e565b90600052602060002090601f016020900481019282620001915760008555620001dc565b82601f10620001ac57805160ff1916838001178555620001dc565b82800160010185558215620001dc579182015b82811115620001dc578251825591602001919060010190620001bf565b50620001ea929150620001ee565b5090565b5b80821115620001ea5760008155600101620001ef565b80516001600160a01b03811681146200021d57600080fd5b919050565b6000806000806080858703121562000238578384fd5b620002438562000205565b9350620002536020860162000205565b9250620002636040860162000205565b9150620002736060860162000205565b905092959194509250565b600181811c908216806200029357607f821691505b60208210811415620002b557634e487b7160e01b600052602260045260246000fd5b50919050565b614c5a80620002cb6000396000f3fe6080604052600436106103765760003560e01c80637098da84116101d1578063bbe07d7911610102578063d8d17e79116100a0578063f2fde38b1161006f578063f2fde38b14610aa1578063f6e9274d14610ac1578063fee0329914610ae1578063ff0eac4514610b0157600080fd5b8063d8d17e79146109f8578063e985e9c514610a18578063e9a5a37214610a61578063f1ac67d314610a8157600080fd5b8063bf1a9657116100dc578063bf1a965714610964578063c87b56dd14610999578063ce51ba90146109b9578063cfc02f5f146109d957600080fd5b8063bbe07d7914610911578063bd3355ed14610924578063bdea26fa1461094457600080fd5b806392e6f9ac1161016f578063a7c9e88111610149578063a7c9e88114610887578063ac03d001146108bf578063ae72e098146108e9578063b88d4fde146108fe57600080fd5b806392e6f9ac1461082b57806395d89b4114610852578063a22cb4651461086757600080fd5b806377738ad2116101ab57806377738ad21461079b5780638ba51d61146107bb5780638da5cb5b146107db578063927ef546146107f957600080fd5b80637098da841461073857806370a0823114610758578063715018a61461078657600080fd5b806330999f7b116102ab5780635a034b3b116102495780636352211e116102235780636352211e146106b85780636579aea2146106d857806365cb8c93146106f8578063668432081461071857600080fd5b80635a034b3b14610658578063600f11db1461067857806361bc8a531461069857600080fd5b80634940df03116102855780634940df03146105dd57806350614e191461060357806358d400cb1461061857806359d0f7131461063857600080fd5b806330999f7b1461058a57806342842e0e146105aa57806347bb0958146105bd57600080fd5b80631694505e1161031857806324d4401a116102f257806324d4401a146105105780632524ba4d146105305780632b56a1c2146105505780632b9e0d721461056a57600080fd5b80631694505e146104a55780631dab1af7146104c557806323b872dd146104fd57600080fd5b8063081812fc11610354578063081812fc146103f8578063095ea7b3146104305780631419841d1461045257806316468b5c1461047257600080fd5b806301ffc9a71461037b5780630292ec36146103b057806306fdde03146103d6575b600080fd5b34801561038757600080fd5b5061039b6103963660046143bc565b610b21565b60405190151581526020015b60405180910390f35b3480156103bc57600080fd5b5060045460ff165b60405160ff90911681526020016103a7565b3480156103e257600080fd5b506103eb610b73565b6040516103a79190614726565b34801561040457600080fd5b50610418610413366004614495565b610c05565b6040516001600160a01b0390911681526020016103a7565b34801561043c57600080fd5b5061045061044b366004614375565b610c6e565b005b34801561045e57600080fd5b5061045061046d3660046141ff565b610d8e565b34801561047e57600080fd5b5061049261048d3660046144c5565b610dda565b60405161ffff90911681526020016103a7565b3480156104b157600080fd5b50600654610418906001600160a01b031681565b3480156104d157600080fd5b506104e56104e03660046144c5565b610e29565b6040516001600160401b0390911681526020016103a7565b61045061050b36600461426f565b610e7e565b34801561051c57600080fd5b5061045061052b3660046141ff565b610e91565b34801561053c57600080fd5b5061045061054b3660046141ff565b610f24565b34801561055c57600080fd5b506004546103c49060ff1681565b34801561057657600080fd5b5061039b6105853660046144c5565b610fc5565b34801561059657600080fd5b5061039b6105a53660046144c5565b610fee565b6104506105b836600461426f565b611051565b3480156105c957600080fd5b506103c46105d83660046144c5565b611074565b3480156105e957600080fd5b50600454610418906201000090046001600160a01b031681565b34801561060f57600080fd5b506103c4603281565b34801561062457600080fd5b5061045061063336600461462e565b6110c2565b34801561064457600080fd5b50600754610418906001600160a01b031681565b34801561066457600080fd5b506104506106733660046144c5565b6111a7565b34801561068457600080fd5b5061039b6106933660046144c5565b6115cf565b3480156106a457600080fd5b506104506106b33660046144c5565b611611565b3480156106c457600080fd5b506104186106d3366004614495565b6116c6565b3480156106e457600080fd5b506104186106f33660046144c5565b611760565b34801561070457600080fd5b506104506107133660046144fa565b6117ae565b34801561072457600080fd5b506104506107333660046144df565b61186d565b34801561074457600080fd5b506104506107533660046143f4565b6119a4565b34801561076457600080fd5b506107786107733660046141ff565b611e07565b6040519081526020016103a7565b34801561079257600080fd5b50610450611e9a565b3480156107a757600080fd5b506104506107b63660046145e8565b611ed0565b3480156107c757600080fd5b506104506107d63660046141ff565b611f3c565b3480156107e757600080fd5b506000546001600160a01b0316610418565b34801561080557600080fd5b506108196108143660046144c5565b611f88565b6040516103a796959493929190614902565b34801561083757600080fd5b5061039b6108463660046144c5565b63ffffffff1660011490565b34801561085e57600080fd5b506103eb612046565b34801561087357600080fd5b50610450610882366004614348565b612055565b34801561089357600080fd5b506108a76108a23660046144c5565b61211a565b6040516001600160801b0390911681526020016103a7565b3480156108cb57600080fd5b506104e56108da3660046144c5565b63ffffffff60201b1660011790565b3480156108f557600080fd5b506103c4600281565b61045061090c3660046142af565b61219a565b61045061091f3660046144c5565b6121eb565b34801561093057600080fd5b506108a761093f3660046144c5565b612584565b34801561095057600080fd5b506104e561095f3660046144c5565b612645565b34801561097057600080fd5b5061098461097f3660046144c5565b6126a2565b60405163ffffffff90911681526020016103a7565b3480156109a557600080fd5b506103eb6109b4366004614495565b6126f0565b3480156109c557600080fd5b5061039b6109d43660046144c5565b612801565b3480156109e557600080fd5b506004546103c490610100900460ff1681565b348015610a0457600080fd5b50610492610a133660046144c5565b612843565b348015610a2457600080fd5b5061039b610a33366004614237565b6001600160a01b039182166000908152600a6020908152604080832093909416825291909152205460ff1690565b348015610a6d57600080fd5b50600554610418906001600160a01b031681565b348015610a8d57600080fd5b50610984610a9c3660046144c5565b612891565b348015610aad57600080fd5b50610450610abc3660046141ff565b61289f565b348015610acd57600080fd5b506108a7610adc3660046144c5565b612937565b348015610aed57600080fd5b50610450610afc3660046145b6565b612986565b348015610b0d57600080fd5b50610450610b1c36600461462e565b612a95565b60006001600160e01b031982166380ac58cd60e01b1480610b5257506001600160e01b03198216635b5e139f60e01b145b80610b6d57506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060028054610b8290614ae5565b80601f0160208091040260200160405190810160405280929190818152602001828054610bae90614ae5565b8015610bfb5780601f10610bd057610100808354040283529160200191610bfb565b820191906000526020600020905b815481529060010190602001808311610bde57829003601f168201915b5050505050905090565b6000610c1361058583612b81565b610c385760405162461bcd60e51b8152600401610c2f906147b0565b60405180910390fd5b60096000610c4584612b81565b6001600160401b031681526020810191909152604001600020546001600160a01b031692915050565b6000610c79826116c6565b9050806001600160a01b0316836001600160a01b03161415610ce95760405162461bcd60e51b8152602060048201526024808201527f537061726b4c696e6b3a20417070726f76616c20746f2063757272656e74206f6044820152633bb732b960e11b6064820152608401610c2f565b336001600160a01b0382161480610d055750610d058133610a33565b610d775760405162461bcd60e51b815260206004820152603b60248201527f537061726b4c696e6b3a20417070726f76652063616c6c6572206973206e6f7460448201527f206f776e6572206e6f7220617070726f76656420666f7220616c6c00000000006064820152608401610c2f565b610d8983610d8484612b81565b612bee565b505050565b6000546001600160a01b03163314610db85760405162461bcd60e51b8152600401610c2f90614739565b600680546001600160a01b0319166001600160a01b0392909216919091179055565b6000610de582610fc5565b610e015760405162461bcd60e51b8152600401610c2f90614854565b63ffffffff60201b82166001176000908152600b602052604090205460281c61ffff16610b6d565b6000610e3482610fc5565b610e505760405162461bcd60e51b8152600401610c2f90614854565b60005b600163ffffffff841614610b6d57610e6c600182614995565b9050610e7783612645565b9250610e53565b610d898383610e8c84612b81565b612c64565b6000546001600160a01b03163314610ebb5760405162461bcd60e51b8152600401610c2f90614739565b600554604080516001600160a01b03928316815291831660208301527f586842069f184fa35046ea5d0a6cedce39f97f49ec80378f306649a0fba5116e910160405180910390a1600580546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610f4e5760405162461bcd60e51b8152600401610c2f90614739565b600454604080516001600160a01b03620100009093048316815291831660208301527f586842069f184fa35046ea5d0a6cedce39f97f49ec80378f306649a0fba5116e910160405180910390a1600480546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6001600160401b03166000908152600b60205260409020600101546001600160a01b0316151590565b6000610ff982610fc5565b6110155760405162461bcd60e51b8152600401610c2f90614854565b610b6d6025600b6000600163ffffffff60201b8716175b6001600160401b039081168252602082019290925260400160002054166001911c1690565b610d89838361105f84612b81565b6040518060200160405280600081525061308e565b600061107f82610fc5565b61109b5760405162461bcd60e51b8152600401610c2f90614854565b63ffffffff60201b82166001176000908152600b602052604090205460381c60ff16610b6d565b6000546001600160a01b031633146110ec5760405162461bcd60e51b8152600401610c2f90614739565b603260ff821611156111505760405162461bcd60e51b815260206004820152602760248201527f537061726b4c696e6b3a204c6f737320726174696f2063616e206e6f742062656044820152666c6f772035302560c81b6064820152608401610c2f565b6004546040805160ff928316815291831660208301527f10a39a3c3bf3e61b479ed61d38c739f7bbf3cfc3f209a3a2f45979992089afcb910160405180910390a16004805460ff191660ff92909216919091179055565b6111b081610fc5565b61120b5760405162461bcd60e51b815260206004820152602660248201527f537061726b4c696e6b3a20546869732065646974696f6e20646f6573206e6f7460448201526508195e1a5cdd60d21b6064820152608401610c2f565b6001600160401b0381166000908152600b6020526040902060030154600160801b90046001600160801b0316156115cc576001600160401b0381166000908152600b6020526040812060030154600160801b90046001600160801b03169061127283611760565b600454909150610100900460ff161561145c5760006112a083600460019054906101000a900460ff166130c7565b90506112ac8184614a3f565b92506001600160a01b03821661130c576004546040516001600160a01b036201000090920491909116906001600160801b03831680156108fc02916000818181858888f19350505050158015611306573d6000803e3d6000fd5b5061145a565b600754600654604080516315ab88c960e31b815290516000936001600160a01b039081169363e6a43905938893919092169163ad5c4648916004808301926020929190829003018186803b15801561136357600080fd5b505afa158015611377573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139b919061421b565b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260440160206040518083038186803b1580156113e157600080fd5b505afa1580156113f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611419919061421b565b6001600160a01b031614156114505760055461144b906001600160a01b0384811691166001600160801b0384166130e9565b61145a565b61145a828261314c565b505b6001600160401b0383166000908152600b6020526040902060030180546001600160801b0316905563ffffffff83166001146114c85760006114a6836114a186611074565b6130c7565b90506114ba6114b485612645565b82613352565b6114c48184614a3f565b9250505b6001600160a01b03811661152f576114e8836001600160401b03166116c6565b6001600160a01b03166108fc836001600160801b03169081150290604051600060405180830381858888f19350505050158015611529573d6000803e3d6000fd5b5061155e565b61155e611544846001600160401b03166116c6565b6001600160a01b038316906001600160801b0385166130e9565b611570836001600160401b03166116c6565b6001600160a01b0316836001600160401b03167f3dc1a77733195d8bbde8f8bc719f598f47f377c9c4b854d561b4d607a8e81f62846040516115c191906001600160801b0391909116815260200190565b60405180910390a350505b50565b60006115da82610fc5565b6115f65760405162461bcd60e51b8152600401610c2f90614854565b610b6d6027600b6000600163ffffffff60201b87161761102c565b336116246001600160401b0383166116c6565b6001600160a01b0316146116915760405162461bcd60e51b815260206004820152602e60248201527f537061726b4c696e6b3a204f6e6c79206f776e65722063616e2075706461746560448201526d2074686520746f6b656e2055524960901b6064820152608401610c2f565b63ffffffff60201b81166001176000908152600b60205260408082206002908101546001600160401b03909416835291200155565b600080600b60006116d685612b81565b6001600160401b031681526020810191909152604001600020600101546001600160a01b0316905080610b6d5760405162461bcd60e51b815260206004820152602c60248201527f537061726b4c696e6b3a204f776e657220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610c2f565b600061176b82610fc5565b6117875760405162461bcd60e51b8152600401610c2f90614854565b5063ffffffff602091821c166000908152600c90915260409020546001600160a01b031690565b336117c16001600160401b0384166116c6565b6001600160a01b0316146118285760405162461bcd60e51b815260206004820152602860248201527f537061726b4c696e6b3a204f6e6c79206f776e65722063616e206c6162656c206044820152671d1a1a5cc813919560c21b6064820152608401610c2f565b816001600160401b03167f07fabc8249b7822cdf933a532a49e1b0589177b1683b4145ee271dbd66700dfa826040516118619190614726565b60405180910390a25050565b611876826115cf565b15611919576001600160401b03821663ffffffff60201b8316600117146119195760405162461bcd60e51b815260206004820152604b60248201527f537061726b4c696e6b3a204e465420666f6c6c6f777320746865204e4420707260448201527f6f746f636f6c2c206f6e6c792074686520726f6f74204e46542773205552492060648201526a31b0b71031329039b2ba1760a91b608482015260a401610c2f565b3361192c6001600160401b0384166116c6565b6001600160a01b0316146119965760405162461bcd60e51b815260206004820152602b60248201527f537061726b4c696e6b3a204f6e6c79206f776e65722063616e2073657420746860448201526a6520746f6b656e2055524960a81b6064820152608401610c2f565b6119a082826133c4565b5050565b60648760ff161115611a0a5760405162461bcd60e51b815260206004820152602960248201527f537061726b4c696e6b3a20526f79616c7479206665652073686f756c64206265604482015268101e1e90189818129760b91b6064820152608401610c2f565b611a18600180546001019055565b63ffffffff611a2660015490565b1115611a855760405162461bcd60e51b815260206004820152602860248201527f537061726b4c696e6b3a2056616c756520646f65736e27742066697420696e206044820152671999103134ba399760c11b6064820152608401610c2f565b6001600160a01b03841615611b54576000846001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611acf57600080fd5b505afa158015611ae3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0791906144ad565b11611b545760405162461bcd60e51b815260206004820152601f60248201527f4e6f7420612076616c696420455243323020746f6b656e2061646472657373006044820152606401610c2f565b6000611b5f60015490565b9050600063ffffffff60201b602083901b166001179050611b926000338360405180602001604052806000815250613426565b611bae5760405162461bcd60e51b8152600401610c2f906147ff565b6001600160401b0381166000908152600b6020526040902064800000000019602686901b1664c000000000196420000000001960288c901b1666ffff20000000001960388e901b1617602589901b171617602785901b17611c10600182614995565b905087600c60008663ffffffff1663ffffffff16815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550808260000160006101000a8154816001600160401b0302191690836001600160401b03160217905550898260000160186101000a81548161ffff021916908361ffff1602179055508b8260000160086101000a8154816001600160801b0302191690836001600160801b03160217905550338260010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550888260020181905550600160086000336001600160a01b03166001600160a01b0316815260200190815260200160002060008282829054906101000a90046001600160401b0316611d419190614995565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550826001600160401b0316336001600160a01b031660006001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a46040516001600160a01b03891681526001600160401b0384169033907f072ee21d81ebd9fc5f68a2c36d04cbbd9eff1e2567a48dd7ecce61d5af159fad9060200160405180910390a3505050505050505050505050565b60006001600160a01b038216611e755760405162461bcd60e51b815260206004820152602d60248201527f537061726b4c696e6b3a2042616c616e636520717565727920666f722074686560448201526c207a65726f206164647265737360981b6064820152608401610c2f565b506001600160a01b03166000908152600860205260409020546001600160401b031690565b6000546001600160a01b03163314611ec45760405162461bcd60e51b8152600401610c2f90614739565b611ece6000613533565b565b611eda8383612986565b611eed81846001600160401b0316610c6e565b6040516001600160801b03831681526001600160a01b038216906001600160401b038516907ff4a029974225230e783a906bf72b4c1037aee2b37958b9a6b5e689da1477729b906020016115c1565b6000546001600160a01b03163314611f665760405162461bcd60e51b8152600401610c2f90614739565b600780546001600160a01b0319166001600160a01b0392909216919091179055565b60008060008060006060611f9b87610fc5565b611fb75760405162461bcd60e51b8152600401610c2f906147b0565b63ffffffff60201b87166001176000908152600b60205260409020546001600160401b0316611fe588612645565b6001600160401b0389166000908152600b6020526040902054600160401b90046001600160801b03166120178a612843565b6120208b612584565b6120328c6001600160401b03166126f0565b949c939b5091995097509550909350915050565b606060038054610b8290614ae5565b6001600160a01b0382163314156120ae5760405162461bcd60e51b815260206004820152601c60248201527f537061726b4c696e6b3a20417070726f766520746f2063616c6c6572000000006044820152606401610c2f565b336000818152600a602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600061212582610fc5565b6121415760405162461bcd60e51b8152600401610c2f90614854565b61214a82610fee565b801561215c5750600163ffffffff8316145b1561216957506000919050565b506001600160401b03166000908152600b6020526040902054600160401b90046001600160801b031690565b919050565b6121e485856121a886612b81565b85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061308e92505050565b5050505050565b6121f481610fc5565b6122105760405162461bcd60e51b8152600401610c2f9061476e565b6001600160401b0381166000908152600b6020526040902054600160c01b900461ffff166122a65760405162461bcd60e51b815260206004820152603860248201527f537061726b4c696e6b3a205468657265206973206e6f2072656d61696e696e6760448201527f207368696c6c2074696d6520666f722074686973204e465400000000000000006064820152608401610c2f565b600163ffffffff82161415806122c257506122c081610fee565b155b156124e55760006122d282611760565b90506001600160a01b03811661238b576001600160401b0382166000908152600b6020526040902054600160401b90046001600160801b031634146123525760405162461bcd60e51b8152602060048201526016602482015275537061726b4c696e6b3a2057726f6e6720707269636560501b6044820152606401610c2f565b6001600160401b0382166000908152600b6020526040902054612386908390600160401b90046001600160801b0316613352565b6124e3565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b1580156123cd57600080fd5b505afa1580156123e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061240591906144ad565b6001600160401b0384166000908152600b6020526040902054909150612449906001600160a01b0384169033903090600160401b90046001600160801b0316613583565b6040516370a0823160e01b81523060048201526124e19084906124dc9084906001600160a01b038716906370a08231906024015b60206040518083038186803b15801561249557600080fd5b505afa1580156124a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124cd91906144ad565b6124d79190614a82565b6135bb565b613352565b505b505b6001600160401b0381166000908152600b6020526040902080546001919060189061251c908490600160c01b900461ffff16614a67565b92506101000a81548161ffff021916908361ffff1602179055506125408133613625565b506001600160401b0381166000908152600b6020526040902054600160c01b900461ffff166115cc576119a08161257f836001600160401b03166116c6565b613625565b600061258f82610fc5565b6125ab5760405162461bcd60e51b8152600401610c2f90614854565b6001600160401b0382166000908152600b6020526040902060030154600454600160801b9091046001600160801b031690610100900460ff161561261457600061260482600460019054906101000a900460ff166130c7565b90506126108183614a3f565b9150505b600163ffffffff841614610b6d576000612631826114a186611074565b905061263d8183614a3f565b949350505050565b600061265082610fc5565b61266c5760405162461bcd60e51b8152600401610c2f90614854565b600163ffffffff8316141561268357506000919050565b506001600160401b039081166000908152600b60205260409020541690565b60006126ad82610fc5565b6126c95760405162461bcd60e51b8152600401610c2f90614854565b63ffffffff60201b82166001176000908152600b602052604090205463ffffffff16610b6d565b60606126fe61058583612b81565b61275d5760405162461bcd60e51b815260206004820152602a60248201527f537061726b4c696e6b3a2055524920717565727920666f72206e6f6e657869736044820152693a32b73a103a37b5b2b760b11b6064820152608401610c2f565b6000600b600061276c85612b81565b6001600160401b03166001600160401b03168152602001908152602001600020600201549050600061279d826138ea565b905060006127d360408051808201909152601581527468747470733a2f2f697066732e696f2f697066732f60581b602082015290565b905080826040516020016127e89291906146b2565b6040516020818303038152906040529350505050919050565b600061280c82610fc5565b6128285760405162461bcd60e51b8152600401610c2f90614854565b610b6d6026600b6000600163ffffffff60201b87161761102c565b600061284e82610fc5565b61286a5760405162461bcd60e51b8152600401610c2f90614854565b506001600160401b03166000908152600b6020526040902054600160c01b900461ffff1690565b600063ffffffff8216610b6d565b6000546001600160a01b031633146128c95760405162461bcd60e51b8152600401610c2f90614739565b6001600160a01b03811661292e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610c2f565b6115cc81613533565b600061294282610fc5565b61295e5760405162461bcd60e51b8152600401610c2f90614854565b506001600160401b03166000908152600b60205260409020600301546001600160801b031690565b61298f82610fc5565b6129ab5760405162461bcd60e51b8152600401610c2f9061476e565b6129bd826001600160401b03166116c6565b6001600160a01b0316336001600160a01b031614612a2d5760405162461bcd60e51b815260206004820152602760248201527f537061726b4c696e6b3a204f6e6c79206f776e65722063616e207365742074686044820152666520707269636560c81b6064820152608401610c2f565b6001600160401b0382166000818152600b602090815260409182902060030180546001600160801b0319166001600160801b03861690811790915591519182527fca72e8ac93611c80ca0e2046cbd0f09834fcca6a61e4979bd62bb6765ff7a9e79101611861565b6000546001600160a01b03163314612abf5760405162461bcd60e51b8152600401610c2f90614739565b600260ff82161115612b1f5760405162461bcd60e51b8152602060048201526024808201527f537061726b4c696e6b3a2044414f206665652063616e206e6f742065786365656044820152636420352560e01b6064820152608401610c2f565b6004546040805160ff6101009093048316815291831660208301527f2f8a36c4ca7c940e13833d1a596527b1ac691622a83cb1cf34d833d01efdeef3910160405180910390a16004805460ff9092166101000261ff0019909216919091179055565b60006001600160401b03821115612bea5760405162461bcd60e51b815260206004820152602760248201527f537061726b4c696e6b3a2056616c756520646f65736e27742066697420696e206044820152663634206269747360c81b6064820152608401610c2f565b5090565b6001600160401b038116600081815260096020526040902080546001600160a01b0319166001600160a01b038516908117909155612c2b826116c6565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b826001600160a01b0316612c80826001600160401b03166116c6565b6001600160a01b031614612ceb5760405162461bcd60e51b815260206004820152602c60248201527f537061726b4c696e6b3a205472616e73666572206f6620746f6b656e2074686160448201526b3a1034b9903737ba1037bbb760a11b6064820152608401610c2f565b612cf53382613b00565b612d5e5760405162461bcd60e51b815260206004820152603460248201527f537061726b4c696e6b3a205472616e736665722063616c6c6572206973206e6f6044820152731d081bdddb995c881b9bdc88185c1c1c9bdd995960621b6064820152608401610c2f565b6001600160a01b038216612dc45760405162461bcd60e51b815260206004820152602760248201527f537061726b4c696e6b3a205472616e7366657220746f20746865207a65726f206044820152666164647265737360c81b6064820152608401610c2f565b612dd6816001600160401b03166116c6565b6001600160a01b0316336001600160a01b031614612f7a576000612df982611760565b6001600160401b0383166000908152600b60205260409020600301549091506001600160801b03166001600160a01b038216612e9657806001600160801b03163414612e875760405162461bcd60e51b815260206004820152601860248201527f537061726b4c696e6b3a205072696365206e6f74206d657400000000000000006044820152606401610c2f565b612e918382613352565b612f6a565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a082319060240160206040518083038186803b158015612ed857600080fd5b505afa158015612eec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f1091906144ad565b9050612f306001600160a01b03841633306001600160801b038616613583565b6040516370a0823160e01b8152306004820152612f689085906124dc9084906001600160a01b038816906370a082319060240161247d565b505b612f73836111a7565b5050612f83565b612f83816111a7565b612f8c81613bfb565b6001600160a01b0383166000908152600860205260408120805460019290612fbe9084906001600160401b0316614a99565b82546101009290920a6001600160401b038181021990931691831602179091556001600160a01b0384166000908152600860205260408120805460019450909261300a91859116614995565b82546101009290920a6001600160401b0381810219909316918316021790915582166000818152600b602052604080822060010180546001600160a01b0319166001600160a01b0388811691821790925591519394509092908716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b613099848484612c64565b6130a584848484613426565b6130c15760405162461bcd60e51b8152600401610c2f906147ff565b50505050565b600060646130d860ff8416856149f1565b6130e291906149b7565b9392505050565b6040516001600160a01b038316602482015260448101829052610d8990849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613c30565b604080516002808252606082018352600092602083019080368337019050509050828160008151811061318f57634e487b7160e01b600052603260045260246000fd5b6001600160a01b03928316602091820292909201810191909152600654604080516315ab88c960e31b81529051919093169263ad5c4648926004808301939192829003018186803b1580156131e357600080fd5b505afa1580156131f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061321b919061421b565b8160018151811061323c57634e487b7160e01b600052603260045260246000fd5b6001600160a01b03928316602091820292909201015260065460405163095ea7b360e01b815290821660048201526001600160801b03841660248201529084169063095ea7b390604401602060405180830381600087803b1580156132a057600080fd5b505af11580156132b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d891906143a0565b506006546004805460405163791ac94760e01b81526001600160a01b039384169363791ac9479361331b9388936000938993620100009093041691429101614889565b600060405180830381600087803b15801561333557600080fd5b505af1158015613349573d6000803e3d6000fd5b50505050505050565b6001600160401b0382166000908152600b6020526040902060030154613389908290600160801b90046001600160801b031661495b565b6001600160401b039092166000908152600b6020526040902060030180546001600160801b03938416600160801b0293169290921790915550565b6001600160401b0382166000818152600b6020908152604091829020600201805490859055825181815291820185905292917f901ae3afe5e7d5594d462fab7cb487880c27d5fc0e3863487a5cfd2a08d350ed910160405180910390a2505050565b60006001600160a01b0384163b1561352857604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061346a9033908990889088906004016146e1565b602060405180830381600087803b15801561348457600080fd5b505af19250505080156134b4575060408051601f3d908101601f191682019092526134b1918101906143d8565b60015b61350e573d8080156134e2576040519150601f19603f3d011682016040523d82523d6000602084013e6134e7565b606091505b5080516135065760405162461bcd60e51b8152600401610c2f906147ff565b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905061263d565b506001949350505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040516001600160a01b03808516602483015283166044820152606481018290526130c19085906323b872dd60e01b90608401613115565b60006001600160801b03821115612bea5760405162461bcd60e51b815260206004820152602860248201527f537061726b4c696e6b3a2056616c756520646f65736e27742066697420696e20604482015267313238206269747360c01b6064820152608401610c2f565b600061363083613d02565b600061363b846126a2565b9050600063ffffffff60201b851663ffffffff831617905061366f6000858360405180602001604052806000815250613426565b61368b5760405162461bcd60e51b8152600401610c2f906147ff565b6001600160401b0381166000908152600b602052604090206136ac86610dda565b815479ffff00000000000000000000000000000000ffffffffffffffff1916600160c01b61ffff929092169190910267ffffffffffffffff1916176001600160401b0387161781556136fd86610fee565b801561370f5750600163ffffffff8716145b15613759576001600160401b0386166000908152600b60205260409020548154600160401b600160c01b031916600160401b918290046001600160801b03169091021781556137b9565b6001600160401b0386166000908152600b602052604090205460045461379291600160401b90046001600160801b03169060ff166130c7565b81546001600160801b0391909116600160401b02600160401b600160c01b03199091161781555b8054600160401b90046001600160801b0316613810576001600160401b0386166000908152600b60205260409020548154600160401b600160c01b031916600160401b918290046001600160801b03169091021781555b600181810180546001600160a01b0319166001600160a01b0388169081179091556001600160401b038881166000908152600b602090815260408083206002908101549088015593825260089052918220805490929161387291859116614995565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550816001600160401b0316856001600160a01b031660006001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a450949350505050565b60606000604051806040016040528060028152602001609160f51b8152508360405160200161391a929190614690565b60408051601f1981840301815281835261082083018252925060009190602082016108008036833701905050905060008160008151811061396b57634e487b7160e01b600052603260045260246000fd5b60ff90921660209283029190910190910152600160005b8351811015613adc5760008482815181106139ad57634e487b7160e01b600052603260045260246000fd5b016020015160f81c905060005b8360ff16811015613a63578481815181106139e557634e487b7160e01b600052603260045260246000fd5b602002602001015160ff166101006139fd9190614a20565b613a07908361497d565b9150613a14603a83614b5b565b858281518110613a3457634e487b7160e01b600052603260045260246000fd5b60ff90921660209283029190910190910152613a51603a836149dd565b9150613a5c81614b20565b90506139ba565b505b8015613acb57613a76603a82614b5b565b848460ff1681518110613a9957634e487b7160e01b600052603260045260246000fd5b60ff9092166020928302919091019091015282613ab581614b3b565b9350613ac49050603a826149dd565b9050613a65565b50613ad581614b20565b9050613982565b50613af7613af2613aed8484613dd2565b613ead565b613f9b565b95945050505050565b6000613b0b82610fc5565b613b6f5760405162461bcd60e51b815260206004820152602f60248201527f537061726b4c696e6b3a204f70657261746f7220717565727920666f72206e6f60448201526e3732bc34b9ba32b73a103a37b5b2b760891b6064820152608401610c2f565b6000613b83836001600160401b03166116c6565b9050806001600160a01b0316846001600160a01b03161480613bc75750836001600160a01b0316613bbc846001600160401b0316610c05565b6001600160a01b0316145b8061263d57506001600160a01b038082166000908152600a602090815260408083209388168352929052205460ff1661263d565b613c06600082612bee565b6001600160401b03166000908152600b6020526040902060030180546001600160801b0319169055565b6000613c85826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166140b59092919063ffffffff16565b805190915015610d895780806020019051810190613ca391906143a0565b610d895760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610c2f565b63ffffffff613d10826126a2565b63ffffffff1610613d765760405162461bcd60e51b815260206004820152602a60248201527f537061726b4c696e6b3a205468657265206973206e6f206c65667420696e20746044820152693434b99034b9b9bab29760b11b6064820152608401610c2f565b600163ffffffff60201b821681176000908152600b602052604081208054909190613dab9084906001600160401b0316614995565b92506101000a8154816001600160401b0302191690836001600160401b0316021790555050565b606060008260ff166001600160401b03811115613dff57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015613e28578160200160208202803683370190505b50905060005b8360ff16811015613ea557848181518110613e5957634e487b7160e01b600052603260045260246000fd5b6020026020010151828281518110613e8157634e487b7160e01b600052603260045260246000fd5b60ff9092166020928302919091019091015280613e9d81614b20565b915050613e2e565b509392505050565b6060600082516001600160401b03811115613ed857634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015613f01578160200160208202803683370190505b50905060005b8351811015613f9457838160018651613f209190614a82565b613f2a9190614a82565b81518110613f4857634e487b7160e01b600052603260045260246000fd5b6020026020010151828281518110613f7057634e487b7160e01b600052603260045260246000fd5b60ff9092166020928302919091019091015280613f8c81614b20565b915050613f07565b5092915050565b6060600082516001600160401b03811115613fc657634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015613ff0576020820181803683370190505b50905060005b8351811015613f94576040518060600160405280603a8152602001614beb603a913984828151811061403857634e487b7160e01b600052603260045260246000fd5b602002602001015160ff168151811061406157634e487b7160e01b600052603260045260246000fd5b602001015160f81c60f81b82828151811061408c57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a905350806140ad81614b20565b915050613ff6565b606061263d848460008585843b61410e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c2f565b600080866001600160a01b0316858760405161412a9190614674565b60006040518083038185875af1925050503d8060008114614167576040519150601f19603f3d011682016040523d82523d6000602084013e61416c565b606091505b509150915061417c828286614187565b979650505050505050565b606083156141965750816130e2565b8251156141a65782518084602001fd5b8160405162461bcd60e51b8152600401610c2f9190614726565b80356001600160801b038116811461219557600080fd5b80356001600160401b038116811461219557600080fd5b803560ff8116811461219557600080fd5b600060208284031215614210578081fd5b81356130e281614bb1565b60006020828403121561422c578081fd5b81516130e281614bb1565b60008060408385031215614249578081fd5b823561425481614bb1565b9150602083013561426481614bb1565b809150509250929050565b600080600060608486031215614283578081fd5b833561428e81614bb1565b9250602084013561429e81614bb1565b929592945050506040919091013590565b6000806000806000608086880312156142c6578081fd5b85356142d181614bb1565b945060208601356142e181614bb1565b93506040860135925060608601356001600160401b0380821115614303578283fd5b818801915088601f830112614316578283fd5b813581811115614324578384fd5b896020828501011115614335578384fd5b9699959850939650602001949392505050565b6000806040838503121561435a578182fd5b823561436581614bb1565b9150602083013561426481614bc6565b60008060408385031215614387578182fd5b823561439281614bb1565b946020939093013593505050565b6000602082840312156143b1578081fd5b81516130e281614bc6565b6000602082840312156143cd578081fd5b81356130e281614bd4565b6000602082840312156143e9578081fd5b81516130e281614bd4565b600080600080600080600080610100898b031215614410578283fd5b614419896141c0565b975061442760208a016141ee565b9650604089013561ffff8116811461443d578384fd5b955060608901359450608089013561445481614bb1565b935060a089013561446481614bc6565b925060c089013561447481614bc6565b915060e089013561448481614bc6565b809150509295985092959890939650565b6000602082840312156144a6578081fd5b5035919050565b6000602082840312156144be578081fd5b5051919050565b6000602082840312156144d6578081fd5b6130e2826141d7565b600080604083850312156144f1578182fd5b614392836141d7565b6000806040838503121561450c578182fd5b614515836141d7565b915060208301356001600160401b0380821115614530578283fd5b818501915085601f830112614543578283fd5b81358181111561455557614555614b9b565b604051601f8201601f19908116603f0116810190838211818310171561457d5761457d614b9b565b81604052828152886020848701011115614595578586fd5b82602086016020830137856020848301015280955050505050509250929050565b600080604083850312156145c8578182fd5b6145d1836141d7565b91506145df602084016141c0565b90509250929050565b6000806000606084860312156145fc578081fd5b614605846141d7565b9250614613602085016141c0565b9150604084013561462381614bb1565b809150509250925092565b60006020828403121561463f578081fd5b6130e2826141ee565b60008151808452614660816020860160208601614ab9565b601f01601f19169290920160200192915050565b60008251614686818460208701614ab9565b9190910192915050565b600083516146a2818460208801614ab9565b9190910191825250602001919050565b600083516146c4818460208801614ab9565b8351908301906146d8818360208801614ab9565b01949350505050565b6001600160a01b038581168252841660208201526001600160401b038316604082015260806060820181905260009061471c90830184614648565b9695505050505050565b6020815260006130e26020830184614648565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526022908201527f537061726b4c696e6b3a2054686973204e465420646f6573206e6f74206578696040820152611cdd60f21b606082015260800190565b6020808252602f908201527f537061726b4c696e6b3a20417070726f76656420717565727920666f72206e6f60408201526e3732bc34b9ba32b73a103a37b5b2b760891b606082015260800190565b60208082526035908201527f537061726b4c696e6b3a205472616e7366657220746f206e6f6e20455243373260408201527418a932b1b2b4bb32b91034b6b83632b6b2b73a32b960591b606082015260800190565b6020808252818101527f537061726b4c696e6b3a2045646974696f6e206973206e6f742065786973742e604082015260600190565b600060a082016001600160801b03881683526020878185015260a0604085015281875180845260c0860191508289019350845b818110156148e15784516001600160a01b0316835293830193918301916001016148bc565b50506001600160a01b03969096166060850152505050608001529392505050565b6001600160401b038781168252861660208201526001600160801b03858116604083015261ffff851660608301528316608082015260c060a0820181905260009061494f90830184614648565b98975050505050505050565b60006001600160801b038083168185168083038211156146d8576146d8614b6f565b6000821982111561499057614990614b6f565b500190565b60006001600160401b038083168185168083038211156146d8576146d8614b6f565b60006001600160801b03808416806149d1576149d1614b85565b92169190910492915050565b6000826149ec576149ec614b85565b500490565b60006001600160801b0380831681851681830481118215151615614a1757614a17614b6f565b02949350505050565b6000816000190483118215151615614a3a57614a3a614b6f565b500290565b60006001600160801b0383811690831681811015614a5f57614a5f614b6f565b039392505050565b600061ffff83811690831681811015614a5f57614a5f614b6f565b600082821015614a9457614a94614b6f565b500390565b60006001600160401b0383811690831681811015614a5f57614a5f614b6f565b60005b83811015614ad4578181015183820152602001614abc565b838111156130c15750506000910152565b600181811c90821680614af957607f821691505b60208210811415614b1a57634e487b7160e01b600052602260045260246000fd5b50919050565b6000600019821415614b3457614b34614b6f565b5060010190565b600060ff821660ff811415614b5257614b52614b6f565b60010192915050565b600082614b6a57614b6a614b85565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146115cc57600080fd5b80151581146115cc57600080fd5b6001600160e01b0319811681146115cc57600080fdfe31323334353637383941424344454647484a4b4c4d4e505152535455565758595a6162636465666768696a6b6d6e6f707172737475767778797aa2646970667358221220933f6f737a354378b11fa0569b363a10f31397d3f42d4be2a8b4cad33b3ab02164736f6c63430008040033", - "deployedBytecode": "0x6080604052600436106103765760003560e01c80637098da84116101d1578063bbe07d7911610102578063d8d17e79116100a0578063f2fde38b1161006f578063f2fde38b14610aa1578063f6e9274d14610ac1578063fee0329914610ae1578063ff0eac4514610b0157600080fd5b8063d8d17e79146109f8578063e985e9c514610a18578063e9a5a37214610a61578063f1ac67d314610a8157600080fd5b8063bf1a9657116100dc578063bf1a965714610964578063c87b56dd14610999578063ce51ba90146109b9578063cfc02f5f146109d957600080fd5b8063bbe07d7914610911578063bd3355ed14610924578063bdea26fa1461094457600080fd5b806392e6f9ac1161016f578063a7c9e88111610149578063a7c9e88114610887578063ac03d001146108bf578063ae72e098146108e9578063b88d4fde146108fe57600080fd5b806392e6f9ac1461082b57806395d89b4114610852578063a22cb4651461086757600080fd5b806377738ad2116101ab57806377738ad21461079b5780638ba51d61146107bb5780638da5cb5b146107db578063927ef546146107f957600080fd5b80637098da841461073857806370a0823114610758578063715018a61461078657600080fd5b806330999f7b116102ab5780635a034b3b116102495780636352211e116102235780636352211e146106b85780636579aea2146106d857806365cb8c93146106f8578063668432081461071857600080fd5b80635a034b3b14610658578063600f11db1461067857806361bc8a531461069857600080fd5b80634940df03116102855780634940df03146105dd57806350614e191461060357806358d400cb1461061857806359d0f7131461063857600080fd5b806330999f7b1461058a57806342842e0e146105aa57806347bb0958146105bd57600080fd5b80631694505e1161031857806324d4401a116102f257806324d4401a146105105780632524ba4d146105305780632b56a1c2146105505780632b9e0d721461056a57600080fd5b80631694505e146104a55780631dab1af7146104c557806323b872dd146104fd57600080fd5b8063081812fc11610354578063081812fc146103f8578063095ea7b3146104305780631419841d1461045257806316468b5c1461047257600080fd5b806301ffc9a71461037b5780630292ec36146103b057806306fdde03146103d6575b600080fd5b34801561038757600080fd5b5061039b6103963660046143bc565b610b21565b60405190151581526020015b60405180910390f35b3480156103bc57600080fd5b5060045460ff165b60405160ff90911681526020016103a7565b3480156103e257600080fd5b506103eb610b73565b6040516103a79190614726565b34801561040457600080fd5b50610418610413366004614495565b610c05565b6040516001600160a01b0390911681526020016103a7565b34801561043c57600080fd5b5061045061044b366004614375565b610c6e565b005b34801561045e57600080fd5b5061045061046d3660046141ff565b610d8e565b34801561047e57600080fd5b5061049261048d3660046144c5565b610dda565b60405161ffff90911681526020016103a7565b3480156104b157600080fd5b50600654610418906001600160a01b031681565b3480156104d157600080fd5b506104e56104e03660046144c5565b610e29565b6040516001600160401b0390911681526020016103a7565b61045061050b36600461426f565b610e7e565b34801561051c57600080fd5b5061045061052b3660046141ff565b610e91565b34801561053c57600080fd5b5061045061054b3660046141ff565b610f24565b34801561055c57600080fd5b506004546103c49060ff1681565b34801561057657600080fd5b5061039b6105853660046144c5565b610fc5565b34801561059657600080fd5b5061039b6105a53660046144c5565b610fee565b6104506105b836600461426f565b611051565b3480156105c957600080fd5b506103c46105d83660046144c5565b611074565b3480156105e957600080fd5b50600454610418906201000090046001600160a01b031681565b34801561060f57600080fd5b506103c4603281565b34801561062457600080fd5b5061045061063336600461462e565b6110c2565b34801561064457600080fd5b50600754610418906001600160a01b031681565b34801561066457600080fd5b506104506106733660046144c5565b6111a7565b34801561068457600080fd5b5061039b6106933660046144c5565b6115cf565b3480156106a457600080fd5b506104506106b33660046144c5565b611611565b3480156106c457600080fd5b506104186106d3366004614495565b6116c6565b3480156106e457600080fd5b506104186106f33660046144c5565b611760565b34801561070457600080fd5b506104506107133660046144fa565b6117ae565b34801561072457600080fd5b506104506107333660046144df565b61186d565b34801561074457600080fd5b506104506107533660046143f4565b6119a4565b34801561076457600080fd5b506107786107733660046141ff565b611e07565b6040519081526020016103a7565b34801561079257600080fd5b50610450611e9a565b3480156107a757600080fd5b506104506107b63660046145e8565b611ed0565b3480156107c757600080fd5b506104506107d63660046141ff565b611f3c565b3480156107e757600080fd5b506000546001600160a01b0316610418565b34801561080557600080fd5b506108196108143660046144c5565b611f88565b6040516103a796959493929190614902565b34801561083757600080fd5b5061039b6108463660046144c5565b63ffffffff1660011490565b34801561085e57600080fd5b506103eb612046565b34801561087357600080fd5b50610450610882366004614348565b612055565b34801561089357600080fd5b506108a76108a23660046144c5565b61211a565b6040516001600160801b0390911681526020016103a7565b3480156108cb57600080fd5b506104e56108da3660046144c5565b63ffffffff60201b1660011790565b3480156108f557600080fd5b506103c4600281565b61045061090c3660046142af565b61219a565b61045061091f3660046144c5565b6121eb565b34801561093057600080fd5b506108a761093f3660046144c5565b612584565b34801561095057600080fd5b506104e561095f3660046144c5565b612645565b34801561097057600080fd5b5061098461097f3660046144c5565b6126a2565b60405163ffffffff90911681526020016103a7565b3480156109a557600080fd5b506103eb6109b4366004614495565b6126f0565b3480156109c557600080fd5b5061039b6109d43660046144c5565b612801565b3480156109e557600080fd5b506004546103c490610100900460ff1681565b348015610a0457600080fd5b50610492610a133660046144c5565b612843565b348015610a2457600080fd5b5061039b610a33366004614237565b6001600160a01b039182166000908152600a6020908152604080832093909416825291909152205460ff1690565b348015610a6d57600080fd5b50600554610418906001600160a01b031681565b348015610a8d57600080fd5b50610984610a9c3660046144c5565b612891565b348015610aad57600080fd5b50610450610abc3660046141ff565b61289f565b348015610acd57600080fd5b506108a7610adc3660046144c5565b612937565b348015610aed57600080fd5b50610450610afc3660046145b6565b612986565b348015610b0d57600080fd5b50610450610b1c36600461462e565b612a95565b60006001600160e01b031982166380ac58cd60e01b1480610b5257506001600160e01b03198216635b5e139f60e01b145b80610b6d57506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060028054610b8290614ae5565b80601f0160208091040260200160405190810160405280929190818152602001828054610bae90614ae5565b8015610bfb5780601f10610bd057610100808354040283529160200191610bfb565b820191906000526020600020905b815481529060010190602001808311610bde57829003601f168201915b5050505050905090565b6000610c1361058583612b81565b610c385760405162461bcd60e51b8152600401610c2f906147b0565b60405180910390fd5b60096000610c4584612b81565b6001600160401b031681526020810191909152604001600020546001600160a01b031692915050565b6000610c79826116c6565b9050806001600160a01b0316836001600160a01b03161415610ce95760405162461bcd60e51b8152602060048201526024808201527f537061726b4c696e6b3a20417070726f76616c20746f2063757272656e74206f6044820152633bb732b960e11b6064820152608401610c2f565b336001600160a01b0382161480610d055750610d058133610a33565b610d775760405162461bcd60e51b815260206004820152603b60248201527f537061726b4c696e6b3a20417070726f76652063616c6c6572206973206e6f7460448201527f206f776e6572206e6f7220617070726f76656420666f7220616c6c00000000006064820152608401610c2f565b610d8983610d8484612b81565b612bee565b505050565b6000546001600160a01b03163314610db85760405162461bcd60e51b8152600401610c2f90614739565b600680546001600160a01b0319166001600160a01b0392909216919091179055565b6000610de582610fc5565b610e015760405162461bcd60e51b8152600401610c2f90614854565b63ffffffff60201b82166001176000908152600b602052604090205460281c61ffff16610b6d565b6000610e3482610fc5565b610e505760405162461bcd60e51b8152600401610c2f90614854565b60005b600163ffffffff841614610b6d57610e6c600182614995565b9050610e7783612645565b9250610e53565b610d898383610e8c84612b81565b612c64565b6000546001600160a01b03163314610ebb5760405162461bcd60e51b8152600401610c2f90614739565b600554604080516001600160a01b03928316815291831660208301527f586842069f184fa35046ea5d0a6cedce39f97f49ec80378f306649a0fba5116e910160405180910390a1600580546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610f4e5760405162461bcd60e51b8152600401610c2f90614739565b600454604080516001600160a01b03620100009093048316815291831660208301527f586842069f184fa35046ea5d0a6cedce39f97f49ec80378f306649a0fba5116e910160405180910390a1600480546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6001600160401b03166000908152600b60205260409020600101546001600160a01b0316151590565b6000610ff982610fc5565b6110155760405162461bcd60e51b8152600401610c2f90614854565b610b6d6025600b6000600163ffffffff60201b8716175b6001600160401b039081168252602082019290925260400160002054166001911c1690565b610d89838361105f84612b81565b6040518060200160405280600081525061308e565b600061107f82610fc5565b61109b5760405162461bcd60e51b8152600401610c2f90614854565b63ffffffff60201b82166001176000908152600b602052604090205460381c60ff16610b6d565b6000546001600160a01b031633146110ec5760405162461bcd60e51b8152600401610c2f90614739565b603260ff821611156111505760405162461bcd60e51b815260206004820152602760248201527f537061726b4c696e6b3a204c6f737320726174696f2063616e206e6f742062656044820152666c6f772035302560c81b6064820152608401610c2f565b6004546040805160ff928316815291831660208301527f10a39a3c3bf3e61b479ed61d38c739f7bbf3cfc3f209a3a2f45979992089afcb910160405180910390a16004805460ff191660ff92909216919091179055565b6111b081610fc5565b61120b5760405162461bcd60e51b815260206004820152602660248201527f537061726b4c696e6b3a20546869732065646974696f6e20646f6573206e6f7460448201526508195e1a5cdd60d21b6064820152608401610c2f565b6001600160401b0381166000908152600b6020526040902060030154600160801b90046001600160801b0316156115cc576001600160401b0381166000908152600b6020526040812060030154600160801b90046001600160801b03169061127283611760565b600454909150610100900460ff161561145c5760006112a083600460019054906101000a900460ff166130c7565b90506112ac8184614a3f565b92506001600160a01b03821661130c576004546040516001600160a01b036201000090920491909116906001600160801b03831680156108fc02916000818181858888f19350505050158015611306573d6000803e3d6000fd5b5061145a565b600754600654604080516315ab88c960e31b815290516000936001600160a01b039081169363e6a43905938893919092169163ad5c4648916004808301926020929190829003018186803b15801561136357600080fd5b505afa158015611377573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139b919061421b565b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260440160206040518083038186803b1580156113e157600080fd5b505afa1580156113f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611419919061421b565b6001600160a01b031614156114505760055461144b906001600160a01b0384811691166001600160801b0384166130e9565b61145a565b61145a828261314c565b505b6001600160401b0383166000908152600b6020526040902060030180546001600160801b0316905563ffffffff83166001146114c85760006114a6836114a186611074565b6130c7565b90506114ba6114b485612645565b82613352565b6114c48184614a3f565b9250505b6001600160a01b03811661152f576114e8836001600160401b03166116c6565b6001600160a01b03166108fc836001600160801b03169081150290604051600060405180830381858888f19350505050158015611529573d6000803e3d6000fd5b5061155e565b61155e611544846001600160401b03166116c6565b6001600160a01b038316906001600160801b0385166130e9565b611570836001600160401b03166116c6565b6001600160a01b0316836001600160401b03167f3dc1a77733195d8bbde8f8bc719f598f47f377c9c4b854d561b4d607a8e81f62846040516115c191906001600160801b0391909116815260200190565b60405180910390a350505b50565b60006115da82610fc5565b6115f65760405162461bcd60e51b8152600401610c2f90614854565b610b6d6027600b6000600163ffffffff60201b87161761102c565b336116246001600160401b0383166116c6565b6001600160a01b0316146116915760405162461bcd60e51b815260206004820152602e60248201527f537061726b4c696e6b3a204f6e6c79206f776e65722063616e2075706461746560448201526d2074686520746f6b656e2055524960901b6064820152608401610c2f565b63ffffffff60201b81166001176000908152600b60205260408082206002908101546001600160401b03909416835291200155565b600080600b60006116d685612b81565b6001600160401b031681526020810191909152604001600020600101546001600160a01b0316905080610b6d5760405162461bcd60e51b815260206004820152602c60248201527f537061726b4c696e6b3a204f776e657220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610c2f565b600061176b82610fc5565b6117875760405162461bcd60e51b8152600401610c2f90614854565b5063ffffffff602091821c166000908152600c90915260409020546001600160a01b031690565b336117c16001600160401b0384166116c6565b6001600160a01b0316146118285760405162461bcd60e51b815260206004820152602860248201527f537061726b4c696e6b3a204f6e6c79206f776e65722063616e206c6162656c206044820152671d1a1a5cc813919560c21b6064820152608401610c2f565b816001600160401b03167f07fabc8249b7822cdf933a532a49e1b0589177b1683b4145ee271dbd66700dfa826040516118619190614726565b60405180910390a25050565b611876826115cf565b15611919576001600160401b03821663ffffffff60201b8316600117146119195760405162461bcd60e51b815260206004820152604b60248201527f537061726b4c696e6b3a204e465420666f6c6c6f777320746865204e4420707260448201527f6f746f636f6c2c206f6e6c792074686520726f6f74204e46542773205552492060648201526a31b0b71031329039b2ba1760a91b608482015260a401610c2f565b3361192c6001600160401b0384166116c6565b6001600160a01b0316146119965760405162461bcd60e51b815260206004820152602b60248201527f537061726b4c696e6b3a204f6e6c79206f776e65722063616e2073657420746860448201526a6520746f6b656e2055524960a81b6064820152608401610c2f565b6119a082826133c4565b5050565b60648760ff161115611a0a5760405162461bcd60e51b815260206004820152602960248201527f537061726b4c696e6b3a20526f79616c7479206665652073686f756c64206265604482015268101e1e90189818129760b91b6064820152608401610c2f565b611a18600180546001019055565b63ffffffff611a2660015490565b1115611a855760405162461bcd60e51b815260206004820152602860248201527f537061726b4c696e6b3a2056616c756520646f65736e27742066697420696e206044820152671999103134ba399760c11b6064820152608401610c2f565b6001600160a01b03841615611b54576000846001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611acf57600080fd5b505afa158015611ae3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0791906144ad565b11611b545760405162461bcd60e51b815260206004820152601f60248201527f4e6f7420612076616c696420455243323020746f6b656e2061646472657373006044820152606401610c2f565b6000611b5f60015490565b9050600063ffffffff60201b602083901b166001179050611b926000338360405180602001604052806000815250613426565b611bae5760405162461bcd60e51b8152600401610c2f906147ff565b6001600160401b0381166000908152600b6020526040902064800000000019602686901b1664c000000000196420000000001960288c901b1666ffff20000000001960388e901b1617602589901b171617602785901b17611c10600182614995565b905087600c60008663ffffffff1663ffffffff16815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550808260000160006101000a8154816001600160401b0302191690836001600160401b03160217905550898260000160186101000a81548161ffff021916908361ffff1602179055508b8260000160086101000a8154816001600160801b0302191690836001600160801b03160217905550338260010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550888260020181905550600160086000336001600160a01b03166001600160a01b0316815260200190815260200160002060008282829054906101000a90046001600160401b0316611d419190614995565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550826001600160401b0316336001600160a01b031660006001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a46040516001600160a01b03891681526001600160401b0384169033907f072ee21d81ebd9fc5f68a2c36d04cbbd9eff1e2567a48dd7ecce61d5af159fad9060200160405180910390a3505050505050505050505050565b60006001600160a01b038216611e755760405162461bcd60e51b815260206004820152602d60248201527f537061726b4c696e6b3a2042616c616e636520717565727920666f722074686560448201526c207a65726f206164647265737360981b6064820152608401610c2f565b506001600160a01b03166000908152600860205260409020546001600160401b031690565b6000546001600160a01b03163314611ec45760405162461bcd60e51b8152600401610c2f90614739565b611ece6000613533565b565b611eda8383612986565b611eed81846001600160401b0316610c6e565b6040516001600160801b03831681526001600160a01b038216906001600160401b038516907ff4a029974225230e783a906bf72b4c1037aee2b37958b9a6b5e689da1477729b906020016115c1565b6000546001600160a01b03163314611f665760405162461bcd60e51b8152600401610c2f90614739565b600780546001600160a01b0319166001600160a01b0392909216919091179055565b60008060008060006060611f9b87610fc5565b611fb75760405162461bcd60e51b8152600401610c2f906147b0565b63ffffffff60201b87166001176000908152600b60205260409020546001600160401b0316611fe588612645565b6001600160401b0389166000908152600b6020526040902054600160401b90046001600160801b03166120178a612843565b6120208b612584565b6120328c6001600160401b03166126f0565b949c939b5091995097509550909350915050565b606060038054610b8290614ae5565b6001600160a01b0382163314156120ae5760405162461bcd60e51b815260206004820152601c60248201527f537061726b4c696e6b3a20417070726f766520746f2063616c6c6572000000006044820152606401610c2f565b336000818152600a602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600061212582610fc5565b6121415760405162461bcd60e51b8152600401610c2f90614854565b61214a82610fee565b801561215c5750600163ffffffff8316145b1561216957506000919050565b506001600160401b03166000908152600b6020526040902054600160401b90046001600160801b031690565b919050565b6121e485856121a886612b81565b85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061308e92505050565b5050505050565b6121f481610fc5565b6122105760405162461bcd60e51b8152600401610c2f9061476e565b6001600160401b0381166000908152600b6020526040902054600160c01b900461ffff166122a65760405162461bcd60e51b815260206004820152603860248201527f537061726b4c696e6b3a205468657265206973206e6f2072656d61696e696e6760448201527f207368696c6c2074696d6520666f722074686973204e465400000000000000006064820152608401610c2f565b600163ffffffff82161415806122c257506122c081610fee565b155b156124e55760006122d282611760565b90506001600160a01b03811661238b576001600160401b0382166000908152600b6020526040902054600160401b90046001600160801b031634146123525760405162461bcd60e51b8152602060048201526016602482015275537061726b4c696e6b3a2057726f6e6720707269636560501b6044820152606401610c2f565b6001600160401b0382166000908152600b6020526040902054612386908390600160401b90046001600160801b0316613352565b6124e3565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b1580156123cd57600080fd5b505afa1580156123e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061240591906144ad565b6001600160401b0384166000908152600b6020526040902054909150612449906001600160a01b0384169033903090600160401b90046001600160801b0316613583565b6040516370a0823160e01b81523060048201526124e19084906124dc9084906001600160a01b038716906370a08231906024015b60206040518083038186803b15801561249557600080fd5b505afa1580156124a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124cd91906144ad565b6124d79190614a82565b6135bb565b613352565b505b505b6001600160401b0381166000908152600b6020526040902080546001919060189061251c908490600160c01b900461ffff16614a67565b92506101000a81548161ffff021916908361ffff1602179055506125408133613625565b506001600160401b0381166000908152600b6020526040902054600160c01b900461ffff166115cc576119a08161257f836001600160401b03166116c6565b613625565b600061258f82610fc5565b6125ab5760405162461bcd60e51b8152600401610c2f90614854565b6001600160401b0382166000908152600b6020526040902060030154600454600160801b9091046001600160801b031690610100900460ff161561261457600061260482600460019054906101000a900460ff166130c7565b90506126108183614a3f565b9150505b600163ffffffff841614610b6d576000612631826114a186611074565b905061263d8183614a3f565b949350505050565b600061265082610fc5565b61266c5760405162461bcd60e51b8152600401610c2f90614854565b600163ffffffff8316141561268357506000919050565b506001600160401b039081166000908152600b60205260409020541690565b60006126ad82610fc5565b6126c95760405162461bcd60e51b8152600401610c2f90614854565b63ffffffff60201b82166001176000908152600b602052604090205463ffffffff16610b6d565b60606126fe61058583612b81565b61275d5760405162461bcd60e51b815260206004820152602a60248201527f537061726b4c696e6b3a2055524920717565727920666f72206e6f6e657869736044820152693a32b73a103a37b5b2b760b11b6064820152608401610c2f565b6000600b600061276c85612b81565b6001600160401b03166001600160401b03168152602001908152602001600020600201549050600061279d826138ea565b905060006127d360408051808201909152601581527468747470733a2f2f697066732e696f2f697066732f60581b602082015290565b905080826040516020016127e89291906146b2565b6040516020818303038152906040529350505050919050565b600061280c82610fc5565b6128285760405162461bcd60e51b8152600401610c2f90614854565b610b6d6026600b6000600163ffffffff60201b87161761102c565b600061284e82610fc5565b61286a5760405162461bcd60e51b8152600401610c2f90614854565b506001600160401b03166000908152600b6020526040902054600160c01b900461ffff1690565b600063ffffffff8216610b6d565b6000546001600160a01b031633146128c95760405162461bcd60e51b8152600401610c2f90614739565b6001600160a01b03811661292e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610c2f565b6115cc81613533565b600061294282610fc5565b61295e5760405162461bcd60e51b8152600401610c2f90614854565b506001600160401b03166000908152600b60205260409020600301546001600160801b031690565b61298f82610fc5565b6129ab5760405162461bcd60e51b8152600401610c2f9061476e565b6129bd826001600160401b03166116c6565b6001600160a01b0316336001600160a01b031614612a2d5760405162461bcd60e51b815260206004820152602760248201527f537061726b4c696e6b3a204f6e6c79206f776e65722063616e207365742074686044820152666520707269636560c81b6064820152608401610c2f565b6001600160401b0382166000818152600b602090815260409182902060030180546001600160801b0319166001600160801b03861690811790915591519182527fca72e8ac93611c80ca0e2046cbd0f09834fcca6a61e4979bd62bb6765ff7a9e79101611861565b6000546001600160a01b03163314612abf5760405162461bcd60e51b8152600401610c2f90614739565b600260ff82161115612b1f5760405162461bcd60e51b8152602060048201526024808201527f537061726b4c696e6b3a2044414f206665652063616e206e6f742065786365656044820152636420352560e01b6064820152608401610c2f565b6004546040805160ff6101009093048316815291831660208301527f2f8a36c4ca7c940e13833d1a596527b1ac691622a83cb1cf34d833d01efdeef3910160405180910390a16004805460ff9092166101000261ff0019909216919091179055565b60006001600160401b03821115612bea5760405162461bcd60e51b815260206004820152602760248201527f537061726b4c696e6b3a2056616c756520646f65736e27742066697420696e206044820152663634206269747360c81b6064820152608401610c2f565b5090565b6001600160401b038116600081815260096020526040902080546001600160a01b0319166001600160a01b038516908117909155612c2b826116c6565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b826001600160a01b0316612c80826001600160401b03166116c6565b6001600160a01b031614612ceb5760405162461bcd60e51b815260206004820152602c60248201527f537061726b4c696e6b3a205472616e73666572206f6620746f6b656e2074686160448201526b3a1034b9903737ba1037bbb760a11b6064820152608401610c2f565b612cf53382613b00565b612d5e5760405162461bcd60e51b815260206004820152603460248201527f537061726b4c696e6b3a205472616e736665722063616c6c6572206973206e6f6044820152731d081bdddb995c881b9bdc88185c1c1c9bdd995960621b6064820152608401610c2f565b6001600160a01b038216612dc45760405162461bcd60e51b815260206004820152602760248201527f537061726b4c696e6b3a205472616e7366657220746f20746865207a65726f206044820152666164647265737360c81b6064820152608401610c2f565b612dd6816001600160401b03166116c6565b6001600160a01b0316336001600160a01b031614612f7a576000612df982611760565b6001600160401b0383166000908152600b60205260409020600301549091506001600160801b03166001600160a01b038216612e9657806001600160801b03163414612e875760405162461bcd60e51b815260206004820152601860248201527f537061726b4c696e6b3a205072696365206e6f74206d657400000000000000006044820152606401610c2f565b612e918382613352565b612f6a565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a082319060240160206040518083038186803b158015612ed857600080fd5b505afa158015612eec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f1091906144ad565b9050612f306001600160a01b03841633306001600160801b038616613583565b6040516370a0823160e01b8152306004820152612f689085906124dc9084906001600160a01b038816906370a082319060240161247d565b505b612f73836111a7565b5050612f83565b612f83816111a7565b612f8c81613bfb565b6001600160a01b0383166000908152600860205260408120805460019290612fbe9084906001600160401b0316614a99565b82546101009290920a6001600160401b038181021990931691831602179091556001600160a01b0384166000908152600860205260408120805460019450909261300a91859116614995565b82546101009290920a6001600160401b0381810219909316918316021790915582166000818152600b602052604080822060010180546001600160a01b0319166001600160a01b0388811691821790925591519394509092908716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b613099848484612c64565b6130a584848484613426565b6130c15760405162461bcd60e51b8152600401610c2f906147ff565b50505050565b600060646130d860ff8416856149f1565b6130e291906149b7565b9392505050565b6040516001600160a01b038316602482015260448101829052610d8990849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613c30565b604080516002808252606082018352600092602083019080368337019050509050828160008151811061318f57634e487b7160e01b600052603260045260246000fd5b6001600160a01b03928316602091820292909201810191909152600654604080516315ab88c960e31b81529051919093169263ad5c4648926004808301939192829003018186803b1580156131e357600080fd5b505afa1580156131f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061321b919061421b565b8160018151811061323c57634e487b7160e01b600052603260045260246000fd5b6001600160a01b03928316602091820292909201015260065460405163095ea7b360e01b815290821660048201526001600160801b03841660248201529084169063095ea7b390604401602060405180830381600087803b1580156132a057600080fd5b505af11580156132b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d891906143a0565b506006546004805460405163791ac94760e01b81526001600160a01b039384169363791ac9479361331b9388936000938993620100009093041691429101614889565b600060405180830381600087803b15801561333557600080fd5b505af1158015613349573d6000803e3d6000fd5b50505050505050565b6001600160401b0382166000908152600b6020526040902060030154613389908290600160801b90046001600160801b031661495b565b6001600160401b039092166000908152600b6020526040902060030180546001600160801b03938416600160801b0293169290921790915550565b6001600160401b0382166000818152600b6020908152604091829020600201805490859055825181815291820185905292917f901ae3afe5e7d5594d462fab7cb487880c27d5fc0e3863487a5cfd2a08d350ed910160405180910390a2505050565b60006001600160a01b0384163b1561352857604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061346a9033908990889088906004016146e1565b602060405180830381600087803b15801561348457600080fd5b505af19250505080156134b4575060408051601f3d908101601f191682019092526134b1918101906143d8565b60015b61350e573d8080156134e2576040519150601f19603f3d011682016040523d82523d6000602084013e6134e7565b606091505b5080516135065760405162461bcd60e51b8152600401610c2f906147ff565b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905061263d565b506001949350505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040516001600160a01b03808516602483015283166044820152606481018290526130c19085906323b872dd60e01b90608401613115565b60006001600160801b03821115612bea5760405162461bcd60e51b815260206004820152602860248201527f537061726b4c696e6b3a2056616c756520646f65736e27742066697420696e20604482015267313238206269747360c01b6064820152608401610c2f565b600061363083613d02565b600061363b846126a2565b9050600063ffffffff60201b851663ffffffff831617905061366f6000858360405180602001604052806000815250613426565b61368b5760405162461bcd60e51b8152600401610c2f906147ff565b6001600160401b0381166000908152600b602052604090206136ac86610dda565b815479ffff00000000000000000000000000000000ffffffffffffffff1916600160c01b61ffff929092169190910267ffffffffffffffff1916176001600160401b0387161781556136fd86610fee565b801561370f5750600163ffffffff8716145b15613759576001600160401b0386166000908152600b60205260409020548154600160401b600160c01b031916600160401b918290046001600160801b03169091021781556137b9565b6001600160401b0386166000908152600b602052604090205460045461379291600160401b90046001600160801b03169060ff166130c7565b81546001600160801b0391909116600160401b02600160401b600160c01b03199091161781555b8054600160401b90046001600160801b0316613810576001600160401b0386166000908152600b60205260409020548154600160401b600160c01b031916600160401b918290046001600160801b03169091021781555b600181810180546001600160a01b0319166001600160a01b0388169081179091556001600160401b038881166000908152600b602090815260408083206002908101549088015593825260089052918220805490929161387291859116614995565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550816001600160401b0316856001600160a01b031660006001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a450949350505050565b60606000604051806040016040528060028152602001609160f51b8152508360405160200161391a929190614690565b60408051601f1981840301815281835261082083018252925060009190602082016108008036833701905050905060008160008151811061396b57634e487b7160e01b600052603260045260246000fd5b60ff90921660209283029190910190910152600160005b8351811015613adc5760008482815181106139ad57634e487b7160e01b600052603260045260246000fd5b016020015160f81c905060005b8360ff16811015613a63578481815181106139e557634e487b7160e01b600052603260045260246000fd5b602002602001015160ff166101006139fd9190614a20565b613a07908361497d565b9150613a14603a83614b5b565b858281518110613a3457634e487b7160e01b600052603260045260246000fd5b60ff90921660209283029190910190910152613a51603a836149dd565b9150613a5c81614b20565b90506139ba565b505b8015613acb57613a76603a82614b5b565b848460ff1681518110613a9957634e487b7160e01b600052603260045260246000fd5b60ff9092166020928302919091019091015282613ab581614b3b565b9350613ac49050603a826149dd565b9050613a65565b50613ad581614b20565b9050613982565b50613af7613af2613aed8484613dd2565b613ead565b613f9b565b95945050505050565b6000613b0b82610fc5565b613b6f5760405162461bcd60e51b815260206004820152602f60248201527f537061726b4c696e6b3a204f70657261746f7220717565727920666f72206e6f60448201526e3732bc34b9ba32b73a103a37b5b2b760891b6064820152608401610c2f565b6000613b83836001600160401b03166116c6565b9050806001600160a01b0316846001600160a01b03161480613bc75750836001600160a01b0316613bbc846001600160401b0316610c05565b6001600160a01b0316145b8061263d57506001600160a01b038082166000908152600a602090815260408083209388168352929052205460ff1661263d565b613c06600082612bee565b6001600160401b03166000908152600b6020526040902060030180546001600160801b0319169055565b6000613c85826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166140b59092919063ffffffff16565b805190915015610d895780806020019051810190613ca391906143a0565b610d895760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610c2f565b63ffffffff613d10826126a2565b63ffffffff1610613d765760405162461bcd60e51b815260206004820152602a60248201527f537061726b4c696e6b3a205468657265206973206e6f206c65667420696e20746044820152693434b99034b9b9bab29760b11b6064820152608401610c2f565b600163ffffffff60201b821681176000908152600b602052604081208054909190613dab9084906001600160401b0316614995565b92506101000a8154816001600160401b0302191690836001600160401b0316021790555050565b606060008260ff166001600160401b03811115613dff57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015613e28578160200160208202803683370190505b50905060005b8360ff16811015613ea557848181518110613e5957634e487b7160e01b600052603260045260246000fd5b6020026020010151828281518110613e8157634e487b7160e01b600052603260045260246000fd5b60ff9092166020928302919091019091015280613e9d81614b20565b915050613e2e565b509392505050565b6060600082516001600160401b03811115613ed857634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015613f01578160200160208202803683370190505b50905060005b8351811015613f9457838160018651613f209190614a82565b613f2a9190614a82565b81518110613f4857634e487b7160e01b600052603260045260246000fd5b6020026020010151828281518110613f7057634e487b7160e01b600052603260045260246000fd5b60ff9092166020928302919091019091015280613f8c81614b20565b915050613f07565b5092915050565b6060600082516001600160401b03811115613fc657634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015613ff0576020820181803683370190505b50905060005b8351811015613f94576040518060600160405280603a8152602001614beb603a913984828151811061403857634e487b7160e01b600052603260045260246000fd5b602002602001015160ff168151811061406157634e487b7160e01b600052603260045260246000fd5b602001015160f81c60f81b82828151811061408c57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a905350806140ad81614b20565b915050613ff6565b606061263d848460008585843b61410e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c2f565b600080866001600160a01b0316858760405161412a9190614674565b60006040518083038185875af1925050503d8060008114614167576040519150601f19603f3d011682016040523d82523d6000602084013e61416c565b606091505b509150915061417c828286614187565b979650505050505050565b606083156141965750816130e2565b8251156141a65782518084602001fd5b8160405162461bcd60e51b8152600401610c2f9190614726565b80356001600160801b038116811461219557600080fd5b80356001600160401b038116811461219557600080fd5b803560ff8116811461219557600080fd5b600060208284031215614210578081fd5b81356130e281614bb1565b60006020828403121561422c578081fd5b81516130e281614bb1565b60008060408385031215614249578081fd5b823561425481614bb1565b9150602083013561426481614bb1565b809150509250929050565b600080600060608486031215614283578081fd5b833561428e81614bb1565b9250602084013561429e81614bb1565b929592945050506040919091013590565b6000806000806000608086880312156142c6578081fd5b85356142d181614bb1565b945060208601356142e181614bb1565b93506040860135925060608601356001600160401b0380821115614303578283fd5b818801915088601f830112614316578283fd5b813581811115614324578384fd5b896020828501011115614335578384fd5b9699959850939650602001949392505050565b6000806040838503121561435a578182fd5b823561436581614bb1565b9150602083013561426481614bc6565b60008060408385031215614387578182fd5b823561439281614bb1565b946020939093013593505050565b6000602082840312156143b1578081fd5b81516130e281614bc6565b6000602082840312156143cd578081fd5b81356130e281614bd4565b6000602082840312156143e9578081fd5b81516130e281614bd4565b600080600080600080600080610100898b031215614410578283fd5b614419896141c0565b975061442760208a016141ee565b9650604089013561ffff8116811461443d578384fd5b955060608901359450608089013561445481614bb1565b935060a089013561446481614bc6565b925060c089013561447481614bc6565b915060e089013561448481614bc6565b809150509295985092959890939650565b6000602082840312156144a6578081fd5b5035919050565b6000602082840312156144be578081fd5b5051919050565b6000602082840312156144d6578081fd5b6130e2826141d7565b600080604083850312156144f1578182fd5b614392836141d7565b6000806040838503121561450c578182fd5b614515836141d7565b915060208301356001600160401b0380821115614530578283fd5b818501915085601f830112614543578283fd5b81358181111561455557614555614b9b565b604051601f8201601f19908116603f0116810190838211818310171561457d5761457d614b9b565b81604052828152886020848701011115614595578586fd5b82602086016020830137856020848301015280955050505050509250929050565b600080604083850312156145c8578182fd5b6145d1836141d7565b91506145df602084016141c0565b90509250929050565b6000806000606084860312156145fc578081fd5b614605846141d7565b9250614613602085016141c0565b9150604084013561462381614bb1565b809150509250925092565b60006020828403121561463f578081fd5b6130e2826141ee565b60008151808452614660816020860160208601614ab9565b601f01601f19169290920160200192915050565b60008251614686818460208701614ab9565b9190910192915050565b600083516146a2818460208801614ab9565b9190910191825250602001919050565b600083516146c4818460208801614ab9565b8351908301906146d8818360208801614ab9565b01949350505050565b6001600160a01b038581168252841660208201526001600160401b038316604082015260806060820181905260009061471c90830184614648565b9695505050505050565b6020815260006130e26020830184614648565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526022908201527f537061726b4c696e6b3a2054686973204e465420646f6573206e6f74206578696040820152611cdd60f21b606082015260800190565b6020808252602f908201527f537061726b4c696e6b3a20417070726f76656420717565727920666f72206e6f60408201526e3732bc34b9ba32b73a103a37b5b2b760891b606082015260800190565b60208082526035908201527f537061726b4c696e6b3a205472616e7366657220746f206e6f6e20455243373260408201527418a932b1b2b4bb32b91034b6b83632b6b2b73a32b960591b606082015260800190565b6020808252818101527f537061726b4c696e6b3a2045646974696f6e206973206e6f742065786973742e604082015260600190565b600060a082016001600160801b03881683526020878185015260a0604085015281875180845260c0860191508289019350845b818110156148e15784516001600160a01b0316835293830193918301916001016148bc565b50506001600160a01b03969096166060850152505050608001529392505050565b6001600160401b038781168252861660208201526001600160801b03858116604083015261ffff851660608301528316608082015260c060a0820181905260009061494f90830184614648565b98975050505050505050565b60006001600160801b038083168185168083038211156146d8576146d8614b6f565b6000821982111561499057614990614b6f565b500190565b60006001600160401b038083168185168083038211156146d8576146d8614b6f565b60006001600160801b03808416806149d1576149d1614b85565b92169190910492915050565b6000826149ec576149ec614b85565b500490565b60006001600160801b0380831681851681830481118215151615614a1757614a17614b6f565b02949350505050565b6000816000190483118215151615614a3a57614a3a614b6f565b500290565b60006001600160801b0383811690831681811015614a5f57614a5f614b6f565b039392505050565b600061ffff83811690831681811015614a5f57614a5f614b6f565b600082821015614a9457614a94614b6f565b500390565b60006001600160401b0383811690831681811015614a5f57614a5f614b6f565b60005b83811015614ad4578181015183820152602001614abc565b838111156130c15750506000910152565b600181811c90821680614af957607f821691505b60208210811415614b1a57634e487b7160e01b600052602260045260246000fd5b50919050565b6000600019821415614b3457614b34614b6f565b5060010190565b600060ff821660ff811415614b5257614b52614b6f565b60010192915050565b600082614b6a57614b6a614b85565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146115cc57600080fd5b80151581146115cc57600080fd5b6001600160e01b0319811681146115cc57600080fdfe31323334353637383941424344454647484a4b4c4d4e505152535455565758595a6162636465666768696a6b6d6e6f707172737475767778797aa2646970667358221220933f6f737a354378b11fa0569b363a10f31397d3f42d4be2a8b4cad33b3ab02164736f6c63430008040033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/contract/chain.sample.ts b/contract/chain.sample.ts deleted file mode 100644 index 94a12fb..0000000 --- a/contract/chain.sample.ts +++ /dev/null @@ -1,11 +0,0 @@ -export default { - defaultNetwork: "hardhat", - networks: { - hardhat: { - }, - rinkeby: { - url: "https://rinkeby.infura.io/v3/xxxxxxx", - accounts: ["0xFFFFFFFFFFFFFFFFFFFFFFFFF"] - } - } -} \ No newline at end of file diff --git a/contract/contracts/IERC721.sol b/contract/contracts/IERC721.sol deleted file mode 100644 index 852ac3c..0000000 --- a/contract/contracts/IERC721.sol +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >= 0.8.0; - -import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; - -/// @title ERC-721 Non-Fungible Token Standard -/// @dev See https://eips.ethereum.org/EIPS/eip-721 -/// Note: the ERC-165 identifier for this interface is 0x80ac58cd. -interface IERC721 is IERC165 { - /** - * @dev Emitted when `tokenId` token is transferred from `from` to `to`. - */ - event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); - - /** - * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. - */ - event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); - - /** - * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. - */ - event ApprovalForAll(address indexed owner, address indexed operator, bool approved); - - /** - * @dev Returns the number of tokens in ``owner``'s account. - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @dev Returns the owner of the `tokenId` token. - * - * Requirements: - * - * - `tokenId` must exist. - */ - function ownerOf(uint256 tokenId) external view returns (address owner); - - /** - * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients - * are aware of the ERC721 protocol to prevent tokens from being forever locked. - * - * Requirements: - * - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `tokenId` token must exist and be owned by `from`. - * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. - * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. - * - * Emits a {Transfer} event. - */ - function safeTransferFrom( - address from, - address to, - uint256 tokenId - ) payable external; - - /** - * @dev Transfers `tokenId` token from `from` to `to`. - * - * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. - * - * Requirements: - * - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `tokenId` token must be owned by `from`. - * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. - * - * Emits a {Transfer} event. - */ - function transferFrom( - address from, - address to, - uint256 tokenId - ) payable external; - - /** - * @dev Gives permission to `to` to transfer `tokenId` token to another account. - * The approval is cleared when the token is transferred. - * - * Only a single account can be approved at a time, so approving the zero address clears previous approvals. - * - * Requirements: - * - * - The caller must own the token or be an approved operator. - * - `tokenId` must exist. - * - * Emits an {Approval} event. - */ - function approve(address to, uint256 tokenId) external; - - /** - * @dev Returns the account approved for `tokenId` token. - * - * Requirements: - * - * - `tokenId` must exist. - */ - function getApproved(uint256 tokenId) external view returns (address operator); - - /** - * @dev Approve or remove `operator` as an operator for the caller. - * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. - * - * Requirements: - * - * - The `operator` cannot be the caller. - * - * Emits an {ApprovalForAll} event. - */ - function setApprovalForAll(address operator, bool _approved) external; - - /** - * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. - * - * See {setApprovalForAll} - */ - function isApprovedForAll(address owner, address operator) external view returns (bool); - - /** - * @dev Safely transfers `tokenId` token from `from` to `to`. - * - * Requirements: - * - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `tokenId` token must exist and be owned by `from`. - * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. - * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. - * - * Emits a {Transfer} event. - */ - function safeTransferFrom( - address from, - address to, - uint256 tokenId, - bytes calldata data - ) payable external; -} diff --git a/contract/contracts/IERC721Metadata.sol b/contract/contracts/IERC721Metadata.sol deleted file mode 100644 index dc42af1..0000000 --- a/contract/contracts/IERC721Metadata.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -import "./IERC721.sol"; - -/** - * @title ERC-721 Non-Fungible Token Standard, optional metadata extension - * @dev See https://eips.ethereum.org/EIPS/eip-721 - */ -interface IERC721Metadata is IERC721 { - /** - * @dev Returns the token collection name. - */ - function name() external view returns (string memory); - - /** - * @dev Returns the token collection symbol. - */ - function symbol() external view returns (string memory); - - /** - * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. - */ - function tokenURI(uint256 tokenId) external view returns (string memory); -} diff --git a/contract/contracts/IERC721Receiver.sol b/contract/contracts/IERC721Receiver.sol deleted file mode 100644 index 9683f4a..0000000 --- a/contract/contracts/IERC721Receiver.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -/** - * @title ERC721 token receiver interface - * @dev Interface for any contract that wants to support safeTransfers - * from ERC721 asset contracts. - */ -interface IERC721Receiver { - /** - * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} - * by `operator` from `from`, this function is called. - * - * It must return its Solidity selector to confirm the token transfer. - * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. - * - * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. - */ - function onERC721Received( - address operator, - address from, - uint256 tokenId, - bytes calldata data - ) external returns (bytes4); -} diff --git a/contract/contracts/SparkLink.sol b/contract/contracts/SparkLink.sol deleted file mode 100644 index bae80a3..0000000 --- a/contract/contracts/SparkLink.sol +++ /dev/null @@ -1,1169 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >= 0.8.4; - -import "./IERC721Receiver.sol"; -import "./IERC721Metadata.sol"; -import "@openzeppelin/contracts/utils/Counters.sol"; -import "@openzeppelin/contracts/utils/Address.sol"; -import "@openzeppelin/contracts/utils/Context.sol"; -import "@openzeppelin/contracts/utils/Strings.sol"; -import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; -import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol"; -import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol"; -import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol'; -contract SparkLink is Ownable, ERC165, IERC721, IERC721Metadata{ - using Address for address; - using Counters for Counters.Counter; - using SafeERC20 for IERC20; - Counters.Counter private _issueIds; - /* - Abstract struct Issue { - uint32 total_amount; - bool is_free - bool is_ND; - bool is_NC; - uint16 shill_times; - uint8 royalty_fee; - } - This structure records some common attributes of a series of NFTs: - - `royalty_fee`: the proportion of royaltyes - - `shill_times`: the number of times a single NFT can been shared - - `total_amount`: the total number of NFTs in the series - To reduce gas cost, this structure is actually stored in the `father_id` attibute of root NFT - - 0~31 `total_amount` - - 37 `is_free` - - 38 `is_NC` - - 39 `is_ND` - - 40~55 `shill_times` - - 56~63 `royalty_fee` - */ - - struct Edition { - // This structure stores NFT related information: - // - `father_id`: For root NFT it stores issue abstract sturcture - // For other NFTs its stores the NFT Id of which NFT it `acceptShill` from - // - `shill_price`: The price should be paid when others `accpetShill` from this NFT - // - remaining_shill_times: The initial value is the shilltimes of the issue it belongs to - // When others `acceptShill` from this NFT, it will subtract one until its value is 0 - // - `owner`: record the owner of this NFT - // - `ipfs_hash`: IPFS hash value of the URI where this NTF's metadata stores - // - `transfer_price`: The initial value is zero - // Set by `determinePrice` or `determinePriceAndApprove` before `transferFrom` - // It will be checked wether equal to msg.value when `transferFrom` is called - // After `transferFrom` this value will be set to zero - // - `profit`: record the profit owner can claim (include royalty fee it should conduct to its father NFT) - uint64 father_id; - uint128 shill_price; - uint16 remaining_shill_times; - address owner; - bytes32 ipfs_hash; - uint128 transfer_price; - uint128 profit; - } - - // Emit when `determinePrice` success - event DeterminePrice( - uint64 indexed NFT_id, - uint128 transfer_price - ); - - // Emit when `determinePriceAndApprove` success - event DeterminePriceAndApprove( - uint64 indexed NFT_id, - uint128 transfer_price, - address indexed to - ); - - // Emit when `publish` success - // - `rootNFTId`: Record the Id of root NFT given to publisher - event Publish( - address indexed publisher, - uint64 indexed rootNFTId, - address token_addr - ); - - // Emit when claimProfit success - //- `amount`: Record the actual amount owner of this NFT received (profit - profit*royalty_fee/100) - event Claim( - uint64 indexed NFT_id, - address indexed receiver, - uint128 amount - ); - // Emit when setURI success - event SetURI( - uint64 indexed NFT_id, - bytes32 old_URI, - bytes32 new_URI - ); - - event Label( - uint64 indexed NFT_id, - string content - ); - - event SetDAOFee( - uint8 old_DAO_fee, - uint8 new_DAO_fee - ); - - event SetLoosRatio( - uint8 old_loss_ratio, - uint8 new_loss_ratio - ); - - event SetDAORouter01( - address old_router_address, - address new_router_address - ); - - event SetDAORouter02( - address old_router_address, - address new_router_address - ); - - //---------------------------------------------------------------------------------------------------- - /** - * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. - */ - constructor(address DAO_router_address01,address DAO_router_address02, address uniswapRouterAddress, address factoryAddress) { - uniswapV2Router = IUniswapV2Router02(uniswapRouterAddress); - uniswapV2Factory = IUniswapV2Factory(factoryAddress); - DAO_router01 = DAO_router_address01; - DAO_router02 = DAO_router_address02; - _name = "SparkLink"; - _symbol = "SPL"; - } - - /** - * @dev Create a issue and mint a root NFT for buyer acceptShill from - * - * Requirements: - * - * - `_first_sell_price`: The price should be paid when others `accpetShill` from this NFT - * - `_royalty_fee`: The proportion of royaltyes, it represents the ratio of the father NFT's profit from the child NFT - * Its value should <= 100 - * - `_shill_times`: the number of times a single NFT can been shared - * Its value should <= 65536 - * - `_ipfs_hash`: IPFS hash value of the URI where this NTF's metadata stores - * - * - `token_address`: list of tokens(address) can be accepted for payment. - * `A token address` can be ERC-20 token contract address or `address(0)`(ETH). - * - * - `_is_free`: - * - `_is_NC`: - * - * - `_is_ND`: - * Emits a {Publish} event. - * - Emitted {Publish} event contains root NFT id. - */ - function publish( - uint128 _first_sell_price, - uint8 _royalty_fee, - uint16 _shill_times, - bytes32 _ipfs_hash, - address _token_addr, - bool _is_free, - bool _is_NC, - bool _is_ND - ) - external - { - require(_royalty_fee <= 100, "SparkLink: Royalty fee should be <= 100%."); - _issueIds.increment(); - require(_issueIds.current() <= type(uint32).max, "SparkLink: Value doesn't fit in 32 bits."); - if (_token_addr != address(0)) - require(IERC20(_token_addr).totalSupply() > 0, "Not a valid ERC20 token address"); - uint32 new_issue_id = uint32(_issueIds.current()); - uint64 rootNFTId = getNftIdByEditionIdAndIssueId(new_issue_id, 1); - require( - _checkOnERC721Received(address(0), msg.sender, rootNFTId, ""), - "SparkLink: Transfer to non ERC721Receiver implementer" - ); - - Edition storage new_NFT = editions_by_id[rootNFTId]; - uint64 information; - information = reWriteUint8InUint64(56, _royalty_fee, information); - information = reWriteUint16InUint64(40, _shill_times, information); - information = reWriteBoolInUint64(37, _is_free, information); - information = reWriteBoolInUint64(38, _is_NC, information); - information = reWriteBoolInUint64(39, _is_ND, information); - information += 1; - token_addresses[new_issue_id] = _token_addr; - new_NFT.father_id = information; - new_NFT.remaining_shill_times = _shill_times; - new_NFT.shill_price = _first_sell_price; - new_NFT.owner = msg.sender; - new_NFT.ipfs_hash = _ipfs_hash; - _balances[msg.sender] += 1; - emit Transfer(address(0), msg.sender, rootNFTId); - emit Publish( - msg.sender, - rootNFTId, - _token_addr - ); - } - - /** - * @dev Buy a child NFT from the _NFT_id buyer input - * - * Requirements: - * - * - `_NFT_id`: _NFT_id the father NFT id buyer mint NFT from - * remain shill times of the NFT_id you input should greater than 0 - * Emits a {Ttansfer} event. - * - Emitted {Transfer} event from 0x0 address to msg.sender, contain new NFT id. - * - New NFT id will be generater by edition id and issue id - * 0~31 edition id - * 32~63 issue id - */ - function acceptShill( - uint64 _NFT_id - ) - external - payable - { - require(isEditionExisting(_NFT_id), "SparkLink: This NFT does not exist"); - require(editions_by_id[_NFT_id].remaining_shill_times > 0, "SparkLink: There is no remaining shill time for this NFT"); - if (!isRootNFT(_NFT_id)||!getIsFreeByNFTId(_NFT_id)){ - address token_addr = getTokenAddrByNFTId(_NFT_id); - if (token_addr == address(0)){ - require(msg.value == editions_by_id[_NFT_id].shill_price, "SparkLink: Wrong price"); - _addProfit( _NFT_id, editions_by_id[_NFT_id].shill_price); - } - else { - uint256 before_balance = IERC20(token_addr).balanceOf(address(this)); - IERC20(token_addr).safeTransferFrom(msg.sender, address(this), editions_by_id[_NFT_id].shill_price); - _addProfit( _NFT_id, uint256toUint128(IERC20(token_addr).balanceOf(address(this))-before_balance)); - } - } - editions_by_id[_NFT_id].remaining_shill_times -= 1; - _mintNFT(_NFT_id, msg.sender); - if (editions_by_id[_NFT_id].remaining_shill_times == 0) - _mintNFT(_NFT_id, ownerOf(_NFT_id)); - } - - /** - * @dev Transfers `tokenId` token from `from` to `to`. - * - * Requirements: - * - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `tokenId` token must be owned by `from`. - * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. - * - If `transfer_price` has been set, caller should give same value in msg.sender. - * - Will call `claimProfit` before transfer and `transfer_price` will be set to zero after transfer. - * Emits a {TransferAsset} events - */ - function transferFrom(address from, address to, uint256 tokenId) external payable override { - _transfer(from, to, uint256toUint64(tokenId)); - } - - function safeTransferFrom(address from, address to, uint256 tokenId) external payable override{ - _safeTransfer(from, to, uint256toUint64(tokenId), ""); - } - - function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata _data) external payable override { - _safeTransfer(from, to, uint256toUint64(tokenId), _data); - } - - /** - * @dev Claim profit from reward pool of NFT. - * - * Requirements: - * - * - `_NFT_id`: The NFT id of NFT caller claim, the profit will give to its owner. - * - If its profit is zero the event {Claim} will not be emited. - * Emits a {Claim} events - */ - function claimProfit(uint64 _NFT_id) public { - require(isEditionExisting(_NFT_id), "SparkLink: This edition does not exist"); - - if (editions_by_id[_NFT_id].profit != 0) { - uint128 amount = editions_by_id[_NFT_id].profit; - address token_addr = getTokenAddrByNFTId(_NFT_id); - if (DAO_fee != 0) { - uint128 DAO_amount = calculateFee(amount, DAO_fee); - amount -= DAO_amount; - if (token_addr == address(0)) { - payable(DAO_router01).transfer(DAO_amount); - } - else if (uniswapV2Factory.getPair(token_addr, uniswapV2Router.WETH()) == address(0)) { - IERC20(token_addr).safeTransfer(DAO_router02,DAO_amount); - } - else { - _swapTokensForEth(token_addr, DAO_amount); - } - } - editions_by_id[_NFT_id].profit = 0; - if (!isRootNFT(_NFT_id)) { - uint128 _royalty_fee = calculateFee(amount, getRoyaltyFeeByNFTId(_NFT_id)); - _addProfit(getFatherByNFTId(_NFT_id), _royalty_fee); - amount -= _royalty_fee; - } - if (token_addr == address(0)){ - payable(ownerOf(_NFT_id)).transfer(amount); - } - else { - IERC20(token_addr).safeTransfer(ownerOf(_NFT_id), amount); - } - emit Claim( - _NFT_id, - ownerOf(_NFT_id), - amount - ); - } - } - - /** - * @dev Set token URI. - * - * Requirements: - * - * - `_NFT_id`: transferred token id. - * - `ipfs_hash`: ipfs hash value of the URI will be set. - * Emits a {SetURI} events - */ - function setURI(uint64 _NFT_id, bytes32 ipfs_hash) public { - if (getIsNDByNFTId(_NFT_id)) { - require(_NFT_id == getRootNFTIdByNFTId(_NFT_id), "SparkLink: NFT follows the ND protocol, only the root NFT's URI can be set."); - } - require(ownerOf(_NFT_id) == msg.sender, "SparkLink: Only owner can set the token URI"); - _setTokenURI(_NFT_id, ipfs_hash); - } - - /** - * @dev update token URI. - * - * Requirements: - * - * - `_NFT_id`: transferred token id. - */ - function updateURI(uint64 _NFT_id) public{ - require(ownerOf(_NFT_id) == msg.sender, "SparkLink: Only owner can update the token URI"); - editions_by_id[_NFT_id].ipfs_hash = editions_by_id[getRootNFTIdByNFTId(_NFT_id)].ipfs_hash; - } - - function label(uint64 _NFT_id, string memory content) public { - require(ownerOf(_NFT_id) == msg.sender, "SparkLink: Only owner can label this NFT"); - emit Label(_NFT_id, content); - } - /** - * @dev Determine NFT price before transfer. - * - * Requirements: - * - * - `_NFT_id`: transferred token id. - * - `_price`: The amount of ETH should be payed for `_NFT_id` - * Emits a {DeterminePrice} events - */ - function determinePrice( - uint64 _NFT_id, - uint128 _price - ) - public - { - require(isEditionExisting(_NFT_id), "SparkLink: This NFT does not exist"); - require(msg.sender == ownerOf(_NFT_id), "SparkLink: Only owner can set the price"); - editions_by_id[_NFT_id].transfer_price = _price; - emit DeterminePrice(_NFT_id, _price); - } - - /** - * @dev Determine NFT price before transfer. - * - * Requirements: - * - * - `_NFT_id`: transferred token id. - * - `_price`: The amount of ETH should be payed for `_NFT_id` - * - `_to`: The account address `approve` to. - * Emits a {DeterminePriceAndApprove} events - */ - function determinePriceAndApprove( - uint64 _NFT_id, - uint128 _price, - address _to - ) - public - { - determinePrice(_NFT_id, _price); - approve(_to, _NFT_id); - emit DeterminePriceAndApprove(_NFT_id, _price, _to); - } - - function setDAOFee(uint8 _DAO_fee) public onlyOwner { - require(_DAO_fee <= MAX_DAO_FEE, "SparkLink: DAO fee can not exceed 5%"); - emit SetDAOFee(DAO_fee, _DAO_fee); - DAO_fee = _DAO_fee; - } - - function setDAORouter01(address _DAO_router01) public onlyOwner { - emit SetDAORouter01(DAO_router01, _DAO_router01); - DAO_router01 = _DAO_router01; - } - - function setDAORouter02(address _DAO_router02) public onlyOwner { - emit SetDAORouter01(DAO_router02, _DAO_router02); - DAO_router02 = _DAO_router02; - } - - function setUniswapV2Router(address _uniswapV2Router) public onlyOwner { - uniswapV2Router = IUniswapV2Router02(_uniswapV2Router); - } - function setUniswapV2Factory(address _uniswapV2Factory) public onlyOwner { - uniswapV2Factory = IUniswapV2Factory(_uniswapV2Factory); - } - - function setLoosRatio(uint8 _loss_ratio) public onlyOwner { - require(_loss_ratio <= MAX_LOSS_RATIO, "SparkLink: Loss ratio can not below 50%"); - emit SetLoosRatio(loss_ratio, _loss_ratio); - loss_ratio = _loss_ratio; - } - /** - * @dev See {IERC721-approve}. - */ - function approve(address to, uint256 tokenId) public virtual override { - address owner = ownerOf(tokenId); - require(to != owner, "SparkLink: Approval to current owner"); - require( - _msgSender() == owner || isApprovedForAll(owner, _msgSender()), - "SparkLink: Approve caller is not owner nor approved for all" - ); - - _approve(to, uint256toUint64(tokenId)); - } - - /** - * @dev See {IERC721-setApprovalForAll}. - */ - function setApprovalForAll(address operator, bool approved) public virtual override { - require(operator != _msgSender(), "SparkLink: Approve to caller"); - _operatorApprovals[_msgSender()][operator] = approved; - emit ApprovalForAll(_msgSender(), operator, approved); - } - - /** - * @dev See {IERC165-supportsInterface}. - */ - function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { - return - interfaceId == type(IERC721).interfaceId || - interfaceId == type(IERC721Metadata).interfaceId || - super.supportsInterface(interfaceId); - } - - /** - * @dev See {IERC721-balanceOf}. - */ - function balanceOf(address owner) public view virtual override returns (uint256) { - require(owner != address(0), "SparkLink: Balance query for the zero address"); - return _balances[owner]; - } - - /** - * @dev See {IERC721-ownerOf}. - */ - function ownerOf(uint256 tokenId) public view virtual override returns (address) { - address owner = editions_by_id[uint256toUint64(tokenId)].owner; - require(owner != address(0), "SparkLink: Owner query for nonexistent token"); - return owner; - } - - /** - * @dev See {IERC721Metadata-name}. - */ - function name() public view virtual override returns (string memory) { - return _name; - } - - /** - * @dev See {IERC721Metadata-symbol}. - */ - function symbol() public view virtual override returns (string memory) { - return _symbol; - } - - /** - * @dev Query NFT information set. - * - * Requirements: - * - `_NFT_id`: The id of the edition queryed. - * Return : - * - `issue_information`: For root NFT it stores issue abstract sturcture - * - 0~31 `total_amount` - * - 37 `is_free` - * - 38 `is_NC` - * - 39 `is_ND` - * - 40~55 `shill_times` - * - 56~63 `royalty_fee` - * - `father_id`: For root NFT it stores issue abstract sturcture - * For other NFTs its stores the NFT Id of which NFT it `acceptShill` from - * - `shill_price`: The price should be paid when others `accpetShill` from this NFT - * - `remaining_shill_times`: The initial value is the shilltimes of the issue it belongs to - * When others `acceptShill` from this NFT, it will subtract one until its value is 0 - * - `owner`: record the owner of this NFT - * - `transfer_price`: The initial value is zero - * Set by `determinePrice` or `determinePriceAndApprove` before `transferFrom` - * It will be checked wether equal to msg.value when `transferFrom` is called - * After `transferFrom` this value will be set to zero - * - `profit`: record the profit owner can claim (include royalty fee it should conduct to its father NFT) - * - `metadata`: IPFS hash value of the URI where this NTF's metadata stores - */ - - function getNFTInfoByNFTID(uint64 _NFT_id) - public view - returns ( - uint64 issue_information, - uint64 father_id, - uint128 shill_price, - uint16 remain_shill_times, - uint128 profit, - string memory metadata - ) - { - require(isEditionExisting(_NFT_id), "SparkLink: Approved query for nonexistent token"); - return( - editions_by_id[getRootNFTIdByNFTId(_NFT_id)].father_id, - getFatherByNFTId(_NFT_id), - editions_by_id[_NFT_id].shill_price, - getRemainShillTimesByNFTId(_NFT_id), - getProfitByNFTId(_NFT_id), - tokenURI(_NFT_id) - ); - } - - /** - * @dev See {IERC721-getApproved}. - */ - function getApproved(uint256 tokenId) public view virtual override returns (address) { - require(isEditionExisting(uint256toUint64(tokenId)), "SparkLink: Approved query for nonexistent token"); - - return _tokenApprovals[uint256toUint64(tokenId)]; - } - - /** - * @dev See {IERC721-isApprovedForAll}. - */ - function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { - return _operatorApprovals[owner][operator]; - } - - /** - * @dev See {IERC721Metadata-tokenURI}. - */ - function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { - require(isEditionExisting(uint256toUint64(tokenId)), "SparkLink: URI query for nonexistent token"); - bytes32 _ipfs_hash = editions_by_id[uint256toUint64(tokenId)].ipfs_hash; - string memory encoded_hash = _toBase58String(_ipfs_hash); - string memory base = _baseURI(); - return string(abi.encodePacked(base, encoded_hash)); - } - - /** - * @dev Query is issue free for first lever buyer. - * - * Requirements: - * - `_NFT_id`: The id of the edition queryed. - * Return a bool value. - */ - function getIsFreeByNFTId(uint64 _NFT_id) public view returns (bool) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return getBoolFromUint64(37, editions_by_id[getRootNFTIdByNFTId(_NFT_id)].father_id); - } - - /** - * @dev Query is issue follows the NC protocol by any NFT belongs to this issue. - * - * Requirements: - * - `_NFT_id`: The id of the edition queryed. - * Return a bool value. - */ - function getIsNCByNFTId(uint64 _NFT_id) public view returns (bool) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return getBoolFromUint64(38, editions_by_id[getRootNFTIdByNFTId(_NFT_id)].father_id); - } - - /** - * @dev Query is issue follows the ND protocol by any NFT belongs to this issue. - * - * Requirements: - * - `_NFT_id`: The id of the edition queryed. - * Return a bool value. - */ - function getIsNDByNFTId(uint64 _NFT_id) public view returns (bool) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return getBoolFromUint64(39, editions_by_id[getRootNFTIdByNFTId(_NFT_id)].father_id); - } - - /** - * @dev Query is edition exist. - * - * Requirements: - * - `_NFT_id`: The id of the edition queryed. - * Return a bool value. - */ - function isEditionExisting(uint64 _NFT_id) public view returns (bool) { - return (editions_by_id[_NFT_id].owner != address(0)); - } - - /** - * @dev Query the amount of ETH a NFT can be claimed. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return the value this NFT can be claimed. - * If the NFT is not root NFT, this value will subtract royalty fee percent. - */ - function getProfitByNFTId(uint64 _NFT_id) public view returns (uint128){ - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - uint128 amount = editions_by_id[_NFT_id].profit; - if (DAO_fee != 0) { - uint128 DAO_amount = calculateFee(amount, DAO_fee); - amount -= DAO_amount; - } - if (!isRootNFT(_NFT_id)) { - uint128 _total_fee = calculateFee(amount, getRoyaltyFeeByNFTId(_NFT_id)); - amount -= _total_fee; - } - return amount; - } - - /** - * @dev Query royalty fee percent of an issue by any NFT belongs to this issue. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return royalty fee percent of this issue. - */ - function getRoyaltyFeeByNFTId(uint64 _NFT_id) public view returns (uint8) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return getUint8FromUint64(56, editions_by_id[getRootNFTIdByNFTId(_NFT_id)].father_id); - } - - /** - * @dev Query max shill times of an issue by any NFT belongs to this issue. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return max shill times of this issue. - */ - function getShillTimesByNFTId(uint64 _NFT_id) public view returns (uint16) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return getUint16FromUint64(40, editions_by_id[getRootNFTIdByNFTId(_NFT_id)].father_id); - } - - /** - * @dev Query total NFT number of a issue by any NFT belongs to this issue. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return total NFT number of this issue. - */ - function getTotalAmountByNFTId(uint64 _NFT_id) public view returns (uint32) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return getBottomUint32FromUint64(editions_by_id[getRootNFTIdByNFTId(_NFT_id)].father_id); - } - - /** - * @dev Query supported token address of a issue by any NFT belongs to this issue. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return supported token address of this NFT. - * Address 0 represent ETH. - */ - function getTokenAddrByNFTId(uint64 _NFT_id) public view returns (address) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return token_addresses[uint32(_NFT_id>>32)]; - } - - /** - * @dev Query the id of this NFT's father NFT. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * - This NFT should exist and not be root NFT. - * Return the father NFT id of this NFT. - */ - function getFatherByNFTId(uint64 _NFT_id) public view returns (uint64) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - if (isRootNFT(_NFT_id)) { - return 0; - } - return editions_by_id[_NFT_id].father_id; - } - - /** - * @dev Query transfer_price of this NFT. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return transfer_price of this NFT. - */ - function getTransferPriceByNFTId(uint64 _NFT_id) public view returns (uint128) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return editions_by_id[_NFT_id].transfer_price; - } - - /** - * @dev Query shill_price of this NFT. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return shill_price of this NFT. - */ - function getShillPriceByNFTId(uint64 _NFT_id) public view returns (uint128) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - if (getIsFreeByNFTId(_NFT_id)&&isRootNFT(_NFT_id)) - return 0; - else - return editions_by_id[_NFT_id].shill_price; - } - - /** - * @dev Query remaining_shill_times of this NFT. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return remaining_shill_times of this NFT. - */ - function getRemainShillTimesByNFTId(uint64 _NFT_id) public view returns (uint16) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return editions_by_id[_NFT_id].remaining_shill_times; - } - - /** - * @dev Query depth of this NFT. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return depth of this NFT. - */ - function getDepthByNFTId(uint64 _NFT_id) public view returns (uint64) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - uint64 depth = 0; - for (depth = 0; !isRootNFT(_NFT_id); _NFT_id = getFatherByNFTId(_NFT_id)) { - depth += 1; - } - return depth; - } - - /** - * @dev Query is this NFT is root NFT by check is its edition id is 1. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return a bool value to indicate wether this NFT is root NFT. - */ - function isRootNFT(uint64 _NFT_id) public pure returns (bool) { - return getBottomUint32FromUint64(_NFT_id) == uint32(1); - } - - /** - * @dev Query root NFT id by NFT id. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return a bool value to indicate wether this NFT is root NFT. - */ - function getRootNFTIdByNFTId(uint64 _NFT_id) public pure returns (uint64) { - return ((_NFT_id>>32)<<32 | uint64(1)); - } - - /** - * @dev Query loss ratio of this contract. - * - * Return loss ratio of this contract. - */ - function getLossRatio() public view returns (uint8) { - return loss_ratio; - } - - /** - * @dev Calculate edition id by NFT id. - * - * Requirements: - * - `_NFT_id`: The NFT id of the NFT caller want to get. - * Return edition id. - */ - function getEditionIdByNFTId(uint64 _NFT_id) public pure returns (uint32) { - return getBottomUint32FromUint64(_NFT_id); - } - // Token name - string private _name; - - // Token symbol - string private _symbol; - uint8 public loss_ratio = 62; - uint8 public DAO_fee = 2; - uint8 public constant MAX_DAO_FEE = 2; - uint8 public constant MAX_LOSS_RATIO = 50; - address public DAO_router01; - address public DAO_router02; - IUniswapV2Router02 public uniswapV2Router; - IUniswapV2Factory public uniswapV2Factory; - // Mapping owner address to token count - mapping(address => uint64) private _balances; - // Mapping from token ID to approved address - mapping(uint64 => address) private _tokenApprovals; - // Mapping from owner to operator approvals - mapping(address => mapping(address => bool)) private _operatorApprovals; - mapping (uint64 => Edition) private editions_by_id; - // mapping from issue ID to support ERC20 token address - mapping(uint32 => address) private token_addresses; - - bytes constant private sha256MultiHash = hex"1220"; - bytes constant private ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; - - function _swapTokensForEth(address token_addr, uint128 token_amount) private { - // generate the uniswap pair path of token -> weth - address[] memory path = new address[](2); - path[0] = token_addr; - path[1] = uniswapV2Router.WETH(); - - IERC20(token_addr).approve(address(uniswapV2Router), token_amount); - - // make the swap - uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens( - token_amount, - 0, // accept any amount of ETH - path, - DAO_router01, - block.timestamp - ); - } - - - /** - * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. - * The call is not executed if the target address is not a contract. - * - * @param from address representing the previous owner of the given token ID - * @param to target address that will receive the tokens - * @param tokenId uint256 ID of the token to be transferred - * @param _data bytes optional data to send along with the call - * @return bool whether the call correctly returned the expected magic value - */ - function _checkOnERC721Received( - address from, - address to, - uint64 tokenId, - bytes memory _data - ) - private - returns (bool) - { - if (to.isContract()) { - try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { - return retval == IERC721Receiver.onERC721Received.selector; - } catch (bytes memory reason) { - if (reason.length == 0) { - revert("SparkLink: Transfer to non ERC721Receiver implementer"); - } else { - assembly { - revert(add(32, reason), mload(reason)) - } - } - } - } else { - return true; - } - } - - /** - * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. - * - * Requirements: - * - * - `tokenId` must exist. - */ - function _setTokenURI(uint64 tokenId, bytes32 ipfs_hash) internal virtual { - bytes32 old_URI = editions_by_id[tokenId].ipfs_hash; - editions_by_id[tokenId].ipfs_hash = ipfs_hash; - emit SetURI(tokenId, old_URI, ipfs_hash); - } - - /** - * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. - * The call is not executed if the target address is not a contract. - * - * @param _NFT_id NFT id of father NFT - * @param _owner indicate the address new NFT transfer to - * @return a uint64 store new NFT id - **/ - function _mintNFT( - uint64 _NFT_id, - address _owner - ) - internal - returns (uint64) - { - _addTotalAmount(_NFT_id); - uint32 new_edition_id = getTotalAmountByNFTId(_NFT_id); - uint64 new_NFT_id = getNftIdByEditionIdAndIssueId(uint32(_NFT_id>>32), new_edition_id); - require( - _checkOnERC721Received(address(0), _owner, new_NFT_id, ""), - "SparkLink: Transfer to non ERC721Receiver implementer" - ); - Edition storage new_NFT = editions_by_id[new_NFT_id]; - new_NFT.remaining_shill_times = getShillTimesByNFTId(_NFT_id); - new_NFT.father_id = _NFT_id; - if (getIsFreeByNFTId(_NFT_id)&&isRootNFT(_NFT_id)) - new_NFT.shill_price = editions_by_id[_NFT_id].shill_price; - else - new_NFT.shill_price = calculateFee(editions_by_id[_NFT_id].shill_price, loss_ratio); - if (new_NFT.shill_price == 0) { - new_NFT.shill_price = editions_by_id[_NFT_id].shill_price; - } - new_NFT.owner = _owner; - new_NFT.ipfs_hash = editions_by_id[_NFT_id].ipfs_hash; - _balances[_owner] += 1; - emit Transfer(address(0), _owner, new_NFT_id); - return new_NFT_id; - } - - /** - * @dev Internal function to clear approve and transfer_price - * - * @param _NFT_id NFT id of father NFT - **/ - function _afterTokenTransfer (uint64 _NFT_id) internal { - // Clear approvals from the previous owner - _approve(address(0), _NFT_id); - editions_by_id[_NFT_id].transfer_price = 0; - } - - /** - * @dev Internal function to support transfer `tokenId` from `from` to `to`. - * - * @param from address representing the previous owner of the given token ID - * @param to target address that will receive the tokens - * @param tokenId uint256 ID of the token to be transferred - * Emits a {Transfer} event. - */ - function _transfer( - address from, - address to, - uint64 tokenId - ) - internal - virtual - { - require(ownerOf(tokenId) == from, "SparkLink: Transfer of token that is not own"); - require(_isApprovedOrOwner(_msgSender(), tokenId), "SparkLink: Transfer caller is not owner nor approved"); - require(to != address(0), "SparkLink: Transfer to the zero address"); - if (msg.sender != ownerOf(tokenId)) { - address token_addr = getTokenAddrByNFTId(tokenId); - uint128 transfer_price = editions_by_id[tokenId].transfer_price; - if (token_addr == address(0)){ - require(msg.value == transfer_price, "SparkLink: Price not met"); - _addProfit(tokenId, transfer_price); - } - else { - uint256 before_balance = IERC20(token_addr).balanceOf(address(this)); - IERC20(token_addr).safeTransferFrom(msg.sender, address(this), transfer_price); - _addProfit(tokenId, uint256toUint128(IERC20(token_addr).balanceOf(address(this))-before_balance)); - } - claimProfit(tokenId); - } - else { - claimProfit(tokenId); - } - _afterTokenTransfer(tokenId); - _balances[from] -= 1; - _balances[to] += 1; - editions_by_id[tokenId].owner = to; - emit Transfer(from, to, tokenId); - } - - /** - * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients - * are aware of the ERC721 protocol to prevent tokens from being forever locked. - * - * `_data` is additional data, it has no specified format and it is sent in call to `to`. - * - * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. - * implement alternative mechanisms to perform token transfer, such as signature-based. - * - * Requirements: - * - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `tokenId` token must exist and be owned by `from`. - * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. - * - * Emits a {Transfer} event. - */ - function _safeTransfer( - address from, - address to, - uint64 tokenId, - bytes memory _data - ) - internal - virtual - { - _transfer(from, to, tokenId); - require(_checkOnERC721Received(from, to, tokenId, _data), "SparkLink: Transfer to non ERC721Receiver implementer"); - } - - /** - * @dev Approve `to` to operate on `tokenId` - * - * Emits a {Approval} event. - */ - function _approve(address to, uint64 tokenId) internal virtual { - _tokenApprovals[tokenId] = to; - emit Approval(ownerOf(tokenId), to, tokenId); - } - - function _addProfit(uint64 _NFT_id, uint128 _increase) internal { - editions_by_id[_NFT_id].profit = editions_by_id[_NFT_id].profit+_increase; - } - - function _addTotalAmount(uint64 _NFT_Id) internal { - require(getTotalAmountByNFTId(_NFT_Id) < type(uint32).max, "SparkLink: There is no left in this issue."); - editions_by_id[getRootNFTIdByNFTId(_NFT_Id)].father_id += 1; - } - - function _isApprovedOrOwner(address spender, uint64 tokenId) internal view virtual returns (bool) { - require(isEditionExisting(tokenId), "SparkLink: Operator query for nonexistent token"); - address owner = ownerOf(tokenId); - return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); - } - - function _baseURI() internal pure returns (string memory) { - return "https://ipfs.io/ipfs/"; - } - - - /** - * @dev Calculate NFT id by issue id and edition id. - * - * Requirements: - * - `_issue_id`: The issue id of the NFT caller want to get. - * - `_edition_id`: The edition id of the NFT caller want to get. - * Return NFT id. - */ - function getNftIdByEditionIdAndIssueId(uint32 _issue_id, uint32 _edition_id) internal pure returns (uint64) { - return (uint64(_issue_id)<<32)|uint64(_edition_id); - } - - function getBoolFromUint64(uint8 position, uint64 data64) internal pure returns (bool flag) { - // (((1 << size) - 1) & base >> position) - assembly { - flag := and(1, shr(position, data64)) - } - } - - function getUint8FromUint64(uint8 position, uint64 data64) internal pure returns (uint8 data8) { - // (((1 << size) - 1) & base >> position) - assembly { - data8 := and(sub(shl(8, 1), 1), shr(position, data64)) - } - } - function getUint16FromUint64(uint8 position, uint64 data64) internal pure returns (uint16 data16) { - // (((1 << size) - 1) & base >> position) - assembly { - data16 := and(sub(shl(16, 1), 1), shr(position, data64)) - } - } - function getBottomUint32FromUint64(uint64 data64) internal pure returns (uint32 data32) { - // (((1 << size) - 1) & base >> position) - assembly { - data32 := and(sub(shl(32, 1), 1), data64) - } - } - - function reWriteBoolInUint64(uint8 position, bool flag, uint64 data64) internal pure returns (uint64 boxed) { - assembly { - // mask = ~((1 << 8 - 1) << position) - // _box = (mask & _box) | ()data << position) - boxed := or( and(data64, not(shl(position, 1))), shl(position, flag)) - } - } - - - function reWriteUint8InUint64(uint8 position, uint8 flag, uint64 data64) internal pure returns (uint64 boxed) { - assembly { - // mask = ~((1 << 8 - 1) << position) - // _box = (mask & _box) | ()data << position) - boxed := or(and(data64, not(shl(position, 1))), shl(position, flag)) - } - } - - function reWriteUint16InUint64(uint8 position, uint16 data16, uint64 data64) internal pure returns (uint64 boxed) { - assembly { - // mask = ~((1 << 16 - 1) << position) - // _box = (mask & _box) | ()data << position) - boxed := or( and(data64, not(shl(position, sub(shl(16, 1), 1)))), shl(position, data16)) - } - } - - function uint256toUint64(uint256 value) internal pure returns (uint64) { - require(value <= type(uint64).max, "SparkLink: Value doesn't fit in 64 bits"); - return uint64(value); - } - - function uint256toUint128(uint256 value) internal pure returns (uint128) { - require(value <= type(uint128).max, "SparkLink: Value doesn't fit in 128 bits"); - return uint128(value); - } - - function calculateFee(uint128 _amount, uint8 _fee_percent) internal pure returns (uint128) { - return _amount*_fee_percent/10**2; - } - - function _toBase58String(bytes32 con) internal pure returns (string memory) { - - bytes memory source = bytes.concat(sha256MultiHash,con); - - uint8[] memory digits = new uint8[](64); //TODO: figure out exactly how much is needed - digits[0] = 0; - uint8 digitlength = 1; - for (uint256 i = 0; i 0) { - digits[digitlength] = uint8(carry % 58); - digitlength++; - carry = carry / 58; - } - } - //return digits; - return string(toAlphabet(reverse(truncate(digits, digitlength)))); - } - - function toAlphabet(uint8[] memory indices) internal pure returns (bytes memory) { - bytes memory output = new bytes(indices.length); - for (uint256 i = 0; i uint256) private _balances; - - mapping(address => mapping(address => uint256)) private _allowances; - - uint256 private _totalSupply; - - string private _name; - string private _symbol; - - /** - * @dev Sets the values for {name} and {symbol}. - * - * The default value of {decimals} is 18. To select a different value for - * {decimals} you should overload it. - * - * All two of these values are immutable: they can only be set once during - * construction. - */ - constructor(string memory name_, string memory symbol_) { - _name = name_; - _symbol = symbol_; - } - - /** - * @dev Returns the name of the token. - */ - function name() public view virtual override returns (string memory) { - return _name; - } - - /** - * @dev Returns the symbol of the token, usually a shorter version of the - * name. - */ - function symbol() public view virtual override returns (string memory) { - return _symbol; - } - - /** - * @dev Returns the number of decimals used to get its user representation. - * For example, if `decimals` equals `2`, a balance of `505` tokens should - * be displayed to a user as `5,05` (`505 / 10 ** 2`). - * - * Tokens usually opt for a value of 18, imitating the relationship between - * Ether and Wei. This is the value {ERC20} uses, unless this function is - * overridden; - * - * NOTE: This information is only used for _display_ purposes: it in - * no way affects any of the arithmetic of the contract, including - * {IERC20-balanceOf} and {IERC20-transfer}. - */ - function decimals() public view virtual override returns (uint8) { - return 18; - } - - /** - * @dev See {IERC20-totalSupply}. - */ - function totalSupply() public view virtual override returns (uint256) { - return _totalSupply; - } - - /** - * @dev See {IERC20-balanceOf}. - */ - function balanceOf(address account) public view virtual override returns (uint256) { - return _balances[account]; - } - - /** - * @dev See {IERC20-transfer}. - * - * Requirements: - * - * - `recipient` cannot be the zero address. - * - the caller must have a balance of at least `amount`. - */ - function transfer(address recipient, uint256 amount) public virtual override returns (bool) { - _transfer(_msgSender(), recipient, amount); - return true; - } - - /** - * @dev See {IERC20-allowance}. - */ - function allowance(address owner, address spender) public view virtual override returns (uint256) { - return _allowances[owner][spender]; - } - - /** - * @dev See {IERC20-approve}. - * - * Requirements: - * - * - `spender` cannot be the zero address. - */ - function approve(address spender, uint256 amount) public virtual override returns (bool) { - _approve(_msgSender(), spender, amount); - return true; - } - - /** - * @dev See {IERC20-transferFrom}. - * - * Emits an {Approval} event indicating the updated allowance. This is not - * required by the EIP. See the note at the beginning of {ERC20}. - * - * Requirements: - * - * - `sender` and `recipient` cannot be the zero address. - * - `sender` must have a balance of at least `amount`. - * - the caller must have allowance for ``sender``'s tokens of at least - * `amount`. - */ - function transferFrom( - address sender, - address recipient, - uint256 amount - ) public virtual override returns (bool) { - _transfer(sender, recipient, amount); - - uint256 currentAllowance = _allowances[sender][_msgSender()]; - require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); - unchecked { - _approve(sender, _msgSender(), currentAllowance - amount); - } - - return true; - } - - /** - * @dev Atomically increases the allowance granted to `spender` by the caller. - * - * This is an alternative to {approve} that can be used as a mitigation for - * problems described in {IERC20-approve}. - * - * Emits an {Approval} event indicating the updated allowance. - * - * Requirements: - * - * - `spender` cannot be the zero address. - */ - function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { - _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue); - return true; - } - - /** - * @dev Atomically decreases the allowance granted to `spender` by the caller. - * - * This is an alternative to {approve} that can be used as a mitigation for - * problems described in {IERC20-approve}. - * - * Emits an {Approval} event indicating the updated allowance. - * - * Requirements: - * - * - `spender` cannot be the zero address. - * - `spender` must have allowance for the caller of at least - * `subtractedValue`. - */ - function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { - uint256 currentAllowance = _allowances[_msgSender()][spender]; - require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); - unchecked { - _approve(_msgSender(), spender, currentAllowance - subtractedValue); - } - - return true; - } - - /** - * @dev Moves `amount` of tokens from `sender` to `recipient`. - * - * This internal function is equivalent to {transfer}, and can be used to - * e.g. implement automatic token fees, slashing mechanisms, etc. - * - * Emits a {Transfer} event. - * - * Requirements: - * - * - `sender` cannot be the zero address. - * - `recipient` cannot be the zero address. - * - `sender` must have a balance of at least `amount`. - */ - function _transfer( - address sender, - address recipient, - uint256 amount - ) internal virtual { - require(sender != address(0), "ERC20: transfer from the zero address"); - require(recipient != address(0), "ERC20: transfer to the zero address"); - - _beforeTokenTransfer(sender, recipient, amount); - - uint256 senderBalance = _balances[sender]; - require(senderBalance >= amount, "ERC20: transfer amount exceeds balance"); - - unchecked { - _balances[sender] = senderBalance - amount; - } - // burn half of the `transfered` tokens - uint256 received_amount = amount/2; - _balances[recipient] += received_amount; - - emit Transfer(sender, recipient, received_amount); - - _afterTokenTransfer(sender, recipient, amount); - } - - /** @dev Creates `amount` tokens and assigns them to `account`, increasing - * the total supply. - * - * Emits a {Transfer} event with `from` set to the zero address. - * - * Requirements: - * - * - `account` cannot be the zero address. - */ - function _mint(address account, uint256 amount) internal virtual { - require(account != address(0), "ERC20: mint to the zero address"); - - _beforeTokenTransfer(address(0), account, amount); - - _totalSupply += amount; - _balances[account] += amount; - emit Transfer(address(0), account, amount); - - _afterTokenTransfer(address(0), account, amount); - } - - /** - * @dev Destroys `amount` tokens from `account`, reducing the - * total supply. - * - * Emits a {Transfer} event with `to` set to the zero address. - * - * Requirements: - * - * - `account` cannot be the zero address. - * - `account` must have at least `amount` tokens. - */ - function _burn(address account, uint256 amount) internal virtual { - require(account != address(0), "ERC20: burn from the zero address"); - - _beforeTokenTransfer(account, address(0), amount); - - uint256 accountBalance = _balances[account]; - require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); - unchecked { - _balances[account] = accountBalance - amount; - } - _totalSupply -= amount; - - emit Transfer(account, address(0), amount); - - _afterTokenTransfer(account, address(0), amount); - } - - /** - * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. - * - * This internal function is equivalent to `approve`, and can be used to - * e.g. set automatic allowances for certain subsystems, etc. - * - * Emits an {Approval} event. - * - * Requirements: - * - * - `owner` cannot be the zero address. - * - `spender` cannot be the zero address. - */ - function _approve( - address owner, - address spender, - uint256 amount - ) internal virtual { - require(owner != address(0), "ERC20: approve from the zero address"); - require(spender != address(0), "ERC20: approve to the zero address"); - - _allowances[owner][spender] = amount; - emit Approval(owner, spender, amount); - } - - /** - * @dev Hook that is called before any transfer of tokens. This includes - * minting and burning. - * - * Calling conditions: - * - * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens - * will be transferred to `to`. - * - when `from` is zero, `amount` tokens will be minted for `to`. - * - when `to` is zero, `amount` of ``from``'s tokens will be burned. - * - `from` and `to` are never both zero. - * - * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. - */ - function _beforeTokenTransfer( - address from, - address to, - uint256 amount - ) internal virtual {} - - /** - * @dev Hook that is called after any transfer of tokens. This includes - * minting and burning. - * - * Calling conditions: - * - * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens - * has been transferred to `to`. - * - when `from` is zero, `amount` tokens have been minted for `to`. - * - when `to` is zero, `amount` of ``from``'s tokens have been burned. - * - `from` and `to` are never both zero. - * - * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. - */ - function _afterTokenTransfer( - address from, - address to, - uint256 amount - ) internal virtual {} -} - -contract BurnToken is ERC20 { - constructor(uint initialSupply) ERC20("TestToken", "TEST") { - _mint(msg.sender, initialSupply); - } -} \ No newline at end of file diff --git a/contract/contracts/tokenA.sol b/contract/contracts/tokenA.sol deleted file mode 100644 index 24018e9..0000000 --- a/contract/contracts/tokenA.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >= 0.8.0; - -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - -contract TestTokenA is ERC20 { - constructor(uint initialSupply) ERC20("TestTokenC", "TESTC") { - _mint(msg.sender, initialSupply); - } -} diff --git a/contract/doc/MathDoc.md b/contract/doc/MathDoc.md deleted file mode 100644 index f2f39a2..0000000 --- a/contract/doc/MathDoc.md +++ /dev/null @@ -1,104 +0,0 @@ -# SparkNFT 收益 - -## 名词表 - -- 「刚刚被 `publish()` 出来的那个 NFT」为第 $L_0$ 层。 -- 某用户在 `acceptShill()` 后会获得一个第 $L_n$ 层 NFT。 - > `Layer` -- 生成 $L_n$ 层的 NFT 需要调用 `acceptShill()` ,调用此函数时需要携带的 `msg.value` 为 $P_n$ - > `Price` 。其中 $P_0$ 没有意义, $P_1$ 由 `publish()` 的传入参数决定 -- $D = P_n \div P_{n-1}$ - > 每层购买价格的衰减比率 (`Decay`), $0 < D < 1$ ,由合约内置,全合约统一,不可更改 -- 本内容树允许每个 NFT 派生出 $S$ 个下级 NFT - > `Shill` ,由 `publish()` 传入参数决定。可以理解为 `S叉树` 。 -- 内容树第$N$层的节点数量同样一$S$控制, $T_n = S^{n}$ -- $L_n$ 的 NFT 获取利润后,需要上交给 $L_{n-1}$ 其所得的 $R$ 倍 - > `Royalty Fee` , $0 < R < 1$ ,由 `publish()` 传入参数决定。 - > 一般场景下不会大于 $10\%$ ,过大不利于调动传播者积极性。 - -## 场景 - -### 新用户购买第 $L_n$ 层所需付费金额 - -- $L_1$ -$$ -P_1 -$$ - -- $L_2$ -$$ -P_1D -$$ - -- $L_n$ -$$ -P_{n-1}D \\ -= P_1D^n -$$ - -### 在有新用户购买第 $X$ 层的 NFT 后,第 $Y$ 层会收到的钱 -收到的钱分为两部分 -- 一部分留在了第 $Y$ 层 -- 另一部分传递到上层 - -- $L_1$ , $L_0$ - - Keep in $L_0$ -$$ -P_1 -$$ - -- $L_2$ - - Keep in $L_1$ -$$ -P_2(1-R) \\ -= P_1D(1-R) -$$ - - Keep in $L_0$ -$$ -P_2R \\ -= P_1DR -$$ -- $L_n \qquad {n > 1}$ - - Keep in $L_{n-1}$ -$$ -P_n(1-R) \\ -= P_{n-1}D(1-R) \\ -= P_1D^{n-1}(1-R) -$$ - - Keep in $L_{n-2}$ -$$ -P_nR \\ -= P_{n-1}DR \\ -= P_1D^{n-1}R -$$ - - Keep in $L_0$ -$$ -P_nR^{n-1} \\ -= P_{n-1}DR^{n-1} \\ -= P_1D^{n-1}R^{n-1} -$$ - - - -### 当$N$层被填满时第$0$层的总收益 -第$N$层的节点数量$T$受到$S$的控制,呈指数增长。 -第$N$层的单价受$D$的控制,指数递减。 -$L_0$从第$N$层的每个NFT获取的利润受$R$的控制,呈指数递减。 -- 第$1$层 -$$ -P_1S -$$ -- 第$2$层 -$$ -P_2S^2R \\ -= P_1DS^2R -$$ - -- 第$N$层 -$$ -P_nS^nR^{n-1} \\ -= P_1D^{n-1}S^nR^{n-1} -$$ -即从第二层开始,第$N$层带给$L_0$的利润增长或下降幅度收到$D, S ,R$三个量的控制,其中D为常数,目前设定为$0.9$ -当$DSR>1$即$SR>1 \div D$时当$N$层被填满时第$0$层的总收益持增长趋势 -此公式同时适用于对任意一节点。 \ No newline at end of file diff --git a/contract/doc/SparkLink_API.md b/contract/doc/SparkLink_API.md deleted file mode 100644 index e104310..0000000 --- a/contract/doc/SparkLink_API.md +++ /dev/null @@ -1,41 +0,0 @@ -# SparkNFT Smart Contract API - -## Contract ABI interface - -List of functions (follow the link to the comment): - -- [publish](./../contracts/SparkNFT.sol) -- [acceptShill]() -- [claimProfit]() -- [determinePrice]() -- [determinePriceAndApprove]() - - -Besides, `SparkNFT Smart Contract` is also a special ERC-721 NFT (attached a tree data structure). - -- Therefore, it supports NFT-721 interfaces, like `ownerOf`, `balanceOf`. -- Since it is special, the behavior of `mint` is very different from common ERC-721 NFT. - There are two methods to mint a new NFT. - When publisher `publish` an issue (represent an series of NFTs), contract will generate a root NFT and transfer it to him. - Then other buyer can using `acceptShill` with a NFT ID mint a NFT which is a child NFT of the NFT ID it used. - In the second progress, buyer need pay for this NFT's price to the owner of the NFT ID he inputs. - And when some one mint NFT from new this NFT, the owner of its father NFT will get part of amount it sells. -- There are some slight differences at the behavior of `token transfer` function. - This token is integrated a price mechanism, if token's price is determined by owner, `transfer` function will check if the value of this transaction is equal price. - -## `Edition` data structure -- -## `Issue` data structure(abstract) -- To reduce gas costs due to storage, we storage - -## Function Briefing - -### 1. publish - -Publisher can call this function to create an issue (e.g a book) which contains several NFT with same or similar content. -The publisher need to provide four elements: first sell price, royalty fee percent, shill times and IPFS hash. - -**`function publish(uint128 _first_sell_price, uint8 _royalty_fee, uint8 _shill_times, bytes32 _ipfs_hash)`** - -- Parameters: - - `_first_sell_price`: \ No newline at end of file diff --git a/contract/doc/gas_report.txt b/contract/doc/gas_report.txt deleted file mode 100644 index c9e3693..0000000 --- a/contract/doc/gas_report.txt +++ /dev/null @@ -1,46 +0,0 @@ -·-------------------------------------------|---------------------------|-------------|-----------------------------· -| Solc version: 0.8.4 · Optimizer enabled: true · Runs: 200 · Block limit: 30000000 gas │ -············································|···························|·············|······························ -| Methods │ -···············|····························|·············|·············|·············|···············|·············· -| Contract · Method · Min · Max · Avg · # calls · usd (avg) │ -···············|····························|·············|·············|·············|···············|·············· -| BurnToken · approve · 46215 · 46227 · 46221 · 18 · - │ -···············|····························|·············|·············|·············|···············|·············· -| BurnToken · transfer · 51661 · 51673 · 51666 · 18 · - │ -···············|····························|·············|·············|·············|···············|·············· -| SparkLink · acceptShill · 118919 · 236659 · 158398 · 163 · - │ -···············|····························|·············|·············|·············|···············|·············· -| SparkLink · approve · - · - · 49127 · 2 · - │ -···············|····························|·············|·············|·············|···············|·············· -| SparkLink · claimProfit · 49156 · 119863 · 67844 · 82 · - │ -···············|····························|·············|·············|·············|···············|·············· -| SparkLink · determinePrice · 28369 · 48281 · 36416 · 6 · - │ -···············|····························|·············|·············|·············|···············|·············· -| SparkLink · determinePriceAndApprove · 41601 · 75837 · 72573 · 43 · - │ -···············|····························|·············|·············|·············|···············|·············· -| SparkLink · label · - · - · 27960 · 2 · - │ -···············|····························|·············|·············|·············|···············|·············· -| SparkLink · publish · 142409 · 167917 · 146479 · 44 · - │ -···············|····························|·············|·············|·············|···············|·············· -| SparkLink · safeTransferFrom · 88130 · 183203 · 131705 · 37 · - │ -···············|····························|·············|·············|·············|···············|·············· -| SparkLink · setApprovalForAll · 24323 · 46235 · 38931 · 3 · - │ -···············|····························|·············|·············|·············|···············|·············· -| SparkLink · setURI · - · - · 34067 · 1 · - │ -···············|····························|·············|·············|·············|···············|·············· -| TestTokenA · approve · 46203 · 46287 · 46221 · 52 · - │ -···············|····························|·············|·············|·············|···············|·············· -| TestTokenA · transfer · 51537 · 51561 · 51550 · 31 · - │ -···············|····························|·············|·············|·············|···············|·············· -| TestTokenA · transferFrom · 59287 · 59299 · 59292 · 19 · - │ -···············|····························|·············|·············|·············|···············|·············· -| Deployments · · % of limit · │ -············································|·············|·············|·············|···············|·············· -| BurnToken · - · - · 654071 · 2.2 % · - │ -············································|·············|·············|·············|···············|·············· -| SparkLink · 4437104 · 4437116 · 4437113 · 14.8 % · - │ -············································|·············|·············|·············|···············|·············· -| TestTokenA · - · - · 638568 · 2.1 % · - │ -·-------------------------------------------|-------------|-------------|-------------|---------------|-------------· - diff --git a/contract/doc/tmp.md b/contract/doc/tmp.md deleted file mode 100644 index 34bdb6d..0000000 --- a/contract/doc/tmp.md +++ /dev/null @@ -1,20 +0,0 @@ -目前增加了ERC20的支持。 -新增的变化有: -publish 多传入一个address类型的_token_addr参数 -shill_times的类型由uint8改为了uint16 -多了两个接口 -getTokenAddrByIssueId -getTokenAddrByNFTId -用于查询对应issue内支持的流通代币的地址 -除了今天讨论的前端的填入地址的变化之外。 -在铸造和购买两个页面都需要有approve的操作了目前。 - -部署地址: -rinkeby: -0xca6090D6F006eF6Dbf7E177b0197aD12B36cd476 -matic: -0xb42d4525841008A69E427026DF354067fD6A524f - -这部分的测试考虑了我们前面说过的相对比较常见的打入账户的token的数量与transfer的时候不一样的情况 -在这种情况下是work的,其他的情况我觉得就是publisher自己的锅了 -(俺去帮女友搬家了今天,嘿嘿。 \ No newline at end of file diff --git a/contract/hardhat.config.ts b/contract/hardhat.config.ts deleted file mode 100644 index 374c632..0000000 --- a/contract/hardhat.config.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { task } from "hardhat/config"; -import '@typechain/hardhat' -import '@nomiclabs/hardhat-ethers' -import "@nomiclabs/hardhat-waffle"; -import "hardhat-gas-reporter"; -import 'hardhat-deploy'; -import 'hardhat-deploy-ethers'; -import chain from "./chain"; - -// This is a sample Hardhat task. To learn how to create your own go to -// https://hardhat.org/guides/create-task.html -task("accounts", "Prints the list of accounts", async (_args, hre) => { - const accounts = await hre.ethers.getSigners(); - - for (const account of accounts) { - console.log(account.address); - } -}); - -// You need to export an object to set up your config -// Go to https://hardhat.org/config/ to learn more - -/** - * @type import('hardhat/config').HardhatUserConfig - */ -export default { - ...chain, - solidity: { - version: "0.8.4", - settings: { - optimizer: { - enabled: true, - runs: 200, - }, - }, - } , - gasReporter: { - currency: 'USD', - gasPrice: '40', - }, - typechain: { - outDir: 'artifacts/typechain', - target: 'ethers-v5', - }, - external: { - contracts: [ - { - artifacts: 'node_modules/@uniswap/v2-core/build', - }, - { - artifacts: 'node_modules/@uniswap/v2-periphery/build', - }, - ], - }, -}; diff --git a/contract/package.json b/contract/package.json deleted file mode 100644 index 8d31a59..0000000 --- a/contract/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "hardhat-project", - "devDependencies": { - "@nomiclabs/hardhat-ethers": "^2.0.2", - "@nomiclabs/hardhat-solhint": "^2.0.0", - "@nomiclabs/hardhat-waffle": "^2.0.1", - "@typechain/ethers-v5": "^7.0.1", - "@typechain/hardhat": "^2.3.0", - "@types/chai": "^4.2.21", - "@types/mocha": "^9.0.0", - "@types/node": "^16.7.2", - "chai": "^4.3.4", - "ethereum-waffle": "^3.4.0", - "ethers": "^5.4.4", - "hardhat": "^2.6.0", - "hardhat-deploy": "^0.9.4", - "hardhat-gas-reporter": "^1.0.4", - "ts-node": "^10.2.1", - "typechain": "^6.0.2", - "typescript": "^4.3.5" - }, - "dependencies": { - "@openzeppelin/contracts": "^4.2.0", - "@uniswap/v2-core": "^1.0.1", - "@uniswap/v2-periphery": "^1.1.0-beta.0", - "weth": "^1.0.4", - "hardhat-deploy": "^0.9.4", - "hardhat-deploy-ethers": "^0.3.0-beta.11" - } -} diff --git a/contract/publish.sol b/contract/publish.sol deleted file mode 100644 index 5ce27a5..0000000 --- a/contract/publish.sol +++ /dev/null @@ -1,2220 +0,0 @@ - -// Sources flattened with hardhat v2.6.1 https://hardhat.org - -// File contracts/IERC721Receiver.sol - -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -/** - * @title ERC721 token receiver interface - * @dev Interface for any contract that wants to support safeTransfers - * from ERC721 asset contracts. - */ -interface IERC721Receiver { - /** - * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} - * by `operator` from `from`, this function is called. - * - * It must return its Solidity selector to confirm the token transfer. - * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. - * - * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. - */ - function onERC721Received( - address operator, - address from, - uint256 tokenId, - bytes calldata data - ) external returns (bytes4); -} - - -// File @openzeppelin/contracts/utils/introspection/IERC165.sol@v4.3.0 - - - -pragma solidity ^0.8.0; - -/** - * @dev Interface of the ERC165 standard, as defined in the - * https://eips.ethereum.org/EIPS/eip-165[EIP]. - * - * Implementers can declare support of contract interfaces, which can then be - * queried by others ({ERC165Checker}). - * - * For an implementation, see {ERC165}. - */ -interface IERC165 { - /** - * @dev Returns true if this contract implements the interface defined by - * `interfaceId`. See the corresponding - * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] - * to learn more about how these ids are created. - * - * This function call must use less than 30 000 gas. - */ - function supportsInterface(bytes4 interfaceId) external view returns (bool); -} - - -// File contracts/IERC721.sol - - - -pragma solidity >= 0.8.0; - -/// @title ERC-721 Non-Fungible Token Standard -/// @dev See https://eips.ethereum.org/EIPS/eip-721 -/// Note: the ERC-165 identifier for this interface is 0x80ac58cd. -interface IERC721 is IERC165 { - /** - * @dev Emitted when `tokenId` token is transferred from `from` to `to`. - */ - event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); - - /** - * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. - */ - event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); - - /** - * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. - */ - event ApprovalForAll(address indexed owner, address indexed operator, bool approved); - - /** - * @dev Returns the number of tokens in ``owner``'s account. - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @dev Returns the owner of the `tokenId` token. - * - * Requirements: - * - * - `tokenId` must exist. - */ - function ownerOf(uint256 tokenId) external view returns (address owner); - - /** - * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients - * are aware of the ERC721 protocol to prevent tokens from being forever locked. - * - * Requirements: - * - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `tokenId` token must exist and be owned by `from`. - * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. - * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. - * - * Emits a {Transfer} event. - */ - function safeTransferFrom( - address from, - address to, - uint256 tokenId - ) payable external; - - /** - * @dev Transfers `tokenId` token from `from` to `to`. - * - * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. - * - * Requirements: - * - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `tokenId` token must be owned by `from`. - * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. - * - * Emits a {Transfer} event. - */ - function transferFrom( - address from, - address to, - uint256 tokenId - ) payable external; - - /** - * @dev Gives permission to `to` to transfer `tokenId` token to another account. - * The approval is cleared when the token is transferred. - * - * Only a single account can be approved at a time, so approving the zero address clears previous approvals. - * - * Requirements: - * - * - The caller must own the token or be an approved operator. - * - `tokenId` must exist. - * - * Emits an {Approval} event. - */ - function approve(address to, uint256 tokenId) external; - - /** - * @dev Returns the account approved for `tokenId` token. - * - * Requirements: - * - * - `tokenId` must exist. - */ - function getApproved(uint256 tokenId) external view returns (address operator); - - /** - * @dev Approve or remove `operator` as an operator for the caller. - * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. - * - * Requirements: - * - * - The `operator` cannot be the caller. - * - * Emits an {ApprovalForAll} event. - */ - function setApprovalForAll(address operator, bool _approved) external; - - /** - * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. - * - * See {setApprovalForAll} - */ - function isApprovedForAll(address owner, address operator) external view returns (bool); - - /** - * @dev Safely transfers `tokenId` token from `from` to `to`. - * - * Requirements: - * - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `tokenId` token must exist and be owned by `from`. - * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. - * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. - * - * Emits a {Transfer} event. - */ - function safeTransferFrom( - address from, - address to, - uint256 tokenId, - bytes calldata data - ) payable external; -} - - -// File contracts/IERC721Metadata.sol - - - -pragma solidity ^0.8.0; - -/** - * @title ERC-721 Non-Fungible Token Standard, optional metadata extension - * @dev See https://eips.ethereum.org/EIPS/eip-721 - */ -interface IERC721Metadata is IERC721 { - /** - * @dev Returns the token collection name. - */ - function name() external view returns (string memory); - - /** - * @dev Returns the token collection symbol. - */ - function symbol() external view returns (string memory); - - /** - * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. - */ - function tokenURI(uint256 tokenId) external view returns (string memory); -} - - -// File @openzeppelin/contracts/utils/Counters.sol@v4.3.0 - - - -pragma solidity ^0.8.0; - -/** - * @title Counters - * @author Matt Condon (@shrugs) - * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number - * of elements in a mapping, issuing ERC721 ids, or counting request ids. - * - * Include with `using Counters for Counters.Counter;` - */ -library Counters { - struct Counter { - // This variable should never be directly accessed by users of the library: interactions must be restricted to - // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add - // this feature: see https://github.com/ethereum/solidity/issues/4637 - uint256 _value; // default: 0 - } - - function current(Counter storage counter) internal view returns (uint256) { - return counter._value; - } - - function increment(Counter storage counter) internal { - unchecked { - counter._value += 1; - } - } - - function decrement(Counter storage counter) internal { - uint256 value = counter._value; - require(value > 0, "Counter: decrement overflow"); - unchecked { - counter._value = value - 1; - } - } - - function reset(Counter storage counter) internal { - counter._value = 0; - } -} - - -// File @openzeppelin/contracts/utils/Address.sol@v4.3.0 - - - -pragma solidity ^0.8.0; - -/** - * @dev Collection of functions related to the address type - */ -library Address { - /** - * @dev Returns true if `account` is a contract. - * - * [IMPORTANT] - * ==== - * It is unsafe to assume that an address for which this function returns - * false is an externally-owned account (EOA) and not a contract. - * - * Among others, `isContract` will return false for the following - * types of addresses: - * - * - an externally-owned account - * - a contract in construction - * - an address where a contract will be created - * - an address where a contract lived, but was destroyed - * ==== - */ - function isContract(address account) internal view returns (bool) { - // This method relies on extcodesize, which returns 0 for contracts in - // construction, since the code is only stored at the end of the - // constructor execution. - - uint256 size; - assembly { - size := extcodesize(account) - } - return size > 0; - } - - /** - * @dev Replacement for Solidity's `transfer`: sends `amount` wei to - * `recipient`, forwarding all available gas and reverting on errors. - * - * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost - * of certain opcodes, possibly making contracts go over the 2300 gas limit - * imposed by `transfer`, making them unable to receive funds via - * `transfer`. {sendValue} removes this limitation. - * - * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. - * - * IMPORTANT: because control is transferred to `recipient`, care must be - * taken to not create reentrancy vulnerabilities. Consider using - * {ReentrancyGuard} or the - * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. - */ - function sendValue(address payable recipient, uint256 amount) internal { - require(address(this).balance >= amount, "Address: insufficient balance"); - - (bool success, ) = recipient.call{value: amount}(""); - require(success, "Address: unable to send value, recipient may have reverted"); - } - - /** - * @dev Performs a Solidity function call using a low level `call`. A - * plain `call` is an unsafe replacement for a function call: use this - * function instead. - * - * If `target` reverts with a revert reason, it is bubbled up by this - * function (like regular Solidity function calls). - * - * Returns the raw returned data. To convert to the expected return value, - * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. - * - * Requirements: - * - * - `target` must be a contract. - * - calling `target` with `data` must not revert. - * - * _Available since v3.1._ - */ - function functionCall(address target, bytes memory data) internal returns (bytes memory) { - return functionCall(target, data, "Address: low-level call failed"); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with - * `errorMessage` as a fallback revert reason when `target` reverts. - * - * _Available since v3.1._ - */ - function functionCall( - address target, - bytes memory data, - string memory errorMessage - ) internal returns (bytes memory) { - return functionCallWithValue(target, data, 0, errorMessage); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], - * but also transferring `value` wei to `target`. - * - * Requirements: - * - * - the calling contract must have an ETH balance of at least `value`. - * - the called Solidity function must be `payable`. - * - * _Available since v3.1._ - */ - function functionCallWithValue( - address target, - bytes memory data, - uint256 value - ) internal returns (bytes memory) { - return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); - } - - /** - * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but - * with `errorMessage` as a fallback revert reason when `target` reverts. - * - * _Available since v3.1._ - */ - function functionCallWithValue( - address target, - bytes memory data, - uint256 value, - string memory errorMessage - ) internal returns (bytes memory) { - require(address(this).balance >= value, "Address: insufficient balance for call"); - require(isContract(target), "Address: call to non-contract"); - - (bool success, bytes memory returndata) = target.call{value: value}(data); - return verifyCallResult(success, returndata, errorMessage); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], - * but performing a static call. - * - * _Available since v3.3._ - */ - function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { - return functionStaticCall(target, data, "Address: low-level static call failed"); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], - * but performing a static call. - * - * _Available since v3.3._ - */ - function functionStaticCall( - address target, - bytes memory data, - string memory errorMessage - ) internal view returns (bytes memory) { - require(isContract(target), "Address: static call to non-contract"); - - (bool success, bytes memory returndata) = target.staticcall(data); - return verifyCallResult(success, returndata, errorMessage); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], - * but performing a delegate call. - * - * _Available since v3.4._ - */ - function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { - return functionDelegateCall(target, data, "Address: low-level delegate call failed"); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], - * but performing a delegate call. - * - * _Available since v3.4._ - */ - function functionDelegateCall( - address target, - bytes memory data, - string memory errorMessage - ) internal returns (bytes memory) { - require(isContract(target), "Address: delegate call to non-contract"); - - (bool success, bytes memory returndata) = target.delegatecall(data); - return verifyCallResult(success, returndata, errorMessage); - } - - /** - * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the - * revert reason using the provided one. - * - * _Available since v4.3._ - */ - function verifyCallResult( - bool success, - bytes memory returndata, - string memory errorMessage - ) internal pure returns (bytes memory) { - if (success) { - return returndata; - } else { - // Look for revert reason and bubble it up if present - if (returndata.length > 0) { - // The easiest way to bubble the revert reason is using memory via assembly - - assembly { - let returndata_size := mload(returndata) - revert(add(32, returndata), returndata_size) - } - } else { - revert(errorMessage); - } - } - } -} - - -// File @openzeppelin/contracts/utils/Context.sol@v4.3.0 - - - -pragma solidity ^0.8.0; - -/** - * @dev Provides information about the current execution context, including the - * sender of the transaction and its data. While these are generally available - * via msg.sender and msg.data, they should not be accessed in such a direct - * manner, since when dealing with meta-transactions the account sending and - * paying for execution may not be the actual sender (as far as an application - * is concerned). - * - * This contract is only required for intermediate, library-like contracts. - */ -abstract contract Context { - function _msgSender() internal view virtual returns (address) { - return msg.sender; - } - - function _msgData() internal view virtual returns (bytes calldata) { - return msg.data; - } -} - - -// File @openzeppelin/contracts/utils/Strings.sol@v4.3.0 - - - -pragma solidity ^0.8.0; - -/** - * @dev String operations. - */ -library Strings { - bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; - - /** - * @dev Converts a `uint256` to its ASCII `string` decimal representation. - */ - function toString(uint256 value) internal pure returns (string memory) { - // Inspired by OraclizeAPI's implementation - MIT licence - // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol - - if (value == 0) { - return "0"; - } - uint256 temp = value; - uint256 digits; - while (temp != 0) { - digits++; - temp /= 10; - } - bytes memory buffer = new bytes(digits); - while (value != 0) { - digits -= 1; - buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); - value /= 10; - } - return string(buffer); - } - - /** - * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. - */ - function toHexString(uint256 value) internal pure returns (string memory) { - if (value == 0) { - return "0x00"; - } - uint256 temp = value; - uint256 length = 0; - while (temp != 0) { - length++; - temp >>= 8; - } - return toHexString(value, length); - } - - /** - * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. - */ - function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { - bytes memory buffer = new bytes(2 * length + 2); - buffer[0] = "0"; - buffer[1] = "x"; - for (uint256 i = 2 * length + 1; i > 1; --i) { - buffer[i] = _HEX_SYMBOLS[value & 0xf]; - value >>= 4; - } - require(value == 0, "Strings: hex length insufficient"); - return string(buffer); - } -} - - -// File @openzeppelin/contracts/utils/introspection/ERC165.sol@v4.3.0 - - - -pragma solidity ^0.8.0; - -/** - * @dev Implementation of the {IERC165} interface. - * - * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check - * for the additional interface id that will be supported. For example: - * - * ```solidity - * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { - * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); - * } - * ``` - * - * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. - */ -abstract contract ERC165 is IERC165 { - /** - * @dev See {IERC165-supportsInterface}. - */ - function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { - return interfaceId == type(IERC165).interfaceId; - } -} - - -// File @openzeppelin/contracts/token/ERC20/IERC20.sol@v4.3.0 - - - -pragma solidity ^0.8.0; - -/** - * @dev Interface of the ERC20 standard as defined in the EIP. - */ -interface IERC20 { - /** - * @dev Returns the amount of tokens in existence. - */ - function totalSupply() external view returns (uint256); - - /** - * @dev Returns the amount of tokens owned by `account`. - */ - function balanceOf(address account) external view returns (uint256); - - /** - * @dev Moves `amount` tokens from the caller's account to `recipient`. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Emits a {Transfer} event. - */ - function transfer(address recipient, uint256 amount) external returns (bool); - - /** - * @dev Returns the remaining number of tokens that `spender` will be - * allowed to spend on behalf of `owner` through {transferFrom}. This is - * zero by default. - * - * This value changes when {approve} or {transferFrom} are called. - */ - function allowance(address owner, address spender) external view returns (uint256); - - /** - * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * IMPORTANT: Beware that changing an allowance with this method brings the risk - * that someone may use both the old and the new allowance by unfortunate - * transaction ordering. One possible solution to mitigate this race - * condition is to first reduce the spender's allowance to 0 and set the - * desired value afterwards: - * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 - * - * Emits an {Approval} event. - */ - function approve(address spender, uint256 amount) external returns (bool); - - /** - * @dev Moves `amount` tokens from `sender` to `recipient` using the - * allowance mechanism. `amount` is then deducted from the caller's - * allowance. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Emits a {Transfer} event. - */ - function transferFrom( - address sender, - address recipient, - uint256 amount - ) external returns (bool); - - /** - * @dev Emitted when `value` tokens are moved from one account (`from`) to - * another (`to`). - * - * Note that `value` may be zero. - */ - event Transfer(address indexed from, address indexed to, uint256 value); - - /** - * @dev Emitted when the allowance of a `spender` for an `owner` is set by - * a call to {approve}. `value` is the new allowance. - */ - event Approval(address indexed owner, address indexed spender, uint256 value); -} - - -// File @openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol@v4.3.0 - - - -pragma solidity ^0.8.0; - - -/** - * @title SafeERC20 - * @dev Wrappers around ERC20 operations that throw on failure (when the token - * contract returns false). Tokens that return no value (and instead revert or - * throw on failure) are also supported, non-reverting calls are assumed to be - * successful. - * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, - * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. - */ -library SafeERC20 { - using Address for address; - - function safeTransfer( - IERC20 token, - address to, - uint256 value - ) internal { - _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); - } - - function safeTransferFrom( - IERC20 token, - address from, - address to, - uint256 value - ) internal { - _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); - } - - /** - * @dev Deprecated. This function has issues similar to the ones found in - * {IERC20-approve}, and its usage is discouraged. - * - * Whenever possible, use {safeIncreaseAllowance} and - * {safeDecreaseAllowance} instead. - */ - function safeApprove( - IERC20 token, - address spender, - uint256 value - ) internal { - // safeApprove should only be called when setting an initial allowance, - // or when resetting it to zero. To increase and decrease it, use - // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' - require( - (value == 0) || (token.allowance(address(this), spender) == 0), - "SafeERC20: approve from non-zero to non-zero allowance" - ); - _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); - } - - function safeIncreaseAllowance( - IERC20 token, - address spender, - uint256 value - ) internal { - uint256 newAllowance = token.allowance(address(this), spender) + value; - _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); - } - - function safeDecreaseAllowance( - IERC20 token, - address spender, - uint256 value - ) internal { - unchecked { - uint256 oldAllowance = token.allowance(address(this), spender); - require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); - uint256 newAllowance = oldAllowance - value; - _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); - } - } - - /** - * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement - * on the return value: the return value is optional (but if data is returned, it must not be false). - * @param token The token targeted by the call. - * @param data The call data (encoded using abi.encode or one of its variants). - */ - function _callOptionalReturn(IERC20 token, bytes memory data) private { - // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since - // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that - // the target address contains contract code and also asserts for success in the low-level call. - - bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); - if (returndata.length > 0) { - // Return data is optional - require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); - } - } -} - - -// File @openzeppelin/contracts/access/Ownable.sol@v4.3.0 - - - -pragma solidity ^0.8.0; - -/** - * @dev Contract module which provides a basic access control mechanism, where - * there is an account (an owner) that can be granted exclusive access to - * specific functions. - * - * By default, the owner account will be the one that deploys the contract. This - * can later be changed with {transferOwnership}. - * - * This module is used through inheritance. It will make available the modifier - * `onlyOwner`, which can be applied to your functions to restrict their use to - * the owner. - */ -abstract contract Ownable is Context { - address private _owner; - - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); - - /** - * @dev Initializes the contract setting the deployer as the initial owner. - */ - constructor() { - _setOwner(_msgSender()); - } - - /** - * @dev Returns the address of the current owner. - */ - function owner() public view virtual returns (address) { - return _owner; - } - - /** - * @dev Throws if called by any account other than the owner. - */ - modifier onlyOwner() { - require(owner() == _msgSender(), "Ownable: caller is not the owner"); - _; - } - - /** - * @dev Leaves the contract without owner. It will not be possible to call - * `onlyOwner` functions anymore. Can only be called by the current owner. - * - * NOTE: Renouncing ownership will leave the contract without an owner, - * thereby removing any functionality that is only available to the owner. - */ - function renounceOwnership() public virtual onlyOwner { - _setOwner(address(0)); - } - - /** - * @dev Transfers ownership of the contract to a new account (`newOwner`). - * Can only be called by the current owner. - */ - function transferOwnership(address newOwner) public virtual onlyOwner { - require(newOwner != address(0), "Ownable: new owner is the zero address"); - _setOwner(newOwner); - } - - function _setOwner(address newOwner) private { - address oldOwner = _owner; - _owner = newOwner; - emit OwnershipTransferred(oldOwner, newOwner); - } -} - - -// File @uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol@v1.1.0-beta.0 - -pragma solidity >=0.6.2; - -interface IUniswapV2Router01 { - function factory() external pure returns (address); - function WETH() external pure returns (address); - - function addLiquidity( - address tokenA, - address tokenB, - uint amountADesired, - uint amountBDesired, - uint amountAMin, - uint amountBMin, - address to, - uint deadline - ) external returns (uint amountA, uint amountB, uint liquidity); - function addLiquidityETH( - address token, - uint amountTokenDesired, - uint amountTokenMin, - uint amountETHMin, - address to, - uint deadline - ) external payable returns (uint amountToken, uint amountETH, uint liquidity); - function removeLiquidity( - address tokenA, - address tokenB, - uint liquidity, - uint amountAMin, - uint amountBMin, - address to, - uint deadline - ) external returns (uint amountA, uint amountB); - function removeLiquidityETH( - address token, - uint liquidity, - uint amountTokenMin, - uint amountETHMin, - address to, - uint deadline - ) external returns (uint amountToken, uint amountETH); - function removeLiquidityWithPermit( - address tokenA, - address tokenB, - uint liquidity, - uint amountAMin, - uint amountBMin, - address to, - uint deadline, - bool approveMax, uint8 v, bytes32 r, bytes32 s - ) external returns (uint amountA, uint amountB); - function removeLiquidityETHWithPermit( - address token, - uint liquidity, - uint amountTokenMin, - uint amountETHMin, - address to, - uint deadline, - bool approveMax, uint8 v, bytes32 r, bytes32 s - ) external returns (uint amountToken, uint amountETH); - function swapExactTokensForTokens( - uint amountIn, - uint amountOutMin, - address[] calldata path, - address to, - uint deadline - ) external returns (uint[] memory amounts); - function swapTokensForExactTokens( - uint amountOut, - uint amountInMax, - address[] calldata path, - address to, - uint deadline - ) external returns (uint[] memory amounts); - function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) - external - payable - returns (uint[] memory amounts); - function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) - external - returns (uint[] memory amounts); - function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) - external - returns (uint[] memory amounts); - function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) - external - payable - returns (uint[] memory amounts); - - function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); - function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); - function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); - function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); - function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); -} - - -// File @uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol@v1.1.0-beta.0 - -pragma solidity >=0.6.2; - -interface IUniswapV2Router02 is IUniswapV2Router01 { - function removeLiquidityETHSupportingFeeOnTransferTokens( - address token, - uint liquidity, - uint amountTokenMin, - uint amountETHMin, - address to, - uint deadline - ) external returns (uint amountETH); - function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( - address token, - uint liquidity, - uint amountTokenMin, - uint amountETHMin, - address to, - uint deadline, - bool approveMax, uint8 v, bytes32 r, bytes32 s - ) external returns (uint amountETH); - - function swapExactTokensForTokensSupportingFeeOnTransferTokens( - uint amountIn, - uint amountOutMin, - address[] calldata path, - address to, - uint deadline - ) external; - function swapExactETHForTokensSupportingFeeOnTransferTokens( - uint amountOutMin, - address[] calldata path, - address to, - uint deadline - ) external payable; - function swapExactTokensForETHSupportingFeeOnTransferTokens( - uint amountIn, - uint amountOutMin, - address[] calldata path, - address to, - uint deadline - ) external; -} - - -// File @uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol@v1.0.1 - -pragma solidity >=0.5.0; - -interface IUniswapV2Factory { - event PairCreated(address indexed token0, address indexed token1, address pair, uint); - - function feeTo() external view returns (address); - function feeToSetter() external view returns (address); - - function getPair(address tokenA, address tokenB) external view returns (address pair); - function allPairs(uint) external view returns (address pair); - function allPairsLength() external view returns (uint); - - function createPair(address tokenA, address tokenB) external returns (address pair); - - function setFeeTo(address) external; - function setFeeToSetter(address) external; -} - - -// File contracts/SparkLink.sol - - - -pragma solidity >= 0.8.4; - - - - - - - - - - - - - -contract SparkLink is Ownable, ERC165, IERC721, IERC721Metadata{ - using Address for address; - using Counters for Counters.Counter; - using SafeERC20 for IERC20; - Counters.Counter private _issueIds; - /* - Abstract struct Issue { - uint32 total_amount; - bool is_free - bool is_ND; - bool is_NC; - uint16 shill_times; - uint8 royalty_fee; - } - This structure records some common attributes of a series of NFTs: - - `royalty_fee`: the proportion of royaltyes - - `shill_times`: the number of times a single NFT can been shared - - `total_amount`: the total number of NFTs in the series - To reduce gas cost, this structure is actually stored in the `father_id` attibute of root NFT - - 0~31 `total_amount` - - 37 `is_free` - - 38 `is_NC` - - 39 `is_ND` - - 40~55 `shill_times` - - 56~63 `royalty_fee` - */ - - struct Edition { - // This structure stores NFT related information: - // - `father_id`: For root NFT it stores issue abstract sturcture - // For other NFTs its stores the NFT Id of which NFT it `acceptShill` from - // - `shill_price`: The price should be paid when others `accpetShill` from this NFT - // - remaining_shill_times: The initial value is the shilltimes of the issue it belongs to - // When others `acceptShill` from this NFT, it will subtract one until its value is 0 - // - `owner`: record the owner of this NFT - // - `ipfs_hash`: IPFS hash value of the URI where this NTF's metadata stores - // - `transfer_price`: The initial value is zero - // Set by `determinePrice` or `determinePriceAndApprove` before `transferFrom` - // It will be checked wether equal to msg.value when `transferFrom` is called - // After `transferFrom` this value will be set to zero - // - `profit`: record the profit owner can claim (include royalty fee it should conduct to its father NFT) - uint64 father_id; - uint128 shill_price; - uint16 remaining_shill_times; - address owner; - bytes32 ipfs_hash; - uint128 transfer_price; - uint128 profit; - } - - // Emit when `determinePrice` success - event DeterminePrice( - uint64 indexed NFT_id, - uint128 transfer_price - ); - - // Emit when `determinePriceAndApprove` success - event DeterminePriceAndApprove( - uint64 indexed NFT_id, - uint128 transfer_price, - address indexed to - ); - - // Emit when `publish` success - // - `rootNFTId`: Record the Id of root NFT given to publisher - event Publish( - address indexed publisher, - uint64 indexed rootNFTId, - address token_addr - ); - - // Emit when claimProfit success - //- `amount`: Record the actual amount owner of this NFT received (profit - profit*royalty_fee/100) - event Claim( - uint64 indexed NFT_id, - address indexed receiver, - uint128 amount - ); - // Emit when setURI success - event SetURI( - uint64 indexed NFT_id, - bytes32 old_URI, - bytes32 new_URI - ); - - event Label( - uint64 indexed NFT_id, - string content - ); - - event SetDAOFee( - uint8 old_DAO_fee, - uint8 new_DAO_fee - ); - - event SetLoosRatio( - uint8 old_loss_ratio, - uint8 new_loss_ratio - ); - - event SetDAORouter01( - address old_router_address, - address new_router_address - ); - - event SetDAORouter02( - address old_router_address, - address new_router_address - ); - - //---------------------------------------------------------------------------------------------------- - /** - * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. - */ - constructor(address DAO_router_address01,address DAO_router_address02, address uniswapRouterAddress, address factoryAddress) { - uniswapV2Router = IUniswapV2Router02(uniswapRouterAddress); - uniswapV2Factory = IUniswapV2Factory(factoryAddress); - DAO_router01 = DAO_router_address01; - DAO_router02 = DAO_router_address02; - _name = "SparkLink"; - _symbol = "SPL"; - } - - /** - * @dev Create a issue and mint a root NFT for buyer acceptShill from - * - * Requirements: - * - * - `_first_sell_price`: The price should be paid when others `accpetShill` from this NFT - * - `_royalty_fee`: The proportion of royaltyes, it represents the ratio of the father NFT's profit from the child NFT - * Its value should <= 100 - * - `_shill_times`: the number of times a single NFT can been shared - * Its value should <= 65536 - * - `_ipfs_hash`: IPFS hash value of the URI where this NTF's metadata stores - * - * - `token_address`: list of tokens(address) can be accepted for payment. - * `A token address` can be ERC-20 token contract address or `address(0)`(ETH). - * - * - `_is_free`: - * - `_is_NC`: - * - * - `_is_ND`: - * Emits a {Publish} event. - * - Emitted {Publish} event contains root NFT id. - */ - function publish( - uint128 _first_sell_price, - uint8 _royalty_fee, - uint16 _shill_times, - bytes32 _ipfs_hash, - address _token_addr, - bool _is_free, - bool _is_NC, - bool _is_ND - ) - external - { - require(_royalty_fee <= 100, "SparkLink: Royalty fee should be <= 100%."); - _issueIds.increment(); - require(_issueIds.current() <= type(uint32).max, "SparkLink: Value doesn't fit in 32 bits."); - if (_token_addr != address(0)) - require(IERC20(_token_addr).totalSupply() > 0, "Not a valid ERC20 token address"); - uint32 new_issue_id = uint32(_issueIds.current()); - uint64 rootNFTId = getNftIdByEditionIdAndIssueId(new_issue_id, 1); - require( - _checkOnERC721Received(address(0), msg.sender, rootNFTId, ""), - "SparkLink: Transfer to non ERC721Receiver implementer" - ); - - Edition storage new_NFT = editions_by_id[rootNFTId]; - uint64 information; - information = reWriteUint8InUint64(56, _royalty_fee, information); - information = reWriteUint16InUint64(40, _shill_times, information); - information = reWriteBoolInUint64(37, _is_free, information); - information = reWriteBoolInUint64(38, _is_NC, information); - information = reWriteBoolInUint64(39, _is_ND, information); - information += 1; - token_addresses[new_issue_id] = _token_addr; - new_NFT.father_id = information; - new_NFT.remaining_shill_times = _shill_times; - new_NFT.shill_price = _first_sell_price; - new_NFT.owner = msg.sender; - new_NFT.ipfs_hash = _ipfs_hash; - _balances[msg.sender] += 1; - emit Transfer(address(0), msg.sender, rootNFTId); - emit Publish( - msg.sender, - rootNFTId, - _token_addr - ); - } - - /** - * @dev Buy a child NFT from the _NFT_id buyer input - * - * Requirements: - * - * - `_NFT_id`: _NFT_id the father NFT id buyer mint NFT from - * remain shill times of the NFT_id you input should greater than 0 - * Emits a {Ttansfer} event. - * - Emitted {Transfer} event from 0x0 address to msg.sender, contain new NFT id. - * - New NFT id will be generater by edition id and issue id - * 0~31 edition id - * 32~63 issue id - */ - function acceptShill( - uint64 _NFT_id - ) - external - payable - { - require(isEditionExisting(_NFT_id), "SparkLink: This NFT does not exist"); - require(editions_by_id[_NFT_id].remaining_shill_times > 0, "SparkLink: There is no remaining shill time for this NFT"); - if (!isRootNFT(_NFT_id)||!getIsFreeByNFTId(_NFT_id)){ - address token_addr = getTokenAddrByNFTId(_NFT_id); - if (token_addr == address(0)){ - require(msg.value == editions_by_id[_NFT_id].shill_price, "SparkLink: Wrong price"); - _addProfit( _NFT_id, editions_by_id[_NFT_id].shill_price); - } - else { - uint256 before_balance = IERC20(token_addr).balanceOf(address(this)); - IERC20(token_addr).safeTransferFrom(msg.sender, address(this), editions_by_id[_NFT_id].shill_price); - _addProfit( _NFT_id, uint256toUint128(IERC20(token_addr).balanceOf(address(this))-before_balance)); - } - } - editions_by_id[_NFT_id].remaining_shill_times -= 1; - _mintNFT(_NFT_id, msg.sender); - if (editions_by_id[_NFT_id].remaining_shill_times == 0) - _mintNFT(_NFT_id, ownerOf(_NFT_id)); - } - - /** - * @dev Transfers `tokenId` token from `from` to `to`. - * - * Requirements: - * - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `tokenId` token must be owned by `from`. - * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. - * - If `transfer_price` has been set, caller should give same value in msg.sender. - * - Will call `claimProfit` before transfer and `transfer_price` will be set to zero after transfer. - * Emits a {TransferAsset} events - */ - function transferFrom(address from, address to, uint256 tokenId) external payable override { - _transfer(from, to, uint256toUint64(tokenId)); - } - - function safeTransferFrom(address from, address to, uint256 tokenId) external payable override{ - _safeTransfer(from, to, uint256toUint64(tokenId), ""); - } - - function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata _data) external payable override { - _safeTransfer(from, to, uint256toUint64(tokenId), _data); - } - - /** - * @dev Claim profit from reward pool of NFT. - * - * Requirements: - * - * - `_NFT_id`: The NFT id of NFT caller claim, the profit will give to its owner. - * - If its profit is zero the event {Claim} will not be emited. - * Emits a {Claim} events - */ - function claimProfit(uint64 _NFT_id) public { - require(isEditionExisting(_NFT_id), "SparkLink: This edition does not exist"); - - if (editions_by_id[_NFT_id].profit != 0) { - uint128 amount = editions_by_id[_NFT_id].profit; - address token_addr = getTokenAddrByNFTId(_NFT_id); - if (DAO_fee != 0) { - uint128 DAO_amount = calculateFee(amount, DAO_fee); - amount -= DAO_amount; - if (token_addr == address(0)) { - payable(DAO_router01).transfer(DAO_amount); - } - else if (uniswapV2Factory.getPair(token_addr, uniswapV2Router.WETH()) == address(0)) { - IERC20(token_addr).safeTransfer(DAO_router02,DAO_amount); - } - else { - _swapTokensForEth(token_addr, DAO_amount); - } - } - editions_by_id[_NFT_id].profit = 0; - if (!isRootNFT(_NFT_id)) { - uint128 _royalty_fee = calculateFee(amount, getRoyaltyFeeByNFTId(_NFT_id)); - _addProfit(getFatherByNFTId(_NFT_id), _royalty_fee); - amount -= _royalty_fee; - } - if (token_addr == address(0)){ - payable(ownerOf(_NFT_id)).transfer(amount); - } - else { - IERC20(token_addr).safeTransfer(ownerOf(_NFT_id), amount); - } - emit Claim( - _NFT_id, - ownerOf(_NFT_id), - amount - ); - } - } - - /** - * @dev Set token URI. - * - * Requirements: - * - * - `_NFT_id`: transferred token id. - * - `ipfs_hash`: ipfs hash value of the URI will be set. - * Emits a {SetURI} events - */ - function setURI(uint64 _NFT_id, bytes32 ipfs_hash) public { - if (getIsNDByNFTId(_NFT_id)) { - require(_NFT_id == getRootNFTIdByNFTId(_NFT_id), "SparkLink: NFT follows the ND protocol, only the root NFT's URI can be set."); - } - require(ownerOf(_NFT_id) == msg.sender, "SparkLink: Only owner can set the token URI"); - _setTokenURI(_NFT_id, ipfs_hash); - } - - /** - * @dev update token URI. - * - * Requirements: - * - * - `_NFT_id`: transferred token id. - */ - function updateURI(uint64 _NFT_id) public{ - require(ownerOf(_NFT_id) == msg.sender, "SparkLink: Only owner can update the token URI"); - editions_by_id[_NFT_id].ipfs_hash = editions_by_id[getRootNFTIdByNFTId(_NFT_id)].ipfs_hash; - } - - function label(uint64 _NFT_id, string memory content) public { - require(ownerOf(_NFT_id) == msg.sender, "SparkLink: Only owner can label this NFT"); - emit Label(_NFT_id, content); - } - /** - * @dev Determine NFT price before transfer. - * - * Requirements: - * - * - `_NFT_id`: transferred token id. - * - `_price`: The amount of ETH should be payed for `_NFT_id` - * Emits a {DeterminePrice} events - */ - function determinePrice( - uint64 _NFT_id, - uint128 _price - ) - public - { - require(isEditionExisting(_NFT_id), "SparkLink: This NFT does not exist"); - require(msg.sender == ownerOf(_NFT_id), "SparkLink: Only owner can set the price"); - editions_by_id[_NFT_id].transfer_price = _price; - emit DeterminePrice(_NFT_id, _price); - } - - /** - * @dev Determine NFT price before transfer. - * - * Requirements: - * - * - `_NFT_id`: transferred token id. - * - `_price`: The amount of ETH should be payed for `_NFT_id` - * - `_to`: The account address `approve` to. - * Emits a {DeterminePriceAndApprove} events - */ - function determinePriceAndApprove( - uint64 _NFT_id, - uint128 _price, - address _to - ) - public - { - determinePrice(_NFT_id, _price); - approve(_to, _NFT_id); - emit DeterminePriceAndApprove(_NFT_id, _price, _to); - } - - function setDAOFee(uint8 _DAO_fee) public onlyOwner { - require(_DAO_fee <= MAX_DAO_FEE, "SparkLink: DAO fee can not exceed 5%"); - emit SetDAOFee(DAO_fee, _DAO_fee); - DAO_fee = _DAO_fee; - } - - function setDAORouter01(address _DAO_router01) public onlyOwner { - emit SetDAORouter01(DAO_router01, _DAO_router01); - DAO_router01 = _DAO_router01; - } - - function setDAORouter02(address _DAO_router02) public onlyOwner { - emit SetDAORouter01(DAO_router02, _DAO_router02); - DAO_router02 = _DAO_router02; - } - - function setUniswapV2Router(address _uniswapV2Router) public onlyOwner { - uniswapV2Router = IUniswapV2Router02(_uniswapV2Router); - } - function setUniswapV2Factory(address _uniswapV2Factory) public onlyOwner { - uniswapV2Factory = IUniswapV2Factory(_uniswapV2Factory); - } - - function setLoosRatio(uint8 _loss_ratio) public onlyOwner { - require(_loss_ratio <= MAX_LOSS_RATIO, "SparkLink: Loss ratio can not below 50%"); - emit SetLoosRatio(loss_ratio, _loss_ratio); - loss_ratio = _loss_ratio; - } - /** - * @dev See {IERC721-approve}. - */ - function approve(address to, uint256 tokenId) public virtual override { - address owner = ownerOf(tokenId); - require(to != owner, "SparkLink: Approval to current owner"); - require( - _msgSender() == owner || isApprovedForAll(owner, _msgSender()), - "SparkLink: Approve caller is not owner nor approved for all" - ); - - _approve(to, uint256toUint64(tokenId)); - } - - /** - * @dev See {IERC721-setApprovalForAll}. - */ - function setApprovalForAll(address operator, bool approved) public virtual override { - require(operator != _msgSender(), "SparkLink: Approve to caller"); - _operatorApprovals[_msgSender()][operator] = approved; - emit ApprovalForAll(_msgSender(), operator, approved); - } - - /** - * @dev See {IERC165-supportsInterface}. - */ - function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { - return - interfaceId == type(IERC721).interfaceId || - interfaceId == type(IERC721Metadata).interfaceId || - super.supportsInterface(interfaceId); - } - - /** - * @dev See {IERC721-balanceOf}. - */ - function balanceOf(address owner) public view virtual override returns (uint256) { - require(owner != address(0), "SparkLink: Balance query for the zero address"); - return _balances[owner]; - } - - /** - * @dev See {IERC721-ownerOf}. - */ - function ownerOf(uint256 tokenId) public view virtual override returns (address) { - address owner = editions_by_id[uint256toUint64(tokenId)].owner; - require(owner != address(0), "SparkLink: Owner query for nonexistent token"); - return owner; - } - - /** - * @dev See {IERC721Metadata-name}. - */ - function name() public view virtual override returns (string memory) { - return _name; - } - - /** - * @dev See {IERC721Metadata-symbol}. - */ - function symbol() public view virtual override returns (string memory) { - return _symbol; - } - - /** - * @dev Query NFT information set. - * - * Requirements: - * - `_NFT_id`: The id of the edition queryed. - * Return : - * - `issue_information`: For root NFT it stores issue abstract sturcture - * - 0~31 `total_amount` - * - 37 `is_free` - * - 38 `is_NC` - * - 39 `is_ND` - * - 40~55 `shill_times` - * - 56~63 `royalty_fee` - * - `father_id`: For root NFT it stores issue abstract sturcture - * For other NFTs its stores the NFT Id of which NFT it `acceptShill` from - * - `shill_price`: The price should be paid when others `accpetShill` from this NFT - * - `remaining_shill_times`: The initial value is the shilltimes of the issue it belongs to - * When others `acceptShill` from this NFT, it will subtract one until its value is 0 - * - `owner`: record the owner of this NFT - * - `transfer_price`: The initial value is zero - * Set by `determinePrice` or `determinePriceAndApprove` before `transferFrom` - * It will be checked wether equal to msg.value when `transferFrom` is called - * After `transferFrom` this value will be set to zero - * - `profit`: record the profit owner can claim (include royalty fee it should conduct to its father NFT) - * - `metadata`: IPFS hash value of the URI where this NTF's metadata stores - */ - - function getNFTInfoByNFTID(uint64 _NFT_id) - public view - returns ( - uint64 issue_information, - uint64 father_id, - uint128 shill_price, - uint16 remain_shill_times, - uint128 profit, - string memory metadata - ) - { - require(isEditionExisting(_NFT_id), "SparkLink: Approved query for nonexistent token"); - return( - editions_by_id[getRootNFTIdByNFTId(_NFT_id)].father_id, - getFatherByNFTId(_NFT_id), - editions_by_id[_NFT_id].shill_price, - getRemainShillTimesByNFTId(_NFT_id), - getProfitByNFTId(_NFT_id), - tokenURI(_NFT_id) - ); - } - - /** - * @dev See {IERC721-getApproved}. - */ - function getApproved(uint256 tokenId) public view virtual override returns (address) { - require(isEditionExisting(uint256toUint64(tokenId)), "SparkLink: Approved query for nonexistent token"); - - return _tokenApprovals[uint256toUint64(tokenId)]; - } - - /** - * @dev See {IERC721-isApprovedForAll}. - */ - function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { - return _operatorApprovals[owner][operator]; - } - - /** - * @dev See {IERC721Metadata-tokenURI}. - */ - function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { - require(isEditionExisting(uint256toUint64(tokenId)), "SparkLink: URI query for nonexistent token"); - bytes32 _ipfs_hash = editions_by_id[uint256toUint64(tokenId)].ipfs_hash; - string memory encoded_hash = _toBase58String(_ipfs_hash); - string memory base = _baseURI(); - return string(abi.encodePacked(base, encoded_hash)); - } - - /** - * @dev Query is issue free for first lever buyer. - * - * Requirements: - * - `_NFT_id`: The id of the edition queryed. - * Return a bool value. - */ - function getIsFreeByNFTId(uint64 _NFT_id) public view returns (bool) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return getBoolFromUint64(37, editions_by_id[getRootNFTIdByNFTId(_NFT_id)].father_id); - } - - /** - * @dev Query is issue follows the NC protocol by any NFT belongs to this issue. - * - * Requirements: - * - `_NFT_id`: The id of the edition queryed. - * Return a bool value. - */ - function getIsNCByNFTId(uint64 _NFT_id) public view returns (bool) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return getBoolFromUint64(38, editions_by_id[getRootNFTIdByNFTId(_NFT_id)].father_id); - } - - /** - * @dev Query is issue follows the ND protocol by any NFT belongs to this issue. - * - * Requirements: - * - `_NFT_id`: The id of the edition queryed. - * Return a bool value. - */ - function getIsNDByNFTId(uint64 _NFT_id) public view returns (bool) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return getBoolFromUint64(39, editions_by_id[getRootNFTIdByNFTId(_NFT_id)].father_id); - } - - /** - * @dev Query is edition exist. - * - * Requirements: - * - `_NFT_id`: The id of the edition queryed. - * Return a bool value. - */ - function isEditionExisting(uint64 _NFT_id) public view returns (bool) { - return (editions_by_id[_NFT_id].owner != address(0)); - } - - /** - * @dev Query the amount of ETH a NFT can be claimed. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return the value this NFT can be claimed. - * If the NFT is not root NFT, this value will subtract royalty fee percent. - */ - function getProfitByNFTId(uint64 _NFT_id) public view returns (uint128){ - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - uint128 amount = editions_by_id[_NFT_id].profit; - if (DAO_fee != 0) { - uint128 DAO_amount = calculateFee(amount, DAO_fee); - amount -= DAO_amount; - } - if (!isRootNFT(_NFT_id)) { - uint128 _total_fee = calculateFee(amount, getRoyaltyFeeByNFTId(_NFT_id)); - amount -= _total_fee; - } - return amount; - } - - /** - * @dev Query royalty fee percent of an issue by any NFT belongs to this issue. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return royalty fee percent of this issue. - */ - function getRoyaltyFeeByNFTId(uint64 _NFT_id) public view returns (uint8) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return getUint8FromUint64(56, editions_by_id[getRootNFTIdByNFTId(_NFT_id)].father_id); - } - - /** - * @dev Query max shill times of an issue by any NFT belongs to this issue. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return max shill times of this issue. - */ - function getShillTimesByNFTId(uint64 _NFT_id) public view returns (uint16) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return getUint16FromUint64(40, editions_by_id[getRootNFTIdByNFTId(_NFT_id)].father_id); - } - - /** - * @dev Query total NFT number of a issue by any NFT belongs to this issue. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return total NFT number of this issue. - */ - function getTotalAmountByNFTId(uint64 _NFT_id) public view returns (uint32) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return getBottomUint32FromUint64(editions_by_id[getRootNFTIdByNFTId(_NFT_id)].father_id); - } - - /** - * @dev Query supported token address of a issue by any NFT belongs to this issue. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return supported token address of this NFT. - * Address 0 represent ETH. - */ - function getTokenAddrByNFTId(uint64 _NFT_id) public view returns (address) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return token_addresses[uint32(_NFT_id>>32)]; - } - - /** - * @dev Query the id of this NFT's father NFT. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * - This NFT should exist and not be root NFT. - * Return the father NFT id of this NFT. - */ - function getFatherByNFTId(uint64 _NFT_id) public view returns (uint64) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - if (isRootNFT(_NFT_id)) { - return 0; - } - return editions_by_id[_NFT_id].father_id; - } - - /** - * @dev Query transfer_price of this NFT. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return transfer_price of this NFT. - */ - function getTransferPriceByNFTId(uint64 _NFT_id) public view returns (uint128) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return editions_by_id[_NFT_id].transfer_price; - } - - /** - * @dev Query shill_price of this NFT. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return shill_price of this NFT. - */ - function getShillPriceByNFTId(uint64 _NFT_id) public view returns (uint128) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - if (getIsFreeByNFTId(_NFT_id)&&isRootNFT(_NFT_id)) - return 0; - else - return editions_by_id[_NFT_id].shill_price; - } - - /** - * @dev Query remaining_shill_times of this NFT. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return remaining_shill_times of this NFT. - */ - function getRemainShillTimesByNFTId(uint64 _NFT_id) public view returns (uint16) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - return editions_by_id[_NFT_id].remaining_shill_times; - } - - /** - * @dev Query depth of this NFT. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return depth of this NFT. - */ - function getDepthByNFTId(uint64 _NFT_id) public view returns (uint64) { - require(isEditionExisting(_NFT_id), "SparkLink: Edition is not exist."); - uint64 depth = 0; - for (depth = 0; !isRootNFT(_NFT_id); _NFT_id = getFatherByNFTId(_NFT_id)) { - depth += 1; - } - return depth; - } - - /** - * @dev Query is this NFT is root NFT by check is its edition id is 1. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return a bool value to indicate wether this NFT is root NFT. - */ - function isRootNFT(uint64 _NFT_id) public pure returns (bool) { - return getBottomUint32FromUint64(_NFT_id) == uint32(1); - } - - /** - * @dev Query root NFT id by NFT id. - * - * Requirements: - * - `_NFT_id`: The id of the NFT queryed. - * Return a bool value to indicate wether this NFT is root NFT. - */ - function getRootNFTIdByNFTId(uint64 _NFT_id) public pure returns (uint64) { - return ((_NFT_id>>32)<<32 | uint64(1)); - } - - /** - * @dev Query loss ratio of this contract. - * - * Return loss ratio of this contract. - */ - function getLossRatio() public view returns (uint8) { - return loss_ratio; - } - - /** - * @dev Calculate edition id by NFT id. - * - * Requirements: - * - `_NFT_id`: The NFT id of the NFT caller want to get. - * Return edition id. - */ - function getEditionIdByNFTId(uint64 _NFT_id) public pure returns (uint32) { - return getBottomUint32FromUint64(_NFT_id); - } - // Token name - string private _name; - - // Token symbol - string private _symbol; - uint8 public loss_ratio = 62; - uint8 public DAO_fee = 2; - uint8 public constant MAX_DAO_FEE = 2; - uint8 public constant MAX_LOSS_RATIO = 50; - address public DAO_router01; - address public DAO_router02; - IUniswapV2Router02 public uniswapV2Router; - IUniswapV2Factory public uniswapV2Factory; - // Mapping owner address to token count - mapping(address => uint64) private _balances; - // Mapping from token ID to approved address - mapping(uint64 => address) private _tokenApprovals; - // Mapping from owner to operator approvals - mapping(address => mapping(address => bool)) private _operatorApprovals; - mapping (uint64 => Edition) private editions_by_id; - // mapping from issue ID to support ERC20 token address - mapping(uint32 => address) private token_addresses; - - bytes constant private sha256MultiHash = hex"1220"; - bytes constant private ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; - - function _swapTokensForEth(address token_addr, uint128 token_amount) private { - // generate the uniswap pair path of token -> weth - address[] memory path = new address[](2); - path[0] = token_addr; - path[1] = uniswapV2Router.WETH(); - - IERC20(token_addr).approve(address(uniswapV2Router), token_amount); - - // make the swap - uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens( - token_amount, - 0, // accept any amount of ETH - path, - DAO_router01, - block.timestamp - ); - } - - - /** - * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. - * The call is not executed if the target address is not a contract. - * - * @param from address representing the previous owner of the given token ID - * @param to target address that will receive the tokens - * @param tokenId uint256 ID of the token to be transferred - * @param _data bytes optional data to send along with the call - * @return bool whether the call correctly returned the expected magic value - */ - function _checkOnERC721Received( - address from, - address to, - uint64 tokenId, - bytes memory _data - ) - private - returns (bool) - { - if (to.isContract()) { - try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { - return retval == IERC721Receiver.onERC721Received.selector; - } catch (bytes memory reason) { - if (reason.length == 0) { - revert("SparkLink: Transfer to non ERC721Receiver implementer"); - } else { - assembly { - revert(add(32, reason), mload(reason)) - } - } - } - } else { - return true; - } - } - - /** - * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. - * - * Requirements: - * - * - `tokenId` must exist. - */ - function _setTokenURI(uint64 tokenId, bytes32 ipfs_hash) internal virtual { - bytes32 old_URI = editions_by_id[tokenId].ipfs_hash; - editions_by_id[tokenId].ipfs_hash = ipfs_hash; - emit SetURI(tokenId, old_URI, ipfs_hash); - } - - /** - * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. - * The call is not executed if the target address is not a contract. - * - * @param _NFT_id NFT id of father NFT - * @param _owner indicate the address new NFT transfer to - * @return a uint64 store new NFT id - **/ - function _mintNFT( - uint64 _NFT_id, - address _owner - ) - internal - returns (uint64) - { - _addTotalAmount(_NFT_id); - uint32 new_edition_id = getTotalAmountByNFTId(_NFT_id); - uint64 new_NFT_id = getNftIdByEditionIdAndIssueId(uint32(_NFT_id>>32), new_edition_id); - require( - _checkOnERC721Received(address(0), _owner, new_NFT_id, ""), - "SparkLink: Transfer to non ERC721Receiver implementer" - ); - Edition storage new_NFT = editions_by_id[new_NFT_id]; - new_NFT.remaining_shill_times = getShillTimesByNFTId(_NFT_id); - new_NFT.father_id = _NFT_id; - if (getIsFreeByNFTId(_NFT_id)&&isRootNFT(_NFT_id)) - new_NFT.shill_price = editions_by_id[_NFT_id].shill_price; - else - new_NFT.shill_price = calculateFee(editions_by_id[_NFT_id].shill_price, loss_ratio); - if (new_NFT.shill_price == 0) { - new_NFT.shill_price = editions_by_id[_NFT_id].shill_price; - } - new_NFT.owner = _owner; - new_NFT.ipfs_hash = editions_by_id[_NFT_id].ipfs_hash; - _balances[_owner] += 1; - emit Transfer(address(0), _owner, new_NFT_id); - return new_NFT_id; - } - - /** - * @dev Internal function to clear approve and transfer_price - * - * @param _NFT_id NFT id of father NFT - **/ - function _afterTokenTransfer (uint64 _NFT_id) internal { - // Clear approvals from the previous owner - _approve(address(0), _NFT_id); - editions_by_id[_NFT_id].transfer_price = 0; - } - - /** - * @dev Internal function to support transfer `tokenId` from `from` to `to`. - * - * @param from address representing the previous owner of the given token ID - * @param to target address that will receive the tokens - * @param tokenId uint256 ID of the token to be transferred - * Emits a {Transfer} event. - */ - function _transfer( - address from, - address to, - uint64 tokenId - ) - internal - virtual - { - require(ownerOf(tokenId) == from, "SparkLink: Transfer of token that is not own"); - require(_isApprovedOrOwner(_msgSender(), tokenId), "SparkLink: Transfer caller is not owner nor approved"); - require(to != address(0), "SparkLink: Transfer to the zero address"); - if (msg.sender != ownerOf(tokenId)) { - address token_addr = getTokenAddrByNFTId(tokenId); - uint128 transfer_price = editions_by_id[tokenId].transfer_price; - if (token_addr == address(0)){ - require(msg.value == transfer_price, "SparkLink: Price not met"); - _addProfit(tokenId, transfer_price); - } - else { - uint256 before_balance = IERC20(token_addr).balanceOf(address(this)); - IERC20(token_addr).safeTransferFrom(msg.sender, address(this), transfer_price); - _addProfit(tokenId, uint256toUint128(IERC20(token_addr).balanceOf(address(this))-before_balance)); - } - claimProfit(tokenId); - } - else { - claimProfit(tokenId); - } - _afterTokenTransfer(tokenId); - _balances[from] -= 1; - _balances[to] += 1; - editions_by_id[tokenId].owner = to; - emit Transfer(from, to, tokenId); - } - - /** - * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients - * are aware of the ERC721 protocol to prevent tokens from being forever locked. - * - * `_data` is additional data, it has no specified format and it is sent in call to `to`. - * - * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. - * implement alternative mechanisms to perform token transfer, such as signature-based. - * - * Requirements: - * - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `tokenId` token must exist and be owned by `from`. - * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. - * - * Emits a {Transfer} event. - */ - function _safeTransfer( - address from, - address to, - uint64 tokenId, - bytes memory _data - ) - internal - virtual - { - _transfer(from, to, tokenId); - require(_checkOnERC721Received(from, to, tokenId, _data), "SparkLink: Transfer to non ERC721Receiver implementer"); - } - - /** - * @dev Approve `to` to operate on `tokenId` - * - * Emits a {Approval} event. - */ - function _approve(address to, uint64 tokenId) internal virtual { - _tokenApprovals[tokenId] = to; - emit Approval(ownerOf(tokenId), to, tokenId); - } - - function _addProfit(uint64 _NFT_id, uint128 _increase) internal { - editions_by_id[_NFT_id].profit = editions_by_id[_NFT_id].profit+_increase; - } - - function _addTotalAmount(uint64 _NFT_Id) internal { - require(getTotalAmountByNFTId(_NFT_Id) < type(uint32).max, "SparkLink: There is no left in this issue."); - editions_by_id[getRootNFTIdByNFTId(_NFT_Id)].father_id += 1; - } - - function _isApprovedOrOwner(address spender, uint64 tokenId) internal view virtual returns (bool) { - require(isEditionExisting(tokenId), "SparkLink: Operator query for nonexistent token"); - address owner = ownerOf(tokenId); - return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); - } - - function _baseURI() internal pure returns (string memory) { - return "https://ipfs.io/ipfs/"; - } - - - /** - * @dev Calculate NFT id by issue id and edition id. - * - * Requirements: - * - `_issue_id`: The issue id of the NFT caller want to get. - * - `_edition_id`: The edition id of the NFT caller want to get. - * Return NFT id. - */ - function getNftIdByEditionIdAndIssueId(uint32 _issue_id, uint32 _edition_id) internal pure returns (uint64) { - return (uint64(_issue_id)<<32)|uint64(_edition_id); - } - - function getBoolFromUint64(uint8 position, uint64 data64) internal pure returns (bool flag) { - // (((1 << size) - 1) & base >> position) - assembly { - flag := and(1, shr(position, data64)) - } - } - - function getUint8FromUint64(uint8 position, uint64 data64) internal pure returns (uint8 data8) { - // (((1 << size) - 1) & base >> position) - assembly { - data8 := and(sub(shl(8, 1), 1), shr(position, data64)) - } - } - function getUint16FromUint64(uint8 position, uint64 data64) internal pure returns (uint16 data16) { - // (((1 << size) - 1) & base >> position) - assembly { - data16 := and(sub(shl(16, 1), 1), shr(position, data64)) - } - } - function getBottomUint32FromUint64(uint64 data64) internal pure returns (uint32 data32) { - // (((1 << size) - 1) & base >> position) - assembly { - data32 := and(sub(shl(32, 1), 1), data64) - } - } - - function reWriteBoolInUint64(uint8 position, bool flag, uint64 data64) internal pure returns (uint64 boxed) { - assembly { - // mask = ~((1 << 8 - 1) << position) - // _box = (mask & _box) | ()data << position) - boxed := or( and(data64, not(shl(position, 1))), shl(position, flag)) - } - } - - - function reWriteUint8InUint64(uint8 position, uint8 flag, uint64 data64) internal pure returns (uint64 boxed) { - assembly { - // mask = ~((1 << 8 - 1) << position) - // _box = (mask & _box) | ()data << position) - boxed := or(and(data64, not(shl(position, 1))), shl(position, flag)) - } - } - - function reWriteUint16InUint64(uint8 position, uint16 data16, uint64 data64) internal pure returns (uint64 boxed) { - assembly { - // mask = ~((1 << 16 - 1) << position) - // _box = (mask & _box) | ()data << position) - boxed := or( and(data64, not(shl(position, sub(shl(16, 1), 1)))), shl(position, data16)) - } - } - - function uint256toUint64(uint256 value) internal pure returns (uint64) { - require(value <= type(uint64).max, "SparkLink: Value doesn't fit in 64 bits"); - return uint64(value); - } - - function uint256toUint128(uint256 value) internal pure returns (uint128) { - require(value <= type(uint128).max, "SparkLink: Value doesn't fit in 128 bits"); - return uint128(value); - } - - function calculateFee(uint128 _amount, uint8 _fee_percent) internal pure returns (uint128) { - return _amount*_fee_percent/10**2; - } - - function _toBase58String(bytes32 con) internal pure returns (string memory) { - - bytes memory source = bytes.concat(sha256MultiHash,con); - - uint8[] memory digits = new uint8[](64); //TODO: figure out exactly how much is needed - digits[0] = 0; - uint8 digitlength = 1; - for (uint256 i = 0; i 0) { - digits[digitlength] = uint8(carry % 58); - digitlength++; - carry = carry / 58; - } - } - //return digits; - return string(toAlphabet(reverse(truncate(digits, digitlength)))); - } - - function toAlphabet(uint8[] memory indices) internal pure returns (bytes memory) { - bytes memory output = new bytes(indices.length); - for (uint256 i = 0; i`. -// -// When running the script with `npx hardhat run