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;
}