Skip to content

Commit 2b4b7db

Browse files
authored
Merge pull request #37 from Gearbox-protocol/liquidity-migrator
feat: liquidity migrator
2 parents 59f3594 + 9740340 commit 2b4b7db

File tree

5 files changed

+66
-4
lines changed

5 files changed

+66
-4
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
// Gearbox Protocol. Generalized leverage for DeFi protocols
3+
// (c) Gearbox Foundation, 2025.
4+
pragma solidity ^0.8.23;
5+
6+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
7+
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
8+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
9+
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
10+
import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol";
11+
12+
/// @title LiquidityMigrator
13+
/// @notice Allows the instance owner to migrate a pool position of a user from one pool to another. The user gives an approval of
14+
/// their pool shares to this contract. The instance owner can then migrate assets from specfic `poolFrom` to specific `poolTo`
15+
/// at their discretion.
16+
contract LiquidityMigrator is Ownable, IVersion {
17+
using SafeERC20 for IERC20;
18+
19+
bytes32 public constant contractType = "ZAPPER::LIQUIDITY_MIGRATOR";
20+
uint256 public constant version = 310;
21+
22+
error PoolAssetsDoNotMatchException();
23+
24+
event Migrate(address indexed user, uint256 assetsAmount);
25+
26+
/// @notice The pool the assets are being migrated from
27+
address public immutable poolFrom;
28+
/// @notice The pool the assets are being migrated to
29+
address public immutable poolTo;
30+
31+
/// @notice Constructs a new LiquidityMigrator
32+
/// @param ioProxy The address of the Instance Owner's ProxyCall contract. The instance owner migrates liquidity by
33+
/// calling `migrate` through the proxy.
34+
/// @param _poolFrom The address of the pool the assets are being migrated from.
35+
/// @param _poolTo The address of the pool the assets are being migrated to.
36+
constructor(address ioProxy, address _poolFrom, address _poolTo) {
37+
_transferOwnership(ioProxy);
38+
poolFrom = _poolFrom;
39+
poolTo = _poolTo;
40+
41+
address assetTo = IERC4626(poolTo).asset();
42+
address assetFrom = IERC4626(poolFrom).asset();
43+
44+
if (assetTo != assetFrom) {
45+
revert PoolAssetsDoNotMatchException();
46+
}
47+
48+
IERC20(assetTo).forceApprove(poolTo, type(uint256).max);
49+
}
50+
51+
/// @notice Migrates assets from `poolFrom` to `poolTo` for `user`
52+
/// @param user The address of the user whose assets are being migrated
53+
/// @param amount The amount of `poolFrom` LP shares to migrate
54+
function migrate(address user, uint256 amount) external onlyOwner {
55+
// Shares are redeemed from `poolFrom`, which returns the amount of assets withdrawn
56+
uint256 assetsAmount = IERC4626(poolFrom).redeem(amount, address(this), user);
57+
// The same amount of assets is deposited into `poolTo`, with the user as the receiver of new LP shares
58+
IERC4626(poolTo).deposit(assetsAmount, user);
59+
60+
emit Migrate(user, assetsAmount);
61+
}
62+
}
Submodule integrations-v3 updated 38 files

0 commit comments

Comments
 (0)