Yield Machine

Created Diff never expires
69 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
716 lines
50 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
699 lines
/**
/**
*Submitted for verification at BscScan.com on 2023-01-14
*Submitted for verification at BscScan.com on 2023-01-19
*/
*/


// SPDX-License-Identifier: UNLICENSED
// File: @openzeppelin/contracts/token/ERC20/IERC20.sol
// File: @openzeppelin/contracts/token/ERC20/IERC20.sol




// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)


pragma solidity ^0.8.0;
pragma solidity ^0.8.0;


/**
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
*/
interface IERC20 {
interface IERC20 {
/**
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
* another (`to`).
*
*
* Note that `value` may be zero.
* Note that `value` may be zero.
*/
*/
event Transfer(address indexed from, address indexed to, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);


/**
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
* a call to {approve}. `value` is the new allowance.
*/
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);


/**
/**
* @dev Returns the amount of tokens in existence.
* @dev Returns the amount of tokens in existence.
*/
*/
function totalSupply() external view returns (uint256);
function totalSupply() external view returns (uint256);


/**
/**
* @dev Returns the amount of tokens owned by `account`.
* @dev Returns the amount of tokens owned by `account`.
*/
*/
function balanceOf(address account) external view returns (uint256);
function balanceOf(address account) external view returns (uint256);


/**
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
* @dev Moves `amount` tokens from the caller's account to `to`.
*
*
* Returns a boolean value indicating whether the operation succeeded.
* Returns a boolean value indicating whether the operation succeeded.
*
*
* Emits a {Transfer} event.
* Emits a {Transfer} event.
*/
*/
function transfer(address to, uint256 amount) external returns (bool);
function transfer(address to, uint256 amount) external returns (bool);


/**
/**
* @dev Returns the remaining number of tokens that `spender` will be
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
* zero by default.
*
*
* This value changes when {approve} or {transferFrom} are called.
* This value changes when {approve} or {transferFrom} are called.
*/
*/
function allowance(address owner, address spender) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);


/**
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
*
* Returns a boolean value indicating whether the operation succeeded.
* Returns a boolean value indicating whether the operation succeeded.
*
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* 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
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
*
* Emits an {Approval} event.
* Emits an {Approval} event.
*/
*/
function approve(address spender, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);


/**
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
* allowance.
*
*
* Returns a boolean value indicating whether the operation succeeded.
* Returns a boolean value indicating whether the operation succeeded.
*
*
* Emits a {Transfer} event.
* Emits a {Transfer} event.
*/
*/
function transferFrom(
function transferFrom(
address from,
address from,
address to,
address to,
uint256 amount
uint256 amount
) external returns (bool);
) external returns (bool);
}
}


// File: @openzeppelin/contracts/utils/Context.sol
// File: @openzeppelin/contracts/utils/Context.sol




// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)


pragma solidity ^0.8.0;
pragma solidity ^0.8.0;


/**
/**
* @dev Provides information about the current execution context, including the
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* 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
* 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
* 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
* paying for execution may not be the actual sender (as far as an application
* is concerned).
* is concerned).
*
*
* This contract is only required for intermediate, library-like contracts.
* This contract is only required for intermediate, library-like contracts.
*/
*/
abstract contract Context {
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
return msg.sender;
}
}


function _msgData() internal view virtual returns (bytes calldata) {
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
return msg.data;
}
}
}
}


// File: @openzeppelin/contracts/access/Ownable.sol
// File: @openzeppelin/contracts/access/Ownable.sol




// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)


pragma solidity ^0.8.0;
pragma solidity ^0.8.0;




/**
/**
* @dev Contract module which provides a basic access control mechanism, where
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
* specific functions.
*
*
* By default, the owner account will be the one that deploys the contract. This
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
* can later be changed with {transferOwnership}.
*
*
* This module is used through inheritance. It will make available the modifier
* 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
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
* the owner.
*/
*/
abstract contract Ownable is Context {
abstract contract Ownable is Context {
address private _owner;
address private _owner;


event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);


/**
/**
* @dev Initializes the contract setting the deployer as the initial owner.
* @dev Initializes the contract setting the deployer as the initial owner.
*/
*/
constructor() {
constructor() {
_transferOwnership(_msgSender());
_transferOwnership(_msgSender());
}
}


/**
/**
* @dev Throws if called by any account other than the owner.
* @dev Throws if called by any account other than the owner.
*/
*/
modifier onlyOwner() {
modifier onlyOwner() {
_checkOwner();
_checkOwner();
_;
_;
}
}


/**
/**
* @dev Returns the address of the current owner.
* @dev Returns the address of the current owner.
*/
*/
function owner() public view virtual returns (address) {
function owner() public view virtual returns (address) {
return _owner;
return _owner;
}
}


/**
/**
* @dev Throws if the sender is not the owner.
* @dev Throws if the sender is not the owner.
*/
*/
function _checkOwner() internal view virtual {
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
}


/**
/**
* @dev Leaves the contract without owner. It will not be possible to call
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
* thereby removing any functionality that is only available to the owner.
*/
*/
function renounceOwnership() public virtual onlyOwner {
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
_transferOwnership(address(0));
}
}


