// Contract: WTCStaking
// Target function: function auditStakers() external
akeholder];
       return temp;
   }

   /**
    * @notice A method to the aggregated stakes from all stakeholders.
    * @return uint256 The aggregated stakes from all stakeholders.
    */
   function totalStakes() external view returns(uint256){ ///
       uint256 _totalStakes = 0;
       for (uint256 s = 0; s < stakeholders.length; s += 1){
           _totalStakes = _totalStakes.add(stakes[stakeholders[s]]);
       }
       return _totalStakes;
   }
   
   //function to get the number of NFT's a user owns via balanceOf
   function getNFTCount(address _holder) public view returns(uint){
       uint temp;
       temp = wrappedcompanion(wrappedcompnft).balanceOf(_holder);
       return temp;
   }

   //function to correct NFT Owner, if somebody stakes and then sells
   function setTokenOwnerToZero(uint _tokenid) external onlyOwner
   {
       nftowners[_tokenid]=0x0000000000000000000000000000000000000000;
   }
 
   //function to check the user for anti-game cheating
   //returns a uint to match the supposed stake!
   function verifyHolder(address _holder) public view returns(uint){
       address tempuser;
       uint arraylength = tokencount; // Number of tokens in Mapping
       uint validstakes;
       uint tokennumber;
       //loop through all staked tokens
       for (uint256 i = 0; i <= arraylength; i++) {
       tokennumber = tokenslist[i]; //Retrieve the mapping of tokens
       if(tokennumber != 0) //ensures no errornous non-existent tokens are entered
       {
       tempuser = wrappedcompanion(wrappedcompnft).ownerOf(tokennumber);
       if (tempuser==_holder) //Verify Token is the same Owner
       {
         if(nftowners[tokennumber]==tempuser)
         {
             validstakes+=1; //increment once looped
         }
       }
       }
       }
       return validstakes;
   }


   /////////Handles Manual NFT entry!
   function createStakeManual(uint256[] calldata tokenIds_) external
   {
       uint temp;
       address user;
       require(stakingenabled == true, "Staking Not Enabled!");
       /////Allow top up staking!///////
       if (allowtopup==false)
       {
       (bool currentstakeholder,) = isStakeholder(msg.sender);
       require(currentstakeholder==false,"Already Staking!");
       }
       /////////////////
       uint templength = tokenIds_.length;
       require(templength >0,"No NFT's Entered in to stake!");
       ////////////////
       bool wluser = wTCWL(whitelist).isOnWhitelist(msg.sender,1); 
       bool isblocked = blockedstaker[msg.sender];
       require(isblocked!=true,"Not Authorized to Stake!");
              
       if (wluser==false){
   
     for (uint256 i = 0; i < templength; i++) {
      //Verify NFT's are not blocked!!!
      (bool _isblocked,uint s) = wrapperdb(wdbaddress).isBlockedNFT(tokenIds_[i]);
      require(_isblocked==false,"Token is blocked!");
      /////Verify User is holder!//////////////////////////
      user = wrappedcompanion(wrappedcompnft).ownerOf(tokenIds_[i]);
      require(user==msg.sender,"Not holder!");
      /////Verify NFT hasnt been staked before/////////////
      require(nftowners[tokenIds_[i]]==0x0000000000000000000000000000000000000000,"Already Staked!");
      nftowners[tokenIds_[i]]=msg.sender; //Sets holder!
      //insert into tokens mapping to capture all staked tokens
      (bool _isStakedtoken, ) = isTokenInList(tokenIds_[i]);
       if(!_isStakedtoken) {
           tokencount +=1;
           tokenslist[tokencount]=tokenIds_[i];
       }
      }

       temp = templength;//Number of NFT's entered!
       }
       if (wluser==true)
       {
           //Only allowing 1 NFT for non Wrapped Companion holders
           temp = 1;
       }
       //Add user to StakeDB
       addStakeholder(msg.sender);
       stakes[msg.sender] = stakes[msg.sender].add(temp);
       //Calculate Reward//
       if (wluser==false) //Wrapper!
       {
       dailyreward[msg.sender] = calculateDailyReward(stakes[msg.sender]);
       }
       if(wluser==true) //non Wrapper!
       {
       dailyreward[msg.sender] = wlreward; //Hardcode a reward    
       }
       //Set initial claim
       lastclaim[msg.sender] = block.timestamp;
       //Set initial stake date
       startedstaking[msg.sender] = block.timestamp;
       //Setup Banking Contract
       if(usebank==true)
           {
               Bank(bank).manageBalances(4,msg.sender,0); //Set User up as Client and balance to 0
           }
           
       
   }

   function removeStake() external
   {
       uint temp;
       uint temp2;
       uint arraylength = tokencount; //38
       address tempuser;
       uint tokennumber;
       bool wluser;
       wluser = wTCWL(whitelist).isOnWhitelist(msg.sender,1);
       bool currentstakeholder = Bank(bank).isClient(msg.sender);
       require(currentstakeholder==true,"Not Staking!");
       if (wluser==false)
       {
       //AG 1) Basic NFT balance must be = or higher that stakes
       temp = getNFTCount(msg.sender);   
       require (temp >= stakes[msg.sender],"Number of NFT's too low!");
       //AG 2) Verify staked balance is = to the stored NFT's in the wallet and staked tokens match source depositor
       temp = verifyHolder(msg.sender);
       require(temp==stakes[msg.sender],"AG-NFT Count Mismatch!");
       }
       ///Clear out the token data
       //loop through all staked tokens
       stakes[msg.sender] = 0;
       for (uint256 i = 0; i <= arraylength; i++) {
       tokennumber = tokenslist[i];
       if(tokennumber != 0) //ensures no errornous non-existent tokens are entered
       {
       tempuser = wrappedcompanion(wrappedcompnft).ownerOf(tokennumber);
       if(tempuser==msg.sender)
       {
           nftowners[tokennumber] = 0x0000000000000000000000000000000000000000;
           //remove token from Mapping as its not being staked
           tokenslist[i] = 0; // Remove the token from the mapping
       }
       }
       }
       if(stakes[msg.sender] == 0) //Remove entire stake and rewards
       {
           
           //Frictionless staking///
           temp2 = calculatePayoutAmount(msg.sender);
           
               Bank(bank).manageBalances(1,msg.sender,temp2);
           
           //Set start stake date to 0
           startedstaking[msg.sender] = 0;
           //Set initialclaim date back to 0
           lastclaim[msg.sender] = 0;
           
          
        }
        removeStakeholder(msg.sender);
       
       
   }
  
    function withdrawRewards()
       external
   {
       uint temp;
       require (collectrewards==true,"Withdrawls are disabled!");
       bool currentstakeholder = Bank(bank).isClient(msg.sender);
       require(currentstakeholder==true,"Not Staking!");
       uint reward;
       bool wluser = wTCWL(whitelist).isOnWhitelist(msg.sender,1); //get Whitelist status
       if (wluser==false)
       {
       //AG 1) Basic NFT balance must be = or higher that stakes
       temp = getNFTCount(msg.sender);   
       require (temp >= stakes[msg.sender],"Number of NFT's too low!");
       //AG 2) Verify staked balance is = to the stored NFT's in the wallet and staked tokens match source depositor
       temp = verifyHolder(msg.sender);
       require(temp==stakes[msg.sender],"AG-NFT Count Mismatch!");
       }
       //block if less than 24 hours since last claim
       temp = lastclaim[msg.sender];
       require (block.timestamp >= temp + 1 minutes);
       //////////////////////////////////////////////
       reward = calculatePayoutAmount(msg.sender);
       require(reward > 0 ,"No pending rewards to collect!");
          
        Bank(bank).manageBalances(1,msg.sender,reward);
           
       rewards[msg.sender] = 0; //Clear balance to ensure correct accounting
       lastclaim[msg.sender]=block.timestamp; //Set last claim
     
      
     
   }
  
   
 
    ///Function for user to check the amount of Staking rewards
    function rewardOf(address _stakeholder) external view returns(uint256)
   {
       return calculatePayoutAmount(_stakeholder);
   }
  
  
   /////Function to correct the stake of a user if they need assistance -> The stake can ONLY be lowered not increased
   /////Due to the nature of frictionless, a user may sell their RCVR and then attempt to lower their stake, this could cause issues when withdrawing rewards
   
   function adjustTotalStaked(address _User,uint _newstake) external onlyOwner
   {
           require(stakes[_User] > _newstake, "Only-");
           stakes[_User] = _newstake;

   }
   //Function to set the last claim of a user to allow a single TX on the raffle side to claim!
   function setLastClaimExternal(address _payee) external{
       require(msg.sender == raffle || msg.sender==futurecontract,"Not Allowed(SR)");
       rewards[_payee] = 0; //Clear balance to ensure correct accounting
       lastclaim[_payee]=block.timestamp; //Set last claim 
       
   } 

   //Additional function to verify and calculate the outstanding amount due for payout,which will ensure
   //one tx!
   function calculatePayoutAmount(address _payee) public view returns(uint)
   {
     uint temp;
     uint temp2;
     uint lastcollect;
     //verify that the user has an open account, created at staking time!
     bool isclient = Bank(bank).isClient(_payee);
     if (isclient==true)
     {
     //Verify if the user is on a whitelist
     bool wluser = wTCWL(whitelist).isOnWhitelist(_payee,1); //get Whitelist status
       if (wluser==false)
       {
       //AG 1) Basic NFT balance must be = or higher that stakes
       temp = getNFTCount(_payee);   
       require (temp >= stakes[_payee],"Number of NFT's too low!");
       //AG 2) Verify staked balance is = to the stored NFT's in the wallet and staked tokens match source depositor
       temp = verifyHolder(_payee);
       require(temp==stakes[_payee],"AG-NFT Count Mismatch!");
       }

     temp = dailyreward[_payee];
     lastcollect = lastclaim[_payee];
     if(block.timestamp >= lastcollect + 1 days)
     {
         temp2 = temp;
     }
     if(block.timestamp >= lastcollect + 2 days)
     {
         temp2 = temp.mul(2);
     }
     if(block.timestamp >= lastcollect + 3 days)
     {
         temp2 = temp.mul(3);
     }
     if(block.timestamp >= lastcollect + 4 days)
     {
         temp2 = temp.mul(4);
     }
     if(block.timestamp >= lastcollect + 5 days)
     {
         temp2 = temp.mul(5);
     }
     if(block.timestamp >= lastcollect + 6 days)
     {
         temp2 = temp.mul(6);
     }
     if(block.timestamp >= lastcollect + 7 days)
     {
         temp2 = temp.mul(7);
     }
     if(block.timestamp >= lastcollect + 8 days)
     {
         temp2 = temp.mul(8);
     }
     if(block.timestamp >= lastcollect + 9 days)
     {
         temp2 = temp.mul(9);
     }
     if(block.timestamp >= lastcollect + 10 days)
     {
         temp2 = temp.mul(10);
     }
     if(block.timestamp >= lastcollect + 11 days)
     {
         temp2 = temp.mul(11);
     }
     if(block.timestamp >= lastcollect + 12 days)
     {
         temp2 = temp.mul(12);
     }
     if(block.timestamp >= lastcollect + 13 days)
     {
         temp2 = temp.mul(13);
     }
     if(block.timestamp >= lastcollect + 14 days)
     {
         temp2 = temp.mul(14);
     }
     if(block.timestamp >= lastcollect + 15 days) 
     {
         temp2 = temp.mul(15);
     }
     if(block.timestamp >= lastcollect + 20 days) 
     {
         temp2 = temp.mul(20);
     }
     if(block.timestamp >= lastcollect + 30 days)
     {
         temp2 = temp.mul(30);
     }
     if(block.timestamp >= lastcollect + 60 days) 
     {
         temp2 = temp.mul(75);
     }
     if(block.timestamp >= lastcollect + 90 days) 
     {
         temp2 = temp.mul(100);
     }
     if(block.timestamp >= lastcollect + 180 days)
         temp2 = temp.mul(300);
     }
     
     return temp2;
   }


   /////////////////////NB Function to calculate rewards//////////////////
   function calculateDailyReward(uint _numNFT)   
       public view
       returns(uint256)
   {
       uint temp;
       uint temp2;
       uint temp4;
       bool temp3;
       //Has the user wrapped?
       temp3 = wrapperdb(wdbaddress).getWrappedStatus(msg.sender);
       uint basesplit = basereward.div(100); 
       //Get wrapped status
       temp = basereward;
       if(_numNFT==1)
       {
           //Default!
       }
       if(_numNFT==2)
       {
           temp2 = basesplit.mul(10);
           temp = temp + temp2; 
       }
       if(_numNFT==3)
       {
           temp2 = basesplit.mul(15);
           temp = temp + temp2;
       }
       if(_numNFT==4)
       {
           temp2 = basesplit.mul(20);
           temp = temp + temp2;
       }
       if(_numNFT==5)
       {
           temp2 = basesplit.mul(25);
           temp = temp + temp2;
       }
       if(_numNFT==6)
       {
           temp2 = basesplit.mul(30);
           temp = temp + temp2;
       }
       if(_numNFT==7)
       {
           temp2 = basesplit.mul(35);
           temp = temp + temp2;
       }
       if(_numNFT==8)
       {
           temp2 = basesplit.mul(40);
           temp = temp + temp2;
       }
       if(_numNFT==9)
       {
           temp2 = basesplit.mul(45);
           temp = temp + temp2;
       }
       if(_numNFT==10)
       {
           temp2 = basesplit.mul(50);
           temp = temp + temp2;
       }
       if(_numNFT==11)
       {
           temp2 = basesplit.mul(55);
           temp = temp + temp2;
       }
       if(_numNFT==12)
       {
           temp2 = basesplit.mul(60);
           temp = temp + temp2;
       }
       if(_numNFT==13)
       {
           temp2 = basesplit.mul(65);
           temp = temp + temp2;
       }
       if(_numNFT==14)
       {
           temp2 = basesplit.mul(70);
           temp = temp + temp2;
       }
       if(_numNFT==18)
       {
           temp2 = basesplit.mul(75);
           temp = temp + temp2;
       }
       if(_numNFT==19)
       {
           temp2 = basesplit.mul(80);
           temp = temp + temp2;
       }
       if(_numNFT==20)
       {
           temp2 = basesplit.mul(85);
           temp = temp + temp2;
       }
       ///Boost reward if wallet is a wrapper!
       if(wrapperboost==true && temp3==true)
       {
        temp2 = 0; //reuse temp2
        temp2 = temp.div(100);
        if (wboostpercentage==10)
        {
            temp4 = temp2.mul(10);
            temp = temp.add(temp4);
        }
        if (wboostpercentage==20)
        {
            temp4 = temp2.mul(20);
            temp = temp.add(temp4);
        }
        if (wboostpercentage==30)
        {
            temp4 = temp2.mul(30);
            temp = temp.add(temp4);
        }
        if (wboostpercentage==50)
        {
            temp4 = temp2.mul(50);
            temp = temp.add(temp4);
        }
        
       }
       if (legendaryboost==true)
        {
        //Boots reward if user holds a legendary
        temp3 = isLegendaryOwner(msg.sender);
        if (temp3==true)
        {
        temp4 = temp.div(100);
        temp2 = temp4.mul(30); //30% boost for Legendary holder!
        temp = temp.add(temp2);
        }
        }
        if (rareboost==true)
        {
        //Boots reward if user holds a rare
        temp3 = isRareOwner(msg.sender);
        if (temp3==true)
        {
        temp4 = temp.div(100);
        temp2 = temp4.mul(20); //20% boost for holder holder!
        temp = temp.add(temp2);
        }
        }
       return temp; // 
   }
   
   
   ///Function to get the number of stakeholders in a pool
   function getnumStakers() onlyOwner external view returns(uint) 
   {
       
           return stakeholders.length;
      
   }