-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathShared.sol
More file actions
165 lines (133 loc) · 5.53 KB
/
Copy pathShared.sol
File metadata and controls
165 lines (133 loc) · 5.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
// Test
import {Base_Test_} from "test/Base.sol";
// Contracts
import {Proxy} from "contracts/Proxy.sol";
import {EthenaARM} from "contracts/EthenaARM.sol";
import {EthenaUnstaker} from "contracts/EthenaUnstaker.sol";
import {EthenaAssetAdapter} from "contracts/adapters/EthenaAssetAdapter.sol";
// Interfaces
import {Mainnet} from "src/contracts/utils/Addresses.sol";
import {IERC20, IERC4626, IStakedUSDe} from "contracts/Interfaces.sol";
abstract contract Fork_Shared_Test is Base_Test_ {
uint256 public constant MAX_UNSTAKERS = 42;
//////////////////////////////////////////////////////
/// --- SETUP
//////////////////////////////////////////////////////
function setUp() public virtual override {
super.setUp();
// Generate a fork
_createAndSelectFork();
// Deploy Mock contracts
_deployMockContracts();
// Generate addresses
_generateAddresses();
// Deploy contracts
_deployContracts();
// Ignite test contract
_ignite();
// Label contracts
labelAll();
}
function _createAndSelectFork() internal {
// Check if the MAINNET_URL is set.
require(vm.envExists("MAINNET_URL"), "MAINNET_URL not set");
// Create and select a fork.
if (vm.envExists("FORK_BLOCK_NUMBER_MAINNET")) {
vm.createSelectFork("mainnet", vm.envUint("FORK_BLOCK_NUMBER_MAINNET"));
} else {
vm.createSelectFork("mainnet");
}
}
function _deployMockContracts() internal {
usde = IERC20(Mainnet.USDE);
susde = IERC4626(Mainnet.SUSDE);
badToken = IERC20(address(0xDEADBEEF));
}
function _generateAddresses() internal {
// Generate addresses
governor = makeAddr("governor");
deployer = makeAddr("deployer");
operator = makeAddr("operator");
feeCollector = makeAddr("feeCollector");
}
function _deployContracts() internal {
vm.startPrank(deployer);
// 1. Deploy Ethena ARM
ethenaARM = new EthenaARM({
_usde: address(usde), _claimDelay: 10 minutes, _minSharesToRedeem: 1e7, _allocateThreshold: 1 ether
});
// 2. Deploy Ethena ARM Proxy
ethenaProxy = new Proxy();
// Fund deployer with USDe and approve proxy to pull USDe for initialization
deal(address(usde), deployer, 1e12);
usde.approve(address(ethenaProxy), 1e12);
// 3. Initialize Ethena ARM Proxy
bytes memory data = abi.encodeWithSelector(
EthenaARM.initialize.selector,
"Ethena Staked USDe ARM",
"ARM-sUSDe-USDe",
operator, // operator
2000, // 20% fee
feeCollector, // feeCollector
address(0) // capManager
);
ethenaProxy.initialize(address(ethenaARM), governor, data);
vm.stopPrank();
// Assign Ethena ARM instance
ethenaARM = EthenaARM(address(ethenaProxy));
EthenaAssetAdapter adapterImpl = new EthenaAssetAdapter(address(ethenaARM), address(usde), address(susde));
Proxy adapterProxy = new Proxy();
adapterProxy.initialize(address(adapterImpl), governor, "");
ethenaAssetAdapter = EthenaAssetAdapter(address(adapterProxy));
}
function _buyPrice() internal view returns (uint256 buyPrice) {
(uint128 buyPriceMem,,,,,,,,) = ethenaARM.baseAssetConfigs(address(susde));
buyPrice = buyPriceMem;
}
function _sellPrice() internal view returns (uint256 sellPrice) {
(, uint128 sellPriceMem,,,,,,,) = ethenaARM.baseAssetConfigs(address(susde));
sellPrice = sellPriceMem;
}
function _crossPrice() internal view returns (uint256 crossPrice) {
(,,,, uint128 crossPriceMem,,,,) = ethenaARM.baseAssetConfigs(address(susde));
crossPrice = crossPriceMem;
}
function _expectedBuySideFee(uint256 amountIn, uint256 amountOut) internal view returns (uint256) {
uint256 realizedAssets = susde.convertToAssets(amountIn) * _crossPrice() / PRICE_SCALE;
uint256 gain = realizedAssets > amountOut ? realizedAssets - amountOut : 0;
return gain * ethenaARM.fee() / FEE_SCALE;
}
function _ignite() internal virtual {
// Assign contract instances
deal(address(usde), address(this), 1_000_000 ether);
deal(address(susde), address(this), 1_000_000 ether);
// Approve USDe and SUSDe to Ethena ARM
usde.approve(address(ethenaARM), type(uint256).max);
susde.approve(address(ethenaARM), type(uint256).max);
// Deposit some usde in the ARM
ethenaARM.deposit(10_000 ether);
vm.startPrank(ethenaARM.owner());
ethenaARM.addBaseAsset(
address(susde),
address(ethenaAssetAdapter),
0.9992e36,
0.9999e36,
type(uint128).max,
type(uint128).max,
0.9998e36,
false
);
ethenaAssetAdapter.setUnstakers(_deployUnstakers());
vm.stopPrank();
// Swap usde to susde using ARM to have some susde balance
ethenaARM.swapExactTokensForTokens(IERC20(address(susde)), usde, 5_000 ether, 0, address(this));
}
function _deployUnstakers() internal returns (address[MAX_UNSTAKERS] memory unstakers) {
for (uint256 i; i < MAX_UNSTAKERS; i++) {
address unstaker = address(new EthenaUnstaker(address(ethenaAssetAdapter), IStakedUSDe(Mainnet.SUSDE)));
unstakers[i] = address(unstaker);
}
}
}