/**
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
* Can only be called by the current owner.
*/
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
_transferOwnership(newOwner);
}
}


/**
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
* Internal function without access restriction.
*/
*/
function _transferOwnership(address newOwner) internal virtual {
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
address oldOwner = _owner;
_owner = newOwner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
emit OwnershipTransferred(oldOwner, newOwner);
}
}
}
}


// File: @openzeppelin/contracts/utils/math/SafeMath.sol
// File: @openzeppelin/contracts/utils/math/SafeMath.sol




// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)
// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)


pragma solidity ^0.8.0;
pragma solidity ^0.8.0;


// CAUTION
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
// because it relies on the compiler's built in overflow checks.


/**
/**
* @dev Wrappers over Solidity's arithmetic operations.
* @dev Wrappers over Solidity's arithmetic operations.
*
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
* now has built in overflow checking.
*/
*/
library SafeMath {
library SafeMath {
/**
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
*
* _Available since v3.4._
* _Available since v3.4._
*/
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
unchecked {
uint256 c = a + b;
uint256 c = a + b;
if (c < a) return (false, 0);
if (c < a) return (false, 0);
return (true, c);
return (true, c);
}
}
}
}


/**
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
*
* _Available since v3.4._
* _Available since v3.4._
*/
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
unchecked {
if (b > a) return (false, 0);
if (b > a) return (false, 0);
return (true, a - b);
return (true, a - b);
}
}
}
}


/**
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
*
* _Available since v3.4._
* _Available since v3.4._
*/
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
if (a == 0) return (true, 0);
uint256 c = a * b;
uint256 c = a * b;
if (c / a != b) return (false, 0);
if (c / a != b) return (false, 0);
return (true, c);
return (true, c);
}
}
}
}


/**
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
*
* _Available since v3.4._
* _Available since v3.4._
*/
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
unchecked {
if (b == 0) return (false, 0);
if (b == 0) return (false, 0);
return (true, a / b);
return (true, a / b);
}
}
}
}


/**
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
*
* _Available since v3.4._
* _Available since v3.4._
*/
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
unchecked {
if (b == 0) return (false, 0);
if (b == 0) return (false, 0);
return (true, a % b);
return (true, a % b);
}
}
}
}


/**
/**
* @dev Returns the addition of two unsigned integers, reverting on
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
* overflow.
*
*
* Counterpart to Solidity's `+` operator.
* Counterpart to Solidity's `+` operator.
*
*
* Requirements:
* Requirements:
*
*
* - Addition cannot overflow.
* - Addition cannot overflow.
*/
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
return a + b;
}
}


/**
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
* overflow (when the result is negative).
*
*
* Counterpart to Solidity's `-` operator.
* Counterpart to Solidity's `-` operator.
*
*
* Requirements:
* Requirements:
*
*
* - Subtraction cannot overflow.
* - Subtraction cannot overflow.
*/
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
return a - b;
}
}


/**
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
* overflow.
*
*
* Counterpart to Solidity's `*` operator.
* Counterpart to Solidity's `*` operator.
*
*
* Requirements:
* Requirements:
*
*
* - Multiplication cannot overflow.
* - Multiplication cannot overflow.
*/
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
return a * b;
}
}


/**
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
* division by zero. The result is rounded towards zero.
*
*
* Counterpart to Solidity's `/` operator.
* Counterpart to Solidity's `/` operator.
*
*
* Requirements:
* Requirements:
*
*
* - The divisor cannot be zero.
* - The divisor cannot be zero.
*/
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
return a / b;
}
}


/**
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
* reverting when dividing by zero.
*
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
* invalid opcode to revert (consuming all remaining gas).
*
*
* Requirements:
* Requirements:
*
*
* - The divisor cannot be zero.
* - The divisor cannot be zero.
*/
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
return a % b;
}
}


