Skip to content

Commit 57120d5

Browse files
committed
additional tests and code optimization
1 parent c022400 commit 57120d5

2 files changed

Lines changed: 278 additions & 38 deletions

File tree

src/helpers/VedaAdapter.sol

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ contract VedaAdapter is Ownable2Step {
140140
/// @dev Thrown when the batch array is empty
141141
error InvalidBatchLength();
142142

143+
/// @dev Thrown when the leaf caveat terms are shorter than 52 bytes (ERC20TransferAmountEnforcer format)
144+
error InvalidTermsLength();
145+
143146
////////////////////////////// State //////////////////////////////
144147

145148
/**
@@ -307,11 +310,26 @@ contract VedaAdapter is Ownable2Step {
307310
}
308311
}
309312

313+
/**
314+
* @notice Parses ERC20TransferAmountEnforcer terms from memory bytes
315+
* @dev Terms format: abi.encodePacked(address token, uint256 amount) = 52 bytes.
316+
* Slice syntax is only available for calldata; assembly is used to read from memory bytes.
317+
* @param _terms The raw terms bytes from a caveat
318+
* @return token_ The token address encoded in the first 20 bytes
319+
* @return amount_ The uint256 amount encoded in bytes 20-51
320+
*/
321+
function _parseERC20TransferTerms(bytes memory _terms) private pure returns (address token_, uint256 amount_) {
322+
if (_terms.length < 52) revert InvalidTermsLength();
323+
assembly {
324+
token_ := shr(96, mload(add(_terms, 32)))
325+
amount_ := mload(add(_terms, 52))
326+
}
327+
}
328+
310329
/**
311330
* @notice Internal implementation of deposit by delegation
312331
* @dev Parses the deposit token and amount from the first caveat of the leaf delegation
313-
* (`_delegations[0].caveats[0].terms`), which must be 52 bytes in
314-
* ERC20TransferAmountEnforcer format: abi.encodePacked(address token, uint256 amount).
332+
* via `_parseERC20TransferTerms`.
315333
* @param _delegations Delegation chain, sorted leaf to root
316334
* @param _minimumMint Minimum vault shares expected (sanity-check bound)
317335
* @param _caller Address of the caller, used only for event emission
@@ -326,21 +344,7 @@ contract VedaAdapter is Ownable2Step {
326344
uint256 length_ = _delegations.length;
327345
if (length_ < 2) revert InvalidDelegationsLength();
328346

329-
// Parse token and amount from the leaf delegation's first caveat terms.
330-
// Terms format (ERC20TransferAmountEnforcer): abi.encodePacked(address token, uint256 amount) = 52 bytes.
331-
// Slice syntax is only available for calldata; use assembly to read from memory bytes.
332-
bytes memory terms_ = _delegations[0].caveats[0].terms;
333-
address token_;
334-
uint256 amount_;
335-
assembly {
336-
// Memory layout of `terms_`: [length (32 bytes)][data ...].
337-
// `add(terms_, 32)` points to byte 0 of the data.
338-
// The address occupies bytes 0-19 (high 20 bytes of the first 32-byte word).
339-
token_ := shr(96, mload(add(terms_, 32)))
340-
// The uint256 occupies bytes 20-51; load the 32-byte word starting at byte 20.
341-
amount_ := mload(add(terms_, 52))
342-
}
343-
347+
(address token_, uint256 amount_) = _parseERC20TransferTerms(_delegations[0].caveats[0].terms);
344348
address rootDelegator_ = _delegations[length_ - 1].delegator;
345349

346350
// Redeem delegation: transfer tokens from user to this adapter
@@ -366,11 +370,11 @@ contract VedaAdapter is Ownable2Step {
366370
/**
367371
* @notice Internal implementation of withdraw by delegation
368372
* @dev Parses the share amount from the first caveat of the leaf delegation
369-
* (`_delegations[0].caveats[0].terms`), which must be 52 bytes in
370-
* ERC20TransferAmountEnforcer format: abi.encodePacked(address boringVault, uint256 shareAmount).
371-
* The transfer target is always the immutable `boringVault` address.
373+
* via `_parseERC20TransferTerms`. The caveat encodes the vault share token and amount;
374+
* `_token` is the desired underlying output asset (e.g. USDC), which differs from the
375+
* share token in the caveat.
372376
* @param _delegations Delegation chain, sorted leaf to root
373-
* @param _token Underlying token to receive from the vault (not in the caveat; differs from the share token)
377+
* @param _token Underlying output token to receive from the vault (differs from the share token in the caveat)
374378
* @param _minimumAssets Minimum underlying assets expected (sanity-check bound)
375379
* @param _caller Address of the caller, used only for event emission
376380
*/
@@ -386,16 +390,7 @@ contract VedaAdapter is Ownable2Step {
386390
if (length_ < 2) revert InvalidDelegationsLength();
387391
if (_token == address(0)) revert InvalidZeroAddress();
388392

389-
// Parse share amount from the leaf delegation's first caveat terms.
390-
// Terms format (ERC20TransferAmountEnforcer): abi.encodePacked(address boringVault, uint256 shareAmount) = 52 bytes.
391-
// Slice syntax is only available for calldata; use assembly to read from memory bytes.
392-
bytes memory terms_ = _delegations[0].caveats[0].terms;
393-
uint256 shareAmount_;
394-
assembly {
395-
// The uint256 shareAmount occupies bytes 20-51; load the 32-byte word starting at byte 20.
396-
shareAmount_ := mload(add(terms_, 52))
397-
}
398-
393+
(, uint256 shareAmount_) = _parseERC20TransferTerms(_delegations[0].caveats[0].terms);
399394
address rootDelegator_ = _delegations[length_ - 1].delegator;
400395

401396
// Redeem delegation: transfer vault shares from user to this adapter

0 commit comments

Comments
 (0)