ETH Price: $2,251.29 (+0.37%)

Transaction Decoder

Block:
21174589 at Nov-12-2024 10:28:11 PM +UTC
Transaction Fee:
0.001874679118358974 ETH $4.22
Gas Used:
74,209 Gas / 25.262153086 Gwei

Emitted Events:

324 DiamondHand.Participated( userAddress=[Sender] 0xde5d7dcca34dac18a86476df05adfd086876bf5a, cycle=1, tickets=3 )

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
5.18176156703795585 Eth5.18176527748795585 Eth0.00000371045
0xdE5d7DcC...86876Bf5A
4.974962010715373993 Eth
Nonce: 2988
4.973087331597015019 Eth
Nonce: 2989
0.001874679118358974
0xe249C7a8...cfdfa4AcC

Execution Trace

DiamondHand.CALL( )
  • BlazeStaking.getUser2888BlazeToken( __user=0xdE5d7DcCA34daC18A86476Df05adFD086876Bf5A, __cycle=1 ) => ( _blazeTokenStaked=12022688500000000000000 )
  • DiamondHandWrapper.getMintedNFT( _user=0xdE5d7DcCA34daC18A86476Df05adFD086876Bf5A ) => ( _nftCount=0 )
    • 0xdefe306eeb33089745e812c4a0d7b731808e061f.70a08231( )
    • 0xdefe306eeb33089745e812c4a0d7b731808e061f.729c11ee( )
      File 1 of 3: DiamondHand
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
      pragma solidity ^0.8.20;
      import {Context} from "../utils/Context.sol";
      /**
       * @dev Contract module which provides a basic access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * The initial owner is set to the address provided by the deployer. This can
       * later be changed with {transferOwnership}.
       *
       * This module is used through inheritance. It will make available the modifier
       * `onlyOwner`, which can be applied to your functions to restrict their use to
       * the owner.
       */
      abstract contract Ownable is Context {
          address private _owner;
          /**
           * @dev The caller account is not authorized to perform an operation.
           */
          error OwnableUnauthorizedAccount(address account);
          /**
           * @dev The owner is not a valid owner account. (eg. `address(0)`)
           */
          error OwnableInvalidOwner(address owner);
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
          /**
           * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
           */
          constructor(address initialOwner) {
              if (initialOwner == address(0)) {
                  revert OwnableInvalidOwner(address(0));
              }
              _transferOwnership(initialOwner);
          }
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              _checkOwner();
              _;
          }
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view virtual returns (address) {
              return _owner;
          }
          /**
           * @dev Throws if the sender is not the owner.
           */
          function _checkOwner() internal view virtual {
              if (owner() != _msgSender()) {
                  revert OwnableUnauthorizedAccount(_msgSender());
              }
          }
          /**
           * @dev Leaves the contract without owner. It will not be possible to call
           * `onlyOwner` functions. Can only be called by the current owner.
           *
           * NOTE: Renouncing ownership will leave the contract without an owner,
           * thereby disabling any functionality that is only available to the owner.
           */
          function renounceOwnership() public virtual onlyOwner {
              _transferOwnership(address(0));
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public virtual onlyOwner {
              if (newOwner == address(0)) {
                  revert OwnableInvalidOwner(address(0));
              }
              _transferOwnership(newOwner);
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Internal function without access restriction.
           */
          function _transferOwnership(address newOwner) internal virtual {
              address oldOwner = _owner;
              _owner = newOwner;
              emit OwnershipTransferred(oldOwner, newOwner);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)
      pragma solidity ^0.8.20;
      import {Ownable} from "./Ownable.sol";
      /**
       * @dev Contract module which provides access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * The initial owner is specified at deployment time in the constructor for `Ownable`. This
       * can later be changed with {transferOwnership} and {acceptOwnership}.
       *
       * This module is used through inheritance. It will make available all functions
       * from parent (Ownable).
       */
      abstract contract Ownable2Step is Ownable {
          address private _pendingOwner;
          event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
          /**
           * @dev Returns the address of the pending owner.
           */
          function pendingOwner() public view virtual returns (address) {
              return _pendingOwner;
          }
          /**
           * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public virtual override onlyOwner {
              _pendingOwner = newOwner;
              emit OwnershipTransferStarted(owner(), newOwner);
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
           * Internal function without access restriction.
           */
          function _transferOwnership(address newOwner) internal virtual override {
              delete _pendingOwner;
              super._transferOwnership(newOwner);
          }
          /**
           * @dev The new owner accepts the ownership transfer.
           */
          function acceptOwnership() public virtual {
              address sender = _msgSender();
              if (pendingOwner() != sender) {
                  revert OwnableUnauthorizedAccount(sender);
              }
              _transferOwnership(sender);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Provides information about the current execution context, including the
       * sender of the transaction and its data. While these are generally available
       * via msg.sender and msg.data, they should not be accessed in such a direct
       * manner, since when dealing with meta-transactions the account sending and
       * paying for execution may not be the actual sender (as far as an application
       * is concerned).
       *
       * This contract is only required for intermediate, library-like contracts.
       */
      abstract contract Context {
          function _msgSender() internal view virtual returns (address) {
              return msg.sender;
          }
          function _msgData() internal view virtual returns (bytes calldata) {
              return msg.data;
          }
          function _contextSuffixLength() internal view virtual returns (uint256) {
              return 0;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Contract module that helps prevent reentrant calls to a function.
       *
       * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
       * available, which can be applied to functions to make sure there are no nested
       * (reentrant) calls to them.
       *
       * Note that because there is a single `nonReentrant` guard, functions marked as
       * `nonReentrant` may not call one another. This can be worked around by making
       * those functions `private`, and then adding `external` `nonReentrant` entry
       * points to them.
       *
       * TIP: If you would like to learn more about reentrancy and alternative ways
       * to protect against it, check out our blog post
       * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
       */
      abstract contract ReentrancyGuard {
          // Booleans are more expensive than uint256 or any type that takes up a full
          // word because each write operation emits an extra SLOAD to first read the
          // slot's contents, replace the bits taken up by the boolean, and then write
          // back. This is the compiler's defense against contract upgrades and
          // pointer aliasing, and it cannot be disabled.
          // The values being non-zero value makes deployment a bit more expensive,
          // but in exchange the refund on every call to nonReentrant will be lower in
          // amount. Since refunds are capped to a percentage of the total
          // transaction's gas, it is best to keep them low in cases like this one, to
          // increase the likelihood of the full refund coming into effect.
          uint256 private constant NOT_ENTERED = 1;
          uint256 private constant ENTERED = 2;
          uint256 private _status;
          /**
           * @dev Unauthorized reentrant call.
           */
          error ReentrancyGuardReentrantCall();
          constructor() {
              _status = NOT_ENTERED;
          }
          /**
           * @dev Prevents a contract from calling itself, directly or indirectly.
           * Calling a `nonReentrant` function from another `nonReentrant`
           * function is not supported. It is possible to prevent this from happening
           * by making the `nonReentrant` function external, and making it call a
           * `private` function that does the actual work.
           */
          modifier nonReentrant() {
              _nonReentrantBefore();
              _;
              _nonReentrantAfter();
          }
          function _nonReentrantBefore() private {
              // On the first call to nonReentrant, _status will be NOT_ENTERED
              if (_status == ENTERED) {
                  revert ReentrancyGuardReentrantCall();
              }
              // Any calls to nonReentrant after this point will fail
              _status = ENTERED;
          }
          function _nonReentrantAfter() private {
              // By storing the original value once again, a refund is triggered (see
              // https://eips.ethereum.org/EIPS/eip-2200)
              _status = NOT_ENTERED;
          }
          /**
           * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
           * `nonReentrant` function in the call stack.
           */
          function _reentrancyGuardEntered() internal view returns (bool) {
              return _status == ENTERED;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.17;
      import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
      import "@openzeppelin/contracts/access/Ownable2Step.sol";
      import {IDiamondNFTWrapper} from "./interfaces/IDiamondNFTWrapper.sol";
      import {IBlazeStaking} from "./interfaces/IBlazeStaking.sol";
      contract DiamondHand is ReentrancyGuard, Ownable2Step {
          IDiamondNFTWrapper dNFT;
          IBlazeStaking blazeStaking;
          uint32 public immutable i_initialTimestamp;
          uint256 public immutable i_periodDuration = 1 days;
          /// @notice Records the total batches purchased by an account in each cycle
          mapping(address => mapping(uint256 => uint256)) public accCycleAllTickets;
          /// @notice Total number of batches purchased in each cycle
          mapping(uint256 => uint256) public cycleTotalTickets;
          /// @notice Last active cycle for each account
          mapping(address => uint256) public lastClaimedCycle;
          /// @notice Total accrued fees per cycle
          mapping(uint256 => uint256) public cycleAccruedPayout;
          /// @notice Event emitted when a new participation is made.
          event Participated(address indexed userAddress, uint256 indexed cycle, uint256 tickets);
          event RewardsClaimed(address indexed userAddress, uint256 cycle, uint256 rewards);
          constructor(address _diamondNFTWrapperAddress, address _blazeStaking, uint32 _startTimestamp) Ownable(_msgSender()) {
              i_initialTimestamp = _startTimestamp;
              dNFT = IDiamondNFTWrapper(_diamondNFTWrapperAddress);
              blazeStaking = IBlazeStaking(_blazeStaking);
          }
          receive() external payable {
              (, uint256 currentCycle, ) = getCurrentDayAndCycleDetails();
              cycleAccruedPayout[currentCycle] += msg.value;
          }
          function participate() external nonReentrant {
              (, uint256 currentCycle, ) = getCurrentDayAndCycleDetails();
              uint256 tickets = 0;
              uint userTicket = accCycleAllTickets[_msgSender()][currentCycle];
              if (userTicket > 0) {
                  cycleTotalTickets[currentCycle] -= userTicket; //bakaNingen
              }
              tickets = getMintedNFT(_msgSender()) + getBlazeStake(_msgSender());
              cycleTotalTickets[currentCycle] += tickets;
              accCycleAllTickets[_msgSender()][currentCycle] = tickets;
              emit Participated(_msgSender(), currentCycle, tickets);
          }
          /// @notice Claims accrued rewards for the caller.
          function claimRewards() external nonReentrant {
              (, uint256 currentCycle, ) = getCurrentDayAndCycleDetails();
              uint256 totalPayoutShare;
              for (uint256 x = lastClaimedCycle[_msgSender()] + 1; x < currentCycle; ++x) {
                  uint256 rewardsForCurrentCycle = 0;
                  if (cycleTotalTickets[x] > 0) {
                      rewardsForCurrentCycle =
                          (accCycleAllTickets[_msgSender()][x] * cycleAccruedPayout[x]) /
                          cycleTotalTickets[x];
                  }
                  emit RewardsClaimed(_msgSender(), x, rewardsForCurrentCycle);
                  totalPayoutShare += rewardsForCurrentCycle;
              }
              require(totalPayoutShare > 0, "Nothing to claim");
              lastClaimedCycle[_msgSender()] = currentCycle - 1;
              _sendETH(_msgSender(), totalPayoutShare);
          }
          function getClaimableRewards(address user) external view returns (uint256 totalClaimableRewards) {
              (, uint256 currentCycle, ) = getCurrentDayAndCycleDetails();
              for (uint256 x = lastClaimedCycle[user] + 1; x < currentCycle; ++x) {
                  uint256 rewardsForCurrentCycle = 0;
                  if (cycleTotalTickets[x] > 0) {
                      rewardsForCurrentCycle = (accCycleAllTickets[user][x] * cycleAccruedPayout[x]) / cycleTotalTickets[x];
                  }
                  totalClaimableRewards += rewardsForCurrentCycle;
              }
          }
          function getMintedNFT(address user) public view returns (uint256) {
              return dNFT.getMintedNFT(user) / 28;
          }
          function getBlazeStake(address user) public view returns (uint256) {
              (, uint256 currentCycle, ) = getCurrentDayAndCycleDetails();
              return blazeStaking.getUser2888BlazeToken(user, currentCycle) / (4000 * 1e18);
          }
          /// @dev Internal function to calculate current day and cycle.
          /// @dev Internal function to calculate current day, current cycle, and current day in the cycle.
          function getCurrentDayAndCycleDetails()
              public
              view
              returns (uint256 currentDay, uint256 currentCycle, uint256 currentDayInCycle)
          {
              currentDay = ((block.timestamp - i_initialTimestamp) / 1 days) + 1;
              currentCycle = (currentDay / 888) + 1;
              currentDayInCycle = currentDay % 888;
          }
          /// @dev Internal function to send ETH to a specified address.
          function _sendETH(address to, uint256 amount) private {
              (bool sent, ) = payable(to).call{value: amount}("");
              require(sent, "Blaze: Failed to send ETH");
          }
      }// SPDX-License-Identifier: UNLICENSED
      pragma solidity 0.8.24;
      interface IBlazeStaking {
          function setFeeRewardsForAllCycle() external;
          function distributeFeeRewardsForAll() external;
          function _deploymentTimeStamp() external view returns (uint32);
          function getNextCycleDistributionDay(uint16) external view returns (uint256);
          function getUser2888BlazeToken(address user, uint256 cycle) external view returns (uint256 blazeTokenStaked);
      }
      // SPDX-License-Identifier: UNLICENSED
      pragma solidity 0.8.24;
      interface IDiamondNFTWrapper {
          function getMintedNFT(address) external view returns (uint256);  // returns the number of NFTs minted & holding by the user   
      }

      File 2 of 3: BlazeStaking
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
      pragma solidity ^0.8.20;
      import {Context} from "../utils/Context.sol";
      /**
       * @dev Contract module which provides a basic access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * The initial owner is set to the address provided by the deployer. This can
       * later be changed with {transferOwnership}.
       *
       * This module is used through inheritance. It will make available the modifier
       * `onlyOwner`, which can be applied to your functions to restrict their use to
       * the owner.
       */
      abstract contract Ownable is Context {
          address private _owner;
          /**
           * @dev The caller account is not authorized to perform an operation.
           */
          error OwnableUnauthorizedAccount(address account);
          /**
           * @dev The owner is not a valid owner account. (eg. `address(0)`)
           */
          error OwnableInvalidOwner(address owner);
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
          /**
           * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
           */
          constructor(address initialOwner) {
              if (initialOwner == address(0)) {
                  revert OwnableInvalidOwner(address(0));
              }
              _transferOwnership(initialOwner);
          }
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              _checkOwner();
              _;
          }
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view virtual returns (address) {
              return _owner;
          }
          /**
           * @dev Throws if the sender is not the owner.
           */
          function _checkOwner() internal view virtual {
              if (owner() != _msgSender()) {
                  revert OwnableUnauthorizedAccount(_msgSender());
              }
          }
          /**
           * @dev Leaves the contract without owner. It will not be possible to call
           * `onlyOwner` functions. Can only be called by the current owner.
           *
           * NOTE: Renouncing ownership will leave the contract without an owner,
           * thereby disabling any functionality that is only available to the owner.
           */
          function renounceOwnership() public virtual onlyOwner {
              _transferOwnership(address(0));
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public virtual onlyOwner {
              if (newOwner == address(0)) {
                  revert OwnableInvalidOwner(address(0));
              }
              _transferOwnership(newOwner);
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Internal function without access restriction.
           */
          function _transferOwnership(address newOwner) internal virtual {
              address oldOwner = _owner;
              _owner = newOwner;
              emit OwnershipTransferred(oldOwner, newOwner);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)
      pragma solidity ^0.8.20;
      import {Ownable} from "./Ownable.sol";
      /**
       * @dev Contract module which provides access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * The initial owner is specified at deployment time in the constructor for `Ownable`. This
       * can later be changed with {transferOwnership} and {acceptOwnership}.
       *
       * This module is used through inheritance. It will make available all functions
       * from parent (Ownable).
       */
      abstract contract Ownable2Step is Ownable {
          address private _pendingOwner;
          event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
          /**
           * @dev Returns the address of the pending owner.
           */
          function pendingOwner() public view virtual returns (address) {
              return _pendingOwner;
          }
          /**
           * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public virtual override onlyOwner {
              _pendingOwner = newOwner;
              emit OwnershipTransferStarted(owner(), newOwner);
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
           * Internal function without access restriction.
           */
          function _transferOwnership(address newOwner) internal virtual override {
              delete _pendingOwner;
              super._transferOwnership(newOwner);
          }
          /**
           * @dev The new owner accepts the ownership transfer.
           */
          function acceptOwnership() public virtual {
              address sender = _msgSender();
              if (pendingOwner() != sender) {
                  revert OwnableUnauthorizedAccount(sender);
              }
              _transferOwnership(sender);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
      pragma solidity ^0.8.20;
      import {IERC20} from "../IERC20.sol";
      /**
       * @dev Interface for the optional metadata functions from the ERC20 standard.
       */
      interface IERC20Metadata is IERC20 {
          /**
           * @dev Returns the name of the token.
           */
          function name() external view returns (string memory);
          /**
           * @dev Returns the symbol of the token.
           */
          function symbol() external view returns (string memory);
          /**
           * @dev Returns the decimals places of the token.
           */
          function decimals() external view returns (uint8);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
       * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
       *
       * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
       * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
       * need to send a transaction, and thus is not required to hold Ether at all.
       *
       * ==== Security Considerations
       *
       * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
       * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
       * considered as an intention to spend the allowance in any specific way. The second is that because permits have
       * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
       * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
       * generally recommended is:
       *
       * ```solidity
       * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
       *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
       *     doThing(..., value);
       * }
       *
       * function doThing(..., uint256 value) public {
       *     token.safeTransferFrom(msg.sender, address(this), value);
       *     ...
       * }
       * ```
       *
       * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
       * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
       * {SafeERC20-safeTransferFrom}).
       *
       * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
       * contracts should have entry points that don't rely on permit.
       */
      interface IERC20Permit {
          /**
           * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
           * given ``owner``'s signed approval.
           *
           * IMPORTANT: The same issues {IERC20-approve} has related to transaction
           * ordering also apply here.
           *
           * Emits an {Approval} event.
           *
           * Requirements:
           *
           * - `spender` cannot be the zero address.
           * - `deadline` must be a timestamp in the future.
           * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
           * over the EIP712-formatted function arguments.
           * - the signature must use ``owner``'s current nonce (see {nonces}).
           *
           * For more information on the signature format, see the
           * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
           * section].
           *
           * CAUTION: See Security Considerations above.
           */
          function permit(
              address owner,
              address spender,
              uint256 value,
              uint256 deadline,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) external;
          /**
           * @dev Returns the current nonce for `owner`. This value must be
           * included whenever a signature is generated for {permit}.
           *
           * Every successful call to {permit} increases ``owner``'s nonce by one. This
           * prevents a signature from being used multiple times.
           */
          function nonces(address owner) external view returns (uint256);
          /**
           * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
           */
          // solhint-disable-next-line func-name-mixedcase
          function DOMAIN_SEPARATOR() external view returns (bytes32);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Interface of the ERC20 standard as defined in the EIP.
       */
      interface IERC20 {
          /**
           * @dev Emitted when `value` tokens are moved from one account (`from`) to
           * another (`to`).
           *
           * Note that `value` may be zero.
           */
          event Transfer(address indexed from, address indexed to, uint256 value);
          /**
           * @dev Emitted when the allowance of a `spender` for an `owner` is set by
           * a call to {approve}. `value` is the new allowance.
           */
          event Approval(address indexed owner, address indexed spender, uint256 value);
          /**
           * @dev Returns the value of tokens in existence.
           */
          function totalSupply() external view returns (uint256);
          /**
           * @dev Returns the value of tokens owned by `account`.
           */
          function balanceOf(address account) external view returns (uint256);
          /**
           * @dev Moves a `value` amount of tokens from the caller's account to `to`.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transfer(address to, uint256 value) external returns (bool);
          /**
           * @dev Returns the remaining number of tokens that `spender` will be
           * allowed to spend on behalf of `owner` through {transferFrom}. This is
           * zero by default.
           *
           * This value changes when {approve} or {transferFrom} are called.
           */
          function allowance(address owner, address spender) external view returns (uint256);
          /**
           * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
           * caller's tokens.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * IMPORTANT: Beware that changing an allowance with this method brings the risk
           * that someone may use both the old and the new allowance by unfortunate
           * transaction ordering. One possible solution to mitigate this race
           * condition is to first reduce the spender's allowance to 0 and set the
           * desired value afterwards:
           * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
           *
           * Emits an {Approval} event.
           */
          function approve(address spender, uint256 value) external returns (bool);
          /**
           * @dev Moves a `value` amount of tokens from `from` to `to` using the
           * allowance mechanism. `value` is then deducted from the caller's
           * allowance.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transferFrom(address from, address to, uint256 value) external returns (bool);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
      pragma solidity ^0.8.20;
      import {IERC20} from "../IERC20.sol";
      import {IERC20Permit} from "../extensions/IERC20Permit.sol";
      import {Address} from "../../../utils/Address.sol";
      /**
       * @title SafeERC20
       * @dev Wrappers around ERC20 operations that throw on failure (when the token
       * contract returns false). Tokens that return no value (and instead revert or
       * throw on failure) are also supported, non-reverting calls are assumed to be
       * successful.
       * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
       * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
       */
      library SafeERC20 {
          using Address for address;
          /**
           * @dev An operation with an ERC20 token failed.
           */
          error SafeERC20FailedOperation(address token);
          /**
           * @dev Indicates a failed `decreaseAllowance` request.
           */
          error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
          /**
           * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
           * non-reverting calls are assumed to be successful.
           */
          function safeTransfer(IERC20 token, address to, uint256 value) internal {
              _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
          }
          /**
           * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
           * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
           */
          function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
              _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
          }
          /**
           * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
           * non-reverting calls are assumed to be successful.
           */
          function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
              uint256 oldAllowance = token.allowance(address(this), spender);
              forceApprove(token, spender, oldAllowance + value);
          }
          /**
           * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
           * value, non-reverting calls are assumed to be successful.
           */
          function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
              unchecked {
                  uint256 currentAllowance = token.allowance(address(this), spender);
                  if (currentAllowance < requestedDecrease) {
                      revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
                  }
                  forceApprove(token, spender, currentAllowance - requestedDecrease);
              }
          }
          /**
           * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
           * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
           * to be set to zero before setting it to a non-zero value, such as USDT.
           */
          function forceApprove(IERC20 token, address spender, uint256 value) internal {
              bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
              if (!_callOptionalReturnBool(token, approvalCall)) {
                  _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
                  _callOptionalReturn(token, approvalCall);
              }
          }
          /**
           * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
           * on the return value: the return value is optional (but if data is returned, it must not be false).
           * @param token The token targeted by the call.
           * @param data The call data (encoded using abi.encode or one of its variants).
           */
          function _callOptionalReturn(IERC20 token, bytes memory data) private {
              // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
              // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
              // the target address contains contract code and also asserts for success in the low-level call.
              bytes memory returndata = address(token).functionCall(data);
              if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
                  revert SafeERC20FailedOperation(address(token));
              }
          }
          /**
           * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
           * on the return value: the return value is optional (but if data is returned, it must not be false).
           * @param token The token targeted by the call.
           * @param data The call data (encoded using abi.encode or one of its variants).
           *
           * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
           */
          function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
              // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
              // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
              // and not revert is the subcall reverts.
              (bool success, bytes memory returndata) = address(token).call(data);
              return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Collection of functions related to the address type
       */
      library Address {
          /**
           * @dev The ETH balance of the account is not enough to perform the operation.
           */
          error AddressInsufficientBalance(address account);
          /**
           * @dev There's no code at `target` (it is not a contract).
           */
          error AddressEmptyCode(address target);
          /**
           * @dev A call to an address target failed. The target may have reverted.
           */
          error FailedInnerCall();
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              if (address(this).balance < amount) {
                  revert AddressInsufficientBalance(address(this));
              }
              (bool success, ) = recipient.call{value: amount}("");
              if (!success) {
                  revert FailedInnerCall();
              }
          }
          /**
           * @dev Performs a Solidity function call using a low level `call`. A
           * plain `call` is an unsafe replacement for a function call: use this
           * function instead.
           *
           * If `target` reverts with a revert reason or custom error, it is bubbled
           * up by this function (like regular Solidity function calls). However, if
           * the call reverted with no returned reason, this function reverts with a
           * {FailedInnerCall} error.
           *
           * Returns the raw returned data. To convert to the expected return value,
           * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
           *
           * Requirements:
           *
           * - `target` must be a contract.
           * - calling `target` with `data` must not revert.
           */
          function functionCall(address target, bytes memory data) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but also transferring `value` wei to `target`.
           *
           * Requirements:
           *
           * - the calling contract must have an ETH balance of at least `value`.
           * - the called Solidity function must be `payable`.
           */
          function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
              if (address(this).balance < value) {
                  revert AddressInsufficientBalance(address(this));
              }
              (bool success, bytes memory returndata) = target.call{value: value}(data);
              return verifyCallResultFromTarget(target, success, returndata);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a static call.
           */
          function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
              (bool success, bytes memory returndata) = target.staticcall(data);
              return verifyCallResultFromTarget(target, success, returndata);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a delegate call.
           */
          function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
              (bool success, bytes memory returndata) = target.delegatecall(data);
              return verifyCallResultFromTarget(target, success, returndata);
          }
          /**
           * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
           * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
           * unsuccessful call.
           */
          function verifyCallResultFromTarget(
              address target,
              bool success,
              bytes memory returndata
          ) internal view returns (bytes memory) {
              if (!success) {
                  _revert(returndata);
              } else {
                  // only check if target is a contract if the call was successful and the return data is empty
                  // otherwise we already know that it was a contract
                  if (returndata.length == 0 && target.code.length == 0) {
                      revert AddressEmptyCode(target);
                  }
                  return returndata;
              }
          }
          /**
           * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
           * revert reason or with a default {FailedInnerCall} error.
           */
          function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
              if (!success) {
                  _revert(returndata);
              } else {
                  return returndata;
              }
          }
          /**
           * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
           */
          function _revert(bytes memory returndata) private pure {
              // Look for revert reason and bubble it up if present
              if (returndata.length > 0) {
                  // The easiest way to bubble the revert reason is using memory via assembly
                  /// @solidity memory-safe-assembly
                  assembly {
                      let returndata_size := mload(returndata)
                      revert(add(32, returndata), returndata_size)
                  }
              } else {
                  revert FailedInnerCall();
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Provides information about the current execution context, including the
       * sender of the transaction and its data. While these are generally available
       * via msg.sender and msg.data, they should not be accessed in such a direct
       * manner, since when dealing with meta-transactions the account sending and
       * paying for execution may not be the actual sender (as far as an application
       * is concerned).
       *
       * This contract is only required for intermediate, library-like contracts.
       */
      abstract contract Context {
          function _msgSender() internal view virtual returns (address) {
              return msg.sender;
          }
          function _msgData() internal view virtual returns (bytes calldata) {
              return msg.data;
          }
          function _contextSuffixLength() internal view virtual returns (uint256) {
              return 0;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Contract module that helps prevent reentrant calls to a function.
       *
       * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
       * available, which can be applied to functions to make sure there are no nested
       * (reentrant) calls to them.
       *
       * Note that because there is a single `nonReentrant` guard, functions marked as
       * `nonReentrant` may not call one another. This can be worked around by making
       * those functions `private`, and then adding `external` `nonReentrant` entry
       * points to them.
       *
       * TIP: If you would like to learn more about reentrancy and alternative ways
       * to protect against it, check out our blog post
       * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
       */
      abstract contract ReentrancyGuard {
          // Booleans are more expensive than uint256 or any type that takes up a full
          // word because each write operation emits an extra SLOAD to first read the
          // slot's contents, replace the bits taken up by the boolean, and then write
          // back. This is the compiler's defense against contract upgrades and
          // pointer aliasing, and it cannot be disabled.
          // The values being non-zero value makes deployment a bit more expensive,
          // but in exchange the refund on every call to nonReentrant will be lower in
          // amount. Since refunds are capped to a percentage of the total
          // transaction's gas, it is best to keep them low in cases like this one, to
          // increase the likelihood of the full refund coming into effect.
          uint256 private constant NOT_ENTERED = 1;
          uint256 private constant ENTERED = 2;
          uint256 private _status;
          /**
           * @dev Unauthorized reentrant call.
           */
          error ReentrancyGuardReentrantCall();
          constructor() {
              _status = NOT_ENTERED;
          }
          /**
           * @dev Prevents a contract from calling itself, directly or indirectly.
           * Calling a `nonReentrant` function from another `nonReentrant`
           * function is not supported. It is possible to prevent this from happening
           * by making the `nonReentrant` function external, and making it call a
           * `private` function that does the actual work.
           */
          modifier nonReentrant() {
              _nonReentrantBefore();
              _;
              _nonReentrantAfter();
          }
          function _nonReentrantBefore() private {
              // On the first call to nonReentrant, _status will be NOT_ENTERED
              if (_status == ENTERED) {
                  revert ReentrancyGuardReentrantCall();
              }
              // Any calls to nonReentrant after this point will fail
              _status = ENTERED;
          }
          function _nonReentrantAfter() private {
              // By storing the original value once again, a refund is triggered (see
              // https://eips.ethereum.org/EIPS/eip-2200)
              _status = NOT_ENTERED;
          }
          /**
           * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
           * `nonReentrant` function in the call stack.
           */
          function _reentrancyGuardEntered() internal view returns (bool) {
              return _status == ENTERED;
          }
      }
      // SPDX-License-Identifier: UNLICENSED
      pragma solidity 0.8.24;
      import "@openzeppelin/contracts/access/Ownable2Step.sol";
      import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
      import "@openzeppelin/contracts/utils/Context.sol";
      import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
      import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
      import "./interfaces/IDiamondHand.sol";
      import "./utils/constants.sol";
      import "./utils/userDefinedType.sol";
      contract BlazeStaking is ReentrancyGuard, Context, Ownable2Step {
          using SafeERC20 for IERC20;
          uint32 public immutable _deploymentTimeStamp;
          address private _blazeToken;
          address private _lastDistributionAddress;
          uint32 private _currentDayInContract;
          uint256 private _currentStakingShareRate;
          uint256 private _stakeIdCounter;
          uint256 private _totalShares;
          uint256 private _totalCompletedShares;
          uint256 private _totalBlazeTokenStaked;
          uint256 private _allCompletedStake;
          uint256 private _totalUndistributedCollectedFees;
          /* Distribution Variables*/
          DistributionTriggered private _isGlobalDistributionTriggered;
          //cycle => rewards
          mapping(uint16 => uint256) private _cycleDistributionTotalRewards;
          //cycle ==> index count
          mapping(uint16 => uint32) private _cycleDistributionIndexCount;
          mapping(uint16 => uint32) _nextCycleDistributionDay;
          //cycle => index count => reward Per share
          mapping(uint16 => mapping(uint32 => CycleRewardsPerShare)) private _cycleRewardsPerShare;
          mapping(address => mapping(uint16 => CycleClaimIndexCountForUser)) private _userAddressToCycleToLastClaimIndex;
          /* STaking Related variables */
          mapping(address => uint256) private _userAddressToStakeId;
          mapping(address => mapping(uint256 => uint256)) private _userStakeIdToGlobalStakeId;
          //global stake id to stake info
          mapping(uint256 => StakeInfo) private _stakeInfo;
          mapping(address => uint256) private _userLatestIndex;
          mapping(address => mapping(uint256 => UserSharesInfo)) private _userIndexToSharesInfo;
          mapping(address => mapping(uint256 => uint256)) private _user2888CycleBlazeTokenAmount;
          event ETHDistributed(address indexed caller, uint256 indexed amount);
          event CycleDistributionTriggered(address indexed caller, uint256 indexed cycleNo, uint256 indexed rewardAmount);
          event DistributionRewardsClaimed(address indexed user, uint256 indexed rewardAmount);
          event StakeStarted(address indexed user,uint256 indexed globalStakeId,uint256 __blazeAmount,uint256 __durationInDays);
          event StakeEnded(address indexed user,uint256 indexed globalStakeId,uint256 indexed __blazeAmount);
          
          modifier dailyUpdate() {
              _dailyUpdate();
              _;
          }
          constructor(address _blazeTokenAddress) Ownable(_msgSender()) {
              _blazeToken = _blazeTokenAddress;
              _deploymentTimeStamp = uint32(block.timestamp);
              _currentDayInContract = 1;
              _currentStakingShareRate = START_SHARE_RATE;
              _nextCycleDistributionDay[DAY8] = DAY8;
              _nextCycleDistributionDay[DAY88] = DAY88;
              _nextCycleDistributionDay[DAY288] = DAY288;
          }
          receive() external payable {
              _totalUndistributedCollectedFees += msg.value;
          }
          function setLastDistributionAddress(address __lastDistributionAddress) external onlyOwner {
              require(__lastDistributionAddress != address(0), "blazeStaking:last distribution address can not be zero");
              _lastDistributionAddress = __lastDistributionAddress;
          }
          function stakeBlaze(uint256 __blazeAmount, uint256 __durationInDays) external dailyUpdate nonReentrant {
              // IBlazeToken(_blazeToken).burn(_msgSender(), __blazeAmount);
              // uint8 _isFirstStake = _stakeBlaze(_msgSender(), __blazeAmount, __durationInDays);
              uint256 stakeId = ++_userAddressToStakeId[_msgSender()];
              require(
                  __durationInDays >= MINIMUM_STAKING_PERIOD && __durationInDays <= MAXIMUM_STAKING_PERIOD,
                  "blazeStaking:blaze stake duration not valid"
              );
              //calculate shares
              (uint256 totalShares, ) = calculateSharesAndBonus(__blazeAmount, __durationInDays);
              uint256 globalStakeId = ++_stakeIdCounter;
              _userStakeIdToGlobalStakeId[_msgSender()][stakeId] = globalStakeId;
              uint32 stakeMaturityTimestamp = uint32(block.timestamp + (__durationInDays * SECONDS_IN_DAY));
              StakeInfo memory stakeInfo = StakeInfo({
                  amount: __blazeAmount,
                  shares: totalShares,
                  stakeDurationInDays: uint16(__durationInDays),
                  startTimestamp: uint32(block.timestamp),
                  maturityTimestamp: stakeMaturityTimestamp,
                  status: StakeStatus.ACTIVE
              });
              _stakeInfo[globalStakeId] = stakeInfo;
              //update shares changes
              uint8 _isFirstStake = _updateSharesStats(_msgSender(), totalShares, __blazeAmount, StakeAction.START);
              if (_isFirstStake == 1) {
                  _firstStakeCycleConfig(_msgSender());
              }
              if (__durationInDays == MAXIMUM_STAKING_PERIOD) {
                  _setDiamondHand(_msgSender(), __blazeAmount);
              }
              IERC20(_blazeToken).safeTransferFrom(_msgSender(), address(this), __blazeAmount);
              emit StakeStarted(_msgSender(),globalStakeId,__durationInDays,__blazeAmount);
          }
          function unstakeBlaze(address __user, uint256 __id) external dailyUpdate nonReentrant {
              uint256 amount = _unstakeBlaze(__user, __id);
              IERC20(_blazeToken).safeTransfer(__user, amount);
          }
          function dailyDetailsUpdater() external dailyUpdate {}
          // function unstakeBlazeForOthers(address __user, uint256 __id) external dailyUpdate nonReentrant {
          //     uint256 amount = _unstakeBlaze(__user, __id);
          //     IERC20(_blazeToken).safeTransfer(__user, amount);
          // }
          function setFeeRewardsForAllCycle() external dailyUpdate nonReentrant {
              (uint256 lastCycleDistributionPortion, uint256 incentiveAmount) = _distributeCollectedETH();
              require(_lastDistributionAddress != address(0), "blazeStaking:last cycle distribution address not set");
              _transferETH(_lastDistributionAddress, lastCycleDistributionPortion);
              if (incentiveAmount > 0) {
                  _transferETH(_msgSender(), incentiveAmount);
              }
          }
          function distributeFeeRewardsForAll() external dailyUpdate nonReentrant {
              uint256 lastCycleDistributionPortion;
              uint256 incentiveAmount;
              if (_totalUndistributedCollectedFees != 0) {
                  (lastCycleDistributionPortion, incentiveAmount) = _distributeCollectedETH();
              }
              uint256 currentActivateShares = _totalShares - _totalCompletedShares;
              require(currentActivateShares > 1, "blazeStaking:no active shares");
              uint32 currentDayInContract = _currentDayInContract;
              DistributionTriggered isDistributionCompleted = DistributionTriggered.NO;
              DistributionTriggered completed = _distributeFeeRewardsForCycle(
                  DAY8,
                  currentDayInContract,
                  currentActivateShares
              );
              if (completed == DistributionTriggered.YES && isDistributionCompleted == DistributionTriggered.NO) {
                  isDistributionCompleted = DistributionTriggered.YES;
              }
              completed = _distributeFeeRewardsForCycle(DAY88, currentDayInContract, currentActivateShares);
              if (completed == DistributionTriggered.YES && isDistributionCompleted == DistributionTriggered.NO) {
                  isDistributionCompleted = DistributionTriggered.YES;
              }
              completed = _distributeFeeRewardsForCycle(DAY288, currentDayInContract, currentActivateShares);
              if (completed == DistributionTriggered.YES && isDistributionCompleted == DistributionTriggered.NO) {
                  isDistributionCompleted = DistributionTriggered.YES;
              }
              if (
                  isDistributionCompleted == DistributionTriggered.YES &&
                  _isGlobalDistributionTriggered == DistributionTriggered.NO
              ) {
                  _isGlobalDistributionTriggered = DistributionTriggered.YES;
              }
              require(_lastDistributionAddress != address(0), "blazeStaking:last cycle distribution address not set");
              if(lastCycleDistributionPortion>0){
                  _transferETH(_lastDistributionAddress, lastCycleDistributionPortion);
              }
              if (incentiveAmount > 0) {
                  _transferETH(_msgSender(), incentiveAmount);
              }
          }
          function claimFeeRewards() external dailyUpdate nonReentrant {
              uint256 reward = _claimCycleDistribution(DAY8);
              reward += _claimCycleDistribution(DAY88);
              reward += _claimCycleDistribution(DAY288);
              if (reward != 0) {
                  _transferETH(_msgSender(), reward);
              }
              emit DistributionRewardsClaimed(_msgSender(), reward);
          }
          function getAvailableRewardsForClaim(address __user) external view returns (uint256 __totalRewards) {
              uint256 rewardsPerCycle;
              (rewardsPerCycle, , ) = _calculateUserCycleFeesReward(__user, DAY8);
              __totalRewards += rewardsPerCycle;
              (rewardsPerCycle, , ) = _calculateUserCycleFeesReward(__user, DAY88);
              __totalRewards += rewardsPerCycle;
              (rewardsPerCycle, , ) = _calculateUserCycleFeesReward(__user, DAY288);
              __totalRewards += rewardsPerCycle;
          }
          function getStakes(
              address __user,
              uint256 __cursor,
              uint256 __size
          ) external view returns (CompleteStakeInfo[] memory __stakes, uint256 __counter) {
              uint256 currentUserCounter = _userAddressToStakeId[__user];
              uint256 count = currentUserCounter;
              if (__cursor >= count) {
                  return (new CompleteStakeInfo[](0), 0);
              }
              uint256 endIndex = __cursor + __size;
              if (endIndex > count) {
                  endIndex = count;
              }
              __stakes = new CompleteStakeInfo[](endIndex - __cursor);
              for (uint256 i = 0; __cursor < endIndex; ++__cursor) {
                  __stakes[i] = CompleteStakeInfo({
                      userStakeId: __cursor + 1,
                      globalStakeId: _userStakeIdToGlobalStakeId[__user][__cursor + 1],
                      stakeInfo: getStakeInfoByUserStakeId(__user, __cursor + 1)
                  });
                  ++i;
              }
              return (__stakes, endIndex);
          }
          function getCurrentSharesOfUser(address __user) external view returns (uint256) {
              return _userIndexToSharesInfo[__user][getUserLatestShareIndex(__user)].currentShares;
          }
          function getUserSharesAtParticularUserIndex(
              address __user,
              uint256 __index
          ) external view returns (uint256 __shares, uint256 __updationDay) {
              return (
                  _userIndexToSharesInfo[__user][__index].currentShares,
                  _userIndexToSharesInfo[__user][__index].updationDay
              );
          }
          function getTotalStakesInfo()
              external
              view
              returns (uint256 __totalStakes, uint256 __totalCompletedStakes, uint256 __currentActiveStakes)
          {
              return (_stakeIdCounter, _allCompletedStake, _stakeIdCounter - _allCompletedStake);
          }
          function getTotalSharesInfo()
              external
              view
              returns (uint256 __totalSharesAllocated, uint256 __totalCompletedStakeShares, uint256 __currentActiveShares)
          {
              return (_totalShares, _totalCompletedShares, _totalShares - _totalCompletedShares);
          }
          function getTotalStakedTokens() external view returns (uint256 __blazeTokens) {
              return _totalBlazeTokenStaked;
          }
          function getTotalCycleRewards(uint16 __cycle) external view returns (uint256 __totalRewards) {
              return _cycleDistributionTotalRewards[__cycle];
          }
          function getNextCycleDistributionDay(uint16 __cycle) external view returns (uint256 __nextDistributionDay) {
              return _nextCycleDistributionDay[__cycle];
          }
          function getCurrentCycleIndex(uint16 __cycle) external view returns (uint256 __currentCycleIndex) {
              return _cycleDistributionIndexCount[__cycle];
          }
          function getCurrentShareRate() external view returns (uint256 __shareRate) {
              return _currentStakingShareRate;
          }
          function getGlobalDistributionTriggeringStatus() external view returns (DistributionTriggered) {
              return _isGlobalDistributionTriggered;
          }
          function getCurrentDayInContract() external view returns (uint256 __currentDay) {
              return _currentDayInContract;
          }
          function getTotalUndistributedFees() external view returns (uint256 __totalUndistributedFees) {
              return _totalUndistributedCollectedFees;
          }
          function getLastDistributionAddress() external view returns (address __lastDsitributionAddress) {
              return _lastDistributionAddress;
          }
          function getUser2888BlazeToken(address __user, uint256 __cycle) external view returns (uint256 _blazeTokenStaked) {
              return _user2888CycleBlazeTokenAmount[__user][__cycle];
          }
          function getUserLastCycleClaimIndex(
              address __user,
              uint16 __cycle
          ) public view returns (uint32 __cycleIndex, uint96 __sharesIndex) {
              return (
                  _userAddressToCycleToLastClaimIndex[__user][__cycle].cycleIndex,
                  _userAddressToCycleToLastClaimIndex[__user][__cycle].sharesIndex
              );
          }
          function getStakeInfoByUserStakeId(address __user, uint256 __userStakeId) public view returns (StakeInfo memory) {
              return _stakeInfo[_userStakeIdToGlobalStakeId[__user][__userStakeId]];
          }
          function getRewardsPerShare(
              uint16 __cycle,
              uint32 __index
          ) public view returns (uint256 __rewardsPerShare, uint256 __distributionDay) {
              return (_cycleRewardsPerShare[__cycle][__index].rewardPerShare, _cycleRewardsPerShare[__cycle][__index].day);
          }
          function getUserLatestShareIndex(address __user) public view returns (uint256 __userLatestIndex) {
              return _userLatestIndex[__user];
          }
          function calculateSharesAndBonus(
              uint256 __blazeAmount,
              uint256 __durationInDays
          ) public view returns (uint256 __shares, uint256 __bonus) {
              // Calculate regular shares
              __shares = __blazeAmount;
              // Calculate bonus based on duration
              __bonus = ((__durationInDays - MINIMUM_STAKING_PERIOD) * BASE_1e18) / Percent_In_Days;
              // Add bonus shares to total shares
              __shares = __shares + ((__shares * __bonus) / BASE_1e18);
              __shares = (__shares * BASE_1e18) / _currentStakingShareRate;
              return (__shares, __bonus);
          }
          function _dailyUpdate() private {
              uint32 currentDayInContract = _currentDayInContract;
              uint32 currentDay = uint32(((block.timestamp - _deploymentTimeStamp) / 1 days) + 1);
              if (currentDay > currentDayInContract) {
                  uint256 newShareRate = _currentStakingShareRate;
                  uint32 dayDifference = currentDay - currentDayInContract;
                  uint32 tempDayInContract = currentDayInContract;
                  for (uint32 i = 0; i < dayDifference; ++i) {
                      ++tempDayInContract;
                      if (tempDayInContract % DAY8 == 0) {
                          newShareRate = (newShareRate -
                              (newShareRate * EIGHTH_DAY_SHARE_RATE_DECREASE_PERCENTAGE) /
                              PERCENT_BASE);
                      }
                  }
                  _currentStakingShareRate = newShareRate;
                  _currentDayInContract = currentDay;
                  _isGlobalDistributionTriggered = DistributionTriggered.NO;
              }
          }
          function _unstakeBlaze(address __user, uint256 __id) private returns (uint256 __blazeAmount) {
              uint256 globalStakeId = _userStakeIdToGlobalStakeId[__user][__id];
              require(globalStakeId != 0, "blazeStaking:blaze staking stake id not valid");
              StakeInfo memory stakeInfo = _stakeInfo[globalStakeId];
              require(stakeInfo.status != StakeStatus.COMPLETED, "blazeStaking:blaze stake has already ended");
              require(block.timestamp >= stakeInfo.maturityTimestamp, "blazeStaking:blaze stake not matured");
              //update shares changes
              uint256 shares = stakeInfo.shares;
              _updateSharesStats(__user, shares, stakeInfo.amount, StakeAction.END);
              ++_allCompletedStake;
              _stakeInfo[globalStakeId].status = StakeStatus.COMPLETED;
              __blazeAmount = stakeInfo.amount;
              emit StakeEnded(__user, globalStakeId,__blazeAmount);
          }
          function _updateSharesStats(
              address __user,
              uint256 __shares,
              uint256 __amount,
              StakeAction __action
          ) private returns (uint8 __firstStake) {
              uint256 index = _userLatestIndex[__user];
              uint256 currentUserShares = _userIndexToSharesInfo[__user][index].currentShares;
              if (__action == StakeAction.START) {
                  if (index == 0) {
                      __firstStake = 1;
                  }
                  _userIndexToSharesInfo[__user][++index].currentShares = currentUserShares + __shares;
                  _totalShares += __shares;
                  _totalBlazeTokenStaked += __amount;
              } else {
                  _userIndexToSharesInfo[__user][++index].currentShares = currentUserShares - __shares;
                  _totalCompletedShares += __shares;
                  _totalBlazeTokenStaked -= __amount;
              }
              _userIndexToSharesInfo[__user][index].updationDay = uint32(
                  _isGlobalDistributionTriggered == DistributionTriggered.NO
                      ? _currentDayInContract
                      : _currentDayInContract + 1
              );
              _userLatestIndex[__user] = index;
          }
          function _firstStakeCycleConfig(address __user) private {
              if (_cycleDistributionIndexCount[DAY8] != 0) {
                  _userAddressToCycleToLastClaimIndex[__user][DAY8].cycleIndex = uint32(
                      _cycleDistributionIndexCount[DAY8] + 1
                  );
                  _userAddressToCycleToLastClaimIndex[__user][DAY88].cycleIndex = uint32(
                      _cycleDistributionIndexCount[DAY88] + 1
                  );
                  _userAddressToCycleToLastClaimIndex[__user][DAY288].cycleIndex = uint32(
                      _cycleDistributionIndexCount[DAY288] + 1
                  );
              }
          }
          function _distributeCollectedETH()
              private
              returns (uint256 __lastCycleDsitributionPortion, uint256 __incentiveAmount)
          {
              uint256 undistributedFees = _totalUndistributedCollectedFees;
              require(undistributedFees > 0, "blazeStaking:No fees to distribute");
              _totalUndistributedCollectedFees = 0;
              __incentiveAmount = (undistributedFees * PUBLIC_CALL_INCENTIVE) / PUBLIC_CALL_INCENTIVE_BASE;
              undistributedFees -= __incentiveAmount;
              uint256 feesPortionForCycle8 = (undistributedFees * PERCENT_FOR_CYCLE_8) / PERCENT_BASE;
              uint256 feesPortionForCycle88 = (undistributedFees * PERCENT_FOR_CYCLE_88) / PERCENT_BASE;
              uint256 feesPortionForCycle288 = (undistributedFees * PERCENT_FOR_CYCLE_288) / PERCENT_BASE;
              __lastCycleDsitributionPortion =
                  undistributedFees -
                  (feesPortionForCycle8 + feesPortionForCycle88 + feesPortionForCycle288);
              _addCycleDistributionPortion(DAY8, feesPortionForCycle8);
              _addCycleDistributionPortion(DAY88, feesPortionForCycle88);
              _addCycleDistributionPortion(DAY288, feesPortionForCycle288);
              emit ETHDistributed(_msgSender(), undistributedFees);
              return (__lastCycleDsitributionPortion, __incentiveAmount);
          }
          function _addCycleDistributionPortion(uint16 __cycle, uint256 __rewards) private {
              _cycleDistributionTotalRewards[__cycle] += __rewards;
          }
          function _distributeFeeRewardsForCycle(
              uint16 __cycle,
              uint32 __currentDay,
              uint256 __currentActiveShares
          ) private returns (DistributionTriggered __completed) {
              if (__currentDay < _nextCycleDistributionDay[__cycle]) {
                  return DistributionTriggered.NO;
              }
              _calculateAndSetNextDistributionDay(__cycle);
              uint256 totalRewardsForThisCycle = _cycleDistributionTotalRewards[__cycle];
              if (totalRewardsForThisCycle == 0) {
                  return DistributionTriggered.NO;
              }
              _setCycleRewardsPerShare(__cycle, __currentDay, __currentActiveShares, totalRewardsForThisCycle);
              _cycleDistributionTotalRewards[__cycle] = 0;
              emit CycleDistributionTriggered(_msgSender(), __cycle, totalRewardsForThisCycle);
              return DistributionTriggered.YES;
          }
          function _calculateAndSetNextDistributionDay(uint16 __cycle) private {
              uint32 mDay = _nextCycleDistributionDay[__cycle];
              uint32 currentDay = _currentDayInContract;
              if (currentDay >= mDay) {
                  uint32 totalCycles = (((currentDay - mDay) / __cycle) + 1);
                  _nextCycleDistributionDay[__cycle] += __cycle * totalCycles;
              }
          }
          function _transferETH(address __to, uint256 __amount) private {
              (bool successful, ) = payable(__to).call{value: __amount}("");
              require(successful, "blazeStaking:eth transfer failed");
          }
          function _setCycleRewardsPerShare(
              uint16 __cycle,
              uint32 __currentDay,
              uint256 __currentActiveShares,
              uint256 __totalRewards
          ) private {
              uint32 _currentCycleindex = ++_cycleDistributionIndexCount[__cycle];
              _cycleRewardsPerShare[__cycle][_currentCycleindex].rewardPerShare =
                  (__totalRewards * BASE_1e18) /
                  __currentActiveShares;
              _cycleRewardsPerShare[__cycle][_currentCycleindex].day = __currentDay;
          }
          function _claimCycleDistribution(uint16 __cycle) private returns (uint256) {
              (uint256 reward, uint256 userClaimSharesIndex, uint32 userClaimCycleIndex) = _calculateUserCycleFeesReward(
                  _msgSender(),
                  __cycle
              );
              _updateUserCycleClaimIndexes(_msgSender(), __cycle, userClaimCycleIndex, userClaimSharesIndex);
              return reward;
          }
          function _calculateUserCycleFeesReward(
              address __user,
              uint16 __cycle
          ) private view returns (uint256 _rewards, uint256 _userClaimSharesIndex, uint32 _userClaimCycleIndex) {
              uint32 latestCycleIndex = _cycleDistributionIndexCount[__cycle];
              (_userClaimCycleIndex, _userClaimSharesIndex) = getUserLastCycleClaimIndex(__user, __cycle);
              uint256 latestUserSharesIndex = _userLatestIndex[__user];
              for (uint32 j = _userClaimCycleIndex; j <= latestCycleIndex; ++j) {
                  (uint256 rewardsPerShare, uint256 dayofDistribution) = getRewardsPerShare(__cycle, j);
                  uint256 shares;
                  for (uint256 k = _userClaimSharesIndex; k <= latestUserSharesIndex; ++k) {
                      if (_userIndexToSharesInfo[__user][k].updationDay <= dayofDistribution)
                          shares = _userIndexToSharesInfo[__user][k].currentShares;
                      else break;
                      _userClaimSharesIndex = k;
                  }
                  if (rewardsPerShare != 0 && shares != 0) {
                      //reward has 18 decimals scaling, so here divide by 1e18
                      _rewards += (shares * rewardsPerShare) / BASE_1e18;
                  }
                  _userClaimCycleIndex = j + 1;
              }
          }
          function _updateUserCycleClaimIndexes(
              address __user,
              uint16 __cycle,
              uint32 __userClaimCycleIndex,
              uint256 __userClaimSharesIndex
          ) private {
              if (__userClaimCycleIndex != _userAddressToCycleToLastClaimIndex[__user][__cycle].cycleIndex)
                  _userAddressToCycleToLastClaimIndex[__user][__cycle].cycleIndex = (__userClaimCycleIndex);
              if (__userClaimSharesIndex != _userAddressToCycleToLastClaimIndex[__user][__cycle].sharesIndex)
                  _userAddressToCycleToLastClaimIndex[__user][__cycle].sharesIndex = uint64(__userClaimSharesIndex);
          }
          function _setDiamondHand(address __user, uint256 __amount) private {
              (uint256 currentDay, uint256 currentCycle, ) = IDiamondHand(_lastDistributionAddress)
                  .getCurrentDayAndCycleDetails();
              uint256 cycleStartDay = (currentCycle - 1) * 888;
              uint256 cycleEndDay = cycleStartDay + 365;
              bool isEligible = currentDay <= cycleEndDay;
              if (isEligible) {
                  _user2888CycleBlazeTokenAmount[__user][currentCycle] += __amount;
              }
          }
      }
      // SPDX-License-Identifier: UNLICENSED
      pragma solidity 0.8.24;
      interface IDiamondHand {
          function getCurrentDayAndCycleDetails() external view returns (uint256 currentDay, uint256 currentCycle, uint256 currentDayInCycle);
      }// SPDX-License-Identifier: UNLICENSED
      pragma solidity 0.8.24;
      //Distribution Cycle Configurations
      uint16 constant DAY8 = 8;
      uint16 constant DAY88 = 88;
      uint16 constant DAY288 = 288;
      uint16 constant DAY888 = 888;
      uint16 constant PERCENT_FOR_CYCLE_8 = 3261;
      uint16 constant PERCENT_FOR_CYCLE_88 = 2608;
      uint16 constant PERCENT_FOR_CYCLE_288 = 2174;
      uint16 constant PERCENT_FOR_CYCLE_888 = 1957;
      // Global
      uint16 constant PERCENT_BASE = 10000;
      uint32 constant SECONDS_IN_DAY = 86400;
      uint256 constant BASE_1e18 = 1e18;
      //Blaze Share Rate Configurations
      uint256 constant START_SHARE_RATE = 1e18;
      uint256 constant EIGHTH_DAY_SHARE_RATE_DECREASE_PERCENTAGE = 126;
      uint256 constant SCALING_SHARES = 1e18;
      //Stake Duration
      uint16 constant MINIMUM_STAKING_PERIOD = 88;
      uint16 constant MAXIMUM_STAKING_PERIOD = 2888;
      //Bonus COnfiguration
      uint256 constant Percent_In_Days = 972;
      //Incentive Configuration
      uint256 constant PUBLIC_CALL_INCENTIVE = 3300;
      uint256 constant PUBLIC_CALL_INCENTIVE_BASE = 1_000_000;
      // SPDX-License-Identifier: UNLICENSED
      pragma solidity 0.8.24;
      enum DistributionTriggered {
          NO,
          YES
      }
      enum StakeStatus {
          ACTIVE,
          COMPLETED
      }
      enum StakeAction {
          START,
          END
      }
      struct CycleRewardsPerShare {
          uint32 day;
          uint256 rewardPerShare;
      }
      struct CycleClaimIndexCountForUser {
          uint32 cycleIndex;
          uint96 sharesIndex;
      }
      struct StakeInfo {
          uint256 amount;
          uint256 shares;
          uint16 stakeDurationInDays;
          uint32 startTimestamp;
          uint32 maturityTimestamp;
          StakeStatus status;
      }
      struct UserSharesInfo {
          uint32 updationDay;
          uint256 currentShares;
      }
      struct CompleteStakeInfo {
          uint256 userStakeId;
          uint256 globalStakeId;
          StakeInfo stakeInfo;
      }
      

      File 3 of 3: DiamondHandWrapper
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
      pragma solidity ^0.8.20;
      import {Context} from "../utils/Context.sol";
      /**
       * @dev Contract module which provides a basic access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * The initial owner is set to the address provided by the deployer. This can
       * later be changed with {transferOwnership}.
       *
       * This module is used through inheritance. It will make available the modifier
       * `onlyOwner`, which can be applied to your functions to restrict their use to
       * the owner.
       */
      abstract contract Ownable is Context {
          address private _owner;
          /**
           * @dev The caller account is not authorized to perform an operation.
           */
          error OwnableUnauthorizedAccount(address account);
          /**
           * @dev The owner is not a valid owner account. (eg. `address(0)`)
           */
          error OwnableInvalidOwner(address owner);
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
          /**
           * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
           */
          constructor(address initialOwner) {
              if (initialOwner == address(0)) {
                  revert OwnableInvalidOwner(address(0));
              }
              _transferOwnership(initialOwner);
          }
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              _checkOwner();
              _;
          }
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view virtual returns (address) {
              return _owner;
          }
          /**
           * @dev Throws if the sender is not the owner.
           */
          function _checkOwner() internal view virtual {
              if (owner() != _msgSender()) {
                  revert OwnableUnauthorizedAccount(_msgSender());
              }
          }
          /**
           * @dev Leaves the contract without owner. It will not be possible to call
           * `onlyOwner` functions. Can only be called by the current owner.
           *
           * NOTE: Renouncing ownership will leave the contract without an owner,
           * thereby disabling any functionality that is only available to the owner.
           */
          function renounceOwnership() public virtual onlyOwner {
              _transferOwnership(address(0));
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public virtual onlyOwner {
              if (newOwner == address(0)) {
                  revert OwnableInvalidOwner(address(0));
              }
              _transferOwnership(newOwner);
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Internal function without access restriction.
           */
          function _transferOwnership(address newOwner) internal virtual {
              address oldOwner = _owner;
              _owner = newOwner;
              emit OwnershipTransferred(oldOwner, newOwner);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)
      pragma solidity ^0.8.20;
      import {Ownable} from "./Ownable.sol";
      /**
       * @dev Contract module which provides access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * The initial owner is specified at deployment time in the constructor for `Ownable`. This
       * can later be changed with {transferOwnership} and {acceptOwnership}.
       *
       * This module is used through inheritance. It will make available all functions
       * from parent (Ownable).
       */
      abstract contract Ownable2Step is Ownable {
          address private _pendingOwner;
          event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
          /**
           * @dev Returns the address of the pending owner.
           */
          function pendingOwner() public view virtual returns (address) {
              return _pendingOwner;
          }
          /**
           * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public virtual override onlyOwner {
              _pendingOwner = newOwner;
              emit OwnershipTransferStarted(owner(), newOwner);
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
           * Internal function without access restriction.
           */
          function _transferOwnership(address newOwner) internal virtual override {
              delete _pendingOwner;
              super._transferOwnership(newOwner);
          }
          /**
           * @dev The new owner accepts the ownership transfer.
           */
          function acceptOwnership() public virtual {
              address sender = _msgSender();
              if (pendingOwner() != sender) {
                  revert OwnableUnauthorizedAccount(sender);
              }
              _transferOwnership(sender);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Provides information about the current execution context, including the
       * sender of the transaction and its data. While these are generally available
       * via msg.sender and msg.data, they should not be accessed in such a direct
       * manner, since when dealing with meta-transactions the account sending and
       * paying for execution may not be the actual sender (as far as an application
       * is concerned).
       *
       * This contract is only required for intermediate, library-like contracts.
       */
      abstract contract Context {
          function _msgSender() internal view virtual returns (address) {
              return msg.sender;
          }
          function _msgData() internal view virtual returns (bytes calldata) {
              return msg.data;
          }
          function _contextSuffixLength() internal view virtual returns (uint256) {
              return 0;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Standard math utilities missing in the Solidity language.
       */
      library Math {
          /**
           * @dev Muldiv operation overflow.
           */
          error MathOverflowedMulDiv();
          enum Rounding {
              Floor, // Toward negative infinity
              Ceil, // Toward positive infinity
              Trunc, // Toward zero
              Expand // Away from zero
          }
          /**
           * @dev Returns the addition of two unsigned integers, with an overflow flag.
           */
          function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  uint256 c = a + b;
                  if (c < a) return (false, 0);
                  return (true, c);
              }
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
           */
          function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  if (b > a) return (false, 0);
                  return (true, a - b);
              }
          }
          /**
           * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
           */
          function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                  // benefit is lost if 'b' is also tested.
                  // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                  if (a == 0) return (true, 0);
                  uint256 c = a * b;
                  if (c / a != b) return (false, 0);
                  return (true, c);
              }
          }
          /**
           * @dev Returns the division of two unsigned integers, with a division by zero flag.
           */
          function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  if (b == 0) return (false, 0);
                  return (true, a / b);
              }
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
           */
          function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  if (b == 0) return (false, 0);
                  return (true, a % b);
              }
          }
          /**
           * @dev Returns the largest of two numbers.
           */
          function max(uint256 a, uint256 b) internal pure returns (uint256) {
              return a > b ? a : b;
          }
          /**
           * @dev Returns the smallest of two numbers.
           */
          function min(uint256 a, uint256 b) internal pure returns (uint256) {
              return a < b ? a : b;
          }
          /**
           * @dev Returns the average of two numbers. The result is rounded towards
           * zero.
           */
          function average(uint256 a, uint256 b) internal pure returns (uint256) {
              // (a + b) / 2 can overflow.
              return (a & b) + (a ^ b) / 2;
          }
          /**
           * @dev Returns the ceiling of the division of two numbers.
           *
           * This differs from standard division with `/` in that it rounds towards infinity instead
           * of rounding towards zero.
           */
          function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
              if (b == 0) {
                  // Guarantee the same behavior as in a regular Solidity division.
                  return a / b;
              }
              // (a + b - 1) / b can overflow on addition, so we distribute.
              return a == 0 ? 0 : (a - 1) / b + 1;
          }
          /**
           * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
           * denominator == 0.
           * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
           * Uniswap Labs also under MIT license.
           */
          function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
              unchecked {
                  // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                  // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                  // variables such that product = prod1 * 2^256 + prod0.
                  uint256 prod0 = x * y; // Least significant 256 bits of the product
                  uint256 prod1; // Most significant 256 bits of the product
                  assembly {
                      let mm := mulmod(x, y, not(0))
                      prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                  }
                  // Handle non-overflow cases, 256 by 256 division.
                  if (prod1 == 0) {
                      // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                      // The surrounding unchecked block does not change this fact.
                      // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                      return prod0 / denominator;
                  }
                  // Make sure the result is less than 2^256. Also prevents denominator == 0.
                  if (denominator <= prod1) {
                      revert MathOverflowedMulDiv();
                  }
                  ///////////////////////////////////////////////
                  // 512 by 256 division.
                  ///////////////////////////////////////////////
                  // Make division exact by subtracting the remainder from [prod1 prod0].
                  uint256 remainder;
                  assembly {
                      // Compute remainder using mulmod.
                      remainder := mulmod(x, y, denominator)
                      // Subtract 256 bit number from 512 bit number.
                      prod1 := sub(prod1, gt(remainder, prod0))
                      prod0 := sub(prod0, remainder)
                  }
                  // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
                  // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
                  uint256 twos = denominator & (0 - denominator);
                  assembly {
                      // Divide denominator by twos.
                      denominator := div(denominator, twos)
                      // Divide [prod1 prod0] by twos.
                      prod0 := div(prod0, twos)
                      // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                      twos := add(div(sub(0, twos), twos), 1)
                  }
                  // Shift in bits from prod1 into prod0.
                  prod0 |= prod1 * twos;
                  // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                  // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                  // four bits. That is, denominator * inv = 1 mod 2^4.
                  uint256 inverse = (3 * denominator) ^ 2;
                  // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
                  // works in modular arithmetic, doubling the correct bits in each step.
                  inverse *= 2 - denominator * inverse; // inverse mod 2^8
                  inverse *= 2 - denominator * inverse; // inverse mod 2^16
                  inverse *= 2 - denominator * inverse; // inverse mod 2^32
                  inverse *= 2 - denominator * inverse; // inverse mod 2^64
                  inverse *= 2 - denominator * inverse; // inverse mod 2^128
                  inverse *= 2 - denominator * inverse; // inverse mod 2^256
                  // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                  // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                  // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                  // is no longer required.
                  result = prod0 * inverse;
                  return result;
              }
          }
          /**
           * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
           */
          function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
              uint256 result = mulDiv(x, y, denominator);
              if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
                  result += 1;
              }
              return result;
          }
          /**
           * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
           * towards zero.
           *
           * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
           */
          function sqrt(uint256 a) internal pure returns (uint256) {
              if (a == 0) {
                  return 0;
              }
              // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
              //
              // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
              // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
              //
              // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
              // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
              // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
              //
              // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
              uint256 result = 1 << (log2(a) >> 1);
              // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
              // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
              // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
              // into the expected uint128 result.
              unchecked {
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  return min(result, a / result);
              }
          }
          /**
           * @notice Calculates sqrt(a), following the selected rounding direction.
           */
          function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
              unchecked {
                  uint256 result = sqrt(a);
                  return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
              }
          }
          /**
           * @dev Return the log in base 2 of a positive value rounded towards zero.
           * Returns 0 if given 0.
           */
          function log2(uint256 value) internal pure returns (uint256) {
              uint256 result = 0;
              unchecked {
                  if (value >> 128 > 0) {
                      value >>= 128;
                      result += 128;
                  }
                  if (value >> 64 > 0) {
                      value >>= 64;
                      result += 64;
                  }
                  if (value >> 32 > 0) {
                      value >>= 32;
                      result += 32;
                  }
                  if (value >> 16 > 0) {
                      value >>= 16;
                      result += 16;
                  }
                  if (value >> 8 > 0) {
                      value >>= 8;
                      result += 8;
                  }
                  if (value >> 4 > 0) {
                      value >>= 4;
                      result += 4;
                  }
                  if (value >> 2 > 0) {
                      value >>= 2;
                      result += 2;
                  }
                  if (value >> 1 > 0) {
                      result += 1;
                  }
              }
              return result;
          }
          /**
           * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
           * Returns 0 if given 0.
           */
          function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
              unchecked {
                  uint256 result = log2(value);
                  return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
              }
          }
          /**
           * @dev Return the log in base 10 of a positive value rounded towards zero.
           * Returns 0 if given 0.
           */
          function log10(uint256 value) internal pure returns (uint256) {
              uint256 result = 0;
              unchecked {
                  if (value >= 10 ** 64) {
                      value /= 10 ** 64;
                      result += 64;
                  }
                  if (value >= 10 ** 32) {
                      value /= 10 ** 32;
                      result += 32;
                  }
                  if (value >= 10 ** 16) {
                      value /= 10 ** 16;
                      result += 16;
                  }
                  if (value >= 10 ** 8) {
                      value /= 10 ** 8;
                      result += 8;
                  }
                  if (value >= 10 ** 4) {
                      value /= 10 ** 4;
                      result += 4;
                  }
                  if (value >= 10 ** 2) {
                      value /= 10 ** 2;
                      result += 2;
                  }
                  if (value >= 10 ** 1) {
                      result += 1;
                  }
              }
              return result;
          }
          /**
           * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
           * Returns 0 if given 0.
           */
          function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
              unchecked {
                  uint256 result = log10(value);
                  return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
              }
          }
          /**
           * @dev Return the log in base 256 of a positive value rounded towards zero.
           * Returns 0 if given 0.
           *
           * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
           */
          function log256(uint256 value) internal pure returns (uint256) {
              uint256 result = 0;
              unchecked {
                  if (value >> 128 > 0) {
                      value >>= 128;
                      result += 16;
                  }
                  if (value >> 64 > 0) {
                      value >>= 64;
                      result += 8;
                  }
                  if (value >> 32 > 0) {
                      value >>= 32;
                      result += 4;
                  }
                  if (value >> 16 > 0) {
                      value >>= 16;
                      result += 2;
                  }
                  if (value >> 8 > 0) {
                      result += 1;
                  }
              }
              return result;
          }
          /**
           * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
           * Returns 0 if given 0.
           */
          function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
              unchecked {
                  uint256 result = log256(value);
                  return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
              }
          }
          /**
           * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
           */
          function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
              return uint8(rounding) % 2 == 1;
          }
      }
      // SPDX-License-Identifier: UNLICENSED
      pragma solidity 0.8.24;
      import "@openzeppelin/contracts/access/Ownable2Step.sol";
      import "@openzeppelin/contracts/utils/math/Math.sol";
      import "./interfaces/IDiamondNFT.sol";
      contract DiamondHandWrapper is Ownable2Step{
          IDiamondNFT private _nftContractAddress;
          constructor() Ownable(_msgSender())  {}
          function updateNFTContractAddress(address _newAddress) external onlyOwner{
              require(_newAddress!=address(0),"DiamondHandWrapper:zero address not allowed");
              _nftContractAddress=IDiamondNFT(_newAddress);
          }
          function getMintedNFT(address _user) external view returns(uint256 _nftCount){
              uint holdingCount = IDiamondNFT(_nftContractAddress).balanceOf(_user);
              uint mintingCount = IDiamondNFT(_nftContractAddress).userMintedNFT(_user);
              return Math.min(holdingCount, mintingCount);
          }
      }// SPDX-License-Identifier: UNLICENSED
      pragma solidity 0.8.24;
      interface IDiamondNFT {
          function balanceOf(address owner) external view returns (uint256 balance);
         
          function userMintedNFT(address user) external view returns (uint);
      }