Skip to main content
Glama
lordbasilaiassistant-sudo

base-multi-wallet-mcp

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

TableJSON Schema
NameRequiredDescriptionDefault
token_addressNoToken address to sweep (ETH-only if omitted)

Implementation Reference

  • 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
      );
    }
  • 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;
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. It successfully conveys the comprehensive nature ('all ETH') and directional flow (managed→main), but omits critical financial operation details like gas costs, irreversibility of transfers, confirmation requirements, or whether this operation is atomic across wallets.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Perfect single-sentence structure with zero waste. Front-loaded with action verb 'Sweep', followed by scope ('all ETH'), optional extension ('and optionally tokens'), source ('managed wallets'), and destination ('main wallet'). Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with 100% schema coverage and no output schema, the description adequately explains the core mechanism. However, as a financial mutation tool without safety annotations, it should ideally mention gas implications or irreversibility warnings to be fully complete for safe agent operation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, establishing baseline 3. The description mentions 'optionally tokens' which aligns with the optional token_address parameter, but adds no semantic detail beyond what the schema already provides (e.g., no format examples, validation rules, or behavior when omitted beyond the schema's own description).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Excellent clarity with specific verb 'Sweep' and clear resource identification ('ETH and optionally tokens from managed wallets back to main wallet'). Clearly distinguishes from sibling 'fund_wallets' (outward distribution) and trading tools by specifying the consolidation direction toward the main wallet.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit when-to-use or alternative guidance provided. However, the phrase 'back to main wallet' implicitly contrasts this tool with 'fund_wallets' (which likely distributes outward) and indicates this is for consolidation/recovery scenarios. Lacks explicit exclusions or prerequisites.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/lordbasilaiassistant-sudo/base-multi-wallet-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server