Skip to content

Commit 0b1827d

Browse files
lekhovitskyVan0k
andauthored
feat: account migration (#34)
* feat: migrator bot prototype * feat: migrator bot can migrate between pools * feat: migrator bot rc * feat: separate account migrator preview logic * fix: additional checks in migrator bot + custom pt deposits / withdrawals removed * feat: account migration now more robustly validates transferred amounts * fix: fix validation for 3.0 credit managers * feat: migrator bot tests + fixes * test: fix cursor artifacts in tests * fix: fix metadata fields and compiler warnings * fix: audit fixes --------- Co-authored-by: Van0k <ivkamakin@gmail.com>
1 parent 44cfb9f commit 0b1827d

19 files changed

+3338
-3
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// SPDX-License-Identifier: MIT
2+
// Gearbox Protocol. Generalized leverage for DeFi protocols
3+
// (c) Gearbox Foundation, 2025.
4+
pragma solidity ^0.8.23;
5+
6+
import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol";
7+
import {IStateSerializer} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IStateSerializer.sol";
8+
import {IBot} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IBot.sol";
9+
import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol";
10+
11+
import {PriceUpdate} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IPriceFeedStore.sol";
12+
import {MigrationParams, PreviewMigrationResult, PhantomTokenOverride} from "../types/AccountMigrationTypes.sol";
13+
14+
interface IAccountMigratorPreviewer is IVersion, IStateSerializer {
15+
function previewMigration(
16+
address sourceCreditAccount,
17+
address targetCreditManager,
18+
PriceUpdate[] memory priceUpdates
19+
) external returns (PreviewMigrationResult memory result);
20+
}
21+
22+
interface IAccountMigratorBot is IBot {
23+
function migrateCreditAccount(MigrationParams memory params, PriceUpdate[] memory priceUpdates) external;
24+
25+
function migrate(MigrationParams memory params) external;
26+
27+
function phantomTokenOverrides(address phantomToken) external view returns (PhantomTokenOverride memory);
28+
}
29+
30+
interface IAccountMigratorAdapter is IAdapter {
31+
function unlock() external;
32+
function lock() external;
33+
function migrate(MigrationParams memory params) external;
34+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// SPDX-License-Identifier: MIT
2+
// Gearbox Protocol. Generalized leverage for DeFi protocols
3+
// (c) Gearbox Foundation, 2025.
4+
pragma solidity ^0.8.23;
5+
6+
import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol";
7+
8+
struct TokenData {
9+
address token;
10+
uint256 balance;
11+
uint256 leftoverBalance;
12+
uint256 numSplits;
13+
bool claimRewards;
14+
}
15+
16+
struct RouterResult {
17+
uint256 amount;
18+
uint256 minAmount;
19+
MultiCall[] calls;
20+
}
21+
22+
interface IGearboxRouter {
23+
function routeOpenManyToOne(address creditManager, address target, uint256 slippage, TokenData[] calldata tData)
24+
external
25+
returns (RouterResult memory);
26+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
// Gearbox Protocol. Generalized leverage for DeFi protocols
3+
// (c) Gearbox Foundation, 2025.
4+
pragma solidity ^0.8.23;
5+
6+
import {AbstractAdapter} from "@gearbox-protocol/integrations-v3/contracts/adapters/AbstractAdapter.sol";
7+
import {IAccountMigratorAdapter} from "../interfaces/IAccountMigratorBot.sol";
8+
import {MigrationParams, MigratedCollateral} from "../types/AccountMigrationTypes.sol";
9+
10+
abstract contract AccountMigratorAdapter is AbstractAdapter {
11+
/// @dev Whether tha adapter is locked. The adapter should only be interactable when unlocked from the migrator bot,
12+
/// as the `migrate` function is fairly dangerous.
13+
bool public locked = true;
14+
15+
modifier onlyMigratorBot() {
16+
if (msg.sender != targetContract) {
17+
revert("MigratorAdapter: caller is not the migrator bot");
18+
}
19+
_;
20+
}
21+
22+
modifier whenUnlocked() {
23+
if (locked) {
24+
revert("MigratorAdapter: adapter is locked");
25+
}
26+
_;
27+
}
28+
29+
constructor(address _creditManager, address _migratorBot) AbstractAdapter(_creditManager, _migratorBot) {}
30+
31+
/// @dev Internal function to migrate collaterals to a new credit account
32+
function _migrate(MigrationParams memory params) internal {
33+
_approveTokens(params.migratedCollaterals, type(uint256).max);
34+
_execute(msg.data);
35+
_approveTokens(params.migratedCollaterals, 0);
36+
}
37+
38+
function _approveTokens(MigratedCollateral[] memory tokens, uint256 amount) internal {
39+
uint256 len = tokens.length;
40+
41+
for (uint256 i = 0; i < len; i++) {
42+
address token = tokens[i].phantomTokenParams.isPhantomToken
43+
? tokens[i].phantomTokenParams.underlying
44+
: tokens[i].collateral;
45+
_approveToken(token, amount);
46+
}
47+
}
48+
49+
function lock() external onlyMigratorBot {
50+
if (locked) {
51+
revert("MigratorAdapter: adapter is already locked");
52+
}
53+
54+
locked = true;
55+
}
56+
57+
function unlock() external onlyMigratorBot {
58+
if (!locked) {
59+
revert("MigratorAdapter: adapter is not locked");
60+
}
61+
62+
locked = false;
63+
}
64+
65+
/// @notice Serialized adapter parameters
66+
function serialize() external view returns (bytes memory serializedData) {
67+
serializedData = abi.encode(creditManager, targetContract);
68+
}
69+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
// Gearbox Protocol. Generalized leverage for DeFi protocols
3+
// (c) Gearbox Foundation, 2025.
4+
pragma solidity ^0.8.23;
5+
6+
import {NotImplementedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol";
7+
import {AccountMigratorAdapter} from "./AccountMigratorAdapter.sol";
8+
import {MigrationParams} from "../types/AccountMigrationTypes.sol";
9+
10+
contract AccountMigratorAdapterV30 is AccountMigratorAdapter {
11+
/// @dev Legacy adapter type for compatibility with 3.0 contracts
12+
uint8 public constant _gearboxAdapterType = 0;
13+
14+
/// @dev Legacy adapter version for compatibility with 3.0 contracts
15+
uint16 public constant _gearboxAdapterVersion = 3_00;
16+
17+
constructor(address _creditManager, address _targetContract)
18+
AccountMigratorAdapter(_creditManager, _targetContract)
19+
{}
20+
21+
function contractType() external pure returns (bytes32) {
22+
revert NotImplementedException();
23+
}
24+
25+
function version() external pure returns (uint256) {
26+
revert NotImplementedException();
27+
}
28+
29+
/// @notice Migrates collaterals to a new credit account, using the migrator bot as a target contract.
30+
function migrate(MigrationParams memory params)
31+
external
32+
whenUnlocked
33+
creditFacadeOnly
34+
returns (uint256 tokensToEnable, uint256 tokensToDisable)
35+
{
36+
_migrate(params);
37+
return (0, type(uint256).max);
38+
}
39+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
// Gearbox Protocol. Generalized leverage for DeFi protocols
3+
// (c) Gearbox Foundation, 2025.
4+
pragma solidity ^0.8.23;
5+
6+
import {AccountMigratorAdapter} from "./AccountMigratorAdapter.sol";
7+
8+
import {MigrationParams} from "../types/AccountMigrationTypes.sol";
9+
10+
contract AccountMigratorAdapterV31 is AccountMigratorAdapter {
11+
bytes32 public constant override contractType = "ADAPTER::ACCOUNT_MIGRATOR";
12+
uint256 public constant override version = 3_10;
13+
14+
constructor(address _creditManager, address _targetContract)
15+
AccountMigratorAdapter(_creditManager, _targetContract)
16+
{}
17+
18+
/// @notice Migrates collaterals to a new credit account, using the migrator bot as a target contract.
19+
function migrate(MigrationParams memory params) external whenUnlocked creditFacadeOnly returns (bool) {
20+
_migrate(params);
21+
return false;
22+
}
23+
}

0 commit comments

Comments
 (0)