@wiimdy/openfunderse 1.1.2 → 1.1.4
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/.env.participant.example +17 -0
- package/.env.strategy.example +31 -0
- package/README.md +9 -4
- package/bin/openfunderse.mjs +62 -82
- package/package.json +6 -1
- package/packs/openfunderse-participant/openfunderse-participant/SKILL.md +1 -1
- package/packs/openfunderse-strategy/openfunderse-strategy/SKILL.md +1 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# OpenFunderse participant env scaffold
|
|
2
|
+
# Copy values from your PARTICIPANT_PK, ADDRESS
|
|
3
|
+
|
|
4
|
+
RELAYER_URL=https://openfunderse-relayer-liard.vercel.app/
|
|
5
|
+
BOT_ID=bot-participant-1
|
|
6
|
+
BOT_API_KEY=replace_me
|
|
7
|
+
|
|
8
|
+
CHAIN_ID=10143
|
|
9
|
+
CLAIM_ATTESTATION_VERIFIER_ADDRESS=0x76AB8571cED9F4A81b733969216F53C1e13BC835
|
|
10
|
+
# Temporary bootstrap key (public and unsafe). Replace via bot-init before real usage.
|
|
11
|
+
PARTICIPANT_PRIVATE_KEY=__TEMP_PRIVATE_KEY__
|
|
12
|
+
PARTICIPANT_ADDRESS=0x00
|
|
13
|
+
|
|
14
|
+
PARTICIPANT_REQUIRE_EXPLICIT_SUBMIT=true
|
|
15
|
+
PARTICIPANT_AUTO_SUBMIT=false
|
|
16
|
+
# PARTICIPANT_TRUSTED_RELAYER_HOSTS=openfunderse-relayer.example.com
|
|
17
|
+
# PARTICIPANT_ALLOW_HTTP_RELAYER=true
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# OpenFunderse strategy env scaffold
|
|
2
|
+
# Copy values from your STRATEGY_PK, ADDRESS
|
|
3
|
+
|
|
4
|
+
RELAYER_URL=https://openfunderse-relayer-liard.vercel.app/
|
|
5
|
+
BOT_ID=bot-strategy-1
|
|
6
|
+
BOT_API_KEY=replace_me
|
|
7
|
+
CHAIN_ID=10143
|
|
8
|
+
RPC_URL=https://testnet-rpc.monad.xyz
|
|
9
|
+
|
|
10
|
+
# NadFun / protocol addresses
|
|
11
|
+
INTENT_BOOK_ADDRESS=0x76AB8571cED9F4A81b733969216F53C1e13BC835
|
|
12
|
+
NADFUN_EXECUTION_ADAPTER_ADDRESS=0x7949DBd0779Cd829D1B2491A33C8EcCc88669Aa4
|
|
13
|
+
ADAPTER_ADDRESS=0x7949DBd0779Cd829D1B2491A33C8EcCc88669Aa4
|
|
14
|
+
VAULT_ADDRESS=0x34FB76f115f4C4E461eB90eA9f92faEF8c4A5E0A
|
|
15
|
+
NADFUN_LENS_ADDRESS=0xB056d79CA5257589692699a46623F901a3BB76f1
|
|
16
|
+
NADFUN_BONDING_CURVE_ROUTER=0x865054F0F6A288adaAc30261731361EA7E908003
|
|
17
|
+
NADFUN_DEX_ROUTER=0x5D4a4f430cA3B1b2dB86B9cFE48a5316800F5fb2
|
|
18
|
+
NADFUN_WMON_ADDRESS=0xFb8bE43D65FBC1290D6178C6DbA6E58c6D18fA60
|
|
19
|
+
|
|
20
|
+
# Strategy signer (EOA)
|
|
21
|
+
# Temporary bootstrap key (public and unsafe). Replace via bot-init before real usage.
|
|
22
|
+
STRATEGY_PRIVATE_KEY=__TEMP_PRIVATE_KEY__
|
|
23
|
+
STRATEGY_ADDRESS=0x00
|
|
24
|
+
|
|
25
|
+
# STRATEGY_CREATE_MIN_SIGNER_BALANCE_WEI=10000000000000000
|
|
26
|
+
|
|
27
|
+
# Safety defaults
|
|
28
|
+
STRATEGY_REQUIRE_EXPLICIT_SUBMIT=true
|
|
29
|
+
STRATEGY_AUTO_SUBMIT=false
|
|
30
|
+
# STRATEGY_TRUSTED_RELAYER_HOSTS=openfunderse-relayer.example.com
|
|
31
|
+
# STRATEGY_ALLOW_HTTP_RELAYER=true
|
package/README.md
CHANGED
|
@@ -15,8 +15,11 @@ npx @wiimdy/openfunderse@latest bot-init --skill-name strategy --yes
|
|
|
15
15
|
# or
|
|
16
16
|
npx @wiimdy/openfunderse@latest bot-init --skill-name participant --yes
|
|
17
17
|
|
|
18
|
-
# 3) load env in current shell
|
|
19
|
-
|
|
18
|
+
# 3) (optional) load env in current shell
|
|
19
|
+
# @wiimdy/openfunderse-agents auto-loads .env.strategy / .env.participant by command role.
|
|
20
|
+
set -a; source .env.strategy; set +a
|
|
21
|
+
# or
|
|
22
|
+
set -a; source .env.participant; set +a
|
|
20
23
|
```
|
|
21
24
|
|
|
22
25
|
## Where Files Are Stored
|
|
@@ -30,5 +33,7 @@ set -a; source .env; set +a
|
|
|
30
33
|
- Use only:
|
|
31
34
|
- `openfunderse-strategy`
|
|
32
35
|
- `openfunderse-participant`
|
|
33
|
-
- Default env scaffold path is
|
|
34
|
-
-
|
|
36
|
+
- Default env scaffold path is role-based:
|
|
37
|
+
- strategy: `.env.strategy`
|
|
38
|
+
- participant: `.env.participant`
|
|
39
|
+
- Use `--env-path` only when you want a custom filename/location.
|
package/bin/openfunderse.mjs
CHANGED
|
@@ -7,10 +7,13 @@ import os from "node:os";
|
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { createInterface } from "node:readline/promises";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
|
10
11
|
|
|
11
12
|
const THIS_FILE = fileURLToPath(import.meta.url);
|
|
12
13
|
const PACKAGE_ROOT = path.resolve(path.dirname(THIS_FILE), "..");
|
|
13
14
|
const PACKS_ROOT = path.join(PACKAGE_ROOT, "packs");
|
|
15
|
+
const STRATEGY_ENV_TEMPLATE_PATH = path.join(PACKAGE_ROOT, ".env.strategy.example");
|
|
16
|
+
const PARTICIPANT_ENV_TEMPLATE_PATH = path.join(PACKAGE_ROOT, ".env.participant.example");
|
|
14
17
|
const DEFAULT_RUNTIME_PACKAGE = "@wiimdy/openfunderse-agents";
|
|
15
18
|
const SUPPORTED_ENV_PROFILES = new Set(["strategy", "participant", "all"]);
|
|
16
19
|
const SUPPORTED_BOT_INIT_ROLES = new Set(["strategy", "participant"]);
|
|
@@ -314,12 +317,37 @@ function runtimeEnvExamplePath(runtimeDir, runtimePackage) {
|
|
|
314
317
|
return path.join(runtimeDir, "node_modules", ...runtimePackage.split("/"), ".env.example");
|
|
315
318
|
}
|
|
316
319
|
|
|
320
|
+
function defaultEnvFileNameForProfile(profile) {
|
|
321
|
+
if (profile === "strategy") {
|
|
322
|
+
return ".env.strategy";
|
|
323
|
+
}
|
|
324
|
+
if (profile === "participant") {
|
|
325
|
+
return ".env.participant";
|
|
326
|
+
}
|
|
327
|
+
return ".env";
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function applyTemplateTokens(template) {
|
|
331
|
+
return template.replaceAll("__TEMP_PRIVATE_KEY__", TEMP_PRIVATE_KEY);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
async function readProfileTemplate(profile) {
|
|
335
|
+
const templatePath =
|
|
336
|
+
profile === "strategy" ? STRATEGY_ENV_TEMPLATE_PATH : PARTICIPANT_ENV_TEMPLATE_PATH;
|
|
337
|
+
const fallback = profile === "strategy" ? STRATEGY_ENV_TEMPLATE : PARTICIPANT_ENV_TEMPLATE;
|
|
338
|
+
if (!existsSync(templatePath)) {
|
|
339
|
+
return fallback;
|
|
340
|
+
}
|
|
341
|
+
const template = await readFile(templatePath, "utf8");
|
|
342
|
+
return applyTemplateTokens(template);
|
|
343
|
+
}
|
|
344
|
+
|
|
317
345
|
async function buildEnvScaffold(profile, runtimeDir, runtimePackage) {
|
|
318
346
|
if (profile === "strategy") {
|
|
319
|
-
return
|
|
347
|
+
return readProfileTemplate("strategy");
|
|
320
348
|
}
|
|
321
349
|
if (profile === "participant") {
|
|
322
|
-
return
|
|
350
|
+
return readProfileTemplate("participant");
|
|
323
351
|
}
|
|
324
352
|
|
|
325
353
|
const runtimeTemplate = runtimeEnvExamplePath(runtimeDir, runtimePackage);
|
|
@@ -327,7 +355,9 @@ async function buildEnvScaffold(profile, runtimeDir, runtimePackage) {
|
|
|
327
355
|
return readFile(runtimeTemplate, "utf8");
|
|
328
356
|
}
|
|
329
357
|
|
|
330
|
-
|
|
358
|
+
const strategy = await readProfileTemplate("strategy");
|
|
359
|
+
const participant = await readProfileTemplate("participant");
|
|
360
|
+
return `${strategy}\n\n${participant}`;
|
|
331
361
|
}
|
|
332
362
|
|
|
333
363
|
async function writeEnvScaffold(options) {
|
|
@@ -340,7 +370,7 @@ async function writeEnvScaffold(options) {
|
|
|
340
370
|
const profile = normalizeEnvProfile(rawProfile);
|
|
341
371
|
const envTarget = options.envFile
|
|
342
372
|
? path.resolve(options.envFile)
|
|
343
|
-
: path.join(runtimeDir,
|
|
373
|
+
: path.join(runtimeDir, defaultEnvFileNameForProfile(profile));
|
|
344
374
|
|
|
345
375
|
const alreadyExists = existsSync(envTarget);
|
|
346
376
|
if (alreadyExists && !options.force) {
|
|
@@ -367,7 +397,7 @@ async function writeEnvScaffold(options) {
|
|
|
367
397
|
}
|
|
368
398
|
|
|
369
399
|
function defaultEnvPathForRole(role) {
|
|
370
|
-
return path.join(process.cwd(),
|
|
400
|
+
return path.join(process.cwd(), `.env.${role}`);
|
|
371
401
|
}
|
|
372
402
|
|
|
373
403
|
function readAssignedEnvValue(content, key) {
|
|
@@ -418,43 +448,6 @@ function shellQuote(input) {
|
|
|
418
448
|
return `'${input.replace(/'/g, `'\\''`)}'`;
|
|
419
449
|
}
|
|
420
450
|
|
|
421
|
-
async function runCommandCapture(cmd, args, cwd = process.cwd()) {
|
|
422
|
-
return await new Promise((resolve, reject) => {
|
|
423
|
-
const child = spawn(cmd, args, {
|
|
424
|
-
cwd,
|
|
425
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
const stdout = [];
|
|
429
|
-
const stderr = [];
|
|
430
|
-
|
|
431
|
-
child.stdout.on("data", (chunk) => {
|
|
432
|
-
stdout.push(chunk);
|
|
433
|
-
});
|
|
434
|
-
child.stderr.on("data", (chunk) => {
|
|
435
|
-
stderr.push(chunk);
|
|
436
|
-
});
|
|
437
|
-
child.on("error", (error) => {
|
|
438
|
-
reject(error);
|
|
439
|
-
});
|
|
440
|
-
child.on("exit", (code) => {
|
|
441
|
-
if (code === 0) {
|
|
442
|
-
resolve({
|
|
443
|
-
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
444
|
-
stderr: Buffer.concat(stderr).toString("utf8")
|
|
445
|
-
});
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
448
|
-
const stderrText = Buffer.concat(stderr).toString("utf8").trim();
|
|
449
|
-
reject(
|
|
450
|
-
new Error(
|
|
451
|
-
`command failed: ${cmd} ${args.join(" ")} (exit ${code})${stderrText ? ` - ${stderrText}` : ""}`
|
|
452
|
-
)
|
|
453
|
-
);
|
|
454
|
-
});
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
|
|
458
451
|
async function confirmBotInit({ role, envFile, privateKeyKey, isRotation, assumeYes }) {
|
|
459
452
|
const mode = isRotation ? "wallet rotation" : "new wallet bootstrap";
|
|
460
453
|
console.log("WARNING: bot-init will generate a new wallet and update your env private key.");
|
|
@@ -486,39 +479,11 @@ async function confirmBotInit({ role, envFile, privateKeyKey, isRotation, assume
|
|
|
486
479
|
}
|
|
487
480
|
}
|
|
488
481
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
output = await runCommandCapture("cast", ["wallet", "new", "--json"]);
|
|
493
|
-
} catch (error) {
|
|
494
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
495
|
-
if (message.includes("ENOENT")) {
|
|
496
|
-
throw new Error(
|
|
497
|
-
"cast is not installed. Install Foundry first (https://book.getfoundry.sh/getting-started/installation)."
|
|
498
|
-
);
|
|
499
|
-
}
|
|
500
|
-
throw error;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
let parsed;
|
|
504
|
-
try {
|
|
505
|
-
parsed = JSON.parse(output.stdout);
|
|
506
|
-
} catch {
|
|
507
|
-
throw new Error(`failed to parse cast output as JSON: ${output.stdout}`);
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
const first = Array.isArray(parsed) ? parsed[0] : parsed;
|
|
511
|
-
const address = String(first?.address ?? "");
|
|
512
|
-
const privateKey = String(first?.private_key ?? first?.privateKey ?? "");
|
|
513
|
-
if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {
|
|
514
|
-
throw new Error(`invalid wallet address from cast: ${address}`);
|
|
515
|
-
}
|
|
516
|
-
if (!/^0x[0-9a-fA-F]{64}$/.test(privateKey)) {
|
|
517
|
-
throw new Error("invalid private key from cast output");
|
|
518
|
-
}
|
|
519
|
-
|
|
482
|
+
function generateMonadWalletWithViem() {
|
|
483
|
+
const privateKey = generatePrivateKey();
|
|
484
|
+
const account = privateKeyToAccount(privateKey);
|
|
520
485
|
return {
|
|
521
|
-
address,
|
|
486
|
+
address: account.address,
|
|
522
487
|
privateKey
|
|
523
488
|
};
|
|
524
489
|
}
|
|
@@ -551,10 +516,13 @@ async function persistWallet(role, wallet, options) {
|
|
|
551
516
|
if (rawName.includes("/") || rawName.includes("\\")) {
|
|
552
517
|
throw new Error("--wallet-name must be a file name, not a path");
|
|
553
518
|
}
|
|
554
|
-
const
|
|
555
|
-
const walletPath = path.join(walletDir,
|
|
556
|
-
|
|
557
|
-
|
|
519
|
+
const baseName = rawName.endsWith(".json") ? rawName.slice(0, -".json".length) : rawName;
|
|
520
|
+
const walletPath = path.join(walletDir, `${baseName}.json`);
|
|
521
|
+
const privateKeyPath = path.join(walletDir, `${baseName}.private-key`);
|
|
522
|
+
if ((existsSync(walletPath) || existsSync(privateKeyPath)) && !options.force) {
|
|
523
|
+
throw new Error(
|
|
524
|
+
`wallet file already exists: ${walletPath} or ${privateKeyPath} (use --force to overwrite)`
|
|
525
|
+
);
|
|
558
526
|
}
|
|
559
527
|
|
|
560
528
|
const payload = {
|
|
@@ -565,11 +533,22 @@ async function persistWallet(role, wallet, options) {
|
|
|
565
533
|
privateKey: wallet.privateKey
|
|
566
534
|
};
|
|
567
535
|
await mkdir(walletDir, { recursive: true, mode: 0o700 });
|
|
536
|
+
if (options.force) {
|
|
537
|
+
await rm(walletPath, { force: true });
|
|
538
|
+
await rm(privateKeyPath, { force: true });
|
|
539
|
+
}
|
|
568
540
|
await writeFile(walletPath, `${JSON.stringify(payload, null, 2)}\n`, {
|
|
569
541
|
mode: 0o600
|
|
570
542
|
});
|
|
543
|
+
await writeFile(privateKeyPath, `${wallet.privateKey}\n`, {
|
|
544
|
+
mode: 0o600
|
|
545
|
+
});
|
|
571
546
|
await chmod(walletPath, 0o600);
|
|
572
|
-
|
|
547
|
+
await chmod(privateKeyPath, 0o600);
|
|
548
|
+
return {
|
|
549
|
+
walletPath,
|
|
550
|
+
privateKeyPath
|
|
551
|
+
};
|
|
573
552
|
}
|
|
574
553
|
|
|
575
554
|
function assertPrivateKeyRotationAllowed(envContent, role, force) {
|
|
@@ -609,8 +588,8 @@ async function runBotInit(options) {
|
|
|
609
588
|
assumeYes: options.yes
|
|
610
589
|
});
|
|
611
590
|
|
|
612
|
-
const wallet =
|
|
613
|
-
const
|
|
591
|
+
const wallet = generateMonadWalletWithViem();
|
|
592
|
+
const walletFiles = await persistWallet(role, wallet, options);
|
|
614
593
|
const updates = roleEnvUpdates(role, wallet);
|
|
615
594
|
const nextEnvContent = upsertEnvValues(envContent, updates);
|
|
616
595
|
|
|
@@ -622,7 +601,8 @@ async function runBotInit(options) {
|
|
|
622
601
|
console.log(`Initialized ${role} bot wallet for Monad testnet (${DEFAULT_MONAD_CHAIN_ID}).`);
|
|
623
602
|
console.log(`Address: ${wallet.address}`);
|
|
624
603
|
console.log(`Env file updated: ${envFile}`);
|
|
625
|
-
console.log(`Wallet backup (keep secret): ${walletPath}`);
|
|
604
|
+
console.log(`Wallet backup (keep secret): ${walletFiles.walletPath}`);
|
|
605
|
+
console.log(`Private key backup (keep secret): ${walletFiles.privateKeyPath}`);
|
|
626
606
|
console.log(`Load env now: ${sourceCommand}`);
|
|
627
607
|
}
|
|
628
608
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wiimdy/openfunderse",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "Install OpenFunderse skill packs into Codex",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,8 +9,13 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"bin",
|
|
11
11
|
"packs",
|
|
12
|
+
".env.strategy.example",
|
|
13
|
+
".env.participant.example",
|
|
12
14
|
"README.md"
|
|
13
15
|
],
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"viem": "^2.38.2"
|
|
18
|
+
},
|
|
14
19
|
"engines": {
|
|
15
20
|
"node": ">=20"
|
|
16
21
|
},
|