repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | import { existsSync, mkdirSync } from "node:fs"; |
| #2 | import { resolve } from "node:path"; |
| #3 | import { spawnSync } from "node:child_process"; |
| #4 | const DEFAULT_SOL_MINT = "So11111111111111111111111111111111111111112"; |
| #5 | const DEFAULT_USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; |
| #6 | function repoCandidates() { |
| #7 | const explicit = process.env.CLAWD_TWAMM_ROOT; |
| #8 | const cwd = process.cwd(); |
| #9 | return [ |
| #10 | ...(explicit ? [explicit] : []), |
| #11 | resolve(cwd, "Perps", "twamm-master"), |
| #12 | resolve(cwd, "..", "Perps", "twamm-master"), |
| #13 | resolve(cwd, "..", "..", "Perps", "twamm-master"), |
| #14 | ]; |
| #15 | } |
| #16 | export function resolveTwammRoot() { |
| #17 | for (const candidate of repoCandidates()) { |
| #18 | if (existsSync(resolve(candidate, "Anchor.toml")) && existsSync(resolve(candidate, "app", "src", "crank.ts"))) { |
| #19 | return candidate; |
| #20 | } |
| #21 | } |
| #22 | return process.env.CLAWD_TWAMM_ROOT || resolve(process.cwd(), "Perps", "twamm-master"); |
| #23 | } |
| #24 | function defaultRpcUrl() { |
| #25 | return process.env.CLAWD_TWAMM_RPC_URL || process.env.SOLANA_RPC_URL || "local"; |
| #26 | } |
| #27 | function defaultTokenAMint() { |
| #28 | return process.env.CLAWD_TWAMM_TOKEN_A_MINT || DEFAULT_SOL_MINT; |
| #29 | } |
| #30 | function defaultTokenBMint() { |
| #31 | return process.env.CLAWD_TWAMM_TOKEN_B_MINT || DEFAULT_USDC_MINT; |
| #32 | } |
| #33 | function baseWarnings() { |
| #34 | const warnings = [ |
| #35 | "Reference TWAMM implementation is unaudited for this perps automation layer.", |
| #36 | "The crank runner signs permissionless crank transactions while running.", |
| #37 | "Use localnet/devnet first and require explicit operator confirmation for mainnet.", |
| #38 | ]; |
| #39 | if (!process.env.CLAWD_TWAMM_TOKEN_A_MINT || !process.env.CLAWD_TWAMM_TOKEN_B_MINT) { |
| #40 | warnings.push("CLAWD_TWAMM_TOKEN_A_MINT/B_MINT not set; defaulting to SOL/USDC mints."); |
| #41 | } |
| #42 | return warnings; |
| #43 | } |
| #44 | export function getTwammAutomationStatus() { |
| #45 | const root = resolveTwammRoot(); |
| #46 | return { |
| #47 | root, |
| #48 | exists: existsSync(root), |
| #49 | anchorToml: existsSync(resolve(root, "Anchor.toml")), |
| #50 | cargoToml: existsSync(resolve(root, "Cargo.toml")), |
| #51 | appPackage: existsSync(resolve(root, "app", "package.json")), |
| #52 | crankScript: existsSync(resolve(root, "app", "src", "crank.ts")), |
| #53 | programIdl: existsSync(resolve(root, "target", "idl", "twamm.json")), |
| #54 | defaultRpcUrl: defaultRpcUrl(), |
| #55 | tokenAMint: defaultTokenAMint(), |
| #56 | tokenBMint: defaultTokenBMint(), |
| #57 | liveEnabled: process.env.CLAWD_TWAMM_LIVE === "true", |
| #58 | operatorConfirmed: process.env.OPERATOR_CONFIRMED === "true", |
| #59 | warnings: baseWarnings(), |
| #60 | }; |
| #61 | } |
| #62 | export function buildTwammBuildPlan(options = {}) { |
| #63 | const status = getTwammAutomationStatus(); |
| #64 | const warnings = [...status.warnings]; |
| #65 | if (!options.skipAppInstall && !existsSync(resolve(status.root, "node_modules"))) { |
| #66 | warnings.push("Run npm install in the TWAMM root before anchor build, or use the build command to do it automatically."); |
| #67 | } |
| #68 | return { |
| #69 | mode: "build", |
| #70 | command: "anchor", |
| #71 | cwd: status.root, |
| #72 | args: ["build"], |
| #73 | env: { RUST_BACKTRACE: process.env.RUST_BACKTRACE || "1" }, |
| #74 | warnings, |
| #75 | }; |
| #76 | } |
| #77 | export function buildTwammTestPlan(options = {}) { |
| #78 | const status = getTwammAutomationStatus(); |
| #79 | const runAnchor = options.anchor ?? true; |
| #80 | const runCargo = options.cargo ?? false; |
| #81 | const args = runAnchor ? ["test", "--", "--features", "test"] : ["test", "--", "--nocapture"]; |
| #82 | return { |
| #83 | mode: "test", |
| #84 | command: runAnchor && !runCargo ? "anchor" : "cargo", |
| #85 | cwd: status.root, |
| #86 | args, |
| #87 | env: { RUST_BACKTRACE: process.env.RUST_BACKTRACE || "1" }, |
| #88 | warnings: status.warnings, |
| #89 | }; |
| #90 | } |
| #91 | export function buildTwammCrankPlan(options = {}) { |
| #92 | const status = getTwammAutomationStatus(); |
| #93 | const warnings = [...status.warnings]; |
| #94 | if (!status.liveEnabled || !status.operatorConfirmed || !options.yes) { |
| #95 | warnings.push("Crank command is blocked until CLAWD_TWAMM_LIVE=true, OPERATOR_CONFIRMED=true, and --yes are all present."); |
| #96 | } |
| #97 | return { |
| #98 | mode: "crank", |
| #99 | command: "npx", |
| #100 | cwd: status.root, |
| #101 | args: [ |
| #102 | "ts-node", |
| #103 | "-P", |
| #104 | "tsconfig.json", |
| #105 | "app/src/crank.ts", |
| #106 | options.rpcUrl || status.defaultRpcUrl, |
| #107 | options.tokenAMint || status.tokenAMint, |
| #108 | options.tokenBMint || status.tokenBMint, |
| #109 | ], |
| #110 | env: { |
| #111 | RUST_BACKTRACE: process.env.RUST_BACKTRACE || "1", |
| #112 | ...(options.walletPath ? { ANCHOR_WALLET: options.walletPath } : {}), |
| #113 | ...(options.once ? { CLAWD_TWAMM_CRANK_ONCE: "true" } : {}), |
| #114 | }, |
| #115 | warnings, |
| #116 | }; |
| #117 | } |
| #118 | export function buildTwammAutomation(options = {}) { |
| #119 | const status = getTwammAutomationStatus(); |
| #120 | if (!status.exists || !status.anchorToml) { |
| #121 | return { ok: false, status, error: "TWAMM workspace not found. Set CLAWD_TWAMM_ROOT." }; |
| #122 | } |
| #123 | mkdirSync(resolve(status.root, "target"), { recursive: true }); |
| #124 | if (!options.skipAppInstall && !existsSync(resolve(status.root, "node_modules"))) { |
| #125 | const install = spawnSync("npm", ["install"], { |
| #126 | cwd: status.root, |
| #127 | env: process.env, |
| #128 | stdio: "pipe", |
| #129 | encoding: "utf8", |
| #130 | }); |
| #131 | if (install.status !== 0) { |
| #132 | return { |
| #133 | ok: false, |
| #134 | status: getTwammAutomationStatus(), |
| #135 | step: "npm install", |
| #136 | stdout: install.stdout, |
| #137 | stderr: install.stderr, |
| #138 | error: install.error?.message, |
| #139 | }; |
| #140 | } |
| #141 | } |
| #142 | const result = spawnSync("anchor", ["build"], { |
| #143 | cwd: status.root, |
| #144 | env: process.env, |
| #145 | stdio: "pipe", |
| #146 | encoding: "utf8", |
| #147 | }); |
| #148 | return { |
| #149 | ok: result.status === 0, |
| #150 | status: getTwammAutomationStatus(), |
| #151 | stdout: result.stdout, |
| #152 | stderr: result.stderr, |
| #153 | error: result.error?.message, |
| #154 | }; |
| #155 | } |
| #156 | export function runTwammCrank(options = {}) { |
| #157 | const status = getTwammAutomationStatus(); |
| #158 | if (!status.exists || !status.crankScript) { |
| #159 | console.error("error: TWAMM workspace not found. Set CLAWD_TWAMM_ROOT."); |
| #160 | process.exit(2); |
| #161 | } |
| #162 | if (!status.liveEnabled || !status.operatorConfirmed || !options.yes) { |
| #163 | console.error("error: TWAMM crank is gated. Set CLAWD_TWAMM_LIVE=true, OPERATOR_CONFIRMED=true, and pass --yes."); |
| #164 | process.exit(3); |
| #165 | } |
| #166 | const plan = buildTwammCrankPlan(options); |
| #167 | const result = spawnSync(plan.command, plan.args, { |
| #168 | cwd: plan.cwd, |
| #169 | env: { ...process.env, ...plan.env }, |
| #170 | stdio: "inherit", |
| #171 | }); |
| #172 | if (result.error) { |
| #173 | console.error(`error: failed to run TWAMM crank: ${result.error.message}`); |
| #174 | process.exit(127); |
| #175 | } |
| #176 | process.exit(typeof result.status === "number" ? result.status : 1); |
| #177 | } |
| #178 | //# sourceMappingURL=twammAutomation.js.map |