-
Notifications
You must be signed in to change notification settings - Fork 360
/
ERC4626.sol
527 lines (476 loc) · 24.7 KB
/
ERC4626.sol
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {ERC20} from "./ERC20.sol";
import {FixedPointMathLib} from "../utils/FixedPointMathLib.sol";
import {SafeTransferLib} from "../utils/SafeTransferLib.sol";
/// @notice Simple ERC4626 tokenized Vault implementation.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC4626.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/mixins/ERC4626.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC4626.sol)
abstract contract ERC4626 is ERC20 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The default underlying decimals.
uint8 internal constant _DEFAULT_UNDERLYING_DECIMALS = 18;
/// @dev The default decimals offset.
uint8 internal constant _DEFAULT_DECIMALS_OFFSET = 0;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Cannot deposit more than the max limit.
error DepositMoreThanMax();
/// @dev Cannot mint more than the max limit.
error MintMoreThanMax();
/// @dev Cannot withdraw more than the max limit.
error WithdrawMoreThanMax();
/// @dev Cannot redeem more than the max limit.
error RedeemMoreThanMax();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Emitted during a mint call or deposit call.
event Deposit(address indexed by, address indexed owner, uint256 assets, uint256 shares);
/// @dev Emitted during a withdraw call or redeem call.
event Withdraw(
address indexed by,
address indexed to,
address indexed owner,
uint256 assets,
uint256 shares
);
/// @dev `keccak256(bytes("Deposit(address,address,uint256,uint256)"))`.
uint256 private constant _DEPOSIT_EVENT_SIGNATURE =
0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7;
/// @dev `keccak256(bytes("Withdraw(address,address,address,uint256,uint256)"))`.
uint256 private constant _WITHDRAW_EVENT_SIGNATURE =
0xfbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC4626 CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev To be overridden to return the address of the underlying asset.
///
/// - MUST be an ERC20 token contract.
/// - MUST NOT revert.
function asset() public view virtual returns (address);
/// @dev To be overridden to return the number of decimals of the underlying asset.
/// Default: 18.
///
/// - MUST NOT revert.
function _underlyingDecimals() internal view virtual returns (uint8) {
return _DEFAULT_UNDERLYING_DECIMALS;
}
/// @dev Override to return a non-zero value to make the inflation attack even more unfeasible.
/// Only used when {_useVirtualShares} returns true.
/// Default: 0.
///
/// - MUST NOT revert.
function _decimalsOffset() internal view virtual returns (uint8) {
return _DEFAULT_DECIMALS_OFFSET;
}
/// @dev Returns whether virtual shares will be used to mitigate the inflation attack.
/// See: https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706
/// Override to return true or false.
/// Default: true.
///
/// - MUST NOT revert.
function _useVirtualShares() internal view virtual returns (bool) {
return true;
}
/// @dev Returns the decimals places of the token.
///
/// - MUST NOT revert.
function decimals() public view virtual override(ERC20) returns (uint8) {
if (!_useVirtualShares()) return _underlyingDecimals();
return _underlyingDecimals() + _decimalsOffset();
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ASSET DECIMALS GETTER HELPER */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Helper function to get the decimals of the underlying asset.
/// Useful for setting the return value of `_underlyingDecimals` during initialization.
/// If the retrieval succeeds, `success` will be true, and `result` will hold the result.
/// Otherwise, `success` will be false, and `result` will be zero.
///
/// Example usage:
/// ```
/// (bool success, uint8 result) = _tryGetAssetDecimals(underlying);
/// _decimals = success ? result : _DEFAULT_UNDERLYING_DECIMALS;
/// ```
function _tryGetAssetDecimals(address underlying)
internal
view
returns (bool success, uint8 result)
{
/// @solidity memory-safe-assembly
assembly {
// Store the function selector of `decimals()`.
mstore(0x00, 0x313ce567)
// Arguments are evaluated last to first.
success :=
and(
// Returned value is less than 256, at left-padded to 32 bytes.
and(lt(mload(0x00), 0x100), gt(returndatasize(), 0x1f)),
// The staticcall succeeds.
staticcall(gas(), underlying, 0x1c, 0x04, 0x00, 0x20)
)
result := mul(mload(0x00), success)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ACCOUNTING LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the total amount of the underlying asset managed by the Vault.
///
/// - SHOULD include any compounding that occurs from the yield.
/// - MUST be inclusive of any fees that are charged against assets in the Vault.
/// - MUST NOT revert.
function totalAssets() public view virtual returns (uint256 assets) {
assets = SafeTransferLib.balanceOf(asset(), address(this));
}
/// @dev Returns the amount of shares that the Vault will exchange for the amount of
/// assets provided, in an ideal scenario where all conditions are met.
///
/// - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
/// - MUST NOT show any variations depending on the caller.
/// - MUST NOT reflect slippage or other on-chain conditions, during the actual exchange.
/// - MUST NOT revert.
///
/// Note: This calculation MAY NOT reflect the "per-user" price-per-share, and instead
/// should reflect the "average-user's" price-per-share, i.e. what the average user should
/// expect to see when exchanging to and from.
function convertToShares(uint256 assets) public view virtual returns (uint256 shares) {
if (!_useVirtualShares()) {
uint256 supply = totalSupply();
return _eitherIsZero(assets, supply)
? _initialConvertToShares(assets)
: FixedPointMathLib.fullMulDiv(assets, supply, totalAssets());
}
uint256 o = _decimalsOffset();
if (o == uint256(0)) {
return FixedPointMathLib.fullMulDiv(assets, totalSupply() + 1, _inc(totalAssets()));
}
return FixedPointMathLib.fullMulDiv(assets, totalSupply() + 10 ** o, _inc(totalAssets()));
}
/// @dev Returns the amount of assets that the Vault will exchange for the amount of
/// shares provided, in an ideal scenario where all conditions are met.
///
/// - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
/// - MUST NOT show any variations depending on the caller.
/// - MUST NOT reflect slippage or other on-chain conditions, during the actual exchange.
/// - MUST NOT revert.
///
/// Note: This calculation MAY NOT reflect the "per-user" price-per-share, and instead
/// should reflect the "average-user's" price-per-share, i.e. what the average user should
/// expect to see when exchanging to and from.
function convertToAssets(uint256 shares) public view virtual returns (uint256 assets) {
if (!_useVirtualShares()) {
uint256 supply = totalSupply();
return supply == uint256(0)
? _initialConvertToAssets(shares)
: FixedPointMathLib.fullMulDiv(shares, totalAssets(), supply);
}
uint256 o = _decimalsOffset();
if (o == uint256(0)) {
return FixedPointMathLib.fullMulDiv(shares, totalAssets() + 1, _inc(totalSupply()));
}
return FixedPointMathLib.fullMulDiv(shares, totalAssets() + 1, totalSupply() + 10 ** o);
}
/// @dev Allows an on-chain or off-chain user to simulate the effects of their deposit
/// at the current block, given current on-chain conditions.
///
/// - MUST return as close to and no more than the exact amount of Vault shares that
/// will be minted in a deposit call in the same transaction, i.e. deposit should
/// return the same or more shares as `previewDeposit` if call in the same transaction.
/// - MUST NOT account for deposit limits like those returned from `maxDeposit` and should
/// always act as if the deposit will be accepted, regardless of approvals, etc.
/// - MUST be inclusive of deposit fees. Integrators should be aware of this.
/// - MUST not revert.
///
/// Note: Any unfavorable discrepancy between `convertToShares` and `previewDeposit` SHOULD
/// be considered slippage in share price or some other type of condition, meaning
/// the depositor will lose assets by depositing.
function previewDeposit(uint256 assets) public view virtual returns (uint256 shares) {
shares = convertToShares(assets);
}
/// @dev Allows an on-chain or off-chain user to simulate the effects of their mint
/// at the current block, given current on-chain conditions.
///
/// - MUST return as close to and no fewer than the exact amount of assets that
/// will be deposited in a mint call in the same transaction, i.e. mint should
/// return the same or fewer assets as `previewMint` if called in the same transaction.
/// - MUST NOT account for mint limits like those returned from `maxMint` and should
/// always act as if the mint will be accepted, regardless of approvals, etc.
/// - MUST be inclusive of deposit fees. Integrators should be aware of this.
/// - MUST not revert.
///
/// Note: Any unfavorable discrepancy between `convertToAssets` and `previewMint` SHOULD
/// be considered slippage in share price or some other type of condition,
/// meaning the depositor will lose assets by minting.
function previewMint(uint256 shares) public view virtual returns (uint256 assets) {
if (!_useVirtualShares()) {
uint256 supply = totalSupply();
return supply == uint256(0)
? _initialConvertToAssets(shares)
: FixedPointMathLib.fullMulDivUp(shares, totalAssets(), supply);
}
uint256 o = _decimalsOffset();
if (o == uint256(0)) {
return FixedPointMathLib.fullMulDivUp(shares, totalAssets() + 1, _inc(totalSupply()));
}
return FixedPointMathLib.fullMulDivUp(shares, totalAssets() + 1, totalSupply() + 10 ** o);
}
/// @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal
/// at the current block, given the current on-chain conditions.
///
/// - MUST return as close to and no fewer than the exact amount of Vault shares that
/// will be burned in a withdraw call in the same transaction, i.e. withdraw should
/// return the same or fewer shares as `previewWithdraw` if call in the same transaction.
/// - MUST NOT account for withdrawal limits like those returned from `maxWithdraw` and should
/// always act as if the withdrawal will be accepted, regardless of share balance, etc.
/// - MUST be inclusive of withdrawal fees. Integrators should be aware of this.
/// - MUST not revert.
///
/// Note: Any unfavorable discrepancy between `convertToShares` and `previewWithdraw` SHOULD
/// be considered slippage in share price or some other type of condition,
/// meaning the depositor will lose assets by depositing.
function previewWithdraw(uint256 assets) public view virtual returns (uint256 shares) {
if (!_useVirtualShares()) {
uint256 supply = totalSupply();
return _eitherIsZero(assets, supply)
? _initialConvertToShares(assets)
: FixedPointMathLib.fullMulDivUp(assets, supply, totalAssets());
}
uint256 o = _decimalsOffset();
if (o == uint256(0)) {
return FixedPointMathLib.fullMulDivUp(assets, totalSupply() + 1, _inc(totalAssets()));
}
return FixedPointMathLib.fullMulDivUp(assets, totalSupply() + 10 ** o, _inc(totalAssets()));
}
/// @dev Allows an on-chain or off-chain user to simulate the effects of their redemption
/// at the current block, given current on-chain conditions.
///
/// - MUST return as close to and no more than the exact amount of assets that
/// will be withdrawn in a redeem call in the same transaction, i.e. redeem should
/// return the same or more assets as `previewRedeem` if called in the same transaction.
/// - MUST NOT account for redemption limits like those returned from `maxRedeem` and should
/// always act as if the redemption will be accepted, regardless of approvals, etc.
/// - MUST be inclusive of withdrawal fees. Integrators should be aware of this.
/// - MUST NOT revert.
///
/// Note: Any unfavorable discrepancy between `convertToAssets` and `previewRedeem` SHOULD
/// be considered slippage in share price or some other type of condition,
/// meaning the depositor will lose assets by depositing.
function previewRedeem(uint256 shares) public view virtual returns (uint256 assets) {
assets = convertToAssets(shares);
}
/// @dev Private helper to return if either value is zero.
function _eitherIsZero(uint256 a, uint256 b) private pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := or(iszero(a), iszero(b))
}
}
/// @dev Private helper to return `x + 1` without the overflow check.
/// Used for computing the denominator input to `FixedPointMathLib.fullMulDiv(a, b, x + 1)`.
/// When `x == type(uint256).max`, we get `x + 1 == 0` (mod 2**256 - 1),
/// and `FixedPointMathLib.fullMulDiv` will revert as the denominator is zero.
function _inc(uint256 x) private pure returns (uint256) {
unchecked {
return x + 1;
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DEPOSIT / WITHDRAWAL LIMIT LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the maximum amount of the underlying asset that can be deposited
/// into the Vault for `to`, via a deposit call.
///
/// - MUST return a limited value if `to` is subject to some deposit limit.
/// - MUST return `2**256-1` if there is no maximum limit.
/// - MUST NOT revert.
function maxDeposit(address to) public view virtual returns (uint256 maxAssets) {
to = to; // Silence unused variable warning.
maxAssets = type(uint256).max;
}
/// @dev Returns the maximum amount of the Vault shares that can be minter for `to`,
/// via a mint call.
///
/// - MUST return a limited value if `to` is subject to some mint limit.
/// - MUST return `2**256-1` if there is no maximum limit.
/// - MUST NOT revert.
function maxMint(address to) public view virtual returns (uint256 maxShares) {
to = to; // Silence unused variable warning.
maxShares = type(uint256).max;
}
/// @dev Returns the maximum amount of the underlying asset that can be withdrawn
/// from the `owner`'s balance in the Vault, via a withdraw call.
///
/// - MUST return a limited value if `owner` is subject to some withdrawal limit or timelock.
/// - MUST NOT revert.
function maxWithdraw(address owner) public view virtual returns (uint256 maxAssets) {
maxAssets = convertToAssets(balanceOf(owner));
}
/// @dev Returns the maximum amount of Vault shares that can be redeemed
/// from the `owner`'s balance in the Vault, via a redeem call.
///
/// - MUST return a limited value if `owner` is subject to some withdrawal limit or timelock.
/// - MUST return `balanceOf(owner)` otherwise.
/// - MUST NOT revert.
function maxRedeem(address owner) public view virtual returns (uint256 maxShares) {
maxShares = balanceOf(owner);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DEPOSIT / WITHDRAWAL LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Mints `shares` Vault shares to `to` by depositing exactly `assets`
/// of underlying tokens.
///
/// - MUST emit the {Deposit} event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault
/// contract before the deposit execution, and are accounted for during deposit.
/// - MUST revert if all of `assets` cannot be deposited, such as due to deposit limit,
/// slippage, insufficient approval, etc.
///
/// Note: Most implementations will require pre-approval of the Vault with the
/// Vault's underlying `asset` token.
function deposit(uint256 assets, address to) public virtual returns (uint256 shares) {
if (assets > maxDeposit(to)) _revert(0xb3c61a83); // `DepositMoreThanMax()`.
shares = previewDeposit(assets);
_deposit(msg.sender, to, assets, shares);
}
/// @dev Mints exactly `shares` Vault shares to `to` by depositing `assets`
/// of underlying tokens.
///
/// - MUST emit the {Deposit} event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault
/// contract before the mint execution, and are accounted for during mint.
/// - MUST revert if all of `shares` cannot be deposited, such as due to deposit limit,
/// slippage, insufficient approval, etc.
///
/// Note: Most implementations will require pre-approval of the Vault with the
/// Vault's underlying `asset` token.
function mint(uint256 shares, address to) public virtual returns (uint256 assets) {
if (shares > maxMint(to)) _revert(0x6a695959); // `MintMoreThanMax()`.
assets = previewMint(shares);
_deposit(msg.sender, to, assets, shares);
}
/// @dev Burns `shares` from `owner` and sends exactly `assets` of underlying tokens to `to`.
///
/// - MUST emit the {Withdraw} event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault
/// contract before the withdraw execution, and are accounted for during withdraw.
/// - MUST revert if all of `assets` cannot be withdrawn, such as due to withdrawal limit,
/// slippage, insufficient balance, etc.
///
/// Note: Some implementations will require pre-requesting to the Vault before a withdrawal
/// may be performed. Those methods should be performed separately.
function withdraw(uint256 assets, address to, address owner)
public
virtual
returns (uint256 shares)
{
if (assets > maxWithdraw(owner)) _revert(0x936941fc); // `WithdrawMoreThanMax()`.
shares = previewWithdraw(assets);
_withdraw(msg.sender, to, owner, assets, shares);
}
/// @dev Burns exactly `shares` from `owner` and sends `assets` of underlying tokens to `to`.
///
/// - MUST emit the {Withdraw} event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault
/// contract before the redeem execution, and are accounted for during redeem.
/// - MUST revert if all of shares cannot be redeemed, such as due to withdrawal limit,
/// slippage, insufficient balance, etc.
///
/// Note: Some implementations will require pre-requesting to the Vault before a redeem
/// may be performed. Those methods should be performed separately.
function redeem(uint256 shares, address to, address owner)
public
virtual
returns (uint256 assets)
{
if (shares > maxRedeem(owner)) _revert(0x4656425a); // `RedeemMoreThanMax()`.
assets = previewRedeem(shares);
_withdraw(msg.sender, to, owner, assets, shares);
}
/// @dev Internal helper for reverting efficiently.
function _revert(uint256 s) private pure {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, s)
revert(0x1c, 0x04)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev For deposits and mints.
///
/// Emits a {Deposit} event.
function _deposit(address by, address to, uint256 assets, uint256 shares) internal virtual {
SafeTransferLib.safeTransferFrom(asset(), by, address(this), assets);
_mint(to, shares);
/// @solidity memory-safe-assembly
assembly {
// Emit the {Deposit} event.
mstore(0x00, assets)
mstore(0x20, shares)
let m := shr(96, not(0))
log3(0x00, 0x40, _DEPOSIT_EVENT_SIGNATURE, and(m, by), and(m, to))
}
_afterDeposit(assets, shares);
}
/// @dev For withdrawals and redemptions.
///
/// Emits a {Withdraw} event.
function _withdraw(address by, address to, address owner, uint256 assets, uint256 shares)
internal
virtual
{
if (by != owner) _spendAllowance(owner, by, shares);
_beforeWithdraw(assets, shares);
_burn(owner, shares);
SafeTransferLib.safeTransfer(asset(), to, assets);
/// @solidity memory-safe-assembly
assembly {
// Emit the {Withdraw} event.
mstore(0x00, assets)
mstore(0x20, shares)
let m := shr(96, not(0))
log4(0x00, 0x40, _WITHDRAW_EVENT_SIGNATURE, and(m, by), and(m, to), and(m, owner))
}
}
/// @dev Internal conversion function (from assets to shares) to apply when the Vault is empty.
/// Only used when {_useVirtualShares} returns false.
///
/// Note: Make sure to keep this function consistent with {_initialConvertToAssets}
/// when overriding it.
function _initialConvertToShares(uint256 assets)
internal
view
virtual
returns (uint256 shares)
{
shares = assets;
}
/// @dev Internal conversion function (from shares to assets) to apply when the Vault is empty.
/// Only used when {_useVirtualShares} returns false.
///
/// Note: Make sure to keep this function consistent with {_initialConvertToShares}
/// when overriding it.
function _initialConvertToAssets(uint256 shares)
internal
view
virtual
returns (uint256 assets)
{
assets = shares;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HOOKS TO OVERRIDE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Hook that is called before any withdrawal or redemption.
function _beforeWithdraw(uint256 assets, uint256 shares) internal virtual {}
/// @dev Hook that is called after any deposit or mint.
function _afterDeposit(uint256 assets, uint256 shares) internal virtual {}
}