/**
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
* overflow (when the result is negative).
*
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
* message unnecessarily. For custom revert reasons use {trySub}.
*
*
* Counterpart to Solidity's `-` operator.
* Counterpart to Solidity's `-` operator.
*
*
* Requirements:
* Requirements:
*
*
* - Subtraction cannot overflow.
* - Subtraction cannot overflow.
*/
*/
function sub(
function sub(
uint256 a,
uint256 a,
uint256 b,
uint256 b,
string memory errorMessage
string memory errorMessage
) internal pure returns (uint256) {
) internal pure returns (uint256) {
unchecked {
unchecked {
require(b <= a, errorMessage);
require(b <= a, errorMessage);
return a - b;
return a - b;
}
}
}
}


/**
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
* division by zero. The result is rounded towards zero.
*
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
* uses an invalid opcode to revert (consuming all remaining gas).
*
*
* Requirements:
* Requirements:
*
*
* - The divisor cannot be zero.
* - The divisor cannot be zero.
*/
*/
function div(
function div(
uint256 a,
uint256 a,
uint256 b,
uint256 b,
string memory errorMessage
string memory errorMessage
) internal pure returns (uint256) {
) internal pure returns (uint256) {
unchecked {
unchecked {
require(b > 0, errorMessage);
require(b > 0, errorMessage);
return a / b;
return a / b;
}
}
}
}


/**
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
* reverting with custom message when dividing by zero.
*
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
* message unnecessarily. For custom revert reasons use {tryMod}.
*
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
* invalid opcode to revert (consuming all remaining gas).
*
*
* Requirements:
* Requirements:
*
*
* - The divisor cannot be zero.
* - The divisor cannot be zero.
*/
*/
function mod(
function mod(
uint256 a,
uint256 a,
uint256 b,
uint256 b,
string memory errorMessage
string memory errorMessage
) internal pure returns (uint256) {
) internal pure returns (uint256) {
unchecked {
unchecked {
require(b > 0, errorMessage);
require(b > 0, errorMessage);
return a % b;
return a % b;
}
}
}
}
}
}


// File: sdf.sol
// File: yield.sol




pragma solidity ^0.8.0;
pragma solidity ^0.8.0;








