dev
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
260
contracts/NFTPool/impl/FilterModel01.sol
Normal file
260
contracts/NFTPool/impl/FilterModel01.sol
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
85
contracts/NFTPool/impl/NFTPoolFeeModel.sol
Normal file
85
contracts/NFTPool/impl/NFTPoolFeeModel.sol
Normal file
@@ -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_;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
16
contracts/NFTPool/intf/IFeeModel.sol
Normal file
16
contracts/NFTPool/intf/IFeeModel.sol
Normal file
@@ -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);
|
||||
}
|
||||
12
contracts/NFTPool/intf/IFilterAdmin.sol
Normal file
12
contracts/NFTPool/intf/IFilterAdmin.sol
Normal file
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
42
contracts/NFTPool/intf/IFilterModel.sol
Normal file
42
contracts/NFTPool/intf/IFilterModel.sol
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user