dev
This commit is contained in:
@@ -16,13 +16,11 @@ contract ControllerModel is InitializableOwnable {
|
|||||||
using SafeMath for uint256;
|
using SafeMath for uint256;
|
||||||
|
|
||||||
uint256 public _GLOBAL_NFT_IN_FEE_ = 0;
|
uint256 public _GLOBAL_NFT_IN_FEE_ = 0;
|
||||||
uint256 public _GLOBAL_NFT_RANDOM_OUT_FEE_ = 0;
|
uint256 public _GLOBAL_NFT_OUT_FEE_ = 0;
|
||||||
uint256 public _GLOBAL_NFT_TARGET_OUT_FEE_ = 50000000000000000;//0.05
|
|
||||||
|
|
||||||
struct FilterAdminFeeInfo {
|
struct FilterAdminFeeInfo {
|
||||||
uint256 nftInFee;
|
uint256 nftInFee;
|
||||||
uint256 nftRandomOutFee;
|
uint256 nftOutFee;
|
||||||
uint256 nftTargetOutFee;
|
|
||||||
bool isSet;
|
bool isSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,26 +33,23 @@ contract ControllerModel is InitializableOwnable {
|
|||||||
|
|
||||||
//==================== Ownable ====================
|
//==================== Ownable ====================
|
||||||
|
|
||||||
function addFilterAdminFeeInfo(address filterAdminAddr, uint256 nftInFee, uint256 nftRandomOutFee, uint256 nftTargetOutFee) external onlyOwner {
|
function addFilterAdminFeeInfo(address filterAdminAddr, uint256 nftInFee, uint256 nftOutFee) external onlyOwner {
|
||||||
FilterAdminFeeInfo memory filterAdmin = FilterAdminFeeInfo({
|
FilterAdminFeeInfo memory filterAdmin = FilterAdminFeeInfo({
|
||||||
nftInFee: nftInFee,
|
nftInFee: nftInFee,
|
||||||
nftRandomOutFee: nftRandomOutFee,
|
nftOutFee: nftOutFee,
|
||||||
nftTargetOutFee: nftTargetOutFee,
|
|
||||||
isSet: true
|
isSet: true
|
||||||
});
|
});
|
||||||
filterAdminFees[filterAdminAddr] = filterAdmin;
|
filterAdminFees[filterAdminAddr] = filterAdmin;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setFilterAdminFeeInfo(address filterAdminAddr, uint256 nftInFee, uint256 nftRandomOutFee, uint256 nftTargetOutFee) external onlyOwner {
|
function setFilterAdminFeeInfo(address filterAdminAddr, uint256 nftInFee, uint256 nftOutFee) external onlyOwner {
|
||||||
filterAdminFees[filterAdminAddr].nftInFee = nftInFee;
|
filterAdminFees[filterAdminAddr].nftInFee = nftInFee;
|
||||||
filterAdminFees[filterAdminAddr].nftRandomOutFee = nftRandomOutFee;
|
filterAdminFees[filterAdminAddr].nftOutFee = nftOutFee;
|
||||||
filterAdminFees[filterAdminAddr].nftTargetOutFee = nftTargetOutFee;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setGlobalParam(uint256 nftInFee, uint256 nftRandomOutFee, uint256 nftTargetOutFee) external onlyOwner {
|
function setGlobalParam(uint256 nftInFee, uint256 nftOutFee) external onlyOwner {
|
||||||
_GLOBAL_NFT_IN_FEE_ = nftInFee;
|
_GLOBAL_NFT_IN_FEE_ = nftInFee;
|
||||||
_GLOBAL_NFT_RANDOM_OUT_FEE_ = nftRandomOutFee;
|
_GLOBAL_NFT_OUT_FEE_ = nftOutFee;
|
||||||
_GLOBAL_NFT_TARGET_OUT_FEE_ = nftTargetOutFee;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setEmergencyWithdraw(address filter, bool isOpen) external onlyOwner {
|
function setEmergencyWithdraw(address filter, bool isOpen) external onlyOwner {
|
||||||
@@ -63,7 +58,7 @@ contract ControllerModel is InitializableOwnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//===================== View ========================
|
//===================== View ========================
|
||||||
function getNFTInFee(address filterAdminAddr, address) external view returns(uint256) {
|
function getMintFee(address filterAdminAddr) external view returns(uint256) {
|
||||||
FilterAdminFeeInfo memory filterAdminFeeInfo = filterAdminFees[filterAdminAddr];
|
FilterAdminFeeInfo memory filterAdminFeeInfo = filterAdminFees[filterAdminAddr];
|
||||||
|
|
||||||
if(filterAdminFeeInfo.isSet) {
|
if(filterAdminFeeInfo.isSet) {
|
||||||
@@ -73,26 +68,16 @@ contract ControllerModel is InitializableOwnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNFTRandomOutFee(address filterAdminAddr, address) external view returns(uint256) {
|
function getBurnFee(address filterAdminAddr) external view returns(uint256) {
|
||||||
FilterAdminFeeInfo memory filterAdminFeeInfo = filterAdminFees[filterAdminAddr];
|
FilterAdminFeeInfo memory filterAdminFeeInfo = filterAdminFees[filterAdminAddr];
|
||||||
|
|
||||||
if(filterAdminFeeInfo.isSet) {
|
if(filterAdminFeeInfo.isSet) {
|
||||||
return filterAdminFeeInfo.nftRandomOutFee;
|
return filterAdminFeeInfo.nftOutFee;
|
||||||
}else {
|
}else {
|
||||||
return _GLOBAL_NFT_RANDOM_OUT_FEE_;
|
return _GLOBAL_NFT_OUT_FEE_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNFTTargetOutFee(address filterAdminAddr, address) external view returns(uint256) {
|
|
||||||
FilterAdminFeeInfo memory filterAdminFeeInfo = filterAdminFees[filterAdminAddr];
|
|
||||||
|
|
||||||
if(filterAdminFeeInfo.isSet) {
|
|
||||||
return filterAdminFeeInfo.nftTargetOutFee;
|
|
||||||
}else {
|
|
||||||
return _GLOBAL_NFT_TARGET_OUT_FEE_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getEmergencySwitch(address filter) external view returns(bool) {
|
function getEmergencySwitch(address filter) external view returns(bool) {
|
||||||
return isEmergencyWithdraw[filter];
|
return isEmergencyWithdraw[filter];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,10 @@ pragma experimental ABIEncoderV2;
|
|||||||
|
|
||||||
import {InitializableInternalMintableERC20} from "../../external/ERC20/InitializableInternalMintableERC20.sol";
|
import {InitializableInternalMintableERC20} from "../../external/ERC20/InitializableInternalMintableERC20.sol";
|
||||||
import {SafeMath} from "../../lib/SafeMath.sol";
|
import {SafeMath} from "../../lib/SafeMath.sol";
|
||||||
import {IFilterModel} from "../intf/IFilterModel.sol";
|
|
||||||
import {IControllerModel} from "../intf/IControllerModel.sol";
|
import {IControllerModel} from "../intf/IControllerModel.sol";
|
||||||
import {ReentrancyGuard} from "../../lib/ReentrancyGuard.sol";
|
|
||||||
import {DecimalMath} from "../../lib/DecimalMath.sol";
|
import {DecimalMath} from "../../lib/DecimalMath.sol";
|
||||||
|
|
||||||
contract FilterAdmin is InitializableInternalMintableERC20, ReentrancyGuard {
|
contract FilterAdmin is InitializableInternalMintableERC20 {
|
||||||
using SafeMath for uint256;
|
using SafeMath for uint256;
|
||||||
|
|
||||||
// ============ Storage ============
|
// ============ Storage ============
|
||||||
@@ -28,69 +26,57 @@ contract FilterAdmin is InitializableInternalMintableERC20, ReentrancyGuard {
|
|||||||
event ChangeFee(uint256 fee);
|
event ChangeFee(uint256 fee);
|
||||||
|
|
||||||
function init(
|
function init(
|
||||||
address _owner,
|
address owner,
|
||||||
string memory _name,
|
uint256 initSupply,
|
||||||
string memory _symbol,
|
string memory name,
|
||||||
|
string memory symbol,
|
||||||
uint256 fee,
|
uint256 fee,
|
||||||
address controllerModel,
|
address controllerModel,
|
||||||
address defaultMaintainer,
|
address defaultMaintainer,
|
||||||
address[] memory filters
|
address[] memory filters
|
||||||
) external {
|
) external {
|
||||||
super.init(_owner, 0, _name, _symbol, 18);
|
super.init(owner, initSupply, name, symbol, 18);
|
||||||
_FILTER_REGISTRY_ = filters;
|
_FILTER_REGISTRY_ = filters;
|
||||||
_FEE_ = fee;
|
_FEE_ = fee;
|
||||||
_CONTROLLER_MODEL_ = controllerModel;
|
_CONTROLLER_MODEL_ = controllerModel;
|
||||||
_DEFAULT_MAINTAINER_ = defaultMaintainer;
|
_DEFAULT_MAINTAINER_ = defaultMaintainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function chargeMint(address user, uint256 totalMintAmount) external {
|
function mintFragTo(address to, uint256 rawAmount) external returns (uint256 received){
|
||||||
require(isIncludeFilter(msg.sender), "FILTER_NOT_REGISTRIED");
|
require(isIncludeFilter(msg.sender), "FILTER_NOT_REGISTRIED");
|
||||||
|
|
||||||
(uint256 poolFeeAmount, uint256 mtFeeAmount) = getMintFee(user, totalMintAmount);
|
(uint256 poolFee, uint256 mtFee) = queryChargeMintFee(rawAmount);
|
||||||
if(poolFeeAmount > 0) _mint(_OWNER_, poolFeeAmount);
|
if(poolFee > 0) _mint(_OWNER_, poolFee);
|
||||||
if(mtFeeAmount > 0) _mint(_DEFAULT_MAINTAINER_, mtFeeAmount);
|
if(mtFee > 0) _mint(_DEFAULT_MAINTAINER_, mtFee);
|
||||||
|
|
||||||
_mint(user, totalMintAmount.sub(poolFeeAmount).sub(mtFeeAmount));
|
received = rawAmount.sub(poolFee).sub(mtFee);
|
||||||
|
_mint(to, received);
|
||||||
}
|
}
|
||||||
|
|
||||||
function chargeRandomBurn(address user, uint256 totalBurnAmount) external {
|
function burnFragFrom(address from, uint256 rawAmount) external returns (uint256 paid){
|
||||||
require(isIncludeFilter(msg.sender), "FILTER_NOT_REGISTRIED");
|
require(isIncludeFilter(msg.sender), "FILTER_NOT_REGISTRIED");
|
||||||
|
|
||||||
(uint256 poolFeeAmount, uint256 mtFeeAmount) = getRandomBurnFee(user, totalBurnAmount);
|
(uint256 poolFee, uint256 mtFee) = queryChargeBurnFee(rawAmount);
|
||||||
if(poolFeeAmount > 0) _mint(_OWNER_, poolFeeAmount);
|
if(poolFee > 0) _mint(_OWNER_, poolFee);
|
||||||
if(mtFeeAmount > 0) _mint(_DEFAULT_MAINTAINER_, mtFeeAmount);
|
if(mtFee > 0) _mint(_DEFAULT_MAINTAINER_, mtFee);
|
||||||
|
|
||||||
_burn(user, totalBurnAmount);
|
paid = rawAmount.add(poolFee).add(mtFee);
|
||||||
}
|
_burn(from, paid);
|
||||||
|
|
||||||
function chargeTargetBurn(address user, uint256 totalBurnAmount) external {
|
|
||||||
require(isIncludeFilter(msg.sender), "FILTER_NOT_REGISTRIED");
|
|
||||||
|
|
||||||
(uint256 poolFeeAmount, uint256 mtFeeAmount) = getTargetBurnFee(user, totalBurnAmount);
|
|
||||||
if(poolFeeAmount > 0) _mint(_OWNER_, poolFeeAmount);
|
|
||||||
if(mtFeeAmount > 0) _mint(_DEFAULT_MAINTAINER_, mtFeeAmount);
|
|
||||||
|
|
||||||
_burn(user, totalBurnAmount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//================ View ================
|
//================ View ================
|
||||||
function getMintFee(address user, uint256 totalMintAmount) public returns (uint256 poolFeeAmount, uint256 mtFeeAmount) {
|
function queryChargeMintFee(uint256 rawAmount) public returns (uint256 poolFee, uint256 mtFee) {
|
||||||
uint256 mtFeeRate = IControllerModel(_CONTROLLER_MODEL_).getNFTInFee(address(this), user);
|
uint256 mtFeeRate = IControllerModel(_CONTROLLER_MODEL_).getMintFee(address(this));
|
||||||
poolFeeAmount = DecimalMath.mulFloor(totalMintAmount, _FEE_);
|
poolFee = DecimalMath.mulFloor(rawAmount, _FEE_);
|
||||||
mtFeeAmount = DecimalMath.mulFloor(totalMintAmount, mtFeeRate);
|
mtFee = DecimalMath.mulFloor(rawAmount, mtFeeRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRandomBurnFee(address user, uint256 totalBurnAmount) public returns (uint256 poolFeeAmount, uint256 mtFeeAmount) {
|
function queryChargeBurnFee(uint256 rawAmount) public returns (uint256 poolFee, uint256 mtFee) {
|
||||||
uint256 mtFeeRate = IControllerModel(_CONTROLLER_MODEL_).getNFTRandomOutFee(address(this), user);
|
uint256 mtFeeRate = IControllerModel(_CONTROLLER_MODEL_).getBurnFee(address(this));
|
||||||
poolFeeAmount = DecimalMath.mulFloor(totalBurnAmount, _FEE_);
|
poolFee = DecimalMath.mulFloor(rawAmount, _FEE_);
|
||||||
mtFeeAmount = DecimalMath.mulFloor(totalBurnAmount, mtFeeRate);
|
mtFee = DecimalMath.mulFloor(rawAmount, mtFeeRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTargetBurnFee(address user, uint256 totalBurnAmount) public returns (uint256 poolFeeAmount, uint256 mtFeeAmount) {
|
|
||||||
uint256 mtFeeRate = IControllerModel(_CONTROLLER_MODEL_).getNFTTargetOutFee(address(this), user);
|
|
||||||
poolFeeAmount = DecimalMath.mulFloor(totalBurnAmount, _FEE_);
|
|
||||||
mtFeeAmount = DecimalMath.mulFloor(totalBurnAmount, mtFeeRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isIncludeFilter(address filter) view public returns (bool) {
|
function isIncludeFilter(address filter) view public returns (bool) {
|
||||||
uint256 i = 0;
|
uint256 i = 0;
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ import {IControllerModel} from "../intf/IControllerModel.sol";
|
|||||||
import {IERC721} from "../../intf/IERC721.sol";
|
import {IERC721} from "../../intf/IERC721.sol";
|
||||||
import {IERC721Receiver} from "../../intf/IERC721Receiver.sol";
|
import {IERC721Receiver} from "../../intf/IERC721Receiver.sol";
|
||||||
import {DecimalMath} from "../../lib/DecimalMath.sol";
|
import {DecimalMath} from "../../lib/DecimalMath.sol";
|
||||||
|
import {ReentrancyGuard} from "../../lib/ReentrancyGuard.sol";
|
||||||
|
|
||||||
|
contract FilterERC721V1 is InitializableOwnable, IERC721Receiver, ReentrancyGuard {
|
||||||
contract FilterModel01 is InitializableOwnable, IERC721Receiver {
|
|
||||||
using SafeMath for uint256;
|
using SafeMath for uint256;
|
||||||
|
|
||||||
//=================== Storage ===================
|
//=================== Storage ===================
|
||||||
@@ -27,6 +27,7 @@ contract FilterModel01 is InitializableOwnable, IERC721Receiver {
|
|||||||
|
|
||||||
//tokenId => isRegistered
|
//tokenId => isRegistered
|
||||||
mapping(uint256 => bool) public _SPREAD_IDS_REGISTRY_;
|
mapping(uint256 => bool) public _SPREAD_IDS_REGISTRY_;
|
||||||
|
//tokenId => 1
|
||||||
mapping(uint256 => uint256) public _NFT_RESERVE_;
|
mapping(uint256 => uint256) public _NFT_RESERVE_;
|
||||||
|
|
||||||
uint256[] public _NFT_IDS_;
|
uint256[] public _NFT_IDS_;
|
||||||
@@ -54,9 +55,25 @@ contract FilterModel01 is InitializableOwnable, IERC721Receiver {
|
|||||||
function init(
|
function init(
|
||||||
address filterAdmin,
|
address filterAdmin,
|
||||||
address nftCollection,
|
address nftCollection,
|
||||||
|
bool[] memory switches,
|
||||||
|
uint256[] memory tokenRanges,
|
||||||
|
uint256[] memory nftAmounts,
|
||||||
|
uint256[] memory priceRules,
|
||||||
|
uint256[] memory spreadIds
|
||||||
) external {
|
) external {
|
||||||
initOwner(filterAdmin);
|
initOwner(filterAdmin);
|
||||||
_NFT_COLLECTION_ = nftCollection;
|
_NFT_COLLECTION_ = nftCollection;
|
||||||
|
|
||||||
|
_changeNFTInPrice(priceRules[0],priceRules[1],switches[0]);
|
||||||
|
_changeNFTRandomInPrice(priceRules[2],priceRules[3],switches[1]);
|
||||||
|
_changeNFTTargetOutPrice(priceRules[4],priceRules[5],switches[2]);
|
||||||
|
|
||||||
|
_changeNFTAmount(nftAmounts[0],nftAmounts[1]);
|
||||||
|
|
||||||
|
_changeTokenIdRange(tokenRanges[0],tokenRanges[1]);
|
||||||
|
for(uint256 i = 0; i < spreadIds.length; i++) {
|
||||||
|
_SPREAD_IDS_REGISTRY_[spreadIds[i]] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================== Query ==================
|
//==================== Query ==================
|
||||||
@@ -69,54 +86,69 @@ contract FilterModel01 is InitializableOwnable, IERC721Receiver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isNFTIDValid(uint256 nftId) public view returns(bool){
|
function isNFTIDValid(uint256 nftId) public view returns(bool) {
|
||||||
if((nftId >= _TOKEN_ID_START_ && nftId <= _TOKEN_ID_END_) || _SPREAD_IDS_REGISTRY_[nftId]) {
|
if((nftId >= _NFT_ID_START_ && nftId <= _NFT_ID_END_) || _SPREAD_IDS_REGISTRY_[nftId]) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAvaliableNFTIn() public view returns(uint256) {
|
function getAvaliableNFTIn() public view returns(uint256) {
|
||||||
if(_MAX_NFT_AMOUNT_ < _TOKEN_IDS_.length) {
|
if(_MAX_NFT_AMOUNT_ < _NFT_IDS_.length) {
|
||||||
return 0;
|
return 0;
|
||||||
}else {
|
}else {
|
||||||
return _MAX_NFT_AMOUNT_ - _TOKEN_IDS_.length;
|
return _MAX_NFT_AMOUNT_ - _NFT_IDS_.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAvaliableNFTOut() public view returns(uint256) {
|
function getAvaliableNFTOut() public view returns(uint256) {
|
||||||
if(_TOKEN_IDS_.length < _MIN_NFT_AMOUNT_) {
|
if(_NFT_IDS_.length < _MIN_NFT_AMOUNT_) {
|
||||||
return 0;
|
return 0;
|
||||||
}else {
|
}else {
|
||||||
return _TOKEN_IDS_.length - _MIN_NFT_AMOUNT_;
|
return _NFT_IDS_.length - _MIN_NFT_AMOUNT_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function queryNFTIn(uint256 NFTInAmount) external view returns (uint256 rawReceive, uint256 receive) {
|
function getNFTIndexById(uint256 tokenId) public view returns(uint256) {
|
||||||
|
uint256 i = 0;
|
||||||
|
for(; i < _NFT_IDS_.length; i++) {
|
||||||
|
if(_NFT_IDS_[i] == tokenId) break;
|
||||||
|
}
|
||||||
|
require(i < _NFT_IDS_.length, "TOKEN_ID_NOT_EXSIT");
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryNFTIn(uint256 NFTInAmount) public view returns (uint256 rawReceive, uint256 received) {
|
||||||
require(NFTInAmount <= getAvaliableNFTIn(), "EXCEDD_IN_AMOUNT");
|
require(NFTInAmount <= getAvaliableNFTIn(), "EXCEDD_IN_AMOUNT");
|
||||||
rawReceive = geometricCalc(_GS_START_IN_, _CR_IN_, _NFT_AMOUNT_, _NFT_AMOUNT_+NFTInAmount);
|
uint256 nftAmount = _NFT_IDS_.length;
|
||||||
receive = IFilterAdmin(_OWNER_).queryChargeMintFee(rawReceive);
|
rawReceive = geometricCalc(_GS_START_IN_, _CR_IN_, nftAmount, nftAmount + NFTInAmount);
|
||||||
|
(uint256 poolFee, uint256 mtFee) = IFilterAdmin(_OWNER_).queryChargeMintFee(rawReceive);
|
||||||
|
received = rawReceive.sub(poolFee).sub(mtFee);
|
||||||
}
|
}
|
||||||
|
|
||||||
function queryNFTTargetOut(uint256 NFTOutAmount) external view returns (uint256 rawPay, uint256 pay) {
|
function queryNFTTargetOut(uint256 NFTOutAmount) public view returns (uint256 rawPay, uint256 pay) {
|
||||||
require(NFTOutAmount <= getAvaliableNFTOut(), "EXCEED_OUT_AMOUNT");
|
require(NFTOutAmount <= getAvaliableNFTOut(), "EXCEED_OUT_AMOUNT");
|
||||||
rawPay = geometricCalc(_GS_START_TARGET_OUT_,_CR_TARGET_OUT_, _NFT_AMOUNT_-NFTOutAmount,_NFT_AMOUNT_);
|
uint256 nftAmount = _NFT_IDS_.length;
|
||||||
pay = IFilterAdmin(_OWNER_).queryChargeBurnFee(rawPay);
|
rawPay = geometricCalc(_GS_START_TARGET_OUT_,_CR_TARGET_OUT_, nftAmount - NFTOutAmount, nftAmount);
|
||||||
|
(uint256 poolFee, uint256 mtFee) = IFilterAdmin(_OWNER_).queryChargeBurnFee(rawPay);
|
||||||
|
pay = rawPay.add(poolFee).add(mtFee);
|
||||||
}
|
}
|
||||||
|
|
||||||
function queryNFTRandomOut(uint256 NFTOutAmount) external view returns (uint256 rawPay, uint256 pay) {
|
function queryNFTRandomOut(uint256 NFTOutAmount) public view returns (uint256 rawPay, uint256 pay) {
|
||||||
require(NFTOutAmount <= getAvaliableNFTOut(), "EXCEED_OUT_AMOUNT");
|
require(NFTOutAmount <= getAvaliableNFTOut(), "EXCEED_OUT_AMOUNT");
|
||||||
rawPay = geometricCalc(_GS_START_RANDOM_OUT_,_CR_RANDOM_OUT_, _NFT_AMOUNT_-NFTOutAmount,_NFT_AMOUNT_);
|
uint256 nftAmount = _NFT_IDS_.length;
|
||||||
pay = IFilterAdmin(_OWNER_).chargeBurnFee(rawPay);
|
rawPay = geometricCalc(_GS_START_RANDOM_OUT_,_CR_RANDOM_OUT_, nftAmount - NFTOutAmount, nftAmount);
|
||||||
|
(uint256 poolFee, uint256 mtFee) = IFilterAdmin(_OWNER_).queryChargeBurnFee(rawPay);
|
||||||
|
pay = rawPay.add(poolFee).add(mtFee);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================= Trading ================
|
// ================= Trading ================
|
||||||
|
|
||||||
function ERC721In(uint256[] memory tokenIds, address to) external preventReentrant returns(uint256 received) {
|
function ERC721In(uint256[] memory tokenIds, address to) external preventReentrant returns(uint256 received) {
|
||||||
for (uint256 i = 0; i < tokenIds.length; i++) {
|
for (uint256 i = 0; i < tokenIds.length; i++) {
|
||||||
require(!_NFT_RESERVE_[tokenIds[i]] && IERC721(_NFT_COLLECTION_).ownerOf(tokenIds[i])==address(this), "NFT_NOT_SEND");
|
require(_NFT_RESERVE_[tokenIds[i]] == 0 && IERC721(_NFT_COLLECTION_).ownerOf(tokenIds[i])==address(this), "NFT_NOT_SEND");
|
||||||
_NFT_IDS_.push(tokenId);
|
_NFT_IDS_.push(tokenIds[i]);
|
||||||
_NFT_RESERVE_[tokenIds[i]] = 1;
|
_NFT_RESERVE_[tokenIds[i]] = 1;
|
||||||
}
|
}
|
||||||
(uint256 rawReceive,) = queryNFTIn(tokenIds.length);
|
(uint256 rawReceive,) = queryNFTIn(tokenIds.length);
|
||||||
@@ -124,7 +156,7 @@ contract FilterModel01 is InitializableOwnable, IERC721Receiver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ERC721TargetOut(uint256[] memory indexes, address to) external preventReentrant returns(uint256 paid) {
|
function ERC721TargetOut(uint256[] memory indexes, address to) external preventReentrant returns(uint256 paid) {
|
||||||
(uint256 rawPay, ) = queryNFTOut(tokenIds.length);
|
(uint256 rawPay, ) = queryNFTTargetOut(indexes.length);
|
||||||
paid = IFilterAdmin(_OWNER_).burnFragFrom(msg.sender, rawPay);
|
paid = IFilterAdmin(_OWNER_).burnFragFrom(msg.sender, rawPay);
|
||||||
for (uint256 i = 0; i < indexes.length; i++) {
|
for (uint256 i = 0; i < indexes.length; i++) {
|
||||||
_transferOutERC721(to, indexes[i]);
|
_transferOutERC721(to, indexes[i]);
|
||||||
@@ -132,7 +164,7 @@ contract FilterModel01 is InitializableOwnable, IERC721Receiver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ERC721RandomOut(uint256 amount, address to) external preventReentrant returns (uint256 paid) {
|
function ERC721RandomOut(uint256 amount, address to) external preventReentrant returns (uint256 paid) {
|
||||||
(uint256 rawPay, ) = queryNFTOut(amount);
|
(uint256 rawPay, ) = queryNFTRandomOut(amount);
|
||||||
paid = IFilterAdmin(_OWNER_).burnFragFrom(msg.sender, rawPay);
|
paid = IFilterAdmin(_OWNER_).burnFragFrom(msg.sender, rawPay);
|
||||||
for (uint256 i = 0; i < amount; i++) {
|
for (uint256 i = 0; i < amount; i++) {
|
||||||
_transferOutERC721(to, getRandomOutId());
|
_transferOutERC721(to, getRandomOutId());
|
||||||
@@ -144,18 +176,18 @@ contract FilterModel01 is InitializableOwnable, IERC721Receiver {
|
|||||||
function onERC721Received(
|
function onERC721Received(
|
||||||
address,
|
address,
|
||||||
address,
|
address,
|
||||||
uint256 tokenId,
|
uint256,
|
||||||
bytes calldata
|
bytes calldata
|
||||||
) external override returns (bytes4) {
|
) external override returns (bytes4) {
|
||||||
return IERC721Receiver.onERC721Received.selector;
|
return IERC721Receiver.onERC721Received.selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _transferOutERC721(address to, uint256 index) internal {
|
function _transferOutERC721(address to, uint256 index) internal {
|
||||||
require(index<_TOKEN_IDS_.length, "INDEX_NOT_EXIST");
|
require(index < _NFT_IDS_.length, "INDEX_NOT_EXIST");
|
||||||
uint256 tokenId = _TOKEN_IDS_[index];
|
uint256 tokenId = _NFT_IDS_[index];
|
||||||
IERC721(_NFT_COLLECTION_).safeTransfer(to, tokenId);
|
IERC721(_NFT_COLLECTION_).safeTransferFrom(address(this), to, tokenId);
|
||||||
_TOKEN_IDS_[index] = _TOKEN_IDS_[_TOKEN_IDS_.length - 1];
|
_NFT_IDS_[index] = _NFT_IDS_[_NFT_IDS_.length - 1];
|
||||||
_TOKEN_IDS_.pop();
|
_NFT_IDS_.pop();
|
||||||
_NFT_RESERVE_[tokenId] = 0;
|
_NFT_RESERVE_[tokenId] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,89 +198,115 @@ contract FilterModel01 is InitializableOwnable, IERC721Receiver {
|
|||||||
require(IControllerModel(controllerModel).getEmergencySwitch(address(this)), "NOT_OPEN");
|
require(IControllerModel(controllerModel).getEmergencySwitch(address(this)), "NOT_OPEN");
|
||||||
|
|
||||||
for(uint256 i = 0; i< nftContract.length; i++) {
|
for(uint256 i = 0; i< nftContract.length; i++) {
|
||||||
if(_NFT_RESERVE_[tokenIds[i]] && nftContract[i]==_NFT_COLLECTION_){
|
if(_NFT_RESERVE_[tokenIds[i]] == 1 && nftContract[i] == _NFT_COLLECTION_){
|
||||||
uint256 index = getNFTIndex(tokenIds[i]);
|
uint256 index = getNFTIndexById(tokenIds[i]);
|
||||||
_TOKEN_IDS_[index] = _TOKEN_IDS_[_TOKEN_IDS_.length - 1];
|
_NFT_IDS_[index] = _NFT_IDS_[_NFT_IDS_.length - 1];
|
||||||
_TOKEN_IDS_.pop();
|
_NFT_IDS_.pop();
|
||||||
_NFT_RESERVE_[tokenId] = 0;
|
_NFT_RESERVE_[tokenIds[i]] = 0;
|
||||||
}
|
}
|
||||||
IERC721(nftContract[i]).safeTransfer(to, tokenId);
|
IERC721(nftContract[i]).safeTransferFrom(address(this), to, tokenIds[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ============ Math =============
|
// ============ Math =============
|
||||||
|
|
||||||
function geometricCalc(uint256 base, uint256 ratio, uint256 times) internal view returns(uint256 newBase, uint256 sum) {
|
function geometricCalc(uint256 a1, uint256 q, uint256 start, uint256 end) internal view returns(uint256) {
|
||||||
sum = 0;
|
//Sn=a1*(q^n-1)/(q-1)
|
||||||
for(uint256 i = 0; i < times; i++) {
|
//Sn-Sm = a1*(q^n-q^m)/(q-1)
|
||||||
base = DecimalMath.mulFloor(base, ratio);
|
|
||||||
sum = sum.add(base);
|
//q^n
|
||||||
}
|
uint256 qn = DecimalMath.powFloor(q, end);
|
||||||
newBase = base;
|
//q^m
|
||||||
|
uint256 qm = DecimalMath.powFloor(q, start);
|
||||||
|
return a1.mul(qn.sub(qm)).div(q.sub(DecimalMath.ONE));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRandomOutId() external view returns (uint256 index) {
|
function getRandomOutId() public view returns (uint256 index) {
|
||||||
uint256 nftAmount = _TOKEN_IDS_.length;
|
uint256 nftAmount = _NFT_IDS_.length;
|
||||||
index = uint256(keccak256(abi.encodePacked(tx.origin, blockhash(block.number-1), gasleft()))) % nftAmount;
|
index = uint256(keccak256(abi.encodePacked(tx.origin, blockhash(block.number-1), gasleft()))) % nftAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ================= Ownable ================
|
// ================= Ownable ================
|
||||||
|
|
||||||
function changeNFTInPrice(uint256 newGsStart, uint256 newCr, bool switch) external {
|
function changeNFTInPrice(uint256 newGsStart, uint256 newCr, bool switchFlag) external {
|
||||||
require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED");
|
require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED");
|
||||||
if (!switch) {
|
_changeNFTInPrice(newGsStart, newCr, switchFlag);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _changeNFTInPrice(uint256 newGsStart, uint256 newCr, bool switchFlag) internal {
|
||||||
|
if (!switchFlag) {
|
||||||
_NFT_IN_SWITCH_ = false;
|
_NFT_IN_SWITCH_ = false;
|
||||||
} else {
|
} else {
|
||||||
require(newCr>DecimalMath.ONE, "CR_ZERO");
|
require(newCr > DecimalMath.ONE, "CR_INVALID");
|
||||||
_GS_START_IN_ = newGsStart;
|
_GS_START_IN_ = newGsStart;
|
||||||
_CR_IN_ = newCr;
|
_CR_IN_ = newCr;
|
||||||
_NFT_IN_SWITCH_ = true;
|
_NFT_IN_SWITCH_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeNFTRandomInPrice(uint256 newGsStart, uint256 newCr, bool switch) external {
|
function changeNFTRandomInPrice(uint256 newGsStart, uint256 newCr, bool switchFlag) external {
|
||||||
require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED");
|
require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED");
|
||||||
if (!switch) {
|
_changeNFTRandomInPrice(newGsStart, newCr, switchFlag);
|
||||||
_NFT_RANDOM_OUT_SWITCH_ = false;
|
}
|
||||||
|
|
||||||
|
function _changeNFTRandomInPrice(uint256 newGsStart, uint256 newCr, bool switchFlag) internal {
|
||||||
|
if (!switchFlag) {
|
||||||
|
_NFT_RANDOM_SWITCH_ = false;
|
||||||
} else {
|
} else {
|
||||||
require(newCr>DecimalMath.ONE, "CR_ZERO");
|
require(newCr > DecimalMath.ONE, "CR_INVALID");
|
||||||
_GS_START_RANDOM_OUT_ = newGsStart;
|
_GS_START_RANDOM_OUT_ = newGsStart;
|
||||||
_CR_RANDOM_OUT_ = newCr;
|
_CR_RANDOM_OUT_ = newCr;
|
||||||
_NFT_RANDOM_OUT_SWITCH_ = true;
|
_NFT_RANDOM_SWITCH_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeNFTTargetOutPrice(uint256 newGsStart, uint256 newCr, bool switch) external {
|
function changeNFTTargetOutPrice(uint256 newGsStart, uint256 newCr, bool switchFlag) external {
|
||||||
require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED");
|
require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED");
|
||||||
if (!switch) {
|
_changeNFTTargetOutPrice(newGsStart, newCr, switchFlag);
|
||||||
_NFT_TARGET_OUT_SWITCH_ = false;
|
}
|
||||||
|
|
||||||
|
function _changeNFTTargetOutPrice(uint256 newGsStart, uint256 newCr, bool switchFlag) internal {
|
||||||
|
if (!switchFlag) {
|
||||||
|
_NFT_TARGET_SWITCH_ = false;
|
||||||
} else {
|
} else {
|
||||||
require(newCr>DecimalMath.ONE, "CR_ZERO");
|
require(newCr > DecimalMath.ONE, "CR_INVALID");
|
||||||
_GS_START_TARGET_OUT_ = newGsStart;
|
_GS_START_TARGET_OUT_ = newGsStart;
|
||||||
_CR_TARGET_OUT_ = newCr;
|
_CR_TARGET_OUT_ = newCr;
|
||||||
_NFT_TARGET_OUT_SWITCH_ = true;
|
_NFT_TARGET_SWITCH_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeNFTAmount(uint256 maxNFTAmount, uint256 minNFTAmount) external {
|
function changeNFTAmount(uint256 maxNFTAmount, uint256 minNFTAmount) external {
|
||||||
require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED");
|
require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED");
|
||||||
|
_changeNFTAmount(maxNFTAmount, minNFTAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _changeNFTAmount(uint256 maxNFTAmount, uint256 minNFTAmount) internal {
|
||||||
require(maxNFTAmount >= minNFTAmount, "AMOUNT_INVALID");
|
require(maxNFTAmount >= minNFTAmount, "AMOUNT_INVALID");
|
||||||
_MAX_NFT_AMOUNT_ = maxNFTAmount;
|
_MAX_NFT_AMOUNT_ = maxNFTAmount;
|
||||||
_MIN_NFT_AMOUNT_ = minNFTAmount;
|
_MIN_NFT_AMOUNT_ = minNFTAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeTokenIdRange(uint256 tokenIdStart, uint256 tokenIdEnd) external {
|
function changeTokenIdRange(uint256 nftIdStart, uint256 nftIdEnd) external {
|
||||||
require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED");
|
require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED");
|
||||||
require(tokenIdStart <= tokenIdEnd, "TOKEN_RANGE_INVALID");
|
_changeTokenIdRange(nftIdStart, nftIdEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _changeTokenIdRange(uint256 nftIdStart, uint256 nftIdEnd) internal {
|
||||||
|
require(nftIdStart <= nftIdEnd, "TOKEN_RANGE_INVALID");
|
||||||
|
|
||||||
_TOKEN_ID_START_ = tokenIdStart;
|
_NFT_ID_START_ = nftIdStart;
|
||||||
_TOKEN_ID_END_ = tokenIdEnd;
|
_NFT_ID_END_ = nftIdEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeTokenIdMap(uint256[] memory tokenIds, bool[] memory isRegistrieds) external {
|
function changeTokenIdMap(uint256[] memory tokenIds, bool[] memory isRegistrieds) external {
|
||||||
require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED");
|
require(msg.sender == IFilterAdmin(_OWNER_)._OWNER_(), "ACCESS_RESTRICTED");
|
||||||
|
_changeTokenIdMap(tokenIds, isRegistrieds);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _changeTokenIdMap(uint256[] memory tokenIds, bool[] memory isRegistrieds) internal {
|
||||||
require(tokenIds.length == isRegistrieds.length, "PARAM_NOT_MATCH");
|
require(tokenIds.length == isRegistrieds.length, "PARAM_NOT_MATCH");
|
||||||
|
|
||||||
for(uint256 i = 0; i < tokenIds.length; i++) {
|
for(uint256 i = 0; i < tokenIds.length; i++) {
|
||||||
@@ -262,42 +320,8 @@ contract FilterModel01 is InitializableOwnable, IERC721Receiver {
|
|||||||
return interfaceId == type(IERC721Receiver).interfaceId;
|
return interfaceId == type(IERC721Receiver).interfaceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function version() virtual external pure returns (string memory) {
|
function version() virtual external pure returns (string memory) {
|
||||||
return "FILTER_1_ERC721 1.0.0";
|
return "FILTER_1_ERC721 1.0.0";
|
||||||
//TODO:
|
|
||||||
function geometricCalc1(uint256 base, uint256 ratio, uint256 times) internal view returns(uint256 newBase, uint256 sum) {
|
|
||||||
require(times > 0);
|
|
||||||
//q^(n-1)
|
|
||||||
uint256 general_coefficient = ratio.powFloor(times - 1);
|
|
||||||
//an=a1*q^n-1
|
|
||||||
newBase = base.mul(general_coefficient);
|
|
||||||
|
|
||||||
if(ratio == 1e18) {
|
|
||||||
//na1
|
|
||||||
sum = base.mul(times);
|
|
||||||
} else {
|
|
||||||
//a1(1-q^n)/(1-q)
|
|
||||||
uint256 denominator = base.mul(1e18.sub(DecimalMath.mulFloor(general_coefficient, ratio)));
|
|
||||||
sum = denominator.div(1e18.sub(ratio));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeTokenId(uint256 id) internal returns(bool){
|
|
||||||
uint256[] memory tokenIds = _TOKEN_IDS_;
|
|
||||||
uint256 i;
|
|
||||||
for (; i < tokenIds.length; i++) {
|
|
||||||
if (tokenIds[i] == id) {
|
|
||||||
tokenIds[i] = tokenIds[tokenIds.length - 1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(i < tokenIds.length) {
|
|
||||||
_TOKEN_IDS_ = tokenIds;
|
|
||||||
_TOKEN_IDS_.pop();
|
|
||||||
return true;
|
|
||||||
}else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -8,11 +8,9 @@
|
|||||||
pragma solidity 0.6.9;
|
pragma solidity 0.6.9;
|
||||||
|
|
||||||
interface IControllerModel {
|
interface IControllerModel {
|
||||||
function getNFTInFee(address filterAdminAddr, address user) external view returns(uint256);
|
function getMintFee(address filterAdminAddr) external view returns (uint256);
|
||||||
|
|
||||||
function getNFTRandomOutFee(address filterAdminAddr, address user) external view returns(uint256);
|
function getBurnFee(address filterAdminAddr) external view returns (uint256);
|
||||||
|
|
||||||
function getNFTTargetOutFee(address filterAdminAddr, address user) external view returns(uint256);
|
function getEmergencySwitch(address filter) external view returns (bool);
|
||||||
|
|
||||||
function getEmergencySwitch(address filter) external view returns(bool);
|
|
||||||
}
|
}
|
||||||
@@ -13,27 +13,21 @@ interface IFilterAdmin {
|
|||||||
function _CONTROLLER_MODEL_() external returns (address);
|
function _CONTROLLER_MODEL_() external returns (address);
|
||||||
|
|
||||||
function init(
|
function init(
|
||||||
address _owner,
|
address owner,
|
||||||
string memory _name,
|
uint256 initSupply,
|
||||||
string memory _symbol,
|
string memory name,
|
||||||
|
string memory symbol,
|
||||||
uint256 fee,
|
uint256 fee,
|
||||||
address mtFeeModel,
|
address mtFeeModel,
|
||||||
address defaultMaintainer,
|
address defaultMaintainer,
|
||||||
address[] memory filters
|
address[] memory filters
|
||||||
) external;
|
) external;
|
||||||
|
|
||||||
function ERC721In(
|
function mintFragTo(address to, uint256 rawAmount) external returns (uint256 received);
|
||||||
address filter,
|
|
||||||
address nftContract,
|
|
||||||
uint256[] memory tokenIds,
|
|
||||||
uint256 minMintAmount
|
|
||||||
) external returns (uint256 actualMintAmount);
|
|
||||||
|
|
||||||
function mintFragTo(address to, uint256 rawAmount) external;
|
function burnFragFrom(address from, uint256 rawAmount) external returns (uint256 paid);
|
||||||
|
|
||||||
function burnFragFrom(address from, uint256 rawAmount) external;
|
function queryChargeMintFee(uint256 rawAmount) external view returns (uint256 poolFee, uint256 mtFee);
|
||||||
|
|
||||||
function queryChargeMintFee(uint256 rawAmount) external;
|
function queryChargeBurnFee(uint256 rawAmount) external view returns (uint256 poolFee, uint256 mtFee);
|
||||||
|
|
||||||
function queryChargeBurnFee(uint256 rawAmount) external;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,35 +8,21 @@
|
|||||||
pragma solidity 0.6.9;
|
pragma solidity 0.6.9;
|
||||||
|
|
||||||
interface IFilterModel {
|
interface IFilterModel {
|
||||||
function isFilterERC721Pass(address nftCollectionAddress, uint256 nftId) external view returns (bool);
|
function isNFTValid(address nftCollectionAddress, uint256 nftId) external view returns (bool);
|
||||||
|
|
||||||
|
function _NFT_COLLECTION_() external view returns(address);
|
||||||
|
|
||||||
function isFilterERC1155Pass(address nftCollectionAddress, uint256 nftId, uint256 amount) external view returns (bool);
|
function queryNFTIn(uint256 NFTInAmount) external view returns (uint256 rawReceive, uint256 received);
|
||||||
|
|
||||||
function getAvaliableNFTIn() external view returns(uint256);
|
function queryNFTTargetOut(uint256 NFTOutAmount) external view returns (uint256 rawPay, uint256 pay);
|
||||||
|
|
||||||
function getAvaliableNFTOut() external view returns(uint256);
|
function queryNFTRandomOut(uint256 NFTOutAmount) external view returns (uint256 rawPay, uint256 pay);
|
||||||
|
|
||||||
function _NFT_IN_SWITCH_() external view returns(bool);
|
function ERC721In(uint256[] memory tokenIds, address to) external returns(uint256 received);
|
||||||
|
|
||||||
function _NFT_RANDOM_SWITCH_() external view returns(bool);
|
function ERC721TargetOut(uint256[] memory indexes, address to) external returns(uint256 paid);
|
||||||
|
|
||||||
function _NFT_TARGET_SWITCH_() external view returns(bool);
|
function ERC721RandomOut(uint256 amount, address to) external returns (uint256 paid);
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
103
contracts/SmartRoute/DODONFTApprove.sol
Normal file
103
contracts/SmartRoute/DODONFTApprove.sol
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2021 DODO ZOO.
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity 0.6.9;
|
||||||
|
|
||||||
|
import {IERC721} from "../intf/IERC721.sol";
|
||||||
|
import {IERC1155} from "../intf/IERC1155.sol";
|
||||||
|
import {InitializableOwnable} from "../lib/InitializableOwnable.sol";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title DODONFTApprove
|
||||||
|
* @author DODO Breeder
|
||||||
|
*
|
||||||
|
* @notice Handle NFT authorizations in DODO platform
|
||||||
|
*/
|
||||||
|
contract DODONFTApprove is InitializableOwnable {
|
||||||
|
|
||||||
|
// ============ Storage ============
|
||||||
|
uint256 private constant _TIMELOCK_DURATION_ = 3 days;
|
||||||
|
mapping (address => bool) public _IS_ALLOWED_PROXY_;
|
||||||
|
uint256 public _TIMELOCK_;
|
||||||
|
address public _PENDING_ADD_DODO_PROXY_;
|
||||||
|
|
||||||
|
// ============ Events ============
|
||||||
|
event AddDODOProxy(address dodoProxy);
|
||||||
|
|
||||||
|
// ============ Modifiers ============
|
||||||
|
modifier notLocked() {
|
||||||
|
require(
|
||||||
|
_TIMELOCK_ <= block.timestamp,
|
||||||
|
"SetProxy is timelocked"
|
||||||
|
);
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
function init(address owner, address[] memory proxies) external {
|
||||||
|
initOwner(owner);
|
||||||
|
for(uint i = 0; i < proxies.length; i++)
|
||||||
|
_IS_ALLOWED_PROXY_[proxies[i]] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function unlockAddProxy(address newDodoProxy) public onlyOwner {
|
||||||
|
_TIMELOCK_ = block.timestamp + _TIMELOCK_DURATION_;
|
||||||
|
_PENDING_ADD_DODO_PROXY_ = newDodoProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
function lockAddProxy() public onlyOwner {
|
||||||
|
_PENDING_ADD_DODO_PROXY_ = address(0);
|
||||||
|
_TIMELOCK_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function addDODOProxy() external onlyOwner notLocked() {
|
||||||
|
_IS_ALLOWED_PROXY_[_PENDING_ADD_DODO_PROXY_] = true;
|
||||||
|
lockAddProxy();
|
||||||
|
emit AddDODOProxy(_PENDING_ADD_DODO_PROXY_);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeDODOProxy (address oldDodoProxy) public onlyOwner {
|
||||||
|
_IS_ALLOWED_PROXY_[oldDodoProxy] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function claimERC721(
|
||||||
|
address nftContract,
|
||||||
|
address who,
|
||||||
|
address dest,
|
||||||
|
uint256 tokenId
|
||||||
|
) external {
|
||||||
|
require(_IS_ALLOWED_PROXY_[msg.sender], "DODONFTApprove:Access restricted");
|
||||||
|
IERC721(nftContract).safeTransferFrom(who, dest, tokenId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function claimERC1155(
|
||||||
|
address nftContract,
|
||||||
|
address who,
|
||||||
|
address dest,
|
||||||
|
uint256 tokenId,
|
||||||
|
uint256 amount
|
||||||
|
) external {
|
||||||
|
require(_IS_ALLOWED_PROXY_[msg.sender], "DODONFTApprove:Access restricted");
|
||||||
|
IERC1155(nftContract).safeTransferFrom(who, dest, tokenId, amount, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function claimERC1155Batch(
|
||||||
|
address nftContract,
|
||||||
|
address who,
|
||||||
|
address dest,
|
||||||
|
uint256[] memory tokenIds,
|
||||||
|
uint256[] memory amounts
|
||||||
|
) external {
|
||||||
|
require(_IS_ALLOWED_PROXY_[msg.sender], "DODONFTApprove:Access restricted");
|
||||||
|
IERC1155(nftContract).safeBatchTransferFrom(who, dest, tokenIds, amounts, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAllowedProxy(address _proxy) external view returns (bool) {
|
||||||
|
return _IS_ALLOWED_PROXY_[_proxy];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,12 +9,13 @@ import {SafeMath} from "../../lib/SafeMath.sol";
|
|||||||
import {InitializableOwnable} from "../../lib/InitializableOwnable.sol";
|
import {InitializableOwnable} from "../../lib/InitializableOwnable.sol";
|
||||||
import {ICloneFactory} from "../../lib/CloneFactory.sol";
|
import {ICloneFactory} from "../../lib/CloneFactory.sol";
|
||||||
import {ReentrancyGuard} from "../../lib/ReentrancyGuard.sol";
|
import {ReentrancyGuard} from "../../lib/ReentrancyGuard.sol";
|
||||||
|
import {IFilterModel} from "../../NFTPool/intf/IFilterModel.sol";
|
||||||
import {IFilterAdmin} from "../../NFTPool/intf/IFilterAdmin.sol";
|
import {IFilterAdmin} from "../../NFTPool/intf/IFilterAdmin.sol";
|
||||||
import {IERC721} from "../../intf/IERC721.sol";
|
import {IDODONFTApprove} from "../../intf/IDODONFTApprove.sol";
|
||||||
import {IERC20} from "../../intf/IERC20.sol";
|
import {IERC20} from "../../intf/IERC20.sol";
|
||||||
import {SafeERC20} from "../../lib/SafeERC20.sol";
|
import {SafeERC20} from "../../lib/SafeERC20.sol";
|
||||||
|
|
||||||
interface IFilter01 {
|
interface IFilterERC721V1 {
|
||||||
function init(
|
function init(
|
||||||
address filterAdmin,
|
address filterAdmin,
|
||||||
address nftCollection,
|
address nftCollection,
|
||||||
@@ -35,8 +36,10 @@ contract DODONFTPoolProxy is ReentrancyGuard, InitializableOwnable {
|
|||||||
mapping(uint256 => address) public _FILTER_TEMPLATES_;
|
mapping(uint256 => address) public _FILTER_TEMPLATES_;
|
||||||
address public _FILTER_ADMIN_TEMPLATE_;
|
address public _FILTER_ADMIN_TEMPLATE_;
|
||||||
address public _DEFAULT_MAINTAINER_;
|
address public _DEFAULT_MAINTAINER_;
|
||||||
address public _NFT_POOL_FEE_MODEL_;
|
address public _CONTROLLER_MODEL_;
|
||||||
address public immutable _CLONE_FACTORY_;
|
address public immutable _CLONE_FACTORY_;
|
||||||
|
address public immutable _DODO_NFT_APPROVE_;
|
||||||
|
address public immutable _DODO_APPROVE_;
|
||||||
|
|
||||||
|
|
||||||
// ============ Event ==============
|
// ============ Event ==============
|
||||||
@@ -45,16 +48,60 @@ contract DODONFTPoolProxy is ReentrancyGuard, InitializableOwnable {
|
|||||||
constructor(
|
constructor(
|
||||||
address cloneFactory,
|
address cloneFactory,
|
||||||
address filterAdminTemplate,
|
address filterAdminTemplate,
|
||||||
address nftPoolFeeModel,
|
address controllerModel,
|
||||||
address defaultMaintainer
|
address defaultMaintainer,
|
||||||
|
address dodoNftApprove,
|
||||||
|
address dodoApprove
|
||||||
) public {
|
) public {
|
||||||
_CLONE_FACTORY_ = cloneFactory;
|
_CLONE_FACTORY_ = cloneFactory;
|
||||||
_FILTER_ADMIN_TEMPLATE_ = filterAdminTemplate;
|
_FILTER_ADMIN_TEMPLATE_ = filterAdminTemplate;
|
||||||
_NFT_POOL_FEE_MODEL_ = nftPoolFeeModel;
|
_CONTROLLER_MODEL_ = controllerModel;
|
||||||
_DEFAULT_MAINTAINER_ = defaultMaintainer;
|
_DEFAULT_MAINTAINER_ = defaultMaintainer;
|
||||||
|
_DODO_NFT_APPROVE_ = dodoNftApprove;
|
||||||
|
_DODO_APPROVE_ = dodoApprove;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================ NFT In and Out ===================
|
||||||
|
function nftIn(
|
||||||
|
address filter,
|
||||||
|
address nftCollection,
|
||||||
|
uint256[] memory tokenIds,
|
||||||
|
address to,
|
||||||
|
uint256 minMintAmount
|
||||||
|
) external {
|
||||||
|
for(uint256 i = 0; i < tokenIds.length; i++) {
|
||||||
|
require(IFilterModel(filter).isNFTValid(nftCollection,tokenIds[i]), "NOT_REGISTRIED");
|
||||||
|
IDODONFTApprove(_DODO_NFT_APPROVE_).claimERC721(nftCollection, msg.sender, filter, tokenIds[i]);
|
||||||
|
}
|
||||||
|
uint256 received = IFilterModel(filter).ERC721In(tokenIds, to);
|
||||||
|
require(received >= minMintAmount, "MINT_AMOUNT_NOT_ENOUGH");
|
||||||
|
}
|
||||||
|
|
||||||
|
function nftTargetOut(
|
||||||
|
address filter,
|
||||||
|
uint256[] memory indexes,
|
||||||
|
address to,
|
||||||
|
uint256 maxBurnAmount
|
||||||
|
) external {
|
||||||
|
uint256 paid = IFilterModel(filter).ERC721TargetOut(indexes, to);
|
||||||
|
require(paid <= maxBurnAmount, "BURN_AMOUNT_EXCEED");
|
||||||
|
}
|
||||||
|
|
||||||
|
function nftRandomOut(
|
||||||
|
address filter,
|
||||||
|
uint256 amount,
|
||||||
|
address to,
|
||||||
|
uint256 maxBurnAmount
|
||||||
|
) external {
|
||||||
|
uint256 paid = IFilterModel(filter).ERC721RandomOut(amount, to);
|
||||||
|
require(paid <= maxBurnAmount, "BURN_AMOUNT_EXCEED");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ================== Create NFTPool ===================
|
||||||
|
|
||||||
function createNewNFTPool01(
|
function createNewNFTPool01(
|
||||||
|
uint256 initSupply,
|
||||||
string memory name,
|
string memory name,
|
||||||
string memory symbol,
|
string memory symbol,
|
||||||
uint256 fee,
|
uint256 fee,
|
||||||
@@ -67,7 +114,7 @@ contract DODONFTPoolProxy is ReentrancyGuard, InitializableOwnable {
|
|||||||
) external returns(address newFilterAdmin) {
|
) external returns(address newFilterAdmin) {
|
||||||
newFilterAdmin = ICloneFactory(_CLONE_FACTORY_).clone(_FILTER_ADMIN_TEMPLATE_);
|
newFilterAdmin = ICloneFactory(_CLONE_FACTORY_).clone(_FILTER_ADMIN_TEMPLATE_);
|
||||||
|
|
||||||
address filter01 = createFilter01(
|
address filter01 = createFilterERC721V1(
|
||||||
newFilterAdmin,
|
newFilterAdmin,
|
||||||
nftCollection,
|
nftCollection,
|
||||||
switches,
|
switches,
|
||||||
@@ -82,16 +129,19 @@ contract DODONFTPoolProxy is ReentrancyGuard, InitializableOwnable {
|
|||||||
|
|
||||||
IFilterAdmin(newFilterAdmin).init(
|
IFilterAdmin(newFilterAdmin).init(
|
||||||
msg.sender,
|
msg.sender,
|
||||||
|
initSupply,
|
||||||
name,
|
name,
|
||||||
symbol,
|
symbol,
|
||||||
fee,
|
fee,
|
||||||
_NFT_POOL_FEE_MODEL_,
|
_CONTROLLER_MODEL_,
|
||||||
_DEFAULT_MAINTAINER_,
|
_DEFAULT_MAINTAINER_,
|
||||||
filters
|
filters
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createFilter01(
|
|
||||||
|
// ================== Create Filter ===================
|
||||||
|
function createFilterERC721V1(
|
||||||
address filterAdmin,
|
address filterAdmin,
|
||||||
address nftCollection,
|
address nftCollection,
|
||||||
bool[] memory switches,
|
bool[] memory switches,
|
||||||
@@ -99,34 +149,42 @@ contract DODONFTPoolProxy is ReentrancyGuard, InitializableOwnable {
|
|||||||
uint256[] memory nftAmounts,
|
uint256[] memory nftAmounts,
|
||||||
uint256[] memory priceRules,
|
uint256[] memory priceRules,
|
||||||
uint256[] memory spreadIds
|
uint256[] memory spreadIds
|
||||||
) public returns(address newFilter01) {
|
) public returns(address newFilterERC721V1) {
|
||||||
newFilter01 = ICloneFactory(_CLONE_FACTORY_).clone(_FILTER_TEMPLATES_[1]);
|
//key = 1 => FilterERC721V1
|
||||||
IFilter01(newFilter01).init(filterAdmin, nftCollection, switches, tokenRanges, nftAmounts, priceRules, spreadIds);
|
newFilterERC721V1 = ICloneFactory(_CLONE_FACTORY_).clone(_FILTER_TEMPLATES_[1]);
|
||||||
|
IFilterERC721V1(newFilterERC721V1).init(
|
||||||
|
filterAdmin,
|
||||||
|
nftCollection,
|
||||||
|
switches,
|
||||||
|
tokenRanges,
|
||||||
|
nftAmounts,
|
||||||
|
priceRules,
|
||||||
|
spreadIds
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ================== NFT ERC20 Swap ======================
|
||||||
function erc721ToErc20(
|
function erc721ToErc20(
|
||||||
address filterAdmin,
|
address filterAdmin,
|
||||||
address filter,
|
address filter,
|
||||||
address nftContract,
|
address nftContract,
|
||||||
uint256 tokenId,
|
uint256 tokenId,
|
||||||
address toToken,
|
address toToken,
|
||||||
address dodoApprove,
|
|
||||||
address dodoProxy,
|
address dodoProxy,
|
||||||
bytes memory dodoSwapData
|
bytes memory dodoSwapData
|
||||||
)
|
)
|
||||||
external
|
external
|
||||||
preventReentrant
|
preventReentrant
|
||||||
{
|
{
|
||||||
IERC721(nftContract).safeTransferFrom(msg.sender, address(this), tokenId);
|
IDODONFTApprove(_DODO_NFT_APPROVE_).claimERC721(nftContract, msg.sender, filter, tokenId);
|
||||||
IERC721(nftContract).approve(filter, tokenId);
|
|
||||||
|
|
||||||
uint256[] memory tokenIds = new uint256[](1);
|
uint256[] memory tokenIds = new uint256[](1);
|
||||||
tokenIds[0] = tokenId;
|
tokenIds[0] = tokenId;
|
||||||
|
|
||||||
//TODO:
|
uint256 receivedFragAmount = IFilterModel(filter).ERC721In(tokenIds, address(this));
|
||||||
uint256 mintAmount = IFilterAdmin(filterAdmin).ERC721In(filter, nftContract, tokenIds, 0);
|
|
||||||
|
|
||||||
_generalApproveMax(filterAdmin, dodoApprove, mintAmount);
|
_generalApproveMax(filterAdmin, _DODO_APPROVE_, receivedFragAmount);
|
||||||
|
|
||||||
(bool success, ) = dodoProxy.call(dodoSwapData);
|
(bool success, ) = dodoProxy.call(dodoSwapData);
|
||||||
require(success, "API_SWAP_FAILED");
|
require(success, "API_SWAP_FAILED");
|
||||||
@@ -146,8 +204,8 @@ contract DODONFTPoolProxy is ReentrancyGuard, InitializableOwnable {
|
|||||||
_FILTER_ADMIN_TEMPLATE_ = newFilterAdminTemplate;
|
_FILTER_ADMIN_TEMPLATE_ = newFilterAdminTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeNftPoolFeeModel(address newNftPoolFeeModel) external onlyOwner {
|
function changeControllerModel(address newControllerModel) external onlyOwner {
|
||||||
_NFT_POOL_FEE_MODEL_ = newNftPoolFeeModel;
|
_CONTROLLER_MODEL_ = newControllerModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setFilterTemplate(uint256 idx, address newFilterTemplate) external onlyOwner {
|
function setFilterTemplate(uint256 idx, address newFilterTemplate) external onlyOwner {
|
||||||
|
|||||||
18
contracts/intf/IDODONFTApprove.sol
Normal file
18
contracts/intf/IDODONFTApprove.sol
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2021 DODO ZOO.
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity 0.6.9;
|
||||||
|
|
||||||
|
interface IDODONFTApprove {
|
||||||
|
function isAllowedProxy(address _proxy) external view returns (bool);
|
||||||
|
|
||||||
|
function claimERC721(address nftContract, address who, address dest, uint256 tokenId) external;
|
||||||
|
|
||||||
|
function claimERC1155(address nftContract, address who, address dest, uint256 tokenId, uint256 amount) external;
|
||||||
|
|
||||||
|
function claimERC1155Batch(address nftContract, address who, address dest, uint256[] memory tokenIds, uint256[] memory amounts) external;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user