ETH Price: $2,658.74 (+0.91%)

Transaction Decoder

Block:
20904777 at Oct-06-2024 06:39:35 AM +UTC
Transaction Fee:
0.005404060399982087 ETH $14.37
Gas Used:
1,487,921 Gas / 3.631953847 Gwei

Emitted Events:

302 Sustainix_Renewable.Transfer( from=[Sender] 0x31585060788ddf05100b87360f01601e8567754c, to=0x703A70817d8E22a417A28BaaAF418Fc3E92a1c68, value=800000000000000000000000000 )
303 ERC1967Proxy.0x2748f43926a5baf523e4d17bfb6663eed7f32c37493d6fc94fb213773900e5e0( 0x2748f43926a5baf523e4d17bfb6663eed7f32c37493d6fc94fb213773900e5e0, 0x000000000000000000000000703a70817d8e22a417a28baaaf418fc3e92a1c68, 0000000000000000000000000000000000000000000000000000000000000000 )
304 0x703a70817d8e22a417a28baaaf418fc3e92a1c68.0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498( 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498, 0000000000000000000000000000000000000000000000000000000000000001 )
305 0x74c6236f7cc3fdcea1518eac212ad67d6dfa0ee2.0x4f2ce4e40f623ca765fc0167a25cb7842ceaafb8d82d3dec26ca0d0e0d2d4896( 0x4f2ce4e40f623ca765fc0167a25cb7842ceaafb8d82d3dec26ca0d0e0d2d4896, 0x00000000000000000000000031585060788ddf05100b87360f01601e8567754c, 0x000000000000000000000000703a70817d8e22a417a28baaaf418fc3e92a1c68 )

Account State Difference:

  Address   Before After State Difference Code
0x135aCfcC...4d2a7d524
0x31585060...E8567754C
0.286855281394222711 Eth
Nonce: 5
0.081451220994240624 Eth
Nonce: 6
0.205404060399982087
(Titan Builder)
14.186044955971632169 Eth14.187142184811638373 Eth0.001097228840006204
0x4B04213C...116D00508 0.329289233312682525 Eth0.529289233312682525 Eth0.2
0x703A7081...3E92a1c68
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 497590261154554171967157405296499048389181317191392310512854721740248519189122157640769527261419965058472947
0x74c6236f...d6DfA0eE2
0xAd574c1B...f8040dD2d

Execution Trace

