@continuumdao/ctm-mpc-defi 0.2.57 → 0.2.59

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.
@@ -288,7 +288,7 @@ var init_constants = __esm({
288
288
  rewards: viem.zeroAddress,
289
289
  governor: viem.zeroAddress
290
290
  };
291
- CTM_TOKEN_ADDRESS = viem.getAddress("0x2026027054F5beBCEB650aBD62dC623e327658e7");
291
+ CTM_TOKEN_ADDRESS = viem.getAddress("0x7581696b0ED142f6534E5797baaABBb9a1b27086");
292
292
  VOTING_ESCROW_LINEA_ADDRESS = viem.getAddress("0x221EC90B3B083A8501A37bdeb7035CeaedF3C31f");
293
293
  viem.getAddress("0x4ebd7cCBe32a51d1638cFE90E8eD1c4BdF42f729");
294
294
  VOTING_ESCROW_MARKETPLACE_LINEA_ADDRESS = viem.getAddress("0x92557d38beAe4658d3c03A02F349FFB60c3bfFA5");
@@ -1028,9 +1028,9 @@ async function loadFullCurveSessionForRpc(rpcUrl) {
1028
1028
  if (!url) {
1029
1029
  throw new Error("rpcUrl is required.");
1030
1030
  }
1031
- const cached2 = curveSessionCache.get(url);
1032
- if (cached2 && cached2.expiresAt > Date.now()) {
1033
- return cached2.session;
1031
+ const cached3 = curveSessionCache.get(url);
1032
+ if (cached3 && cached3.expiresAt > Date.now()) {
1033
+ return cached3.session;
1034
1034
  }
1035
1035
  try {
1036
1036
  const { default: curve } = await import('@curvefi/api');
@@ -4572,6 +4572,77 @@ var mcpLidoFetchStethAprOutputSchema = zod.z.object({
4572
4572
  source: zod.z.string(),
4573
4573
  notes: zod.z.string()
4574
4574
  });
4575
+ var mcpRailgunFetchPopularAssetsInputSchema = zod.z.object({
4576
+ chainId: agentEvmChainIdSchema,
4577
+ rpcUrl: zod.z.string().min(1).optional().describe("Server-filled from the chain registry. Agents should omit.")
4578
+ }).strict();
4579
+ var mcpRailgunFetchPopularAssetsOutputSchema = zod.z.object({
4580
+ chainId: zod.z.number(),
4581
+ tokens: zod.z.array(zod.z.object({ address: zod.z.string() }).strict()),
4582
+ nativeWrapped: zod.z.string().optional(),
4583
+ notes: zod.z.string()
4584
+ }).strict();
4585
+ var mcpRailgunFetchPrivateBalancesInputSchema = zod.z.object({
4586
+ keyGenId: zod.z.string().min(1).describe("KeyGen request id. The shielded wallet is stored on that KeyGen record."),
4587
+ chainId: agentEvmChainIdSchema,
4588
+ refresh: zod.z.boolean().optional().describe("Scan again and write the KeyGen record. Default reads the stored scan, and scans when none is stored.")
4589
+ }).strict();
4590
+ var mcpRailgunPrivateBalanceSchema = zod.z.object({
4591
+ tokenAddress: zod.z.string(),
4592
+ spendable: zod.z.string(),
4593
+ pending: zod.z.string(),
4594
+ symbol: zod.z.string().optional()
4595
+ }).strict();
4596
+ var mcpRailgunFetchPrivateBalancesOutputSchema = zod.z.object({
4597
+ railgunAddress: zod.z.string(),
4598
+ walletConfigured: zod.z.boolean(),
4599
+ chainId: zod.z.number(),
4600
+ scanned: zod.z.boolean(),
4601
+ scanStatus: zod.z.enum(["scanning", "ready", "empty", "error", "unscanned"]),
4602
+ balances: zod.z.array(mcpRailgunPrivateBalanceSchema),
4603
+ notes: zod.z.string()
4604
+ }).strict();
4605
+ var mcpRailgunEnsureWalletInputSchema = zod.z.object({
4606
+ keyGenId: zod.z.string().min(1),
4607
+ chainId: agentEvmChainIdSchema.optional()
4608
+ }).strict();
4609
+ var mcpRailgunEnsureWalletOutputSchema = zod.z.object({
4610
+ railgunAddress: zod.z.string(),
4611
+ created: zod.z.boolean()
4612
+ }).strict();
4613
+ var mcpRailgunShieldInputSchema = mcpMultisignInput({
4614
+ tokenAddress: evmAddressSchema.describe("ERC-20 contract to shield"),
4615
+ amountWei: zod.z.string().min(1).describe("Amount in wei"),
4616
+ railgunAddress: zod.z.string().min(1).describe("Recipient 0zk address"),
4617
+ shieldSignature: zod.z.string().min(1).optional().describe("personal_sign result from the first shield call. Omit on the first call.")
4618
+ });
4619
+ var mcpRailgunPrivateTransferInputSchema = zod.z.object({
4620
+ keyGenId: zod.z.string().min(1),
4621
+ chainId: agentEvmChainIdSchema,
4622
+ tokenAddress: evmAddressSchema,
4623
+ amountWei: zod.z.string().min(1),
4624
+ recipientAddress: zod.z.string().min(1).describe("Recipient 0zk address"),
4625
+ memoText: zod.z.string().optional()
4626
+ }).strict();
4627
+ var mcpRailgunUnshieldInputSchema = zod.z.object({
4628
+ keyGenId: zod.z.string().min(1),
4629
+ chainId: agentEvmChainIdSchema,
4630
+ tokenAddress: evmAddressSchema,
4631
+ amountWei: zod.z.string().min(1),
4632
+ recipientAddress: evmAddressSchema.optional().describe("Public recipient. Defaults to this KeyGen Ethereum address.")
4633
+ }).strict();
4634
+ var mcpRailgunAgreeSpendInputSchema = zod.z.object({
4635
+ keyGenId: zod.z.string().min(1),
4636
+ spendId: zod.z.string().min(1)
4637
+ }).strict();
4638
+ var mcpRailgunPrivateActionOutputSchema = zod.z.object({
4639
+ status: zod.z.enum(["pending", "submitted", "failed"]),
4640
+ spendId: zod.z.string(),
4641
+ approvals: zod.z.number().int().nonnegative(),
4642
+ quorum: zod.z.number().int().positive(),
4643
+ txHash: zod.z.string().optional(),
4644
+ error: zod.z.string().optional()
4645
+ }).strict();
4575
4646
  var mcpSkyFetchSusdsRateInputSchema = zod.z.object({
4576
4647
  rpcUrl: zod.z.string().min(1).optional().describe("Server-filled from chain registry. Agents should omit.")
4577
4648
  }).strict();
@@ -6314,7 +6385,7 @@ var mcpCctpFetchBurnFeesInputSchema = zod.z.object({
6314
6385
  transferAmountHuman: zod.z.string().min(1).optional().describe(
6315
6386
  "Human USDC amount the recipient receives (6 decimals). Required for a maxFee that includes the fast-transfer protocol fee and for totalBurn. Omit only to inspect raw forwarding tiers."
6316
6387
  ),
6317
- feeTier: zod.z.enum(["low", "med", "high"]).optional().describe("Iris forwardFee tier; default med"),
6388
+ feeTier: zod.z.enum(["low", "med", "high"]).optional().describe("Iris forwardFee tier; default high"),
6318
6389
  minFinalityThreshold: agentCoercedOptionalIntSchema(zod.z.number().int().positive()).describe(
6319
6390
  "Iris fee row. 1000 (default) is fast transfer and includes minimumFee bps. 2000 is standard transfer."
6320
6391
  )
@@ -6351,7 +6422,7 @@ var mcpCctpBuildBurnMultisignInputSchema = mcpMultisignInput({
6351
6422
  destChainId: agentEvmChainIdSchema.describe("Destination chain EIP-155 id (mint chain)"),
6352
6423
  transferAmountHuman: zod.z.string().min(1).describe("Human USDC amount recipient receives"),
6353
6424
  mintRecipient: evmAddressSchema.optional().describe("Recipient on destination chain; defaults to MPC executor address"),
6354
- feeTier: zod.z.enum(["low", "med", "high"]).optional(),
6425
+ feeTier: zod.z.enum(["low", "med", "high"]).optional().describe("Iris forwardFee tier; default high"),
6355
6426
  minFinalityThreshold: agentCoercedOptionalIntSchema(zod.z.number().int().positive()),
6356
6427
  feeSnapshot: jsonObjectSchema.optional().describe(
6357
6428
  "Optional output from ctm_cctp_fetch_burn_fees. Build re-quotes Iris. A snapshot maxFee below the live forward+protocol total is ignored; a higher snapshot is kept as a cap."
@@ -7929,6 +8000,16 @@ var MCP_PROTOCOL_TOOL_DEFINITIONS = [
7929
8000
  prerequisites: ["keyGenId", "chainId 999", "question", "outcome", "amountHuman", "purposeText"],
7930
8001
  handler: { importPath: "protocols/evm/hyperliquidOutcome", exportName: "buildEvmMultisignBodyHyperliquidOutcomeNegate" },
7931
8002
  inputZod: mcpHyperliquidOutcomeNegateInputSchema
8003
+ }),
8004
+ defineProtocolMcpTool({
8005
+ name: "ctm_railgun_build_shield_multisign",
8006
+ actionId: "railgun.shield",
8007
+ protocolId: "railgun",
8008
+ chainCategory: "evm",
8009
+ description: "Shield an ERC-20 into a Railgun 0zk address. The first call omits shieldSignature and returns a personal_sign. Submit it, then call again with shieldSignature to build the approve-and-shield transaction.",
8010
+ prerequisites: ["keyGen", "executorAddress", "RPC URL", "0zk recipient"],
8011
+ handler: { importPath: "protocols/evm/railgun", exportName: "buildEvmMultisignBodyRailgunShield" },
8012
+ inputZod: mcpRailgunShieldInputSchema
7932
8013
  })
7933
8014
  ];
7934
8015
  var catalogQuery = {
@@ -10959,6 +11040,78 @@ var CORE_MCP_TOOL_DEFINITIONS = [
10959
11040
  handler: { importPath: "protocols/evm/trueo", exportName: "trueoFetchOrderbookSummary" },
10960
11041
  inputZod: mcpTrueoFetchOrderbookInputSchema,
10961
11042
  outputZod: mcpTrueoFetchOrderbookOutputSchema
11043
+ }),
11044
+ defineMcpTool({
11045
+ name: "ctm_railgun_fetch_popular_assets",
11046
+ actionId: "railgun.fetch-popular-assets",
11047
+ protocolId: "railgun",
11048
+ chainCategory: "evm",
11049
+ description: "Top 5 public ERC-20s on a Railgun chain by recent shield count. This is the asset-row icon list, not the user shielded holdings. rpcUrl is injected.",
11050
+ prerequisites: ["chainId", "get_defi_protocol_supported_chains"],
11051
+ followUp: ["ctm_railgun_build_shield_multisign"],
11052
+ handler: { importPath: "protocols/evm/railgun", exportName: "railgunFetchPopularAssets" },
11053
+ inputZod: mcpRailgunFetchPopularAssetsInputSchema,
11054
+ outputZod: mcpRailgunFetchPopularAssetsOutputSchema
11055
+ }),
11056
+ defineMcpTool({
11057
+ name: "ctm_railgun_ensure_wallet",
11058
+ actionId: "railgun.ensure-wallet",
11059
+ protocolId: "railgun",
11060
+ chainCategory: "evm",
11061
+ description: "Create the Railgun wallet on this KeyGen if it does not exist yet, and return its 0zk address. The spending key is split across the KeyGen nodes. No node receives a key it can spend alone. Does not return a mnemonic. Use this from the node agent and from Telegram before shield, unshield, or private transfer.",
11062
+ prerequisites: ["keyGenId"],
11063
+ followUp: ["ctm_railgun_fetch_private_balances", "ctm_railgun_build_shield_multisign"],
11064
+ handler: { importPath: "protocols/evm/railgun", exportName: "railgunFetchPrivateBalancesSummary" },
11065
+ inputZod: mcpRailgunEnsureWalletInputSchema,
11066
+ outputZod: mcpRailgunEnsureWalletOutputSchema
11067
+ }),
11068
+ defineMcpTool({
11069
+ name: "ctm_railgun_fetch_private_balances",
11070
+ actionId: "railgun.fetch-private-balances",
11071
+ protocolId: "railgun",
11072
+ chainCategory: "evm",
11073
+ description: "Shielded balances stored on the KeyGen record for this chain. Scans on the node when no scan is stored, or when refresh is true, then writes the result back to the KeyGen. Does not return a mnemonic or viewing key. Works from the node agent and from Telegram.",
11074
+ prerequisites: ["keyGenId", "chainId", "ctm_railgun_ensure_wallet"],
11075
+ followUp: ["ctm_railgun_private_transfer", "ctm_railgun_unshield"],
11076
+ handler: { importPath: "protocols/evm/railgun", exportName: "railgunFetchPrivateBalancesSummary" },
11077
+ inputZod: mcpRailgunFetchPrivateBalancesInputSchema,
11078
+ outputZod: mcpRailgunFetchPrivateBalancesOutputSchema
11079
+ }),
11080
+ defineMcpTool({
11081
+ name: "ctm_railgun_private_transfer",
11082
+ actionId: "railgun.private-transfer",
11083
+ protocolId: "railgun",
11084
+ chainCategory: "evm",
11085
+ description: "Start a private Railgun transfer. It stays pending until the KeyGen signing quorum agrees with ctm_railgun_agree_spend. No single node can spend. Do not pass a mnemonic.",
11086
+ prerequisites: ["keyGenId", "chainId", "0zk recipient", "ctm_railgun_ensure_wallet"],
11087
+ followUp: ["ctm_railgun_fetch_private_balances"],
11088
+ handler: { importPath: "protocols/evm/railgun", exportName: "railgunPrivateTransfer" },
11089
+ inputZod: mcpRailgunPrivateTransferInputSchema,
11090
+ outputZod: mcpRailgunPrivateActionOutputSchema
11091
+ }),
11092
+ defineMcpTool({
11093
+ name: "ctm_railgun_unshield",
11094
+ actionId: "railgun.unshield",
11095
+ protocolId: "railgun",
11096
+ chainCategory: "evm",
11097
+ description: "Start an unshield to a public address. It stays pending until the KeyGen signing quorum agrees with ctm_railgun_agree_spend. Recipient defaults to the KeyGen Ethereum address. No single node can spend. Do not pass a mnemonic.",
11098
+ prerequisites: ["keyGenId", "chainId", "ctm_railgun_ensure_wallet"],
11099
+ followUp: ["ctm_railgun_fetch_private_balances"],
11100
+ handler: { importPath: "protocols/evm/railgun", exportName: "railgunUnshield" },
11101
+ inputZod: mcpRailgunUnshieldInputSchema,
11102
+ outputZod: mcpRailgunPrivateActionOutputSchema
11103
+ }),
11104
+ defineMcpTool({
11105
+ name: "ctm_railgun_agree_spend",
11106
+ actionId: "railgun.agree-spend",
11107
+ protocolId: "railgun",
11108
+ chainCategory: "evm",
11109
+ description: "Agree this node\u2019s Railgun spending share for a pending spendId. Read the pending spend on the KeyGen record before agreeing. One share cannot spend the 0zk wallet.",
11110
+ prerequisites: ["keyGenId", "spendId"],
11111
+ followUp: ["ctm_railgun_fetch_private_balances"],
11112
+ handler: { importPath: "protocols/evm/railgun", exportName: "railgunFetchPrivateBalancesSummary" },
11113
+ inputZod: mcpRailgunAgreeSpendInputSchema,
11114
+ outputZod: mcpRailgunPrivateActionOutputSchema
10962
11115
  })
10963
11116
  ];
10964
11117
  var MCP_TOOL_DEFINITIONS = [
@@ -11075,6 +11228,222 @@ var lidoProtocolModule = {
11075
11228
  ]
11076
11229
  };
11077
11230
  registerProtocolModule(lidoProtocolModule);
11231
+
11232
+ // src/protocols/evm/railgun/networks.ts
11233
+ function selectRailgunNetworks(config) {
11234
+ const rows = [];
11235
+ for (const entry of Object.values(config)) {
11236
+ if (!entry || entry.deprecated || entry.isDevOnlyNetwork) continue;
11237
+ const chainId = Number(entry.chain?.id);
11238
+ const proxyContract = String(entry.proxyContract ?? "").trim();
11239
+ const wrappedAddress = String(entry.baseToken?.wrappedAddress ?? "").trim();
11240
+ if (!Number.isFinite(chainId) || chainId <= 0 || !proxyContract || !wrappedAddress) continue;
11241
+ rows.push({
11242
+ chainId,
11243
+ networkName: String(entry.name ?? ""),
11244
+ publicName: String(entry.publicName ?? entry.name ?? ""),
11245
+ proxyContract,
11246
+ deploymentBlock: Number(entry.deploymentBlock ?? 0),
11247
+ wrappedAddress,
11248
+ wrappedSymbol: String(entry.baseToken?.wrappedSymbol ?? entry.baseToken?.symbol ?? ""),
11249
+ wrappedDecimals: Number(entry.baseToken?.decimals ?? 18),
11250
+ isTestnet: Boolean(entry.isTestnet)
11251
+ });
11252
+ }
11253
+ rows.sort((a, b) => a.chainId - b.chainId);
11254
+ return rows;
11255
+ }
11256
+ var cached = null;
11257
+ async function loadRailgunNetworks() {
11258
+ if (cached) return cached;
11259
+ const mod = await import('@railgun-community/shared-models');
11260
+ cached = selectRailgunNetworks(mod.NETWORK_CONFIG);
11261
+ return cached;
11262
+ }
11263
+ async function loadRailgunSupportedChainIds() {
11264
+ const rows = await loadRailgunNetworks();
11265
+ return new Set(rows.map((row) => row.chainId));
11266
+ }
11267
+ async function railgunNetworkByChainId(chainId) {
11268
+ const rows = await loadRailgunNetworks();
11269
+ return rows.find((row) => row.chainId === chainId);
11270
+ }
11271
+
11272
+ // src/protocols/evm/railgun/popular-assets.ts
11273
+ init_constants();
11274
+ var RAILGUN_POPULAR_ASSET_LIMIT = 5;
11275
+ var POPULAR_ASSET_CACHE_MS = 10 * 60 * 1e3;
11276
+ var RECENT_SHIELD_LIMIT = 200;
11277
+ var SHIELD_INDEX_BY_NETWORK_NAME = {
11278
+ Ethereum: "https://rail-squid.squids.live/squid-railgun-ethereum-v2/graphql",
11279
+ BNB_Chain: "https://rail-squid.squids.live/squid-railgun-bsc-v2/graphql",
11280
+ Polygon: "https://rail-squid.squids.live/squid-railgun-polygon-v2/graphql",
11281
+ Arbitrum: "https://rail-squid.squids.live/squid-railgun-arbitrum-v2/graphql"
11282
+ };
11283
+ var RECENT_SHIELDS_QUERY = `query RecentShields($limit: Int!) {
11284
+ shieldCommitments(orderBy: [blockNumber_DESC], limit: $limit) {
11285
+ preimage { token { tokenType tokenAddress } }
11286
+ }
11287
+ }`;
11288
+ var cache = /* @__PURE__ */ new Map();
11289
+ function rankPopularShieldTokens(rows, limit = RAILGUN_POPULAR_ASSET_LIMIT) {
11290
+ const counts = /* @__PURE__ */ new Map();
11291
+ for (const row of rows) {
11292
+ if (Number(row.tokenType) !== 0) continue;
11293
+ let address;
11294
+ try {
11295
+ address = viem.getAddress(row.tokenAddress);
11296
+ } catch {
11297
+ continue;
11298
+ }
11299
+ if (address === viem.zeroAddress) continue;
11300
+ const key = address.toLowerCase();
11301
+ counts.set(key, (counts.get(key) ?? 0) + 1);
11302
+ }
11303
+ return [...counts.entries()].sort((a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0)).slice(0, limit).map(([address]) => viem.getAddress(address));
11304
+ }
11305
+ function shieldIndexEndpoint(networkName) {
11306
+ return SHIELD_INDEX_BY_NETWORK_NAME[networkName] ?? null;
11307
+ }
11308
+ function commitmentsFromShieldIndex(payload) {
11309
+ const rows = payload?.data?.shieldCommitments;
11310
+ if (!Array.isArray(rows)) return [];
11311
+ return rows.map((row) => {
11312
+ const token = row?.preimage?.token;
11313
+ const tokenType = token?.tokenType === "ERC20" || token?.tokenType === 0 ? 0 : Number(token?.tokenType ?? -1);
11314
+ return {
11315
+ tokenAddress: String(token?.tokenAddress ?? ""),
11316
+ tokenType: Number.isFinite(tokenType) ? tokenType : -1
11317
+ };
11318
+ });
11319
+ }
11320
+ var shieldLogReaderOverride = null;
11321
+ async function readShieldCommitments(args) {
11322
+ const endpoint = shieldIndexEndpoint(args.networkName);
11323
+ if (!endpoint) return [];
11324
+ const response = await fetch(endpoint, {
11325
+ method: "POST",
11326
+ headers: { "content-type": "application/json" },
11327
+ body: JSON.stringify({
11328
+ query: RECENT_SHIELDS_QUERY,
11329
+ variables: { limit: RECENT_SHIELD_LIMIT }
11330
+ })
11331
+ });
11332
+ if (!response.ok) throw new Error(`Railgun shield index returned ${response.status}`);
11333
+ return commitmentsFromShieldIndex(await response.json());
11334
+ }
11335
+ function applyContinuumToken(chainId, result) {
11336
+ const ctm = ctmTokenAddressOnEvmChain(chainId);
11337
+ if (!ctm) return result;
11338
+ const present = result.tokens.some((token) => token.address.toLowerCase() === ctm.toLowerCase());
11339
+ {
11340
+ if (!present) return result;
11341
+ return {
11342
+ ...result,
11343
+ tokens: result.tokens.filter((token) => token.address.toLowerCase() !== ctm.toLowerCase())
11344
+ };
11345
+ }
11346
+ }
11347
+ async function loadRailgunPopularAssets(args) {
11348
+ const network = await railgunNetworkByChainId(args.chainId);
11349
+ if (!network) {
11350
+ return { tokens: [], notes: "Railgun is not deployed on this chain." };
11351
+ }
11352
+ const cached3 = cache.get(args.chainId);
11353
+ if (cached3 && Date.now() - cached3.at < POPULAR_ASSET_CACHE_MS) {
11354
+ return applyContinuumToken(args.chainId, {
11355
+ tokens: cached3.tokens,
11356
+ nativeWrapped: cached3.nativeWrapped,
11357
+ notes: cached3.notes
11358
+ });
11359
+ }
11360
+ const rpcUrl = args.rpcUrl?.trim() ?? "";
11361
+ if (!shieldIndexEndpoint(network.networkName) && !shieldLogReaderOverride) {
11362
+ return applyContinuumToken(args.chainId, {
11363
+ tokens: [],
11364
+ nativeWrapped: network.wrappedAddress,
11365
+ notes: "This chain has no indexed Railgun shield feed."
11366
+ });
11367
+ }
11368
+ try {
11369
+ const commitments = await (shieldLogReaderOverride ?? readShieldCommitments)({
11370
+ rpcUrl,
11371
+ chainId: args.chainId,
11372
+ proxy: viem.getAddress(network.proxyContract),
11373
+ deploymentBlock: network.deploymentBlock,
11374
+ networkName: network.networkName
11375
+ });
11376
+ const tokens = rankPopularShieldTokens(commitments).map((address) => ({ address }));
11377
+ const notes = tokens.length === 0 ? "No recent ERC-20 shields were returned for this chain." : `Top ${tokens.length} ERC-20s by recent indexed shield count.`;
11378
+ const entry = {
11379
+ at: Date.now(),
11380
+ tokens,
11381
+ nativeWrapped: network.wrappedAddress,
11382
+ notes
11383
+ };
11384
+ cache.set(args.chainId, entry);
11385
+ return applyContinuumToken(args.chainId, { tokens, nativeWrapped: network.wrappedAddress, notes });
11386
+ } catch {
11387
+ return applyContinuumToken(args.chainId, {
11388
+ tokens: [],
11389
+ nativeWrapped: network.wrappedAddress,
11390
+ notes: "The Railgun shield index could not be read."
11391
+ });
11392
+ }
11393
+ }
11394
+
11395
+ // src/protocols/evm/railgun/index.ts
11396
+ var RAILGUN_PROTOCOL_ID = "railgun";
11397
+ var railgunProtocolModule = {
11398
+ id: RAILGUN_PROTOCOL_ID,
11399
+ chainCategory: "evm",
11400
+ isChainSupported(ctx) {
11401
+ if (ctx.chainCategory !== "evm") return false;
11402
+ return loadRailgunSupportedChainIds().then((ids) => ids.has(Number(ctx.chainId)));
11403
+ },
11404
+ isTokenSupported(token) {
11405
+ return token.category === "evm" && (token.kind === "native" || token.kind === "erc20");
11406
+ },
11407
+ actions: [
11408
+ {
11409
+ id: "railgun.shield",
11410
+ protocolId: RAILGUN_PROTOCOL_ID,
11411
+ chainCategory: "evm",
11412
+ description: "Shield an ERC-20 into a Railgun 0zk address",
11413
+ commonParams: ["keyGen", "purposeText", "useCustomGas"],
11414
+ params: {
11415
+ tokenAddress: { type: "string", required: true, description: "ERC-20 to shield" },
11416
+ amountWei: { type: "string", required: true, description: "Amount in wei" },
11417
+ railgunAddress: { type: "string", required: true, description: "Recipient 0zk address" }
11418
+ }
11419
+ },
11420
+ {
11421
+ id: "railgun.private-transfer",
11422
+ protocolId: RAILGUN_PROTOCOL_ID,
11423
+ chainCategory: "evm",
11424
+ description: "Private transfer from the unlocked Railgun wallet",
11425
+ commonParams: ["purposeText"],
11426
+ params: {
11427
+ tokenAddress: { type: "string", required: true, description: "Shielded ERC-20" },
11428
+ amountWei: { type: "string", required: true, description: "Amount in wei" },
11429
+ recipientAddress: { type: "string", required: true, description: "Recipient 0zk address" }
11430
+ }
11431
+ },
11432
+ {
11433
+ id: "railgun.unshield",
11434
+ protocolId: RAILGUN_PROTOCOL_ID,
11435
+ chainCategory: "evm",
11436
+ description: "Unshield from the unlocked Railgun wallet to a public address",
11437
+ commonParams: ["purposeText"],
11438
+ params: {
11439
+ tokenAddress: { type: "string", required: true, description: "Shielded ERC-20" },
11440
+ amountWei: { type: "string", required: true, description: "Amount in wei" },
11441
+ recipientAddress: { type: "string", required: true, description: "Public recipient" }
11442
+ }
11443
+ }
11444
+ ]
11445
+ };
11446
+ registerProtocolModule(railgunProtocolModule);
11078
11447
  var USDE_ETHEREUM_MAINNET = "0x4c9edd5852cd905f086c759e8383e09bff1e68b3";
11079
11448
  var SUSDE_ETHEREUM_MAINNET = "0x9d39a5de30e57443bff2a8307a4256c8797a3497";
11080
11449
  var USDE_MOST_L2S = "0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34";
@@ -11467,19 +11836,19 @@ function ensureEulerV2ChainAssetCache(chainId) {
11467
11836
  }
11468
11837
 
11469
11838
  // src/protocols/evm/euler-v2/loadEulerV2SupportedChainIds.ts
11470
- var cached = null;
11839
+ var cached2 = null;
11471
11840
  async function loadEulerV2SupportedChainIds() {
11472
- if (cached) return cached;
11841
+ if (cached2) return cached2;
11473
11842
  try {
11474
11843
  const ids = await fetchEulerV3ActiveChainIds();
11475
11844
  if (ids.length) {
11476
- cached = new Set(ids);
11477
- return cached;
11845
+ cached2 = new Set(ids);
11846
+ return cached2;
11478
11847
  }
11479
11848
  } catch {
11480
11849
  }
11481
- cached = new Set(Object.keys(EULER_V2_GOLDSKY_SUBGRAPH_URL_BY_CHAIN_ID).map((k) => Number(k)));
11482
- return cached;
11850
+ cached2 = new Set(Object.keys(EULER_V2_GOLDSKY_SUBGRAPH_URL_BY_CHAIN_ID).map((k) => Number(k)));
11851
+ return cached2;
11483
11852
  }
11484
11853
 
11485
11854
  // src/protocols/evm/euler-v2/index.ts
@@ -12260,9 +12629,9 @@ async function ensureMorphoChainAssetCache(chainId) {
12260
12629
  }
12261
12630
  } catch {
12262
12631
  }
12263
- const cache = { modesByUnderlying: modes, nativeWrapped: null };
12264
- chainAssetCache.set(chainId, cache);
12265
- return cache;
12632
+ const cache2 = { modesByUnderlying: modes, nativeWrapped: null };
12633
+ chainAssetCache.set(chainId, cache2);
12634
+ return cache2;
12266
12635
  }
12267
12636
 
12268
12637
  // src/protocols/evm/morpho/index.ts
@@ -13760,8 +14129,8 @@ async function pendleFetchMarketsPage(args) {
13760
14129
  }
13761
14130
  async function pendleFetchMarketsForChain(chainId) {
13762
14131
  const now = Date.now();
13763
- const cached2 = marketsCacheByChain.get(chainId);
13764
- if (cached2 && now - cached2.at < PENDLE_ICON_CACHE_MS) return cached2.rows;
14132
+ const cached3 = marketsCacheByChain.get(chainId);
14133
+ if (cached3 && now - cached3.at < PENDLE_ICON_CACHE_MS) return cached3.rows;
13765
14134
  const rows = [];
13766
14135
  for (let page = 0; page < PENDLE_LISTING_MAX_PAGES; page++) {
13767
14136
  const batch = await pendleFetchMarketsPage({
@@ -14300,6 +14669,7 @@ var skillsDir = path.join(path.dirname(url.fileURLToPath((typeof document === 'u
14300
14669
  var SKILL_PROTOCOL_IDS = [
14301
14670
  "aave-v4",
14302
14671
  "lido",
14672
+ "railgun",
14303
14673
  "uniswap-v4",
14304
14674
  "curve-dao",
14305
14675
  "ethena",
@@ -14419,9 +14789,9 @@ var PROTOCOL_SUPPORT_ADVISORS = {
14419
14789
  return [...set].sort((a, b) => a - b);
14420
14790
  },
14421
14791
  async supportedTokens(chainId) {
14422
- const cache = await ensureAaveV4ChainTokenCache(chainId);
14792
+ const cache2 = await ensureAaveV4ChainTokenCache(chainId);
14423
14793
  await ensureCoinbaseB20StockCatalog().catch(() => []);
14424
- const tokens = [...cache.supportedUnderlying].map((address) => {
14794
+ const tokens = [...cache2.supportedUnderlying].map((address) => {
14425
14795
  const known = lookupCoinbaseB20StockToken(address);
14426
14796
  if (!known) return { address, roles: ["underlying"] };
14427
14797
  return {
@@ -14432,31 +14802,31 @@ var PROTOCOL_SUPPORT_ADVISORS = {
14432
14802
  roles: ["underlying", "coinbase_b20", "collateral"]
14433
14803
  };
14434
14804
  });
14435
- if (cache.nativeWrapped) {
14805
+ if (cache2.nativeWrapped) {
14436
14806
  tokens.unshift({
14437
- address: cache.nativeWrapped,
14807
+ address: cache2.nativeWrapped,
14438
14808
  symbol: "WETH",
14439
14809
  roles: ["native_wrapped"]
14440
14810
  });
14441
14811
  }
14442
14812
  return {
14443
14813
  tokens,
14444
- nativeWrapped: cache.nativeWrapped ?? void 0,
14814
+ nativeWrapped: cache2.nativeWrapped ?? void 0,
14445
14815
  notes: "Native ETH deposits use wrapped native token address from Aave v4 API. Base chainId 8453 Coinbase Stocks hub is marketId bstocks. Listed equities come from the Aave v4 API; tickers resolve from the live Coinbase catalog. Equities are collateral-only; USDC is the borrow asset."
14446
14816
  };
14447
14817
  },
14448
14818
  async isTokenSupported(chainId, address) {
14449
- const cache = await ensureAaveV4ChainTokenCache(chainId);
14819
+ const cache2 = await ensureAaveV4ChainTokenCache(chainId);
14450
14820
  let normalized;
14451
14821
  try {
14452
14822
  normalized = viem.getAddress(address).toLowerCase();
14453
14823
  } catch {
14454
14824
  return false;
14455
14825
  }
14456
- if (cache.nativeWrapped && viem.getAddress(cache.nativeWrapped).toLowerCase() === normalized) {
14826
+ if (cache2.nativeWrapped && viem.getAddress(cache2.nativeWrapped).toLowerCase() === normalized) {
14457
14827
  return true;
14458
14828
  }
14459
- return cache.supportedUnderlying.has(normalized);
14829
+ return cache2.supportedUnderlying.has(normalized);
14460
14830
  }
14461
14831
  }),
14462
14832
  "uniswap-v4": advisor("uniswap-v4", "any_erc20_on_chain", {
@@ -14589,8 +14959,8 @@ var PROTOCOL_SUPPORT_ADVISORS = {
14589
14959
  return [...set].sort((a, b) => a - b);
14590
14960
  },
14591
14961
  async supportedTokens(chainId) {
14592
- const cache = await ensureMorphoChainAssetCache(chainId);
14593
- const tokens = [...cache.modesByUnderlying.entries()].map(([address, modes]) => ({
14962
+ const cache2 = await ensureMorphoChainAssetCache(chainId);
14963
+ const tokens = [...cache2.modesByUnderlying.entries()].map(([address, modes]) => ({
14594
14964
  address,
14595
14965
  roles: [
14596
14966
  ...modes.earn ? ["vault_underlying"] : [],
@@ -14604,14 +14974,14 @@ var PROTOCOL_SUPPORT_ADVISORS = {
14604
14974
  };
14605
14975
  },
14606
14976
  async isTokenSupported(chainId, address) {
14607
- const cache = await ensureMorphoChainAssetCache(chainId);
14977
+ const cache2 = await ensureMorphoChainAssetCache(chainId);
14608
14978
  let normalized;
14609
14979
  try {
14610
14980
  normalized = viem.getAddress(address).toLowerCase();
14611
14981
  } catch {
14612
14982
  return false;
14613
14983
  }
14614
- return cache.modesByUnderlying.has(normalized);
14984
+ return cache2.modesByUnderlying.has(normalized);
14615
14985
  }
14616
14986
  }),
14617
14987
  "euler-v2": advisor("euler-v2", "subgraph_vaults", {
@@ -14620,8 +14990,8 @@ var PROTOCOL_SUPPORT_ADVISORS = {
14620
14990
  return [...set].sort((a, b) => a - b);
14621
14991
  },
14622
14992
  async supportedTokens(chainId) {
14623
- const cache = await ensureEulerV2ChainAssetCache(chainId);
14624
- const tokens = [...cache.modesByUnderlying.entries()].map(([address, modes]) => ({
14993
+ const cache2 = await ensureEulerV2ChainAssetCache(chainId);
14994
+ const tokens = [...cache2.modesByUnderlying.entries()].map(([address, modes]) => ({
14625
14995
  address,
14626
14996
  roles: [
14627
14997
  ...modes.lend ? ["vault_underlying"] : [],
@@ -14631,19 +15001,19 @@ var PROTOCOL_SUPPORT_ADVISORS = {
14631
15001
  }));
14632
15002
  return {
14633
15003
  tokens,
14634
- nativeWrapped: cache.nativeWrapped ?? void 0,
15004
+ nativeWrapped: cache2.nativeWrapped ?? void 0,
14635
15005
  notes: "Euler EVK vault underlyings and Earn vault assets from the Euler V3 API. Use address as underlyingAddress for ctm_euler_v2_fetch_lend_vaults."
14636
15006
  };
14637
15007
  },
14638
15008
  async isTokenSupported(chainId, address) {
14639
- const cache = await ensureEulerV2ChainAssetCache(chainId);
15009
+ const cache2 = await ensureEulerV2ChainAssetCache(chainId);
14640
15010
  let normalized;
14641
15011
  try {
14642
15012
  normalized = viem.getAddress(address).toLowerCase();
14643
15013
  } catch {
14644
15014
  return false;
14645
15015
  }
14646
- return cache.modesByUnderlying.has(normalized);
15016
+ return cache2.modesByUnderlying.has(normalized);
14647
15017
  }
14648
15018
  }),
14649
15019
  [MAPLE_PROTOCOL_ID]: advisor(MAPLE_PROTOCOL_ID, "fixed_addresses", {
@@ -14793,7 +15163,7 @@ var PROTOCOL_SUPPORT_ADVISORS = {
14793
15163
  return listCompoundV3SupportedChainIds();
14794
15164
  },
14795
15165
  async supportedTokens(chainId, ctx) {
14796
- const cache = await ensureCompoundV3ChainAssetCache({ chainId, rpcUrl: ctx?.rpcUrl });
15166
+ const cache2 = await ensureCompoundV3ChainAssetCache({ chainId, rpcUrl: ctx?.rpcUrl });
14797
15167
  const nativeWrapped = compoundV3WrappedNative(chainId);
14798
15168
  const tokens = [];
14799
15169
  if (nativeWrapped) {
@@ -14809,7 +15179,7 @@ var PROTOCOL_SUPPORT_ADVISORS = {
14809
15179
  roles: ["native_wrapped"]
14810
15180
  });
14811
15181
  }
14812
- for (const [address, modes] of cache) {
15182
+ for (const [address, modes] of cache2) {
14813
15183
  if (nativeWrapped && address === nativeWrapped.toLowerCase()) continue;
14814
15184
  tokens.push({
14815
15185
  address,
@@ -14823,7 +15193,7 @@ var PROTOCOL_SUPPORT_ADVISORS = {
14823
15193
  };
14824
15194
  },
14825
15195
  async isTokenSupported(chainId, address, ctx) {
14826
- const cache = await ensureCompoundV3ChainAssetCache({ chainId, rpcUrl: ctx?.rpcUrl });
15196
+ const cache2 = await ensureCompoundV3ChainAssetCache({ chainId, rpcUrl: ctx?.rpcUrl });
14827
15197
  let normalized;
14828
15198
  try {
14829
15199
  normalized = viem.getAddress(address).toLowerCase();
@@ -14833,7 +15203,7 @@ var PROTOCOL_SUPPORT_ADVISORS = {
14833
15203
  if (normalized === "0x0000000000000000000000000000000000000000") return true;
14834
15204
  const wrapped = compoundV3WrappedNative(chainId);
14835
15205
  if (wrapped && wrapped.toLowerCase() === normalized) return true;
14836
- return cache.has(normalized);
15206
+ return cache2.has(normalized);
14837
15207
  }
14838
15208
  }),
14839
15209
  [PENDLE_PROTOCOL_ID]: advisor(PENDLE_PROTOCOL_ID, "api_underlyings", {
@@ -14961,6 +15331,32 @@ var PROTOCOL_SUPPORT_ADVISORS = {
14961
15331
  return false;
14962
15332
  }
14963
15333
  }
15334
+ }),
15335
+ railgun: advisor("railgun", "api_underlyings", {
15336
+ async supportedChainIds() {
15337
+ return [...await loadRailgunSupportedChainIds()];
15338
+ },
15339
+ async supportedTokens(chainId, ctx) {
15340
+ const result = await loadRailgunPopularAssets({ chainId, rpcUrl: ctx?.rpcUrl });
15341
+ return {
15342
+ tokens: result.tokens.map((token) => ({ address: token.address, roles: ["shield"] })),
15343
+ nativeWrapped: result.nativeWrapped,
15344
+ notes: result.notes
15345
+ };
15346
+ },
15347
+ async isTokenSupported(chainId, address, ctx) {
15348
+ const result = await loadRailgunPopularAssets({ chainId, rpcUrl: ctx?.rpcUrl });
15349
+ const listed = new Set(result.tokens.map((token) => token.address.toLowerCase()));
15350
+ try {
15351
+ const normalized = viem.getAddress(address);
15352
+ if (normalized === viem.zeroAddress) {
15353
+ return Boolean(result.nativeWrapped && listed.has(result.nativeWrapped.toLowerCase()));
15354
+ }
15355
+ return listed.has(normalized.toLowerCase());
15356
+ } catch {
15357
+ return false;
15358
+ }
15359
+ }
14964
15360
  })
14965
15361
  };
14966
15362
  function getProtocolSupportAdvisor(protocolId) {
@@ -14982,6 +15378,7 @@ function getAgentCatalog() {
14982
15378
  uniswapV4: uniswapV4ProtocolModule,
14983
15379
  curveDao: curveDaoProtocolModule,
14984
15380
  lido: lidoProtocolModule,
15381
+ railgun: railgunProtocolModule,
14985
15382
  ethena: ethenaProtocolModule,
14986
15383
  maple: mapleProtocolModule,
14987
15384
  sky: skyProtocolModule,
@@ -15428,6 +15825,17 @@ exports.mcpPendleQuoteSwapInputSchema = mcpPendleQuoteSwapInputSchema;
15428
15825
  exports.mcpPendleSearchAssetsInputSchema = mcpPendleSearchAssetsInputSchema;
15429
15826
  exports.mcpPendleSearchAssetsOutputSchema = mcpPendleSearchAssetsOutputSchema;
15430
15827
  exports.mcpPredictionMarketRowSchema = mcpPredictionMarketRowSchema;
15828
+ exports.mcpRailgunAgreeSpendInputSchema = mcpRailgunAgreeSpendInputSchema;
15829
+ exports.mcpRailgunEnsureWalletInputSchema = mcpRailgunEnsureWalletInputSchema;
15830
+ exports.mcpRailgunEnsureWalletOutputSchema = mcpRailgunEnsureWalletOutputSchema;
15831
+ exports.mcpRailgunFetchPopularAssetsInputSchema = mcpRailgunFetchPopularAssetsInputSchema;
15832
+ exports.mcpRailgunFetchPopularAssetsOutputSchema = mcpRailgunFetchPopularAssetsOutputSchema;
15833
+ exports.mcpRailgunFetchPrivateBalancesInputSchema = mcpRailgunFetchPrivateBalancesInputSchema;
15834
+ exports.mcpRailgunFetchPrivateBalancesOutputSchema = mcpRailgunFetchPrivateBalancesOutputSchema;
15835
+ exports.mcpRailgunPrivateActionOutputSchema = mcpRailgunPrivateActionOutputSchema;
15836
+ exports.mcpRailgunPrivateTransferInputSchema = mcpRailgunPrivateTransferInputSchema;
15837
+ exports.mcpRailgunShieldInputSchema = mcpRailgunShieldInputSchema;
15838
+ exports.mcpRailgunUnshieldInputSchema = mcpRailgunUnshieldInputSchema;
15431
15839
  exports.mcpSearchPredictionMarketsInputSchema = mcpSearchPredictionMarketsInputSchema;
15432
15840
  exports.mcpSearchPredictionMarketsOutputSchema = mcpSearchPredictionMarketsOutputSchema;
15433
15841
  exports.mcpServerCommonInputSchema = mcpServerCommonInputSchema;