@sherwoodagent/cli 0.19.0 → 0.19.2
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/{chat-MUUC5L5W.js → chat-WKOSUZXO.js} +7 -7
- package/dist/{chunk-HRA2KPGW.js → chunk-I7CKBBOG.js} +3 -3
- package/dist/{chunk-W76CHVD3.js → chunk-LHDWONBI.js} +2 -2
- package/dist/{chunk-WHCXQBPS.js → chunk-P4J6FKAP.js} +4 -4
- package/dist/{chunk-VZZ2V6EM.js → chunk-QT7BUKWR.js} +5 -5
- package/dist/{chunk-B4BMCXWK.js → chunk-SZ5QQJGA.js} +2 -2
- package/dist/chunk-SZ5QQJGA.js.map +1 -0
- package/dist/{chunk-FEDSWXSD.js → chunk-TAAEMX3L.js} +2 -2
- package/dist/{chunk-G2RQLZZI.js → chunk-WWH4GD3N.js} +10 -10
- package/dist/chunk-WWH4GD3N.js.map +1 -0
- package/dist/{chunk-ZXV4TBPE.js → chunk-XR2ZUO4R.js} +2 -2
- package/dist/{chunk-DCT3IDBS.js → chunk-YJAMY25R.js} +14 -7
- package/dist/chunk-YJAMY25R.js.map +1 -0
- package/dist/{client-I56MIQAM.js → client-3AAXAX4C.js} +4 -4
- package/dist/{config-2VMLHIXD.js → config-IDAHD7S3.js} +2 -2
- package/dist/{eas-YZF6MN65.js → eas-MPDYDPJK.js} +6 -6
- package/dist/{governor-ZWKGLGMG.js → governor-J3W67NXA.js} +6 -6
- package/dist/index.js +36 -25
- package/dist/index.js.map +1 -1
- package/dist/{network-3MVRM7O4.js → network-DBUZ7GRF.js} +3 -3
- package/dist/research-DZINC4N4.js +14 -0
- package/dist/{research-VZKLOTMU.js → research-LOSOHKOJ.js} +12 -8
- package/dist/research-LOSOHKOJ.js.map +1 -0
- package/dist/{session-X3QFFCJ7.js → session-Q2WRYXYF.js} +10 -10
- package/dist/{trade-YCBFXOB3.js → trade-JLQPIA5W.js} +20 -12
- package/dist/trade-JLQPIA5W.js.map +1 -0
- package/dist/{xmtp-IH57GYSR.js → xmtp-7DF7UG66.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-B4BMCXWK.js.map +0 -1
- package/dist/chunk-DCT3IDBS.js.map +0 -1
- package/dist/chunk-G2RQLZZI.js.map +0 -1
- package/dist/research-HC2UOLFT.js +0 -14
- package/dist/research-VZKLOTMU.js.map +0 -1
- package/dist/trade-YCBFXOB3.js.map +0 -1
- /package/dist/{chat-MUUC5L5W.js.map → chat-WKOSUZXO.js.map} +0 -0
- /package/dist/{chunk-HRA2KPGW.js.map → chunk-I7CKBBOG.js.map} +0 -0
- /package/dist/{chunk-W76CHVD3.js.map → chunk-LHDWONBI.js.map} +0 -0
- /package/dist/{chunk-WHCXQBPS.js.map → chunk-P4J6FKAP.js.map} +0 -0
- /package/dist/{chunk-VZZ2V6EM.js.map → chunk-QT7BUKWR.js.map} +0 -0
- /package/dist/{chunk-FEDSWXSD.js.map → chunk-TAAEMX3L.js.map} +0 -0
- /package/dist/{chunk-ZXV4TBPE.js.map → chunk-XR2ZUO4R.js.map} +0 -0
- /package/dist/{client-I56MIQAM.js.map → client-3AAXAX4C.js.map} +0 -0
- /package/dist/{config-2VMLHIXD.js.map → config-IDAHD7S3.js.map} +0 -0
- /package/dist/{eas-YZF6MN65.js.map → eas-MPDYDPJK.js.map} +0 -0
- /package/dist/{governor-ZWKGLGMG.js.map → governor-J3W67NXA.js.map} +0 -0
- /package/dist/{network-3MVRM7O4.js.map → network-DBUZ7GRF.js.map} +0 -0
- /package/dist/{research-HC2UOLFT.js.map → research-DZINC4N4.js.map} +0 -0
- /package/dist/{session-X3QFFCJ7.js.map → session-Q2WRYXYF.js.map} +0 -0
- /package/dist/{xmtp-IH57GYSR.js.map → xmtp-7DF7UG66.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/eas.ts"],"sourcesContent":["/**\n * EAS (Ethereum Attestation Service) wrapper for syndicate join requests and approvals.\n *\n * Uses viem for on-chain writes and the EAS GraphQL API for queries.\n * No ethers dependency — attestation data is encoded with viem's encodeAbiParameters.\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, parseAbiParameters, decodeAbiParameters } from \"viem\";\nimport { getPublicClient, getWalletClient, getAccount } from \"./client.js\";\nimport { getChain, getNetwork, getChainConfig } from \"./network.js\";\nimport { EAS_CONTRACTS, EAS_SCHEMAS } from \"./addresses.js\";\nimport { EAS_ABI } from \"./abis.js\";\n\n// ── Schema definitions ──\n\nconst ZERO_BYTES32 = \"0x0000000000000000000000000000000000000000000000000000000000000000\" as Hex;\n\n// keccak256(\"Attested(address,address,bytes32,bytes32)\")\nconst ATTESTED_TOPIC = \"0x8bf46bf4cfd674fa735a3d63ec1c9ad4153f033c290341f3a588b75685141b35\" as Hex;\n\nconst JOIN_REQUEST_PARAMS = parseAbiParameters(\"uint256, uint256, address, string\");\nconst AGENT_APPROVED_PARAMS = parseAbiParameters(\"uint256, uint256, address\");\nconst X402_RESEARCH_PARAMS = parseAbiParameters(\"string, string, string, string, string\");\nconst VENICE_PROVISION_PARAMS = parseAbiParameters(\"address, string\");\nconst VENICE_INFERENCE_PARAMS = parseAbiParameters(\"string, uint256, uint256, string\");\nconst TRADE_EXECUTED_PARAMS = parseAbiParameters(\"address, address, uint256, string, string, string\");\n\nfunction assertSchemasRegistered() {\n const schemas = EAS_SCHEMAS();\n if (schemas.SYNDICATE_JOIN_REQUEST === ZERO_BYTES32 || schemas.AGENT_APPROVED === ZERO_BYTES32) {\n throw new Error(\n \"EAS schemas not registered. Run: npx tsx scripts/register-eas-schemas.ts --testnet\",\n );\n }\n}\n\n// ── GraphQL ──\n\nfunction getEasGraphqlUrl(): string {\n const url = getChainConfig().easGraphqlUrl;\n if (!url) {\n throw new Error(\n `EAS is not available on ${getNetwork()}. Attestation operations require a chain with EAS (e.g. base, base-sepolia).`,\n );\n }\n return url;\n}\n\nexport function getEasScanUrl(uid: Hex): string {\n const host = getChainConfig().easScanHost;\n if (!host) {\n throw new Error(`EAS scan is not available on ${getNetwork()}.`);\n }\n return `https://${host}/attestation/view/${uid}`;\n}\n\n// ── Attestation Creation ──\n\n/**\n * Extract the attestation UID from a transaction receipt.\n * The EAS contract emits: event Attested(address indexed recipient, address indexed attester, bytes32 uid, bytes32 indexed schemaUID)\n * uid is a non-indexed parameter in the event data.\n */\nfunction extractAttestationUid(receipt: { logs: readonly { topics: readonly Hex[]; data: Hex }[] }): Hex {\n for (const log of receipt.logs) {\n // Match the Attested event signature to avoid false positives from other events\n if (log.topics[0] !== ATTESTED_TOPIC) continue;\n // Attested event has 4 topics (sig + 3 indexed) and data contains the uid (bytes32)\n if (log.topics.length === 4 && log.data.length >= 66) {\n return (\"0x\" + log.data.slice(2, 66)) as Hex;\n }\n }\n throw new Error(\"Could not extract attestation UID from transaction receipt\");\n}\n\n/**\n * Create a SYNDICATE_JOIN_REQUEST attestation.\n * Attester: the calling agent. Recipient: the syndicate creator.\n */\nexport async function createJoinRequest(\n syndicateId: bigint,\n agentId: bigint,\n vault: Address,\n creatorAddress: Address,\n message: string,\n): Promise<{ uid: Hex; hash: Hex }> {\n assertSchemasRegistered();\n const wallet = getWalletClient();\n const client = getPublicClient();\n\n const data = encodeAbiParameters(JOIN_REQUEST_PARAMS, [\n syndicateId, agentId, vault, message,\n ]);\n\n const hash = await wallet.writeContract({\n account: getAccount(),\n chain: getChain(),\n address: EAS_CONTRACTS().EAS,\n abi: EAS_ABI,\n functionName: \"attest\",\n args: [{\n schema: EAS_SCHEMAS().SYNDICATE_JOIN_REQUEST,\n data: {\n recipient: creatorAddress,\n expirationTime: 0n,\n revocable: true,\n refUID: ZERO_BYTES32,\n data,\n value: 0n,\n },\n }],\n value: 0n,\n });\n\n const receipt = await client.waitForTransactionReceipt({ hash });\n const uid = extractAttestationUid(receipt);\n\n return { uid, hash };\n}\n\n/**\n * Create an AGENT_APPROVED attestation.\n * Attester: the syndicate creator. Recipient: the agent wallet.\n */\nexport async function createApproval(\n syndicateId: bigint,\n agentId: bigint,\n vault: Address,\n agentAddress: Address,\n): Promise<{ uid: Hex; hash: Hex }> {\n assertSchemasRegistered();\n const wallet = getWalletClient();\n const client = getPublicClient();\n\n const data = encodeAbiParameters(AGENT_APPROVED_PARAMS, [\n syndicateId, agentId, vault,\n ]);\n\n const hash = await wallet.writeContract({\n account: getAccount(),\n chain: getChain(),\n address: EAS_CONTRACTS().EAS,\n abi: EAS_ABI,\n functionName: \"attest\",\n args: [{\n schema: EAS_SCHEMAS().AGENT_APPROVED,\n data: {\n recipient: agentAddress,\n expirationTime: 0n,\n revocable: true,\n refUID: ZERO_BYTES32,\n data,\n value: 0n,\n },\n }],\n value: 0n,\n });\n\n const receipt = await client.waitForTransactionReceipt({ hash });\n const uid = extractAttestationUid(receipt);\n\n return { uid, hash };\n}\n\n/**\n * Revoke an attestation. Only the original attester can revoke.\n */\nexport async function revokeAttestation(\n schemaUid: Hex,\n attestationUid: Hex,\n): Promise<Hex> {\n const wallet = getWalletClient();\n\n return wallet.writeContract({\n account: getAccount(),\n chain: getChain(),\n address: EAS_CONTRACTS().EAS,\n abi: EAS_ABI,\n functionName: \"revoke\",\n args: [{\n schema: schemaUid,\n data: {\n uid: attestationUid,\n value: 0n,\n },\n }],\n value: 0n,\n });\n}\n\n/**\n * Create an X402_RESEARCH attestation — records a research query on-chain.\n * Attester: the agent. Recipient: the agent itself (self-attestation for audit trail).\n * Schema: \"string provider, string queryType, string prompt, string costUsdc, string resultUri\"\n */\nexport async function createResearchAttestation(\n provider: string,\n queryType: string,\n prompt: string,\n costUsdc: string,\n resultUri: string,\n): Promise<{ uid: Hex; hash: Hex }> {\n const schemas = EAS_SCHEMAS();\n if (schemas.X402_RESEARCH === ZERO_BYTES32) {\n throw new Error(\n \"X402_RESEARCH schema not registered. Run: npx tsx scripts/register-eas-schemas.ts --testnet\",\n );\n }\n\n const wallet = getWalletClient();\n const client = getPublicClient();\n const account = getAccount();\n\n const data = encodeAbiParameters(X402_RESEARCH_PARAMS, [\n provider, queryType, prompt, costUsdc, resultUri,\n ]);\n\n const hash = await wallet.writeContract({\n account,\n chain: getChain(),\n address: EAS_CONTRACTS().EAS,\n abi: EAS_ABI,\n functionName: \"attest\",\n args: [{\n schema: schemas.X402_RESEARCH,\n data: {\n recipient: account.address,\n expirationTime: 0n,\n revocable: false,\n refUID: ZERO_BYTES32,\n data,\n value: 0n,\n },\n }],\n value: 0n,\n });\n\n const receipt = await client.waitForTransactionReceipt({ hash });\n const uid = extractAttestationUid(receipt);\n\n return { uid, hash };\n}\n\n/**\n * Create a VENICE_PROVISION attestation — records that an agent provisioned a Venice API key.\n * Schema: \"address agent, string status\"\n */\nexport async function createVeniceProvisionAttestation(\n agent: Address,\n): Promise<{ uid: Hex; hash: Hex }> {\n const schemas = EAS_SCHEMAS();\n if (schemas.VENICE_PROVISION === ZERO_BYTES32) return skipAttestation(\"VENICE_PROVISION\");\n\n const wallet = getWalletClient();\n const client = getPublicClient();\n const account = getAccount();\n\n const data = encodeAbiParameters(VENICE_PROVISION_PARAMS, [agent, \"provisioned\"]);\n\n const hash = await wallet.writeContract({\n account,\n chain: getChain(),\n address: EAS_CONTRACTS().EAS,\n abi: EAS_ABI,\n functionName: \"attest\",\n args: [{\n schema: schemas.VENICE_PROVISION,\n data: {\n recipient: agent,\n expirationTime: 0n,\n revocable: false,\n refUID: ZERO_BYTES32,\n data,\n value: 0n,\n },\n }],\n value: 0n,\n });\n\n const receipt = await client.waitForTransactionReceipt({ hash });\n const uid = extractAttestationUid(receipt);\n return { uid, hash };\n}\n\n/**\n * Create a VENICE_INFERENCE attestation — records an inference call.\n * Schema: \"string model, uint256 promptTokens, uint256 completionTokens, string promptHash\"\n */\nexport async function createVeniceInferenceAttestation(\n model: string,\n promptTokens: number,\n completionTokens: number,\n promptHash: string,\n): Promise<{ uid: Hex; hash: Hex }> {\n const schemas = EAS_SCHEMAS();\n if (schemas.VENICE_INFERENCE === ZERO_BYTES32) return skipAttestation(\"VENICE_INFERENCE\");\n\n const wallet = getWalletClient();\n const client = getPublicClient();\n const account = getAccount();\n\n const data = encodeAbiParameters(VENICE_INFERENCE_PARAMS, [\n model,\n BigInt(promptTokens),\n BigInt(completionTokens),\n promptHash,\n ]);\n\n const hash = await wallet.writeContract({\n account,\n chain: getChain(),\n address: EAS_CONTRACTS().EAS,\n abi: EAS_ABI,\n functionName: \"attest\",\n args: [{\n schema: schemas.VENICE_INFERENCE,\n data: {\n recipient: account.address,\n expirationTime: 0n,\n revocable: false,\n refUID: ZERO_BYTES32,\n data,\n value: 0n,\n },\n }],\n value: 0n,\n });\n\n const receipt = await client.waitForTransactionReceipt({ hash });\n const uid = extractAttestationUid(receipt);\n return { uid, hash };\n}\n\n/**\n * Create a TRADE_EXECUTED attestation — records a swap on-chain.\n * Schema: \"address tokenIn, address tokenOut, uint256 amountIn, string amountOut, string txHash, string routing\"\n */\nexport async function createTradeAttestation(\n tokenIn: Address,\n tokenOut: Address,\n amountIn: bigint,\n amountOut: string,\n txHash: string,\n routing: string,\n): Promise<{ uid: Hex; hash: Hex }> {\n const schemas = EAS_SCHEMAS();\n if (schemas.TRADE_EXECUTED === ZERO_BYTES32) return skipAttestation(\"TRADE_EXECUTED\");\n\n const wallet = getWalletClient();\n const client = getPublicClient();\n const account = getAccount();\n\n const data = encodeAbiParameters(TRADE_EXECUTED_PARAMS, [\n tokenIn, tokenOut, amountIn, amountOut, txHash, routing,\n ]);\n\n const hash = await wallet.writeContract({\n account,\n chain: getChain(),\n address: EAS_CONTRACTS().EAS,\n abi: EAS_ABI,\n functionName: \"attest\",\n args: [{\n schema: schemas.TRADE_EXECUTED,\n data: {\n recipient: account.address,\n expirationTime: 0n,\n revocable: false,\n refUID: ZERO_BYTES32,\n data,\n value: 0n,\n },\n }],\n value: 0n,\n });\n\n const receipt = await client.waitForTransactionReceipt({ hash });\n const uid = extractAttestationUid(receipt);\n return { uid, hash };\n}\n\n/** Skip attestation gracefully when schema isn't registered on this chain. */\nfunction skipAttestation(name: string): { uid: Hex; hash: Hex } {\n return { uid: ZERO_BYTES32, hash: ZERO_BYTES32 };\n}\n\n// ── Attestation Queries ──\n\nexport interface JoinRequestAttestation {\n uid: Hex;\n attester: Address;\n recipient: Address;\n time: number;\n decoded: {\n syndicateId: bigint;\n agentId: bigint;\n vault: Address;\n message: string;\n };\n}\n\n/**\n * Query pending (non-revoked) join requests for a given recipient (creator address).\n * Uses the EAS GraphQL API.\n */\nexport interface ApprovalAttestation {\n uid: Hex;\n attester: Address;\n recipient: Address;\n time: number;\n decoded: {\n syndicateId: bigint;\n agentId: bigint;\n vault: Address;\n };\n}\n\n/**\n * Query existing (non-revoked) AGENT_APPROVED attestations created by a given attester (creator).\n * Used to check for duplicates before creating a new approval and to filter already-approved agents from requests.\n */\nexport async function queryApprovals(\n attester: Address,\n): Promise<ApprovalAttestation[]> {\n assertSchemasRegistered();\n const schemaUid = EAS_SCHEMAS().AGENT_APPROVED;\n const url = getEasGraphqlUrl();\n\n const query = `\n query Approvals($schemaId: String!, $attester: String!) {\n attestations(\n where: {\n schemaId: { equals: $schemaId }\n attester: { equals: $attester }\n revoked: { equals: false }\n }\n orderBy: [{ time: desc }]\n ) {\n id\n attester\n recipient\n time\n data\n }\n }\n `;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n query,\n variables: { schemaId: schemaUid, attester },\n }),\n });\n\n if (!response.ok) {\n throw new Error(`EAS GraphQL query failed: ${response.statusText}`);\n }\n\n const json = await response.json() as {\n data?: {\n attestations: Array<{\n id: string;\n attester: string;\n recipient: string;\n time: number;\n data: string;\n }>;\n };\n };\n\n if (!json.data?.attestations) return [];\n\n return json.data.attestations.map((a) => {\n const decoded = decodeAbiParameters(AGENT_APPROVED_PARAMS, a.data as Hex);\n return {\n uid: a.id as Hex,\n attester: a.attester as Address,\n recipient: a.recipient as Address,\n time: a.time,\n decoded: {\n syndicateId: decoded[0],\n agentId: decoded[1],\n vault: decoded[2],\n },\n };\n });\n}\n\nexport async function queryJoinRequests(\n recipient: Address,\n): Promise<JoinRequestAttestation[]> {\n assertSchemasRegistered();\n const schemaUid = EAS_SCHEMAS().SYNDICATE_JOIN_REQUEST;\n const url = getEasGraphqlUrl();\n\n const query = `\n query JoinRequests($schemaId: String!, $recipient: String!) {\n attestations(\n where: {\n schemaId: { equals: $schemaId }\n recipient: { equals: $recipient }\n revoked: { equals: false }\n }\n orderBy: [{ time: desc }]\n ) {\n id\n attester\n recipient\n time\n data\n }\n }\n `;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n query,\n variables: { schemaId: schemaUid, recipient },\n }),\n });\n\n if (!response.ok) {\n throw new Error(`EAS GraphQL query failed: ${response.statusText}`);\n }\n\n const json = await response.json() as {\n data?: {\n attestations: Array<{\n id: string;\n attester: string;\n recipient: string;\n time: number;\n data: string;\n }>;\n };\n };\n\n if (!json.data?.attestations) return [];\n\n return json.data.attestations.map((a) => {\n const decoded = decodeAbiParameters(JOIN_REQUEST_PARAMS, a.data as Hex);\n return {\n uid: a.id as Hex,\n attester: a.attester as Address,\n recipient: a.recipient as Address,\n time: a.time,\n decoded: {\n syndicateId: decoded[0],\n agentId: decoded[1],\n vault: decoded[2],\n message: decoded[3],\n },\n };\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAQA,SAAS,qBAAqB,oBAAoB,2BAA2B;AAQ7E,IAAM,eAAe;AAGrB,IAAM,iBAAiB;AAEvB,IAAM,sBAAsB,mBAAmB,mCAAmC;AAClF,IAAM,wBAAwB,mBAAmB,2BAA2B;AAC5E,IAAM,uBAAuB,mBAAmB,wCAAwC;AACxF,IAAM,0BAA0B,mBAAmB,iBAAiB;AACpE,IAAM,0BAA0B,mBAAmB,kCAAkC;AACrF,IAAM,wBAAwB,mBAAmB,mDAAmD;AAEpG,SAAS,0BAA0B;AACjC,QAAM,UAAU,YAAY;AAC5B,MAAI,QAAQ,2BAA2B,gBAAgB,QAAQ,mBAAmB,cAAc;AAC9F,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;AAIA,SAAS,mBAA2B;AAClC,QAAM,MAAM,eAAe,EAAE;AAC7B,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR,2BAA2B,WAAW,CAAC;AAAA,IACzC;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,cAAc,KAAkB;AAC9C,QAAM,OAAO,eAAe,EAAE;AAC9B,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,gCAAgC,WAAW,CAAC,GAAG;AAAA,EACjE;AACA,SAAO,WAAW,IAAI,qBAAqB,GAAG;AAChD;AASA,SAAS,sBAAsB,SAA0E;AACvG,aAAW,OAAO,QAAQ,MAAM;AAE9B,QAAI,IAAI,OAAO,CAAC,MAAM,eAAgB;AAEtC,QAAI,IAAI,OAAO,WAAW,KAAK,IAAI,KAAK,UAAU,IAAI;AACpD,aAAQ,OAAO,IAAI,KAAK,MAAM,GAAG,EAAE;AAAA,IACrC;AAAA,EACF;AACA,QAAM,IAAI,MAAM,4DAA4D;AAC9E;AAMA,eAAsB,kBACpB,aACA,SACA,OACA,gBACA,SACkC;AAClC,0BAAwB;AACxB,QAAM,SAAS,gBAAgB;AAC/B,QAAM,SAAS,gBAAgB;AAE/B,QAAM,OAAO,oBAAoB,qBAAqB;AAAA,IACpD;AAAA,IAAa;AAAA,IAAS;AAAA,IAAO;AAAA,EAC/B,CAAC;AAED,QAAM,OAAO,MAAM,OAAO,cAAc;AAAA,IACtC,SAAS,WAAW;AAAA,IACpB,OAAO,SAAS;AAAA,IAChB,SAAS,cAAc,EAAE;AAAA,IACzB,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC;AAAA,MACL,QAAQ,YAAY,EAAE;AAAA,MACtB,MAAM;AAAA,QACJ,WAAW;AAAA,QACX,gBAAgB;AAAA,QAChB,WAAW;AAAA,QACX,QAAQ;AAAA,QACR;AAAA,QACA,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,IACD,OAAO;AAAA,EACT,CAAC;AAED,QAAM,UAAU,MAAM,OAAO,0BAA0B,EAAE,KAAK,CAAC;AAC/D,QAAM,MAAM,sBAAsB,OAAO;AAEzC,SAAO,EAAE,KAAK,KAAK;AACrB;AAMA,eAAsB,eACpB,aACA,SACA,OACA,cACkC;AAClC,0BAAwB;AACxB,QAAM,SAAS,gBAAgB;AAC/B,QAAM,SAAS,gBAAgB;AAE/B,QAAM,OAAO,oBAAoB,uBAAuB;AAAA,IACtD;AAAA,IAAa;AAAA,IAAS;AAAA,EACxB,CAAC;AAED,QAAM,OAAO,MAAM,OAAO,cAAc;AAAA,IACtC,SAAS,WAAW;AAAA,IACpB,OAAO,SAAS;AAAA,IAChB,SAAS,cAAc,EAAE;AAAA,IACzB,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC;AAAA,MACL,QAAQ,YAAY,EAAE;AAAA,MACtB,MAAM;AAAA,QACJ,WAAW;AAAA,QACX,gBAAgB;AAAA,QAChB,WAAW;AAAA,QACX,QAAQ;AAAA,QACR;AAAA,QACA,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,IACD,OAAO;AAAA,EACT,CAAC;AAED,QAAM,UAAU,MAAM,OAAO,0BAA0B,EAAE,KAAK,CAAC;AAC/D,QAAM,MAAM,sBAAsB,OAAO;AAEzC,SAAO,EAAE,KAAK,KAAK;AACrB;AAKA,eAAsB,kBACpB,WACA,gBACc;AACd,QAAM,SAAS,gBAAgB;AAE/B,SAAO,OAAO,cAAc;AAAA,IAC1B,SAAS,WAAW;AAAA,IACpB,OAAO,SAAS;AAAA,IAChB,SAAS,cAAc,EAAE;AAAA,IACzB,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC;AAAA,MACL,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,IACD,OAAO;AAAA,EACT,CAAC;AACH;AAOA,eAAsB,0BACpB,UACA,WACA,QACA,UACA,WACkC;AAClC,QAAM,UAAU,YAAY;AAC5B,MAAI,QAAQ,kBAAkB,cAAc;AAC1C,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,gBAAgB;AAC/B,QAAM,SAAS,gBAAgB;AAC/B,QAAM,UAAU,WAAW;AAE3B,QAAM,OAAO,oBAAoB,sBAAsB;AAAA,IACrD;AAAA,IAAU;AAAA,IAAW;AAAA,IAAQ;AAAA,IAAU;AAAA,EACzC,CAAC;AAED,QAAM,OAAO,MAAM,OAAO,cAAc;AAAA,IACtC;AAAA,IACA,OAAO,SAAS;AAAA,IAChB,SAAS,cAAc,EAAE;AAAA,IACzB,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC;AAAA,MACL,QAAQ,QAAQ;AAAA,MAChB,MAAM;AAAA,QACJ,WAAW,QAAQ;AAAA,QACnB,gBAAgB;AAAA,QAChB,WAAW;AAAA,QACX,QAAQ;AAAA,QACR;AAAA,QACA,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,IACD,OAAO;AAAA,EACT,CAAC;AAED,QAAM,UAAU,MAAM,OAAO,0BAA0B,EAAE,KAAK,CAAC;AAC/D,QAAM,MAAM,sBAAsB,OAAO;AAEzC,SAAO,EAAE,KAAK,KAAK;AACrB;AAMA,eAAsB,iCACpB,OACkC;AAClC,QAAM,UAAU,YAAY;AAC5B,MAAI,QAAQ,qBAAqB,aAAc,QAAO,gBAAgB,kBAAkB;AAExF,QAAM,SAAS,gBAAgB;AAC/B,QAAM,SAAS,gBAAgB;AAC/B,QAAM,UAAU,WAAW;AAE3B,QAAM,OAAO,oBAAoB,yBAAyB,CAAC,OAAO,aAAa,CAAC;AAEhF,QAAM,OAAO,MAAM,OAAO,cAAc;AAAA,IACtC;AAAA,IACA,OAAO,SAAS;AAAA,IAChB,SAAS,cAAc,EAAE;AAAA,IACzB,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC;AAAA,MACL,QAAQ,QAAQ;AAAA,MAChB,MAAM;AAAA,QACJ,WAAW;AAAA,QACX,gBAAgB;AAAA,QAChB,WAAW;AAAA,QACX,QAAQ;AAAA,QACR;AAAA,QACA,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,IACD,OAAO;AAAA,EACT,CAAC;AAED,QAAM,UAAU,MAAM,OAAO,0BAA0B,EAAE,KAAK,CAAC;AAC/D,QAAM,MAAM,sBAAsB,OAAO;AACzC,SAAO,EAAE,KAAK,KAAK;AACrB;AAMA,eAAsB,iCACpB,OACA,cACA,kBACA,YACkC;AAClC,QAAM,UAAU,YAAY;AAC5B,MAAI,QAAQ,qBAAqB,aAAc,QAAO,gBAAgB,kBAAkB;AAExF,QAAM,SAAS,gBAAgB;AAC/B,QAAM,SAAS,gBAAgB;AAC/B,QAAM,UAAU,WAAW;AAE3B,QAAM,OAAO,oBAAoB,yBAAyB;AAAA,IACxD;AAAA,IACA,OAAO,YAAY;AAAA,IACnB,OAAO,gBAAgB;AAAA,IACvB;AAAA,EACF,CAAC;AAED,QAAM,OAAO,MAAM,OAAO,cAAc;AAAA,IACtC;AAAA,IACA,OAAO,SAAS;AAAA,IAChB,SAAS,cAAc,EAAE;AAAA,IACzB,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC;AAAA,MACL,QAAQ,QAAQ;AAAA,MAChB,MAAM;AAAA,QACJ,WAAW,QAAQ;AAAA,QACnB,gBAAgB;AAAA,QAChB,WAAW;AAAA,QACX,QAAQ;AAAA,QACR;AAAA,QACA,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,IACD,OAAO;AAAA,EACT,CAAC;AAED,QAAM,UAAU,MAAM,OAAO,0BAA0B,EAAE,KAAK,CAAC;AAC/D,QAAM,MAAM,sBAAsB,OAAO;AACzC,SAAO,EAAE,KAAK,KAAK;AACrB;AAMA,eAAsB,uBACpB,SACA,UACA,UACA,WACA,QACA,SACkC;AAClC,QAAM,UAAU,YAAY;AAC5B,MAAI,QAAQ,mBAAmB,aAAc,QAAO,gBAAgB,gBAAgB;AAEpF,QAAM,SAAS,gBAAgB;AAC/B,QAAM,SAAS,gBAAgB;AAC/B,QAAM,UAAU,WAAW;AAE3B,QAAM,OAAO,oBAAoB,uBAAuB;AAAA,IACtD;AAAA,IAAS;AAAA,IAAU;AAAA,IAAU;AAAA,IAAW;AAAA,IAAQ;AAAA,EAClD,CAAC;AAED,QAAM,OAAO,MAAM,OAAO,cAAc;AAAA,IACtC;AAAA,IACA,OAAO,SAAS;AAAA,IAChB,SAAS,cAAc,EAAE;AAAA,IACzB,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC;AAAA,MACL,QAAQ,QAAQ;AAAA,MAChB,MAAM;AAAA,QACJ,WAAW,QAAQ;AAAA,QACnB,gBAAgB;AAAA,QAChB,WAAW;AAAA,QACX,QAAQ;AAAA,QACR;AAAA,QACA,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,IACD,OAAO;AAAA,EACT,CAAC;AAED,QAAM,UAAU,MAAM,OAAO,0BAA0B,EAAE,KAAK,CAAC;AAC/D,QAAM,MAAM,sBAAsB,OAAO;AACzC,SAAO,EAAE,KAAK,KAAK;AACrB;AAGA,SAAS,gBAAgB,MAAuC;AAC9D,SAAO,EAAE,KAAK,cAAc,MAAM,aAAa;AACjD;AAqCA,eAAsB,eACpB,UACgC;AAChC,0BAAwB;AACxB,QAAM,YAAY,YAAY,EAAE;AAChC,QAAM,MAAM,iBAAiB;AAE7B,QAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBd,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU;AAAA,MACnB;AAAA,MACA,WAAW,EAAE,UAAU,WAAW,SAAS;AAAA,IAC7C,CAAC;AAAA,EACH,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,6BAA6B,SAAS,UAAU,EAAE;AAAA,EACpE;AAEA,QAAM,OAAO,MAAM,SAAS,KAAK;AAYjC,MAAI,CAAC,KAAK,MAAM,aAAc,QAAO,CAAC;AAEtC,SAAO,KAAK,KAAK,aAAa,IAAI,CAAC,MAAM;AACvC,UAAM,UAAU,oBAAoB,uBAAuB,EAAE,IAAW;AACxE,WAAO;AAAA,MACL,KAAK,EAAE;AAAA,MACP,UAAU,EAAE;AAAA,MACZ,WAAW,EAAE;AAAA,MACb,MAAM,EAAE;AAAA,MACR,SAAS;AAAA,QACP,aAAa,QAAQ,CAAC;AAAA,QACtB,SAAS,QAAQ,CAAC;AAAA,QAClB,OAAO,QAAQ,CAAC;AAAA,MAClB;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,kBACpB,WACmC;AACnC,0BAAwB;AACxB,QAAM,YAAY,YAAY,EAAE;AAChC,QAAM,MAAM,iBAAiB;AAE7B,QAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBd,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU;AAAA,MACnB;AAAA,MACA,WAAW,EAAE,UAAU,WAAW,UAAU;AAAA,IAC9C,CAAC;AAAA,EACH,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,6BAA6B,SAAS,UAAU,EAAE;AAAA,EACpE;AAEA,QAAM,OAAO,MAAM,SAAS,KAAK;AAYjC,MAAI,CAAC,KAAK,MAAM,aAAc,QAAO,CAAC;AAEtC,SAAO,KAAK,KAAK,aAAa,IAAI,CAAC,MAAM;AACvC,UAAM,UAAU,oBAAoB,qBAAqB,EAAE,IAAW;AACtE,WAAO;AAAA,MACL,KAAK,EAAE;AAAA,MACP,UAAU,EAAE;AAAA,MACZ,WAAW,EAAE;AAAA,MACb,MAAM,EAAE;AAAA,MACR,SAAS;AAAA,QACP,aAAa,QAAQ,CAAC;AAAA,QACtB,SAAS,QAAQ,CAAC;AAAA,QAClB,OAAO,QAAQ,CAAC;AAAA,QAChB,SAAS,QAAQ,CAAC;AAAA,MACpB;AAAA,IACF;AAAA,EACF,CAAC;AACH;","names":[]}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
MessariProvider,
|
|
3
|
-
NansenProvider,
|
|
4
|
-
getResearchProvider
|
|
5
|
-
} from "./chunk-ZXV4TBPE.js";
|
|
6
|
-
import "./chunk-HRA2KPGW.js";
|
|
7
|
-
import "./chunk-FEDSWXSD.js";
|
|
8
|
-
import "./chunk-B4BMCXWK.js";
|
|
9
|
-
export {
|
|
10
|
-
MessariProvider,
|
|
11
|
-
NansenProvider,
|
|
12
|
-
getResearchProvider
|
|
13
|
-
};
|
|
14
|
-
//# sourceMappingURL=research-HC2UOLFT.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/research.ts"],"sourcesContent":["/**\n * Research commands — sherwood research <subcommand>\n *\n * Query DeFi research providers (Messari, Nansen) using x402 micropayments.\n * Agent pays per-query with USDC from its own wallet — no vault interaction needed.\n *\n * --post <syndicate>: pins result to IPFS, creates EAS attestation, posts\n * lightweight notification to syndicate XMTP chat (not the full result).\n *\n * --yes: skip the cost confirmation prompt (for non-interactive / agent use).\n */\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { confirm } from \"@inquirer/prompts\";\nimport { isAddress } from \"viem\";\nimport { getAccount } from \"../lib/client.js\";\nimport type { MessageType } from \"../lib/types.js\";\nimport { getResearchProvider } from \"../providers/research/index.js\";\nimport type { ResearchResult } from \"../providers/research/index.js\";\nimport { MESSARI_COST_ESTIMATE } from \"../providers/research/messari.js\";\nimport { NANSEN_COST_ESTIMATE } from \"../providers/research/nansen.js\";\n\n// Lazy-load XMTP to avoid breaking non-chat commands when @xmtp/cli is missing\nasync function loadXmtp() {\n return import(\"../lib/xmtp.js\");\n}\n\n// ── Cost estimates ──\n\nconst COST_ESTIMATES: Record<string, Record<string, string>> = {\n messari: MESSARI_COST_ESTIMATE,\n nansen: NANSEN_COST_ESTIMATE,\n};\n\nfunction getEstimatedCost(provider: string, queryType: string): string {\n return COST_ESTIMATES[provider]?.[queryType] ?? \"unknown\";\n}\n\n/**\n * Confirm cost with the user before executing the x402 query.\n * Skipped when --yes is passed (non-interactive / agent mode).\n */\nasync function confirmCost(\n provider: string,\n queryType: string,\n target: string,\n skipConfirm: boolean,\n): Promise<boolean> {\n const estimate = getEstimatedCost(provider, queryType);\n\n console.log();\n console.log(chalk.bold(`Research Query`));\n console.log(chalk.dim(\"─\".repeat(40)));\n console.log(` Provider: ${provider}`);\n console.log(` Type: ${queryType}`);\n console.log(` Target: ${target}`);\n console.log(` Est. cost: ${chalk.yellow(estimate + \" USDC\")} (x402 micropayment)`);\n console.log();\n\n if (skipConfirm) return true;\n\n return confirm({\n message: `Pay ${estimate} USDC to ${provider} for this query?`,\n default: true,\n });\n}\n\n// ── Output formatting ──\n\nfunction formatResearchResult(result: ResearchResult): void {\n console.log();\n console.log(\n chalk.bold(`Research: ${result.queryType} ${result.target} (${result.provider})`),\n );\n console.log(chalk.dim(\"─\".repeat(50)));\n\n // Flatten the top-level data keys into a readable summary\n const data = result.data;\n for (const [key, value] of Object.entries(data)) {\n if (value === null || value === undefined) continue;\n\n if (typeof value === \"object\" && !Array.isArray(value)) {\n // Nested object — show as sub-section\n console.log(chalk.bold(`\\n ${key}`));\n for (const [subKey, subValue] of Object.entries(\n value as Record<string, unknown>,\n )) {\n console.log(` ${subKey}: ${formatValue(subValue)}`);\n }\n } else if (Array.isArray(value)) {\n console.log(` ${key}: ${chalk.dim(`[${value.length} items]`)}`);\n } else {\n console.log(` ${key}: ${formatValue(value)}`);\n }\n }\n\n console.log();\n console.log(\n chalk.dim(\n ` Cost: $${result.costUsdc} USDC • Provider: ${result.provider}`,\n ),\n );\n console.log();\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === \"number\") {\n // Format large numbers with commas\n return value.toLocaleString(\"en-US\", { maximumFractionDigits: 4 });\n }\n if (typeof value === \"bigint\") {\n return value.toLocaleString(\"en-US\");\n }\n return String(value);\n}\n\n// ── Post flow: IPFS → EAS → XMTP ──\n\nasync function postResearch(\n syndicateName: string,\n result: ResearchResult,\n prompt: string,\n): Promise<void> {\n const { pinJSON } = await import(\"../lib/ipfs.js\");\n const { createResearchAttestation, getEasScanUrl } = await import(\n \"../lib/eas.js\"\n );\n const xmtp = await loadXmtp();\n\n // 1. Pin full research result to IPFS\n const pinSpinner = ora(\"Pinning research result to IPFS...\").start();\n let resultUri: string;\n try {\n resultUri = await pinJSON(\n {\n schema: \"sherwood/research/v1\",\n provider: result.provider,\n queryType: result.queryType,\n target: result.target,\n prompt,\n costUsdc: result.costUsdc,\n data: result.data,\n timestamp: result.timestamp,\n } as Record<string, unknown>,\n `sherwood-research-${result.provider}-${result.queryType}-${Date.now()}`,\n );\n pinSpinner.succeed(`Pinned to IPFS: ${chalk.dim(resultUri)}`);\n } catch (err) {\n pinSpinner.fail(\"Failed to pin to IPFS\");\n console.error(\n chalk.red(err instanceof Error ? err.message : String(err)),\n );\n return;\n }\n\n // 2. Create EAS attestation with prompt, cost, provider, and IPFS URI\n const easSpinner = ora(\"Creating EAS attestation...\").start();\n let attestationUid: string;\n try {\n const { uid } = await createResearchAttestation(\n result.provider,\n result.queryType,\n prompt,\n result.costUsdc,\n resultUri,\n );\n attestationUid = uid;\n easSpinner.succeed(\n `Attested: ${chalk.dim(getEasScanUrl(uid))}`,\n );\n } catch (err) {\n easSpinner.fail(\"Failed to create EAS attestation\");\n console.error(\n chalk.red(err instanceof Error ? err.message : String(err)),\n );\n return;\n }\n\n // 3. Post lightweight notification to XMTP chat\n const chatSpinner = ora(\"Posting to syndicate chat...\").start();\n try {\n const group = await xmtp.getGroup(\"\", syndicateName);\n await xmtp.sendEnvelope(group, {\n type: \"X402_RESEARCH\" as MessageType,\n from: getAccount().address,\n text: `Ran ${result.provider} ${result.queryType} on ${result.target} ($${result.costUsdc} USDC)`,\n data: {\n provider: result.provider,\n queryType: result.queryType,\n target: result.target,\n costUsdc: result.costUsdc,\n resultUri,\n attestationUid,\n },\n timestamp: result.timestamp,\n });\n chatSpinner.succeed(\"Posted to syndicate chat\");\n } catch (err) {\n chatSpinner.fail(\"Failed to post to chat\");\n console.error(\n chalk.red(err instanceof Error ? err.message : String(err)),\n );\n }\n}\n\n// ── Command registration ──\n\nexport function registerResearchCommands(program: Command): void {\n const research = program\n .command(\"research\")\n .description(\n \"Query DeFi research providers via x402 micropayments (USDC on Base)\",\n );\n\n // ── research token <target> ──\n\n research\n .command(\"token <target>\")\n .description(\"Token report — profile, market data, on-chain metrics\")\n .requiredOption(\n \"--provider <name>\",\n \"Research provider (messari, nansen)\",\n )\n .option(\n \"--post <syndicate>\",\n \"Post result to syndicate chat (pin to IPFS + attest to EAS)\",\n )\n .option(\"--yes\", \"Skip cost confirmation prompt\", false)\n .action(async (target: string, opts: { provider: string; post?: string; yes: boolean }) => {\n const ok = await confirmCost(opts.provider, \"token\", target, opts.yes);\n if (!ok) {\n console.log(chalk.dim(\"Cancelled.\"));\n return;\n }\n\n const spinner = ora(\n `Querying ${opts.provider} for token ${target}...`,\n ).start();\n\n try {\n const provider = getResearchProvider(opts.provider);\n const result = await provider.query({ type: \"token\", target });\n spinner.succeed(`Token data received from ${opts.provider}`);\n formatResearchResult(result);\n\n if (opts.post) {\n await postResearch(opts.post, result, `token ${target}`);\n }\n } catch (err) {\n spinner.fail(`Token query failed`);\n console.error(\n chalk.red(err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n });\n\n // ── research market <asset> ──\n\n research\n .command(\"market <asset>\")\n .description(\"Market overview — price, volume, market cap, ROI, ATH\")\n .requiredOption(\n \"--provider <name>\",\n \"Research provider (messari, nansen)\",\n )\n .option(\n \"--post <syndicate>\",\n \"Post result to syndicate chat (pin to IPFS + attest to EAS)\",\n )\n .option(\"--yes\", \"Skip cost confirmation prompt\", false)\n .action(async (asset: string, opts: { provider: string; post?: string; yes: boolean }) => {\n const ok = await confirmCost(opts.provider, \"market\", asset, opts.yes);\n if (!ok) {\n console.log(chalk.dim(\"Cancelled.\"));\n return;\n }\n\n const spinner = ora(\n `Querying ${opts.provider} for ${asset} market data...`,\n ).start();\n\n try {\n const provider = getResearchProvider(opts.provider);\n const result = await provider.query({ type: \"market\", target: asset });\n spinner.succeed(`Market data received from ${opts.provider}`);\n formatResearchResult(result);\n\n if (opts.post) {\n await postResearch(opts.post, result, `market ${asset}`);\n }\n } catch (err) {\n spinner.fail(`Market query failed`);\n console.error(\n chalk.red(err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n });\n\n // ── research smart-money ──\n\n research\n .command(\"smart-money\")\n .description(\n \"Smart money flows — net flow, DEX trades, holdings from labeled wallets\",\n )\n .requiredOption(\"--token <symbol>\", \"Token symbol to analyze (e.g. WETH)\")\n .requiredOption(\n \"--provider <name>\",\n \"Research provider (messari, nansen)\",\n )\n .option(\n \"--post <syndicate>\",\n \"Post result to syndicate chat (pin to IPFS + attest to EAS)\",\n )\n .option(\"--yes\", \"Skip cost confirmation prompt\", false)\n .action(async (opts: { token: string; provider: string; post?: string; yes: boolean }) => {\n const ok = await confirmCost(opts.provider, \"smart-money\", opts.token, opts.yes);\n if (!ok) {\n console.log(chalk.dim(\"Cancelled.\"));\n return;\n }\n\n const spinner = ora(\n `Querying ${opts.provider} for ${opts.token} smart money flows...`,\n ).start();\n\n try {\n const provider = getResearchProvider(opts.provider);\n const result = await provider.query({\n type: \"smart-money\",\n target: opts.token,\n options: { token: opts.token },\n });\n spinner.succeed(\n `Smart money data received from ${opts.provider}`,\n );\n formatResearchResult(result);\n\n if (opts.post) {\n await postResearch(\n opts.post,\n result,\n `smart-money --token ${opts.token}`,\n );\n }\n } catch (err) {\n spinner.fail(`Smart money query failed`);\n console.error(\n chalk.red(err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n });\n\n // ── research wallet <address> ──\n\n research\n .command(\"wallet <address>\")\n .description(\n \"Wallet due diligence — PnL history, transaction patterns, counterparties\",\n )\n .requiredOption(\n \"--provider <name>\",\n \"Research provider (messari, nansen)\",\n )\n .option(\n \"--post <syndicate>\",\n \"Post result to syndicate chat (pin to IPFS + attest to EAS)\",\n )\n .option(\"--yes\", \"Skip cost confirmation prompt\", false)\n .action(async (address: string, opts: { provider: string; post?: string; yes: boolean }) => {\n if (!isAddress(address)) {\n console.error(chalk.red(`Invalid wallet address: ${address}`));\n process.exit(1);\n }\n\n const ok = await confirmCost(opts.provider, \"wallet\", address, opts.yes);\n if (!ok) {\n console.log(chalk.dim(\"Cancelled.\"));\n return;\n }\n\n const spinner = ora(\n `Querying ${opts.provider} for wallet ${address.slice(0, 8)}...`,\n ).start();\n\n try {\n const provider = getResearchProvider(opts.provider);\n const result = await provider.query({\n type: \"wallet\",\n target: address,\n });\n spinner.succeed(`Wallet data received from ${opts.provider}`);\n formatResearchResult(result);\n\n if (opts.post) {\n await postResearch(opts.post, result, `wallet ${address}`);\n }\n } catch (err) {\n spinner.fail(`Wallet query failed`);\n console.error(\n chalk.red(err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/trade.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 } from \"../lib/client.js\";\nimport { getExplorerUrl } 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 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\nasync function resolveToken(\n symbolOrAddress: string,\n): Promise<{ address: Address; symbol: string; decimals: number }> {\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 upper = symbolOrAddress.toUpperCase();\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 syndicate: 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(\"\", syndicate);\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\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 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(\"--syndicate <name>\", \"Post results to syndicate chat\")\n .option(\"--yes\", \"Skip cost confirmation\", false)\n .action(async (opts: { token?: string; syndicate?: 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.syndicate) {\n await postToChat(opts.syndicate, \"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 with USDC via Uniswap Trading API\")\n .requiredOption(\"--token <addr|symbol>\", \"Token to buy\")\n .requiredOption(\"--amount <usdc>\", \"USDC amount to spend\")\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(\"--syndicate <name>\", \"Post trade to syndicate chat\")\n .action(async (opts) => {\n const { address: tokenAddr, symbol, decimals } = await resolveToken(opts.token as string);\n const usdc = TOKENS().USDC;\n const usdcAmount = parseUnits(opts.amount as string, 6);\n const slippage = Number(opts.slippage);\n\n // Check USDC balance\n const client = getPublicClient();\n const account = getAccount();\n const balance = (await client.readContract({\n address: usdc,\n abi: ERC20_ABI,\n functionName: \"balanceOf\",\n args: [account.address],\n })) as bigint;\n\n if (balance < usdcAmount) {\n console.error(chalk.red(\n `Insufficient USDC. Have ${formatUnits(balance, 6)}, need ${opts.amount}`,\n ));\n process.exit(1);\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: usdc,\n tokenOut: tokenAddr,\n amountIn: usdcAmount,\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(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n\n // Execute swap (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: usdc,\n tokenOut: tokenAddr,\n amountIn: usdcAmount,\n amountOutMinimum: 0n, // slippage handled by API\n fee: 3000, // unused in API mode\n });\n txHash = result.hash;\n\n if (!result.success) {\n swapSpinner.fail(\"Swap reverted\");\n process.exit(1);\n }\n swapSpinner.succeed(\"Swap executed\");\n } catch (err) {\n swapSpinner.fail(\"Swap failed\");\n console.error(chalk.red(err instanceof Error ? err.message : String(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 });\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} USDC`);\n console.log(` Received: ${formatUnits(tokensReceived, decimals)} ${symbol}`);\n console.log(` Entry: $${entryPrice.toFixed(8)} per ${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)\n try {\n const { createTradeAttestation, getEasScanUrl } = await import(\"../lib/eas.js\");\n const { uid } = await createTradeAttestation(\n usdc, tokenAddr, usdcAmount,\n formatUnits(tokensReceived, decimals),\n txHash, \"BUY\",\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.syndicate) {\n await postToChat(opts.syndicate, \"TRADE_EXECUTED\" as MessageType,\n `Bought ${formatUnits(tokensReceived, decimals)} ${symbol} for ${opts.amount} USDC via Uniswap`,\n { token: symbol, address: tokenAddr, amountUsdc: opts.amount, txHash },\n );\n }\n });\n\n // ── trade sell ──\n\n trade\n .command(\"sell\")\n .description(\"Sell a token position back to USDC 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(\"--slippage <pct>\", \"Slippage tolerance % (default: 0.5)\", \"0.5\")\n .option(\"--syndicate <name>\", \"Post trade to syndicate chat\")\n .action(async (opts) => {\n const { address: tokenAddr, symbol, decimals } = await resolveToken(opts.token as string);\n const usdc = TOKENS().USDC;\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 expectedUsdc: bigint;\n\n try {\n const result = await uniswap.fullQuote({\n tokenIn: tokenAddr,\n tokenOut: usdc,\n amountIn: sellAmount,\n slippageTolerance: slippage,\n });\n expectedUsdc = result.amountOut;\n const routing = result.routing;\n quoteSpinner.succeed(\n `Quote: ${formatUnits(result.amountOut, 6)} USDC (${routing} route)`,\n );\n } catch (err) {\n quoteSpinner.fail(\"Quote failed\");\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n\n // Execute sell\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: usdc,\n amountIn: sellAmount,\n amountOutMinimum: 0n,\n fee: 3000,\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(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n\n // Calculate P&L\n const usdcReceived = Number(formatUnits(expectedUsdc, 6));\n const costBasis = pos ? Number(pos.amountIn) : 0;\n const pnlUsdc = costBasis > 0 ? usdcReceived - costBasis : 0;\n const pnlPct = costBasis > 0 ? (pnlUsdc / costBasis) * 100 : 0;\n const exitPrice = sellAmount > 0n\n ? usdcReceived / 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,\n pnlPct,\n });\n }\n\n const pnlColor = pnlUsdc >= 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: ~${usdcReceived.toFixed(2)} USDC`);\n if (costBasis > 0) {\n console.log(` Cost: ${costBasis.toFixed(2)} USDC`);\n console.log(` P&L: ${pnlColor(`${pnlUsdc >= 0 ? \"+\" : \"\"}${pnlUsdc.toFixed(2)} USDC (${pnlPct >= 0 ? \"+\" : \"\"}${pnlPct.toFixed(1)}%)`)}`);\n }\n console.log(` Tx: ${chalk.dim(getExplorerUrl(txHash as `0x${string}`))}`);\n\n // EAS attestation (best-effort)\n try {\n const { createTradeAttestation, getEasScanUrl } = await import(\"../lib/eas.js\");\n const { uid } = await createTradeAttestation(\n tokenAddr, usdc, sellAmount,\n usdcReceived.toFixed(6),\n txHash, \"SELL\",\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.syndicate) {\n await postToChat(opts.syndicate, \"TRADE_EXECUTED\" as MessageType,\n `Sold ${formatUnits(sellAmount, decimals)} ${symbol} for ~${usdcReceived.toFixed(2)} USDC (P&L: ${pnlUsdc >= 0 ? \"+\" : \"\"}${pnlUsdc.toFixed(2)})`,\n { token: symbol, address: tokenAddr, usdcReceived, pnlUsdc, 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(\"--syndicate <name>\", \"Post updates to syndicate 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.syndicate) {\n await postToChat(opts.syndicate, \"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 });\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.syndicate) {\n await postToChat(opts.syndicate, \"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}: ${err instanceof Error ? err.message : String(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 * 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; // USDC spent (human-readable, e.g. \"500\")\n amountOut: string; // tokens received (raw bigint as string)\n entryPrice: number; // USDC per 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}\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":["parseUnits","formatUnits","client","parseUnits","formatUnits"]}
|
|
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
|