/** * Protocolink: Complex multi-step batch transactions * * This example demonstrates how to build complex multi-step transactions * using Protocolink, such as: * - Flash loan * - Swap * - Supply * - Borrow * - Repay * All in one transaction! */ import * as api from '@protocolink/api'; import * as common from '@protocolink/common'; import { createWalletRpcClient } from '../../src/utils/chain-config.js'; import { waitForTransaction } from '../../src/utils/rpc.js'; const CHAIN_ID = common.ChainId.mainnet; const PRIVATE_KEY = process.env.PRIVATE_KEY as `0x${string}`; async function batchComplexTransaction() { 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 USDC: common.Token = { chainId: CHAIN_ID, address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', decimals: 6, symbol: 'USDC', name: 'USD Coin', }; const USDT: common.Token = { chainId: CHAIN_ID, address: '0xdAC17F958D2ee523a2206206994597C13D831ec7', decimals: 6, symbol: 'USDT', name: 'Tether USD', }; console.log('Building complex batch transaction:'); console.log(' 1. Flash loan USDC'); console.log(' 2. Supply USDC to Aave'); console.log(' 3. Borrow USDT from Aave'); console.log(' 4. Swap USDT → USDC'); console.log(' 5. Repay flash loan'); console.log(`Account: ${account}`); try { const logics: any[] = []; const flashLoanAmount = '10000'; // 10,000 USDC // Step 1: Flash loan logic (using utility flash loan) console.log('\n1. Adding flash loan logic...'); const flashLoanQuotation = await api.utility.getFlashLoanQuotation(CHAIN_ID, { loans: [{ token: USDC, amount: flashLoanAmount }], }); const flashLoanLogic = api.utility.newFlashLoanLogic(flashLoanQuotation); logics.push(flashLoanLogic); // Step 2: Supply logic console.log('2. Adding supply logic...'); const supplyQuotation = await api.protocols.aavev3.getSupplyQuotation(CHAIN_ID, { input: { token: USDC, amount: flashLoanAmount }, }); const supplyLogic = api.protocols.aavev3.newSupplyLogic(supplyQuotation); logics.push(supplyLogic); // Step 3: Borrow logic console.log('3. Adding borrow logic...'); const borrowAmount = '5000'; // 5,000 USDT const borrowQuotation = await api.protocols.aavev3.getBorrowQuotation(CHAIN_ID, { output: { token: USDT, amount: borrowAmount }, }); const borrowLogic = api.protocols.aavev3.newBorrowLogic(borrowQuotation); logics.push(borrowLogic); // Step 4: Swap logic console.log('4. Adding swap logic...'); const swapQuotation = await api.protocols.uniswapv3.getSwapTokenQuotation(CHAIN_ID, { input: { token: USDT, amount: borrowAmount }, tokenOut: USDC, slippage: 100, // 1% slippage }); const swapLogic = api.protocols.uniswapv3.newSwapTokenLogic(swapQuotation); logics.push(swapLogic); // Step 5: Flash loan repay logic console.log('5. Adding flash loan repay logic...'); const flashLoanRepayLogic = api.utility.newFlashLoanRepayLogic({ id: flashLoanLogic.id, input: swapQuotation.output, // Use swapped USDC to repay }); logics.push(flashLoanRepayLogic); // Step 6: Get router data and execute console.log('\n6. Building router transaction...'); const routerData = await api.router.getRouterData(CHAIN_ID, { account, logics, }); console.log(`Router: ${routerData.router}`); console.log(`Estimated gas: ${routerData.estimation.gas}`); console.log('\n7. Executing transaction...'); const tx = await walletClient.sendTransaction({ to: routerData.router, data: routerData.data, value: BigInt(routerData.estimation.value || '0'), gas: BigInt(routerData.estimation.gas), }); await waitForTransaction(publicClient, tx); console.log(`Transaction executed: ${tx}`); console.log('\nāœ… Complex batch transaction completed successfully!'); } catch (error) { console.error('Error executing batch transaction:', error); throw error; } } // Run if executed directly if (import.meta.url === `file://${process.argv[1]}`) { batchComplexTransaction().catch(console.error); } export { batchComplexTransaction };