contract YieldMachineBUSD is Ownable {
contract YieldMachineBUSD is Ownable {
using SafeMath for uint256;
using SafeMath for uint256;


// BUSD token address
// BUSD token address
IERC20 public BUSDToken = IERC20(0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56);
IERC20 public BUSDToken = IERC20(0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56);


// --- Constants ---
// --- Constants ---
uint256 public constant MINIMUM_DEPOSIT_AMOUNT = 10 ether; // 10 BUSD
uint256 public constant MINIMUM_DEPOSIT_AMOUNT = 10 ether; // 10 BUSD
uint256 public constant MAXIMUM_DEPOSIT_AMOUNT = 50000 ether; // 50,000 BUSD
uint256 public constant MAXIMUM_DEPOSIT_AMOUNT = 50000 ether; // 50,000 BUSD
uint256 public constant MINIMUM_WITHDRAW_AMOUNT = 10 ether; // 10 BUSD
uint256 public constant MINIMUM_WITHDRAW_AMOUNT = 1 ether; // 1 BUSD
uint256 public constant BASE_DAILY_ROI_PERCENTAGE = 20; // 2%
uint256 public constant BASE_DAILY_ROI_PERCENTAGE = 20; // 2%


uint256 public constant PERCENTAGE_DIVISOR = 1000; // 1000 = 100%
uint256 public constant PERCENTAGE_DIVISOR = 1000; // 1000 = 100%


uint256 public constant AUTO_REINVEST_MIN_PERCENTAGE = 100; // 10%
uint256 public constant AUTO_REINVEST_MIN_PERCENTAGE = 100; // 10%
uint256 public constant AUTO_REINVEST_MAX_PERCENTAGE = 1000; // 100%
uint256 public constant AUTO_REINVEST_MAX_PERCENTAGE = 1000; // 100%
uint256 public constant AUTO_REINVEST_STEP_PERCENTAGE = 100; // 10%
uint256 public constant AUTO_REINVEST_STEP_PERCENTAGE = 100; // 10%


uint256 public constant AUTO_REINVEST_BONUS_MIN_PERCENTAGE = 5; // 0.5%
uint256 public constant AUTO_REINVEST_BONUS_MIN_PERCENTAGE = 5; // 0.5%
uint256 public constant AUTO_REINVEST_BONUS_MAX_PERCENTAGE = 50; // 5%
uint256 public constant AUTO_REINVEST_BONUS_MAX_PERCENTAGE = 50; // 5%
uint256 public constant AUTO_REINVEST_BONUS_STEP_PERCENTAGE = 5; // 0.5%
uint256 public constant AUTO_REINVEST_BONUS_STEP_PERCENTAGE = 5; // 0.5%


uint256 public PLATFORM_FEE_PERCENTAGE = 30; // 3%
uint256 public PLATFORM_FEE_PERCENTAGE = 30; // 3%
uint256 public constant PLATFORM_FEE_MAX_PERCENTAGE = 65; // 6.5%
uint256 public constant PLATFORM_FEE_MAX_PERCENTAGE = 65; // 6.5%
uint256[] public REFERRAL_BONUS_PERCENTAGES = [60, 20, 10, 5, 5, 3, 3, 2, 1, 1]; // 6%, 2%, 1%, 0.5%, 0.5%, 0.3%, 0.3%, 0.2%, 0.1%, 0.1%
uint256[] public REFERRAL_BONUS_PERCENTAGES = [60, 20, 10, 5, 5, 3, 3, 2, 1, 1]; // 6%, 2%, 1%, 0.5%, 0.5%, 0.3%, 0.3%, 0.2%, 0.1%, 0.1%


uint256 public constant CONTRACT_BALANCE_BONUS_STEP = 100000 ether; // Each 100,000 BUSD in contract balance will increase the daily ROI by 0.1%
uint256 public constant CONTRACT_BALANCE_BONUS_STEP = 100000 ether; // Each 100,000 BUSD in contract balance will increase the daily ROI by 0.1%
uint256 public constant CONTRACT_BALANCE_BONUS_PERCENTAGE = 1; // 0.1%
uint256 public constant CONTRACT_BALANCE_BONUS_PERCENTAGE = 1; // 0.1%
uint256 public constant CONTRACT_BALANCE_BONUS_MAX_PERCENTAGE = 20; // 2%
uint256 public constant CONTRACT_BALANCE_BONUS_MAX_PERCENTAGE = 20; // 2%


uint256 public constant HOLD_BONUS_STEP = 1 days; // Each 1 day user holds their rewards will increase daily interest rate by 0.1%
uint256 public constant HOLD_BONUS_STEP = 1 days; // Each 1 day user holds their rewards will increase daily interest rate by 0.1%
uint256 public constant HOLD_BONUS_PERCENTAGE = 1; // 0.1%
uint256 public constant HOLD_BONUS_PERCENTAGE = 1; // 0.1%
uint256 public constant HOLD_BONUS_MAX_PERCENTAGE = 30; // 3%
uint256 public constant HOLD_BONUS_MAX_PERCENTAGE = 30; // 3%


// The maximum profit can't exceed 400% of the original deposited amount
// The maximum profit can't exceed 400% of the original deposited amount
uint256 public constant MAXIMUM_PROFIT_PERCENTAGE = 4000; // 400%
uint256 public constant MAXIMUM_PROFIT_PERCENTAGE = 4000; // 400%


uint256 public constant MAXIMUM_BENEFICIARIES = 4;
uint256 public constant MAXIMUM_BENEFICIARIES = 4;


// --- Variables ---
// --- Variables ---
address[] public beneficiaries; // The addresses that will receive the platform fee
address[] public beneficiaries; // The addresses that will receive the platform fee


uint256 public totalUsers;
uint256 public totalUsers;
uint256 public totalDeposited;
uint256 public totalDeposited;
uint256 public totalPaidOut;
uint256 public totalPaidOut;


bool public initialized = false;
bool public initialized = false;


// --- Structs ---
// --- Structs ---
struct Deposit {
struct Deposit {
uint256 amount;
uint256 amount;
uint256 withdrawn;
uint256 withdrawn;
uint256 timestamp;
uint256 timestamp;
}
}


struct User {
struct User {
address referrer; // Referrer address
address referrer; // Referrer address
mapping(uint256 => uint256) referrals; // Referrals count
mapping(uint256 => uint256) referrals; // Referrals count
mapping(uint256 => uint256) referralBonuses; // Referral bonuses
mapping(uint256 => uint256) referralBonuses; // Referral bonuses
uint256 referralBonusWithdrawn; // Referral bonus withdrawn
uint256 referralBonusWithdrawn; // Referral bonus withdrawn
Deposit[] deposits; // Deposit history
Deposit[] deposits; // Deposit history
uint256 totalDeposited; // Total deposited
}
}


// --- Mappings ---
// --- Mappings ---
mapping(address => User) public users;
mapping(address => User) public users;


// --- Events ---
// --- Events ---
event Initialized(address indexed owner, address[] beneficiaries);
event Initialized(address indexed owner, address[] beneficiaries);
event BeneficiaryAdded(address indexed beneficiary);
event BeneficiaryAdded(address indexed beneficiary);
event BeneficiaryRemoved(address indexed beneficiary);
event BeneficiaryRemoved(address indexed beneficiary);
event PlatformFeeChanged(uint256 platformFee);
event PlatformFeeChanged(uint256 platformFee);
event PlatformFeePaid(uint256 amount);
event PlatformFeePaid(uint256 amount);
event Deposited(address indexed user, uint256 amount, address indexed referrer);
event Deposited(address indexed user, uint256 amount, address indexed referrer);
event Claimed(address indexed user, uint256 amount);
event Claimed(address indexed user, uint256 amount);
event ReferralBonusClaimed(address indexed user, uint256 amount);
event ReferralBonusClaimed(address indexed user, uint256 amount);
event Reinvested(address indexed user, uint256 amount);
event Reinvested(address indexed user, uint256 amount);
event UserdataTransferred(address indexed from, address indexed to);
event UserdataTransferred(address indexed from, address indexed to);


// --- Modifiers ---
// --- Modifiers ---
modifier onlyInitialized() {
modifier onlyInitialized() {
require(initialized, "Contract is not initialized");
require(initialized, "Contract is not initialized");
_;
_;
}
}


// --- FallBack ---
// --- FallBack ---
receive() external payable onlyInitialized {
receive() external payable onlyInitialized {
// Reject any ETH sent directly to the contract
// Reject any ETH sent directly to the contract
revert();
revert();
}
}


// --- Constructor ---
// --- Constructor ---
constructor(address payable beneficiary) {
constructor(address payable beneficiary) {
beneficiaries.push(beneficiary);
beneficiaries.push(beneficiary);
}
}


// --- Public functions ---
// --- Public functions ---
function initialize() public onlyOwner {
function initialize() public onlyOwner {
require(!initialized, "Already initialized");
require(!initialized, "Already initialized");
initialized = true;
initialized = true;
}
}


// --- Main functions ---
// --- Main functions ---
function deposit(address referrer, uint256 amount) public payable onlyInitialized {
function deposit(address referrer, uint256 amount) public onlyInitialized {
require(amount >= MINIMUM_DEPOSIT_AMOUNT, "Deposit amount is too low");
require(amount >= MINIMUM_DEPOSIT_AMOUNT, "Deposit amount is too low");
require(getUserTotalDeposit(msg.sender).add(amount) <= MAXIMUM_DEPOSIT_AMOUNT, "Deposit amount is too high");
require(getUserRawTotalDeposit(msg.sender).add(amount) <= MAXIMUM_DEPOSIT_AMOUNT, "Deposit amount is too high");
BUSDToken.transferFrom(address(msg.sender), address(this), amount);
// Update total users and total deposited
// Update total users and total deposited
if (isInvestor(msg.sender) == false) {
if (isInvestor(msg.sender) == false) {
totalUsers = totalUsers.add(1);
totalUsers = totalUsers.add(1);
}
}


// Update referrer
// Update referrer
if (users[msg.sender].referrer == address(0) && isInvestor(referrer) && referrer != msg.sender) {
if (users[msg.sender].referrer == address(0) && isInvestor(referrer) && referrer != msg.sender) {
users[msg.sender].referrer = referrer;
users[msg.sender].referrer = referrer;
}
}


// Update referrer's rewards
// Update referrer's rewards
address upline = users[msg.sender].referrer;
address upline = users[msg.sender].referrer;
for (uint256 i = 0; i < REFERRAL_BONUS_PERCENTAGES.length; i++) {
for (uint256 i = 0; i < REFERRAL_BONUS_PERCENTAGES.length; i++) {
if (upline != address(0)) {
if (upline != address(0)) {
uint256 referralBonus = amount.mul(REFERRAL_BONUS_PERCENTAGES[i]).div(PERCENTAGE_DIVISOR);
uint256 referralBonus = amount.mul(REFERRAL_BONUS_PERCENTAGES[i]).div(PERCENTAGE_DIVISOR);
users[upline].referrals[i] = users[upline].referrals[i].add(1);
users[upline].referrals[i] = users[upline].referrals[i].add(1);
users[upline].referralBonuses[i] = users[upline].referralBonuses[i].add(referralBonus);
users[upline].referralBonuses[i] = users[upline].referralBonuses[i].add(referralBonus);
upline = users[upline].referrer;
upline = users[upline].referrer;
} else break;
} else break;
}
}


// Update user's total deposited
users[msg.sender].totalDeposited = users[msg.sender].totalDeposited.add(amount);

// Send platform fee
// Send platform fee
uint256 fee = payPlatformFee(amount);
uint256 fee = payPlatformFee(amount);
amount = amount.sub(fee);
amount = amount.sub(fee);
// Subtract platform fee from the deposit amount
BUSDToken.transferFrom(address(msg.sender), address(this), amount);


totalDeposited = totalDeposited.add(amount);
totalDeposited = totalDeposited.add(amount);


// Update user deposits
// Update user deposits
users[msg.sender].deposits.push(Deposit(amount, 0, block.timestamp));
users[msg.sender].deposits.push(Deposit(amount, 0, block.timestamp));


emit Deposited(msg.sender, amount, referrer);
emit Deposited(msg.sender, amount, referrer);
}
}


function claim(uint256 reinvestPercent) public onlyInitialized {
function claim(uint256 reinvestPercent) public onlyInitialized {
// As we get reinvestPercent in a percent format, we need to convert it to a decimal format
// As we get reinvestPercent in a percent format, we need to convert it to a decimal format
reinvestPercent = reinvestPercent.mul(10);
reinvestPercent = reinvestPercent.mul(10);
// reinvestPercent must be between AUTO_REINVEST_BONUS_MAX and AUTO_REINVEST_MIN_PERCENTAGE (inclusive)
// reinvestPercent must be between AUTO_REINVEST_BONUS_MAX and AUTO_REINVEST_MIN_PERCENTAGE (inclusive)
// reinvestPercent must be a multiple of AUTO_REINVEST_STEP_PERCENTAGE
// reinvestPercent must be a multiple of AUTO_REINVEST_STEP_PERCENTAGE
require(reinvestPercent >= AUTO_REINVEST_MIN_PERCENTAGE, "Reinvest percentage is too low");
require(reinvestPercent >= AUTO_REINVEST_MIN_PERCENTAGE, "Reinvest percentage is too low");
require(reinvestPercent <= AUTO_REINVEST_MAX_PERCENTAGE, "Reinvest percentage is too high");
require(reinvestPercent <= AUTO_REINVEST_MAX_PERCENTAGE, "Reinvest percentage is too high");
require(reinvestPercent.mod(AUTO_REINVEST_STEP_PERCENTAGE) == 0, "Reinvest percentage is not valid");
require(reinvestPercent.mod(AUTO_REINVEST_STEP_PERCENTAGE) == 0, "Reinvest percentage is not valid");


// Calculate reinvestBonus
uint256 reinvestBonus = reinvestPercent.div(AUTO_REINVEST_STEP_PERCENTAGE).mul(AUTO_REINVEST_BONUS_STEP_PERCENTAGE);
// Calculate reinvest percent

User storage user = users[msg.sender];
User storage user = users[msg.sender];
uint256 fullProfit = 0;
uint256 dividends = 0;
uint256 dividends = 0;
for (uint256 i = 0; i < user.deposits.length; i++) {
for (uint256 i = 0; i < user.deposits.length; i++) { // Loop through all deposits
if (user.deposits[i].withdrawn < user.deposits[i].amount.mul(MAXIMUM_PROFIT_PERCENTAGE).div(PERCENTAGE_DIVISOR)) {
if (user.deposits[i].withdrawn < user.deposits[i].amount.mul(MAXIMUM_PROFIT_PERCENTAGE).div(PERCENTAGE_DIVISOR)) {// Check if deposit is not fully withdrawn
uint256 depositAmount = user.deposits[i].amount;
uint256 depositAmount = user.deposits[i].amount;
// Get deposit amount
uint256 depositTime = user.deposits[i].timestamp;
uint256 depositTime = user.deposits[i].timestamp;

// Get deposit timestamp
uint256 secondsPassed = block.timestamp.sub(depositTime);
uint256 secondsPassed = block.timestamp.sub(depositTime);
// Get seconds passed since deposit


if (secondsPassed > 0) {
if (secondsPassed > 0) {// Check if deposit is not new
uint256 dailyRoi = getContractBalanceBonusPercentage().add(getHoldBonusPercentage(depositTime)).add(BASE_DAILY_ROI_PERCENTAGE);
uint256 dailyRoi = getContractBalanceBonusPercentage().add(getHoldBonusPercentage(depositTime)).add(BASE_DAILY_ROI_PERCENTAGE);
// Calculate daily ROI
uint256 profit = depositAmount.mul(dailyRoi).div(PERCENTAGE_DIVISOR).mul(secondsPassed).div(1 days);
uint256 profit = depositAmount.mul(dailyRoi).div(PERCENTAGE_DIVISOR).mul(secondsPassed).div(1 days);
// Calculate profit
fullProfit = fullProfit.add(profit);
// Add profit to full profit

uint256 maxProfit = depositAmount.mul(MAXIMUM_PROFIT_PERCENTAGE).div(PERCENTAGE_DIVISOR);
uint256 maxProfit = depositAmount.mul(MAXIMUM_PROFIT_PERCENTAGE).div(PERCENTAGE_DIVISOR);

// Calculate max profit
if (profit.add(user.deposits[i].withdrawn) > maxProfit) {
if (profit.add(user.deposits[i].withdrawn) > maxProfit) {// Check if profit is greater than max profit
profit = maxProfit.sub(user.deposits[i].withdrawn);
profit = maxProfit.sub(user.deposits[i].withdrawn);
// Set profit to max profit minus withdrawn amount to prevent overflow
}
}


user.deposits[i].withdrawn = user.deposits[i].withdrawn.add(profit);
uint256 BUSDReinvested = profit.mul(reinvestPercent).div(PERCENTAGE_DIVISOR);
dividends = dividends.add(profit);
// Calculate reinvested amount
uint256 BUSDReinvestBonus = profit.mul(reinvestBonus).div(PERCENTAGE_DIVISOR);
// Calculate reinvest bonus amount

dividends = dividends.add(profit.sub(BUSDReinvested));
// Add profit minus reinvested amount to dividends
user.deposits[i].withdrawn = user.deposits[i].withdrawn.add(profit.sub(BUSDReinvested));
// Add profit minus reinvested amount to withdrawn amount
user.deposits[i].amount = user.deposits[i].amount.add(BUSDReinvested).add(BUSDReinvestBonus);
// Add reinvested amount and reinvest bonus to deposit amount
user.deposits[i].timestamp = block.timestamp;
user.deposits[i].timestamp = block.timestamp;
// Update deposit timestamp to current timestamp
}
}
}
}
}
}


require(dividends > MINIMUM_WITHDRAW_AMOUNT, "User dividends not meet minimum withdraw amount");
require(fullProfit > MINIMUM_WITHDRAW_AMOUNT, "User dividends not meet minimum withdraw amount");

uint256 fee = payPlatformFee(dividends);
dividends = dividends.sub(fee);

// Calculate reinvest bonus
uint256 reinvestBonus = reinvestPercent.div(AUTO_REINVEST_STEP_PERCENTAGE).mul(AUTO_REINVEST_BONUS_STEP_PERCENTAGE);
// Add reinvest bonus to reinvestPercent
reinvestPercent = reinvestPercent.add(reinvestBonus);
uint256 reinvestAmount = dividends.mul(reinvestPercent).div(PERCENTAGE_DIVISOR);

// Add reinvest amount to the last deposit
user.deposits[user.deposits.length - 1].amount = user.deposits[user.deposits.length - 1].amount.add(reinvestAmount);
emit Reinvested(msg.sender, dividends);

// If dividends is less than reinvestAmount, then
if (dividends < reinvestAmount) {
dividends = 0;
} else {
dividends = dividends.sub(reinvestAmount);
}


// If the contract balance is less than the dividends, then set dividends to the contract balance
uint256 contractBalance = getContractBalance();
uint256 contractBalance = getContractBalance();
if (dividends > contractBalance) {
if (dividends > contractBalance) {
dividends = contractBalance;
dividends = contractBalance;
}
}


totalPaidOut = totalPaidOut.add(dividends);
BUSDToken.transfer(address(msg.sender), dividends); // Transfer full profit to user
uint256 fee = payPlatformFee(dividends); // Pay platform fee


BUSDToken.transfer(address(msg.sender), dividends);
// Update total withdrawn
totalPaidOut = totalPaidOut.add(dividends.sub(fee));


emit Claimed(msg.sender, dividends);
emit Claimed(msg.sender, dividends);
emit Reinvested(msg.sender, dividends);
}
}


function claimReferralBonus() public onlyInitialized {
function claimReferralBonus() public onlyInitialized {
uint256 amount = getReferralBonus(msg.sender);
uint256 amount = getReferralBonus(msg.sender);
require(amount > 0, "No referral bonus available");
require(amount >= MINIMUM_WITHDRAW_AMOUNT, "Referral bonus not meet minimum withdraw amount");


// Update user referral bonuses
// Update user referral bonuses
for (uint256 i = 0; i < REFERRAL_BONUS_PERCENTAGES.length; i++) {
for (uint256 i = 0; i < REFERRAL_BONUS_PERCENTAGES.length; i++) {
users[msg.sender].referralBonuses[i] = 0;
users[msg.sender].referralBonuses[i] = 0;
}
}


// Update total paid out
// Update total paid out
totalPaidOut = totalPaidOut.add(amount);
totalPaidOut = totalPaidOut.add(amount);


// Update user referral bonus withdrawn
// Update user referral bonus withdrawn
users[msg.sender].referralBonusWithdrawn = users[msg.sender].referralBonusWithdrawn.add(amount);
users[msg.sender].referralBonusWithdrawn = users[msg.sender].referralBonusWithdrawn.add(amount);


// Send referral bonus
// Send referral bonus
BUSDToken.transfer(address(msg.sender), amount);
BUSDToken.transfer(address(msg.sender), amount);


emit ReferralBonusClaimed(msg.sender, amount);
emit ReferralBonusClaimed(msg.sender, amount);
}
}


// --- Management functions ---
// --- Management functions ---
function addBeneficiary(address payable beneficiary) public onlyOwner {
function addBeneficiary(address payable beneficiary) public onlyOwner {
require(beneficiaries.length < MAXIMUM_BENEFICIARIES, "Maximum beneficiaries reached");
require(beneficiaries.length < MAXIMUM_BENEFICIARIES, "Maximum beneficiaries reached");
beneficiaries.push(beneficiary);
beneficiaries.push(beneficiary);


emit BeneficiaryAdded(beneficiary);
emit BeneficiaryAdded(beneficiary);
}
}


function removeBeneficiary(address payable beneficiary) public onlyOwner {
function removeBeneficiary(address payable beneficiary) public onlyOwner {
for (uint256 i = 0; i < beneficiaries.length; i++) {
for (uint256 i = 0; i < beneficiaries.length; i++) {
if (beneficiaries[i] == beneficiary) {
if (beneficiaries[i] == beneficiary) {
beneficiaries[i] = beneficiaries[beneficiaries.length - 1];
beneficiaries[i] = beneficiaries[beneficiaries.length - 1];
beneficiaries.pop();
beneficiaries.pop();
break;
break;
}
}
}
}


emit BeneficiaryRemoved(beneficiary);
emit BeneficiaryRemoved(beneficiary);
}
}


function setPlatformFeePercentage(uint256 platformFeePercentage) public onlyOwner {
function setPlatformFeePercentage(
require(platformFeePercentage <= PLATFORM_FEE_MAX_PERCENTAGE, "Platform fee percentage is too high");
PLATFORM_FEE_PERCENTAGE = platformFeePercentage;

emit PlatformFeeChanged(platformFeePercentage);
}

function transferUserDepositsAndRewards(address payable from, address payable to) public {
require(msg.sender == from, "Only user can transfer their deposits and rewards");
require(from != address(0), "Invalid from address");
require(to != address(0), "Invalid to address");
require(from != to, "From and to addresses are the same");

// Transfer deposits
for (uint256 i = 0; i < users[from].deposits.length; i++) {
users[to].deposits.push(users[from].deposits[i]);
}
delete users[from].deposits;

emit UserdataTransferred(from, to);
}

// --- Internal functions ---
function payPlatformFee(uint256 amount) internal returns (uint256) {
uint256 fee = amount.mul(PLATFORM_FEE_PERCENTAGE).div(PERCENTAGE_DIVISOR);

for (uint256 i = 0;