Skip to main content
Glama

write.asset_manager.yield_claimer_cowswap

Read-onlyIdempotent

Claim LP fees from any position, then swap collected tokens to a target token using CowSwap's MEV-protected batch auctions. Encodes all required arguments for both yield claimer and CowSwapper.

Instructions

Encode args for yield claimer coupled with CowSwap. Claims LP fees, then swaps the claimed tokens to a target token via CowSwap batch auctions (MEV-protected). For staked LPs, sell_tokens is the staking reward token list (e.g. [AERO_address]). For non-staked LPs, sell_tokens is all LP fee tokens except the buy_token — e.g. for a WETH/USDC LP claiming fees as USDC, use sell_tokens: [WETH_address], buy_token: USDC_address. Sets metadata on BOTH the CowSwapper and the Yield Claimer. Returns { asset_managers, statuses, datas } with 2 entries (cowswapper + yield_claimer). Base only. Combinable with other intent tools.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
dex_protocolYesDEX protocol of the LP position — used to resolve the correct asset manager address.
sell_tokensYesToken addresses to sell. Staked LP: [AERO]. Non-staked: [token0, token1] minus buy_token.
buy_tokenYesToken address to receive after swap
fee_recipientYesAddress to receive claimed fees
enabledNoTrue to enable, false to disable
chain_idNoChain ID: 8453 (Base), 130 (Unichain), or 10 (Optimism)

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
descriptionNo
asset_managersYes
statusesYes
datasYes
strategy_nameNo

