Skip to content

Commit 1e69572

Browse files
chore: refactor
1 parent 3eca48a commit 1e69572

13 files changed

+685
-729
lines changed

contracts/interfaces/IStrategy.sol

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
pragma solidity 0.8.13;
1+
pragma solidity 0.8.19;
22

33
interface IStrategy {
4-
54
function withdraw(uint256 amount_) external returns (uint256 loss_);
65
function estimatedTotalAssets() external view returns (uint256 totalAssets_);
6+
function invest() external;
77
}
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// SPDX-License-Identifier: GPL-3.0-only
2+
pragma solidity 0.8.19;
3+
4+
5+
6+
contract AaveStrategy {
7+
function withdraw(uint256 amount_) external returns (uint256 loss_);
8+
function estimatedTotalAssets() external view returns (uint256 totalAssets_);
9+
}

contracts/superbridge/FiatTokenV2_1/IFiatTokenV2_1_Mintable.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
pragma solidity 0.8.13;
1+
pragma solidity 0.8.19;
22

33
import "solmate/tokens/ERC20.sol";
44

contracts/superbridge/Gauge.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
pragma solidity 0.8.13;
1+
pragma solidity 0.8.19;
22

33
abstract contract Gauge {
44
struct LimitParams {

contracts/superbridge/IMintableERC20.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
pragma solidity 0.8.13;
1+
pragma solidity 0.8.19;
22

33
import "solmate/tokens/ERC20.sol";
44

contracts/superbridge/RescueFundsLib.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: GPL-3.0-only
2-
pragma solidity 0.8.13;
2+
pragma solidity ^0.8.13;
33

44
import "solmate/utils/SafeTransferLib.sol";
55

contracts/superbridge/VaultProxy.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: GPL-3.0-only
2-
pragma solidity ^0.8.0;
2+
pragma solidity 0.8.19;
33

44
import "openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
55

contracts/superbridge/YVault.sol

+64-115
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,36 @@
11
// SPDX-License-Identifier: GPL-3.0-only
2-
pragma solidity 0.8.13;
2+
pragma solidity 0.8.19;
33

44
import "solmate/mixins/ERC4626.sol";
55
import "openzeppelin-contracts/contracts/access/Ownable2Step.sol";
66
import {Gauge} from "./Gauge.sol";
77
import {IStrategy} from "../interfaces/IStrategy.sol";
8-
import {RescueFundsLib} from "./RescueFundsLib.sol";
8+
import "./RescueFundsLib.sol";
99
import "openzeppelin-contracts/contracts/utils/math/Math.sol";
10+
import "openzeppelin-contracts/contracts/security/ReentrancyGuard.sol";
1011

11-
// add report external function (called from cron)
12-
// call report from withdraw and deposit too (with timestamp check, settable by admin)
12+
13+
// add rebalance external function (called from cron)
14+
// call rebalance from withdraw and deposit too (with timestamp check, settable by admin)
1315
// pausable vault
1416
// redeem all from strategy and detach
1517
// reentrancy guard
1618

19+
20+
21+
1722
contract YVault is Gauge, Ownable2Step, ERC4626 {
1823
using SafeTransferLib for ERC20;
1924
ERC20 public immutable token__;
2025

2126
uint256 public totalIdle; // Amount of tokens that are in the vault
2227
uint256 public totalDebt; // Amount of tokens that strategy have borrowed
23-
24-
uint256 public totalProfit; // Amount of tokens that strategy have earned
25-
uint256 public totalLoss; // Amount of tokens that strategy have lost
2628
uint256 public debtRatio; // Debt ratio for the Vault (in BPS, <= 10k)
29+
uint128 public lastRebalanceTimestamp; // Timstamp of last rebalance
30+
uint128 public rebalanceingDelay; // Delay between rebalances
2731
address public strategy; // address of the strategy contract
32+
bool public emergencyShutdown; // if true, no funds can be invested in the strategy
33+
2834
uint256 public constant MAX_BPS = 10_000;
2935
struct UpdateLimitParams {
3036
bool isLock;
@@ -36,9 +42,9 @@ contract YVault is Gauge, Ownable2Step, ERC4626 {
3642
error ConnectorUnavailable();
3743
error ZeroAmount();
3844
error DebtRatioTooHigh();
39-
error ZeroAddress();
4045
error InvestingAboveThreshold();
4146
error NotEnoughAssets();
47+
error VaultShutdown();
4248

4349
event LimitParamsUpdated(UpdateLimitParams[] updates);
4450
event TokensDeposited(address depositor, uint256 depositAmount);
@@ -68,20 +74,19 @@ contract YVault is Gauge, Ownable2Step, ERC4626 {
6874
address receiver,
6975
uint256 unlockedAmount
7076
);
71-
event WithdrawFromStrategy(uint256 withdrawn, uint256 loss);
72-
73-
event StrategyReported(
74-
address strategy,
75-
uint256 profit,
76-
uint256 loss,
77-
uint256 debtPayment,
78-
uint256 totalProfit,
79-
uint256 totalLoss,
77+
event WithdrawFromStrategy(uint256 withdrawn);
78+
79+
event Rebalanced(
80+
uint256 totalIdle,
8081
uint256 totalDebt,
8182
uint256 credit,
82-
uint256 debtRatio
83+
uint256 debtOutstanding
8384
);
8485

86+
modifier notShutdown() {
87+
if (emergencyShutdown) revert VaultShutdown();
88+
_;
89+
}
8590
constructor(
8691
address token_,
8792
string memory name_,
@@ -100,6 +105,14 @@ contract YVault is Gauge, Ownable2Step, ERC4626 {
100105
strategy = strategy_;
101106
}
102107

108+
function setRebalanceingDelay(address rebalanceingDelay_) external onlyOwner {
109+
rebalanceingDelay = rebalanceingDelay_;
110+
}
111+
112+
function updateEmergencyShutdownState(bool shutdownState_) external onlyOwner {
113+
emergencyShutdown = shutdownState_;
114+
}
115+
103116
/// @notice Returns the total quantity of all assets under control of this
104117
/// Vault, whether they're loaned out to a Strategy, or currently held in
105118
/// the Vault.
@@ -117,144 +130,80 @@ contract YVault is Gauge, Ownable2Step, ERC4626 {
117130
function deposit(
118131
uint256 assets_,
119132
address receiver_
120-
) public override returns (uint256) {
133+
) public override nonReentrant notShutdown returns (uint256) {
121134
if (receiver_ == address(0)) revert ZeroAddress();
122135
totalIdle += assets_;
136+
_checkDelayAndRebalance();
123137
return super.deposit(assets_, receiver_);
124138
}
125139

126140
function withdraw(
127141
uint256 assets_,
128142
address receiver_,
129143
address owner_
130-
) public override returns (uint256) {
144+
) external override nonReentrant notShutdown returns (uint256) {
131145
if (receiver_ == address(0)) revert ZeroAddress();
132146
if (assets_ > totalIdle) revert NotEnoughAssets();
133147

134148
totalIdle -= assets_;
149+
_checkDelayAndRebalance();
135150
return super.withdraw(assets_, receiver_, owner_);
136151
}
137152

138153
function withdrawFromStrategy(
139154
uint256 assets_
140155
) external onlyOwner returns (uint256) {
156+
_witndrawFromStrategy(assets_);
157+
}
158+
159+
function _withdrawFromStrategy(
160+
uint256 assets_
161+
) internal returns (uint256) {
141162
uint256 preBalance = token__.balanceOf(address(this));
142-
uint256 loss = IStrategy(strategy).withdraw(assets_);
163+
IStrategy(strategy).withdraw(assets_);
143164
uint256 withdrawn = token__.balanceOf(address(this)) - preBalance;
144165
totalIdle += withdrawn;
145166
totalDebt -= withdrawn;
146-
if (loss > 0) _reportLoss(loss);
147-
emit WithdrawFromStrategy(withdrawn, loss);
167+
emit WithdrawFromStrategy(withdrawn);
148168
return withdrawn;
149169
}
150170

171+
151172
function maxAvailableShares() public view returns (uint256) {
152173
return convertToShares(_totalAssets());
153174
}
154175

155-
function report(
156-
uint256 profit_,
157-
uint256 loss_,
158-
uint256 debtPayment_
159-
) external returns (uint256) {
160-
// Only approved strategies can call this function
161-
require(msg.sender == strategy, "Not a strategy");
176+
function rebalance() external notShutdown returns (uint256) {
177+
_rebalance();
178+
}
162179

163-
// No lying about total available to withdraw
164-
require(
165-
token__.balanceOf(msg.sender) >= profit_ + debtPayment_,
166-
"Insufficient balance for reporting"
167-
);
180+
function _checkDelayAndRebalance() internal returns (uint256) {
168181

169-
// We have a loss to report, do it before the rest of the calculations
170-
if (loss_ > 0) _reportLoss(loss_);
182+
uint128 timeElapsed = uint128(block.timestamp) - lastRebalanceTimestamp;
183+
if (timeElapsed >= rebalanceingDelay) {
184+
return _rebalance();
185+
}
186+
}
171187

172-
// Returns are always "realized profits"
173-
totalProfit += profit_;
188+
function _rebalance() internal returns (uint256) {
174189

175190
// Compute the line of credit the Vault is able to offer the Strategy (if any)
176191
uint256 credit = _creditAvailable();
192+
uint256 pendingDebt = _debtOutstanding();
177193

178-
// Outstanding debt the Strategy wants to take back from the Vault (if any)
179-
// debtOutstanding <= StrategyParams.totalDebt
180-
uint256 debt = _debtOutstanding();
181-
uint256 debtPayment = Math.min(debtPayment_, debt);
182-
183-
if (debtPayment > 0) {
184-
totalDebt -= debtPayment;
185-
debt -= debtPayment;
186-
}
187-
188-
// Update the actual debt based on the full credit we are extending to the Strategy
189-
// or the returns if we are taking funds back
190-
// credit + strategies[msg.sender].totalDebt is always < debtLimit
191-
// At least one of credit or debt is always 0 (both can be 0)
192-
if (credit > 0) totalDebt += credit;
193-
194-
// Give/take balance to Strategy, based on the difference between the reported profits
195-
// (if any), the debt payment (if any), the credit increase we are offering (if any),
196-
// and the debt needed to be paid off (if any)
197-
// This is just used to adjust the balance of tokens between the Strategy and
198-
// the Vault based on the Strategy's debt limit (as well as the Vault's).
199-
uint256 totalAvailable = profit_ + debtPayment;
200-
201-
if (totalAvailable < credit) {
194+
if (credit>0) {
202195
// Credit surplus, give to Strategy
203-
totalIdle -= credit - totalAvailable;
204-
token__.safeTransfer(msg.sender, credit - totalAvailable);
205-
} else if (totalAvailable > credit) {
206-
// Credit deficit, take from Strategy
207-
totalIdle += totalAvailable - credit;
208-
token__.safeTransferFrom(
209-
msg.sender,
210-
address(this),
211-
totalAvailable - credit
212-
);
213-
}
214-
// else, don't do anything because it is balanced
215-
216-
// Profit is locked and gradually released per block
217-
// compute current locked profit and replace with sum of current and new
218-
// uint256 lockedProfitBeforeLoss = _calculateLockedProfit() + profit - totalFees;
219-
220-
// if (lockedProfitBeforeLoss > loss) {
221-
// lockedProfit = lockedProfitBeforeLoss - loss;
222-
// } else {
223-
// lockedProfit = 0;
224-
// }
225-
226-
// Update reporting time
227-
// strategies[msg.sender].lastReport = block.timestamp;
228-
// lastReport = block.timestamp;
229-
230-
emit StrategyReported(
231-
msg.sender,
232-
profit_,
233-
loss_,
234-
debtPayment,
235-
totalProfit,
236-
totalLoss,
237-
totalDebt,
238-
credit,
239-
debtRatio
240-
);
196+
totalIdle -= credit;
197+
totalDebt += credit;
198+
token__.safeTransfer(strategy, credit);
199+
IStrategy(strategy).invest();
241200

242-
if (debtRatio == 0) {
243-
// Take every last penny the Strategy has (Emergency Exit/revokeStrategy)
244-
// This is different than debt in order to extract *all* of the returns
245-
return IStrategy(msg.sender).estimatedTotalAssets();
246-
} else {
247-
// Otherwise, just return what we have as debt outstanding
248-
return debt;
201+
} else if (pendingDebt > 0) {
202+
// Credit deficit, take from Strategy
203+
_withdrawFromStrategy(pendingDebt);
249204
}
250-
}
251205

252-
function _reportLoss(uint256 loss) internal {
253-
// Loss can only be up to the amount of debt issued to strategy
254-
require(totalDebt >= loss, "Loss exceeds total debt");
255-
// Adjust strategy's parameters by the loss
256-
totalLoss += loss;
257-
totalDebt -= loss;
206+
emit Rebalanced(totalIdle, totalDebt, credit, debtOutstanding);
258207
}
259208

260209
function _creditAvailable() internal view returns (uint256) {

foundry.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
src = 'contracts'
33
out = 'out'
44
libs = ['lib']
5-
solc_version = '0.8.13'
5+
solc_version = '0.8.19'
66
optimizer = true
77
optimizer_runs = 99999
88
no-match-contract='LyraBurnUSDC'

0 commit comments

Comments
 (0)