/** * Protocolink: Multi-protocol composition (swap → supply) * * This example demonstrates how to compose multiple DeFi operations * into a single transaction using Protocolink. * * Example: Swap USDC → WBTC on Uniswap v3, then supply WBTC to Aave v3 */ 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; // 1 for mainnet, 8453 for Base, etc. const PRIVATE_KEY = process.env.PRIVATE_KEY as `0x${string}`; async function composeSwapAndSupply() { 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'); } // Token definitions const USDC: common.Token = { chainId: CHAIN_ID, address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', decimals: 6, symbol: 'USDC', name: 'USD Coin', }; const WBTC: common.Token = { chainId: CHAIN_ID, address: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', decimals: 8, symbol: 'WBTC', name: 'Wrapped Bitcoin', }; const amountIn = '1000'; // 1000 USDC const slippage = 100; // 1% slippage tolerance in basis points console.log(`Composing transaction: Swap ${amountIn} USDC → WBTC, then supply to Aave`); console.log(`Chain ID: ${CHAIN_ID}`); console.log(`Account: ${account}`); try { // Step 1: Get swap quotation from Uniswap v3 console.log('\n1. Getting swap quotation...'); const swapQuotation = await api.protocols.uniswapv3.getSwapTokenQuotation(CHAIN_ID, { input: { token: USDC, amount: amountIn }, tokenOut: WBTC, slippage, }); console.log(`Expected output: ${swapQuotation.output.amount} ${swapQuotation.output.token.symbol}`); // Step 2: Build swap logic const swapLogic = api.protocols.uniswapv3.newSwapTokenLogic(swapQuotation); // Step 3: Get Aave v3 supply quotation console.log('\n2. Getting Aave supply quotation...'); const supplyQuotation = await api.protocols.aavev3.getSupplyQuotation(CHAIN_ID, { input: swapQuotation.output, // Use WBTC from swap as input tokenOut: swapQuotation.output.token, // aWBTC (Protocolink will resolve the aToken) }); console.log(`Expected aToken output: ${supplyQuotation.output.amount} ${supplyQuotation.output.token.symbol}`); // Step 4: Build supply logic const supplyLogic = api.protocols.aavev3.newSupplyLogic(supplyQuotation); // Step 5: Build router logics (combine swap + supply) const routerLogics = [swapLogic, supplyLogic]; // Step 6: Get router data console.log('\n3. Building router transaction...'); const routerData = await api.router.getRouterData(CHAIN_ID, { account, logics: routerLogics, }); console.log(`Router: ${routerData.router}`); console.log(`Estimated gas: ${routerData.estimation.gas}`); // Step 7: Execute transaction console.log('\n4. 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āœ… Multi-protocol transaction completed successfully!'); } catch (error) { console.error('Error composing transaction:', error); throw error; } } // Run if executed directly if (import.meta.url === `file://${process.argv[1]}`) { composeSwapAndSupply().catch(console.error); } export { composeSwapAndSupply };