Skip to content

Commit eee25ce

Browse files
authored
Merge pull request #68 from stabilitydao/fixing
23.12.1-alpha
2 parents 7f3e2ff + b6f5fa2 commit eee25ce

15 files changed

Lines changed: 309 additions & 91 deletions
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.23;
3+
4+
import {console} from "forge-std/Test.sol";
5+
import "forge-std/Script.sol";
6+
import "../chains/PolygonLib.sol";
7+
import "../src/core/Factory.sol";
8+
import "../src/core/Zap.sol";
9+
import "../src/core/vaults/CVault.sol";
10+
import "../src/core/vaults/RVault.sol";
11+
import "../src/core/vaults/RMVault.sol";
12+
13+
contract PrepareUpgrade1Polygon is Script {
14+
function run() external {
15+
uint deployerPrivateKey = vm.envUint("PRIVATE_KEY");
16+
vm.startBroadcast(deployerPrivateKey);
17+
address newImpl;
18+
19+
newImpl = address(new Factory());
20+
console.log("Factory 1.0.1", newImpl);
21+
newImpl = address(new Zap());
22+
console.log("Zap 1.0.1", newImpl);
23+
24+
newImpl = address(new CVault());
25+
console.log("CVault 1.0.1", newImpl);
26+
newImpl = address(new RVault());
27+
console.log("RVault 1.0.1", newImpl);
28+
newImpl = address(new RMVault());
29+
console.log("RMVault 1.0.1", newImpl);
30+
31+
vm.stopBroadcast();
32+
}
33+
34+
function testDeployPolygon() external {}
35+
}

