115 lines
3.9 KiB
TypeScript
115 lines
3.9 KiB
TypeScript
|
|
/**
|
||
|
|
* 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 };
|
||
|
|
|