@floatonnear/float-adapter 0.2.1 → 0.3.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/blocked-scan.d.ts +78 -0
- package/dist/blocked-scan.js +162 -8
- package/dist/env-file.d.ts +16 -0
- package/dist/env-file.js +16 -0
- package/dist/gate.d.ts +9 -5
- package/dist/gate.js +32 -5
- package/dist/handlers.d.ts +176 -3
- package/dist/handlers.js +262 -29
- package/dist/keyring.d.ts +81 -2
- package/dist/keyring.js +80 -10
- package/dist/map.d.ts +56 -11
- package/dist/map.js +43 -21
- package/dist/owner-plan.d.ts +112 -0
- package/dist/owner-plan.js +112 -0
- package/dist/server.d.ts +10 -1
- package/dist/server.js +461 -53
- package/dist/unavailable.d.ts +31 -0
- package/dist/unavailable.js +90 -0
- package/package.json +2 -2
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { planAddRole, planFreezeNode, planPurgeSettled, planSetCooldown, planSetNodeCaps, planSetPaused, planSetRecipients, planSetStrictAllocation, planWithdraw, } from "@floatonnear/mcp/payloads";
|
|
2
|
+
/**
|
|
3
|
+
* The action name is not one we serve.
|
|
4
|
+
*
|
|
5
|
+
* A SEPARATE type from a bad argument, because the HTTP layer has to tell
|
|
6
|
+
* them apart: it used to catch every throw from here and report
|
|
7
|
+
* `unknown action: <name>`, so a negative cooldown or a duplicate recipient
|
|
8
|
+
* was reported as a method that does not exist - the one explanation that
|
|
9
|
+
* cannot lead the caller to a fix.
|
|
10
|
+
*/
|
|
11
|
+
export class UnknownActionError extends Error {
|
|
12
|
+
constructor(action) {
|
|
13
|
+
super(`unknown action: ${action}`);
|
|
14
|
+
this.name = "UnknownActionError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* A node-scoped action must name its node.
|
|
19
|
+
*
|
|
20
|
+
* THE TYPE SAYS `nodeId: number` AND THAT PROVES NOTHING AT RUNTIME. The body
|
|
21
|
+
* arrives as JSON and is cast, so a request that simply omits the field type-
|
|
22
|
+
* checks all the way through. Measured live on 2026-11-09:
|
|
23
|
+
* `{"action":"freeze"}` returned HTTP 200 with `args: {"frozen": false}` and
|
|
24
|
+
* the summary "Unfreeze node undefined" — `JSON.stringify` drops an undefined
|
|
25
|
+
* value, so `node_id` vanished from the args and from the CLI string, and the
|
|
26
|
+
* user was handed a confident command for a node that does not exist.
|
|
27
|
+
*
|
|
28
|
+
* It reverts rather than doing damage: `freeze_node(node_id: NodeId, ..)` uses
|
|
29
|
+
* `NodeId = u32` with no `#[serde(default)]`, so near-sdk fails to deserialize
|
|
30
|
+
* instead of falling back to `ROOT_NODE = 0`. Wasted gas and a confusing
|
|
31
|
+
* failure, not a silently frozen root.
|
|
32
|
+
*
|
|
33
|
+
* `!== "number"`, NOT `!b.nodeId`. Root is node 0 and 0 is falsy, so the
|
|
34
|
+
* obvious guard would refuse the node most likely to be frozen or re-capped.
|
|
35
|
+
* `NaN` is excluded too, because `JSON.parse` cannot produce it but a hand-
|
|
36
|
+
* built caller can, and `node_id: NaN` serialises to `null`.
|
|
37
|
+
*/
|
|
38
|
+
function requireNode(b) {
|
|
39
|
+
if (typeof b.nodeId !== "number" || !Number.isInteger(b.nodeId) || b.nodeId < 0) {
|
|
40
|
+
throw new Error(`action '${b.action}' needs nodeId: a non-negative integer naming the node to change. ` +
|
|
41
|
+
`Root is nodeId 0. Omitting it would build a command with no node_id at all, ` +
|
|
42
|
+
`which the contract refuses after the owner has already signed it.`);
|
|
43
|
+
}
|
|
44
|
+
return b.nodeId;
|
|
45
|
+
}
|
|
46
|
+
export function planOwnerAction(b, env) {
|
|
47
|
+
switch (b.action) {
|
|
48
|
+
case "caps":
|
|
49
|
+
// HUMAN units, with decimals — `planSetNodeCaps` scales them itself via
|
|
50
|
+
// limitsToArgs. Calling toBaseUnits here too would scale twice and turn
|
|
51
|
+
// a 100 USDC cap into 100 million USDC, which is not a cap at all.
|
|
52
|
+
return planSetNodeCaps(env.vault, requireNode(b), [
|
|
53
|
+
{
|
|
54
|
+
token: env.token,
|
|
55
|
+
dailyCap: b.dailyCap ?? "0",
|
|
56
|
+
perTxCap: b.perTxCap ?? "0",
|
|
57
|
+
decimals: env.decimals,
|
|
58
|
+
},
|
|
59
|
+
]);
|
|
60
|
+
case "cooldown":
|
|
61
|
+
return planSetCooldown(env.vault, requireNode(b), b.cooldownSec ?? 0);
|
|
62
|
+
case "recipients":
|
|
63
|
+
// `?? null` is load-bearing: an absent list means INHERIT. Defaulting to
|
|
64
|
+
// `[]` would panic `validate_recipients`, which demands "1..=32
|
|
65
|
+
// recipients, or None to inherit".
|
|
66
|
+
return planSetRecipients(env.vault, requireNode(b), b.recipients ?? null);
|
|
67
|
+
case "freeze":
|
|
68
|
+
return planFreezeNode(env.vault, requireNode(b), b.frozen ?? false);
|
|
69
|
+
case "pause":
|
|
70
|
+
// Vault-wide. Takes no nodeId, because it stops every payment at every
|
|
71
|
+
// level rather than muting one agent.
|
|
72
|
+
return planSetPaused(env.vault, b.paused ?? false);
|
|
73
|
+
case "allocation":
|
|
74
|
+
return planSetStrictAllocation(env.vault, b.strict ?? false);
|
|
75
|
+
case "withdraw":
|
|
76
|
+
// BASE UNITS, and no default. An amount is the one argument that must
|
|
77
|
+
// never be guessed: `?? "0"` would be refused by the contract, and any
|
|
78
|
+
// other fallback would move a quantity nobody asked for.
|
|
79
|
+
if (!b.amountBase)
|
|
80
|
+
throw new Error("withdraw needs amountBase, in base units");
|
|
81
|
+
if (!b.receiverId)
|
|
82
|
+
throw new Error("withdraw needs receiverId");
|
|
83
|
+
return planWithdraw(env.vault, b.token ?? env.token, b.amountBase, b.receiverId, env.decimals);
|
|
84
|
+
case "role":
|
|
85
|
+
// NOTHING IS DEFAULTED that the user has to confirm. A label, a key
|
|
86
|
+
// and a funding amount are all things an owner approves in a wallet,
|
|
87
|
+
// and a guessed one would be approved by someone who never chose it.
|
|
88
|
+
if (!b.label)
|
|
89
|
+
throw new Error("role needs a label");
|
|
90
|
+
if (!b.publicKey)
|
|
91
|
+
throw new Error("role needs the agent's publicKey");
|
|
92
|
+
if (!b.fundingYocto)
|
|
93
|
+
throw new Error("role needs fundingYocto for the gas key");
|
|
94
|
+
return planAddRole(env.vault, b.label, [
|
|
95
|
+
{
|
|
96
|
+
token: env.token,
|
|
97
|
+
dailyCap: b.dailyCap ?? "0",
|
|
98
|
+
perTxCap: b.perTxCap ?? "0",
|
|
99
|
+
decimals: env.decimals,
|
|
100
|
+
},
|
|
101
|
+
], b.cooldownSec ?? 0, b.recipients ?? null, b.publicKey, b.fundingYocto);
|
|
102
|
+
case "purge":
|
|
103
|
+
// `before_day` is read from the contract's own `current_day` by the
|
|
104
|
+
// caller and passed as current_day + 1 — records are removed strictly
|
|
105
|
+
// BEFORE it. Defaulting it here would invent a cutoff.
|
|
106
|
+
if (typeof b.beforeDay !== "number")
|
|
107
|
+
throw new Error("purge needs beforeDay");
|
|
108
|
+
return planPurgeSettled(env.vault, b.beforeDay, b.limit ?? 100);
|
|
109
|
+
default:
|
|
110
|
+
throw new UnknownActionError(String(b.action));
|
|
111
|
+
}
|
|
112
|
+
}
|
package/dist/server.d.ts
CHANGED
|
@@ -12,8 +12,17 @@
|
|
|
12
12
|
* NEAR_VAULT_RPC_URL default https://test.rpc.fastnear.com
|
|
13
13
|
* NEAR_VAULT_TOKEN required (the NEP-141 the vault pays in)
|
|
14
14
|
* NEAR_VAULT_TOKEN_DECIMALS default 6
|
|
15
|
-
* NEAR_VAULT_AGENT_ID only needed for POST /v1/pay
|
|
15
|
+
* NEAR_VAULT_AGENT_ID only needed for POST /v1/pay. Taken from the key
|
|
16
|
+
* file's `account_id` when one is given.
|
|
16
17
|
* NEAR_VAULT_AGENT_KEY only needed for POST /v1/pay (the restricted key)
|
|
18
|
+
* NEAR_VAULT_AGENT_KEY_FILE PREFERRED over the inline value above: a PATH to
|
|
19
|
+
* a ~/.near-credentials-shaped JSON file or a bare
|
|
20
|
+
* key file. See key-file.ts — a path is not a
|
|
21
|
+
* secret, so reading this config to check which
|
|
22
|
+
* vault is wired up stops printing a live private
|
|
23
|
+
* key. If both are set the FILE wins.
|
|
24
|
+
* FLOAT_QUOTE_SIGNER_KEY 32-byte hex, for rail=intents
|
|
25
|
+
* FLOAT_QUOTE_SIGNER_KEY_FILE the same, as a path
|
|
17
26
|
* PORT default 8787 (Float's dashboard default)
|
|
18
27
|
*/
|
|
19
28
|
export {};
|