Sushiforth Token - Smart Contract Audit Report

Summary

Sushiforth Audit Report Sushiforth is a crypto asset pegged to the total liquidity in the sushiswap ecosystem. The intent of the project is to give holders exposure to the performance of the entire sushiswap market as well as dividends from every buy/sell/transaction from the Sushiforth markets.

We have verified that the code audited below is deployed at the following addresses on the mainnet:

  • Uniforth - 0x665A6b80208a1F8EcCB1ecb6d0271dDe910c9EF1
  • Sushiforth - 0x718141de19e51ca6e704c4b9346608236c00b781
  • Besides some changes in numbers related to the token's supply & fees and the token's presale, the main notable difference between these contracts is that the Sushiforth contract allows the owner to lock transactions that are queued in the SUSF contract (related to the rebase function). View the full comparison of the two contracts here.
  • The contract displayed below is SUSF, but as the logic is the same and they are deployed immutably, all findings discussedapply equally to both contracts.
  • Audit Findings:
    • SUSF and UNIF tokens rebase based on the SushiSwap/UniSwap's Total Liquidity.
    • The tokens can only be minted via the rebase function.
    • The rebase function can only be called by an address which is either the contract's owner and has the rebaser role.
    • The owner has the ability to set any address as the rebaser at any time.
    • The owner/rebaser provides the supply delta (change in SushiSwap/UniSwap liquidity) manually when rebasing.

    • The contract uses the fee-redistribution method from RFI. The contract charges an fee on transfers; the proceeds of which are entirely redistributed to existing token holders instantly and automatically at the time of each transaction.
    • The owner can exclude any address from the fee mechanism.

    • The current set fees for both SUSF and UNIF is 2.72%.
    • The owner has the ability to update fee amounts at any time. However, the contract owner set limits on the following metrics to zero: Maximum Transfer Amount, Maximum Balance. Therefore if these fees are changed, they can only be changed to 0.
    • At the conclusion of the presale, the owner will call listToken() which takes the ETH collected along with tokens and adds it as liquidity on Uniswap.
    • Note that while the code refers to a sell fee, no sell fee is implemented.


    • No security issues from external attackers were identified.
    • Investing requires placing trust in the project team as they must manually push the supply deltas and call the rebase function.
    • Initial Date: January 4th, 2020.
    • Update Date: January 6th, 2020. (Updated setting of pertinent fee limits to 0).

    Vulnerability CategoryNotesResult
    Arbitrary Storage WriteN/APASS
    Arbitrary JumpN/APASS
    Delegate Call to Untrusted ContractN/APASS
    Dependence on Predictable VariablesN/APASS
    Deprecated OpcodesN/APASS
    Ether ThiefN/APASS
    ExceptionsN/APASS
    External CallsN/APASS
    Flash LoansN/APASS
    Integer Over/UnderflowN/APASS
    Multiple SendsN/APASS
    OraclesN/APASS
    SuicideN/APASS
    State Change External CallsN/APass
    Unchecked RetvalN/APASS
    User Supplied AssertionN/APASS
    Critical Solidity CompilerN/APASS
    Overall Contract Safety PASS

    Smart Contract Graph

    Contract Inheritance

    
       ($) = payable function
        # = non-constant function
    
     + [Lib] SafeCast 
        - [Int] toUint128
        - [Int] toUint64
        - [Int] toUint32
        - [Int] toUint16
        - [Int] toUint8
        - [Int] toUint256
        - [Int] toInt256
    
     +  Initializable 
        - [Prv] isConstructor
    
     +  ContextUpgradeSafe (Initializable)
        - [Int] __Context_init #
           - modifiers: initializer
        - [Int] __Context_init_unchained #
           - modifiers: initializer
        - [Int] _msgSender
        - [Int] _msgData
    
     +  OwnableUpgradeSafe (Initializable, ContextUpgradeSafe)
        - [Int] __Ownable_init #
           - modifiers: initializer
        - [Int] __Ownable_init_unchained #
           - modifiers: initializer
        - [Pub] owner
        - [Pub] renounceOwnership #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
    
     + [Int] IERC20 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
    
     + [Lib] SafeMath 
        - [Int] add
        - [Int] sub
        - [Int] sub
        - [Int] mul
        - [Int] div
        - [Int] div
        - [Int] mod
        - [Int] mod
    
     + [Lib] Address 
        - [Int] isContract
        - [Int] sendValue #
    
     +  ERC20UpgradeSafe (Initializable, ContextUpgradeSafe, IERC20)
        - [Int] __ERC20_init #
           - modifiers: initializer
        - [Int] __ERC20_init_unchained #
           - modifiers: initializer
        - [Pub] name
        - [Pub] symbol
        - [Pub] decimals
        - [Pub] totalSupply
        - [Pub] balanceOf
        - [Pub] transfer #
        - [Pub] allowance
        - [Pub] approve #
        - [Pub] transferFrom #
        - [Pub] increaseAllowance #
        - [Pub] decreaseAllowance #
        - [Int] _transfer #
        - [Int] _approve #
        - [Int] _setupDecimals #
        - [Int] _beforeTokenTransfer #
    
     + [Int] IUniswapV2Factory 
        - [Ext] feeTo
        - [Ext] feeToSetter
        - [Ext] migrator
        - [Ext] getPair
        - [Ext] allPairs
        - [Ext] allPairsLength
        - [Ext] createPair #
        - [Ext] setFeeTo #
        - [Ext] setFeeToSetter #
        - [Ext] setMigrator #
    
     + [Int] IUniswapV2Router01 
        - [Ext] factory
        - [Ext] WETH
        - [Ext] addLiquidity #
        - [Ext] addLiquidityETH ($)
        - [Ext] removeLiquidity #
        - [Ext] removeLiquidityETH #
        - [Ext] removeLiquidityWithPermit #
        - [Ext] removeLiquidityETHWithPermit #
        - [Ext] swapExactTokensForTokens #
        - [Ext] swapTokensForExactTokens #
        - [Ext] swapExactETHForTokens ($)
        - [Ext] swapTokensForExactETH #
        - [Ext] swapExactTokensForETH #
        - [Ext] swapETHForExactTokens ($)
        - [Ext] quote
        - [Ext] getAmountOut
        - [Ext] getAmountIn
        - [Ext] getAmountsOut
        - [Ext] getAmountsIn
    
     + [Int] IUniswapV2Router02 (IUniswapV2Router01)
        - [Ext] removeLiquidityETHSupportingFeeOnTransferTokens #
        - [Ext] removeLiquidityETHWithPermitSupportingFeeOnTransferTokens #
        - [Ext] swapExactTokensForTokensSupportingFeeOnTransferTokens #
        - [Ext] swapExactETHForTokensSupportingFeeOnTransferTokens ($)
        - [Ext] swapExactTokensForETHSupportingFeeOnTransferTokens #
    
     + [Int] IUniswapV2Pair 
        - [Ext] name
        - [Ext] symbol
        - [Ext] decimals
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transfer #
        - [Ext] transferFrom #
        - [Ext] DOMAIN_SEPARATOR
        - [Ext] PERMIT_TYPEHASH
        - [Ext] nonces
        - [Ext] permit #
        - [Ext] MINIMUM_LIQUIDITY
        - [Ext] factory
        - [Ext] token0
        - [Ext] token1
        - [Ext] getReserves
        - [Ext] price0CumulativeLast
        - [Ext] price1CumulativeLast
        - [Ext] kLast
        - [Ext] mint #
        - [Ext] burn #
        - [Ext] swap #
        - [Ext] skim #
        - [Ext] sync #
        - [Ext] initialize #
    
     + [Int] IWETH 
        - [Ext] deposit ($)
        - [Ext] transfer #
        - [Ext] withdraw #
    
     +  SUSF (ERC20UpgradeSafe, OwnableUpgradeSafe)
        - [Pub] initialize #
           - modifiers: initializer
        - [Ext]  ($)
        - [Ext] listToken #
           - modifiers: onlyOwner
        - [Ext] setRebaser #
           - modifiers: onlyOwner
        - [Ext] setLock #
           - modifiers: onlyOwner
        - [Ext] setTransferFeePercent #
           - modifiers: onlyOwner
        - [Ext] setLimit #
           - modifiers: onlyOwner
        - [Pub] totalSupply
        - [Ext] rebase #
        - [Ext] addTransaction #
           - modifiers: onlyOwner
        - [Ext] removeTransaction #
           - modifiers: onlyOwner
        - [Ext] setTransactionEnabled #
           - modifiers: onlyOwner
        - [Ext] transactionsSize
        - [Int] externalCall #
        - [Pub] balanceOf
        - [Pub] transfer #
        - [Pub] allowance
        - [Pub] approve #
        - [Pub] transferFrom #
        - [Pub] increaseAllowance #
        - [Pub] decreaseAllowance #
        - [Pub] isExcluded
        - [Pub] totalFees
        - [Pub] refract #
        - [Pub] refractionFromToken
        - [Pub] tokenFromRefraction
        - [Pub] excludeAccount #
           - modifiers: onlyOwner
        - [Pub] includeAccount #
           - modifiers: onlyOwner
        - [Int] _approve #
        - [Int] _transfer #
        - [Prv] _transferStandard #
        - [Prv] _transferToExcluded #
        - [Prv] _transferFromExcluded #
        - [Prv] _transferBothExcluded #
        - [Prv] _refractFee #
        - [Prv] _getValues
        - [Prv] _getTValues
        - [Prv] _getRValues
        - [Prv] _getRate
        - [Prv] _getCurrentSupply
    							

    Click here to download the source code as a .sol file.

    
    /**
     *Submitted for verification at Etherscan.io on 2021-01-01
    */
    
    pragma solidity ^0.6.12;
    
    library SafeCast {
    
        function toUint128(uint256 value) internal pure returns (uint128) {
            require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits");
            return uint128(value);
        }
    
        function toUint64(uint256 value) internal pure returns (uint64) {
            require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits");
            return uint64(value);
        }
    
        function toUint32(uint256 value) internal pure returns (uint32) {
            require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits");
            return uint32(value);
        }
    
        function toUint16(uint256 value) internal pure returns (uint16) {
            require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits");
            return uint16(value);
        }
    
        function toUint8(uint256 value) internal pure returns (uint8) {
            require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits");
            return uint8(value);
        }
        
        function toUint256(int256 value) internal pure returns (uint256) {
            require(value >= 0, "SafeCast: value must be positive");
            return uint256(value);
        }
    
        function toInt256(uint256 value) internal pure returns (int256) {
            require(value < 2**255, "SafeCast: value doesn't fit in an int256");
            return int256(value);
        }
    }
    
    contract Initializable {
    
      bool private initialized;
    
      bool private initializing;
    
      modifier initializer() {
        require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");
    
        bool isTopLevelCall = !initializing;
        if (isTopLevelCall) {
          initializing = true;
          initialized = true;
        }
    
        _;
    
        if (isTopLevelCall) {
          initializing = false;
        }
      }
    
      function isConstructor() private view returns (bool) {
        address self = address(this);
        uint256 cs;
        assembly { cs := extcodesize(self) }
        return cs == 0;
      }
    
      uint256[50] private ______gap;
    }
    
    contract ContextUpgradeSafe is Initializable {
    
        function __Context_init() internal initializer {
            __Context_init_unchained();
        }
    
        function __Context_init_unchained() internal initializer {
        }
    
        function _msgSender() internal view virtual returns (address payable) {
            return msg.sender;
        }
    
        function _msgData() internal view virtual returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
        }
    
        uint256[50] private __gap;
    }
    
    contract OwnableUpgradeSafe is Initializable, ContextUpgradeSafe {
        address private _owner;
    
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
        function __Ownable_init() internal initializer {
            __Context_init_unchained();
            __Ownable_init_unchained();
        }
    
        function __Ownable_init_unchained() internal initializer {
            address msgSender = _msgSender();
            _owner = msgSender;
            emit OwnershipTransferred(address(0), msgSender);
    
        }
    
        function owner() public view returns (address) {
            return _owner;
        }
    
        modifier onlyOwner() {
            require(_owner == _msgSender(), "Ownable: caller is not the owner");
            _;
        }
    
        function renounceOwnership() public virtual onlyOwner {
            emit OwnershipTransferred(_owner, address(0));
            _owner = address(0);
        }
    
        function transferOwnership(address newOwner) public virtual onlyOwner {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            emit OwnershipTransferred(_owner, newOwner);
            _owner = newOwner;
        }
    
        uint256[49] private __gap;
    }
    
    interface IERC20 {
        function totalSupply() external view returns (uint256);
    
        function balanceOf(address account) external view returns (uint256);
    
        function transfer(address recipient, uint256 amount) external returns (bool);
    
        function allowance(address owner, address spender) external view returns (uint256);
    
        function approve(address spender, uint256 amount) external returns (bool);
    
        function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    
    library SafeMath {
       
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
    
            return c;
        }
    
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, "SafeMath: subtraction overflow");
        }
    
        function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
    
            return c;
        }
        
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            if (a == 0) {
                return 0;
            }
    
            uint256 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
    
            return c;
        }
    
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, "SafeMath: division by zero");
        }
    
        function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b > 0, errorMessage);
            uint256 c = a / b;
            return c;
        }
    
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, "SafeMath: modulo by zero");
        }
    
        function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
        }
    }
    
    library Address {
        function isContract(address account) internal view returns (bool) {
            bytes32 codehash;
            bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
            assembly { codehash := extcodehash(account) }
            return (codehash != accountHash && codehash != 0x0);
        }
    
        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");
        }
    }
    
    contract ERC20UpgradeSafe is Initializable, ContextUpgradeSafe, IERC20 {
        using SafeMath for uint256;
        using Address for address;
    
        mapping (address => uint256) private _balances;
    
        mapping (address => mapping (address => uint256)) private _allowances;
    
        uint256 private _totalSupply;
    
        string private _name;
        string private _symbol;
        uint8 private _decimals;
    
        function __ERC20_init(string memory name, string memory symbol) internal initializer {
            __Context_init_unchained();
            __ERC20_init_unchained(name, symbol);
        }
    
        function __ERC20_init_unchained(string memory name, string memory symbol) internal initializer {
    
    
            _name = name;
            _symbol = symbol;
            _decimals = 18;
    
        }
    
        function name() public view returns (string memory) {
            return _name;
        }
    
        function symbol() public view returns (string memory) {
            return _symbol;
        }
    
        function decimals() public view returns (uint8) {
            return _decimals;
        }
    
        function totalSupply() public view virtual override returns (uint256) {
            return _totalSupply;
        }
    
        function balanceOf(address account) public view virtual override returns (uint256) {
            return _balances[account];
        }
    
        function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
            _transfer(_msgSender(), recipient, amount);
            return true;
        }
    
        function allowance(address owner, address spender) public view virtual override returns (uint256) {
            return _allowances[owner][spender];
        }
    
        function approve(address spender, uint256 amount) public virtual override returns (bool) {
            _approve(_msgSender(), spender, amount);
            return true;
        }
    
        function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
            _transfer(sender, recipient, amount);
            _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
            return true;
        }
        
        function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
            _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
            return true;
        }
    
        function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
            _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
            return true;
        }
        
        function _transfer(address sender, address recipient, uint256 amount) internal virtual {
            require(sender != address(0), "ERC20: transfer from the zero address");
            require(recipient != address(0), "ERC20: transfer to the zero address");
    
            _beforeTokenTransfer(sender, recipient, amount);
    
            _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
            _balances[recipient] = _balances[recipient].add(amount);
            emit Transfer(sender, recipient, amount);
        }
    
        function _approve(address owner, address spender, uint256 amount) internal virtual {
            require(owner != address(0), "ERC20: approve from the zero address");
            require(spender != address(0), "ERC20: approve to the zero address");
    
            _allowances[owner][spender] = amount;
            emit Approval(owner, spender, amount);
        }
    
        function _setupDecimals(uint8 decimals_) internal {
            _decimals = decimals_;
        }
    
        function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
    
        uint256[44] private __gap;
    }
    
    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 migrator() 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;
        function setMigrator(address) external;
    }
    
    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);
    }
    
    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;
    }
    
    
    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;
    }
    
    interface IWETH {
        function deposit() external payable;
        function transfer(address to, uint value) external returns (bool);
        function withdraw(uint) external;
    }
    
    contract SUSF is ERC20UpgradeSafe, OwnableUpgradeSafe {
        
        using SafeCast for int256;
        using SafeMath for uint256;
        using Address for address;
        
        struct Transaction {
            bool enabled;
            address destination;
            bytes data;
        }
    
        event TransactionFailed(address indexed destination, uint index, bytes data);
    	
    	// Stable ordering is not guaranteed.
    
        Transaction[] public transactions;
    
        uint256 private _epoch;
        event LogRebase(uint256 indexed epoch, uint256 totalSupply);
    
        mapping (address => uint256) private _rOwned;
        mapping (address => uint256) private _tOwned;
        mapping (address => mapping (address => uint256)) private _allowances;
    
        mapping (address => bool) private _isExcluded;
        address[] private _excluded;
    	
    	uint256 private _totalSupply;
       
        uint256 private constant MAX = ~uint256(0);
        uint256 private _rTotal;
        uint256 private _tFeeTotal;
        
        uint256 private constant DECIMALS = 9;
        uint256 private constant RATE_PRECISION = 10 ** DECIMALS;
        
        uint256 public _tFeePercent;
        
        address public _rebaser;
        
        uint256 public _limitTransferAmount;
        uint256 public _limitMaxBalance;
        uint256 public _limitSellFeePercent;
        
        uint256 public _limitTimestamp;
    
        uint256 public _presaleTimestamp;
        uint256 public _presaleEth;
        bool public endSale;
        uint256 public _presaleRate;
        mapping(address => uint256) public saleAmt;
        mapping(uint256 => bool) public locked;
        
        IUniswapV2Router02 public uniswapRouterV2;
        IUniswapV2Factory public uniswapFactory;
        
        function initialize()
            public
            initializer
        {
            __ERC20_init("Sushiforth", "SUSF");
            _setupDecimals(uint8(DECIMALS));
            __Ownable_init();
            
            _totalSupply = 12000000 * 10**9 ;
            _rTotal = (MAX - (MAX % _totalSupply));
            
            _rebaser = _msgSender();
            
            _tFeePercent = 237; //2.6682%
    
            _rOwned[address(this)] = _rTotal;
            emit Transfer(address(0), address(this), _totalSupply);
    
            _presaleTimestamp = 1609696800;
            endSale = false;
            _presaleEth = 600 ether;
            _presaleRate = 6666;
            
            excludeAccount(_msgSender());
            excludeAccount(address(this));
            
            uniswapRouterV2 = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
            uniswapFactory = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);
        }
    
        receive() external payable {
            require(!endSale, "PreSale Ended");
            require(now > 1609524000, "presale yet to start");
            require(_presaleEth >= msg.value, "Sold out");
            saleAmt[msg.sender] += msg.value;
            require(saleAmt[msg.sender] <=  7500000000000000000, "max presale limit reached");
            address payable wallet = address(uint160(owner()));
            wallet.transfer(msg.value.div(3));
            _presaleEth = _presaleEth.sub(msg.value);
            uint256 amountBought = msg.value.div(10**9).mul(_presaleRate);
            _transfer(address(this), msg.sender, amountBought );
        }
    
        function listToken() external onlyOwner() {
            require(!endSale, 'already listed');
            require(_presaleEth == 0 || _presaleTimestamp < now, "Sale has not ended yet");
            endSale = true;
            _transfer(address(this), _msgSender(), 8000000 * 10**9);
            address tokenUniswapPair = uniswapFactory.createPair(
                address(uniswapRouterV2.WETH()),
                address(address(this))
            );
            IUniswapV2Pair pair = IUniswapV2Pair(tokenUniswapPair);
            address WETH = uniswapRouterV2.WETH();
            uint256 ethToSend = address(this).balance;
            IWETH(WETH).deposit{value : ethToSend}();
            require(address(this).balance == 0 , "Transfer Failed");
            uint256 tokenToAdd = 2666666 * 10**9;
            if(_presaleEth != 0) {
                tokenToAdd = ethToSend.div(10**9).mul(_presaleRate);
                uint256 unsoldTokens = balanceOf(address(this)) - tokenToAdd; 
                _transfer(address(this), address(0), unsoldTokens);
            }
            IWETH(WETH).transfer(address(pair),ethToSend);
            _transfer(address(this), address(pair), tokenToAdd);
            pair.mint(address(this));
            IERC20(address(pair)).transfer(msg.sender, IERC20(address(pair)).balanceOf(address(this)));
        }
        
        function setRebaser(address rebaser) external onlyOwner() {
            _rebaser = rebaser;
        }
         
        function setLock(uint256 _index) external onlyOwner() {
            locked[_index] = true;
        }
        
        function setTransferFeePercent(uint256 tFeePercent) external onlyOwner() {
    
            _tFeePercent = tFeePercent;
        }
        
        function setLimit(uint256 transferAmount, uint256 maxBalance, uint256 sellFeePercent) external onlyOwner() {
            require(_limitTimestamp == 0, "Limit changes not allowed");
            
            _limitTransferAmount = transferAmount;
            _limitMaxBalance = maxBalance;
            _limitSellFeePercent = sellFeePercent;
    
            _limitTimestamp = now;
        }
        
        function totalSupply() public view override returns (uint256) {
            return _totalSupply;
        }
        
        function rebase(int256 supplyDelta)
            external
            returns (uint256)
        {
            require(_msgSender() == owner() || _msgSender() == _rebaser, "Sender not authorized");
            
            _epoch = _epoch.add(1);
    		
            if (supplyDelta == 0) {
                emit LogRebase(_epoch, _totalSupply);
                return _totalSupply;
            }
            
            uint256 uSupplyDelta = (supplyDelta < 0 ? -supplyDelta : supplyDelta).toUint256();
            uint256 rate = uSupplyDelta.mul(RATE_PRECISION).div(_totalSupply);
            uint256 multiplier;
            
            if (supplyDelta < 0) {
                multiplier = RATE_PRECISION.sub(rate);
            } else {
                multiplier = RATE_PRECISION.add(rate);
            }
            
            if (supplyDelta < 0) {
                _totalSupply = _totalSupply.sub(uSupplyDelta);
            } else {
                _totalSupply = _totalSupply.add(uSupplyDelta);
            }
            
            if (_totalSupply > MAX) {
                _totalSupply = MAX;
            }
            
            for (uint256 i = 0; i < _excluded.length; i++) {
                if(_tOwned[_excluded[i]] > 0) {
                    _tOwned[_excluded[i]] = _tOwned[_excluded[i]].mul(multiplier).div(RATE_PRECISION);
                }
            }
            
            emit LogRebase(_epoch, _totalSupply);
    
    		for (uint i = 0; i < transactions.length; i++) {
                Transaction storage t = transactions[i];
                if (t.enabled) {
                    bool result = externalCall(t.destination, t.data);
                    if (!result) {
                        emit TransactionFailed(t.destination, i, t.data);
                        revert("Transaction Failed");
                    }
                }
            }
    
            return _totalSupply;
        }
        
        /**
         * @notice Adds a transaction that gets called for a downstream receiver of rebases
         * @param destination Address of contract destination
         * @param data Transaction data payload
         */
    	
        function addTransaction(address destination, bytes memory data)
            external
            onlyOwner
        {
            transactions.push(Transaction({
                enabled: true,
                destination: destination,
                data: data
            }));
        }
    	
    	/**
         * @param index Index of transaction to remove.
         *              Transaction ordering may have changed since adding.
         */
    
        function removeTransaction(uint index)
            external
            onlyOwner
        {
            require(index < transactions.length, "index out of bounds");
            require(!locked[index], "index is locked");
    
            if (index < transactions.length - 1) {
                transactions[index] = transactions[transactions.length - 1];
            }
    
            transactions.pop();
        }
    	
    	/**
         * @param index Index of transaction. Transaction ordering may have changed since adding.
         * @param enabled True for enabled, false for disabled.
         */
    
        function setTransactionEnabled(uint index, bool enabled)
            external
            onlyOwner
        {
            require(index < transactions.length, "index must be in range of stored tx list");
            transactions[index].enabled = enabled;
        }
    	
    	/**
         * @return Number of transactions, both enabled and disabled, in transactions list.
         */
    
        function transactionsSize()
            external
            view
            returns (uint256)
        {
            return transactions.length;
        }
    	
    	/**
         * @dev wrapper to call the encoded transactions on downstream consumers.
         * @param destination Address of destination contract.
         * @param data The encoded data payload.
         * @return True on success
         */
    
        function externalCall(address destination, bytes memory data)
            internal
            returns (bool)
        {
            bool result;
            assembly {  // solhint-disable-line no-inline-assembly
                // "Allocate" memory for output
                // (0x40 is where "free memory" pointer is stored by convention)
                let outputAddress := mload(0x40)
    
                // First 32 bytes are the padded length of data, so exclude that
                let dataAddress := add(data, 32)
    
                result := call(
                    // 34710 is the value that solidity is currently emitting
                    // It includes callGas (700) + callVeryLow (3, to pay for SUB)
                    // + callValueTransferGas (9000) + callNewAccountGas
                    // (25000, in case the destination address does not exist and needs creating)
                    sub(gas(), 34710),
    
    
                    destination,
                    0, // transfer value in wei
                    dataAddress,
                    mload(data),  // Size of the input, in bytes. Stored in position 0 of the array.
                    outputAddress,
                    0  // Output is ignored, therefore the output size is zero
                )
            }
            return result;
        }
    
        function balanceOf(address account) public view override returns (uint256) {
            if (_isExcluded[account]) return _tOwned[account];
            return tokenFromRefraction(_rOwned[account]);
        }
    
        function transfer(address recipient, uint256 amount) public override returns (bool) {
            _transfer(_msgSender(), recipient, amount);
            return true;
        }
    
        function allowance(address owner, address spender) public view override returns (uint256) {
            return _allowances[owner][spender];
        }
    
        function approve(address spender, uint256 amount) public override returns (bool) {
            _approve(_msgSender(), spender, amount);
            return true;
        }
    
        function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
            _transfer(sender, recipient, amount);
            _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
            return true;
        }
    
        function increaseAllowance(address spender, uint256 addedValue) public virtual override returns (bool) {
            _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
            return true;
        }
    
        function decreaseAllowance(address spender, uint256 subtractedValue) public virtual override returns (bool) {
            _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
            return true;
        }
    
        function isExcluded(address account) public view returns (bool) {
            return _isExcluded[account];
        }
    
        function totalFees() public view returns (uint256) {
            return _tFeeTotal;
        }
    
        function refract(uint256 tAmount) public {
            address sender = _msgSender();
            require(!_isExcluded[sender], "Excluded addresses cannot call this function");
            (uint256 rAmount,,,,) = _getValues(tAmount, _tFeePercent);
            _rOwned[sender] = _rOwned[sender].sub(rAmount);
            _rTotal = _rTotal.sub(rAmount);
            _tFeeTotal = _tFeeTotal.add(tAmount);
        }
    
        function refractionFromToken(uint256 tAmount, bool deductTransferFee) public view returns(uint256) {
            require(tAmount <= _totalSupply, "Amount must be less than supply");
            if (!deductTransferFee) {
                (uint256 rAmount,,,,) = _getValues(tAmount, _tFeePercent);
                return rAmount;
            } else {
                (,uint256 rTransferAmount,,,) = _getValues(tAmount, _tFeePercent);
                return rTransferAmount;
            }
        }
    
        function tokenFromRefraction(uint256 rAmount) public view returns(uint256) {
            require(rAmount <= _rTotal, "Amount must be less than total refractions");
            uint256 currentRate =  _getRate();
            return rAmount.div(currentRate);
        }
    
        function excludeAccount(address account) public onlyOwner() {
            require(!_isExcluded[account], "Account is already excluded");
            if(_rOwned[account] > 0) {
                _tOwned[account] = tokenFromRefraction(_rOwned[account]);
            }
            _isExcluded[account] = true;
            _excluded.push(account);
        }
    
        function includeAccount(address account) public onlyOwner() {
            require(_isExcluded[account], "Account is already excluded");
            for (uint256 i = 0; i < _excluded.length; i++) {
                if (_excluded[i] == account) {
                    _excluded[i] = _excluded[_excluded.length - 1];
                    _tOwned[account] = 0;
                    _isExcluded[account] = false;
                    _excluded.pop();
                    break;
                }
            }
        }
    
        function _approve(address owner, address spender, uint256 amount) internal override {
            require(owner != address(0), "ERC20: approve from the zero address");
            require(spender != address(0), "ERC20: approve to the zero address");
    
            _allowances[owner][spender] = amount;
            emit Approval(owner, spender, amount);
        }
    
        function _transfer(address sender, address recipient, uint256 amount) internal override {
            require(sender != address(0), "ERC20: transfer from the zero address");
            require(amount > 0, "Transfer amount must be greater than zero");
            require(endSale || sender == owner() || sender == address(this), "transfer paused for sale");
            if(sender == address(this) || sender == owner()) {
                _transferBothExcluded(sender, recipient, amount, 0);
            } else if(_isExcluded[sender] && !_isExcluded[recipient]) {
                _transferFromExcluded(sender, recipient, amount, _tFeePercent);
            } else if (!_isExcluded[sender] && _isExcluded[recipient]) {
                    _transferToExcluded(sender, recipient, amount, _tFeePercent);
            } else if (!_isExcluded[sender] && !_isExcluded[recipient]) {
                _transferStandard(sender, recipient, amount, _tFeePercent);
            } else if (_isExcluded[sender] && _isExcluded[recipient]) {
                _transferBothExcluded(sender, recipient, amount, 0);
            } else {
                _transferStandard(sender, recipient, amount, _tFeePercent);
            }
        }
        
    
        function _transferStandard(address sender, address recipient, uint256 tAmount, uint256 tFeePercent) private {
            (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee) = _getValues(tAmount, tFeePercent);
            _rOwned[sender] = _rOwned[sender].sub(rAmount);
            _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);       
            _refractFee(rFee, tFee);
            emit Transfer(sender, recipient, tTransferAmount);
        }
    
        function _transferToExcluded(address sender, address recipient, uint256 tAmount, uint256 tFeePercent) private {
            (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee) = _getValues(tAmount, tFeePercent);
            _rOwned[sender] = _rOwned[sender].sub(rAmount);
            _tOwned[recipient] = _tOwned[recipient].add(tTransferAmount);
            _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);           
            _refractFee(rFee, tFee);
            emit Transfer(sender, recipient, tTransferAmount);
        }
    
        function _transferFromExcluded(address sender, address recipient, uint256 tAmount, uint256 tFeePercent) private {
            (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee) = _getValues(tAmount, tFeePercent);
            _tOwned[sender] = _tOwned[sender].sub(tAmount);
            _rOwned[sender] = _rOwned[sender].sub(rAmount);
            _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);   
            _refractFee(rFee, tFee);
            emit Transfer(sender, recipient, tTransferAmount);
        }
    
        function _transferBothExcluded(address sender, address recipient, uint256 tAmount, uint256 tFeePercent) private {
            (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee) = _getValues(tAmount, tFeePercent);
            _tOwned[sender] = _tOwned[sender].sub(tAmount);
            _rOwned[sender] = _rOwned[sender].sub(rAmount);
            _tOwned[recipient] = _tOwned[recipient].add(tTransferAmount);
            _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);        
            _refractFee(rFee, tFee);
            emit Transfer(sender, recipient, tTransferAmount);
        }
    
        function _refractFee(uint256 rFee, uint256 tFee) private {
            _rTotal = _rTotal.sub(rFee);
            _tFeeTotal = _tFeeTotal.add(tFee);
        }
    
        function _getValues(uint256 tAmount, uint256 tFeePercent) private view returns (uint256, uint256, uint256, uint256, uint256) {
            (uint256 tTransferAmount, uint256 tFee) = _getTValues(tAmount, tFeePercent);
            uint256 currentRate =  _getRate();
            (uint256 rAmount, uint256 rTransferAmount, uint256 rFee) = _getRValues(tAmount, tFee, currentRate);
            return (rAmount, rTransferAmount, rFee, tTransferAmount, tFee);
        }
    
        function _getTValues(uint256 tAmount, uint256 tFeePercent) private pure returns (uint256, uint256) {
            uint256 tFee = tAmount.mul(tFeePercent).div(10000);
            uint256 tTransferAmount = tAmount.sub(tFee);
            return (tTransferAmount, tFee);
        }
    
        function _getRValues(uint256 tAmount, uint256 tFee, uint256 currentRate) private pure returns (uint256, uint256, uint256) {
            uint256 rAmount = tAmount.mul(currentRate);
            uint256 rFee = tFee.mul(currentRate);
            uint256 rTransferAmount = rAmount.sub(rFee);
            return (rAmount, rTransferAmount, rFee);
        }
    
        function _getRate() private view returns(uint256) {
            (uint256 rSupply, uint256 tSupply) = _getCurrentSupply();
            return rSupply.div(tSupply);
        }
    
        function _getCurrentSupply() private view returns(uint256, uint256) {
            uint256 rSupply = _rTotal;
            uint256 tSupply = _totalSupply;      
            for (uint256 i = 0; i < _excluded.length; i++) {
                if (_rOwned[_excluded[i]] > rSupply || _tOwned[_excluded[i]] > tSupply) return (_rTotal, _totalSupply);
                rSupply = rSupply.sub(_rOwned[_excluded[i]]);
                tSupply = tSupply.sub(_tOwned[_excluded[i]]);
            }
            if (rSupply < _rTotal.div(_totalSupply)) return (_rTotal, _totalSupply);
            return (rSupply, tSupply);
        }
    }