Implementation Reference

  • The main handler function for the 'write.asset_manager.yield_claimer_cowswap' tool. Validates inputs, resolves CowSwapper and YieldClaimer addresses, encodes CowSwap token metadata and yield claimer coupled callback data, and returns the formatted result with both asset manager entries.
      async (params) => {
        try {
          const validChainId = validateChainId(params.chain_id);
          const amKey = dexProtocolToAmKey(params.dex_protocol);
          let cowSwapperAddress: string;
          try {
            cowSwapperAddress = getStandaloneAmAddress(validChainId, "cowSwapper");
          } catch (err) {
            const reason = err instanceof Error ? err.message : String(err);
            throw new Error(`yield_claimer_cowswap requires cow_swapper. ${reason}`);
          }
          const yieldClaimerAddress = getAmProtocolAddress(validChainId, "yieldClaimers", amKey);
    
          if (!params.enabled) {
            return formatResult(
              disabledIntent(
                [cowSwapperAddress, yieldClaimerAddress],
                `Disable yield_claimer_cowswap (${params.dex_protocol})`,
              ),
            );
          }
    
          const validSellTokens = params.sell_tokens.map((t, i) =>
            validateAddress(t, `sell_tokens[${i}]`),
          );
          const validBuyToken = validateAddress(params.buy_token, "buy_token");
          const validFeeRecipient = validateAddress(params.fee_recipient, "fee_recipient");
    
          const cowSwapperData = encodeCowSwapTokenMetadata(
            "cow_swap_yield_claim",
            validSellTokens,
            validBuyToken,
          );
    
          const yieldClaimerData = encodeYieldClaimerCoupledCallbackData(
            COWSWAPPER_INITIATOR,
            validFeeRecipient,
            "cow_swap_yield_claim",
          );
    
          const result = {
            description: `Enable yield_claimer_cowswap (${params.dex_protocol}, cowswap)`,
            asset_managers: [cowSwapperAddress, yieldClaimerAddress],
            statuses: [true, true],
            datas: [cowSwapperData, yieldClaimerData],
          };
          return formatResult(result);
        } catch (err) {
          return {
            content: [
              {
                type: "text" as const,
                text: `Error: ${err instanceof Error ? err.message : String(err)}`,
              },
            ],
            isError: true,
          };
        }
      },
    );
  • Registration of the 'write.asset_manager.yield_claimer_cowswap' tool on the MCP server, including annotations (title, readOnlyHint, destructiveHint, etc.), description, inputSchema (dex_protocol, sell_tokens, buy_token, fee_recipient, enabled, chain_id), and outputSchema (IntentOutput).
    server.registerTool(
      "write.asset_manager.yield_claimer_cowswap",
      {
        annotations: {
          title: "Encode Yield Claimer + CowSwap Automation",
          readOnlyHint: true,
          destructiveHint: false,
          idempotentHint: true,
          openWorldHint: false,
        },
        description:
          "Encode args for yield claimer coupled with CowSwap. Claims LP fees, then swaps the claimed tokens to a target token via CowSwap batch auctions (MEV-protected). For staked LPs, sell_tokens is the staking reward token list (e.g. [AERO_address]). For non-staked LPs, sell_tokens is all LP fee tokens except the buy_token — e.g. for a WETH/USDC LP claiming fees as USDC, use sell_tokens: [WETH_address], buy_token: USDC_address. Sets metadata on BOTH the CowSwapper and the Yield Claimer. Returns { asset_managers, statuses, datas } with 2 entries (cowswapper + yield_claimer). Base only. Combinable with other intent tools.",
        outputSchema: IntentOutput,
        inputSchema: {
          dex_protocol: DEX_PROTOCOL_SCHEMA,
          sell_tokens: z
            .array(z.string())
            .describe(
              "Token addresses to sell. Staked LP: [AERO]. Non-staked: [token0, token1] minus buy_token.",
            ),
          buy_token: z.string().describe("Token address to receive after swap"),
          fee_recipient: z.string().describe("Address to receive claimed fees"),
          enabled: z.boolean().default(true).describe("True to enable, false to disable"),
          chain_id: z.number().default(8453).describe(CHAIN_ID_DESCRIPTION),
        },
      },
      async (params) => {
        try {
          const validChainId = validateChainId(params.chain_id);
          const amKey = dexProtocolToAmKey(params.dex_protocol);
          let cowSwapperAddress: string;
          try {
            cowSwapperAddress = getStandaloneAmAddress(validChainId, "cowSwapper");
          } catch (err) {
            const reason = err instanceof Error ? err.message : String(err);
            throw new Error(`yield_claimer_cowswap requires cow_swapper. ${reason}`);
          }
          const yieldClaimerAddress = getAmProtocolAddress(validChainId, "yieldClaimers", amKey);
    
          if (!params.enabled) {
            return formatResult(
              disabledIntent(
                [cowSwapperAddress, yieldClaimerAddress],
                `Disable yield_claimer_cowswap (${params.dex_protocol})`,
              ),
            );
          }
    
          const validSellTokens = params.sell_tokens.map((t, i) =>
            validateAddress(t, `sell_tokens[${i}]`),
          );
          const validBuyToken = validateAddress(params.buy_token, "buy_token");
          const validFeeRecipient = validateAddress(params.fee_recipient, "fee_recipient");
    
          const cowSwapperData = encodeCowSwapTokenMetadata(
            "cow_swap_yield_claim",
            validSellTokens,
            validBuyToken,
          );
    
          const yieldClaimerData = encodeYieldClaimerCoupledCallbackData(
            COWSWAPPER_INITIATOR,
            validFeeRecipient,
            "cow_swap_yield_claim",
          );
    
          const result = {
            description: `Enable yield_claimer_cowswap (${params.dex_protocol}, cowswap)`,
            asset_managers: [cowSwapperAddress, yieldClaimerAddress],
            statuses: [true, true],
            datas: [cowSwapperData, yieldClaimerData],
          };
          return formatResult(result);
        } catch (err) {
          return {
            content: [
              {
                type: "text" as const,
                text: `Error: ${err instanceof Error ? err.message : String(err)}`,
              },
            ],
            isError: true,
          };
        }
      },
    );
  • Input schema for the yield_claimer_cowswap tool: dex_protocol (enum), sell_tokens (string[]), buy_token (string), fee_recipient (string), enabled (boolean, default true), chain_id (number, default 8453).
    inputSchema: {
      dex_protocol: DEX_PROTOCOL_SCHEMA,
      sell_tokens: z
        .array(z.string())
        .describe(
          "Token addresses to sell. Staked LP: [AERO]. Non-staked: [token0, token1] minus buy_token.",
        ),
      buy_token: z.string().describe("Token address to receive after swap"),
      fee_recipient: z.string().describe("Address to receive claimed fees"),
      enabled: z.boolean().default(true).describe("True to enable, false to disable"),
      chain_id: z.number().default(8453).describe(CHAIN_ID_DESCRIPTION),
    },
  • IntentOutput schema used as output schema for the tool: description (optional), asset_managers (string[]), statuses (boolean[]), datas (string[]), strategy_name (optional string).
    export const IntentOutput = z.object({
      description: z.string().optional(),
      asset_managers: z.array(z.string()),
      statuses: z.array(z.boolean()),
      datas: z.array(z.string()),
      strategy_name: z.string().optional(),
    });
  • Helper function encodeCowSwapTokenMetadata that encodes sell_tokens and buy_token into ABI-encoded metadata for the CowSwapper, used by the yield_claimer_cowswap handler.
    export function encodeCowSwapTokenMetadata(
      strategy: string,
      sellTokens: `0x${string}`[],
      buyToken: `0x${string}`,
    ): `0x${string}` {
      const innerData = encodeAbiParameters(
        [
          { name: "sellTokens", type: "address[]" },
          { name: "buyToken", type: "address" },
        ],
        [sellTokens, buyToken],
      );
      return encodeOuterMetadata(strategy, innerData);
    }
  • Helper function encodeYieldClaimerCoupledCallbackData that encodes the yield claimer callback data with coupled CowSwap metadata, used by the yield_claimer_cowswap handler.
    export function encodeYieldClaimerCoupledCallbackData(
      initiator: `0x${string}`,
      feeRecipient: `0x${string}`,
      strategy: string,
    ): `0x${string}` {
      const metaData = encodeCoupledStrategyMetadata(strategy);
      return encodeAbiParameters(
        [
          { name: "initiator", type: "address" },
          { name: "feeRecipient", type: "address" },
          { name: "maxClaimFee", type: "uint256" },
          { name: "metaData_", type: "bytes" },
        ],
        [initiator, feeRecipient, DEFAULT_MAX_CLAIM_FEE, metaData],
      );
    }
