S Price: $0.730144 (+8.49%)

Contract Diff Checker

Contract Name:
IchiVaultRegistry

Contract Source Code:

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

import { ICustomConnectorRegistry } from "contracts/ConnectorRegistry.sol";
import { IchiConnector } from "contracts/connectors/IchiConnector.sol";
import { IICHIVault } from "contracts/interfaces/external/swapx/IIchiVault.sol";

interface IICHIVaultFactory {
    function genKey(
        address deployer,
        address token0,
        address token1,
        bool allowToken0,
        bool allowToken1
    ) external pure returns (bytes32 key);

    function getICHIVault(
        bytes32 vaultKey
    ) external view returns (address);
}

contract IchiVaultRegistry is ICustomConnectorRegistry {
    IchiConnector public immutable ichiConnector;
    IICHIVaultFactory public immutable ichiVaultFactory;

    constructor(IchiConnector ichiConnector_, IICHIVaultFactory vaultFactory_) {
        ichiConnector = ichiConnector_;
        ichiVaultFactory = vaultFactory_;
    }

    function connectorOf(
        address target
    ) external view override returns (address) {
        bytes memory data =
            abi.encodeWithSelector(IICHIVault.ichiVaultFactory.selector);
        (bool success, bytes memory returnData) = target.staticcall(data);
        if (success && returnData.length == 32) {
            address result = abi.decode(returnData, (address));
            if (result == address(ichiVaultFactory)) {
                bytes32 key = ichiVaultFactory.genKey(
                    IICHIVault(target).owner(),
                    IICHIVault(target).token0(),
                    IICHIVault(target).token1(),
                    IICHIVault(target).allowToken0(),
                    IICHIVault(target).allowToken1()
                );
                address ichiVault = ichiVaultFactory.getICHIVault(key);
                if (ichiVault == target) {
                    return address(ichiConnector);
                } else {
                    return address(0);
                }
            } else {
                return address(0);
            }
        } else {
            return address(0);
        }
    }
}

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

import { Admin } from "contracts/base/Admin.sol";
import { TimelockAdmin } from "contracts/base/TimelockAdmin.sol";

error ConnectorNotRegistered(address target);

interface ICustomConnectorRegistry {
    function connectorOf(address target) external view returns (address);
}

contract ConnectorRegistry is Admin, TimelockAdmin {
    event ConnectorChanged(address target, address connector);
    event CustomRegistryAdded(address registry);
    event CustomRegistryRemoved(address registry);

    error ConnectorAlreadySet(address target);
    error ConnectorNotSet(address target);

    ICustomConnectorRegistry[] public customRegistries;
    mapping(ICustomConnectorRegistry => bool) public isCustomRegistry;

    mapping(address target => address connector) private connectors_;

    constructor(
        address admin_,
        address timelockAdmin_
    ) Admin(admin_) TimelockAdmin(timelockAdmin_) { }

    /// @notice Update connector addresses for a batch of targets.
    /// @dev Controls which connector contracts are used for the specified
    /// targets.
    /// @custom:access Restricted to protocol admin.
    function setConnectors(
        address[] calldata targets,
        address[] calldata connectors
    ) external onlyAdmin {
        for (uint256 i; i != targets.length;) {
            if (connectors_[targets[i]] != address(0)) {
                revert ConnectorAlreadySet(targets[i]);
            }
            connectors_[targets[i]] = connectors[i];
            emit ConnectorChanged(targets[i], connectors[i]);

            unchecked {
                ++i;
            }
        }
    }

    function updateConnectors(
        address[] calldata targets,
        address[] calldata connectors
    ) external onlyTimelockAdmin {
        for (uint256 i; i != targets.length;) {
            if (connectors_[targets[i]] == address(0)) {
                revert ConnectorNotSet(targets[i]);
            }
            connectors_[targets[i]] = connectors[i];
            emit ConnectorChanged(targets[i], connectors[i]);

            unchecked {
                ++i;
            }
        }
    }

    /// @notice Append an address to the custom registries list.
    /// @custom:access Restricted to protocol admin.
    function addCustomRegistry(ICustomConnectorRegistry registry)
        external
        onlyAdmin
    {
        customRegistries.push(registry);
        isCustomRegistry[registry] = true;
        emit CustomRegistryAdded(address(registry));
    }

    /// @notice Replace an address in the custom registries list.
    /// @custom:access Restricted to protocol admin.
    function updateCustomRegistry(
        uint256 index,
        ICustomConnectorRegistry newRegistry
    ) external onlyTimelockAdmin {
        address oldRegistry = address(customRegistries[index]);
        isCustomRegistry[customRegistries[index]] = false;
        emit CustomRegistryRemoved(oldRegistry);
        customRegistries[index] = newRegistry;
        isCustomRegistry[newRegistry] = true;
        if (address(newRegistry) != address(0)) {
            emit CustomRegistryAdded(address(newRegistry));
        }
    }

    function connectorOf(address target) external view returns (address) {
        address connector = connectors_[target];
        if (connector != address(0)) {
            return connector;
        }

        uint256 length = customRegistries.length;
        for (uint256 i; i != length;) {
            if (address(customRegistries[i]) != address(0)) {
                try customRegistries[i].connectorOf(target) returns (
                    address _connector
                ) {
                    if (_connector != address(0)) {
                        return _connector;
                    }
                } catch {
                    // Ignore
                }
            }

            unchecked {
                ++i;
            }
        }

        revert ConnectorNotRegistered(target);
    }

    function hasConnector(address target) external view returns (bool) {
        if (connectors_[target] != address(0)) {
            return true;
        }

        uint256 length = customRegistries.length;
        for (uint256 i; i != length;) {
            if (address(customRegistries[i]) != address(0)) {
                try customRegistries[i].connectorOf(target) returns (
                    address _connector
                ) {
                    if (_connector != address(0)) {
                        return true;
                    }
                } catch {
                    // Ignore
                }

                unchecked {
                    ++i;
                }
            }
        }

        return false;
    }
}

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

