Flash unwinder contracts and scripts, relay lane tuning, trustless bridge and token-aggregation updates.

Made-with: Cursor
This commit is contained in:
defiQUG
2026-04-12 06:33:54 -07:00
parent 662b35ad69
commit 6817f53591
40 changed files with 682 additions and 88 deletions

View File

@@ -5,6 +5,16 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
interface IAavePoolLike {
function flashLoan(
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata interestRateModes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external;
function flashLoanSimple(
address receiverAddress,
address asset,
@@ -14,6 +24,16 @@ interface IAavePoolLike {
) external;
}
interface IAaveFlashLoanReceiver {
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external returns (bool);
}
interface IAaveFlashLoanSimpleReceiver {
function executeOperation(
address asset,
@@ -58,10 +78,9 @@ interface IAaveAtomicBridgeCoordinator {
/**
* @title AaveQuotePushFlashReceiver
* @notice Aave V3 flashLoanSimple receiver for the quote-push workflow:
* flash borrow quote -> buy PMM base -> unwind base externally -> repay lender, retaining any surplus.
* @notice Aave V3 flash-loan receiver for the quote-push workflow (uses `flashLoan` with singleton arrays).
*/
contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver {
contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver, IAaveFlashLoanReceiver {
using SafeERC20 for IERC20;
address public immutable pool;
@@ -119,7 +138,28 @@ contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver {
}
function flashQuotePush(address asset, uint256 amount, QuotePushParams calldata params) external {
IAavePoolLike(pool).flashLoanSimple(address(this), asset, amount, abi.encode(address(this), params), 0);
address[] memory assets = new address[](1);
uint256[] memory amts = new uint256[](1);
uint256[] memory modes = new uint256[](1);
assets[0] = asset;
amts[0] = amount;
modes[0] = 0;
IAavePoolLike(pool).flashLoan(
address(this), assets, amts, modes, address(this), abi.encode(address(this), params), 0
);
}
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external returns (bool) {
if (msg.sender != pool) revert UntrustedPool();
if (assets.length != 1 || amounts.length != 1 || premiums.length != 1) revert BadParams();
_executeQuotePush(assets[0], amounts[0], premiums[0], initiator, params);
return true;
}
function executeOperation(
@@ -130,6 +170,17 @@ contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver {
bytes calldata params
) external returns (bool) {
if (msg.sender != pool) revert UntrustedPool();
_executeQuotePush(asset, amount, premium, initiator, params);
return true;
}
function _executeQuotePush(
address asset,
uint256 amount,
uint256 premium,
address initiator,
bytes calldata params
) internal {
(address expectedInitiator, QuotePushParams memory p) = abi.decode(params, (address, QuotePushParams));
if (initiator != expectedInitiator) revert UntrustedInitiator();
if (
@@ -148,7 +199,6 @@ contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver {
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);
return true;
}
function _swapQuoteForBase(address asset, uint256 amount, address integration, address pmmPool, uint256 minOutPmm)

View File

@@ -95,7 +95,7 @@ contract AaveQuotePushFlashReceiverMainnetForkTest is Test {
receiver = new AaveQuotePushFlashReceiver(AAVE_POOL_MAINNET);
unwinder = new AaveForkMockExternalUnwinder(IERC20(CWUSDC), IERC20(USDC), 130, 100);
deal(USDC, address(unwinder), 100_000_000);
deal(USDC, address(unwinder), 50_000_000_000);
cusdc138 = new MockMintableToken("Chain 138 USDC", "cUSDC", 6, address(this));
bondToken = new MockMintableToken("Atomic Bond", "aBOND", 6, address(this));

View File

@@ -7,7 +7,7 @@ import {DODOToUniswapV3MultiHopExternalUnwinder} from "../src/DODOToUniswapV3Mul
contract DODOToUniswapV3MultiHopExternalUnwinderMainnetForkTest is Test {
address constant DODO_PMM_INTEGRATION_MAINNET = 0xa9F284eD010f4F7d7F8F201742b49b9f58e29b84;
address constant UNISWAP_V3_ROUTER = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45;
address constant UNISWAP_V3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
address constant POOL_CWUSDC_USDT = 0xCC0fd27A40775c9AfcD2BBd3f7c902b0192c247A;
address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;

View File

@@ -11,7 +11,7 @@ interface IWETHFork {
}
contract UniswapV3ExternalUnwinderMainnetForkTest is Test {
address constant UNISWAP_V3_ROUTER = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45;
address constant UNISWAP_V3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address constant CWUSDC = 0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a;