@candledottv/mcp 0.10.20 → 0.10.21
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 +4 -2
- package/dist/index.js +90 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,8 +57,10 @@ Both take decimal amounts, never raw base units, and resolve the scale themselve
|
|
|
57
57
|
|
|
58
58
|
Both launch tools also take `mode: "exp-custom"` with `curve: { virtualQuote, threshold }`: a
|
|
59
59
|
Solana curve with your own V and G, in whole SOL or CNDL as decimal strings, inside limits the
|
|
60
|
-
API enforces and each tool's description states.
|
|
61
|
-
|
|
60
|
+
API enforces and each tool's description states. Any `exp-` mode takes `creatorFeeBps` (0, 100 or
|
|
61
|
+
200). Dry-run first: the dry run returns the launch preview (`curveTerms`: the curve's terms, the
|
|
62
|
+
share your own `buyAmount` takes, the fees and the migration terms) and `devBuyMax`, the dev-buy
|
|
63
|
+
ceiling that applies. `exp-custom` works only where the deployment has switched it on. See
|
|
62
64
|
[Custom curves](https://docs.candle.tv/developers/headless-launch#custom-curves-choose-v-and-g-switched-off).
|
|
63
65
|
|
|
64
66
|
For a full walkthrough of `candle_launch_and_seed` and `candle_trade`, including the keyless read
|
package/dist/index.js
CHANGED
|
@@ -151,7 +151,7 @@ import { lstat, open, realpath } from "node:fs/promises";
|
|
|
151
151
|
import { dirname, isAbsolute, relative, sep } from "node:path";
|
|
152
152
|
|
|
153
153
|
// src/version.ts
|
|
154
|
-
var SERVER_VERSION = "0.10.
|
|
154
|
+
var SERVER_VERSION = "0.10.21";
|
|
155
155
|
|
|
156
156
|
// src/update-notice.ts
|
|
157
157
|
var PLAIN_VERSION = /^\d+\.\d+\.\d+$/;
|
|
@@ -2474,18 +2474,55 @@ function perpsCandleWindow(opts, now) {
|
|
|
2474
2474
|
return usage(`interval must be one of ${PERPS_CANDLE_INTERVALS.join(" ")}.`);
|
|
2475
2475
|
const count = bounded(opts.count, 100, 1, 5000, "count");
|
|
2476
2476
|
const raw = opts.end;
|
|
2477
|
-
const endTime = raw === undefined ? now :
|
|
2477
|
+
const endTime = raw === undefined ? now : epoch(raw);
|
|
2478
2478
|
const startTime = endTime - count * at(INTERVAL_MS, index);
|
|
2479
2479
|
if (!Number.isSafeInteger(endTime) || endTime < 0 || endTime > now || startTime < 0)
|
|
2480
2480
|
return usage("end must be an ISO 8601 time or epoch milliseconds, no later than now.");
|
|
2481
2481
|
return { interval, count, startTime, endTime };
|
|
2482
2482
|
}
|
|
2483
|
+
function epoch(raw) {
|
|
2484
|
+
return typeof raw === "number" || /^\d+$/.test(raw) ? Number(raw) : /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})$/.test(raw) ? Date.parse(raw) : NaN;
|
|
2485
|
+
}
|
|
2486
|
+
var PERPS_FUNDING_HISTORY_MAX_MS = 30 * 86400000;
|
|
2487
|
+
var PERPS_FUNDING_HISTORY_MAX_ROWS = 500;
|
|
2488
|
+
function perpsFundingWindow(opts, now) {
|
|
2489
|
+
const endTime = opts.end === undefined ? now : epoch(opts.end);
|
|
2490
|
+
if (!Number.isSafeInteger(endTime) || endTime < 0 || endTime > now)
|
|
2491
|
+
return usage("end must be an ISO 8601 time or epoch milliseconds, no later than now.");
|
|
2492
|
+
const startTime = opts.start === undefined ? endTime - 86400000 : epoch(opts.start);
|
|
2493
|
+
if (!Number.isSafeInteger(startTime) || startTime < 0 || startTime > endTime)
|
|
2494
|
+
return usage("start must be an ISO 8601 time or epoch milliseconds, no later than end.");
|
|
2495
|
+
if (endTime - startTime > PERPS_FUNDING_HISTORY_MAX_MS)
|
|
2496
|
+
return usage("start must be at most 30 days before end.");
|
|
2497
|
+
return { startTime, endTime };
|
|
2498
|
+
}
|
|
2483
2499
|
function bounded(value, fallback, min, max, name) {
|
|
2484
2500
|
const n = value ?? fallback;
|
|
2485
2501
|
if (!Number.isInteger(n) || n < min || n > max)
|
|
2486
2502
|
return usage(`${name} must be an integer from ${min} to ${max}.`);
|
|
2487
2503
|
return n;
|
|
2488
2504
|
}
|
|
2505
|
+
function parsePerpsFundingHistory(value, coin, window) {
|
|
2506
|
+
if (!Array.isArray(value))
|
|
2507
|
+
return unavailable();
|
|
2508
|
+
const funding = [];
|
|
2509
|
+
for (const row of value) {
|
|
2510
|
+
if (!object(row) || row.coin !== coin || !integer(row.time) || !decimal2(row.fundingRate) || !decimal2(row.premium))
|
|
2511
|
+
return unavailable();
|
|
2512
|
+
if (row.time >= window.startTime && row.time <= window.endTime)
|
|
2513
|
+
funding.push({
|
|
2514
|
+
time: row.time,
|
|
2515
|
+
fundingRate: row.fundingRate,
|
|
2516
|
+
fundingAprPct: fixed(scaled(row.fundingRate) * 876000n, 2),
|
|
2517
|
+
premium: row.premium
|
|
2518
|
+
});
|
|
2519
|
+
}
|
|
2520
|
+
funding.sort((a, b) => a.time - b.time);
|
|
2521
|
+
return {
|
|
2522
|
+
funding: funding.slice(0, PERPS_FUNDING_HISTORY_MAX_ROWS),
|
|
2523
|
+
truncated: funding.length > PERPS_FUNDING_HISTORY_MAX_ROWS
|
|
2524
|
+
};
|
|
2525
|
+
}
|
|
2489
2526
|
|
|
2490
2527
|
class PerpsMarketReader {
|
|
2491
2528
|
opts;
|
|
@@ -2763,6 +2800,44 @@ class PerpsMarketReader {
|
|
|
2763
2800
|
candles: candles.slice(-window.count)
|
|
2764
2801
|
};
|
|
2765
2802
|
}
|
|
2803
|
+
async fundingHistory(coin, opts = {}) {
|
|
2804
|
+
this.key();
|
|
2805
|
+
const window = perpsFundingWindow(opts, this.now());
|
|
2806
|
+
const [config, core] = await Promise.all([this.config(), this.core()]);
|
|
2807
|
+
const canonical2 = at(core.universe, resolve(core, coin)).name;
|
|
2808
|
+
const value = await info(this.opts.fetcher, this.opts.network, {
|
|
2809
|
+
type: "fundingHistory",
|
|
2810
|
+
coin: canonical2,
|
|
2811
|
+
startTime: window.startTime,
|
|
2812
|
+
endTime: window.endTime
|
|
2813
|
+
});
|
|
2814
|
+
return {
|
|
2815
|
+
...this.envelope(config),
|
|
2816
|
+
coin: canonical2,
|
|
2817
|
+
startTime: window.startTime,
|
|
2818
|
+
endTime: window.endTime,
|
|
2819
|
+
...parsePerpsFundingHistory(value, canonical2, window)
|
|
2820
|
+
};
|
|
2821
|
+
}
|
|
2822
|
+
async predictedFunding() {
|
|
2823
|
+
this.key();
|
|
2824
|
+
const [config, core, extras] = await Promise.all([this.config(), this.core(), this.extras()]);
|
|
2825
|
+
if (extras.predicted === null)
|
|
2826
|
+
return unavailable();
|
|
2827
|
+
const predicted = [];
|
|
2828
|
+
for (const meta of core.universe) {
|
|
2829
|
+
const row = extras.predicted.get(meta.name);
|
|
2830
|
+
if (row)
|
|
2831
|
+
predicted.push({
|
|
2832
|
+
coin: meta.name,
|
|
2833
|
+
fundingRate: row.fundingRate,
|
|
2834
|
+
fundingAprPct: fixed(scaled(row.fundingRate) * 876000n, 2),
|
|
2835
|
+
nextFundingTime: row.nextFundingTime
|
|
2836
|
+
});
|
|
2837
|
+
}
|
|
2838
|
+
predicted.sort((a, b) => a.coin < b.coin ? -1 : a.coin > b.coin ? 1 : 0);
|
|
2839
|
+
return { ...this.envelope(config, extras.warnings, this.extrasCache?.at ?? this.now()), predicted };
|
|
2840
|
+
}
|
|
2766
2841
|
}
|
|
2767
2842
|
|
|
2768
2843
|
// src/perps-history.ts
|
|
@@ -4570,7 +4645,7 @@ function planTableMarkdown(table) {
|
|
|
4570
4645
|
|
|
4571
4646
|
// src/tools.ts
|
|
4572
4647
|
var VAMP_CANDIDATES_DESCRIPTION = "Lists Solana tokens that are close to graduating or graduated in the last 6 hours whose ticker other tokens " + "are copying, most-copied in the last 24 hours first. Each entry carries a launch draft (name, ticker, image URL) " + "for `candle_launch_token` or `candle_launch_and_seed`; draft notes identify fields you must supply or adjust. " + "Upload your own image through the agent image upload when the image is unavailable. Use `dryRun: true` first. " + "Counts exclude the candidate itself and cover both Solana and Hood launches at the venues returned in " + "`coverage`, not Candle's own. `coverage.since` is the returned Solana coverage date; Hood history may differ.";
|
|
4573
|
-
var CUSTOM_CURVE_RULE = 'mode "exp-custom" with curve { virtualQuote, threshold } launches a Solana curve with your own V (the virtual ' + "quote it starts with) and G (the quote it raises before graduating), in whole SOL or CNDL as decimal strings, " + "accepted when V is 1 to 100 SOL and G 1 to 250 SOL (66,000 to 6,600,000 and 66,000 to 16,500,000 CNDL), when " + "every price up to 20 x G stays under the ceiling (V + 20G)^2 < V x X at this stakerAllocationBps, when neither " + "is finer than the quote's decimals, and when the dev buy is at most 10% of G; a curve past a limit is " + "CURVE_OUT_OF_RANGE, and at the ceiling it carries maxThresholdRaw, the largest G that fits. " + "Dry-run it first (dryRun: true): the dry run spends nothing and returns curveTerms, the market cap at start and " + "at graduation
|
|
4648
|
+
var CUSTOM_CURVE_RULE = 'mode "exp-custom" with curve { virtualQuote, threshold } launches a Solana curve with your own V (the virtual ' + "quote it starts with) and G (the quote it raises before graduating), in whole SOL or CNDL as decimal strings, " + "accepted when V is 1 to 100 SOL and G 1 to 250 SOL (66,000 to 6,600,000 and 66,000 to 16,500,000 CNDL), when " + "every price up to 20 x G stays under the ceiling (V + 20G)^2 < V x X at this stakerAllocationBps, when neither " + "is finer than the quote's decimals, and when the dev buy is at most 0.5 SOL (2,000,000 CNDL), or 10% of G when " + "that is lower (every exp- mode; an operator may set the 0.5 SOL lower); a curve past a limit is " + "CURVE_OUT_OF_RANGE, and at the ceiling it carries maxThresholdRaw, the largest G that fits. " + "Dry-run it first (dryRun: true): the dry run spends nothing and returns curveTerms, the market cap at start and " + "at graduation, the supply sold by graduation, the share your own buyAmount takes, the fees and the migration " + "terms, and devBuyMax, the dev-buy ceiling that applies. Only where the API has EXP_CUSTOM_CURVES on; " + "elsewhere exp-custom is refused as an unknown mode.";
|
|
4574
4649
|
var localProfileTools = new WeakMap;
|
|
4575
4650
|
var STAKING_DISCLOSURE = "No instant unstake. Read pool.withdrawalTimelockSeconds for the wait. Solana rewards accrue to the holding wallet. sCNDL in any eligible account wallet counts toward Pro and earns the account's Hood staking reward, except a wallet another account also claims, wallets past the 200-wallet cap, and an account with no EVM wallet. CNDL in a pending withdrawal counts toward nothing for Pro.";
|
|
4576
4651
|
var stakingWriteShape = {
|
|
@@ -5003,12 +5078,23 @@ var launchTokenShape = {
|
|
|
5003
5078
|
bannerUrl: z4.string().optional().describe("Optional https URL to WIDE artwork for the token page's banner strip (wider than 1.5:1, " + "e.g. 1200x630). This is where a share card or OG image belongs. A square image here is " + "rejected with BANNER_WRONG_SHAPE: send the wide original, not a cropped copy. Omit it and the strip " + "falls back to imageUrl"),
|
|
5004
5079
|
chain: z4.string().optional().describe('"solana" or "hood"; defaults to solana'),
|
|
5005
5080
|
quoteAsset: z4.string().optional().describe("Quote asset symbol; defaults per chain"),
|
|
5006
|
-
mode: z4.string().optional().describe('"open" or "exclusive"; defaults to open. "test-open" / "test-exclusive" launch the ' + "low-threshold test curves (~1/80 economics) where the API has ENABLE_TEST_CURVES on. " + '"exp-custom" launches a Solana curve with your own V and G, given in curve, where the API has it ' + "switched on"),
|
|
5081
|
+
mode: z4.string().optional().describe('"open" or "exclusive"; defaults to open. "test-open" / "test-exclusive" launch the ' + "low-threshold test curves (~1/80 economics) where the API has ENABLE_TEST_CURVES on. " + '"exp-a", "exp-b" and "exp-c" are the experimental fast Solana curves (sol or cndl). ' + '"exp-custom" launches a Solana curve with your own V and G, given in curve, where the API has it ' + "switched on"),
|
|
5007
5082
|
curve: z4.object({
|
|
5008
5083
|
virtualQuote: z4.string().describe('V: the virtual quote the curve starts with, in whole quote units, e.g. "12" SOL'),
|
|
5009
5084
|
threshold: z4.string().describe('G: the quote the curve raises before it graduates, in whole quote units, e.g. "40" SOL')
|
|
5010
5085
|
}).strict().optional().describe('mode "exp-custom" only, and required there. Decimal strings in whole units of the quote asset (sol or ' + "cndl), never raw units. Dry-run first: the API checks the limits and returns the curve's terms"),
|
|
5086
|
+
creatorFeeBps: z4.union([z4.literal(0), z4.literal(100), z4.literal(200)]).optional().describe("An exp- mode only: an extra creator fee of 100 or 200 basis points on top of the curve's 1% and the " + "pool's 0.5%, paid to the creator in full. 0 is the same as leaving it out"),
|
|
5011
5087
|
stakerAllocationBps: z4.number().optional().describe("Staker allocation in basis points"),
|
|
5088
|
+
poolFee: z4.union([
|
|
5089
|
+
z4.object({ tier: z4.union([z4.literal(25), z4.literal(50), z4.literal(100)]) }).strict(),
|
|
5090
|
+
z4.object({
|
|
5091
|
+
startBps: z4.number().int().max(2500),
|
|
5092
|
+
endBps: z4.union([z4.literal(25), z4.literal(50), z4.literal(100)]),
|
|
5093
|
+
minutes: z4.number().positive().max(30)
|
|
5094
|
+
}).strict()
|
|
5095
|
+
]).optional().describe("Solana only: the graduated pool's fee. { tier: 25 | 50 | 100 } is a flat fee in bps (default 50), or " + "{ startBps, endBps, minutes } is an anti-snipe fall from startBps (at most 2500, at least endBps) to " + "endBps (25, 50 or 100) over minutes (at most 30). Cannot be combined with creatorFeeBps unless the tier is 50. " + "Omit for the standard 50 bps pool"),
|
|
5096
|
+
poolOpen: z4.enum(["legacy", "curve_price"]).optional().describe(`Solana preset tiers only. "curve_price" opens the pool at the curve's last price (the whole reserve is ` + "seeded and the remaining base burned); stakerAllocationBps plus the team allocation must fit the tier's limit, " + "which the dry run returns as graduation.maxStakerCarveBps. Omit for legacy"),
|
|
5097
|
+
expPoolShape: z4.enum(["floor", "full_range"]).optional().describe('Solana exp- curves only. "full_range" opens the pool across the whole price range. Omit for floor'),
|
|
5012
5098
|
dexVersion: z4.string().nullable().optional().describe('"v3" or "v4"; required for hood launches'),
|
|
5013
5099
|
buyAmount: z4.union([z4.string(), z4.number()]).optional().describe("Initial buy, in quote base units (string or number)"),
|
|
5014
5100
|
description: z4.string().optional(),
|