import { IICHIVault } from "contracts/interfaces/external/swapx/IIchiVault.sol";
import {
    ILiquidityConnector,
    AddLiquidityParams,
    RemoveLiquidityParams,
    SwapParams,
    GetAmountOutParams
} from "contracts/interfaces/ILiquidityConnector.sol";

contract IchiConnector is ILiquidityConnector {
    error NotSupported();
    error PoolTokensNotAllowed();

    function addLiquidity(
        AddLiquidityParams memory addLiquidityParams
    ) external payable override {
        if (
            IICHIVault(addLiquidityParams.lpToken).allowToken0()
                && !IICHIVault(addLiquidityParams.lpToken).allowToken1()
        ) {
            IICHIVault(addLiquidityParams.lpToken).deposit(
                addLiquidityParams.desiredAmounts[0], 0, address(this)
            );
        } else if (
            !IICHIVault(addLiquidityParams.lpToken).allowToken0()
                && IICHIVault(addLiquidityParams.lpToken).allowToken1()
        ) {
            IICHIVault(addLiquidityParams.lpToken).deposit(
                0, addLiquidityParams.desiredAmounts[1], address(this)
            );
        } else if (
            IICHIVault(addLiquidityParams.lpToken).allowToken0()
                && IICHIVault(addLiquidityParams.lpToken).allowToken1()
        ) {
            IICHIVault(addLiquidityParams.lpToken).deposit(
                addLiquidityParams.desiredAmounts[0],
                addLiquidityParams.desiredAmounts[1],
                address(this)
            );
        } else {
            revert PoolTokensNotAllowed();
        }
    }

    function removeLiquidity(
        RemoveLiquidityParams memory removeLiquidityParams
    ) external override {
        IICHIVault(removeLiquidityParams.lpToken).withdraw(
            removeLiquidityParams.lpAmountIn, address(this)
        );
    }

    function swapExactTokensForTokens(
        SwapParams memory
    ) external payable override {
        revert NotSupported();
    }

    function getAmountOut(
        GetAmountOutParams memory
    ) external pure returns (uint256) {
        revert NotSupported();
    }
}

// SPDX-License-Identifier: Unlicense

pragma solidity >=0.8.4;

interface IICHIVault {
    function ichiVaultFactory() external view returns (address);

    function balanceOf(
        address
    ) external view returns (uint256);

    function pool() external view returns (address);

    function owner() external view returns (address);

    function token0() external view returns (address);

    function allowToken0() external view returns (bool);

    function token1() external view returns (address);

    function allowToken1() external view returns (bool);

    function fee() external view returns (uint24);

    function tickSpacing() external view returns (int24);

    function ammFeeRecipient() external view returns (address);

    function affiliate() external view returns (address);

    function baseLower() external view returns (int24);

    function baseUpper() external view returns (int24);

    function limitLower() external view returns (int24);

    function limitUpper() external view returns (int24);

    /// @notice NFT ID of the base position. If 0, the base position is not
    /// initialized.
    function basePositionId() external view returns (uint256);

    /// @notice NFT ID of the limit position. If 0, the limit position is not
    /// initialized.
    function limitPositionId() external view returns (uint256);

    function deposit0Max() external view returns (uint256);

    function deposit1Max() external view returns (uint256);

    function hysteresis() external view returns (uint256);

    function twapPeriod() external view returns (uint32);

    function auxTwapPeriod() external view returns (uint32);

    function getTotalAmounts() external view returns (uint256, uint256);

    function getBasePosition()
        external
        view
        returns (uint128, uint256, uint256);

    function getLimitPosition()
        external
        view
        returns (uint128, uint256, uint256);

    function deposit(uint256, uint256, address) external returns (uint256);

    function withdraw(uint256, address) external returns (uint256, uint256);

    function currentTick() external view returns (int24);

    function resetAllowances() external;

