diff --git a/contracts/Factory/Registries/DODONFTPoolRegistry.sol b/contracts/Factory/Registries/DODONFTPoolRegistry.sol deleted file mode 100644 index e69de29..0000000 diff --git a/contracts/NFTPool/impl/FilterAdmin.sol b/contracts/NFTPool/impl/FilterAdmin.sol index 8a3250e..a76fd91 100644 --- a/contracts/NFTPool/impl/FilterAdmin.sol +++ b/contracts/NFTPool/impl/FilterAdmin.sol @@ -10,137 +10,238 @@ pragma experimental ABIEncoderV2; import {InitializableInternalMintableERC20} from "../../external/ERC20/InitializableInternalMintableERC20.sol"; import {SafeMath} from "../../lib/SafeMath.sol"; -import {IFilterERC721Model} from "../intf/IFilterERC721Model.sol"; -import {IFilterERC1155Model} from "../intf/IFilterERC1155Model.sol"; -import {IERC721} from "../../intf/IERC721.sol"; -import {IERC721Receiver} from "../../intf/IERC721Receiver.sol"; -import {IERC1155} from "../../intf/IERC1155.sol"; -import {IERC1155Receiver} from "../../intf/IERC1155Receiver.sol"; +import {IFilterModel} from "../intf/IFilterModel.sol"; +import {IFeeModel} from "../intf/IFeeModel.sol"; +import {ReentrancyGuard} from "../../lib/ReentrancyGuard.sol"; +import {DecimalMath} from "../../lib/DecimalMath.sol"; -contract FilterAdmin is InitializableInternalMintableERC20, IERC721Receiver, IERC1155Receiver { +contract FilterAdmin is InitializableInternalMintableERC20, ReentrancyGuard { using SafeMath for uint256; // ============ Storage ============ - address public _ERC721_FILTER_MODEL_; - address public _ERC1155_FILTER_MODEL_; + address[] public _FILTER_REGISTRY_; + uint256 public _FEE_; + address public _MT_FEE_MODEL_; + address public _DEFAULT_MAINTAINER_; function init( address _owner, - uint256 _initSupply, string memory _name, string memory _symbol, - uint8 _decimals, - address _erc721FilterModel, - address _erc1155FilterModel + uint256 fee, + address mtFeeModel, + address defaultMaintainer, + address[] memory filters ) external { - super.init(_owner, _initSupply, _name, _symbol, _decimals); - _ERC721_FILTER_MODEL_ = _erc721FilterModel; - _ERC1155_FILTER_MODEL_ = _erc1155FilterModel; + super.init(_owner, 0, _name, _symbol, 18); + _FILTER_REGISTRY_ = filters; + _FEE_ = fee; + _MT_FEE_MODEL_ = mtFeeModel; + _DEFAULT_MAINTAINER_ = defaultMaintainer; } - // ============ Event ============ - event RemoveNftToken(address nftContract, uint256 tokenId, uint256 amount); - event AddNftToken(address nftContract, uint256 tokenId, uint256 amount); - - - function depositERC721(address nftContract, uint256[] memory tokenIds) public { - require(nftContract != address(0), "ZERO_ADDRESS"); + function ERC721In( + address filter, + address nftContract, + uint256[] memory tokenIds + ) + external + preventReentrant + { + require(isIncludeFilter(filter), "FILTER_NOT_INCLUDE"); + require(IFilterModel(filter)._NFT_IN_SWITCH_(), "NFT_IN_CLOSED"); + require(IFilterModel(filter).getAvaliableNFTIn() >= tokenIds.length, "EXCEED_MAX_AMOUNT"); + uint256 totalPrice = 0; for(uint256 i = 0; i < tokenIds.length; i++) { - uint256 price = IFilterERC721Model(_ERC721_FILTER_MODEL_).saveNFTPrice(nftContract, tokenIds[i]); - _mint(msg.sender, price); - - IERC721(nftContract).safeTransferFrom(msg.sender, address(this), tokenIds[i]); - emit AddNftToken(nftContract, tokenIds[i], 1); + require(IFilterModel(filter).isFilterERC721Pass(nftContract, tokenIds[i]), "NOT_REGISTERED"); + totalPrice = totalPrice.add(IFilterModel(filter).getNFTInPrice(nftContract, tokenIds[i])); + IFilterModel(filter).transferInERC721(nftContract, msg.sender, tokenIds[i]); } + + (uint256 poolFeeAmount, uint256 mtFeeAmount) = _nftInFeeTransfer(totalPrice); + if(poolFeeAmount > 0) _mint(_OWNER_, poolFeeAmount); + if(mtFeeAmount > 0) _mint(_DEFAULT_MAINTAINER_, mtFeeAmount); + + _mint(msg.sender, totalPrice.sub(mtFeeAmount).sub(poolFeeAmount)); } - function depoistERC1155(address nftContract, uint256[] memory tokenIds, uint256[] memory amounts) public { - require(nftContract != address(0), "ZERO_ADDRESS"); + function ERC1155In( + address filter, + address nftContract, + uint256[] memory tokenIds, + uint256[] memory amounts + ) + external + preventReentrant + { require(tokenIds.length == amounts.length, "PARAMS_NOT_MATCH"); + require(isIncludeFilter(filter), "FILTER_NOT_INCLUDE"); + require(IFilterModel(filter)._NFT_IN_SWITCH_(), "NFT_IN_CLOSED"); + require(IFilterModel(filter).getAvaliableNFTIn() >= tokenIds.length, "EXCEED_MAX_AMOUNT"); + uint256 totalPrice = 0; for(uint256 i = 0; i < tokenIds.length; i++) { - uint256 price = IFilterERC1155Model(_ERC1155_FILTER_MODEL_).saveNFTPrice(nftContract, tokenIds[i], amounts[i]); - _mint(msg.sender, price); - - emit AddNftToken(nftContract, tokenIds[i], amounts[i]); + require(IFilterModel(filter).isFilterERC1155Pass(nftContract, tokenIds[i], amounts[i]), "NOT_REGISTERED"); + totalPrice = totalPrice.add(IFilterModel(filter).getNFTInPrice(nftContract, tokenIds[i]).mul(amounts[i])); } - IERC1155(nftContract).safeBatchTransferFrom(msg.sender, address(this), tokenIds, amounts, ""); - } + (uint256 poolFeeAmount, uint256 mtFeeAmount) = _nftInFeeTransfer(totalPrice); + if(poolFeeAmount > 0) _mint(_OWNER_, poolFeeAmount); + if(mtFeeAmount > 0) _mint(_DEFAULT_MAINTAINER_, mtFeeAmount); + + _mint(msg.sender, totalPrice.sub(mtFeeAmount).sub(poolFeeAmount)); - function doLotteryERC721() external { - uint256 lotteryPrice = IFilterERC721Model(_ERC721_FILTER_MODEL_).buyLotteryNFTPrice(); - _burn(msg.sender, lotteryPrice); - (address nftContract, uint256 tokenId) = IFilterERC721Model(_ERC721_FILTER_MODEL_).lottery(); - - IERC721(nftContract).safeTransferFrom(address(this), msg.sender, tokenId); - emit RemoveNftToken(nftContract, tokenId, 1); - } - - function doLotteryERC1155() external { - uint256 lotteryPrice = IFilterERC1155Model(_ERC1155_FILTER_MODEL_).buyLotteryNFTPrice(); - _burn(msg.sender, lotteryPrice); - (address nftContract, uint256 tokenId) = IFilterERC1155Model(_ERC721_FILTER_MODEL_).lottery(); - - //TODO: amount - IERC1155(nftContract).safeTransferFrom(address(this), msg.sender, tokenId, 1, ""); - emit RemoveNftToken(nftContract, tokenId, 1); - } - - function buySpecERC721(address nftContract, uint256 tokenId) external { - uint256 price = IFilterERC721Model(_ERC721_FILTER_MODEL_).buySpecNFTPrice(nftContract, tokenId); - _burn(msg.sender, price); - - IERC721(nftContract).safeTransferFrom(address(this), msg.sender, tokenId); - emit RemoveNftToken(nftContract, tokenId, 1); - } - - function buySpecERC1155(address nftContract, uint256 tokenId, uint256 amount) external { - uint256 price = IFilterERC1155Model(_ERC1155_FILTER_MODEL_).buySpecNFTPrice(nftContract, tokenId, amount); - _burn(msg.sender, price); - IERC1155(nftContract).safeTransferFrom(address(this), msg.sender, tokenId, amount, ""); - - emit RemoveNftToken(nftContract, tokenId, amount); + IFilterModel(filter).transferBatchInERC1155(nftContract, msg.sender, tokenIds, amounts); } - function supportsInterface(bytes4 interfaceId) public override view returns (bool) { - return interfaceId == type(IERC1155Receiver).interfaceId - || interfaceId == type(IERC721Receiver).interfaceId; - } - - // ============ Callback ============ - function onERC721Received( - address, - address, - uint256 tokenId, - bytes calldata - ) external override returns (bytes4) { - emit AddNftToken(msg.sender, tokenId, 1); - return IERC721Receiver.onERC721Received.selector; - } - - function onERC1155Received( - address, - address, - uint256 id, - uint256 value, - bytes calldata - ) external override returns (bytes4){ - emit AddNftToken(msg.sender, id, value); - return IERC1155Receiver.onERC1155Received.selector; - } - - function onERC1155BatchReceived( - address, - address, - uint256[] calldata ids, - uint256[] calldata values, - bytes calldata - ) external override returns (bytes4){ - require(ids.length == values.length, "PARAMS_NOT_MATCH"); - for(uint256 i = 0; i < ids.length; i++) { - emit AddNftToken(msg.sender, ids[i], values[i]); + function ERC721RandomOut( + address filter, + uint256 times + ) + external + preventReentrant + { + require(msg.sender == tx.origin, "ONLY_ALLOW_EOA"); + require(isIncludeFilter(filter), "FILTER_NOT_INCLUDE"); + require(IFilterModel(filter)._NFT_RANDOM_SWITCH_(), "NFT_RANDOM_CLOSED"); + require(IFilterModel(filter).getAvaliableNFTOut() >= times, "EXCEED_MAX_AMOUNT"); + uint256 totalPrice = 0; + for(uint256 i = 0; i < times; i++) { + totalPrice = totalPrice.add(IFilterModel(filter).getNFTRandomOutPrice()); + (address nftContract, uint256 tokenId) = IFilterModel(filter).getRandomOutId(); + IFilterModel(filter).transferOutERC721(nftContract, msg.sender, tokenId); } - return IERC1155Receiver.onERC1155BatchReceived.selector; + + (uint256 poolFeeAmount, uint256 mtFeeAmount) = _nftRandomOutFeeTransfer(totalPrice); + if(poolFeeAmount > 0) _mint(_OWNER_, poolFeeAmount); + if(mtFeeAmount > 0) _mint(_DEFAULT_MAINTAINER_, mtFeeAmount); + + _burn(msg.sender, totalPrice); + } + + + //TODO: amount == 1 + function ERC1155RandomOut( + address filter, + uint256 times + ) + external + preventReentrant + { + require(msg.sender == tx.origin, "ONLY_ALLOW_EOA"); + require(isIncludeFilter(filter), "FILTER_NOT_INCLUDE"); + require(IFilterModel(filter)._NFT_RANDOM_SWITCH_(), "NFT_RANDOM_OUT_CLOSED"); + require(IFilterModel(filter).getAvaliableNFTOut() >= times, "EXCEED_MAX_AMOUNT"); + + uint256 totalPrice = 0; + uint256[] memory tokenIds; + uint256[] memory amounts; + for(uint256 i = 0; i < times; i++) { + totalPrice = totalPrice.add(IFilterModel(filter).getNFTRandomOutPrice()); + (address nftContract, uint256 tokenId) = IFilterModel(filter).getRandomOutId(); + IFilterModel(filter).transferOutERC1155(nftContract, msg.sender, tokenId, 1); + } + + (uint256 poolFeeAmount, uint256 mtFeeAmount) = _nftRandomOutFeeTransfer(totalPrice); + if(poolFeeAmount > 0) _mint(_OWNER_, poolFeeAmount); + if(mtFeeAmount > 0) _mint(_DEFAULT_MAINTAINER_, mtFeeAmount); + + _burn(msg.sender, totalPrice); + } + + function ERC721TargetOut( + address filter, + address nftContract, + uint256[] memory tokenIds + ) + external + preventReentrant + { + require(isIncludeFilter(filter), "FILTER_NOT_INCLUDE"); + require(IFilterModel(filter)._NFT_TARGET_SWITCH_(), "NFT_TARGET_OUT_CLOSED"); + require(IFilterModel(filter).getAvaliableNFTOut() >= tokenIds.length, "EXCEED_MAX_AMOUNT"); + uint256 totalPrice = 0; + for(uint256 i = 0; i < tokenIds.length; i++) { + totalPrice = totalPrice.add(IFilterModel(filter).getNFTTargetOutPrice(nftContract, tokenIds[i])); + IFilterModel(filter).transferOutERC721(nftContract, msg.sender, tokenIds[i]); + } + + (uint256 poolFeeAmount, uint256 mtFeeAmount) = _nftTargetOutFeeTransfer(totalPrice); + if(poolFeeAmount > 0) _mint(_OWNER_, poolFeeAmount); + if(mtFeeAmount > 0) _mint(_DEFAULT_MAINTAINER_, mtFeeAmount); + + _burn(msg.sender, totalPrice); + } + + function ERC1155TargetOut( + address filter, + address nftContract, + uint256[] memory tokenIds, + uint256[] memory amounts + ) + external + preventReentrant + { + require(tokenIds.length == amounts.length, "PARAMS_NOT_MATCH"); + require(isIncludeFilter(filter), "FILTER_NOT_INCLUDE"); + require(IFilterModel(filter)._NFT_TARGET_SWITCH_(), "NFT_TARGET_OUT_CLOSED"); + require(IFilterModel(filter).getAvaliableNFTOut() >= tokenIds.length, "EXCEED_MAX_AMOUNT"); + uint256 totalPrice = 0; + for(uint256 i = 0; i < tokenIds.length; i++) { + totalPrice = totalPrice.add(IFilterModel(filter).getNFTTargetOutPrice(nftContract, tokenIds[i]).mul(amounts[i])); + } + (uint256 poolFeeAmount, uint256 mtFeeAmount) = _nftTargetOutFeeTransfer(totalPrice); + if(poolFeeAmount > 0) _mint(_OWNER_, poolFeeAmount); + if(mtFeeAmount > 0) _mint(_DEFAULT_MAINTAINER_, mtFeeAmount); + + _burn(msg.sender, totalPrice); + + IFilterModel(filter).transferBatchOutERC1155(nftContract, msg.sender, tokenIds, amounts); + } + + + //================ View ================ + function isIncludeFilter(address filter) view public returns (bool) { + uint256 i = 0; + for(; i < _FILTER_REGISTRY_.length; i++) { + if(filter == _FILTER_REGISTRY_[i]) break; + } + return i == _FILTER_REGISTRY_.length ? false : true; + } + + function getFilters() view public returns (address[] memory) { + return _FILTER_REGISTRY_; + } + + function version() virtual external pure returns (string memory) { + return "FADMIN 1.0.0"; + } + + //=============== Owner ============== + function addFilter(address filter) external onlyOwner { + require(!isIncludeFilter(filter), "FILTER_NOT_INCLUDE"); + _FILTER_REGISTRY_.push(filter); + } + + //TODO: remove Filter是否有必要? + + + //=============== Internal ============== + function _nftInFeeTransfer(uint256 totalPrice) internal returns (uint256 poolFeeAmount, uint256 mtFeeAmount) { + uint256 mtFeeRate = IFeeModel(_MT_FEE_MODEL_).getNFTInFee(address(this), msg.sender); + poolFeeAmount = DecimalMath.mulFloor(totalPrice, _FEE_); + mtFeeAmount = DecimalMath.mulFloor(totalPrice, mtFeeRate); + } + + function _nftRandomOutFeeTransfer(uint256 totalPrice) internal returns (uint256 poolFeeAmount, uint256 mtFeeAmount) { + uint256 mtFeeRate = IFeeModel(_MT_FEE_MODEL_).getNFTRandomOutFee(address(this), msg.sender); + poolFeeAmount = DecimalMath.mulFloor(totalPrice, _FEE_); + mtFeeAmount = DecimalMath.mulFloor(totalPrice, mtFeeRate); + } + + function _nftTargetOutFeeTransfer(uint256 totalPrice) internal returns (uint256 poolFeeAmount, uint256 mtFeeAmount) { + uint256 mtFeeRate = IFeeModel(_MT_FEE_MODEL_).getNFTTargetOutFee(address(this), msg.sender); + poolFeeAmount = DecimalMath.mulFloor(totalPrice, _FEE_); + mtFeeAmount = DecimalMath.mulFloor(totalPrice, mtFeeRate); } } diff --git a/contracts/NFTPool/impl/FilterERC1155Model.sol b/contracts/NFTPool/impl/FilterERC1155Model.sol deleted file mode 100644 index 41f2224..0000000 --- a/contracts/NFTPool/impl/FilterERC1155Model.sol +++ /dev/null @@ -1,130 +0,0 @@ -/* - - Copyright 2021 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {InitializableOwnable} from "../../lib/InitializableOwnable.sol"; -import {SafeMath} from "../../lib/SafeMath.sol"; -import {IFilterERC1155Model} from "../intf/IFilterERC1155Model.sol"; - -contract FilterERC1155Model is InitializableOwnable, IFilterERC1155Model { - using SafeMath for uint256; - - //=================== Storage ===================== - // nftCollection -> nftId -> price(frag) - mapping(address => mapping(uint256 => uint256)) public _PRICES_; - // nftCollection -> nftId -> amount - mapping(address => mapping(uint256 => uint256)) public _ERC1155_AMOUNT_; - // nftCollection -> nftId -> specPrice(frag) - mapping(address => mapping(uint256 => uint256)) public _SPEC_PRICES_; - - uint256 public _SPEC_FACTOR_ = 200; - - // nftColletcion -> nftIds - mapping(address => uint256[]) public _NFT_COLLECTION_IDS_; - - address[] public _NFT_COLLECTIONS_; - - uint256 public _LOTTERY_THRESHOLD_; - - uint256 public _TOTAL_NFT_AMOUNT_; - - uint256 public _CURRENT_NFT_AMOUNT_; - - function init( - address owner - ) external { - //TODO: - initOwner(owner); - } - - //================== View ====================== - function isFilterERC1155Pass(address nftCollectionAddress, uint256 nftId, uint256 amount) override external view returns (bool) { - if(_PRICES_[nftCollectionAddress][nftId] == 0) - return false; - else { - if(_ERC1155_AMOUNT_[nftCollectionAddress][nftId] >= amount) - return true; - else - return false; - } - } - - - //TODO: nftInCap - //TODO: nftOutCap - - function saveNFTPrice(address nftCollectionAddress, uint256 nftId, uint256 amount) override external view returns(uint256) { - return _PRICES_[nftCollectionAddress][nftId].mul(amount); - } - - function buySpecNFTPrice(address nftCollectionAddress, uint256 nftId, uint256 amount) override external view returns(uint256) { - require(_ERC1155_AMOUNT_[nftCollectionAddress][nftId] >= amount, "BUY_OVERFLOW"); - return _SPEC_PRICES_[nftCollectionAddress][nftId].mul(amount); - } - - //TODO: amount = 1 - function buyLotteryNFTPrice() override external view returns(uint256) { - return _LOTTERY_THRESHOLD_; - } - - function lottery() override external view returns(address nftCollection, uint256 nftId) { - //random - } - - - //================== Owner ===================== - function setNFTFilter( - address[] memory nftCollections, - uint256[] memory nftIds, - uint256[] memory amounts, - uint256[] memory prices, - uint256[] memory specPrices - ) external onlyOwner { - require(nftCollections.length == nftIds.length, "PARAMS_INVALID"); - require(nftCollections.length == amounts.length, "PARAMS_INVALID"); - require(nftCollections.length == prices.length, "PARAMS_INVALID"); - require(nftCollections.length == specPrices.length, "PARAMS_INVALID"); - - for(uint256 i = 0; i < nftCollections.length; i++){ - _PRICES_[nftCollections[i]][nftIds[i]] = prices[i]; - _PRICES_[nftCollections[i]][nftIds[i]] = amounts[i]; - - if(specPrices[i] == 0){ - _SPEC_PRICES_[nftCollections[i]][nftIds[i]] = prices[i].mul(_SPEC_FACTOR_).div(100); - }else { - _SPEC_PRICES_[nftCollections[i]][nftIds[i]] = specPrices[i]; - } - - if(_NFT_COLLECTION_IDS_[nftCollections[i]].length == 0) { - _NFT_COLLECTIONS_.push(nftCollections[i]); - _NFT_COLLECTION_IDS_[nftCollections[i]] = [nftIds[i]]; - require(++_CURRENT_NFT_AMOUNT_ <= _TOTAL_NFT_AMOUNT_, "OVERFLOW_NFT_AMOUNT"); - } else { - uint256 j = 0; - for(; j < _NFT_COLLECTION_IDS_[nftCollections[i]].length; i++) { - if(_NFT_COLLECTION_IDS_[nftCollections[i]][j] == nftIds[i]) { - break; - } - } - if(j == _NFT_COLLECTION_IDS_[nftCollections[i]].length) { - _NFT_COLLECTION_IDS_[nftCollections[i]].push(nftIds[i]); - require(++_CURRENT_NFT_AMOUNT_ <= _TOTAL_NFT_AMOUNT_, "OVERFLOW_NFT_AMOUNT"); - } - } - } - } - - function setLotteryThreshold(uint256 newLotteryThreshold) external onlyOwner { - _LOTTERY_THRESHOLD_ = newLotteryThreshold; - } - - function setSpecFactor(uint256 newSpecFactor) external onlyOwner { - _SPEC_FACTOR_ = newSpecFactor; - } -} diff --git a/contracts/NFTPool/impl/FilterERC721Model.sol b/contracts/NFTPool/impl/FilterERC721Model.sol deleted file mode 100644 index dabdae4..0000000 --- a/contracts/NFTPool/impl/FilterERC721Model.sol +++ /dev/null @@ -1,242 +0,0 @@ -/* - - Copyright 2021 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {InitializableOwnable} from "../../lib/InitializableOwnable.sol"; -import {SafeMath} from "../../lib/SafeMath.sol"; -import {IFilterERC721Model} from "../intf/IFilterERC721Model.sol"; - -contract FilterERC721Model is InitializableOwnable, IFilterERC721Model { - using SafeMath for uint256; - - //=================== Storage =================== - // nftCollection -> nftId -> price(frag) - mapping(address => mapping(uint256 => uint256)) public _PRICES_; - // nftCollection -> nftId -> specPrice(frag) - mapping(address => mapping(uint256 => uint256)) public _SPEC_PRICES_; - uint256 public _SPEC_FACTOR_ = 200; - // nftColletcion -> nftIds - mapping(address => uint256[]) public _NFT_COLLECTION_IDS_; - address[] public _NFT_COLLECTIONS_; - - uint256 public _LOTTERY_THRESHOLD_; - uint256 public _TOTAL_NFT_AMOUNT_; - uint256 public _CURRENT_NFT_AMOUNT_; - - - uint256 public _TIMELOCK_DURATION_; - - struct LockFilterInfo { - address[] nftCollections; - uint256[] nftIds; - uint256[] prices; - uint256[] specPrices; - uint256 releaseTime; - } - mapping(bytes32 => LockFilterInfo) public _TIME_LOCKS_; - - uint256 public _PENDING_LOTTERY_THRESHOLD_; - uint256 public _PENDING_TOTAL_NFT_AMOUNT_; - uint256 public _PENDING_SPEC_FACTOR_; - uint256 public _GLOBAL_TIME_LOCK_; - - - function init( - address owner, - uint256 specFactor, - uint256 lotteryThreshold, - uint256 totalNftAmount, - uint256 timeLockDuration - ) external { - initOwner(owner); - _SPEC_FACTOR_ = specFactor; - _LOTTERY_THRESHOLD_ = lotteryThreshold; - _TOTAL_NFT_AMOUNT_ = totalNftAmount; - _TIMELOCK_DURATION_ = timeLockDuration; - } - - //==================== View ================== - function isFilterERC721Pass(address nftCollectionAddress, uint256 nftId) override external view returns (bool) { - return _isInclude(nftCollectionAddress, nftId); - } - - function saveNFTPrice(address nftCollectionAddress, uint256 nftId) override external view returns(uint256) { - return _PRICES_[nftCollectionAddress][nftId]; - } - - function buySpecNFTPrice(address nftCollectionAddress, uint256 nftId) override external view returns(uint256) { - return _SPEC_PRICES_[nftCollectionAddress][nftId]; - } - - function buyLotteryNFTPrice() override external view returns(uint256) { - return _LOTTERY_THRESHOLD_; - } - - function lottery() override external view returns(address nftCollection, uint256 nftId) { - //random - } - - - - //TODO: nftInCap - //TODO: nftOutCap - - - //============= Owner =============== - - function addNFTFilter( - address[] memory nftCollections, - uint256[] memory nftIds, - uint256[] memory prices, - uint256[] memory specPrices - ) external onlyOwner { - require(nftCollections.length == nftIds.length, "PARAMS_INVALID"); - require(nftCollections.length == prices.length, "PARAMS_INVALID"); - require(nftCollections.length == specPrices.length, "PARAMS_INVALID"); - - for(uint256 i = 0; i < nftCollections.length; i++){ - if(_isInclude(nftCollections[i], nftIds[i])) continue; - - _PRICES_[nftCollections[i]][nftIds[i]] = prices[i]; - - if(specPrices[i] == 0){ - _SPEC_PRICES_[nftCollections[i]][nftIds[i]] = prices[i].mul(_SPEC_FACTOR_).div(100); - }else { - _SPEC_PRICES_[nftCollections[i]][nftIds[i]] = specPrices[i]; - } - - if(_NFT_COLLECTION_IDS_[nftCollections[i]].length == 0) { - _NFT_COLLECTIONS_.push(nftCollections[i]); - } - - _NFT_COLLECTION_IDS_[nftCollections[i]].push(nftIds[i]); - require(++_CURRENT_NFT_AMOUNT_ <= _TOTAL_NFT_AMOUNT_, "OVERFLOW_NFT_AMOUNT"); - } - } - - - function scheduleUpdateNftFilter( - address[] memory nftCollections, - uint256[] memory nftIds, - uint256[] memory prices, - uint256[] memory specPrices - ) external onlyOwner { - require(nftCollections.length == nftIds.length, "PARAMS_INVALID"); - require(nftCollections.length == prices.length, "PARAMS_INVALID"); - require(nftCollections.length == specPrices.length, "PARAMS_INVALID"); - - uint256 releaseTime = block.timestamp.add(_TIMELOCK_DURATION_); - bytes32 id = keccak256(abi.encode(nftCollections, nftIds, prices, specPrices, releaseTime)); - LockFilterInfo memory lockFilterInfo = LockFilterInfo({ - nftCollections: nftCollections, - nftIds: nftIds, - prices: prices, - specPrices: specPrices, - releaseTime: releaseTime - }); - require(_TIME_LOCKS_[id].releaseTime == 0, "ALREADY_ADDED"); - for(uint256 i = 0; i< nftCollections.length; i++) { - require(_isInclude(nftCollections[i],nftIds[i])); - } - _TIME_LOCKS_[id] = lockFilterInfo; - } - - - function executeUpdateNftFilter( - bytes32 id - ) external onlyOwner { - LockFilterInfo memory lockFilterInfo = _TIME_LOCKS_[id]; - uint256 releaseTime = lockFilterInfo.releaseTime; - require(releaseTime != 0 && releaseTime !=1 && block.timestamp > releaseTime, "TIMELOCKED"); - - address[] memory nftCollections = lockFilterInfo.nftCollections; - uint256[] memory nftIds = lockFilterInfo.nftIds; - uint256[] memory prices = lockFilterInfo.prices; - uint256[] memory specPrices = lockFilterInfo.specPrices; - - - for(uint256 i = 0; i < nftCollections.length; i++){ - _PRICES_[nftCollections[i]][nftIds[i]] = prices[i]; - - if(specPrices[i] == 0){ - _SPEC_PRICES_[nftCollections[i]][nftIds[i]] = prices[i].mul(_SPEC_FACTOR_).div(100); - }else { - _SPEC_PRICES_[nftCollections[i]][nftIds[i]] = specPrices[i]; - } - } - - lockFilterInfo.releaseTime = 1; - _TIME_LOCKS_[id] = lockFilterInfo; - } - - - //TODO:价格修改为0,是否是同样的效果 - function scheduleRemoveNFTFilter( - address[] memory nftCollections, - uint256[] memory nftIds - ) external onlyOwner { - require(nftCollections.length == nftIds.length, "PARAMS_INVALID"); - } - - function executeRemoveNFTFilter( - bytes32 id - ) external onlyOwner { - - } - - - function scheduleUpdateGlobalState( - uint256 newLotteryThreshold, - uint256 newSpecFactor, - uint256 newTotalNFTAmount - ) external onlyOwner { - require(newTotalNFTAmount >= _CURRENT_NFT_AMOUNT_, "NFT_ALREADY_EXCEED"); - require(newSpecFactor > 100, "SPEC_FACTOR_TOO_LOW"); - - _PENDING_LOTTERY_THRESHOLD_ = newLotteryThreshold; - _PENDING_TOTAL_NFT_AMOUNT_ = newSpecFactor; - _PENDING_SPEC_FACTOR_ = newTotalNFTAmount; - - _GLOBAL_TIME_LOCK_ = block.timestamp.add(_TIMELOCK_DURATION_); - } - - function executeUpdateGlobalState() external onlyOwner { - require(block.timestamp > _GLOBAL_TIME_LOCK_ && _GLOBAL_TIME_LOCK_ !=0, "TIMELOCKED"); - - require(_PENDING_TOTAL_NFT_AMOUNT_ >= _CURRENT_NFT_AMOUNT_, "NFT_ALREADY_EXCEED"); - require(_PENDING_SPEC_FACTOR_ > 100, "SPEC_FACTOR_TOO_LOW"); - - _LOTTERY_THRESHOLD_ = _PENDING_LOTTERY_THRESHOLD_; - _SPEC_FACTOR_ = _PENDING_SPEC_FACTOR_; - _TOTAL_NFT_AMOUNT_ = _PENDING_TOTAL_NFT_AMOUNT_; - - lockGlobalState(); - } - - function lockGlobalState() public onlyOwner { - _PENDING_LOTTERY_THRESHOLD_ = 0; - _PENDING_TOTAL_NFT_AMOUNT_ = 0; - _PENDING_SPEC_FACTOR_ = 0; - _GLOBAL_TIME_LOCK_ = 0; - } - - - //==================== internal =================== - function _isInclude(address nftCollection, uint256 nftId) internal view returns (bool) { - uint256[] memory ids = _NFT_COLLECTION_IDS_[nftCollection]; - uint256 i = 0; - for(;i < ids.length; i++) { - if(nftId == i) break; - } - if(i == ids.length) - return false; - else - return true; - } -} diff --git a/contracts/NFTPool/impl/FilterModel01.sol b/contracts/NFTPool/impl/FilterModel01.sol new file mode 100644 index 0000000..b85a721 --- /dev/null +++ b/contracts/NFTPool/impl/FilterModel01.sol @@ -0,0 +1,260 @@ +/* + + Copyright 2021 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {InitializableOwnable} from "../../lib/InitializableOwnable.sol"; +import {SafeMath} from "../../lib/SafeMath.sol"; +import {IFilterAdmin} from "../intf/IFilterAdmin.sol"; +import {IERC721} from "../../intf/IERC721.sol"; +import {IERC721Receiver} from "../../intf/IERC721Receiver.sol"; +import {DecimalMath} from "../../lib/DecimalMath.sol"; + + +contract FilterModel01 is InitializableOwnable, IERC721Receiver { + using SafeMath for uint256; + + //=================== Storage =================== + address public _NFT_COLLECTION_; + uint256 public _TOKEN_ID_START_; + uint256 public _TOKEN_ID_END_; + //tokenId => isRegistered + mapping(uint256 => bool) public _SPREAD_IDS_REGISTRY_; + + uint256 public _MAX_NFT_AMOUNT_; + uint256 public _MIN_NFT_AMOUNT_; + + //For NFT IN + uint256 public _GS_START_IN_; + uint256 public _CR_IN_; + bool public _NFT_IN_SWITCH_ = true; + + //For NFT Random OUT + uint256 public _GS_START_RANDOM_OUT_; + uint256 public _CR_RANDOM_OUT_; + bool public _NFT_RANDOM_SWITCH_ = true; + + //For NFT Target OUT + uint256 public _GS_START_TARGET_OUT_; + uint256 public _CR_TARGET_OUT_; + bool public _NFT_TARGET_SWITCH_ = true; + + uint256[] public _TOKEN_IDS_; + + function init( + address filterAdmin, + address nftCollection, + bool[] memory switches, + uint256[] memory tokenRanges, + uint256[] memory nftAmounts, + uint256[] memory priceRules, + uint256[] memory spreadIds + ) external { + require(priceRules[1] != 0, "CR_IN_INVALID"); + require(priceRules[3] != 0, "CR_RANDOM_OUT_INVALID"); + require(priceRules[5] != 0, "CR_TARGET_OUT_INVALID"); + require(tokenRanges[1] >= tokenRanges[0], "TOKEN_RANGE_INVALID"); + require(nftAmounts[0] >= nftAmounts[1], "AMOUNT_INVALID"); + + initOwner(filterAdmin); + _NFT_COLLECTION_ = nftCollection; + + _TOKEN_ID_START_ = tokenRanges[0]; + _TOKEN_ID_END_ = tokenRanges[1]; + + _MAX_NFT_AMOUNT_ = nftAmounts[0]; + _MIN_NFT_AMOUNT_ = nftAmounts[1]; + + _GS_START_IN_ = priceRules[0]; + _CR_IN_ = priceRules[1]; + _NFT_IN_SWITCH_ = switches[0]; + + _GS_START_RANDOM_OUT_ = priceRules[2]; + _CR_RANDOM_OUT_ = priceRules[3]; + _NFT_RANDOM_SWITCH_ = switches[1]; + + _GS_START_TARGET_OUT_ = priceRules[4]; + _CR_TARGET_OUT_ = priceRules[5]; + _NFT_TARGET_SWITCH_ = switches[2]; + + for(uint256 i = 0; i < spreadIds.length; i++) { + _SPREAD_IDS_REGISTRY_[spreadIds[i]] = true; + } + } + + //==================== View ================== + function isFilterERC721Pass(address nftCollectionAddress, uint256 nftId) external view returns (bool) { + if(nftCollectionAddress == _NFT_COLLECTION_) { + if((nftId >= _TOKEN_ID_START_ && nftId <= _TOKEN_ID_END_) || _SPREAD_IDS_REGISTRY_[nftId]) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + function getAvaliableNFTIn() external view returns(uint256) { + if(_MAX_NFT_AMOUNT_ < _TOKEN_IDS_.length) { + return 0; + }else { + return _MAX_NFT_AMOUNT_ - _TOKEN_IDS_.length; + } + } + + function getAvaliableNFTOut() external view returns(uint256) { + if(_TOKEN_IDS_.length < _MIN_NFT_AMOUNT_) { + return 0; + }else { + return _TOKEN_IDS_.length - _MIN_NFT_AMOUNT_; + } + } + + function getNFTInPrice(address, uint256) external view returns(uint256) { + uint256 nftAmount = _TOKEN_IDS_.length; + if(nftAmount == 0) { + return _GS_START_IN_; + }else { + uint256 price = _GS_START_IN_; + //TODO:gas + for(uint256 i = 0; i < nftAmount; i++) { + price = DecimalMath.mulFloor(price, _CR_IN_); + } + return price; + } + } + + function getNFTRandomOutPrice() external view returns (uint256) { + uint256 nftAmount = _TOKEN_IDS_.length; + require(nftAmount != 0, "EMPTY"); + uint256 price = _GS_START_RANDOM_OUT_; + for(uint256 i = 0; i < nftAmount; i++) { + price = DecimalMath.mulFloor(price, _CR_RANDOM_OUT_); + } + return price; + } + + function getNFTTargetOutPrice(address, uint256) external view returns (uint256) { + uint256 nftAmount = _TOKEN_IDS_.length; + require(nftAmount != 0, "EMPTY"); + uint256 price = _GS_START_TARGET_OUT_; + for(uint256 i = 0; i < nftAmount; i++) { + price = DecimalMath.mulFloor(price, _CR_TARGET_OUT_); + } + return price; + } + + function supportsInterface(bytes4 interfaceId) public view returns (bool) { + return interfaceId == type(IERC721Receiver).interfaceId; + } + + //Pseudorandomness + function getRandomOutId() external view returns (address nftCollection, uint256 nftId) { + uint256 nftAmount = _TOKEN_IDS_.length; + uint256 idx = uint256(keccak256(abi.encodePacked(blockhash(block.number-1), gasleft(), msg.sender, nftAmount))) % nftAmount; + nftCollection = _NFT_COLLECTION_; + nftId = _TOKEN_IDS_[idx]; + } + + // ================= Ownable ================ + function transferOutERC721(address nftContract, address assetTo, uint256 nftId) external onlyOwner { + require(nftContract == _NFT_COLLECTION_, "WRONG_NFT_COLLECTION"); + uint256[] memory tokenIds = _TOKEN_IDS_; + uint256 i; + for (; i < tokenIds.length; i++) { + if (tokenIds[i] == nftId) { + tokenIds[i] = tokenIds[tokenIds.length - 1]; + break; + } + } + require(i < tokenIds.length, "NOT_EXIST_ID"); + _TOKEN_IDS_ = tokenIds; + _TOKEN_IDS_.pop(); + + IERC721(nftContract).safeTransferFrom(address(this), assetTo, nftId); + } + + function transferInERC721(address nftContract, address assetFrom, uint256 nftId) external onlyOwner { + require(nftContract == _NFT_COLLECTION_, "WRONG_NFT_COLLECTION"); + uint256 i; + for(; i < _TOKEN_IDS_.length; i++) { + if(_TOKEN_IDS_[i] == nftId) break; + } + require(i == _TOKEN_IDS_.length, "EXIST_ID"); + + _TOKEN_IDS_.push(nftId); + IERC721(nftContract).safeTransferFrom(assetFrom, address(this), nftId); + } + + function changeNFTInPrice(uint256 newGsStart, uint256 newCr) external { + require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED"); + require(newCr != 0, "CR_ZERO"); + _GS_START_IN_ = newGsStart; + _CR_IN_ = newCr; + } + + function changeNFTROutPrice(uint256 newGsStart, uint256 newCr) external { + require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED"); + require(newCr != 0, "CR_ZERO"); + _GS_START_RANDOM_OUT_ = newGsStart; + _CR_RANDOM_OUT_ = newCr; + } + + function changeNFTTOutPrice(uint256 newGsStart, uint256 newCr) external { + require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED"); + require(newCr != 0, "CR_ZERO"); + _GS_START_TARGET_OUT_ = newGsStart; + _CR_TARGET_OUT_ = newCr; + } + + function changeNFTAmount(uint256 maxNFTAmount, uint256 minNFTAmount) external { + require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED"); + require(maxNFTAmount >= minNFTAmount, "AMOUNT_INVALID"); + _MAX_NFT_AMOUNT_ = maxNFTAmount; + _MIN_NFT_AMOUNT_ = minNFTAmount; + } + + function changeSwitches( + bool newNFTInSwitch, + bool newNFTRandomSwitch, + bool newNFTTargetSwitch + ) external { + require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED"); + _NFT_IN_SWITCH_ = newNFTInSwitch; + _NFT_RANDOM_SWITCH_ = newNFTRandomSwitch; + _NFT_TARGET_SWITCH_ = newNFTTargetSwitch; + } + + function changeTokenIdRange(uint256 tokenIdStart, uint256 tokenIdEnd) external { + require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED"); + require(tokenIdStart <= tokenIdEnd, "TOKEN_RANGE_INVALID"); + + _TOKEN_ID_START_ = tokenIdStart; + _TOKEN_ID_END_ = tokenIdEnd; + } + + function changeTokenIdMap(uint256[] memory tokenIds, bool[] memory isRegistrieds) external { + require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED"); + require(tokenIds.length == isRegistrieds.length, "PARAM_NOT_MATCH"); + + for(uint256 i = 0; i < tokenIds.length; i++) { + _SPREAD_IDS_REGISTRY_[tokenIds[i]] = isRegistrieds[i]; + } + } + + // ============ Callback ============ + function onERC721Received( + address, + address, + uint256 tokenId, + bytes calldata + ) external override returns (bytes4) { + return IERC721Receiver.onERC721Received.selector; + } +} \ No newline at end of file diff --git a/contracts/NFTPool/impl/NFTPoolFeeModel.sol b/contracts/NFTPool/impl/NFTPoolFeeModel.sol new file mode 100644 index 0000000..c5818a2 --- /dev/null +++ b/contracts/NFTPool/impl/NFTPoolFeeModel.sol @@ -0,0 +1,85 @@ +/* + + Copyright 2021 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {InitializableOwnable} from "../../lib/InitializableOwnable.sol"; +import {IERC20} from "../../intf/IERC20.sol"; +import {SafeMath} from "../../lib/SafeMath.sol"; + +contract NFTPoolFeeModel is InitializableOwnable { + using SafeMath for uint256; + + uint256 public _GLOBAL_NFT_IN_FEE_ = 0; + uint256 public _GLOBAL_NFT_RANDOM_OUT_FEE_ = 0; + uint256 public _GLOBAL_NFT_TARGET_OUT_FEE_ = 50000000000000000;//0.05 + + struct FilterAdminInfo { + uint256 nftInFee; + uint256 nftRandomOutFee; + uint256 nftTargetOutFee; + bool isSet; + } + + mapping(address => FilterAdminInfo) filterAdmins; + + function addFilterAdminInfo(address filterAdminAddr, uint256 nftInFee, uint256 nftRandomOutFee, uint256 nftTargetOutFee) external onlyOwner { + FilterAdminInfo memory filterAdmin = FilterAdminInfo({ + nftInFee: nftInFee, + nftRandomOutFee: nftRandomOutFee, + nftTargetOutFee: nftTargetOutFee, + isSet: true + }); + filterAdmins[filterAdminAddr] = filterAdmin; + } + + function setFilterAdminInfo(address filterAdminAddr, uint256 nftInFee, uint256 nftRandomOutFee, uint256 nftTargetOutFee) external onlyOwner { + filterAdmins[filterAdminAddr].nftInFee = nftInFee; + filterAdmins[filterAdminAddr].nftRandomOutFee = nftRandomOutFee; + filterAdmins[filterAdminAddr].nftTargetOutFee = nftTargetOutFee; + } + + function setGlobalParam(uint256 nftInFee, uint256 nftRandomOutFee, uint256 nftTargetOutFee) external onlyOwner { + _GLOBAL_NFT_IN_FEE_ = nftInFee; + _GLOBAL_NFT_RANDOM_OUT_FEE_ = nftRandomOutFee; + _GLOBAL_NFT_TARGET_OUT_FEE_ = nftTargetOutFee; + } + + + function getNFTInFee(address filterAdminAddr, address) external view returns(uint256) { + FilterAdminInfo memory filterAdminInfo = filterAdmins[filterAdminAddr]; + + if(filterAdminInfo.isSet) { + return filterAdminInfo.nftInFee; + }else { + return _GLOBAL_NFT_IN_FEE_; + } + } + + + function getNFTRandomOutFee(address filterAdminAddr, address) external view returns(uint256) { + FilterAdminInfo memory filterAdminInfo = filterAdmins[filterAdminAddr]; + + if(filterAdminInfo.isSet) { + return filterAdminInfo.nftRandomOutFee; + }else { + return _GLOBAL_NFT_RANDOM_OUT_FEE_; + } + } + + function getNFTTargetOutFee(address filterAdminAddr, address) external view returns(uint256) { + FilterAdminInfo memory filterAdminInfo = filterAdmins[filterAdminAddr]; + + if(filterAdminInfo.isSet) { + return filterAdminInfo.nftTargetOutFee; + }else { + return _GLOBAL_NFT_TARGET_OUT_FEE_; + } + } + +} diff --git a/contracts/NFTPool/intf/IFeeModel.sol b/contracts/NFTPool/intf/IFeeModel.sol new file mode 100644 index 0000000..79a745b --- /dev/null +++ b/contracts/NFTPool/intf/IFeeModel.sol @@ -0,0 +1,16 @@ +/* + + Copyright 2021 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +interface IFeeModel { + function getNFTInFee(address filterAdminAddr, address user) external view returns(uint256); + + function getNFTRandomOutFee(address filterAdminAddr, address user) external view returns(uint256); + + function getNFTTargetOutFee(address filterAdminAddr, address user) external view returns(uint256); +} \ No newline at end of file diff --git a/contracts/NFTPool/intf/IFilterAdmin.sol b/contracts/NFTPool/intf/IFilterAdmin.sol new file mode 100644 index 0000000..542539c --- /dev/null +++ b/contracts/NFTPool/intf/IFilterAdmin.sol @@ -0,0 +1,12 @@ +/* + + Copyright 2021 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +interface IFilterAdmin { + function _OWNER_() external returns (address); +} \ No newline at end of file diff --git a/contracts/NFTPool/intf/IFilterERC1155Model.sol b/contracts/NFTPool/intf/IFilterERC1155Model.sol deleted file mode 100644 index f4fae33..0000000 --- a/contracts/NFTPool/intf/IFilterERC1155Model.sol +++ /dev/null @@ -1,20 +0,0 @@ -/* - - Copyright 2021 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; - -interface IFilterERC1155Model { - function isFilterERC1155Pass(address nftCollectionAddress, uint256 nftId, uint256 amount) external view returns (bool); - - function saveNFTPrice(address nftCollectionAddress, uint256 nftId, uint256 amount) external view returns(uint256); - - function buySpecNFTPrice(address nftCollectionAddress, uint256 nftId, uint256 amount) external view returns(uint256); - - function buyLotteryNFTPrice() external view returns(uint256); - - function lottery() external view returns(address nftCollection, uint256 nftId); -} \ No newline at end of file diff --git a/contracts/NFTPool/intf/IFilterERC721Model.sol b/contracts/NFTPool/intf/IFilterERC721Model.sol deleted file mode 100644 index 2e2cd42..0000000 --- a/contracts/NFTPool/intf/IFilterERC721Model.sol +++ /dev/null @@ -1,20 +0,0 @@ -/* - - Copyright 2021 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; - -interface IFilterERC721Model { - function isFilterERC721Pass(address nftCollectionAddress, uint256 nftId) external view returns (bool); - - function saveNFTPrice(address nftCollectionAddress, uint256 nftId) external view returns(uint256); - - function buySpecNFTPrice(address nftCollectionAddress, uint256 nftId) external view returns(uint256); - - function buyLotteryNFTPrice() external view returns(uint256); - - function lottery() external view returns(address nftCollection, uint256 nftId); -} \ No newline at end of file diff --git a/contracts/NFTPool/intf/IFilterModel.sol b/contracts/NFTPool/intf/IFilterModel.sol new file mode 100644 index 0000000..2d626af --- /dev/null +++ b/contracts/NFTPool/intf/IFilterModel.sol @@ -0,0 +1,42 @@ +/* + + Copyright 2021 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +interface IFilterModel { + function isFilterERC721Pass(address nftCollectionAddress, uint256 nftId) external view returns (bool); + + function isFilterERC1155Pass(address nftCollectionAddress, uint256 nftId, uint256 amount) external view returns (bool); + + function getAvaliableNFTIn() external view returns(uint256); + + function getAvaliableNFTOut() external view returns(uint256); + + function _NFT_IN_SWITCH_() external view returns(bool); + + function _NFT_RANDOM_SWITCH_() external view returns(bool); + + function _NFT_TARGET_SWITCH_() external view returns(bool); + + function getNFTInPrice(address nftCollectionAddress, uint256 nftId) external view returns (uint256); + + function getNFTRandomOutPrice() external view returns (uint256); + + function getNFTTargetOutPrice(address nftCollectionAddress, uint256 nftId) external view returns (uint256); + + function getRandomOutId() external view returns (address nftCollection, uint256 nftId); + + function transferOutERC721(address nftContract, address assetTo, uint256 nftId) external; + + function transferInERC721(address nftContract, address assetFrom, uint256 nftId) external; + + function transferOutERC1155(address nftContract, address assetTo, uint256 nftId, uint256 amount) external; + + function transferBatchOutERC1155(address nftContract, address assetTo, uint256[] memory nftIds, uint256[] memory amounts) external; + + function transferBatchInERC1155(address nftContract, address assetFrom, uint256[] memory nftIds, uint256[] memory amounts) external; +} \ No newline at end of file diff --git a/contracts/SmartRoute/proxies/DODONFTPoolProxy.sol b/contracts/SmartRoute/proxies/DODONFTPoolProxy.sol index e69de29..d641290 100644 --- a/contracts/SmartRoute/proxies/DODONFTPoolProxy.sol +++ b/contracts/SmartRoute/proxies/DODONFTPoolProxy.sol @@ -0,0 +1,81 @@ +/* + Copyright 2021 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 +*/ + +pragma solidity 0.6.9; + +import {SafeMath} from "../../lib/SafeMath.sol"; +import {InitializableOwnable} from "../../lib/InitializableOwnable.sol"; +import {ICloneFactory} from "../../lib/CloneFactory.sol"; +import {ReentrancyGuard} from "../../lib/ReentrancyGuard.sol"; + + +contract DODONFTPoolProxy is ReentrancyGuard, InitializableOwnable { + using SafeMath for uint256; + + // ============ Storage ============ + mapping(uint256 => address) public _FILTER_TEMPLATES_; + address public _FILTER_ADMIN_TEMPLATE_; + address public _DEFAULT_MAINTAINER_; + address public _NFT_POOL_FEE_MODEL_; + address public immutable _CLONE_FACTORY_; + + + // ============ Event ============== + event SetFilterTemplate(uint256 idx, address filterTemplate); + + constructor( + address cloneFactory, + address filterAdminTemplate, + address nftPoolFeeModel, + address defaultMaintainer + ) public { + _CLONE_FACTORY_ = cloneFactory; + _FILTER_ADMIN_TEMPLATE_ = filterAdminTemplate; + _NFT_POOL_FEE_MODEL_ = nftPoolFeeModel; + _DEFAULT_MAINTAINER_ = defaultMaintainer; + } + + //TODO:一笔交易 + + function createFilterAdmin( + string memory name, + string memory symbol, + uint256 fee + ) external returns(address) { + + } + + + function createFilter01( + address filterAdmin, + address nftCollection, + bool[] memory switches, + uint256[] memory tokenRanges, + uint256[] memory nftAmounts, + uint256[] memory priceRules, + uint256[] memory spreadIds + ) external returns(address) { + + } + + + //====================== Ownable ======================== + function changeDefaultMaintainer(address newMaintainer) external onlyOwner { + _DEFAULT_MAINTAINER_ = newMaintainer; + } + + function changeFilterAdminTemplate(address newFilterAdminTemplate) external onlyOwner { + _FILTER_ADMIN_TEMPLATE_ = newFilterAdminTemplate; + } + + function changeNftPoolFeeModel(address newNftPoolFeeModel) external onlyOwner { + _NFT_POOL_FEE_MODEL_ = newNftPoolFeeModel; + } + + function setFilterTemplate(uint256 idx, address newFilterTemplate) external onlyOwner { + _FILTER_TEMPLATES_[idx] = newFilterTemplate; + emit SetFilterTemplate(idx, newFilterTemplate); + } +} \ No newline at end of file diff --git a/contracts/external/ERC20/InitializableInternalMintableERC20.sol b/contracts/external/ERC20/InitializableInternalMintableERC20.sol index d22349d..ec3eb49 100644 --- a/contracts/external/ERC20/InitializableInternalMintableERC20.sol +++ b/contracts/external/ERC20/InitializableInternalMintableERC20.sol @@ -8,8 +8,9 @@ pragma solidity 0.6.9; import {SafeMath} from "../../lib/SafeMath.sol"; +import {InitializableOwnable} from "../../lib/InitializableOwnable.sol"; -contract InitializableInternalMintableERC20 { +contract InitializableInternalMintableERC20 is InitializableOwnable { using SafeMath for uint256; string public name; @@ -32,6 +33,7 @@ contract InitializableInternalMintableERC20 { string memory _symbol, uint8 _decimals ) public { + initOwner(_creator); name = _name; symbol = _symbol; decimals = _decimals;