Browse Source

Update docs

github-actions 2 years ago
parent
commit
8d69b7affd

+ 3 - 0
contracts/token/ERC20/extensions/ERC20Votes.sol

@@ -263,6 +263,9 @@ abstract contract ERC20Votes is IVotes, ERC20Permit {
         return a - b;
         return a - b;
     }
     }
 
 
+    /**
+     * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
+     */
     function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) private pure returns (Checkpoint storage result) {
     function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) private pure returns (Checkpoint storage result) {
         assembly {
         assembly {
             mstore(0, ckpts.slot)
             mstore(0, ckpts.slot)

+ 14 - 3
contracts/token/ERC20/extensions/ERC4626.sol

@@ -17,8 +17,12 @@ import "../../../utils/math/Math.sol";
  * the ERC20 standard. Any additional extensions included along it would affect the "shares" token represented by this
  * the ERC20 standard. Any additional extensions included along it would affect the "shares" token represented by this
  * contract and not the "assets" token which is an independent contract.
  * contract and not the "assets" token which is an independent contract.
  *
  *
- * CAUTION: Deposits and withdrawals may incur unexpected slippage. Users should verify that the amount received of
- * shares or assets is as expected. EOAs should operate through a wrapper that performs these checks such as
+ * CAUTION: When the vault is empty or nearly empty, deposits are at high risk of being stolen through frontrunning with
+ * a "donation" to the vault that inflates the price of a share. This is variously known as a donation or inflation
+ * attack and is essentially a problem of slippage. Vault deployers can protect against this attack by making an initial
+ * deposit of a non-trivial amount of the asset, such that price manipulation becomes infeasible. Withdrawals may
+ * similarly be affected by slippage. Users can protect against this attack as well unexpected slippage in general by
+ * verifying the amount received is as expected, using a wrapper that performs these checks such as
  * https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router].
  * https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router].
  *
  *
  * _Available since v4.7._
  * _Available since v4.7._
@@ -134,7 +138,11 @@ abstract contract ERC4626 is ERC20, IERC4626 {
         return shares;
         return shares;
     }
     }
 
 
