@continuumdao/ctm-mpc-defi 0.2.35 → 0.2.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1098,7 +1098,7 @@ var evmMultisignCommonInputSchema = zod.z.object({
1098
1098
  chainDetail: chainDetailSchema.optional().describe("Server-filled gas row from chain registry when keyGenId is set."),
1099
1099
  customGasChainDetails: zod.z.record(zod.z.unknown()).optional().describe("Snapshot written to extraJSON.customGasChainDetails when useCustomGas is true."),
1100
1100
  expiryDate: zod.z.number().int().positive().optional().describe(
1101
- "Optional Unix seconds (UTC) when the MPC sign request expires. Uniswap V4, GMX, Hyperliquid, Curve DAO, and Aerodrome default to 30 minutes when omitted; other protocols use the node default (7 days)."
1101
+ "Optional Unix seconds (UTC) when the MPC sign request expires. Uniswap V4, GMX, Hyperliquid, Curve DAO, Aerodrome, and Pendle default to 30 minutes when omitted; other protocols use the node default (7 days)."
1102
1102
  )
1103
1103
  });
1104
1104
  function withMultisignKeySourceRefine(schema) {
@@ -3417,6 +3417,193 @@ var mcpEthenaFetchSusdeApyOutputSchema = zod.z.object({
3417
3417
  cooldownDurationSec: zod.z.number().nullable(),
3418
3418
  notes: zod.z.string()
3419
3419
  });
3420
+ var mcpPendleFetchMarketsInputSchema = zod.z.object({
3421
+ chainId: agentEvmChainIdSchema,
3422
+ query: zod.z.string().trim().min(1).optional().describe("Optional shrink filter on name, PT/YT/underlying symbol or address."),
3423
+ pointsOnly: zod.z.boolean().optional().describe("If true, only markets with point campaigns.")
3424
+ });
3425
+ var mcpPendleFetchMarketsOutputSchema = jsonObjectSchema.describe(
3426
+ "{ chainId, markets[] (address, pt, yt, sy, underlying, expiry, impliedApy, tvlUsd, points), notes }. Live markets only, hard cap 100 TVL-ranked."
3427
+ );
3428
+ var mcpPendleFetchPricesInputSchema = zod.z.object({
3429
+ chainId: agentEvmChainIdSchema,
3430
+ ids: zod.z.array(zod.z.string().min(1)).optional().describe("Asset ids (chainId-0x\u2026). Omit to price the current live listing."),
3431
+ query: zod.z.string().trim().min(1).optional()
3432
+ });
3433
+ var mcpPendleFetchPricesOutputSchema = jsonObjectSchema.describe(
3434
+ "{ chainId, prices[] ({ id, usd }), notes }"
3435
+ );
3436
+ var mcpPendleSearchAssetsInputSchema = zod.z.object({
3437
+ chainId: agentEvmChainIdSchema,
3438
+ query: zod.z.string().trim().min(1).describe("Ticker, name, 0x address, or chainId-0x asset id.")
3439
+ });
3440
+ var mcpPendleSearchAssetsOutputSchema = jsonObjectSchema.describe(
3441
+ "{ chainId, results[] (live PT/YT/SY/market + expiry, liquidity, points), notes }"
3442
+ );
3443
+ var mcpPendleFetchPositionsInputSchema = zod.z.object({
3444
+ user: evmAddressSchema.describe("KeyGen / wallet to list Pendle LP for."),
3445
+ chainId: agentEvmChainIdSchema.optional().describe("If set, only this chain. Omit for all Core chains."),
3446
+ filterUsd: zod.z.number().min(0).optional().describe("Drop holdings below this USD valuation. Omit to keep dust.")
3447
+ });
3448
+ var mcpPendleFetchPositionsOutputSchema = jsonObjectSchema.describe(
3449
+ "{ user, chainId, lp[] (market, name, expiry, matured, lpAmountHuman, lpUsd), notes }. Includes matured. Not the node token list."
3450
+ );
3451
+ var mcpPendleFetchMerkleRewardsInputSchema = zod.z.object({
3452
+ user: evmAddressSchema.describe("Wallet to list off-chain airdrop rows for (informational; no claim).")
3453
+ });
3454
+ var mcpPendleFetchMerkleRewardsOutputSchema = jsonObjectSchema.describe(
3455
+ "{ user, claimableRewards[], claimedRewards[], notes }. List only \u2014 cannot build a claim from these rows."
3456
+ );
3457
+ var mcpPendleQuoteSwapInputSchema = zod.z.object({
3458
+ chainId: agentEvmChainIdSchema,
3459
+ rpcUrl: zod.z.string().min(1).optional(),
3460
+ tokenIn: zod.z.string().min(1).describe("Underlying, PT, or YT (0xeeee / 0x0 = native)."),
3461
+ tokenOut: zod.z.string().min(1),
3462
+ amountHuman: zod.z.string().min(1),
3463
+ slippagePercent: zod.z.number().gt(0).lt(100),
3464
+ receiver: evmAddressSchema.optional(),
3465
+ enableAggregator: zod.z.boolean().optional(),
3466
+ tokenInDecimals: zod.z.number().int().min(0).max(18).optional()
3467
+ });
3468
+ var mcpPendleQuoteOutputSchema = jsonObjectSchema.describe(
3469
+ "Hosted SDK convert quote: action, outputs, priceImpact, impliedApy, requiredApprovals, tx (do not hardcode tx.to)."
3470
+ );
3471
+ var mcpPendleQuoteMintPyInputSchema = zod.z.object({
3472
+ chainId: agentEvmChainIdSchema,
3473
+ rpcUrl: zod.z.string().min(1).optional(),
3474
+ tokenIn: zod.z.string().min(1),
3475
+ pt: evmAddressSchema,
3476
+ yt: evmAddressSchema,
3477
+ amountHuman: zod.z.string().min(1),
3478
+ slippagePercent: zod.z.number().gt(0).lt(100),
3479
+ receiver: evmAddressSchema.optional()
3480
+ });
3481
+ var mcpPendleQuoteRedeemPyInputSchema = zod.z.object({
3482
+ chainId: agentEvmChainIdSchema,
3483
+ rpcUrl: zod.z.string().min(1).optional(),
3484
+ pt: evmAddressSchema,
3485
+ yt: evmAddressSchema,
3486
+ tokenOut: zod.z.string().min(1),
3487
+ amountPtHuman: zod.z.string().min(1),
3488
+ amountYtHuman: zod.z.string().min(1).optional(),
3489
+ slippagePercent: zod.z.number().gt(0).lt(100),
3490
+ receiver: evmAddressSchema.optional()
3491
+ });
3492
+ var mcpPendleQuoteMintSyInputSchema = zod.z.object({
3493
+ chainId: agentEvmChainIdSchema,
3494
+ rpcUrl: zod.z.string().min(1).optional(),
3495
+ tokenIn: zod.z.string().min(1),
3496
+ sy: evmAddressSchema,
3497
+ amountHuman: zod.z.string().min(1),
3498
+ slippagePercent: zod.z.number().gt(0).lt(100),
3499
+ receiver: evmAddressSchema.optional()
3500
+ });
3501
+ var mcpPendleQuoteRedeemSyInputSchema = zod.z.object({
3502
+ chainId: agentEvmChainIdSchema,
3503
+ rpcUrl: zod.z.string().min(1).optional(),
3504
+ sy: evmAddressSchema,
3505
+ tokenOut: zod.z.string().min(1),
3506
+ amountHuman: zod.z.string().min(1),
3507
+ slippagePercent: zod.z.number().gt(0).lt(100),
3508
+ receiver: evmAddressSchema.optional()
3509
+ });
3510
+ var mcpPendleQuoteAddLiquidityInputSchema = zod.z.object({
3511
+ chainId: agentEvmChainIdSchema,
3512
+ rpcUrl: zod.z.string().min(1).optional(),
3513
+ tokensIn: zod.z.array(zod.z.object({ token: zod.z.string().min(1), amountHuman: zod.z.string().min(1) })).min(1),
3514
+ market: evmAddressSchema,
3515
+ keepYt: zod.z.boolean().optional(),
3516
+ yt: evmAddressSchema.optional(),
3517
+ slippagePercent: zod.z.number().gt(0).lt(100),
3518
+ receiver: evmAddressSchema.optional()
3519
+ });
3520
+ var mcpPendleQuoteRemoveLiquidityInputSchema = zod.z.object({
3521
+ chainId: agentEvmChainIdSchema,
3522
+ rpcUrl: zod.z.string().min(1).optional(),
3523
+ market: evmAddressSchema,
3524
+ lpAmountHuman: zod.z.string().min(1),
3525
+ tokensOut: zod.z.array(zod.z.string().min(1)).min(1),
3526
+ slippagePercent: zod.z.number().gt(0).lt(100),
3527
+ enableAggregator: zod.z.boolean().optional(),
3528
+ receiver: evmAddressSchema.optional()
3529
+ });
3530
+ var mcpPendleBuildSwapMultisignInputSchema = withMultisignKeySourceRefine(
3531
+ evmMultisignCommonInputSchema.extend({
3532
+ tokenIn: zod.z.string().min(1),
3533
+ tokenOut: zod.z.string().min(1),
3534
+ amountHuman: zod.z.string().min(1),
3535
+ slippagePercent: zod.z.number().gt(0).lt(100),
3536
+ enableAggregator: zod.z.boolean().optional(),
3537
+ convertSnapshot: jsonObjectSchema.optional()
3538
+ })
3539
+ );
3540
+ var mcpPendleBuildMintPyMultisignInputSchema = withMultisignKeySourceRefine(
3541
+ evmMultisignCommonInputSchema.extend({
3542
+ tokenIn: zod.z.string().min(1),
3543
+ pt: evmAddressSchema,
3544
+ yt: evmAddressSchema,
3545
+ amountHuman: zod.z.string().min(1),
3546
+ slippagePercent: zod.z.number().gt(0).lt(100),
3547
+ convertSnapshot: jsonObjectSchema.optional()
3548
+ })
3549
+ );
3550
+ var mcpPendleBuildRedeemPyMultisignInputSchema = withMultisignKeySourceRefine(
3551
+ evmMultisignCommonInputSchema.extend({
3552
+ pt: evmAddressSchema,
3553
+ yt: evmAddressSchema,
3554
+ tokenOut: zod.z.string().min(1),
3555
+ amountPtHuman: zod.z.string().min(1),
3556
+ amountYtHuman: zod.z.string().min(1).optional(),
3557
+ slippagePercent: zod.z.number().gt(0).lt(100),
3558
+ convertSnapshot: jsonObjectSchema.optional()
3559
+ })
3560
+ );
3561
+ var mcpPendleBuildMintSyMultisignInputSchema = withMultisignKeySourceRefine(
3562
+ evmMultisignCommonInputSchema.extend({
3563
+ tokenIn: zod.z.string().min(1),
3564
+ sy: evmAddressSchema,
3565
+ amountHuman: zod.z.string().min(1),
3566
+ slippagePercent: zod.z.number().gt(0).lt(100),
3567
+ convertSnapshot: jsonObjectSchema.optional()
3568
+ })
3569
+ );
3570
+ var mcpPendleBuildRedeemSyMultisignInputSchema = withMultisignKeySourceRefine(
3571
+ evmMultisignCommonInputSchema.extend({
3572
+ sy: evmAddressSchema,
3573
+ tokenOut: zod.z.string().min(1),
3574
+ amountHuman: zod.z.string().min(1),
3575
+ slippagePercent: zod.z.number().gt(0).lt(100),
3576
+ convertSnapshot: jsonObjectSchema.optional()
3577
+ })
3578
+ );
3579
+ var mcpPendleBuildAddLiquidityMultisignInputSchema = withMultisignKeySourceRefine(
3580
+ evmMultisignCommonInputSchema.extend({
3581
+ tokensIn: zod.z.array(zod.z.object({ token: zod.z.string().min(1), amountHuman: zod.z.string().min(1) })).min(1),
3582
+ market: evmAddressSchema,
3583
+ keepYt: zod.z.boolean().optional(),
3584
+ yt: evmAddressSchema.optional(),
3585
+ slippagePercent: zod.z.number().gt(0).lt(100),
3586
+ convertSnapshot: jsonObjectSchema.optional()
3587
+ })
3588
+ );
3589
+ var mcpPendleBuildRemoveLiquidityMultisignInputSchema = withMultisignKeySourceRefine(
3590
+ evmMultisignCommonInputSchema.extend({
3591
+ market: evmAddressSchema,
3592
+ lpAmountHuman: zod.z.string().min(1),
3593
+ tokensOut: zod.z.array(zod.z.string().min(1)).min(1),
3594
+ slippagePercent: zod.z.number().gt(0).lt(100),
3595
+ enableAggregator: zod.z.boolean().optional(),
3596
+ convertSnapshot: jsonObjectSchema.optional()
3597
+ })
3598
+ );
3599
+ var mcpPendleBuildRedeemRewardsMultisignInputSchema = withMultisignKeySourceRefine(
3600
+ evmMultisignCommonInputSchema.extend({
3601
+ sys: zod.z.array(evmAddressSchema).optional(),
3602
+ yts: zod.z.array(evmAddressSchema).optional(),
3603
+ markets: zod.z.array(evmAddressSchema).optional(),
3604
+ convertSnapshot: jsonObjectSchema.optional()
3605
+ })
3606
+ );
3420
3607
  var mcpCompoundV3FetchMarketsInputSchema = zod.z.object({
3421
3608
  chainId: agentEvmChainIdSchema,
3422
3609
  rpcUrl: zod.z.string().min(1).optional().describe("Server-filled from chain registry. Agents should omit.")
@@ -7254,6 +7441,238 @@ var CORE_MCP_TOOL_DEFINITIONS = [
7254
7441
  handler: { importPath: "protocols/evm/compound-v3", exportName: "compoundV3FetchAccountSummary" },
7255
7442
  inputZod: mcpCompoundV3FetchAccountInputSchema,
7256
7443
  outputZod: mcpCompoundV3FetchAccountOutputSchema
7444
+ }),
7445
+ defineMcpTool({
7446
+ name: "ctm_pendle_fetch_markets",
7447
+ actionId: "pendle.fetch-markets",
7448
+ protocolId: "pendle",
7449
+ chainCategory: "evm",
7450
+ description: "Pendle V2: live (unexpired) markets on chainId, scanned from Core, TVL-ranked, hard cap 100. Matured YT markets are omitted. Includes points[] campaigns. Use ctm_pendle_search_assets for long-tail or a specific expired market (PT redeem / remove LP). Never Convert. load_defi_protocol pendle activates this pack.",
7451
+ prerequisites: ["chainId in get_chain_registry \u2229 Pendle GET /v1/chains"],
7452
+ followUp: ["ctm_pendle_search_assets", "ctm_pendle_fetch_prices", "ctm_pendle_quote_swap"],
7453
+ handler: { importPath: "protocols/evm/pendle", exportName: "pendleFetchMarketsSummary" },
7454
+ inputZod: mcpPendleFetchMarketsInputSchema,
7455
+ outputZod: mcpPendleFetchMarketsOutputSchema
7456
+ }),
7457
+ defineMcpTool({
7458
+ name: "ctm_pendle_fetch_prices",
7459
+ actionId: "pendle.fetch-prices",
7460
+ protocolId: "pendle",
7461
+ chainCategory: "evm",
7462
+ description: "Pendle V2: USD prices for listed or searched asset ids (GET /v1/prices/assets). Do not use Convert as a ticker.",
7463
+ prerequisites: ["chainId", "ids from fetch_markets / search_assets (or omit to price the current live listing)"],
7464
+ followUp: ["ctm_pendle_quote_swap"],
7465
+ handler: { importPath: "protocols/evm/pendle", exportName: "pendleFetchPricesSummary" },
7466
+ inputZod: mcpPendleFetchPricesInputSchema,
7467
+ outputZod: mcpPendleFetchPricesOutputSchema
7468
+ }),
7469
+ defineMcpTool({
7470
+ name: "ctm_pendle_search_assets",
7471
+ actionId: "pendle.search-assets",
7472
+ protocolId: "pendle",
7473
+ chainCategory: "evm",
7474
+ description: "Pendle V2: search live markets by ticker, 0x, or chainId-0x. Prefers unexpired hits; returns a matured market only if nothing live matched or you looked up that address (PT redeem / remove LP). Returns expiry, APY, TVL, points.",
7475
+ prerequisites: ["chainId", "query (ticker, 0x, or chainId-0x)"],
7476
+ followUp: ["ctm_pendle_quote_swap", "ctm_pendle_quote_mint_py", "ctm_pendle_quote_add_liquidity"],
7477
+ handler: { importPath: "protocols/evm/pendle", exportName: "pendleSearchAssets" },
7478
+ inputZod: mcpPendleSearchAssetsInputSchema,
7479
+ outputZod: mcpPendleSearchAssetsOutputSchema
7480
+ }),
7481
+ defineMcpTool({
7482
+ name: "ctm_pendle_quote_swap",
7483
+ actionId: "pendle.quote-swap",
7484
+ protocolId: "pendle",
7485
+ chainCategory: "evm",
7486
+ description: "Pendle V2 Hosted SDK Convert quote: token \u2194 PT or YT (this is also how you trade points). Fresh calldata; do not cache as a price ticker.",
7487
+ prerequisites: ["ctm_pendle_fetch_markets or ctm_pendle_search_assets", "activate_tool_group pendle:swap"],
7488
+ followUp: ["ctm_pendle_build_swap_multisign"],
7489
+ handler: { importPath: "protocols/evm/pendle", exportName: "pendleQuoteSwap" },
7490
+ inputZod: mcpPendleQuoteSwapInputSchema,
7491
+ outputZod: mcpPendleQuoteOutputSchema
7492
+ }),
7493
+ defineMcpTool({
7494
+ name: "ctm_pendle_quote_mint_py",
7495
+ actionId: "pendle.quote-mint-py",
7496
+ protocolId: "pendle",
7497
+ chainCategory: "evm",
7498
+ description: "Pendle V2 Convert quote: mint PT+YT from an underlying or SY.",
7499
+ prerequisites: ["activate_tool_group pendle:mint"],
7500
+ followUp: ["ctm_pendle_build_mint_py_multisign"],
7501
+ handler: { importPath: "protocols/evm/pendle", exportName: "pendleQuoteMintPy" },
7502
+ inputZod: mcpPendleQuoteMintPyInputSchema,
7503
+ outputZod: mcpPendleQuoteOutputSchema
7504
+ }),
7505
+ defineMcpTool({
7506
+ name: "ctm_pendle_quote_redeem_py",
7507
+ actionId: "pendle.quote-redeem-py",
7508
+ protocolId: "pendle",
7509
+ chainCategory: "evm",
7510
+ description: "Pendle V2 Convert quote: redeem PT+YT to underlying or SY. After expiry, pass amountYtHuman 0 (PT only).",
7511
+ prerequisites: ["activate_tool_group pendle:mint"],
7512
+ followUp: ["ctm_pendle_build_redeem_py_multisign"],
7513
+ handler: { importPath: "protocols/evm/pendle", exportName: "pendleQuoteRedeemPy" },
7514
+ inputZod: mcpPendleQuoteRedeemPyInputSchema,
7515
+ outputZod: mcpPendleQuoteOutputSchema
7516
+ }),
7517
+ defineMcpTool({
7518
+ name: "ctm_pendle_quote_mint_sy",
7519
+ actionId: "pendle.quote-mint-sy",
7520
+ protocolId: "pendle",
7521
+ chainCategory: "evm",
7522
+ description: "Pendle V2 Convert quote: wrap underlying into SY.",
7523
+ prerequisites: ["activate_tool_group pendle:mint"],
7524
+ followUp: ["ctm_pendle_build_mint_sy_multisign"],
7525
+ handler: { importPath: "protocols/evm/pendle", exportName: "pendleQuoteMintSy" },
7526
+ inputZod: mcpPendleQuoteMintSyInputSchema,
7527
+ outputZod: mcpPendleQuoteOutputSchema
7528
+ }),
7529
+ defineMcpTool({
7530
+ name: "ctm_pendle_quote_redeem_sy",
7531
+ actionId: "pendle.quote-redeem-sy",
7532
+ protocolId: "pendle",
7533
+ chainCategory: "evm",
7534
+ description: "Pendle V2 Convert quote: unwrap SY to underlying.",
7535
+ prerequisites: ["activate_tool_group pendle:mint"],
7536
+ followUp: ["ctm_pendle_build_redeem_sy_multisign"],
7537
+ handler: { importPath: "protocols/evm/pendle", exportName: "pendleQuoteRedeemSy" },
7538
+ inputZod: mcpPendleQuoteRedeemSyInputSchema,
7539
+ outputZod: mcpPendleQuoteOutputSchema
7540
+ }),
7541
+ defineMcpTool({
7542
+ name: "ctm_pendle_quote_add_liquidity",
7543
+ actionId: "pendle.quote-add-liquidity",
7544
+ protocolId: "pendle",
7545
+ chainCategory: "evm",
7546
+ description: "Pendle V2 Convert quote: add LP. keepYt+yt = zero-price-impact (keep YT in the wallet instead of selling it into the AMM).",
7547
+ prerequisites: ["activate_tool_group pendle:lp"],
7548
+ followUp: ["ctm_pendle_build_add_liquidity_multisign"],
7549
+ handler: { importPath: "protocols/evm/pendle", exportName: "pendleQuoteAddLiquidity" },
7550
+ inputZod: mcpPendleQuoteAddLiquidityInputSchema,
7551
+ outputZod: mcpPendleQuoteOutputSchema
7552
+ }),
7553
+ defineMcpTool({
7554
+ name: "ctm_pendle_quote_remove_liquidity",
7555
+ actionId: "pendle.quote-remove-liquidity",
7556
+ protocolId: "pendle",
7557
+ chainCategory: "evm",
7558
+ description: "Pendle V2 Convert quote: remove LP to tokensOut (use underlying). After expiry still works. Copy market + lpAmountHuman from ctm_pendle_fetch_positions.",
7559
+ prerequisites: ["activate_tool_group pendle:lp", "market + lpAmountHuman from fetch_positions or the user"],
7560
+ followUp: ["ctm_pendle_build_remove_liquidity_multisign"],
7561
+ handler: { importPath: "protocols/evm/pendle", exportName: "pendleQuoteRemoveLiquidity" },
7562
+ inputZod: mcpPendleQuoteRemoveLiquidityInputSchema,
7563
+ outputZod: mcpPendleQuoteOutputSchema
7564
+ }),
7565
+ defineMcpTool({
7566
+ name: "ctm_pendle_fetch_positions",
7567
+ actionId: "pendle.fetch-positions",
7568
+ protocolId: "pendle",
7569
+ chainCategory: "evm",
7570
+ description: "Pendle V2: this wallet\u2019s LP holdings from official Core dashboard (including matured). Not the node token list. Use before remove LP. ~4 CU. Do not treat claimable amounts here as a live redeem quote.",
7571
+ prerequisites: ["activate_tool_group pendle:lp", "user address", "optional chainId"],
7572
+ followUp: ["ctm_pendle_quote_remove_liquidity"],
7573
+ handler: { importPath: "protocols/evm/pendle", exportName: "pendleFetchPositions" },
7574
+ inputZod: mcpPendleFetchPositionsInputSchema,
7575
+ outputZod: mcpPendleFetchPositionsOutputSchema
7576
+ }),
7577
+ defineMultisignSubmitMcpTool({
7578
+ name: "ctm_pendle_build_swap_multisign",
7579
+ actionId: "pendle.swap",
7580
+ protocolId: "pendle",
7581
+ chainCategory: "evm",
7582
+ description: "Pendle V2: approve Convert tx.to then swap token \u2194 PT/YT. 30-min multiSign expiry unless expiryDate is set. Fresh Convert at build time.",
7583
+ prerequisites: [
7584
+ "ctm_pendle_quote_swap",
7585
+ "get_multi_sign_gas_options + user confirms useCustomGas and 30-minute deadline",
7586
+ "keyGenId + chainId + purposeText + slippagePercent"
7587
+ ],
7588
+ handler: { importPath: "protocols/evm/pendle", exportName: "buildEvmMultisignBodyPendleSwapBatch" },
7589
+ inputZod: mcpPendleBuildSwapMultisignInputSchema
7590
+ }),
7591
+ defineMultisignSubmitMcpTool({
7592
+ name: "ctm_pendle_build_mint_py_multisign",
7593
+ actionId: "pendle.mint-py",
7594
+ protocolId: "pendle",
7595
+ chainCategory: "evm",
7596
+ description: "Pendle V2: mint PT+YT multiSign (approve + Convert). 30-min expiry default.",
7597
+ prerequisites: ["ctm_pendle_quote_mint_py", "keyGenId + purposeText + slippagePercent"],
7598
+ handler: { importPath: "protocols/evm/pendle", exportName: "buildEvmMultisignBodyPendleMintPyBatch" },
7599
+ inputZod: mcpPendleBuildMintPyMultisignInputSchema
7600
+ }),
7601
+ defineMultisignSubmitMcpTool({
7602
+ name: "ctm_pendle_build_redeem_py_multisign",
7603
+ actionId: "pendle.redeem-py",
7604
+ protocolId: "pendle",
7605
+ chainCategory: "evm",
7606
+ description: "Pendle V2: redeem PT+YT multiSign. After expiry, pass amountYtHuman 0 (PT only). 30-min expiry default.",
7607
+ prerequisites: ["ctm_pendle_quote_redeem_py", "keyGenId + purposeText + slippagePercent"],
7608
+ handler: { importPath: "protocols/evm/pendle", exportName: "buildEvmMultisignBodyPendleRedeemPyBatch" },
7609
+ inputZod: mcpPendleBuildRedeemPyMultisignInputSchema
7610
+ }),
7611
+ defineMultisignSubmitMcpTool({
7612
+ name: "ctm_pendle_build_mint_sy_multisign",
7613
+ actionId: "pendle.mint-sy",
7614
+ protocolId: "pendle",
7615
+ chainCategory: "evm",
7616
+ description: "Pendle V2: mint SY multiSign. 30-min expiry default.",
7617
+ prerequisites: ["ctm_pendle_quote_mint_sy", "keyGenId + purposeText + slippagePercent"],
7618
+ handler: { importPath: "protocols/evm/pendle", exportName: "buildEvmMultisignBodyPendleMintSyBatch" },
7619
+ inputZod: mcpPendleBuildMintSyMultisignInputSchema
7620
+ }),
7621
+ defineMultisignSubmitMcpTool({
7622
+ name: "ctm_pendle_build_redeem_sy_multisign",
7623
+ actionId: "pendle.redeem-sy",
7624
+ protocolId: "pendle",
7625
+ chainCategory: "evm",
7626
+ description: "Pendle V2: redeem SY multiSign. 30-min expiry default.",
7627
+ prerequisites: ["ctm_pendle_quote_redeem_sy", "keyGenId + purposeText + slippagePercent"],
7628
+ handler: { importPath: "protocols/evm/pendle", exportName: "buildEvmMultisignBodyPendleRedeemSyBatch" },
7629
+ inputZod: mcpPendleBuildRedeemSyMultisignInputSchema
7630
+ }),
7631
+ defineMultisignSubmitMcpTool({
7632
+ name: "ctm_pendle_build_add_liquidity_multisign",
7633
+ actionId: "pendle.add-liquidity",
7634
+ protocolId: "pendle",
7635
+ chainCategory: "evm",
7636
+ description: "Pendle V2: add LP multiSign. 30-min expiry default.",
7637
+ prerequisites: ["ctm_pendle_quote_add_liquidity", "keyGenId + purposeText + slippagePercent"],
7638
+ handler: { importPath: "protocols/evm/pendle", exportName: "buildEvmMultisignBodyPendleAddLiquidityBatch" },
7639
+ inputZod: mcpPendleBuildAddLiquidityMultisignInputSchema
7640
+ }),
7641
+ defineMultisignSubmitMcpTool({
7642
+ name: "ctm_pendle_build_remove_liquidity_multisign",
7643
+ actionId: "pendle.remove-liquidity",
7644
+ protocolId: "pendle",
7645
+ chainCategory: "evm",
7646
+ description: "Pendle V2: remove LP multiSign. 30-min expiry default.",
7647
+ prerequisites: ["ctm_pendle_quote_remove_liquidity", "keyGenId + purposeText + slippagePercent"],
7648
+ handler: { importPath: "protocols/evm/pendle", exportName: "buildEvmMultisignBodyPendleRemoveLiquidityBatch" },
7649
+ inputZod: mcpPendleBuildRemoveLiquidityMultisignInputSchema
7650
+ }),
7651
+ defineMcpTool({
7652
+ name: "ctm_pendle_fetch_merkle_rewards",
7653
+ actionId: "pendle.fetch-merkle-rewards",
7654
+ protocolId: "pendle",
7655
+ chainCategory: "evm",
7656
+ description: "Pendle V2: list off-chain airdrop rows for a wallet (token, amount). Informational only \u2014 Core has no claim proofs. Tell the user to claim airdrops on app.pendle.finance. Do not invent a claim tx. On-chain SY/YT/LP incentives use ctm_pendle_build_redeem_rewards_multisign.",
7657
+ prerequisites: ["activate_tool_group pendle:rewards", "user address"],
7658
+ followUp: [],
7659
+ handler: { importPath: "protocols/evm/pendle", exportName: "pendleFetchMerkleRewards" },
7660
+ inputZod: mcpPendleFetchMerkleRewardsInputSchema,
7661
+ outputZod: mcpPendleFetchMerkleRewardsOutputSchema
7662
+ }),
7663
+ defineMultisignSubmitMcpTool({
7664
+ name: "ctm_pendle_build_redeem_rewards_multisign",
7665
+ actionId: "pendle.redeem-rewards",
7666
+ protocolId: "pendle",
7667
+ chainCategory: "evm",
7668
+ description: "Pendle V2: redeem on-chain interest and incentives from SY, YT, and LP (usually PENDLE) via Hosted SDK. Not merkle airdrops. 30-min expiry default.",
7669
+ prerequisites: [
7670
+ "activate_tool_group pendle:rewards",
7671
+ "sys / yts / markets from fetch_markets or search",
7672
+ "keyGenId + purposeText"
7673
+ ],
7674
+ handler: { importPath: "protocols/evm/pendle", exportName: "buildEvmMultisignBodyPendleRedeemRewardsBatch" },
7675
+ inputZod: mcpPendleBuildRedeemRewardsMultisignInputSchema
7257
7676
  })
7258
7677
  ];
7259
7678
  var MCP_TOOL_DEFINITIONS = [
@@ -7504,6 +7923,17 @@ registerProtocolModule(ethenaProtocolModule);
7504
7923
  function isMapleSyrupSupportedChain(chainId) {
7505
7924
  return chainId === 1 || chainId === 11155111;
7506
7925
  }
7926
+ function matchesAssetFilter(opts) {
7927
+ const f = (opts.filter ?? "").trim();
7928
+ if (!f) return true;
7929
+ const addr = (opts.address ?? "").trim();
7930
+ if (viem.isAddress(f) && viem.isAddress(addr)) {
7931
+ return viem.getAddress(addr) === viem.getAddress(f);
7932
+ }
7933
+ const sym = (opts.symbol ?? "").trim();
7934
+ if (!sym) return false;
7935
+ return sym.toLowerCase() === f.toLowerCase();
7936
+ }
7507
7937
 
7508
7938
  // src/protocols/evm/maple/index.ts
7509
7939
  var MAPLE_PROTOCOL_ID = "maple-syrup";
@@ -9802,6 +10232,347 @@ var compoundV3ProtocolModule = {
9802
10232
  ]
9803
10233
  };
9804
10234
  registerProtocolModule(compoundV3ProtocolModule);
10235
+
10236
+ // src/protocols/evm/pendle/support.ts
10237
+ var PENDLE_PROTOCOL_ID = "pendle";
10238
+ var PENDLE_CORE_API_BASE = "https://api-v2.pendle.finance/core";
10239
+ var PENDLE_LISTING_CAP = 100;
10240
+ var PENDLE_LISTING_MAX_PAGES = 8;
10241
+ var PENDLE_ICON_CACHE_MS = 12 * 60 * 1e3;
10242
+ var PENDLE_CHAIN_CACHE_MS = 30 * 60 * 1e3;
10243
+ function parsePendleAssetId(id) {
10244
+ const raw = (id ?? "").trim();
10245
+ const dash = raw.indexOf("-");
10246
+ if (dash <= 0) return null;
10247
+ const chainId = Number.parseInt(raw.slice(0, dash), 10);
10248
+ const address = raw.slice(dash + 1).trim();
10249
+ if (!Number.isFinite(chainId) || chainId <= 0 || !address) return null;
10250
+ return { chainId, address };
10251
+ }
10252
+
10253
+ // src/protocols/evm/pendle/api.ts
10254
+ var FETCH_TIMEOUT_MS = 12e4;
10255
+ var PendleApiError = class extends Error {
10256
+ status;
10257
+ path;
10258
+ constructor(message, status, path) {
10259
+ super(message);
10260
+ this.name = "PendleApiError";
10261
+ this.status = status;
10262
+ this.path = path;
10263
+ }
10264
+ };
10265
+ function sleep(ms) {
10266
+ return new Promise((resolve) => setTimeout(resolve, ms));
10267
+ }
10268
+ function queryString(params) {
10269
+ const q = new URLSearchParams();
10270
+ for (const [k, v] of Object.entries(params)) {
10271
+ if (v === void 0 || v === "") continue;
10272
+ q.set(k, String(v));
10273
+ }
10274
+ const s = q.toString();
10275
+ return s ? `?${s}` : "";
10276
+ }
10277
+ async function pendleCoreFetch(args) {
10278
+ const path = args.path.startsWith("/") ? args.path : `/${args.path}`;
10279
+ const url = `${PENDLE_CORE_API_BASE}${path}${queryString(args.query ?? {})}`;
10280
+ const headers = { Accept: "application/json" };
10281
+ if (args.apiKey?.trim()) headers.Authorization = `Bearer ${args.apiKey.trim()}`;
10282
+ if (args.body !== void 0) headers["Content-Type"] = "application/json";
10283
+ let lastError;
10284
+ for (let attempt = 0; attempt < 4; attempt++) {
10285
+ const ac = new AbortController();
10286
+ const timer = setTimeout(() => ac.abort(), FETCH_TIMEOUT_MS);
10287
+ try {
10288
+ const res = await fetch(url, {
10289
+ method: args.method ?? "GET",
10290
+ headers,
10291
+ body: args.body === void 0 ? void 0 : JSON.stringify(args.body),
10292
+ signal: ac.signal
10293
+ });
10294
+ if (res.status === 429) {
10295
+ const wait = Math.min(8e3, 500 * 2 ** attempt);
10296
+ await sleep(wait);
10297
+ lastError = new PendleApiError(`Pendle API rate limited (429) on ${path}`, 429, path);
10298
+ continue;
10299
+ }
10300
+ const text = await res.text();
10301
+ if (!res.ok) {
10302
+ throw new PendleApiError(
10303
+ `Pendle API ${res.status} ${path}: ${text.slice(0, 400)}`,
10304
+ res.status,
10305
+ path
10306
+ );
10307
+ }
10308
+ if (!text.trim()) return {};
10309
+ return JSON.parse(text);
10310
+ } catch (err) {
10311
+ lastError = err;
10312
+ if (err instanceof PendleApiError && err.status !== 429) throw err;
10313
+ if (attempt < 3 && (err instanceof PendleApiError || err?.name === "AbortError")) {
10314
+ await sleep(Math.min(8e3, 400 * 2 ** attempt));
10315
+ continue;
10316
+ }
10317
+ throw err;
10318
+ } finally {
10319
+ clearTimeout(timer);
10320
+ }
10321
+ }
10322
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
10323
+ }
10324
+
10325
+ // src/protocols/evm/pendle/discover.ts
10326
+ var marketsCacheByChain = /* @__PURE__ */ new Map();
10327
+ var chainIdsCache = null;
10328
+ function asRecord(v) {
10329
+ return v && typeof v === "object" && !Array.isArray(v) ? v : null;
10330
+ }
10331
+ function asNumber(v) {
10332
+ if (typeof v === "number" && Number.isFinite(v)) return v;
10333
+ if (typeof v === "string" && v.trim()) {
10334
+ const n = Number.parseFloat(v);
10335
+ return Number.isFinite(n) ? n : null;
10336
+ }
10337
+ return null;
10338
+ }
10339
+ function asString(v) {
10340
+ if (typeof v === "string" && v.trim()) return v.trim();
10341
+ return null;
10342
+ }
10343
+ function asExpiry(v) {
10344
+ const s = asString(v);
10345
+ if (s) return s;
10346
+ const n = asNumber(v);
10347
+ if (n == null) return null;
10348
+ const ms = n < 1e12 ? n * 1e3 : n;
10349
+ return new Date(ms).toISOString();
10350
+ }
10351
+ function pendleMarketExpiryMs(expiry) {
10352
+ const raw = (expiry ?? "").trim();
10353
+ if (!raw) return null;
10354
+ if (/^\d+$/.test(raw)) {
10355
+ const n = Number(raw);
10356
+ return n < 1e12 ? n * 1e3 : n;
10357
+ }
10358
+ const t = Date.parse(raw);
10359
+ return Number.isFinite(t) ? t : null;
10360
+ }
10361
+ function isPendleMarketExpired(row, nowMs = Date.now()) {
10362
+ const t = pendleMarketExpiryMs(row.expiry);
10363
+ if (t == null) return false;
10364
+ return t <= nowMs;
10365
+ }
10366
+ function marketMatchesPin(row, address) {
10367
+ const a = address.trim().toLowerCase();
10368
+ if (!a) return false;
10369
+ return [row.address, row.pt, row.yt, row.sy].some((x) => x.toLowerCase() === a);
10370
+ }
10371
+ function selectPendleListingMarkets(rows, args = {}) {
10372
+ const nowMs = args.nowMs ?? Date.now();
10373
+ const cap = args.cap ?? PENDLE_LISTING_CAP;
10374
+ const pins = (args.includeAddresses ?? []).map((a) => a.trim().toLowerCase()).filter(Boolean);
10375
+ const q = (args.query ?? "").trim();
10376
+ let out = rows.filter((r) => {
10377
+ const pinned = pins.some((p) => marketMatchesPin(r, p));
10378
+ if (!args.includeExpired && !pinned && isPendleMarketExpired(r, nowMs)) return false;
10379
+ if (args.pointsOnly && r.points.length === 0) return false;
10380
+ if (q && !marketMatchesQuery(r, q)) return false;
10381
+ return true;
10382
+ });
10383
+ out.sort(sortPendleMarketsByTvl);
10384
+ return out.slice(0, cap);
10385
+ }
10386
+ function addressFromAssetIdOrHex(raw, fallbackChainId) {
10387
+ if (typeof raw !== "string" || !raw.trim()) return null;
10388
+ const parsed = parsePendleAssetId(raw);
10389
+ if (parsed) {
10390
+ try {
10391
+ return viem.getAddress(parsed.address);
10392
+ } catch {
10393
+ return parsed.address.toLowerCase();
10394
+ }
10395
+ }
10396
+ if (viem.isAddress(raw)) return viem.getAddress(raw);
10397
+ if (raw.startsWith(`${fallbackChainId}-`)) {
10398
+ const rest = raw.slice(String(fallbackChainId).length + 1);
10399
+ if (viem.isAddress(rest)) return viem.getAddress(rest);
10400
+ }
10401
+ return null;
10402
+ }
10403
+ function parsePoints(raw) {
10404
+ if (!Array.isArray(raw)) return [];
10405
+ const out = [];
10406
+ for (const item of raw) {
10407
+ const o = asRecord(item);
10408
+ if (!o) continue;
10409
+ const name = asString(o.name) ?? asString(o.key) ?? asString(o.pointName);
10410
+ if (!name) continue;
10411
+ out.push({
10412
+ name,
10413
+ type: asString(o.type),
10414
+ pendleAsset: asString(o.pendleAsset),
10415
+ value: asNumber(o.value)
10416
+ });
10417
+ }
10418
+ return out;
10419
+ }
10420
+ function marketTvlUsd(row) {
10421
+ return row.tvlUsd ?? row.liquidityUsd ?? 0;
10422
+ }
10423
+ function sortPendleMarketsByTvl(a, b) {
10424
+ const d = marketTvlUsd(b) - marketTvlUsd(a);
10425
+ if (d !== 0) return d;
10426
+ return a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
10427
+ }
10428
+ function parsePendleMarket(raw) {
10429
+ const o = asRecord(raw);
10430
+ if (!o) return null;
10431
+ const chainId = asNumber(o.chainId);
10432
+ const address = addressFromAssetIdOrHex(o.address, chainId ?? 0);
10433
+ if (chainId == null || !address) return null;
10434
+ const details = asRecord(o.details);
10435
+ const tvl = asNumber(o.tvl) ?? asNumber(details?.tvl) ?? asNumber(details?.totalTvl) ?? asNumber(asRecord(details?.liquidity)?.usd);
10436
+ const liquidity = asNumber(o.liquidity) ?? asNumber(details?.liquidity) ?? asNumber(asRecord(details?.liquidity)?.usd);
10437
+ const impliedApy = asNumber(o.impliedApy) ?? asNumber(details?.impliedApy) ?? asNumber(asRecord(o.pt)?.impliedApy);
10438
+ const pt = addressFromAssetIdOrHex(o.pt ?? asRecord(o.pt)?.address ?? asRecord(o.pt)?.id, chainId);
10439
+ const yt = addressFromAssetIdOrHex(o.yt ?? asRecord(o.yt)?.address ?? asRecord(o.yt)?.id, chainId);
10440
+ const sy = addressFromAssetIdOrHex(o.sy ?? asRecord(o.sy)?.address ?? asRecord(o.sy)?.id, chainId);
10441
+ const underlying = addressFromAssetIdOrHex(
10442
+ o.underlyingAsset ?? o.underlying ?? asRecord(o.underlyingAsset)?.address,
10443
+ chainId
10444
+ );
10445
+ if (!pt || !yt || !sy || !underlying) return null;
10446
+ const expired = asExpiry(o.expiry) ?? asExpiry(details?.expiry);
10447
+ return {
10448
+ chainId,
10449
+ name: asString(o.name) ?? asString(o.proSymbol) ?? `${address.slice(0, 8)}\u2026`,
10450
+ address,
10451
+ expiry: expired,
10452
+ pt,
10453
+ yt,
10454
+ sy,
10455
+ underlying,
10456
+ underlyingSymbol: asString(asRecord(o.underlyingAsset)?.symbol) ?? asString(o.underlyingSymbol),
10457
+ ptSymbol: asString(asRecord(o.pt)?.symbol) ?? asString(o.ptSymbol),
10458
+ ytSymbol: asString(asRecord(o.yt)?.symbol) ?? asString(o.ytSymbol),
10459
+ impliedApy,
10460
+ tvlUsd: tvl,
10461
+ liquidityUsd: liquidity,
10462
+ points: parsePoints(o.points ?? details?.points)
10463
+ };
10464
+ }
10465
+ async function pendleFetchSupportedChainIds() {
10466
+ const now = Date.now();
10467
+ if (chainIdsCache && now - chainIdsCache.at < PENDLE_CHAIN_CACHE_MS) return chainIdsCache.chainIds;
10468
+ const json = await pendleCoreFetch({ path: "/v1/chains" });
10469
+ const ids = Array.isArray(json.chainIds) ? json.chainIds.map((n) => Number(n)).filter((n) => Number.isFinite(n) && n > 0) : [];
10470
+ chainIdsCache = { at: now, chainIds: ids };
10471
+ return ids;
10472
+ }
10473
+ async function isPendleChainSupported(chainId) {
10474
+ try {
10475
+ const ids = await pendleFetchSupportedChainIds();
10476
+ if (ids.length === 0) return true;
10477
+ return ids.includes(chainId);
10478
+ } catch {
10479
+ return true;
10480
+ }
10481
+ }
10482
+ async function pendleFetchMarketsPage(args) {
10483
+ const limit = Math.min(PENDLE_LISTING_CAP, Math.max(1, args.limit));
10484
+ const json = await pendleCoreFetch({
10485
+ path: "/v2/markets/all",
10486
+ query: {
10487
+ skip: args.skip ?? 0,
10488
+ limit,
10489
+ ...args.chainId != null ? { chainId: args.chainId } : {}
10490
+ }
10491
+ });
10492
+ const raw = Array.isArray(json.markets) ? json.markets : Array.isArray(json.results) ? json.results : [];
10493
+ const rows = [];
10494
+ for (const item of raw) {
10495
+ const row = parsePendleMarket(item);
10496
+ if (row) rows.push(row);
10497
+ }
10498
+ return rows;
10499
+ }
10500
+ async function pendleFetchMarketsForChain(chainId) {
10501
+ const now = Date.now();
10502
+ const cached2 = marketsCacheByChain.get(chainId);
10503
+ if (cached2 && now - cached2.at < PENDLE_ICON_CACHE_MS) return cached2.rows;
10504
+ const rows = [];
10505
+ for (let page = 0; page < PENDLE_LISTING_MAX_PAGES; page++) {
10506
+ const batch = await pendleFetchMarketsPage({
10507
+ skip: page * PENDLE_LISTING_CAP,
10508
+ limit: PENDLE_LISTING_CAP,
10509
+ chainId
10510
+ });
10511
+ const onChain = batch.filter((r) => r.chainId === chainId);
10512
+ rows.push(...onChain);
10513
+ if (batch.length < PENDLE_LISTING_CAP || onChain.length === 0) break;
10514
+ }
10515
+ marketsCacheByChain.set(chainId, { at: now, rows });
10516
+ return rows;
10517
+ }
10518
+ function marketMatchesQuery(row, query) {
10519
+ const q = query.trim();
10520
+ if (!q) return true;
10521
+ if (matchesAssetFilter({ address: row.address, symbol: row.name, filter: q }) || matchesAssetFilter({ address: row.pt, symbol: row.ptSymbol ?? void 0, filter: q }) || matchesAssetFilter({ address: row.yt, symbol: row.ytSymbol ?? void 0, filter: q }) || matchesAssetFilter({ address: row.sy, filter: q }) || matchesAssetFilter({ address: row.underlying, symbol: row.underlyingSymbol ?? void 0, filter: q })) {
10522
+ return true;
10523
+ }
10524
+ const hay = `${row.name} ${row.ptSymbol ?? ""} ${row.ytSymbol ?? ""} ${row.underlyingSymbol ?? ""}`.toLowerCase();
10525
+ return hay.includes(q.toLowerCase());
10526
+ }
10527
+ async function pendleFetchMarketsSummary(args) {
10528
+ if (!await isPendleChainSupported(args.chainId)) {
10529
+ return {
10530
+ chainId: args.chainId,
10531
+ markets: [],
10532
+ notes: `Pendle Core API does not list chain ${args.chainId}.`
10533
+ };
10534
+ }
10535
+ const scanned = await pendleFetchMarketsForChain(args.chainId);
10536
+ const rows = selectPendleListingMarkets(scanned, {
10537
+ query: args.query,
10538
+ pointsOnly: args.pointsOnly,
10539
+ includeAddresses: args.includeAddresses
10540
+ });
10541
+ const expiredOmitted = scanned.filter((r) => isPendleMarketExpired(r)).length;
10542
+ return {
10543
+ chainId: args.chainId,
10544
+ markets: rows,
10545
+ notes: `Top ${rows.length} active Pendle markets on chain ${args.chainId} by TVL/liquidity (scanned ${scanned.length}, omitted ${expiredOmitted} matured). Use ctm_pendle_search_assets for long-tail or expired markets (PT redeem / remove LP). Do not web-search Pendle APYs.`
10546
+ };
10547
+ }
10548
+
10549
+ // src/protocols/evm/pendle/index.ts
10550
+ var pendleProtocolModule = {
10551
+ id: PENDLE_PROTOCOL_ID,
10552
+ chainCategory: "evm",
10553
+ isChainSupported(ctx) {
10554
+ if (ctx.chainCategory !== "evm") return false;
10555
+ const n = typeof ctx.chainId === "number" ? ctx.chainId : Number.parseInt(String(ctx.chainId), 10);
10556
+ if (!Number.isFinite(n)) return false;
10557
+ return isPendleChainSupported(n);
10558
+ },
10559
+ isTokenSupported(token) {
10560
+ if (token.category !== "evm") return false;
10561
+ return token.kind === "native" || token.kind === "erc20";
10562
+ },
10563
+ actions: [
10564
+ { id: "pendle.fetch-markets", protocolId: PENDLE_PROTOCOL_ID, chainCategory: "evm", description: "List live Pendle markets (TVL-ranked, cap 100, matured omitted)", commonParams: [], params: {} },
10565
+ { id: "pendle.search-assets", protocolId: PENDLE_PROTOCOL_ID, chainCategory: "evm", description: "Search live PT/YT/SY/underlying (matured only if address-pinned)", commonParams: [], params: {} },
10566
+ { id: "pendle.swap", protocolId: PENDLE_PROTOCOL_ID, chainCategory: "evm", description: "Swap token \u2194 PT/YT via Hosted SDK convert", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
10567
+ { id: "pendle.mint-py", protocolId: PENDLE_PROTOCOL_ID, chainCategory: "evm", description: "Mint PT + YT", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
10568
+ { id: "pendle.redeem-py", protocolId: PENDLE_PROTOCOL_ID, chainCategory: "evm", description: "Redeem PT + YT (PT only after expiry)", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
10569
+ { id: "pendle.add-liquidity", protocolId: PENDLE_PROTOCOL_ID, chainCategory: "evm", description: "Add Pendle AMM liquidity", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
10570
+ { id: "pendle.fetch-positions", protocolId: PENDLE_PROTOCOL_ID, chainCategory: "evm", description: "List this wallet\u2019s Pendle LP (including matured)", commonParams: [], params: {} },
10571
+ { id: "pendle.remove-liquidity", protocolId: PENDLE_PROTOCOL_ID, chainCategory: "evm", description: "Remove Pendle AMM liquidity", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
10572
+ { id: "pendle.redeem-rewards", protocolId: PENDLE_PROTOCOL_ID, chainCategory: "evm", description: "Redeem on-chain SY/YT/LP interest and incentives (not merkle airdrops)", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} }
10573
+ ]
10574
+ };
10575
+ registerProtocolModule(pendleProtocolModule);
9805
10576
  var skillsDir = path.join(path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('catalog.cjs', document.baseURI).href)))), "skills");
9806
10577
  var SKILL_PROTOCOL_IDS = [
9807
10578
  "aave-v4",
@@ -9818,6 +10589,7 @@ var SKILL_PROTOCOL_IDS = [
9818
10589
  "morpho",
9819
10590
  "circle-cctp",
9820
10591
  "aerodrome",
10592
+ "pendle",
9821
10593
  "continuum-dao",
9822
10594
  "compound-v3",
9823
10595
  "yield-compare"
@@ -10298,6 +11070,55 @@ var PROTOCOL_SUPPORT_ADVISORS = {
10298
11070
  return cache.has(normalized);
10299
11071
  }
10300
11072
  }),
11073
+ [PENDLE_PROTOCOL_ID]: advisor(PENDLE_PROTOCOL_ID, "api_underlyings", {
11074
+ async supportedChainIds() {
11075
+ try {
11076
+ return [...await pendleFetchSupportedChainIds()].sort((a, b) => a - b);
11077
+ } catch {
11078
+ return [];
11079
+ }
11080
+ },
11081
+ async supportedTokens(chainId) {
11082
+ if (!await isPendleChainSupported(chainId)) {
11083
+ return { tokens: [], notes: `Pendle Core API does not list chain ${chainId}.` };
11084
+ }
11085
+ const listed = await pendleFetchMarketsSummary({ chainId });
11086
+ const byAddr = /* @__PURE__ */ new Map();
11087
+ const add = (address, symbol, roles) => {
11088
+ const key = address.toLowerCase();
11089
+ const prev = byAddr.get(key);
11090
+ byAddr.set(key, {
11091
+ address,
11092
+ symbol: symbol ?? prev?.symbol,
11093
+ roles: [.../* @__PURE__ */ new Set([...prev?.roles ?? [], ...roles])]
11094
+ });
11095
+ };
11096
+ for (const m of listed.markets) {
11097
+ add(m.underlying, m.underlyingSymbol, ["underlying"]);
11098
+ add(m.pt, m.ptSymbol, ["pt"]);
11099
+ add(m.yt, m.ytSymbol, ["yt"]);
11100
+ add(m.sy, null, ["sy"]);
11101
+ add(m.address, m.name, ["lp", "market"]);
11102
+ }
11103
+ return {
11104
+ tokens: [...byAddr.values()],
11105
+ notes: "Official Pendle live (unexpired) TVL-ranked markets on this chain, cap 100 (PT/YT/SY/LP + underlyings). Use ctm_pendle_search_assets for long-tail or matured markets. Use ctm_pendle_fetch_positions for this wallet\u2019s LP (including matured). Do not hardcode routers."
11106
+ };
11107
+ },
11108
+ async isTokenSupported(chainId, address) {
11109
+ if (!await isPendleChainSupported(chainId)) return false;
11110
+ let normalized;
11111
+ try {
11112
+ normalized = viem.getAddress(address).toLowerCase();
11113
+ } catch {
11114
+ return false;
11115
+ }
11116
+ const listed = await pendleFetchMarketsSummary({ chainId });
11117
+ return listed.markets.some(
11118
+ (m) => m.address.toLowerCase() === normalized || m.pt.toLowerCase() === normalized || m.yt.toLowerCase() === normalized || m.sy.toLowerCase() === normalized || m.underlying.toLowerCase() === normalized
11119
+ );
11120
+ }
11121
+ }),
10301
11122
  arcus: advisor("arcus", "api_underlyings", {
10302
11123
  async supportedChainIds() {
10303
11124
  return [...ARCUS_SUPPORTED_CHAIN_IDS];
@@ -10335,6 +11156,7 @@ registerProtocolModule(veniceProtocolModule);
10335
11156
  registerProtocolModule(aerodromeProtocolModule);
10336
11157
  registerProtocolModule(continuumDaoProtocolModule);
10337
11158
  registerProtocolModule(compoundV3ProtocolModule);
11159
+ registerProtocolModule(pendleProtocolModule);
10338
11160
  function getAgentCatalog() {
10339
11161
  return {
10340
11162
  protocols: getProtocolModules(),
@@ -10360,6 +11182,7 @@ function getAgentCatalog() {
10360
11182
  aerodrome: aerodromeProtocolModule,
10361
11183
  continuumDao: continuumDaoProtocolModule,
10362
11184
  compoundV3: compoundV3ProtocolModule,
11185
+ pendle: pendleProtocolModule,
10363
11186
  /** Prefer getAgentCatalogForMcp() or getMcpToolDefinitions() for MCP servers. */
10364
11187
  mcp: getAgentCatalogForMcp()
10365
11188
  };
@@ -10676,6 +11499,32 @@ exports.mcpMorphoVaultWithdrawInputSchema = mcpMorphoVaultWithdrawInputSchema;
10676
11499
  exports.mcpMultisignInput = mcpMultisignInput;
10677
11500
  exports.mcpMultisignOutputSchema = multisignOutputSchema;
10678
11501
  exports.mcpMultisignSubmitOutputSchema = mcpServerSubmitOutputSchema;
11502
+ exports.mcpPendleBuildAddLiquidityMultisignInputSchema = mcpPendleBuildAddLiquidityMultisignInputSchema;
11503
+ exports.mcpPendleBuildMintPyMultisignInputSchema = mcpPendleBuildMintPyMultisignInputSchema;
11504
+ exports.mcpPendleBuildMintSyMultisignInputSchema = mcpPendleBuildMintSyMultisignInputSchema;
11505
+ exports.mcpPendleBuildRedeemPyMultisignInputSchema = mcpPendleBuildRedeemPyMultisignInputSchema;
11506
+ exports.mcpPendleBuildRedeemRewardsMultisignInputSchema = mcpPendleBuildRedeemRewardsMultisignInputSchema;
11507
+ exports.mcpPendleBuildRedeemSyMultisignInputSchema = mcpPendleBuildRedeemSyMultisignInputSchema;
11508
+ exports.mcpPendleBuildRemoveLiquidityMultisignInputSchema = mcpPendleBuildRemoveLiquidityMultisignInputSchema;
11509
+ exports.mcpPendleBuildSwapMultisignInputSchema = mcpPendleBuildSwapMultisignInputSchema;
11510
+ exports.mcpPendleFetchMarketsInputSchema = mcpPendleFetchMarketsInputSchema;
11511
+ exports.mcpPendleFetchMarketsOutputSchema = mcpPendleFetchMarketsOutputSchema;
11512
+ exports.mcpPendleFetchMerkleRewardsInputSchema = mcpPendleFetchMerkleRewardsInputSchema;
11513
+ exports.mcpPendleFetchMerkleRewardsOutputSchema = mcpPendleFetchMerkleRewardsOutputSchema;
11514
+ exports.mcpPendleFetchPositionsInputSchema = mcpPendleFetchPositionsInputSchema;
11515
+ exports.mcpPendleFetchPositionsOutputSchema = mcpPendleFetchPositionsOutputSchema;
11516
+ exports.mcpPendleFetchPricesInputSchema = mcpPendleFetchPricesInputSchema;
11517
+ exports.mcpPendleFetchPricesOutputSchema = mcpPendleFetchPricesOutputSchema;
11518
+ exports.mcpPendleQuoteAddLiquidityInputSchema = mcpPendleQuoteAddLiquidityInputSchema;
11519
+ exports.mcpPendleQuoteMintPyInputSchema = mcpPendleQuoteMintPyInputSchema;
11520
+ exports.mcpPendleQuoteMintSyInputSchema = mcpPendleQuoteMintSyInputSchema;
11521
+ exports.mcpPendleQuoteOutputSchema = mcpPendleQuoteOutputSchema;
11522
+ exports.mcpPendleQuoteRedeemPyInputSchema = mcpPendleQuoteRedeemPyInputSchema;
11523
+ exports.mcpPendleQuoteRedeemSyInputSchema = mcpPendleQuoteRedeemSyInputSchema;
11524
+ exports.mcpPendleQuoteRemoveLiquidityInputSchema = mcpPendleQuoteRemoveLiquidityInputSchema;
11525
+ exports.mcpPendleQuoteSwapInputSchema = mcpPendleQuoteSwapInputSchema;
11526
+ exports.mcpPendleSearchAssetsInputSchema = mcpPendleSearchAssetsInputSchema;
11527
+ exports.mcpPendleSearchAssetsOutputSchema = mcpPendleSearchAssetsOutputSchema;
10679
11528
  exports.mcpServerCommonInputSchema = mcpServerCommonInputSchema;
10680
11529
  exports.mcpServerMultisignInput = mcpServerMultisignInput;
10681
11530
  exports.mcpServerSubmitOutputSchema = mcpServerSubmitOutputSchema;