@paydprotocol/mcp 0.1.0 → 0.2.0

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.
package/README.md CHANGED
@@ -14,7 +14,9 @@ claude mcp add payd -- npx -y @paydprotocol/mcp # any MCP client: same command
14
14
 
15
15
  Tools: `payd_list_tokens`, `payd_token_info`, `payd_holder_shares`,
16
16
  `payd_launch_options`, and the prepare tools `payd_prepare_create_vault`,
17
- `payd_prepare_launch`, `payd_prepare_bind`, `payd_prepare_claim`. Every prepare
17
+ `payd_prepare_launch`, `payd_prepare_bind`, `payd_prepare_claim`, and for keepers
18
+ `payd_pending_work`, `payd_prepare_harvest`, `payd_prepare_buy_basket` — open
19
+ calls that pay their caller (gas back, or a bounty). Every prepare
18
20
  tool simulates from `from` first and returns an error instead of calldata when
19
21
  the simulation reverts.
20
22
 
package/dist/server.js CHANGED
@@ -644,6 +644,7 @@ async function listTokens(c, o) {
644
644
  }));
645
645
  return { total: all.length, offset: o.offset, tokens: rows };
646
646
  }
647
+ var pct2 = (bps) => bps === null ? null : `${bps / 100} %`;
647
648
  var HOOK = ["not launched", "collecting", "redirect scheduled", "fees lost"];
648
649
  async function tokenInfo(c, vault) {
649
650
  const i = await createPayd({ vault: requireAddress("vault", vault), client: c }).info();
@@ -651,9 +652,13 @@ async function tokenInfo(c, vault) {
651
652
  ...i,
652
653
  symbol: untrusted(i.symbol),
653
654
  quote: i.quote === ZERO2 ? "native ETH" : i.quote,
655
+ // Spelled out: a model handed 873 next to totalFeeBps 1000 told holders
656
+ // "87.3 % of volume" (assistant eval, 2026-10-04). The real figure is 8.73 %.
657
+ holdersGetPercentOfVolume: pct2(i.rewardsOfVolumeBps),
658
+ creatorGetsPercentOfVolume: pct2(i.creatorOfVolumeBps),
654
659
  hookStatus: i.hookStatus === null ? null : { code: i.hookStatus, meaning: HOOK[i.hookStatus] },
655
660
  warning: i.hookStatus !== null && i.hookStatus !== 1 ? "Fees are not (or soon will not be) arriving at this launch. Say so; do not quote its percentages as current." : void 0,
656
- note: "rewardsOfVolumeBps is a share of TRADED VOLUME paid to holders as stock, not a yield. null means unread \u2014 hide it, never show 0."
661
+ note: "holdersGetPercentOfVolume is a share of TRADED VOLUME paid to holders as stock, not a yield; quote it as written, never recompute it from the bps fields. null means unread \u2014 hide it, never show 0."
657
662
  };
658
663
  }
