@arcnow/mcp 0.1.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.
Files changed (71) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +624 -0
  3. package/dist/client-options.d.ts +16 -0
  4. package/dist/client-options.d.ts.map +1 -0
  5. package/dist/client-options.js +22 -0
  6. package/dist/client-options.js.map +1 -0
  7. package/dist/config.d.ts +223 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +516 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/format.d.ts +79 -0
  12. package/dist/format.d.ts.map +1 -0
  13. package/dist/format.js +164 -0
  14. package/dist/format.js.map +1 -0
  15. package/dist/index.d.ts +17 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +50 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/sdk-port.d.ts +227 -0
  20. package/dist/sdk-port.d.ts.map +1 -0
  21. package/dist/sdk-port.js +144 -0
  22. package/dist/sdk-port.js.map +1 -0
  23. package/dist/server.d.ts +25 -0
  24. package/dist/server.d.ts.map +1 -0
  25. package/dist/server.js +103 -0
  26. package/dist/server.js.map +1 -0
  27. package/dist/tools/errors.d.ts +44 -0
  28. package/dist/tools/errors.d.ts.map +1 -0
  29. package/dist/tools/errors.js +231 -0
  30. package/dist/tools/errors.js.map +1 -0
  31. package/dist/tools/index.d.ts +35 -0
  32. package/dist/tools/index.d.ts.map +1 -0
  33. package/dist/tools/index.js +59 -0
  34. package/dist/tools/index.js.map +1 -0
  35. package/dist/tools/launch-params.d.ts +27 -0
  36. package/dist/tools/launch-params.d.ts.map +1 -0
  37. package/dist/tools/launch-params.js +29 -0
  38. package/dist/tools/launch-params.js.map +1 -0
  39. package/dist/tools/pool.d.ts +84 -0
  40. package/dist/tools/pool.d.ts.map +1 -0
  41. package/dist/tools/pool.js +249 -0
  42. package/dist/tools/pool.js.map +1 -0
  43. package/dist/tools/quote.d.ts +53 -0
  44. package/dist/tools/quote.d.ts.map +1 -0
  45. package/dist/tools/quote.js +85 -0
  46. package/dist/tools/quote.js.map +1 -0
  47. package/dist/tools/read.d.ts +26 -0
  48. package/dist/tools/read.d.ts.map +1 -0
  49. package/dist/tools/read.js +920 -0
  50. package/dist/tools/read.js.map +1 -0
  51. package/dist/tools/resolve.d.ts +45 -0
  52. package/dist/tools/resolve.d.ts.map +1 -0
  53. package/dist/tools/resolve.js +75 -0
  54. package/dist/tools/resolve.js.map +1 -0
  55. package/dist/tools/schema.d.ts +98 -0
  56. package/dist/tools/schema.d.ts.map +1 -0
  57. package/dist/tools/schema.js +143 -0
  58. package/dist/tools/schema.js.map +1 -0
  59. package/dist/tools/spend.d.ts +45 -0
  60. package/dist/tools/spend.d.ts.map +1 -0
  61. package/dist/tools/spend.js +99 -0
  62. package/dist/tools/spend.js.map +1 -0
  63. package/dist/tools/venue.d.ts +67 -0
  64. package/dist/tools/venue.d.ts.map +1 -0
  65. package/dist/tools/venue.js +110 -0
  66. package/dist/tools/venue.js.map +1 -0
  67. package/dist/tools/write.d.ts +56 -0
  68. package/dist/tools/write.d.ts.map +1 -0
  69. package/dist/tools/write.js +950 -0
  70. package/dist/tools/write.js.map +1 -0
  71. package/package.json +55 -0
