Add Aave quote-push collateral supply and toggle hooks.
Some checks failed
CI/CD Pipeline / Security Scanning (push) Has been cancelled
CI/CD Pipeline / Solidity Contracts (push) Has been cancelled
CI/CD Pipeline / Lint and Format (push) Has been cancelled
CI/CD Pipeline / Terraform Validation (push) Has been cancelled
CI/CD Pipeline / Kubernetes Validation (push) Has been cancelled
Validation / validate-genesis (push) Has started running
Validation / validate-terraform (push) Has been cancelled
Validation / validate-kubernetes (push) Has been cancelled
Validation / validate-smart-contracts (push) Has been cancelled
Validation / validate-security (push) Has been cancelled
Validation / validate-documentation (push) Has been cancelled

Extends AaveQuotePushFlashReceiver with before/after swap collateral steps, env-driven run scripts, forkproof parity, and scoped forge tests for supply/toggle callback ordering.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-06-26 02:07:30 -07:00
parent aa5790bb8b
commit 848a5e35ea
12 changed files with 486 additions and 11 deletions

View File

@@ -22,6 +22,10 @@ interface IAavePoolLike {
bytes calldata params,
uint16 referralCode
) external;
function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external;
}
interface IAaveFlashLoanReceiver {
@@ -85,6 +89,29 @@ contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver, IAaveFlashL
address public immutable pool;
enum CollateralHook {
BeforeSwap,
AfterSwap,
BeforeUnwind
}
struct CollateralSupplyStep {
address asset;
uint256 amount;
}
struct CollateralToggleStep {
address asset;
bool useAsCollateral;
}
struct CollateralParams {
CollateralSupplyStep[] supplyBeforeSwap;
CollateralToggleStep[] toggleBeforeSwap;
CollateralToggleStep[] toggleAfterSwap;
CollateralToggleStep[] toggleBeforeUnwind;
}
struct QuotePushParams {
address integration;
address pmmPool;
@@ -94,6 +121,7 @@ contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver, IAaveFlashL
uint256 minOutUnwind;
bytes unwindData;
AtomicBridgeParams atomicBridge;
CollateralParams collateral;
}
struct AtomicBridgeParams {
@@ -132,6 +160,16 @@ contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver, IAaveFlashL
uint256 bridgeAmount,
uint256 minDestinationAmount
);
event CollateralSupplied(address indexed asset, uint256 amount);
event CollateralToggled(address indexed asset, bool useAsCollateral, CollateralHook hook);
function emptyCollateralParams() external pure returns (CollateralParams memory params) {
return params;
}
function collateralHooksVersion() external pure returns (uint256) {
return 1;
}
constructor(address pool_) {
pool = pool_;
@@ -189,13 +227,20 @@ contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver, IAaveFlashL
) revert BadParams();
if (p.baseToken == asset) revert BadParams();
_applyCollateralSupplies(p.collateral.supplyBeforeSwap);
_applyCollateralToggles(p.collateral.toggleBeforeSwap, CollateralHook.BeforeSwap);
uint256 baseOut = _swapQuoteForBase(asset, amount, p.integration, p.pmmPool, p.minOutPmm);
_applyCollateralToggles(p.collateral.toggleAfterSwap, CollateralHook.AfterSwap);
uint256 baseBal = IERC20(p.baseToken).balanceOf(address(this));
if (p.atomicBridge.coordinator != address(0)) {
_triggerAtomicBridge(p.baseToken, baseBal, p.atomicBridge);
}
_applyCollateralToggles(p.collateral.toggleBeforeUnwind, CollateralHook.BeforeUnwind);
uint256 unwindOut = _unwindBaseIntoQuote(p.baseToken, asset, p.externalUnwinder, p.minOutUnwind, p.unwindData);
uint256 surplus = _approveRepayment(asset, amount + premium);
emit QuotePushExecuted(asset, p.baseToken, amount, premium, baseOut, unwindOut, surplus);
@@ -222,6 +267,27 @@ contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver, IAaveFlashL
IAaveExternalUnwinder(externalUnwinder).unwind(baseToken, quoteToken, remainingBase, minOutUnwind, unwindData);
}
function _applyCollateralSupplies(CollateralSupplyStep[] memory steps) internal {
uint256 n = steps.length;
for (uint256 i = 0; i < n; ++i) {
CollateralSupplyStep memory step = steps[i];
if (step.asset == address(0) || step.amount == 0) continue;
IERC20(step.asset).forceApprove(pool, step.amount);
IAavePoolLike(pool).supply(step.asset, step.amount, address(this), 0);
emit CollateralSupplied(step.asset, step.amount);
}
}
function _applyCollateralToggles(CollateralToggleStep[] memory steps, CollateralHook hook) internal {
uint256 n = steps.length;
for (uint256 i = 0; i < n; ++i) {
CollateralToggleStep memory step = steps[i];
if (step.asset == address(0)) continue;
IAavePoolLike(pool).setUserUseReserveAsCollateral(step.asset, step.useAsCollateral);
emit CollateralToggled(step.asset, step.useAsCollateral, hook);
}
}
function _approveRepayment(address quoteToken, uint256 need) internal returns (uint256 surplus) {
IERC20 quote = IERC20(quoteToken);
uint256 quoteBal = quote.balanceOf(address(this));

View File

@@ -186,7 +186,8 @@ contract AaveQuotePushFlashReceiverMainnetForkTest is Test {
routeId: bytes32(0),
settlementMode: bytes32(0),
submitCommitment: false
})
}),
collateral: receiver.emptyCollateralParams()
});
receiver.flashQuotePush(USDC, amount, p);
@@ -239,7 +240,8 @@ contract AaveQuotePushFlashReceiverMainnetForkTest is Test {
routeId: atomicCorridorId,
settlementMode: bytes32(0),
submitCommitment: true
})
}),
collateral: receiver.emptyCollateralParams()
});
uint256 receiverQuoteBefore = IERC20(USDC).balanceOf(address(receiver));
@@ -297,7 +299,8 @@ contract AaveQuotePushFlashReceiverMainnetForkTest is Test {
routeId: atomicCorridorId,
settlementMode: bytes32(0),
submitCommitment: true
})
}),
collateral: receiver.emptyCollateralParams()
});
receiver.flashQuotePush(USDC, amount, p);