contract Meowshi is ERC20, BaseBoringBatchable {
    IBentoBoxBasic private constant bentoBox = IBentoBoxBasic(0xF5BCE5077908a1b7370B9ae04AdC565EBd643966); // BENTO vault contract
    ISushiBar private constant sushiToken = ISushiBar(0x6B3595068778DD592e39A122f4f5a5cF09C90fE2); // SUSHI token contract
    address private constant sushiBar = 0x8798249c2E607446EfB7Ad49eC89dD1865Ff4272; // xSUSHI token contract for staking SUSHI

    string public constant name = "Meowshi";
    string public constant symbol = "NYAN";
    uint8 public constant decimals = 18;
    uint256 private constant multiplier = 10000; // 1 xSUSHI BENTO share = 10000 NYAN
    uint256 public totalSupply;
    
    constructor() {
        sushiToken.approve(sushiBar, type(uint256).max); // max approve xSUSHI to draw SUSHI from this contract
        ISushiBar(sushiBar).approve(address(bentoBox), type(uint256).max); // max approve BENTO to draw xSUSHI from this contract
    }
    
    // **** xSUSHI
    /// @notice Enter Meowshi. Deposit xSUSHI `amount`. Mint NYAN for `to`.
    function nyan(address to, uint256 amount) external returns (uint256 shares) {
        ISushiBar(sushiBar).transferFrom(msg.sender, address(this), amount);
        (, shares) = bentoBox.deposit(IERC20(sushiBar), address(this), address(this), amount, 0);
        nyanMint(to, shares * multiplier);
    }

    /// @notice Leave Meowshi. Burn NYAN `amount`. Claim xSUSHI for `to`.
    function unNyan(address to, uint256 amount) external returns (uint256 amountOut) {
        nyanBurn(amount);
        (amountOut, ) = bentoBox.withdraw(IERC20(sushiBar), address(this), to, 0, amount / multiplier);
    }
    
    // **** SUSHI
    /// @notice Enter Meowshi. Deposit SUSHI `amount`. Mint NYAN for `to`.
    function nyanSushi(address to, uint256 amount) external returns (uint256 shares) {
        sushiToken.transferFrom(msg.sender, address(this), amount);
        ISushiBar(sushiBar).enter(amount);
        (, shares) = bentoBox.deposit(IERC20(sushiBar), address(this), address(this), ISushiBar(sushiBar).balanceOf(address(this)), 0);
        nyanMint(to, shares * multiplier);
    }

    /// @notice Leave Meowshi. Burn NYAN `amount`. Claim SUSHI for `to`.
    function unNyanSushi(address to, uint256 amount) external returns (uint256 amountOut) {
        nyanBurn(amount);
        (amountOut, ) = bentoBox.withdraw(IERC20(sushiBar), address(this), address(this), 0, amount / multiplier);
        ISushiBar(sushiBar).leave(amountOut);
        sushiToken.transfer(to, sushiToken.balanceOf(address(this))); 
    }

    // **** SUPPLY
    /// @notice Internal mint function for *nyan*.
    function nyanMint(address to, uint256 amount) private {
        balanceOf[to] += amount;
        totalSupply += amount;
        emit Transfer(address(0), to, amount);
    }
    
    /// @notice Internal burn function for *unNyan*.
    function nyanBurn(uint256 amount) private {
        balanceOf[msg.sender] -= amount;
        totalSupply -= amount;
        emit Transfer(msg.sender, address(0), amount);
    }
}
//  ៱˳_˳៱   ∫
function nyanBurn(uint256 amount) private {
    balanceOf[msg.sender] -= amount;
    totalSupply -= amount;
    emit Transfer(msg.sender, address(0), amount);
}

/// @notice Internal burn function for *unNyan*.