@@ -41,6 +41,14 @@ import { IVedaTeller } from "./interfaces/IVedaTeller.sol";
4141 *
4242 * Requirements:
4343 * - VedaAdapter must approve the BoringVault to spend deposit tokens
44+ *
45+ * @notice Security consideration: Anyone can call `depositByDelegation` and `withdrawByDelegation` — there is no
46+ * caller restriction. Security is enforced entirely through the delegation chain. The redelegation from the
47+ * operator to this adapter MUST include an `ERC20TransferAmountEnforcer` caveat capped to exactly the intended
48+ * deposit or withdrawal amount. Once that amount is transferred the enforcer's running total is exhausted and
49+ * any replay attempt will revert, making the delegation effectively single-use. A delegation without this
50+ * enforcer (or with an amount larger than intended) could be exploited by any caller to transfer more tokens
51+ * than authorised.
4452 */
4553contract VedaAdapter is Ownable2Step {
4654 using SafeERC20 for IERC20 ;
@@ -129,9 +137,6 @@ contract VedaAdapter is Ownable2Step {
129137 /// @dev Thrown when the batch array is empty
130138 error InvalidBatchLength ();
131139
132- /// @dev Thrown when msg.sender is not the leaf delegator
133- error NotLeafDelegator ();
134-
135140 ////////////////////////////// State //////////////////////////////
136141
137142 /**
@@ -179,16 +184,19 @@ contract VedaAdapter is Ownable2Step {
179184 * @param _token Address of the token to deposit
180185 * @param _amount Amount of tokens to deposit
181186 * @param _minimumMint Minimum vault shares the user expects to receive (slippage protection)
187+ * @notice Security consideration: Callable by anyone. The redelegation passed in MUST include an
188+ * `ERC20TransferAmountEnforcer` capped to exactly `_amount` to prevent over-spending or replay.
182189 */
183190 function depositByDelegation (Delegation[] memory _delegations , address _token , uint256 _amount , uint256 _minimumMint ) external {
184191 _executeDepositByDelegation (_delegations, _token, _amount, _minimumMint, msg .sender );
185192 }
186193
187194 /**
188195 * @notice Deposits tokens using multiple delegation streams, executed sequentially
189- * @dev Each element is executed one after the other. The caller must be the delegator
190- * (first delegate in the chain) for each stream.
196+ * @dev Each element is executed one after the other.
191197 * @param _depositStreams Array of deposit parameters
198+ * @notice Security consideration: Callable by anyone. Each redelegation in the batch MUST include an
199+ * `ERC20TransferAmountEnforcer` capped to exactly the intended deposit amount to prevent over-spending or replay.
192200 */
193201 function depositByDelegationBatch (DepositParams[] memory _depositStreams ) external {
194202 uint256 streamsLength_ = _depositStreams.length ;
@@ -215,6 +223,8 @@ contract VedaAdapter is Ownable2Step {
215223 * @param _token Address of the underlying token to receive
216224 * @param _shareAmount Amount of vault shares to redeem
217225 * @param _minimumAssets Minimum underlying assets the user expects to receive (slippage protection)
226+ * @notice Security consideration: Callable by anyone. The redelegation passed in MUST include an
227+ * `ERC20TransferAmountEnforcer` capped to exactly `_shareAmount` to prevent over-spending or replay.
218228 */
219229 function withdrawByDelegation (
220230 Delegation[] memory _delegations ,
@@ -229,9 +239,10 @@ contract VedaAdapter is Ownable2Step {
229239
230240 /**
231241 * @notice Withdraws underlying tokens using multiple delegation streams, executed sequentially
232- * @dev Each element is executed one after the other. The caller must be the delegator
233- * (first delegate in the chain) for each stream.
242+ * @dev Each element is executed one after the other.
234243 * @param _withdrawStreams Array of withdraw parameters
244+ * @notice Security consideration: Callable by anyone. Each redelegation in the batch MUST include an
245+ * `ERC20TransferAmountEnforcer` capped to exactly the intended share amount to prevent over-spending or replay.
235246 */
236247 function withdrawByDelegationBatch (WithdrawParams[] memory _withdrawStreams ) external {
237248 uint256 streamsLength_ = _withdrawStreams.length ;
@@ -288,7 +299,7 @@ contract VedaAdapter is Ownable2Step {
288299 * @param _token Token to deposit
289300 * @param _amount Amount to deposit
290301 * @param _minimumMint Minimum vault shares expected
291- * @param _caller Authorized caller (must match leaf delegator)
302+ * @param _caller Address of the caller, used only for event emission
292303 */
293304 function _executeDepositByDelegation (
294305 Delegation[] memory _delegations ,
@@ -301,7 +312,6 @@ contract VedaAdapter is Ownable2Step {
301312 {
302313 uint256 length_ = _delegations.length ;
303314 if (length_ < 2 ) revert InvalidDelegationsLength ();
304- if (_delegations[0 ].delegator != _caller) revert NotLeafDelegator ();
305315 if (_token == address (0 )) revert InvalidZeroAddress ();
306316
307317 address rootDelegator_ = _delegations[length_ - 1 ].delegator;
@@ -332,7 +342,7 @@ contract VedaAdapter is Ownable2Step {
332342 * @param _token Underlying token to receive
333343 * @param _shareAmount Amount of vault shares to redeem
334344 * @param _minimumAssets Minimum underlying assets expected
335- * @param _caller Authorized caller (must match leaf delegator)
345+ * @param _caller Address of the caller, used only for event emission
336346 */
337347 function _executeWithdrawByDelegation (
338348 Delegation[] memory _delegations ,
@@ -345,7 +355,6 @@ contract VedaAdapter is Ownable2Step {
345355 {
346356 uint256 length_ = _delegations.length ;
347357 if (length_ < 2 ) revert InvalidDelegationsLength ();
348- if (_delegations[0 ].delegator != _caller) revert NotLeafDelegator ();
349358 if (_token == address (0 )) revert InvalidZeroAddress ();
350359
351360 address rootDelegator_ = _delegations[length_ - 1 ].delegator;
0 commit comments