/** * Aave v3: Multi-asset flash loan * * This example demonstrates how to execute a flash loan for multiple assets. * Useful for arbitrage opportunities across multiple tokens. */ import { createWalletRpcClient } from '../../src/utils/chain-config.js'; import { getAavePoolAddress } from '../../src/utils/addresses.js'; import { getTokenMetadata, parseTokenAmount } from '../../src/utils/tokens.js'; import { waitForTransaction } from '../../src/utils/rpc.js'; import type { Address, Hex } from 'viem'; const CHAIN_ID = 1; // Mainnet const PRIVATE_KEY = process.env.PRIVATE_KEY as `0x${string}`; // Aave Pool ABI const POOL_ABI = [ { name: 'flashLoan', type: 'function', stateMutability: 'nonpayable', inputs: [ { name: 'receiverAddress', type: 'address' }, { name: 'assets', type: 'address[]' }, { name: 'amounts', type: 'uint256[]' }, { name: 'modes', type: 'uint256[]' }, { name: 'onBehalfOf', type: 'address' }, { name: 'params', type: 'bytes' }, { name: 'referralCode', type: 'uint16' }, ], outputs: [], }, ] as const; /** * Flash loan modes: * 0: No debt (just flash loan, repay fully) * 1: Stable debt (deprecated in v3.3+) * 2: Variable debt (open debt position) */ const FLASH_LOAN_MODE_NO_DEBT = 0; const FLASH_LOAN_MODE_VARIABLE_DEBT = 2; const FLASH_LOAN_RECEIVER = process.env.FLASH_LOAN_RECEIVER as `0x${string}`; async function flashLoanMulti() { const walletClient = createWalletRpcClient(CHAIN_ID, PRIVATE_KEY); const publicClient = walletClient as any; const account = walletClient.account?.address; if (!account) { throw new Error('No account available'); } const poolAddress = getAavePoolAddress(CHAIN_ID); // Multiple tokens for flash loan const tokens = [ getTokenMetadata(CHAIN_ID, 'USDC'), getTokenMetadata(CHAIN_ID, 'USDT'), ]; const amounts = [ parseTokenAmount('10000', tokens[0].decimals), // 10,000 USDC parseTokenAmount('5000', tokens[1].decimals), // 5,000 USDT ]; const assets = tokens.map(t => t.address); const modes = [FLASH_LOAN_MODE_NO_DEBT, FLASH_LOAN_MODE_NO_DEBT]; console.log('Executing multi-asset flash loan:'); tokens.forEach((token, i) => { console.log(` ${amounts[i]} ${token.symbol}`); }); console.log(`Pool: ${poolAddress}`); console.log(`Receiver: ${FLASH_LOAN_RECEIVER}`); if (!FLASH_LOAN_RECEIVER) { throw new Error('FLASH_LOAN_RECEIVER environment variable not set'); } // Execute multi-asset flash loan // The receiver contract must: // 1. Receive all loaned tokens // 2. Perform desired operations (e.g., arbitrage) // 3. For each asset, approve the pool for (amount + premium) // 4. If mode = 2, approve for amount only (premium added to debt) // 5. Return true from executeOperation const tx = await walletClient.writeContract({ address: poolAddress, abi: POOL_ABI, functionName: 'flashLoan', args: [ FLASH_LOAN_RECEIVER, assets, amounts, modes, account, // onBehalfOf '0x' as Hex, // Optional params 0, // Referral code ], }); await waitForTransaction(publicClient, tx); console.log(`Multi-asset flash loan executed: ${tx}`); console.log('\n✅ Multi-asset flash loan completed successfully!'); } // Run if executed directly if (import.meta.url === `file://${process.argv[1]}`) { flashLoanMulti().catch(console.error); } export { flashLoanMulti };