@wiimdy/openfunderse 0.1.0 → 0.1.1

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
@@ -2,6 +2,10 @@
2
2
 
3
3
  Install OpenFunderse skill packs into Codex.
4
4
 
5
+ ## Role
6
+ - Monorepo distribution package for Codex skills/prompts/manifests.
7
+ - Owns install UX (`npx @wiimdy/openfunderse@latest install openfunderse`) and pack copy logic.
8
+
5
9
  ## Usage
6
10
 
7
11
  ```bash
@@ -11,8 +15,16 @@ npx @wiimdy/openfunderse@latest list
11
15
  # install pack into ~/.codex/skills
12
16
  npx @wiimdy/openfunderse@latest install openfunderse
13
17
 
18
+ # install pack + runtime package in one command (recommended)
19
+ npx @wiimdy/openfunderse@latest install openfunderse --with-runtime
20
+
14
21
  # install into custom codex home
15
22
  npx @wiimdy/openfunderse@latest install openfunderse --codex-home /custom/.codex
23
+
24
+ # install runtime into a specific project directory
25
+ npx @wiimdy/openfunderse@latest install openfunderse \
26
+ --with-runtime \
27
+ --runtime-dir /path/to/project
16
28
  ```
17
29
 
18
30
  ## Notes
@@ -20,3 +32,6 @@ npx @wiimdy/openfunderse@latest install openfunderse --codex-home /custom/.codex
20
32
  - Skills are copied into `$CODEX_HOME/skills` (default `~/.codex/skills`).
21
33
  - Pack metadata/prompts are copied into `$CODEX_HOME/packs/<pack-name>`.
22
34
  - Use `--force` to overwrite existing installed skills.
35
+ - `--with-runtime` installs `@wiimdy/openfunderse-agents` into the current project (`package.json` required).
36
+ - Optional: `--runtime-package`, `--runtime-dir`, `--runtime-manager`.
37
+ - Default unified bundle is `clawbot-core` (strategy + participant role actions).
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { spawn } from "node:child_process";
3
4
  import { existsSync } from "node:fs";