ETH 0.2 0x74c6236f7cc3fdcea1518eac212ad67d6dfa0ee2.43a9f684( )
  • ETH 0.2 0x4b04213c2774f77e60702880654206b116d00508.CALL( )
  • 0x703a70817d8e22a417a28baaaf418fc3e92a1c68.3d602d80( )
  • 0x703a70817d8e22a417a28baaaf418fc3e92a1c68.STATICCALL( )
    • 0xaecf9f09dd43cfb5b0bc0b6504928bdea346a4ba.DELEGATECALL( )
    • 0xad574c1b36cb5f03eb471a9501c4ccff8040dd2d.ad36b16b( )
    • Sustainix_Renewable.balanceOf( account=0x31585060788dDf05100B87360F01601E8567754C ) => ( 10000000000000000000000000000 )
    • Sustainix_Renewable.allowance( owner=0x31585060788dDf05100B87360F01601E8567754C, spender=0x74c6236f7cc3FDCeA1518EAc212ad67d6DfA0eE2 ) => ( 800000000000000000000000000 )
    • Sustainix_Renewable.transferFrom( from=0x31585060788dDf05100B87360F01601E8567754C, to=0x703A70817d8E22a417A28BaaAF418Fc3E92a1c68, value=800000000000000000000000000 ) => ( True )
    • Sustainix_Renewable.balanceOf( account=0x703A70817d8E22a417A28BaaAF418Fc3E92a1c68 ) => ( 800000000000000000000000000 )
    • 0x703a70817d8e22a417a28baaaf418fc3e92a1c68.df684630( )
      • 0xaecf9f09dd43cfb5b0bc0b6504928bdea346a4ba.df684630( )
        • 0x5a7c88b40eb08c8c903cb0ebf0990d86f3c6f742.a5734f0a( )
        • ERC1967Proxy.84147029( )
          • 0xe01b2ae8eddbd071da55dc889065c46cbd93383d.84147029( )
            • 0xad574c1b36cb5f03eb471a9501c4ccff8040dd2d.7420c31f( )
              File 1 of 2: Sustainix_Renewable
              /*
              #####################################
              Token generated with ❤️ on 20lab.app
              #####################################
              */
              // SPDX-License-Identifier: No License
              pragma solidity 0.8.25;
              import {IERC20, ERC20} from "./ERC20.sol";
              import {ERC20Burnable} from "./ERC20Burnable.sol";
              import {Ownable, Ownable2Step} from "./Ownable2Step.sol";
              import {SafeERC20Remastered} from "./SafeERC20Remastered.sol";
              import {Initializable} from "./Initializable.sol";
              import "./IUniswapV2Factory.sol";
              import "./IUniswapV2Pair.sol";
              import "./IUniswapV2Router01.sol";
              import "./IUniswapV2Router02.sol";
              contract Sustainix_Renewable is ERC20, ERC20Burnable, Ownable2Step, Initializable {
                  
                  using SafeERC20Remastered for IERC20;
               
                  uint16 public swapThresholdRatio;
                  
                  uint256 private _researchPending;
                  uint256 private _liquidityPending;
                  address public researchAddress;
                  uint16[3] public researchFees;
                  uint16[3] public liquidityFees;
                  mapping (address => bool) public isExcludedFromFees;
                  uint16[3] public totalFees;
                  bool private _swapping;
                  IUniswapV2Router02 public routerV2;
                  address public pairV2;
                  mapping (address => bool) public AMMs;
                  mapping (address => bool) public isExcludedFromLimits;
                  uint256 public maxBuyAmount;
                  uint256 public maxSellAmount;
                  mapping (address => uint256) public lastTrade;
                  uint256 public tradeCooldownTime;
               
                  error InvalidAmountToRecover(uint256 amount, uint256 maxAmount);
                  error InvalidToken(address tokenAddress);
                  error CannotDepositNativeCoins(address account);
                  error InvalidSwapThresholdRatio(uint16 swapThresholdRatio);
                  error InvalidTaxRecipientAddress(address account);
                  error CannotExceedMaxTotalFee(uint16 buyFee, uint16 sellFee, uint16 transferFee);
                  error InvalidAMM(address AMM);
                  error MaxTransactionAmountTooLow(uint256 maxAmount, uint256 limit);
                  error CannotExceedMaxTransactionAmount(uint256 maxAmount);
                  error InvalidTradeCooldownTime(uint256 tradeCooldownTime);
                  error AddressInCooldown(address account);
               
                  event SwapThresholdUpdated(uint16 swapThresholdRatio);
                  event WalletTaxAddressUpdated(uint8 indexed id, address newAddress);
                  event WalletTaxFeesUpdated(uint8 indexed id, uint16 buyFee, uint16 sellFee, uint16 transferFee);
                  event WalletTaxSent(uint8 indexed id, address recipient, uint256 amount);
                  event LiquidityFeesUpdated(uint16 buyFee, uint16 sellFee, uint16 transferFee);
                  event LiquidityAdded(uint amountToken, uint amountCoin, uint liquidity);
                  event ForceLiquidityAdded(uint256 leftoverTokens, uint256 unaddedTokens);
                  event ExcludeFromFees(address indexed account, bool isExcluded);
                  event RouterV2Updated(address indexed routerV2);
                  event AMMUpdated(address indexed AMM, bool isAMM);
                  event ExcludeFromLimits(address indexed account, bool isExcluded);
                  event MaxBuyAmountUpdated(uint256 maxBuyAmount);
                  event MaxSellAmountUpdated(uint256 maxSellAmount);
                  event TradeCooldownTimeUpdated(uint256 tradeCooldownTime);
               
                  constructor()
                      ERC20(unicode"Sustainix Renewable", unicode"SXR")
                      Ownable(msg.sender)
                  {
                      address supplyRecipient = 0x31585060788dDf05100B87360F01601E8567754C;
                      
                      updateSwapThreshold(50);
                      researchAddressSetup(0x690615f7fF1e0109bCC6b046C4617Ddbd8C04Ca8);
                      researchFeesSetup(100, 100, 0);
                      liquidityFeesSetup(50, 50, 0);
                      excludeFromFees(supplyRecipient, true);
                      excludeFromFees(address(this), true); 
                      _excludeFromLimits(supplyRecipient, true);
                      _excludeFromLimits(address(this), true);
                      _excludeFromLimits(address(0), true); 
                      updateMaxBuyAmount(500000000 * (10 ** decimals()) / 10);
                      updateMaxSellAmount(300000000 * (10 ** decimals()) / 10);
                      updateTradeCooldownTime(1800);
                      _mint(supplyRecipient, 100000000000 * (10 ** decimals()) / 10);
                      _transferOwnership(0x31585060788dDf05100B87360F01601E8567754C);
                  }
                  
                  /*
                      This token is not upgradeable. Function afterConstructor finishes post-deployment setup.
                  */
                  function afterConstructor(address _router) initializer external {
                      _updateRouterV2(_router);
                  }
                  function decimals() public pure override returns (uint8) {
                      return 18;
                  }
                  
                  function recoverToken(uint256 amount) external onlyOwner {
                      uint256 maxRecoverable = balanceOf(address(this)) - getAllPending();
                      if (amount > maxRecoverable) revert InvalidAmountToRecover(amount, maxRecoverable);
                      _update(address(this), msg.sender, amount);
                  }
                  function recoverForeignERC20(address tokenAddress, uint256 amount) external onlyOwner {
                      if (tokenAddress == address(this)) revert InvalidToken(tokenAddress);
                      IERC20(tokenAddress).safeTransfer(msg.sender, amount);
                  }
                  // Prevent unintended coin transfers
                  receive() external payable {
                      if (msg.sender != address(routerV2)) revert CannotDepositNativeCoins(msg.sender);
                  }
                  function _swapTokensForCoin(uint256 tokenAmount) private {
                      address[] memory path = new address[](2);
                      path[0] = address(this);
                      path[1] = routerV2.WETH();
                      _approve(address(this), address(routerV2), tokenAmount);
                      routerV2.swapExactTokensForETHSupportingFeeOnTransferTokens(tokenAmount, 0, path, address(this), block.timestamp);
                  }
                  function updateSwapThreshold(uint16 _swapThresholdRatio) public onlyOwner {
                      if (_swapThresholdRatio == 0 || _swapThresholdRatio > 500) revert InvalidSwapThresholdRatio(_swapThresholdRatio);
                      swapThresholdRatio = _swapThresholdRatio;
                      
                      emit SwapThresholdUpdated(_swapThresholdRatio);
                  }
                  function getSwapThresholdAmount() public view returns (uint256) {
                      return balanceOf(pairV2) * swapThresholdRatio / 10000;
                  }
                  function getAllPending() public view returns (uint256) {
                      return 0 + _researchPending + _liquidityPending;
                  }
                  function researchAddressSetup(address _newAddress) public onlyOwner {
                      if (_newAddress == address(0)) revert InvalidTaxRecipientAddress(address(0));
                      researchAddress = _newAddress;
                      excludeFromFees(_newAddress, true);
                      _excludeFromLimits(_newAddress, true);
                      emit WalletTaxAddressUpdated(1, _newAddress);
                  }
                  function researchFeesSetup(uint16 _buyFee, uint16 _sellFee, uint16 _transferFee) public onlyOwner {
                      totalFees[0] = totalFees[0] - researchFees[0] + _buyFee;
                      totalFees[1] = totalFees[1] - researchFees[1] + _sellFee;
                      totalFees[2] = totalFees[2] - researchFees[2] + _transferFee;
                      if (totalFees[0] > 2500 || totalFees[1] > 2500 || totalFees[2] > 2500) revert CannotExceedMaxTotalFee(totalFees[0], totalFees[1], totalFees[2]);
                      researchFees = [_buyFee, _sellFee, _transferFee];
                      emit WalletTaxFeesUpdated(1, _buyFee, _sellFee, _transferFee);
                  }
                  function _swapAndLiquify(uint256 tokenAmount) private returns (uint256 leftover) {
                      // Sub-optimal method for supplying liquidity
                      uint256 halfAmount = tokenAmount / 2;
                      uint256 otherHalf = tokenAmount - halfAmount;
                      _swapTokensForCoin(halfAmount);
                      uint256 coinBalance = address(this).balance;
                      if (coinBalance > 0) {
                          (uint amountToken, uint amountCoin, uint liquidity) = _addLiquidity(otherHalf, coinBalance);
                          emit LiquidityAdded(amountToken, amountCoin, liquidity);
                          return otherHalf - amountToken;
                      } else {
                          return otherHalf;
                      }
                  }
                  function _addLiquidity(uint256 tokenAmount, uint256 coinAmount) private returns (uint, uint, uint) {
                      _approve(address(this), address(routerV2), tokenAmount);
                      return routerV2.addLiquidityETH{value: coinAmount}(address(this), tokenAmount, 0, 0, address(0), block.timestamp);
                  }
                  function addLiquidityFromLeftoverTokens() external {
                      uint256 leftoverTokens = balanceOf(address(this)) - getAllPending();
                      uint256 unaddedTokens = _swapAndLiquify(leftoverTokens);
                      emit ForceLiquidityAdded(leftoverTokens, unaddedTokens);
                  }
                  function liquidityFeesSetup(uint16 _buyFee, uint16 _sellFee, uint16 _transferFee) public onlyOwner {
                      totalFees[0] = totalFees[0] - liquidityFees[0] + _buyFee;
                      totalFees[1] = totalFees[1] - liquidityFees[1] + _sellFee;
                      totalFees[2] = totalFees[2] - liquidityFees[2] + _transferFee;
                      if (totalFees[0] > 2500 || totalFees[1] > 2500 || totalFees[2] > 2500) revert CannotExceedMaxTotalFee(totalFees[0], totalFees[1], totalFees[2]);
                      liquidityFees = [_buyFee, _sellFee, _transferFee];
                      emit LiquidityFeesUpdated(_buyFee, _sellFee, _transferFee);
                  }
                  function excludeFromFees(address account, bool isExcluded) public onlyOwner {
                      isExcludedFromFees[account] = isExcluded;
                      
                      emit ExcludeFromFees(account, isExcluded);
                  }
                  function _updateRouterV2(address router) private {
                      routerV2 = IUniswapV2Router02(router);
                      pairV2 = IUniswapV2Factory(routerV2.factory()).createPair(address(this), routerV2.WETH());
                      
                      _setAMM(router, true);
                      _setAMM(pairV2, true);
                      emit RouterV2Updated(router);
                  }
                  function setAMM(address AMM, bool isAMM) external onlyOwner {
                      if (AMM == pairV2 || AMM == address(routerV2)) revert InvalidAMM(AMM);
                      _setAMM(AMM, isAMM);
                  }
                  function _setAMM(address AMM, bool isAMM) private {
                      AMMs[AMM] = isAMM;
                      if (isAMM) { 
                          _excludeFromLimits(AMM, true);
                      }
                      emit AMMUpdated(AMM, isAMM);
                  }
                  function excludeFromLimits(address account, bool isExcluded) external onlyOwner {
                      _excludeFromLimits(account, isExcluded);
                  }
                  function _excludeFromLimits(address account, bool isExcluded) internal {
                      isExcludedFromLimits[account] = isExcluded;
                      emit ExcludeFromLimits(account, isExcluded);
                  }
                  function _maxTxSafeLimit() private view returns (uint256) {
                      return totalSupply() * 5 / 10000;
                  }
                  function updateMaxBuyAmount(uint256 _maxBuyAmount) public onlyOwner {
                      if (_maxBuyAmount < _maxTxSafeLimit()) revert MaxTransactionAmountTooLow(_maxBuyAmount, _maxTxSafeLimit());
                      maxBuyAmount = _maxBuyAmount;
                      
                      emit MaxBuyAmountUpdated(_maxBuyAmount);
                  }
                  function updateMaxSellAmount(uint256 _maxSellAmount) public onlyOwner {
                      if (_maxSellAmount < _maxTxSafeLimit()) revert MaxTransactionAmountTooLow(_maxSellAmount, _maxTxSafeLimit());
                      maxSellAmount = _maxSellAmount;
                      
                      emit MaxSellAmountUpdated(_maxSellAmount);
                  }
                  function updateTradeCooldownTime(uint256 _tradeCooldownTime) public onlyOwner {
                      if (_tradeCooldownTime > 12 hours) revert InvalidTradeCooldownTime(_tradeCooldownTime);
                          
                      tradeCooldownTime = _tradeCooldownTime;
                      
                      emit TradeCooldownTimeUpdated(_tradeCooldownTime);
                  }
                  function _update(address from, address to, uint256 amount)
                      internal
                      override
                  {
                      _beforeTokenUpdate(from, to, amount);
                      
                      if (from != address(0) && to != address(0)) {
                          if (!_swapping && amount > 0 && !isExcludedFromFees[from] && !isExcludedFromFees[to]) {
                              uint256 fees = 0;
                              uint8 txType = 3;
                              
                              if (AMMs[from] && !AMMs[to]) {
                                  if (totalFees[0] > 0) txType = 0;
                              }
                              else if (AMMs[to] && !AMMs[from]) {
                                  if (totalFees[1] > 0) txType = 1;
                              }
                              else if (!AMMs[from] && !AMMs[to]) {
                                  if (totalFees[2] > 0) txType = 2;
                              }
                              
                              if (txType < 3) {
                                  
                                  fees = amount * totalFees[txType] / 10000;
                                  amount -= fees;
                                  
                                  _researchPending += fees * researchFees[txType] / totalFees[txType];
                                  _liquidityPending += fees * liquidityFees[txType] / totalFees[txType];
                                  
                              }
                              if (fees > 0) {
                                  super._update(from, address(this), fees);
                              }
                          }
                          
                          bool canSwap = getAllPending() >= getSwapThresholdAmount() && balanceOf(pairV2) > 0;
                          
                          if (!_swapping && from != pairV2 && from != address(routerV2) && canSwap) {
                              _swapping = true;
                              
                              if (false || _researchPending > 0) {
                                  uint256 token2Swap = 0 + _researchPending;
                                  bool success = false;
                                  _swapTokensForCoin(token2Swap);
                                  uint256 coinsReceived = address(this).balance;
                                  
                                  uint256 researchPortion = coinsReceived * _researchPending / token2Swap;
                                  if (researchPortion > 0) {
                                      (success,) = payable(researchAddress).call{value: researchPortion}("");
                                      if (success) {
                                          emit WalletTaxSent(1, researchAddress, researchPortion);
                                      }
                                  }
                                  _researchPending = 0;
                              }
                              if (_liquidityPending > 0) {
                                  _swapAndLiquify(_liquidityPending);
                                  _liquidityPending = 0;
                              }
                              _swapping = false;
                          }
                      }
                      super._update(from, to, amount);
                      
                      _afterTokenUpdate(from, to, amount);
                      
                  }
                  function _beforeTokenUpdate(address from, address to, uint256 amount)
                      internal
                      view
                  {
                      if (AMMs[from] && !isExcludedFromLimits[to] && amount > maxBuyAmount) { // BUY
                          revert CannotExceedMaxTransactionAmount(maxBuyAmount);
                      }
                  
                      if (AMMs[to] && !isExcludedFromLimits[from] && amount > maxSellAmount) { // SELL
                          revert CannotExceedMaxTransactionAmount(maxSellAmount);
                      }
                  
                      if(!isExcludedFromLimits[from] && lastTrade[from] + tradeCooldownTime > block.timestamp) revert AddressInCooldown(from);
                      if(!isExcludedFromLimits[to] && lastTrade[to] + tradeCooldownTime > block.timestamp) revert AddressInCooldown(to);
                  }
                  function _afterTokenUpdate(address from, address to, uint256 amount)
                      internal
                  {
                      if (AMMs[from] && !isExcludedFromLimits[to]) lastTrade[to] = block.timestamp;
                      else if (AMMs[to] && !isExcludedFromLimits[from]) lastTrade[from] = block.timestamp;
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
              pragma solidity ^0.8.20;
              import {IERC20} from "./IERC20.sol";
              import {IERC20Metadata} from "./IERC20Metadata.sol";
              import {Context} from "./Context.sol";
              import {IERC20Errors} from "./draft-IERC6093.sol";
              /**
               * @dev Implementation of the {IERC20} interface.
               *
               * This implementation is agnostic to the way tokens are created. This means
               * that a supply mechanism has to be added in a derived contract using {_mint}.
               *
               * TIP: For a detailed writeup see our guide
               * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
               * to implement supply mechanisms].
               *
               * The default value of {decimals} is 18. To change this, you should override
               * this function so it returns a different value.
               *
               * We have followed general OpenZeppelin Contracts guidelines: functions revert
               * instead returning `false` on failure. This behavior is nonetheless
               * conventional and does not conflict with the expectations of ERC20
               * applications.
               *
               * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
               * This allows applications to reconstruct the allowance for all accounts just
               * by listening to said events. Other implementations of the EIP may not emit
               * these events, as it isn't required by the specification.
               */
              abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
                  mapping(address account => uint256) private _balances;
                  mapping(address account => mapping(address spender => uint256)) private _allowances;
                  uint256 private _totalSupply;
                  string private _name;
                  string private _symbol;
                  /**
                   * @dev Sets the values for {name} and {symbol}.
                   *
                   * All two of these values are immutable: they can only be set once during
                   * construction.
                   */
                  constructor(string memory name_, string memory symbol_) {
                      _name = name_;
                      _symbol = symbol_;
                  }
                  /**
                   * @dev Returns the name of the token.
                   */
                  function name() public view virtual returns (string memory) {
                      return _name;
                  }
                  /**
                   * @dev Returns the symbol of the token, usually a shorter version of the
                   * name.
                   */
                  function symbol() public view virtual returns (string memory) {
                      return _symbol;
                  }
                  /**
                   * @dev Returns the number of decimals used to get its user representation.
                   * For example, if `decimals` equals `2`, a balance of `505` tokens should
                   * be displayed to a user as `5.05` (`505 / 10 ** 2`).
                   *
                   * Tokens usually opt for a value of 18, imitating the relationship between
                   * Ether and Wei. This is the default value returned by this function, unless
                   * it's overridden.
                   *
                   * NOTE: This information is only used for _display_ purposes: it in
                   * no way affects any of the arithmetic of the contract, including
                   * {IERC20-balanceOf} and {IERC20-transfer}.
                   */
                  function decimals() public view virtual returns (uint8) {
                      return 18;
                  }
                  /**
                   * @dev See {IERC20-totalSupply}.
                   */
                  function totalSupply() public view virtual returns (uint256) {
                      return _totalSupply;
                  }
                  /**
                   * @dev See {IERC20-balanceOf}.
                   */
                  function balanceOf(address account) public view virtual returns (uint256) {
                      return _balances[account];
                  }
                  /**
                   * @dev See {IERC20-transfer}.
                   *
                   * Requirements:
                   *
                   * - `to` cannot be the zero address.
                   * - the caller must have a balance of at least `value`.
                   */
                  function transfer(address to, uint256 value) public virtual returns (bool) {
                      address owner = _msgSender();
                      _transfer(owner, to, value);
                      return true;
                  }
                  /**
                   * @dev See {IERC20-allowance}.
                   */
                  function allowance(address owner, address spender) public view virtual returns (uint256) {
                      return _allowances[owner][spender];
                  }
                  /**
                   * @dev See {IERC20-approve}.
                   *
                   * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
                   * `transferFrom`. This is semantically equivalent to an infinite approval.
                   *
                   * Requirements:
                   *
                   * - `spender` cannot be the zero address.
                   */
                  function approve(address spender, uint256 value) public virtual returns (bool) {
                      address owner = _msgSender();
                      _approve(owner, spender, value);
                      return true;
                  }
                  /**
                   * @dev See {IERC20-transferFrom}.
                   *
                   * Emits an {Approval} event indicating the updated allowance. This is not
                   * required by the EIP. See the note at the beginning of {ERC20}.
                   *
                   * NOTE: Does not update the allowance if the current allowance
                   * is the maximum `uint256`.
                   *
                   * Requirements:
                   *
                   * - `from` and `to` cannot be the zero address.
                   * - `from` must have a balance of at least `value`.
                   * - the caller must have allowance for ``from``'s tokens of at least
                   * `value`.
                   */
                  function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
                      address spender = _msgSender();
                      _spendAllowance(from, spender, value);
                      _transfer(from, to, value);
                      return true;
                  }
                  /**
                   * @dev Moves a `value` amount of tokens from `from` to `to`.
                   *
                   * This internal function is equivalent to {transfer}, and can be used to
                   * e.g. implement automatic token fees, slashing mechanisms, etc.
                   *
                   * Emits a {Transfer} event.
                   *
                   * NOTE: This function is not virtual, {_update} should be overridden instead.
                   */
                  function _transfer(address from, address to, uint256 value) internal {
                      if (from == address(0)) {
                          revert ERC20InvalidSender(address(0));
                      }
                      if (to == address(0)) {
                          revert ERC20InvalidReceiver(address(0));
                      }
                      _update(from, to, value);
                  }
                  /**
                   * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
                   * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
                   * this function.
                   *
                   * Emits a {Transfer} event.
                   */
                  function _update(address from, address to, uint256 value) internal virtual {
                      if (from == address(0)) {
                          // Overflow check required: The rest of the code assumes that totalSupply never overflows
                          _totalSupply += value;
                      } else {
                          uint256 fromBalance = _balances[from];
                          if (fromBalance < value) {
                              revert ERC20InsufficientBalance(from, fromBalance, value);
                          }
                          unchecked {
                              // Overflow not possible: value <= fromBalance <= totalSupply.
                              _balances[from] = fromBalance - value;
                          }
                      }
                      if (to == address(0)) {
                          unchecked {
                              // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                              _totalSupply -= value;
                          }
                      } else {
                          unchecked {
                              // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                              _balances[to] += value;
                          }
                      }
                      emit Transfer(from, to, value);
                  }
                  /**
                   * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
                   * Relies on the `_update` mechanism
                   *
                   * Emits a {Transfer} event with `from` set to the zero address.
                   *
                   * NOTE: This function is not virtual, {_update} should be overridden instead.
                   */
                  function _mint(address account, uint256 value) internal {
                      if (account == address(0)) {
                          revert ERC20InvalidReceiver(address(0));
                      }
                      _update(address(0), account, value);
                  }
                  /**
                   * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
                   * Relies on the `_update` mechanism.
                   *
                   * Emits a {Transfer} event with `to` set to the zero address.
                   *
                   * NOTE: This function is not virtual, {_update} should be overridden instead
                   */
                  function _burn(address account, uint256 value) internal {
                      if (account == address(0)) {
                          revert ERC20InvalidSender(address(0));
                      }
                      _update(account, address(0), value);
                  }
                  /**
                   * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
                   *
                   * This internal function is equivalent to `approve`, and can be used to
                   * e.g. set automatic allowances for certain subsystems, etc.
                   *
                   * Emits an {Approval} event.
                   *
                   * Requirements:
                   *
                   * - `owner` cannot be the zero address.
                   * - `spender` cannot be the zero address.
                   *
                   * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
                   */
                  function _approve(address owner, address spender, uint256 value) internal {
                      _approve(owner, spender, value, true);
                  }
                  /**
                   * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
                   *
                   * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
                   * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
                   * `Approval` event during `transferFrom` operations.
                   *
                   * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
                   * true using the following override:
                   * ```
                   * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
                   *     super._approve(owner, spender, value, true);
                   * }
                   * ```
                   *
                   * Requirements are the same as {_approve}.
                   */
                  function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
                      if (owner == address(0)) {
                          revert ERC20InvalidApprover(address(0));
                      }
                      if (spender == address(0)) {
                          revert ERC20InvalidSpender(address(0));
                      }
                      _allowances[owner][spender] = value;
                      if (emitEvent) {
                          emit Approval(owner, spender, value);
                      }
                  }
                  /**
                   * @dev Updates `owner` s allowance for `spender` based on spent `value`.
                   *
                   * Does not update the allowance value in case of infinite allowance.
                   * Revert if not enough allowance is available.
                   *
                   * Does not emit an {Approval} event.
                   */
                  function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
                      uint256 currentAllowance = allowance(owner, spender);
                      if (currentAllowance != type(uint256).max) {
                          if (currentAllowance < value) {
                              revert ERC20InsufficientAllowance(spender, currentAllowance, value);
                          }
                          unchecked {
                              _approve(owner, spender, currentAllowance - value, false);
                          }
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol)
              pragma solidity ^0.8.20;
              import {ERC20} from "./ERC20.sol";
              import {Context} from "./Context.sol";
              /**
               * @dev Extension of {ERC20} that allows token holders to destroy both their own
               * tokens and those that they have an allowance for, in a way that can be
               * recognized off-chain (via event analysis).
               */
              abstract contract ERC20Burnable is Context, ERC20 {
                  /**
                   * @dev Destroys a `value` amount of tokens from the caller.
                   *
                   * See {ERC20-_burn}.
                   */
                  function burn(uint256 value) public virtual {
                      _burn(_msgSender(), value);
                  }
                  /**
                   * @dev Destroys a `value` amount of tokens from `account`, deducting from
                   * the caller's allowance.
                   *
                   * See {ERC20-_burn} and {ERC20-allowance}.
                   *
                   * Requirements:
                   *
                   * - the caller must have allowance for ``accounts``'s tokens of at least
                   * `value`.
                   */
                  function burnFrom(address account, uint256 value) public virtual {
                      _spendAllowance(account, _msgSender(), value);
                      _burn(account, value);
                  }
              }
              // 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
              // Remastered from OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
              pragma solidity ^0.8.20;
              import {IERC20} from "./IERC20.sol";
              import {Address} from "./Address.sol";
              library SafeERC20Remastered {
                  using Address for address;
                  /**
                   * @dev An operation with an ERC20 token failed.
                   */
                  error SafeERC20FailedOperation(address token);
                  /**
                   * @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 the calling contract to `to`. If `token` returns no value,
                   * non-reverting calls are assumed to be successful.
                   */
                  function safeTransfer_noRevert(IERC20 token, address to, uint256 value) internal returns (bool) {
                      return _callOptionalReturnBool(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 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
              pragma solidity ^0.8.19;
              abstract contract Initializable {
                  /**
                   * @dev Indicates that the contract has been initialized.
                   */
                  bool private _initialized;
                  /**
                   * @dev Indicates that the contract is in the process of being initialized.
                   */
                  bool private _initializing;
                  /**
                   * @dev Modifier to protect an initializer function from being invoked twice.
                   */
                  modifier initializer() {
                      require(_initializing || !_initialized, "Initializable: contract is already initialized");
                      bool isTopLevelCall = !_initializing;
                      if (isTopLevelCall) {
                          _initializing = true;
                          _initialized = true;
                      }
                      _;
                      if (isTopLevelCall) {
                          _initializing = false;
                      }
                  }
              }pragma solidity >=0.5.0;
              interface IUniswapV2Factory {
                  event PairCreated(address indexed token0, address indexed token1, address pair, uint);
                  function feeTo() external view returns (address);
                  function feeToSetter() external view returns (address);
                  function getPair(address tokenA, address tokenB) external view returns (address pair);
                  function allPairs(uint) external view returns (address pair);
                  function allPairsLength() external view returns (uint);
                  function createPair(address tokenA, address tokenB) external returns (address pair);
                  function setFeeTo(address) external;
                  function setFeeToSetter(address) external;
              }
              pragma solidity >=0.5.0;
              interface IUniswapV2Pair {
                  event Approval(address indexed owner, address indexed spender, uint value);
                  event Transfer(address indexed from, address indexed to, uint value);
                  function name() external pure returns (string memory);
                  function symbol() external pure returns (string memory);
                  function decimals() external pure returns (uint8);
                  function totalSupply() external view returns (uint);
                  function balanceOf(address owner) external view returns (uint);
                  function allowance(address owner, address spender) external view returns (uint);
                  function approve(address spender, uint value) external returns (bool);
                  function transfer(address to, uint value) external returns (bool);
                  function transferFrom(address from, address to, uint value) external returns (bool);
                  function DOMAIN_SEPARATOR() external view returns (bytes32);
                  function PERMIT_TYPEHASH() external pure returns (bytes32);
                  function nonces(address owner) external view returns (uint);
                  function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
                  event Mint(address indexed sender, uint amount0, uint amount1);
                  event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
                  event Swap(
                      address indexed sender,
                      uint amount0In,
                      uint amount1In,
                      uint amount0Out,
                      uint amount1Out,
                      address indexed to
                  );
                  event Sync(uint112 reserve0, uint112 reserve1);
                  function MINIMUM_LIQUIDITY() external pure returns (uint);
                  function factory() external view returns (address);
                  function token0() external view returns (address);
                  function token1() external view returns (address);
                  function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
                  function price0CumulativeLast() external view returns (uint);
                  function price1CumulativeLast() external view returns (uint);
                  function kLast() external view returns (uint);
                  function mint(address to) external returns (uint liquidity);
                  function burn(address to) external returns (uint amount0, uint amount1);
                  function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
                  function skim(address to) external;
                  function sync() external;
                  function initialize(address, address) external;
              }
              pragma solidity >=0.6.2;
              interface IUniswapV2Router01 {
                  function factory() external pure returns (address);
                  function WETH() external pure returns (address);
                  function addLiquidity(
                      address tokenA,
                      address tokenB,
                      uint amountADesired,
                      uint amountBDesired,
                      uint amountAMin,
                      uint amountBMin,
                      address to,
                      uint deadline
                  ) external returns (uint amountA, uint amountB, uint liquidity);
                  function addLiquidityETH(
                      address token,
                      uint amountTokenDesired,
                      uint amountTokenMin,
                      uint amountETHMin,
                      address to,
                      uint deadline
                  ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
                  function removeLiquidity(
                      address tokenA,
                      address tokenB,
                      uint liquidity,
                      uint amountAMin,
                      uint amountBMin,
                      address to,
                      uint deadline
                  ) external returns (uint amountA, uint amountB);
                  function removeLiquidityETH(
                      address token,
                      uint liquidity,
                      uint amountTokenMin,
                      uint amountETHMin,
                      address to,
                      uint deadline
                  ) external returns (uint amountToken, uint amountETH);
                  function removeLiquidityWithPermit(
                      address tokenA,
                      address tokenB,
                      uint liquidity,
                      uint amountAMin,
                      uint amountBMin,
                      address to,
                      uint deadline,
                      bool approveMax, uint8 v, bytes32 r, bytes32 s
                  ) external returns (uint amountA, uint amountB);
                  function removeLiquidityETHWithPermit(
                      address token,
                      uint liquidity,
                      uint amountTokenMin,
                      uint amountETHMin,
                      address to,
                      uint deadline,
                      bool approveMax, uint8 v, bytes32 r, bytes32 s
                  ) external returns (uint amountToken, uint amountETH);
                  function swapExactTokensForTokens(
                      uint amountIn,
                      uint amountOutMin,
                      address[] calldata path,
                      address to,
                      uint deadline
                  ) external returns (uint[] memory amounts);
                  function swapTokensForExactTokens(
                      uint amountOut,
                      uint amountInMax,
                      address[] calldata path,
                      address to,
                      uint deadline
                  ) external returns (uint[] memory amounts);
                  function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
                      external
                      payable
                      returns (uint[] memory amounts);
                  function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
                      external
                      returns (uint[] memory amounts);
                  function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
                      external
                      returns (uint[] memory amounts);
                  function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
                      external
                      payable
                      returns (uint[] memory amounts);
                  function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
                  function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
                  function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
                  function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
                  function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
              }
              pragma solidity >=0.6.2;
              import './IUniswapV2Router01.sol';
              interface IUniswapV2Router02 is IUniswapV2Router01 {
                  function removeLiquidityETHSupportingFeeOnTransferTokens(
                      address token,
                      uint liquidity,
                      uint amountTokenMin,
                      uint amountETHMin,
                      address to,
                      uint deadline
                  ) external returns (uint amountETH);
                  function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
                      address token,
                      uint liquidity,
                      uint amountTokenMin,
                      uint amountETHMin,
                      address to,
                      uint deadline,
                      bool approveMax, uint8 v, bytes32 r, bytes32 s
                  ) external returns (uint amountETH);
                  function swapExactTokensForTokensSupportingFeeOnTransferTokens(
                      uint amountIn,
                      uint amountOutMin,
                      address[] calldata path,
                      address to,
                      uint deadline
                  ) external;
                  function swapExactETHForTokensSupportingFeeOnTransferTokens(
                      uint amountOutMin,
                      address[] calldata path,
                      address to,
                      uint deadline
                  ) external payable;
                  function swapExactTokensForETHSupportingFeeOnTransferTokens(
                      uint amountIn,
                      uint amountOutMin,
                      address[] calldata path,
                      address to,
                      uint deadline
                  ) external;
              }
              // 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) (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.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.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) (interfaces/draft-IERC6093.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev Standard ERC20 Errors
               * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
               */
              interface IERC20Errors {
                  /**
                   * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
                   * @param sender Address whose tokens are being transferred.
                   * @param balance Current balance for the interacting account.
                   * @param needed Minimum amount required to perform a transfer.
                   */
                  error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
                  /**
                   * @dev Indicates a failure with the token `sender`. Used in transfers.
                   * @param sender Address whose tokens are being transferred.
                   */
                  error ERC20InvalidSender(address sender);
                  /**
                   * @dev Indicates a failure with the token `receiver`. Used in transfers.
                   * @param receiver Address to which tokens are being transferred.
                   */
                  error ERC20InvalidReceiver(address receiver);
                  /**
                   * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
                   * @param spender Address that may be allowed to operate on tokens without being their owner.
                   * @param allowance Amount of tokens a `spender` is allowed to operate with.
                   * @param needed Minimum amount required to perform a transfer.
                   */
                  error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
                  /**
                   * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
                   * @param approver Address initiating an approval operation.
                   */
                  error ERC20InvalidApprover(address approver);
                  /**
                   * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
                   * @param spender Address that may be allowed to operate on tokens without being their owner.
                   */
                  error ERC20InvalidSpender(address spender);
              }
              /**
               * @dev Standard ERC721 Errors
               * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
               */
              interface IERC721Errors {
                  /**
                   * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
                   * Used in balance queries.
                   * @param owner Address of the current owner of a token.
                   */
                  error ERC721InvalidOwner(address owner);
                  /**
                   * @dev Indicates a `tokenId` whose `owner` is the zero address.
                   * @param tokenId Identifier number of a token.
                   */
                  error ERC721NonexistentToken(uint256 tokenId);
                  /**
                   * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
                   * @param sender Address whose tokens are being transferred.
                   * @param tokenId Identifier number of a token.
                   * @param owner Address of the current owner of a token.
                   */
                  error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
                  /**
                   * @dev Indicates a failure with the token `sender`. Used in transfers.
                   * @param sender Address whose tokens are being transferred.
                   */
                  error ERC721InvalidSender(address sender);
                  /**
                   * @dev Indicates a failure with the token `receiver`. Used in transfers.
                   * @param receiver Address to which tokens are being transferred.
                   */
                  error ERC721InvalidReceiver(address receiver);
                  /**
                   * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
                   * @param operator Address that may be allowed to operate on tokens without being their owner.
                   * @param tokenId Identifier number of a token.
                   */
                  error ERC721InsufficientApproval(address operator, uint256 tokenId);
                  /**
                   * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
                   * @param approver Address initiating an approval operation.
                   */
                  error ERC721InvalidApprover(address approver);
                  /**
                   * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
                   * @param operator Address that may be allowed to operate on tokens without being their owner.
                   */
                  error ERC721InvalidOperator(address operator);
              }
              /**
               * @dev Standard ERC1155 Errors
               * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
               */
              interface IERC1155Errors {
                  /**
                   * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
                   * @param sender Address whose tokens are being transferred.
                   * @param balance Current balance for the interacting account.
                   * @param needed Minimum amount required to perform a transfer.
                   * @param tokenId Identifier number of a token.
                   */
                  error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
                  /**
                   * @dev Indicates a failure with the token `sender`. Used in transfers.
                   * @param sender Address whose tokens are being transferred.
                   */
                  error ERC1155InvalidSender(address sender);
                  /**
                   * @dev Indicates a failure with the token `receiver`. Used in transfers.
                   * @param receiver Address to which tokens are being transferred.
                   */
                  error ERC1155InvalidReceiver(address receiver);
                  /**
                   * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
                   * @param operator Address that may be allowed to operate on tokens without being their owner.
                   * @param owner Address of the current owner of a token.
                   */
                  error ERC1155MissingApprovalForAll(address operator, address owner);
                  /**
                   * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
                   * @param approver Address initiating an approval operation.
                   */
                  error ERC1155InvalidApprover(address approver);
                  /**
                   * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
                   * @param operator Address that may be allowed to operate on tokens without being their owner.
                   */
                  error ERC1155InvalidOperator(address operator);
                  /**
                   * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
                   * Used in batch transfers.
                   * @param idsLength Length of the array of token identifiers
                   * @param valuesLength Length of the array of token amounts
                   */
                  error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
              pragma solidity ^0.8.20;
              import {Context} from "./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);
                  }
              }
              

              File 2 of 2: ERC1967Proxy
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.0;
              
              /**
               * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
               * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
               * be specified by overriding the virtual {_implementation} function.
               *
               * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
               * different contract through the {_delegate} function.
               *
               * The success and return data of the delegated call will be returned back to the caller of the proxy.
               */
              abstract contract Proxy {
                  /**
                   * @dev Delegates the current call to `implementation`.
                   *
                   * This function does not return to its internall call site, it will return directly to the external caller.
                   */
                  function _delegate(address implementation) internal virtual {
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                      // Copy msg.data. We take full control of memory in this inline assembly
                      // block because it will not return to Solidity code. We overwrite the
                      // Solidity scratch pad at memory position 0.
                          calldatacopy(0, 0, calldatasize())
              
                      // Call the implementation.
                      // out and outsize are 0 because we don't know the size yet.
                          let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
              
                      // Copy the returned data.
                          returndatacopy(0, 0, returndatasize())
              
                          switch result
                          // delegatecall returns 0 on error.
                          case 0 { revert(0, returndatasize()) }
                          default { return(0, returndatasize()) }
                      }
                  }
              
                  /**
                   * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
                   * and {_fallback} should delegate.
                   */
                  function _implementation() internal view virtual returns (address);
              
                  /**
                   * @dev Delegates the current call to the address returned by `_implementation()`.
                   *
                   * This function does not return to its internall call site, it will return directly to the external caller.
                   */
                  function _fallback() internal virtual {
                      _beforeFallback();
                      _delegate(_implementation());
                  }
              
                  /**
                   * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                   * function in the contract matches the call data.
                   */
                  fallback () external payable virtual {
                      _fallback();
                  }
              
                  /**
                   * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                   * is empty.
                   */
                  receive () external payable virtual {
                      _fallback();
                  }
              
                  /**
                   * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                   * call, or as part of the Solidity `fallback` or `receive` functions.
                   *
                   * If overriden should call `super._beforeFallback()`.
                   */
                  function _beforeFallback() internal virtual {
                  }
              }
              
              
              /**
               * @dev This abstract contract provides getters and event emitting update functions for
               * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
               *
               * _Available since v4.1._
               *
               */
              abstract contract ERC1967Upgrade {
                  // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                  bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
              
                  /**
                   * @dev Storage slot with the address of the current implementation.
                   * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                   * validated in the constructor.
                   */
                  bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
              
                  /**
                   * @dev Emitted when the implementation is upgraded.
                   */
                  event Upgraded(address indexed implementation);
              
                  /**
                   * @dev Returns the current implementation address.
                   */
                  function _getImplementation() internal view returns (address) {
                      return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                  }
              
                  /**
                   * @dev Stores a new address in the EIP1967 implementation slot.
                   */
                  function _setImplementation(address newImplementation) private {
                      require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                      StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                  }
              
                  /**
                   * @dev Perform implementation upgrade
                   *
                   * Emits an {Upgraded} event.
                   */
                  function _upgradeTo(address newImplementation) internal {
                      _setImplementation(newImplementation);
                      emit Upgraded(newImplementation);
                  }
              
                  /**
                   * @dev Perform implementation upgrade with additional setup call.
                   *
                   * Emits an {Upgraded} event.
                   */
                  function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                      _setImplementation(newImplementation);
                      emit Upgraded(newImplementation);
                      if (data.length > 0 || forceCall) {
                          Address.functionDelegateCall(newImplementation, data);
                      }
                  }
              
                  /**
                   * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                   *
                   * Emits an {Upgraded} event.
                   */
                  function _upgradeToAndCallSecure(address newImplementation, bytes memory data, bool forceCall) internal {
                      address oldImplementation = _getImplementation();
              
                      // Initial upgrade and setup call
                      _setImplementation(newImplementation);
                      if (data.length > 0 || forceCall) {
                          Address.functionDelegateCall(newImplementation, data);
                      }
              
                      // Perform rollback test if not already in progress
                      StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
                      if (!rollbackTesting.value) {
                          // Trigger rollback using upgradeTo from the new implementation
                          rollbackTesting.value = true;
                          Address.functionDelegateCall(
                              newImplementation,
                              abi.encodeWithSignature(
                                  "upgradeTo(address)",
                                  oldImplementation
                              )
                          );
                          rollbackTesting.value = false;
                          // Check rollback was effective
                          require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
                          // Finally reset to the new implementation and log the upgrade
                          _setImplementation(newImplementation);
                          emit Upgraded(newImplementation);
                      }
                  }
              
                  /**
                   * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                   * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                   *
                   * Emits a {BeaconUpgraded} event.
                   */
                  function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                      _setBeacon(newBeacon);
                      emit BeaconUpgraded(newBeacon);
                      if (data.length > 0 || forceCall) {
                          Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                      }
                  }
              
                  /**
                   * @dev Storage slot with the admin of the contract.
                   * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                   * validated in the constructor.
                   */
                  bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
              
                  /**
                   * @dev Emitted when the admin account has changed.
                   */
                  event AdminChanged(address previousAdmin, address newAdmin);
              
                  /**
                   * @dev Returns the current admin.
                   */
                  function _getAdmin() internal view returns (address) {
                      return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                  }
              
                  /**
                   * @dev Stores a new address in the EIP1967 admin slot.
                   */
                  function _setAdmin(address newAdmin) private {
                      require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                      StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                  }
              
                  /**
                   * @dev Changes the admin of the proxy.
                   *
                   * Emits an {AdminChanged} event.
                   */
                  function _changeAdmin(address newAdmin) internal {
                      emit AdminChanged(_getAdmin(), newAdmin);
                      _setAdmin(newAdmin);
                  }
              
                  /**
                   * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                   * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                   */
                  bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
              
                  /**
                   * @dev Emitted when the beacon is upgraded.
                   */
                  event BeaconUpgraded(address indexed beacon);
              
                  /**
                   * @dev Returns the current beacon.
                   */
                  function _getBeacon() internal view returns (address) {
                      return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                  }
              
                  /**
                   * @dev Stores a new beacon in the EIP1967 beacon slot.
                   */
                  function _setBeacon(address newBeacon) private {
                      require(
                          Address.isContract(newBeacon),
                          "ERC1967: new beacon is not a contract"
                      );
                      require(
                          Address.isContract(IBeacon(newBeacon).implementation()),
                          "ERC1967: beacon implementation is not a contract"
                      );
                      StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                  }
              }
              
              /**
               * @dev This is the interface that {BeaconProxy} expects of its beacon.
               */
              interface IBeacon {
                  /**
                   * @dev Must return an address that can be used as a delegate call target.
                   *
                   * {BeaconProxy} will check that this address is a contract.
                   */
                  function implementation() external view returns (address);
              }
              
              /**
               * @dev Collection of functions related to the address type
               */
              library Address {
                  /**
                   * @dev Returns true if `account` is a contract.
                   *
                   * [IMPORTANT]
                   * ====
                   * It is unsafe to assume that an address for which this function returns
                   * false is an externally-owned account (EOA) and not a contract.
                   *
                   * Among others, `isContract` will return false for the following
                   * types of addresses:
                   *
                   *  - an externally-owned account
                   *  - a contract in construction
                   *  - an address where a contract will be created
                   *  - an address where a contract lived, but was destroyed
                   * ====
                   */
                  function isContract(address account) internal view returns (bool) {
                      // This method relies on extcodesize, which returns 0 for contracts in
                      // construction, since the code is only stored at the end of the
                      // constructor execution.
              
                      uint256 size;
                      // solhint-disable-next-line no-inline-assembly
                      assembly { size := extcodesize(account) }
                      return size > 0;
                  }
              
                  /**
                   * @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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                   */
                  function sendValue(address payable recipient, uint256 amount) internal {
                      require(address(this).balance >= amount, "Address: insufficient balance");
              
                      // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                      (bool success, ) = recipient.call{ value: amount }("");
                      require(success, "Address: unable to send value, recipient may have reverted");
                  }
              
                  /**
                   * @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, it is bubbled up by this
                   * function (like regular Solidity function calls).
                   *
                   * 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.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                      return functionCall(target, data, "Address: low-level call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                   * `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, 0, errorMessage);
                  }
              
                  /**
                   * @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`.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                   * with `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                      require(address(this).balance >= value, "Address: insufficient balance for call");
                      require(isContract(target), "Address: call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.call{ value: value }(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a static call.
                   *
                   * _Available since v3.3._
                   */
                  function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                      return functionStaticCall(target, data, "Address: low-level static call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                   * but performing a static call.
                   *
                   * _Available since v3.3._
                   */
                  function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                      require(isContract(target), "Address: static call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.staticcall(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a delegate call.
                   *
                   * _Available since v3.4._
                   */
                  function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                      return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                   * but performing a delegate call.
                   *
                   * _Available since v3.4._
                   */
                  function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      require(isContract(target), "Address: delegate call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.delegatecall(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                      if (success) {
                          return returndata;
                      } else {
                          // 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
              
                              // solhint-disable-next-line no-inline-assembly
                              assembly {
                                  let returndata_size := mload(returndata)
                                  revert(add(32, returndata), returndata_size)
                              }
                          } else {
                              revert(errorMessage);
                          }
                      }
                  }
              }
              
              /**
               * @dev Library for reading and writing primitive types to specific storage slots.
               *
               * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
               * This library helps with reading and writing to such slots without the need for inline assembly.
               *
               * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
               *
               * Example usage to set ERC1967 implementation slot:
               * ```
               * contract ERC1967 {
               *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
               *
               *     function _getImplementation() internal view returns (address) {
               *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
               *     }
               *
               *     function _setImplementation(address newImplementation) internal {
               *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
               *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
               *     }
               * }
               * ```
               *
               * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
               */
              library StorageSlot {
                  struct AddressSlot {
                      address value;
                  }
              
                  struct BooleanSlot {
                      bool value;
                  }
              
                  struct Bytes32Slot {
                      bytes32 value;
                  }
              
                  struct Uint256Slot {
                      uint256 value;
                  }
              
                  /**
                   * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                   */
                  function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                      assembly {
                          r.slot := slot
                      }
                  }
              
                  /**
                   * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                   */
                  function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                      assembly {
                          r.slot := slot
                      }
                  }
              
                  /**
                   * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                   */
                  function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                      assembly {
                          r.slot := slot
                      }
                  }
              
                  /**
                   * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                   */
                  function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                      assembly {
                          r.slot := slot
                      }
                  }
              }
              
              /*
               * @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) {
                      this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                      return msg.data;
                  }
              }
              
              /**
               * @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.
               *
               * By default, the owner account will be the one that deploys the contract. 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;
              
                  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              
                  /**
                   * @dev Initializes the contract setting the deployer as the initial owner.
                   */
                  constructor () {
                      address msgSender = _msgSender();
                      _owner = msgSender;
                      emit OwnershipTransferred(address(0), msgSender);
                  }
              
                  /**
                   * @dev Returns the address of the current owner.
                   */
                  function owner() public view virtual returns (address) {
                      return _owner;
                  }
              
                  /**
                   * @dev Throws if called by any account other than the owner.
                   */
                  modifier onlyOwner() {
                      require(owner() == _msgSender(), "Ownable: caller is not the owner");
                      _;
                  }
              
                  /**
                   * @dev Leaves the contract without owner. It will not be possible to call
                   * `onlyOwner` functions anymore. Can only be called by the current owner.
                   *
                   * NOTE: Renouncing ownership will leave the contract without an owner,
                   * thereby removing any functionality that is only available to the owner.
                   */
                  function renounceOwnership() public virtual onlyOwner {
                      emit OwnershipTransferred(_owner, address(0));
                      _owner = 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 {
                      require(newOwner != address(0), "Ownable: new owner is the zero address");
                      emit OwnershipTransferred(_owner, newOwner);
                      _owner = newOwner;
                  }
              }
              
              /**
               * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
               * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
               */
              contract ProxyAdmin is Ownable {
              
                  /**
                   * @dev Returns the current implementation of `proxy`.
                   *
                   * Requirements:
                   *
                   * - This contract must be the admin of `proxy`.
                   */
                  function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                      // We need to manually run the static call since the getter cannot be flagged as view
                      // bytes4(keccak256("implementation()")) == 0x5c60da1b
                      (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
                      require(success);
                      return abi.decode(returndata, (address));
                  }
              
                  /**
                   * @dev Returns the current admin of `proxy`.
                   *
                   * Requirements:
                   *
                   * - This contract must be the admin of `proxy`.
                   */
                  function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                      // We need to manually run the static call since the getter cannot be flagged as view
                      // bytes4(keccak256("admin()")) == 0xf851a440
                      (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
                      require(success);
                      return abi.decode(returndata, (address));
                  }
              
                  /**
                   * @dev Changes the admin of `proxy` to `newAdmin`.
                   *
                   * Requirements:
                   *
                   * - This contract must be the current admin of `proxy`.
                   */
                  function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
                      proxy.changeAdmin(newAdmin);
                  }
              
                  /**
                   * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
                   *
                   * Requirements:
                   *
                   * - This contract must be the admin of `proxy`.
                   */
                  function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
                      proxy.upgradeTo(implementation);
                  }
              
                  /**
                   * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
                   * {TransparentUpgradeableProxy-upgradeToAndCall}.
                   *
                   * Requirements:
                   *
                   * - This contract must be the admin of `proxy`.
                   */
                  function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable virtual onlyOwner {
                      proxy.upgradeToAndCall{value: msg.value}(implementation, data);
                  }
              }
              
              
              /**
               * @dev Base contract for building openzeppelin-upgrades compatible implementations for the {ERC1967Proxy}. It includes
               * publicly available upgrade functions that are called by the plugin and by the secure upgrade mechanism to verify
               * continuation of the upgradability.
               *
               * The {_authorizeUpgrade} function MUST be overridden to include access restriction to the upgrade mechanism.
               *
               * _Available since v4.1._
               */
              abstract contract UUPSUpgradeable is ERC1967Upgrade {
                  function upgradeTo(address newImplementation) external virtual {
                      _authorizeUpgrade(newImplementation);
                      _upgradeToAndCallSecure(newImplementation, bytes(""), false);
                  }
              
                  function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual {
                      _authorizeUpgrade(newImplementation);
                      _upgradeToAndCallSecure(newImplementation, data, true);
                  }
              
                  function _authorizeUpgrade(address newImplementation) internal virtual;
              }
              
              
              abstract contract Proxiable is UUPSUpgradeable {
                  function _authorizeUpgrade(address newImplementation) internal override {
                      _beforeUpgrade(newImplementation);
                  }
              
                  function _beforeUpgrade(address newImplementation) internal virtual;
              }
              
              contract ChildOfProxiable is Proxiable {
                  function _beforeUpgrade(address newImplementation) internal virtual override {}
              }
              
              
              /**
               * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
               * implementation address that can be changed. This address is stored in storage in the location specified by
               * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
               * implementation behind the proxy.
               */
              contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                  /**
                   * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                   *
                   * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                   * function call, and allows initializating the storage of the proxy like a Solidity constructor.
                   */
                  constructor(address _logic, bytes memory _data) payable {
                      assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                      _upgradeToAndCall(_logic, _data, false);
                  }
              
                  /**
                   * @dev Returns the current implementation address.
                   */
                  function _implementation() internal view virtual override returns (address impl) {
                      return ERC1967Upgrade._getImplementation();
                  }
              }
              
              /**
               * @dev This contract implements a proxy that is upgradeable by an admin.
               *
               * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
               * clashing], which can potentially be used in an attack, this contract uses the
               * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
               * things that go hand in hand:
               *
               * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
               * that call matches one of the admin functions exposed by the proxy itself.
               * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
               * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
               * "admin cannot fallback to proxy target".
               *
               * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
               * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
               * to sudden errors when trying to call a function from the proxy implementation.
               *
               * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
               * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
               */
              contract TransparentUpgradeableProxy is ERC1967Proxy {
                  /**
                   * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
                   * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
                   */
                  constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
                      assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                      _changeAdmin(admin_);
                  }
              
                  /**
                   * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
                   */
                  modifier ifAdmin() {
                      if (msg.sender == _getAdmin()) {
                          _;
                      } else {
                          _fallback();
                      }
                  }
              
                  /**
                   * @dev Returns the current admin.
                   *
                   * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
                   *
                   * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                   * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                   * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                   */
                  function admin() external ifAdmin returns (address admin_) {
                      admin_ = _getAdmin();
                  }
              
                  /**
                   * @dev Returns the current implementation.
                   *
                   * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
                   *
                   * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                   * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                   * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                   */
                  function implementation() external ifAdmin returns (address implementation_) {
                      implementation_ = _implementation();
                  }
              
                  /**
                   * @dev Changes the admin of the proxy.
                   *
                   * Emits an {AdminChanged} event.
                   *
                   * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
                   */
                  function changeAdmin(address newAdmin) external virtual ifAdmin {
                      _changeAdmin(newAdmin);
                  }
              
                  /**
                   * @dev Upgrade the implementation of the proxy.
                   *
                   * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
                   */
                  function upgradeTo(address newImplementation) external ifAdmin {
                      _upgradeToAndCall(newImplementation, bytes(""), false);
                  }
              
                  /**
                   * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
                   * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
                   * proxied contract.
                   *
                   * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
                   */
                  function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                      _upgradeToAndCall(newImplementation, data, true);
                  }
              
                  /**
                   * @dev Returns the current admin.
                   */
                  function _admin() internal view virtual returns (address) {
                      return _getAdmin();
                  }
              
                  /**
                   * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
                   */
                  function _beforeFallback() internal virtual override {
                      require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                      super._beforeFallback();
                  }
              }
              
              
              // Kept for backwards compatibility with older versions of Hardhat and Truffle plugins.
              contract AdminUpgradeabilityProxy is TransparentUpgradeableProxy {
                  constructor(address logic, address admin, bytes memory data) payable TransparentUpgradeableProxy(logic, admin, data) {}
              }