-    /** @dev See {IERC4626-mint}. */
+    /** @dev See {IERC4626-mint}.
+     *
+     * As opposed to {deposit}, minting is allowed even if the vault is in a state where the price of a share is zero.
+     * In this case, the shares will be minted without requiring any assets to be deposited.
+     */
     function mint(uint256 shares, address receiver) public virtual override returns (uint256) {
     function mint(uint256 shares, address receiver) public virtual override returns (uint256) {
         require(shares <= maxMint(receiver), "ERC4626: mint more than max");
         require(shares <= maxMint(receiver), "ERC4626: mint more than max");
 
 
@@ -267,6 +275,9 @@ abstract contract ERC4626 is ERC20, IERC4626 {
         emit Withdraw(caller, receiver, owner, assets, shares);
         emit Withdraw(caller, receiver, owner, assets, shares);
     }
     }
 
 
+    /**
+     * @dev Checks if vault is "healthy" in the sense of having assets backing the circulating shares.
+     */
     function _isVaultCollateralized() private view returns (bool) {
     function _isVaultCollateralized() private view returns (bool) {
         return totalAssets() > 0 || totalSupply() == 0;
         return totalAssets() > 0 || totalSupply() == 0;
     }
     }

+ 11 - 1
contracts/utils/Checkpoints.sol

@@ -28,7 +28,8 @@ library Checkpoints {
 
 
     /**
     /**
      * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one
      * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one
-     * before it is returned, or zero otherwise.
+     * before it is returned, or zero otherwise. Because the number returned corresponds to that at the end of the
+     * block, the requested block number must be in the past, excluding the current block.
      */
      */
     function getAtBlock(History storage self, uint256 blockNumber) internal view returns (uint256) {
     function getAtBlock(History storage self, uint256 blockNumber) internal view returns (uint256) {
         require(blockNumber < block.number, "Checkpoints: block not yet mined");
         require(blockNumber < block.number, "Checkpoints: block not yet mined");
@@ -205,6 +206,9 @@ library Checkpoints {
         return high;
         return high;
     }
     }
 
 
+    /**
+     * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
+     */
     function _unsafeAccess(Checkpoint[] storage self, uint256 pos) private pure returns (Checkpoint storage result) {
     function _unsafeAccess(Checkpoint[] storage self, uint256 pos) private pure returns (Checkpoint storage result) {
         assembly {
         assembly {
             mstore(0, self.slot)
             mstore(0, self.slot)
@@ -366,6 +370,9 @@ library Checkpoints {
         return high;
         return high;
     }
     }
 
 
+    /**
+     * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
+     */
     function _unsafeAccess(Checkpoint224[] storage self, uint256 pos)
     function _unsafeAccess(Checkpoint224[] storage self, uint256 pos)
         private
         private
         pure
         pure
@@ -531,6 +538,9 @@ library Checkpoints {
         return high;
         return high;
     }
     }
 
 
+    /**
+     * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
+     */
     function _unsafeAccess(Checkpoint160[] storage self, uint256 pos)
     function _unsafeAccess(Checkpoint160[] storage self, uint256 pos)
         private
         private
         pure
         pure

+ 9 - 2
docs/modules/api/pages/token/ERC20.adoc

@@ -2167,8 +2167,12 @@ underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn}
 the ERC20 standard. Any additional extensions included along it would affect the "shares" token represented by this
 the ERC20 standard. Any additional extensions included along it would affect the "shares" token represented by this
 contract and not the "assets" token which is an independent contract.
 contract and not the "assets" token which is an independent contract.
 
 
-CAUTION: Deposits and withdrawals may incur unexpected slippage. Users should verify that the amount received of
-shares or assets is as expected. EOAs should operate through a wrapper that performs these checks such as
+CAUTION: When the vault is empty or nearly empty, deposits are at high risk of being stolen through frontrunning with
+a "donation" to the vault that inflates the price of a share. This is variously known as a donation or inflation
+attack and is essentially a problem of slippage. Vault deployers can protect against this attack by making an initial
+deposit of a non-trivial amount of the asset, such that price manipulation becomes infeasible. Withdrawals may
+similarly be affected by slippage. Users can protect against this attack as well unexpected slippage in general by
+verifying the amount received is as expected, using a wrapper that performs these checks such as
 https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router].
 https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router].
 
 
 _Available since v4.7._
 _Available since v4.7._
@@ -2353,6 +2357,9 @@ See {IERC4626-deposit}.
 
 
 See {IERC4626-mint}.
 See {IERC4626-mint}.
 
 
+As opposed to {deposit}, minting is allowed even if the vault is in a state where the price of a share is zero.
+In this case, the shares will be minted without requiring any assets to be deposited.
+
 [.contract-item]
 [.contract-item]
 [[ERC4626-withdraw-uint256-address-address-]]
 [[ERC4626-withdraw-uint256-address-address-]]
 ==== `[.contract-item-name]#++withdraw++#++(uint256 assets, address receiver, address owner) → uint256++` [.item-kind]#public#
 ==== `[.contract-item-name]#++withdraw++#++(uint256 assets, address receiver, address owner) → uint256++` [.item-kind]#public#

+ 2 - 1
docs/modules/api/pages/utils.adoc

@@ -4157,7 +4157,8 @@ _Available since v4.5._
 ==== `[.contract-item-name]#++getAtBlock++#++(struct Checkpoints.History self, uint256 blockNumber) → uint256++` [.item-kind]#internal#
 ==== `[.contract-item-name]#++getAtBlock++#++(struct Checkpoints.History self, uint256 blockNumber) → uint256++` [.item-kind]#internal#
 
 
 Returns the value at a given block number. If a checkpoint is not available at that block, the closest one
 Returns the value at a given block number. If a checkpoint is not available at that block, the closest one
-before it is returned, or zero otherwise.
+before it is returned, or zero otherwise. Because the number returned corresponds to that at the end of the
+block, the requested block number must be in the past, excluding the current block.
 
 
 [.contract-item]
 [.contract-item]
 [[Checkpoints-getAtProbablyRecentBlock-struct-Checkpoints-History-uint256-]]
 [[Checkpoints-getAtProbablyRecentBlock-struct-Checkpoints-History-uint256-]]

+ 5 - 1
scripts/generate/templates/Checkpoints.js

@@ -67,7 +67,8 @@ function upperLookup(${opts.historyTypeName} storage self, ${opts.keyTypeName} k
 const legacyOperations = opts => `\
 const legacyOperations = opts => `\
 /**
 /**
  * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one
  * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one
- * before it is returned, or zero otherwise.
+ * before it is returned, or zero otherwise. Because the number returned corresponds to that at the end of the
+ * block, the requested block number must be in the past, excluding the current block.
  */
  */
 function getAtBlock(${opts.historyTypeName} storage self, uint256 blockNumber) internal view returns (uint256) {
 function getAtBlock(${opts.historyTypeName} storage self, uint256 blockNumber) internal view returns (uint256) {
     require(blockNumber < block.number, "Checkpoints: block not yet mined");
     require(blockNumber < block.number, "Checkpoints: block not yet mined");
@@ -246,6 +247,9 @@ function _lowerBinaryLookup(
     return high;
     return high;
 }
 }
 
 
+/**
+ * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
+ */
 function _unsafeAccess(${opts.checkpointTypeName}[] storage self, uint256 pos)
 function _unsafeAccess(${opts.checkpointTypeName}[] storage self, uint256 pos)
     private
     private
     pure
     pure