collect_funds
Sweep ETH and tokens from managed wallets back to the main wallet for portfolio consolidation and fund management on Base.
Instructions
Sweep all ETH (and optionally tokens) from managed wallets back to main wallet.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| token_address | No | Token address to sweep (ETH-only if omitted) |
Implementation Reference
- src/index.ts:599-712 (handler)The handler function 'handleCollectFunds' that implements the logic for sweeping tokens and ETH from managed wallets to the main wallet.
async function handleCollectFunds( args: z.infer<typeof CollectFundsSchema> ): Promise<string> { if (wallets.length === 0) { return JSON.stringify({ success: false, error: "No managed wallets to collect from.", }); } const mainWallet = getMainWallet(); const provider = getProvider(); const mainAddress = mainWallet.address; const collectPromises = wallets.map(async (w) => { const signer = getSignerForWallet(w); const results: { address: string; label: string; eth_collected: string; token_collected: string; txHashes: string[]; success: boolean; error?: string; } = { address: w.address, label: w.label, eth_collected: "0", token_collected: "0", txHashes: [], success: true, }; try { // Collect tokens if token_address provided if (args.token_address) { const tokenBal = await getTokenBalance( provider, args.token_address, w.address ); if (tokenBal > 0n) { const token = new ethers.Contract(args.token_address, ERC20_ABI, signer); const tx = await token.approve(mainAddress, tokenBal, { gasLimit: 100_000n, }); await tx.wait(); // Transfer tokens const transferAbi = [ "function transfer(address to, uint256 amount) external returns (bool)", ]; const tokenTransfer = new ethers.Contract( args.token_address, transferAbi, signer ); const ttx = await tokenTransfer.transfer(mainAddress, tokenBal, { gasLimit: 100_000n, }); await ttx.wait(); const info = await getTokenInfo(provider, args.token_address); results.token_collected = ethers.formatUnits(tokenBal, info.decimals); results.txHashes.push(ttx.hash); } } // Collect ETH (leave gas for the tx itself) const ethBal = await provider.getBalance(w.address); const feeData = await provider.getFeeData(); const gasPrice = feeData.gasPrice ?? 1_000_000n; const gasCost = 21_000n * gasPrice * 2n; // 2x buffer if (ethBal > gasCost) { const sendAmount = ethBal - gasCost; const tx = await signer.sendTransaction({ to: mainAddress, value: sendAmount, gasLimit: 21_000n, }); await tx.wait(); results.eth_collected = formatEth(sendAmount); results.txHashes.push(tx.hash); } } catch (err: unknown) { results.success = false; results.error = err instanceof Error ? err.message : String(err); } return results; }); const settled = await Promise.allSettled(collectPromises); const outcomes = settled.map((r) => r.status === "fulfilled" ? r.value : { address: "unknown", label: "", success: false, error: "Promise rejected" } ); const succeeded = outcomes.filter((o) => o.success).length; return JSON.stringify( { success: succeeded > 0, collected_from: succeeded, failed: outcomes.length - succeeded, main_wallet: mainAddress, results: outcomes, }, null, 2 ); } - src/index.ts:154-159 (schema)Zod schema definition for input arguments to the 'collect_funds' tool.
const CollectFundsSchema = z.object({ token_address: z .string() .optional() .describe("Token address to sweep (ETH-only if omitted)"), }); - src/index.ts:875-888 (registration)Registration of the 'collect_funds' tool in the MCP server's listTools handler.
name: "collect_funds", description: "Sweep all ETH (and optionally tokens) from managed wallets back to main wallet.", inputSchema: { type: "object" as const, properties: { token_address: { type: "string", description: "Token address to sweep (ETH-only if omitted)", }, }, }, }, - src/index.ts:938-940 (registration)Registration of the 'collect_funds' tool in the MCP server's CallToolRequest handler.
case "collect_funds": result = await handleCollectFunds(CollectFundsSchema.parse(args ?? {})); break;