@floatonnear/mcp 0.6.4 → 0.9.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/dist/amounts.d.ts +51 -0
- package/dist/amounts.js +55 -0
- package/dist/explain.d.ts +59 -0
- package/dist/explain.js +209 -0
- package/dist/roles.d.ts +3 -0
- package/dist/roles.js +34 -3
- package/dist/server.js +620 -28
- package/dist/token-meta.d.ts +42 -0
- package/dist/token-meta.js +46 -0
- package/package.json +1 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a token is CALLED, and how many decimals it really has.
|
|
3
|
+
*
|
|
4
|
+
* WHY. Caps, balances and errors were all rendered with the raw NEP-141
|
|
5
|
+
* account id, and on mainnet USDC that is
|
|
6
|
+
* `17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1` — 64
|
|
7
|
+
* hex characters appearing in `vault_tree`, `vault_budget`, the teardown
|
|
8
|
+
* report and every "no limit for that token" message. Nobody reading a budget
|
|
9
|
+
* can tell that is USDC, and two different tokens look identical at a glance
|
|
10
|
+
* until you diff the strings.
|
|
11
|
+
*
|
|
12
|
+
* AND IT FIXES A REAL CORRECTNESS LIMIT, not just readability. `vault_tree`
|
|
13
|
+
* could only humanise the ONE token whose decimals the operator had
|
|
14
|
+
* configured; any other kept base units, because scaling by a guessed
|
|
15
|
+
* exponent prints a figure wrong by orders of magnitude while looking tidy.
|
|
16
|
+
* The chain knows the answer — `ft_metadata` returns it — so the guess was
|
|
17
|
+
* never necessary. Every token can now be rendered correctly.
|
|
18
|
+
*
|
|
19
|
+
* CACHED FOR THE PROCESS LIFETIME. Metadata is immutable in practice (a token
|
|
20
|
+
* that changed its decimals would break every holder), and a budget read
|
|
21
|
+
* should not make an extra round trip per node per token. A failed lookup is
|
|
22
|
+
* cached as `null` too: the common cause is an account that is not a token at
|
|
23
|
+
* all, and retrying that on every render turns one bad id into a storm.
|
|
24
|
+
*/
|
|
25
|
+
export interface TokenMeta {
|
|
26
|
+
symbol: string;
|
|
27
|
+
decimals: number;
|
|
28
|
+
}
|
|
29
|
+
type Fetcher = (rpcUrl: string, token: string) => Promise<unknown>;
|
|
30
|
+
/** Visible for tests; a process-lifetime cache is otherwise untestable. */
|
|
31
|
+
export declare function clearTokenMetaCache(): void;
|
|
32
|
+
export declare function tokenMeta(rpcUrl: string, token: string, view: Fetcher): Promise<TokenMeta | null>;
|
|
33
|
+
/**
|
|
34
|
+
* `USDC` where known, the raw id where not — never a symbol alone.
|
|
35
|
+
*
|
|
36
|
+
* The id stays because a symbol is NOT unique: anyone can deploy a token
|
|
37
|
+
* calling itself USDC, and a budget that names only the symbol cannot be
|
|
38
|
+
* checked against the one the user meant. This is money; the identifier has
|
|
39
|
+
* to remain visible.
|
|
40
|
+
*/
|
|
41
|
+
export declare function label(token: string, meta: TokenMeta | null): string;
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const cache = new Map();
|
|
2
|
+
/** Visible for tests; a process-lifetime cache is otherwise untestable. */
|
|
3
|
+
export function clearTokenMetaCache() {
|
|
4
|
+
cache.clear();
|
|
5
|
+
}
|
|
6
|
+
export async function tokenMeta(rpcUrl, token, view) {
|
|
7
|
+
if (cache.has(token))
|
|
8
|
+
return cache.get(token) ?? null;
|
|
9
|
+
let meta = null;
|
|
10
|
+
try {
|
|
11
|
+
const raw = (await view(rpcUrl, token));
|
|
12
|
+
// BOTH FIELDS OR NEITHER. A partial answer is worse than none: a symbol
|
|
13
|
+
// without decimals invites rendering with the configured default, which
|
|
14
|
+
// is the wrong-exponent bug this exists to remove.
|
|
15
|
+
if (raw &&
|
|
16
|
+
typeof raw.symbol === "string" &&
|
|
17
|
+
raw.symbol.length > 0 &&
|
|
18
|
+
// REDUNDANT WITH THE NEXT LINE, kept for readability. Mutation-tested:
|
|
19
|
+
// removing this changes nothing because Number.isInteger(undefined) is
|
|
20
|
+
// already false, so `Number.isInteger` is the clause actually carrying
|
|
21
|
+
// the guard. Delete that one and the suite reds; delete this one and it
|
|
22
|
+
// does not.
|
|
23
|
+
typeof raw.decimals === "number" &&
|
|
24
|
+
Number.isInteger(raw.decimals) &&
|
|
25
|
+
raw.decimals >= 0 &&
|
|
26
|
+
raw.decimals <= 24) {
|
|
27
|
+
meta = { symbol: raw.symbol, decimals: raw.decimals };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
meta = null;
|
|
32
|
+
}
|
|
33
|
+
cache.set(token, meta);
|
|
34
|
+
return meta;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* `USDC` where known, the raw id where not — never a symbol alone.
|
|
38
|
+
*
|
|
39
|
+
* The id stays because a symbol is NOT unique: anyone can deploy a token
|
|
40
|
+
* calling itself USDC, and a budget that names only the symbol cannot be
|
|
41
|
+
* checked against the one the user meant. This is money; the identifier has
|
|
42
|
+
* to remain visible.
|
|
43
|
+
*/
|
|
44
|
+
export function label(token, meta) {
|
|
45
|
+
return meta ? `${meta.symbol} (${token})` : token;
|
|
46
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@floatonnear/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP server for the hierarchical budget vault. The agent key signs request_payment only; owner methods emit unsigned payloads for wallet approval.",
|
|
6
6
|
"license": "MIT",
|