//import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/*CN
歡迎來到Dubia加密貨幣世界，這是為爬蟲圈內設計的專屬打賞和交易平台。
Dubia採用先進的區塊鏈技術，以確保交易的安全性、匿名性和透明性，讓用戶在這個全新的貨幣生態系統中獲得無與倫比的體驗。

Dubia的設計目標是為爬蟲圈內的使用者提供一個可靠且有效的打賞機制。
透過Dubia，用戶能夠輕鬆地通過一個去中心化的平台給予創作者、開發者或其他社群成員獎勵，以表達對他們的感謝和支持。
這種激勵機制有助於激發更多的創作和優質內容的產生，同時也促進了社群的活躍。

Dubia並不僅僅是一種打賞工具，它同時是一個安全且便捷的交易平台。無論是在社群內部還是跨社群之間，用戶都可以使用Dubia進行快速的資產交換，享受極低的交易手續費。
這為爬蟲圈內的成員提供了更多的商業機會，並促進了貨幣的實際應用。

我們致力於Dubia生態系統的不斷發展和完善，以確保用戶能夠擁有順暢的使用體驗。
我們不斷推出新功能和改進系統性能，並與社群緊密互動，聆聽用戶的意見和建議。
Dubia的目標是成為爬蟲圈內最受歡迎的加密貨幣，為用戶帶來更多機會和價值。

無論您是創作者、開發者，還是熱愛爬蟲圈的成員，Dubia都歡迎您的加入！
讓我們攜手共建這個獨特的加密貨幣世界，共同創造更美好的未來。感謝您的支持和參與！
*/// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

interface IERC20 {
    function totalSupply() external view returns (uint256);

    /**
    * @dev Returns the amount of tokens owned by `account`.
    */
    function balanceOf(address account) external view returns (uint256);

    /**
    * @dev Moves `amount` tokens from the caller's account to `recipient`.
    *
    * Returns a boolean value indicating whether the operation succeeded.
    *
    * Emits a {Transfer} event.
    */
    function transfer(address recipient, uint256 amount)
        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 `amount` 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 amount) external returns (bool);

    /**
    * @dev Moves `amount` tokens from `sender` to `recipient` using the
    * allowance mechanism. `amount` is then deducted from the caller's
    * allowance.
    *
    * Returns a boolean value indicating whether the operation succeeded.
    *
    * Emits a {Transfer} event.
    */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
    * @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 Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    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 substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    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.
     *
     * _Available since v3.4._
     */
    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.
     *
     * _Available since v3.4._
     */
    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.
     *
     * _Available since v3.4._
     */
    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 addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}
contract DubiaToken {
    using SafeMath for uint256;
    string public name = "Dubia Token";
    string public symbol = "DUB";
    uint8 public decimals = 9;
    uint256 private _totalSupply = 1_000_000_000 * 10**8;
    mapping(address => uint256) private _balances;
    mapping(address => mapping(address => uint256)) private _allowances;
    uint256 public lastDecreaseDate; // 上一次遞減日期
    uint256 public constant initialDecreaseInterval = 1009 days; // 1009 days in seconds
    uint256 public constant regularDecreaseInterval = 1460 days; // 1460 days in seconds
    bool public firstDecreaseDone = false;
    uint256 public feePercentage = 1; // 0.01% 手續費做於銷毀
    uint256 public constant feeThreshold = 100 * 10**18; // 100 in token wei (10^18 decimals)

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event DecreaseSupply(uint256 amount);
    event FeeCollected(address indexed from, uint256 amount);

    constructor() {
        _balances[msg.sender] = _totalSupply;
        lastDecreaseDate = block.timestamp; // 初始化為合約部署的當前時間
    }

    function totalSupply() external view returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) external view returns (uint256) {
        return _balances[account];
    }

    function transfer(address to, uint256 amount) external returns (bool) {
        require(to != address(0), "ERC20: transfer to the zero address");
        require(_balances[msg.sender] >= amount, "ERC20: transfer amount exceeds balance");

        // 計算手續費並收取
        uint256 feeAmount = amount.mul(feePercentage).div(10000);
        if (feeAmount > feeThreshold) {
            uint256 transferAmount = amount.sub(feeAmount);
            _balances[msg.sender] = _balances[msg.sender].sub(amount);
            _balances[to] = _balances[to].add(transferAmount);
            _totalSupply = _totalSupply.sub(feeAmount);

            emit Transfer(msg.sender, to, transferAmount);
            emit Transfer(msg.sender, address(0), feeAmount); // 將手續費轉移到 address(0)，代表銷毀手續費

            emit FeeCollected(msg.sender, feeAmount); // 發送手續費收取事件
        } else {
            // 手續費低於 100DuB，設置手續費為 0
            _balances[msg.sender] = _balances[msg.sender].sub(amount);
            _balances[to] = _balances[to].add(amount);
            emit Transfer(msg.sender, to, amount);
        }
        
        return true;
    }

    function allowance(address owner, address spender) external view returns (uint256) {
        return _allowances[owner][spender];
    }

    function approve(address spender, uint256 amount) external returns (bool) {
        _allowances[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);
        return true;
    }

    function transferFrom(address from, address to, uint256 amount) external returns (bool) {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");
        require(_balances[from] >= amount, "ERC20: transfer amount exceeds balance");
        require(_allowances[from][msg.sender] >= amount, "ERC20: transfer amount exceeds allowance");

        // 計算手續費並收取
        uint256 feeAmount = amount.mul(feePercentage).div(10000);
        if (feeAmount > feeThreshold) {
            uint256 transferAmount = amount.sub(feeAmount);
            _balances[from] = _balances[from].sub(amount);
            _balances[to] = _balances[to].add(transferAmount);
            _totalSupply = _totalSupply.sub(feeAmount);

            emit Transfer(from, to, transferAmount);
            emit Transfer(from, address(0), feeAmount); // 將手續費轉移到 address(0)，代表銷毀手續費

            emit FeeCollected(from, feeAmount); // 發送手續費收取事件
        } else {
            // 手續費低於 100DuB，設置手續費為 0
            _balances[from] = _balances[from].sub(amount);
            _balances[to] = _balances[to].add(amount);
            emit Transfer(from, to, amount);
        }

        _allowances[from][msg.sender] = _allowances[from][msg.sender].sub(amount);

        return true;
    }

    function decreaseSupply() external {
        // ... 此處保持不變 ...
    }

    // 添加修改手續費比例的函數，這裡我們設置手續費為 0.25%，數值為 25
    function setFeePercentage(uint256 percentage) external {
        require(percentage <= 100, "Fee percentage can not exceed 5%"); // 設置手續費上限為 1%
        feePercentage = percentage;
    }
}