@sherwoodagent/cli 0.22.8 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chat-JYAJMP4D.js → chat-52PWNH7Y.js} +7 -7
- package/dist/{chunk-4YIE7GHL.js → chunk-66VFSLPS.js} +2 -2
- package/dist/{chunk-VO6DCRWV.js → chunk-7PCI3WHQ.js} +4 -4
- package/dist/{chunk-LVPBJ7MI.js → chunk-GWIW6DDG.js} +2 -2
- package/dist/{chunk-4Y6Y4SVH.js → chunk-JEVBC7DV.js} +4 -4
- package/dist/{chunk-G7JQRLQE.js → chunk-QBNWBWD3.js} +5 -5
- package/dist/{chunk-B42ZCCZ7.js → chunk-RGOTBJIN.js} +28 -3
- package/dist/chunk-RGOTBJIN.js.map +1 -0
- package/dist/{chunk-ASJTFFZH.js → chunk-SBVHGUQJ.js} +3 -3
- package/dist/{chunk-Y7LS6DEF.js → chunk-VQIFAXUY.js} +5 -5
- package/dist/{chunk-JR5K5WVR.js → chunk-ZPLUJT4V.js} +169 -13
- package/dist/chunk-ZPLUJT4V.js.map +1 -0
- package/dist/{client-SCIY6SUP.js → client-CWQFYZ5Z.js} +4 -4
- package/dist/{config-BGS5MX4D.js → config-YXZKPSZB.js} +8 -2
- package/dist/{eas-X5UIEM6D.js → eas-YZIHYQAI.js} +6 -6
- package/dist/{governor-ZKRSAHG4.js → governor-YPDAOT3S.js} +6 -6
- package/dist/index.js +741 -74
- package/dist/index.js.map +1 -1
- package/dist/{network-UTSOP7EF.js → network-QEMP3DSP.js} +3 -3
- package/dist/price-SWNEGWO4.js +156 -0
- package/dist/price-SWNEGWO4.js.map +1 -0
- package/dist/{research-EWH43HFN.js → research-PH77VSE4.js} +9 -9
- package/dist/research-ZX7T2ZIJ.js +14 -0
- package/dist/{session-XZNKLK3I.js → session-NMA4RLKC.js} +12 -12
- package/dist/{trade-VKSXEHWW.js → trade-N2A74UPX.js} +16 -16
- package/dist/{xmtp-XKHXATPQ.js → xmtp-YNOGIZ4G.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-B42ZCCZ7.js.map +0 -1
- package/dist/chunk-JR5K5WVR.js.map +0 -1
- package/dist/research-W3M3VZBD.js +0 -14
- /package/dist/{chat-JYAJMP4D.js.map → chat-52PWNH7Y.js.map} +0 -0
- /package/dist/{chunk-4YIE7GHL.js.map → chunk-66VFSLPS.js.map} +0 -0
- /package/dist/{chunk-VO6DCRWV.js.map → chunk-7PCI3WHQ.js.map} +0 -0
- /package/dist/{chunk-LVPBJ7MI.js.map → chunk-GWIW6DDG.js.map} +0 -0
- /package/dist/{chunk-4Y6Y4SVH.js.map → chunk-JEVBC7DV.js.map} +0 -0
- /package/dist/{chunk-G7JQRLQE.js.map → chunk-QBNWBWD3.js.map} +0 -0
- /package/dist/{chunk-ASJTFFZH.js.map → chunk-SBVHGUQJ.js.map} +0 -0
- /package/dist/{chunk-Y7LS6DEF.js.map → chunk-VQIFAXUY.js.map} +0 -0
- /package/dist/{client-SCIY6SUP.js.map → client-CWQFYZ5Z.js.map} +0 -0
- /package/dist/{config-BGS5MX4D.js.map → config-YXZKPSZB.js.map} +0 -0
- /package/dist/{eas-X5UIEM6D.js.map → eas-YZIHYQAI.js.map} +0 -0
- /package/dist/{governor-ZKRSAHG4.js.map → governor-YPDAOT3S.js.map} +0 -0
- /package/dist/{network-UTSOP7EF.js.map → network-QEMP3DSP.js.map} +0 -0
- /package/dist/{research-EWH43HFN.js.map → research-PH77VSE4.js.map} +0 -0
- /package/dist/{research-W3M3VZBD.js.map → research-ZX7T2ZIJ.js.map} +0 -0
- /package/dist/{session-XZNKLK3I.js.map → session-NMA4RLKC.js.map} +0 -0
- /package/dist/{trade-VKSXEHWW.js.map → trade-N2A74UPX.js.map} +0 -0
- /package/dist/{xmtp-XKHXATPQ.js.map → xmtp-YNOGIZ4G.js.map} +0 -0
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
isTestnet,
|
|
10
10
|
robinhoodTestnet,
|
|
11
11
|
setNetwork
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-GWIW6DDG.js";
|
|
13
|
+
import "./chunk-RGOTBJIN.js";
|
|
14
14
|
export {
|
|
15
15
|
CHAIN_REGISTRY,
|
|
16
16
|
VALID_NETWORKS,
|
|
@@ -23,4 +23,4 @@ export {
|
|
|
23
23
|
robinhoodTestnet,
|
|
24
24
|
setNetwork
|
|
25
25
|
};
|
|
26
|
-
//# sourceMappingURL=network-
|
|
26
|
+
//# sourceMappingURL=network-QEMP3DSP.js.map
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SYNTHRA,
|
|
3
|
+
UNISWAP,
|
|
4
|
+
UNISWAP_QUOTER_V2_ABI
|
|
5
|
+
} from "./chunk-ZPLUJT4V.js";
|
|
6
|
+
import {
|
|
7
|
+
getPublicClient
|
|
8
|
+
} from "./chunk-SBVHGUQJ.js";
|
|
9
|
+
import {
|
|
10
|
+
getNetwork
|
|
11
|
+
} from "./chunk-GWIW6DDG.js";
|
|
12
|
+
import "./chunk-RGOTBJIN.js";
|
|
13
|
+
|
|
14
|
+
// src/lib/price.ts
|
|
15
|
+
import { encodeFunctionData, decodeFunctionResult, parseUnits, formatUnits } from "viem";
|
|
16
|
+
var ZERO = "0x0000000000000000000000000000000000000000";
|
|
17
|
+
async function getTokenPriceInAsset(params) {
|
|
18
|
+
const { token, tokenDecimals, asset, assetDecimals, feeTier } = params;
|
|
19
|
+
if (token.toLowerCase() === asset.toLowerCase()) {
|
|
20
|
+
return { price: 1, amountOut: parseUnits("1", assetDecimals), source: "uniswap" };
|
|
21
|
+
}
|
|
22
|
+
const network = getNetwork();
|
|
23
|
+
const client = getPublicClient();
|
|
24
|
+
if (network === "robinhood-testnet") {
|
|
25
|
+
return quoteSynthra(client, token, tokenDecimals, asset, assetDecimals, feeTier);
|
|
26
|
+
}
|
|
27
|
+
return quoteUniswap(client, token, tokenDecimals, asset, assetDecimals, feeTier);
|
|
28
|
+
}
|
|
29
|
+
async function getTokenPricesInAsset(params) {
|
|
30
|
+
const { tokens, asset, assetDecimals } = params;
|
|
31
|
+
const results = await Promise.allSettled(
|
|
32
|
+
tokens.map(
|
|
33
|
+
(t) => getTokenPriceInAsset({
|
|
34
|
+
token: t.token,
|
|
35
|
+
tokenDecimals: t.tokenDecimals,
|
|
36
|
+
asset,
|
|
37
|
+
assetDecimals,
|
|
38
|
+
feeTier: t.feeTier
|
|
39
|
+
})
|
|
40
|
+
)
|
|
41
|
+
);
|
|
42
|
+
return results.map((r) => r.status === "fulfilled" ? r.value : null);
|
|
43
|
+
}
|
|
44
|
+
var POOL_SLOT0_ABI = [
|
|
45
|
+
{
|
|
46
|
+
type: "function",
|
|
47
|
+
name: "slot0",
|
|
48
|
+
inputs: [],
|
|
49
|
+
outputs: [
|
|
50
|
+
{ name: "sqrtPriceX96", type: "uint160" },
|
|
51
|
+
{ name: "tick", type: "int24" },
|
|
52
|
+
{ name: "observationIndex", type: "uint16" },
|
|
53
|
+
{ name: "observationCardinality", type: "uint16" },
|
|
54
|
+
{ name: "observationCardinalityNext", type: "uint16" },
|
|
55
|
+
{ name: "feeProtocol", type: "uint8" },
|
|
56
|
+
{ name: "unlocked", type: "bool" }
|
|
57
|
+
],
|
|
58
|
+
stateMutability: "view"
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
var POOL_TOKEN0_ABI = [
|
|
62
|
+
{
|
|
63
|
+
type: "function",
|
|
64
|
+
name: "token0",
|
|
65
|
+
inputs: [],
|
|
66
|
+
outputs: [{ name: "", type: "address" }],
|
|
67
|
+
stateMutability: "view"
|
|
68
|
+
}
|
|
69
|
+
];
|
|
70
|
+
var FACTORY_GET_POOL_ABI = [
|
|
71
|
+
{
|
|
72
|
+
type: "function",
|
|
73
|
+
name: "getPool",
|
|
74
|
+
inputs: [
|
|
75
|
+
{ name: "tokenA", type: "address" },
|
|
76
|
+
{ name: "tokenB", type: "address" },
|
|
77
|
+
{ name: "fee", type: "uint24" }
|
|
78
|
+
],
|
|
79
|
+
outputs: [{ name: "", type: "address" }],
|
|
80
|
+
stateMutability: "view"
|
|
81
|
+
}
|
|
82
|
+
];
|
|
83
|
+
function priceFromSqrtPriceX96(sqrtPriceX96, token0Decimals, token1Decimals, tokenInIsToken0) {
|
|
84
|
+
const Q96 = 2 ** 96;
|
|
85
|
+
const ratio = Number(sqrtPriceX96) / Q96;
|
|
86
|
+
const rawPrice = ratio * ratio;
|
|
87
|
+
const decimalAdjust = 10 ** (token0Decimals - token1Decimals);
|
|
88
|
+
const token1PerToken0 = rawPrice * decimalAdjust;
|
|
89
|
+
return tokenInIsToken0 ? token1PerToken0 : 1 / token1PerToken0;
|
|
90
|
+
}
|
|
91
|
+
async function quoteSynthra(client, tokenIn, tokenInDecimals, tokenOut, tokenOutDecimals, fee) {
|
|
92
|
+
const factoryAddr = SYNTHRA().FACTORY;
|
|
93
|
+
if (factoryAddr === ZERO) {
|
|
94
|
+
throw new Error("Synthra Factory not deployed on this network");
|
|
95
|
+
}
|
|
96
|
+
const pool = await client.readContract({
|
|
97
|
+
address: factoryAddr,
|
|
98
|
+
abi: FACTORY_GET_POOL_ABI,
|
|
99
|
+
functionName: "getPool",
|
|
100
|
+
args: [tokenIn, tokenOut, fee]
|
|
101
|
+
});
|
|
102
|
+
if (!pool || pool === ZERO) {
|
|
103
|
+
throw new Error(`No Synthra pool for ${tokenIn}\u2194${tokenOut} fee=${fee}`);
|
|
104
|
+
}
|
|
105
|
+
const [slot0, token0] = await Promise.all([
|
|
106
|
+
client.readContract({ address: pool, abi: POOL_SLOT0_ABI, functionName: "slot0" }),
|
|
107
|
+
client.readContract({ address: pool, abi: POOL_TOKEN0_ABI, functionName: "token0" })
|
|
108
|
+
]);
|
|
109
|
+
const sqrtPriceX96 = slot0[0];
|
|
110
|
+
if (sqrtPriceX96 === 0n) {
|
|
111
|
+
throw new Error(`Pool ${pool} not initialized (sqrtPriceX96 = 0)`);
|
|
112
|
+
}
|
|
113
|
+
const tokenInIsToken0 = tokenIn.toLowerCase() === token0.toLowerCase();
|
|
114
|
+
const t0Decimals = tokenInIsToken0 ? tokenInDecimals : tokenOutDecimals;
|
|
115
|
+
const t1Decimals = tokenInIsToken0 ? tokenOutDecimals : tokenInDecimals;
|
|
116
|
+
const price = priceFromSqrtPriceX96(sqrtPriceX96, t0Decimals, t1Decimals, tokenInIsToken0);
|
|
117
|
+
const oneToken = parseUnits("1", tokenInDecimals);
|
|
118
|
+
const amountOut = BigInt(Math.round(price * Number(parseUnits("1", tokenOutDecimals))));
|
|
119
|
+
return { price, amountOut, source: "synthra" };
|
|
120
|
+
}
|
|
121
|
+
async function quoteUniswap(client, tokenIn, tokenInDecimals, tokenOut, tokenOutDecimals, fee) {
|
|
122
|
+
const quoterAddr = UNISWAP().QUOTER_V2;
|
|
123
|
+
if (quoterAddr === ZERO) {
|
|
124
|
+
throw new Error("Uniswap QuoterV2 not deployed on this network");
|
|
125
|
+
}
|
|
126
|
+
const oneToken = parseUnits("1", tokenInDecimals);
|
|
127
|
+
const calldata = encodeFunctionData({
|
|
128
|
+
abi: UNISWAP_QUOTER_V2_ABI,
|
|
129
|
+
functionName: "quoteExactInputSingle",
|
|
130
|
+
args: [
|
|
131
|
+
{
|
|
132
|
+
tokenIn,
|
|
133
|
+
tokenOut,
|
|
134
|
+
amountIn: oneToken,
|
|
135
|
+
fee,
|
|
136
|
+
sqrtPriceLimitX96: 0n
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
});
|
|
140
|
+
const { data } = await client.call({ to: quoterAddr, data: calldata });
|
|
141
|
+
if (!data) {
|
|
142
|
+
throw new Error(`Uniswap quoter returned no data for ${tokenIn}\u2192${tokenOut} fee=${fee}`);
|
|
143
|
+
}
|
|
144
|
+
const [amountOut] = decodeFunctionResult({
|
|
145
|
+
abi: UNISWAP_QUOTER_V2_ABI,
|
|
146
|
+
functionName: "quoteExactInputSingle",
|
|
147
|
+
data
|
|
148
|
+
});
|
|
149
|
+
const price = Number(formatUnits(amountOut, tokenOutDecimals));
|
|
150
|
+
return { price, amountOut, source: "uniswap" };
|
|
151
|
+
}
|
|
152
|
+
export {
|
|
153
|
+
getTokenPriceInAsset,
|
|
154
|
+
getTokenPricesInAsset
|
|
155
|
+
};
|
|
156
|
+
//# sourceMappingURL=price-SWNEGWO4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/price.ts"],"sourcesContent":["/**\n * Network-aware price quoting for portfolio valuation.\n *\n * Dispatches to the right DEX quoter based on network:\n * - Base / Base Sepolia → Uniswap QuoterV2 (struct params, 4-tuple return)\n * - Robinhood testnet → Direct pool slot0 (Synthra QuoterV2 can't resolve\n * proxy-deployed pools via CREATE2, so we read sqrtPriceX96 from the pool)\n *\n * Uniswap quoter uses eth_call (not view — it reverts internally).\n */\n\nimport type { Address } from \"viem\";\nimport { encodeFunctionData, decodeFunctionResult, parseUnits, formatUnits } from \"viem\";\nimport { getPublicClient } from \"./client.js\";\nimport { getNetwork } from \"./network.js\";\nimport { UNISWAP, SYNTHRA } from \"./addresses.js\";\nimport { UNISWAP_QUOTER_V2_ABI } from \"./abis.js\";\n\nexport interface TokenPrice {\n price: number; // 1 token = X asset units (human-readable)\n amountOut: bigint; // raw quoter output\n source: \"uniswap\" | \"synthra\";\n}\n\nconst ZERO: Address = \"0x0000000000000000000000000000000000000000\";\n\n/**\n * Get the price of one token denominated in the strategy's asset.\n * Uses the appropriate DEX quoter for the current network.\n */\nexport async function getTokenPriceInAsset(params: {\n token: Address;\n tokenDecimals: number;\n asset: Address;\n assetDecimals: number;\n feeTier: number;\n}): Promise<TokenPrice> {\n const { token, tokenDecimals, asset, assetDecimals, feeTier } = params;\n\n // Short-circuit: token IS the asset\n if (token.toLowerCase() === asset.toLowerCase()) {\n return { price: 1.0, amountOut: parseUnits(\"1\", assetDecimals), source: \"uniswap\" };\n }\n\n const network = getNetwork();\n const client = getPublicClient();\n\n if (network === \"robinhood-testnet\") {\n return quoteSynthra(client, token, tokenDecimals, asset, assetDecimals, feeTier);\n }\n\n return quoteUniswap(client, token, tokenDecimals, asset, assetDecimals, feeTier);\n}\n\n/**\n * Batch price lookup — parallel, graceful failure (null per failed quote).\n */\nexport async function getTokenPricesInAsset(params: {\n tokens: { token: Address; tokenDecimals: number; feeTier: number }[];\n asset: Address;\n assetDecimals: number;\n}): Promise<(TokenPrice | null)[]> {\n const { tokens, asset, assetDecimals } = params;\n\n const results = await Promise.allSettled(\n tokens.map((t) =>\n getTokenPriceInAsset({\n token: t.token,\n tokenDecimals: t.tokenDecimals,\n asset,\n assetDecimals,\n feeTier: t.feeTier,\n }),\n ),\n );\n\n return results.map((r) => (r.status === \"fulfilled\" ? r.value : null));\n}\n\n// ── Synthra direct pool pricing (Robinhood testnet) ──\n//\n// The Synthra QuoterV2 can't resolve proxy-deployed pools via CREATE2 (same\n// issue that led to SynthraDirectAdapter). Instead we look up the pool via\n// factory.getPool(), read slot0.sqrtPriceX96, and derive the spot price.\n\nconst POOL_SLOT0_ABI = [\n {\n type: \"function\" as const,\n name: \"slot0\",\n inputs: [],\n outputs: [\n { name: \"sqrtPriceX96\", type: \"uint160\" as const },\n { name: \"tick\", type: \"int24\" as const },\n { name: \"observationIndex\", type: \"uint16\" as const },\n { name: \"observationCardinality\", type: \"uint16\" as const },\n { name: \"observationCardinalityNext\", type: \"uint16\" as const },\n { name: \"feeProtocol\", type: \"uint8\" as const },\n { name: \"unlocked\", type: \"bool\" as const },\n ],\n stateMutability: \"view\" as const,\n },\n] as const;\n\nconst POOL_TOKEN0_ABI = [\n {\n type: \"function\" as const,\n name: \"token0\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\" as const }],\n stateMutability: \"view\" as const,\n },\n] as const;\n\nconst FACTORY_GET_POOL_ABI = [\n {\n type: \"function\" as const,\n name: \"getPool\",\n inputs: [\n { name: \"tokenA\", type: \"address\" as const },\n { name: \"tokenB\", type: \"address\" as const },\n { name: \"fee\", type: \"uint24\" as const },\n ],\n outputs: [{ name: \"\", type: \"address\" as const }],\n stateMutability: \"view\" as const,\n },\n] as const;\n\n/**\n * Derive a spot price from a Uniswap V3 / Synthra V3 pool's sqrtPriceX96.\n *\n * sqrtPriceX96 = sqrt(token1/token0) × 2^96\n * price (token1 per token0) = (sqrtPriceX96 / 2^96)^2\n *\n * Returns the price of `tokenIn` denominated in `tokenOut`.\n */\nfunction priceFromSqrtPriceX96(\n sqrtPriceX96: bigint,\n token0Decimals: number,\n token1Decimals: number,\n tokenInIsToken0: boolean,\n): number {\n const Q96 = 2 ** 96;\n const ratio = Number(sqrtPriceX96) / Q96;\n // raw price = token1 per token0 (adjusted for same-decimal tokens only)\n const rawPrice = ratio * ratio;\n // decimal adjustment: token0Decimals - token1Decimals\n const decimalAdjust = 10 ** (token0Decimals - token1Decimals);\n const token1PerToken0 = rawPrice * decimalAdjust;\n\n // If tokenIn is token0, price = how many token1 per token0 → token1PerToken0\n // If tokenIn is token1, price = how many token0 per token1 → 1/token1PerToken0\n return tokenInIsToken0 ? token1PerToken0 : 1 / token1PerToken0;\n}\n\nasync function quoteSynthra(\n client: ReturnType<typeof getPublicClient>,\n tokenIn: Address,\n tokenInDecimals: number,\n tokenOut: Address,\n tokenOutDecimals: number,\n fee: number,\n): Promise<TokenPrice> {\n const factoryAddr = SYNTHRA().FACTORY;\n if (factoryAddr === ZERO) {\n throw new Error(\"Synthra Factory not deployed on this network\");\n }\n\n // 1. Resolve pool via factory.getPool()\n const pool = await client.readContract({\n address: factoryAddr,\n abi: FACTORY_GET_POOL_ABI,\n functionName: \"getPool\",\n args: [tokenIn, tokenOut, fee],\n });\n\n if (!pool || pool === ZERO) {\n throw new Error(`No Synthra pool for ${tokenIn}↔${tokenOut} fee=${fee}`);\n }\n\n // 2. Read slot0 and token0 from the pool\n const [slot0, token0] = await Promise.all([\n client.readContract({ address: pool, abi: POOL_SLOT0_ABI, functionName: \"slot0\" }),\n client.readContract({ address: pool, abi: POOL_TOKEN0_ABI, functionName: \"token0\" }),\n ]);\n\n const sqrtPriceX96 = slot0[0];\n if (sqrtPriceX96 === 0n) {\n throw new Error(`Pool ${pool} not initialized (sqrtPriceX96 = 0)`);\n }\n\n // 3. Determine token ordering\n const tokenInIsToken0 = tokenIn.toLowerCase() === token0.toLowerCase();\n const t0Decimals = tokenInIsToken0 ? tokenInDecimals : tokenOutDecimals;\n const t1Decimals = tokenInIsToken0 ? tokenOutDecimals : tokenInDecimals;\n\n const price = priceFromSqrtPriceX96(sqrtPriceX96, t0Decimals, t1Decimals, tokenInIsToken0);\n\n // Compute amountOut for 1 tokenIn\n const oneToken = parseUnits(\"1\", tokenInDecimals);\n const amountOut = BigInt(Math.round(price * Number(parseUnits(\"1\", tokenOutDecimals))));\n\n return { price, amountOut, source: \"synthra\" };\n}\n\n// ── Uniswap QuoterV2 (Base / Base Sepolia) ──\n\nasync function quoteUniswap(\n client: ReturnType<typeof getPublicClient>,\n tokenIn: Address,\n tokenInDecimals: number,\n tokenOut: Address,\n tokenOutDecimals: number,\n fee: number,\n): Promise<TokenPrice> {\n const quoterAddr = UNISWAP().QUOTER_V2;\n if (quoterAddr === ZERO) {\n throw new Error(\"Uniswap QuoterV2 not deployed on this network\");\n }\n\n const oneToken = parseUnits(\"1\", tokenInDecimals);\n\n const calldata = encodeFunctionData({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInputSingle\",\n args: [\n {\n tokenIn,\n tokenOut,\n amountIn: oneToken,\n fee,\n sqrtPriceLimitX96: 0n,\n },\n ],\n });\n\n const { data } = await client.call({ to: quoterAddr, data: calldata });\n\n if (!data) {\n throw new Error(`Uniswap quoter returned no data for ${tokenIn}→${tokenOut} fee=${fee}`);\n }\n\n const [amountOut] = decodeFunctionResult({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInputSingle\",\n data,\n }) as [bigint, bigint, number, bigint];\n\n const price = Number(formatUnits(amountOut, tokenOutDecimals));\n return { price, amountOut, source: \"uniswap\" };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,13 +2,13 @@ import {
|
|
|
2
2
|
MESSARI_COST_ESTIMATE,
|
|
3
3
|
NANSEN_COST_ESTIMATE,
|
|
4
4
|
getResearchProvider
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-66VFSLPS.js";
|
|
6
6
|
import {
|
|
7
7
|
formatContractError,
|
|
8
8
|
getAccount
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-SBVHGUQJ.js";
|
|
10
|
+
import "./chunk-GWIW6DDG.js";
|
|
11
|
+
import "./chunk-RGOTBJIN.js";
|
|
12
12
|
|
|
13
13
|
// src/commands/research.ts
|
|
14
14
|
import chalk from "chalk";
|
|
@@ -16,7 +16,7 @@ import ora from "ora";
|
|
|
16
16
|
import { confirm } from "@inquirer/prompts";
|
|
17
17
|
import { isAddress } from "viem";
|
|
18
18
|
async function loadXmtp() {
|
|
19
|
-
return import("./xmtp-
|
|
19
|
+
return import("./xmtp-YNOGIZ4G.js");
|
|
20
20
|
}
|
|
21
21
|
var COST_ESTIMATES = {
|
|
22
22
|
messari: MESSARI_COST_ESTIMATE,
|
|
@@ -83,7 +83,7 @@ function formatValue(value) {
|
|
|
83
83
|
}
|
|
84
84
|
async function postResearch(syndicateName, result, prompt) {
|
|
85
85
|
const { pinJSON } = await import("./ipfs-22YLNQ2C.js");
|
|
86
|
-
const { createResearchAttestation, getEasScanUrl } = await import("./eas-
|
|
86
|
+
const { createResearchAttestation, getEasScanUrl } = await import("./eas-YZIHYQAI.js");
|
|
87
87
|
const xmtp = await loadXmtp();
|
|
88
88
|
const pinSpinner = ora("Pinning research result to IPFS...").start();
|
|
89
89
|
let resultUri;
|
|
@@ -112,8 +112,8 @@ async function postResearch(syndicateName, result, prompt) {
|
|
|
112
112
|
const easSpinner = ora("Creating EAS attestation...").start();
|
|
113
113
|
let attestationUid;
|
|
114
114
|
try {
|
|
115
|
-
const { getChainContracts } = await import("./config-
|
|
116
|
-
const { getChain } = await import("./network-
|
|
115
|
+
const { getChainContracts } = await import("./config-YXZKPSZB.js");
|
|
116
|
+
const { getChain } = await import("./network-QEMP3DSP.js");
|
|
117
117
|
const vaultRecipient = getChainContracts(getChain().id).vault;
|
|
118
118
|
const { uid } = await createResearchAttestation(
|
|
119
119
|
result.provider,
|
|
@@ -312,4 +312,4 @@ function registerResearchCommands(program) {
|
|
|
312
312
|
export {
|
|
313
313
|
registerResearchCommands
|
|
314
314
|
};
|
|
315
|
-
//# sourceMappingURL=research-
|
|
315
|
+
//# sourceMappingURL=research-PH77VSE4.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MessariProvider,
|
|
3
|
+
NansenProvider,
|
|
4
|
+
getResearchProvider
|
|
5
|
+
} from "./chunk-66VFSLPS.js";
|
|
6
|
+
import "./chunk-SBVHGUQJ.js";
|
|
7
|
+
import "./chunk-GWIW6DDG.js";
|
|
8
|
+
import "./chunk-RGOTBJIN.js";
|
|
9
|
+
export {
|
|
10
|
+
MessariProvider,
|
|
11
|
+
NansenProvider,
|
|
12
|
+
getResearchProvider
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=research-ZX7T2ZIJ.js.map
|
|
@@ -4,27 +4,27 @@ import {
|
|
|
4
4
|
resetSession,
|
|
5
5
|
updateSession
|
|
6
6
|
} from "./chunk-W2ZUPR3W.js";
|
|
7
|
+
import {
|
|
8
|
+
resolveSyndicate
|
|
9
|
+
} from "./chunk-QBNWBWD3.js";
|
|
7
10
|
import {
|
|
8
11
|
PROPOSAL_STATES,
|
|
9
12
|
getProposal
|
|
10
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-7PCI3WHQ.js";
|
|
11
14
|
import {
|
|
12
15
|
resolveMetadataSummary
|
|
13
16
|
} from "./chunk-KEUEO4UE.js";
|
|
14
|
-
import {
|
|
15
|
-
resolveSyndicate
|
|
16
|
-
} from "./chunk-G7JQRLQE.js";
|
|
17
17
|
import {
|
|
18
18
|
SHERWOOD,
|
|
19
19
|
SYNDICATE_VAULT_ABI
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-ZPLUJT4V.js";
|
|
21
21
|
import {
|
|
22
22
|
getPublicClient
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-SBVHGUQJ.js";
|
|
24
|
+
import "./chunk-GWIW6DDG.js";
|
|
25
25
|
import {
|
|
26
26
|
loadConfig
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-RGOTBJIN.js";
|
|
28
28
|
|
|
29
29
|
// src/commands/session.ts
|
|
30
30
|
import chalk from "chalk";
|
|
@@ -185,7 +185,7 @@ async function enrichProposalEvents(events, metadataCache) {
|
|
|
185
185
|
|
|
186
186
|
// src/commands/session.ts
|
|
187
187
|
async function loadXmtp() {
|
|
188
|
-
return import("./xmtp-
|
|
188
|
+
return import("./xmtp-YNOGIZ4G.js");
|
|
189
189
|
}
|
|
190
190
|
async function resolveGovernor(vaultAddress) {
|
|
191
191
|
const client = getPublicClient();
|
|
@@ -422,8 +422,8 @@ function registerSessionCommands(program) {
|
|
|
422
422
|
);
|
|
423
423
|
session.command("cron <name>").description("Manage participation crons (OpenClaw agents)").option("--remove", "Remove participation crons", false).option("--status", "Show cron status", false).action(async (name, opts) => {
|
|
424
424
|
const { isOpenClaw, registerSyndicateCrons, unregisterSyndicateCrons, getSyndicateCronStatus } = await import("./cron-EOULYO3R.js");
|
|
425
|
-
const { isTestnet } = await import("./network-
|
|
426
|
-
const { getNotifyTo } = await import("./config-
|
|
425
|
+
const { isTestnet } = await import("./network-QEMP3DSP.js");
|
|
426
|
+
const { getNotifyTo } = await import("./config-YXZKPSZB.js");
|
|
427
427
|
if (!isOpenClaw()) {
|
|
428
428
|
console.log(chalk.yellow("Not running on OpenClaw \u2014 cron commands unavailable"));
|
|
429
429
|
console.log(chalk.dim(` Set up your own scheduler: sherwood session check ${name} --stream`));
|
|
@@ -464,4 +464,4 @@ function registerSessionCommands(program) {
|
|
|
464
464
|
export {
|
|
465
465
|
registerSessionCommands
|
|
466
466
|
};
|
|
467
|
-
//# sourceMappingURL=session-
|
|
467
|
+
//# sourceMappingURL=session-NMA4RLKC.js.map
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getResearchProvider
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-66VFSLPS.js";
|
|
4
4
|
import {
|
|
5
5
|
UniswapProvider,
|
|
6
6
|
chatCompletion,
|
|
7
7
|
getQuote
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-VQIFAXUY.js";
|
|
9
9
|
import {
|
|
10
10
|
ERC20_ABI,
|
|
11
11
|
TOKENS
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ZPLUJT4V.js";
|
|
13
13
|
import {
|
|
14
14
|
formatContractError,
|
|
15
15
|
getAccount,
|
|
16
16
|
getPublicClient
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-SBVHGUQJ.js";
|
|
18
18
|
import {
|
|
19
19
|
getExplorerUrl
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-GWIW6DDG.js";
|
|
21
21
|
import {
|
|
22
22
|
loadConfig,
|
|
23
23
|
saveConfig
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-RGOTBJIN.js";
|
|
25
25
|
|
|
26
26
|
// src/commands/trade.ts
|
|
27
27
|
import chalk from "chalk";
|
|
@@ -330,7 +330,7 @@ async function getCurrentPrice(tokenAddress, tokenDecimals, feeTier) {
|
|
|
330
330
|
// src/commands/trade.ts
|
|
331
331
|
var uniswap = new UniswapProvider();
|
|
332
332
|
async function loadXmtp() {
|
|
333
|
-
return import("./xmtp-
|
|
333
|
+
return import("./xmtp-YNOGIZ4G.js");
|
|
334
334
|
}
|
|
335
335
|
var ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
336
336
|
var KNOWN_MEMECOINS = {
|
|
@@ -514,7 +514,7 @@ function registerTradeCommands(program) {
|
|
|
514
514
|
}
|
|
515
515
|
const wrapSpinner = ora("Wrapping ETH \u2192 WETH...").start();
|
|
516
516
|
try {
|
|
517
|
-
const { writeContractWithRetry, waitForReceipt: waitForReceiptFn } = await import("./client-
|
|
517
|
+
const { writeContractWithRetry, waitForReceipt: waitForReceiptFn } = await import("./client-CWQFYZ5Z.js");
|
|
518
518
|
const wethAddr = TOKENS().WETH;
|
|
519
519
|
const wrapHash = await writeContractWithRetry({
|
|
520
520
|
address: wethAddr,
|
|
@@ -523,7 +523,7 @@ function registerTradeCommands(program) {
|
|
|
523
523
|
args: [],
|
|
524
524
|
value: inputAmount,
|
|
525
525
|
account,
|
|
526
|
-
chain: (await import("./network-
|
|
526
|
+
chain: (await import("./network-QEMP3DSP.js")).getChain()
|
|
527
527
|
});
|
|
528
528
|
await waitForReceiptFn(wrapHash);
|
|
529
529
|
wrapSpinner.succeed(`Wrapped ${opts.amount} ETH \u2192 WETH`);
|
|
@@ -637,9 +637,9 @@ function registerTradeCommands(program) {
|
|
|
637
637
|
}
|
|
638
638
|
console.log(` Tx: ${chalk.dim(getExplorerUrl(txHash))}`);
|
|
639
639
|
try {
|
|
640
|
-
const { createTradeAttestation, getEasScanUrl } = await import("./eas-
|
|
641
|
-
const { getChainContracts } = await import("./config-
|
|
642
|
-
const { getChain: getActiveChain } = await import("./network-
|
|
640
|
+
const { createTradeAttestation, getEasScanUrl } = await import("./eas-YZIHYQAI.js");
|
|
641
|
+
const { getChainContracts } = await import("./config-YXZKPSZB.js");
|
|
642
|
+
const { getChain: getActiveChain } = await import("./network-QEMP3DSP.js");
|
|
643
643
|
const vaultRecipient = getChainContracts(getActiveChain().id).vault;
|
|
644
644
|
const { uid } = await createTradeAttestation(
|
|
645
645
|
inputAddr,
|
|
@@ -765,9 +765,9 @@ function registerTradeCommands(program) {
|
|
|
765
765
|
}
|
|
766
766
|
console.log(` Tx: ${chalk.dim(getExplorerUrl(txHash))}`);
|
|
767
767
|
try {
|
|
768
|
-
const { createTradeAttestation, getEasScanUrl } = await import("./eas-
|
|
769
|
-
const { getChainContracts } = await import("./config-
|
|
770
|
-
const { getChain: getActiveChain } = await import("./network-
|
|
768
|
+
const { createTradeAttestation, getEasScanUrl } = await import("./eas-YZIHYQAI.js");
|
|
769
|
+
const { getChainContracts } = await import("./config-YXZKPSZB.js");
|
|
770
|
+
const { getChain: getActiveChain } = await import("./network-QEMP3DSP.js");
|
|
771
771
|
const vaultRecipient = getChainContracts(getActiveChain().id).vault;
|
|
772
772
|
const { uid } = await createTradeAttestation(
|
|
773
773
|
tokenAddr,
|
|
@@ -942,4 +942,4 @@ function sleep(ms) {
|
|
|
942
942
|
export {
|
|
943
943
|
registerTradeCommands
|
|
944
944
|
};
|
|
945
|
-
//# sourceMappingURL=trade-
|
|
945
|
+
//# sourceMappingURL=trade-N2A74UPX.js.map
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getTextRecord
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-QBNWBWD3.js";
|
|
4
|
+
import "./chunk-ZPLUJT4V.js";
|
|
5
5
|
import {
|
|
6
6
|
getAccount
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-SBVHGUQJ.js";
|
|
8
8
|
import {
|
|
9
9
|
getChainConfig
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-GWIW6DDG.js";
|
|
11
11
|
import {
|
|
12
12
|
cacheGroupId,
|
|
13
13
|
getCachedGroupId,
|
|
14
14
|
loadConfig,
|
|
15
15
|
saveConfig
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-RGOTBJIN.js";
|
|
17
17
|
|
|
18
18
|
// src/lib/xmtp.ts
|
|
19
19
|
import fs from "fs";
|
|
@@ -275,4 +275,4 @@ export {
|
|
|
275
275
|
sendReaction,
|
|
276
276
|
streamMessages
|
|
277
277
|
};
|
|
278
|
-
//# sourceMappingURL=xmtp-
|
|
278
|
+
//# sourceMappingURL=xmtp-YNOGIZ4G.js.map
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/config.ts"],"sourcesContent":["/**\n * Local config management — ~/.sherwood/config.json\n *\n * Stores group ID cache, per-chain contract addresses, and wallet config.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst CONFIG_DIR = path.join(os.homedir(), \".sherwood\");\nconst CONFIG_PATH = path.join(CONFIG_DIR, \"config.json\");\n\n/** Per-chain user-specific addresses (stored by chainId). */\nexport interface ChainContracts {\n vault?: string; // user's default vault address\n}\n\n/** A syndicate the agent belongs to (creator or member). */\nexport interface SyndicateMembership {\n subdomain: string;\n vault: string;\n role: \"creator\" | \"agent\";\n}\n\nexport interface SherwoodConfig {\n dbEncryptionKey?: string; // legacy — no longer used, XMTP CLI manages its own DB\n privateKey?: string; // wallet private key (0x-prefixed)\n xmtpInboxId?: string;\n groupCache: Record<string, string>; // subdomain → XMTP group ID\n veniceApiKey?: string; // Venice AI inference API key\n agentId?: number; // ERC-8004 identity token ID\n contracts?: Record<string, ChainContracts>; // chainId → user addresses\n syndicates?: Record<string, SyndicateMembership[]>; // chainId → syndicate memberships\n primarySyndicate?: Record<string, string>; // chainId → subdomain of the active syndicate\n rpc?: Record<string, string>; // network name → custom RPC URL\n notifyTo?: string; // destination for cron summaries (Telegram chat ID, phone, etc.)\n uniswapApiKey?: string; // Uniswap Trading API key (from developers.uniswap.org)\n positions?: unknown[]; // open trade positions (typed in positions.ts)\n closedPositions?: unknown[]; // historical closed positions\n _xmtpMigrated?: boolean; // one-time flag: revoked stale installations from ~/.xmtp/ era\n}\n\nexport function loadConfig(): SherwoodConfig {\n if (fs.existsSync(CONFIG_PATH)) {\n return JSON.parse(fs.readFileSync(CONFIG_PATH, \"utf-8\"));\n }\n\n return { groupCache: {} };\n}\n\nexport function saveConfig(config: SherwoodConfig): void {\n fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });\n}\n\nexport function cacheGroupId(subdomain: string, groupId: string): void {\n const config = loadConfig();\n config.groupCache[subdomain] = groupId;\n saveConfig(config);\n}\n\nexport function getCachedGroupId(subdomain: string): string | undefined {\n const config = loadConfig();\n return config.groupCache[subdomain];\n}\n\nexport function setVeniceApiKey(apiKey: string): void {\n const config = loadConfig();\n config.veniceApiKey = apiKey;\n saveConfig(config);\n}\n\nexport function getVeniceApiKey(): string | undefined {\n return loadConfig().veniceApiKey ?? process.env.VENICE_API_KEY;\n}\n\nexport function setAgentId(agentId: number): void {\n const config = loadConfig();\n config.agentId = agentId;\n saveConfig(config);\n}\n\nexport function getAgentId(): number | undefined {\n return loadConfig().agentId;\n}\n\nexport function setPrivateKey(key: string): void {\n const config = loadConfig();\n config.privateKey = key.startsWith(\"0x\") ? key : `0x${key}`;\n saveConfig(config);\n}\n\nexport function getPrivateKey(): string | undefined {\n return loadConfig().privateKey;\n}\n\n// ── Uniswap Trading API Key ──\n\nexport function setUniswapApiKey(apiKey: string): void {\n const config = loadConfig();\n config.uniswapApiKey = apiKey;\n saveConfig(config);\n}\n\nexport function getUniswapApiKey(): string | undefined {\n return loadConfig().uniswapApiKey ?? process.env.UNISWAP_API_KEY;\n}\n\n// ── Per-network RPC URLs ──\n\nexport function getConfigRpcUrl(network: string): string | undefined {\n return loadConfig().rpc?.[network];\n}\n\nexport function setConfigRpcUrl(network: string, url: string): void {\n const config = loadConfig();\n if (!config.rpc) config.rpc = {};\n config.rpc[network] = url;\n saveConfig(config);\n}\n\n// ── Per-chain contract addresses ──\n\nexport function getChainContracts(chainId: number): ChainContracts {\n const config = loadConfig();\n return config.contracts?.[String(chainId)] ?? {};\n}\n\nexport function getNotifyTo(): string | undefined {\n return loadConfig().notifyTo;\n}\n\nexport function setNotifyTo(id: string): void {\n const config = loadConfig();\n config.notifyTo = id;\n saveConfig(config);\n}\n\nexport function setChainContract(\n chainId: number,\n key: keyof ChainContracts,\n value: string,\n): void {\n const config = loadConfig();\n if (!config.contracts) config.contracts = {};\n const cid = String(chainId);\n if (!config.contracts[cid]) config.contracts[cid] = {};\n config.contracts[cid][key] = value;\n saveConfig(config);\n}\n\n// ── Syndicate Membership ──\n\n/**\n * Add (or update) a syndicate membership. Deduplicates by subdomain.\n * Automatically sets it as primary if it's the first syndicate on this chain.\n */\nexport function addSyndicate(\n chainId: number,\n membership: SyndicateMembership,\n): void {\n const config = loadConfig();\n const cid = String(chainId);\n if (!config.syndicates) config.syndicates = {};\n if (!config.syndicates[cid]) config.syndicates[cid] = [];\n\n // Upsert — replace existing entry with same subdomain\n const idx = config.syndicates[cid].findIndex(\n (s) => s.subdomain === membership.subdomain,\n );\n if (idx >= 0) {\n config.syndicates[cid][idx] = membership;\n } else {\n config.syndicates[cid].push(membership);\n }\n\n // Auto-set as primary if it's the first syndicate (or no primary set)\n if (!config.primarySyndicate) config.primarySyndicate = {};\n if (!config.primarySyndicate[cid]) {\n config.primarySyndicate[cid] = membership.subdomain;\n }\n\n saveConfig(config);\n}\n\n/** Get all syndicate memberships for a chain. */\nexport function getSyndicates(chainId: number): SyndicateMembership[] {\n const config = loadConfig();\n return config.syndicates?.[String(chainId)] ?? [];\n}\n\n/** Set which syndicate is the active/primary one for CLI commands. */\nexport function setPrimarySyndicate(\n chainId: number,\n subdomain: string,\n): void {\n const config = loadConfig();\n if (!config.primarySyndicate) config.primarySyndicate = {};\n config.primarySyndicate[String(chainId)] = subdomain;\n saveConfig(config);\n}\n\n/**\n * Get the primary syndicate for this chain.\n * Falls back to ChainContracts.vault for backwards compat with older configs.\n */\nexport function getPrimarySyndicate(\n chainId: number,\n): SyndicateMembership | undefined {\n const config = loadConfig();\n const cid = String(chainId);\n\n // Check new syndicates store first\n const primarySubdomain = config.primarySyndicate?.[cid];\n if (primarySubdomain && config.syndicates?.[cid]) {\n const found = config.syndicates[cid].find(\n (s) => s.subdomain === primarySubdomain,\n );\n if (found) return found;\n }\n\n // Backwards compat: if syndicates list has entries but no primary, use the first one\n if (config.syndicates?.[cid]?.length) {\n return config.syndicates[cid][0];\n }\n\n // Legacy fallback: config only has a vault address, no subdomain\n const vault = config.contracts?.[cid]?.vault;\n if (vault) {\n return { subdomain: \"\", vault, role: \"creator\" };\n }\n\n return undefined;\n}\n"],"mappings":";AAMA,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,IAAM,aAAa,KAAK,KAAK,GAAG,QAAQ,GAAG,WAAW;AACtD,IAAM,cAAc,KAAK,KAAK,YAAY,aAAa;AAgChD,SAAS,aAA6B;AAC3C,MAAI,GAAG,WAAW,WAAW,GAAG;AAC9B,WAAO,KAAK,MAAM,GAAG,aAAa,aAAa,OAAO,CAAC;AAAA,EACzD;AAEA,SAAO,EAAE,YAAY,CAAC,EAAE;AAC1B;AAEO,SAAS,WAAW,QAA8B;AACvD,KAAG,UAAU,YAAY,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AACzD,KAAG,cAAc,aAAa,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,EAAE,MAAM,IAAM,CAAC;AAChF;AAEO,SAAS,aAAa,WAAmB,SAAuB;AACrE,QAAM,SAAS,WAAW;AAC1B,SAAO,WAAW,SAAS,IAAI;AAC/B,aAAW,MAAM;AACnB;AAEO,SAAS,iBAAiB,WAAuC;AACtE,QAAM,SAAS,WAAW;AAC1B,SAAO,OAAO,WAAW,SAAS;AACpC;AAEO,SAAS,gBAAgB,QAAsB;AACpD,QAAM,SAAS,WAAW;AAC1B,SAAO,eAAe;AACtB,aAAW,MAAM;AACnB;AAEO,SAAS,kBAAsC;AACpD,SAAO,WAAW,EAAE,gBAAgB,QAAQ,IAAI;AAClD;AAEO,SAAS,WAAW,SAAuB;AAChD,QAAM,SAAS,WAAW;AAC1B,SAAO,UAAU;AACjB,aAAW,MAAM;AACnB;AAEO,SAAS,aAAiC;AAC/C,SAAO,WAAW,EAAE;AACtB;AAEO,SAAS,cAAc,KAAmB;AAC/C,QAAM,SAAS,WAAW;AAC1B,SAAO,aAAa,IAAI,WAAW,IAAI,IAAI,MAAM,KAAK,GAAG;AACzD,aAAW,MAAM;AACnB;AAEO,SAAS,gBAAoC;AAClD,SAAO,WAAW,EAAE;AACtB;AAIO,SAAS,iBAAiB,QAAsB;AACrD,QAAM,SAAS,WAAW;AAC1B,SAAO,gBAAgB;AACvB,aAAW,MAAM;AACnB;AAEO,SAAS,mBAAuC;AACrD,SAAO,WAAW,EAAE,iBAAiB,QAAQ,IAAI;AACnD;AAIO,SAAS,gBAAgB,SAAqC;AACnE,SAAO,WAAW,EAAE,MAAM,OAAO;AACnC;AAEO,SAAS,gBAAgB,SAAiB,KAAmB;AAClE,QAAM,SAAS,WAAW;AAC1B,MAAI,CAAC,OAAO,IAAK,QAAO,MAAM,CAAC;AAC/B,SAAO,IAAI,OAAO,IAAI;AACtB,aAAW,MAAM;AACnB;AAIO,SAAS,kBAAkB,SAAiC;AACjE,QAAM,SAAS,WAAW;AAC1B,SAAO,OAAO,YAAY,OAAO,OAAO,CAAC,KAAK,CAAC;AACjD;AAEO,SAAS,cAAkC;AAChD,SAAO,WAAW,EAAE;AACtB;AAEO,SAAS,YAAY,IAAkB;AAC5C,QAAM,SAAS,WAAW;AAC1B,SAAO,WAAW;AAClB,aAAW,MAAM;AACnB;AAEO,SAAS,iBACd,SACA,KACA,OACM;AACN,QAAM,SAAS,WAAW;AAC1B,MAAI,CAAC,OAAO,UAAW,QAAO,YAAY,CAAC;AAC3C,QAAM,MAAM,OAAO,OAAO;AAC1B,MAAI,CAAC,OAAO,UAAU,GAAG,EAAG,QAAO,UAAU,GAAG,IAAI,CAAC;AACrD,SAAO,UAAU,GAAG,EAAE,GAAG,IAAI;AAC7B,aAAW,MAAM;AACnB;AAQO,SAAS,aACd,SACA,YACM;AACN,QAAM,SAAS,WAAW;AAC1B,QAAM,MAAM,OAAO,OAAO;AAC1B,MAAI,CAAC,OAAO,WAAY,QAAO,aAAa,CAAC;AAC7C,MAAI,CAAC,OAAO,WAAW,GAAG,EAAG,QAAO,WAAW,GAAG,IAAI,CAAC;AAGvD,QAAM,MAAM,OAAO,WAAW,GAAG,EAAE;AAAA,IACjC,CAAC,MAAM,EAAE,cAAc,WAAW;AAAA,EACpC;AACA,MAAI,OAAO,GAAG;AACZ,WAAO,WAAW,GAAG,EAAE,GAAG,IAAI;AAAA,EAChC,OAAO;AACL,WAAO,WAAW,GAAG,EAAE,KAAK,UAAU;AAAA,EACxC;AAGA,MAAI,CAAC,OAAO,iBAAkB,QAAO,mBAAmB,CAAC;AACzD,MAAI,CAAC,OAAO,iBAAiB,GAAG,GAAG;AACjC,WAAO,iBAAiB,GAAG,IAAI,WAAW;AAAA,EAC5C;AAEA,aAAW,MAAM;AACnB;AAGO,SAAS,cAAc,SAAwC;AACpE,QAAM,SAAS,WAAW;AAC1B,SAAO,OAAO,aAAa,OAAO,OAAO,CAAC,KAAK,CAAC;AAClD;AAGO,SAAS,oBACd,SACA,WACM;AACN,QAAM,SAAS,WAAW;AAC1B,MAAI,CAAC,OAAO,iBAAkB,QAAO,mBAAmB,CAAC;AACzD,SAAO,iBAAiB,OAAO,OAAO,CAAC,IAAI;AAC3C,aAAW,MAAM;AACnB;AAMO,SAAS,oBACd,SACiC;AACjC,QAAM,SAAS,WAAW;AAC1B,QAAM,MAAM,OAAO,OAAO;AAG1B,QAAM,mBAAmB,OAAO,mBAAmB,GAAG;AACtD,MAAI,oBAAoB,OAAO,aAAa,GAAG,GAAG;AAChD,UAAM,QAAQ,OAAO,WAAW,GAAG,EAAE;AAAA,MACnC,CAAC,MAAM,EAAE,cAAc;AAAA,IACzB;AACA,QAAI,MAAO,QAAO;AAAA,EACpB;AAGA,MAAI,OAAO,aAAa,GAAG,GAAG,QAAQ;AACpC,WAAO,OAAO,WAAW,GAAG,EAAE,CAAC;AAAA,EACjC;AAGA,QAAM,QAAQ,OAAO,YAAY,GAAG,GAAG;AACvC,MAAI,OAAO;AACT,WAAO,EAAE,WAAW,IAAI,OAAO,MAAM,UAAU;AAAA,EACjD;AAEA,SAAO;AACT;","names":[]}
|