package/dist/format.js ADDED
@@ -0,0 +1,164 @@
1
+ /**
2
+ * How numbers and addresses reach the model.
3
+ *
4
+ * # Every amount is printed with its own quote token, every time
5
+ *
6
+ * A curve is priced in one quote token for life: native USDC (18 decimals, the
7
+ * gas currency) or an allowlisted ERC-20 such as EURC (6 decimals). An amount
8
+ * is a `QuoteAmount` from the SDK, which carries the token it is denominated
9
+ * in, so a figure is always printed as `1.5 EURC` or `25 USDC` — the symbol of
10
+ * the quote it is actually in, never "USDC" for a EURC amount.
11
+ *
12
+ * On Arc, native USDC is 18-decimal and the USDC ERC-20 predeploy is the same
13
+ * asset at **6**. A bare `1000000` is a dollar under one reading and a
14
+ * millionth of a dollar under the other, which is why nothing here ever emits
15
+ * a bare number for money.
16
+ *
17
+ * # Text, not structured content
18
+ *
19
+ * Every tool returns one readable report. There is no parallel
20
+ * `structuredContent` payload, and that is a choice: two renderings of the same
21
+ * numbers is two places for a unit to be wrong, and only one of them is the one
22
+ * a person reads when they check what the assistant was told. The report
23
+ * carries exact decimal strings, so nothing is lost to rounding on the way.
24
+ *
25
+ * @module
26
+ */
27
+ import { getAddress } from "viem";
28
+ import { QuoteAmount, WAD } from "@arcnow/sdk";
29
+ /** The zero address, which on Arc is a real account, not a null. */
30
+ export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
31
+ /** `123.75 USDC`, `1.5 EURC`: always with the symbol of the quote the amount is in. */
32
+ export function money(amount) {
33
+ return amount.format();
34
+ }
35
+ /** Money plus its raw integers, for anything that has to be exact. */
36
+ export function moneyExact(amount) {
37
+ const raw = amount.isRepresentable() ? `, ${amount.toRaw()} raw at ${amount.token.decimals} decimals` : "";
38
+ return `${amount.format()} (${amount.wad} wad${raw})`;
39
+ }
40
+ export function qty(amount, symbol) {
41
+ return symbol === undefined ? amount.toString() : `${amount.toString()} ${symbol}`;
42
+ }
43
+ /** A price is the quote **per whole token**; saying so every time is the point. */
44
+ export function price(p) {
45
+ return `${p.toString()} ${p.token.symbol} per token`;
46
+ }
47
+ /**
48
+ * One quote token, said in full: `EURC — ERC-20 0x89b5…, 6 decimals` or
49
+ * `USDC — native (the gas currency, paid as msg.value), 18 decimals`.
50
+ */
51
+ export function quoteLine(token) {
52
+ return token.isNative
53
+ ? `${token.symbol} — native, the gas currency, paid as msg.value (${addr(token.address)}), `
54
+ + `${token.decimals} decimals`
55
+ : `${token.symbol} (${token.name}) — ERC-20 at ${addr(token.address)}, ${token.decimals} decimals, `
56
+ + "pulled with an exact ERC-20 approval";
57
+ }
58
+ /** Checksummed, because that is the form a person pastes back. */
59
+ export function addr(value) {
60
+ try {
61
+ return getAddress(value);
62
+ }
63
+ catch {
64
+ return value;
65
+ }
66
+ }
67
+ /** A share of the fee, said both ways — the single easiest thing to misread. */
68
+ export function share(bps, tradeFeeBps) {
69
+ return `${bps.bps} bps of the fee (${bps.percentOfFee()}% of the fee, `
70
+ + `${bps.percentOfTrade(tradeFeeBps)}% of a trade)`;
71
+ }
72
+ /** Graduation progress. `progressBps` is out of 10,000, not out of 100. */
73
+ export function progress(bps) {
74
+ const percent = Number(bps.bps) / 100;
75
+ return `${percent.toFixed(2)}% (${bps.bps} / 10000 bps)`;
76
+ }
77
+ /**
78
+ * The average price a whole order actually filled at.
79
+ *
80
+ * Not the same number as `spotPrice`, which is the marginal price of the next
81
+ * infinitesimal token. The curve integrates price across an order, so a buyer
82
+ * pays a rising price over their own trade and this is what they paid.
83
+ */
84
+ export function effectivePrice(spent, received) {
85
+ if (received.wad === 0n)
86
+ return undefined;
87
+ return QuoteAmount.fromWad(spent.token, (spent.wad * WAD) / received.wad);
88
+ }
89
+ /** Percentage difference between two prices in the same quote, as a signed string. */
90
+ export function priceMove(from, to) {
91
+ if (from.wad === 0n)
92
+ return "n/a (the curve had no price to move from)";
93
+ const deltaBps = ((to.wad - from.wad) * 10000n) / from.wad;
94
+ const percent = Number(deltaBps) / 100;
95
+ return `${percent >= 0 ? "+" : ""}${percent.toFixed(4)}%`;
96
+ }
97
+ /**
98
+ * Which venue a migrator address is, by asking the deployment rather than
99
+ * assuming. A token graduates to the migrator **its own curve snapshotted at
100
+ * launch**, which need not be the one this network would choose today.
101
+ */
102
+ export function venueOf(migrator, config) {
103
+ const known = [
104
+ [config.contracts.v4Migrator, "Uniswap v4"],
105
+ [config.contracts.v3Migrator, "Uniswap v3"],
106
+ [config.contracts.v2Migrator, "Uniswap v2"],
107
+ [config.contracts.escrowMigrator, "escrow (custodial)"],
108
+ ];
109
+ const lower = migrator.toLowerCase();
110
+ for (const [address, name] of known) {
111
+ if (address !== undefined && address.toLowerCase() === lower)
112
+ return name;
113
+ }
114
+ if (migrator.toLowerCase() === ZERO_ADDRESS) {
115
+ return "none — the zero address, which on Arc is a real account and not a null";
116
+ }
117
+ return "an address this deployment's preset does not name — verify it before trusting it";
118
+ }
119
+ // ── the curve ──────────────────────────────────────────────────────────────
120
+ /**
121
+ * A curve's immutable parameters. arcnow.io has one curve, the constant-product
122
+ * `arcnow/bonding-curve@3.x.x`, and the SDK prices no other: `r0Wad` is its
123
+ * virtual quote reserve at launch, in 18-decimal WAD of its quote token, and
124
+ * `y0Wad` its virtual token reserve at launch.
125
+ */
126
+ export function curveParamsLine(params, quote) {
127
+ return `r0Wad ${params.r0Wad} (the virtual ${quote.symbol} reserve at launch, in WAD), `
128
+ + `y0Wad ${params.y0Wad} (the virtual token reserve at launch) — immutable`;
129
+ }
130
+ /** A titled block of `label value` lines. */
131
+ export function section(title, rows) {
132
+ const width = rows.reduce((w, [label]) => Math.max(w, label.length), 0);
133
+ const body = rows.map(([label, value]) => ` ${label.padEnd(width)} ${value}`).join("\n");
134
+ return `${title}\n${body}`;
135
+ }
136
+ /** Joins sections with a blank line, dropping the ones that had nothing to say. */
137
+ export function report(...parts) {
138
+ return parts.filter((p) => p !== undefined && p !== "").join("\n\n");
139
+ }
140
+ /** A paragraph the model is meant to act on, set apart from the figures. */
141
+ export function note(text) {
142
+ return wrap(text, 88);
143
+ }
144
+ function wrap(text, width) {
145
+ const out = [];
146
+ for (const paragraph of text.split("\n")) {
147
+ let line = "";
148
+ for (const word of paragraph.split(/\s+/)) {
149
+ if (line === "") {
150
+ line = word;
151
+ }
152
+ else if (line.length + 1 + word.length <= width) {
153
+ line += ` ${word}`;
154
+ }
155
+ else {
156
+ out.push(line);
157
+ line = word;
158
+ }
159
+ }
160
+ out.push(line);
161
+ }
162
+ return out.join("\n");
163
+ }
164
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The entry point: read the configuration, say what mode it produced, connect.
4
+ *
5
+ * # stdout belongs to the protocol
6
+ *
7
+ * An MCP stdio server speaks JSON-RPC over stdout. One stray byte there — a
8
+ * `console.log`, a library's banner, a warning — corrupts a frame and the
9
+ * client's connection with it. So **everything** this process says to a human
10
+ * goes to stderr, and the rule holds for the whole codebase: there is no
11
+ * `console.log` anywhere in `src/`, and the tools return text to the client
12
+ * rather than printing it.
13
+ *
14
+ * @module
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG"}
package/dist/index.js ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The entry point: read the configuration, say what mode it produced, connect.
4
+ *
5
+ * # stdout belongs to the protocol
6
+ *
7
+ * An MCP stdio server speaks JSON-RPC over stdout. One stray byte there — a
8
+ * `console.log`, a library's banner, a warning — corrupts a frame and the
9
+ * client's connection with it. So **everything** this process says to a human
10
+ * goes to stderr, and the rule holds for the whole codebase: there is no
11
+ * `console.log` anywhere in `src/`, and the tools return text to the client
12
+ * rather than printing it.
13
+ *
14
+ * @module
15
+ */
16
+ import { createArcNowClient } from "@arcnow/sdk";
17
+ import { clientOptionsFor } from "./client-options.js";
18
+ import { ConfigError, loadConfig, startupBanner } from "./config.js";
19
+ import { createSdkPort } from "./sdk-port.js";
20
+ import { createServer } from "./server.js";
21
+ async function main() {
22
+ const config = loadConfig(process.env, process.argv.slice(2));
23
+ process.stderr.write(`${startupBanner(config)}\n`);
24
+ const client = createArcNowClient(clientOptionsFor(config));
25
+ // Asked once, up front, and reported rather than fatal: an endpoint that is
26
+ // briefly unreachable should not stop the server from starting, but a client
27
+ // pointed at the wrong chain should find out now and not from a transaction.
28
+ try {
29
+ await client.verifyChain();
30
+ }
31
+ catch (error) {
32
+ process.stderr.write(` warning the endpoint could not be verified as chain ${config.network}: `
33
+ + `${error instanceof Error ? error.message : String(error)}\n`
34
+ + " Tools will report this again when they are called.\n");
35
+ }
36
+ const port = createSdkPort(client, config.logScan);
37
+ const server = createServer(port, config);
38
+ const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
39
+ await server.connect(new StdioServerTransport());
40
+ process.stderr.write(" ready listening on stdio\n");
41
+ }
42
+ main().catch((error) => {
43
+ if (error instanceof ConfigError) {
44
+ process.stderr.write(`arcnow.io MCP server cannot start.\n\n${error.message}\n`);
45
+ process.exit(2);
46
+ }
47
+ process.stderr.write(`arcnow.io MCP server failed: ${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
48
+ process.exit(1);
49
+ });
50
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAEnD,MAAM,MAAM,GAAG,kBAAkB,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;IAE5D,4EAA4E;IAC5E,6EAA6E;IAC7E,6EAA6E;IAC7E,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,6DAA6D,MAAM,CAAC,OAAO,IAAI;cAC7E,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI;cAC7D,oEAAoE,CACvE,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAE1C,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,MAAM,CAC3C,2CAA2C,CAC5C,CAAC;IACF,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;IACjD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;AAC7D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;QACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yCAAyC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;QACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gCAAgC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAC1G,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,227 @@
1
+ /**
2
+ * The seam between the tools and `@arcnow/sdk`.
3
+ *
4
+ * # Why there is a seam at all
5
+ *
6
+ * Every chain interaction in this server goes through the SDK. Nothing here
7
+ * encodes a call, computes a curve, or knows an address: the SDK owns all of
8
+ * that, it is pinned to a commit in `pins.json`, and it is the thing the
9
+ * project's forked-chain suite actually tests. Reimplementing any of it here
10
+ * would produce a second, unpinned, untested copy of the most expensive code in
11
+ * the project to get wrong.
12
+ *
13
+ * What this file adds is a set of **interfaces the SDK's handles already
14
+ * satisfy**. The SDK's `Curve`, `Token`, `Trade`, `Pool`, `Launchpad` and `PlatformRegistry` are
15
+ * classes with private fields, which means a test cannot construct a stand-in
16
+ * for one — not because faking them is difficult, but because a class with a
17
+ * `private` member is nominally typed and nothing else is assignable to it. So
18
+ * the tools depend on {@link ArcNowPort}, {@link CurveHandle} and friends, and
19
+ * {@link createSdkPort} is the one place that mentions the SDK's classes.
20
+ *
21
+ * That buys the whole suite: a fake port drives every tool through every
22
+ * branch — a graduating buy, a stale quote, a cost over the ceiling, a curve
23
+ * that already migrated — with no chain, no container and no key. The seam is
24
+ * type-level only; it wraps nothing and computes nothing.
25
+ *
26
+ * The types crossing it are the SDK's own: {@link QuoteAmount}, {@link Tokens},
27
+ * {@link Bps}, `CurveState`, `BuyQuote`. Re-describing those would be exactly
28
+ * the reimplementation this file exists to avoid, and the amount types in
29
+ * particular are the reason an amount of EURC cannot be read as USDC, and the
30
+ * 18-decimal native USDC cannot be confused with the 6-decimal ERC-20 view.
31
+ *
32
+ * @module
33
+ */
34
+ import type { Address, Hash } from "viem";
35
+ import { type ArcNowClient, type Bps, type BuyQuote, type BuyRequest, type BuyResult, type CurveState, type CurveTemplateParams, type FeeConfig, type FeeSplit, type LaunchParams, type LaunchQuote, type LaunchResult, type MigrateResult, type NetworkConfig, type NewPlatform, type PlatformSettings, type PoolBuyQuote, type PoolKeyStruct, QuoteAmount, type QuoteFrom, type QuoteRegistryEntry, type QuoteTokenInfo, type RegisterPlatformResult, type SellQuote, type SellRequest, type SellResult, type SpendState, Tokens, type TradeBuyQuote, type TradeBuyRequest, type TradeBuyResult, type TradeSellQuote, type TradeSellRequest, type TradeSellResult, type Venue } from "@arcnow/sdk";
36
+ /**
37
+ * One graduated token's Uniswap v4 pool: `client.pool(token)`, and the `pool`
38
+ * half of `client.trade(token)`.
39
+ *
40
+ * Only what the tools read or do. Notably absent: `buy` and `sell`, which the
41
+ * tools reach through {@link TradeHandle} so that the venue is decided by the
42
+ * SDK, in one place, and never by this server.
43
+ */
44
+ export interface PoolHandle {
45
+ readonly token: Address;
46
+ key(): Promise<PoolKeyStruct>;
47
+ poolId(): Promise<`0x${string}`>;
48
+ /** The PoolManager the liquidity is in. A v4 pool has no address of its own. */
49
+ poolManager(): Promise<Address>;
50
+ /** False with no router configured, or when the router serves another manager. */
51
+ isReachable(): Promise<boolean>;
52
+ /**
53
+ * The pool's quote token: the key's currency that is not the token, whichever
54
+ * of `currency0` and `currency1` that is. Never assume it is `currency0`.
55
+ */
56
+ quoteToken(): Promise<QuoteTokenInfo>;
57
+ /** True when the quote is the key's `currency0`: always for native USDC, either for an ERC-20. */
58
+ quoteIsCurrency0(): Promise<boolean>;
59
+ quoteBuy(quoteIn: QuoteAmount, opts?: QuoteFrom): Promise<PoolBuyQuote>;
60
+ routerAllowance(owner: Address): Promise<Tokens>;
61
+ /** A separate transaction, granting the router spending rights over `amount`. */
62
+ approveRouter(amount: Tokens): Promise<`0x${string}`>;
63
+ /**
64
+ * What the pool's fee hook has charged and not yet paid out, in the pool's quote.
65
+ * `UnknownHookVersion` for a hook that is not `arcnow/arc-now-fee-hook@3.x.x`.
66
+ */
67
+ accruedHookFee(): Promise<QuoteAmount>;
68
+ }
69
+ /**
70
+ * `client.trade(token)`: a token traded wherever it currently trades.
71
+ *
72
+ * The write tools send every buy and sell through this, curve or pool, so the
73
+ * SDK's own refusals — a `recipient` on a curve, a `referrer`, `developer` or
74
+ * `gasLimit` on a pool — stand behind this server's.
75
+ */
76
+ export interface TradeHandle {
77
+ readonly token: Address;
78
+ readonly pool: PoolHandle;
79
+ venue(): Promise<Venue>;
80
+ /** The quote token this token trades against for life, read off its curve. */
81
+ quoteToken(): Promise<QuoteTokenInfo>;
82
+ quoteBuy(quoteIn: QuoteAmount, opts?: {
83
+ readonly from?: Address | undefined;
84
+ }): Promise<TradeBuyQuote>;
85
+ quoteSell(tokensIn: Tokens, opts?: {
86
+ readonly from?: Address | undefined;
87
+ }): Promise<TradeSellQuote>;
88
+ buy(request: TradeBuyRequest): Promise<TradeBuyResult>;
89
+ sell(request: TradeSellRequest): Promise<TradeSellResult>;
90
+ }
91
+ /** One `Launchpad.Launched` log, decoded. */
92
+ export interface LaunchRecord {
93
+ readonly token: Address;
94
+ readonly curve: Address;
95
+ readonly creator: Address;
96
+ readonly platform: Address;
97
+ readonly migrator: Address;
98
+ /**
99
+ * The quote the token launched in, from the log's own `quoteToken` field and
100
+ * labelled from the network's `quoteTokens` — no RPC — or, for a quote the
101
+ * network does not list, the SDK's per-process cached metadata read.
102
+ */
103
+ readonly quoteToken: QuoteTokenInfo;
104
+ readonly launchFee: QuoteAmount;
105
+ readonly initialBuy: QuoteAmount;
106
+ readonly tokensOut: Tokens;
107
+ readonly blockNumber: bigint;
108
+ readonly txHash: Hash;
109
+ }
110
+ /** What a launch scan looked at, so a caller is never told more than was seen. */
111
+ export interface LaunchScan {
112
+ readonly launches: readonly LaunchRecord[];
113
+ readonly tipBlock: bigint;
114
+ readonly scannedFromBlock: bigint;
115
+ readonly scannedToBlock: bigint;
116
+ /** True when the scan reached the block the deployment starts at. */
117
+ readonly reachedDeployment: boolean;
118
+ /** True when the scan stopped on its chunk budget with history left unread. */
119
+ readonly stoppedOnBudget: boolean;
120
+ }
121
+ export interface ListLaunchesOptions {
122
+ readonly limit: number;
123
+ readonly creator?: Address | undefined;
124
+ readonly token?: Address | undefined;
125
+ }
126
+ export interface CurveHandle {
127
+ readonly address: Address;
128
+ state(): Promise<CurveState>;
129
+ quoteBuy(quoteIn: QuoteAmount): Promise<BuyQuote>;
130
+ quoteSell(tokensIn: Tokens): Promise<SellQuote>;
131
+ previewFeeSplit(fee: QuoteAmount, referrer?: Address, developer?: Address): Promise<FeeSplit>;
132
+ feeConfig(): Promise<FeeConfig>;
133
+ pendingWithdrawal(account: Address): Promise<QuoteAmount>;
134
+ buy(request: BuyRequest): Promise<BuyResult>;
135
+ sell(request: SellRequest): Promise<SellResult>;
136
+ migrate(): Promise<MigrateResult>;
137
+ withdraw(to: Address): Promise<{
138
+ amount: QuoteAmount;
139
+ txHash: Hash;
140
+ }>;
141
+ }
142
+ export interface TokenHandle {
143
+ readonly address: Address;
144
+ name(): Promise<string>;
145
+ symbol(): Promise<string>;
146
+ metadataUri(): Promise<string>;
147
+ totalSupply(): Promise<Tokens>;
148
+ balanceOf(account: Address): Promise<Tokens>;
149
+ creator(): Promise<Address>;
150
+ curve(): Promise<Address>;
151
+ migratedPool(): Promise<Address>;
152
+ canonicalRouter(): Promise<Address>;
153
+ }
154
+ export interface LaunchpadHandle {
155
+ readonly address: Address;
156
+ /** The flat launch fee in `quote` (native USDC when omitted), from the quote registry. */
157
+ launchFee(quote?: Address): Promise<QuoteAmount>;
158
+ quoteLaunch(params: LaunchParams): Promise<LaunchQuote>;
159
+ predictAddresses(creator: Address, params: LaunchParams): Promise<{
160
+ token: Address;
161
+ curve: Address;
162
+ }>;
163
+ launch(params: LaunchParams): Promise<LaunchResult>;
164
+ }
165
+ export interface PlatformsHandle {
166
+ readonly address: Address;
167
+ isPlatform(platform: Address): Promise<boolean>;
168
+ platformCount(): Promise<bigint>;
169
+ platformAt(index: bigint): Promise<Address>;
170
+ settings(platform: Address): Promise<PlatformSettings>;
171
+ feeConfigFor(platform: Address): Promise<FeeConfig>;
172
+ checkCurveTemplate(template: CurveTemplateParams, platform?: Address): Promise<void>;
173
+ /**
174
+ * The template `platform` serves launches in `quote`. `NoCurveParameters` when
175
+ * the platform has not enabled that quote.
176
+ */
177
+ curveParametersFor(platform: Address, quote?: Address | QuoteTokenInfo): Promise<CurveTemplateParams>;
178
+ registerPlatform(platform: NewPlatform): Promise<RegisterPlatformResult>;
179
+ protocolSummary(): Promise<{
180
+ protocolShareBps: Bps;
181
+ protocolRecipient: Address;
182
+ launchFee: QuoteAmount;
183
+ }>;
184
+ }
185
+ /** `client.quoteRegistry`: the allowlist of quote tokens a launch may use. */
186
+ export interface QuoteRegistryHandle {
187
+ /** Every registered quote, in at most three `eth_call`s. */
188
+ list(): Promise<readonly QuoteRegistryEntry[]>;
189
+ }
190
+ /** Everything the tools are allowed to reach. */
191
+ export interface ArcNowPort {
192
+ readonly config: NetworkConfig;
193
+ readonly canWrite: boolean;
194
+ readonly signerAddress: Address | undefined;
195
+ curve(address: Address): CurveHandle;
196
+ token(address: Address): TokenHandle;
197
+ /** The token wherever it trades: `client.trade(token)`. Every buy and sell goes through it. */
198
+ trade(token: Address): TradeHandle;
199
+ readonly launchpad: LaunchpadHandle;
200
+ readonly platforms: PlatformsHandle;
201
+ readonly quoteRegistry: QuoteRegistryHandle;
202
+ /**
203
+ * What `owner` holds of a quote token and, for an ERC-20 with a `spender`
204
+ * named, what it has approved that spender for — in ONE Multicall3 `eth_call`
205
+ * (`client.quoteToken(token).spendState`). Native USDC is the account's native
206
+ * balance and has no allowance.
207
+ */
208
+ quoteSpendState(token: QuoteTokenInfo, owner: Address, spender?: Address): Promise<SpendState>;
209
+ /**
210
+ * A quote token's metadata: the network's `quoteTokens` with no RPC, otherwise
211
+ * one cached Multicall3 read of `symbol`, `name` and `decimals`.
212
+ */
213
+ quoteTokenInfo(address: Address): Promise<QuoteTokenInfo>;
214
+ listLaunches(options: ListLaunchesOptions): Promise<LaunchScan>;
215
+ verifyChain(): Promise<void>;
216
+ }
217
+ /** How far back and in what steps a launch scan walks. */
218
+ export interface ScanLimits {
219
+ readonly chunkBlocks: bigint;
220
+ readonly maxChunks: number;
221
+ }
222
+ /**
223
+ * Wrap a live {@link ArcNowClient}. The only function in this repository that
224
+ * names the SDK's classes.
225
+ */
226
+ export declare function createSdkPort(client: ArcNowClient, limits: ScanLimits): ArcNowPort;
227
+ //# sourceMappingURL=sdk-port.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk-port.d.ts","sourceRoot":"","sources":["../src/sdk-port.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * The seam between the tools and `@arcnow/sdk`.
3
+ *
4
+ * # Why there is a seam at all
5
+ *
6
+ * Every chain interaction in this server goes through the SDK. Nothing here
7
+ * encodes a call, computes a curve, or knows an address: the SDK owns all of
8
+ * that, it is pinned to a commit in `pins.json`, and it is the thing the
9
+ * project's forked-chain suite actually tests. Reimplementing any of it here
10
+ * would produce a second, unpinned, untested copy of the most expensive code in
11
+ * the project to get wrong.
12
+ *
13
+ * What this file adds is a set of **interfaces the SDK's handles already
14
+ * satisfy**. The SDK's `Curve`, `Token`, `Trade`, `Pool`, `Launchpad` and `PlatformRegistry` are
15
+ * classes with private fields, which means a test cannot construct a stand-in
16
+ * for one — not because faking them is difficult, but because a class with a
17
+ * `private` member is nominally typed and nothing else is assignable to it. So
18
+ * the tools depend on {@link ArcNowPort}, {@link CurveHandle} and friends, and
19
+ * {@link createSdkPort} is the one place that mentions the SDK's classes.
20
+ *
21
+ * That buys the whole suite: a fake port drives every tool through every
22
+ * branch — a graduating buy, a stale quote, a cost over the ceiling, a curve
23
+ * that already migrated — with no chain, no container and no key. The seam is
24
+ * type-level only; it wraps nothing and computes nothing.
25
+ *
26
+ * The types crossing it are the SDK's own: {@link QuoteAmount}, {@link Tokens},
27
+ * {@link Bps}, `CurveState`, `BuyQuote`. Re-describing those would be exactly
28
+ * the reimplementation this file exists to avoid, and the amount types in
29
+ * particular are the reason an amount of EURC cannot be read as USDC, and the
30
+ * 18-decimal native USDC cannot be confused with the 6-decimal ERC-20 view.
31
+ *
32
+ * @module
33
+ */
34
+ import { getAbiItem } from "viem";
35
+ import { abi, findQuoteToken, QuoteAmount, Tokens, } from "@arcnow/sdk";
36
+ const LAUNCHED_EVENT = getAbiItem({ abi: abi.launchpadAbi, name: "Launched" });
37
+ /**
38
+ * Wrap a live {@link ArcNowClient}. The only function in this repository that
39
+ * names the SDK's classes.
40
+ */
41
+ export function createSdkPort(client, limits) {
42
+ return {
43
+ config: client.config,
44
+ canWrite: client.canWrite,
45
+ signerAddress: client.walletClient?.account?.address,
46
+ curve: (address) => client.curve(address),
47
+ token: (address) => client.token(address),
48
+ trade: (address) => client.trade(address),
49
+ launchpad: client.launchpad,
50
+ platforms: client.platforms,
51
+ quoteRegistry: client.quoteRegistry,
52
+ quoteSpendState: (token, owner, spender) => client.quoteToken(token).spendState(owner, spender),
53
+ quoteTokenInfo: (address) => client.quoteTokenInfo(address),
54
+ verifyChain: () => client.verifyChain(),
55
+ async listLaunches(options) {
56
+ return scanLaunches(client, limits, options);
57
+ },
58
+ };
59
+ }
60
+ /**
61
+ * Walk `Launchpad.Launched` backwards from the tip.
62
+ *
63
+ * **This is the one thing the SDK does not do for us.** There is no enumeration
64
+ * anywhere in `@arcnow/sdk` — deliberately, per its `networks.json`: a token and
65
+ * its curve come from this log, one pair per launch, and there are as many as
66
+ * there have been launches, so a network preset cannot carry them. That leaves
67
+ * "show me the recent tokens", which is the first thing anyone asks an
68
+ * assistant, with nowhere to come from.
69
+ *
70
+ * So this reads the log directly — with the SDK's own pinned ABI, through the
71
+ * SDK's own configured client, at the SDK's own launchpad address. Nothing is
72
+ * re-derived; the only thing added is the scan. It is written down in the
73
+ * README as a gap in the SDK rather than a feature of this server, because that
74
+ * is what it is: a `launchpad.recentLaunches()` belongs there, where the fork
75
+ * suite could test it against a real chain.
76
+ *
77
+ * Backwards from the tip, in chunks, with a budget — because a public endpoint
78
+ * will refuse an unbounded range and the deployment starts six million blocks
79
+ * back. What it could not reach is reported rather than implied.
80
+ */
81
+ async function scanLaunches(client, limits, options) {
82
+ const tip = await client.publicClient.getBlockNumber();
83
+ const floor = BigInt(client.config.deployedAtBlock ?? 0);
84
+ const found = [];
85
+ let upper = tip;
86
+ let chunks = 0;
87
+ let lowest = tip;
88
+ while (upper >= floor && chunks < limits.maxChunks && found.length < options.limit) {
89
+ const lower = upper + 1n > limits.chunkBlocks
90
+ ? bigMax(floor, upper - limits.chunkBlocks + 1n)
91
+ : floor;
92
+ const logs = await client.publicClient.getLogs({
93
+ address: client.config.contracts.launchpad,
94
+ event: LAUNCHED_EVENT,
95
+ args: {
96
+ ...(options.token === undefined ? {} : { token: options.token }),
97
+ ...(options.creator === undefined ? {} : { creator: options.creator }),
98
+ },
99
+ fromBlock: lower,
100
+ toBlock: upper,
101
+ });
102
+ // Newest first, which is the order a person means by "recent".
103
+ for (const log of [...logs].reverse()) {
104
+ const args = log.args;
105
+ // The quote is in the log itself: labelling it costs nothing for a quote
106
+ // the network lists, and one cached read per process for one it does not.
107
+ const quoteAddress = args.quoteToken;
108
+ const quoteToken = findQuoteToken(client.config, quoteAddress)
109
+ ?? await client.quoteTokenInfo(quoteAddress);
110
+ found.push({
111
+ token: args.token,
112
+ curve: args.curve,
113
+ creator: args.creator,
114
+ platform: args.platform,
115
+ migrator: args.migrator,
116
+ quoteToken,
117
+ launchFee: QuoteAmount.fromWad(quoteToken, args.launchFeeWad),
118
+ initialBuy: QuoteAmount.fromWad(quoteToken, args.initialBuyWad),
119
+ tokensOut: Tokens.fromWad(args.tokensOutWad),
120
+ blockNumber: log.blockNumber ?? 0n,
121
+ txHash: log.transactionHash ?? ("0x"),
122
+ });
123
+ if (found.length >= options.limit)
124
+ break;
125
+ }
126
+ lowest = lower;
127
+ chunks += 1;
128
+ if (lower <= floor)
129
+ break;
130
+ upper = lower - 1n;
131
+ }
132
+ return {
133
+ launches: found.slice(0, options.limit),
134
+ tipBlock: tip,
135
+ scannedFromBlock: lowest,
136
+ scannedToBlock: tip,
137
+ reachedDeployment: lowest <= floor,
138
+ stoppedOnBudget: lowest > floor && found.length < options.limit,
139
+ };
140
+ }
141
+ function bigMax(a, b) {
142
+ return a > b ? a : b;
143
+ }
144
+ //# sourceMappingURL=sdk-port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk-port.js","sourceRoot":"","sources":["../src/sdk-port.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAKH,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EACL,GAAG,EAGH,cAAc,EAiBd,WAAW,EASX,MAAM,GAQP,MAAM,aAAa,CAAC;AA0MrB,MAAM,cAAc,GAAG,UAAU,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,CAAa,CAAC;AAE3F;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,MAAoB,EAAE,MAAkB;IACpE,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,aAAa,EAAE,MAAM,CAAC,YAAY,EAAE,OAAO,EAAE,OAAO;QACpD,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;QACzC,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;QACzC,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;QACzC,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,eAAe,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC;QAC/F,cAAc,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC;QAC3D,WAAW,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE;QACvC,KAAK,CAAC,YAAY,CAAC,OAAO;YACxB,OAAO,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/C,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,KAAK,UAAU,YAAY,CACzB,MAAoB,EACpB,MAAkB,EAClB,OAA4B;IAE5B,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;IACvD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,IAAI,CAAC,CAAC,CAAC;IACzD,MAAM,KAAK,GAAmB,EAAE,CAAC;IAEjC,IAAI,KAAK,GAAG,GAAG,CAAC;IAChB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,MAAM,GAAG,GAAG,CAAC;IAEjB,OAAO,KAAK,IAAI,KAAK,IAAI,MAAM,GAAG,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;QACnF,MAAM,KAAK,GAAG,KAAK,GAAG,EAAE,GAAG,MAAM,CAAC,WAAW;YAC3C,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAAC,WAAW,GAAG,EAAE,CAAC;YAChD,CAAC,CAAC,KAAK,CAAC;QACV,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC;YAC7C,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS;YAC1C,KAAK,EAAE,cAAc;YACrB,IAAI,EAAE;gBACJ,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;gBAChE,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;aACvE;YACD,SAAS,EAAE,KAAK;YAChB,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QACH,+DAA+D;QAC/D,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,GAAG,CAAC,IAA+B,CAAC;YACjD,yEAAyE;YACzE,0EAA0E;YAC1E,MAAM,YAAY,GAAG,IAAI,CAAC,UAAqB,CAAC;YAChD,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC;mBACzD,MAAM,MAAM,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;YAC/C,KAAK,CAAC,IAAI,CAAC;gBACT,KAAK,EAAE,IAAI,CAAC,KAAgB;gBAC5B,KAAK,EAAE,IAAI,CAAC,KAAgB;gBAC5B,OAAO,EAAE,IAAI,CAAC,OAAkB;gBAChC,QAAQ,EAAE,IAAI,CAAC,QAAmB;gBAClC,QAAQ,EAAE,IAAI,CAAC,QAAmB;gBAClC,UAAU;gBACV,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,YAAsB,CAAC;gBACvE,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,aAAuB,CAAC;gBACzE,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,YAAsB,CAAC;gBACtD,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,EAAE;gBAClC,MAAM,EAAE,GAAG,CAAC,eAAe,IAAI,CAAC,IAAI,CAAC;aACtC,CAAC,CAAC;YACH,IAAI,KAAK,CAAC,MAAM,IAAI,OAAO,CAAC,KAAK;gBAAE,MAAM;QAC3C,CAAC;QACD,MAAM,GAAG,KAAK,CAAC;QACf,MAAM,IAAI,CAAC,CAAC;QACZ,IAAI,KAAK,IAAI,KAAK;YAAE,MAAM;QAC1B,KAAK,GAAG,KAAK,GAAG,EAAE,CAAC;IACrB,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC;QACvC,QAAQ,EAAE,GAAG;QACb,gBAAgB,EAAE,MAAM;QACxB,cAAc,EAAE,GAAG;QACnB,iBAAiB,EAAE,MAAM,IAAI,KAAK;QAClC,eAAe,EAAE,MAAM,GAAG,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK;KAChE,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,CAAS,EAAE,CAAS;IAClC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvB,CAAC"}