659
664
  async function holderShares(c, vault, holder) {
@@ -1357,7 +1362,8 @@ var registryAbi2 = parseAbi4([
1357
1362
  "function listing(address stock) view returns (uint24 poolFee, address feed, bool allowed)",
1358
1363
  "function quoteListing(address quote) view returns (uint24 poolFee, uint24 wethFee, uint256 minBuy, bool allowed)",
1359
1364
  "function platformBps() view returns (uint256)",
1360
- "function isVault(address vault) view returns (bool)"
1365
+ "function isVault(address vault) view returns (bool)",
1366
+ "function vaults() view returns (address[])"
1361
1367
  ]);
1362
1368
  var vaultAbi2 = parseAbi4([
1363
1369
  "function bind(address token)",
@@ -1365,6 +1371,10 @@ var vaultAbi2 = parseAbi4([
1365
1371
  "function token() view returns (address)",
1366
1372
  "function QUOTE() view returns (address)"
1367
1373
  ]);
1374
+ var cycleAbi = parseAbi4([
1375
+ "function harvest() returns (uint256 gross)",
1376
+ "function buyBasket(uint256[] minOuts) returns (uint256 legsBought)"
1377
+ ]);
1368
1378
  var claimAbi = parseAbi4([
1369
1379
  "function claim(address[] stocks, uint256[] cumulative, bytes32[][] proofs) returns (uint256 delivered)"
1370
1380
  ]);
@@ -1485,10 +1495,49 @@ async function prepareClaim(c, i) {
1485
1495
  notes: ["Proofs are valid for the CURRENT root only; a new one is published every epoch. Sign and send now, or prepare again."]
1486
1496
  };
1487
1497
  }
1498
+ async function registryVault(c, v) {
1499
+ const vault = requireAddress("vault", v);
1500
+ if (!await c.readContract({ address: REGISTRY, abi: registryAbi2, functionName: "isVault", args: [vault] })) {
1501
+ throw new Error(`${vault} is not a vault the Payd registry built`);
1502
+ }
1503
+ return vault;
1504
+ }
1505
+ var PAYS = "An ETH-quoted vault refunds the caller's gas; any other quote pays a bounty in its own currency. A wallet that refuses ETH gets its refund set aside: collect it with the vault's withdraw().";
1506
+ async function prepareHarvest(c, i) {
1507
+ const vault = await registryVault(c, i.vault);
1508
+ return {
1509
+ ...await prepare(c, { from: requireAddress("from", i.from), to: vault, abi: cycleAbi, functionName: "harvest", args: [] }),
1510
+ notes: [PAYS]
1511
+ };
1512
+ }
1513
+ async function prepareBuyBasket(c, i) {
1514
+ const vault = await registryVault(c, i.vault);
1515
+ const legs = (await createPayd({ vault, client: c }).info()).basket.length;
1516
+ const minOuts = Array(legs).fill(0n);
1517
+ return {
1518
+ ...await prepare(c, { from: requireAddress("from", i.from), to: vault, abi: cycleAbi, functionName: "buyBasket", args: [minOuts] }),
1519
+ notes: [PAYS, "minOuts are zeros: the vault's own oracle floor bounds every leg. Do not loosen it \u2014 you cannot."]
1520
+ };
1521
+ }
1522
+ async function pendingWork(c, i) {
1523
+ const vaults = i.vault ? [await registryVault(c, i.vault)] : await c.readContract({ address: REGISTRY, abi: registryAbi2, functionName: "vaults" });
1524
+ const status = (p) => p.then(() => "ready", (e) => e.message);
1525
+ const rows = await Promise.all(vaults.map(async (vault) => ({
1526
+ vault,
1527
+ harvest: await status(prepareHarvest(c, { vault, from: i.from })),
1528
+ buyBasket: await status(prepareBuyBasket(c, { vault, from: i.from }))
1529
+ })));
1530
+ const ready = rows.filter((r) => r.harvest === "ready" || r.buyBasket === "ready");
1531
+ return {
1532
+ ready,
1533
+ idle: rows.length - ready.length,
1534
+ note: '"ready" means it simulated from `from` just now; another caller may land first, and NothingToDo is then the normal answer. Harvest before buyBasket. distribute() is not offered here: it needs the push tree.'
1535
+ };
1536
+ }
1488
1537
 
1489
1538
  // src/server.ts
1490
1539
  var client = makeClient();
1491
- var server = new McpServer({ name: "payd", version: "0.1.0" });
1540
+ var server = new McpServer({ name: "payd", version: "0.2.0" });
1492
1541
  var run = async (f) => {
1493
1542
  try {
1494
1543
  return { content: [{ type: "text", text: toJson(await f()) }] };
@@ -1562,4 +1611,20 @@ server.registerTool("payd_prepare_claim", {
1562
1611
  inputSchema: { vault: address, holder: address },
1563
1612
  annotations: PREPARE_HINTS
1564
1613
  }, (a) => run(() => prepareClaim(client, a)));
1614
+ var KEEPER = "Open to anyone and pays its caller (docs/SDK.md \xA79); it gives no say over where the money goes. ";
1615
+ server.registerTool("payd_pending_work", {
1616
+ description: "For keepers: which Payd vaults have a harvest or a buyBasket that would succeed right now, simulated from `from`. Omit vault to scan every launch. " + KEEPER,
1617
+ inputSchema: { from: address, vault: address.optional() },
1618
+ annotations: READ_ONLY
1619
+ }, (a) => run(() => pendingWork(client, a)));
1620
+ server.registerTool("payd_prepare_harvest", {
1621
+ description: "Pull a launch's creator fees out of the Pons escrow and split them. " + KEEPER + PREPARE,
1622
+ inputSchema: { vault: address, from: address },
1623
+ annotations: PREPARE_HINTS
1624
+ }, (a) => run(() => prepareHarvest(client, a)));
1625
+ server.registerTool("payd_prepare_buy_basket", {
1626
+ description: "Buy a launch's whole stock basket for every closed epoch not yet bought; slippage is bounded by the vault's own oracle floor. Harvest first. " + KEEPER + PREPARE,
1627
+ inputSchema: { vault: address, from: address },
1628
+ annotations: PREPARE_HINTS
1629
+ }, (a) => run(() => prepareBuyBasket(client, a)));
1565
1630
  await server.connect(new StdioServerTransport());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paydprotocol/mcp",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Keyless MCP server for Payd on Robinhood Chain: read launches, baskets and holder shares, and prepare unsigned transactions for your own wallet.",
5
5
  "type": "module",
6
6
  "license": "MIT",