105 lines
3.1 KiB
TypeScript
105 lines
3.1 KiB
TypeScript
/**
|
|
* Aave v3: Single-asset flash loan
|
|
*
|
|
* This example demonstrates how to execute a flash loan for a single asset.
|
|
* Flash loans must be repaid within the same transaction, including a premium.
|
|
*/
|
|
|
|
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: 'flashLoanSimple',
|
|
type: 'function',
|
|
stateMutability: 'nonpayable',
|
|
inputs: [
|
|
{ name: 'receiverAddress', type: 'address' },
|
|
{ name: 'asset', type: 'address' },
|
|
{ name: 'amount', type: 'uint256' },
|
|
{ name: 'params', type: 'bytes' },
|
|
{ name: 'referralCode', type: 'uint16' },
|
|
],
|
|
outputs: [],
|
|
},
|
|
] as const;
|
|
|
|
// Flash loan receiver contract ABI (you need to deploy this)
|
|
interface IFlashLoanReceiver {
|
|
executeOperation: (
|
|
asset: Address,
|
|
amount: bigint,
|
|
premium: bigint,
|
|
initiator: Address,
|
|
params: Hex
|
|
) => Promise<boolean>;
|
|
}
|
|
|
|
/**
|
|
* Example flash loan receiver contract address
|
|
*
|
|
* In production, you would deploy your own flash loan receiver contract
|
|
* that implements IFlashLoanReceiver and performs your desired logic.
|
|
*/
|
|
const FLASH_LOAN_RECEIVER = process.env.FLASH_LOAN_RECEIVER as `0x${string}`;
|
|
|
|
async function flashLoanSimple() {
|
|
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);
|
|
const token = getTokenMetadata(CHAIN_ID, 'USDC');
|
|
const amount = parseTokenAmount('10000', token.decimals); // 10,000 USDC
|
|
|
|
console.log(`Executing flash loan for ${amount} ${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 flash loan
|
|
// The receiver contract must:
|
|
// 1. Receive the loaned tokens
|
|
// 2. Perform desired operations
|
|
// 3. Approve the pool for (amount + premium)
|
|
// 4. Return true from executeOperation
|
|
const tx = await walletClient.writeContract({
|
|
address: poolAddress,
|
|
abi: POOL_ABI,
|
|
functionName: 'flashLoanSimple',
|
|
args: [
|
|
FLASH_LOAN_RECEIVER, // Your flash loan receiver contract
|
|
token.address,
|
|
amount,
|
|
'0x' as Hex, // Optional params
|
|
0, // Referral code
|
|
],
|
|
});
|
|
|
|
await waitForTransaction(publicClient, tx);
|
|
console.log(`Flash loan executed: ${tx}`);
|
|
console.log('\n✅ Flash loan completed successfully!');
|
|
}
|
|
|
|
// Run if executed directly
|
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
flashLoanSimple().catch(console.error);
|
|
}
|
|
|
|
export { flashLoanSimple };
|
|
|