Skip to content

Commit e957184

Browse files
authored
feat: deprecated external position impl (#1424)
1 parent 813ea9b commit e957184

File tree

3 files changed

+211
-0
lines changed

3 files changed

+211
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// SPDX-License-Identifier: GPL-3.0
2+
3+
/*
4+
This file is part of the Enzyme Protocol.
5+
6+
(c) Enzyme Foundation <security@enzyme.finance>
7+
8+
For the full license information, please view the LICENSE
9+
file that was distributed with this source code.
10+
*/
11+
12+
pragma solidity 0.8.19;
13+
14+
import {Address} from "openzeppelin-solc-0.8/utils/Address.sol";
15+
import {IExternalPositionProxy} from "../../../../../persistent/external-positions/IExternalPositionProxy.sol";
16+
import {IVaultCore} from "../../../../../persistent/vault/interfaces/IVaultCore.sol";
17+
import {IExternalPosition} from "../../IExternalPosition.sol";
18+
19+
/// @title DeprecatedPositionLib Contract
20+
/// @author Enzyme Foundation <security@enzyme.finance>
21+
/// @notice An External Position library contract for deprecated positions
22+
contract DeprecatedPositionLib is IExternalPosition {
23+
error DeprecatedPositionLib__Deprecated();
24+
error DeprecatedPositionLib__OnlyVaultOwner();
25+
26+
function callFromVaultOwner(address _target, bytes calldata _data, uint256 _value) external {
27+
address vault = IExternalPositionProxy(address(this)).getVaultProxy();
28+
address owner = IVaultCore(vault).getOwner();
29+
if (msg.sender != owner) revert DeprecatedPositionLib__OnlyVaultOwner();
30+
31+
Address.functionCallWithValue({target: _target, data: _data, value: _value});
32+
}
33+
34+
// REVERT ALL REQUIRED FUNCTIONS
35+
36+
function init(bytes memory) external pure override {
37+
revert DeprecatedPositionLib__Deprecated();
38+
}
39+
40+
function receiveCallFromVault(bytes memory) external pure override {
41+
revert DeprecatedPositionLib__Deprecated();
42+
}
43+
44+
function getDebtAssets() external pure override returns (address[] memory, uint256[] memory) {
45+
revert DeprecatedPositionLib__Deprecated();
46+
}
47+
48+
function getManagedAssets() external pure override returns (address[] memory, uint256[] memory) {
49+
revert DeprecatedPositionLib__Deprecated();
50+
}
51+
}

tests/interfaces/interfaces.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ IAliceV2PositionLib.sol: AliceV2PositionLib.abi.json
142142
IAliceV2PositionParser.sol: AliceV2PositionParser.abi.json
143143
IMysoV3OptionWritingPositionLib.sol: MysoV3OptionWritingPositionLib.abi.json
144144
IMysoV3OptionWritingPositionParser.sol: MysoV3OptionWritingPositionParser.abi.json
145+
IDeprecatedPosition.sol: DeprecatedPositionLib.abi.json
145146

146147
# Value interpreter
147148
IValueInterpreter.sol: ValueInterpreter.abi.json
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// SPDX-License-Identifier: GPL-3.0
2+
pragma solidity 0.8.19;
3+
4+
import {IERC20 as IERC20Prod} from "openzeppelin-solc-0.8/token/ERC20/IERC20.sol";
5+
6+
import {
7+
IExternalPosition as IExternalPositionProd
8+
} from "contracts/release/extensions/external-position-manager/IExternalPosition.sol";
9+
import {
10+
IExternalPositionParser as IExternalPositionParserProd
11+
} from "contracts/release/extensions/external-position-manager/IExternalPositionParser.sol";
12+
13+
import {IntegrationTest} from "tests/bases/IntegrationTest.sol";
14+
import {IERC20} from "tests/interfaces/external/IERC20.sol";
15+
import {IComptrollerLib} from "tests/interfaces/internal/IComptrollerLib.sol";
16+
import {IDeprecatedPosition} from "tests/interfaces/internal/IDeprecatedPosition.sol";
17+
import {IVaultLib} from "tests/interfaces/internal/IVaultLib.sol";
18+
19+
contract MockExternalPositionLib is IExternalPositionProd {
20+
function init(bytes memory) external pure override {}
21+
22+
function receiveCallFromVault(bytes memory) external pure override {}
23+
24+
function getDebtAssets() external pure override returns (address[] memory, uint256[] memory) {}
25+
26+
function getManagedAssets() external pure override returns (address[] memory, uint256[] memory) {}
27+
}
28+
29+
contract MockExternalPositionParser is IExternalPositionParserProd {
30+
function parseAssetsForAction(address, uint256, bytes memory)
31+
external
32+
returns (address[] memory, uint256[] memory, address[] memory)
33+
{}
34+
35+
function parseInitArgs(address, bytes memory) external returns (bytes memory) {}
36+
}
37+
38+
contract DeprecatedPositionTest is IntegrationTest {
39+
IERC20 usdtToken = IERC20(ETHEREUM_USDT); // Use USDT because it has annoying behavior
40+
41+
IDeprecatedPosition deprecatedPosition;
42+
43+
address fundOwner;
44+
address comptrollerProxyAddress;
45+
address vaultProxyAddress;
46+
47+
// Creates a fund that holds a deprecated position
48+
function setUp() public override {
49+
setUpMainnetEnvironment();
50+
51+
// Deploy initial EP contracts
52+
address initialLibAddress = address(new MockExternalPositionLib());
53+
address initialParserAddress = address(new MockExternalPositionParser());
54+
55+
// Register the EP type with its initial contracts
56+
uint256 typeId = registerExternalPositionType({
57+
_externalPositionManager: core.release.externalPositionManager,
58+
_label: "POSITION_TO_BE_DEPRECATED",
59+
_lib: initialLibAddress,
60+
_parser: initialParserAddress
61+
});
62+
63+
// Create a fund
64+
IComptrollerLib comptrollerProxy;
65+
IVaultLib vaultProxy;
66+
(comptrollerProxy, vaultProxy, fundOwner) = createFundMinimal({_fundDeployer: core.release.fundDeployer});
67+
comptrollerProxyAddress = address(comptrollerProxy);
68+
vaultProxyAddress = address(vaultProxy);
69+
70+
// Deploy the position to be deprecated
71+
vm.prank(fundOwner);
72+
address positionAddress = createExternalPosition({
73+
_externalPositionManager: core.release.externalPositionManager,
74+
_comptrollerProxy: IComptrollerLib(comptrollerProxyAddress),
75+
_typeId: typeId,
76+
_initializationData: "",
77+
_callOnExternalPositionCallArgs: ""
78+
});
79+
80+
// Update to the deprecated lib and no parser
81+
address deprecatedLibAddress = __deployDeprecatedPositionLib();
82+
address deprecatedParserAddress = address(0);
83+
vm.prank(core.release.fundDeployer.getOwner());
84+
core.release.externalPositionManager
85+
.updateExternalPositionTypesInfo({
86+
_typeIds: toArray(typeId),
87+
_libs: toArray(deprecatedLibAddress),
88+
_parsers: toArray(deprecatedParserAddress)
89+
});
90+
91+
// Assign the deprecated position
92+
deprecatedPosition = IDeprecatedPosition(positionAddress);
93+
}
94+
95+
// DEPLOYMENT HELPERS
96+
97+
function __deployDeprecatedPositionLib() internal returns (address libAddress_) {
98+
return deployCode("DeprecatedPositionLib.sol");
99+
}
100+
101+
// TESTS
102+
103+
function test_callFromVaultOwner_fail_notVaultOwner() public {
104+
address assetManager = makeAddr("assetManager");
105+
address randomUser = makeAddr("randomUser");
106+
107+
bytes4 revertSelector = IDeprecatedPosition.DeprecatedPositionLib__OnlyVaultOwner.selector;
108+
109+
vm.expectRevert(revertSelector);
110+
vm.prank(assetManager);
111+
deprecatedPosition.callFromVaultOwner({_target: address(0), _data: "", _value: 0});
112+
113+
vm.expectRevert(revertSelector);
114+
vm.prank(randomUser);
115+
deprecatedPosition.callFromVaultOwner({_target: address(0), _data: "", _value: 0});
116+
}
117+
118+
function test_callFromVaultOwner_success_transferToken() public {
119+
uint256 tokenBalance = 1000e6;
120+
increaseTokenBalance({_token: usdtToken, _to: address(deprecatedPosition), _amount: tokenBalance});
121+
122+
address recipient = makeAddr("transferRecipient");
123+
uint256 transferAmount = tokenBalance / 3;
124+
125+
vm.prank(fundOwner);
126+
deprecatedPosition.callFromVaultOwner({
127+
_target: address(usdtToken),
128+
_data: abi.encodeWithSelector(IERC20Prod.transfer.selector, recipient, transferAmount),
129+
_value: 0
130+
});
131+
132+
assertEq(usdtToken.balanceOf(address(deprecatedPosition)), tokenBalance - transferAmount);
133+
assertEq(usdtToken.balanceOf(recipient), transferAmount);
134+
}
135+
136+
// ALL INTERFACE FUNCTIONS SHOULD REVERT
137+
bytes4 deprecatedRevertSelector = IDeprecatedPosition.DeprecatedPositionLib__Deprecated.selector;
138+
139+
function test_init_fail() public {
140+
vm.expectRevert(deprecatedRevertSelector);
141+
deprecatedPosition.init("");
142+
}
143+
144+
function test_receiveCallFromVault_fail() public {
145+
vm.expectRevert(deprecatedRevertSelector);
146+
vm.prank(address(vaultProxyAddress));
147+
deprecatedPosition.receiveCallFromVault("");
148+
}
149+
150+
function test_getDebtAssets_fail() public {
151+
vm.expectRevert(deprecatedRevertSelector);
152+
deprecatedPosition.getDebtAssets();
153+
}
154+
155+
function test_getManagedAssets_fail() public {
156+
vm.expectRevert(deprecatedRevertSelector);
157+
deprecatedPosition.getManagedAssets();
158+
}
159+
}

0 commit comments

Comments
 (0)