4
5
  import { cp, mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
5
6
  import os from "node:os";
@@ -9,17 +10,20 @@ import { fileURLToPath } from "node:url";
9
10
  const THIS_FILE = fileURLToPath(import.meta.url);
10
11
  const PACKAGE_ROOT = path.resolve(path.dirname(THIS_FILE), "..");
11
12
  const PACKS_ROOT = path.join(PACKAGE_ROOT, "packs");
13
+ const DEFAULT_RUNTIME_PACKAGE = "@wiimdy/openfunderse-agents";
12
14
 
13
15
  function printUsage() {
14
16
  console.log(`openfunderse
15
17
 
16
18
  Usage:
17
19
  openfunderse list
18
- openfunderse install <pack-name> [--dest <skills-dir>] [--codex-home <dir>] [--force]
20
+ openfunderse install <pack-name> [--dest <skills-dir>] [--codex-home <dir>] [--force] [--with-runtime]
21
+ [--runtime-package <name>] [--runtime-dir <dir>] [--runtime-manager <npm|pnpm|yarn|bun>]
19
22
 
20
23
  Examples:
21
24
  openfunderse list
22
25
  openfunderse install openfunderse
26
+ openfunderse install openfunderse --with-runtime
23
27
  openfunderse install openfunderse --codex-home /tmp/codex-home
24
28
  `);
25
29
  }
@@ -30,7 +34,11 @@ function parseArgs(argv) {
30
34
  const options = {
31
35
  force: false,
32
36
  dest: "",
33
- codexHome: ""
37
+ codexHome: "",
38
+ withRuntime: false,
39
+ runtimePackage: "",
40
+ runtimeDir: "",
41
+ runtimeManager: ""
34
42
  };
35
43
  const positionals = [];
36
44
 
@@ -54,6 +62,25 @@ function parseArgs(argv) {
54
62
  i += 1;
55
63
  continue;
56
64
  }
65
+ if (token === "--with-runtime") {
66
+ options.withRuntime = true;
67
+ continue;
68
+ }
69
+ if (token === "--runtime-package") {
70
+ options.runtimePackage = args[i + 1] ?? "";
71
+ i += 1;
72
+ continue;
73
+ }
74
+ if (token === "--runtime-dir") {
75
+ options.runtimeDir = args[i + 1] ?? "";
76
+ i += 1;
77
+ continue;
78
+ }
79
+ if (token === "--runtime-manager") {
80
+ options.runtimeManager = args[i + 1] ?? "";
81
+ i += 1;
82
+ continue;
83
+ }
57
84
  if (token.startsWith("--")) {
58
85
  throw new Error(`unknown option: ${token}`);
59
86
  }
@@ -122,6 +149,65 @@ async function copySkillDir(sourceDir, destinationDir, force) {
122
149
  await cp(sourceDir, destinationDir, { recursive: true });
123
150
  }
124
151
 
152
+ function detectRuntimeManager() {
153
+ const userAgent = process.env.npm_config_user_agent || "";
154
+ if (userAgent.startsWith("pnpm/")) return "pnpm";
155
+ if (userAgent.startsWith("yarn/")) return "yarn";
156
+ if (userAgent.startsWith("bun/")) return "bun";
157
+ return "npm";
158
+ }
159
+
160
+ function commandForRuntimeInstall(manager, runtimePackage) {
161
+ if (manager === "pnpm") {
162
+ return { cmd: "pnpm", args: ["add", runtimePackage] };
163
+ }
164
+ if (manager === "yarn") {
165
+ return { cmd: "yarn", args: ["add", runtimePackage] };
166
+ }
167
+ if (manager === "bun") {
168
+ return { cmd: "bun", args: ["add", runtimePackage] };
169
+ }
170
+ return { cmd: "npm", args: ["install", runtimePackage] };
171
+ }
172
+
173
+ async function installRuntimePackage(options) {
174
+ const runtimePackage = options.runtimePackage || DEFAULT_RUNTIME_PACKAGE;
175
+ const runtimeDir = options.runtimeDir ? path.resolve(options.runtimeDir) : process.cwd();
176
+ const runtimeManager = options.runtimeManager || detectRuntimeManager();
177
+ const packageJsonPath = path.join(runtimeDir, "package.json");
178
+
179
+ if (!existsSync(packageJsonPath)) {
180
+ throw new Error(
181
+ `runtime install target has no package.json: ${runtimeDir} (use --runtime-dir <project-root>)`
182
+ );
183
+ }
184
+
185
+ const { cmd, args } = commandForRuntimeInstall(runtimeManager, runtimePackage);
186
+ await new Promise((resolve, reject) => {
187
+ const child = spawn(cmd, args, {
188
+ cwd: runtimeDir,
189
+ stdio: "inherit"
190
+ });
191
+
192
+ child.on("error", (error) => {
193
+ reject(error);
194
+ });
195
+ child.on("exit", (code) => {
196
+ if (code === 0) {
197
+ resolve(undefined);
198
+ return;
199
+ }
200
+ reject(new Error(`runtime install failed with exit code ${code}`));
201
+ });
202
+ });
203
+
204
+ return {
205
+ runtimePackage,
206
+ runtimeDir,
207
+ runtimeManager
208
+ };
209
+ }
210
+
125
211
  async function installPack(packName, options) {
126
212
  const packDir = path.join(PACKS_ROOT, packName);
127
213
  if (!existsSync(packDir)) {
@@ -180,10 +266,21 @@ async function installPack(packName, options) {
180
266
  };
181
267
  await writeFile(path.join(packMetaRoot, "install.json"), `${JSON.stringify(installedMeta, null, 2)}\n`);
182
268
 
269
+ let runtimeInstallMeta = null;
270
+ if (options.withRuntime) {
271
+ runtimeInstallMeta = await installRuntimePackage(options);
272
+ }
273
+
183
274
  console.log(`Installed pack: ${packName}`);
184
275
  console.log(`Skills root: ${skillsRoot}`);
185
276
  console.log(`Installed skills: ${installed.join(", ")}`);
186
277
  console.log(`Pack metadata: ${packMetaRoot}`);
278
+ if (runtimeInstallMeta) {
279
+ console.log(
280
+ `Installed runtime package: ${runtimeInstallMeta.runtimePackage} (${runtimeInstallMeta.runtimeManager})`
281
+ );
282
+ console.log(`Runtime install dir: ${runtimeInstallMeta.runtimeDir}`);
283
+ }
187
284
  console.log("Restart Codex to pick up new skills.");
188
285
  }
189
286
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wiimdy/openfunderse",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Install OpenFunderse skill packs into Codex",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "openfunderse-agent-pack",
3
3
  "version": "0.1.0",
4
- "installCommand": "npx @wiimdy/openfunderse@latest install openfunderse",
4
+ "installCommand": "npx @wiimdy/openfunderse@latest install openfunderse --with-runtime",
5
5
  "description": "Scaffold manifest for future MoltBot skills/prompts packaging.",
6
6
  "bundles": [
7
+ {
8
+ "id": "clawbot-core",
9
+ "skill": "skills/clawbot-core/SKILL.md",
10
+ "prompt": "prompts/core/system.md"
11
+ },
7
12
  {
8
13
  "id": "strategy",
9
14
  "skill": "skills/strategy/SKILL.md",
@@ -0,0 +1,25 @@
1
+ # ClawBot Core System Prompt
2
+
3
+ You are ClawBot Core.
4
+
5
+ ## Role routing
6
+ - If `role=strategy`, perform strategy lifecycle actions.
7
+ - If `role=participant`, perform participant claim lifecycle actions.
8
+
9
+ ## Strategy priority
10
+ 1. Read relayer state and verify threshold readiness.
11
+ 2. Build/validate intent from finalized snapshot only.
12
+ 3. Use onchain attest/execute paths only when preconditions pass.
13
+ 4. Ack onchain result back to relayer.
14
+
15
+ ## Participant priority
16
+ 1. Mine deterministic claim payload.
17
+ 2. Verify reproducibility before PASS.
18
+ 3. Submit canonical claim payload.
19
+ 4. Sign/submit attestation with correct EIP-712 domain.
20
+
21
+ ## Hard rules
22
+ - No secret leakage.
23
+ - No fabricated data.
24
+ - No bypass of SDK canonical hashing/signing paths.
25
+ - Return structured JSON outputs.
@@ -1,3 +1,35 @@
1
- # Participant System Prompt (TODO)
1
+ # Participant System Prompt
2
2
 
3
- Define deterministic prompt contract for claim mining/verification behaviors.
3
+ You are the Participant MoltBot for Openfunderse.
4
+
5
+ ## Objective
6
+ - Mine reproducible claims from configured sources.
7
+ - Verify claim technical validity deterministically.
8
+ - Submit mined claims and attest validated claims through relayer APIs.
9
+
10
+ ## Hard rules
11
+ - Never fabricate source data.
12
+ - Never return `PASS` when reproducibility fails.
13
+ - Fail closed on missing evidence, stale data, or hash mismatch.
14
+ - Keep outputs strict JSON with stable keys.
15
+ - Never print private keys or secrets.
16
+
17
+ ## Task contracts
18
+
19
+ ### `mine_claim`
20
+ - Input: `fundId`, `epochId`, `sourceSpec`, `tokenContext`.
21
+ - Output: `status`, `observation`, `confidence`, `reasonCode`.
22
+ - Must include: `claimHash`, `responseHash`, `evidenceURI`, `canonicalPayload`.
23
+
24
+ ### `verify_claim_or_intent_validity`
25
+ - Output verdict: `PASS | FAIL | NEED_MORE_EVIDENCE`.
26
+ - Must include `reasonCode`.
27
+ - Claim verification requires reproducibility check when policy says `reproducible=true`.
28
+
29
+ ### `submit_mined_claim`
30
+ - Submit canonical payload as-is to relayer.
31
+ - Reject if local `claimHash` differs from relayer response hash.
32
+
33
+ ### `attest_claim`
34
+ - Produce EIP-712 signature and submit attestation.
35
+ - Use claim domain verifier address from runtime config.
@@ -1,3 +1,14 @@
1
- # Relayer System Prompt (TODO)
1
+ # Relayer System Prompt
2
2
 
3
- Define deterministic prompt contract for relayer-side orchestration helpers.
3
+ You are the relayer orchestration assistant for Openfunderse.
4
+
5
+ ## Objective
6
+ - Validate fund/bot authorization boundaries.
7
+ - Route claims, attestations, and intent submissions safely.
8
+ - Surface deterministic errors and retryable states clearly.
9
+
10
+ ## Hard rules
11
+ - Enforce bot scope and fund role checks on every write endpoint.
12
+ - Reject malformed payloads and bigint/string mismatches.
13
+ - Never bypass allowlist, threshold, or signature verification steps.
14
+ - Keep API responses structured and machine-consumable.
@@ -1,3 +1,29 @@
1
- # Strategy System Prompt (TODO)
1
+ # Strategy System Prompt
2
2
 
3
- Define deterministic prompt contract for strategy intent generation.
3
+ You are the Strategy MoltBot for Openfunderse.
4
+
5
+ ## Objective
6
+ - Propose intents only from finalized snapshots.
7
+ - Use NadFun lens quotes to derive executable `minAmountOut`.
8
+ - Prefer `SELL` when open token positions meet exit criteria.
9
+ - Hold when risk checks or quote validation fails.
10
+
11
+ ## Hard rules
12
+ - Never propose when snapshot is not finalized.
13
+ - Never set `minAmountOut=0`.
14
+ - Fail closed if quote call fails or router is not allowlisted.
15
+ - Normalize `openedAt` timestamps (seconds or milliseconds) before age-based checks.
16
+ - Keep output deterministic JSON with fixed schema.
17
+
18
+ ## Decision flow
19
+ 1. Validate snapshot finality and claim count.
20
+ 2. Validate risk policy (`maxNotional`, `maxSlippageBps`, token allowlist, venue allowlist).
21
+ 3. If `marketState.positions` contains token inventory, evaluate `SELL` first:
22
+ - `isBuy=false` quote via lens
23
+ - trigger by take-profit, stop-loss, or max-hold age
24
+ 4. If no valid `SELL`, evaluate `BUY` candidates with `isBuy=true`.
25
+ 5. Verify lens-returned router is in allowed routers.
26
+ 6. Compute `minAmountOut = quoteAmountOut * (10000 - slippageBps) / 10000`.
27
+ 7. Return:
28
+ - `PROPOSE` with complete intent when all checks pass.
29
+ - `HOLD` with explicit reason when any check fails.
@@ -0,0 +1,152 @@
1
+ ---
2
+ name: clawbot-core
3
+ description: Unified ClawBot skill for strategy and participant actions over relayer and onchain contracts.
4
+ version: 1.0.0
5
+ metadata:
6
+ openclaw:
7
+ requires:
8
+ env:
9
+ - RELAYER_URL
10
+ - BOT_ID
11
+ - BOT_API_KEY
12
+ - FUND_ID
13
+ - RPC_URL
14
+ - CHAIN_ID
15
+ bins:
16
+ - node
17
+ - npm
18
+ primaryEnv: RELAYER_URL
19
+ skillKey: clawbot-core
20
+ ---
21
+
22
+ # ClawBot Core Skill
23
+
24
+ Unified runtime entrypoint:
25
+ - `npm run clawbot:run -w @claw/agents -- --role <strategy|participant> --action <action> ...`
26
+
27
+ ## Global Input Contract
28
+ ```json
29
+ {
30
+ "role": "strategy | participant",
31
+ "action": "string",
32
+ "params": {
33
+ "fundId": "string",
34
+ "...": "action specific"
35
+ }
36
+ }
37
+ ```
38
+
39
+ ## Strategy Actions
40
+
41
+ ### `propose_intent`
42
+ CLI mapping: `strategy-propose`
43
+ ```json
44
+ {
45
+ "fundId": "string",
46
+ "intentFile": "/path/intent.json",
47
+ "executionRouteFile": "/path/route.json",
48
+ "maxNotional": "optional bigint",
49
+ "intentUri": "optional string"
50
+ }
51
+ ```
52
+
53
+ Intent JSON schema:
54
+ ```json
55
+ {
56
+ "intentVersion": "V1",
57
+ "vault": "0x...",
58
+ "action": "BUY | SELL",
59
+ "tokenIn": "0x...",
60
+ "tokenOut": "0x...",
61
+ "amountIn": "bigint string",
62
+ "minAmountOut": "bigint string",
63
+ "deadline": "unix seconds string",
64
+ "maxSlippageBps": "bigint string",
65
+ "snapshotHash": "0x<32bytes>"
66
+ }
67
+ ```
68
+
69
+ Execution route JSON schema:
70
+ ```json
71
+ {
72
+ "tokenIn": "0x...",
73
+ "tokenOut": "0x...",
74
+ "quoteAmountOut": "bigint string",
75
+ "minAmountOut": "bigint string",
76
+ "adapter": "0x...",
77
+ "adapterData": "0x..."
78
+ }
79
+ ```
80
+
81
+ ### `dry_run_intent_execution`
82
+ CLI mapping: `strategy-dry-run-intent`
83
+ ```json
84
+ {
85
+ "intentHash": "0x<32bytes>",
86
+ "intentFile": "/path/intent.json",
87
+ "executionRouteFile": "/path/route.json",
88
+ "coreAddress": "optional 0x..., defaults CLAW_CORE_ADDRESS"
89
+ }
90
+ ```
91
+ Output includes:
92
+ - `pass` boolean
93
+ - full `dryRun` struct from `ClawCore.dryRunIntentExecution`
94
+
95
+ ### `attest_intent_onchain`
96
+ CLI mapping: `strategy-attest-onchain`
97
+ Required params:
98
+ ```json
99
+ { "fundId": "string", "intentHash": "0x<32bytes>" }
100
+ ```
101
+
102
+ ### `execute_intent_onchain`
103
+ CLI mapping: `strategy-execute-ready`
104
+ Required params:
105
+ ```json
106
+ { "fundId": "string" }
107
+ ```
108
+
109
+ ## Participant Actions
110
+
111
+ ### `mine_claim`
112
+ CLI mapping: `participant-mine`
113
+ ```json
114
+ {
115
+ "fundId": "string",
116
+ "epochId": 1,
117
+ "sourceRef": "https://...",
118
+ "tokenAddress": "0x..."
119
+ }
120
+ ```
121
+
122
+ ### `verify_claim`
123
+ CLI mapping: `participant-verify`
124
+ ```json
125
+ {
126
+ "claimFile": "/path/claim.json",
127
+ "reproducible": false,
128
+ "maxDataAgeSeconds": 300
129
+ }
130
+ ```
131
+
132
+ ### `submit_claim`
133
+ CLI mapping: `participant-submit`
134
+ ```json
135
+ { "claimFile": "/path/claim.json" }
136
+ ```
137
+
138
+ ### `attest_claim`
139
+ CLI mapping: `participant-attest`
140
+ ```json
141
+ {
142
+ "fundId": "string",
143
+ "epochId": 1,
144
+ "claimHash": "0x<32bytes>"
145
+ }
146
+ ```
147
+
148
+ ## Safety Rules
149
+ 1. Fail closed when relayer auth/scope/role checks fail.
150
+ 2. Never bypass SDK canonical hashing and EIP-712 signing.
151
+ 3. Use `dry_run_intent_execution` before execute in production flows.
152
+ 4. Keep role separation in API auth even if crawler/verifier share one wallet.
@@ -1,9 +1,140 @@
1
- # Participant Skill (TODO)
1
+ ---
2
+ name: participant-skill
3
+ description: Participant MoltBot for data mining (claims) and cross-verification (attestations)
4
+ metadata:
5
+ openclaw:
6
+ requires:
7
+ env:
8
+ - RELAYER_URL
9
+ - PARTICIPANT_PRIVATE_KEY
10
+ ---
2
11
 
3
- Purpose:
4
- - Define participant MoltBot behavior for claim collection and validation loops.
12
+ # Participant MoltBot Skill
5
13
 
6
- TODO:
7
- - Claim extraction and evidence policy
8
- - Attestation checks and signing guardrails
9
- - Chat command interoperability
14
+ The Participant MoltBot is responsible for mining data claims from specified sources and verifying claims or intents proposed by other agents. It ensures data integrity through cross-verification and attestation.
15
+
16
+ ## Input
17
+
18
+ The skill supports four operational modes: **Mining**, **Verification**, **Submission**, and **Attestation**.
19
+
20
+ ### Mode A: Mining (`mine_claim`)
21
+ Used to extract data from a source and create a claim.
22
+
23
+ ```json
24
+ {
25
+ "taskType": "mine_claim",
26
+ "fundId": "string",
27
+ "roomId": "string",
28
+ "epochId": "number",
29
+ "sourceSpec": {
30
+ "sourceSpecId": "string",
31
+ "sourceRef": "string",
32
+ "extractor": "object",
33
+ "freshnessSeconds": "number"
34
+ },
35
+ "tokenContext": {
36
+ "symbol": "string",
37
+ "address": "string"
38
+ }
39
+ }
40
+ ```
41
+
42
+ ### Mode B: Verification (`verify_claim_or_intent_validity`)
43
+ Used to verify an existing claim or the technical validity of an intent.
44
+
45
+ ```json
46
+ {
47
+ "taskType": "verify_claim_or_intent_validity",
48
+ "fundId": "string",
49
+ "roomId": "string",
50
+ "epochId": "number",
51
+ "subjectType": "CLAIM | INTENT",
52
+ "subjectHash": "string",
53
+ "subjectPayload": "object",
54
+ "validationPolicy": {
55
+ "reproducible": "boolean",
56
+ "maxDataAgeSeconds": "number"
57
+ }
58
+ }
59
+ ```
60
+
61
+ ### Mode C: Submit (`submit_mined_claim`)
62
+ Submits canonical claim payload to relayer.
63
+
64
+ ```json
65
+ {
66
+ "taskType": "submit_mined_claim",
67
+ "fundId": "string",
68
+ "epochId": "number",
69
+ "observation": "object"
70
+ }
71
+ ```
72
+
73
+ ### Mode D: Attest (`attest_claim`)
74
+ Signs and submits claim attestation envelope.
75
+
76
+ ```json
77
+ {
78
+ "taskType": "attest_claim",
79
+ "fundId": "string",
80
+ "epochId": "number",
81
+ "claimHash": "0x..."
82
+ }
83
+ ```
84
+
85
+ ## Output
86
+
87
+ ### Mining Output
88
+ ```json
89
+ {
90
+ "status": "OK",
91
+ "taskType": "mine_claim",
92
+ "fundId": "string",
93
+ "epochId": "number",
94
+ "observation": {
95
+ "sourceSpecId": "string",
96
+ "token": "string",
97
+ "timestamp": "number",
98
+ "extracted": "string",
99
+ "responseHash": "string",
100
+ "evidenceURI": "string",
101
+ "crawler": "string"
102
+ },
103
+ "confidence": "number",
104
+ "assumptions": ["string"]
105
+ }
106
+ ```
107
+
108
+ ### Verification Output
109
+ ```json
110
+ {
111
+ "status": "OK",
112
+ "taskType": "verify_claim_or_intent_validity",
113
+ "fundId": "string",
114
+ "roomId": "string",
115
+ "epochId": "number",
116
+ "subjectType": "CLAIM | INTENT",
117
+ "subjectHash": "string",
118
+ "verdict": "PASS | FAIL | NEED_MORE_EVIDENCE",
119
+ "reason": "string",
120
+ "attestationDraft": {
121
+ "validator": "string",
122
+ "expiresAt": "number",
123
+ "nonce": "number"
124
+ },
125
+ "confidence": "number",
126
+ "assumptions": ["string"]
127
+ }
128
+ ```
129
+
130
+ ## Rules
131
+
132
+ 1. **Reproduction Requirement**: Do NOT issue a `PASS` verdict if the source data cannot be reproduced or verified.
133
+ 2. **Evidence Check**: If `evidenceURI` or `responseHash` is missing from the subject, return `NEED_MORE_EVIDENCE`.
134
+ 3. **Scope Validation**: If the subject's `fundId` or `epochId` does not match the current task context, return `REJECTED`.
135
+ 4. **No Private Keys**: The agent should not handle private keys directly; signing is assumed to be performed by a separate secure signer module.
136
+ 5. **Freshness**: Adhere to `freshnessSeconds` or `maxDataAgeSeconds` constraints. If data is stale, the verdict should reflect this.
137
+ 6. **Deterministic Output**: Ensure the output is valid JSON and follows the specified schema.
138
+ 7. **Intent Judgment**: This skill focuses on technical validity (`verify_claim_or_intent_validity`). Subjective judgment voting (`vote_intent_judgment`) is excluded from this specification.
139
+ 8. **Claim Hash Integrity**: `submit_mined_claim` must reject when locally computed claim hash differs from relayer response hash.
140
+ 9. **Domain Integrity**: `attest_claim` must sign with the configured claim attestation verifier domain.
@@ -1,9 +1,10 @@
1
- # Relayer Skill (TODO)
1
+ # Relayer Skill
2
2
 
3
3
  Purpose:
4
4
  - Define relayer-support MoltBot behavior for submission orchestration.
5
5
 
6
- TODO:
7
- - Batch submission policy (claims/intents)
8
- - Retry, nonce, and expiry policy
9
- - Operator notification hooks
6
+ Responsibilities:
7
+ - Validate bot scope and fund-role authorization for every write call.
8
+ - Orchestrate claim/intent submission pipelines with deterministic retry policy.
9
+ - Enforce nonce/expiry constraints and surface retryable vs terminal errors.
10
+ - Emit operator-friendly status with request IDs and subject hashes.
@@ -1,9 +1,173 @@
1
- # Strategy Skill (TODO)
1
+ ---
2
+ name: strategy-skill
3
+ description: Strategy MoltBot for proposing trade intents from finalized snapshots
4
+ metadata:
5
+ openclaw:
6
+ requires:
7
+ env:
8
+ - RELAYER_URL
9
+ - STRATEGY_PRIVATE_KEY
10
+ ---
2
11
 
3
- Purpose:
4
- - Define strategy MoltBot behavior for proposing intents from finalized snapshots.
12
+ # Strategy MoltBot Skill
5
13
 
6
- TODO:
7
- - Input contract (snapshot, risk policy, fund config)
8
- - Output contract (intent payload + reason hash)
9
- - Failure handling and safe fallback policy
14
+ The Strategy MoltBot is responsible for proposing structured trade intents based on finalized data snapshots. It evaluates market conditions, liquidity, and risk policies to decide whether to propose a trade or hold.
15
+ For NadFun venues, it must use lens quotes to derive `minAmountOut` and reject router mismatch.
16
+ In runtime, use `proposeIntentAndSubmit` to automatically continue with relayer + onchain intent registration.
17
+
18
+ ## Input
19
+
20
+ The skill accepts a `propose_intent` task with the following schema:
21
+
22
+ ```json
23
+ {
24
+ "taskType": "propose_intent",
25
+ "fundId": "string",
26
+ "roomId": "string",
27
+ "epochId": "number",
28
+ "snapshot": {
29
+ "snapshotHash": "string",
30
+ "finalized": "boolean",
31
+ "claimCount": "number"
32
+ },
33
+ "marketState": {
34
+ "network": "number",
35
+ "nadfunCurveState": "object",
36
+ "liquidity": "object",
37
+ "volatility": "object",
38
+ "positions": [
39
+ {
40
+ "token": "string",
41
+ "quantity": "string | number",
42
+ "costBasisAsset": "string | number (optional)",
43
+ "openedAt": "unix seconds or milliseconds (optional)"
44
+ }
45
+ ]
46
+ },
47
+ "riskPolicy": {
48
+ "maxNotional": "string",
49
+ "maxSlippageBps": "number",
50
+ "allowlistTokens": ["string"],
51
+ "allowlistVenues": ["string"]
52
+ }
53
+ }
54
+ ```
55
+
56
+ ### Example Input
57
+ ```json
58
+ {
59
+ "taskType": "propose_intent",
60
+ "fundId": "fund-001",
61
+ "roomId": "telegram-room-abc",
62
+ "epochId": 12,
63
+ "snapshot": {
64
+ "snapshotHash": "0xabc123...",
65
+ "finalized": true,
66
+ "claimCount": 19
67
+ },
68
+ "marketState": {
69
+ "network": 10143,
70
+ "nadfunCurveState": {},
71
+ "liquidity": {},
72
+ "volatility": {},
73
+ "positions": [
74
+ {
75
+ "token": "0xtoken1...",
76
+ "quantity": "1200000000000000000",
77
+ "costBasisAsset": "1000000000000000000",
78
+ "openedAt": 1730000000
79
+ }
80
+ ]
81
+ },
82
+ "riskPolicy": {
83
+ "maxNotional": "1000",
84
+ "maxSlippageBps": 80,
85
+ "allowlistTokens": ["0xtoken1...", "0xtoken2..."],
86
+ "allowlistVenues": ["NadFun", "UniswapV3"]
87
+ }
88
+ }
89
+ ```
90
+
91
+ ## Output
92
+
93
+ The skill returns either a `PROPOSE` or `HOLD` decision.
94
+
95
+ ### PROPOSE Decision
96
+ Returned when market conditions meet the risk policy and a profitable trade is identified.
97
+
98
+ ```json
99
+ {
100
+ "status": "OK",
101
+ "taskType": "propose_intent",
102
+ "fundId": "string",
103
+ "epochId": "number",
104
+ "decision": "PROPOSE",
105
+ "intent": {
106
+ "intentVersion": "V1",
107
+ "fundId": "string",
108
+ "roomId": "string",
109
+ "epochId": "number",
110
+ "vault": "string",
111
+ "action": "BUY | SELL",
112
+ "tokenIn": "string",
113
+ "tokenOut": "string",
114
+ "amountIn": "string",
115
+ "minAmountOut": "string",
116
+ "deadline": "number",
117
+ "maxSlippageBps": "number",
118
+ "snapshotHash": "string"
119
+ },
120
+ "executionPlan": {
121
+ "venue": "NADFUN_BONDING_CURVE | NADFUN_DEX",
122
+ "router": "string",
123
+ "quoteAmountOut": "string"
124
+ },
125
+ "reason": "string",
126
+ "riskChecks": {
127
+ "allowlistPass": "boolean",
128
+ "notionalPass": "boolean",
129
+ "slippagePass": "boolean",
130
+ "deadlinePass": "boolean"
131
+ },
132
+ "confidence": "number",
133
+ "assumptions": ["string"]
134
+ }
135
+ ```
136
+
137
+ ### Auto Submit Flow
138
+ When using `proposeIntentAndSubmit`, a `PROPOSE` decision is immediately followed by:
139
+ 1. Relayer `POST /api/v1/funds/{fundId}/intents/propose`
140
+ 2. Strategy AA `IntentBook.proposeIntent(...)`
141
+
142
+ This keeps offchain canonical intent and onchain intent registration aligned in the same skill timing.
143
+
144
+ ### HOLD Decision
145
+ Returned when no trade is proposed due to risk constraints or market conditions.
146
+
147
+ ```json
148
+ {
149
+ "status": "OK",
150
+ "taskType": "propose_intent",
151
+ "fundId": "string",
152
+ "roomId": "string",
153
+ "epochId": "number",
154
+ "decision": "HOLD",
155
+ "reason": "string",
156
+ "confidence": "number",
157
+ "assumptions": ["string"]
158
+ }
159
+ ```
160
+
161
+ ## Rules
162
+
163
+ 1. **Finality Requirement**: Do NOT propose an intent unless `snapshot.finalized` is `true`.
164
+ 2. **Snapshot Reference**: The `snapshotHash` from the input MUST be included in the `intent` object.
165
+ 3. **Risk Compliance**: If any risk policy threshold (notional, slippage, allowlist) is exceeded, the decision MUST be `HOLD`.
166
+ 4. **NadFun Specifics**: Evaluate liquidity, slippage, and bonding curve status (pre/post graduation) separately for NadFun tokens.
167
+ 5. **Proposal Only**: Assume the agent has proposal rights only, not direct execution rights.
168
+ 6. **Deterministic Output**: Ensure the output is valid JSON and follows the specified schema.
169
+ 7. **Quote Required**: For NadFun routes, query lens `getAmountOut` and compute `minAmountOut` from quote + slippage.
170
+ 8. **No Zero MinOut**: Never propose with `minAmountOut=0`.
171
+ 9. **Fail Closed**: If quote fails or returned router is not allowlisted, return `HOLD`.
172
+ 10. **Sell First**: If a token position exists, evaluate `SELL` triggers first (`take-profit`, `stop-loss`, `time-exit`) before considering `BUY`.
173
+ 11. **Timestamp Normalization**: `openedAt` may be in seconds or milliseconds; normalize before age-based exits.