@sherwoodagent/cli 0.81.0 → 0.83.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/{abis-OLIDCWDS.js → abis-ZQ6I3S6L.js} +2 -4
- package/dist/{addresses-EF5OQSKV.js → addresses-MS6BB7AB.js} +3 -3
- package/dist/{agent-VLYILEUP.js → agent-I6AUSTZG.js} +7 -7
- package/dist/{chat-ANE3SNHH.js → chat-5SI7K5FA.js} +8 -8
- package/dist/{chunk-Z7GRB3OQ.js → chunk-4BMAFJKO.js} +6 -6
- package/dist/{chunk-BJ4G3TPP.js → chunk-5BYJ3TGZ.js} +2 -2
- package/dist/{chunk-WUYJ7AS6.js → chunk-5O3KO7ZI.js} +3 -3
- package/dist/{chunk-QSYLZA4Z.js → chunk-7ILOT3SI.js} +2 -2
- package/dist/{chunk-QK3FUTVI.js → chunk-I7NXKJCG.js} +5 -5
- package/dist/{chunk-XW6NDXBA.js → chunk-I7TMY7AS.js} +12 -12
- package/dist/{chunk-XW6NDXBA.js.map → chunk-I7TMY7AS.js.map} +1 -1
- package/dist/{chunk-XDWYX5ZM.js → chunk-MRUTBOMZ.js} +2 -2
- package/dist/{chunk-54WMDJTL.js → chunk-N5RIB6ZZ.js} +386 -5
- package/dist/chunk-N5RIB6ZZ.js.map +1 -0
- package/dist/{chunk-RFJSV3EZ.js → chunk-UK2G5AZG.js} +5 -5
- package/dist/{chunk-TU655ZTV.js → chunk-XSP64L7L.js} +1102 -480
- package/dist/chunk-XSP64L7L.js.map +1 -0
- package/dist/{chunk-K2NEFUEP.js → chunk-ZEZQM42M.js} +5 -5
- package/dist/chunk-ZEZQM42M.js.map +1 -0
- package/dist/{chunk-UO4UITOY.js → chunk-ZTR2GPZO.js} +28 -7
- package/dist/chunk-ZTR2GPZO.js.map +1 -0
- package/dist/{chunk-VJKZDHH3.js → chunk-ZW2VKCFZ.js} +11 -10
- package/dist/chunk-ZW2VKCFZ.js.map +1 -0
- package/dist/{client-25LF2O4P.js → client-Z7LNEG2F.js} +3 -3
- package/dist/{cron-QMLRWDJG.js → cron-E3UAZF5B.js} +1 -1
- package/dist/cron-E3UAZF5B.js.map +1 -0
- package/dist/{eas-HHMRO37P.js → eas-DWBT332K.js} +6 -6
- package/dist/{governor-AL2XUGBE.js → governor-ZVNTHHML.js} +6 -6
- package/dist/index.js +4837 -4576
- package/dist/index.js.map +1 -1
- package/dist/{network-R45QDUYO.js → network-HCFCNZUI.js} +2 -2
- package/dist/{price-QO22NF5Q.js → price-GEUCSTO4.js} +6 -6
- package/dist/{providers-ALMXBRNW.js → providers-PWUJ2AR7.js} +4 -4
- package/dist/{research-IFMAQWCH.js → research-SW6PLO32.js} +7 -7
- package/dist/{session-BE52OSEV.js → session-6RSOG5NE.js} +11 -11
- package/dist/{trade-YNQVWUYZ.js → trade-45JPCKGP.js} +16 -16
- package/dist/trade-45JPCKGP.js.map +1 -0
- package/dist/{vault-KE5TKCSY.js → vault-GAIOZZPC.js} +8 -8
- package/dist/{xmtp-M2OBCCNR.js → xmtp-A2KIQWGA.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-54WMDJTL.js.map +0 -1
- package/dist/chunk-K2NEFUEP.js.map +0 -1
- package/dist/chunk-TU655ZTV.js.map +0 -1
- package/dist/chunk-UO4UITOY.js.map +0 -1
- package/dist/chunk-VJKZDHH3.js.map +0 -1
- package/dist/cron-QMLRWDJG.js.map +0 -1
- package/dist/trade-YNQVWUYZ.js.map +0 -1
- /package/dist/{abis-OLIDCWDS.js.map → abis-ZQ6I3S6L.js.map} +0 -0
- /package/dist/{addresses-EF5OQSKV.js.map → addresses-MS6BB7AB.js.map} +0 -0
- /package/dist/{agent-VLYILEUP.js.map → agent-I6AUSTZG.js.map} +0 -0
- /package/dist/{chat-ANE3SNHH.js.map → chat-5SI7K5FA.js.map} +0 -0
- /package/dist/{chunk-Z7GRB3OQ.js.map → chunk-4BMAFJKO.js.map} +0 -0
- /package/dist/{chunk-BJ4G3TPP.js.map → chunk-5BYJ3TGZ.js.map} +0 -0
- /package/dist/{chunk-WUYJ7AS6.js.map → chunk-5O3KO7ZI.js.map} +0 -0
- /package/dist/{chunk-QSYLZA4Z.js.map → chunk-7ILOT3SI.js.map} +0 -0
- /package/dist/{chunk-QK3FUTVI.js.map → chunk-I7NXKJCG.js.map} +0 -0
- /package/dist/{chunk-XDWYX5ZM.js.map → chunk-MRUTBOMZ.js.map} +0 -0
- /package/dist/{chunk-RFJSV3EZ.js.map → chunk-UK2G5AZG.js.map} +0 -0
- /package/dist/{client-25LF2O4P.js.map → client-Z7LNEG2F.js.map} +0 -0
- /package/dist/{eas-HHMRO37P.js.map → eas-DWBT332K.js.map} +0 -0
- /package/dist/{governor-AL2XUGBE.js.map → governor-ZVNTHHML.js.map} +0 -0
- /package/dist/{network-R45QDUYO.js.map → network-HCFCNZUI.js.map} +0 -0
- /package/dist/{price-QO22NF5Q.js.map → price-GEUCSTO4.js.map} +0 -0
- /package/dist/{providers-ALMXBRNW.js.map → providers-PWUJ2AR7.js.map} +0 -0
- /package/dist/{research-IFMAQWCH.js.map → research-SW6PLO32.js.map} +0 -0
- /package/dist/{session-BE52OSEV.js.map → session-6RSOG5NE.js.map} +0 -0
- /package/dist/{vault-KE5TKCSY.js.map → vault-GAIOZZPC.js.map} +0 -0
- /package/dist/{xmtp-M2OBCCNR.js.map → xmtp-A2KIQWGA.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/governor.ts","../src/lib/generated/proposal-state.ts"],"sourcesContent":["/**\n * Governor contract wrapper — reads/writes to SyndicateGovernor.\n *\n * Per-vault governor design: the factory deploys ONE governor per vault\n * (BeaconProxy). Every helper takes the vault address and resolves its\n * governor via `factory.governorOf(vault)` (memoized per chain+vault —\n * the binding is set once at createSyndicate and never changes).\n *\n * Protocol-wide fee parameters (protocol/guardian fee bps + recipients)\n * live on the separate ProtocolConfig contract, resolved via\n * `factory.protocolConfig()`.\n */\n\nimport type { Address, Hex, Log } from \"viem\";\nimport { parseEventLogs } from \"viem\";\nimport { getPublicClient, getAccount, writeContractWithRetry, waitForReceipt } from \"./client.js\";\nimport { getChain } from \"./network.js\";\nimport { SHERWOOD } from \"./addresses.js\";\nimport { SYNDICATE_GOVERNOR_ABI, SYNDICATE_FACTORY_ABI, PROTOCOL_CONFIG_ABI } from \"./abis.js\";\nimport { PROPOSAL_STATE, PROPOSAL_STATES } from \"./generated/proposal-state.js\";\n\n// ── Types ──\n\nexport interface GovernorParams {\n votingPeriod: bigint;\n executionWindow: bigint;\n vetoThresholdBps: bigint;\n maxPerformanceFeeBps: bigint;\n cooldownPeriod: bigint;\n collaborationWindow: bigint;\n maxCoProposers: bigint;\n minStrategyDuration: bigint;\n maxStrategyDuration: bigint;\n}\n\nexport interface StrategyProposal {\n id: bigint;\n proposer: Address;\n vault: Address;\n /** Strategy contract address whose `positionValue()` the vault polls\n * for live NAV. Set at propose time, immutable thereafter. address(0)\n * for queue-only proposals (no live NAV). */\n strategy: Address;\n metadataURI: string;\n /** Agent fee (bps) snapshotted from the vault's `agentFeeBps` at propose. */\n performanceFeeBps: bigint;\n strategyDuration: bigint;\n votesFor: bigint;\n votesAgainst: bigint;\n votesAbstain: bigint;\n snapshotTimestamp: bigint;\n voteEnd: bigint;\n reviewEnd: bigint;\n executeBy: bigint;\n executedAt: bigint;\n state: number;\n vetoThresholdBps: bigint;\n /** Fee snapshot taken from ProtocolConfig at propose time (PR #421). These\n * four fields sit between `vetoThresholdBps` and `selfManagesFees` in the\n * on-chain `StrategyProposal` struct — omitting them corrupts tuple decode. */\n snapshotProtocolFeeBps: bigint;\n snapshotProtocolFeeRecipient: Address;\n snapshotGuardianFeeBps: bigint;\n snapshotGuardiansFeeRecipient: Address;\n /** `IStrategy.selfManagesFees()` snapshotted at propose (PR #388 #2); read\n * from storage at settle so it can't flip mid-flight or brick settlement. */\n selfManagesFees: boolean;\n}\n\nexport interface CoProposer {\n agent: Address;\n splitBps: bigint;\n}\n\nexport interface BatchCall {\n target: Address;\n data: Hex;\n value: bigint;\n}\n\n// ProposalState ordering is code-generated from the Solidity enum\n// (contracts/src/interfaces/ISyndicateGovernor.sol) — `npm run codegen`.\n// History: PR #229 inserted GuardianReview at index 2 and this hand-kept\n// mirror drifted for ~2 months, mislabeling Approved (3) as Rejected and\n// making `proposal execute` reject valid approved proposals. The generated\n// module (checked by codegen-drift.test.ts + CI) makes that impossible.\nexport { PROPOSAL_STATE, PROPOSAL_STATES };\n\nexport const VOTE_TYPE = {\n For: 0,\n Against: 1,\n Abstain: 2,\n} as const;\n\n// ── Client-side action gates (mirror SyndicateGovernor) ──\n//\n// The governor's mutating entrypoints resolve state INLINE and can act on a\n// state the read-only `getProposalState` view is still reporting as\n// GuardianReview. The client gates below reproduce that divergence so the CLI\n// stops refusing txs the contract would accept (issue #452).\n\n/** Result of the `proposal execute` client gate. */\nexport type ExecuteGate =\n | { kind: \"send\" } // state == Approved — straightforward execute.\n | { kind: \"send-self-resolve\" } // GuardianReview, window elapsed, still within\n // the execution window — executeProposal\n // self-resolves the (cold-start) review inline.\n | { kind: \"refuse-review-open\" } // GuardianReview, review window still open — the\n // tx WOULD revert (ProposalNotApproved).\n | { kind: \"refuse-expired\" } // GuardianReview past executeBy — the inline\n // self-resolve maps to Expired, tx WOULD revert.\n | { kind: \"refuse-state\" }; // any other non-executable state.\n\n/**\n * Decide whether `executeProposal(id)` should be broadcast.\n *\n * Mirrors `SyndicateGovernor.executeProposal` (contracts/src/SyndicateGovernor.sol:342)\n * vs. the `getProposalState` view:\n * - The view (`_resolveStateView` @824 / `_resolveAfterVote` @865) keeps\n * reporting `GuardianReview` once the review window elapses but the registry\n * has not cached a resolution — a zero-guardian / never-opened cold-start\n * review NEVER auto-opens, so the view is stuck there indefinitely.\n * - `executeProposal` runs the MUTATING `_resolveState` (@789) which, when the\n * window elapsed (`now > reviewEnd`), calls `registry.resolveReview` inline\n * (cold-start ⇒ blocked=false) and maps to Approved when `now <= executeBy`\n * (else Expired) — then executes in the same tx.\n * Invariant `voteEnd < reviewEnd < executeBy` (@528-530) holds for any past-vote\n * proposal, so `reviewEnd`/`executeBy` are always populated in the GuardianReview\n * branch.\n *\n * `now` MUST be chain time (latest block timestamp), not wall-clock — on a\n * time-warped vnet the two diverge and the contract compares against chain time.\n */\nexport function evaluateExecuteGate(args: {\n state: number;\n reviewEnd: bigint;\n executeBy: bigint;\n now: bigint;\n}): ExecuteGate {\n const { state, reviewEnd, executeBy, now } = args;\n if (state === PROPOSAL_STATE.Approved) return { kind: \"send\" };\n if (state === PROPOSAL_STATE.GuardianReview) {\n if (now <= reviewEnd) return { kind: \"refuse-review-open\" };\n if (now > executeBy) return { kind: \"refuse-expired\" };\n return { kind: \"send-self-resolve\" };\n }\n return { kind: \"refuse-state\" };\n}\n\n/**\n * Classification for the `resolve-reviews` keeper.\n * - `resolvable`: an OPENED, unresolved review past its window — needs a real\n * `resolveReview` tx (computes block quorum, may slash approvers).\n * - `cold-start`: an UNOPENED, unresolved review past its window — the\n * zero-guardian case. `resolveReview` would only mark it resolved/not-blocked\n * (GuardianRegistry.resolveReview @639-643), which `executeProposal`\n * already does inline, so the keeper should report it (pointing at\n * `proposal execute`) rather than spend a redundant tx.\n * - `none`: not past window yet, or already resolved.\n */\nexport type ReviewResolveClass = \"resolvable\" | \"cold-start\" | \"none\";\n\nexport function classifyReview(args: {\n opened: boolean;\n resolved: boolean;\n reviewEnd: bigint;\n now: bigint;\n}): ReviewResolveClass {\n const { opened, resolved, reviewEnd, now } = args;\n const pastWindow = reviewEnd > 0n && now >= reviewEnd;\n if (!pastWindow || resolved) return \"none\";\n return opened ? \"resolvable\" : \"cold-start\";\n}\n\n// ── Duration parser ──\n\nexport function parseDuration(input: string): bigint {\n const match = input.match(/^(\\d+)(d|h|m|s)?$/);\n if (!match) throw new Error(`Invalid duration: ${input}`);\n const value = BigInt(match[1]);\n switch (match[2]) {\n case \"d\":\n return value * 86400n;\n case \"h\":\n return value * 3600n;\n case \"m\":\n return value * 60n;\n case \"s\":\n case undefined:\n return value;\n default:\n throw new Error(`Unknown duration unit: ${match[2]}`);\n }\n}\n\n// ── Address helpers ──\n\n// governorOf(vault) is set once at createSyndicate and never rebinds, so\n// it is safe to memoize per chain+vault for the lifetime of the process.\nconst governorCache = new Map<string, Address>();\n\n/** Resolve the per-vault governor via `factory.governorOf(vault)`. */\nexport async function getGovernorOf(vault: Address): Promise<Address> {\n const key = `${getChain().id}:${vault.toLowerCase()}`;\n const cached = governorCache.get(key);\n if (cached) return cached;\n\n const client = getPublicClient();\n const governor = await client.readContract({\n address: SHERWOOD().FACTORY,\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"governorOf\",\n args: [vault],\n }) as Address;\n\n if (governor === \"0x0000000000000000000000000000000000000000\") {\n throw new Error(`No governor registered for vault ${vault} — is it a factory-created vault?`);\n }\n\n governorCache.set(key, governor);\n return governor;\n}\n\n// ProtocolConfig is a protocol-wide singleton behind the factory — same\n// set-once semantics as governorOf, memoized per chain.\nconst protocolConfigCache = new Map<number, Address>();\n\n/** Resolve the ProtocolConfig address via `factory.protocolConfig()`. */\nexport async function getProtocolConfigAddress(): Promise<Address> {\n const chainId = getChain().id;\n const cached = protocolConfigCache.get(chainId);\n if (cached) return cached;\n\n const client = getPublicClient();\n const config = await client.readContract({\n address: SHERWOOD().FACTORY,\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"protocolConfig\",\n }) as Address;\n\n protocolConfigCache.set(chainId, config);\n return config;\n}\n\n// ── Read helpers ──\n\nexport async function getGovernorParams(vault: Address): Promise<GovernorParams> {\n const client = getPublicClient();\n const result = await client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getGovernorParams\",\n }) as {\n votingPeriod: bigint;\n executionWindow: bigint;\n vetoThresholdBps: bigint;\n maxPerformanceFeeBps: bigint;\n cooldownPeriod: bigint;\n collaborationWindow: bigint;\n maxCoProposers: bigint;\n minStrategyDuration: bigint;\n maxStrategyDuration: bigint;\n };\n return result;\n}\n\nexport async function getProposal(vault: Address, id: bigint): Promise<StrategyProposal> {\n const client = getPublicClient();\n const result = await client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getProposal\",\n args: [id],\n }) as StrategyProposal;\n return result;\n}\n\nexport async function getProposalState(vault: Address, id: bigint): Promise<number> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getProposalState\",\n args: [id],\n }) as Promise<number>;\n}\n\nexport async function proposalCount(vault: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"proposalCount\",\n }) as Promise<bigint>;\n}\n\nexport async function getVoteWeight(vault: Address, proposalId: bigint, voter: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getVoteWeight\",\n args: [proposalId, voter],\n }) as Promise<bigint>;\n}\n\nexport async function hasVoted(vault: Address, proposalId: bigint, voter: Address): Promise<boolean> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"hasVoted\",\n args: [proposalId, voter],\n }) as Promise<boolean>;\n}\n\n// `getProposalCalls` (concat of execute + settle) was dropped in V1.5\n// to reclaim governor bytecode under EIP-170. Use `getExecuteCalls`\n// + `getSettlementCalls` instead — same data, no on-chain copy loop.\n\nexport async function getExecuteCalls(vault: Address, proposalId: bigint): Promise<BatchCall[]> {\n const client = getPublicClient();\n const result = await client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getExecuteCalls\",\n args: [proposalId],\n }) as { target: Address; data: Hex; value: bigint }[];\n return result.map((c) => ({ target: c.target, data: c.data, value: c.value }));\n}\n\nexport async function getSettlementCalls(vault: Address, proposalId: bigint): Promise<BatchCall[]> {\n const client = getPublicClient();\n const result = await client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getSettlementCalls\",\n args: [proposalId],\n }) as { target: Address; data: Hex; value: bigint }[];\n return result.map((c) => ({ target: c.target, data: c.data, value: c.value }));\n}\n\n// Per-vault governor: `getRegisteredVaults` / `isRegisteredVault` were\n// removed on-chain — a governor serves exactly one vault (`governor.vault()`).\n// Enumerate vaults via the factory (`getAllActiveSyndicates`) instead.\n\nexport async function getActiveProposal(vault: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getActiveProposal\",\n }) as Promise<bigint>;\n}\n\nexport async function getCooldownEnd(vault: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getCooldownEnd\",\n }) as Promise<bigint>;\n}\n\nexport async function openProposalCount(vault: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"openProposalCount\",\n }) as Promise<bigint>;\n}\n\nexport async function getCapitalSnapshot(vault: Address, proposalId: bigint): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getCapitalSnapshot\",\n args: [proposalId],\n }) as Promise<bigint>;\n}\n\n/**\n * Extract proposalId from ProposalCreated event logs.\n * Returns undefined if the event is not found or parsing fails.\n */\nexport function parseProposalIdFromLogs(logs: Log[]): bigint | undefined {\n try {\n const parsed = parseEventLogs({\n abi: SYNDICATE_GOVERNOR_ABI,\n logs,\n eventName: \"ProposalCreated\",\n });\n return parsed[0]?.args.proposalId;\n } catch {\n return undefined;\n }\n}\n\n// ── Write helpers ──\n\nexport async function propose(\n vault: Address,\n strategy: Address,\n metadataURI: string,\n strategyDuration: bigint,\n executeCalls: BatchCall[],\n settlementCalls: BatchCall[],\n coProposers: CoProposer[] = [],\n): Promise<{ hash: Hex; proposalId: bigint }> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"propose\",\n args: [vault, strategy, metadataURI, strategyDuration, executeCalls, settlementCalls, coProposers],\n });\n\n const receipt = await waitForReceipt(hash);\n\n // Parse proposalId from the ProposalCreated event in the receipt logs.\n // Falls back to proposalCount() if event parsing fails.\n let proposalId = parseProposalIdFromLogs(receipt.logs);\n if (proposalId === undefined) {\n try {\n proposalId = await proposalCount(vault);\n } catch {\n proposalId = 0n;\n }\n }\n\n return { hash: receipt.transactionHash, proposalId };\n}\n\nexport async function vote(vault: Address, proposalId: bigint, support: number): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"vote\",\n args: [proposalId, support],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function executeProposal(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"executeProposal\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\n/**\n * Walk a proposal's executeCalls and pick the strategy clone — the\n * target of the call whose selector matches `BaseStrategy.execute()`\n * (0x61461954). This is the canonical entry point that every Sherwood\n * strategy template inherits from BaseStrategy, so it's a reliable\n * marker even across template families (Moonwell / Aerodrome /\n * Hyperliquid / Mamo / Venice / Portfolio).\n *\n * Returns null when no execute() call is present (e.g. proposals that\n * only do approves and direct ERC-20 transfers without a strategy).\n */\nexport function detectStrategyAdapter(\n calls: { target: Address; data: Hex; value: bigint }[],\n): Address | null {\n const STRATEGY_EXECUTE_SELECTOR = \"0x61461954\";\n for (const call of calls) {\n if (call.data.slice(0, 10).toLowerCase() === STRATEGY_EXECUTE_SELECTOR) {\n return call.target;\n }\n }\n return null;\n}\n\nexport async function settleProposal(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"settleProposal\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function emergencySettle(vault: Address, proposalId: bigint, calls: BatchCall[]): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"emergencySettleWithCalls\",\n args: [proposalId, calls],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function cancelProposal(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"cancelProposal\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function emergencyCancel(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"emergencyCancel\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\n// ── Parameter setters ──\n//\n// Per-vault governor: governance parameters are per-vault now, set by the\n// VAULT OWNER on that vault's governor. Setters revert with\n// `ParamsFrozenDuringProposal` while any proposal is open on the vault.\n\ntype GovernorParamSetter =\n | \"setVotingPeriod\"\n | \"setExecutionWindow\"\n | \"setVetoThresholdBps\"\n | \"setMaxPerformanceFeeBps\"\n | \"setMaxStrategyDuration\"\n | \"setCooldownPeriod\";\n\nasync function setGovernorParam(\n vault: Address,\n functionName: GovernorParamSetter,\n value: bigint,\n): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName,\n args: [value],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function setVotingPeriod(vault: Address, seconds: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setVotingPeriod\", seconds);\n}\n\nexport async function setExecutionWindow(vault: Address, seconds: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setExecutionWindow\", seconds);\n}\n\nexport async function setVetoThresholdBps(vault: Address, bps: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setVetoThresholdBps\", bps);\n}\n\nexport async function setMaxPerformanceFeeBps(vault: Address, bps: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setMaxPerformanceFeeBps\", bps);\n}\n\nexport async function setMaxStrategyDuration(vault: Address, seconds: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setMaxStrategyDuration\", seconds);\n}\n\nexport async function setCooldownPeriod(vault: Address, seconds: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setCooldownPeriod\", seconds);\n}\n\nexport async function vetoProposal(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"vetoProposal\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\n// ── ProtocolConfig fee setters (protocol-owner only) ──\n//\n// Fee parameters moved off the governor onto the protocol-wide\n// ProtocolConfig contract (resolved via `factory.protocolConfig()`).\n\nexport async function setProtocolFeeBps(bps: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getProtocolConfigAddress(),\n abi: PROTOCOL_CONFIG_ABI,\n functionName: \"setProtocolFeeBps\",\n args: [bps],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n","/**\n * AUTO-GENERATED by cli/scripts/codegen-contracts.ts — do not edit.\n * Regenerate: npm run codegen (in cli/)\n *\n * Source of truth: sherwood-protocol src/interfaces/ISyndicateGovernor.sol (enum ProposalState)\n */\n\n/** On-chain `ProposalState` member names, index === Solidity enum value. */\nexport const PROPOSAL_STATES = [\n \"Draft\",\n \"Pending\",\n \"GuardianReview\",\n \"Approved\",\n \"Rejected\",\n \"Expired\",\n \"Executed\",\n \"Settled\",\n \"Cancelled\",\n] as const;\n\nexport type ProposalStateName = (typeof PROPOSAL_STATES)[number];\n\n/** Name → Solidity enum value. */\nexport const PROPOSAL_STATE = {\n Draft: 0,\n Pending: 1,\n GuardianReview: 2,\n Approved: 3,\n Rejected: 4,\n Expired: 5,\n Executed: 6,\n Settled: 7,\n Cancelled: 8,\n} as const;\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/network.ts"],"sourcesContent":["/**\n * Network state singleton.\n *\n * Called once at CLI startup via the --chain flag's preAction hook.\n * Every other module reads from here — never hardcodes a chain.\n *\n * Current deployment target: Robinhood L2 testnet (chain 46630) only. Sherwood\n * launches on Robinhood first; other chains may be added back later, at which\n * point they re-enter the Network union + CHAIN_REGISTRY below.\n */\n\nimport { type Chain, defineChain, parseEther } from \"viem\";\nimport { getConfigRpcUrl } from \"./config.js\";\n\n// ── Robinhood L2 Testnet (Arbitrum Orbit, chain ID 46630) ──\n\nexport const robinhoodTestnet = defineChain({\n id: 46630,\n name: \"Robinhood Chain Testnet\",\n nativeCurrency: { name: \"Ethereum\", symbol: \"ETH\", decimals: 18 },\n rpcUrls: {\n default: { http: [\"https://rpc.testnet.chain.robinhood.com\"] },\n },\n blockExplorers: {\n default: {\n name: \"Blockscout\",\n url: \"https://explorer.testnet.chain.robinhood.com\",\n },\n },\n testnet: true,\n});\n\n// ── Robinhood Chain mainnet fork (Tenderly Virtual TestNet, chain ID 9994663) ──\n//\n// A fork of Robinhood Chain *mainnet* (USDG stablecoin, official Uniswap v3+v4,\n// Chainlink push feeds, tokenized-stock liquidity). Used for mainnet-faithful\n// e2e + guardian-network simulations. Ephemeral: Tenderly vnets expire — the RPC\n// is overridable via ROBINHOOD_FORK_RPC_URL when a new vnet is minted.\n\nexport const robinhoodFork = defineChain({\n id: 9994663,\n name: \"Robinhood Chain (fork)\",\n nativeCurrency: { name: \"Ethereum\", symbol: \"ETH\", decimals: 18 },\n rpcUrls: {\n default: {\n http: [\n \"https://virtual.robinhood-chain.eu.rpc.tenderly.co/moonwell/wormhole-bridge/f4e186\",\n ],\n },\n },\n blockExplorers: {\n default: {\n name: \"Tenderly\",\n url: \"https://dashboard.tenderly.co\",\n },\n },\n testnet: true,\n});\n\n// ── Types ──\n\nexport type Network = \"robinhood-testnet\" | \"robinhood-fork\";\n\nexport interface ChainConfig {\n chain: Chain;\n /**\n * Ordered list of public RPC URLs tried in sequence when no user RPC is set.\n * First entry is the primary; the rest are fallbacks used transparently via\n * viem's `fallback` transport on rate-limit / network errors.\n */\n rpcFallbacks: string[];\n /** Legacy env var for backwards compat (optional per chain) */\n rpcEnvVar?: string;\n explorerHost: string;\n /** EAS GraphQL endpoint — null if EAS is not available on this chain */\n easGraphqlUrl: string | null;\n /** EAS scan host — null if unavailable */\n easScanHost: string | null;\n xmtpEnv: \"production\" | \"dev\";\n isTestnet: boolean;\n /**\n * ETH held back for gas in the native-ETH-wrap deposit path — the floor and\n * fallback for the live per-tx cushion estimate (`estimateGasCushion` in\n * client.ts), NOT a fixed requirement. High-fee chains (Base) want a\n * Base-scale reserve; near-zero-fee chains (Robinhood testnet, ~14-wei base\n * fee) want a tiny one so a valid deposit isn't rejected client-side. Unset →\n * `DEFAULT_MIN_GAS_RESERVE`.\n */\n minGasReserve?: bigint;\n}\n\n/**\n * Base-scale default reserve, used when a chain omits `minGasReserve`. Matches\n * the old hardcoded 0.0005-ETH cushion so higher-fee chains keep prior behavior.\n */\nexport const DEFAULT_MIN_GAS_RESERVE = parseEther(\"0.0005\");\n\n// ── Chain Registry ──\n\nexport const CHAIN_REGISTRY: Record<Network, ChainConfig> = {\n \"robinhood-testnet\": {\n chain: robinhoodTestnet,\n rpcFallbacks: [\"https://rpc.testnet.chain.robinhood.com\"],\n rpcEnvVar: \"ROBINHOOD_TESTNET_RPC_URL\",\n explorerHost: \"explorer.testnet.chain.robinhood.com\",\n easGraphqlUrl: null,\n easScanHost: null,\n xmtpEnv: \"production\",\n isTestnet: true,\n // ~14-wei base fee: a full wrap+approve+deposit sequence costs a few\n // million wei (~1e-11 ETH). 0.00002 ETH is a generous floor that still\n // leaves a 0.00058-ETH wallet room to wrap 0.0005 and deposit.\n minGasReserve: parseEther(\"0.00002\"),\n },\n \"robinhood-fork\": {\n chain: robinhoodFork,\n rpcFallbacks: [\n \"https://virtual.robinhood-chain.eu.rpc.tenderly.co/moonwell/wormhole-bridge/f4e186\",\n ],\n rpcEnvVar: \"ROBINHOOD_FORK_RPC_URL\",\n explorerHost: \"dashboard.tenderly.co\",\n easGraphqlUrl: null,\n easScanHost: null,\n xmtpEnv: \"production\",\n isTestnet: true,\n // Robinhood-mainnet-fork gas (~0.17 gwei) is higher than testnet's ~14 wei —\n // keep a modest reserve so the ETH-wrap deposit path isn't rejected.\n minGasReserve: parseEther(\"0.0005\"),\n },\n};\n\nexport const VALID_NETWORKS = Object.keys(CHAIN_REGISTRY) as Network[];\n\nexport const DEFAULT_NETWORK: Network = \"robinhood-testnet\";\n\n// ── Singleton state ──\n\nlet _network: Network = DEFAULT_NETWORK;\n\nexport function setNetwork(n: Network) {\n const config = CHAIN_REGISTRY[n];\n if (!config) {\n throw new Error(\n `Unknown network: ${n}. Valid: ${VALID_NETWORKS.join(\", \")}`,\n );\n }\n _network = n;\n}\n\nexport function getNetwork(): Network {\n return _network;\n}\n\n/**\n * Run `fn` with the network singleton temporarily switched to `network`,\n * restoring the previous network in `finally`.\n *\n * The viem clients (`getPublicClient`, `getWalletClient`) auto-invalidate on\n * chain change, so callers get fresh per-chain RPC + chain context inside the\n * block. Used for cross-chain fund resolution.\n */\nexport async function withNetwork<T>(\n network: Network,\n fn: () => Promise<T>,\n): Promise<T> {\n const previous = _network;\n _network = network;\n try {\n return await fn();\n } finally {\n _network = previous;\n }\n}\n\nexport function getChainConfig(): ChainConfig {\n return CHAIN_REGISTRY[_network];\n}\n\n/**\n * Per-chain ETH gas reserve floor/fallback for the ETH-wrap deposit path.\n * Falls back to the Base-scale default when the active chain doesn't set one.\n */\nexport function getMinGasReserve(): bigint {\n return CHAIN_REGISTRY[_network].minGasReserve ?? DEFAULT_MIN_GAS_RESERVE;\n}\n\n/**\n * Dev/CI-only chain-id override (`SIM_CHAIN_ID`) for custom-chainId vnet forks.\n * viem asserts the node's chainId matches the chain definition on every write,\n * so signing for such a fork requires the id to be swapped at the source.\n *\n * Interlock: honored ONLY while `SIM_ADDRESSES_FILE` is also set (the vnet\n * e2e harness's address override). A bare SIM_CHAIN_ID does nothing, so this\n * can never redirect signing on a real network run.\n */\nexport function applyChainIdOverride(chain: Chain): Chain {\n const raw = process.env.SIM_CHAIN_ID;\n if (!raw || !process.env.SIM_ADDRESSES_FILE) return chain;\n const id = Number(raw);\n if (!Number.isInteger(id) || id <= 0) return chain;\n return { ...chain, id };\n}\n\nexport function getChain(): Chain {\n return applyChainIdOverride(CHAIN_REGISTRY[_network].chain);\n}\n\n/**\n * Ordered list of RPC URLs to try, deduped:\n * 1. User config (~/.sherwood/config.json) — honored first\n * 2. Legacy env var (ROBINHOOD_TESTNET_RPC_URL)\n * 3. Public fallback list from CHAIN_REGISTRY\n *\n * Fed to viem's `fallback()` transport so rate-limited RPCs transparently\n * advance to the next entry. See issue #182.\n */\nexport function getRpcUrls(): string[] {\n const cfg = CHAIN_REGISTRY[_network];\n const urls: string[] = [];\n\n const fromConfig = getConfigRpcUrl(_network);\n if (fromConfig) urls.push(fromConfig);\n\n if (cfg.rpcEnvVar && process.env[cfg.rpcEnvVar]) {\n urls.push(process.env[cfg.rpcEnvVar]!);\n }\n\n // Vnet harness (SIM_CHAIN_ID + SIM_ADDRESSES_FILE interlock): the fork RPC\n // is the ONLY valid endpoint — the public fallbacks point at the real\n // network. viem's fallback() otherwise rotates there on a vnet hiccup and\n // silently estimates gas/fees against MAINNET state (live finding: an\n // approve estimated at 21.9k gas on mainnet — no code at that address —\n // reverted out-of-gas on the vnet where it needs ~46k). A vnet call must\n // fail loudly, never retarget the real chain.\n if (process.env.SIM_CHAIN_ID && process.env.SIM_ADDRESSES_FILE && urls.length > 0) {\n return Array.from(new Set(urls));\n }\n\n urls.push(...cfg.rpcFallbacks);\n\n return Array.from(new Set(urls));\n}\n\nexport function getRpcUrl(): string {\n return getRpcUrls()[0];\n}\n\nexport function getExplorerUrl(txHash: string): string {\n return `https://${CHAIN_REGISTRY[_network].explorerHost}/tx/${txHash}`;\n}\n\nexport function isTestnet(): boolean {\n return CHAIN_REGISTRY[_network].isTestnet;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/cron.ts"],"sourcesContent":["/**\n * OpenClaw cron integration — auto-register participation crons for fund agents.\n *\n * When an agent creates or joins a fund, the CLI registers two cron jobs:\n * 1. Silent check (every 15m) — processes messages/events, responds autonomously\n * 2. Human summary (every 1h) — brief activity report delivered to the human's channel\n *\n * Non-OpenClaw agents skip silently — the caller prints guidance instead.\n */\n\nimport { execFileSync } from \"node:child_process\";\n\n// ── OpenClaw detection (cached per process) ──\n\nlet _isOpenClaw: boolean | null = null;\n\nexport function isOpenClaw(): boolean {\n if (_isOpenClaw !== null) return _isOpenClaw;\n try {\n execFileSync(\"openclaw\", [\"cron\", \"list\"], {\n encoding: \"utf8\",\n timeout: 10_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n _isOpenClaw = true;\n } catch {\n _isOpenClaw = false;\n }\n return _isOpenClaw;\n}\n\n// ── Types ──\n\nexport interface CronResult {\n registered: boolean;\n isOpenClaw: boolean;\n cronNames: string[];\n}\n\nexport interface CronStatus {\n isOpenClaw: boolean;\n crons: { name: string; every: string; lastRun?: string }[];\n}\n\n// ── Cron naming ──\n\nfunction cronName(subdomain: string, testnet: boolean): string {\n return `sherwood-${subdomain}${testnet ? \"-testnet\" : \"\"}`;\n}\n\nfunction summaryCronName(subdomain: string, testnet: boolean): string {\n return `${cronName(subdomain, testnet)}-summary`;\n}\n\n// ── Prompts ──\n\nfunction silentPrompt(subdomain: string, testnet: boolean): string {\n // Current deployment target (robinhood-testnet) is the ungated CLI default,\n // so cron commands need no explicit --chain flag or env gate.\n const chainFlag = \"\";\n const envPrefix = \"\";\n void testnet;\n return [\n `You are a sherwood fund member. Your fund: ${subdomain}.sherwoodagent.eth`,\n \"\",\n `Step 1: Run \\`${envPrefix}sherwood session check ${subdomain}${chainFlag}\\``,\n \"Step 2: Parse the JSON output. The output is a single JSON object with fields: fund, messages[], events[], meta{}.\",\n \" - If the command fails or returns an error, reply HEARTBEAT_ERROR with the error message.\",\n \" - If meta.newMessages === 0 and meta.newEvents === 0, you may still be pending approval.\",\n \" Check: `\" + envPrefix + \"sherwood vault info\" + chainFlag + \"`\",\n \" If your wallet is not listed as a registered agent, you are still pending. Reply HEARTBEAT_OK.\",\n \" If you ARE registered but this is your first time seeing it, alert your human that you've been approved and are now active.\",\n \" - If there are new messages from OTHER agents, respond thoughtfully via:\",\n ` \\`${envPrefix}sherwood chat ${subdomain} send \"<response>\"${chainFlag}\\``,\n \" - If there are on-chain events (proposals, votes, settlements), acknowledge them in chat if relevant.\",\n \"Step 3: If you responded to anything, summarize what you did (for your own session log).\",\n \" If nothing happened, reply HEARTBEAT_OK\",\n \"\",\n \"Rules:\",\n \"- Be a real fund member — discuss strategies, share opinions, ask questions\",\n \"- Keep responses concise and on-topic\",\n \"- Do NOT alert your human unless something requires their approval (or you were just approved)\",\n `- You can use \\`sherwood research\\` commands if you need data to back up your response`,\n ].join(\"\\n\");\n}\n\nfunction summaryPrompt(subdomain: string, testnet: boolean): string {\n // Current deployment target (robinhood-testnet) is the ungated CLI default,\n // so cron commands need no explicit --chain flag or env gate.\n const chainFlag = \"\";\n const envPrefix = \"\";\n void testnet;\n return [\n \"You are reporting fund activity to your human operator.\",\n \"\",\n `Run: \\`${envPrefix}sherwood session check ${subdomain}${chainFlag}\\``,\n \"\",\n \"The output is a single JSON object with fields: fund, messages[], events[], meta{}.\",\n \"If the command fails, report the error to your human.\",\n \"\",\n \"If there was activity (messages, events, proposals) since last check:\",\n \" Send a brief summary — who said what, any decisions made, any actions you took.\",\n \" Keep it to 3-5 lines max.\",\n \"\",\n \"If there was no activity:\",\n \" Reply HEARTBEAT_OK\",\n \"\",\n \"Only escalate (flag as urgent) if:\",\n \"- A proposal needs human sign-off\",\n \"- An agent left the fund\",\n \"- Risk alert or health factor warning\",\n \"- Human was directly asked for input\",\n ].join(\"\\n\");\n}\n\n// ── Helpers ──\n\n/** Parse `openclaw cron list --json` and return job names. */\nfunction listCronNames(): string[] {\n try {\n const raw = execFileSync(\"openclaw\", [\"cron\", \"list\", \"--json\"], {\n encoding: \"utf8\",\n timeout: 10_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n const parsed = JSON.parse(raw);\n const jobs: { name: string }[] = parsed.jobs || parsed || [];\n return jobs.map((j) => j.name);\n } catch {\n return [];\n }\n}\n\n/** Parse `openclaw cron list --json` with full details for status display. */\nfunction listCronDetails(): { name: string; every: string; lastRun?: string }[] {\n try {\n const raw = execFileSync(\"openclaw\", [\"cron\", \"list\", \"--json\"], {\n encoding: \"utf8\",\n timeout: 10_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n const parsed = JSON.parse(raw);\n const jobs: { name: string; every?: string; interval?: string; lastRun?: string }[] =\n parsed.jobs || parsed || [];\n return jobs.map((j) => ({\n name: j.name,\n every: j.every || j.interval || \"unknown\",\n lastRun: j.lastRun,\n }));\n } catch {\n return [];\n }\n}\n\n// ── Public API ──\n\nexport function registerFundCrons(\n subdomain: string,\n testnet: boolean,\n notifyTo?: string,\n): CronResult {\n if (!isOpenClaw()) {\n return { registered: false, isOpenClaw: false, cronNames: [] };\n }\n\n const checkName = cronName(subdomain, testnet);\n const summaryName = summaryCronName(subdomain, testnet);\n const existing = listCronNames();\n const created: string[] = [];\n\n // Cron 1: Silent participation check (every 15m)\n if (!existing.includes(checkName)) {\n try {\n execFileSync(\"openclaw\", [\n \"cron\", \"create\",\n \"--name\", checkName,\n \"--every\", \"15m\",\n \"--session\", \"isolated\",\n \"--timeout-seconds\", \"120\",\n \"--no-deliver\",\n \"--message\", silentPrompt(subdomain, testnet),\n ], {\n encoding: \"utf8\",\n timeout: 30_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n created.push(checkName);\n } catch (err) {\n console.warn(`Could not create silent cron: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n // Cron 2: Human summary (every 1h)\n if (!existing.includes(summaryName)) {\n try {\n const args = [\n \"cron\", \"create\",\n \"--name\", summaryName,\n \"--every\", \"1h\",\n \"--session\", \"isolated\",\n \"--timeout-seconds\", \"90\",\n \"--announce\",\n ];\n\n // Use explicit destination if configured, otherwise auto-route via --channel last\n if (notifyTo) {\n args.push(\"--to\", notifyTo);\n } else {\n args.push(\"--channel\", \"last\");\n }\n\n args.push(\"--message\", summaryPrompt(subdomain, testnet));\n\n execFileSync(\"openclaw\", args, {\n encoding: \"utf8\",\n timeout: 30_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n created.push(summaryName);\n } catch (err) {\n console.warn(`Could not create summary cron: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return {\n registered: created.length > 0,\n isOpenClaw: true,\n cronNames: created,\n };\n}\n\nexport function unregisterFundCrons(\n subdomain: string,\n testnet: boolean,\n): { removed: boolean; isOpenClaw: boolean } {\n if (!isOpenClaw()) {\n return { removed: false, isOpenClaw: false };\n }\n\n const names = [cronName(subdomain, testnet), summaryCronName(subdomain, testnet)];\n let removed = false;\n\n for (const name of names) {\n try {\n execFileSync(\"openclaw\", [\"cron\", \"remove\", \"--name\", name], {\n encoding: \"utf8\",\n timeout: 10_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n removed = true;\n } catch {\n // Cron may not exist — that's fine\n }\n }\n\n return { removed, isOpenClaw: true };\n}\n\nexport function getFundCronStatus(\n subdomain: string,\n testnet: boolean,\n): CronStatus {\n if (!isOpenClaw()) {\n return { isOpenClaw: false, crons: [] };\n }\n\n const prefix = cronName(subdomain, testnet);\n const all = listCronDetails();\n const matching = all.filter((c) => c.name.startsWith(prefix));\n\n return { isOpenClaw: true, crons: matching };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/trade.ts","../src/providers/uniswap.ts","../src/lib/signals.ts","../src/lib/exit-strategy.ts","../src/lib/positions.ts"],"sourcesContent":["/**\n * Trade commands — sherwood trade <subcommand>\n *\n * Memecoin trading via the Uniswap Trading API on Base, driven by signal-based\n * analysis (on-chain flows, social sentiment, fundamentals).\n *\n * Trades execute from the agent's own EOA wallet using USDC as quote currency.\n * Requires a Uniswap API key: `sherwood config set --uniswap-api-key <key>`\n */\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { confirm } from \"@inquirer/prompts\";\nimport type { Address } from \"viem\";\nimport { isAddress, parseUnits, formatUnits } from \"viem\";\n\nimport { getPublicClient, getAccount, formatContractError } from \"../lib/client.js\";\nimport { getExplorerUrl, getNetwork } from \"../lib/network.js\";\nimport { TOKENS } from \"../lib/addresses.js\";\nimport { ERC20_ABI } from \"../lib/abis.js\";\nimport { UniswapProvider } from \"../providers/uniswap.js\";\nimport { analyzeToken } from \"../lib/signals.js\";\nimport type { SignalResult } from \"../lib/signals.js\";\nimport { checkExit, DEFAULT_EXIT_CONFIG } from \"../lib/exit-strategy.js\";\nimport type { ExitConfig } from \"../lib/exit-strategy.js\";\nimport {\n getOpenPositions,\n addPosition,\n closePosition,\n updateHighWater,\n getCurrentPrice,\n} from \"../lib/positions.js\";\nimport type { MessageType } from \"../lib/types.js\";\n\nconst uniswap = new UniswapProvider();\n\n// Lazy-load XMTP to avoid breaking non-chat environments\nasync function loadXmtp() {\n return import(\"../lib/xmtp.js\");\n}\n\n// ── Token resolution ──\n\nconst ETH_ADDRESS = \"0x0000000000000000000000000000000000000000\" as Address;\n\nconst KNOWN_MEMECOINS: Record<string, Address> = {\n DEGEN: \"0x4ed4E862860beD51a9570b96d89aF5E1B0Efefed\" as Address,\n TOSHI: \"0xAC1Bd2486aAf3B5C0fc3Fd868558b082a531B2B4\" as Address,\n BRETT: \"0x532f27101965dd16442E59d40670FaF5eBB142E4\" as Address,\n HIGHER: \"0x0578d8A44db98B23BF096A382e016e29a5Ce0ffe\" as Address,\n};\n\nconst WETH_ABI = [\n {\n name: \"deposit\",\n type: \"function\",\n stateMutability: \"payable\",\n inputs: [],\n outputs: [],\n },\n] as const;\n\nasync function resolveToken(\n symbolOrAddress: string,\n): Promise<{ address: Address; symbol: string; decimals: number }> {\n const upper = symbolOrAddress.toUpperCase();\n\n // ETH is native — not an ERC-20, handle specially\n if (upper === \"ETH\") {\n return { address: ETH_ADDRESS, symbol: \"ETH\", decimals: 18 };\n }\n\n let address: Address;\n let symbol: string;\n\n if (isAddress(symbolOrAddress)) {\n address = symbolOrAddress as Address;\n const client = getPublicClient();\n try {\n symbol = (await client.readContract({\n address,\n abi: ERC20_ABI,\n functionName: \"symbol\",\n })) as string;\n } catch {\n symbol = address.slice(0, 8);\n }\n } else {\n const tokens = TOKENS();\n const tokenMap: Record<string, Address> = {\n USDC: tokens.USDC,\n WETH: tokens.WETH,\n ...KNOWN_MEMECOINS,\n };\n address = tokenMap[upper];\n if (!address) {\n throw new Error(\n `Unknown token: ${symbolOrAddress}. Use a contract address or known symbol (${Object.keys(tokenMap).join(\", \")}).`,\n );\n }\n symbol = upper;\n }\n\n const client = getPublicClient();\n const decimals = (await client.readContract({\n address,\n abi: ERC20_ABI,\n functionName: \"decimals\",\n })) as number;\n\n return { address, symbol, decimals };\n}\n\n// ── Chat posting ──\n\nasync function postToChat(\n fund: string,\n type: MessageType,\n text: string,\n data: Record<string, unknown>,\n): Promise<void> {\n try {\n const xmtp = await loadXmtp();\n const group = await xmtp.getGroup(\"\", fund);\n await xmtp.sendEnvelope(group, {\n type,\n from: getAccount().address,\n text,\n data,\n timestamp: Math.floor(Date.now() / 1000),\n });\n } catch {\n // Chat posting is best-effort\n }\n}\n\n// ── Formatting ──\n\nfunction formatSignalTable(results: { symbol: string; address: Address; result: SignalResult }[]): void {\n console.log();\n console.log(chalk.bold(\" Token Score Action Conf. On-chain Social Fundmtl\"));\n console.log(chalk.dim(\" \" + \"─\".repeat(72)));\n\n for (const { symbol, address, result } of results) {\n const scoreColor = result.compositeScore > 0 ? chalk.green : result.compositeScore < 0 ? chalk.red : chalk.dim;\n const actionColor =\n result.action === \"buy\" ? chalk.green.bold :\n result.action === \"sell\" ? chalk.red.bold :\n chalk.dim;\n\n const onChain = result.signals.find((s) => s.source === \"onchain\");\n const social = result.signals.find((s) => s.source === \"social\");\n const fundamental = result.signals.find((s) => s.source === \"fundamental\");\n\n const shortAddr = `${address.slice(0, 6)}..`;\n const label = `${symbol.padEnd(6)} (${shortAddr})`;\n\n console.log(\n ` ${label.padEnd(16)} ` +\n `${scoreColor(result.compositeScore.toFixed(2).padStart(6))} ` +\n `${actionColor(result.action.toUpperCase().padEnd(6))} ` +\n `${(result.confidence * 100).toFixed(0).padStart(4)}% ` +\n `${formatSignalValue(onChain?.value).padStart(8)} ` +\n `${formatSignalValue(social?.value).padStart(6)} ` +\n `${formatSignalValue(fundamental?.value).padStart(7)}`,\n );\n }\n console.log();\n}\n\nfunction formatSignalValue(v: number | undefined): string {\n if (v === undefined) return chalk.dim(\"n/a\");\n const s = (v >= 0 ? \"+\" : \"\") + v.toFixed(2);\n return v > 0 ? chalk.green(s) : v < 0 ? chalk.red(s) : chalk.dim(s);\n}\n\n// ── Commands ──\n\n// The Uniswap Trading API (and the KNOWN_MEMECOINS universe) covers Base only.\n// No currently registered network qualifies — Sherwood currently deploys on\n// Robinhood testnet (chain 46630) — so every trade subcommand fails fast\n// instead of advertising a capability that would throw mid-flow.\nconst TRADING_API_NETWORKS = new Set<string>([\"base\", \"base-sepolia\"]);\n\nexport function registerTradeCommands(program: Command): void {\n const trade = program\n .command(\"trade\")\n .description(\"Memecoin trading — scan, buy, sell, monitor positions (Uniswap Trading API on Base)\");\n\n trade.hook(\"preAction\", () => {\n const network = getNetwork();\n if (!TRADING_API_NETWORKS.has(network)) {\n console.error(chalk.red(`trade commands are not supported on ${network}.`));\n console.error(\n chalk.dim(\n \"They require the Uniswap Trading API, which covers Base only. \" +\n \"Sherwood currently deploys on Robinhood testnet (chain 46630).\",\n ),\n );\n process.exit(1);\n }\n });\n\n // ── trade scan ──\n\n trade\n .command(\"scan\")\n .description(\"Analyze token(s) using on-chain, social, and fundamental signals\")\n .option(\"--token <addr|symbol>\", \"Specific token to analyze (otherwise scans known memecoins)\")\n .option(\"--fund <name>\", \"Post results to fund chat\")\n .option(\"--yes\", \"Skip cost confirmation\", false)\n .action(async (opts: { token?: string; fund?: string; yes: boolean }) => {\n const targets: { symbol: string; address: Address }[] = [];\n\n if (opts.token) {\n const resolved = await resolveToken(opts.token);\n targets.push({ symbol: resolved.symbol, address: resolved.address });\n } else {\n for (const [symbol, address] of Object.entries(KNOWN_MEMECOINS)) {\n targets.push({ symbol, address });\n }\n }\n\n const estCost = targets.length * 0.26;\n console.log();\n console.log(chalk.bold(\"Memecoin Alpha Scan\"));\n console.log(chalk.dim(\"─\".repeat(40)));\n console.log(` Tokens: ${targets.map((t) => t.symbol).join(\", \")}`);\n console.log(` Est. cost: ${chalk.yellow(`~$${estCost.toFixed(2)} USDC`)} (x402 research) + Venice inference`);\n console.log();\n\n if (!opts.yes) {\n const ok = await confirm({\n message: `Proceed with signal analysis?`,\n default: true,\n });\n if (!ok) {\n console.log(chalk.dim(\"Cancelled.\"));\n return;\n }\n }\n\n const spinner = ora(\"Analyzing signals...\").start();\n const results: { symbol: string; address: Address; result: SignalResult }[] = [];\n\n for (const target of targets) {\n try {\n spinner.text = `Analyzing ${target.symbol}...`;\n const result = await analyzeToken(target.address, target.symbol);\n results.push({ ...target, result });\n } catch {\n results.push({\n ...target,\n result: {\n action: \"hold\",\n confidence: 0,\n compositeScore: 0,\n signals: [],\n costUsdc: \"0\",\n timestamp: Math.floor(Date.now() / 1000),\n },\n });\n }\n }\n\n spinner.succeed(\"Scan complete\");\n formatSignalTable(results);\n\n const totalCost = results.reduce((sum, r) => sum + Number(r.result.costUsdc), 0);\n console.log(chalk.dim(` Total research cost: $${totalCost.toFixed(4)} USDC`));\n console.log();\n\n if (opts.fund) {\n await postToChat(opts.fund, \"TRADE_SIGNAL\" as MessageType,\n `Scanned ${results.length} tokens: ${results.filter((r) => r.result.action === \"buy\").map((r) => r.symbol).join(\", \") || \"no buys\"}`,\n { results: results.map((r) => ({ symbol: r.symbol, action: r.result.action, score: r.result.compositeScore })) },\n );\n }\n });\n\n // ── trade buy ──\n\n trade\n .command(\"buy\")\n .description(\"Buy a token via Uniswap Trading API\")\n .requiredOption(\"--token <addr|symbol>\", \"Token to buy\")\n .requiredOption(\"--amount <n>\", \"Amount of input token to spend\")\n .option(\"--with <token>\", \"Input token to spend (default: USDC). Use ETH for native ETH (auto-wraps to WETH).\", \"USDC\")\n .option(\"--slippage <pct>\", \"Slippage tolerance % (default: 0.5)\", \"0.5\")\n .option(\"--stop-loss <pct>\", \"Stop loss percentage (default: 10)\", \"10\")\n .option(\"--trailing-stop <pct>\", \"Trailing stop percentage (0 = disabled)\", \"0\")\n .option(\"--deadline <hours>\", \"Force exit after N hours (0 = none)\", \"0\")\n .option(\"--fund <name>\", \"Post trade to fund chat\")\n .action(async (opts) => {\n const { address: tokenAddr, symbol, decimals } = await resolveToken(opts.token as string);\n const slippage = Number(opts.slippage);\n\n // Resolve input token\n const inputSpec = (opts.with as string).toUpperCase();\n const isEthInput = inputSpec === \"ETH\";\n // ETH input: wrap to WETH first, then swap WETH → target\n const {\n address: inputAddr,\n symbol: inputSymbol,\n decimals: inputDecimals,\n } = isEthInput\n ? { address: TOKENS().WETH, symbol: \"ETH\", decimals: 18 }\n : await resolveToken(opts.with as string);\n const inputAmount = parseUnits(opts.amount as string, inputDecimals);\n\n // Check balance\n const client = getPublicClient();\n const account = getAccount();\n\n if (isEthInput) {\n const ethBalance = await client.getBalance({ address: account.address });\n if (ethBalance < inputAmount) {\n console.error(chalk.red(\n `Insufficient ETH. Have ${formatUnits(ethBalance, 18)}, need ${opts.amount}`,\n ));\n process.exit(1);\n }\n\n // Wrap ETH → WETH\n const wrapSpinner = ora(\"Wrapping ETH → WETH...\").start();\n try {\n const { writeContractWithRetry, waitForReceipt: waitForReceiptFn } = await import(\"../lib/client.js\");\n const wethAddr = TOKENS().WETH;\n const wrapHash = await writeContractWithRetry({\n address: wethAddr,\n abi: WETH_ABI,\n functionName: \"deposit\",\n args: [],\n value: inputAmount,\n account,\n chain: (await import(\"../lib/network.js\")).getChain(),\n });\n await waitForReceiptFn(wrapHash);\n wrapSpinner.succeed(`Wrapped ${opts.amount} ETH → WETH`);\n } catch (err) {\n wrapSpinner.fail(\"ETH wrap failed\");\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n } else {\n const balance = (await client.readContract({\n address: inputAddr,\n abi: ERC20_ABI,\n functionName: \"balanceOf\",\n args: [account.address],\n })) as bigint;\n\n if (balance < inputAmount) {\n console.error(chalk.red(\n `Insufficient ${inputSymbol}. Have ${formatUnits(balance, inputDecimals)}, need ${opts.amount}`,\n ));\n process.exit(1);\n }\n }\n\n // Get quote via Uniswap Trading API (handles routing automatically)\n const quoteSpinner = ora(\"Getting quote from Uniswap API...\").start();\n let expectedOut: bigint;\n\n try {\n const result = await uniswap.fullQuote({\n tokenIn: inputAddr,\n tokenOut: tokenAddr,\n amountIn: inputAmount,\n slippageTolerance: slippage,\n });\n expectedOut = result.amountOut;\n const routing = result.routing;\n quoteSpinner.succeed(\n `Quote: ${formatUnits(result.amountOut, decimals)} ${symbol} (${routing} route)`,\n );\n } catch (err) {\n quoteSpinner.fail(\"Quote failed\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n\n // Execute swap via Uniswap Trading API (check_approval + quote + swap + sign + broadcast)\n const swapSpinner = ora(\"Executing swap via Uniswap API...\").start();\n let txHash: string;\n try {\n const result = await uniswap.swap({\n tokenIn: inputAddr,\n tokenOut: tokenAddr,\n amountIn: inputAmount,\n amountOutMinimum: 0n, // slippage handled by API\n fee: 3000,\n slippageTolerance: slippage,\n });\n txHash = result.hash;\n\n if (!result.success) {\n swapSpinner.fail(\"Swap reverted\");\n console.error(chalk.dim(` Tx: ${getExplorerUrl(result.hash)}`));\n process.exit(1);\n }\n swapSpinner.succeed(\"Swap executed\");\n } catch (err) {\n swapSpinner.fail(\"Swap failed\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n\n // Read actual token balance received\n const tokenBalance = (await client.readContract({\n address: tokenAddr,\n abi: ERC20_ABI,\n functionName: \"balanceOf\",\n args: [account.address],\n })) as bigint;\n\n const tokensReceived = tokenBalance > 0n ? tokenBalance : expectedOut;\n const entryPrice = Number(opts.amount) / Number(formatUnits(tokensReceived, decimals));\n\n // Build exit config\n const exitConfig: ExitConfig = {\n stopLossPct: Number(opts.stopLoss) || DEFAULT_EXIT_CONFIG.stopLossPct,\n trailingStopPct: Number(opts.trailingStop) || DEFAULT_EXIT_CONFIG.trailingStopPct,\n takeProfitPct: DEFAULT_EXIT_CONFIG.takeProfitPct,\n deadlineUnix: Number(opts.deadline) > 0\n ? Math.floor(Date.now() / 1000) + Number(opts.deadline) * 3600\n : 0,\n signalExitEnabled: true,\n };\n\n // Save position\n addPosition({\n tokenAddress: tokenAddr,\n tokenSymbol: symbol,\n tokenDecimals: decimals,\n amountIn: opts.amount as string,\n amountOut: tokensReceived.toString(),\n entryPrice,\n highWaterPrice: entryPrice,\n feeTier: 3000, // stored for price lookups via QuoterV2\n openedAt: Math.floor(Date.now() / 1000),\n txHash,\n exitConfig,\n inputTokenAddress: inputAddr,\n inputTokenSymbol: inputSymbol,\n inputTokenDecimals: inputDecimals,\n });\n\n console.log();\n console.log(chalk.bold(\"Trade Executed\"));\n console.log(chalk.dim(\"─\".repeat(40)));\n console.log(` Token: ${symbol} (${tokenAddr})`);\n console.log(` Spent: ${opts.amount} ${inputSymbol}`);\n console.log(` Received: ${formatUnits(tokensReceived, decimals)} ${symbol}`);\n console.log(` Entry: ${entryPrice.toFixed(8)} ${inputSymbol}/${symbol}`);\n console.log(` Stop: -${exitConfig.stopLossPct}%`);\n if (exitConfig.trailingStopPct > 0) {\n console.log(` Trailing: ${exitConfig.trailingStopPct}%`);\n }\n if (exitConfig.deadlineUnix > 0) {\n console.log(` Deadline: ${new Date(exitConfig.deadlineUnix * 1000).toISOString()}`);\n }\n console.log(` Tx: ${chalk.dim(getExplorerUrl(txHash as `0x${string}`))}`);\n\n // EAS attestation (best-effort) — recipient is vault so dashboard can display it\n try {\n const { createTradeAttestation, getEasScanUrl } = await import(\"../lib/eas.js\");\n const { getChainContracts } = await import(\"../lib/config.js\");\n const { getChain: getActiveChain } = await import(\"../lib/network.js\");\n const vaultRecipient = getChainContracts(getActiveChain().id).vault as `0x${string}` | undefined;\n const { uid } = await createTradeAttestation(\n inputAddr, tokenAddr, inputAmount,\n formatUnits(tokensReceived, decimals),\n txHash, \"BUY\", vaultRecipient,\n );\n if (uid !== \"0x0000000000000000000000000000000000000000000000000000000000000000\") {\n console.log(` Attested: ${chalk.dim(getEasScanUrl(uid))}`);\n }\n } catch {\n // Attestation is best-effort\n }\n\n console.log();\n\n if (opts.fund) {\n await postToChat(opts.fund, \"TRADE_EXECUTED\" as MessageType,\n `Bought ${formatUnits(tokensReceived, decimals)} ${symbol} for ${opts.amount} ${inputSymbol} via Uniswap`,\n { token: symbol, address: tokenAddr, amountIn: opts.amount, inputToken: inputSymbol, txHash },\n );\n }\n });\n\n // ── trade sell ──\n\n trade\n .command(\"sell\")\n .description(\"Sell a token position via Uniswap Trading API\")\n .requiredOption(\"--token <addr|symbol>\", \"Token to sell\")\n .option(\"--amount <n>\", \"Token amount to sell (default: entire position)\")\n .option(\"--for <token>\", \"Output token to receive (default: USDC)\", \"USDC\")\n .option(\"--slippage <pct>\", \"Slippage tolerance % (default: 0.5)\", \"0.5\")\n .option(\"--fund <name>\", \"Post trade to fund chat\")\n .action(async (opts) => {\n const { address: tokenAddr, symbol, decimals } = await resolveToken(opts.token as string);\n const {\n address: outputAddr,\n symbol: outputSymbol,\n decimals: outputDecimals,\n } = await resolveToken(opts.for as string);\n const slippage = Number(opts.slippage);\n\n // Find open position\n const positions = getOpenPositions();\n const pos = positions.find(\n (p) => p.tokenAddress.toLowerCase() === tokenAddr.toLowerCase(),\n );\n\n // Determine sell amount\n const client = getPublicClient();\n const account = getAccount();\n let sellAmount: bigint;\n\n if (opts.amount) {\n sellAmount = parseUnits(opts.amount as string, decimals);\n } else {\n sellAmount = (await client.readContract({\n address: tokenAddr,\n abi: ERC20_ABI,\n functionName: \"balanceOf\",\n args: [account.address],\n })) as bigint;\n }\n\n if (sellAmount === 0n) {\n console.error(chalk.red(\"No tokens to sell.\"));\n process.exit(1);\n }\n\n // Quote via Uniswap Trading API\n const quoteSpinner = ora(\"Getting quote from Uniswap API...\").start();\n let expectedOut: bigint;\n\n try {\n const result = await uniswap.fullQuote({\n tokenIn: tokenAddr,\n tokenOut: outputAddr,\n amountIn: sellAmount,\n slippageTolerance: slippage,\n });\n expectedOut = result.amountOut;\n const routing = result.routing;\n quoteSpinner.succeed(\n `Quote: ${formatUnits(result.amountOut, outputDecimals)} ${outputSymbol} (${routing} route)`,\n );\n } catch (err) {\n quoteSpinner.fail(\"Quote failed\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n\n // Execute sell via Uniswap Trading API\n const swapSpinner = ora(\"Executing sell via Uniswap API...\").start();\n let txHash: string;\n try {\n const result = await uniswap.swap({\n tokenIn: tokenAddr,\n tokenOut: outputAddr,\n amountIn: sellAmount,\n amountOutMinimum: 0n,\n fee: 3000,\n slippageTolerance: slippage,\n });\n txHash = result.hash;\n\n if (!result.success) {\n swapSpinner.fail(\"Sell reverted\");\n process.exit(1);\n }\n swapSpinner.succeed(\"Sell executed\");\n } catch (err) {\n swapSpinner.fail(\"Sell failed\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n\n // Calculate P&L (meaningful when output matches the original input token)\n const outputReceived = Number(formatUnits(expectedOut, outputDecimals));\n const costBasis = pos ? Number(pos.amountIn) : 0;\n const inputMatchesOutput = pos\n ? (pos.inputTokenSymbol ?? \"USDC\").toUpperCase() === outputSymbol.toUpperCase()\n : outputSymbol.toUpperCase() === \"USDC\";\n const pnl = costBasis > 0 && inputMatchesOutput ? outputReceived - costBasis : 0;\n const pnlPct = costBasis > 0 && inputMatchesOutput ? (pnl / costBasis) * 100 : 0;\n const exitPrice = sellAmount > 0n\n ? outputReceived / Number(formatUnits(sellAmount, decimals))\n : 0;\n\n if (pos) {\n closePosition(tokenAddr, {\n exitPrice,\n closedAt: Math.floor(Date.now() / 1000),\n exitTxHash: txHash,\n exitReason: \"manual\",\n pnlUsdc: pnl,\n pnlPct,\n });\n }\n\n const pnlColor = pnl >= 0 ? chalk.green : chalk.red;\n\n console.log();\n console.log(chalk.bold(\"Position Closed\"));\n console.log(chalk.dim(\"─\".repeat(40)));\n console.log(` Token: ${symbol}`);\n console.log(` Sold: ${formatUnits(sellAmount, decimals)} ${symbol}`);\n console.log(` Received: ~${outputReceived.toFixed(outputDecimals <= 6 ? 2 : 6)} ${outputSymbol}`);\n if (costBasis > 0 && inputMatchesOutput) {\n const posInputSymbol = pos?.inputTokenSymbol ?? \"USDC\";\n console.log(` Cost: ${costBasis.toFixed(2)} ${posInputSymbol}`);\n console.log(` P&L: ${pnlColor(`${pnl >= 0 ? \"+\" : \"\"}${pnl.toFixed(2)} ${outputSymbol} (${pnlPct >= 0 ? \"+\" : \"\"}${pnlPct.toFixed(1)}%)`)}`);\n }\n console.log(` Tx: ${chalk.dim(getExplorerUrl(txHash as `0x${string}`))}`);\n\n // EAS attestation (best-effort) — recipient is vault so dashboard can display it\n try {\n const { createTradeAttestation, getEasScanUrl } = await import(\"../lib/eas.js\");\n const { getChainContracts } = await import(\"../lib/config.js\");\n const { getChain: getActiveChain } = await import(\"../lib/network.js\");\n const vaultRecipient = getChainContracts(getActiveChain().id).vault as `0x${string}` | undefined;\n const { uid } = await createTradeAttestation(\n tokenAddr, outputAddr, sellAmount,\n formatUnits(expectedOut, outputDecimals),\n txHash, \"SELL\", vaultRecipient,\n );\n if (uid !== \"0x0000000000000000000000000000000000000000000000000000000000000000\") {\n console.log(` Attested: ${chalk.dim(getEasScanUrl(uid))}`);\n }\n } catch {\n // Attestation is best-effort\n }\n\n console.log();\n\n if (opts.fund) {\n await postToChat(opts.fund, \"TRADE_EXECUTED\" as MessageType,\n `Sold ${formatUnits(sellAmount, decimals)} ${symbol} for ~${outputReceived.toFixed(2)} ${outputSymbol}${inputMatchesOutput && costBasis > 0 ? ` (P&L: ${pnl >= 0 ? \"+\" : \"\"}${pnl.toFixed(2)})` : \"\"}`,\n { token: symbol, address: tokenAddr, outputReceived, outputToken: outputSymbol, pnl, pnlPct, txHash },\n );\n }\n });\n\n // ── trade positions ──\n\n trade\n .command(\"positions\")\n .description(\"Show open positions with current prices and unrealized P&L\")\n .action(async () => {\n const positions = getOpenPositions();\n if (positions.length === 0) {\n console.log(chalk.dim(\"\\n No open positions.\\n\"));\n return;\n }\n\n console.log();\n console.log(chalk.bold(\"Open Positions\"));\n console.log(chalk.dim(\"─\".repeat(80)));\n console.log(chalk.dim(\n \" Token Entry Current Qty Cost Value P&L\",\n ));\n\n for (const pos of positions) {\n try {\n const current = await getCurrentPrice(pos.tokenAddress, pos.tokenDecimals, pos.feeTier);\n const qty = Number(formatUnits(BigInt(pos.amountOut), pos.tokenDecimals));\n const cost = Number(pos.amountIn);\n const value = qty * current;\n const pnl = value - cost;\n const pnlPct = cost > 0 ? (pnl / cost) * 100 : 0;\n const pnlColor = pnl >= 0 ? chalk.green : chalk.red;\n\n console.log(\n ` ${pos.tokenSymbol.padEnd(14)} ` +\n `$${pos.entryPrice.toFixed(6).padStart(10)} ` +\n `$${current.toFixed(6).padStart(10)} ` +\n `${qty.toFixed(2).padStart(15)} ` +\n `$${cost.toFixed(2).padStart(8)} ` +\n `$${value.toFixed(2).padStart(8)} ` +\n pnlColor(`${pnl >= 0 ? \"+\" : \"\"}${pnl.toFixed(2)} (${pnlPct >= 0 ? \"+\" : \"\"}${pnlPct.toFixed(1)}%)`),\n );\n\n if (current > pos.highWaterPrice) {\n updateHighWater(pos.tokenAddress, current);\n }\n } catch {\n console.log(\n ` ${pos.tokenSymbol.padEnd(14)} ` +\n `$${pos.entryPrice.toFixed(6).padStart(10)} ` +\n `${chalk.dim(\"price unavailable\")}`,\n );\n }\n }\n console.log();\n });\n\n // ── trade monitor ──\n\n trade\n .command(\"monitor\")\n .description(\"Monitor positions and auto-exit on signal triggers\")\n .option(\"--interval <seconds>\", \"Check interval in seconds (default: 300)\", \"300\")\n .option(\"--fund <name>\", \"Post updates to fund chat\")\n .action(async (opts) => {\n const interval = Number(opts.interval) * 1000;\n\n console.log();\n console.log(chalk.bold(\"Position Monitor\"));\n console.log(chalk.dim(`Checking every ${opts.interval}s. Press Ctrl-C to stop.`));\n console.log();\n\n const running = { value: true };\n process.on(\"SIGINT\", () => {\n running.value = false;\n console.log(chalk.dim(\"\\nStopping monitor...\"));\n });\n\n while (running.value) {\n const positions = getOpenPositions();\n if (positions.length === 0) {\n console.log(chalk.dim(\" No open positions. Waiting...\"));\n await sleep(interval);\n continue;\n }\n\n for (const pos of positions) {\n if (!running.value) break;\n\n try {\n const current = await getCurrentPrice(pos.tokenAddress, pos.tokenDecimals, pos.feeTier);\n const hwPrice = Math.max(current, pos.highWaterPrice);\n if (current > pos.highWaterPrice) {\n updateHighWater(pos.tokenAddress, current);\n }\n\n // Run signal analysis for exit check\n let signalResult: SignalResult | undefined;\n if (pos.exitConfig.signalExitEnabled) {\n try {\n signalResult = await analyzeToken(pos.tokenAddress, pos.tokenSymbol);\n } catch {\n // Signal analysis can fail — continue with price-only checks\n }\n }\n\n const exit = checkExit(pos.entryPrice, current, hwPrice, pos.exitConfig, signalResult);\n const pnlPct = exit.currentPnlPct;\n const pnlColor = pnlPct >= 0 ? chalk.green : chalk.red;\n const ts = new Date().toLocaleTimeString();\n\n console.log(\n ` [${ts}] ${pos.tokenSymbol}: ` +\n `$${current.toFixed(6)} ` +\n pnlColor(`(${pnlPct >= 0 ? \"+\" : \"\"}${pnlPct.toFixed(1)}%)`) +\n (exit.shouldExit ? chalk.red.bold(` → EXIT (${exit.reason})`) : \"\"),\n );\n\n if (exit.shouldExit) {\n console.log(chalk.yellow(` Executing exit for ${pos.tokenSymbol}: ${exit.reason}`));\n\n if (opts.fund) {\n await postToChat(opts.fund, \"RISK_ALERT\" as MessageType,\n `Exit triggered for ${pos.tokenSymbol}: ${exit.reason} (${pnlPct >= 0 ? \"+\" : \"\"}${pnlPct.toFixed(1)}%)`,\n { token: pos.tokenSymbol, reason: exit.reason, pnlPct },\n );\n }\n\n try {\n const sellAmount = BigInt(pos.amountOut);\n const usdc = TOKENS().USDC;\n\n // Get quote for P&L calculation\n const { amountOut: sellQuote } = await uniswap.fullQuote({\n tokenIn: pos.tokenAddress,\n tokenOut: usdc,\n amountIn: sellAmount,\n slippageTolerance: 0.5,\n });\n\n // Execute sell via Trading API\n const result = await uniswap.swap({\n tokenIn: pos.tokenAddress,\n tokenOut: usdc,\n amountIn: sellAmount,\n amountOutMinimum: 0n,\n fee: 3000,\n slippageTolerance: 1.0, // 1% for auto-sell\n });\n\n const usdcReceived = Number(formatUnits(sellQuote, 6));\n const costBasis = Number(pos.amountIn);\n const pnlUsdc = usdcReceived - costBasis;\n\n closePosition(pos.tokenAddress, {\n exitPrice: current,\n closedAt: Math.floor(Date.now() / 1000),\n exitTxHash: result.hash,\n exitReason: exit.reason,\n pnlUsdc,\n pnlPct,\n });\n\n const pnlStr = `${pnlUsdc >= 0 ? \"+\" : \"\"}${pnlUsdc.toFixed(2)} USDC`;\n console.log(chalk.green(` Sold ${pos.tokenSymbol}: ${pnlStr}`));\n\n if (opts.fund) {\n await postToChat(opts.fund, \"TRADE_EXECUTED\" as MessageType,\n `Auto-sold ${pos.tokenSymbol}: ${pnlStr} (${exit.reason})`,\n { token: pos.tokenSymbol, reason: exit.reason, pnlUsdc, pnlPct, txHash: result.hash },\n );\n }\n } catch (err) {\n console.error(chalk.red(\n ` Failed to sell ${pos.tokenSymbol}: ${formatContractError(err)}`,\n ));\n }\n }\n } catch {\n console.error(chalk.dim(\n ` [${new Date().toLocaleTimeString()}] ${pos.tokenSymbol}: price check failed`,\n ));\n }\n }\n\n if (running.value) {\n await sleep(interval);\n }\n }\n\n console.log(chalk.dim(\"Monitor stopped.\"));\n });\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * PARKED — Base-only Uniswap Trading API adapter (inactive on the current\n * deployment target).\n *\n * The hosted Trading API covers Base / Base Sepolia only; the CLI's sole\n * registered chain is Robinhood testnet (chain 46630), so this adapter cannot\n * execute there and is NOT advertised by `sherwood providers` (see\n * providers/index.ts). Its only consumer is `sherwood trade`, which fails fast\n * on unsupported networks (commands/trade.ts). Swaps on the live chain go\n * through lib/swap-router.ts (Synthra). Retained for a future Base deployment.\n *\n * Uniswap Trading API provider — swaps on Base via the hosted API.\n *\n * Uses the 3-step flow:\n * 1. POST /check_approval → check/submit token approval\n * 2. POST /quote → get optimal route + executable quote\n * 3. POST /swap → get transaction calldata to sign\n *\n * API key required — set via `sherwood config set --uniswap-api-key <key>`\n * or UNISWAP_API_KEY env var.\n *\n * Docs: https://docs.uniswap.org/api/trading-api\n * Key: https://developers.uniswap.org/\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { isAddress, isHex, formatUnits } from \"viem\";\nimport type { SwapParams, SwapQuoteParams, TxResult, SwapQuote } from \"../types.js\";\nimport { getPublicClient, getAccount, writeContractWithRetry, sendTxWithRetry, waitForReceipt } from \"../lib/client.js\";\nimport { getChain } from \"../lib/network.js\";\nimport { getUniswapApiKey } from \"../lib/config.js\";\n\nconst API_BASE = \"https://trade-api.gateway.uniswap.org/v1\";\n\n// ── API Types ──\n\ninterface ApprovalResponse {\n approval: {\n to: Address;\n from: Address;\n data: Hex;\n value: string;\n chainId: number;\n } | null;\n}\n\n// CLASSIC route quote\ninterface ClassicQuote {\n routing: \"CLASSIC\" | \"WRAP\" | \"UNWRAP\";\n quote: {\n input: { token: string; amount: string };\n output: { token: string; amount: string };\n slippage: number;\n route: unknown[];\n gasFee: string;\n gasFeeUSD: string;\n gasUseEstimate: string;\n };\n permitData: Record<string, unknown> | null;\n}\n\n// UniswapX route quote (PRIORITY on Base)\ninterface UniswapXQuote {\n routing: \"DUTCH_V2\" | \"DUTCH_V3\" | \"PRIORITY\";\n quote: {\n orderInfo: {\n outputs: Array<{\n token: string;\n startAmount: string;\n endAmount: string;\n recipient: string;\n }>;\n input: { token: string; startAmount: string; endAmount: string };\n deadline: number;\n nonce: string;\n };\n encodedOrder: string;\n orderHash: string;\n };\n permitData: Record<string, unknown> | null;\n}\n\ntype QuoteResponse = ClassicQuote | UniswapXQuote;\n\ninterface SwapResponse {\n swap: {\n to: Address;\n from: Address;\n data: Hex;\n value: string;\n chainId: number;\n gasLimit?: string;\n };\n}\n\n// ── Helpers ──\n\nfunction getApiKey(): string {\n const key = getUniswapApiKey();\n if (!key) {\n throw new Error(\n \"Uniswap API key not configured. Run 'sherwood config set --uniswap-api-key <key>' \" +\n \"or set UNISWAP_API_KEY env var.\\n\" +\n \"Get your key at https://developers.uniswap.org/\",\n );\n }\n return key;\n}\n\nfunction apiHeaders(): Record<string, string> {\n return {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": getApiKey(),\n \"x-universal-router-version\": \"2.0\",\n };\n}\n\nfunction isUniswapXRouting(routing: string): boolean {\n return routing === \"DUTCH_V2\" || routing === \"DUTCH_V3\" || routing === \"PRIORITY\";\n}\n\nfunction getOutputAmount(q: QuoteResponse): string {\n if (isUniswapXRouting(q.routing)) {\n const ux = q as UniswapXQuote;\n const firstOutput = ux.quote.orderInfo.outputs[0];\n if (!firstOutput) throw new Error(\"UniswapX quote has no outputs\");\n return firstOutput.startAmount; // best-case fill\n }\n return (q as ClassicQuote).quote.output.amount;\n}\n\nasync function fetchWithRetry(\n url: string,\n init: RequestInit,\n maxRetries = 3,\n): Promise<Response> {\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const response = await fetch(url, {\n ...init,\n signal: AbortSignal.timeout(30_000),\n });\n if (response.status !== 429 && response.status < 500) return response;\n if (attempt === maxRetries) return response;\n\n const delay = Math.min(200 * Math.pow(2, attempt) + Math.random() * 100, 10000);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n throw new Error(\"Unreachable\");\n}\n\n// ── Provider ──\n\nexport class UniswapProvider {\n /**\n * Get a quote from the Uniswap Trading API.\n * Returns the optimal route (CLASSIC, PRIORITY, or UniswapX).\n */\n async quote(params: SwapQuoteParams): Promise<SwapQuote> {\n const account = getAccount();\n const chainId = getChain().id;\n\n const body = {\n swapper: account.address,\n tokenIn: params.tokenIn,\n tokenOut: params.tokenOut,\n tokenInChainId: String(chainId),\n tokenOutChainId: String(chainId),\n amount: params.amountIn.toString(),\n type: \"EXACT_INPUT\",\n slippageTolerance: 0.5,\n routingPreference: \"BEST_PRICE\",\n };\n\n const res = await fetchWithRetry(`${API_BASE}/quote`, {\n method: \"POST\",\n headers: apiHeaders(),\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`Uniswap quote failed (${res.status}): ${err}`);\n }\n\n const data = (await res.json()) as QuoteResponse;\n const amountOut = BigInt(getOutputAmount(data));\n\n return {\n amountOut,\n priceImpact: 0,\n route: `${data.routing}: ${params.tokenIn.slice(0, 8)}→${params.tokenOut.slice(0, 8)}`,\n };\n }\n\n /**\n * Get a full quote response (preserving the raw API response for swap execution).\n */\n async fullQuote(params: {\n tokenIn: Address;\n tokenOut: Address;\n amountIn: bigint;\n slippageTolerance?: number;\n }): Promise<{ quoteResponse: QuoteResponse; amountOut: bigint; routing: string }> {\n const account = getAccount();\n const chainId = getChain().id;\n\n const body = {\n swapper: account.address,\n tokenIn: params.tokenIn,\n tokenOut: params.tokenOut,\n tokenInChainId: String(chainId),\n tokenOutChainId: String(chainId),\n amount: params.amountIn.toString(),\n type: \"EXACT_INPUT\",\n slippageTolerance: params.slippageTolerance ?? 0.5,\n routingPreference: \"BEST_PRICE\",\n };\n\n const res = await fetchWithRetry(`${API_BASE}/quote`, {\n method: \"POST\",\n headers: apiHeaders(),\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`Uniswap quote failed (${res.status}): ${err}`);\n }\n\n const quoteResponse = (await res.json()) as QuoteResponse;\n const amountOut = BigInt(getOutputAmount(quoteResponse));\n return { quoteResponse, amountOut, routing: quoteResponse.routing };\n }\n\n /**\n * Check and handle token approval for Uniswap.\n * Uses the Trading API's /check_approval endpoint.\n */\n async checkApproval(params: {\n token: Address;\n amount: bigint;\n }): Promise<void> {\n const account = getAccount();\n const chainId = getChain().id;\n const client = getPublicClient();\n\n const res = await fetchWithRetry(`${API_BASE}/check_approval`, {\n method: \"POST\",\n headers: apiHeaders(),\n body: JSON.stringify({\n walletAddress: account.address,\n token: params.token,\n amount: params.amount.toString(),\n chainId,\n }),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`Approval check failed (${res.status}): ${err}`);\n }\n\n const data = (await res.json()) as ApprovalResponse;\n\n if (data.approval) {\n // API returns a ready-to-send transaction — use sendTxWithRetry for nonce safety\n const approvalHash = await sendTxWithRetry({\n to: data.approval.to,\n data: data.approval.data,\n value: BigInt(data.approval.value || \"0\"),\n account,\n chain: getChain(),\n });\n await waitForReceipt(approvalHash);\n }\n }\n\n /**\n * Execute a swap via the Uniswap Trading API.\n *\n * Full flow: check_approval → quote → swap → sign & broadcast.\n */\n async swap(params: SwapParams): Promise<TxResult> {\n const account = getAccount();\n const client = getPublicClient();\n\n // 1. Check approval (skip for native ETH)\n const ETH_ADDRESS = \"0x0000000000000000000000000000000000000000\" as Address;\n if (params.tokenIn !== ETH_ADDRESS) {\n await this.checkApproval({\n token: params.tokenIn,\n amount: params.amountIn,\n });\n }\n\n // 2. Get quote\n const { quoteResponse } = await this.fullQuote({\n tokenIn: params.tokenIn,\n tokenOut: params.tokenOut,\n amountIn: params.amountIn,\n slippageTolerance: params.slippageTolerance ?? 0.5,\n });\n\n // 3. Prepare swap request — routing-aware permitData handling\n const quoteRaw = quoteResponse as unknown as Record<string, unknown>;\n const { permitData, ...cleanQuote } = quoteRaw;\n const swapRequest: Record<string, unknown> = { ...cleanQuote };\n\n // Sign permitData if present (required for both CLASSIC and UniswapX).\n // For CLASSIC routes using Permit2 (PermitSingle): include BOTH permitData + signature.\n // For UniswapX routes: include signature only (order-level signing, no permitData in body).\n if (permitData && typeof permitData === \"object\") {\n const typedData = permitData as {\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n values: Record<string, unknown>;\n };\n const primaryType =\n Object.keys(typedData.types).find((k) => k !== \"EIP712Domain\") ?? \"PermitSingle\";\n const signature = await account.signTypedData({\n domain: typedData.domain as Record<string, unknown>,\n types: typedData.types as Record<string, Array<{ name: string; type: string }>>,\n primaryType,\n message: typedData.values,\n });\n swapRequest.signature = signature;\n // CLASSIC routes: /swap requires both permitData and signature\n // UniswapX routes: /swap requires signature only (order is in quote body)\n if (!isUniswapXRouting(quoteResponse.routing)) {\n swapRequest.permitData = permitData;\n }\n }\n\n // 4. Get swap transaction\n const swapRes = await fetchWithRetry(`${API_BASE}/swap`, {\n method: \"POST\",\n headers: apiHeaders(),\n body: JSON.stringify(swapRequest),\n });\n\n if (!swapRes.ok) {\n const err = await swapRes.text();\n throw new Error(`Uniswap swap failed (${swapRes.status}): ${err}`);\n }\n\n const swapData = (await swapRes.json()) as SwapResponse;\n\n // 5. Validate before broadcasting\n if (!swapData.swap?.data || swapData.swap.data === (\"\" as Hex) || swapData.swap.data === \"0x\") {\n throw new Error(\"Empty swap data — quote may have expired. Try again.\");\n }\n if (!isAddress(swapData.swap.to) || !isAddress(swapData.swap.from)) {\n throw new Error(\"Invalid address in swap response\");\n }\n\n // 6. Sign and broadcast with retry-aware sender\n // Apply a 1.5x buffer to the API's gasLimit: the Uniswap API under-estimates for WETH\n // and other non-USDC inputs where PermitSingle+transfer adds overhead.\n const gasLimit = swapData.swap.gasLimit\n ? (BigInt(swapData.swap.gasLimit) * 150n) / 100n\n : undefined;\n const hash = await sendTxWithRetry({\n to: swapData.swap.to,\n data: swapData.swap.data,\n value: BigInt(swapData.swap.value || \"0\"),\n gas: gasLimit,\n account,\n chain: getChain(),\n });\n\n const receipt = await waitForReceipt(hash);\n return {\n hash,\n success: receipt.status === \"success\",\n gasUsed: receipt.gasUsed,\n };\n }\n}\n","/**\n * Signal engine — aggregates on-chain, social, and fundamental data\n * into a composite buy/sell/hold recommendation.\n *\n * Sources:\n * On-chain: Nansen smart-money net flow (x402, ~$0.06)\n * Social: Venice inference with web search (X/Twitter sentiment)\n * Fundamental: Messari market data (x402, ~$0.20)\n *\n * No technical analysis — purely signal-driven.\n */\n\nimport type { Address } from \"viem\";\nimport { getResearchProvider } from \"../providers/research/index.js\";\nimport type { ResearchResult } from \"../providers/research/index.js\";\nimport { chatCompletion } from \"./venice.js\";\n\n// ── Types ──\n\nexport type SignalAction = \"buy\" | \"sell\" | \"hold\";\nexport type SignalSource = \"onchain\" | \"social\" | \"fundamental\";\n\nexport interface Signal {\n source: SignalSource;\n name: string;\n value: number; // -1.0 (bearish) to +1.0 (bullish)\n weight: number; // contribution to composite score\n raw: Record<string, unknown>;\n}\n\nexport interface SignalResult {\n action: SignalAction;\n confidence: number; // 0.0 to 1.0\n compositeScore: number; // -1.0 to +1.0\n signals: Signal[];\n costUsdc: string; // total x402 cost\n timestamp: number;\n}\n\nexport interface SignalConfig {\n buyThreshold: number; // composite score above this → buy (default 0.3)\n sellThreshold: number; // composite score below this → sell (default -0.2)\n}\n\nconst DEFAULT_CONFIG: SignalConfig = {\n buyThreshold: 0.3,\n sellThreshold: -0.2,\n};\n\n// ── Main Entry Point ──\n\n/**\n * Analyze a token using on-chain, social, and fundamental signals.\n * Runs all three data sources in parallel for speed.\n */\nexport async function analyzeToken(\n tokenAddress: Address,\n tokenSymbol: string,\n config?: Partial<SignalConfig>,\n): Promise<SignalResult> {\n const cfg = { ...DEFAULT_CONFIG, ...config };\n let totalCostUsdc = 0;\n\n // Run all three signals in parallel — each returns a Signal + cost\n const [onChain, social, fundamental] = await Promise.allSettled([\n getOnChainSignal(tokenSymbol),\n getSocialSignal(tokenAddress, tokenSymbol),\n getFundamentalSignal(tokenSymbol),\n ]);\n\n const signals: Signal[] = [];\n\n if (onChain.status === \"fulfilled\") {\n signals.push(onChain.value.signal);\n totalCostUsdc += onChain.value.costUsdc;\n }\n\n if (social.status === \"fulfilled\") {\n signals.push(social.value.signal);\n totalCostUsdc += social.value.costUsdc;\n }\n\n if (fundamental.status === \"fulfilled\") {\n signals.push(fundamental.value.signal);\n totalCostUsdc += fundamental.value.costUsdc;\n }\n\n // Compute composite score\n let weightedSum = 0;\n let totalWeight = 0;\n for (const s of signals) {\n weightedSum += s.value * s.weight;\n totalWeight += s.weight;\n }\n const compositeScore = totalWeight > 0 ? weightedSum / totalWeight : 0;\n\n // Confidence = average absolute signal strength\n const confidence =\n signals.length > 0\n ? signals.reduce((sum, s) => sum + Math.abs(s.value), 0) / signals.length\n : 0;\n\n // Decision\n let action: SignalAction = \"hold\";\n if (compositeScore >= cfg.buyThreshold && confidence >= 0.5) {\n action = \"buy\";\n } else if (compositeScore <= cfg.sellThreshold) {\n action = \"sell\";\n }\n\n return {\n action,\n confidence: Math.min(confidence, 1),\n compositeScore,\n signals,\n costUsdc: totalCostUsdc.toFixed(4),\n timestamp: Math.floor(Date.now() / 1000),\n };\n}\n\n// ── Individual Signal Sources ──\n\ninterface SignalWithCost {\n signal: Signal;\n costUsdc: number;\n}\n\n/**\n * On-chain signal: Nansen smart-money net flow.\n * Positive net flow (whales buying) → bullish.\n */\nasync function getOnChainSignal(tokenSymbol: string): Promise<SignalWithCost> {\n const nansen = getResearchProvider(\"nansen\");\n let result: ResearchResult;\n try {\n result = await nansen.query({ type: \"smart-money\", target: tokenSymbol });\n } catch {\n return {\n signal: {\n source: \"onchain\",\n name: \"smart_money_net_flow\",\n value: 0,\n weight: 0.40,\n raw: { error: \"nansen query failed\" },\n },\n costUsdc: 0,\n };\n }\n\n const data = result.data as Record<string, unknown>;\n\n // Extract net flow value — Nansen returns flow data in various formats\n const netFlow = extractNetFlow(data);\n // Normalize to -1..+1 range (clamp large values)\n const value = Math.max(-1, Math.min(1, netFlow));\n\n return {\n signal: {\n source: \"onchain\",\n name: \"smart_money_net_flow\",\n value,\n weight: 0.40,\n raw: data,\n },\n costUsdc: Number(result.costUsdc) || 0.06,\n };\n}\n\n/**\n * Social signal: Venice inference with web search for X/Twitter sentiment.\n */\nasync function getSocialSignal(\n tokenAddress: Address,\n tokenSymbol: string,\n): Promise<SignalWithCost> {\n try {\n const result = await chatCompletion({\n model: \"llama-3.3-70b\",\n messages: [\n {\n role: \"system\",\n content: `You are a crypto market sentiment analyst. Analyze current Twitter/X discourse about the given token. Return ONLY valid JSON with no markdown: {\"sentiment\": <number from -1.0 to 1.0>, \"reasoning\": \"<brief explanation>\", \"tweetCount\": <estimated tweets in last 24h>, \"keyTopics\": [\"topic1\", \"topic2\"]}. Positive sentiment means bullish discussion, influencer endorsements, positive news. Negative means FUD, rug pull warnings, community exodus. If you cannot find data, return {\"sentiment\": 0, \"reasoning\": \"insufficient data\", \"tweetCount\": 0, \"keyTopics\": []}.`,\n },\n {\n role: \"user\",\n content: `Analyze current X/Twitter sentiment for token ${tokenSymbol} (contract: ${tokenAddress} on Base chain). What is the social consensus in the last 24 hours?`,\n },\n ],\n temperature: 0.3,\n maxTokens: 500,\n enableWebSearch: true,\n });\n\n // Parse JSON from response\n const parsed = parseJsonResponse(result.content);\n const sentiment = typeof parsed.sentiment === \"number\"\n ? Math.max(-1, Math.min(1, parsed.sentiment))\n : 0;\n\n return {\n signal: {\n source: \"social\",\n name: \"x_sentiment\",\n value: sentiment,\n weight: 0.30,\n raw: parsed as Record<string, unknown>,\n },\n costUsdc: 0, // Venice inference is prepaid via sVVV, no per-call cost\n };\n } catch {\n return {\n signal: {\n source: \"social\",\n name: \"x_sentiment\",\n value: 0,\n weight: 0.30,\n raw: { error: \"venice inference failed\" },\n },\n costUsdc: 0,\n };\n }\n}\n\n/**\n * Fundamental signal: Messari market data — volume spike, market cap, ATH distance.\n */\nasync function getFundamentalSignal(\n tokenSymbol: string,\n): Promise<SignalWithCost> {\n const messari = getResearchProvider(\"messari\");\n let result: ResearchResult;\n try {\n result = await messari.query({ type: \"market\", target: tokenSymbol });\n } catch {\n return {\n signal: {\n source: \"fundamental\",\n name: \"market_fundamentals\",\n value: 0,\n weight: 0.30,\n raw: { error: \"messari query failed\" },\n },\n costUsdc: 0,\n };\n }\n\n const data = result.data as Record<string, unknown>;\n const value = scoreFundamentals(data);\n\n return {\n signal: {\n source: \"fundamental\",\n name: \"market_fundamentals\",\n value,\n weight: 0.30,\n raw: data,\n },\n costUsdc: Number(result.costUsdc) || 0.20,\n };\n}\n\n// ── Scoring Helpers ──\n\n/**\n * Extract net flow from Nansen smart-money response.\n * Normalizes to -1..+1 range.\n */\nfunction extractNetFlow(data: Record<string, unknown>): number {\n // Nansen returns various formats — try common paths\n const netFlow =\n (data.netFlow as number) ??\n (data.net_flow as number) ??\n ((data.inflow as number ?? 0) - (data.outflow as number ?? 0));\n\n if (typeof netFlow !== \"number\" || isNaN(netFlow)) return 0;\n\n // Normalize: scale by rough heuristic (> $1M net flow = strong signal)\n const normalized = netFlow / 1_000_000;\n return Math.max(-1, Math.min(1, normalized));\n}\n\n/**\n * Score fundamental data from Messari.\n *\n * Factors:\n * - Volume spike (24h vs 7d avg): > 3x = +0.5, > 2x = +0.25\n * - Market cap: < $10M with volume = +0.3 (high upside)\n * - ATH distance: > 80% down = +0.2 (recovery play), < 10% = -0.3 (possible top)\n */\nfunction scoreFundamentals(data: Record<string, unknown>): number {\n let score = 0;\n\n // Try to extract market data from nested Messari response\n const marketData = (data.marketData ?? data.market_data ?? data) as Record<string, unknown>;\n const athData = (data.allTimeHigh ?? data.ath ?? {}) as Record<string, unknown>;\n\n // Volume spike\n const vol24h = toNumber(marketData.volume_last_24_hours ?? marketData.volume24h);\n const vol7d = toNumber(marketData.volume_last_7_days ?? marketData.volume7d);\n if (vol24h > 0 && vol7d > 0) {\n const dailyAvg7d = vol7d / 7;\n const ratio = vol24h / dailyAvg7d;\n if (ratio > 3) score += 0.5;\n else if (ratio > 2) score += 0.25;\n else if (ratio < 0.5) score -= 0.25;\n }\n\n // Market cap\n const mcap = toNumber(marketData.current_marketcap_usd ?? marketData.marketCap);\n if (mcap > 0 && mcap < 10_000_000 && vol24h > 0) {\n score += 0.3; // small cap with volume = high upside potential\n } else if (mcap > 1_000_000_000) {\n score -= 0.15; // large cap = less upside for memecoins\n }\n\n // ATH distance\n const currentPrice = toNumber(marketData.price_usd ?? marketData.currentPrice);\n const athPrice = toNumber(athData.price ?? athData.athPrice);\n if (currentPrice > 0 && athPrice > 0) {\n const athDistance = ((athPrice - currentPrice) / athPrice) * 100;\n if (athDistance > 80) score += 0.2; // deep discount recovery play\n else if (athDistance < 10) score -= 0.3; // near ATH, potential top\n }\n\n return Math.max(-1, Math.min(1, score));\n}\n\nfunction toNumber(v: unknown): number {\n if (typeof v === \"number\") return v;\n if (typeof v === \"string\") return Number(v) || 0;\n return 0;\n}\n\n/**\n * Parse a JSON response from Venice, handling markdown fences and extra text.\n */\nfunction parseJsonResponse(content: string): Record<string, unknown> {\n // Strip markdown code fences if present\n let cleaned = content.trim();\n if (cleaned.startsWith(\"```\")) {\n cleaned = cleaned.replace(/^```(?:json)?\\n?/, \"\").replace(/\\n?```$/, \"\");\n }\n // Find the first { ... } block\n const start = cleaned.indexOf(\"{\");\n const end = cleaned.lastIndexOf(\"}\");\n if (start >= 0 && end > start) {\n try {\n return JSON.parse(cleaned.slice(start, end + 1));\n } catch {\n // Fall through\n }\n }\n return { sentiment: 0, reasoning: \"failed to parse response\", raw: content };\n}\n","/**\n * Signal-based exit strategy for memecoin trades.\n *\n * Pure computation — no network calls. Evaluates a priority-ordered\n * set of exit conditions against the current position state.\n */\n\nimport type { SignalResult } from \"./signals.js\";\n\nexport interface ExitConfig {\n stopLossPct: number; // exit if PnL drops below this % (default 10)\n trailingStopPct: number; // exit if drawdown from high-water exceeds this % (0 = disabled)\n takeProfitPct: number; // exit if PnL reaches this % (0 = disabled, use signal exit)\n deadlineUnix: number; // force exit before this unix timestamp (0 = none)\n signalExitEnabled: boolean; // exit when signals flip bearish (default true)\n}\n\nexport type ExitReason =\n | \"stop_loss\"\n | \"trailing_stop\"\n | \"take_profit\"\n | \"deadline\"\n | \"signal_bearish\"\n | \"hold\";\n\nexport interface ExitCheck {\n shouldExit: boolean;\n reason: ExitReason;\n currentPnlPct: number;\n highWaterPnlPct: number;\n}\n\nexport const DEFAULT_EXIT_CONFIG: ExitConfig = {\n stopLossPct: 10,\n trailingStopPct: 0,\n takeProfitPct: 0,\n deadlineUnix: 0,\n signalExitEnabled: true,\n};\n\n/**\n * Check whether a position should be exited.\n *\n * Priority order (first match wins):\n * 1. Deadline passed\n * 2. Stop loss\n * 3. Trailing stop (drawdown from high-water mark)\n * 4. Take profit\n * 5. Signal-based (bearish signals with sufficient confidence)\n * 6. Hold\n */\nexport function checkExit(\n entryPrice: number,\n currentPrice: number,\n highWaterPrice: number,\n config: ExitConfig,\n signalResult?: SignalResult,\n): ExitCheck {\n if (entryPrice <= 0) {\n return { shouldExit: false, reason: \"hold\", currentPnlPct: 0, highWaterPnlPct: 0 };\n }\n\n const currentPnlPct = ((currentPrice - entryPrice) / entryPrice) * 100;\n const highWaterPnlPct = ((highWaterPrice - entryPrice) / entryPrice) * 100;\n\n // 1. Deadline\n if (config.deadlineUnix > 0 && Date.now() / 1000 > config.deadlineUnix) {\n return { shouldExit: true, reason: \"deadline\", currentPnlPct, highWaterPnlPct };\n }\n\n // 2. Stop loss\n if (currentPnlPct <= -config.stopLossPct) {\n return { shouldExit: true, reason: \"stop_loss\", currentPnlPct, highWaterPnlPct };\n }\n\n // 3. Trailing stop\n if (config.trailingStopPct > 0 && highWaterPrice > 0) {\n const drawdownPct = ((highWaterPrice - currentPrice) / highWaterPrice) * 100;\n if (drawdownPct >= config.trailingStopPct) {\n return { shouldExit: true, reason: \"trailing_stop\", currentPnlPct, highWaterPnlPct };\n }\n }\n\n // 4. Take profit\n if (config.takeProfitPct > 0 && currentPnlPct >= config.takeProfitPct) {\n return { shouldExit: true, reason: \"take_profit\", currentPnlPct, highWaterPnlPct };\n }\n\n // 5. Signal-based exit\n if (\n config.signalExitEnabled &&\n signalResult &&\n signalResult.action === \"sell\" &&\n signalResult.confidence > 0.4\n ) {\n return { shouldExit: true, reason: \"signal_bearish\", currentPnlPct, highWaterPnlPct };\n }\n\n // 6. Hold\n return { shouldExit: false, reason: \"hold\", currentPnlPct, highWaterPnlPct };\n}\n","/**\n * Position tracking for memecoin trades.\n *\n * Persists open and closed positions to ~/.sherwood/config.json.\n * Uses Uniswap QuoterV2 for current price lookups.\n */\n\nimport type { Address } from \"viem\";\nimport { formatUnits, parseUnits } from \"viem\";\nimport { loadConfig, saveConfig } from \"./config.js\";\nimport { getQuote } from \"./quote.js\";\nimport { TOKENS } from \"./addresses.js\";\nimport type { ExitConfig } from \"./exit-strategy.js\";\n\nexport interface Position {\n tokenAddress: Address;\n tokenSymbol: string;\n tokenDecimals: number;\n amountIn: string; // amount spent (human-readable, e.g. \"500\")\n amountOut: string; // tokens received (raw bigint as string)\n entryPrice: number; // input token per target token at entry\n highWaterPrice: number; // highest observed price since entry\n feeTier: number; // Uniswap fee tier used\n openedAt: number; // unix timestamp\n txHash: string; // buy tx hash\n exitConfig: ExitConfig; // per-position exit parameters\n inputTokenAddress?: Address; // token used to buy (default: USDC for backwards compat)\n inputTokenSymbol?: string; // symbol of input token (default: \"USDC\")\n inputTokenDecimals?: number; // decimals of input token (default: 6)\n}\n\nexport interface ClosedPosition extends Position {\n exitPrice: number;\n closedAt: number;\n exitTxHash: string;\n exitReason: string;\n pnlUsdc: number;\n pnlPct: number;\n}\n\n// ── Reads ──\n\nexport function getOpenPositions(): Position[] {\n const config = loadConfig();\n return (config.positions as Position[] | undefined) ?? [];\n}\n\nexport function getClosedPositions(): ClosedPosition[] {\n const config = loadConfig();\n return (config.closedPositions as ClosedPosition[] | undefined) ?? [];\n}\n\n// ── Writes ──\n\nexport function addPosition(pos: Position): void {\n const config = loadConfig();\n const positions = (config.positions as Position[] | undefined) ?? [];\n positions.push(pos);\n config.positions = positions;\n saveConfig(config);\n}\n\nexport function closePosition(\n tokenAddress: Address,\n exitData: {\n exitPrice: number;\n closedAt: number;\n exitTxHash: string;\n exitReason: string;\n pnlUsdc: number;\n pnlPct: number;\n },\n): void {\n const config = loadConfig();\n const positions = (config.positions as Position[] | undefined) ?? [];\n const idx = positions.findIndex(\n (p) => p.tokenAddress.toLowerCase() === tokenAddress.toLowerCase(),\n );\n if (idx === -1) {\n throw new Error(`No open position for ${tokenAddress}`);\n }\n\n const [pos] = positions.splice(idx, 1);\n const closed: ClosedPosition = { ...pos, ...exitData };\n\n const closedPositions = (config.closedPositions as ClosedPosition[] | undefined) ?? [];\n closedPositions.push(closed);\n\n config.positions = positions;\n config.closedPositions = closedPositions;\n saveConfig(config);\n}\n\nexport function updateHighWater(tokenAddress: Address, price: number): void {\n const config = loadConfig();\n const positions = (config.positions as Position[] | undefined) ?? [];\n const pos = positions.find(\n (p) => p.tokenAddress.toLowerCase() === tokenAddress.toLowerCase(),\n );\n if (pos && price > pos.highWaterPrice) {\n pos.highWaterPrice = price;\n config.positions = positions;\n saveConfig(config);\n }\n}\n\n// ── Price Lookup ──\n\n/**\n * Get the current USDC price of one token via Uniswap QuoterV2.\n * Quotes 1 full token unit against USDC.\n */\nexport async function getCurrentPrice(\n tokenAddress: Address,\n tokenDecimals: number,\n feeTier: number,\n): Promise<number> {\n const oneToken = parseUnits(\"1\", tokenDecimals);\n const usdc = TOKENS().USDC;\n\n const { amountOut } = await getQuote({\n tokenIn: tokenAddress,\n tokenOut: usdc,\n amountIn: oneToken,\n fee: feeTier,\n });\n\n // USDC has 6 decimals\n return Number(formatUnits(amountOut, 6));\n}\n"],"mappings":"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","names":["isAddress","parseUnits","formatUnits","ETH_ADDRESS","formatUnits","formatUnits","isAddress","client","parseUnits","formatUnits","writeContractWithRetry"]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|