Contract Diff Checker

Contract Name:
VaultSushiLP

Contract Source Code:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import {ERC20} from "./ERC20.sol";
import {IERC20} from "./interfaces/IERC20.sol";
import {IOracle} from "./interfaces/IOracle.sol";
import {IPairUniV2} from "./interfaces/IPairUniV2.sol";
import {IRouterUniV2} from "./interfaces/IRouterUniV2.sol";
import {IRewarderMiniChefV2} from "./interfaces/IRewarderMiniChefV2.sol";

contract VaultSushiLP is ERC20 {
    error TransferFailed();

    IRewarderMiniChefV2 public rewarder; // MiniChefV2
    IRouterUniV2 public router; // UniswapV2Router02
    IPairUniV2 public asset; // UniswapV2Pair
    uint256 poolId;
    address[] public path0;
    address[] public path1;

    constructor(
        address _rewarder,
        address _router,
        uint256 _poolId,
        address[] memory _path0,
        address[] memory _path1
    )
        ERC20("SushiLP Vault", "vSLP", 18)
    {
        rewarder = IRewarderMiniChefV2(_rewarder);
        router = IRouterUniV2(_router);
        asset = IPairUniV2(rewarder.lpToken(poolId));
        poolId = _poolId;
        path0 = _path0;
        path1 = _path1;
    }

    function mint(uint256 amt, address usr) external returns (uint256) {
        earn();
        _pull(address(asset), msg.sender, amt);
        uint256 tma = totalManagedAssets();
        uint256 sha = tma == 0 ? amt : amt * totalSupply / tma;
        IERC20(address(asset)).approve(address(rewarder), amt);
        rewarder.deposit(poolId, amt, address(this));
        _mint(sha, usr);
        return sha;
    }

    function burn(uint256 sha, address usr) external returns (uint256) {
        earn();
        if (balanceOf[msg.sender] < sha) revert InsufficientBalance();
        uint256 tma = totalManagedAssets();
        uint256 amt = sha * tma / totalSupply;
        _burn(sha, msg.sender);
        rewarder.withdraw(poolId, amt, address(this));
        _push(address(asset), usr, amt);
        return amt;
    }

    function earn() public {
        rewarder.harvest(poolId, address(this));
        uint256 amt = IERC20(rewarder.SUSHI()).balanceOf(address(this));
        uint256 haf = amt / 2;
        if (amt == 0) return;
        if (path0.length > 0) {
          router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
              haf,
              0, // TODO fix using oracle
              path0,
              address(asset),
              type(uint256).max
          );
        }
        if (path1.length > 0) {
          router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
              amt - haf,
              0, // TODO fix using oracle
              path1,
              address(asset),
              type(uint256).max
          );
        }
        asset.mint(address(this));
        asset.skim(address(this));
        uint256 liq = IERC20(address(asset)).balanceOf(address(this));
        rewarder.deposit(poolId, liq, address(this));
    }

    function totalManagedAssets() public view returns (uint256) {
        (uint256 amt,) = rewarder.userInfo(poolId, address(this));
        return amt;
    }

    function _pull(address tkn, address usr, uint256 amt) internal {
        if (!IERC20(tkn).transferFrom(usr, address(this), amt)) revert
            TransferFailed();
    }

    function _push(address tkn, address usr, uint256 amt) internal {
        if (!IERC20(tkn).transfer(usr, amt)) revert TransferFailed();
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

contract ERC20 {
    error InsufficientBalance();
    error InsufficientAllowance();

    string public name;
    string public symbol;
    uint8 public immutable decimals;
    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    event Approval(address indexed src, address indexed guy, uint256 amt);
    event Transfer(address indexed src, address indexed dst, uint256 amt);

    constructor(string memory _name, string memory _symbol, uint8 _decimals) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
    }

    function transfer(address dst, uint256 amt) external returns (bool) {
        return transferFrom(msg.sender, dst, amt);
    }

    function transferFrom(address src, address dst, uint256 amt)
        public
        returns (bool)
    {
        if (balanceOf[src] < amt) revert InsufficientBalance();
        if (
            src != msg.sender && allowance[src][msg.sender] != type(uint256).max
        ) {
            if (allowance[src][msg.sender] < amt) revert InsufficientAllowance();
            allowance[src][msg.sender] = allowance[src][msg.sender] - amt;
        }
        balanceOf[src] = balanceOf[src] - amt;
        balanceOf[dst] = balanceOf[dst] + amt;
        emit Transfer(src, dst, amt);
        return true;
    }

    function approve(address usr, uint256 amt) external returns (bool) {
        allowance[msg.sender][usr] = amt;
        emit Approval(msg.sender, usr, amt);
        return true;
    }

    function _mint(uint256 amt, address usr) internal {
        balanceOf[usr] = balanceOf[usr] + amt;
        totalSupply = totalSupply + amt;
        emit Transfer(address(0), usr, amt);
    }

    function _burn(uint256 amt, address usr) internal {
        if (balanceOf[usr] < amt) revert InsufficientBalance();
        balanceOf[usr] = balanceOf[usr] - amt;
        totalSupply = totalSupply - amt;
        emit Transfer(usr, address(0), amt);
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

interface IERC20 {
    function decimals() external view returns (uint8);
    function totalSupply() external view returns (uint256);
    function balanceOf(address) external view returns (uint256);
    function approve(address, uint256) external returns (bool);
    function transfer(address, uint256) external returns (bool);
    function transferFrom(address, address, uint256) external returns (bool);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

interface IOracle {
    function latestAnswer() external view returns (int256);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

interface IPairUniV2 {
    function token0() external view returns (address);
    function token1() external view returns (address);
    function totalSupply() external view returns (uint256);
    function getReserves() external view returns (uint112, uint112, uint32);
    function mint(address) external returns (uint256 liquidity);
    function burn(address) external returns (uint256 amount0, uint256 amount1);
    function swap(uint256, uint256, address, bytes calldata) external;
    function skim(address to) external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

interface IRouterUniV2 {
    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    )
        external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

interface IRewarderMiniChefV2 {
    function SUSHI() external view returns (address);
    function lpToken(uint256) external view returns (address);
    function pendingSushi(uint256, address) external view returns (uint256);
    function userInfo(uint256, address) external view returns (uint256, int256);
    function deposit(uint256, uint256, address) external;
    function withdraw(uint256, uint256, address) external;
    function harvest(uint256, address) external;
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):