You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

371 lines
15 KiB

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "./NFT.sol";
import "./Pool.sol";
import "./PledgeType.sol";
import "./Utils.sol";
contract Pledge is Initializable {
NFT nftContract;
Pool poolContract;
ProductInfo[] public productInfo;
mapping(uint256 => PledgeType) pledges;
mapping(address => PledgeType[]) public pledgeRecords;
mapping(uint256 => PledgeType) public invitationPledges;
mapping(address => RecommendObjType) public recommendObj;
mapping(address => uint256[]) public invitationTokens;
mapping(address => address[]) public invitationAddress;
mapping(address => PledgeWithdrawRecordType[]) public pledgeWithdrawRecord;
mapping(address => InvitationWithdrawRecordType[]) public invitationWithdrawRecord;
address[] public blackList;
address[] public whiteList;
mapping(address => PledgeType[]) public pledgeDestoryRecords;
uint256 public invitationRate;
uint256 public nextTokenId;
bool public pledgeStatus;
uint256 public dayTime;
function initialize(address nftAddress, address poolAddress) public initializer {
nftContract = NFT(nftAddress);
poolContract = Pool(poolAddress);
nextTokenId = 1;
invitationRate = 1;
pledgeStatus = false;
dayTime = 1 days;
productInfo.push(ProductInfo(180, 14));
productInfo.push(ProductInfo(270, 15));
productInfo.push(ProductInfo(360, 16));
}
modifier onlyAdmin (){
address[] memory _admins = nftContract.getAdmin();
bool _isAdmin = Utils.isAdmin(_admins, msg.sender);
require(_isAdmin == true,"For administrators only");
_;
}
modifier onlyBlacks (){
bool _isBlack = Utils.isAdmin(blackList, msg.sender);
require(_isBlack == false,"You've been blacklisted.");
_;
}
function getPledgeRecords(address _owner) public view returns(PledgeType[] memory){
return pledgeRecords[_owner];
}
function getPledgeWithdrawRecord(address _owner) public view returns(PledgeWithdrawRecordType[] memory){
return pledgeWithdrawRecord[_owner];
}
function getInvitationWithdrawRecord(address _owner) public view returns(InvitationWithdrawRecordType[] memory){
return invitationWithdrawRecord[_owner];
}
function getPledgeDestoryRecords(address _owner) public view returns(PledgeType[] memory){
return pledgeDestoryRecords[_owner];
}
function getProductInfo() public view returns (ProductInfo[] memory) {
return productInfo;
}
function getOwnerAllPledgeInfo( address _ownerAddress ) public view returns (PledgeType[] memory result) {
uint256[] memory tokens = getOwnerAllTokens(_ownerAddress);
result = new PledgeType[](tokens.length);
for (uint256 i = 0; i < tokens.length; i++) {
result[i] = pledges[tokens[i]];
}
return result;
}
function bindRecommend(address _referrer) internal {
require(recommendObj[msg.sender].key == address(0),"Already have recommenders");
require(msg.sender != _referrer ,"You can't recommend yourself.");
require(recommendObj[_referrer].referrer != msg.sender,"Can't recommend each other");
recommendObj[msg.sender] = RecommendObjType(
msg.sender,
_referrer,
block.timestamp,
0
);
invitationAddress[_referrer].push(msg.sender);
}
function setInvitationIncomes(PledgeType memory _pledge) internal {
address recommendAddr = recommendObj[msg.sender].referrer;
PledgeType memory _invitationPledge = _pledge;
_invitationPledge.rate = invitationRate;
uint256 amount = _invitationPledge.pledgeAmount;
uint256 rate = _invitationPledge.rate;
uint256 day = _invitationPledge.pledgeDay;
uint256 tokenId = _invitationPledge.tokenId;
uint256 contribute = (((amount * rate) / 365) * day) / 100;
recommendObj[msg.sender].contribute += contribute;
if (invitationTokens[recommendAddr].length == 0) {
invitationTokens[recommendAddr] = new uint256[](0);
}
if (invitationAddress[recommendAddr].length == 0) {
invitationAddress[recommendAddr] = new address[](0);
}
invitationTokens[recommendAddr].push(tokenId);
invitationPledges[tokenId] = _invitationPledge;
}
function pledge(uint256 amount, uint256 index, address _referrer) external onlyBlacks {
bool _isWhite = Utils.isAdmin(whiteList, msg.sender);
if(!_isWhite){
require(pledgeStatus == false,"The pledge is closed.");
}
require(amount >= 1, "Minimum pledge 1FIL");
require(index < productInfo.length, "Product does not exist");
poolContract.deposit(msg.sender, amount);
uint256 tokenId = nextTokenId++;
if (_referrer != address(0)) {
bindRecommend(_referrer);
}
ProductInfo memory item = productInfo[index];
uint256 startTime = block.timestamp;
uint256 endTime = block.timestamp + (item.day * dayTime);
nftContract.mint(msg.sender, tokenId);
PledgeType memory _pledge = PledgeType(tokenId,startTime,endTime,startTime,amount,item.rate,item.day,msg.sender,false);
pledges[tokenId] = _pledge;
pledgeRecords[msg.sender].push(_pledge);
if (recommendObj[msg.sender].key != address(0)) {
setInvitationIncomes(_pledge);
}
}
function getOwnerAllTokens( address _ownerAddress ) public view returns (uint256[] memory) {
uint256 nftAmount = nftContract.balanceOf(_ownerAddress);
uint256[] memory tokens = new uint256[](nftAmount);
for (uint256 i = 0; i < nftAmount; i++) {
tokens[i] = nftContract.tokenOfOwnerByIndex(_ownerAddress, i);
}
return tokens;
}
function calculateInterest( PledgeType memory _pledge ) public view returns (uint256) {
uint256 total_amount = _pledge.pledgeAmount;
uint256 currentTime = block.timestamp;
uint256 withdrawTime = _pledge.withdrawTime;
uint256 rate = _pledge.rate;
if(_pledge.endTime < currentTime){
currentTime = _pledge.endTime;
}
uint256 daysPassed = (currentTime - withdrawTime) / dayTime;
uint256 dailyShare = (((total_amount * rate) / 365) * daysPassed) / 100;
return dailyShare;
}
function getWithdrawbleAmount( address _owner ) public view returns (uint256) {
uint256[] memory tokens = getOwnerAllTokens(_owner);
if (tokens.length <= 0) return 0;
uint256 _total_interest = 0;
for (uint256 i = 0; i < tokens.length; i++) {
uint256 _tokenId = tokens[i];
PledgeType memory _item = pledges[_tokenId];
_total_interest += calculateInterest(_item);
}
return _total_interest;
}
function withdraAllInterest() external onlyBlacks {
uint256 _total_interest = getWithdrawbleAmount(msg.sender);
require(_total_interest > 0, "Withdrawal amount must be greater than 0");
uint256[] memory tokens = getOwnerAllTokens(msg.sender);
for(uint256 i=0;i<tokens.length;i++){
uint256 _withdrawTime = block.timestamp;
uint256 _tokenId = tokens[i];
require(!pledges[_tokenId].isBlack,"Unable to withdraw, the NFT Tokend is blacklisted.");
if(pledges[_tokenId].endTime < _withdrawTime){
_withdrawTime = pledges[_tokenId].endTime;
}
pledges[_tokenId].withdrawTime = _withdrawTime;
}
poolContract.withdraw(msg.sender, _total_interest);
pledgeWithdrawRecord[msg.sender].push(PledgeWithdrawRecordType(_total_interest,block.timestamp,0,0,2));
}
function withdrawInterest(uint256 tokenId) external onlyBlacks {
address _owner = nftContract.ownerOf(tokenId);
require(_owner == msg.sender,"It's not a contract.");
PledgeType memory data = pledges[tokenId];
require(!data.isBlack,"Unable to withdraw,the NFT Tokend is blacklisted.");
uint256 _interest = calculateInterest(data);
require(_interest > 0, "Withdrawal amount must be greater than 0");
uint256 _withdrawTime = block.timestamp;
if(data.endTime < _withdrawTime){
_withdrawTime = data.endTime;
}
poolContract.withdraw(msg.sender, _interest);
pledges[tokenId].withdrawTime = _withdrawTime;
pledgeWithdrawRecord[msg.sender].push(PledgeWithdrawRecordType(_interest,block.timestamp,data.tokenId,data.pledgeDay,1));
}
function getOwnerInvitationPledges( address addr ) public view returns (PledgeType[] memory result) {
uint256[] memory _tokens = invitationTokens[addr];
result = new PledgeType[](_tokens.length);
for (uint256 i = 0; i < _tokens.length; i++) {
uint256 _tokenId = _tokens[i];
result[i] = invitationPledges[_tokenId];
}
return result;
}
function getOwnerAllInvitationWithdrawAmout(address owner) public view returns(uint256){
uint256 _income = 0;
PledgeType[] memory _pledges = getOwnerInvitationPledges(owner);
for(uint256 i=0;i<_pledges.length;i++){
PledgeType memory data = _pledges[i];
_income += calculateInterest(data);
}
return _income;
}
function withdraInvitationAllInterest() external onlyBlacks {
uint256 _total_interest = getOwnerAllInvitationWithdrawAmout(msg.sender);
require(_total_interest > 0, "Withdrawal amount must be greater than 0");
uint256[] memory tokens = invitationTokens[msg.sender];
for(uint256 i=0;i<tokens.length;i++){
uint256 _withdrawTime = block.timestamp;
uint256 _tokenId = tokens[i];
if(invitationPledges[_tokenId].endTime < _withdrawTime){
_withdrawTime = invitationPledges[_tokenId].endTime;
}
invitationPledges[_tokenId].withdrawTime = _withdrawTime;
}
uint256 currentTime = block.timestamp;
poolContract.withdraw(msg.sender, _total_interest);
invitationWithdrawRecord[msg.sender].push(InvitationWithdrawRecordType(_total_interest,currentTime));
}
function withdrawInvitationInterest(uint256 tokenId) external onlyBlacks {
uint256[] memory _tokens = invitationTokens[msg.sender];
bool _owner = false;
for(uint256 i=0;i<_tokens.length;i++){
uint256 _tokenId = _tokens[i];
if(_tokenId == tokenId){
_owner = true;
break;
}
}
require(_owner == true,"It's not a contract.");
PledgeType memory data = invitationPledges[tokenId];
uint256 _interest = calculateInterest(data);
require(_interest > 0, "Withdrawal amount must be greater than 0");
uint256 _withdrawTime = block.timestamp;
if(data.endTime < _withdrawTime){
_withdrawTime = data.endTime;
}
poolContract.withdraw(msg.sender, _interest);
uint256 currentTime = block.timestamp;
invitationPledges[tokenId].withdrawTime = _withdrawTime;
invitationWithdrawRecord[msg.sender].push(InvitationWithdrawRecordType(_interest,currentTime));
}
function getAllInvitationMember( address addr ) public view returns (RecommendObjType[] memory result) {
address[] memory _addresss = invitationAddress[addr];
result = new RecommendObjType[](_addresss.length);
for (uint256 i = 0; i < _addresss.length; i++) {
result[i] = recommendObj[_addresss[i]];
}
return result;
}
function getCurrentTime() public view returns (uint256){
uint256 currentTime = block.timestamp;
return currentTime;
}
function destroyPledge(uint256 tokenId) external onlyBlacks{
address _owner = nftContract.ownerOf(tokenId);
require(_owner == msg.sender,"You're not a contract owner.");
uint256 currentTime = block.timestamp;
PledgeType memory data = pledges[tokenId];
require(data.endTime < currentTime,"Unexpired Pledge Agreement");
nftContract.transferFrom(msg.sender,address(this), tokenId);
poolContract.withdraw(msg.sender, data.pledgeAmount);
data.withdrawTime = currentTime;
pledgeDestoryRecords[msg.sender].push(data);
}
function setInvitationRate(uint256 _rate) external onlyAdmin{
invitationRate = _rate;
}
function setPledgeStatus(bool _status) external onlyAdmin {
pledgeStatus = _status;
}
function addBlackOrWhiteList(address[] memory _blacks,uint256 _type) external onlyAdmin {
require(_blacks.length>0,"Enter at least one address");
if(_type == 1){
address[] memory blacks = Utils.addAdmin(blackList, _blacks);
blackList = blacks;
}
if(_type == 2){
address[] memory whites = Utils.addAdmin(whiteList, _blacks);
whiteList = whites;
}
}
function delBlackOrWhiteList(address[] memory _blacks,uint256 _type) external onlyAdmin{
require(_blacks.length>0,"Enter at least one address");
if(_type == 1){
address[] memory blacks = Utils.deleteAdmin(blackList, _blacks);
blackList = blacks;
}
if(_type == 2){
address[] memory whites = Utils.deleteAdmin(whiteList, _blacks);
whiteList = whites;
}
}
function getBlackOrWhiteList(uint256 _type) public view returns (address[] memory) {
return _type == 1 ? blackList : whiteList;
}
function setProductInfo(uint256[] memory _days,uint256[] memory _rates) external onlyAdmin {
delete productInfo;
for(uint256 i=0;i<3;i++){
productInfo.push(ProductInfo(_days[i],_rates[i]));
}
}
function getDetails(uint256 tokenId,uint256 _type) public view returns(PledgeType memory){
if(_type == 1){
return pledges[tokenId];
}
return invitationPledges[tokenId];
}
function addNftBalcks(uint256[] memory _tokenIds) external onlyAdmin {
require(_tokenIds.length > 0,"Parameter is empty");
nftContract.addBlacks(_tokenIds);
for(uint256 i=0;i<_tokenIds.length;i++){
uint256 _id = _tokenIds[i];
require(pledges[_id].sender != address(0), "NFT ID does not exist");
require(!pledges[_id].isBlack,"NFT ID already exists");
pledges[_id].isBlack = true;
}
}
function deleteNftBlacks(uint256[] memory _ids) external onlyAdmin {
require(_ids.length > 0,"Parameter is empty");
nftContract.delBlacks(_ids);
for(uint256 i=0;i<_ids.length;i++){
uint256 _id = _ids[i];
require(pledges[_id].sender != address(0), "NFT ID does not exist");
pledges[_id].isBlack = false;
}
}
}