Skip to content

Commit 56357fb

Browse files
committed
Optimize aave adapter without selfdelegation.
1 parent 1ed69ec commit 56357fb

File tree

3 files changed

+144
-183
lines changed

3 files changed

+144
-183
lines changed

src/helpers/AaveAdapter.sol

Lines changed: 68 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ import { ModeLib } from "@erc7579/lib/ModeLib.sol";
88
import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol";
99
import { CallType, ExecType, Delegation, ModeCode } from "../utils/Types.sol";
1010
import { CALLTYPE_SINGLE, EXECTYPE_DEFAULT } from "../utils/Constants.sol";
11-
import { ExecutionHelper } from "@erc7579/core/ExecutionHelper.sol";
12-
1311
import { IDelegationManager } from "../interfaces/IDelegationManager.sol";
1412
import { IAavePool } from "./interfaces/IAavePool.sol";
1513

@@ -43,7 +41,7 @@ import { IAavePool } from "./interfaces/IAavePool.sol";
4341
* - The contract is designed to never hold tokens during normal operation, making owner functions
4442
* purely for exceptional circumstances
4543
*/
46-
contract AaveAdapter is Ownable2Step, ExecutionHelper {
44+
contract AaveAdapter is Ownable2Step {
4745
using SafeERC20 for IERC20;
4846
using ExecutionLib for bytes;
4947
using ModeLib for ModeCode;
@@ -93,6 +91,11 @@ contract AaveAdapter is Ownable2Step, ExecutionHelper {
9391
*/
9492
error InvalidDelegationsLength();
9593

94+
/**
95+
* @notice Thrown when the batch array is empty or lengths don't match
96+
*/
97+
error InvalidBatchLength();
98+
9699
/**
97100
* @notice Thrown when the caller is not the delegator for restricted functions
98101
*/
@@ -118,24 +121,6 @@ contract AaveAdapter is Ownable2Step, ExecutionHelper {
118121
*/
119122
error UnsupportedExecType(ExecType execType);
120123

121-
////////////////////// Modifiers //////////////////////
122-
123-
/**
124-
* @notice Require the function call to come from the DelegationManager.
125-
*/
126-
modifier onlyDelegationManager() {
127-
if (msg.sender != address(delegationManager)) revert NotDelegationManager();
128-
_;
129-
}
130-
131-
/**
132-
* @notice Require the function call to come from this contract itself
133-
*/
134-
modifier onlySelf() {
135-
if (msg.sender != address(this)) revert NotSelf();
136-
_;
137-
}
138-
139124
////////////////////// State //////////////////////
140125

141126
/**
@@ -180,6 +165,15 @@ contract AaveAdapter is Ownable2Step, ExecutionHelper {
180165

181166
////////////////////// Public Functions //////////////////////
182167

168+
/**
169+
* @notice Parameters for a single supply operation in a batch
170+
*/
171+
struct SupplyParams {
172+
Delegation[] delegations;
173+
address token;
174+
uint256 amount;
175+
}
176+
183177
/**
184178
* @notice Supplies tokens to Aave using delegation-based token transfer
185179
* @dev Only the delegator can execute this function, ensuring full control over supply parameters.
@@ -189,33 +183,69 @@ contract AaveAdapter is Ownable2Step, ExecutionHelper {
189183
* @param _amount Amount of tokens to supply (use type(uint256).max for full balance)
190184
*/
191185
function supplyByDelegation(Delegation[] memory _delegations, address _token, uint256 _amount) external {
186+
_executeSupplyByDelegation(_delegations, _token, _amount, msg.sender);
187+
}
188+
189+
/**
190+
* @notice Supplies tokens to Aave using multiple delegation streams, executed sequentially
191+
* @dev Each element in _supplyStreams is executed one after the other. The caller must be the delegator
192+
* (first delegate in the chain) for each stream. Useful for batch operations across multiple users/tokens.
193+
* @param _supplyStreams Array of supply parameters, each containing delegations, token, and amount
194+
*/
195+
function supplyByDelegationBatch(SupplyParams[] memory _supplyStreams) external {
196+
uint256 streamsLength_ = _supplyStreams.length;
197+
if (streamsLength_ == 0) revert InvalidBatchLength();
198+
199+
address caller_ = msg.sender;
200+
for (uint256 i = 0; i < streamsLength_;) {
201+
SupplyParams memory params_ = _supplyStreams[i];
202+
_executeSupplyByDelegation(params_.delegations, params_.token, params_.amount, caller_);
203+
unchecked {
204+
++i;
205+
}
206+
}
207+
}
208+
209+
/**
210+
* @notice Internal implementation of supply by delegation
211+
* @param _delegations Delegation chain for the redelegation pattern
212+
* @param _token Token to supply
213+
* @param _amount Amount to supply
214+
* @param _caller Authorized caller (must match first delegator in chain)
215+
*/
216+
function _executeSupplyByDelegation(
217+
Delegation[] memory _delegations,
218+
address _token,
219+
uint256 _amount,
220+
address _caller
221+
)
222+
internal
223+
{
192224
uint256 length_ = _delegations.length;
193225
if (length_ < 2) revert InvalidDelegationsLength();
194-
if (_delegations[0].delegator != msg.sender) revert UnauthorizedCaller();
226+
if (_delegations[0].delegator != _caller) revert UnauthorizedCaller();
195227
if (_token == address(0)) revert InvalidZeroAddress();
196228

197229
// Root delegator is the original token owner (last in the delegation chain)
198230
address rootDelegator_ = _delegations[length_ - 1].delegator;
199231

200-
bytes[] memory permissionContexts_ = new bytes[](2);
232+
bytes[] memory permissionContexts_ = new bytes[](1);
201233
permissionContexts_[0] = abi.encode(_delegations);
202-
permissionContexts_[1] = abi.encode(new Delegation[](0));
203234

204-
ModeCode[] memory encodedModes_ = new ModeCode[](2);
235+
ModeCode[] memory encodedModes_ = new ModeCode[](1);
205236
encodedModes_[0] = ModeLib.encodeSimpleSingle();
206-
encodedModes_[1] = ModeLib.encodeSimpleSingle();
207237

208-
bytes[] memory executionCallDatas_ = new bytes[](2);
238+
bytes[] memory executionCallDatas_ = new bytes[](1);
209239

210240
bytes memory encodedTransfer_ = abi.encodeCall(IERC20.transfer, (address(this), _amount));
211241
executionCallDatas_[0] = ExecutionLib.encodeSingle(address(_token), 0, encodedTransfer_);
212-
executionCallDatas_[1] = ExecutionLib.encodeSingle(
213-
address(this), 0, abi.encodeWithSelector(this.supply.selector, _token, _amount, rootDelegator_)
214-
);
215242

216243
delegationManager.redeemDelegations(permissionContexts_, encodedModes_, executionCallDatas_);
217244

218-
emit SupplyExecuted(rootDelegator_, msg.sender, _token, _amount);
245+
_ensureAllowance(IERC20(_token), _amount);
246+
aavePool.supply(_token, _amount, rootDelegator_, 0);
247+
248+
emit SupplyExecuted(rootDelegator_, _caller, _token, _amount);
219249
}
220250

221251
/**
@@ -227,89 +257,32 @@ contract AaveAdapter is Ownable2Step, ExecutionHelper {
227257
* @param _amount Amount of tokens to withdraw (use type(uint256).max for full balance)
228258
*/
229259
function withdrawByDelegation(Delegation[] memory _delegations, address _token, uint256 _amount) external {
230-
uint256 length_ = _delegations.length;
231-
if (length_ < 2) revert InvalidDelegationsLength();
260+
if (_delegations.length < 2) revert InvalidDelegationsLength();
232261
if (_delegations[0].delegator != msg.sender) revert UnauthorizedCaller();
233262
if (_token == address(0)) revert InvalidZeroAddress();
234263

235264
// Root delegator is the original token owner (last in the delegation chain)
236-
address rootDelegator_ = _delegations[length_ - 1].delegator;
265+
address rootDelegator_ = _delegations[1].delegator;
237266

238-
bytes[] memory permissionContexts_ = new bytes[](2);
267+
bytes[] memory permissionContexts_ = new bytes[](1);
239268
permissionContexts_[0] = abi.encode(_delegations);
240-
permissionContexts_[1] = abi.encode(new Delegation[](0));
241269

242-
ModeCode[] memory encodedModes_ = new ModeCode[](2);
270+
ModeCode[] memory encodedModes_ = new ModeCode[](1);
243271
encodedModes_[0] = ModeLib.encodeSimpleSingle();
244-
encodedModes_[1] = ModeLib.encodeSimpleSingle();
245272

246-
bytes[] memory executionCallDatas_ = new bytes[](2);
273+
bytes[] memory executionCallDatas_ = new bytes[](1);
247274

248275
// Get the aToken address for the underlying token
249276
IERC20 aToken_ = IERC20(aavePool.getReserveAToken(_token));
250277

251278
bytes memory encodedTransfer_ = abi.encodeCall(IERC20.transfer, (address(this), _amount));
252279
executionCallDatas_[0] = ExecutionLib.encodeSingle(address(aToken_), 0, encodedTransfer_);
253-
executionCallDatas_[1] = ExecutionLib.encodeSingle(
254-
address(this), 0, abi.encodeWithSelector(this.withdraw.selector, _token, _amount, rootDelegator_)
255-
);
256280

257281
delegationManager.redeemDelegations(permissionContexts_, encodedModes_, executionCallDatas_);
258282

259-
emit WithdrawExecuted(rootDelegator_, msg.sender, _token, _amount);
260-
}
283+
aavePool.withdraw(_token, _amount, rootDelegator_);
261284

262-
/**
263-
* @notice Calls the actual supply function on the Aave pool
264-
* @dev This function can only be called internally by this contract (`onlySelf`).
265-
* @param _token Address of the token to supply
266-
* @param _amount Amount of tokens to supply
267-
* @param _onBehalfOf Address that will receive the aTokens
268-
*/
269-
function supply(address _token, uint256 _amount, address _onBehalfOf) external onlySelf {
270-
_ensureAllowance(IERC20(_token), _amount);
271-
aavePool.supply(_token, _amount, _onBehalfOf, 0);
272-
}
273-
274-
/**
275-
* @notice Calls the actual withdraw function on the Aave pool
276-
* @dev This function can only be called internally by this contract (`onlySelf`).
277-
* @param _token Address of the underlying token to withdraw
278-
* @param _amount Amount of tokens to withdraw
279-
* @param _to Address that will receive the withdrawn tokens
280-
*/
281-
function withdraw(address _token, uint256 _amount, address _to) external onlySelf {
282-
aavePool.withdraw(_token, _amount, _to);
283-
}
284-
285-
/**
286-
* @notice Executes a call on behalf of this contract, authorized by the DelegationManager
287-
* @dev Only callable by the DelegationManager. Supports single-call execution
288-
* and handles the revert logic via ExecType.
289-
* @dev Related: @erc7579/MSAAdvanced.sol
290-
* @param _mode The encoded execution mode of the transaction (CallType, ExecType, etc.)
291-
* @param _executionCalldata The encoded call data (single) to be executed
292-
* @return returnData_ An array of returned data from the executed call
293-
*/
294-
function executeFromExecutor(
295-
ModeCode _mode,
296-
bytes calldata _executionCalldata
297-
)
298-
external
299-
payable
300-
onlyDelegationManager
301-
returns (bytes[] memory returnData_)
302-
{
303-
(CallType callType_, ExecType execType_,,) = _mode.decode();
304-
305-
/* Only support single call type with default execution */
306-
if (CallType.unwrap(CALLTYPE_SINGLE) != CallType.unwrap(callType_)) revert UnsupportedCallType(callType_);
307-
if (ExecType.unwrap(EXECTYPE_DEFAULT) != ExecType.unwrap(execType_)) revert UnsupportedExecType(execType_);
308-
/* Process single execution directly without additional checks */
309-
(address target_, uint256 value_, bytes calldata callData_) = _executionCalldata.decodeSingle();
310-
returnData_ = new bytes[](1);
311-
returnData_[0] = _execute(target_, value_, callData_);
312-
return returnData_;
285+
emit WithdrawExecuted(rootDelegator_, msg.sender, _token, _amount);
313286
}
314287

315288
/**

0 commit comments

Comments
 (0)