    function rebalance(
        int24 _baseLower,
        int24 _baseUpper,
        int24 _limitLower,
        int24 _limitUpper,
        int256 swapQuantity
    ) external;

    function collectFees() external returns (uint256 fees0, uint256 fees1);

    function setDepositMax(
        uint256 _deposit0Max,
        uint256 _deposit1Max
    ) external;

    function setHysteresis(
        uint256 _hysteresis
    ) external;

    function setAmmFeeRecipient(
        address _ammFeeRecipient
    ) external;

    function setAffiliate(
        address _affiliate
    ) external;

    function setTwapPeriod(
        uint32 newTwapPeriod
    ) external;

    function setAuxTwapPeriod(
        uint32 newAuxTwapPeriod
    ) external;
}

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

/// @title Admin contract
/// @author vfat.tools
/// @notice Provides an administration mechanism allowing restricted functions
abstract contract Admin {
    /// ERRORS ///

    /// @notice Thrown when the caller is not the admin
    error NotAdminError(); //0xb5c42b3b

    /// EVENTS ///

    /// @notice Emitted when a new admin is set
    /// @param oldAdmin Address of the old admin
    /// @param newAdmin Address of the new admin
    event AdminSet(address oldAdmin, address newAdmin);

    /// STORAGE ///

    /// @notice Address of the current admin
    address public admin;

    /// MODIFIERS ///

    /// @dev Restricts a function to the admin
    modifier onlyAdmin() {
        if (msg.sender != admin) revert NotAdminError();
        _;
    }

    /// WRITE FUNCTIONS ///

    /// @param admin_ Address of the admin
    constructor(address admin_) {
        emit AdminSet(admin, admin_);
        admin = admin_;
    }

    /// @notice Sets a new admin
    /// @param newAdmin Address of the new admin
    /// @custom:access Restricted to protocol admin.
    function setAdmin(address newAdmin) external onlyAdmin {
        emit AdminSet(admin, newAdmin);
        admin = newAdmin;
    }
}

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

/// @title TimelockAdmin contract
/// @author vfat.tools
/// @notice Provides an timelockAdministration mechanism allowing restricted
/// functions
abstract contract TimelockAdmin {
    /// ERRORS ///

    /// @notice Thrown when the caller is not the timelockAdmin
    error NotTimelockAdminError();

    /// EVENTS ///

    /// @notice Emitted when a new timelockAdmin is set
    /// @param oldTimelockAdmin Address of the old timelockAdmin
    /// @param newTimelockAdmin Address of the new timelockAdmin
    event TimelockAdminSet(address oldTimelockAdmin, address newTimelockAdmin);

    /// STORAGE ///

    /// @notice Address of the current timelockAdmin
    address public timelockAdmin;

    /// MODIFIERS ///

    /// @dev Restricts a function to the timelockAdmin
    modifier onlyTimelockAdmin() {
        if (msg.sender != timelockAdmin) revert NotTimelockAdminError();
        _;
    }

    /// WRITE FUNCTIONS ///

    /// @param timelockAdmin_ Address of the timelockAdmin
    constructor(address timelockAdmin_) {
        emit TimelockAdminSet(timelockAdmin, timelockAdmin_);
        timelockAdmin = timelockAdmin_;
    }

    /// @notice Sets a new timelockAdmin
    /// @dev Can only be called by the current timelockAdmin
    /// @param newTimelockAdmin Address of the new timelockAdmin
    function setTimelockAdmin(address newTimelockAdmin)
        external
        onlyTimelockAdmin
    {
        emit TimelockAdminSet(timelockAdmin, newTimelockAdmin);
        timelockAdmin = newTimelockAdmin;
    }
}

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

import {
    AddLiquidityParams,
    RemoveLiquidityParams,
    SwapParams,
    GetAmountOutParams
} from "contracts/structs/LiquidityStructs.sol";

interface ILiquidityConnector {
    function addLiquidity(
        AddLiquidityParams memory addLiquidityParams
    ) external payable;

    function removeLiquidity(
        RemoveLiquidityParams memory removeLiquidityParams
    ) external;

    function swapExactTokensForTokens(
        SwapParams memory swap
    ) external payable;

    function getAmountOut(
        GetAmountOutParams memory getAmountOutParams
    ) external view returns (uint256);
}

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

struct AddLiquidityParams {
    address router;
    address lpToken;
    address[] tokens;
    uint256[] desiredAmounts;
    uint256[] minAmounts;
    bytes extraData;
}

struct RemoveLiquidityParams {
    address router;
    address lpToken;
    address[] tokens;
    uint256 lpAmountIn;
    uint256[] minAmountsOut;
    bytes extraData;
}

struct SwapParams {
    address router;
    uint256 amountIn;
    uint256 minAmountOut;
    address tokenIn;
    bytes extraData;
}

struct GetAmountOutParams {
    address router;
    address lpToken;
    address tokenIn;
    address tokenOut;
    uint256 amountIn;
}

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

Context size (optional):