Behavior4/5

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

Description discloses that it 'Sets metadata on BOTH the CowSwapper and the Yield Claimer' and returns a specific output shape. Annotations readOnlyHint=true align with encoding nature. Adds behavioral context beyond annotations (metadata setting, output format). No contradiction.

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?

Description is two sentences plus one bullet point, efficiently conveying purpose, usage, and output. No redundant information; every sentence serves a purpose.

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

Completeness5/5

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

Given tool complexity (combining two actions) and rich schema+annotations, description covers purpose, usage, parameter semantics, constraints (Base only), combinability, and output structure. No gaps identified.

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

Parameters5/5

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

Schema coverage 100% and description enhances each parameter: clarifies sell_tokens construction (staked vs non-staked), buy_token as target, and chain_id enum values. Adds significant meaning beyond schema definitions.

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?

Description clearly states it encodes args for yield claimer coupled with CowSwap, combining LP fee claiming and swapping via batch auctions. It distinguishes from siblings by explaining the unique combination of claim+swap and provides concrete examples for staked vs non-staked LPs.

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

Usage Guidelines4/5

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

Description explains when to use: for claiming LP fees and swapping to target token with MEV protection. It differentiates staked vs non-staked LP handling and mentions 'Base only' and 'Combinable with other intent tools'. Lacks explicit when-not-to-use but context from sibling names implies alternatives.

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/arcadia-finance/mcp-server'

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