@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 +15 -0
- package/bin/openfunderse.mjs +99 -2
- package/package.json +1 -1
- package/packs/openfunderse/config/setup-manifest.json +6 -1
- package/packs/openfunderse/prompts/core/system.md +25 -0
- package/packs/openfunderse/prompts/participant/system.md +34 -2
- package/packs/openfunderse/prompts/relayer/system.md +13 -2
- package/packs/openfunderse/prompts/strategy/system.md +28 -2
- package/packs/openfunderse/skills/clawbot-core/SKILL.md +152 -0
- package/packs/openfunderse/skills/participant/SKILL.md +138 -7
- package/packs/openfunderse/skills/relayer/SKILL.md +6 -5
- package/packs/openfunderse/skills/strategy/SKILL.md +171 -7
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).
|
package/bin/openfunderse.mjs
CHANGED
|
@@ -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,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
|
|
1
|
+
# Participant System Prompt
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
1
|
+
# Relayer System Prompt
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
1
|
+
# Strategy System Prompt
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4
|
-
- Define participant MoltBot behavior for claim collection and validation loops.
|
|
12
|
+
# Participant MoltBot Skill
|
|
5
13
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
1
|
+
# Relayer Skill
|
|
2
2
|
|
|
3
3
|
Purpose:
|
|
4
4
|
- Define relayer-support MoltBot behavior for submission orchestration.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
4
|
-
- Define strategy MoltBot behavior for proposing intents from finalized snapshots.
|
|
12
|
+
# Strategy MoltBot Skill
|
|
5
13
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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.
|