@@ -4,21 +4,12 @@ pragma solidity ^0.8.30;
44import {ReentrancyGuard} from "openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol " ;
55
66import {IERC20 } from "./interfaces/IERC20.sol " ;
7- import {IPool} from "./interfaces/IPool.sol " ;
7+ import {YieldSaveVaultStorage} from "./base/YieldSaveVaultStorage.sol " ;
8+ import {ERC20TransferLib } from "./libraries/ERC20TransferLib.sol " ;
9+ import {YieldSaveVaultAccounting} from "./base/YieldSaveVaultAccounting.sol " ;
810
9- contract YieldSaveVault is ReentrancyGuard {
10- uint256 public constant BPS_DENOMINATOR = 10_000 ;
11- uint256 public constant MAX_FEE_BPS = 1_000 ;
12-
13- IERC20 public immutable usdc;
14- IERC20 public immutable aUsdc;
15- IPool public immutable aavePool;
16- address public immutable treasury;
17- uint256 public immutable feeRate;
18-
19- uint256 public totalShares;
20- mapping (address => uint256 ) public userShares;
21- mapping (address => uint256 ) public userDeposits;
11+ contract YieldSaveVault is ReentrancyGuard , YieldSaveVaultAccounting {
12+ using ERC20TransferLib for IERC20 ;
2213
2314 error ZeroAddress ();
2415 error ZeroAmount ();
@@ -36,17 +27,13 @@ contract YieldSaveVault is ReentrancyGuard {
3627 uint256 payout
3728 );
3829
39- constructor (address usdc_ , address aUsdc_ , address aavePool_ , address treasury_ , uint256 feeRate_ ) {
30+ constructor (address usdc_ , address aUsdc_ , address aavePool_ , address treasury_ , uint256 feeRate_ )
31+ YieldSaveVaultStorage (usdc_, aUsdc_, aavePool_, treasury_, feeRate_)
32+ {
4033 if (usdc_ == address (0 ) || aUsdc_ == address (0 ) || aavePool_ == address (0 ) || treasury_ == address (0 )) {
4134 revert ZeroAddress ();
4235 }
4336 if (feeRate_ > MAX_FEE_BPS) revert InvalidFeeRate ();
44-
45- usdc = IERC20 (usdc_);
46- aUsdc = IERC20 (aUsdc_);
47- aavePool = IPool (aavePool_);
48- treasury = treasury_;
49- feeRate = feeRate_;
5037 }
5138
5239 /// @notice Deposits USDC into the vault and mints internal shares for the sender.
@@ -139,63 +126,15 @@ contract YieldSaveVault is ReentrancyGuard {
139126 (payout, grossAssets, fee) = _previewWithdrawForUser (user, shares);
140127 }
141128
142- function _previewWithdrawForUser (address user , uint256 shares )
143- internal
144- view
145- returns (uint256 payout , uint256 grossAssets , uint256 fee )
146- {
147- uint256 userShareBalance = userShares[user];
148- if (shares == 0 || userShareBalance == 0 || shares > userShareBalance) {
149- return (0 , 0 , 0 );
150- }
151-
152- (grossAssets,, fee) = _quoteWithdraw (user, shares, _totalAssets (), totalShares, userShareBalance);
153- payout = grossAssets - fee;
154- }
155-
156- function _previewDeposit (uint256 amount , uint256 assetsBefore ) internal view returns (uint256 ) {
157- if (amount == 0 ) return 0 ;
158- if (totalShares == 0 || assetsBefore == 0 ) return amount;
159- return amount * totalShares / assetsBefore;
160- }
161-
162- function _quoteWithdraw (
163- address user ,
164- uint256 shares ,
165- uint256 assets ,
166- uint256 currentTotalShares ,
167- uint256 userShareBalance
168- ) internal view returns (uint256 grossAssets , uint256 principalPortion , uint256 fee ) {
169- grossAssets = shares * assets / currentTotalShares;
170- principalPortion = userDeposits[user] * shares / userShareBalance;
171-
172- uint256 yld = grossAssets > principalPortion ? grossAssets - principalPortion : 0 ;
173- fee = yld * feeRate / BPS_DENOMINATOR;
174- }
175-
176- // get the vault total assets (that is the USDC and the accrued yield)
177- function _totalAssets () internal view returns (uint256 ) {
178- return aUsdc.balanceOf (address (this ));
179- }
180-
181129 function _safeTransfer (IERC20 token , address to , uint256 amount ) internal {
182- (bool success , bytes memory data ) =
183- address (token).call (abi.encodeCall (IERC20 .transfer, (to, amount)));
184- if (! success || (data.length != 0 && ! abi.decode (data, (bool )))) revert ERC20CallFailed ();
130+ if (! token.safeTransfer (to, amount)) revert ERC20CallFailed ();
185131 }
186132
187133 function _safeTransferFrom (IERC20 token , address from , address to , uint256 amount ) internal {
188- (bool success , bytes memory data ) =
189- address (token).call (abi.encodeCall (IERC20 .transferFrom, (from, to, amount)));
190- if (! success || (data.length != 0 && ! abi.decode (data, (bool )))) revert ERC20CallFailed ();
134+ if (! token.safeTransferFrom (from, to, amount)) revert ERC20CallFailed ();
191135 }
192136
193137 function _forceApprove (IERC20 token , address spender , uint256 amount ) internal {
194- (bool success , bytes memory data ) =
195- address (token).call (abi.encodeCall (IERC20 .approve, (spender, 0 )));
196- if (! success || (data.length != 0 && ! abi.decode (data, (bool )))) revert ERC20CallFailed ();
197-
198- (success, data) = address (token).call (abi.encodeCall (IERC20 .approve, (spender, amount)));
199- if (! success || (data.length != 0 && ! abi.decode (data, (bool )))) revert ERC20CallFailed ();
138+ if (! token.forceApprove (spender, amount)) revert ERC20CallFailed ();
200139 }
201140}
0 commit comments