src/core/Factory.sol

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ contract Factory is Controllable, ReentrancyGuardUpgradeable, IFactory {
3131
//region ----- Constants -----
3232

3333
/// @inheritdoc IControllable
34-
string public constant VERSION = "1.0.0";
34+
string public constant VERSION = "1.0.1";
3535

3636
uint internal constant _WEEK = 60 * 60 * 24 * 7;
3737

@@ -104,6 +104,9 @@ contract Factory is Controllable, ReentrancyGuardUpgradeable, IFactory {
104104
bytes32 typeHash = keccak256(abi.encodePacked(type_));
105105
$.vaultConfig[typeHash] = vaultConfig_;
106106
bool newVaultType = $.vaultTypeHashes.add(typeHash);
107+
if (!newVaultType) {
108+
_requireGovernanceOrMultisig();
109+
}
107110
emit VaultConfigChanged(
108111
type_, vaultConfig_.implementation, vaultConfig_.deployAllowed, vaultConfig_.upgradeAllowed, newVaultType
109112
);
@@ -126,6 +129,9 @@ contract Factory is Controllable, ReentrancyGuardUpgradeable, IFactory {
126129
}
127130
$.strategyLogicConfig[strategyIdHash] = config;
128131
bool newStrategy = $.strategyLogicIdHashes.add(strategyIdHash);
132+
if (!newStrategy) {
133+
_requireGovernanceOrMultisig();
134+
}
129135
emit StrategyLogicConfigChanged(
130136
config.id, config.implementation, config.deployAllowed, config.upgradeAllowed, newStrategy
131137
);

src/core/Zap.sol

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ contract Zap is Controllable, ReentrancyGuardUpgradeable, IZap {
2525
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
2626

2727
/// @inheritdoc IControllable
28-
string public constant VERSION = "1.0.0";
28+
string public constant VERSION = "1.0.1";
2929

3030
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
3131
/* INITIALIZATION */
@@ -74,11 +74,14 @@ contract Zap is Controllable, ReentrancyGuardUpgradeable, IZap {
7474
uint[] memory depositAmounts = new uint[](len);
7575
//nosemgrep
7676
for (uint i; i < len; ++i) {
77-
if (tokenIn != assets[i]) {
78-
//slither-disable-next-line low-level-calls
79-
(bool success, bytes memory result) = agg.call(swapData[i]);
80-
//nosemgrep
81-
require(success, string(result));
77+
if (tokenIn == assets[i]) {
78+
continue;
79+
}
80+
81+
//slither-disable-next-line low-level-calls
82+
(bool success, bytes memory result) = agg.call(swapData[i]);
83+
if (!success) {
84+
revert AggSwapFailed(string(result));
8285
}
8386
}
8487
//nosemgrep
@@ -106,20 +109,24 @@ contract Zap is Controllable, ReentrancyGuardUpgradeable, IZap {
106109
revert NotAllowedDexAggregator(agg);
107110
}
108111

109-
IERC20(vault).safeTransferFrom(msg.sender, address(this), sharesToBurn);
110-
111112
address strategy = address(IVault(vault).strategy());
112113
address[] memory assets = IStrategy(strategy).assets();
113-
uint[] memory amountsOut = IVault(vault).withdrawAssets(assets, sharesToBurn, minAssetAmountsOut);
114+
uint[] memory amountsOut =
115+
IVault(vault).withdrawAssets(assets, sharesToBurn, minAssetAmountsOut, address(this), msg.sender);
114116

115117
uint len = swapData.length;
116118
for (uint i; i < len; ++i) {
119+
if (tokenOut == assets[i]) {
120+
continue;
121+
}
122+
117123
_approveIfNeeds(assets[i], amountsOut[i], agg);
118124
// slither-disable-next-line calls-loop
119125
// slither-disable-next-line low-level-calls
120126
(bool success, bytes memory result) = agg.call(swapData[i]);
121-
//nosemgrep
122-
require(success, string(result));
127+
if (!success) {
128+
revert AggSwapFailed(string(result));
129+
}
123130
}
124131

125132
_sendAllRemaining(tokenOut, assets, IStrategy(strategy).underlying());
@@ -135,14 +142,10 @@ contract Zap is Controllable, ReentrancyGuardUpgradeable, IZap {
135142
address tokenIn,
136143
uint amountIn
137144
) external view returns (address[] memory tokensOut, uint[] memory swapAmounts) {
138-
// todo check vault
139-
140145
address strategy = address(IVault(vault).strategy());
141146
tokensOut = IStrategy(strategy).assets();
142147
uint len = tokensOut.length;
143-
144148
swapAmounts = new uint[](len);
145-
146149
uint[] memory proportions = IStrategy(strategy).getAssetsProportions();
147150
uint amountInUsed = 0;
148151
//nosemgrep
@@ -151,7 +154,6 @@ contract Zap is Controllable, ReentrancyGuardUpgradeable, IZap {
151154
amountInUsed += amountIn * proportions[i] / 1e18;
152155
continue;
153156
}
154-
155157
if (i < len - 1) {
156158
swapAmounts[i] = amountIn * proportions[i] / 1e18;
157159
amountInUsed += swapAmounts[i];

src/core/base/VaultBase.sol

Lines changed: 87 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ abstract contract VaultBase is Controllable, ERC20Upgradeable, ReentrancyGuardUp
2929
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
3030

3131
/// @dev Version of VaultBase implementation
32-
string public constant VERSION_VAULT_BASE = "1.0.0";
32+
string public constant VERSION_VAULT_BASE = "1.0.1";
3333

3434
/// @dev Delay between deposits/transfers and withdrawals
3535
uint internal constant _WITHDRAW_REQUEST_BLOCKS = 5;
@@ -200,61 +200,18 @@ abstract contract VaultBase is Controllable, ERC20Upgradeable, ReentrancyGuardUp
200200
uint amountShares,
201201
uint[] memory minAssetAmountsOut
202202
) external virtual nonReentrant returns (uint[] memory) {
203-
if (amountShares == 0) {
204-
revert IControllable.IncorrectZeroArgument();
205-
}
206-
if (amountShares > balanceOf(msg.sender)) {
207-
revert NotEnoughBalanceToPay();
208-
}
209-
if (assets_.length != minAssetAmountsOut.length) {
210-
revert IControllable.IncorrectArrayLength();
211-
}
212-
213-
VaultBaseStorage storage $ = _getVaultBaseStorage();
214-
_beforeWithdraw($);
215-
216-
IStrategy _strategy = $.strategy;
217-
uint localTotalSupply = totalSupply();
218-
uint totalValue = _strategy.total();
219-
220-
uint[] memory amountsOut;
221-
address underlying = _strategy.underlying();
222-
//nosemgrep
223-
bool isUnderlyingWithdrawal = assets_.length == 1 && underlying != address(0) && underlying == assets_[0];
224-
225-
// fuse is not triggered
226-
if (totalValue > 0) {
227-
uint value = amountShares * totalValue / localTotalSupply;
228-
if (isUnderlyingWithdrawal) {
229-
amountsOut = new uint[](1);
230-
amountsOut[0] = value;
231-
$.strategy.withdrawUnderlying(amountsOut[0], msg.sender);
232-
} else {
233-
amountsOut = $.strategy.withdrawAssets(assets_, value, msg.sender);
234-
}
235-
} else {
236-
if (isUnderlyingWithdrawal) {
237-
amountsOut = new uint[](1);
238-
amountsOut[0] = amountShares * IERC20(underlying).balanceOf(address(_strategy)) / localTotalSupply;
239-
$.strategy.withdrawUnderlying(amountsOut[0], msg.sender);
240-
} else {
241-
amountsOut = $.strategy.transferAssets(amountShares, localTotalSupply, msg.sender);
242-
}
243-
}
244-
245-
uint len = amountsOut.length;
246-
//nosemgrep
247-
for (uint i; i < len; ++i) {
248-
if (amountsOut[i] < minAssetAmountsOut[i]) {
249-
revert ExceedSlippageExactAsset(assets_[i], amountsOut[i], minAssetAmountsOut[i]);
250-
}
251-
}
252-
253-
_burn(msg.sender, amountShares);
254-
255-
emit WithdrawAssets(msg.sender, assets_, amountShares, amountsOut);
203+
return _withdrawAssets(assets_, amountShares, minAssetAmountsOut, msg.sender, msg.sender);
204+
}
256205

257-
return amountsOut;
206+
/// @inheritdoc IVault
207+
function withdrawAssets(
208+
address[] memory assets_,
209+
uint amountShares,
210+
uint[] memory minAssetAmountsOut,
211+
address receiver,
212+
address owner
213+
) external virtual nonReentrant returns (uint[] memory) {
214+
return _withdrawAssets(assets_, amountShares, minAssetAmountsOut, receiver, owner);
258215
}
259216

260217
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
@@ -465,19 +422,88 @@ abstract contract VaultBase is Controllable, ERC20Upgradeable, ReentrancyGuardUp
465422
}
466423
}
467424

468-
function _beforeWithdraw(VaultBaseStorage storage $) internal {
469-
if ($.withdrawRequests[msg.sender] + _WITHDRAW_REQUEST_BLOCKS >= block.number) {
425+
function _withdrawAssets(
426+
address[] memory assets_,
427+
uint amountShares,
428+
uint[] memory minAssetAmountsOut,
429+
address receiver,
430+
address owner
431+
) internal virtual returns (uint[] memory) {
432+
if (msg.sender != owner) {
433+
_spendAllowance(owner, msg.sender, amountShares);
434+
}
435+
436+
if (amountShares == 0) {
437+
revert IControllable.IncorrectZeroArgument();
438+
}
439+
if (amountShares > balanceOf(owner)) {
440+
revert NotEnoughBalanceToPay();
441+
}
442+
if (assets_.length != minAssetAmountsOut.length) {
443+
revert IControllable.IncorrectArrayLength();
444+
}
445+
446+
VaultBaseStorage storage $ = _getVaultBaseStorage();
447+
_beforeWithdraw($, owner);
448+
449+
IStrategy _strategy = $.strategy;
450+
uint localTotalSupply = totalSupply();
451+
uint totalValue = _strategy.total();
452+
453+
uint[] memory amountsOut;
454+
455+
{
456+
address underlying = _strategy.underlying();
457+
//nosemgrep
458+
bool isUnderlyingWithdrawal = assets_.length == 1 && underlying != address(0) && underlying == assets_[0];
459+
460+
// fuse is not triggered
461+
if (totalValue > 0) {
462+
uint value = amountShares * totalValue / localTotalSupply;
463+
if (isUnderlyingWithdrawal) {
464+
amountsOut = new uint[](1);
465+
amountsOut[0] = value;
466+
$.strategy.withdrawUnderlying(amountsOut[0], receiver);
467+
} else {
468+
amountsOut = $.strategy.withdrawAssets(assets_, value, receiver);
469+
}
470+
} else {
471+
if (isUnderlyingWithdrawal) {
472+
amountsOut = new uint[](1);
473+
amountsOut[0] = amountShares * IERC20(underlying).balanceOf(address(_strategy)) / localTotalSupply;
474+
$.strategy.withdrawUnderlying(amountsOut[0], receiver);
475+
} else {
476+
amountsOut = $.strategy.transferAssets(amountShares, localTotalSupply, receiver);
477+
}
478+
}
479+
480+
uint len = amountsOut.length;
481+
//nosemgrep
482+
for (uint i; i < len; ++i) {
483+
if (amountsOut[i] < minAssetAmountsOut[i]) {
484+
revert ExceedSlippageExactAsset(assets_[i], amountsOut[i], minAssetAmountsOut[i]);
485+
}
486+
}
487+
}
488+
489+
_burn(owner, amountShares);
490+
491+
emit WithdrawAssets(msg.sender, owner, assets_, amountShares, amountsOut);
492+
493+
return amountsOut;
494+
}
495+
496+
function _beforeWithdraw(VaultBaseStorage storage $, address owner) internal {
497+
if ($.withdrawRequests[owner] + _WITHDRAW_REQUEST_BLOCKS >= block.number) {
470498
revert WaitAFewBlocks();
471499
}
472-
$.withdrawRequests[msg.sender] = block.number;
500+
$.withdrawRequests[owner] = block.number;
473501
}
474502

475503
function _update(address from, address to, uint value) internal virtual override {
476504
super._update(from, to, value);
477505
VaultBaseStorage storage $ = _getVaultBaseStorage();
478506
$.withdrawRequests[from] = block.number;
479-
if (to != IPlatform(platform()).zap()) {
480-
$.withdrawRequests[to] = block.number;
481-
}
507+
$.withdrawRequests[to] = block.number;
482508
}
483509
}

src/core/vaults/CVault.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ contract CVault is VaultBase {
1414
//region ----- Constants -----
1515

1616
/// @dev Version of CVault implementation
17-
string public constant VERSION = "1.0.0";
17+
string public constant VERSION = "1.0.1";
1818

1919
uint internal constant _UNIQUE_INIT_ADDRESSES = 1;
2020

src/core/vaults/RMVault.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ contract RMVault is RVaultBase, IManagedVault {
2121
//region ----- Constants -----
2222

2323
/// @dev Version of RMVault implementation
24-
string public constant VERSION = "1.0.0";
24+
string public constant VERSION = "1.0.1";
2525

2626
uint internal constant _UNIQUE_INIT_ADDRESSES = 1;
2727

src/core/vaults/RVault.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ contract RVault is RVaultBase {
2020
//region ----- Constants -----
2121

2222
/// @dev Version of RVault implementation
23-
string public constant VERSION = "1.0.0";
23+
string public constant VERSION = "1.0.1";
2424

2525
uint public constant BB_TOKEN_DURATION = 86400 * 7;
2626

src/interfaces/IFactory.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,10 +318,12 @@ interface IFactory {
318318
function updateFarm(uint id, Farm memory farm_) external;
319319

320320
/// @notice Initial addition or change of vault type settings.
321+
/// Operator can add new vault type. Governance or multisig can change existing vault type config.
321322
/// @param vaultConfig_ Vault type settings
322323
function setVaultConfig(VaultConfig memory vaultConfig_) external;
323324

324325
/// @notice Initial addition or change of strategy logic settings.
326+
/// Operator can add new strategy logic. Governance or multisig can change existing logic config.
325327
/// @param config Strategy logic settings
326328
/// @param developer Strategy developer is receiver of minted StrategyLogic NFT on initial addition
327329
function setStrategyLogicConfig(StrategyLogicConfig memory config, address developer) external;

src/interfaces/IVault.sol

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ interface IVault is IERC165 {
2727
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
2828

2929
event DepositAssets(address indexed account, address[] assets, uint[] amounts, uint mintAmount);
30-
event WithdrawAssets(address indexed account, address[] assets, uint sharesAmount, uint[] amountsOut);
30+
event WithdrawAssets(
31+
address indexed sender, address indexed owner, address[] assets, uint sharesAmount, uint[] amountsOut
32+
);
3133
event HardWorkGas(uint gasUsed, uint gasCost, bool compensated);
3234
event DoHardWorkOnDepositChanged(bool oldValue, bool newValue);
3335
event MaxSupply(uint maxShares);
@@ -181,6 +183,21 @@ interface IVault is IERC165 {
181183
uint[] memory minAssetAmountsOut
182184
) external returns (uint[] memory);
183185

186+
/// @dev Burning shares of vault and obtaining strategy assets.
187+
/// @param assets_ Assets suitable for the strategy. Can be strategy assets, underlying asset or specific set of assets depending on strategy logic.
188+
/// @param amountShares Shares amount for burning
189+
/// @param minAssetAmountsOut Slippage tolerance. Minimal amounts of strategy assets that user must receive.
190+
/// @param receiver Receiver of assets
191+
/// @param owner Owner of vault shares
192+
/// @return Amount of assets for withdraw. It's related to assets_ one-by-one.
193+
function withdrawAssets(
194+
address[] memory assets_,
195+
uint amountShares,
196+
uint[] memory minAssetAmountsOut,
197+
address receiver,
198+
address owner
199+
) external returns (uint[] memory);
200+
184201
/// @dev Setting of vault capacity
185202
/// @param maxShares If totalSupply() exceeds this value, deposits will not be possible
186203
function setMaxSupply(uint maxShares) external;

0 commit comments

Comments
 (0)