ETH Price: $1,953.16 (-1.73%)

Contract Diff Checker

Contract Name:
ZenjiViewHelper

Contract Source Code:

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.33;

import { ILoanManager } from "./interfaces/ILoanManager.sol";
import { IYieldStrategy } from "./interfaces/IYieldStrategy.sol";
import { IERC20 } from "./interfaces/IERC20.sol";

interface IZenjiView {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function getTotalCollateral() external view returns (uint256);
    function loanManager() external view returns (ILoanManager);
    function collateralAsset() external view returns (IERC20);
    function debtAsset() external view returns (IERC20);
    function idle() external view returns (bool);
    function targetLtv() external view returns (uint256);
    function DEADBAND_SPREAD() external view returns (uint256);
    function feeRate() external view returns (uint256);
    function PRECISION() external view returns (uint256);
    function accumulatedFees() external view returns (uint256);
    function lastStrategyBalance() external view returns (uint256);
    function yieldStrategy() external view returns (IYieldStrategy);
    function VIRTUAL_SHARE_OFFSET() external view returns (uint256);
}

/// @title ZenjiViewHelper
/// @notice External helper for view utilities to reduce Zenji bytecode size
contract ZenjiViewHelper {
    function getUserValue(address vault, address user)
        external
        view
        returns (uint256 collateralValue)
    {
        IZenjiView v = IZenjiView(vault);
        uint256 supply = v.totalSupply();
        if (supply == 0) return 0;
        uint256 userShares = v.balanceOf(user);
        uint256 offset = v.VIRTUAL_SHARE_OFFSET();
        return (userShares * (v.getTotalCollateral() + offset)) / (supply + offset);
    }

    function getHealth(address vault) external view returns (int256 health) {
        return IZenjiView(vault).loanManager().getHealth();
    }

    function isRebalanceNeeded(address vault) external view returns (bool needed) {
        ILoanManager lm = IZenjiView(vault).loanManager();
        if (!lm.loanExists()) return false;
        uint256 ltv = lm.getCurrentLTV();
        uint256 target = IZenjiView(vault).targetLtv();
        uint256 deadband = IZenjiView(vault).DEADBAND_SPREAD();
        return ltv < (target - deadband) || ltv > (target + deadband);
    }

    function getLtvBounds(address vault)
        external
        view
        returns (uint256 lowerBand, uint256 upperBand)
    {
        IZenjiView v = IZenjiView(vault);
        uint256 target = v.targetLtv();
        uint256 deadband = v.DEADBAND_SPREAD();
        lowerBand = target - deadband;
        upperBand = target + deadband;
    }

    function getPendingFees(address vault)
        external
        view
        returns (uint256 totalFees, uint256 pendingFees)
    {
        IZenjiView v = IZenjiView(vault);
        IYieldStrategy strategy = v.yieldStrategy();
        uint256 strategyBalance = strategy.balanceOf();
        uint256 lastBalance = v.lastStrategyBalance();
        if (strategyBalance > lastBalance) {
            uint256 delta = strategyBalance - lastBalance;
            pendingFees = (delta * v.feeRate()) / v.PRECISION();
        }

        totalFees = v.accumulatedFees() + pendingFees;
    }

    /// @notice Get total value in collateral asset units (e.g., WBTC satoshis)
    /// @dev Computes all values natively in collateral terms to avoid double conversion errors
    function getTotalCollateralValue(address vault) external view returns (uint256 totalValue) {
        IZenjiView v = IZenjiView(vault);
        ILoanManager lm = v.loanManager();

        if (v.idle()) {
            return v.collateralAsset().balanceOf(vault);
        }

        // Idle collateral in vault (native units)
        totalValue = v.collateralAsset().balanceOf(vault);

        // Net collateral value in loan manager (collateral - debt in collateral terms)
        totalValue += lm.getNetCollateralValue();

        // Yield strategy balance converted to collateral (excluding fees)
        IYieldStrategy strategy = v.yieldStrategy();
        if (address(strategy) != address(0)) {
            uint256 strategyBalance = strategy.balanceOf();
            uint256 accFees = v.accumulatedFees();
            if (strategyBalance > accFees) {
                totalValue += lm.getDebtValue(strategyBalance - accFees);
            }
        }

        // Idle debt asset in vault converted to collateral
        uint256 idleDebt = v.debtAsset().balanceOf(vault);
        if (idleDebt > 0) {
            totalValue += lm.getDebtValue(idleDebt);
        }

        // Raw collateral in loan manager (not yet supplied)
        totalValue += lm.getCollateralBalance();

        // Raw debt asset in loan manager converted to collateral
        uint256 lmDebt = lm.getDebtBalance();
        if (lmDebt > 0) {
            totalValue += lm.getDebtValue(lmDebt);
        }
    }

    /// @notice Get total value in debt asset units (for diagnostics/logging)
    /// @dev This is a diagnostic function - use getTotalCollateralValue for actual accounting
    function getTotalDebtValue(address vault) external view returns (uint256 totalValue) {
        IZenjiView v = IZenjiView(vault);
        ILoanManager lm = v.loanManager();

        if (v.idle()) {
            return lm.getCollateralValue(v.collateralAsset().balanceOf(vault));
        }

        // Idle collateral converted to debt units
        totalValue = lm.getCollateralValue(v.collateralAsset().balanceOf(vault));

        // Position value in debt terms
        if (lm.loanExists()) {
            (uint256 collateral, uint256 debt) = lm.getPositionValues();
            uint256 collateralInDebt = lm.getCollateralValue(collateral);
            if (collateralInDebt > debt) {
                totalValue += collateralInDebt - debt;
            }
        }

        // Strategy balance (already in debt units, minus fees)
        IYieldStrategy strategy = v.yieldStrategy();
        if (address(strategy) != address(0)) {
            uint256 strategyBalance = strategy.balanceOf();
            uint256 accFees = v.accumulatedFees();
            if (strategyBalance > accFees) {
                totalValue += strategyBalance - accFees;
            }
        }

        // Idle debt in vault
        totalValue += v.debtAsset().balanceOf(vault);

        // Raw collateral in loan manager converted to debt
        uint256 lmCollateral = lm.getCollateralBalance();
        if (lmCollateral > 0) {
            totalValue += lm.getCollateralValue(lmCollateral);
        }

        // Raw debt in loan manager
        totalValue += lm.getDebtBalance();
    }

    function yieldCostBasis(address vault) external view returns (uint256) {
        return IZenjiView(vault).yieldStrategy().costBasis();
    }

    function getYieldStrategyStats(address vault)
        external
        view
        returns (
            string memory strategyName,
            uint256 currentValue,
            uint256 costBasis,
            uint256 unrealizedProfit
        )
    {
        IYieldStrategy strategy = IZenjiView(vault).yieldStrategy();
        strategyName = strategy.name();
        currentValue = strategy.balanceOf();
        costBasis = strategy.costBasis();
        unrealizedProfit = strategy.unrealizedProfit();
    }

    function getYieldVaultStats(address vault)
        external
        view
        returns (
            uint256 yieldShares,
            uint256 currentValue,
            uint256 costBasis,
            uint256 unrealizedProfit
        )
    {
        IYieldStrategy strategy = IZenjiView(vault).yieldStrategy();
        return (0, strategy.balanceOf(), strategy.costBasis(), strategy.unrealizedProfit());
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.33;

/// @title ILoanManager
/// @notice Interface for loan managers that handle collateralized borrowing
interface ILoanManager {
    // ============ Events ============
    event LoanCreated(uint256 collateral, uint256 debt, uint256 bands);
    event CollateralAdded(uint256 amount);
    event LoanBorrowedMore(uint256 collateral, uint256 debt);
    event LoanRepaid(uint256 amount);
    event CollateralRemoved(uint256 amount);

    // ============ Errors ============
    error Unauthorized();
    error InvalidAddress();
    error InvalidPrice();
    error StaleOracle();
    error DebtNotFullyRepaid();
    error ZeroAmount();
    error TransferFailed();

    // ============ Loan Management Functions ============

    /// @notice Create a new loan with collateral
    /// @param collateral Amount of collateral asset
    /// @param debt Amount of debt asset to borrow
    /// @param bands Number of bands for the loan (if applicable)
    function createLoan(uint256 collateral, uint256 debt, uint256 bands) external;

    /// @notice Add collateral to an existing loan
    /// @param collateral Amount of collateral asset
    function addCollateral(uint256 collateral) external;

    /// @notice Borrow more against existing collateral
    /// @param collateral Additional collateral (can be 0)
    /// @param debt Additional debt to borrow
    function borrowMore(uint256 collateral, uint256 debt) external;

    /// @notice Repay debt
    /// @param amount Amount of debt asset to repay
    function repayDebt(uint256 amount) external;

    /// @notice Remove collateral from the loan
    /// @param amount Amount of collateral asset to remove
    function removeCollateral(uint256 amount) external;

    /// @notice Unified position unwind for both partial and full withdrawals
    /// @dev Pass type(uint256).max for collateralNeeded to fully close the position.
    /// @param collateralNeeded Amount of collateral to free, or type(uint256).max for full close
    function unwindPosition(uint256 collateralNeeded) external;

    // ============ View Functions ============

    /// @notice Get current LTV ratio
    /// @return ltv Current LTV (1e18 = 100%)
    function getCurrentLTV() external view returns (uint256 ltv);

    /// @notice Get current collateral amount
    /// @return collateral Current collateral amount
    function getCurrentCollateral() external view returns (uint256 collateral);

    /// @notice Get current debt amount
    /// @return debt Current debt amount
    function getCurrentDebt() external view returns (uint256 debt);

    /// @notice Collateral asset used by this loan manager
    function collateralAsset() external view returns (address);

    /// @notice Debt asset used by this loan manager
    function debtAsset() external view returns (address);

    /// @notice Get vault health factor
    /// @return health Health factor (positive = healthy)
    function getHealth() external view returns (int256 health);

    /// @notice Check if loan exists
    /// @return exists True if loan exists
    function loanExists() external view returns (bool exists);

    /// @notice Get collateral value in debt asset terms
    /// @param collateralAmount Amount of collateral asset
    /// @return value Value in debt asset (18 decimals unless specified by implementation)
    function getCollateralValue(uint256 collateralAmount) external view returns (uint256 value);

    /// @notice Get debt asset value in collateral terms
    /// @param debtAmount Amount of debt asset
    /// @return value Value in collateral asset (collateral decimals)
    function getDebtValue(uint256 debtAmount) external view returns (uint256 value);

    /// @notice Calculate borrow amount for given collateral and target LTV
    /// @param collateral Amount of collateral asset
    /// @param targetLtv Target LTV (1e18 = 100%)
    /// @return borrowAmount Amount of debt asset to borrow
    function calculateBorrowAmount(uint256 collateral, uint256 targetLtv)
        external
        view
        returns (uint256 borrowAmount);

    /// @notice Calculate health after hypothetical changes
    /// @param dCollateral Change in collateral
    /// @param dDebt Change in debt
    /// @return health Projected health factor
    function healthCalculator(int256 dCollateral, int256 dDebt)
        external
        view
        returns (int256 health);

    /// @notice Get minimum collateral required for a debt amount
    /// @param debt_ Desired debt amount
    /// @param bands Number of bands
    /// @return Minimum collateral required
    function minCollateral(uint256 debt_, uint256 bands) external view returns (uint256);

    /// @notice Get position values (collateral and debt)
    /// @return collateralValue Current collateral value
    /// @return debtValue Current debt value
    function getPositionValues()
        external
        view
        returns (uint256 collateralValue, uint256 debtValue);

    /// @notice Get net collateral value (collateral - debt in collateral terms)
    /// @return value Net value in collateral asset
    function getNetCollateralValue() external view returns (uint256 value);

    /// @notice Check oracle freshness
    function checkOracleFreshness() external view;

    // ============ Token Management ============

    /// @notice Transfer collateral from this contract
    /// @param to Recipient address
    /// @param amount Amount to transfer
    function transferCollateral(address to, uint256 amount) external;

    /// @notice Transfer debt asset from this contract
    /// @param to Recipient address
    /// @param amount Amount to transfer
    function transferDebt(address to, uint256 amount) external;

    /// @notice Get collateral balance of this contract
    /// @return balance Collateral balance
    function getCollateralBalance() external view returns (uint256 balance);

    /// @notice Get debt balance of this contract
    /// @return balance Debt balance
    function getDebtBalance() external view returns (uint256 balance);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.33;

/// @title IYieldStrategy
/// @notice Interface for yield strategies used by Zenji
/// @dev All strategies accept the debt asset from the vault and deploy to yield-generating protocols
interface IYieldStrategy {
    // ============ Events ============

    event Deposited(uint256 debtAssetAmount, uint256 underlyingDeposited);
    event Withdrawn(uint256 debtAssetAmount, uint256 debtAssetReceived);
    event Harvested(uint256 rewardsValue);
    event EmergencyWithdrawn(uint256 debtAssetReceived);
    event StrategyPauseToggled(bool paused, uint256 debtAssetReceived);

    // ============ Errors ============

    error Unauthorized();
    error ZeroAmount();
    error StrategyPaused();
    error SlippageExceeded();
    error TransferFailed();
    error InvalidAddress();

    // ============ Core Functions ============

    /// @notice Deposit debt asset into the yield strategy
    /// @param debtAssetAmount Amount of debt asset to deposit
    /// @return underlyingDeposited Amount deposited into the underlying protocol
    function deposit(uint256 debtAssetAmount) external returns (uint256 underlyingDeposited);

    /// @notice Withdraw debt asset from the yield strategy
    /// @param debtAssetAmount Amount of debt asset to withdraw
    /// @return debtAssetReceived Actual debt asset received (may differ due to slippage)
    function withdraw(uint256 debtAssetAmount) external returns (uint256 debtAssetReceived);

    /// @notice Withdraw all assets from the yield strategy
    /// @return debtAssetReceived Total debt asset received
    function withdrawAll() external returns (uint256 debtAssetReceived);

    /// @notice Harvest rewards and compound them back into the strategy
    /// @return rewardsValue Value of rewards harvested (in debt asset terms)
    function harvest() external returns (uint256 rewardsValue);

    /// @notice Emergency withdraw all assets, bypassing slippage checks
    /// @return debtAssetReceived Total debt asset received
    function emergencyWithdraw() external returns (uint256 debtAssetReceived);

    /// @notice Toggle pause state for the strategy
    /// @dev When pausing, should unwind all deployed assets back to the vault
    /// @return debtAssetReceived Total debt asset received if unwound (0 when unpausing)
    function pauseStrategy() external returns (uint256 debtAssetReceived);

    // ============ View Functions ============

    /// @notice Returns the asset accepted by the strategy (debt asset)
    function asset() external view returns (address);

    /// @notice Returns the underlying asset of the yield protocol (debt asset or swapped asset)
    function underlyingAsset() external view returns (address);

    /// @notice Returns the current value of the strategy holdings in debt asset terms
    function balanceOf() external view returns (uint256);

    /// @notice Returns the total debt asset deposited (cost basis)
    function costBasis() external view returns (uint256);

    /// @notice Returns unrealized profit (current value - cost basis)
    function unrealizedProfit() external view returns (uint256);

    /// @notice Returns pending rewards value in debt asset terms
    function pendingRewards() external view returns (uint256);

    /// @notice Returns whether the strategy is paused
    function paused() external view returns (bool);

    /// @notice Returns the strategy name
    function name() external view returns (string memory);

    /// @notice Returns the vault address
    function vault() external view returns (address);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.33;

/// @title IERC20
/// @notice Standard ERC20 interface
interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, 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 from, address to, uint256 amount) external returns (bool);
    function decimals() external view returns (uint8);
    function symbol() external view returns (string memory);
    function name() external view returns (string memory);
}

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

Context size (optional):